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