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