1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
24 */
25
26 /*
27 * SMB server interface to idmap
28 * (smb_idmap_get..., smb_idmap_batch_...)
29 *
30 * There are three implementations of this interface:
31 * uts/common/fs/smbsrv/smb_idmap.c (smbsrv kmod)
32 * lib/smbsrv/libfksmbsrv/common/fksmb_idmap.c (libfksmbsrv)
33 * lib/smbsrv/libsmb/common/smb_idmap.c (libsmb)
34 *
35 * There are enough differences (relative to the code size)
36 * that it's more trouble than it's worth to merge them.
37 *
38 * This one differs from the others in that it:
39 * calls kernel (kidmap_...) interfaces
40 * domain SIDs are shared, not strdup'ed
41 */
42
43 /*
44 * SMB ID mapping
45 *
46 * Solaris ID mapping service (aka Winchester) works with domain SIDs
47 * and RIDs where domain SIDs are in string format. CIFS service works
48 * with binary SIDs understandable by CIFS clients. A layer of SMB ID
49 * mapping functions are implemeted to hide the SID conversion details
50 * and also hide the handling of array of batch mapping requests.
51 */
52
53 #include <sys/param.h>
54 #include <sys/types.h>
55 #include <sys/tzfile.h>
56 #include <sys/atomic.h>
57 #include <sys/kidmap.h>
58 #include <sys/time.h>
59 #include <sys/spl.h>
60 #include <sys/random.h>
61 #include <smbsrv/smb_kproto.h>
62 #include <smbsrv/smb_fsops.h>
63 #include <smbsrv/smbinfo.h>
64 #include <smbsrv/smb_xdr.h>
65 #include <smbsrv/smb_vops.h>
66 #include <smbsrv/smb_idmap.h>
67
68 #include <sys/sid.h>
69 #include <sys/priv_names.h>
70
71 static int smb_idmap_batch_binsid(smb_idmap_batch_t *sib);
72
73 /*
74 * smb_idmap_getsid
75 *
76 * Maps the given Solaris ID to a Windows SID using the
77 * simple mapping API.
78 */
79 idmap_stat
smb_idmap_getsid(uid_t id,int idtype,smb_sid_t ** sid)80 smb_idmap_getsid(uid_t id, int idtype, smb_sid_t **sid)
81 {
82 smb_idmap_t sim;
83
84 switch (idtype) {
85 case SMB_IDMAP_USER:
86 sim.sim_stat = kidmap_getsidbyuid(global_zone, id,
87 (const char **)&sim.sim_domsid, &sim.sim_rid);
88 break;
89
90 case SMB_IDMAP_GROUP:
91 sim.sim_stat = kidmap_getsidbygid(global_zone, id,
92 (const char **)&sim.sim_domsid, &sim.sim_rid);
93 break;
94
95 case SMB_IDMAP_EVERYONE:
96 /* Everyone S-1-1-0 */
97 sim.sim_domsid = "S-1-1";
98 sim.sim_rid = 0;
99 sim.sim_stat = IDMAP_SUCCESS;
100 break;
101
102 default:
103 ASSERT(0);
104 return (IDMAP_ERR_ARG);
105 }
106
107 if (sim.sim_stat != IDMAP_SUCCESS)
108 return (sim.sim_stat);
109
110 if (sim.sim_domsid == NULL)
111 return (IDMAP_ERR_NOMAPPING);
112
113 sim.sim_sid = smb_sid_fromstr(sim.sim_domsid);
114 if (sim.sim_sid == NULL)
115 return (IDMAP_ERR_INTERNAL);
116
117 *sid = smb_sid_splice(sim.sim_sid, sim.sim_rid);
118 smb_sid_free(sim.sim_sid);
119 if (*sid == NULL)
120 sim.sim_stat = IDMAP_ERR_INTERNAL;
121
122 return (sim.sim_stat);
123 }
124
125 /*
126 * smb_idmap_getid
127 *
128 * Maps the given Windows SID to a Unix ID using the
129 * simple mapping API.
130 */
131 idmap_stat
smb_idmap_getid(smb_sid_t * sid,uid_t * id,int * idtype)132 smb_idmap_getid(smb_sid_t *sid, uid_t *id, int *idtype)
133 {
134 smb_idmap_t sim;
135 char sidstr[SMB_SID_STRSZ];
136
137 smb_sid_tostr(sid, sidstr);
138 if (smb_sid_splitstr(sidstr, &sim.sim_rid) != 0)
139 return (IDMAP_ERR_SID);
140 sim.sim_domsid = sidstr;
141 sim.sim_id = id;
142
143 switch (*idtype) {
144 case SMB_IDMAP_USER:
145 sim.sim_stat = kidmap_getuidbysid(global_zone, sim.sim_domsid,
146 sim.sim_rid, sim.sim_id);
147 break;
148
149 case SMB_IDMAP_GROUP:
150 sim.sim_stat = kidmap_getgidbysid(global_zone, sim.sim_domsid,
151 sim.sim_rid, sim.sim_id);
152 break;
153
154 case SMB_IDMAP_UNKNOWN:
155 sim.sim_stat = kidmap_getpidbysid(global_zone, sim.sim_domsid,
156 sim.sim_rid, sim.sim_id, &sim.sim_idtype);
157 break;
158
159 default:
160 ASSERT(0);
161 return (IDMAP_ERR_ARG);
162 }
163
164 *idtype = sim.sim_idtype;
165
166 return (sim.sim_stat);
167 }
168
169 /*
170 * smb_idmap_batch_create
171 *
172 * Creates and initializes the context for batch ID mapping.
173 */
174 idmap_stat
smb_idmap_batch_create(smb_idmap_batch_t * sib,uint16_t nmap,int flags)175 smb_idmap_batch_create(smb_idmap_batch_t *sib, uint16_t nmap, int flags)
176 {
177 ASSERT(sib);
178
179 bzero(sib, sizeof (smb_idmap_batch_t));
180
181 sib->sib_idmaph = kidmap_get_create(global_zone);
182
183 sib->sib_flags = flags;
184 sib->sib_nmap = nmap;
185 sib->sib_size = nmap * sizeof (smb_idmap_t);
186 sib->sib_maps = kmem_zalloc(sib->sib_size, KM_SLEEP);
187
188 return (IDMAP_SUCCESS);
189 }
190
191 /*
192 * smb_idmap_batch_destroy
193 *
194 * Frees the batch ID mapping context.
195 * If ID mapping is Solaris -> Windows it frees memories
196 * allocated for binary SIDs.
197 */
198 void
smb_idmap_batch_destroy(smb_idmap_batch_t * sib)199 smb_idmap_batch_destroy(smb_idmap_batch_t *sib)
200 {
201 char *domsid;
202 int i;
203
204 ASSERT(sib);
205 ASSERT(sib->sib_maps);
206
207 if (sib->sib_idmaph)
208 kidmap_get_destroy(sib->sib_idmaph);
209
210 if (sib->sib_flags & SMB_IDMAP_ID2SID) {
211 /*
212 * SIDs are allocated only when mapping
213 * UID/GID to SIDs
214 */
215 for (i = 0; i < sib->sib_nmap; i++)
216 smb_sid_free(sib->sib_maps[i].sim_sid);
217 } else if (sib->sib_flags & SMB_IDMAP_SID2ID) {
218 /*
219 * SID prefixes are allocated only when mapping
220 * SIDs to UID/GID
221 */
222 for (i = 0; i < sib->sib_nmap; i++) {
223 domsid = sib->sib_maps[i].sim_domsid;
224 if (domsid)
225 smb_mem_free(domsid);
226 }
227 }
228
229 if (sib->sib_size && sib->sib_maps)
230 kmem_free(sib->sib_maps, sib->sib_size);
231 }
232
233 /*
234 * smb_idmap_batch_getid
235 *
236 * Queue a request to map the given SID to a UID or GID.
237 *
238 * sim->sim_id should point to variable that's supposed to
239 * hold the returned UID/GID. This needs to be setup by caller
240 * of this function.
241 *
242 * If requested ID type is known, it's passed as 'idtype',
243 * if it's unknown it'll be returned in sim->sim_idtype.
244 */
245 idmap_stat
smb_idmap_batch_getid(idmap_get_handle_t * idmaph,smb_idmap_t * sim,smb_sid_t * sid,int idtype)246 smb_idmap_batch_getid(idmap_get_handle_t *idmaph, smb_idmap_t *sim,
247 smb_sid_t *sid, int idtype)
248 {
249 char strsid[SMB_SID_STRSZ];
250 idmap_stat idm_stat;
251
252 ASSERT(idmaph);
253 ASSERT(sim);
254 ASSERT(sid);
255
256 smb_sid_tostr(sid, strsid);
257 if (smb_sid_splitstr(strsid, &sim->sim_rid) != 0)
258 return (IDMAP_ERR_SID);
259 sim->sim_domsid = smb_mem_strdup(strsid);
260
261 switch (idtype) {
262 case SMB_IDMAP_USER:
263 idm_stat = kidmap_batch_getuidbysid(idmaph, sim->sim_domsid,
264 sim->sim_rid, sim->sim_id, &sim->sim_stat);
265 break;
266
267 case SMB_IDMAP_GROUP:
268 idm_stat = kidmap_batch_getgidbysid(idmaph, sim->sim_domsid,
269 sim->sim_rid, sim->sim_id, &sim->sim_stat);
270 break;
271
272 case SMB_IDMAP_UNKNOWN:
273 idm_stat = kidmap_batch_getpidbysid(idmaph, sim->sim_domsid,
274 sim->sim_rid, sim->sim_id, &sim->sim_idtype,
275 &sim->sim_stat);
276 break;
277
278 default:
279 ASSERT(0);
280 return (IDMAP_ERR_ARG);
281 }
282
283 return (idm_stat);
284 }
285
286 /*
287 * smb_idmap_batch_getsid
288 *
289 * Queue a request to map the given UID/GID to a SID.
290 *
291 * sim->sim_domsid and sim->sim_rid will contain the mapping
292 * result upon successful process of the batched request.
293 */
294 idmap_stat
smb_idmap_batch_getsid(idmap_get_handle_t * idmaph,smb_idmap_t * sim,uid_t id,int idtype)295 smb_idmap_batch_getsid(idmap_get_handle_t *idmaph, smb_idmap_t *sim,
296 uid_t id, int idtype)
297 {
298 idmap_stat idm_stat;
299
300 switch (idtype) {
301 case SMB_IDMAP_USER:
302 idm_stat = kidmap_batch_getsidbyuid(idmaph, id,
303 (const char **)&sim->sim_domsid, &sim->sim_rid,
304 &sim->sim_stat);
305 break;
306
307 case SMB_IDMAP_GROUP:
308 idm_stat = kidmap_batch_getsidbygid(idmaph, id,
309 (const char **)&sim->sim_domsid, &sim->sim_rid,
310 &sim->sim_stat);
311 break;
312
313 case SMB_IDMAP_OWNERAT:
314 /* Current Owner S-1-5-32-766 */
315 sim->sim_domsid = NT_BUILTIN_DOMAIN_SIDSTR;
316 sim->sim_rid = SECURITY_CURRENT_OWNER_RID;
317 sim->sim_stat = IDMAP_SUCCESS;
318 idm_stat = IDMAP_SUCCESS;
319 break;
320
321 case SMB_IDMAP_GROUPAT:
322 /* Current Group S-1-5-32-767 */
323 sim->sim_domsid = NT_BUILTIN_DOMAIN_SIDSTR;
324 sim->sim_rid = SECURITY_CURRENT_GROUP_RID;
325 sim->sim_stat = IDMAP_SUCCESS;
326 idm_stat = IDMAP_SUCCESS;
327 break;
328
329 case SMB_IDMAP_EVERYONE:
330 /* Everyone S-1-1-0 */
331 sim->sim_domsid = NT_WORLD_AUTH_SIDSTR;
332 sim->sim_rid = 0;
333 sim->sim_stat = IDMAP_SUCCESS;
334 idm_stat = IDMAP_SUCCESS;
335 break;
336
337 default:
338 ASSERT(0);
339 return (IDMAP_ERR_ARG);
340 }
341
342 return (idm_stat);
343 }
344
345 /*
346 * smb_idmap_batch_getmappings
347 *
348 * trigger ID mapping service to get the mappings for queued
349 * requests.
350 *
351 * Checks the result of all the queued requests.
352 * If this is a Solaris -> Windows mapping it generates
353 * binary SIDs from returned (domsid, rid) pairs.
354 */
355 idmap_stat
smb_idmap_batch_getmappings(smb_idmap_batch_t * sib)356 smb_idmap_batch_getmappings(smb_idmap_batch_t *sib)
357 {
358 idmap_stat idm_stat = IDMAP_SUCCESS;
359 int i;
360
361 idm_stat = kidmap_get_mappings(sib->sib_idmaph);
362 if (idm_stat != IDMAP_SUCCESS)
363 return (idm_stat);
364
365 /*
366 * Check the status for all the queued requests
367 */
368 for (i = 0; i < sib->sib_nmap; i++) {
369 if (sib->sib_maps[i].sim_stat != IDMAP_SUCCESS)
370 return (sib->sib_maps[i].sim_stat);
371 }
372
373 if (smb_idmap_batch_binsid(sib) != 0)
374 idm_stat = IDMAP_ERR_OTHER;
375
376 return (idm_stat);
377 }
378
379 /*
380 * smb_idmap_batch_binsid
381 *
382 * Convert sidrids to binary sids
383 *
384 * Returns 0 if successful and non-zero upon failure.
385 */
386 static int
smb_idmap_batch_binsid(smb_idmap_batch_t * sib)387 smb_idmap_batch_binsid(smb_idmap_batch_t *sib)
388 {
389 smb_sid_t *sid;
390 smb_idmap_t *sim;
391 int i;
392
393 if (sib->sib_flags & SMB_IDMAP_SID2ID)
394 /* This operation is not required */
395 return (0);
396
397 sim = sib->sib_maps;
398 for (i = 0; i < sib->sib_nmap; sim++, i++) {
399 ASSERT(sim->sim_domsid);
400 if (sim->sim_domsid == NULL)
401 return (1);
402
403 if ((sid = smb_sid_fromstr(sim->sim_domsid)) == NULL)
404 return (1);
405
406 sim->sim_sid = smb_sid_splice(sid, sim->sim_rid);
407 smb_sid_free(sid);
408 }
409
410 return (0);
411 }
412