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