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