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