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