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
        
*** 20,30 ****
   */
  /*
   * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
   * Use is subject to license terms.
   *
!  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
   */
  
  /*
   * This file defines the domain environment values and the domain
   * database interface. The database is a single linked list of
--- 20,30 ----
   */
  /*
   * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
   * Use is subject to license terms.
   *
!  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
   */
  
  /*
   * This file defines the domain environment values and the domain
   * database interface. The database is a single linked list of
*** 35,44 ****
--- 35,45 ----
  #include <sys/stat.h>
  #include <sys/list.h>
  #include <stdio.h>
  #include <strings.h>
  #include <string.h>
+ #include <syslog.h>
  #include <unistd.h>
  #include <stdlib.h>
  #include <synch.h>
  #include <pwd.h>
  #include <grp.h>
*** 68,81 ****
  #define SMB_DCACHE_WRLOCK       1
  
  typedef struct smb_domain_cache {
          list_t          dc_cache;
          rwlock_t        dc_cache_lck;
-         mutex_t         dc_mtx;
-         cond_t          dc_cv;
          uint32_t        dc_state;
          uint32_t        dc_nops;
          smb_dcinfo_t    dc_dci;
  } smb_domain_cache_t;
  
  static smb_domain_cache_t smb_dcache;
  
--- 69,85 ----
  #define SMB_DCACHE_WRLOCK       1
  
  typedef struct smb_domain_cache {
          list_t          dc_cache;
          rwlock_t        dc_cache_lck;
          uint32_t        dc_state;
          uint32_t        dc_nops;
+         mutex_t         dc_mtx;
+         cond_t          dc_cv;
+         /* domain controller information */
+         cond_t          dc_dci_cv;
+         boolean_t       dc_dci_valid;
          smb_dcinfo_t    dc_dci;
  } smb_domain_cache_t;
  
  static smb_domain_cache_t smb_dcache;
  
*** 88,98 ****
  static void smb_dcache_destroy(void);
  static uint32_t smb_dcache_lock(int);
  static void smb_dcache_unlock(void);
  static void smb_dcache_remove(smb_domain_t *);
  static uint32_t smb_dcache_add(smb_domain_t *);
! static boolean_t smb_dcache_getdc(smb_dcinfo_t *);
  static void smb_dcache_setdc(const smb_dcinfo_t *);
  static boolean_t smb_dcache_wait(void);
  static uint32_t smb_dcache_updating(void);
  static void smb_dcache_ready(void);
  
--- 92,102 ----
  static void smb_dcache_destroy(void);
  static uint32_t smb_dcache_lock(int);
  static void smb_dcache_unlock(void);
  static void smb_dcache_remove(smb_domain_t *);
  static uint32_t smb_dcache_add(smb_domain_t *);
! static boolean_t smb_dcache_getdc(smb_dcinfo_t *, boolean_t);
  static void smb_dcache_setdc(const smb_dcinfo_t *);
  static boolean_t smb_dcache_wait(void);
  static uint32_t smb_dcache_updating(void);
  static void smb_dcache_ready(void);
  
*** 111,120 ****
--- 115,125 ----
          smb_dcache_create();
  
          if ((rc = smb_domain_add_local()) != 0)
                  return (rc);
  
+         bzero(&di, sizeof (di));
          smb_domain_set_basic_info(NT_BUILTIN_DOMAIN_SIDSTR, "BUILTIN", "", &di);
          (void) smb_domain_add(SMB_DOMAIN_BUILTIN, &di);
  
          return (smb_domain_add_primary(secmode));
  }
*** 287,318 ****
  }
  
  /*
   * Returns primary domain information plus the name of
   * the selected domain controller.
   */
  boolean_t
  smb_domain_getinfo(smb_domainex_t *dxi)
  {
          boolean_t rv;
  
          /* Note: this waits for the dcache lock. */
          rv = smb_domain_lookup_type(SMB_DOMAIN_PRIMARY, &dxi->d_primary);
!         if (rv)
!                 rv = smb_dcache_getdc(&dxi->d_dci);
  
!         return (rv);
  }
  
  /*
   * Get the name of the current DC (if any)
   * Does NOT block.
   */
  void
  smb_domain_current_dc(smb_dcinfo_t *dci)
  {
!         (void) smb_dcache_getdc(dci);
  }
  
  /*
   * Transfer the cache to updating state.
   * In this state any request for reading the cache would
--- 292,342 ----
  }
  
  /*
   * Returns primary domain information plus the name of
   * the selected domain controller.
+  *
+  * Returns TRUE on success.
   */
  boolean_t
  smb_domain_getinfo(smb_domainex_t *dxi)
  {
          boolean_t rv;
  
          /* Note: this waits for the dcache lock. */
          rv = smb_domain_lookup_type(SMB_DOMAIN_PRIMARY, &dxi->d_primary);
!         if (!rv) {
!                 syslog(LOG_ERR, "smb_domain_getinfo: no primary domain");
!                 return (B_FALSE);
!         }
  
!         /*
!          * The 2nd arg TRUE means this will wait for DC info.
!          *
!          * Note that we do NOT hold the dcache rwlock here
!          * (not even as reader) because we already have what we
!          * need from the dcache (our primary domain) and we don't
!          * want to interfere with the DC locator which will take
!          * the dcache lock as write to update the domain info.
!          */
!         rv = smb_dcache_getdc(&dxi->d_dci, B_TRUE);
!         if (!rv) {
!                 syslog(LOG_ERR, "smb_domain_getinfo: no DC info");
!                 return (B_FALSE);
!         }
! 
!         return (B_TRUE);
  }
  
  /*
   * Get the name of the current DC (if any)
   * Does NOT block.
   */
  void
  smb_domain_current_dc(smb_dcinfo_t *dci)
  {
!         (void) smb_dcache_getdc(dci, B_FALSE);
  }
  
  /*
   * Transfer the cache to updating state.
   * In this state any request for reading the cache would
*** 332,341 ****
--- 356,377 ----
  {
          smb_dcache_ready();
  }
  
  /*
+  * Mark the current domain controller (DC) info invalid
+  * until the DC locator call smb_domain_update().
+  */
+ void
+ smb_domain_bad_dc(void)
+ {
+         (void) mutex_lock(&smb_dcache.dc_mtx);
+         smb_dcache.dc_dci_valid = B_FALSE;
+         (void) mutex_unlock(&smb_dcache.dc_mtx);
+ }
+ 
+ /*
   * Updates the cache with given information for the primary
   * domain, possible trusted domains and the selected domain
   * controller.
   *
   * Before adding the new entries existing entries of type
*** 482,491 ****
--- 518,528 ----
      char *forest, char *guid, smb_domain_t *di)
  {
          if (di == NULL || forest == NULL || guid == NULL)
                  return;
  
+         /* Caller zeros out *di before this. */
          smb_domain_set_basic_info(sid, nb_domain, fq_domain, di);
          (void) strlcpy(di->di_u.di_dns.ddi_forest, forest, MAXHOSTNAMELEN);
          (void) strlcpy(di->di_u.di_dns.ddi_guid, guid,
              UUID_PRINTABLE_STRING_LENGTH);
  }
*** 498,507 ****
--- 535,545 ----
          smb_domain_trust_t *ti;
  
          if (di == NULL)
                  return;
  
+         /* Caller zeros out *di before this. */
          di->di_type = SMB_DOMAIN_TRUSTED;
          ti = &di->di_u.di_trust;
          smb_domain_set_basic_info(sid, nb_domain, fq_domain, di);
          ti->dti_trust_direction = trust_dir;
          ti->dti_trust_type = trust_type;
*** 538,547 ****
--- 576,586 ----
          if (smb_getnetbiosname(hostname, NETBIOS_NAME_SZ) != 0) {
                  free(lsidstr);
                  return (SMB_DOMAIN_NOMACHINE_SID);
          }
  
+         bzero(&di, sizeof (di));
          *fq_name = '\0';
          (void) smb_getfqhostname(fq_name, MAXHOSTNAMELEN);
          smb_domain_set_basic_info(lsidstr, hostname, fq_name, &di);
          (void) smb_domain_add(SMB_DOMAIN_LOCAL, &di);
  
*** 570,579 ****
--- 609,619 ----
  
          rc = smb_config_getstr(SMB_CI_DOMAIN_NAME, nb_name, NETBIOS_NAME_SZ);
          if ((rc != SMBD_SMF_OK) || (*nb_name == '\0'))
                  return (SMB_DOMAIN_NODOMAIN_NAME);
  
+         bzero(&di, sizeof (di));
          (void) smb_getfqdomainname(fq_name, MAXHOSTNAMELEN);
          smb_domain_set_basic_info(sidstr, nb_name, fq_name, &di);
          (void) smb_domain_add(SMB_DOMAIN_PRIMARY, &di);
          return (SMB_DOMAIN_SUCCESS);
  }
*** 594,603 ****
--- 634,644 ----
          list_create(&smb_dcache.dc_cache, sizeof (smb_domain_t),
              offsetof(smb_domain_t, di_lnd));
  
          smb_dcache.dc_nops = 0;
          bzero(&smb_dcache.dc_dci, sizeof (smb_dcache.dc_dci));
+         smb_dcache.dc_dci_valid = B_FALSE;
          smb_dcache.dc_state = SMB_DCACHE_STATE_READY;
          (void) mutex_unlock(&smb_dcache.dc_mtx);
  }
  
  /*
*** 650,659 ****
--- 691,701 ----
  {
          (void) mutex_lock(&smb_dcache.dc_mtx);
          switch (smb_dcache.dc_state) {
          case SMB_DCACHE_STATE_NONE:
          case SMB_DCACHE_STATE_DESTROYING:
+         default:
                  (void) mutex_unlock(&smb_dcache.dc_mtx);
                  return (SMB_DOMAIN_INTERNAL_ERR);
  
          case SMB_DCACHE_STATE_UPDATING:
                  if (mode == SMB_DCACHE_RDLOCK) {
*** 664,675 ****
                          if (!smb_dcache_wait()) {
                                  (void) mutex_unlock(&smb_dcache.dc_mtx);
                                  return (SMB_DOMAIN_INTERNAL_ERR);
                          }
                  }
  
!         default:
                  smb_dcache.dc_nops++;
                  break;
          }
          (void) mutex_unlock(&smb_dcache.dc_mtx);
  
--- 706,718 ----
                          if (!smb_dcache_wait()) {
                                  (void) mutex_unlock(&smb_dcache.dc_mtx);
                                  return (SMB_DOMAIN_INTERNAL_ERR);
                          }
                  }
+                 /* FALLTHROUGH */
  
!         case SMB_DCACHE_STATE_READY:
                  smb_dcache.dc_nops++;
                  break;
          }
          (void) mutex_unlock(&smb_dcache.dc_mtx);
  
*** 730,752 ****
  static void
  smb_dcache_setdc(const smb_dcinfo_t *dci)
  {
          (void) mutex_lock(&smb_dcache.dc_mtx);
          smb_dcache.dc_dci = *dci; /* struct assignment! */
          (void) mutex_unlock(&smb_dcache.dc_mtx);
  }
  
  /*
!  * Return B_TRUE if we have DC information.
   */
  static boolean_t
! smb_dcache_getdc(smb_dcinfo_t *dci)
  {
          (void) mutex_lock(&smb_dcache.dc_mtx);
          *dci = smb_dcache.dc_dci; /* struct assignment! */
          (void) mutex_unlock(&smb_dcache.dc_mtx);
!         return (dci->dc_name[0] != '\0');
  }
  
  /*
   * Waits for SMB_DCACHE_UPDATE_WAIT seconds if cache is in
   * UPDATING state. Upon wake up returns true if cache is
--- 773,816 ----
  static void
  smb_dcache_setdc(const smb_dcinfo_t *dci)
  {
          (void) mutex_lock(&smb_dcache.dc_mtx);
          smb_dcache.dc_dci = *dci; /* struct assignment! */
+         smb_dcache.dc_dci_valid = B_TRUE;
+         (void) cond_broadcast(&smb_dcache.dc_dci_cv);
          (void) mutex_unlock(&smb_dcache.dc_mtx);
  }
  
  /*
!  * Get information about our domain controller.  If the wait arg
!  * is true, wait for the DC locator to finish before copying.
!  * Returns TRUE on success (have DC info).
   */
  static boolean_t
! smb_dcache_getdc(smb_dcinfo_t *dci, boolean_t wait)
  {
+         timestruc_t to;
+         boolean_t rv;
+         int err;
+ 
+         to.tv_sec = time(NULL) + SMB_DCACHE_UPDATE_WAIT;
+         to.tv_nsec = 0;
+ 
          (void) mutex_lock(&smb_dcache.dc_mtx);
+ 
+         while (wait && !smb_dcache.dc_dci_valid) {
+                 err = cond_timedwait(&smb_dcache.dc_dci_cv,
+                     &smb_dcache.dc_mtx, &to);
+                 if (err == ETIME)
+                         break;
+         }
          *dci = smb_dcache.dc_dci; /* struct assignment! */
+         rv = smb_dcache.dc_dci_valid;
+ 
          (void) mutex_unlock(&smb_dcache.dc_mtx);
! 
!         return (rv);
  }
  
  /*
   * Waits for SMB_DCACHE_UPDATE_WAIT seconds if cache is in
   * UPDATING state. Upon wake up returns true if cache is
*** 756,769 ****
  smb_dcache_wait(void)
  {
          timestruc_t to;
          int err;
  
!         to.tv_sec = SMB_DCACHE_UPDATE_WAIT;
          to.tv_nsec = 0;
          while (smb_dcache.dc_state == SMB_DCACHE_STATE_UPDATING) {
!                 err = cond_reltimedwait(&smb_dcache.dc_cv,
                      &smb_dcache.dc_mtx, &to);
                  if (err == ETIME)
                          break;
          }
  
--- 820,835 ----
  smb_dcache_wait(void)
  {
          timestruc_t to;
          int err;
  
!         assert(MUTEX_HELD(&smb_dcache.dc_mtx));
! 
!         to.tv_sec = time(NULL) + SMB_DCACHE_UPDATE_WAIT;
          to.tv_nsec = 0;
          while (smb_dcache.dc_state == SMB_DCACHE_STATE_UPDATING) {
!                 err = cond_timedwait(&smb_dcache.dc_cv,
                      &smb_dcache.dc_mtx, &to);
                  if (err == ETIME)
                          break;
          }