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,11 +20,11 @@
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
- * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+ * 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,10 +35,11 @@
#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,14 +69,17 @@
#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;
+ 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,11 +92,11 @@
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 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,10 +115,11 @@
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,32 +292,51 @@
}
/*
* 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)
- rv = smb_dcache_getdc(&dxi->d_dci);
+ if (!rv) {
+ syslog(LOG_ERR, "smb_domain_getinfo: no primary domain");
+ return (B_FALSE);
+ }
- return (rv);
+ /*
+ * 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);
+ (void) smb_dcache_getdc(dci, B_FALSE);
}
/*
* Transfer the cache to updating state.
* In this state any request for reading the cache would
@@ -332,10 +356,22 @@
{
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,10 +518,11 @@
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,10 +535,11 @@
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,10 +576,11 @@
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,10 +609,11 @@
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,10 +634,11 @@
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,10 +691,11 @@
{
(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,12 +706,13 @@
if (!smb_dcache_wait()) {
(void) mutex_unlock(&smb_dcache.dc_mtx);
return (SMB_DOMAIN_INTERNAL_ERR);
}
}
+ /* FALLTHROUGH */
- default:
+ case SMB_DCACHE_STATE_READY:
smb_dcache.dc_nops++;
break;
}
(void) mutex_unlock(&smb_dcache.dc_mtx);
@@ -730,23 +773,44 @@
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);
}
/*
- * Return B_TRUE if we have DC information.
+ * 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)
+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 (dci->dc_name[0] != '\0');
+
+ return (rv);
}
/*
* Waits for SMB_DCACHE_UPDATE_WAIT seconds if cache is in
* UPDATING state. Upon wake up returns true if cache is
@@ -756,14 +820,16 @@
smb_dcache_wait(void)
{
timestruc_t to;
int err;
- to.tv_sec = SMB_DCACHE_UPDATE_WAIT;
+ 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_reltimedwait(&smb_dcache.dc_cv,
+ err = cond_timedwait(&smb_dcache.dc_cv,
&smb_dcache.dc_mtx, &to);
if (err == ETIME)
break;
}