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