1*1fcced4cSJordan Brown /* 2*1fcced4cSJordan Brown * CDDL HEADER START 3*1fcced4cSJordan Brown * 4*1fcced4cSJordan Brown * The contents of this file are subject to the terms of the 5*1fcced4cSJordan Brown * Common Development and Distribution License (the "License"). 6*1fcced4cSJordan Brown * You may not use this file except in compliance with the License. 7*1fcced4cSJordan Brown * 8*1fcced4cSJordan Brown * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*1fcced4cSJordan Brown * or http://www.opensolaris.org/os/licensing. 10*1fcced4cSJordan Brown * See the License for the specific language governing permissions 11*1fcced4cSJordan Brown * and limitations under the License. 12*1fcced4cSJordan Brown * 13*1fcced4cSJordan Brown * When distributing Covered Code, include this CDDL HEADER in each 14*1fcced4cSJordan Brown * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*1fcced4cSJordan Brown * If applicable, add the following below this CDDL HEADER, with the 16*1fcced4cSJordan Brown * fields enclosed by brackets "[]" replaced with your own identifying 17*1fcced4cSJordan Brown * information: Portions Copyright [yyyy] [name of copyright owner] 18*1fcced4cSJordan Brown * 19*1fcced4cSJordan Brown * CDDL HEADER END 20*1fcced4cSJordan Brown */ 21*1fcced4cSJordan Brown 22*1fcced4cSJordan Brown /* 23*1fcced4cSJordan Brown * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24*1fcced4cSJordan Brown * Use is subject to license terms. 25*1fcced4cSJordan Brown */ 26*1fcced4cSJordan Brown 27*1fcced4cSJordan Brown /* 28*1fcced4cSJordan Brown * Directory lookup functions. These are shims that translate from the API 29*1fcced4cSJordan Brown * into the RPC protocol. 30*1fcced4cSJordan Brown */ 31*1fcced4cSJordan Brown 32*1fcced4cSJordan Brown #include <assert.h> 33*1fcced4cSJordan Brown #include <stdio.h> 34*1fcced4cSJordan Brown #include <stdlib.h> 35*1fcced4cSJordan Brown #include <stdarg.h> 36*1fcced4cSJordan Brown #include <malloc.h> 37*1fcced4cSJordan Brown #include <sys/types.h> 38*1fcced4cSJordan Brown #include <netdb.h> 39*1fcced4cSJordan Brown #include <pthread.h> 40*1fcced4cSJordan Brown #include <unistd.h> 41*1fcced4cSJordan Brown #include <string.h> 42*1fcced4cSJordan Brown #include "directory.h" 43*1fcced4cSJordan Brown #include "directory_private.h" 44*1fcced4cSJordan Brown #include <rpcsvc/idmap_prot.h> 45*1fcced4cSJordan Brown #include "directory_library_impl.h" 46*1fcced4cSJordan Brown #include "sized_array.h" 47*1fcced4cSJordan Brown 48*1fcced4cSJordan Brown static directory_error_t copy_directory_attribute_value( 49*1fcced4cSJordan Brown directory_attribute_value_t *dav, 50*1fcced4cSJordan Brown directory_values_rpc *dav_rpc); 51*1fcced4cSJordan Brown static directory_error_t copy_directory_entry(directory_entry_t *ent, 52*1fcced4cSJordan Brown directory_entry_rpc *ent_rpc); 53*1fcced4cSJordan Brown static void directory_results_free(directory_results_rpc *dr); 54*1fcced4cSJordan Brown static directory_datum_t directory_datum(void *data, size_t len); 55*1fcced4cSJordan Brown static void directory_datum_free(directory_datum_t d); 56*1fcced4cSJordan Brown 57*1fcced4cSJordan Brown /* 58*1fcced4cSJordan Brown * This is the actual implementation of the opaque directory_t structure. 59*1fcced4cSJordan Brown */ 60*1fcced4cSJordan Brown struct directory { 61*1fcced4cSJordan Brown CLIENT *client; 62*1fcced4cSJordan Brown }; 63*1fcced4cSJordan Brown 64*1fcced4cSJordan Brown /* 65*1fcced4cSJordan Brown * Set up a directory search context. 66*1fcced4cSJordan Brown */ 67*1fcced4cSJordan Brown directory_error_t 68*1fcced4cSJordan Brown directory_open(directory_t *ret) 69*1fcced4cSJordan Brown { 70*1fcced4cSJordan Brown directory_t d; 71*1fcced4cSJordan Brown directory_error_t de; 72*1fcced4cSJordan Brown char host[] = "localhost"; 73*1fcced4cSJordan Brown 74*1fcced4cSJordan Brown *ret = NULL; 75*1fcced4cSJordan Brown 76*1fcced4cSJordan Brown d = calloc(1, sizeof (*d)); 77*1fcced4cSJordan Brown if (d == NULL) 78*1fcced4cSJordan Brown goto nomem; 79*1fcced4cSJordan Brown 80*1fcced4cSJordan Brown d->client = clnt_door_create(IDMAP_PROG, IDMAP_V1, 0); 81*1fcced4cSJordan Brown if (d->client == NULL) { 82*1fcced4cSJordan Brown de = directory_error("clnt_create.directory_open", 83*1fcced4cSJordan Brown "Error: %1", 84*1fcced4cSJordan Brown clnt_spcreateerror(host), 85*1fcced4cSJordan Brown NULL); 86*1fcced4cSJordan Brown goto err; 87*1fcced4cSJordan Brown } 88*1fcced4cSJordan Brown 89*1fcced4cSJordan Brown *ret = d; 90*1fcced4cSJordan Brown return (NULL); 91*1fcced4cSJordan Brown 92*1fcced4cSJordan Brown nomem: 93*1fcced4cSJordan Brown de = directory_error("ENOMEM.directory_open", 94*1fcced4cSJordan Brown "Insufficient memory setting up directory access", NULL); 95*1fcced4cSJordan Brown err: 96*1fcced4cSJordan Brown directory_close(d); 97*1fcced4cSJordan Brown return (de); 98*1fcced4cSJordan Brown } 99*1fcced4cSJordan Brown 100*1fcced4cSJordan Brown /* 101*1fcced4cSJordan Brown * Tear down a directory search context. 102*1fcced4cSJordan Brown * 103*1fcced4cSJordan Brown * Does nothing if d==NULL. 104*1fcced4cSJordan Brown */ 105*1fcced4cSJordan Brown void 106*1fcced4cSJordan Brown directory_close(directory_t d) 107*1fcced4cSJordan Brown { 108*1fcced4cSJordan Brown if (d == NULL) 109*1fcced4cSJordan Brown return; 110*1fcced4cSJordan Brown 111*1fcced4cSJordan Brown if (d->client != NULL) 112*1fcced4cSJordan Brown clnt_destroy(d->client); 113*1fcced4cSJordan Brown 114*1fcced4cSJordan Brown free(d); 115*1fcced4cSJordan Brown } 116*1fcced4cSJordan Brown 117*1fcced4cSJordan Brown /* 118*1fcced4cSJordan Brown * Given a list of identifiers, a list of their types, and a list of attributes, 119*1fcced4cSJordan Brown * return the information. 120*1fcced4cSJordan Brown */ 121*1fcced4cSJordan Brown directory_error_t 122*1fcced4cSJordan Brown directory_get_v( 123*1fcced4cSJordan Brown directory_t d, 124*1fcced4cSJordan Brown directory_entry_list_t *ret, 125*1fcced4cSJordan Brown char **ids, 126*1fcced4cSJordan Brown int nids, 127*1fcced4cSJordan Brown char *types, 128*1fcced4cSJordan Brown char **attr_list) 129*1fcced4cSJordan Brown { 130*1fcced4cSJordan Brown int nattrs; 131*1fcced4cSJordan Brown directory_entry_list_t del; 132*1fcced4cSJordan Brown directory_error_t de; 133*1fcced4cSJordan Brown directory_results_rpc dr; 134*1fcced4cSJordan Brown idmap_utf8str_list sl_ids; 135*1fcced4cSJordan Brown idmap_utf8str_list sl_attrs; 136*1fcced4cSJordan Brown directory_entry_rpc *users; 137*1fcced4cSJordan Brown int i; 138*1fcced4cSJordan Brown enum clnt_stat cs; 139*1fcced4cSJordan Brown 140*1fcced4cSJordan Brown *ret = NULL; 141*1fcced4cSJordan Brown del = NULL; 142*1fcced4cSJordan Brown 143*1fcced4cSJordan Brown if (nids == 0) { 144*1fcced4cSJordan Brown for (nids = 0; ids[nids] != NULL; nids++) 145*1fcced4cSJordan Brown /* LOOP */; 146*1fcced4cSJordan Brown } 147*1fcced4cSJordan Brown 148*1fcced4cSJordan Brown for (nattrs = 0; attr_list[nattrs] != NULL; nattrs++) 149*1fcced4cSJordan Brown /* LOOP */; 150*1fcced4cSJordan Brown 151*1fcced4cSJordan Brown sl_ids.idmap_utf8str_list_len = nids; 152*1fcced4cSJordan Brown sl_ids.idmap_utf8str_list_val = ids; 153*1fcced4cSJordan Brown sl_attrs.idmap_utf8str_list_len = nattrs; 154*1fcced4cSJordan Brown sl_attrs.idmap_utf8str_list_val = attr_list; 155*1fcced4cSJordan Brown 156*1fcced4cSJordan Brown (void) memset(&dr, 0, sizeof (dr)); 157*1fcced4cSJordan Brown cs = directory_get_common_1(sl_ids, types, sl_attrs, &dr, d->client); 158*1fcced4cSJordan Brown if (cs != RPC_SUCCESS) { 159*1fcced4cSJordan Brown char errbuf[100]; /* well long enough for any integer */ 160*1fcced4cSJordan Brown (void) sprintf(errbuf, "%d", cs); 161*1fcced4cSJordan Brown de = directory_error("RPC.Get_common", 162*1fcced4cSJordan Brown "Get_common RPC (%1)%2", errbuf, 163*1fcced4cSJordan Brown clnt_sperror(d->client, ""), NULL); 164*1fcced4cSJordan Brown goto err; 165*1fcced4cSJordan Brown } 166*1fcced4cSJordan Brown 167*1fcced4cSJordan Brown if (dr.failed) { 168*1fcced4cSJordan Brown de = directory_error_from_rpc( 169*1fcced4cSJordan Brown &dr.directory_results_rpc_u.err); 170*1fcced4cSJordan Brown goto err; 171*1fcced4cSJordan Brown } 172*1fcced4cSJordan Brown 173*1fcced4cSJordan Brown assert(dr.directory_results_rpc_u.entries.entries_len == nids); 174*1fcced4cSJordan Brown 175*1fcced4cSJordan Brown users = dr.directory_results_rpc_u.entries.entries_val; 176*1fcced4cSJordan Brown 177*1fcced4cSJordan Brown del = sized_array(nids, sizeof (directory_entry_t)); 178*1fcced4cSJordan Brown 179*1fcced4cSJordan Brown for (i = 0; i < nids; i++) { 180*1fcced4cSJordan Brown de = copy_directory_entry(&del[i], &users[i]); 181*1fcced4cSJordan Brown if (de != NULL) 182*1fcced4cSJordan Brown goto err; 183*1fcced4cSJordan Brown } 184*1fcced4cSJordan Brown 185*1fcced4cSJordan Brown directory_results_free(&dr); 186*1fcced4cSJordan Brown 187*1fcced4cSJordan Brown *ret = del; 188*1fcced4cSJordan Brown return (NULL); 189*1fcced4cSJordan Brown 190*1fcced4cSJordan Brown err: 191*1fcced4cSJordan Brown directory_results_free(&dr); 192*1fcced4cSJordan Brown directory_free(del); 193*1fcced4cSJordan Brown return (de); 194*1fcced4cSJordan Brown } 195*1fcced4cSJordan Brown 196*1fcced4cSJordan Brown /* 197*1fcced4cSJordan Brown * Free the results from a directory_get_*() request. 198*1fcced4cSJordan Brown */ 199*1fcced4cSJordan Brown void 200*1fcced4cSJordan Brown directory_free(directory_entry_list_t del) 201*1fcced4cSJordan Brown { 202*1fcced4cSJordan Brown directory_entry_t *ent; 203*1fcced4cSJordan Brown directory_attribute_value_t dav; 204*1fcced4cSJordan Brown int i; 205*1fcced4cSJordan Brown int j; 206*1fcced4cSJordan Brown int k; 207*1fcced4cSJordan Brown 208*1fcced4cSJordan Brown if (del == NULL) 209*1fcced4cSJordan Brown return; 210*1fcced4cSJordan Brown 211*1fcced4cSJordan Brown /* For each directory entry returned */ 212*1fcced4cSJordan Brown for (i = 0; i < sized_array_n(del); i++) { 213*1fcced4cSJordan Brown ent = &del[i]; 214*1fcced4cSJordan Brown 215*1fcced4cSJordan Brown if (ent->attrs != NULL) { 216*1fcced4cSJordan Brown /* For each attribute */ 217*1fcced4cSJordan Brown for (j = 0; j < sized_array_n(ent->attrs); j++) { 218*1fcced4cSJordan Brown dav = ent->attrs[j]; 219*1fcced4cSJordan Brown if (dav != NULL) { 220*1fcced4cSJordan Brown for (k = 0; k < sized_array_n(dav); k++) 221*1fcced4cSJordan Brown directory_datum_free(dav[k]); 222*1fcced4cSJordan Brown 223*1fcced4cSJordan Brown sized_array_free(dav); 224*1fcced4cSJordan Brown } 225*1fcced4cSJordan Brown } 226*1fcced4cSJordan Brown sized_array_free(ent->attrs); 227*1fcced4cSJordan Brown } 228*1fcced4cSJordan Brown 229*1fcced4cSJordan Brown directory_error_free(ent->err); 230*1fcced4cSJordan Brown } 231*1fcced4cSJordan Brown 232*1fcced4cSJordan Brown sized_array_free(del); 233*1fcced4cSJordan Brown } 234*1fcced4cSJordan Brown 235*1fcced4cSJordan Brown /* 236*1fcced4cSJordan Brown * Create a directory datum. Note that we allocate an extra byte and 237*1fcced4cSJordan Brown * zero it, so that strings get null-terminated. Return NULL on error. 238*1fcced4cSJordan Brown */ 239*1fcced4cSJordan Brown static 240*1fcced4cSJordan Brown directory_datum_t 241*1fcced4cSJordan Brown directory_datum(void *data, size_t len) 242*1fcced4cSJordan Brown { 243*1fcced4cSJordan Brown void *p; 244*1fcced4cSJordan Brown 245*1fcced4cSJordan Brown p = sized_array(len + 1, 1); 246*1fcced4cSJordan Brown if (p == NULL) 247*1fcced4cSJordan Brown return (NULL); 248*1fcced4cSJordan Brown (void) memcpy(p, data, len); 249*1fcced4cSJordan Brown *((char *)p + len) = '\0'; 250*1fcced4cSJordan Brown return (p); 251*1fcced4cSJordan Brown } 252*1fcced4cSJordan Brown 253*1fcced4cSJordan Brown /* 254*1fcced4cSJordan Brown * Return the size of a directory_datum_t. Note that this does not include 255*1fcced4cSJordan Brown * the terminating \0, so it represents the value as returned by LDAP. 256*1fcced4cSJordan Brown */ 257*1fcced4cSJordan Brown size_t 258*1fcced4cSJordan Brown directory_datum_len(directory_datum_t d) 259*1fcced4cSJordan Brown { 260*1fcced4cSJordan Brown /* 261*1fcced4cSJordan Brown * Deduct the terminal \0, so that binary data gets the 262*1fcced4cSJordan Brown * expected length. 263*1fcced4cSJordan Brown */ 264*1fcced4cSJordan Brown return (sized_array_n(d) - 1); 265*1fcced4cSJordan Brown } 266*1fcced4cSJordan Brown 267*1fcced4cSJordan Brown static 268*1fcced4cSJordan Brown void 269*1fcced4cSJordan Brown directory_datum_free(directory_datum_t d) 270*1fcced4cSJordan Brown { 271*1fcced4cSJordan Brown sized_array_free(d); 272*1fcced4cSJordan Brown } 273*1fcced4cSJordan Brown 274*1fcced4cSJordan Brown /* 275*1fcced4cSJordan Brown * Unmarshall an RPC directory entry into an API directory entry. 276*1fcced4cSJordan Brown */ 277*1fcced4cSJordan Brown static 278*1fcced4cSJordan Brown directory_error_t 279*1fcced4cSJordan Brown copy_directory_entry( 280*1fcced4cSJordan Brown directory_entry_t *ent, 281*1fcced4cSJordan Brown directory_entry_rpc *ent_rpc) 282*1fcced4cSJordan Brown { 283*1fcced4cSJordan Brown int nattrs; 284*1fcced4cSJordan Brown int i; 285*1fcced4cSJordan Brown directory_error_t de; 286*1fcced4cSJordan Brown 287*1fcced4cSJordan Brown /* If the entry wasn't found, leave the entry attrs and err NULL. */ 288*1fcced4cSJordan Brown if (ent_rpc->status == DIRECTORY_NOT_FOUND) 289*1fcced4cSJordan Brown return (NULL); 290*1fcced4cSJordan Brown 291*1fcced4cSJordan Brown if (ent_rpc->status == DIRECTORY_ERROR) { 292*1fcced4cSJordan Brown ent->err = directory_error_from_rpc( 293*1fcced4cSJordan Brown &ent_rpc->directory_entry_rpc_u.err); 294*1fcced4cSJordan Brown return (NULL); 295*1fcced4cSJordan Brown } 296*1fcced4cSJordan Brown 297*1fcced4cSJordan Brown nattrs = ent_rpc->directory_entry_rpc_u.attrs.attrs_len; 298*1fcced4cSJordan Brown 299*1fcced4cSJordan Brown ent->attrs = sized_array(nattrs, sizeof (directory_attribute_value_t)); 300*1fcced4cSJordan Brown if (ent->attrs == NULL) { 301*1fcced4cSJordan Brown return (directory_error("ENOMEM.copy_directory_entry", 302*1fcced4cSJordan Brown "Insufficient memory copying directory entry", NULL)); 303*1fcced4cSJordan Brown } 304*1fcced4cSJordan Brown for (i = 0; i < nattrs; i++) { 305*1fcced4cSJordan Brown de = copy_directory_attribute_value(&ent->attrs[i], 306*1fcced4cSJordan Brown &ent_rpc->directory_entry_rpc_u.attrs.attrs_val[i]); 307*1fcced4cSJordan Brown if (de != NULL) 308*1fcced4cSJordan Brown return (de); 309*1fcced4cSJordan Brown } 310*1fcced4cSJordan Brown 311*1fcced4cSJordan Brown return (NULL); 312*1fcced4cSJordan Brown } 313*1fcced4cSJordan Brown 314*1fcced4cSJordan Brown /* 315*1fcced4cSJordan Brown * Unmarshall an RPC directory attribute value into the API equivalent. 316*1fcced4cSJordan Brown * 317*1fcced4cSJordan Brown * Note that on error some entries may have been copied, and so 318*1fcced4cSJordan Brown * the caller needs to clean up dav. This is normally not a problem 319*1fcced4cSJordan Brown * since the caller will have called this function several times and 320*1fcced4cSJordan Brown * will need to clean up the results from the other calls too. 321*1fcced4cSJordan Brown */ 322*1fcced4cSJordan Brown static 323*1fcced4cSJordan Brown directory_error_t 324*1fcced4cSJordan Brown copy_directory_attribute_value( 325*1fcced4cSJordan Brown directory_attribute_value_t *dav, 326*1fcced4cSJordan Brown directory_values_rpc *dav_rpc) 327*1fcced4cSJordan Brown { 328*1fcced4cSJordan Brown int i; 329*1fcced4cSJordan Brown int nvals; 330*1fcced4cSJordan Brown directory_value_rpc *vals; 331*1fcced4cSJordan Brown 332*1fcced4cSJordan Brown /* If it wasn't found, leave the corresponding entry NULL */ 333*1fcced4cSJordan Brown if (!dav_rpc->found) 334*1fcced4cSJordan Brown return (NULL); 335*1fcced4cSJordan Brown 336*1fcced4cSJordan Brown nvals = dav_rpc->directory_values_rpc_u.values.values_len; 337*1fcced4cSJordan Brown *dav = sized_array(nvals + 1, sizeof (directory_datum_t)); 338*1fcced4cSJordan Brown if (*dav == NULL) { 339*1fcced4cSJordan Brown return (directory_error("ENOMEM.copy_directory_attribute_value", 340*1fcced4cSJordan Brown "Insufficient memory copying directory entry", NULL)); 341*1fcced4cSJordan Brown } 342*1fcced4cSJordan Brown 343*1fcced4cSJordan Brown vals = dav_rpc->directory_values_rpc_u.values.values_val; 344*1fcced4cSJordan Brown for (i = 0; i < nvals; i++) { 345*1fcced4cSJordan Brown (*dav)[i] = directory_datum(vals[i].directory_value_rpc_val, 346*1fcced4cSJordan Brown vals[i].directory_value_rpc_len); 347*1fcced4cSJordan Brown if ((*dav)[i] == NULL) { 348*1fcced4cSJordan Brown return (directory_error( 349*1fcced4cSJordan Brown "ENOMEM.copy_directory_attribute_value", 350*1fcced4cSJordan Brown "Insufficient memory copying directory entry", 351*1fcced4cSJordan Brown NULL)); 352*1fcced4cSJordan Brown } 353*1fcced4cSJordan Brown } 354*1fcced4cSJordan Brown 355*1fcced4cSJordan Brown return (NULL); 356*1fcced4cSJordan Brown } 357*1fcced4cSJordan Brown 358*1fcced4cSJordan Brown /* 359*1fcced4cSJordan Brown * Free the results of a directory RPC request. 360*1fcced4cSJordan Brown */ 361*1fcced4cSJordan Brown static 362*1fcced4cSJordan Brown void 363*1fcced4cSJordan Brown directory_results_free(directory_results_rpc *dr) 364*1fcced4cSJordan Brown { 365*1fcced4cSJordan Brown xdr_free(xdr_directory_results_rpc, (char *)&dr); 366*1fcced4cSJordan Brown } 367