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 */
51directory_error_t
52directory_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
114nomem:
115	de = directory_error("ENOMEM.directory_sid_from_name_common",
116	    "Insufficient memory retrieving data about SID", NULL);
117
118out:
119	directory_free(ret_list);
120	if (d == NULL)
121		directory_close(d1);
122	return (de);
123}
124
125directory_error_t
126directory_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
136directory_error_t
137directory_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
143directory_error_t
144directory_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 */
161static
162directory_error_t
163directory_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
227nomem:
228	de = directory_error("ENOMEM.directory_canon_common",
229	    "Insufficient memory retrieving data about name", NULL);
230
231out:
232	directory_free(ret_list);
233	if (d == NULL)
234		directory_close(d1);
235	return (de);
236}
237
238directory_error_t
239directory_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
249directory_error_t
250directory_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
260directory_error_t
261directory_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
267directory_error_t
268directory_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
274boolean_t
275is_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
284uint64_t
285class_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