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 #include <stdlib.h> 29 #include <unistd.h> 30 #include <limits.h> 31 #include <strings.h> 32 #include <synch.h> 33 #include <errno.h> 34 #include <sys/types.h> 35 #include <sys/stat.h> 36 #include <sys/avl.h> 37 #include <fcntl.h> 38 #include <thread.h> 39 #include <pwd.h> 40 #include <dlfcn.h> 41 #include <link.h> 42 #include <assert.h> 43 #include <smbsrv/libsmb.h> 44 45 #define SMB_PASSWD "/var/smb/smbpasswd" 46 #define SMB_OPASSWD "/var/smb/osmbpasswd" 47 #define SMB_PASSTEMP "/var/smb/ptmp" 48 #define SMB_PASSLCK "/var/smb/.pwd.lock" 49 50 #define SMB_LIB_ALT "/usr/lib/smbsrv/libsmb_pwd.so" 51 52 #define SMB_PWD_DISABLE "*DIS*" 53 #define SMB_PWD_BUFSIZE 256 54 55 #define S_WAITTIME 15 56 57 typedef enum { 58 SMB_PWD_NAME = 0, 59 SMB_PWD_UID, 60 SMB_PWD_LMHASH, 61 SMB_PWD_NTHASH, 62 SMB_PWD_NARG 63 } smb_pwdarg_t; 64 65 static struct flock flock = { 0, 0, 0, 0, 0, 0 }; 66 static pid_t lck_pid = 0; /* process's pid at last lock */ 67 static thread_t lck_tid = 0; /* thread that holds the lock */ 68 static int fildes = -1; 69 static mutex_t lck_lock = DEFAULTMUTEX; 70 static void *smb_pwd_hdl = NULL; 71 72 static struct { 73 smb_passwd_t *(*pwop_getpasswd)(const char *, smb_passwd_t *); 74 int (*pwop_setcntl)(const char *, int); 75 int (*pwop_setpasswd)(const char *, const char *); 76 int (*pwop_num)(void); 77 int (*pwop_iteropen)(smb_pwditer_t *); 78 smb_luser_t *(*pwop_iterate)(smb_pwditer_t *); 79 void (*pwop_iterclose)(smb_pwditer_t *); 80 } smb_pwd_ops; 81 82 static int smb_pwd_lock(void); 83 static int smb_pwd_unlock(void); 84 static int smb_pwd_flck(void); 85 static int smb_pwd_fulck(void); 86 87 /* 88 * buffer structure used by smb_pwd_fgetent/smb_pwd_fputent 89 */ 90 typedef struct smb_pwbuf { 91 char pw_buf[SMB_PWD_BUFSIZE]; 92 char *pw_name; 93 smb_passwd_t *pw_pwd; 94 } smb_pwbuf_t; 95 96 /* 97 * flag values used with smb_pwd_fgetent 98 */ 99 #define SMB_PWD_GETF_ALL 1 /* get all the account info */ 100 #define SMB_PWD_GETF_NOPWD 2 /* password is not needed */ 101 102 static smb_pwbuf_t *smb_pwd_fgetent(FILE *, smb_pwbuf_t *, uint32_t); 103 static int smb_pwd_fputent(FILE *, smb_pwbuf_t *); 104 static int smb_pwd_chgpwent(smb_passwd_t *, const char *, int); 105 static int smb_pwd_update(const char *, const char *, int); 106 107 /* 108 * Local Users Cache 109 * 110 * Simplifying assumptions 111 * 112 * o smbpasswd is a service private file and shouldn't be edited manually 113 * o accounts are only added/modified via passwd and/or smbadm CLIs 114 * o accounts are not removed but disabled using smbadm CLI 115 * o editing smbpasswd manually might result in cache inconsistency 116 * 117 * Cache is created and populated upon service startup. 118 * Cache is updated each time users list is requested if there's been 119 * any change in smbpasswd file. The change criteria is smbpasswd's 120 * modification timestamp. 121 */ 122 123 /* 124 * User cache handle 125 */ 126 typedef struct smb_uchandle { 127 avl_tree_t uc_cache; 128 rwlock_t uc_cache_lck; 129 timestruc_t uc_timestamp; 130 uint32_t uc_refcnt; 131 uint32_t uc_state; 132 mutex_t uc_mtx; 133 cond_t uc_cv; 134 } smb_uchandle_t; 135 136 #define SMB_UCHS_NOCACHE 0 137 #define SMB_UCHS_CREATED 1 138 #define SMB_UCHS_UPDATING 2 139 #define SMB_UCHS_UPDATED 3 140 #define SMB_UCHS_DESTROYING 4 141 142 /* 143 * User cache node 144 */ 145 typedef struct smb_ucnode { 146 smb_luser_t cn_user; 147 avl_node_t cn_link; 148 } smb_ucnode_t; 149 150 static void smb_lucache_create(void); 151 static void smb_lucache_destroy(void); 152 static void smb_lucache_update(void); 153 static int smb_lucache_num(void); 154 static int smb_lucache_lock(void); 155 static void smb_lucache_unlock(void); 156 static int smb_lucache_do_update(void); 157 static void smb_lucache_flush(void); 158 159 static smb_uchandle_t smb_uch; 160 161 /* 162 * smb_pwd_init 163 * 164 * Initializes the cache if requested. 165 * Checks to see if a password management utility library 166 * is interposed. If yes then it'll initializes smb_pwd_ops 167 * structure with function pointers from this library. 168 */ 169 void 170 smb_pwd_init(boolean_t create_cache) 171 { 172 if (create_cache) { 173 smb_lucache_create(); 174 smb_lucache_update(); 175 } 176 177 smb_pwd_hdl = dlopen(SMB_LIB_ALT, RTLD_NOW | RTLD_LOCAL); 178 if (smb_pwd_hdl == NULL) { 179 /* No library is interposed */ 180 return; 181 } 182 183 bzero((void *)&smb_pwd_ops, sizeof (smb_pwd_ops)); 184 185 smb_pwd_ops.pwop_getpasswd = 186 (smb_passwd_t *(*)())dlsym(smb_pwd_hdl, "smb_pwd_getpasswd"); 187 188 smb_pwd_ops.pwop_setcntl = 189 (int (*)())dlsym(smb_pwd_hdl, "smb_pwd_setcntl"); 190 191 smb_pwd_ops.pwop_setpasswd = 192 (int (*)())dlsym(smb_pwd_hdl, "smb_pwd_setpasswd"); 193 194 smb_pwd_ops.pwop_num = 195 (int (*)())dlsym(smb_pwd_hdl, "smb_pwd_num"); 196 197 smb_pwd_ops.pwop_iteropen = 198 (int (*)())dlsym(smb_pwd_hdl, "smb_pwd_iteropen"); 199 200 smb_pwd_ops.pwop_iterclose = 201 (void (*)())dlsym(smb_pwd_hdl, "smb_pwd_iterclose"); 202 203 smb_pwd_ops.pwop_iterate = 204 (smb_luser_t *(*)())dlsym(smb_pwd_hdl, "smb_pwd_iterate"); 205 206 if (smb_pwd_ops.pwop_getpasswd == NULL || 207 smb_pwd_ops.pwop_setcntl == NULL || 208 smb_pwd_ops.pwop_setpasswd == NULL || 209 smb_pwd_ops.pwop_num == NULL || 210 smb_pwd_ops.pwop_iteropen == NULL || 211 smb_pwd_ops.pwop_iterclose == NULL || 212 smb_pwd_ops.pwop_iterate == NULL) { 213 (void) dlclose(smb_pwd_hdl); 214 smb_pwd_hdl = NULL; 215 216 /* If error or function(s) are missing, use original lib */ 217 bzero((void *)&smb_pwd_ops, sizeof (smb_pwd_ops)); 218 } 219 } 220 221 /* 222 * smb_pwd_fini 223 * 224 * Destroys the cache. 225 * Closes interposed library. 226 */ 227 void 228 smb_pwd_fini(void) 229 { 230 smb_lucache_destroy(); 231 232 if (smb_pwd_hdl) { 233 (void) dlclose(smb_pwd_hdl); 234 smb_pwd_hdl = NULL; 235 } 236 } 237 238 /* 239 * smb_pwd_getpasswd 240 * 241 * Returns a smb password structure for the given user name. 242 * smbpw is a pointer to a buffer allocated by the caller. 243 * 244 * Returns NULL upon failure. 245 */ 246 smb_passwd_t * 247 smb_pwd_getpasswd(const char *name, smb_passwd_t *smbpw) 248 { 249 boolean_t found = B_FALSE; 250 smb_pwbuf_t pwbuf; 251 FILE *fp; 252 int err; 253 254 if (smb_pwd_ops.pwop_getpasswd != NULL) 255 return (smb_pwd_ops.pwop_getpasswd(name, smbpw)); 256 257 err = smb_pwd_lock(); 258 if (err != SMB_PWE_SUCCESS) 259 return (NULL); 260 261 if ((fp = fopen(SMB_PASSWD, "rF")) == NULL) { 262 (void) smb_pwd_unlock(); 263 return (NULL); 264 } 265 266 pwbuf.pw_name = NULL; 267 pwbuf.pw_pwd = smbpw; 268 269 while (smb_pwd_fgetent(fp, &pwbuf, SMB_PWD_GETF_ALL) != NULL) { 270 if (strcmp(name, pwbuf.pw_name) == 0) { 271 if ((smbpw->pw_flags & (SMB_PWF_LM | SMB_PWF_NT))) 272 found = B_TRUE; 273 break; 274 } 275 } 276 277 (void) fclose(fp); 278 (void) smb_pwd_unlock(); 279 280 if (!found) { 281 bzero(smbpw, sizeof (smb_passwd_t)); 282 return (NULL); 283 } 284 285 return (smbpw); 286 } 287 288 /* 289 * smb_pwd_setpasswd 290 * 291 * Update/add the given user to the smbpasswd file. 292 */ 293 int 294 smb_pwd_setpasswd(const char *name, const char *password) 295 { 296 if (smb_pwd_ops.pwop_setpasswd != NULL) 297 return (smb_pwd_ops.pwop_setpasswd(name, password)); 298 299 return (smb_pwd_update(name, password, 0)); 300 } 301 302 /* 303 * smb_pwd_setcntl 304 * 305 * Change the account state. This can be making the account 306 * disable/enable or removing its LM hash. 307 */ 308 int 309 smb_pwd_setcntl(const char *name, int control) 310 { 311 if (smb_pwd_ops.pwop_setcntl != NULL) 312 return (smb_pwd_ops.pwop_setcntl(name, control)); 313 314 if (control == 0) 315 return (SMB_PWE_SUCCESS); 316 317 return (smb_pwd_update(name, NULL, control)); 318 } 319 320 /* 321 * smb_pwd_num 322 * 323 * Returns the number of cached local users 324 */ 325 int 326 smb_pwd_num(void) 327 { 328 if (smb_pwd_ops.pwop_num != NULL) 329 return (smb_pwd_ops.pwop_num()); 330 331 return (smb_lucache_num()); 332 } 333 334 /* 335 * smb_pwd_iteropen 336 * 337 * Initalizes the given iterator handle. 338 * This handle will be used to iterate the users cache 339 * by the caller. The cache will be locked for read and it 340 * will remain locked until smb_pwd_iterclose() is called. 341 */ 342 int 343 smb_pwd_iteropen(smb_pwditer_t *iter) 344 { 345 if (iter == NULL) 346 return (SMB_PWE_INVALID_PARAM); 347 348 if (smb_pwd_ops.pwop_iteropen != NULL) 349 return (smb_pwd_ops.pwop_iteropen(iter)); 350 351 iter->spi_next = NULL; 352 353 smb_lucache_update(); 354 355 return (smb_lucache_lock()); 356 } 357 358 /* 359 * smb_pwd_iterate 360 * 361 * Scans through users cache using the given iterator 362 */ 363 smb_luser_t * 364 smb_pwd_iterate(smb_pwditer_t *iter) 365 { 366 smb_ucnode_t *ucnode; 367 368 if (iter == NULL) 369 return (NULL); 370 371 if (smb_pwd_ops.pwop_iterate != NULL) 372 return (smb_pwd_ops.pwop_iterate(iter)); 373 374 if (iter->spi_next == NULL) 375 ucnode = avl_first(&smb_uch.uc_cache); 376 else 377 ucnode = AVL_NEXT(&smb_uch.uc_cache, iter->spi_next); 378 379 if ((iter->spi_next = ucnode) != NULL) 380 return (&ucnode->cn_user); 381 382 return (NULL); 383 } 384 385 /* 386 * smb_pwd_iterclose 387 * 388 * Closes the given iterator. Effectively it only unlocks the cache 389 */ 390 void 391 smb_pwd_iterclose(smb_pwditer_t *iter) 392 { 393 if (smb_pwd_ops.pwop_iterclose != NULL) { 394 smb_pwd_ops.pwop_iterclose(iter); 395 return; 396 } 397 398 if (iter != NULL) 399 smb_lucache_unlock(); 400 } 401 402 /* 403 * smb_pwd_update 404 * 405 * Updates the password entry of the given user if the user already 406 * has an entry, otherwise it'll add an entry for the user with 407 * given password and control information. 408 */ 409 static int 410 smb_pwd_update(const char *name, const char *password, int control) 411 { 412 struct stat64 stbuf; 413 FILE *src, *dst; 414 int tempfd; 415 int err = SMB_PWE_SUCCESS; 416 smb_pwbuf_t pwbuf; 417 smb_passwd_t smbpw; 418 boolean_t newent = B_TRUE; 419 boolean_t user_disable = B_FALSE; 420 char uxbuf[1024]; 421 struct passwd uxpw; 422 int64_t lm_level; 423 424 err = smb_pwd_lock(); 425 if (err != SMB_PWE_SUCCESS) 426 return (err); 427 428 if (stat64(SMB_PASSWD, &stbuf) < 0) { 429 err = SMB_PWE_STAT_FAILED; 430 goto passwd_exit; 431 } 432 433 if ((tempfd = open(SMB_PASSTEMP, O_WRONLY|O_CREAT|O_TRUNC, 0600)) < 0) { 434 err = SMB_PWE_OPEN_FAILED; 435 goto passwd_exit; 436 } 437 438 if ((dst = fdopen(tempfd, "wF")) == NULL) { 439 err = SMB_PWE_OPEN_FAILED; 440 goto passwd_exit; 441 } 442 443 if ((src = fopen(SMB_PASSWD, "rF")) == NULL) { 444 err = SMB_PWE_OPEN_FAILED; 445 (void) fclose(dst); 446 (void) unlink(SMB_PASSTEMP); 447 goto passwd_exit; 448 } 449 450 if (smb_config_getnum(SMB_CI_LM_LEVEL, &lm_level) != SMBD_SMF_OK) 451 lm_level = 4; 452 453 if (lm_level >= 4) 454 control |= SMB_PWC_NOLM; 455 456 pwbuf.pw_name = NULL; 457 pwbuf.pw_pwd = &smbpw; 458 459 /* 460 * copy old password entries to temporary file while replacing 461 * the entry that matches "name" 462 */ 463 while (smb_pwd_fgetent(src, &pwbuf, SMB_PWD_GETF_ALL) != NULL) { 464 if (strcmp(pwbuf.pw_name, name) == 0) { 465 err = smb_pwd_chgpwent(&smbpw, password, control); 466 if (err == SMB_PWE_USER_DISABLE) 467 user_disable = B_TRUE; 468 err = smb_pwd_fputent(dst, &pwbuf); 469 newent = B_FALSE; 470 } else { 471 err = smb_pwd_fputent(dst, &pwbuf); 472 } 473 474 if (err != SMB_PWE_SUCCESS) { 475 (void) fclose(src); 476 (void) fclose(dst); 477 goto passwd_exit; 478 } 479 } 480 481 if (newent) { 482 if (getpwnam_r(name, &uxpw, uxbuf, sizeof (uxbuf))) { 483 pwbuf.pw_name = uxpw.pw_name; 484 bzero(&smbpw, sizeof (smb_passwd_t)); 485 smbpw.pw_uid = uxpw.pw_uid; 486 (void) smb_pwd_chgpwent(&smbpw, password, control); 487 err = smb_pwd_fputent(dst, &pwbuf); 488 } else { 489 err = SMB_PWE_USER_UNKNOWN; 490 } 491 492 if (err != SMB_PWE_SUCCESS) { 493 (void) fclose(src); 494 (void) fclose(dst); 495 goto passwd_exit; 496 } 497 } 498 499 (void) fclose(src); 500 if (fclose(dst) != 0) { 501 err = SMB_PWE_CLOSE_FAILED; 502 goto passwd_exit; /* Don't trust the temporary file */ 503 } 504 505 /* Rename temp to passwd */ 506 if (unlink(SMB_OPASSWD) && access(SMB_OPASSWD, 0) == 0) { 507 err = SMB_PWE_UPDATE_FAILED; 508 (void) unlink(SMB_PASSTEMP); 509 goto passwd_exit; 510 } 511 512 if (link(SMB_PASSWD, SMB_OPASSWD) == -1) { 513 err = SMB_PWE_UPDATE_FAILED; 514 (void) unlink(SMB_PASSTEMP); 515 goto passwd_exit; 516 } 517 518 if (rename(SMB_PASSTEMP, SMB_PASSWD) == -1) { 519 err = SMB_PWE_UPDATE_FAILED; 520 (void) unlink(SMB_PASSTEMP); 521 goto passwd_exit; 522 } 523 524 (void) chmod(SMB_PASSWD, 0400); 525 526 passwd_exit: 527 (void) smb_pwd_unlock(); 528 if ((err == SMB_PWE_SUCCESS) && user_disable) 529 err = SMB_PWE_USER_DISABLE; 530 531 return (err); 532 } 533 534 /* 535 * smb_pwd_fgetent 536 * 537 * Parse the buffer in the passed pwbuf and fill in the 538 * smb password structure to point to the parsed information. 539 * The entry format is: 540 * 541 * <user-name>:<user-id>:<LM hash>:<NTLM hash> 542 * 543 * Returns a pointer to the passed pwbuf structure on success, 544 * otherwise returns NULL. 545 */ 546 static smb_pwbuf_t * 547 smb_pwd_fgetent(FILE *fp, smb_pwbuf_t *pwbuf, uint32_t flags) 548 { 549 char *argv[SMB_PWD_NARG]; 550 char *pwentry; 551 smb_passwd_t *pw; 552 smb_pwdarg_t i; 553 int lm_len, nt_len; 554 555 pwentry = pwbuf->pw_buf; 556 if (fgets(pwentry, SMB_PWD_BUFSIZE, fp) == NULL) 557 return (NULL); 558 (void) trim_whitespace(pwentry); 559 560 for (i = 0; i < SMB_PWD_NARG; ++i) { 561 if ((argv[i] = strsep((char **)&pwentry, ":")) == NULL) 562 return (NULL); 563 } 564 565 if ((*argv[SMB_PWD_NAME] == '\0') || (*argv[SMB_PWD_UID] == '\0')) 566 return (NULL); 567 568 pwbuf->pw_name = argv[SMB_PWD_NAME]; 569 570 pw = pwbuf->pw_pwd; 571 bzero(pw, sizeof (smb_passwd_t)); 572 pw->pw_uid = strtoul(argv[SMB_PWD_UID], 0, 10); 573 574 if (strcmp(argv[SMB_PWD_LMHASH], SMB_PWD_DISABLE) == 0) { 575 pw->pw_flags |= SMB_PWF_DISABLE; 576 if (flags != SMB_PWD_GETF_NOPWD) { 577 (void) strcpy((char *)pw->pw_lmhash, SMB_PWD_DISABLE); 578 (void) strcpy((char *)pw->pw_nthash, SMB_PWD_DISABLE); 579 } 580 return (pwbuf); 581 } 582 583 if (flags == SMB_PWD_GETF_NOPWD) 584 return (pwbuf); 585 586 lm_len = strlen(argv[SMB_PWD_LMHASH]); 587 if (lm_len == SMBAUTH_HEXHASH_SZ) { 588 (void) hextobin(argv[SMB_PWD_LMHASH], SMBAUTH_HEXHASH_SZ, 589 (char *)pw->pw_lmhash, SMBAUTH_HASH_SZ); 590 591 pw->pw_flags |= SMB_PWF_LM; 592 } else if (lm_len != 0) { 593 return (NULL); 594 } 595 596 nt_len = strlen(argv[SMB_PWD_NTHASH]); 597 if (nt_len == SMBAUTH_HEXHASH_SZ) { 598 (void) hextobin(argv[SMB_PWD_NTHASH], SMBAUTH_HEXHASH_SZ, 599 (char *)pw->pw_nthash, SMBAUTH_HASH_SZ); 600 601 pw->pw_flags |= SMB_PWF_NT; 602 } else if (nt_len != 0) { 603 return (NULL); 604 } 605 606 return (pwbuf); 607 } 608 609 /* 610 * smb_pwd_chgpwent 611 * 612 * Updates the given smb_passwd_t structure with given password and 613 * control information. 614 */ 615 static int 616 smb_pwd_chgpwent(smb_passwd_t *smbpw, const char *password, int control) 617 { 618 if (control & SMB_PWC_DISABLE) { 619 /* disable the user */ 620 smbpw->pw_flags |= SMB_PWF_DISABLE; 621 (void) strcpy((char *)smbpw->pw_lmhash, SMB_PWD_DISABLE); 622 (void) strcpy((char *)smbpw->pw_nthash, SMB_PWD_DISABLE); 623 smbpw->pw_flags &= ~(SMB_PWF_LM | SMB_PWF_NT); 624 return (SMB_PWE_SUCCESS); 625 } 626 627 if ((control & SMB_PWC_ENABLE) && (smbpw->pw_flags & SMB_PWF_DISABLE)) { 628 /* enable the user if it's been disabled */ 629 *smbpw->pw_lmhash = '\0'; 630 *smbpw->pw_nthash = '\0'; 631 smbpw->pw_flags &= ~(SMB_PWF_LM | SMB_PWF_NT); 632 return (SMB_PWE_SUCCESS); 633 } 634 635 /* No password update if account is disabled */ 636 if (smbpw->pw_flags & SMB_PWF_DISABLE) 637 return (SMB_PWE_USER_DISABLE); 638 639 /* This call was just to update the control flags */ 640 if (password == NULL) 641 return (SMB_PWE_SUCCESS); 642 643 if (control & SMB_PWC_NOLM) { 644 /* LM hash should not be present */ 645 smbpw->pw_flags &= ~SMB_PWF_LM; 646 *smbpw->pw_lmhash = '\0'; 647 } else { 648 smbpw->pw_flags |= SMB_PWF_LM; 649 (void) smb_auth_lm_hash((char *)password, smbpw->pw_lmhash); 650 } 651 652 smbpw->pw_flags |= SMB_PWF_NT; 653 (void) smb_auth_ntlm_hash((char *)password, smbpw->pw_nthash); 654 return (SMB_PWE_SUCCESS); 655 } 656 657 /* 658 * smb_pwd_fputent 659 * 660 * If LM/NTLM hash are present, converts them to hex string 661 * and write them along with user's name and Id to the smbpasswd 662 * file. 663 */ 664 static int 665 smb_pwd_fputent(FILE *fp, smb_pwbuf_t *pwbuf) 666 { 667 smb_passwd_t *pw = pwbuf->pw_pwd; 668 char hex_nthash[SMBAUTH_HEXHASH_SZ+1]; 669 char hex_lmhash[SMBAUTH_HEXHASH_SZ+1]; 670 int rc; 671 672 if ((pw->pw_flags & SMB_PWF_LM) == SMB_PWF_LM) { 673 (void) bintohex((char *)pw->pw_lmhash, SMBAUTH_HASH_SZ, 674 hex_lmhash, SMBAUTH_HEXHASH_SZ); 675 hex_lmhash[SMBAUTH_HEXHASH_SZ] = '\0'; 676 } else { 677 (void) strcpy(hex_lmhash, (char *)pw->pw_lmhash); 678 } 679 680 if ((pw->pw_flags & SMB_PWF_NT) == SMB_PWF_NT) { 681 (void) bintohex((char *)pw->pw_nthash, SMBAUTH_HASH_SZ, 682 hex_nthash, SMBAUTH_HEXHASH_SZ); 683 hex_nthash[SMBAUTH_HEXHASH_SZ] = '\0'; 684 } else { 685 (void) strcpy(hex_nthash, (char *)pw->pw_nthash); 686 } 687 688 rc = fprintf(fp, "%s:%u:%s:%s\n", pwbuf->pw_name, pw->pw_uid, 689 hex_lmhash, hex_nthash); 690 691 if (rc <= 0) 692 return (SMB_PWE_WRITE_FAILED); 693 694 return (SMB_PWE_SUCCESS); 695 } 696 697 /* 698 * smb_pwd_lock 699 * 700 * A wrapper around smb_pwd_flck() which locks smb password 701 * file so that only one thread at a time is operational. 702 */ 703 static int 704 smb_pwd_lock(void) 705 { 706 int res; 707 708 if (smb_pwd_flck()) { 709 switch (errno) { 710 case EINTR: 711 res = SMB_PWE_BUSY; 712 break; 713 case EACCES: 714 res = SMB_PWE_DENIED; 715 break; 716 case 0: 717 res = SMB_PWE_SUCCESS; 718 break; 719 } 720 } else 721 res = SMB_PWE_SUCCESS; 722 723 return (res); 724 } 725 726 /* 727 * smb_pwd_lock 728 * 729 * A wrapper around smb_pwd_fulck() which unlocks 730 * smb password file. 731 */ 732 static int 733 smb_pwd_unlock(void) 734 { 735 if (smb_pwd_fulck()) 736 return (SMB_PWE_SYSTEM_ERROR); 737 738 return (SMB_PWE_SUCCESS); 739 } 740 741 /* 742 * smb_pwd_flck 743 * 744 * Creates a lock file and grabs an exclusive (write) lock on it. 745 */ 746 static int 747 smb_pwd_flck(void) 748 { 749 int seconds = 0; 750 751 (void) mutex_lock(&lck_lock); 752 for (;;) { 753 if (lck_pid != 0 && lck_pid != getpid()) { 754 /* somebody forked */ 755 lck_pid = 0; 756 lck_tid = 0; 757 } 758 759 if (lck_tid == 0) { 760 if ((fildes = creat(SMB_PASSLCK, 0600)) == -1) 761 break; 762 flock.l_type = F_WRLCK; 763 if (fcntl(fildes, F_SETLK, &flock) != -1) { 764 lck_pid = getpid(); 765 lck_tid = thr_self(); 766 (void) mutex_unlock(&lck_lock); 767 return (0); 768 } 769 (void) close(fildes); 770 fildes = -1; 771 } 772 773 if (seconds++ >= S_WAITTIME) { 774 /* 775 * For compatibility with the past, pretend 776 * that we were interrupted by SIGALRM. 777 */ 778 errno = EINTR; 779 break; 780 } 781 782 (void) mutex_unlock(&lck_lock); 783 (void) sleep(1); 784 (void) mutex_lock(&lck_lock); 785 } 786 (void) mutex_unlock(&lck_lock); 787 788 return (-1); 789 } 790 791 /* 792 * smb_pwd_fulck 793 * 794 * Unlocks smb password file for operations done via 795 * this library APIs. 796 */ 797 static int 798 smb_pwd_fulck(void) 799 { 800 (void) mutex_lock(&lck_lock); 801 if (lck_tid == thr_self() && fildes >= 0) { 802 flock.l_type = F_UNLCK; 803 (void) fcntl(fildes, F_SETLK, &flock); 804 (void) close(fildes); 805 fildes = -1; 806 lck_pid = 0; 807 lck_tid = 0; 808 (void) mutex_unlock(&lck_lock); 809 return (0); 810 } 811 (void) mutex_unlock(&lck_lock); 812 return (-1); 813 } 814 815 /* 816 * Local User Cache Functions 817 * 818 * Local user cache is implemented using AVL tree 819 */ 820 821 /* 822 * smb_lucache_cmp 823 * 824 * AVL compare function, the key is username. 825 */ 826 static int 827 smb_lucache_cmp(const void *p1, const void *p2) 828 { 829 smb_ucnode_t *u1 = (smb_ucnode_t *)p1; 830 smb_ucnode_t *u2 = (smb_ucnode_t *)p2; 831 int rc; 832 833 rc = strcmp(u1->cn_user.su_name, u2->cn_user.su_name); 834 835 if (rc < 0) 836 return (-1); 837 838 if (rc > 0) 839 return (1); 840 841 return (0); 842 } 843 844 /* 845 * smb_lucache_update 846 * 847 * Updates the cache if needed. Whether an update is needed 848 * is determined based on smbpasswd file modification timestamp 849 */ 850 static void 851 smb_lucache_update(void) 852 { 853 struct stat64 stbuf; 854 int rc; 855 856 (void) mutex_lock(&smb_uch.uc_mtx); 857 switch (smb_uch.uc_state) { 858 default: 859 case SMB_UCHS_NOCACHE: 860 assert(0); 861 (void) mutex_unlock(&smb_uch.uc_mtx); 862 return; 863 864 case SMB_UCHS_CREATED: 865 case SMB_UCHS_UPDATED: 866 break; 867 868 case SMB_UCHS_UPDATING: 869 /* Want only one thread executing this function at a time */ 870 (void) mutex_unlock(&smb_uch.uc_mtx); 871 return; 872 873 case SMB_UCHS_DESTROYING: 874 (void) mutex_unlock(&smb_uch.uc_mtx); 875 return; 876 } 877 878 /* 879 * smb_pwd_lock() is not called here so it can 880 * be checked quickly whether an updated is needed 881 */ 882 if (stat64(SMB_PASSWD, &stbuf) < 0) { 883 (void) mutex_unlock(&smb_uch.uc_mtx); 884 if (errno != ENOENT) 885 return; 886 887 /* no smbpasswd file; empty the cache */ 888 smb_lucache_flush(); 889 return; 890 } 891 892 if (stbuf.st_size == 0) { 893 (void) mutex_unlock(&smb_uch.uc_mtx); 894 895 /* empty smbpasswd file; empty the cache */ 896 smb_lucache_flush(); 897 return; 898 } 899 900 if ((smb_uch.uc_timestamp.tv_sec == stbuf.st_mtim.tv_sec) && 901 (smb_uch.uc_timestamp.tv_nsec == stbuf.st_mtim.tv_nsec)) { 902 (void) mutex_unlock(&smb_uch.uc_mtx); 903 /* No changes since the last cache update */ 904 return; 905 } 906 907 smb_uch.uc_state = SMB_UCHS_UPDATING; 908 smb_uch.uc_refcnt++; 909 (void) mutex_unlock(&smb_uch.uc_mtx); 910 911 rc = smb_lucache_do_update(); 912 913 (void) mutex_lock(&smb_uch.uc_mtx); 914 if ((rc == SMB_PWE_SUCCESS) && (stat64(SMB_PASSWD, &stbuf) == 0)) 915 smb_uch.uc_timestamp = stbuf.st_mtim; 916 smb_uch.uc_state = SMB_UCHS_UPDATED; 917 smb_uch.uc_refcnt--; 918 (void) cond_broadcast(&smb_uch.uc_cv); 919 (void) mutex_unlock(&smb_uch.uc_mtx); 920 } 921 922 /* 923 * smb_lucache_do_update 924 * 925 * This function takes care of updating the AVL tree. 926 * If an entry has been updated, it'll be modified in place. 927 * 928 * New entries will be added to a temporary AVL tree then 929 * passwod file is unlocked and all the new entries will 930 * be transferred to the main cache from the temporary tree. 931 * 932 * This function MUST NOT be called directly 933 */ 934 static int 935 smb_lucache_do_update(void) 936 { 937 avl_tree_t tmp_cache; 938 smb_pwbuf_t pwbuf; 939 smb_passwd_t smbpw; 940 smb_ucnode_t uc_node; 941 smb_ucnode_t *uc_newnode; 942 smb_luser_t *user; 943 smb_sid_t *sid; 944 idmap_stat idm_stat; 945 int rc = SMB_PWE_SUCCESS; 946 void *cookie = NULL; 947 FILE *fp; 948 949 if ((rc = smb_pwd_lock()) != SMB_PWE_SUCCESS) 950 return (rc); 951 952 if ((fp = fopen(SMB_PASSWD, "rF")) == NULL) { 953 (void) smb_pwd_unlock(); 954 return (SMB_PWE_OPEN_FAILED); 955 } 956 957 avl_create(&tmp_cache, smb_lucache_cmp, 958 sizeof (smb_ucnode_t), offsetof(smb_ucnode_t, cn_link)); 959 960 bzero(&pwbuf, sizeof (smb_pwbuf_t)); 961 pwbuf.pw_pwd = &smbpw; 962 963 (void) rw_rdlock(&smb_uch.uc_cache_lck); 964 965 while (smb_pwd_fgetent(fp, &pwbuf, SMB_PWD_GETF_NOPWD) != NULL) { 966 uc_node.cn_user.su_name = pwbuf.pw_name; 967 uc_newnode = avl_find(&smb_uch.uc_cache, &uc_node, NULL); 968 if (uc_newnode) { 969 /* update the node info */ 970 uc_newnode->cn_user.su_ctrl = smbpw.pw_flags; 971 continue; 972 } 973 974 /* create a new node */ 975 if ((uc_newnode = malloc(sizeof (smb_ucnode_t))) == NULL) { 976 rc = SMB_PWE_NO_MEMORY; 977 break; 978 } 979 980 bzero(uc_newnode, sizeof (smb_ucnode_t)); 981 user = &uc_newnode->cn_user; 982 user->su_ctrl = smbpw.pw_flags; 983 984 idm_stat = smb_idmap_getsid(smbpw.pw_uid, SMB_IDMAP_USER, &sid); 985 if (idm_stat != IDMAP_SUCCESS) { 986 syslog(LOG_WARNING, "smb_pwdutil: couldn't obtain SID " 987 "for uid=%u (%d)", smbpw.pw_uid, idm_stat); 988 free(uc_newnode); 989 continue; 990 } 991 (void) smb_sid_getrid(sid, &user->su_rid); 992 smb_sid_free(sid); 993 994 user->su_name = strdup(pwbuf.pw_name); 995 if (user->su_name == NULL) { 996 rc = SMB_PWE_NO_MEMORY; 997 free(uc_newnode); 998 break; 999 } 1000 1001 avl_add(&tmp_cache, uc_newnode); 1002 } 1003 1004 (void) rw_unlock(&smb_uch.uc_cache_lck); 1005 (void) fclose(fp); 1006 (void) smb_pwd_unlock(); 1007 1008 /* Destroy the temporary list */ 1009 (void) rw_wrlock(&smb_uch.uc_cache_lck); 1010 while ((uc_newnode = avl_destroy_nodes(&tmp_cache, &cookie)) != NULL) { 1011 avl_add(&smb_uch.uc_cache, uc_newnode); 1012 } 1013 (void) rw_unlock(&smb_uch.uc_cache_lck); 1014 1015 avl_destroy(&tmp_cache); 1016 1017 return (rc); 1018 } 1019 1020 /* 1021 * smb_lucache_create 1022 * 1023 * Creates the AVL tree and initializes the global user cache handle. 1024 * This function doesn't populate the cache. 1025 * User cache is only created by smbd at startup 1026 */ 1027 static void 1028 smb_lucache_create(void) 1029 { 1030 (void) mutex_lock(&smb_uch.uc_mtx); 1031 if (smb_uch.uc_state != SMB_UCHS_NOCACHE) { 1032 (void) mutex_unlock(&smb_uch.uc_mtx); 1033 return; 1034 } 1035 1036 avl_create(&smb_uch.uc_cache, smb_lucache_cmp, 1037 sizeof (smb_ucnode_t), offsetof(smb_ucnode_t, cn_link)); 1038 1039 smb_uch.uc_state = SMB_UCHS_CREATED; 1040 bzero(&smb_uch.uc_timestamp, sizeof (timestruc_t)); 1041 smb_uch.uc_refcnt = 0; 1042 (void) mutex_unlock(&smb_uch.uc_mtx); 1043 } 1044 1045 /* 1046 * smb_lucache_flush 1047 * 1048 * Removes and frees all the cache entries 1049 */ 1050 static void 1051 smb_lucache_flush(void) 1052 { 1053 void *cookie = NULL; 1054 smb_ucnode_t *ucnode; 1055 1056 (void) rw_wrlock(&smb_uch.uc_cache_lck); 1057 while ((ucnode = avl_destroy_nodes(&smb_uch.uc_cache, &cookie)) 1058 != NULL) { 1059 free(ucnode->cn_user.su_name); 1060 free(ucnode->cn_user.su_fullname); 1061 free(ucnode->cn_user.su_desc); 1062 free(ucnode); 1063 } 1064 (void) rw_unlock(&smb_uch.uc_cache_lck); 1065 } 1066 1067 /* 1068 * smb_lucache_destroy 1069 * 1070 * Destroys the cache. 1071 * This function is only called in smb_pwd_fini() 1072 * User cache is only destroyed by smbd upon shutdown 1073 */ 1074 static void 1075 smb_lucache_destroy(void) 1076 { 1077 (void) mutex_lock(&smb_uch.uc_mtx); 1078 switch (smb_uch.uc_state) { 1079 case SMB_UCHS_NOCACHE: 1080 case SMB_UCHS_DESTROYING: 1081 (void) mutex_unlock(&smb_uch.uc_mtx); 1082 return; 1083 1084 default: 1085 break; 1086 } 1087 1088 smb_uch.uc_state = SMB_UCHS_DESTROYING; 1089 1090 while (smb_uch.uc_refcnt > 0) 1091 (void) cond_wait(&smb_uch.uc_cv, &smb_uch.uc_mtx); 1092 1093 smb_lucache_flush(); 1094 1095 avl_destroy(&smb_uch.uc_cache); 1096 smb_uch.uc_state = SMB_UCHS_NOCACHE; 1097 (void) mutex_unlock(&smb_uch.uc_mtx); 1098 } 1099 1100 /* 1101 * smb_lucache_lock 1102 * 1103 * Locks the user cache for reading and also 1104 * increment the handle reference count. 1105 */ 1106 static int 1107 smb_lucache_lock(void) 1108 { 1109 (void) mutex_lock(&smb_uch.uc_mtx); 1110 switch (smb_uch.uc_state) { 1111 case SMB_UCHS_NOCACHE: 1112 assert(0); 1113 (void) mutex_unlock(&smb_uch.uc_mtx); 1114 return (SMB_PWE_DENIED); 1115 1116 case SMB_UCHS_DESTROYING: 1117 (void) mutex_unlock(&smb_uch.uc_mtx); 1118 return (SMB_PWE_DENIED); 1119 } 1120 smb_uch.uc_refcnt++; 1121 (void) mutex_unlock(&smb_uch.uc_mtx); 1122 1123 (void) rw_rdlock(&smb_uch.uc_cache_lck); 1124 return (SMB_PWE_SUCCESS); 1125 } 1126 1127 /* 1128 * smb_lucache_unlock 1129 * 1130 * Unlock the cache 1131 */ 1132 static void 1133 smb_lucache_unlock(void) 1134 { 1135 (void) rw_unlock(&smb_uch.uc_cache_lck); 1136 1137 (void) mutex_lock(&smb_uch.uc_mtx); 1138 smb_uch.uc_refcnt--; 1139 (void) cond_broadcast(&smb_uch.uc_cv); 1140 (void) mutex_unlock(&smb_uch.uc_mtx); 1141 } 1142 1143 /* 1144 * smb_lucache_num 1145 * 1146 * Returns the number of cache entries 1147 */ 1148 static int 1149 smb_lucache_num(void) 1150 { 1151 int num; 1152 1153 (void) mutex_lock(&smb_uch.uc_mtx); 1154 switch (smb_uch.uc_state) { 1155 case SMB_UCHS_NOCACHE: 1156 assert(0); 1157 (void) mutex_unlock(&smb_uch.uc_mtx); 1158 return (0); 1159 1160 case SMB_UCHS_DESTROYING: 1161 (void) mutex_unlock(&smb_uch.uc_mtx); 1162 return (0); 1163 } 1164 (void) mutex_unlock(&smb_uch.uc_mtx); 1165 1166 (void) rw_rdlock(&smb_uch.uc_cache_lck); 1167 num = (int)avl_numnodes(&smb_uch.uc_cache); 1168 (void) rw_unlock(&smb_uch.uc_cache_lck); 1169 1170 return (num); 1171 } 1172