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 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * This file defines the NT domain environment values and the domain 30 * database interface. The database is a single linked list of 31 * structures containing domain type, name and SID information. 32 */ 33 34 #include <strings.h> 35 #include <unistd.h> 36 #include <netdb.h> 37 #include <syslog.h> 38 #include <synch.h> 39 40 #include <smbsrv/smbinfo.h> 41 #include <smbsrv/string.h> 42 #include <smbsrv/ntsid.h> 43 #include <smbsrv/alloc.h> 44 45 #include <smbsrv/libsmb.h> 46 47 48 static void nt_domain_unlist(nt_domain_t *); 49 50 /* 51 * Valid domain type identifiers as text. This table must be kept 52 * in step with the nt_domain_type_t enum in ntdomain.h. 53 */ 54 static char *nt_domain_type_name[NT_DOMAIN_NUM_TYPES] = { 55 "null", 56 "builtin", 57 "local", 58 "primary", 59 "account", 60 "trusted", 61 "untrusted" 62 }; 63 64 65 static rwlock_t nt_domain_lock; 66 static nt_domain_t *nt_domain_list; 67 68 /* 69 * nt_domain_init 70 * 71 * NT domain database one time initialization. This function should 72 * be called during module installation. 73 * 74 * Returns 0 on successful domain initialization. Less than zero otherwise. 75 */ 76 int 77 nt_domain_init(char *resource_domain, uint32_t secmode) 78 { 79 nt_domain_t *domain; 80 nt_sid_t *sid; 81 char *sidstr; 82 char *lsidstr; 83 char hostname[MAXHOSTNAMELEN]; 84 85 if (rwlock_init(&nt_domain_lock, USYNC_THREAD, NULL)) 86 return (SMB_DOMAIN_NODOMAIN_SID); 87 88 if (smb_gethostname(hostname, MAXHOSTNAMELEN, 1) != 0) { 89 (void) rwlock_destroy(&nt_domain_lock); 90 return (SMB_DOMAIN_NOMACHINE_SID); 91 } 92 93 lsidstr = smb_config_get_localsid(); 94 95 if (lsidstr) { 96 sid = nt_sid_strtosid(lsidstr); 97 98 if (sid) { 99 domain = nt_domain_new(NT_DOMAIN_LOCAL, hostname, sid); 100 (void) nt_domain_add(domain); 101 free(sid); 102 } 103 free(lsidstr); 104 } else { 105 (void) rwlock_destroy(&nt_domain_lock); 106 return (SMB_DOMAIN_NOMACHINE_SID); 107 } 108 109 if (secmode == SMB_SECMODE_DOMAIN) { 110 sid = nt_sid_strtosid(NT_BUILTIN_DOMAIN_SIDSTR); 111 domain = nt_domain_new(NT_DOMAIN_BUILTIN, "BUILTIN", sid); 112 (void) nt_domain_add(domain); 113 free(sid); 114 115 smb_config_rdlock(); 116 sidstr = smb_config_get(SMB_CI_DOMAIN_SID); 117 if (sidstr) { 118 sid = nt_sid_strtosid(sidstr); 119 smb_config_unlock(); 120 domain = nt_domain_new(NT_DOMAIN_PRIMARY, 121 resource_domain, sid); 122 (void) nt_domain_add(domain); 123 free(sid); 124 } else { 125 smb_config_unlock(); 126 (void) rwlock_destroy(&nt_domain_lock); 127 return (SMB_DOMAIN_NODOMAIN_SID); 128 } 129 130 } 131 return (0); 132 } 133 134 /* 135 * nt_domain_new 136 * 137 * Allocate and initialize a new domain structure. On success, a pointer to 138 * the new domain structure is returned. Otherwise a null pointer is returned. 139 */ 140 nt_domain_t * 141 nt_domain_new(nt_domain_type_t type, char *name, nt_sid_t *sid) 142 { 143 nt_domain_t *new_domain; 144 145 if ((name == NULL) || (sid == NULL)) 146 return (NULL); 147 148 if (type == NT_DOMAIN_NULL || type >= NT_DOMAIN_NUM_TYPES) 149 return (NULL); 150 151 if ((new_domain = malloc(sizeof (nt_domain_t))) == NULL) 152 return (NULL); 153 154 bzero(new_domain, sizeof (nt_domain_t)); 155 new_domain->type = type; 156 new_domain->name = strdup(name); 157 new_domain->sid = nt_sid_dup(sid); 158 159 return (new_domain); 160 } 161 162 /* 163 * nt_domain_delete 164 * 165 * Free the memory used by the specified domain structure. 166 */ 167 void 168 nt_domain_delete(nt_domain_t *domain) 169 { 170 if (domain) { 171 free(domain->name); 172 free(domain->sid); 173 free(domain); 174 } 175 } 176 177 178 /* 179 * nt_domain_add 180 * 181 * Add a domain structure to the global list. There is no checking 182 * for duplicates. If it's the primary domain, we save the SID in the 183 * environment. Returns a pointer to the new domain entry on success. 184 * Otherwise a null pointer is returned. 185 */ 186 nt_domain_t * 187 nt_domain_add(nt_domain_t *new_domain) 188 { 189 char *sidstr; 190 191 if (new_domain == NULL) 192 return (NULL); 193 194 (void) rw_wrlock(&nt_domain_lock); 195 196 new_domain->next = nt_domain_list; 197 nt_domain_list = new_domain; 198 199 if (new_domain->type == NT_DOMAIN_PRIMARY) { 200 sidstr = nt_sid_format(new_domain->sid); 201 smb_config_wrlock(); 202 (void) smb_config_set(SMB_CI_DOMAIN_SID, sidstr); 203 smb_config_unlock(); 204 free(sidstr); 205 } 206 (void) rw_unlock(&nt_domain_lock); 207 208 return (new_domain); 209 } 210 211 212 /* 213 * nt_domain_remove 214 * 215 * Remove a domain from the global list. The memory 216 * used by the structure is not freed. 217 */ 218 void 219 nt_domain_remove(nt_domain_t *domain) 220 { 221 (void) rw_wrlock(&nt_domain_lock); 222 nt_domain_unlist(domain); 223 (void) rw_unlock(&nt_domain_lock); 224 } 225 226 227 /* 228 * nt_domain_flush 229 * 230 * Flush all domains of the specified type from the list. This is 231 * useful for things like updating the list of trusted domains. 232 */ 233 void 234 nt_domain_flush(nt_domain_type_t domain_type) 235 { 236 nt_domain_t *domain = nt_domain_list; 237 238 (void) rw_wrlock(&nt_domain_lock); 239 while (domain) { 240 if (domain->type == domain_type) { 241 nt_domain_unlist(domain); 242 nt_domain_delete(domain); 243 domain = nt_domain_list; 244 continue; 245 } 246 domain = domain->next; 247 } 248 (void) rw_unlock(&nt_domain_lock); 249 } 250 251 /* 252 * nt_domain_xlat_type 253 * 254 * Translate a domain type into a text string. 255 */ 256 char * 257 nt_domain_xlat_type(nt_domain_type_t domain_type) 258 { 259 if (domain_type < NT_DOMAIN_NUM_TYPES) 260 return (nt_domain_type_name[domain_type]); 261 else 262 return ("unknown"); 263 } 264 265 266 /* 267 * nt_domain_xlat_type_name 268 * 269 * Translate a domain type test string into a domain type. 270 */ 271 nt_domain_type_t 272 nt_domain_xlat_type_name(char *type_name) 273 { 274 int i; 275 276 for (i = 0; i < NT_DOMAIN_NUM_TYPES; ++i) 277 if (utf8_strcasecmp(nt_domain_type_name[i], type_name) == 0) 278 return (i); 279 280 return (NT_DOMAIN_NUM_TYPES); 281 } 282 283 284 /* 285 * nt_domain_lookup_name 286 * 287 * Lookup a domain by its domain name. If the domain is in the list, 288 * a pointer to it is returned. Otherwise a null pointer is returned. 289 */ 290 nt_domain_t * 291 nt_domain_lookup_name(char *domain_name) 292 { 293 nt_domain_t *domain = nt_domain_list; 294 295 (void) rw_rdlock(&nt_domain_lock); 296 while (domain) { 297 if (utf8_strcasecmp(domain->name, domain_name) == 0) 298 break; 299 300 domain = domain->next; 301 } 302 (void) rw_unlock(&nt_domain_lock); 303 304 return (domain); 305 } 306 307 308 /* 309 * nt_domain_lookup_sid 310 * 311 * Lookup a domain by its domain SID. If the domain is in the list, 312 * a pointer to it is returned. Otherwise a null pointer is returned. 313 */ 314 nt_domain_t * 315 nt_domain_lookup_sid(nt_sid_t *domain_sid) 316 { 317 nt_domain_t *domain = nt_domain_list; 318 319 (void) rw_rdlock(&nt_domain_lock); 320 while (domain) { 321 if (nt_sid_is_equal(domain->sid, domain_sid)) 322 break; 323 324 domain = domain->next; 325 } 326 (void) rw_unlock(&nt_domain_lock); 327 328 return (domain); 329 } 330 331 332 /* 333 * nt_domain_lookupbytype 334 * 335 * Lookup a domain by its type. The first matching entry in the list 336 * is returned. Otherwise a null pointer is returned. 337 */ 338 nt_domain_t * 339 nt_domain_lookupbytype(nt_domain_type_t type) 340 { 341 nt_domain_t *domain = nt_domain_list; 342 343 (void) rw_rdlock(&nt_domain_lock); 344 while (domain) { 345 if (domain->type == type) 346 break; 347 348 domain = domain->next; 349 } 350 (void) rw_unlock(&nt_domain_lock); 351 352 return (domain); 353 } 354 355 356 /* 357 * nt_domain_local_sid 358 * 359 * Return a pointer to the local domain SID. Each system has a SID that 360 * represents the local domain, which is named after the local hostname. 361 * The local domain SID must exist. 362 */ 363 nt_sid_t * 364 nt_domain_local_sid(void) 365 { 366 nt_domain_t *domain = nt_domain_list; 367 368 (void) rw_rdlock(&nt_domain_lock); 369 while (domain) { 370 if (domain->type == NT_DOMAIN_LOCAL) 371 break; 372 373 domain = domain->next; 374 } 375 (void) rw_unlock(&nt_domain_lock); 376 377 return (domain->sid); 378 } 379 380 381 static void 382 nt_domain_unlist(nt_domain_t *domain) 383 { 384 nt_domain_t **ppdomain = &nt_domain_list; 385 386 while (*ppdomain) { 387 if (*ppdomain == domain) { 388 *ppdomain = domain->next; 389 domain->next = NULL; 390 return; 391 } 392 ppdomain = &(*ppdomain)->next; 393 } 394 } 395