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