1*1fcced4cSJordan Brown /*
2*1fcced4cSJordan Brown  * CDDL HEADER START
3*1fcced4cSJordan Brown  *
4*1fcced4cSJordan Brown  * The contents of this file are subject to the terms of the
5*1fcced4cSJordan Brown  * Common Development and Distribution License (the "License").
6*1fcced4cSJordan Brown  * You may not use this file except in compliance with the License.
7*1fcced4cSJordan Brown  *
8*1fcced4cSJordan Brown  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*1fcced4cSJordan Brown  * or http://www.opensolaris.org/os/licensing.
10*1fcced4cSJordan Brown  * See the License for the specific language governing permissions
11*1fcced4cSJordan Brown  * and limitations under the License.
12*1fcced4cSJordan Brown  *
13*1fcced4cSJordan Brown  * When distributing Covered Code, include this CDDL HEADER in each
14*1fcced4cSJordan Brown  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*1fcced4cSJordan Brown  * If applicable, add the following below this CDDL HEADER, with the
16*1fcced4cSJordan Brown  * fields enclosed by brackets "[]" replaced with your own identifying
17*1fcced4cSJordan Brown  * information: Portions Copyright [yyyy] [name of copyright owner]
18*1fcced4cSJordan Brown  *
19*1fcced4cSJordan Brown  * CDDL HEADER END
20*1fcced4cSJordan Brown  */
21*1fcced4cSJordan Brown 
22*1fcced4cSJordan Brown /*
23*1fcced4cSJordan Brown  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24*1fcced4cSJordan Brown  * Use is subject to license terms.
25*1fcced4cSJordan Brown  */
26*1fcced4cSJordan Brown 
27*1fcced4cSJordan Brown /*
28*1fcced4cSJordan Brown  * Directory lookup functions.  These are shims that translate from the API
29*1fcced4cSJordan Brown  * into the RPC protocol.
30*1fcced4cSJordan Brown  */
31*1fcced4cSJordan Brown 
32*1fcced4cSJordan Brown #include <assert.h>
33*1fcced4cSJordan Brown #include <stdio.h>
34*1fcced4cSJordan Brown #include <stdlib.h>
35*1fcced4cSJordan Brown #include <stdarg.h>
36*1fcced4cSJordan Brown #include <malloc.h>
37*1fcced4cSJordan Brown #include <sys/types.h>
38*1fcced4cSJordan Brown #include <netdb.h>
39*1fcced4cSJordan Brown #include <pthread.h>
40*1fcced4cSJordan Brown #include <unistd.h>
41*1fcced4cSJordan Brown #include <string.h>
42*1fcced4cSJordan Brown #include "directory.h"
43*1fcced4cSJordan Brown #include "directory_private.h"
44*1fcced4cSJordan Brown #include <rpcsvc/idmap_prot.h>
45*1fcced4cSJordan Brown #include "directory_library_impl.h"
46*1fcced4cSJordan Brown #include "sized_array.h"
47*1fcced4cSJordan Brown 
48*1fcced4cSJordan Brown static directory_error_t copy_directory_attribute_value(
49*1fcced4cSJordan Brown     directory_attribute_value_t *dav,
50*1fcced4cSJordan Brown     directory_values_rpc *dav_rpc);
51*1fcced4cSJordan Brown static directory_error_t copy_directory_entry(directory_entry_t *ent,
52*1fcced4cSJordan Brown     directory_entry_rpc *ent_rpc);
53*1fcced4cSJordan Brown static void directory_results_free(directory_results_rpc *dr);
54*1fcced4cSJordan Brown static directory_datum_t directory_datum(void *data, size_t len);
55*1fcced4cSJordan Brown static void directory_datum_free(directory_datum_t d);
56*1fcced4cSJordan Brown 
57*1fcced4cSJordan Brown /*
58*1fcced4cSJordan Brown  * This is the actual implementation of the opaque directory_t structure.
59*1fcced4cSJordan Brown  */
60*1fcced4cSJordan Brown struct directory {
61*1fcced4cSJordan Brown 	CLIENT	*client;
62*1fcced4cSJordan Brown };
63*1fcced4cSJordan Brown 
64*1fcced4cSJordan Brown /*
65*1fcced4cSJordan Brown  * Set up a directory search context.
66*1fcced4cSJordan Brown  */
67*1fcced4cSJordan Brown directory_error_t
directory_open(directory_t * ret)68*1fcced4cSJordan Brown directory_open(directory_t *ret)
69*1fcced4cSJordan Brown {
70*1fcced4cSJordan Brown 	directory_t d;
71*1fcced4cSJordan Brown 	directory_error_t de;
72*1fcced4cSJordan Brown 	char host[] = "localhost";
73*1fcced4cSJordan Brown 
74*1fcced4cSJordan Brown 	*ret = NULL;
75*1fcced4cSJordan Brown 
76*1fcced4cSJordan Brown 	d = calloc(1, sizeof (*d));
77*1fcced4cSJordan Brown 	if (d == NULL)
78*1fcced4cSJordan Brown 		goto nomem;
79*1fcced4cSJordan Brown 
80*1fcced4cSJordan Brown 	d->client = clnt_door_create(IDMAP_PROG, IDMAP_V1, 0);
81*1fcced4cSJordan Brown 	if (d->client == NULL) {
82*1fcced4cSJordan Brown 		de = directory_error("clnt_create.directory_open",
83*1fcced4cSJordan Brown 		    "Error: %1",
84*1fcced4cSJordan Brown 		    clnt_spcreateerror(host),
85*1fcced4cSJordan Brown 		    NULL);
86*1fcced4cSJordan Brown 		goto err;
87*1fcced4cSJordan Brown 	}
88*1fcced4cSJordan Brown 
89*1fcced4cSJordan Brown 	*ret = d;
90*1fcced4cSJordan Brown 	return (NULL);
91*1fcced4cSJordan Brown 
92*1fcced4cSJordan Brown nomem:
93*1fcced4cSJordan Brown 	de = directory_error("ENOMEM.directory_open",
94*1fcced4cSJordan Brown 	    "Insufficient memory setting up directory access", NULL);
95*1fcced4cSJordan Brown err:
96*1fcced4cSJordan Brown 	directory_close(d);
97*1fcced4cSJordan Brown 	return (de);
98*1fcced4cSJordan Brown }
99*1fcced4cSJordan Brown 
100*1fcced4cSJordan Brown /*
101*1fcced4cSJordan Brown  * Tear down a directory search context.
102*1fcced4cSJordan Brown  *
103*1fcced4cSJordan Brown  * Does nothing if d==NULL.
104*1fcced4cSJordan Brown  */
105*1fcced4cSJordan Brown void
directory_close(directory_t d)106*1fcced4cSJordan Brown directory_close(directory_t d)
107*1fcced4cSJordan Brown {
108*1fcced4cSJordan Brown 	if (d == NULL)
109*1fcced4cSJordan Brown 		return;
110*1fcced4cSJordan Brown 
111*1fcced4cSJordan Brown 	if (d->client != NULL)
112*1fcced4cSJordan Brown 		clnt_destroy(d->client);
113*1fcced4cSJordan Brown 
114*1fcced4cSJordan Brown 	free(d);
115*1fcced4cSJordan Brown }
116*1fcced4cSJordan Brown 
117*1fcced4cSJordan Brown /*
118*1fcced4cSJordan Brown  * Given a list of identifiers, a list of their types, and a list of attributes,
119*1fcced4cSJordan Brown  * return the information.
120*1fcced4cSJordan Brown  */
121*1fcced4cSJordan Brown directory_error_t
directory_get_v(directory_t d,directory_entry_list_t * ret,char ** ids,int nids,char * types,char ** attr_list)122*1fcced4cSJordan Brown directory_get_v(
123*1fcced4cSJordan Brown     directory_t d,
124*1fcced4cSJordan Brown     directory_entry_list_t *ret,
125*1fcced4cSJordan Brown     char **ids,
126*1fcced4cSJordan Brown     int nids,
127*1fcced4cSJordan Brown     char *types,
128*1fcced4cSJordan Brown     char **attr_list)
129*1fcced4cSJordan Brown {
130*1fcced4cSJordan Brown 	int nattrs;
131*1fcced4cSJordan Brown 	directory_entry_list_t del;
132*1fcced4cSJordan Brown 	directory_error_t de;
133*1fcced4cSJordan Brown 	directory_results_rpc dr;
134*1fcced4cSJordan Brown 	idmap_utf8str_list sl_ids;
135*1fcced4cSJordan Brown 	idmap_utf8str_list sl_attrs;
136*1fcced4cSJordan Brown 	directory_entry_rpc *users;
137*1fcced4cSJordan Brown 	int i;
138*1fcced4cSJordan Brown 	enum clnt_stat cs;
139*1fcced4cSJordan Brown 
140*1fcced4cSJordan Brown 	*ret = NULL;
141*1fcced4cSJordan Brown 	del = NULL;
142*1fcced4cSJordan Brown 
143*1fcced4cSJordan Brown 	if (nids == 0) {
144*1fcced4cSJordan Brown 		for (nids = 0; ids[nids] != NULL; nids++)
145*1fcced4cSJordan Brown 			/* LOOP */;
146*1fcced4cSJordan Brown 	}
147*1fcced4cSJordan Brown 
148*1fcced4cSJordan Brown 	for (nattrs = 0; attr_list[nattrs] != NULL; nattrs++)
149*1fcced4cSJordan Brown 		/* LOOP */;
150*1fcced4cSJordan Brown 
151*1fcced4cSJordan Brown 	sl_ids.idmap_utf8str_list_len = nids;
152*1fcced4cSJordan Brown 	sl_ids.idmap_utf8str_list_val = ids;
153*1fcced4cSJordan Brown 	sl_attrs.idmap_utf8str_list_len = nattrs;
154*1fcced4cSJordan Brown 	sl_attrs.idmap_utf8str_list_val = attr_list;
155*1fcced4cSJordan Brown 
156*1fcced4cSJordan Brown 	(void) memset(&dr, 0, sizeof (dr));
157*1fcced4cSJordan Brown 	cs = directory_get_common_1(sl_ids, types, sl_attrs, &dr, d->client);
158*1fcced4cSJordan Brown 	if (cs != RPC_SUCCESS) {
159*1fcced4cSJordan Brown 		char errbuf[100];	/* well long enough for any integer */
160*1fcced4cSJordan Brown 		(void) sprintf(errbuf, "%d", cs);
161*1fcced4cSJordan Brown 		de = directory_error("RPC.Get_common",
162*1fcced4cSJordan Brown 		    "Get_common RPC (%1)%2", errbuf,
163*1fcced4cSJordan Brown 		    clnt_sperror(d->client, ""), NULL);
164*1fcced4cSJordan Brown 		goto err;
165*1fcced4cSJordan Brown 	}
166*1fcced4cSJordan Brown 
167*1fcced4cSJordan Brown 	if (dr.failed) {
168*1fcced4cSJordan Brown 		de = directory_error_from_rpc(
169*1fcced4cSJordan Brown 		    &dr.directory_results_rpc_u.err);
170*1fcced4cSJordan Brown 		goto err;
171*1fcced4cSJordan Brown 	}
172*1fcced4cSJordan Brown 
173*1fcced4cSJordan Brown 	assert(dr.directory_results_rpc_u.entries.entries_len == nids);
174*1fcced4cSJordan Brown 
175*1fcced4cSJordan Brown 	users = dr.directory_results_rpc_u.entries.entries_val;
176*1fcced4cSJordan Brown 
177*1fcced4cSJordan Brown 	del = sized_array(nids, sizeof (directory_entry_t));
178*1fcced4cSJordan Brown 
179*1fcced4cSJordan Brown 	for (i = 0; i < nids; i++) {
180*1fcced4cSJordan Brown 		de = copy_directory_entry(&del[i], &users[i]);
181*1fcced4cSJordan Brown 		if (de != NULL)
182*1fcced4cSJordan Brown 			goto err;
183*1fcced4cSJordan Brown 	}
184*1fcced4cSJordan Brown 
185*1fcced4cSJordan Brown 	directory_results_free(&dr);
186*1fcced4cSJordan Brown 
187*1fcced4cSJordan Brown 	*ret = del;
188*1fcced4cSJordan Brown 	return (NULL);
189*1fcced4cSJordan Brown 
190*1fcced4cSJordan Brown err:
191*1fcced4cSJordan Brown 	directory_results_free(&dr);
192*1fcced4cSJordan Brown 	directory_free(del);
193*1fcced4cSJordan Brown 	return (de);
194*1fcced4cSJordan Brown }
195*1fcced4cSJordan Brown 
196*1fcced4cSJordan Brown /*
197*1fcced4cSJordan Brown  * Free the results from a directory_get_*() request.
198*1fcced4cSJordan Brown  */
199*1fcced4cSJordan Brown void
directory_free(directory_entry_list_t del)200*1fcced4cSJordan Brown directory_free(directory_entry_list_t del)
201*1fcced4cSJordan Brown {
202*1fcced4cSJordan Brown 	directory_entry_t *ent;
203*1fcced4cSJordan Brown 	directory_attribute_value_t dav;
204*1fcced4cSJordan Brown 	int i;
205*1fcced4cSJordan Brown 	int j;
206*1fcced4cSJordan Brown 	int k;
207*1fcced4cSJordan Brown 
208*1fcced4cSJordan Brown 	if (del == NULL)
209*1fcced4cSJordan Brown 		return;
210*1fcced4cSJordan Brown 
211*1fcced4cSJordan Brown 	/* For each directory entry returned */
212*1fcced4cSJordan Brown 	for (i = 0; i < sized_array_n(del); i++) {
213*1fcced4cSJordan Brown 		ent = &del[i];
214*1fcced4cSJordan Brown 
215*1fcced4cSJordan Brown 		if (ent->attrs != NULL) {
216*1fcced4cSJordan Brown 			/* For each attribute */
217*1fcced4cSJordan Brown 			for (j = 0; j < sized_array_n(ent->attrs); j++) {
218*1fcced4cSJordan Brown 				dav = ent->attrs[j];
219*1fcced4cSJordan Brown 				if (dav != NULL) {
220*1fcced4cSJordan Brown 					for (k = 0; k < sized_array_n(dav); k++)
221*1fcced4cSJordan Brown 						directory_datum_free(dav[k]);
222*1fcced4cSJordan Brown 
223*1fcced4cSJordan Brown 					sized_array_free(dav);
224*1fcced4cSJordan Brown 				}
225*1fcced4cSJordan Brown 			}
226*1fcced4cSJordan Brown 			sized_array_free(ent->attrs);
227*1fcced4cSJordan Brown 		}
228*1fcced4cSJordan Brown 
229*1fcced4cSJordan Brown 		directory_error_free(ent->err);
230*1fcced4cSJordan Brown 	}
231*1fcced4cSJordan Brown 
232*1fcced4cSJordan Brown 	sized_array_free(del);
233*1fcced4cSJordan Brown }
234*1fcced4cSJordan Brown 
235*1fcced4cSJordan Brown /*
236*1fcced4cSJordan Brown  * Create a directory datum.  Note that we allocate an extra byte and
237*1fcced4cSJordan Brown  * zero it, so that strings get null-terminated.  Return NULL on error.
238*1fcced4cSJordan Brown  */
239*1fcced4cSJordan Brown static
240*1fcced4cSJordan Brown directory_datum_t
directory_datum(void * data,size_t len)241*1fcced4cSJordan Brown directory_datum(void *data, size_t len)
242*1fcced4cSJordan Brown {
243*1fcced4cSJordan Brown 	void *p;
244*1fcced4cSJordan Brown 
245*1fcced4cSJordan Brown 	p = sized_array(len + 1, 1);
246*1fcced4cSJordan Brown 	if (p == NULL)
247*1fcced4cSJordan Brown 		return (NULL);
248*1fcced4cSJordan Brown 	(void) memcpy(p, data, len);
249*1fcced4cSJordan Brown 	*((char *)p + len) = '\0';
250*1fcced4cSJordan Brown 	return (p);
251*1fcced4cSJordan Brown }
252*1fcced4cSJordan Brown 
253*1fcced4cSJordan Brown /*
254*1fcced4cSJordan Brown  * Return the size of a directory_datum_t.  Note that this does not include
255*1fcced4cSJordan Brown  * the terminating \0, so it represents the value as returned by LDAP.
256*1fcced4cSJordan Brown  */
257*1fcced4cSJordan Brown size_t
directory_datum_len(directory_datum_t d)258*1fcced4cSJordan Brown directory_datum_len(directory_datum_t d)
259*1fcced4cSJordan Brown {
260*1fcced4cSJordan Brown 	/*
261*1fcced4cSJordan Brown 	 * Deduct the terminal \0, so that binary data gets the
262*1fcced4cSJordan Brown 	 * expected length.
263*1fcced4cSJordan Brown 	 */
264*1fcced4cSJordan Brown 	return (sized_array_n(d) - 1);
265*1fcced4cSJordan Brown }
266*1fcced4cSJordan Brown 
267*1fcced4cSJordan Brown static
268*1fcced4cSJordan Brown void
directory_datum_free(directory_datum_t d)269*1fcced4cSJordan Brown directory_datum_free(directory_datum_t d)
270*1fcced4cSJordan Brown {
271*1fcced4cSJordan Brown 	sized_array_free(d);
272*1fcced4cSJordan Brown }
273*1fcced4cSJordan Brown 
274*1fcced4cSJordan Brown /*
275*1fcced4cSJordan Brown  * Unmarshall an RPC directory entry into an API directory entry.
276*1fcced4cSJordan Brown  */
277*1fcced4cSJordan Brown static
278*1fcced4cSJordan Brown directory_error_t
copy_directory_entry(directory_entry_t * ent,directory_entry_rpc * ent_rpc)279*1fcced4cSJordan Brown copy_directory_entry(
280*1fcced4cSJordan Brown     directory_entry_t *ent,
281*1fcced4cSJordan Brown     directory_entry_rpc *ent_rpc)
282*1fcced4cSJordan Brown {
283*1fcced4cSJordan Brown 	int nattrs;
284*1fcced4cSJordan Brown 	int i;
285*1fcced4cSJordan Brown 	directory_error_t de;
286*1fcced4cSJordan Brown 
287*1fcced4cSJordan Brown 	/* If the entry wasn't found, leave the entry attrs and err NULL. */
288*1fcced4cSJordan Brown 	if (ent_rpc->status == DIRECTORY_NOT_FOUND)
289*1fcced4cSJordan Brown 		return (NULL);
290*1fcced4cSJordan Brown 
291*1fcced4cSJordan Brown 	if (ent_rpc->status == DIRECTORY_ERROR) {
292*1fcced4cSJordan Brown 		ent->err = directory_error_from_rpc(
293*1fcced4cSJordan Brown 		    &ent_rpc->directory_entry_rpc_u.err);
294*1fcced4cSJordan Brown 		return (NULL);
295*1fcced4cSJordan Brown 	}
296*1fcced4cSJordan Brown 
297*1fcced4cSJordan Brown 	nattrs = ent_rpc->directory_entry_rpc_u.attrs.attrs_len;
298*1fcced4cSJordan Brown 
299*1fcced4cSJordan Brown 	ent->attrs = sized_array(nattrs, sizeof (directory_attribute_value_t));
300*1fcced4cSJordan Brown 	if (ent->attrs == NULL) {
301*1fcced4cSJordan Brown 		return (directory_error("ENOMEM.copy_directory_entry",
302*1fcced4cSJordan Brown 		    "Insufficient memory copying directory entry", NULL));
303*1fcced4cSJordan Brown 	}
304*1fcced4cSJordan Brown 	for (i = 0; i < nattrs; i++) {
305*1fcced4cSJordan Brown 		de = copy_directory_attribute_value(&ent->attrs[i],
306*1fcced4cSJordan Brown 		    &ent_rpc->directory_entry_rpc_u.attrs.attrs_val[i]);
307*1fcced4cSJordan Brown 		if (de != NULL)
308*1fcced4cSJordan Brown 			return (de);
309*1fcced4cSJordan Brown 	}
310*1fcced4cSJordan Brown 
311*1fcced4cSJordan Brown 	return (NULL);
312*1fcced4cSJordan Brown }
313*1fcced4cSJordan Brown 
314*1fcced4cSJordan Brown /*
315*1fcced4cSJordan Brown  * Unmarshall an RPC directory attribute value into the API equivalent.
316*1fcced4cSJordan Brown  *
317*1fcced4cSJordan Brown  * Note that on error some entries may have been copied, and so
318*1fcced4cSJordan Brown  * the caller needs to clean up dav.  This is normally not a problem
319*1fcced4cSJordan Brown  * since the caller will have called this function several times and
320*1fcced4cSJordan Brown  * will need to clean up the results from the other calls too.
321*1fcced4cSJordan Brown  */
322*1fcced4cSJordan Brown static
323*1fcced4cSJordan Brown directory_error_t
copy_directory_attribute_value(directory_attribute_value_t * dav,directory_values_rpc * dav_rpc)324*1fcced4cSJordan Brown copy_directory_attribute_value(
325*1fcced4cSJordan Brown     directory_attribute_value_t *dav,
326*1fcced4cSJordan Brown     directory_values_rpc *dav_rpc)
327*1fcced4cSJordan Brown {
328*1fcced4cSJordan Brown 	int i;
329*1fcced4cSJordan Brown 	int nvals;
330*1fcced4cSJordan Brown 	directory_value_rpc *vals;
331*1fcced4cSJordan Brown 
332*1fcced4cSJordan Brown 	/* If it wasn't found, leave the corresponding entry NULL */
333*1fcced4cSJordan Brown 	if (!dav_rpc->found)
334*1fcced4cSJordan Brown 		return (NULL);
335*1fcced4cSJordan Brown 
336*1fcced4cSJordan Brown 	nvals = dav_rpc->directory_values_rpc_u.values.values_len;
337*1fcced4cSJordan Brown 	*dav = sized_array(nvals + 1, sizeof (directory_datum_t));
338*1fcced4cSJordan Brown 	if (*dav == NULL) {
339*1fcced4cSJordan Brown 		return (directory_error("ENOMEM.copy_directory_attribute_value",
340*1fcced4cSJordan Brown 		    "Insufficient memory copying directory entry", NULL));
341*1fcced4cSJordan Brown 	}
342*1fcced4cSJordan Brown 
343*1fcced4cSJordan Brown 	vals = dav_rpc->directory_values_rpc_u.values.values_val;
344*1fcced4cSJordan Brown 	for (i = 0; i < nvals; i++) {
345*1fcced4cSJordan Brown 		(*dav)[i] = directory_datum(vals[i].directory_value_rpc_val,
346*1fcced4cSJordan Brown 		    vals[i].directory_value_rpc_len);
347*1fcced4cSJordan Brown 		if ((*dav)[i] == NULL) {
348*1fcced4cSJordan Brown 			return (directory_error(
349*1fcced4cSJordan Brown 			    "ENOMEM.copy_directory_attribute_value",
350*1fcced4cSJordan Brown 			    "Insufficient memory copying directory entry",
351*1fcced4cSJordan Brown 			    NULL));
352*1fcced4cSJordan Brown 		}
353*1fcced4cSJordan Brown 	}
354*1fcced4cSJordan Brown 
355*1fcced4cSJordan Brown 	return (NULL);
356*1fcced4cSJordan Brown }
357*1fcced4cSJordan Brown 
358*1fcced4cSJordan Brown /*
359*1fcced4cSJordan Brown  * Free the results of a directory RPC request.
360*1fcced4cSJordan Brown  */
361*1fcced4cSJordan Brown static
362*1fcced4cSJordan Brown void
directory_results_free(directory_results_rpc * dr)363*1fcced4cSJordan Brown directory_results_free(directory_results_rpc *dr)
364*1fcced4cSJordan Brown {
365*1fcced4cSJordan Brown 	xdr_free(xdr_directory_results_rpc, (char *)&dr);
366*1fcced4cSJordan Brown }
367