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