xref: /illumos-gate/usr/src/lib/smbsrv/libsmb/common/smb_idmap.c (revision c51cb4bc539e1650eb5bb4f805cc779bfce99c06)
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, smb_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 = smb_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(smb_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 	int i;
203 
204 	if (sib == NULL)
205 		return;
206 
207 	if (sib->sib_idmaph) {
208 		idmap_get_destroy(sib->sib_idmaph);
209 		sib->sib_idmaph = NULL;
210 	}
211 
212 	if (sib->sib_maps == NULL)
213 		return;
214 
215 	if (sib->sib_flags & SMB_IDMAP_ID2SID) {
216 		/*
217 		 * SIDs are allocated only when mapping
218 		 * UID/GID to SIDs
219 		 */
220 		for (i = 0; i < sib->sib_nmap; i++)
221 			smb_sid_free(sib->sib_maps[i].sim_sid);
222 	}
223 
224 	if (sib->sib_size && sib->sib_maps) {
225 		free(sib->sib_maps);
226 		sib->sib_maps = NULL;
227 	}
228 }
229 
230 /*
231  * smb_idmap_batch_getid
232  *
233  * Queue a request to map the given SID to a UID or GID.
234  *
235  * sim->sim_id should point to variable that's supposed to
236  * hold the returned UID/GID. This needs to be setup by caller
237  * of this function.
238  * If requested ID type is known, it's passed as 'idtype',
239  * if it's unknown it'll be returned in sim->sim_idtype.
240  */
241 idmap_stat
242 smb_idmap_batch_getid(idmap_get_handle_t *idmaph, smb_idmap_t *sim,
243     smb_sid_t *sid, int idtype)
244 {
245 	char sidstr[SMB_SID_STRSZ];
246 	smb_sid_t *tmpsid;
247 	idmap_stat stat;
248 	int flag = 0;
249 
250 	if (!idmaph || !sim || !sid)
251 		return (IDMAP_ERR_ARG);
252 
253 	tmpsid = smb_sid_dup(sid);
254 	if (!tmpsid)
255 		return (IDMAP_ERR_MEMORY);
256 
257 	if (smb_sid_split(tmpsid, &sim->sim_rid) != 0) {
258 		smb_sid_free(tmpsid);
259 		return (IDMAP_ERR_ARG);
260 	}
261 
262 	smb_sid_tostr(tmpsid, sidstr);
263 	sim->sim_domsid = sidstr;
264 	smb_sid_free(tmpsid);
265 
266 	switch (idtype) {
267 	case SMB_IDMAP_USER:
268 		stat = idmap_get_uidbysid(idmaph, sim->sim_domsid,
269 		    sim->sim_rid, flag, sim->sim_id, &sim->sim_stat);
270 		break;
271 
272 	case SMB_IDMAP_GROUP:
273 		stat = idmap_get_gidbysid(idmaph, sim->sim_domsid,
274 		    sim->sim_rid, flag, sim->sim_id, &sim->sim_stat);
275 		break;
276 
277 	case SMB_IDMAP_UNKNOWN:
278 		stat = idmap_get_pidbysid(idmaph, sim->sim_domsid,
279 		    sim->sim_rid, flag, sim->sim_id, &sim->sim_idtype,
280 		    &sim->sim_stat);
281 		break;
282 
283 	default:
284 		return (IDMAP_ERR_ARG);
285 	}
286 
287 	return (stat);
288 }
289 
290 /*
291  * smb_idmap_batch_getsid
292  *
293  * Queue a request to map the given UID/GID to a SID.
294  *
295  * sim->sim_domsid and sim->sim_rid will contain the mapping
296  * result upon successful process of the batched request.
297  */
298 idmap_stat
299 smb_idmap_batch_getsid(idmap_get_handle_t *idmaph, smb_idmap_t *sim,
300     uid_t id, int idtype)
301 {
302 	idmap_stat stat;
303 	int flag = 0;
304 
305 	if (!idmaph || !sim)
306 		return (IDMAP_ERR_ARG);
307 
308 	switch (idtype) {
309 	case SMB_IDMAP_USER:
310 		stat = idmap_get_sidbyuid(idmaph, id, flag,
311 		    &sim->sim_domsid, &sim->sim_rid, &sim->sim_stat);
312 		break;
313 
314 	case SMB_IDMAP_GROUP:
315 		stat = idmap_get_sidbygid(idmaph, id, flag,
316 		    &sim->sim_domsid, &sim->sim_rid, &sim->sim_stat);
317 		break;
318 
319 	case SMB_IDMAP_EVERYONE:
320 		/* Everyone S-1-1-0 */
321 		sim->sim_domsid = "S-1-1";
322 		sim->sim_rid = 0;
323 		sim->sim_stat = IDMAP_SUCCESS;
324 		stat = IDMAP_SUCCESS;
325 		break;
326 
327 	default:
328 		return (IDMAP_ERR_ARG);
329 	}
330 
331 	return (stat);
332 }
333 
334 /*
335  * smb_idmap_batch_getmappings
336  *
337  * trigger ID mapping service to get the mappings for queued
338  * requests.
339  *
340  * Checks the result of all the queued requests.
341  */
342 idmap_stat
343 smb_idmap_batch_getmappings(smb_idmap_batch_t *sib)
344 {
345 	idmap_stat stat = IDMAP_SUCCESS;
346 	int i;
347 
348 	stat = idmap_get_mappings(sib->sib_idmaph);
349 	if (stat != IDMAP_SUCCESS) {
350 		return (stat);
351 	}
352 
353 	/*
354 	 * Check the status for all the queued requests
355 	 */
356 	for (i = 0; i < sib->sib_nmap; i++) {
357 		if (sib->sib_maps[i].sim_stat != IDMAP_SUCCESS) {
358 			return (sib->sib_maps[i].sim_stat);
359 		}
360 	}
361 
362 	if (smb_idmap_batch_binsid(sib) != 0) {
363 		stat = IDMAP_ERR_OTHER;
364 	}
365 
366 	return (stat);
367 }
368 
369 /*
370  * smb_idmap_batch_binsid
371  *
372  * Convert sidrids to binary sids
373  *
374  * Returns 0 if successful and non-zero upon failure.
375  */
376 static int
377 smb_idmap_batch_binsid(smb_idmap_batch_t *sib)
378 {
379 	smb_sid_t *sid;
380 	smb_idmap_t *sim;
381 	int i;
382 
383 	if (sib->sib_flags & SMB_IDMAP_SID2ID)
384 		/* This operation is not required */
385 		return (0);
386 
387 	sim = sib->sib_maps;
388 	for (i = 0; i < sib->sib_nmap; sim++, i++) {
389 		if (sim->sim_domsid == NULL)
390 			return (-1);
391 
392 		sid = smb_sid_fromstr(sim->sim_domsid);
393 		free(sim->sim_domsid);
394 		if (sid == NULL)
395 			return (-1);
396 
397 		sim->sim_sid = smb_sid_splice(sid, sim->sim_rid);
398 		free(sid);
399 	}
400 
401 	return (0);
402 }
403