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