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