xref: /illumos-gate/usr/src/cmd/idmap/idmapd/directory_server.c (revision 66582b606a8194f7f3ba5b3a3a6dca5b0d346361)
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  * Server-side support for directory information lookup functions.
28  */
29 
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <stdarg.h>
33 #include <malloc.h>
34 #include <sys/types.h>
35 #include <netdb.h>
36 #include <pthread.h>
37 #include <unistd.h>
38 #include <string.h>
39 #include <libuutil.h>
40 #include <note.h>
41 #include "idmapd.h"
42 #include "directory.h"
43 #include "directory_private.h"
44 #include <rpcsvc/idmap_prot.h>
45 #include "directory_library_impl.h"
46 #include "directory_server_impl.h"
47 #include "sized_array.h"
48 
49 /*
50  * Here's a list of all of the modules that provide directory
51  * information.  In the fullness of time this should probably be
52  * a plugin-able switch mechanism.
53  * Note that the list is in precedence order.
54  */
55 extern struct directory_provider_static directory_provider_builtin;
56 extern struct directory_provider_static directory_provider_nsswitch;
57 extern struct directory_provider_static directory_provider_ad;
58 struct directory_provider_static *providers[] = {
59 	&directory_provider_builtin,
60 	&directory_provider_nsswitch,
61 	&directory_provider_ad,
62 };
63 
64 /*
65  * This is the entry point for all directory lookup service requests.
66  */
67 bool_t
68 directory_get_common_1_svc(
69     idmap_utf8str_list ids,
70     idmap_utf8str types,
71     idmap_utf8str_list attrs,
72     directory_results_rpc *result,
73     struct svc_req *req)
74 {
75 	NOTE(ARGUNUSED(req))
76 	int nids;
77 	directory_entry_rpc *entries;
78 	directory_error_t de;
79 	int i;
80 
81 	nids = ids.idmap_utf8str_list_len;
82 
83 	entries = (directory_entry_rpc *)
84 	    calloc(nids, sizeof (directory_entry_rpc));
85 	if (entries == NULL)
86 		goto nomem;
87 	result->directory_results_rpc_u.entries.entries_val = entries;
88 	result->directory_results_rpc_u.entries.entries_len = nids;
89 	result->failed = FALSE;
90 
91 	for (i = 0; i < nids; i++) {
92 		if (strlen(ids.idmap_utf8str_list_val[i]) >
93 		    IDMAP_MAX_NAME_LEN) {
94 			directory_entry_set_error(&entries[i],
95 			    directory_error("invalid_arg.id.too_long",
96 			    "Identifier too long", NULL));
97 		}
98 	}
99 
100 	for (i = 0; i < UU_NELEM(providers); i++) {
101 		de = providers[i]->get(entries, &ids, types,
102 		    &attrs);
103 		if (de != NULL)
104 			goto err;
105 	}
106 
107 	return (TRUE);
108 
109 nomem:
110 	de = directory_error("ENOMEM.get_common",
111 	    "Insufficient memory retrieving directory data", NULL);
112 
113 err:
114 	xdr_free(xdr_directory_results_rpc, (char *)result);
115 	result->failed = TRUE;
116 	return (
117 	    directory_error_to_rpc(&result->directory_results_rpc_u.err, de));
118 }
119 
120 /*
121  * Split name into {domain, name}.
122  * Suggest allocating name and domain on the stack, same size as id,
123  * using variable length arrays.
124  */
125 void
126 split_name(char *name, char *domain, char *id)
127 {
128 	char *p;
129 
130 	if ((p = strchr(id, '@')) != NULL) {
131 		(void) strlcpy(name, id, p - id + 1);
132 		(void) strcpy(domain, p + 1);
133 	} else if ((p = strchr(id, '\\')) != NULL) {
134 		(void) strcpy(name, p + 1);
135 		(void) strlcpy(domain, id, p - id + 1);
136 	} else {
137 		(void) strcpy(name, id);
138 		(void) strcpy(domain, "");
139 	}
140 }
141 
142 /*
143  * Given a list of strings, return a set of directory attribute values.
144  *
145  * Mark that the attribute was found.
146  *
147  * Note that the terminating \0 is *not* included in the result, because
148  * that's the way that strings come from LDAP.
149  * (Note also that the client side stuff adds in a terminating \0.)
150  *
151  * Note that on error the array may have been partially populated and will
152  * need to be cleaned up by the caller.  This is normally not a problem
153  * because the caller will need to clean up several such arrays.
154  */
155 directory_error_t
156 str_list_dav(directory_values_rpc *lvals, const char * const *str_list, int n)
157 {
158 	directory_value_rpc *dav;
159 	int i;
160 
161 	if (n == 0) {
162 		for (n = 0; str_list[n] != NULL; n++)
163 			/* LOOP */;
164 	}
165 
166 	dav = calloc(n, sizeof (directory_value_rpc));
167 	if (dav == NULL)
168 		goto nomem;
169 
170 	lvals->directory_values_rpc_u.values.values_val = dav;
171 	lvals->directory_values_rpc_u.values.values_len = n;
172 	lvals->found = TRUE;
173 
174 	for (i = 0; i < n; i++) {
175 		int len;
176 
177 		len = strlen(str_list[i]);
178 		dav[i].directory_value_rpc_val = uu_memdup(str_list[i], len);
179 		if (dav[i].directory_value_rpc_val == NULL)
180 			goto nomem;
181 		dav[i].directory_value_rpc_len = len;
182 	}
183 
184 	return (NULL);
185 
186 nomem:
187 	return (directory_error("ENOMEM.str_list_dav",
188 	    "Insufficient memory copying values"));
189 }
190 
191 /*
192  * Given a list of unsigned integers, return a set of string directory
193  * attribute values.
194  *
195  * Mark that the attribute was found.
196  *
197  * Note that the terminating \0 is *not* included in the result, because
198  * that's the way that strings come from LDAP.
199  * (Note also that the client side stuff adds in a terminating \0.)
200  *
201  * Note that on error the array may have been partially populated and will
202  * need to be cleaned up by the caller.  This is normally not a problem
203  * because the caller will need to clean up several such arrays.
204  */
205 directory_error_t
206 uint_list_dav(directory_values_rpc *lvals, const unsigned int *array, int n)
207 {
208 	directory_value_rpc *dav;
209 	int i;
210 
211 	dav = calloc(n, sizeof (directory_value_rpc));
212 	if (dav == NULL)
213 		goto nomem;
214 
215 	lvals->directory_values_rpc_u.values.values_val = dav;
216 	lvals->directory_values_rpc_u.values.values_len = n;
217 	lvals->found = TRUE;
218 
219 	for (i = 0; i < n; i++) {
220 		char buf[100];	/* larger than any integer */
221 		int len;
222 
223 		(void) snprintf(buf, sizeof (buf), "%u", array[i]);
224 
225 		len = strlen(buf);
226 		dav[i].directory_value_rpc_val = uu_memdup(buf, len);
227 		if (dav[i].directory_value_rpc_val == NULL)
228 			goto nomem;
229 		dav[i].directory_value_rpc_len = len;
230 	}
231 
232 	return (NULL);
233 
234 nomem:
235 	return (directory_error("ENOMEM.uint_list_dav",
236 	    "Insufficient memory copying values"));
237 }
238 
239 /*
240  * Given a list of fixed-length binary chunks, return a set of binary
241  * directory attribute values.
242  *
243  * Mark that the attribute was found.
244  *
245  * Note that on error the array may have been partially populated and will
246  * need to be cleaned up by the caller.  This is normally not a problem
247  * because the caller will need to clean up several such arrays.
248  */
249 directory_error_t
250 bin_list_dav(directory_values_rpc *lvals, const void *array, int n, size_t sz)
251 {
252 	directory_value_rpc *dav;
253 	char *inbuf = (char *)array;
254 	int i;
255 
256 	dav = calloc(n, sizeof (directory_value_rpc));
257 	if (dav == NULL)
258 		goto nomem;
259 
260 	lvals->directory_values_rpc_u.values.values_val = dav;
261 	lvals->directory_values_rpc_u.values.values_len = n;
262 	lvals->found = TRUE;
263 
264 	for (i = 0; i < n; i++) {
265 		dav[i].directory_value_rpc_val = uu_memdup(inbuf, sz);
266 		if (dav[i].directory_value_rpc_val == NULL)
267 			goto nomem;
268 		dav[i].directory_value_rpc_len = sz;
269 		inbuf += sz;
270 	}
271 
272 	return (NULL);
273 
274 nomem:
275 	return (directory_error("ENOMEM.bin_list_dav",
276 	    "Insufficient memory copying values"));
277 }
278 
279 /*
280  * Set up to return an error on a particular directory entry.
281  * Note that the caller need not (and in fact must not) free
282  * the directory_error_t; it will be freed when the directory entry
283  * list is freed.
284  */
285 void
286 directory_entry_set_error(directory_entry_rpc *ent, directory_error_t de)
287 {
288 	xdr_free(xdr_directory_entry_rpc, (char *)&ent);
289 	ent->status = DIRECTORY_ERROR;
290 	(void) directory_error_to_rpc(&ent->directory_entry_rpc_u.err, de);
291 }
292