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.
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.
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]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * Directory lookup functions. These are shims that translate from the API
29 * into the RPC protocol.
37 #include <sys/types.h>
42 #include "directory.h"
43 #include "directory_private.h"
44 #include <rpcsvc/idmap_prot.h>
45 #include "directory_library_impl.h"
46 #include "sized_array.h"
48 static directory_error_t
copy_directory_attribute_value(
49 directory_attribute_value_t
*dav
,
50 directory_values_rpc
*dav_rpc
);
51 static directory_error_t
copy_directory_entry(directory_entry_t
*ent
,
52 directory_entry_rpc
*ent_rpc
);
53 static void directory_results_free(directory_results_rpc
*dr
);
54 static directory_datum_t
directory_datum(void *data
, size_t len
);
55 static void directory_datum_free(directory_datum_t d
);
58 * This is the actual implementation of the opaque directory_t structure.
65 * Set up a directory search context.
68 directory_open(directory_t
*ret
)
72 char host
[] = "localhost";
76 d
= calloc(1, sizeof (*d
));
80 d
->client
= clnt_door_create(IDMAP_PROG
, IDMAP_V1
, 0);
81 if (d
->client
== NULL
) {
82 de
= directory_error("clnt_create.directory_open",
84 clnt_spcreateerror(host
),
93 de
= directory_error("ENOMEM.directory_open",
94 "Insufficient memory setting up directory access", NULL
);
101 * Tear down a directory search context.
103 * Does nothing if d==NULL.
106 directory_close(directory_t d
)
111 if (d
->client
!= NULL
)
112 clnt_destroy(d
->client
);
118 * Given a list of identifiers, a list of their types, and a list of attributes,
119 * return the information.
124 directory_entry_list_t
*ret
,
131 directory_entry_list_t del
;
132 directory_error_t de
;
133 directory_results_rpc dr
;
134 idmap_utf8str_list sl_ids
;
135 idmap_utf8str_list sl_attrs
;
136 directory_entry_rpc
*users
;
144 for (nids
= 0; ids
[nids
] != NULL
; nids
++)
148 for (nattrs
= 0; attr_list
[nattrs
] != NULL
; nattrs
++)
151 sl_ids
.idmap_utf8str_list_len
= nids
;
152 sl_ids
.idmap_utf8str_list_val
= ids
;
153 sl_attrs
.idmap_utf8str_list_len
= nattrs
;
154 sl_attrs
.idmap_utf8str_list_val
= attr_list
;
156 (void) memset(&dr
, 0, sizeof (dr
));
157 cs
= directory_get_common_1(sl_ids
, types
, sl_attrs
, &dr
, d
->client
);
158 if (cs
!= RPC_SUCCESS
) {
159 char errbuf
[100]; /* well long enough for any integer */
160 (void) sprintf(errbuf
, "%d", cs
);
161 de
= directory_error("RPC.Get_common",
162 "Get_common RPC (%1)%2", errbuf
,
163 clnt_sperror(d
->client
, ""), NULL
);
168 de
= directory_error_from_rpc(
169 &dr
.directory_results_rpc_u
.err
);
173 assert(dr
.directory_results_rpc_u
.entries
.entries_len
== nids
);
175 users
= dr
.directory_results_rpc_u
.entries
.entries_val
;
177 del
= sized_array(nids
, sizeof (directory_entry_t
));
179 for (i
= 0; i
< nids
; i
++) {
180 de
= copy_directory_entry(&del
[i
], &users
[i
]);
185 directory_results_free(&dr
);
191 directory_results_free(&dr
);
197 * Free the results from a directory_get_*() request.
200 directory_free(directory_entry_list_t del
)
202 directory_entry_t
*ent
;
203 directory_attribute_value_t dav
;
211 /* For each directory entry returned */
212 for (i
= 0; i
< sized_array_n(del
); i
++) {
215 if (ent
->attrs
!= NULL
) {
216 /* For each attribute */
217 for (j
= 0; j
< sized_array_n(ent
->attrs
); j
++) {
220 for (k
= 0; k
< sized_array_n(dav
); k
++)
221 directory_datum_free(dav
[k
]);
223 sized_array_free(dav
);
226 sized_array_free(ent
->attrs
);
229 directory_error_free(ent
->err
);
232 sized_array_free(del
);
236 * Create a directory datum. Note that we allocate an extra byte and
237 * zero it, so that strings get null-terminated. Return NULL on error.
241 directory_datum(void *data
, size_t len
)
245 p
= sized_array(len
+ 1, 1);
248 (void) memcpy(p
, data
, len
);
249 *((char *)p
+ len
) = '\0';
254 * Return the size of a directory_datum_t. Note that this does not include
255 * the terminating \0, so it represents the value as returned by LDAP.
258 directory_datum_len(directory_datum_t d
)
261 * Deduct the terminal \0, so that binary data gets the
264 return (sized_array_n(d
) - 1);
269 directory_datum_free(directory_datum_t d
)
275 * Unmarshall an RPC directory entry into an API directory entry.
279 copy_directory_entry(
280 directory_entry_t
*ent
,
281 directory_entry_rpc
*ent_rpc
)
285 directory_error_t de
;
287 /* If the entry wasn't found, leave the entry attrs and err NULL. */
288 if (ent_rpc
->status
== DIRECTORY_NOT_FOUND
)
291 if (ent_rpc
->status
== DIRECTORY_ERROR
) {
292 ent
->err
= directory_error_from_rpc(
293 &ent_rpc
->directory_entry_rpc_u
.err
);
297 nattrs
= ent_rpc
->directory_entry_rpc_u
.attrs
.attrs_len
;
299 ent
->attrs
= sized_array(nattrs
, sizeof (directory_attribute_value_t
));
300 if (ent
->attrs
== NULL
) {
301 return (directory_error("ENOMEM.copy_directory_entry",
302 "Insufficient memory copying directory entry", NULL
));
304 for (i
= 0; i
< nattrs
; i
++) {
305 de
= copy_directory_attribute_value(&ent
->attrs
[i
],
306 &ent_rpc
->directory_entry_rpc_u
.attrs
.attrs_val
[i
]);
315 * Unmarshall an RPC directory attribute value into the API equivalent.
317 * Note that on error some entries may have been copied, and so
318 * the caller needs to clean up dav. This is normally not a problem
319 * since the caller will have called this function several times and
320 * will need to clean up the results from the other calls too.
324 copy_directory_attribute_value(
325 directory_attribute_value_t
*dav
,
326 directory_values_rpc
*dav_rpc
)
330 directory_value_rpc
*vals
;
332 /* If it wasn't found, leave the corresponding entry NULL */
336 nvals
= dav_rpc
->directory_values_rpc_u
.values
.values_len
;
337 *dav
= sized_array(nvals
+ 1, sizeof (directory_datum_t
));
339 return (directory_error("ENOMEM.copy_directory_attribute_value",
340 "Insufficient memory copying directory entry", NULL
));
343 vals
= dav_rpc
->directory_values_rpc_u
.values
.values_val
;
344 for (i
= 0; i
< nvals
; i
++) {
345 (*dav
)[i
] = directory_datum(vals
[i
].directory_value_rpc_val
,
346 vals
[i
].directory_value_rpc_len
);
347 if ((*dav
)[i
] == NULL
) {
348 return (directory_error(
349 "ENOMEM.copy_directory_attribute_value",
350 "Insufficient memory copying directory entry",
359 * Free the results of a directory RPC request.
363 directory_results_free(directory_results_rpc
*dr
)
365 xdr_free(xdr_directory_results_rpc
, (char *)&dr
);