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