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

Split Close
Expand all
Collapse all
          --- old/usr/src/lib/smbsrv/libsmb/common/smb_domain.c
          +++ new/usr/src/lib/smbsrv/libsmb/common/smb_domain.c
↓ open down ↓ 14 lines elided ↑ open up ↑
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  /*
  22   22   * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23   23   * Use is subject to license terms.
  24   24   *
  25      - * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
       25 + * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
  26   26   */
  27   27  
  28   28  /*
  29   29   * This file defines the domain environment values and the domain
  30   30   * database interface. The database is a single linked list of
  31   31   * structures containing domain type, name and SID information.
  32   32   */
  33   33  
  34   34  #include <sys/types.h>
  35   35  #include <sys/stat.h>
  36   36  #include <sys/list.h>
  37   37  #include <stdio.h>
  38   38  #include <strings.h>
  39   39  #include <string.h>
       40 +#include <syslog.h>
  40   41  #include <unistd.h>
  41   42  #include <stdlib.h>
  42   43  #include <synch.h>
  43   44  #include <pwd.h>
  44   45  #include <grp.h>
  45   46  #include <assert.h>
  46   47  
  47   48  #include <smbsrv/smbinfo.h>
  48   49  #include <smbsrv/string.h>
  49   50  #include <smbsrv/smb_sid.h>
↓ open down ↓ 13 lines elided ↑ open up ↑
  63   64  
  64   65  /*
  65   66   * Cache lock modes
  66   67   */
  67   68  #define SMB_DCACHE_RDLOCK       0
  68   69  #define SMB_DCACHE_WRLOCK       1
  69   70  
  70   71  typedef struct smb_domain_cache {
  71   72          list_t          dc_cache;
  72   73          rwlock_t        dc_cache_lck;
  73      -        mutex_t         dc_mtx;
  74      -        cond_t          dc_cv;
  75   74          uint32_t        dc_state;
  76   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;
  77   81          smb_dcinfo_t    dc_dci;
  78   82  } smb_domain_cache_t;
  79   83  
  80   84  static smb_domain_cache_t smb_dcache;
  81   85  
  82   86  static uint32_t smb_domain_add(smb_domain_type_t, smb_domain_t *);
  83   87  static uint32_t smb_domain_add_local(void);
  84   88  static uint32_t smb_domain_add_primary(uint32_t);
  85   89  static void smb_domain_unlink(void);
  86   90  
  87   91  static void smb_dcache_create(void);
  88   92  static void smb_dcache_destroy(void);
  89   93  static uint32_t smb_dcache_lock(int);
  90   94  static void smb_dcache_unlock(void);
  91   95  static void smb_dcache_remove(smb_domain_t *);
  92   96  static uint32_t smb_dcache_add(smb_domain_t *);
  93      -static boolean_t smb_dcache_getdc(smb_dcinfo_t *);
       97 +static boolean_t smb_dcache_getdc(smb_dcinfo_t *, boolean_t);
  94   98  static void smb_dcache_setdc(const smb_dcinfo_t *);
  95   99  static boolean_t smb_dcache_wait(void);
  96  100  static uint32_t smb_dcache_updating(void);
  97  101  static void smb_dcache_ready(void);
  98  102  
  99  103  /*
 100  104   * domain cache one time initialization. This function should
 101  105   * only be called during service startup.
 102  106   *
 103  107   * Returns 0 on success and an error code on failure.
↓ open down ↓ 2 lines elided ↑ open up ↑
 106  110  smb_domain_init(uint32_t secmode)
 107  111  {
 108  112          smb_domain_t di;
 109  113          int rc;
 110  114  
 111  115          smb_dcache_create();
 112  116  
 113  117          if ((rc = smb_domain_add_local()) != 0)
 114  118                  return (rc);
 115  119  
      120 +        bzero(&di, sizeof (di));
 116  121          smb_domain_set_basic_info(NT_BUILTIN_DOMAIN_SIDSTR, "BUILTIN", "", &di);
 117  122          (void) smb_domain_add(SMB_DOMAIN_BUILTIN, &di);
 118  123  
 119  124          return (smb_domain_add_primary(secmode));
 120  125  }
 121  126  
 122  127  /*
 123  128   * Destroys the cache upon service termination
 124  129   */
 125  130  void
↓ open down ↓ 156 lines elided ↑ open up ↑
 282  287                  dcnode = list_next(&smb_dcache.dc_cache, dcnode);
 283  288          }
 284  289  
 285  290          smb_dcache_unlock();
 286  291          return (found);
 287  292  }
 288  293  
 289  294  /*
 290  295   * Returns primary domain information plus the name of
 291  296   * the selected domain controller.
      297 + *
      298 + * Returns TRUE on success.
 292  299   */
 293  300  boolean_t
 294  301  smb_domain_getinfo(smb_domainex_t *dxi)
 295  302  {
 296  303          boolean_t rv;
 297  304  
 298  305          /* Note: this waits for the dcache lock. */
 299  306          rv = smb_domain_lookup_type(SMB_DOMAIN_PRIMARY, &dxi->d_primary);
 300      -        if (rv)
 301      -                rv = smb_dcache_getdc(&dxi->d_dci);
      307 +        if (!rv) {
      308 +                syslog(LOG_ERR, "smb_domain_getinfo: no primary domain");
      309 +                return (B_FALSE);
      310 +        }
 302  311  
 303      -        return (rv);
      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);
 304  328  }
 305  329  
 306  330  /*
 307  331   * Get the name of the current DC (if any)
 308  332   * Does NOT block.
 309  333   */
 310  334  void
 311  335  smb_domain_current_dc(smb_dcinfo_t *dci)
 312  336  {
 313      -        (void) smb_dcache_getdc(dci);
      337 +        (void) smb_dcache_getdc(dci, B_FALSE);
 314  338  }
 315  339  
 316  340  /*
 317  341   * Transfer the cache to updating state.
 318  342   * In this state any request for reading the cache would
 319  343   * be blocked until the update is finished.
 320  344   */
 321  345  uint32_t
 322  346  smb_domain_start_update(void)
 323  347  {
↓ open down ↓ 3 lines elided ↑ open up ↑
 327  351  /*
 328  352   * Transfer the cache from updating to ready state.
 329  353   */
 330  354  void
 331  355  smb_domain_end_update(void)
 332  356  {
 333  357          smb_dcache_ready();
 334  358  }
 335  359  
 336  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 +/*
 337  373   * Updates the cache with given information for the primary
 338  374   * domain, possible trusted domains and the selected domain
 339  375   * controller.
 340  376   *
 341  377   * Before adding the new entries existing entries of type
 342  378   * primary and trusted will be removed from cache.
 343  379   */
 344  380  void
 345  381  smb_domain_update(smb_domainex_t *dxi)
 346  382  {
↓ open down ↓ 130 lines elided ↑ open up ↑
 477  513          di->di_binsid = NULL;
 478  514  }
 479  515  
 480  516  void
 481  517  smb_domain_set_dns_info(char *sid, char *nb_domain, char *fq_domain,
 482  518      char *forest, char *guid, smb_domain_t *di)
 483  519  {
 484  520          if (di == NULL || forest == NULL || guid == NULL)
 485  521                  return;
 486  522  
      523 +        /* Caller zeros out *di before this. */
 487  524          smb_domain_set_basic_info(sid, nb_domain, fq_domain, di);
 488  525          (void) strlcpy(di->di_u.di_dns.ddi_forest, forest, MAXHOSTNAMELEN);
 489  526          (void) strlcpy(di->di_u.di_dns.ddi_guid, guid,
 490  527              UUID_PRINTABLE_STRING_LENGTH);
 491  528  }
 492  529  
 493  530  void
 494  531  smb_domain_set_trust_info(char *sid, char *nb_domain, char *fq_domain,
 495  532      uint32_t trust_dir, uint32_t trust_type, uint32_t trust_attrs,
 496  533      smb_domain_t *di)
 497  534  {
 498  535          smb_domain_trust_t *ti;
 499  536  
 500  537          if (di == NULL)
 501  538                  return;
 502  539  
      540 +        /* Caller zeros out *di before this. */
 503  541          di->di_type = SMB_DOMAIN_TRUSTED;
 504  542          ti = &di->di_u.di_trust;
 505  543          smb_domain_set_basic_info(sid, nb_domain, fq_domain, di);
 506  544          ti->dti_trust_direction = trust_dir;
 507  545          ti->dti_trust_type = trust_type;
 508  546          ti->dti_trust_attrs = trust_attrs;
 509  547  }
 510  548  
 511  549  /*
 512  550   * Remove the /var/run/smb/domains file.
↓ open down ↓ 20 lines elided ↑ open up ↑
 533  571          smb_domain_t di;
 534  572  
 535  573          if ((lsidstr = smb_config_get_localsid()) == NULL)
 536  574                  return (SMB_DOMAIN_NOMACHINE_SID);
 537  575  
 538  576          if (smb_getnetbiosname(hostname, NETBIOS_NAME_SZ) != 0) {
 539  577                  free(lsidstr);
 540  578                  return (SMB_DOMAIN_NOMACHINE_SID);
 541  579          }
 542  580  
      581 +        bzero(&di, sizeof (di));
 543  582          *fq_name = '\0';
 544  583          (void) smb_getfqhostname(fq_name, MAXHOSTNAMELEN);
 545  584          smb_domain_set_basic_info(lsidstr, hostname, fq_name, &di);
 546  585          (void) smb_domain_add(SMB_DOMAIN_LOCAL, &di);
 547  586  
 548  587          free(lsidstr);
 549  588          return (SMB_DOMAIN_SUCCESS);
 550  589  }
 551  590  
 552  591  /*
↓ open down ↓ 12 lines elided ↑ open up ↑
 565  604                  return (SMB_DOMAIN_SUCCESS);
 566  605  
 567  606          rc = smb_config_getstr(SMB_CI_DOMAIN_SID, sidstr, sizeof (sidstr));
 568  607          if (rc != SMBD_SMF_OK)
 569  608                  return (SMB_DOMAIN_NODOMAIN_SID);
 570  609  
 571  610          rc = smb_config_getstr(SMB_CI_DOMAIN_NAME, nb_name, NETBIOS_NAME_SZ);
 572  611          if ((rc != SMBD_SMF_OK) || (*nb_name == '\0'))
 573  612                  return (SMB_DOMAIN_NODOMAIN_NAME);
 574  613  
      614 +        bzero(&di, sizeof (di));
 575  615          (void) smb_getfqdomainname(fq_name, MAXHOSTNAMELEN);
 576  616          smb_domain_set_basic_info(sidstr, nb_name, fq_name, &di);
 577  617          (void) smb_domain_add(SMB_DOMAIN_PRIMARY, &di);
 578  618          return (SMB_DOMAIN_SUCCESS);
 579  619  }
 580  620  
 581  621  /*
 582  622   * Initialize the domain cache.
 583  623   * This function does not populate the cache.
 584  624   */
↓ open down ↓ 4 lines elided ↑ open up ↑
 589  629          if (smb_dcache.dc_state != SMB_DCACHE_STATE_NONE) {
 590  630                  (void) mutex_unlock(&smb_dcache.dc_mtx);
 591  631                  return;
 592  632          }
 593  633  
 594  634          list_create(&smb_dcache.dc_cache, sizeof (smb_domain_t),
 595  635              offsetof(smb_domain_t, di_lnd));
 596  636  
 597  637          smb_dcache.dc_nops = 0;
 598  638          bzero(&smb_dcache.dc_dci, sizeof (smb_dcache.dc_dci));
      639 +        smb_dcache.dc_dci_valid = B_FALSE;
 599  640          smb_dcache.dc_state = SMB_DCACHE_STATE_READY;
 600  641          (void) mutex_unlock(&smb_dcache.dc_mtx);
 601  642  }
 602  643  
 603  644  /*
 604  645   * Removes and frees all the cache entries
 605  646   */
 606  647  static void
 607  648  smb_dcache_flush(void)
 608  649  {
↓ open down ↓ 36 lines elided ↑ open up ↑
 645  686   * Whenever a lock is granted, the number of inflight cache
 646  687   * operations is incremented.
 647  688   */
 648  689  static uint32_t
 649  690  smb_dcache_lock(int mode)
 650  691  {
 651  692          (void) mutex_lock(&smb_dcache.dc_mtx);
 652  693          switch (smb_dcache.dc_state) {
 653  694          case SMB_DCACHE_STATE_NONE:
 654  695          case SMB_DCACHE_STATE_DESTROYING:
      696 +        default:
 655  697                  (void) mutex_unlock(&smb_dcache.dc_mtx);
 656  698                  return (SMB_DOMAIN_INTERNAL_ERR);
 657  699  
 658  700          case SMB_DCACHE_STATE_UPDATING:
 659  701                  if (mode == SMB_DCACHE_RDLOCK) {
 660  702                          /*
 661  703                           * Read operations should wait until the update
 662  704                           * is completed.
 663  705                           */
 664  706                          if (!smb_dcache_wait()) {
 665  707                                  (void) mutex_unlock(&smb_dcache.dc_mtx);
 666  708                                  return (SMB_DOMAIN_INTERNAL_ERR);
 667  709                          }
 668  710                  }
      711 +                /* FALLTHROUGH */
 669  712  
 670      -        default:
      713 +        case SMB_DCACHE_STATE_READY:
 671  714                  smb_dcache.dc_nops++;
 672  715                  break;
 673  716          }
 674  717          (void) mutex_unlock(&smb_dcache.dc_mtx);
 675  718  
 676  719          /*
 677  720           * Lock has to be taken outside the mutex otherwise
 678  721           * there could be a deadlock
 679  722           */
 680  723          if (mode == SMB_DCACHE_RDLOCK)
↓ open down ↓ 44 lines elided ↑ open up ↑
 725  768          list_remove(&smb_dcache.dc_cache, di);
 726  769          smb_sid_free(di->di_binsid);
 727  770          free(di);
 728  771  }
 729  772  
 730  773  static void
 731  774  smb_dcache_setdc(const smb_dcinfo_t *dci)
 732  775  {
 733  776          (void) mutex_lock(&smb_dcache.dc_mtx);
 734  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);
 735  780          (void) mutex_unlock(&smb_dcache.dc_mtx);
 736  781  }
 737  782  
 738  783  /*
 739      - * Return B_TRUE if we have DC information.
      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).
 740  787   */
 741  788  static boolean_t
 742      -smb_dcache_getdc(smb_dcinfo_t *dci)
      789 +smb_dcache_getdc(smb_dcinfo_t *dci, boolean_t wait)
 743  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 +
 744  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 +        }
 745  806          *dci = smb_dcache.dc_dci; /* struct assignment! */
      807 +        rv = smb_dcache.dc_dci_valid;
      808 +
 746  809          (void) mutex_unlock(&smb_dcache.dc_mtx);
 747      -        return (dci->dc_name[0] != '\0');
      810 +
      811 +        return (rv);
 748  812  }
 749  813  
 750  814  /*
 751  815   * Waits for SMB_DCACHE_UPDATE_WAIT seconds if cache is in
 752  816   * UPDATING state. Upon wake up returns true if cache is
 753  817   * ready to be used, otherwise it returns false.
 754  818   */
 755  819  static boolean_t
 756  820  smb_dcache_wait(void)
 757  821  {
 758  822          timestruc_t to;
 759  823          int err;
 760  824  
 761      -        to.tv_sec = SMB_DCACHE_UPDATE_WAIT;
      825 +        assert(MUTEX_HELD(&smb_dcache.dc_mtx));
      826 +
      827 +        to.tv_sec = time(NULL) + SMB_DCACHE_UPDATE_WAIT;
 762  828          to.tv_nsec = 0;
 763  829          while (smb_dcache.dc_state == SMB_DCACHE_STATE_UPDATING) {
 764      -                err = cond_reltimedwait(&smb_dcache.dc_cv,
      830 +                err = cond_timedwait(&smb_dcache.dc_cv,
 765  831                      &smb_dcache.dc_mtx, &to);
 766  832                  if (err == ETIME)
 767  833                          break;
 768  834          }
 769  835  
 770  836          return (smb_dcache.dc_state == SMB_DCACHE_STATE_READY);
 771  837  }
 772  838  
 773  839  /*
 774  840   * Transfers the cache into UPDATING state, this will ensure
↓ open down ↓ 72 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX