xref: /onnv-gate/usr/src/cmd/idmap/idmapd/directory_server.c (revision 12890:16985853e3aa)
110122SJordan.Brown@Sun.COM /*
210122SJordan.Brown@Sun.COM  * CDDL HEADER START
310122SJordan.Brown@Sun.COM  *
410122SJordan.Brown@Sun.COM  * The contents of this file are subject to the terms of the
510122SJordan.Brown@Sun.COM  * Common Development and Distribution License (the "License").
610122SJordan.Brown@Sun.COM  * You may not use this file except in compliance with the License.
710122SJordan.Brown@Sun.COM  *
810122SJordan.Brown@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
910122SJordan.Brown@Sun.COM  * or http://www.opensolaris.org/os/licensing.
1010122SJordan.Brown@Sun.COM  * See the License for the specific language governing permissions
1110122SJordan.Brown@Sun.COM  * and limitations under the License.
1210122SJordan.Brown@Sun.COM  *
1310122SJordan.Brown@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
1410122SJordan.Brown@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1510122SJordan.Brown@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
1610122SJordan.Brown@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
1710122SJordan.Brown@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
1810122SJordan.Brown@Sun.COM  *
1910122SJordan.Brown@Sun.COM  * CDDL HEADER END
2010122SJordan.Brown@Sun.COM  */
2110122SJordan.Brown@Sun.COM 
2210122SJordan.Brown@Sun.COM /*
23*12890SJoyce.McIntosh@Sun.COM  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
2410122SJordan.Brown@Sun.COM  */
2510122SJordan.Brown@Sun.COM 
2610122SJordan.Brown@Sun.COM /*
2710122SJordan.Brown@Sun.COM  * Server-side support for directory information lookup functions.
2810122SJordan.Brown@Sun.COM  */
2910122SJordan.Brown@Sun.COM 
3010122SJordan.Brown@Sun.COM #include <stdio.h>
3110122SJordan.Brown@Sun.COM #include <stdlib.h>
3210122SJordan.Brown@Sun.COM #include <stdarg.h>
3310122SJordan.Brown@Sun.COM #include <malloc.h>
3410122SJordan.Brown@Sun.COM #include <sys/types.h>
3510122SJordan.Brown@Sun.COM #include <netdb.h>
3610122SJordan.Brown@Sun.COM #include <pthread.h>
3710122SJordan.Brown@Sun.COM #include <unistd.h>
3810122SJordan.Brown@Sun.COM #include <string.h>
39*12890SJoyce.McIntosh@Sun.COM #include <libuutil.h>
4010122SJordan.Brown@Sun.COM #include <note.h>
4110122SJordan.Brown@Sun.COM #include "idmapd.h"
4210122SJordan.Brown@Sun.COM #include "directory.h"
4310122SJordan.Brown@Sun.COM #include "directory_private.h"
4410122SJordan.Brown@Sun.COM #include <rpcsvc/idmap_prot.h>
4510122SJordan.Brown@Sun.COM #include "directory_library_impl.h"
4610122SJordan.Brown@Sun.COM #include "directory_server_impl.h"
4710122SJordan.Brown@Sun.COM #include "sized_array.h"
4810122SJordan.Brown@Sun.COM 
4910122SJordan.Brown@Sun.COM /*
5010122SJordan.Brown@Sun.COM  * Here's a list of all of the modules that provide directory
5110122SJordan.Brown@Sun.COM  * information.  In the fullness of time this should probably be
5210122SJordan.Brown@Sun.COM  * a plugin-able switch mechanism.
5310122SJordan.Brown@Sun.COM  * Note that the list is in precedence order.
5410122SJordan.Brown@Sun.COM  */
5510122SJordan.Brown@Sun.COM extern struct directory_provider_static directory_provider_builtin;
5610122SJordan.Brown@Sun.COM extern struct directory_provider_static directory_provider_nsswitch;
5710122SJordan.Brown@Sun.COM extern struct directory_provider_static directory_provider_ad;
5810122SJordan.Brown@Sun.COM struct directory_provider_static *providers[] = {
5910122SJordan.Brown@Sun.COM 	&directory_provider_builtin,
6010122SJordan.Brown@Sun.COM 	&directory_provider_nsswitch,
6110122SJordan.Brown@Sun.COM 	&directory_provider_ad,
6210122SJordan.Brown@Sun.COM };
6310122SJordan.Brown@Sun.COM 
6410122SJordan.Brown@Sun.COM /*
6510122SJordan.Brown@Sun.COM  * This is the entry point for all directory lookup service requests.
6610122SJordan.Brown@Sun.COM  */
6710122SJordan.Brown@Sun.COM bool_t
directory_get_common_1_svc(idmap_utf8str_list ids,idmap_utf8str types,idmap_utf8str_list attrs,directory_results_rpc * result,struct svc_req * req)6810122SJordan.Brown@Sun.COM directory_get_common_1_svc(
6910122SJordan.Brown@Sun.COM     idmap_utf8str_list ids,
7010122SJordan.Brown@Sun.COM     idmap_utf8str types,
7110122SJordan.Brown@Sun.COM     idmap_utf8str_list attrs,
7210122SJordan.Brown@Sun.COM     directory_results_rpc *result,
7310122SJordan.Brown@Sun.COM     struct svc_req *req)
7410122SJordan.Brown@Sun.COM {
7510122SJordan.Brown@Sun.COM 	NOTE(ARGUNUSED(req))
7610122SJordan.Brown@Sun.COM 	int nids;
7710122SJordan.Brown@Sun.COM 	directory_entry_rpc *entries;
7810122SJordan.Brown@Sun.COM 	directory_error_t de;
7910122SJordan.Brown@Sun.COM 	int i;
8010122SJordan.Brown@Sun.COM 
8110122SJordan.Brown@Sun.COM 	nids = ids.idmap_utf8str_list_len;
8210122SJordan.Brown@Sun.COM 
8310122SJordan.Brown@Sun.COM 	entries = (directory_entry_rpc *)
8410122SJordan.Brown@Sun.COM 	    calloc(nids, sizeof (directory_entry_rpc));
8510122SJordan.Brown@Sun.COM 	if (entries == NULL)
8610122SJordan.Brown@Sun.COM 		goto nomem;
8710122SJordan.Brown@Sun.COM 	result->directory_results_rpc_u.entries.entries_val = entries;
8810122SJordan.Brown@Sun.COM 	result->directory_results_rpc_u.entries.entries_len = nids;
8910122SJordan.Brown@Sun.COM 	result->failed = FALSE;
9010122SJordan.Brown@Sun.COM 
9110122SJordan.Brown@Sun.COM 	for (i = 0; i < nids; i++) {
9210122SJordan.Brown@Sun.COM 		if (strlen(ids.idmap_utf8str_list_val[i]) >
9310122SJordan.Brown@Sun.COM 		    IDMAP_MAX_NAME_LEN) {
9410122SJordan.Brown@Sun.COM 			directory_entry_set_error(&entries[i],
9510122SJordan.Brown@Sun.COM 			    directory_error("invalid_arg.id.too_long",
9610122SJordan.Brown@Sun.COM 			    "Identifier too long", NULL));
9710122SJordan.Brown@Sun.COM 		}
9810122SJordan.Brown@Sun.COM 	}
9910122SJordan.Brown@Sun.COM 
100*12890SJoyce.McIntosh@Sun.COM 	for (i = 0; i < UU_NELEM(providers); i++) {
10110122SJordan.Brown@Sun.COM 		de = providers[i]->get(entries, &ids, types,
10210122SJordan.Brown@Sun.COM 		    &attrs);
10310122SJordan.Brown@Sun.COM 		if (de != NULL)
10410122SJordan.Brown@Sun.COM 			goto err;
10510122SJordan.Brown@Sun.COM 	}
10610122SJordan.Brown@Sun.COM 
10710122SJordan.Brown@Sun.COM 	return (TRUE);
10810122SJordan.Brown@Sun.COM 
10910122SJordan.Brown@Sun.COM nomem:
11010122SJordan.Brown@Sun.COM 	de = directory_error("ENOMEM.get_common",
11110122SJordan.Brown@Sun.COM 	    "Insufficient memory retrieving directory data", NULL);
11210122SJordan.Brown@Sun.COM 
11310122SJordan.Brown@Sun.COM err:
11410122SJordan.Brown@Sun.COM 	xdr_free(xdr_directory_results_rpc, (char *)result);
11510122SJordan.Brown@Sun.COM 	result->failed = TRUE;
11610122SJordan.Brown@Sun.COM 	return (
11710122SJordan.Brown@Sun.COM 	    directory_error_to_rpc(&result->directory_results_rpc_u.err, de));
11810122SJordan.Brown@Sun.COM }
11910122SJordan.Brown@Sun.COM 
12010122SJordan.Brown@Sun.COM /*
12110122SJordan.Brown@Sun.COM  * Split name into {domain, name}.
12210122SJordan.Brown@Sun.COM  * Suggest allocating name and domain on the stack, same size as id,
12310122SJordan.Brown@Sun.COM  * using variable length arrays.
12410122SJordan.Brown@Sun.COM  */
12510122SJordan.Brown@Sun.COM void
split_name(char * name,char * domain,char * id)12610122SJordan.Brown@Sun.COM split_name(char *name, char *domain, char *id)
12710122SJordan.Brown@Sun.COM {
12810122SJordan.Brown@Sun.COM 	char *p;
12910122SJordan.Brown@Sun.COM 
13010122SJordan.Brown@Sun.COM 	if ((p = strchr(id, '@')) != NULL) {
13110122SJordan.Brown@Sun.COM 		(void) strlcpy(name, id, p - id + 1);
13210122SJordan.Brown@Sun.COM 		(void) strcpy(domain, p + 1);
13310122SJordan.Brown@Sun.COM 	} else if ((p = strchr(id, '\\')) != NULL) {
13410122SJordan.Brown@Sun.COM 		(void) strcpy(name, p + 1);
13510122SJordan.Brown@Sun.COM 		(void) strlcpy(domain, id, p - id + 1);
13610122SJordan.Brown@Sun.COM 	} else {
13710122SJordan.Brown@Sun.COM 		(void) strcpy(name, id);
13810122SJordan.Brown@Sun.COM 		(void) strcpy(domain, "");
13910122SJordan.Brown@Sun.COM 	}
14010122SJordan.Brown@Sun.COM }
14110122SJordan.Brown@Sun.COM 
14210122SJordan.Brown@Sun.COM /*
14310122SJordan.Brown@Sun.COM  * Given a list of strings, return a set of directory attribute values.
14410122SJordan.Brown@Sun.COM  *
14510122SJordan.Brown@Sun.COM  * Mark that the attribute was found.
14610122SJordan.Brown@Sun.COM  *
14710122SJordan.Brown@Sun.COM  * Note that the terminating \0 is *not* included in the result, because
14810122SJordan.Brown@Sun.COM  * that's the way that strings come from LDAP.
14910122SJordan.Brown@Sun.COM  * (Note also that the client side stuff adds in a terminating \0.)
15010122SJordan.Brown@Sun.COM  *
15110122SJordan.Brown@Sun.COM  * Note that on error the array may have been partially populated and will
15210122SJordan.Brown@Sun.COM  * need to be cleaned up by the caller.  This is normally not a problem
15310122SJordan.Brown@Sun.COM  * because the caller will need to clean up several such arrays.
15410122SJordan.Brown@Sun.COM  */
15510122SJordan.Brown@Sun.COM directory_error_t
str_list_dav(directory_values_rpc * lvals,const char * const * str_list,int n)15610122SJordan.Brown@Sun.COM str_list_dav(directory_values_rpc *lvals, const char * const *str_list, int n)
15710122SJordan.Brown@Sun.COM {
15810122SJordan.Brown@Sun.COM 	directory_value_rpc *dav;
15910122SJordan.Brown@Sun.COM 	int i;
16010122SJordan.Brown@Sun.COM 
16110122SJordan.Brown@Sun.COM 	if (n == 0) {
16210122SJordan.Brown@Sun.COM 		for (n = 0; str_list[n] != NULL; n++)
16310122SJordan.Brown@Sun.COM 			/* LOOP */;
16410122SJordan.Brown@Sun.COM 	}
16510122SJordan.Brown@Sun.COM 
16610122SJordan.Brown@Sun.COM 	dav = calloc(n, sizeof (directory_value_rpc));
16710122SJordan.Brown@Sun.COM 	if (dav == NULL)
16810122SJordan.Brown@Sun.COM 		goto nomem;
16910122SJordan.Brown@Sun.COM 
17010122SJordan.Brown@Sun.COM 	lvals->directory_values_rpc_u.values.values_val = dav;
17110122SJordan.Brown@Sun.COM 	lvals->directory_values_rpc_u.values.values_len = n;
17210122SJordan.Brown@Sun.COM 	lvals->found = TRUE;
17310122SJordan.Brown@Sun.COM 
17410122SJordan.Brown@Sun.COM 	for (i = 0; i < n; i++) {
17510122SJordan.Brown@Sun.COM 		int len;
17610122SJordan.Brown@Sun.COM 
17710122SJordan.Brown@Sun.COM 		len = strlen(str_list[i]);
178*12890SJoyce.McIntosh@Sun.COM 		dav[i].directory_value_rpc_val = uu_memdup(str_list[i], len);
17910122SJordan.Brown@Sun.COM 		if (dav[i].directory_value_rpc_val == NULL)
18010122SJordan.Brown@Sun.COM 			goto nomem;
18110122SJordan.Brown@Sun.COM 		dav[i].directory_value_rpc_len = len;
18210122SJordan.Brown@Sun.COM 	}
18310122SJordan.Brown@Sun.COM 
18410122SJordan.Brown@Sun.COM 	return (NULL);
18510122SJordan.Brown@Sun.COM 
18610122SJordan.Brown@Sun.COM nomem:
18710122SJordan.Brown@Sun.COM 	return (directory_error("ENOMEM.str_list_dav",
18810122SJordan.Brown@Sun.COM 	    "Insufficient memory copying values"));
18910122SJordan.Brown@Sun.COM }
19010122SJordan.Brown@Sun.COM 
19110122SJordan.Brown@Sun.COM /*
19210122SJordan.Brown@Sun.COM  * Given a list of unsigned integers, return a set of string directory
19310122SJordan.Brown@Sun.COM  * attribute values.
19410122SJordan.Brown@Sun.COM  *
19510122SJordan.Brown@Sun.COM  * Mark that the attribute was found.
19610122SJordan.Brown@Sun.COM  *
19710122SJordan.Brown@Sun.COM  * Note that the terminating \0 is *not* included in the result, because
19810122SJordan.Brown@Sun.COM  * that's the way that strings come from LDAP.
19910122SJordan.Brown@Sun.COM  * (Note also that the client side stuff adds in a terminating \0.)
20010122SJordan.Brown@Sun.COM  *
20110122SJordan.Brown@Sun.COM  * Note that on error the array may have been partially populated and will
20210122SJordan.Brown@Sun.COM  * need to be cleaned up by the caller.  This is normally not a problem
20310122SJordan.Brown@Sun.COM  * because the caller will need to clean up several such arrays.
20410122SJordan.Brown@Sun.COM  */
20510122SJordan.Brown@Sun.COM directory_error_t
uint_list_dav(directory_values_rpc * lvals,const unsigned int * array,int n)20610122SJordan.Brown@Sun.COM uint_list_dav(directory_values_rpc *lvals, const unsigned int *array, int n)
20710122SJordan.Brown@Sun.COM {
20810122SJordan.Brown@Sun.COM 	directory_value_rpc *dav;
20910122SJordan.Brown@Sun.COM 	int i;
21010122SJordan.Brown@Sun.COM 
21110122SJordan.Brown@Sun.COM 	dav = calloc(n, sizeof (directory_value_rpc));
21210122SJordan.Brown@Sun.COM 	if (dav == NULL)
21310122SJordan.Brown@Sun.COM 		goto nomem;
21410122SJordan.Brown@Sun.COM 
21510122SJordan.Brown@Sun.COM 	lvals->directory_values_rpc_u.values.values_val = dav;
21610122SJordan.Brown@Sun.COM 	lvals->directory_values_rpc_u.values.values_len = n;
21710122SJordan.Brown@Sun.COM 	lvals->found = TRUE;
21810122SJordan.Brown@Sun.COM 
21910122SJordan.Brown@Sun.COM 	for (i = 0; i < n; i++) {
22010122SJordan.Brown@Sun.COM 		char buf[100];	/* larger than any integer */
22110122SJordan.Brown@Sun.COM 		int len;
22210122SJordan.Brown@Sun.COM 
22310122SJordan.Brown@Sun.COM 		(void) snprintf(buf, sizeof (buf), "%u", array[i]);
22410122SJordan.Brown@Sun.COM 
22510122SJordan.Brown@Sun.COM 		len = strlen(buf);
226*12890SJoyce.McIntosh@Sun.COM 		dav[i].directory_value_rpc_val = uu_memdup(buf, len);
22710122SJordan.Brown@Sun.COM 		if (dav[i].directory_value_rpc_val == NULL)
22810122SJordan.Brown@Sun.COM 			goto nomem;
22910122SJordan.Brown@Sun.COM 		dav[i].directory_value_rpc_len = len;
23010122SJordan.Brown@Sun.COM 	}
23110122SJordan.Brown@Sun.COM 
23210122SJordan.Brown@Sun.COM 	return (NULL);
23310122SJordan.Brown@Sun.COM 
23410122SJordan.Brown@Sun.COM nomem:
23510122SJordan.Brown@Sun.COM 	return (directory_error("ENOMEM.uint_list_dav",
23610122SJordan.Brown@Sun.COM 	    "Insufficient memory copying values"));
23710122SJordan.Brown@Sun.COM }
23810122SJordan.Brown@Sun.COM 
23910122SJordan.Brown@Sun.COM /*
24010122SJordan.Brown@Sun.COM  * Given a list of fixed-length binary chunks, return a set of binary
24110122SJordan.Brown@Sun.COM  * directory attribute values.
24210122SJordan.Brown@Sun.COM  *
24310122SJordan.Brown@Sun.COM  * Mark that the attribute was found.
24410122SJordan.Brown@Sun.COM  *
24510122SJordan.Brown@Sun.COM  * Note that on error the array may have been partially populated and will
24610122SJordan.Brown@Sun.COM  * need to be cleaned up by the caller.  This is normally not a problem
24710122SJordan.Brown@Sun.COM  * because the caller will need to clean up several such arrays.
24810122SJordan.Brown@Sun.COM  */
24910122SJordan.Brown@Sun.COM directory_error_t
bin_list_dav(directory_values_rpc * lvals,const void * array,int n,size_t sz)25010122SJordan.Brown@Sun.COM bin_list_dav(directory_values_rpc *lvals, const void *array, int n, size_t sz)
25110122SJordan.Brown@Sun.COM {
25210122SJordan.Brown@Sun.COM 	directory_value_rpc *dav;
25310122SJordan.Brown@Sun.COM 	char *inbuf = (char *)array;
25410122SJordan.Brown@Sun.COM 	int i;
25510122SJordan.Brown@Sun.COM 
25610122SJordan.Brown@Sun.COM 	dav = calloc(n, sizeof (directory_value_rpc));
25710122SJordan.Brown@Sun.COM 	if (dav == NULL)
25810122SJordan.Brown@Sun.COM 		goto nomem;
25910122SJordan.Brown@Sun.COM 
26010122SJordan.Brown@Sun.COM 	lvals->directory_values_rpc_u.values.values_val = dav;
26110122SJordan.Brown@Sun.COM 	lvals->directory_values_rpc_u.values.values_len = n;
26210122SJordan.Brown@Sun.COM 	lvals->found = TRUE;
26310122SJordan.Brown@Sun.COM 
26410122SJordan.Brown@Sun.COM 	for (i = 0; i < n; i++) {
265*12890SJoyce.McIntosh@Sun.COM 		dav[i].directory_value_rpc_val = uu_memdup(inbuf, sz);
26610122SJordan.Brown@Sun.COM 		if (dav[i].directory_value_rpc_val == NULL)
26710122SJordan.Brown@Sun.COM 			goto nomem;
26810122SJordan.Brown@Sun.COM 		dav[i].directory_value_rpc_len = sz;
26910122SJordan.Brown@Sun.COM 		inbuf += sz;
27010122SJordan.Brown@Sun.COM 	}
27110122SJordan.Brown@Sun.COM 
27210122SJordan.Brown@Sun.COM 	return (NULL);
27310122SJordan.Brown@Sun.COM 
27410122SJordan.Brown@Sun.COM nomem:
27510122SJordan.Brown@Sun.COM 	return (directory_error("ENOMEM.bin_list_dav",
27610122SJordan.Brown@Sun.COM 	    "Insufficient memory copying values"));
27710122SJordan.Brown@Sun.COM }
27810122SJordan.Brown@Sun.COM 
27910122SJordan.Brown@Sun.COM /*
28010122SJordan.Brown@Sun.COM  * Set up to return an error on a particular directory entry.
28110122SJordan.Brown@Sun.COM  * Note that the caller need not (and in fact must not) free
28210122SJordan.Brown@Sun.COM  * the directory_error_t; it will be freed when the directory entry
28310122SJordan.Brown@Sun.COM  * list is freed.
28410122SJordan.Brown@Sun.COM  */
28510122SJordan.Brown@Sun.COM void
directory_entry_set_error(directory_entry_rpc * ent,directory_error_t de)28610122SJordan.Brown@Sun.COM directory_entry_set_error(directory_entry_rpc *ent, directory_error_t de)
28710122SJordan.Brown@Sun.COM {
28810122SJordan.Brown@Sun.COM 	xdr_free(xdr_directory_entry_rpc, (char *)&ent);
28910122SJordan.Brown@Sun.COM 	ent->status = DIRECTORY_ERROR;
29010122SJordan.Brown@Sun.COM 	(void) directory_error_to_rpc(&ent->directory_entry_rpc_u.err, de);
29110122SJordan.Brown@Sun.COM }
292