2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A */
2N/A
2N/A/*
2N/A * Directory lookup functions. These are shims that translate from the API
2N/A * into the RPC protocol.
2N/A */
2N/A
2N/A#include <assert.h>
2N/A#include <stdio.h>
2N/A#include <stdlib.h>
2N/A#include <stdarg.h>
2N/A#include <malloc.h>
2N/A#include <sys/types.h>
2N/A#include <netdb.h>
2N/A#include <pthread.h>
2N/A#include <unistd.h>
2N/A#include <string.h>
2N/A#include "directory.h"
2N/A#include "directory_private.h"
2N/A#include <rpcsvc/idmap_prot.h>
2N/A#include "directory_library_impl.h"
2N/A#include "sized_array.h"
2N/A
2N/Astatic directory_error_t copy_directory_attribute_value(
2N/A directory_attribute_value_t *dav,
2N/A directory_values_rpc *dav_rpc);
2N/Astatic directory_error_t copy_directory_entry(directory_entry_t *ent,
2N/A directory_entry_rpc *ent_rpc);
2N/Astatic void directory_results_free(directory_results_rpc *dr);
2N/Astatic directory_datum_t directory_datum(void *data, size_t len);
2N/Astatic void directory_datum_free(directory_datum_t d);
2N/A
2N/A/*
2N/A * This is the actual implementation of the opaque directory_t structure.
2N/A */
2N/Astruct directory {
2N/A CLIENT *client;
2N/A};
2N/A
2N/A/*
2N/A * Set up a directory search context.
2N/A */
2N/Adirectory_error_t
2N/Adirectory_open(directory_t *ret)
2N/A{
2N/A directory_t d;
2N/A directory_error_t de;
2N/A char host[] = "localhost";
2N/A
2N/A *ret = NULL;
2N/A
2N/A d = calloc(1, sizeof (*d));
2N/A if (d == NULL)
2N/A goto nomem;
2N/A
2N/A d->client = clnt_door_create(IDMAP_PROG, IDMAP_V1, 0);
2N/A if (d->client == NULL) {
2N/A de = directory_error("clnt_create.directory_open",
2N/A "Error: %1",
2N/A clnt_spcreateerror(host),
2N/A NULL);
2N/A goto err;
2N/A }
2N/A
2N/A *ret = d;
2N/A return (NULL);
2N/A
2N/Anomem:
2N/A de = directory_error("ENOMEM.directory_open",
2N/A "Insufficient memory setting up directory access", NULL);
2N/Aerr:
2N/A directory_close(d);
2N/A return (de);
2N/A}
2N/A
2N/A/*
2N/A * Tear down a directory search context.
2N/A *
2N/A * Does nothing if d==NULL.
2N/A */
2N/Avoid
2N/Adirectory_close(directory_t d)
2N/A{
2N/A if (d == NULL)
2N/A return;
2N/A
2N/A if (d->client != NULL)
2N/A clnt_destroy(d->client);
2N/A
2N/A free(d);
2N/A}
2N/A
2N/A/*
2N/A * Given a list of identifiers, a list of their types, and a list of attributes,
2N/A * return the information.
2N/A */
2N/Adirectory_error_t
2N/Adirectory_get_v(
2N/A directory_t d,
2N/A directory_entry_list_t *ret,
2N/A char **ids,
2N/A int nids,
2N/A char *types,
2N/A char **attr_list)
2N/A{
2N/A int nattrs;
2N/A directory_entry_list_t del;
2N/A directory_error_t de;
2N/A directory_results_rpc dr;
2N/A idmap_utf8str_list sl_ids;
2N/A idmap_utf8str_list sl_attrs;
2N/A directory_entry_rpc *users;
2N/A int i;
2N/A enum clnt_stat cs;
2N/A
2N/A *ret = NULL;
2N/A del = NULL;
2N/A
2N/A if (nids == 0) {
2N/A for (nids = 0; ids[nids] != NULL; nids++)
2N/A /* LOOP */;
2N/A }
2N/A
2N/A for (nattrs = 0; attr_list[nattrs] != NULL; nattrs++)
2N/A /* LOOP */;
2N/A
2N/A sl_ids.idmap_utf8str_list_len = nids;
2N/A sl_ids.idmap_utf8str_list_val = ids;
2N/A sl_attrs.idmap_utf8str_list_len = nattrs;
2N/A sl_attrs.idmap_utf8str_list_val = attr_list;
2N/A
2N/A (void) memset(&dr, 0, sizeof (dr));
2N/A cs = directory_get_common_1(sl_ids, types, sl_attrs, &dr, d->client);
2N/A if (cs != RPC_SUCCESS) {
2N/A char errbuf[100]; /* well long enough for any integer */
2N/A (void) sprintf(errbuf, "%d", cs);
2N/A de = directory_error("RPC.Get_common",
2N/A "Get_common RPC (%1)%2", errbuf,
2N/A clnt_sperror(d->client, ""), NULL);
2N/A goto err;
2N/A }
2N/A
2N/A if (dr.failed) {
2N/A de = directory_error_from_rpc(
2N/A &dr.directory_results_rpc_u.err);
2N/A goto err;
2N/A }
2N/A
2N/A assert(dr.directory_results_rpc_u.entries.entries_len == nids);
2N/A
2N/A users = dr.directory_results_rpc_u.entries.entries_val;
2N/A
2N/A del = sized_array(nids, sizeof (directory_entry_t));
2N/A
2N/A for (i = 0; i < nids; i++) {
2N/A de = copy_directory_entry(&del[i], &users[i]);
2N/A if (de != NULL)
2N/A goto err;
2N/A }
2N/A
2N/A directory_results_free(&dr);
2N/A
2N/A *ret = del;
2N/A return (NULL);
2N/A
2N/Aerr:
2N/A directory_results_free(&dr);
2N/A directory_free(del);
2N/A return (de);
2N/A}
2N/A
2N/A/*
2N/A * Free the results from a directory_get_*() request.
2N/A */
2N/Avoid
2N/Adirectory_free(directory_entry_list_t del)
2N/A{
2N/A directory_entry_t *ent;
2N/A directory_attribute_value_t dav;
2N/A int i;
2N/A int j;
2N/A int k;
2N/A
2N/A if (del == NULL)
2N/A return;
2N/A
2N/A /* For each directory entry returned */
2N/A for (i = 0; i < sized_array_n(del); i++) {
2N/A ent = &del[i];
2N/A
2N/A if (ent->attrs != NULL) {
2N/A /* For each attribute */
2N/A for (j = 0; j < sized_array_n(ent->attrs); j++) {
2N/A dav = ent->attrs[j];
2N/A if (dav != NULL) {
2N/A for (k = 0; k < sized_array_n(dav); k++)
2N/A directory_datum_free(dav[k]);
2N/A
2N/A sized_array_free(dav);
2N/A }
2N/A }
2N/A sized_array_free(ent->attrs);
2N/A }
2N/A
2N/A directory_error_free(ent->err);
2N/A }
2N/A
2N/A sized_array_free(del);
2N/A}
2N/A
2N/A/*
2N/A * Create a directory datum. Note that we allocate an extra byte and
2N/A * zero it, so that strings get null-terminated. Return NULL on error.
2N/A */
2N/Astatic
2N/Adirectory_datum_t
2N/Adirectory_datum(void *data, size_t len)
2N/A{
2N/A void *p;
2N/A
2N/A p = sized_array(len + 1, 1);
2N/A if (p == NULL)
2N/A return (NULL);
2N/A (void) memcpy(p, data, len);
2N/A *((char *)p + len) = '\0';
2N/A return (p);
2N/A}
2N/A
2N/A/*
2N/A * Return the size of a directory_datum_t. Note that this does not include
2N/A * the terminating \0, so it represents the value as returned by LDAP.
2N/A */
2N/Asize_t
2N/Adirectory_datum_len(directory_datum_t d)
2N/A{
2N/A /*
2N/A * Deduct the terminal \0, so that binary data gets the
2N/A * expected length.
2N/A */
2N/A return (sized_array_n(d) - 1);
2N/A}
2N/A
2N/Astatic
2N/Avoid
2N/Adirectory_datum_free(directory_datum_t d)
2N/A{
2N/A sized_array_free(d);
2N/A}
2N/A
2N/A/*
2N/A * Unmarshall an RPC directory entry into an API directory entry.
2N/A */
2N/Astatic
2N/Adirectory_error_t
2N/Acopy_directory_entry(
2N/A directory_entry_t *ent,
2N/A directory_entry_rpc *ent_rpc)
2N/A{
2N/A int nattrs;
2N/A int i;
2N/A directory_error_t de;
2N/A
2N/A /* If the entry wasn't found, leave the entry attrs and err NULL. */
2N/A if (ent_rpc->status == DIRECTORY_NOT_FOUND)
2N/A return (NULL);
2N/A
2N/A if (ent_rpc->status == DIRECTORY_ERROR) {
2N/A ent->err = directory_error_from_rpc(
2N/A &ent_rpc->directory_entry_rpc_u.err);
2N/A return (NULL);
2N/A }
2N/A
2N/A nattrs = ent_rpc->directory_entry_rpc_u.attrs.attrs_len;
2N/A
2N/A ent->attrs = sized_array(nattrs, sizeof (directory_attribute_value_t));
2N/A if (ent->attrs == NULL) {
2N/A return (directory_error("ENOMEM.copy_directory_entry",
2N/A "Insufficient memory copying directory entry", NULL));
2N/A }
2N/A for (i = 0; i < nattrs; i++) {
2N/A de = copy_directory_attribute_value(&ent->attrs[i],
2N/A &ent_rpc->directory_entry_rpc_u.attrs.attrs_val[i]);
2N/A if (de != NULL)
2N/A return (de);
2N/A }
2N/A
2N/A return (NULL);
2N/A}
2N/A
2N/A/*
2N/A * Unmarshall an RPC directory attribute value into the API equivalent.
2N/A *
2N/A * Note that on error some entries may have been copied, and so
2N/A * the caller needs to clean up dav. This is normally not a problem
2N/A * since the caller will have called this function several times and
2N/A * will need to clean up the results from the other calls too.
2N/A */
2N/Astatic
2N/Adirectory_error_t
2N/Acopy_directory_attribute_value(
2N/A directory_attribute_value_t *dav,
2N/A directory_values_rpc *dav_rpc)
2N/A{
2N/A int i;
2N/A int nvals;
2N/A directory_value_rpc *vals;
2N/A
2N/A /* If it wasn't found, leave the corresponding entry NULL */
2N/A if (!dav_rpc->found)
2N/A return (NULL);
2N/A
2N/A nvals = dav_rpc->directory_values_rpc_u.values.values_len;
2N/A *dav = sized_array(nvals + 1, sizeof (directory_datum_t));
2N/A if (*dav == NULL) {
2N/A return (directory_error("ENOMEM.copy_directory_attribute_value",
2N/A "Insufficient memory copying directory entry", NULL));
2N/A }
2N/A
2N/A vals = dav_rpc->directory_values_rpc_u.values.values_val;
2N/A for (i = 0; i < nvals; i++) {
2N/A (*dav)[i] = directory_datum(vals[i].directory_value_rpc_val,
2N/A vals[i].directory_value_rpc_len);
2N/A if ((*dav)[i] == NULL) {
2N/A return (directory_error(
2N/A "ENOMEM.copy_directory_attribute_value",
2N/A "Insufficient memory copying directory entry",
2N/A NULL));
2N/A }
2N/A }
2N/A
2N/A return (NULL);
2N/A}
2N/A
2N/A/*
2N/A * Free the results of a directory RPC request.
2N/A */
2N/Astatic
2N/Avoid
2N/Adirectory_results_free(directory_results_rpc *dr)
2N/A{
2N/A xdr_free(xdr_directory_results_rpc, (char *)&dr);
2N/A}