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 * Some helper routines for directory lookup. These offer functions that 28 * you could implement yourself on top of the generic routines, but since 29 * they're a common request we implement them here. (Well, OK, we cheat a bit 30 * and call an internal routine to do the dirty work to reduce code 31 * duplication, but you could still implement them using the generic routines.) 32 */ 33 34 #include <stdio.h> 35 #include <string.h> 36 #include <libuutil.h> 37 #include <rpcsvc/idmap_prot.h> 38 #include "directory.h" 39 #include "directory_private.h" 40 #include "directory_library_impl.h" 41 #include "sidutil.h" 42 43 /* 44 * Given a username, return a text-form SID. 45 * 46 * The SID must be free()ed by the caller. 47 * 48 * d, if non-NULL, specifies an existing directory-search context. 49 * If NULL, a temporary one will be created. 50 */ 51 directory_error_t 52 directory_sid_from_name_common( 53 directory_t d, 54 char *name, 55 char *type, 56 char **sid, 57 uint64_t *classes) 58 { 59 directory_t d1 = NULL; 60 static char *attrs[] = { 61 "objectSid", 62 "objectClass", 63 NULL, 64 }; 65 directory_entry_t *ret_list = NULL; 66 directory_error_t de; 67 struct ret_sid { 68 sid_t **objectSid; 69 char **objectClass; 70 } *ret_sid; 71 72 /* Prep for error cases. */ 73 *sid = NULL; 74 if (classes != NULL) 75 *classes = 0; 76 77 if (d == NULL) { 78 de = directory_open(&d1); 79 if (de != NULL) 80 goto out; 81 } else { 82 d1 = d; 83 } 84 85 de = directory_get_v(d1, &ret_list, &name, 1, type, attrs); 86 if (de != NULL) 87 goto out; 88 if (ret_list[0].err != NULL) { 89 de = ret_list[0].err; 90 ret_list[0].err = NULL; 91 goto out; 92 } 93 94 ret_sid = (struct ret_sid *)ret_list[0].attrs; 95 if (ret_sid == NULL) 96 goto out; 97 98 if (ret_sid->objectSid != NULL && 99 ret_sid->objectSid[0] != NULL) { 100 char text_sid[SID_STRSZ+1]; 101 sid_from_le(ret_sid->objectSid[0]); 102 sid_tostr(ret_sid->objectSid[0], text_sid); 103 *sid = strdup(text_sid); 104 if (*sid == NULL) 105 goto nomem; 106 } 107 108 if (ret_sid->objectClass != NULL && 109 classes != NULL) 110 *classes = class_bitmap(ret_sid->objectClass); 111 112 goto out; 113 114 nomem: 115 de = directory_error("ENOMEM.directory_sid_from_name_common", 116 "Insufficient memory retrieving data about SID", NULL); 117 118 out: 119 directory_free(ret_list); 120 if (d == NULL) 121 directory_close(d1); 122 return (de); 123 } 124 125 directory_error_t 126 directory_sid_from_name( 127 directory_t d, 128 char *name, 129 char **sid, 130 uint64_t *classes) 131 { 132 return (directory_sid_from_name_common(d, name, DIRECTORY_ID_NAME, sid, 133 classes)); 134 } 135 136 directory_error_t 137 directory_sid_from_user_name(directory_t d, char *name, char **sid) 138 { 139 return (directory_sid_from_name_common(d, name, DIRECTORY_ID_USER, sid, 140 NULL)); 141 } 142 143 directory_error_t 144 directory_sid_from_group_name(directory_t d, char *name, char **sid) 145 { 146 return (directory_sid_from_name_common(d, name, DIRECTORY_ID_GROUP, sid, 147 NULL)); 148 } 149 150 /* 151 * Given a name or text-format SID, return a user@domain. 152 * 153 * The user@domain returned must be free()ed by the caller. 154 * 155 * Returns NULL and sets *name to NULL if no error occurred but the specified 156 * entity does not exist. 157 * 158 * d, if non-NULL, specifies an existing directory-search context. 159 * If NULL, a temporary one will be created. 160 */ 161 static 162 directory_error_t 163 directory_canon_common( 164 directory_t d, 165 char *id, 166 char *id_type, 167 char **canon, 168 uint64_t *classes) 169 { 170 directory_t d1 = NULL; 171 directory_entry_t *ret_list = NULL; 172 directory_error_t de; 173 /* 174 * Attributes required to generate a canonical name, in named-list and 175 * structure form. 176 */ 177 static char *attrs[] = { 178 "x-sun-canonicalName", 179 "objectClass", 180 NULL, 181 }; 182 183 struct canon_name_ret { 184 char **x_sun_canonicalName; 185 char **objectClass; 186 } *ret_name; 187 188 /* Prep for error cases. */ 189 *canon = NULL; 190 if (classes != NULL) 191 *classes = 0; 192 193 if (d == NULL) { 194 de = directory_open(&d1); 195 if (de != NULL) 196 goto out; 197 } else { 198 d1 = d; 199 } 200 201 de = directory_get_v(d1, &ret_list, &id, 1, id_type, attrs); 202 if (de != NULL) 203 goto out; 204 if (ret_list[0].err != NULL) { 205 de = ret_list[0].err; 206 ret_list[0].err = NULL; 207 goto out; 208 } 209 210 ret_name = (struct canon_name_ret *)ret_list[0].attrs; 211 if (ret_name == NULL) 212 goto out; 213 214 if (ret_name->x_sun_canonicalName != NULL && 215 ret_name->x_sun_canonicalName[0] != NULL) { 216 *canon = strdup(ret_name->x_sun_canonicalName[0]); 217 if (*canon == NULL) 218 goto nomem; 219 } 220 221 if (ret_name->objectClass != NULL && 222 classes != NULL) 223 *classes = class_bitmap(ret_name->objectClass); 224 225 goto out; 226 227 nomem: 228 de = directory_error("ENOMEM.directory_canon_common", 229 "Insufficient memory retrieving data about name", NULL); 230 231 out: 232 directory_free(ret_list); 233 if (d == NULL) 234 directory_close(d1); 235 return (de); 236 } 237 238 directory_error_t 239 directory_name_from_sid( 240 directory_t d, 241 char *sid, 242 char **canon, 243 uint64_t *classes) 244 { 245 return (directory_canon_common(d, sid, DIRECTORY_ID_SID, canon, 246 classes)); 247 } 248 249 directory_error_t 250 directory_canon_from_name( 251 directory_t d, 252 char *name, 253 char **canon, 254 uint64_t *classes) 255 { 256 return (directory_canon_common(d, name, DIRECTORY_ID_NAME, canon, 257 classes)); 258 } 259 260 directory_error_t 261 directory_canon_from_user_name(directory_t d, char *name, char **canon) 262 { 263 return ( 264 directory_canon_common(d, name, DIRECTORY_ID_USER, canon, NULL)); 265 } 266 267 directory_error_t 268 directory_canon_from_group_name(directory_t d, char *name, char **canon) 269 { 270 return ( 271 directory_canon_common(d, name, DIRECTORY_ID_GROUP, canon, NULL)); 272 } 273 274 boolean_t 275 is_in_list(char **list, char *val) 276 { 277 for (; *list != NULL; list++) { 278 if (uu_strcaseeq(*list, val)) 279 return (B_TRUE); 280 } 281 return (B_FALSE); 282 } 283 284 uint64_t 285 class_bitmap(char **objectClass) 286 { 287 uint64_t ret = 0; 288 289 for (; *objectClass != NULL; objectClass++) { 290 if (uu_strcaseeq(*objectClass, "user") || 291 uu_strcaseeq(*objectClass, "posixAccount")) 292 ret |= DIRECTORY_CLASS_USER; 293 294 if (uu_strcaseeq(*objectClass, "group") || 295 uu_strcaseeq(*objectClass, "posixGroup")) 296 ret |= DIRECTORY_CLASS_GROUP; 297 } 298 299 return (ret); 300 } 301