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