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 2009 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 <sys/types.h> 33 #include <sys/stat.h> 34 #include <stdio.h> 35 #include <strings.h> 36 #include <string.h> 37 #include <unistd.h> 38 #include <stdlib.h> 39 #include <netdb.h> 40 #include <syslog.h> 41 #include <synch.h> 42 #include <pwd.h> 43 #include <grp.h> 44 45 #include <smbsrv/smbinfo.h> 46 #include <smbsrv/string.h> 47 #include <smbsrv/smb_sid.h> 48 #include <smbsrv/libsmb.h> 49 50 #define SMB_DOMAINS_FILE "domains" 51 52 static void nt_domain_unlist(nt_domain_t *); 53 54 /* 55 * Valid domain type identifiers as text. This table must be kept 56 * in step with the nt_domain_type_t enum in ntdomain.h. 57 */ 58 static char *nt_domain_type_name[NT_DOMAIN_NUM_TYPES] = { 59 "null", 60 "builtin", 61 "local", 62 "primary", 63 "account", 64 "trusted", 65 "untrusted" 66 }; 67 68 69 static rwlock_t nt_domain_lock; 70 static nt_domain_t *nt_domain_list; 71 72 /* 73 * nt_domain_init 74 * 75 * NT domain database one time initialization. This function should 76 * be called during module installation. 77 * 78 * Returns 0 on successful domain initialization. Less than zero otherwise. 79 */ 80 int 81 nt_domain_init(char *resource_domain, uint32_t secmode) 82 { 83 nt_domain_t *domain; 84 smb_sid_t *sid = NULL; 85 char sidstr[128]; 86 char *lsidstr; 87 char hostname[NETBIOS_NAME_SZ]; 88 int rc; 89 90 if (rwlock_init(&nt_domain_lock, USYNC_THREAD, NULL)) 91 return (SMB_DOMAIN_NODOMAIN_SID); 92 93 if (smb_getnetbiosname(hostname, NETBIOS_NAME_SZ) != 0) { 94 (void) rwlock_destroy(&nt_domain_lock); 95 return (SMB_DOMAIN_NOMACHINE_SID); 96 } 97 98 lsidstr = smb_config_get_localsid(); 99 100 if (lsidstr) { 101 sid = smb_sid_fromstr(lsidstr); 102 103 if (sid) { 104 domain = nt_domain_new(NT_DOMAIN_LOCAL, hostname, sid); 105 (void) nt_domain_add(domain); 106 free(sid); 107 } 108 free(lsidstr); 109 } else { 110 (void) rwlock_destroy(&nt_domain_lock); 111 return (SMB_DOMAIN_NOMACHINE_SID); 112 } 113 114 if ((sid = smb_sid_fromstr(NT_BUILTIN_DOMAIN_SIDSTR)) != NULL) { 115 domain = nt_domain_new(NT_DOMAIN_BUILTIN, "BUILTIN", sid); 116 (void) nt_domain_add(domain); 117 free(sid); 118 } 119 120 if (secmode == SMB_SECMODE_DOMAIN) { 121 rc = smb_config_getstr(SMB_CI_DOMAIN_SID, sidstr, 122 sizeof (sidstr)); 123 sid = (rc == SMBD_SMF_OK) ? smb_sid_fromstr(sidstr) : NULL; 124 if (smb_sid_isvalid(sid)) { 125 domain = nt_domain_new(NT_DOMAIN_PRIMARY, 126 resource_domain, sid); 127 (void) nt_domain_add(domain); 128 free(sid); 129 } else { 130 free(sid); 131 (void) rwlock_destroy(&nt_domain_lock); 132 return (SMB_DOMAIN_NODOMAIN_SID); 133 } 134 135 } 136 137 return (0); 138 } 139 140 /* 141 * nt_domain_new 142 * 143 * Allocate and initialize a new domain structure. On success, a pointer to 144 * the new domain structure is returned. Otherwise a null pointer is returned. 145 */ 146 nt_domain_t * 147 nt_domain_new(nt_domain_type_t type, char *name, smb_sid_t *sid) 148 { 149 nt_domain_t *new_domain; 150 151 if ((name == NULL) || (sid == NULL)) 152 return (NULL); 153 154 if (type == NT_DOMAIN_NULL || type >= NT_DOMAIN_NUM_TYPES) 155 return (NULL); 156 157 if ((new_domain = malloc(sizeof (nt_domain_t))) == NULL) 158 return (NULL); 159 160 bzero(new_domain, sizeof (nt_domain_t)); 161 new_domain->type = type; 162 new_domain->name = strdup(name); 163 new_domain->sid = smb_sid_dup(sid); 164 165 return (new_domain); 166 } 167 168 /* 169 * nt_domain_delete 170 * 171 * Free the memory used by the specified domain structure. 172 */ 173 void 174 nt_domain_delete(nt_domain_t *domain) 175 { 176 if (domain) { 177 free(domain->name); 178 free(domain->sid); 179 free(domain); 180 } 181 } 182 183 184 /* 185 * nt_domain_add 186 * 187 * Add a domain structure to the global list. There is no checking 188 * for duplicates. If it's the primary domain, we save the SID in the 189 * environment. Returns a pointer to the new domain entry on success. 190 * Otherwise a null pointer is returned. 191 */ 192 nt_domain_t * 193 nt_domain_add(nt_domain_t *new_domain) 194 { 195 char sidstr[SMB_SID_STRSZ]; 196 197 if (new_domain == NULL) 198 return (NULL); 199 200 (void) rw_wrlock(&nt_domain_lock); 201 202 new_domain->next = nt_domain_list; 203 nt_domain_list = new_domain; 204 205 if (new_domain->type == NT_DOMAIN_PRIMARY) { 206 smb_sid_tostr(new_domain->sid, sidstr); 207 (void) smb_config_setstr(SMB_CI_DOMAIN_SID, sidstr); 208 } 209 (void) rw_unlock(&nt_domain_lock); 210 211 return (new_domain); 212 } 213 214 215 /* 216 * nt_domain_remove 217 * 218 * Remove a domain from the global list. The memory 219 * used by the structure is not freed. 220 */ 221 void 222 nt_domain_remove(nt_domain_t *domain) 223 { 224 (void) rw_wrlock(&nt_domain_lock); 225 nt_domain_unlist(domain); 226 (void) rw_unlock(&nt_domain_lock); 227 } 228 229 230 /* 231 * nt_domain_flush 232 * 233 * Flush all domains of the specified type from the list. This is 234 * useful for things like updating the list of trusted domains. 235 */ 236 void 237 nt_domain_flush(nt_domain_type_t domain_type) 238 { 239 nt_domain_t *domain = nt_domain_list; 240 241 (void) rw_wrlock(&nt_domain_lock); 242 while (domain) { 243 if (domain->type == domain_type) { 244 nt_domain_unlist(domain); 245 nt_domain_delete(domain); 246 domain = nt_domain_list; 247 continue; 248 } 249 domain = domain->next; 250 } 251 (void) rw_unlock(&nt_domain_lock); 252 } 253 254 /* 255 * nt_domain_xlat_type 256 * 257 * Translate a domain type into a text string. 258 */ 259 char * 260 nt_domain_xlat_type(nt_domain_type_t domain_type) 261 { 262 if (domain_type < NT_DOMAIN_NUM_TYPES) 263 return (nt_domain_type_name[domain_type]); 264 else 265 return ("unknown"); 266 } 267 268 269 /* 270 * nt_domain_xlat_type_name 271 * 272 * Translate a domain type test string into a domain type. 273 */ 274 nt_domain_type_t 275 nt_domain_xlat_type_name(char *type_name) 276 { 277 int i; 278 279 for (i = 0; i < NT_DOMAIN_NUM_TYPES; ++i) 280 if (utf8_strcasecmp(nt_domain_type_name[i], type_name) == 0) 281 return (i); 282 283 return (NT_DOMAIN_NUM_TYPES); 284 } 285 286 287 /* 288 * nt_domain_lookup_name 289 * 290 * Lookup a domain by its domain name. If the domain is in the list, 291 * a pointer to it is returned. Otherwise a null pointer is returned. 292 */ 293 nt_domain_t * 294 nt_domain_lookup_name(char *domain_name) 295 { 296 nt_domain_t *domain = nt_domain_list; 297 298 (void) rw_rdlock(&nt_domain_lock); 299 while (domain) { 300 if (utf8_strcasecmp(domain->name, domain_name) == 0) 301 break; 302 303 domain = domain->next; 304 } 305 (void) rw_unlock(&nt_domain_lock); 306 307 return (domain); 308 } 309 310 311 /* 312 * nt_domain_lookup_sid 313 * 314 * Lookup a domain by its domain SID. If the domain is in the list, 315 * a pointer to it is returned. Otherwise a null pointer is returned. 316 */ 317 nt_domain_t * 318 nt_domain_lookup_sid(smb_sid_t *domain_sid) 319 { 320 nt_domain_t *domain = nt_domain_list; 321 322 (void) rw_rdlock(&nt_domain_lock); 323 while (domain) { 324 if (smb_sid_cmp(domain->sid, domain_sid)) 325 break; 326 327 domain = domain->next; 328 } 329 (void) rw_unlock(&nt_domain_lock); 330 331 return (domain); 332 } 333 334 335 /* 336 * nt_domain_lookupbytype 337 * 338 * Lookup a domain by its type. The first matching entry in the list 339 * is returned. Otherwise a null pointer is returned. 340 */ 341 nt_domain_t * 342 nt_domain_lookupbytype(nt_domain_type_t type) 343 { 344 nt_domain_t *domain = nt_domain_list; 345 346 (void) rw_rdlock(&nt_domain_lock); 347 while (domain) { 348 if (domain->type == type) 349 break; 350 351 domain = domain->next; 352 } 353 (void) rw_unlock(&nt_domain_lock); 354 355 return (domain); 356 } 357 358 359 /* 360 * nt_domain_local_sid 361 * 362 * Return a pointer to the local domain SID. Each system has a SID that 363 * represents the local domain, which is named after the local hostname. 364 * The local domain SID must exist. 365 */ 366 smb_sid_t * 367 nt_domain_local_sid(void) 368 { 369 nt_domain_t *domain = nt_domain_list; 370 371 (void) rw_rdlock(&nt_domain_lock); 372 while (domain) { 373 if (domain->type == NT_DOMAIN_LOCAL) 374 break; 375 376 domain = domain->next; 377 } 378 (void) rw_unlock(&nt_domain_lock); 379 380 return (domain->sid); 381 } 382 383 384 static void 385 nt_domain_unlist(nt_domain_t *domain) 386 { 387 nt_domain_t **ppdomain = &nt_domain_list; 388 389 while (*ppdomain) { 390 if (*ppdomain == domain) { 391 *ppdomain = domain->next; 392 domain->next = NULL; 393 return; 394 } 395 ppdomain = &(*ppdomain)->next; 396 } 397 } 398 399 /* 400 * Write the list of domains to /var/run/smb/domains. 401 */ 402 void 403 nt_domain_save(void) 404 { 405 char fname[MAXPATHLEN]; 406 char sidstr[SMB_SID_STRSZ]; 407 char tag; 408 nt_domain_t *domain; 409 FILE *fp; 410 struct passwd *pwd; 411 struct group *grp; 412 uid_t uid; 413 gid_t gid; 414 415 (void) snprintf(fname, MAXPATHLEN, "%s/%s", 416 SMB_VARRUN_DIR, SMB_DOMAINS_FILE); 417 418 if ((fp = fopen(fname, "w")) == NULL) 419 return; 420 421 pwd = getpwnam("root"); 422 grp = getgrnam("sys"); 423 uid = (pwd == NULL) ? 0 : pwd->pw_uid; 424 gid = (grp == NULL) ? 3 : grp->gr_gid; 425 426 (void) lockf(fileno(fp), F_LOCK, 0); 427 (void) fchmod(fileno(fp), 0600); 428 (void) fchown(fileno(fp), uid, gid); 429 430 (void) rw_rdlock(&nt_domain_lock); 431 432 domain = nt_domain_list; 433 while (domain) { 434 smb_sid_tostr(domain->sid, sidstr); 435 switch (domain->type) { 436 case NT_DOMAIN_PRIMARY: 437 tag = '*'; 438 break; 439 440 case NT_DOMAIN_TRUSTED: 441 case NT_DOMAIN_UNTRUSTED: 442 tag = '-'; 443 break; 444 445 case NT_DOMAIN_LOCAL: 446 tag = '.'; 447 break; 448 default: 449 domain = domain->next; 450 continue; 451 } 452 453 (void) fprintf(fp, "[%c] [%s] [%s]\n", 454 tag, domain->name, sidstr); 455 456 domain = domain->next; 457 } 458 459 (void) rw_unlock(&nt_domain_lock); 460 (void) lockf(fileno(fp), F_ULOCK, 0); 461 (void) fclose(fp); 462 } 463 464 /* 465 * List the domains in /var/run/smb/domains. 466 */ 467 void 468 nt_domain_show(void) 469 { 470 char buf[MAXPATHLEN]; 471 char *p; 472 FILE *fp; 473 474 (void) snprintf(buf, MAXPATHLEN, "%s/%s", 475 SMB_VARRUN_DIR, SMB_DOMAINS_FILE); 476 477 if ((fp = fopen(buf, "r")) != NULL) { 478 (void) lockf(fileno(fp), F_LOCK, 0); 479 480 while (fgets(buf, MAXPATHLEN, fp) != NULL) { 481 if ((p = strchr(buf, '\n')) != NULL) 482 *p = '\0'; 483 (void) printf("%s\n", buf); 484 } 485 486 (void) lockf(fileno(fp), F_ULOCK, 0); 487 (void) fclose(fp); 488 } 489 } 490 491 /* 492 * Remove the /var/run/smb/domains file. 493 */ 494 void 495 nt_domain_unlink(void) 496 { 497 char fname[MAXPATHLEN]; 498 499 (void) snprintf(fname, MAXPATHLEN, "%s/%s", 500 SMB_VARRUN_DIR, SMB_DOMAINS_FILE); 501 (void) unlink(fname); 502 } 503