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