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 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 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 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 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 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 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