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 char nbname[MAXHOSTNAMELEN]; 297 nt_domain_t *domain = nt_domain_list; 298 char *p; 299 300 if (domain_name == NULL || *domain_name == '\0') 301 return (NULL); 302 303 (void) strlcpy(nbname, domain_name, sizeof (nbname)); 304 if ((p = strchr(nbname, '.')) != NULL) 305 *p = '\0'; 306 307 (void) rw_rdlock(&nt_domain_lock); 308 while (domain) { 309 if (utf8_strcasecmp(domain->name, nbname) == 0) 310 break; 311 312 domain = domain->next; 313 } 314 (void) rw_unlock(&nt_domain_lock); 315 316 return (domain); 317 } 318 319 320 /* 321 * nt_domain_lookup_sid 322 * 323 * Lookup a domain by its domain SID. If the domain is in the list, 324 * a pointer to it is returned. Otherwise a null pointer is returned. 325 */ 326 nt_domain_t * 327 nt_domain_lookup_sid(smb_sid_t *domain_sid) 328 { 329 nt_domain_t *domain = nt_domain_list; 330 331 (void) rw_rdlock(&nt_domain_lock); 332 while (domain) { 333 if (smb_sid_cmp(domain->sid, domain_sid)) 334 break; 335 336 domain = domain->next; 337 } 338 (void) rw_unlock(&nt_domain_lock); 339 340 return (domain); 341 } 342 343 344 /* 345 * nt_domain_lookupbytype 346 * 347 * Lookup a domain by its type. The first matching entry in the list 348 * is returned. Otherwise a null pointer is returned. 349 */ 350 nt_domain_t * 351 nt_domain_lookupbytype(nt_domain_type_t type) 352 { 353 nt_domain_t *domain = nt_domain_list; 354 355 (void) rw_rdlock(&nt_domain_lock); 356 while (domain) { 357 if (domain->type == type) 358 break; 359 360 domain = domain->next; 361 } 362 (void) rw_unlock(&nt_domain_lock); 363 364 return (domain); 365 } 366 367 368 /* 369 * nt_domain_local_sid 370 * 371 * Return a pointer to the local domain SID. Each system has a SID that 372 * represents the local domain, which is named after the local hostname. 373 * The local domain SID must exist. 374 */ 375 smb_sid_t * 376 nt_domain_local_sid(void) 377 { 378 nt_domain_t *domain = nt_domain_list; 379 380 (void) rw_rdlock(&nt_domain_lock); 381 while (domain) { 382 if (domain->type == NT_DOMAIN_LOCAL) 383 break; 384 385 domain = domain->next; 386 } 387 (void) rw_unlock(&nt_domain_lock); 388 389 return (domain->sid); 390 } 391 392 393 static void 394 nt_domain_unlist(nt_domain_t *domain) 395 { 396 nt_domain_t **ppdomain = &nt_domain_list; 397 398 while (*ppdomain) { 399 if (*ppdomain == domain) { 400 *ppdomain = domain->next; 401 domain->next = NULL; 402 return; 403 } 404 ppdomain = &(*ppdomain)->next; 405 } 406 } 407 408 /* 409 * Write the list of domains to /var/run/smb/domains. 410 */ 411 void 412 nt_domain_save(void) 413 { 414 char fname[MAXPATHLEN]; 415 char sidstr[SMB_SID_STRSZ]; 416 char tag; 417 nt_domain_t *domain; 418 FILE *fp; 419 struct passwd *pwd; 420 struct group *grp; 421 uid_t uid; 422 gid_t gid; 423 424 (void) snprintf(fname, MAXPATHLEN, "%s/%s", 425 SMB_VARRUN_DIR, SMB_DOMAINS_FILE); 426 427 if ((fp = fopen(fname, "w")) == NULL) 428 return; 429 430 pwd = getpwnam("root"); 431 grp = getgrnam("sys"); 432 uid = (pwd == NULL) ? 0 : pwd->pw_uid; 433 gid = (grp == NULL) ? 3 : grp->gr_gid; 434 435 (void) lockf(fileno(fp), F_LOCK, 0); 436 (void) fchmod(fileno(fp), 0600); 437 (void) fchown(fileno(fp), uid, gid); 438 439 (void) rw_rdlock(&nt_domain_lock); 440 441 domain = nt_domain_list; 442 while (domain) { 443 smb_sid_tostr(domain->sid, sidstr); 444 switch (domain->type) { 445 case NT_DOMAIN_PRIMARY: 446 tag = '*'; 447 break; 448 449 case NT_DOMAIN_TRUSTED: 450 case NT_DOMAIN_UNTRUSTED: 451 tag = '-'; 452 break; 453 454 case NT_DOMAIN_LOCAL: 455 tag = '.'; 456 break; 457 default: 458 domain = domain->next; 459 continue; 460 } 461 462 (void) fprintf(fp, "[%c] [%s] [%s]\n", 463 tag, domain->name, sidstr); 464 465 domain = domain->next; 466 } 467 468 (void) rw_unlock(&nt_domain_lock); 469 (void) lockf(fileno(fp), F_ULOCK, 0); 470 (void) fclose(fp); 471 } 472 473 /* 474 * List the domains in /var/run/smb/domains. 475 */ 476 void 477 nt_domain_show(void) 478 { 479 char buf[MAXPATHLEN]; 480 char *p; 481 FILE *fp; 482 483 (void) snprintf(buf, MAXPATHLEN, "%s/%s", 484 SMB_VARRUN_DIR, SMB_DOMAINS_FILE); 485 486 if ((fp = fopen(buf, "r")) != NULL) { 487 (void) lockf(fileno(fp), F_LOCK, 0); 488 489 while (fgets(buf, MAXPATHLEN, fp) != NULL) { 490 if ((p = strchr(buf, '\n')) != NULL) 491 *p = '\0'; 492 (void) printf("%s\n", buf); 493 } 494 495 (void) lockf(fileno(fp), F_ULOCK, 0); 496 (void) fclose(fp); 497 } 498 } 499 500 /* 501 * Remove the /var/run/smb/domains file. 502 */ 503 void 504 nt_domain_unlink(void) 505 { 506 char fname[MAXPATHLEN]; 507 508 (void) snprintf(fname, MAXPATHLEN, "%s/%s", 509 SMB_VARRUN_DIR, SMB_DOMAINS_FILE); 510 (void) unlink(fname); 511 } 512