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 * Copyright 2023 RackTop Systems, Inc.
25 */
26
27 /*
28 * SMB server interface to idmap
29 * (smb_idmap_get..., smb_idmap_batch_...)
30 *
31 * There are three implementations of this interface.
32 * This is the "fake kernel" version of these routines. See also:
33 * $SRC/lib/smbsrv/libsmb/common/smb_idmap.c
34 * $SRC/uts/common/fs/smbsrv/smb_idmap.c
35 *
36 * There are enough differences (relative to the code size)
37 * that it's more trouble than it's worth to merge them.
38 *
39 * This one differs from the others in that it:
40 * calls idmap interfaces (libidmap)
41 * uses kmem_... interfaces (libfakekernel)
42 * uses cmn_err instead of syslog, etc.
43 * The code in this variant looks a lot like the one in libsmb.
44 */
45
46 #include <sys/param.h>
47 #include <sys/types.h>
48
49 #include <smbsrv/smb_kproto.h>
50 #include <smbsrv/smb_idmap.h>
51
52 static int smb_idmap_batch_binsid(smb_idmap_batch_t *sib);
53
54 /*
55 * Report an idmap error.
56 */
57 void
smb_idmap_check(const char * s,idmap_stat stat)58 smb_idmap_check(const char *s, idmap_stat stat)
59 {
60 if (stat != IDMAP_SUCCESS) {
61 if (s == NULL)
62 s = "smb_idmap_check";
63
64 cmn_err(CE_NOTE, "%s: %d", s, (int)stat);
65 }
66 }
67
68 /*
69 * smb_idmap_getsid
70 *
71 * Tries to get a mapping for the given uid/gid
72 * Allocates ->sim_domsid
73 */
74 idmap_stat
smb_idmap_getsid(uid_t id,int idtype,smb_sid_t ** sid)75 smb_idmap_getsid(uid_t id, int idtype, smb_sid_t **sid)
76 {
77 smb_idmap_batch_t sib;
78 idmap_stat stat;
79
80 stat = smb_idmap_batch_create(&sib, 1, SMB_IDMAP_ID2SID);
81 if (stat != IDMAP_SUCCESS)
82 return (stat);
83
84 stat = smb_idmap_batch_getsid(sib.sib_idmaph, &sib.sib_maps[0],
85 id, idtype);
86
87 if (stat != IDMAP_SUCCESS) {
88 smb_idmap_batch_destroy(&sib);
89 return (stat);
90 }
91
92 /* Leave error reporting to the caller. */
93 stat = smb_idmap_batch_getmappings(&sib, NULL);
94
95 if (stat != IDMAP_SUCCESS) {
96 smb_idmap_batch_destroy(&sib);
97 return (stat);
98 }
99
100 *sid = smb_sid_dup(sib.sib_maps[0].sim_sid);
101
102 smb_idmap_batch_destroy(&sib);
103
104 return (IDMAP_SUCCESS);
105 }
106
107 /*
108 * smb_idmap_getid
109 *
110 * Tries to get a mapping for the given SID
111 */
112 idmap_stat
smb_idmap_getid(smb_sid_t * sid,uid_t * id,int * id_type)113 smb_idmap_getid(smb_sid_t *sid, uid_t *id, int *id_type)
114 {
115 smb_idmap_batch_t sib;
116 smb_idmap_t *sim;
117 idmap_stat stat;
118
119 stat = smb_idmap_batch_create(&sib, 1, SMB_IDMAP_SID2ID);
120 if (stat != IDMAP_SUCCESS)
121 return (stat);
122
123 sim = &sib.sib_maps[0];
124 sim->sim_id = id;
125 stat = smb_idmap_batch_getid(sib.sib_idmaph, sim, sid, *id_type);
126 if (stat != IDMAP_SUCCESS) {
127 smb_idmap_batch_destroy(&sib);
128 return (stat);
129 }
130
131 /* Leave error reporting to the caller. */
132 stat = smb_idmap_batch_getmappings(&sib, NULL);
133
134 if (stat != IDMAP_SUCCESS) {
135 smb_idmap_batch_destroy(&sib);
136 return (stat);
137 }
138
139 *id_type = sim->sim_idtype;
140 smb_idmap_batch_destroy(&sib);
141
142 return (IDMAP_SUCCESS);
143 }
144
145 /*
146 * smb_idmap_batch_create
147 *
148 * Creates and initializes the context for batch ID mapping.
149 */
150 idmap_stat
smb_idmap_batch_create(smb_idmap_batch_t * sib,uint16_t nmap,int flags)151 smb_idmap_batch_create(smb_idmap_batch_t *sib, uint16_t nmap, int flags)
152 {
153 idmap_stat stat;
154
155 ASSERT(sib != NULL);
156
157 bzero(sib, sizeof (smb_idmap_batch_t));
158 stat = idmap_get_create(&sib->sib_idmaph);
159
160 if (stat != IDMAP_SUCCESS) {
161 smb_idmap_check("idmap_get_create", stat);
162 return (stat);
163 }
164
165 sib->sib_flags = flags;
166 sib->sib_nmap = nmap;
167 sib->sib_size = nmap * sizeof (smb_idmap_t);
168 sib->sib_maps = kmem_zalloc(sib->sib_size, KM_SLEEP);
169
170 return (IDMAP_SUCCESS);
171 }
172
173 /*
174 * smb_idmap_batch_destroy
175 *
176 * Frees the batch ID mapping context.
177 */
178 void
smb_idmap_batch_destroy(smb_idmap_batch_t * sib)179 smb_idmap_batch_destroy(smb_idmap_batch_t *sib)
180 {
181 char *domsid;
182 int i;
183
184 ASSERT(sib != NULL);
185 ASSERT(sib->sib_maps != NULL);
186
187 if (sib->sib_idmaph) {
188 idmap_get_destroy(sib->sib_idmaph);
189 sib->sib_idmaph = NULL;
190 }
191
192 if (sib->sib_flags & SMB_IDMAP_ID2SID) {
193 /*
194 * SIDs are allocated only when mapping
195 * UID/GID to SIDs
196 */
197 for (i = 0; i < sib->sib_nmap; i++) {
198 smb_sid_free(sib->sib_maps[i].sim_sid);
199 /* from strdup() in libidmap */
200 free(sib->sib_maps[i].sim_domsid);
201 }
202 } else if (sib->sib_flags & SMB_IDMAP_SID2ID) {
203 /*
204 * SID prefixes are allocated only when mapping
205 * SIDs to UID/GID
206 */
207 for (i = 0; i < sib->sib_nmap; i++) {
208 domsid = sib->sib_maps[i].sim_domsid;
209 if (domsid)
210 smb_mem_free(domsid);
211 }
212 }
213
214 if (sib->sib_size && sib->sib_maps) {
215 kmem_free(sib->sib_maps, sib->sib_size);
216 sib->sib_maps = NULL;
217 }
218 }
219
220 /*
221 * smb_idmap_batch_getid
222 *
223 * Queue a request to map the given SID to a UID or GID.
224 *
225 * sim->sim_id should point to variable that's supposed to
226 * hold the returned UID/GID. This needs to be setup by caller
227 * of this function.
228 * If requested ID type is known, it's passed as 'idtype',
229 * if it's unknown it'll be returned in sim->sim_idtype.
230 */
231 idmap_stat
smb_idmap_batch_getid(idmap_get_handle_t * idmaph,smb_idmap_t * sim,smb_sid_t * sid,int idtype)232 smb_idmap_batch_getid(idmap_get_handle_t *idmaph, smb_idmap_t *sim,
233 smb_sid_t *sid, int idtype)
234 {
235 char sidstr[SMB_SID_STRSZ];
236 idmap_stat stat;
237 int flag = 0;
238
239 ASSERT(idmaph != NULL);
240 ASSERT(sim != NULL);
241 ASSERT(sid != NULL);
242
243 smb_sid_tostr(sid, sidstr);
244 if (smb_sid_splitstr(sidstr, &sim->sim_rid) != 0)
245 return (IDMAP_ERR_SID);
246 /* Note: Free sim_domsid in smb_idmap_batch_destroy */
247 sim->sim_domsid = smb_mem_strdup(sidstr);
248 sim->sim_idtype = idtype;
249
250 switch (idtype) {
251 case SMB_IDMAP_USER:
252 stat = idmap_get_uidbysid(idmaph, sim->sim_domsid,
253 sim->sim_rid, flag, sim->sim_id, &sim->sim_stat);
254 smb_idmap_check("idmap_get_uidbysid", stat);
255 break;
256
257 case SMB_IDMAP_GROUP:
258 stat = idmap_get_gidbysid(idmaph, sim->sim_domsid,
259 sim->sim_rid, flag, sim->sim_id, &sim->sim_stat);
260 smb_idmap_check("idmap_get_gidbysid", stat);
261 break;
262
263 case SMB_IDMAP_UNKNOWN:
264 stat = idmap_get_pidbysid(idmaph, sim->sim_domsid,
265 sim->sim_rid, flag, sim->sim_id, &sim->sim_idtype,
266 &sim->sim_stat);
267 smb_idmap_check("idmap_get_pidbysid", stat);
268 break;
269
270 default:
271 stat = IDMAP_ERR_ARG;
272 break;
273 }
274
275 return (stat);
276 }
277
278 /*
279 * smb_idmap_batch_getsid
280 *
281 * Queue a request to map the given UID/GID to a SID.
282 *
283 * sim->sim_domsid and sim->sim_rid will contain the mapping
284 * result upon successful process of the batched request.
285 * Stash the type for error reporting (caller saves the ID).
286 *
287 * NB: sim_domsid allocated by strdup, here or in libidmap
288 */
289 idmap_stat
smb_idmap_batch_getsid(idmap_get_handle_t * idmaph,smb_idmap_t * sim,uid_t id,int idtype)290 smb_idmap_batch_getsid(idmap_get_handle_t *idmaph, smb_idmap_t *sim,
291 uid_t id, int idtype)
292 {
293 idmap_stat stat;
294 int flag = 0;
295
296 if (!idmaph || !sim)
297 return (IDMAP_ERR_ARG);
298
299 sim->sim_idtype = idtype;
300 switch (idtype) {
301 case SMB_IDMAP_USER:
302 stat = idmap_get_sidbyuid(idmaph, id, flag,
303 &sim->sim_domsid, &sim->sim_rid, &sim->sim_stat);
304 smb_idmap_check("idmap_get_sidbyuid", stat);
305 break;
306
307 case SMB_IDMAP_GROUP:
308 stat = idmap_get_sidbygid(idmaph, id, flag,
309 &sim->sim_domsid, &sim->sim_rid, &sim->sim_stat);
310 smb_idmap_check("idmap_get_sidbygid", stat);
311 break;
312
313 case SMB_IDMAP_OWNERAT:
314 /* Current Owner S-1-5-32-766 */
315 sim->sim_domsid = strdup(NT_BUILTIN_DOMAIN_SIDSTR);
316 sim->sim_rid = SECURITY_CURRENT_OWNER_RID;
317 sim->sim_stat = IDMAP_SUCCESS;
318 stat = IDMAP_SUCCESS;
319 break;
320
321 case SMB_IDMAP_GROUPAT:
322 /* Current Group S-1-5-32-767 */
323 sim->sim_domsid = strdup(NT_BUILTIN_DOMAIN_SIDSTR);
324 sim->sim_rid = SECURITY_CURRENT_GROUP_RID;
325 sim->sim_stat = IDMAP_SUCCESS;
326 stat = IDMAP_SUCCESS;
327 break;
328
329 case SMB_IDMAP_EVERYONE:
330 /* Everyone S-1-1-0 */
331 sim->sim_domsid = strdup(NT_WORLD_AUTH_SIDSTR);
332 sim->sim_rid = 0;
333 sim->sim_stat = IDMAP_SUCCESS;
334 stat = IDMAP_SUCCESS;
335 break;
336
337 default:
338 ASSERT(0);
339 return (IDMAP_ERR_ARG);
340 }
341
342 return (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 */
353 idmap_stat
smb_idmap_batch_getmappings(smb_idmap_batch_t * sib,smb_idmap_batch_errcb_t errcb)354 smb_idmap_batch_getmappings(smb_idmap_batch_t *sib,
355 smb_idmap_batch_errcb_t errcb)
356 {
357 idmap_stat stat = IDMAP_SUCCESS;
358 smb_idmap_t *sim;
359 int i;
360
361 if ((stat = idmap_get_mappings(sib->sib_idmaph)) != IDMAP_SUCCESS) {
362 smb_idmap_check("idmap_get_mappings", stat);
363 return (stat);
364 }
365
366 /*
367 * Check the status for all the queued requests
368 */
369 for (i = 0, sim = sib->sib_maps; i < sib->sib_nmap; i++, sim++) {
370 if (sim->sim_stat != IDMAP_SUCCESS) {
371 sib->sib_nerr++;
372 if (errcb != NULL)
373 errcb(sib, sim);
374 if ((sib->sib_flags & SMB_IDMAP_SKIP_ERRS) == 0) {
375 return (sim->sim_stat);
376 }
377 }
378 }
379
380 if (smb_idmap_batch_binsid(sib) != 0)
381 stat = IDMAP_ERR_OTHER;
382
383 return (stat);
384 }
385
386 /*
387 * smb_idmap_batch_binsid
388 *
389 * Convert sidrids to binary sids
390 *
391 * Returns 0 if successful and non-zero upon failure.
392 */
393 static int
smb_idmap_batch_binsid(smb_idmap_batch_t * sib)394 smb_idmap_batch_binsid(smb_idmap_batch_t *sib)
395 {
396 smb_sid_t *sid;
397 smb_idmap_t *sim;
398 int i;
399
400 if (sib->sib_flags & SMB_IDMAP_SID2ID)
401 /* This operation is not required */
402 return (0);
403
404 sim = sib->sib_maps;
405 for (i = 0; i < sib->sib_nmap; sim++, i++) {
406 ASSERT(sim->sim_domsid != NULL);
407 if (sim->sim_domsid == NULL)
408 return (-1);
409
410 sid = smb_sid_fromstr(sim->sim_domsid);
411 if (sid == NULL)
412 return (-1);
413
414 sim->sim_sid = smb_sid_splice(sid, sim->sim_rid);
415 smb_sid_free(sid);
416 }
417
418 return (0);
419 }
420