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