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