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