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