xref: /illumos-gate/usr/src/lib/smbsrv/libsmb/common/smb_idmap.c (revision 89a7715a55deca73d03076f5c24463717f0aaa91)
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 2007 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_batch_create
130  *
131  * Creates and initializes the context for batch ID mapping.
132  */
133 idmap_stat
134 smb_idmap_batch_create(smb_idmap_batch_t *sib, uint16_t nmap, int flags)
135 {
136 	idmap_stat stat;
137 
138 	if (!sib)
139 		return (IDMAP_ERR_ARG);
140 
141 	bzero(sib, sizeof (smb_idmap_batch_t));
142 	stat = idmap_get_create(idmap_clnt_hdl, &sib->sib_idmaph);
143 	if (stat != IDMAP_SUCCESS)
144 		return (stat);
145 
146 	sib->sib_flags = flags;
147 	sib->sib_nmap = nmap;
148 	sib->sib_size = nmap * sizeof (smb_idmap_t);
149 	sib->sib_maps = malloc(sib->sib_size);
150 	if (!sib->sib_maps)
151 		return (IDMAP_ERR_MEMORY);
152 
153 	bzero(sib->sib_maps, sib->sib_size);
154 	return (IDMAP_SUCCESS);
155 }
156 
157 /*
158  * smb_idmap_batch_destroy
159  *
160  * Frees the batch ID mapping context.
161  */
162 void
163 smb_idmap_batch_destroy(smb_idmap_batch_t *sib)
164 {
165 	nt_sid_t *sid;
166 	char *domsid;
167 	int i;
168 
169 	if (!sib)
170 		return;
171 
172 	if (sib->sib_idmaph) {
173 		idmap_get_destroy(sib->sib_idmaph);
174 		sib->sib_idmaph = NULL;
175 	}
176 
177 	if (!sib->sib_maps)
178 		return;
179 
180 	switch (sib->sib_flags) {
181 	case SMB_IDMAP_SID2ID:
182 		/*
183 		 * SIDs are allocated only when mapping
184 		 * UID/GID to SIDs
185 		 */
186 		for (i = 0; i < sib->sib_nmap; i++) {
187 			sid = sib->sib_maps[i].sim_sid;
188 			if (sid)
189 				free(sid);
190 		}
191 		break;
192 	case SMB_IDMAP_ID2SID:
193 		/*
194 		 * SID prefixes are allocated only when mapping
195 		 * SIDs to UID/GID
196 		 */
197 		for (i = 0; i < sib->sib_nmap; i++) {
198 			domsid = sib->sib_maps[i].sim_domsid;
199 			if (domsid)
200 				free(domsid);
201 		}
202 		break;
203 	default:
204 		break;
205 	}
206 
207 	if (sib->sib_size && sib->sib_maps) {
208 		free(sib->sib_maps);
209 		sib->sib_maps = NULL;
210 	}
211 }
212 
213 /*
214  * smb_idmap_batch_getid
215  *
216  * Queue a request to map the given SID to a UID or GID.
217  *
218  * sim->sim_id should point to variable that's supposed to
219  * hold the returned UID/GID. This needs to be setup by caller
220  * of this function.
221  * If requested ID type is known, it's passed as 'idtype',
222  * if it's unknown it'll be returned in sim->sim_idtype.
223  */
224 idmap_stat
225 smb_idmap_batch_getid(idmap_get_handle_t *idmaph, smb_idmap_t *sim,
226     nt_sid_t *sid, int idtype)
227 {
228 	nt_sid_t *tmpsid;
229 	idmap_stat stat;
230 	int flag = 0;
231 
232 	if (!idmaph || !sim || !sid)
233 		return (IDMAP_ERR_ARG);
234 
235 	tmpsid = nt_sid_dup(sid);
236 	if (!tmpsid)
237 		return (IDMAP_ERR_MEMORY);
238 
239 	if (nt_sid_split(tmpsid, &sim->sim_rid) != 0) {
240 		free(tmpsid);
241 		return (IDMAP_ERR_ARG);
242 	}
243 
244 	sim->sim_domsid = nt_sid_format(tmpsid);
245 	free(tmpsid);
246 
247 	switch (idtype) {
248 	case SMB_IDMAP_USER:
249 		stat = idmap_get_uidbysid(idmaph, sim->sim_domsid,
250 		    sim->sim_rid, flag, sim->sim_id, &sim->sim_stat);
251 		break;
252 
253 	case SMB_IDMAP_GROUP:
254 		stat = idmap_get_gidbysid(idmaph, sim->sim_domsid,
255 		    sim->sim_rid, flag, sim->sim_id, &sim->sim_stat);
256 		break;
257 
258 	case SMB_IDMAP_UNKNOWN:
259 		stat = idmap_get_pidbysid(idmaph, sim->sim_domsid,
260 		    sim->sim_rid, flag, sim->sim_id, &sim->sim_idtype,
261 		    &sim->sim_stat);
262 		break;
263 
264 	default:
265 		return (IDMAP_ERR_ARG);
266 	}
267 
268 	return (stat);
269 }
270 
271 /*
272  * smb_idmap_batch_getsid
273  *
274  * Queue a request to map the given UID/GID to a SID.
275  *
276  * sim->sim_domsid and sim->sim_rid will contain the mapping
277  * result upon successful process of the batched request.
278  */
279 idmap_stat
280 smb_idmap_batch_getsid(idmap_get_handle_t *idmaph, smb_idmap_t *sim,
281     uid_t id, int idtype)
282 {
283 	idmap_stat stat;
284 	int flag = 0;
285 
286 	if (!idmaph || !sim)
287 		return (IDMAP_ERR_ARG);
288 
289 	switch (idtype) {
290 	case SMB_IDMAP_USER:
291 		stat = idmap_get_sidbyuid(idmaph, id, flag,
292 		    &sim->sim_domsid, &sim->sim_rid, &sim->sim_stat);
293 		break;
294 
295 	case SMB_IDMAP_GROUP:
296 		stat = idmap_get_sidbygid(idmaph, id, flag,
297 		    &sim->sim_domsid, &sim->sim_rid, &sim->sim_stat);
298 		break;
299 
300 	case SMB_IDMAP_EVERYONE:
301 		/* Everyone S-1-1-0 */
302 		sim->sim_domsid = "S-1-1";
303 		sim->sim_rid = 0;
304 		sim->sim_stat = IDMAP_SUCCESS;
305 		stat = IDMAP_SUCCESS;
306 		break;
307 
308 	default:
309 		return (IDMAP_ERR_ARG);
310 	}
311 
312 	return (stat);
313 }
314 
315 /*
316  * smb_idmap_batch_getmappings
317  *
318  * trigger ID mapping service to get the mappings for queued
319  * requests.
320  *
321  * Checks the result of all the queued requests.
322  */
323 idmap_stat
324 smb_idmap_batch_getmappings(smb_idmap_batch_t *sib)
325 {
326 	idmap_stat stat = IDMAP_SUCCESS;
327 	int i;
328 
329 	stat = idmap_get_mappings(sib->sib_idmaph);
330 	if (stat != IDMAP_SUCCESS) {
331 		return (stat);
332 	}
333 
334 	/*
335 	 * Check the status for all the queued requests
336 	 */
337 	for (i = 0; i < sib->sib_nmap; i++) {
338 		if (sib->sib_maps[i].sim_stat != IDMAP_SUCCESS) {
339 			return (sib->sib_maps[i].sim_stat);
340 		}
341 	}
342 
343 	if (smb_idmap_batch_binsid(sib) != 0) {
344 		stat = IDMAP_ERR_OTHER;
345 	}
346 
347 	return (stat);
348 }
349 
350 /*
351  * smb_idmap_batch_binsid
352  *
353  * Convert sidrids to binary sids
354  *
355  * Returns 0 if successful and non-zero upon failure.
356  */
357 static int
358 smb_idmap_batch_binsid(smb_idmap_batch_t *sib)
359 {
360 	nt_sid_t *sid;
361 	smb_idmap_t *sim;
362 	int i;
363 
364 	if (sib->sib_flags & SMB_IDMAP_SID2ID)
365 		/* This operation is not required */
366 		return (0);
367 
368 	sim = sib->sib_maps;
369 	for (i = 0; i < sib->sib_nmap; sim++, i++) {
370 		if (sim->sim_domsid == NULL)
371 			return (-1);
372 
373 		sid = nt_sid_strtosid(sim->sim_domsid);
374 		if (sid == NULL)
375 			return (-1);
376 
377 		sim->sim_sid = nt_sid_splice(sid, sim->sim_rid);
378 		free(sid);
379 	}
380 
381 	return (0);
382 }
383