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 <libuutil.h>
37 #include <rpcsvc/idmap_prot.h>
38 #include "directory.h"
39 #include "directory_private.h"
40 #include "directory_library_impl.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
directory_sid_from_name_common(directory_t d,char * name,char * type,char ** sid,uint64_t * classes)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
directory_sid_from_name(directory_t d,char * name,char ** sid,uint64_t * classes)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
directory_sid_from_user_name(directory_t d,char * name,char ** sid)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
directory_sid_from_group_name(directory_t d,char * name,char ** sid)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
directory_canon_common(directory_t d,char * id,char * id_type,char ** canon,uint64_t * classes)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
directory_name_from_sid(directory_t d,char * sid,char ** canon,uint64_t * classes)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
directory_canon_from_name(directory_t d,char * name,char ** canon,uint64_t * classes)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
directory_canon_from_user_name(directory_t d,char * name,char ** canon)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
directory_canon_from_group_name(directory_t d,char * name,char ** canon)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
is_in_list(char ** list,char * val)275 is_in_list(char **list, char *val)
276 {
277 for (; *list != NULL; list++) {
278 if (uu_strcaseeq(*list, val))
279 return (B_TRUE);
280 }
281 return (B_FALSE);
282 }
283
284 uint64_t
class_bitmap(char ** objectClass)285 class_bitmap(char **objectClass)
286 {
287 uint64_t ret = 0;
288
289 for (; *objectClass != NULL; objectClass++) {
290 if (uu_strcaseeq(*objectClass, "user") ||
291 uu_strcaseeq(*objectClass, "posixAccount"))
292 ret |= DIRECTORY_CLASS_USER;
293
294 if (uu_strcaseeq(*objectClass, "group") ||
295 uu_strcaseeq(*objectClass, "posixGroup"))
296 ret |= DIRECTORY_CLASS_GROUP;
297 }
298
299 return (ret);
300 }
301