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