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;
}