xref: /illumos-gate/usr/src/lib/smbsrv/libsmb/common/smb_idmap.c (revision dc20a3024900c47dd2ee44b9707e6df38f7d62a5)
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 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <strings.h>
29 #include <smbsrv/libsmb.h>
30 
31 static idmap_handle_t *idmap_clnt_hdl = NULL;
32 static int smb_idmap_batch_binsid(smb_idmap_batch_t *sib);
33 
34 /*
35  * smb_idmap_start
36  *
37  * This function initializes the idmap client handle. It should be called
38  * at startup.
39  */
40 int
41 smb_idmap_start(void)
42 {
43 	idmap_stat stat;
44 
45 	if (idmap_clnt_hdl)
46 		return (0);
47 
48 	stat = idmap_init(&idmap_clnt_hdl);
49 	if (stat < 0) {
50 		syslog(LOG_ERR, "smb_idmap_start: idmap_init failed (%s)",
51 		    idmap_stat2string(NULL, stat));
52 		return (-1);
53 	}
54 
55 	return (0);
56 }
57 
58 /*
59  * smb_idmap_stop
60  *
61  * This function destroys the idmap client handle. It should be called
62  * prior to exiting the SMB daemon.
63  */
64 void
65 smb_idmap_stop(void)
66 {
67 	if (idmap_clnt_hdl) {
68 		(void) idmap_fini(idmap_clnt_hdl);
69 		idmap_clnt_hdl = NULL;
70 	}
71 }
72 
73 /*
74  * smb_idmap_restart
75  *
76  * This function should be called when the idmap client handle
77  * becomes invalid.
78  */
79 int
80 smb_idmap_restart(void)
81 {
82 	smb_idmap_stop();
83 	if (smb_idmap_start() != 0) {
84 		syslog(LOG_ERR, "smb_idmap_restart: smb_idmap_start failed");
85 		return (-1);
86 	}
87 
88 	return (0);
89 }
90 
91 /*
92  * smb_idmap_getsid
93  *
94  * Tries to get a mapping for the given uid/gid
95  */
96 idmap_stat
97 smb_idmap_getsid(uid_t id, int idtype, nt_sid_t **sid)
98 {
99 	smb_idmap_batch_t sib;
100 	idmap_stat stat;
101 
102 	stat = smb_idmap_batch_create(&sib, 1, SMB_IDMAP_ID2SID);
103 	if (stat != IDMAP_SUCCESS)
104 		return (stat);
105 
106 	stat = smb_idmap_batch_getsid(sib.sib_idmaph, &sib.sib_maps[0],
107 	    id, idtype);
108 
109 	if (stat != IDMAP_SUCCESS) {
110 		smb_idmap_batch_destroy(&sib);
111 		return (stat);
112 	}
113 
114 	stat = smb_idmap_batch_getmappings(&sib);
115 
116 	if (stat != IDMAP_SUCCESS) {
117 		smb_idmap_batch_destroy(&sib);
118 		return (stat);
119 	}
120 
121 	*sid = nt_sid_dup(sib.sib_maps[0].sim_sid);
122 
123 	smb_idmap_batch_destroy(&sib);
124 
125 	return (IDMAP_SUCCESS);
126 }
127 
128 /*
129  * smb_idmap_getid
130  *
131  * Tries to get a mapping for the given SID
132  */
133 idmap_stat
134 smb_idmap_getid(nt_sid_t *sid, uid_t *id, int *id_type)
135 {
136 	smb_idmap_batch_t sib;
137 	smb_idmap_t *sim;
138 	idmap_stat stat;
139 
140 	stat = smb_idmap_batch_create(&sib, 1, SMB_IDMAP_SID2ID);
141 	if (stat != IDMAP_SUCCESS)
142 		return (stat);
143 
144 	sim = &sib.sib_maps[0];
145 	sim->sim_id = id;
146 	stat = smb_idmap_batch_getid(sib.sib_idmaph, sim, sid, *id_type);
147 	if (stat != IDMAP_SUCCESS) {
148 		smb_idmap_batch_destroy(&sib);
149 		return (stat);
150 	}
151 
152 	stat = smb_idmap_batch_getmappings(&sib);
153 
154 	if (stat != IDMAP_SUCCESS) {
155 		smb_idmap_batch_destroy(&sib);
156 		return (stat);
157 	}
158 
159 	*id_type = sim->sim_idtype;
160 	smb_idmap_batch_destroy(&sib);
161 
162 	return (IDMAP_SUCCESS);
163 }
164 
165 /*
166  * smb_idmap_batch_create
167  *
168  * Creates and initializes the context for batch ID mapping.
169  */
170 idmap_stat
171 smb_idmap_batch_create(smb_idmap_batch_t *sib, uint16_t nmap, int flags)
172 {
173 	idmap_stat stat;
174 
175 	if (!sib)
176 		return (IDMAP_ERR_ARG);
177 
178 	bzero(sib, sizeof (smb_idmap_batch_t));
179 	stat = idmap_get_create(idmap_clnt_hdl, &sib->sib_idmaph);
180 	if (stat != IDMAP_SUCCESS)
181 		return (stat);
182 
183 	sib->sib_flags = flags;
184 	sib->sib_nmap = nmap;
185 	sib->sib_size = nmap * sizeof (smb_idmap_t);
186 	sib->sib_maps = malloc(sib->sib_size);
187 	if (!sib->sib_maps)
188 		return (IDMAP_ERR_MEMORY);
189 
190 	bzero(sib->sib_maps, sib->sib_size);
191 	return (IDMAP_SUCCESS);
192 }
193 
194 /*
195  * smb_idmap_batch_destroy
196  *
197  * Frees the batch ID mapping context.
198  */
199 void
200 smb_idmap_batch_destroy(smb_idmap_batch_t *sib)
201 {
202 	nt_sid_t *sid;
203 	int i;
204 
205 	if (!sib)
206 		return;
207 
208 	if (sib->sib_idmaph) {
209 		idmap_get_destroy(sib->sib_idmaph);
210 		sib->sib_idmaph = NULL;
211 	}
212 
213 	if (!sib->sib_maps)
214 		return;
215 
216 	if (sib->sib_flags & SMB_IDMAP_ID2SID) {
217 		/*
218 		 * SIDs are allocated only when mapping
219 		 * UID/GID to SIDs
220 		 */
221 		for (i = 0; i < sib->sib_nmap; i++) {
222 			sid = sib->sib_maps[i].sim_sid;
223 			if (sid)
224 				free(sid);
225 		}
226 	}
227 
228 	if (sib->sib_size && sib->sib_maps) {
229 		free(sib->sib_maps);
230 		sib->sib_maps = NULL;
231 	}
232 }
233 
234 /*
235  * smb_idmap_batch_getid
236  *
237  * Queue a request to map the given SID to a UID or GID.
238  *
239  * sim->sim_id should point to variable that's supposed to
240  * hold the returned UID/GID. This needs to be setup by caller
241  * of this function.
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
246 smb_idmap_batch_getid(idmap_get_handle_t *idmaph, smb_idmap_t *sim,
247     nt_sid_t *sid, int idtype)
248 {
249 	nt_sid_t *tmpsid;
250 	idmap_stat stat;
251 	int flag = 0;
252 
253 	if (!idmaph || !sim || !sid)
254 		return (IDMAP_ERR_ARG);
255 
256 	tmpsid = nt_sid_dup(sid);
257 	if (!tmpsid)
258 		return (IDMAP_ERR_MEMORY);
259 
260 	if (nt_sid_split(tmpsid, &sim->sim_rid) != 0) {
261 		free(tmpsid);
262 		return (IDMAP_ERR_ARG);
263 	}
264 
265 	sim->sim_domsid = nt_sid_format(tmpsid);
266 	free(tmpsid);
267 
268 	switch (idtype) {
269 	case SMB_IDMAP_USER:
270 		stat = idmap_get_uidbysid(idmaph, sim->sim_domsid,
271 		    sim->sim_rid, flag, sim->sim_id, &sim->sim_stat);
272 		break;
273 
274 	case SMB_IDMAP_GROUP:
275 		stat = idmap_get_gidbysid(idmaph, sim->sim_domsid,
276 		    sim->sim_rid, flag, sim->sim_id, &sim->sim_stat);
277 		break;
278 
279 	case SMB_IDMAP_UNKNOWN:
280 		stat = idmap_get_pidbysid(idmaph, sim->sim_domsid,
281 		    sim->sim_rid, flag, sim->sim_id, &sim->sim_idtype,
282 		    &sim->sim_stat);
283 		break;
284 
285 	default:
286 		free(sim->sim_domsid);
287 		return (IDMAP_ERR_ARG);
288 	}
289 
290 	free(sim->sim_domsid);
291 	return (stat);
292 }
293 
294 /*
295  * smb_idmap_batch_getsid
296  *
297  * Queue a request to map the given UID/GID to a SID.
298  *
299  * sim->sim_domsid and sim->sim_rid will contain the mapping
300  * result upon successful process of the batched request.
301  */
302 idmap_stat
303 smb_idmap_batch_getsid(idmap_get_handle_t *idmaph, smb_idmap_t *sim,
304     uid_t id, int idtype)
305 {
306 	idmap_stat stat;
307 	int flag = 0;
308 
309 	if (!idmaph || !sim)
310 		return (IDMAP_ERR_ARG);
311 
312 	switch (idtype) {
313 	case SMB_IDMAP_USER:
314 		stat = idmap_get_sidbyuid(idmaph, id, flag,
315 		    &sim->sim_domsid, &sim->sim_rid, &sim->sim_stat);
316 		break;
317 
318 	case SMB_IDMAP_GROUP:
319 		stat = idmap_get_sidbygid(idmaph, id, flag,
320 		    &sim->sim_domsid, &sim->sim_rid, &sim->sim_stat);
321 		break;
322 
323 	case SMB_IDMAP_EVERYONE:
324 		/* Everyone S-1-1-0 */
325 		sim->sim_domsid = "S-1-1";
326 		sim->sim_rid = 0;
327 		sim->sim_stat = IDMAP_SUCCESS;
328 		stat = IDMAP_SUCCESS;
329 		break;
330 
331 	default:
332 		return (IDMAP_ERR_ARG);
333 	}
334 
335 	return (stat);
336 }
337 
338 /*
339  * smb_idmap_batch_getmappings
340  *
341  * trigger ID mapping service to get the mappings for queued
342  * requests.
343  *
344  * Checks the result of all the queued requests.
345  */
346 idmap_stat
347 smb_idmap_batch_getmappings(smb_idmap_batch_t *sib)
348 {
349 	idmap_stat stat = IDMAP_SUCCESS;
350 	int i;
351 
352 	stat = idmap_get_mappings(sib->sib_idmaph);
353 	if (stat != IDMAP_SUCCESS) {
354 		return (stat);
355 	}
356 
357 	/*
358 	 * Check the status for all the queued requests
359 	 */
360 	for (i = 0; i < sib->sib_nmap; i++) {
361 		if (sib->sib_maps[i].sim_stat != IDMAP_SUCCESS) {
362 			return (sib->sib_maps[i].sim_stat);
363 		}
364 	}
365 
366 	if (smb_idmap_batch_binsid(sib) != 0) {
367 		stat = IDMAP_ERR_OTHER;
368 	}
369 
370 	return (stat);
371 }
372 
373 /*
374  * smb_idmap_batch_binsid
375  *
376  * Convert sidrids to binary sids
377  *
378  * Returns 0 if successful and non-zero upon failure.
379  */
380 static int
381 smb_idmap_batch_binsid(smb_idmap_batch_t *sib)
382 {
383 	nt_sid_t *sid;
384 	smb_idmap_t *sim;
385 	int i;
386 
387 	if (sib->sib_flags & SMB_IDMAP_SID2ID)
388 		/* This operation is not required */
389 		return (0);
390 
391 	sim = sib->sib_maps;
392 	for (i = 0; i < sib->sib_nmap; sim++, i++) {
393 		if (sim->sim_domsid == NULL)
394 			return (-1);
395 
396 		sid = nt_sid_strtosid(sim->sim_domsid);
397 		free(sim->sim_domsid);
398 		if (sid == NULL)
399 			return (-1);
400 
401 		sim->sim_sid = nt_sid_splice(sid, sim->sim_rid);
402 		free(sid);
403 	}
404 
405 	return (0);
406 }
407