xref: /illumos-gate/usr/src/lib/libidmap/common/directory_helper.c (revision 27954b0d964ffcb749cf19296906e7fecdf3da1b)
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 /*
23  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 /*
27  * Some helper routines for directory lookup.  These offer functions that
28  * you could implement yourself on top of the generic routines, but since
29  * they're a common request we implement them here.  (Well, OK, we cheat a bit
30  * and call an internal routine to do the dirty work to reduce code
31  * duplication, but you could still implement them using the generic routines.)
32  */
33 
34 #include <stdio.h>
35 #include <string.h>
36 #include <rpcsvc/idmap_prot.h>
37 #include "directory.h"
38 #include "directory_private.h"
39 #include "directory_library_impl.h"
40 #include "miscutils.h"
41 #include "sidutil.h"
42 
43 /*
44  * Given a username, return a text-form SID.
45  *
46  * The SID must be free()ed by the caller.
47  *
48  * d, if non-NULL, specifies an existing directory-search context.
49  * If NULL, a temporary one will be created.
50  */
51 directory_error_t
52 directory_sid_from_name_common(
53     directory_t d,
54     char *name,
55     char *type,
56     char **sid,
57     uint64_t *classes)
58 {
59 	directory_t d1 = NULL;
60 	static char *attrs[] = {
61 		"objectSid",
62 		"objectClass",
63 		NULL,
64 	};
65 	directory_entry_t *ret_list = NULL;
66 	directory_error_t de;
67 	struct ret_sid {
68 		sid_t **objectSid;
69 		char **objectClass;
70 	} *ret_sid;
71 
72 	/* Prep for error cases. */
73 	*sid = NULL;
74 	if (classes != NULL)
75 		*classes = 0;
76 
77 	if (d == NULL) {
78 		de = directory_open(&d1);
79 		if (de != NULL)
80 			goto out;
81 	} else {
82 		d1 = d;
83 	}
84 
85 	de = directory_get_v(d1, &ret_list, &name, 1, type, attrs);
86 	if (de != NULL)
87 		goto out;
88 	if (ret_list[0].err != NULL) {
89 		de = ret_list[0].err;
90 		ret_list[0].err = NULL;
91 		goto out;
92 	}
93 
94 	ret_sid = (struct ret_sid *)ret_list[0].attrs;
95 	if (ret_sid == NULL)
96 		goto out;
97 
98 	if (ret_sid->objectSid != NULL &&
99 	    ret_sid->objectSid[0] != NULL) {
100 		char text_sid[SID_STRSZ+1];
101 		sid_from_le(ret_sid->objectSid[0]);
102 		sid_tostr(ret_sid->objectSid[0], text_sid);
103 		*sid = strdup(text_sid);
104 		if (*sid == NULL)
105 			goto nomem;
106 	}
107 
108 	if (ret_sid->objectClass != NULL &&
109 	    classes != NULL)
110 		*classes = class_bitmap(ret_sid->objectClass);
111 
112 	goto out;
113 
114 nomem:
115 	de = directory_error("ENOMEM.directory_sid_from_name_common",
116 	    "Insufficient memory retrieving data about SID", NULL);
117 
118 out:
119 	directory_free(ret_list);
120 	if (d == NULL)
121 		directory_close(d1);
122 	return (de);
123 }
124 
125 directory_error_t
126 directory_sid_from_name(
127     directory_t d,
128     char *name,
129     char **sid,
130     uint64_t *classes)
131 {
132 	return (directory_sid_from_name_common(d, name, DIRECTORY_ID_NAME, sid,
133 	    classes));
134 }
135 
136 directory_error_t
137 directory_sid_from_user_name(directory_t d, char *name, char **sid)
138 {
139 	return (directory_sid_from_name_common(d, name, DIRECTORY_ID_USER, sid,
140 	    NULL));
141 }
142 
143 directory_error_t
144 directory_sid_from_group_name(directory_t d, char *name, char **sid)
145 {
146 	return (directory_sid_from_name_common(d, name, DIRECTORY_ID_GROUP, sid,
147 	    NULL));
148 }
149 
150 /*
151  * Given a name or text-format SID, return a user@domain.
152  *
153  * The user@domain returned must be free()ed by the caller.
154  *
155  * Returns NULL and sets *name to NULL if no error occurred but the specified
156  * entity does not exist.
157  *
158  * d, if non-NULL, specifies an existing directory-search context.
159  * If NULL, a temporary one will be created.
160  */
161 static
162 directory_error_t
163 directory_canon_common(
164     directory_t d,
165     char *id,
166     char *id_type,
167     char **canon,
168     uint64_t *classes)
169 {
170 	directory_t d1 = NULL;
171 	directory_entry_t *ret_list = NULL;
172 	directory_error_t de;
173 	/*
174 	 * Attributes required to generate a canonical name, in named-list and
175 	 * structure form.
176 	 */
177 	static char *attrs[] = {
178 		"x-sun-canonicalName",
179 		"objectClass",
180 		NULL,
181 	};
182 
183 	struct canon_name_ret {
184 		char **x_sun_canonicalName;
185 		char **objectClass;
186 	} *ret_name;
187 
188 	/* Prep for error cases. */
189 	*canon = NULL;
190 	if (classes != NULL)
191 		*classes = 0;
192 
193 	if (d == NULL) {
194 		de = directory_open(&d1);
195 		if (de != NULL)
196 			goto out;
197 	} else {
198 		d1 = d;
199 	}
200 
201 	de = directory_get_v(d1, &ret_list, &id, 1, id_type, attrs);
202 	if (de != NULL)
203 		goto out;
204 	if (ret_list[0].err != NULL) {
205 		de = ret_list[0].err;
206 		ret_list[0].err = NULL;
207 		goto out;
208 	}
209 
210 	ret_name = (struct canon_name_ret *)ret_list[0].attrs;
211 	if (ret_name == NULL)
212 		goto out;
213 
214 	if (ret_name->x_sun_canonicalName != NULL &&
215 	    ret_name->x_sun_canonicalName[0] != NULL) {
216 		*canon = strdup(ret_name->x_sun_canonicalName[0]);
217 		if (*canon == NULL)
218 			goto nomem;
219 	}
220 
221 	if (ret_name->objectClass != NULL &&
222 	    classes != NULL)
223 		*classes = class_bitmap(ret_name->objectClass);
224 
225 	goto out;
226 
227 nomem:
228 	de = directory_error("ENOMEM.directory_canon_common",
229 	    "Insufficient memory retrieving data about name", NULL);
230 
231 out:
232 	directory_free(ret_list);
233 	if (d == NULL)
234 		directory_close(d1);
235 	return (de);
236 }
237 
238 directory_error_t
239 directory_name_from_sid(
240     directory_t d,
241     char *sid,
242     char **canon,
243     uint64_t *classes)
244 {
245 	return (directory_canon_common(d, sid, DIRECTORY_ID_SID, canon,
246 	    classes));
247 }
248 
249 directory_error_t
250 directory_canon_from_name(
251     directory_t d,
252     char *name,
253     char **canon,
254     uint64_t *classes)
255 {
256 	return (directory_canon_common(d, name, DIRECTORY_ID_NAME, canon,
257 	    classes));
258 }
259 
260 directory_error_t
261 directory_canon_from_user_name(directory_t d, char *name, char **canon)
262 {
263 	return (
264 	    directory_canon_common(d, name, DIRECTORY_ID_USER, canon, NULL));
265 }
266 
267 directory_error_t
268 directory_canon_from_group_name(directory_t d, char *name, char **canon)
269 {
270 	return (
271 	    directory_canon_common(d, name, DIRECTORY_ID_GROUP, canon, NULL));
272 }
273 
274 boolean_t
275 is_in_list(char **list, char *val)
276 {
277 	for (; *list != NULL; list++) {
278 		if (strcaseeq(*list, val))
279 			return (B_TRUE);
280 	}
281 	return (B_FALSE);
282 }
283 
284 uint64_t
285 class_bitmap(char **objectClass)
286 {
287 	uint64_t ret = 0;
288 
289 	for (; *objectClass != NULL; objectClass++) {
290 		if (strcaseeq(*objectClass, "user") ||
291 		    strcaseeq(*objectClass, "posixAccount"))
292 			ret |= DIRECTORY_CLASS_USER;
293 
294 		if (strcaseeq(*objectClass, "group") ||
295 		    strcaseeq(*objectClass, "posixGroup"))
296 			ret |= DIRECTORY_CLASS_GROUP;
297 	}
298 
299 	return (ret);
300 }
301