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 if (smb_pwd_flck()) { 777 switch (errno) { 778 case EINTR: 779 res = SMB_PWE_BUSY; 780 break; 781 case EACCES: 782 res = SMB_PWE_DENIED; 783 break; 784 case 0: 785 res = SMB_PWE_SUCCESS; 786 break; 787 } 788 } else 789 res = SMB_PWE_SUCCESS; 790 791 return (res); 792 } 793 794 /* 795 * smb_pwd_unlock 796 * 797 * A wrapper around smb_pwd_fulck() which unlocks 798 * smb password file. 799 */ 800 static int 801 smb_pwd_unlock(void) 802 { 803 if (smb_pwd_fulck()) 804 return (SMB_PWE_SYSTEM_ERROR); 805 806 return (SMB_PWE_SUCCESS); 807 } 808 809 /* 810 * smb_pwd_flck 811 * 812 * Creates a lock file and grabs an exclusive (write) lock on it. 813 */ 814 static int 815 smb_pwd_flck(void) 816 { 817 int seconds = 0; 818 819 (void) mutex_lock(&lck_lock); 820 for (;;) { 821 if (lck_pid != 0 && lck_pid != getpid()) { 822 /* somebody forked */ 823 lck_pid = 0; 824 lck_tid = 0; 825 } 826 827 if (lck_tid == 0) { 828 if ((fildes = creat(SMB_PASSLCK, 0600)) == -1) 829 break; 830 flock.l_type = F_WRLCK; 831 if (fcntl(fildes, F_SETLK, &flock) != -1) { 832 lck_pid = getpid(); 833 lck_tid = thr_self(); 834 (void) mutex_unlock(&lck_lock); 835 return (0); 836 } 837 (void) close(fildes); 838 fildes = -1; 839 } 840 841 if (seconds++ >= S_WAITTIME) { 842 /* 843 * For compatibility with the past, pretend 844 * that we were interrupted by SIGALRM. 845 */ 846 errno = EINTR; 847 break; 848 } 849 850 (void) mutex_unlock(&lck_lock); 851 (void) sleep(1); 852 (void) mutex_lock(&lck_lock); 853 } 854 (void) mutex_unlock(&lck_lock); 855 856 return (-1); 857 } 858 859 /* 860 * smb_pwd_fulck 861 * 862 * Unlocks smb password file for operations done via 863 * this library APIs. 864 */ 865 static int 866 smb_pwd_fulck(void) 867 { 868 (void) mutex_lock(&lck_lock); 869 if (lck_tid == thr_self() && fildes >= 0) { 870 flock.l_type = F_UNLCK; 871 (void) fcntl(fildes, F_SETLK, &flock); 872 (void) close(fildes); 873 fildes = -1; 874 lck_pid = 0; 875 lck_tid = 0; 876 (void) mutex_unlock(&lck_lock); 877 return (0); 878 } 879 (void) mutex_unlock(&lck_lock); 880 return (-1); 881 } 882 883 /* 884 * Local User Cache Functions 885 * 886 * Local user cache is implemented using AVL tree 887 */ 888 889 /* 890 * smb_lucache_cmp 891 * 892 * AVL compare function, the key is username. 893 */ 894 static int 895 smb_lucache_cmp(const void *p1, const void *p2) 896 { 897 smb_ucnode_t *u1 = (smb_ucnode_t *)p1; 898 smb_ucnode_t *u2 = (smb_ucnode_t *)p2; 899 int rc; 900 901 rc = strcmp(u1->cn_user.su_name, u2->cn_user.su_name); 902 903 if (rc < 0) 904 return (-1); 905 906 if (rc > 0) 907 return (1); 908 909 return (0); 910 } 911 912 /* 913 * smb_lucache_update 914 * 915 * Updates the cache if needed. Whether an update is needed 916 * is determined based on smbpasswd file modification timestamp 917 */ 918 static void 919 smb_lucache_update(void) 920 { 921 struct stat64 stbuf; 922 int rc; 923 924 (void) mutex_lock(&smb_uch.uc_mtx); 925 switch (smb_uch.uc_state) { 926 default: 927 case SMB_UCHS_NOCACHE: 928 assert(0); 929 (void) mutex_unlock(&smb_uch.uc_mtx); 930 return; 931 932 case SMB_UCHS_CREATED: 933 case SMB_UCHS_UPDATED: 934 break; 935 936 case SMB_UCHS_UPDATING: 937 /* Want only one thread executing this function at a time */ 938 (void) mutex_unlock(&smb_uch.uc_mtx); 939 return; 940 941 case SMB_UCHS_DESTROYING: 942 (void) mutex_unlock(&smb_uch.uc_mtx); 943 return; 944 } 945 946 /* 947 * smb_pwd_lock() is not called here so it can 948 * be checked quickly whether an updated is needed 949 */ 950 if (stat64(SMB_PASSWD, &stbuf) < 0) { 951 (void) mutex_unlock(&smb_uch.uc_mtx); 952 if (errno != ENOENT) 953 return; 954 955 /* no smbpasswd file; empty the cache */ 956 smb_lucache_flush(); 957 return; 958 } 959 960 if (stbuf.st_size == 0) { 961 (void) mutex_unlock(&smb_uch.uc_mtx); 962 963 /* empty smbpasswd file; empty the cache */ 964 smb_lucache_flush(); 965 return; 966 } 967 968 if ((smb_uch.uc_timestamp.tv_sec == stbuf.st_mtim.tv_sec) && 969 (smb_uch.uc_timestamp.tv_nsec == stbuf.st_mtim.tv_nsec)) { 970 (void) mutex_unlock(&smb_uch.uc_mtx); 971 /* No changes since the last cache update */ 972 return; 973 } 974 975 smb_uch.uc_state = SMB_UCHS_UPDATING; 976 smb_uch.uc_refcnt++; 977 (void) mutex_unlock(&smb_uch.uc_mtx); 978 979 rc = smb_lucache_do_update(); 980 981 (void) mutex_lock(&smb_uch.uc_mtx); 982 if ((rc == SMB_PWE_SUCCESS) && (stat64(SMB_PASSWD, &stbuf) == 0)) 983 smb_uch.uc_timestamp = stbuf.st_mtim; 984 smb_uch.uc_state = SMB_UCHS_UPDATED; 985 smb_uch.uc_refcnt--; 986 (void) cond_broadcast(&smb_uch.uc_cv); 987 (void) mutex_unlock(&smb_uch.uc_mtx); 988 } 989 990 /* 991 * smb_lucache_do_update 992 * 993 * This function takes care of updating the AVL tree. 994 * If an entry has been updated, it'll be modified in place. 995 * 996 * New entries will be added to a temporary AVL tree then 997 * passwod file is unlocked and all the new entries will 998 * be transferred to the main cache from the temporary tree. 999 * 1000 * This function MUST NOT be called directly 1001 */ 1002 static int 1003 smb_lucache_do_update(void) 1004 { 1005 avl_tree_t tmp_cache; 1006 smb_pwbuf_t pwbuf; 1007 smb_passwd_t smbpw; 1008 smb_ucnode_t uc_node; 1009 smb_ucnode_t *uc_newnode; 1010 smb_luser_t *user; 1011 smb_sid_t *sid; 1012 idmap_stat idm_stat; 1013 int rc = SMB_PWE_SUCCESS; 1014 void *cookie = NULL; 1015 FILE *fp; 1016 1017 if ((rc = smb_pwd_lock()) != SMB_PWE_SUCCESS) { 1018 syslog(LOG_WARNING, "smb_pwdutil: lock failed, err=%d", rc); 1019 return (rc); 1020 } 1021 1022 if ((fp = fopen(SMB_PASSWD, "rF")) == NULL) { 1023 syslog(LOG_WARNING, "smb_pwdutil: open failed, %m"); 1024 (void) smb_pwd_unlock(); 1025 return (SMB_PWE_OPEN_FAILED); 1026 } 1027 1028 avl_create(&tmp_cache, smb_lucache_cmp, 1029 sizeof (smb_ucnode_t), offsetof(smb_ucnode_t, cn_link)); 1030 1031 bzero(&pwbuf, sizeof (smb_pwbuf_t)); 1032 pwbuf.pw_pwd = &smbpw; 1033 1034 (void) rw_rdlock(&smb_uch.uc_cache_lck); 1035 1036 while (smb_pwd_fgetent(fp, &pwbuf, SMB_PWD_GETF_NOPWD) != NULL) { 1037 uc_node.cn_user.su_name = smbpw.pw_name; 1038 uc_newnode = avl_find(&smb_uch.uc_cache, &uc_node, NULL); 1039 if (uc_newnode) { 1040 /* update the node info */ 1041 uc_newnode->cn_user.su_ctrl = smbpw.pw_flags; 1042 continue; 1043 } 1044 1045 /* create a new node */ 1046 if ((uc_newnode = malloc(sizeof (smb_ucnode_t))) == NULL) { 1047 rc = SMB_PWE_NO_MEMORY; 1048 break; 1049 } 1050 1051 bzero(uc_newnode, sizeof (smb_ucnode_t)); 1052 user = &uc_newnode->cn_user; 1053 user->su_ctrl = smbpw.pw_flags; 1054 1055 idm_stat = smb_idmap_getsid(smbpw.pw_uid, SMB_IDMAP_USER, &sid); 1056 if (idm_stat != IDMAP_SUCCESS) { 1057 syslog(LOG_WARNING, "smb_pwdutil: couldn't obtain SID " 1058 "for uid=%u (%d)", smbpw.pw_uid, idm_stat); 1059 free(uc_newnode); 1060 continue; 1061 } 1062 (void) smb_sid_getrid(sid, &user->su_rid); 1063 smb_sid_free(sid); 1064 1065 user->su_name = strdup(smbpw.pw_name); 1066 if (user->su_name == NULL) { 1067 rc = SMB_PWE_NO_MEMORY; 1068 free(uc_newnode); 1069 break; 1070 } 1071 1072 avl_add(&tmp_cache, uc_newnode); 1073 } 1074 1075 (void) rw_unlock(&smb_uch.uc_cache_lck); 1076 (void) fclose(fp); 1077 (void) smb_pwd_unlock(); 1078 1079 /* Destroy the temporary list */ 1080 (void) rw_wrlock(&smb_uch.uc_cache_lck); 1081 while ((uc_newnode = avl_destroy_nodes(&tmp_cache, &cookie)) != NULL) { 1082 avl_add(&smb_uch.uc_cache, uc_newnode); 1083 } 1084 (void) rw_unlock(&smb_uch.uc_cache_lck); 1085 1086 avl_destroy(&tmp_cache); 1087 1088 return (rc); 1089 } 1090 1091 /* 1092 * smb_lucache_create 1093 * 1094 * Creates the AVL tree and initializes the global user cache handle. 1095 * This function doesn't populate the cache. 1096 * User cache is only created by smbd at startup 1097 */ 1098 static void 1099 smb_lucache_create(void) 1100 { 1101 (void) mutex_lock(&smb_uch.uc_mtx); 1102 if (smb_uch.uc_state != SMB_UCHS_NOCACHE) { 1103 (void) mutex_unlock(&smb_uch.uc_mtx); 1104 return; 1105 } 1106 1107 avl_create(&smb_uch.uc_cache, smb_lucache_cmp, 1108 sizeof (smb_ucnode_t), offsetof(smb_ucnode_t, cn_link)); 1109 1110 smb_uch.uc_state = SMB_UCHS_CREATED; 1111 bzero(&smb_uch.uc_timestamp, sizeof (timestruc_t)); 1112 smb_uch.uc_refcnt = 0; 1113 (void) mutex_unlock(&smb_uch.uc_mtx); 1114 } 1115 1116 /* 1117 * smb_lucache_flush 1118 * 1119 * Removes and frees all the cache entries 1120 */ 1121 static void 1122 smb_lucache_flush(void) 1123 { 1124 void *cookie = NULL; 1125 smb_ucnode_t *ucnode; 1126 1127 (void) rw_wrlock(&smb_uch.uc_cache_lck); 1128 while ((ucnode = avl_destroy_nodes(&smb_uch.uc_cache, &cookie)) 1129 != NULL) { 1130 free(ucnode->cn_user.su_name); 1131 free(ucnode->cn_user.su_fullname); 1132 free(ucnode->cn_user.su_desc); 1133 free(ucnode); 1134 } 1135 (void) rw_unlock(&smb_uch.uc_cache_lck); 1136 } 1137 1138 /* 1139 * smb_lucache_destroy 1140 * 1141 * Destroys the cache. 1142 * This function is only called in smb_pwd_fini() 1143 * User cache is only destroyed by smbd upon shutdown 1144 */ 1145 static void 1146 smb_lucache_destroy(void) 1147 { 1148 (void) mutex_lock(&smb_uch.uc_mtx); 1149 switch (smb_uch.uc_state) { 1150 case SMB_UCHS_NOCACHE: 1151 case SMB_UCHS_DESTROYING: 1152 (void) mutex_unlock(&smb_uch.uc_mtx); 1153 return; 1154 1155 default: 1156 break; 1157 } 1158 1159 smb_uch.uc_state = SMB_UCHS_DESTROYING; 1160 1161 while (smb_uch.uc_refcnt > 0) 1162 (void) cond_wait(&smb_uch.uc_cv, &smb_uch.uc_mtx); 1163 1164 smb_lucache_flush(); 1165 1166 avl_destroy(&smb_uch.uc_cache); 1167 smb_uch.uc_state = SMB_UCHS_NOCACHE; 1168 (void) mutex_unlock(&smb_uch.uc_mtx); 1169 } 1170 1171 /* 1172 * smb_lucache_lock 1173 * 1174 * Locks the user cache for reading and also 1175 * increment the handle reference count. 1176 */ 1177 static int 1178 smb_lucache_lock(void) 1179 { 1180 (void) mutex_lock(&smb_uch.uc_mtx); 1181 switch (smb_uch.uc_state) { 1182 case SMB_UCHS_NOCACHE: 1183 assert(0); 1184 (void) mutex_unlock(&smb_uch.uc_mtx); 1185 return (SMB_PWE_DENIED); 1186 1187 case SMB_UCHS_DESTROYING: 1188 (void) mutex_unlock(&smb_uch.uc_mtx); 1189 return (SMB_PWE_DENIED); 1190 } 1191 smb_uch.uc_refcnt++; 1192 (void) mutex_unlock(&smb_uch.uc_mtx); 1193 1194 (void) rw_rdlock(&smb_uch.uc_cache_lck); 1195 return (SMB_PWE_SUCCESS); 1196 } 1197 1198 /* 1199 * smb_lucache_unlock 1200 * 1201 * Unlock the cache 1202 */ 1203 static void 1204 smb_lucache_unlock(void) 1205 { 1206 (void) rw_unlock(&smb_uch.uc_cache_lck); 1207 1208 (void) mutex_lock(&smb_uch.uc_mtx); 1209 smb_uch.uc_refcnt--; 1210 (void) cond_broadcast(&smb_uch.uc_cv); 1211 (void) mutex_unlock(&smb_uch.uc_mtx); 1212 } 1213 1214 /* 1215 * smb_lucache_num 1216 * 1217 * Returns the number of cache entries 1218 */ 1219 static int 1220 smb_lucache_num(void) 1221 { 1222 int num; 1223 1224 (void) mutex_lock(&smb_uch.uc_mtx); 1225 switch (smb_uch.uc_state) { 1226 case SMB_UCHS_NOCACHE: 1227 assert(0); 1228 (void) mutex_unlock(&smb_uch.uc_mtx); 1229 return (0); 1230 1231 case SMB_UCHS_DESTROYING: 1232 (void) mutex_unlock(&smb_uch.uc_mtx); 1233 return (0); 1234 } 1235 (void) mutex_unlock(&smb_uch.uc_mtx); 1236 1237 (void) rw_rdlock(&smb_uch.uc_cache_lck); 1238 num = (int)avl_numnodes(&smb_uch.uc_cache); 1239 (void) rw_unlock(&smb_uch.uc_cache_lck); 1240 1241 return (num); 1242 } 1243