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