Print this page
NEX-15558 SMB logon fails during 1st second after service start
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-15558 SMB logon fails during 1st second after service start
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-2225 Unable to join NexentaStor to 2008 AD


   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 2009 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 /*
  29  * This file defines the domain environment values and the domain
  30  * database interface. The database is a single linked list of
  31  * structures containing domain type, name and SID information.
  32  */
  33 
  34 #include <sys/types.h>
  35 #include <sys/stat.h>
  36 #include <sys/list.h>
  37 #include <stdio.h>
  38 #include <strings.h>
  39 #include <string.h>

  40 #include <unistd.h>
  41 #include <stdlib.h>
  42 #include <synch.h>
  43 #include <pwd.h>
  44 #include <grp.h>
  45 #include <assert.h>
  46 
  47 #include <smbsrv/smbinfo.h>
  48 #include <smbsrv/string.h>
  49 #include <smbsrv/smb_sid.h>
  50 #include <smbsrv/libsmb.h>
  51 
  52 #define SMB_DOMAINS_FILE        "domains"
  53 
  54 #define SMB_DCACHE_UPDATE_WAIT  45      /* seconds */
  55 
  56 /*
  57  * Domain cache states
  58  */
  59 #define SMB_DCACHE_STATE_NONE           0
  60 #define SMB_DCACHE_STATE_READY          1
  61 #define SMB_DCACHE_STATE_UPDATING       2
  62 #define SMB_DCACHE_STATE_DESTROYING     3
  63 
  64 /*
  65  * Cache lock modes
  66  */
  67 #define SMB_DCACHE_RDLOCK       0
  68 #define SMB_DCACHE_WRLOCK       1
  69 
  70 typedef struct smb_domain_cache {
  71         list_t          dc_cache;
  72         rwlock_t        dc_cache_lck;
  73         mutex_t         dc_mtx;
  74         cond_t          dc_cv;
  75         uint32_t        dc_state;
  76         uint32_t        dc_nops;





  77         smb_dcinfo_t    dc_dci;
  78 } smb_domain_cache_t;
  79 
  80 static smb_domain_cache_t smb_dcache;
  81 
  82 static uint32_t smb_domain_add(smb_domain_type_t, smb_domain_t *);
  83 static uint32_t smb_domain_add_local(void);
  84 static uint32_t smb_domain_add_primary(uint32_t);
  85 static void smb_domain_unlink(void);
  86 
  87 static void smb_dcache_create(void);
  88 static void smb_dcache_destroy(void);
  89 static uint32_t smb_dcache_lock(int);
  90 static void smb_dcache_unlock(void);
  91 static void smb_dcache_remove(smb_domain_t *);
  92 static uint32_t smb_dcache_add(smb_domain_t *);
  93 static boolean_t smb_dcache_getdc(smb_dcinfo_t *);
  94 static void smb_dcache_setdc(const smb_dcinfo_t *);
  95 static boolean_t smb_dcache_wait(void);
  96 static uint32_t smb_dcache_updating(void);
  97 static void smb_dcache_ready(void);
  98 
  99 /*
 100  * domain cache one time initialization. This function should
 101  * only be called during service startup.
 102  *
 103  * Returns 0 on success and an error code on failure.
 104  */
 105 int
 106 smb_domain_init(uint32_t secmode)
 107 {
 108         smb_domain_t di;
 109         int rc;
 110 
 111         smb_dcache_create();
 112 
 113         if ((rc = smb_domain_add_local()) != 0)
 114                 return (rc);
 115 

 116         smb_domain_set_basic_info(NT_BUILTIN_DOMAIN_SIDSTR, "BUILTIN", "", &di);
 117         (void) smb_domain_add(SMB_DOMAIN_BUILTIN, &di);
 118 
 119         return (smb_domain_add_primary(secmode));
 120 }
 121 
 122 /*
 123  * Destroys the cache upon service termination
 124  */
 125 void
 126 smb_domain_fini(void)
 127 {
 128         smb_dcache_destroy();
 129         smb_domain_unlink();
 130 }
 131 
 132 /*
 133  * Add a domain structure to domain cache. There is no checking
 134  * for duplicates.
 135  */


 272 
 273         dcnode = list_head(&smb_dcache.dc_cache);
 274         while (dcnode) {
 275                 if (dcnode->di_type == type) {
 276                         found = B_TRUE;
 277                         if (di)
 278                                 *di = *dcnode;
 279                         break;
 280                 }
 281 
 282                 dcnode = list_next(&smb_dcache.dc_cache, dcnode);
 283         }
 284 
 285         smb_dcache_unlock();
 286         return (found);
 287 }
 288 
 289 /*
 290  * Returns primary domain information plus the name of
 291  * the selected domain controller.


 292  */
 293 boolean_t
 294 smb_domain_getinfo(smb_domainex_t *dxi)
 295 {
 296         boolean_t rv;
 297 
 298         /* Note: this waits for the dcache lock. */
 299         rv = smb_domain_lookup_type(SMB_DOMAIN_PRIMARY, &dxi->d_primary);
 300         if (rv)
 301                 rv = smb_dcache_getdc(&dxi->d_dci);


 302 
 303         return (rv);















 304 }
 305 
 306 /*
 307  * Get the name of the current DC (if any)
 308  * Does NOT block.
 309  */
 310 void
 311 smb_domain_current_dc(smb_dcinfo_t *dci)
 312 {
 313         (void) smb_dcache_getdc(dci);
 314 }
 315 
 316 /*
 317  * Transfer the cache to updating state.
 318  * In this state any request for reading the cache would
 319  * be blocked until the update is finished.
 320  */
 321 uint32_t
 322 smb_domain_start_update(void)
 323 {
 324         return (smb_dcache_updating());
 325 }
 326 
 327 /*
 328  * Transfer the cache from updating to ready state.
 329  */
 330 void
 331 smb_domain_end_update(void)
 332 {
 333         smb_dcache_ready();
 334 }
 335 
 336 /*












 337  * Updates the cache with given information for the primary
 338  * domain, possible trusted domains and the selected domain
 339  * controller.
 340  *
 341  * Before adding the new entries existing entries of type
 342  * primary and trusted will be removed from cache.
 343  */
 344 void
 345 smb_domain_update(smb_domainex_t *dxi)
 346 {
 347         smb_domain_t *dcnode;
 348         int i;
 349 
 350         if (smb_dcache_lock(SMB_DCACHE_WRLOCK) != SMB_DOMAIN_SUCCESS)
 351                 return;
 352 
 353         dcnode = list_head(&smb_dcache.dc_cache);
 354         while (dcnode) {
 355                 if ((dcnode->di_type == SMB_DOMAIN_PRIMARY) ||
 356                     (dcnode->di_type == SMB_DOMAIN_TRUSTED)) {


 467     smb_domain_t *di)
 468 {
 469         if (sid == NULL || nb_domain == NULL || fq_domain == NULL ||
 470             di == NULL)
 471                 return;
 472 
 473         (void) strlcpy(di->di_sid, sid, SMB_SID_STRSZ);
 474         (void) strlcpy(di->di_nbname, nb_domain, NETBIOS_NAME_SZ);
 475         (void) smb_strupr(di->di_nbname);
 476         (void) strlcpy(di->di_fqname, fq_domain, MAXHOSTNAMELEN);
 477         di->di_binsid = NULL;
 478 }
 479 
 480 void
 481 smb_domain_set_dns_info(char *sid, char *nb_domain, char *fq_domain,
 482     char *forest, char *guid, smb_domain_t *di)
 483 {
 484         if (di == NULL || forest == NULL || guid == NULL)
 485                 return;
 486 

 487         smb_domain_set_basic_info(sid, nb_domain, fq_domain, di);
 488         (void) strlcpy(di->di_u.di_dns.ddi_forest, forest, MAXHOSTNAMELEN);
 489         (void) strlcpy(di->di_u.di_dns.ddi_guid, guid,
 490             UUID_PRINTABLE_STRING_LENGTH);
 491 }
 492 
 493 void
 494 smb_domain_set_trust_info(char *sid, char *nb_domain, char *fq_domain,
 495     uint32_t trust_dir, uint32_t trust_type, uint32_t trust_attrs,
 496     smb_domain_t *di)
 497 {
 498         smb_domain_trust_t *ti;
 499 
 500         if (di == NULL)
 501                 return;
 502 

 503         di->di_type = SMB_DOMAIN_TRUSTED;
 504         ti = &di->di_u.di_trust;
 505         smb_domain_set_basic_info(sid, nb_domain, fq_domain, di);
 506         ti->dti_trust_direction = trust_dir;
 507         ti->dti_trust_type = trust_type;
 508         ti->dti_trust_attrs = trust_attrs;
 509 }
 510 
 511 /*
 512  * Remove the /var/run/smb/domains file.
 513  */
 514 static void
 515 smb_domain_unlink(void)
 516 {
 517         char fname[MAXPATHLEN];
 518 
 519         (void) snprintf(fname, MAXPATHLEN, "%s/%s",
 520             SMB_VARRUN_DIR, SMB_DOMAINS_FILE);
 521         (void) unlink(fname);
 522 }
 523 
 524 /*
 525  * Add an entry for the local domain to the domain cache
 526  */
 527 static uint32_t
 528 smb_domain_add_local(void)
 529 {
 530         char *lsidstr;
 531         char hostname[NETBIOS_NAME_SZ];
 532         char fq_name[MAXHOSTNAMELEN];
 533         smb_domain_t di;
 534 
 535         if ((lsidstr = smb_config_get_localsid()) == NULL)
 536                 return (SMB_DOMAIN_NOMACHINE_SID);
 537 
 538         if (smb_getnetbiosname(hostname, NETBIOS_NAME_SZ) != 0) {
 539                 free(lsidstr);
 540                 return (SMB_DOMAIN_NOMACHINE_SID);
 541         }
 542 

 543         *fq_name = '\0';
 544         (void) smb_getfqhostname(fq_name, MAXHOSTNAMELEN);
 545         smb_domain_set_basic_info(lsidstr, hostname, fq_name, &di);
 546         (void) smb_domain_add(SMB_DOMAIN_LOCAL, &di);
 547 
 548         free(lsidstr);
 549         return (SMB_DOMAIN_SUCCESS);
 550 }
 551 
 552 /*
 553  * Add an entry for the primary domain to the domain cache
 554  */
 555 static uint32_t
 556 smb_domain_add_primary(uint32_t secmode)
 557 {
 558         char sidstr[SMB_SID_STRSZ];
 559         char fq_name[MAXHOSTNAMELEN];
 560         char nb_name[NETBIOS_NAME_SZ];
 561         smb_domain_t di;
 562         int rc;
 563 
 564         if (secmode != SMB_SECMODE_DOMAIN)
 565                 return (SMB_DOMAIN_SUCCESS);
 566 
 567         rc = smb_config_getstr(SMB_CI_DOMAIN_SID, sidstr, sizeof (sidstr));
 568         if (rc != SMBD_SMF_OK)
 569                 return (SMB_DOMAIN_NODOMAIN_SID);
 570 
 571         rc = smb_config_getstr(SMB_CI_DOMAIN_NAME, nb_name, NETBIOS_NAME_SZ);
 572         if ((rc != SMBD_SMF_OK) || (*nb_name == '\0'))
 573                 return (SMB_DOMAIN_NODOMAIN_NAME);
 574 

 575         (void) smb_getfqdomainname(fq_name, MAXHOSTNAMELEN);
 576         smb_domain_set_basic_info(sidstr, nb_name, fq_name, &di);
 577         (void) smb_domain_add(SMB_DOMAIN_PRIMARY, &di);
 578         return (SMB_DOMAIN_SUCCESS);
 579 }
 580 
 581 /*
 582  * Initialize the domain cache.
 583  * This function does not populate the cache.
 584  */
 585 static void
 586 smb_dcache_create(void)
 587 {
 588         (void) mutex_lock(&smb_dcache.dc_mtx);
 589         if (smb_dcache.dc_state != SMB_DCACHE_STATE_NONE) {
 590                 (void) mutex_unlock(&smb_dcache.dc_mtx);
 591                 return;
 592         }
 593 
 594         list_create(&smb_dcache.dc_cache, sizeof (smb_domain_t),
 595             offsetof(smb_domain_t, di_lnd));
 596 
 597         smb_dcache.dc_nops = 0;
 598         bzero(&smb_dcache.dc_dci, sizeof (smb_dcache.dc_dci));

 599         smb_dcache.dc_state = SMB_DCACHE_STATE_READY;
 600         (void) mutex_unlock(&smb_dcache.dc_mtx);
 601 }
 602 
 603 /*
 604  * Removes and frees all the cache entries
 605  */
 606 static void
 607 smb_dcache_flush(void)
 608 {
 609         smb_domain_t *di;
 610 
 611         (void) rw_wrlock(&smb_dcache.dc_cache_lck);
 612         while ((di = list_head(&smb_dcache.dc_cache)) != NULL)
 613                 smb_dcache_remove(di);
 614         (void) rw_unlock(&smb_dcache.dc_cache_lck);
 615 }
 616 
 617 /*
 618  * Destroys the cache.


 635         }
 636         (void) mutex_unlock(&smb_dcache.dc_mtx);
 637 }
 638 
 639 /*
 640  * Lock the cache with the specified mode.
 641  * If the cache is in updating state and a read lock is
 642  * requested, the lock won't be granted until either the
 643  * update is finished or SMB_DCACHE_UPDATE_WAIT has passed.
 644  *
 645  * Whenever a lock is granted, the number of inflight cache
 646  * operations is incremented.
 647  */
 648 static uint32_t
 649 smb_dcache_lock(int mode)
 650 {
 651         (void) mutex_lock(&smb_dcache.dc_mtx);
 652         switch (smb_dcache.dc_state) {
 653         case SMB_DCACHE_STATE_NONE:
 654         case SMB_DCACHE_STATE_DESTROYING:

 655                 (void) mutex_unlock(&smb_dcache.dc_mtx);
 656                 return (SMB_DOMAIN_INTERNAL_ERR);
 657 
 658         case SMB_DCACHE_STATE_UPDATING:
 659                 if (mode == SMB_DCACHE_RDLOCK) {
 660                         /*
 661                          * Read operations should wait until the update
 662                          * is completed.
 663                          */
 664                         if (!smb_dcache_wait()) {
 665                                 (void) mutex_unlock(&smb_dcache.dc_mtx);
 666                                 return (SMB_DOMAIN_INTERNAL_ERR);
 667                         }
 668                 }

 669 
 670         default:
 671                 smb_dcache.dc_nops++;
 672                 break;
 673         }
 674         (void) mutex_unlock(&smb_dcache.dc_mtx);
 675 
 676         /*
 677          * Lock has to be taken outside the mutex otherwise
 678          * there could be a deadlock
 679          */
 680         if (mode == SMB_DCACHE_RDLOCK)
 681                 (void) rw_rdlock(&smb_dcache.dc_cache_lck);
 682         else
 683                 (void) rw_wrlock(&smb_dcache.dc_cache_lck);
 684 
 685         return (SMB_DOMAIN_SUCCESS);
 686 }
 687 
 688 /*
 689  * Decrement the number of inflight operations and then unlock.
 690  */


 715                 return (SMB_DOMAIN_NO_MEMORY);
 716         }
 717 
 718         list_insert_tail(&smb_dcache.dc_cache, dcnode);
 719         return (SMB_DOMAIN_SUCCESS);
 720 }
 721 
 722 static void
 723 smb_dcache_remove(smb_domain_t *di)
 724 {
 725         list_remove(&smb_dcache.dc_cache, di);
 726         smb_sid_free(di->di_binsid);
 727         free(di);
 728 }
 729 
 730 static void
 731 smb_dcache_setdc(const smb_dcinfo_t *dci)
 732 {
 733         (void) mutex_lock(&smb_dcache.dc_mtx);
 734         smb_dcache.dc_dci = *dci; /* struct assignment! */


 735         (void) mutex_unlock(&smb_dcache.dc_mtx);
 736 }
 737 
 738 /*
 739  * Return B_TRUE if we have DC information.


 740  */
 741 static boolean_t
 742 smb_dcache_getdc(smb_dcinfo_t *dci)
 743 {







 744         (void) mutex_lock(&smb_dcache.dc_mtx);







 745         *dci = smb_dcache.dc_dci; /* struct assignment! */


 746         (void) mutex_unlock(&smb_dcache.dc_mtx);
 747         return (dci->dc_name[0] != '\0');

 748 }
 749 
 750 /*
 751  * Waits for SMB_DCACHE_UPDATE_WAIT seconds if cache is in
 752  * UPDATING state. Upon wake up returns true if cache is
 753  * ready to be used, otherwise it returns false.
 754  */
 755 static boolean_t
 756 smb_dcache_wait(void)
 757 {
 758         timestruc_t to;
 759         int err;
 760 
 761         to.tv_sec = SMB_DCACHE_UPDATE_WAIT;


 762         to.tv_nsec = 0;
 763         while (smb_dcache.dc_state == SMB_DCACHE_STATE_UPDATING) {
 764                 err = cond_reltimedwait(&smb_dcache.dc_cv,
 765                     &smb_dcache.dc_mtx, &to);
 766                 if (err == ETIME)
 767                         break;
 768         }
 769 
 770         return (smb_dcache.dc_state == SMB_DCACHE_STATE_READY);
 771 }
 772 
 773 /*
 774  * Transfers the cache into UPDATING state, this will ensure
 775  * any read access to the cache will be stalled until the
 776  * update is finished. This is to avoid providing incomplete,
 777  * inconsistent or stale information.
 778  *
 779  * If another thread is already updating the cache, other
 780  * callers will wait until cache is no longer in UPDATING
 781  * state. The return code is decided based on the new
 782  * state of the cache.
 783  */
 784 static uint32_t




   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 2009 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 /*
  29  * This file defines the domain environment values and the domain
  30  * database interface. The database is a single linked list of
  31  * structures containing domain type, name and SID information.
  32  */
  33 
  34 #include <sys/types.h>
  35 #include <sys/stat.h>
  36 #include <sys/list.h>
  37 #include <stdio.h>
  38 #include <strings.h>
  39 #include <string.h>
  40 #include <syslog.h>
  41 #include <unistd.h>
  42 #include <stdlib.h>
  43 #include <synch.h>
  44 #include <pwd.h>
  45 #include <grp.h>
  46 #include <assert.h>
  47 
  48 #include <smbsrv/smbinfo.h>
  49 #include <smbsrv/string.h>
  50 #include <smbsrv/smb_sid.h>
  51 #include <smbsrv/libsmb.h>
  52 
  53 #define SMB_DOMAINS_FILE        "domains"
  54 
  55 #define SMB_DCACHE_UPDATE_WAIT  45      /* seconds */
  56 
  57 /*
  58  * Domain cache states
  59  */
  60 #define SMB_DCACHE_STATE_NONE           0
  61 #define SMB_DCACHE_STATE_READY          1
  62 #define SMB_DCACHE_STATE_UPDATING       2
  63 #define SMB_DCACHE_STATE_DESTROYING     3
  64 
  65 /*
  66  * Cache lock modes
  67  */
  68 #define SMB_DCACHE_RDLOCK       0
  69 #define SMB_DCACHE_WRLOCK       1
  70 
  71 typedef struct smb_domain_cache {
  72         list_t          dc_cache;
  73         rwlock_t        dc_cache_lck;


  74         uint32_t        dc_state;
  75         uint32_t        dc_nops;
  76         mutex_t         dc_mtx;
  77         cond_t          dc_cv;
  78         /* domain controller information */
  79         cond_t          dc_dci_cv;
  80         boolean_t       dc_dci_valid;
  81         smb_dcinfo_t    dc_dci;
  82 } smb_domain_cache_t;
  83 
  84 static smb_domain_cache_t smb_dcache;
  85 
  86 static uint32_t smb_domain_add(smb_domain_type_t, smb_domain_t *);
  87 static uint32_t smb_domain_add_local(void);
  88 static uint32_t smb_domain_add_primary(uint32_t);
  89 static void smb_domain_unlink(void);
  90 
  91 static void smb_dcache_create(void);
  92 static void smb_dcache_destroy(void);
  93 static uint32_t smb_dcache_lock(int);
  94 static void smb_dcache_unlock(void);
  95 static void smb_dcache_remove(smb_domain_t *);
  96 static uint32_t smb_dcache_add(smb_domain_t *);
  97 static boolean_t smb_dcache_getdc(smb_dcinfo_t *, boolean_t);
  98 static void smb_dcache_setdc(const smb_dcinfo_t *);
  99 static boolean_t smb_dcache_wait(void);
 100 static uint32_t smb_dcache_updating(void);
 101 static void smb_dcache_ready(void);
 102 
 103 /*
 104  * domain cache one time initialization. This function should
 105  * only be called during service startup.
 106  *
 107  * Returns 0 on success and an error code on failure.
 108  */
 109 int
 110 smb_domain_init(uint32_t secmode)
 111 {
 112         smb_domain_t di;
 113         int rc;
 114 
 115         smb_dcache_create();
 116 
 117         if ((rc = smb_domain_add_local()) != 0)
 118                 return (rc);
 119 
 120         bzero(&di, sizeof (di));
 121         smb_domain_set_basic_info(NT_BUILTIN_DOMAIN_SIDSTR, "BUILTIN", "", &di);
 122         (void) smb_domain_add(SMB_DOMAIN_BUILTIN, &di);
 123 
 124         return (smb_domain_add_primary(secmode));
 125 }
 126 
 127 /*
 128  * Destroys the cache upon service termination
 129  */
 130 void
 131 smb_domain_fini(void)
 132 {
 133         smb_dcache_destroy();
 134         smb_domain_unlink();
 135 }
 136 
 137 /*
 138  * Add a domain structure to domain cache. There is no checking
 139  * for duplicates.
 140  */


 277 
 278         dcnode = list_head(&smb_dcache.dc_cache);
 279         while (dcnode) {
 280                 if (dcnode->di_type == type) {
 281                         found = B_TRUE;
 282                         if (di)
 283                                 *di = *dcnode;
 284                         break;
 285                 }
 286 
 287                 dcnode = list_next(&smb_dcache.dc_cache, dcnode);
 288         }
 289 
 290         smb_dcache_unlock();
 291         return (found);
 292 }
 293 
 294 /*
 295  * Returns primary domain information plus the name of
 296  * the selected domain controller.
 297  *
 298  * Returns TRUE on success.
 299  */
 300 boolean_t
 301 smb_domain_getinfo(smb_domainex_t *dxi)
 302 {
 303         boolean_t rv;
 304 
 305         /* Note: this waits for the dcache lock. */
 306         rv = smb_domain_lookup_type(SMB_DOMAIN_PRIMARY, &dxi->d_primary);
 307         if (!rv) {
 308                 syslog(LOG_ERR, "smb_domain_getinfo: no primary domain");
 309                 return (B_FALSE);
 310         }
 311 
 312         /*
 313          * The 2nd arg TRUE means this will wait for DC info.
 314          *
 315          * Note that we do NOT hold the dcache rwlock here
 316          * (not even as reader) because we already have what we
 317          * need from the dcache (our primary domain) and we don't
 318          * want to interfere with the DC locator which will take
 319          * the dcache lock as write to update the domain info.
 320          */
 321         rv = smb_dcache_getdc(&dxi->d_dci, B_TRUE);
 322         if (!rv) {
 323                 syslog(LOG_ERR, "smb_domain_getinfo: no DC info");
 324                 return (B_FALSE);
 325         }
 326 
 327         return (B_TRUE);
 328 }
 329 
 330 /*
 331  * Get the name of the current DC (if any)
 332  * Does NOT block.
 333  */
 334 void
 335 smb_domain_current_dc(smb_dcinfo_t *dci)
 336 {
 337         (void) smb_dcache_getdc(dci, B_FALSE);
 338 }
 339 
 340 /*
 341  * Transfer the cache to updating state.
 342  * In this state any request for reading the cache would
 343  * be blocked until the update is finished.
 344  */
 345 uint32_t
 346 smb_domain_start_update(void)
 347 {
 348         return (smb_dcache_updating());
 349 }
 350 
 351 /*
 352  * Transfer the cache from updating to ready state.
 353  */
 354 void
 355 smb_domain_end_update(void)
 356 {
 357         smb_dcache_ready();
 358 }
 359 
 360 /*
 361  * Mark the current domain controller (DC) info invalid
 362  * until the DC locator call smb_domain_update().
 363  */
 364 void
 365 smb_domain_bad_dc(void)
 366 {
 367         (void) mutex_lock(&smb_dcache.dc_mtx);
 368         smb_dcache.dc_dci_valid = B_FALSE;
 369         (void) mutex_unlock(&smb_dcache.dc_mtx);
 370 }
 371 
 372 /*
 373  * Updates the cache with given information for the primary
 374  * domain, possible trusted domains and the selected domain
 375  * controller.
 376  *
 377  * Before adding the new entries existing entries of type
 378  * primary and trusted will be removed from cache.
 379  */
 380 void
 381 smb_domain_update(smb_domainex_t *dxi)
 382 {
 383         smb_domain_t *dcnode;
 384         int i;
 385 
 386         if (smb_dcache_lock(SMB_DCACHE_WRLOCK) != SMB_DOMAIN_SUCCESS)
 387                 return;
 388 
 389         dcnode = list_head(&smb_dcache.dc_cache);
 390         while (dcnode) {
 391                 if ((dcnode->di_type == SMB_DOMAIN_PRIMARY) ||
 392                     (dcnode->di_type == SMB_DOMAIN_TRUSTED)) {


 503     smb_domain_t *di)
 504 {
 505         if (sid == NULL || nb_domain == NULL || fq_domain == NULL ||
 506             di == NULL)
 507                 return;
 508 
 509         (void) strlcpy(di->di_sid, sid, SMB_SID_STRSZ);
 510         (void) strlcpy(di->di_nbname, nb_domain, NETBIOS_NAME_SZ);
 511         (void) smb_strupr(di->di_nbname);
 512         (void) strlcpy(di->di_fqname, fq_domain, MAXHOSTNAMELEN);
 513         di->di_binsid = NULL;
 514 }
 515 
 516 void
 517 smb_domain_set_dns_info(char *sid, char *nb_domain, char *fq_domain,
 518     char *forest, char *guid, smb_domain_t *di)
 519 {
 520         if (di == NULL || forest == NULL || guid == NULL)
 521                 return;
 522 
 523         /* Caller zeros out *di before this. */
 524         smb_domain_set_basic_info(sid, nb_domain, fq_domain, di);
 525         (void) strlcpy(di->di_u.di_dns.ddi_forest, forest, MAXHOSTNAMELEN);
 526         (void) strlcpy(di->di_u.di_dns.ddi_guid, guid,
 527             UUID_PRINTABLE_STRING_LENGTH);
 528 }
 529 
 530 void
 531 smb_domain_set_trust_info(char *sid, char *nb_domain, char *fq_domain,
 532     uint32_t trust_dir, uint32_t trust_type, uint32_t trust_attrs,
 533     smb_domain_t *di)
 534 {
 535         smb_domain_trust_t *ti;
 536 
 537         if (di == NULL)
 538                 return;
 539 
 540         /* Caller zeros out *di before this. */
 541         di->di_type = SMB_DOMAIN_TRUSTED;
 542         ti = &di->di_u.di_trust;
 543         smb_domain_set_basic_info(sid, nb_domain, fq_domain, di);
 544         ti->dti_trust_direction = trust_dir;
 545         ti->dti_trust_type = trust_type;
 546         ti->dti_trust_attrs = trust_attrs;
 547 }
 548 
 549 /*
 550  * Remove the /var/run/smb/domains file.
 551  */
 552 static void
 553 smb_domain_unlink(void)
 554 {
 555         char fname[MAXPATHLEN];
 556 
 557         (void) snprintf(fname, MAXPATHLEN, "%s/%s",
 558             SMB_VARRUN_DIR, SMB_DOMAINS_FILE);
 559         (void) unlink(fname);
 560 }
 561 
 562 /*
 563  * Add an entry for the local domain to the domain cache
 564  */
 565 static uint32_t
 566 smb_domain_add_local(void)
 567 {
 568         char *lsidstr;
 569         char hostname[NETBIOS_NAME_SZ];
 570         char fq_name[MAXHOSTNAMELEN];
 571         smb_domain_t di;
 572 
 573         if ((lsidstr = smb_config_get_localsid()) == NULL)
 574                 return (SMB_DOMAIN_NOMACHINE_SID);
 575 
 576         if (smb_getnetbiosname(hostname, NETBIOS_NAME_SZ) != 0) {
 577                 free(lsidstr);
 578                 return (SMB_DOMAIN_NOMACHINE_SID);
 579         }
 580 
 581         bzero(&di, sizeof (di));
 582         *fq_name = '\0';
 583         (void) smb_getfqhostname(fq_name, MAXHOSTNAMELEN);
 584         smb_domain_set_basic_info(lsidstr, hostname, fq_name, &di);
 585         (void) smb_domain_add(SMB_DOMAIN_LOCAL, &di);
 586 
 587         free(lsidstr);
 588         return (SMB_DOMAIN_SUCCESS);
 589 }
 590 
 591 /*
 592  * Add an entry for the primary domain to the domain cache
 593  */
 594 static uint32_t
 595 smb_domain_add_primary(uint32_t secmode)
 596 {
 597         char sidstr[SMB_SID_STRSZ];
 598         char fq_name[MAXHOSTNAMELEN];
 599         char nb_name[NETBIOS_NAME_SZ];
 600         smb_domain_t di;
 601         int rc;
 602 
 603         if (secmode != SMB_SECMODE_DOMAIN)
 604                 return (SMB_DOMAIN_SUCCESS);
 605 
 606         rc = smb_config_getstr(SMB_CI_DOMAIN_SID, sidstr, sizeof (sidstr));
 607         if (rc != SMBD_SMF_OK)
 608                 return (SMB_DOMAIN_NODOMAIN_SID);
 609 
 610         rc = smb_config_getstr(SMB_CI_DOMAIN_NAME, nb_name, NETBIOS_NAME_SZ);
 611         if ((rc != SMBD_SMF_OK) || (*nb_name == '\0'))
 612                 return (SMB_DOMAIN_NODOMAIN_NAME);
 613 
 614         bzero(&di, sizeof (di));
 615         (void) smb_getfqdomainname(fq_name, MAXHOSTNAMELEN);
 616         smb_domain_set_basic_info(sidstr, nb_name, fq_name, &di);
 617         (void) smb_domain_add(SMB_DOMAIN_PRIMARY, &di);
 618         return (SMB_DOMAIN_SUCCESS);
 619 }
 620 
 621 /*
 622  * Initialize the domain cache.
 623  * This function does not populate the cache.
 624  */
 625 static void
 626 smb_dcache_create(void)
 627 {
 628         (void) mutex_lock(&smb_dcache.dc_mtx);
 629         if (smb_dcache.dc_state != SMB_DCACHE_STATE_NONE) {
 630                 (void) mutex_unlock(&smb_dcache.dc_mtx);
 631                 return;
 632         }
 633 
 634         list_create(&smb_dcache.dc_cache, sizeof (smb_domain_t),
 635             offsetof(smb_domain_t, di_lnd));
 636 
 637         smb_dcache.dc_nops = 0;
 638         bzero(&smb_dcache.dc_dci, sizeof (smb_dcache.dc_dci));
 639         smb_dcache.dc_dci_valid = B_FALSE;
 640         smb_dcache.dc_state = SMB_DCACHE_STATE_READY;
 641         (void) mutex_unlock(&smb_dcache.dc_mtx);
 642 }
 643 
 644 /*
 645  * Removes and frees all the cache entries
 646  */
 647 static void
 648 smb_dcache_flush(void)
 649 {
 650         smb_domain_t *di;
 651 
 652         (void) rw_wrlock(&smb_dcache.dc_cache_lck);
 653         while ((di = list_head(&smb_dcache.dc_cache)) != NULL)
 654                 smb_dcache_remove(di);
 655         (void) rw_unlock(&smb_dcache.dc_cache_lck);
 656 }
 657 
 658 /*
 659  * Destroys the cache.


 676         }
 677         (void) mutex_unlock(&smb_dcache.dc_mtx);
 678 }
 679 
 680 /*
 681  * Lock the cache with the specified mode.
 682  * If the cache is in updating state and a read lock is
 683  * requested, the lock won't be granted until either the
 684  * update is finished or SMB_DCACHE_UPDATE_WAIT has passed.
 685  *
 686  * Whenever a lock is granted, the number of inflight cache
 687  * operations is incremented.
 688  */
 689 static uint32_t
 690 smb_dcache_lock(int mode)
 691 {
 692         (void) mutex_lock(&smb_dcache.dc_mtx);
 693         switch (smb_dcache.dc_state) {
 694         case SMB_DCACHE_STATE_NONE:
 695         case SMB_DCACHE_STATE_DESTROYING:
 696         default:
 697                 (void) mutex_unlock(&smb_dcache.dc_mtx);
 698                 return (SMB_DOMAIN_INTERNAL_ERR);
 699 
 700         case SMB_DCACHE_STATE_UPDATING:
 701                 if (mode == SMB_DCACHE_RDLOCK) {
 702                         /*
 703                          * Read operations should wait until the update
 704                          * is completed.
 705                          */
 706                         if (!smb_dcache_wait()) {
 707                                 (void) mutex_unlock(&smb_dcache.dc_mtx);
 708                                 return (SMB_DOMAIN_INTERNAL_ERR);
 709                         }
 710                 }
 711                 /* FALLTHROUGH */
 712 
 713         case SMB_DCACHE_STATE_READY:
 714                 smb_dcache.dc_nops++;
 715                 break;
 716         }
 717         (void) mutex_unlock(&smb_dcache.dc_mtx);
 718 
 719         /*
 720          * Lock has to be taken outside the mutex otherwise
 721          * there could be a deadlock
 722          */
 723         if (mode == SMB_DCACHE_RDLOCK)
 724                 (void) rw_rdlock(&smb_dcache.dc_cache_lck);
 725         else
 726                 (void) rw_wrlock(&smb_dcache.dc_cache_lck);
 727 
 728         return (SMB_DOMAIN_SUCCESS);
 729 }
 730 
 731 /*
 732  * Decrement the number of inflight operations and then unlock.
 733  */


 758                 return (SMB_DOMAIN_NO_MEMORY);
 759         }
 760 
 761         list_insert_tail(&smb_dcache.dc_cache, dcnode);
 762         return (SMB_DOMAIN_SUCCESS);
 763 }
 764 
 765 static void
 766 smb_dcache_remove(smb_domain_t *di)
 767 {
 768         list_remove(&smb_dcache.dc_cache, di);
 769         smb_sid_free(di->di_binsid);
 770         free(di);
 771 }
 772 
 773 static void
 774 smb_dcache_setdc(const smb_dcinfo_t *dci)
 775 {
 776         (void) mutex_lock(&smb_dcache.dc_mtx);
 777         smb_dcache.dc_dci = *dci; /* struct assignment! */
 778         smb_dcache.dc_dci_valid = B_TRUE;
 779         (void) cond_broadcast(&smb_dcache.dc_dci_cv);
 780         (void) mutex_unlock(&smb_dcache.dc_mtx);
 781 }
 782 
 783 /*
 784  * Get information about our domain controller.  If the wait arg
 785  * is true, wait for the DC locator to finish before copying.
 786  * Returns TRUE on success (have DC info).
 787  */
 788 static boolean_t
 789 smb_dcache_getdc(smb_dcinfo_t *dci, boolean_t wait)
 790 {
 791         timestruc_t to;
 792         boolean_t rv;
 793         int err;
 794 
 795         to.tv_sec = time(NULL) + SMB_DCACHE_UPDATE_WAIT;
 796         to.tv_nsec = 0;
 797 
 798         (void) mutex_lock(&smb_dcache.dc_mtx);
 799 
 800         while (wait && !smb_dcache.dc_dci_valid) {
 801                 err = cond_timedwait(&smb_dcache.dc_dci_cv,
 802                     &smb_dcache.dc_mtx, &to);
 803                 if (err == ETIME)
 804                         break;
 805         }
 806         *dci = smb_dcache.dc_dci; /* struct assignment! */
 807         rv = smb_dcache.dc_dci_valid;
 808 
 809         (void) mutex_unlock(&smb_dcache.dc_mtx);
 810 
 811         return (rv);
 812 }
 813 
 814 /*
 815  * Waits for SMB_DCACHE_UPDATE_WAIT seconds if cache is in
 816  * UPDATING state. Upon wake up returns true if cache is
 817  * ready to be used, otherwise it returns false.
 818  */
 819 static boolean_t
 820 smb_dcache_wait(void)
 821 {
 822         timestruc_t to;
 823         int err;
 824 
 825         assert(MUTEX_HELD(&smb_dcache.dc_mtx));
 826 
 827         to.tv_sec = time(NULL) + SMB_DCACHE_UPDATE_WAIT;
 828         to.tv_nsec = 0;
 829         while (smb_dcache.dc_state == SMB_DCACHE_STATE_UPDATING) {
 830                 err = cond_timedwait(&smb_dcache.dc_cv,
 831                     &smb_dcache.dc_mtx, &to);
 832                 if (err == ETIME)
 833                         break;
 834         }
 835 
 836         return (smb_dcache.dc_state == SMB_DCACHE_STATE_READY);
 837 }
 838 
 839 /*
 840  * Transfers the cache into UPDATING state, this will ensure
 841  * any read access to the cache will be stalled until the
 842  * update is finished. This is to avoid providing incomplete,
 843  * inconsistent or stale information.
 844  *
 845  * If another thread is already updating the cache, other
 846  * callers will wait until cache is no longer in UPDATING
 847  * state. The return code is decided based on the new
 848  * state of the cache.
 849  */
 850 static uint32_t