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