11fcced4cSJordan Brown /*
21fcced4cSJordan Brown  * CDDL HEADER START
31fcced4cSJordan Brown  *
41fcced4cSJordan Brown  * The contents of this file are subject to the terms of the
51fcced4cSJordan Brown  * Common Development and Distribution License (the "License").
61fcced4cSJordan Brown  * You may not use this file except in compliance with the License.
71fcced4cSJordan Brown  *
81fcced4cSJordan Brown  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91fcced4cSJordan Brown  * or http://www.opensolaris.org/os/licensing.
101fcced4cSJordan Brown  * See the License for the specific language governing permissions
111fcced4cSJordan Brown  * and limitations under the License.
121fcced4cSJordan Brown  *
131fcced4cSJordan Brown  * When distributing Covered Code, include this CDDL HEADER in each
141fcced4cSJordan Brown  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151fcced4cSJordan Brown  * If applicable, add the following below this CDDL HEADER, with the
161fcced4cSJordan Brown  * fields enclosed by brackets "[]" replaced with your own identifying
171fcced4cSJordan Brown  * information: Portions Copyright [yyyy] [name of copyright owner]
181fcced4cSJordan Brown  *
191fcced4cSJordan Brown  * CDDL HEADER END
201fcced4cSJordan Brown  */
211fcced4cSJordan Brown 
221fcced4cSJordan Brown /*
23*cb174861Sjoyce mcintosh  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
241fcced4cSJordan Brown  */
251fcced4cSJordan Brown 
261fcced4cSJordan Brown /*
271fcced4cSJordan Brown  * Server-side support for directory information lookup functions.
281fcced4cSJordan Brown  */
291fcced4cSJordan Brown 
301fcced4cSJordan Brown #include <stdio.h>
311fcced4cSJordan Brown #include <stdlib.h>
321fcced4cSJordan Brown #include <stdarg.h>
331fcced4cSJordan Brown #include <malloc.h>
341fcced4cSJordan Brown #include <sys/types.h>
351fcced4cSJordan Brown #include <netdb.h>
361fcced4cSJordan Brown #include <pthread.h>
371fcced4cSJordan Brown #include <unistd.h>
381fcced4cSJordan Brown #include <string.h>
39*cb174861Sjoyce mcintosh #include <libuutil.h>
401fcced4cSJordan Brown #include <note.h>
411fcced4cSJordan Brown #include "idmapd.h"
421fcced4cSJordan Brown #include "directory.h"
431fcced4cSJordan Brown #include "directory_private.h"
441fcced4cSJordan Brown #include <rpcsvc/idmap_prot.h>
451fcced4cSJordan Brown #include "directory_library_impl.h"
461fcced4cSJordan Brown #include "directory_server_impl.h"
471fcced4cSJordan Brown #include "sized_array.h"
481fcced4cSJordan Brown 
491fcced4cSJordan Brown /*
501fcced4cSJordan Brown  * Here's a list of all of the modules that provide directory
511fcced4cSJordan Brown  * information.  In the fullness of time this should probably be
521fcced4cSJordan Brown  * a plugin-able switch mechanism.
531fcced4cSJordan Brown  * Note that the list is in precedence order.
541fcced4cSJordan Brown  */
551fcced4cSJordan Brown extern struct directory_provider_static directory_provider_builtin;
561fcced4cSJordan Brown extern struct directory_provider_static directory_provider_nsswitch;
571fcced4cSJordan Brown extern struct directory_provider_static directory_provider_ad;
581fcced4cSJordan Brown struct directory_provider_static *providers[] = {
591fcced4cSJordan Brown 	&directory_provider_builtin,
601fcced4cSJordan Brown 	&directory_provider_nsswitch,
611fcced4cSJordan Brown 	&directory_provider_ad,
621fcced4cSJordan Brown };
631fcced4cSJordan Brown 
641fcced4cSJordan Brown /*
651fcced4cSJordan Brown  * This is the entry point for all directory lookup service requests.
661fcced4cSJordan Brown  */
671fcced4cSJordan Brown 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)681fcced4cSJordan Brown directory_get_common_1_svc(
691fcced4cSJordan Brown     idmap_utf8str_list ids,
701fcced4cSJordan Brown     idmap_utf8str types,
711fcced4cSJordan Brown     idmap_utf8str_list attrs,
721fcced4cSJordan Brown     directory_results_rpc *result,
731fcced4cSJordan Brown     struct svc_req *req)
741fcced4cSJordan Brown {
751fcced4cSJordan Brown 	NOTE(ARGUNUSED(req))
761fcced4cSJordan Brown 	int nids;
771fcced4cSJordan Brown 	directory_entry_rpc *entries;
781fcced4cSJordan Brown 	directory_error_t de;
791fcced4cSJordan Brown 	int i;
801fcced4cSJordan Brown 
811fcced4cSJordan Brown 	nids = ids.idmap_utf8str_list_len;
821fcced4cSJordan Brown 
831fcced4cSJordan Brown 	entries = (directory_entry_rpc *)
841fcced4cSJordan Brown 	    calloc(nids, sizeof (directory_entry_rpc));
851fcced4cSJordan Brown 	if (entries == NULL)
861fcced4cSJordan Brown 		goto nomem;
871fcced4cSJordan Brown 	result->directory_results_rpc_u.entries.entries_val = entries;
881fcced4cSJordan Brown 	result->directory_results_rpc_u.entries.entries_len = nids;
891fcced4cSJordan Brown 	result->failed = FALSE;
901fcced4cSJordan Brown 
911fcced4cSJordan Brown 	for (i = 0; i < nids; i++) {
921fcced4cSJordan Brown 		if (strlen(ids.idmap_utf8str_list_val[i]) >
931fcced4cSJordan Brown 		    IDMAP_MAX_NAME_LEN) {
941fcced4cSJordan Brown 			directory_entry_set_error(&entries[i],
951fcced4cSJordan Brown 			    directory_error("invalid_arg.id.too_long",
961fcced4cSJordan Brown 			    "Identifier too long", NULL));
971fcced4cSJordan Brown 		}
981fcced4cSJordan Brown 	}
991fcced4cSJordan Brown 
100*cb174861Sjoyce mcintosh 	for (i = 0; i < UU_NELEM(providers); i++) {
1011fcced4cSJordan Brown 		de = providers[i]->get(entries, &ids, types,
1021fcced4cSJordan Brown 		    &attrs);
1031fcced4cSJordan Brown 		if (de != NULL)
1041fcced4cSJordan Brown 			goto err;
1051fcced4cSJordan Brown 	}
1061fcced4cSJordan Brown 
1071fcced4cSJordan Brown 	return (TRUE);
1081fcced4cSJordan Brown 
1091fcced4cSJordan Brown nomem:
1101fcced4cSJordan Brown 	de = directory_error("ENOMEM.get_common",
1111fcced4cSJordan Brown 	    "Insufficient memory retrieving directory data", NULL);
1121fcced4cSJordan Brown 
1131fcced4cSJordan Brown err:
1141fcced4cSJordan Brown 	xdr_free(xdr_directory_results_rpc, (char *)result);
1151fcced4cSJordan Brown 	result->failed = TRUE;
1161fcced4cSJordan Brown 	return (
1171fcced4cSJordan Brown 	    directory_error_to_rpc(&result->directory_results_rpc_u.err, de));
1181fcced4cSJordan Brown }
1191fcced4cSJordan Brown 
1201fcced4cSJordan Brown /*
1211fcced4cSJordan Brown  * Split name into {domain, name}.
1221fcced4cSJordan Brown  * Suggest allocating name and domain on the stack, same size as id,
1231fcced4cSJordan Brown  * using variable length arrays.
1241fcced4cSJordan Brown  */
1251fcced4cSJordan Brown void
split_name(char * name,char * domain,char * id)1261fcced4cSJordan Brown split_name(char *name, char *domain, char *id)
1271fcced4cSJordan Brown {
1281fcced4cSJordan Brown 	char *p;
1291fcced4cSJordan Brown 
1301fcced4cSJordan Brown 	if ((p = strchr(id, '@')) != NULL) {
1311fcced4cSJordan Brown 		(void) strlcpy(name, id, p - id + 1);
1321fcced4cSJordan Brown 		(void) strcpy(domain, p + 1);
1331fcced4cSJordan Brown 	} else if ((p = strchr(id, '\\')) != NULL) {
1341fcced4cSJordan Brown 		(void) strcpy(name, p + 1);
1351fcced4cSJordan Brown 		(void) strlcpy(domain, id, p - id + 1);
1361fcced4cSJordan Brown 	} else {
1371fcced4cSJordan Brown 		(void) strcpy(name, id);
1381fcced4cSJordan Brown 		(void) strcpy(domain, "");
1391fcced4cSJordan Brown 	}
1401fcced4cSJordan Brown }
1411fcced4cSJordan Brown 
1421fcced4cSJordan Brown /*
1431fcced4cSJordan Brown  * Given a list of strings, return a set of directory attribute values.
1441fcced4cSJordan Brown  *
1451fcced4cSJordan Brown  * Mark that the attribute was found.
1461fcced4cSJordan Brown  *
1471fcced4cSJordan Brown  * Note that the terminating \0 is *not* included in the result, because
1481fcced4cSJordan Brown  * that's the way that strings come from LDAP.
1491fcced4cSJordan Brown  * (Note also that the client side stuff adds in a terminating \0.)
1501fcced4cSJordan Brown  *
1511fcced4cSJordan Brown  * Note that on error the array may have been partially populated and will
1521fcced4cSJordan Brown  * need to be cleaned up by the caller.  This is normally not a problem
1531fcced4cSJordan Brown  * because the caller will need to clean up several such arrays.
1541fcced4cSJordan Brown  */
1551fcced4cSJordan Brown directory_error_t
str_list_dav(directory_values_rpc * lvals,const char * const * str_list,int n)1561fcced4cSJordan Brown str_list_dav(directory_values_rpc *lvals, const char * const *str_list, int n)
1571fcced4cSJordan Brown {
1581fcced4cSJordan Brown 	directory_value_rpc *dav;
1591fcced4cSJordan Brown 	int i;
1601fcced4cSJordan Brown 
1611fcced4cSJordan Brown 	if (n == 0) {
1621fcced4cSJordan Brown 		for (n = 0; str_list[n] != NULL; n++)
1631fcced4cSJordan Brown 			/* LOOP */;
1641fcced4cSJordan Brown 	}
1651fcced4cSJordan Brown 
1661fcced4cSJordan Brown 	dav = calloc(n, sizeof (directory_value_rpc));
1671fcced4cSJordan Brown 	if (dav == NULL)
1681fcced4cSJordan Brown 		goto nomem;
1691fcced4cSJordan Brown 
1701fcced4cSJordan Brown 	lvals->directory_values_rpc_u.values.values_val = dav;
1711fcced4cSJordan Brown 	lvals->directory_values_rpc_u.values.values_len = n;
1721fcced4cSJordan Brown 	lvals->found = TRUE;
1731fcced4cSJordan Brown 
1741fcced4cSJordan Brown 	for (i = 0; i < n; i++) {
1751fcced4cSJordan Brown 		int len;
1761fcced4cSJordan Brown 
1771fcced4cSJordan Brown 		len = strlen(str_list[i]);
178*cb174861Sjoyce mcintosh 		dav[i].directory_value_rpc_val = uu_memdup(str_list[i], len);
1791fcced4cSJordan Brown 		if (dav[i].directory_value_rpc_val == NULL)
1801fcced4cSJordan Brown 			goto nomem;
1811fcced4cSJordan Brown 		dav[i].directory_value_rpc_len = len;
1821fcced4cSJordan Brown 	}
1831fcced4cSJordan Brown 
1841fcced4cSJordan Brown 	return (NULL);
1851fcced4cSJordan Brown 
1861fcced4cSJordan Brown nomem:
1871fcced4cSJordan Brown 	return (directory_error("ENOMEM.str_list_dav",
1881fcced4cSJordan Brown 	    "Insufficient memory copying values"));
1891fcced4cSJordan Brown }
1901fcced4cSJordan Brown 
1911fcced4cSJordan Brown /*
1921fcced4cSJordan Brown  * Given a list of unsigned integers, return a set of string directory
1931fcced4cSJordan Brown  * attribute values.
1941fcced4cSJordan Brown  *
1951fcced4cSJordan Brown  * Mark that the attribute was found.
1961fcced4cSJordan Brown  *
1971fcced4cSJordan Brown  * Note that the terminating \0 is *not* included in the result, because
1981fcced4cSJordan Brown  * that's the way that strings come from LDAP.
1991fcced4cSJordan Brown  * (Note also that the client side stuff adds in a terminating \0.)
2001fcced4cSJordan Brown  *
2011fcced4cSJordan Brown  * Note that on error the array may have been partially populated and will
2021fcced4cSJordan Brown  * need to be cleaned up by the caller.  This is normally not a problem
2031fcced4cSJordan Brown  * because the caller will need to clean up several such arrays.
2041fcced4cSJordan Brown  */
2051fcced4cSJordan Brown directory_error_t
uint_list_dav(directory_values_rpc * lvals,const unsigned int * array,int n)2061fcced4cSJordan Brown uint_list_dav(directory_values_rpc *lvals, const unsigned int *array, int n)
2071fcced4cSJordan Brown {
2081fcced4cSJordan Brown 	directory_value_rpc *dav;
2091fcced4cSJordan Brown 	int i;
2101fcced4cSJordan Brown 
2111fcced4cSJordan Brown 	dav = calloc(n, sizeof (directory_value_rpc));
2121fcced4cSJordan Brown 	if (dav == NULL)
2131fcced4cSJordan Brown 		goto nomem;
2141fcced4cSJordan Brown 
2151fcced4cSJordan Brown 	lvals->directory_values_rpc_u.values.values_val = dav;
2161fcced4cSJordan Brown 	lvals->directory_values_rpc_u.values.values_len = n;
2171fcced4cSJordan Brown 	lvals->found = TRUE;
2181fcced4cSJordan Brown 
2191fcced4cSJordan Brown 	for (i = 0; i < n; i++) {
2201fcced4cSJordan Brown 		char buf[100];	/* larger than any integer */
2211fcced4cSJordan Brown 		int len;
2221fcced4cSJordan Brown 
2231fcced4cSJordan Brown 		(void) snprintf(buf, sizeof (buf), "%u", array[i]);
2241fcced4cSJordan Brown 
2251fcced4cSJordan Brown 		len = strlen(buf);
226*cb174861Sjoyce mcintosh 		dav[i].directory_value_rpc_val = uu_memdup(buf, len);
2271fcced4cSJordan Brown 		if (dav[i].directory_value_rpc_val == NULL)
2281fcced4cSJordan Brown 			goto nomem;
2291fcced4cSJordan Brown 		dav[i].directory_value_rpc_len = len;
2301fcced4cSJordan Brown 	}
2311fcced4cSJordan Brown 
2321fcced4cSJordan Brown 	return (NULL);
2331fcced4cSJordan Brown 
2341fcced4cSJordan Brown nomem:
2351fcced4cSJordan Brown 	return (directory_error("ENOMEM.uint_list_dav",
2361fcced4cSJordan Brown 	    "Insufficient memory copying values"));
2371fcced4cSJordan Brown }
2381fcced4cSJordan Brown 
2391fcced4cSJordan Brown /*
2401fcced4cSJordan Brown  * Given a list of fixed-length binary chunks, return a set of binary
2411fcced4cSJordan Brown  * directory attribute values.
2421fcced4cSJordan Brown  *
2431fcced4cSJordan Brown  * Mark that the attribute was found.
2441fcced4cSJordan Brown  *
2451fcced4cSJordan Brown  * Note that on error the array may have been partially populated and will
2461fcced4cSJordan Brown  * need to be cleaned up by the caller.  This is normally not a problem
2471fcced4cSJordan Brown  * because the caller will need to clean up several such arrays.
2481fcced4cSJordan Brown  */
2491fcced4cSJordan Brown directory_error_t
bin_list_dav(directory_values_rpc * lvals,const void * array,int n,size_t sz)2501fcced4cSJordan Brown bin_list_dav(directory_values_rpc *lvals, const void *array, int n, size_t sz)
2511fcced4cSJordan Brown {
2521fcced4cSJordan Brown 	directory_value_rpc *dav;
2531fcced4cSJordan Brown 	char *inbuf = (char *)array;
2541fcced4cSJordan Brown 	int i;
2551fcced4cSJordan Brown 
2561fcced4cSJordan Brown 	dav = calloc(n, sizeof (directory_value_rpc));
2571fcced4cSJordan Brown 	if (dav == NULL)
2581fcced4cSJordan Brown 		goto nomem;
2591fcced4cSJordan Brown 
2601fcced4cSJordan Brown 	lvals->directory_values_rpc_u.values.values_val = dav;
2611fcced4cSJordan Brown 	lvals->directory_values_rpc_u.values.values_len = n;
2621fcced4cSJordan Brown 	lvals->found = TRUE;
2631fcced4cSJordan Brown 
2641fcced4cSJordan Brown 	for (i = 0; i < n; i++) {
265*cb174861Sjoyce mcintosh 		dav[i].directory_value_rpc_val = uu_memdup(inbuf, sz);
2661fcced4cSJordan Brown 		if (dav[i].directory_value_rpc_val == NULL)
2671fcced4cSJordan Brown 			goto nomem;
2681fcced4cSJordan Brown 		dav[i].directory_value_rpc_len = sz;
2691fcced4cSJordan Brown 		inbuf += sz;
2701fcced4cSJordan Brown 	}
2711fcced4cSJordan Brown 
2721fcced4cSJordan Brown 	return (NULL);
2731fcced4cSJordan Brown 
2741fcced4cSJordan Brown nomem:
2751fcced4cSJordan Brown 	return (directory_error("ENOMEM.bin_list_dav",
2761fcced4cSJordan Brown 	    "Insufficient memory copying values"));
2771fcced4cSJordan Brown }
2781fcced4cSJordan Brown 
2791fcced4cSJordan Brown /*
2801fcced4cSJordan Brown  * Set up to return an error on a particular directory entry.
2811fcced4cSJordan Brown  * Note that the caller need not (and in fact must not) free
2821fcced4cSJordan Brown  * the directory_error_t; it will be freed when the directory entry
2831fcced4cSJordan Brown  * list is freed.
2841fcced4cSJordan Brown  */
2851fcced4cSJordan Brown void
directory_entry_set_error(directory_entry_rpc * ent,directory_error_t de)2861fcced4cSJordan Brown directory_entry_set_error(directory_entry_rpc *ent, directory_error_t de)
2871fcced4cSJordan Brown {
2881fcced4cSJordan Brown 	xdr_free(xdr_directory_entry_rpc, (char *)&ent);
2891fcced4cSJordan Brown 	ent->status = DIRECTORY_ERROR;
2901fcced4cSJordan Brown 	(void) directory_error_to_rpc(&ent->directory_entry_rpc_u.err, de);
2911fcced4cSJordan Brown }
292