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 }