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 2018 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 * This is the kernel version of these routines. See also:
32 * $SRC/lib/smbsrv/libfksmbsrv/common/fksmb_idmap.c
33 * $SRC/lib/smbsrv/libsmb/common/smb_idmap.c
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 * returned 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
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 /*
108 * IDMAP_ERR_NOTFOUND is an advisory error
109 * and idmap will generate a local sid.
110 */
111 if (sim.sim_stat == IDMAP_ERR_NOTFOUND &&
112 sim.sim_domsid != NULL)
113 sim.sim_stat = IDMAP_SUCCESS;
114
115 if (sim.sim_stat != IDMAP_SUCCESS)
116 return (sim.sim_stat);
117
118 if (sim.sim_domsid == NULL)
119 return (IDMAP_ERR_NOMAPPING);
120
121 sim.sim_sid = smb_sid_fromstr(sim.sim_domsid);
122 if (sim.sim_sid == NULL)
123 return (IDMAP_ERR_INTERNAL);
124
125 *sid = smb_sid_splice(sim.sim_sid, sim.sim_rid);
126 smb_sid_free(sim.sim_sid);
127 if (*sid == NULL)
128 sim.sim_stat = IDMAP_ERR_INTERNAL;
129
130 return (sim.sim_stat);
131 }
132
133 /*
134 * smb_idmap_getid
135 *
136 * Maps the given Windows SID to a Unix ID using the
137 * simple mapping API.
138 */
139 idmap_stat
140 smb_idmap_getid(smb_sid_t *sid, uid_t *id, int *idtype)
141 {
142 smb_idmap_t sim;
143 char sidstr[SMB_SID_STRSZ];
144
145 smb_sid_tostr(sid, sidstr);
146 if (smb_sid_splitstr(sidstr, &sim.sim_rid) != 0)
147 return (IDMAP_ERR_SID);
148 sim.sim_domsid = sidstr;
149 sim.sim_id = id;
150
151 switch (*idtype) {
152 case SMB_IDMAP_USER:
153 sim.sim_stat = kidmap_getuidbysid(global_zone, sim.sim_domsid,
154 sim.sim_rid, sim.sim_id);
155 break;
156
157 case SMB_IDMAP_GROUP:
158 sim.sim_stat = kidmap_getgidbysid(global_zone, sim.sim_domsid,
159 sim.sim_rid, sim.sim_id);
160 break;
161
162 case SMB_IDMAP_UNKNOWN:
163 sim.sim_stat = kidmap_getpidbysid(global_zone, sim.sim_domsid,
164 sim.sim_rid, sim.sim_id, &sim.sim_idtype);
165 break;
166
167 default:
168 ASSERT(0);
169 return (IDMAP_ERR_ARG);
170 }
171
172 *idtype = sim.sim_idtype;
173
174 return (sim.sim_stat);
175 }
176
177 /*
178 * smb_idmap_batch_create
179 *
180 * Creates and initializes the context for batch ID mapping.
181 */
182 idmap_stat
183 smb_idmap_batch_create(smb_idmap_batch_t *sib, uint16_t nmap, int flags)
184 {
185 ASSERT(sib != NULL);
186
187 bzero(sib, sizeof (smb_idmap_batch_t));
188
189 sib->sib_idmaph = kidmap_get_create(global_zone);
190
191 sib->sib_flags = flags;
192 sib->sib_nmap = nmap;
193 sib->sib_size = nmap * sizeof (smb_idmap_t);
194 sib->sib_maps = kmem_zalloc(sib->sib_size, KM_SLEEP);
195
196 return (IDMAP_SUCCESS);
197 }
198
199 /*
200 * smb_idmap_batch_destroy
201 *
202 * Frees the batch ID mapping context.
203 * If ID mapping is Solaris -> Windows it frees memories
204 * allocated for binary SIDs.
205 */
206 void
207 smb_idmap_batch_destroy(smb_idmap_batch_t *sib)
208 {
209 char *domsid;
210 int i;
211
212 ASSERT(sib != NULL);
213 ASSERT(sib->sib_maps != NULL);
214
215 if (sib->sib_idmaph) {
216 kidmap_get_destroy(sib->sib_idmaph);
217 sib->sib_idmaph = NULL;
218 }
219
220 if (sib->sib_flags & SMB_IDMAP_ID2SID) {
221 /*
222 * SIDs are allocated only when mapping
223 * UID/GID to SIDs
224 */
225 for (i = 0; i < sib->sib_nmap; i++)
226 smb_sid_free(sib->sib_maps[i].sim_sid);
227 } else if (sib->sib_flags & SMB_IDMAP_SID2ID) {
228 /*
229 * SID prefixes are allocated only when mapping
230 * SIDs to UID/GID
231 */
232 for (i = 0; i < sib->sib_nmap; i++) {
233 domsid = sib->sib_maps[i].sim_domsid;
234 if (domsid)
235 smb_mem_free(domsid);
236 }
237 }
238
239 if (sib->sib_size && sib->sib_maps) {
240 kmem_free(sib->sib_maps, sib->sib_size);
241 sib->sib_maps = NULL;
242 }
243 }
244
245 /*
246 * smb_idmap_batch_getid
247 *
248 * Queue a request to map the given SID to a UID or GID.
249 *
250 * sim->sim_id should point to variable that's supposed to
251 * hold the returned UID/GID. This needs to be setup by caller
252 * of this function.
253 *
254 * If requested ID type is known, it's passed as 'idtype',
255 * if it's unknown it'll be returned in sim->sim_idtype.
256 */
257 idmap_stat
258 smb_idmap_batch_getid(idmap_get_handle_t *idmaph, smb_idmap_t *sim,
259 smb_sid_t *sid, int idtype)
260 {
261 char strsid[SMB_SID_STRSZ];
262 idmap_stat idm_stat;
263
264 ASSERT(idmaph != NULL);
265 ASSERT(sim != NULL);
266 ASSERT(sid != NULL);
267
268 smb_sid_tostr(sid, strsid);
269 if (smb_sid_splitstr(strsid, &sim->sim_rid) != 0)
270 return (IDMAP_ERR_SID);
271 /* Note: Free sim_domsid in smb_idmap_batch_destroy */
272 sim->sim_domsid = smb_mem_strdup(strsid);
273 sim->sim_idtype = idtype;
274
275 switch (idtype) {
276 case SMB_IDMAP_USER:
277 idm_stat = kidmap_batch_getuidbysid(idmaph, sim->sim_domsid,
278 sim->sim_rid, sim->sim_id, &sim->sim_stat);
279 break;
280
281 case SMB_IDMAP_GROUP:
282 idm_stat = kidmap_batch_getgidbysid(idmaph, sim->sim_domsid,
283 sim->sim_rid, sim->sim_id, &sim->sim_stat);
284 break;
285
286 case SMB_IDMAP_UNKNOWN:
287 idm_stat = kidmap_batch_getpidbysid(idmaph, sim->sim_domsid,
288 sim->sim_rid, sim->sim_id, &sim->sim_idtype,
289 &sim->sim_stat);
290 break;
291
292 default:
293 ASSERT(0);
294 return (IDMAP_ERR_ARG);
295 }
296
297 return (idm_stat);
298 }
299
300 /*
301 * smb_idmap_batch_getsid
302 *
303 * Queue a request to map the given UID/GID to a SID.
304 *
305 * sim->sim_domsid and sim->sim_rid will contain the mapping
306 * result upon successful process of the batched request.
307 * Stash the type for error reporting (caller saves the ID).
308 */
309 idmap_stat
310 smb_idmap_batch_getsid(idmap_get_handle_t *idmaph, smb_idmap_t *sim,
311 uid_t id, int idtype)
312 {
313 idmap_stat idm_stat;
314
315 sim->sim_idtype = idtype;
316 switch (idtype) {
317 case SMB_IDMAP_USER:
318 idm_stat = kidmap_batch_getsidbyuid(idmaph, id,
319 (const char **)&sim->sim_domsid, &sim->sim_rid,
320 &sim->sim_stat);
321 break;
322
323 case SMB_IDMAP_GROUP:
324 idm_stat = kidmap_batch_getsidbygid(idmaph, id,
325 (const char **)&sim->sim_domsid, &sim->sim_rid,
326 &sim->sim_stat);
327 break;
328
329 case SMB_IDMAP_OWNERAT:
330 /* Current Owner S-1-5-32-766 */
331 sim->sim_domsid = NT_BUILTIN_DOMAIN_SIDSTR;
332 sim->sim_rid = SECURITY_CURRENT_OWNER_RID;
333 sim->sim_stat = IDMAP_SUCCESS;
334 idm_stat = IDMAP_SUCCESS;
335 break;
336
337 case SMB_IDMAP_GROUPAT:
338 /* Current Group S-1-5-32-767 */
339 sim->sim_domsid = NT_BUILTIN_DOMAIN_SIDSTR;
340 sim->sim_rid = SECURITY_CURRENT_GROUP_RID;
341 sim->sim_stat = IDMAP_SUCCESS;
342 idm_stat = IDMAP_SUCCESS;
343 break;
344
345 case SMB_IDMAP_EVERYONE:
346 /* Everyone S-1-1-0 */
347 sim->sim_domsid = NT_WORLD_AUTH_SIDSTR;
348 sim->sim_rid = 0;
349 sim->sim_stat = IDMAP_SUCCESS;
350 idm_stat = IDMAP_SUCCESS;
351 break;
352
353 default:
354 ASSERT(0);
355 return (IDMAP_ERR_ARG);
356 }
357
358 return (idm_stat);
359 }
360
361 static void
362 smb_idmap_bgm_report(smb_idmap_batch_t *sib, smb_idmap_t *sim)
363 {
364
365 if ((sib->sib_flags & SMB_IDMAP_ID2SID) != 0) {
366 /*
367 * Note: The ID and type we asked idmap to map
368 * were saved in *sim_id and sim_idtype.
369 */
370 uint_t id = (sim->sim_id == NULL) ?
371 0 : (uint_t)*sim->sim_id;
372 cmn_err(CE_WARN, "Can't get SID for "
373 "ID=%u type=%d, status=%d",
374 id, sim->sim_idtype, sim->sim_stat);
375 }
376
377 if ((sib->sib_flags & SMB_IDMAP_SID2ID) != 0) {
378 cmn_err(CE_WARN, "Can't get ID for SID %s-%u, status=%d",
379 sim->sim_domsid, sim->sim_rid, sim->sim_stat);
380 }
381 }
382
383 /*
384 * smb_idmap_batch_getmappings
385 *
386 * trigger ID mapping service to get the mappings for queued
387 * requests.
388 *
389 * Checks the result of all the queued requests.
390 * If this is a Solaris -> Windows mapping it generates
391 * binary SIDs from returned (domsid, rid) pairs.
392 */
393 idmap_stat
394 smb_idmap_batch_getmappings(smb_idmap_batch_t *sib)
395 {
396 idmap_stat idm_stat = IDMAP_SUCCESS;
397 smb_idmap_t *sim;
398 int i;
399
400 idm_stat = kidmap_get_mappings(sib->sib_idmaph);
401 if (idm_stat != IDMAP_SUCCESS)
402 return (idm_stat);
403
404 /*
405 * Check the status for all the queued requests
406 */
407 for (i = 0, sim = sib->sib_maps; i < sib->sib_nmap; i++, sim++) {
408 if (sim->sim_stat != IDMAP_SUCCESS) {
409 smb_idmap_bgm_report(sib, sim);
410 if ((sib->sib_flags & SMB_IDMAP_SKIP_ERRS) == 0) {
411 return (sim->sim_stat);
412 }
413 }
414 }
415
416 if (smb_idmap_batch_binsid(sib) != 0)
417 idm_stat = IDMAP_ERR_OTHER;
418
419 return (idm_stat);
420 }
421
422 /*
423 * smb_idmap_batch_binsid
424 *
425 * Convert sidrids to binary sids
426 *
427 * Returns 0 if successful and non-zero upon failure.
428 */
429 static int
430 smb_idmap_batch_binsid(smb_idmap_batch_t *sib)
431 {
432 smb_sid_t *sid;
433 smb_idmap_t *sim;
434 int i;
435
436 if (sib->sib_flags & SMB_IDMAP_SID2ID)
437 /* This operation is not required */
438 return (0);
439
440 sim = sib->sib_maps;
441 for (i = 0; i < sib->sib_nmap; sim++, i++) {
442 ASSERT(sim->sim_domsid != NULL);
443 if (sim->sim_domsid == NULL)
444 return (1);
445
446 if ((sid = smb_sid_fromstr(sim->sim_domsid)) == NULL)
447 return (1);
448
449 sim->sim_sid = smb_sid_splice(sid, sim->sim_rid);
450 smb_sid_free(sid);
451 }
452
453 return (0);
454 }