xref: /onnv-gate/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_domain.c (revision 8474:7803efd2fa77)
18334SJose.Borrego@Sun.COM /*
28334SJose.Borrego@Sun.COM  * CDDL HEADER START
38334SJose.Borrego@Sun.COM  *
48334SJose.Borrego@Sun.COM  * The contents of this file are subject to the terms of the
58334SJose.Borrego@Sun.COM  * Common Development and Distribution License (the "License").
68334SJose.Borrego@Sun.COM  * You may not use this file except in compliance with the License.
78334SJose.Borrego@Sun.COM  *
88334SJose.Borrego@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
98334SJose.Borrego@Sun.COM  * or http://www.opensolaris.org/os/licensing.
108334SJose.Borrego@Sun.COM  * See the License for the specific language governing permissions
118334SJose.Borrego@Sun.COM  * and limitations under the License.
128334SJose.Borrego@Sun.COM  *
138334SJose.Borrego@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
148334SJose.Borrego@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
158334SJose.Borrego@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
168334SJose.Borrego@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
178334SJose.Borrego@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
188334SJose.Borrego@Sun.COM  *
198334SJose.Borrego@Sun.COM  * CDDL HEADER END
208334SJose.Borrego@Sun.COM  */
218334SJose.Borrego@Sun.COM /*
22*8474SJose.Borrego@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
238334SJose.Borrego@Sun.COM  * Use is subject to license terms.
248334SJose.Borrego@Sun.COM  */
258334SJose.Borrego@Sun.COM 
268334SJose.Borrego@Sun.COM #include <syslog.h>
278334SJose.Borrego@Sun.COM #include <synch.h>
288334SJose.Borrego@Sun.COM #include <pthread.h>
298334SJose.Borrego@Sun.COM #include <unistd.h>
308334SJose.Borrego@Sun.COM #include <string.h>
318334SJose.Borrego@Sun.COM #include <strings.h>
328334SJose.Borrego@Sun.COM #include <sys/errno.h>
338334SJose.Borrego@Sun.COM #include <sys/types.h>
348334SJose.Borrego@Sun.COM #include <netinet/in.h>
358334SJose.Borrego@Sun.COM #include <arpa/nameser.h>
368334SJose.Borrego@Sun.COM #include <resolv.h>
378334SJose.Borrego@Sun.COM #include <netdb.h>
388334SJose.Borrego@Sun.COM #include <assert.h>
398334SJose.Borrego@Sun.COM 
408334SJose.Borrego@Sun.COM #include <smbsrv/libsmb.h>
418334SJose.Borrego@Sun.COM #include <smbsrv/libsmbrdr.h>
428334SJose.Borrego@Sun.COM #include <smbsrv/libsmbns.h>
438334SJose.Borrego@Sun.COM #include <smbsrv/libmlsvc.h>
448334SJose.Borrego@Sun.COM 
458334SJose.Borrego@Sun.COM #include <smbsrv/smbinfo.h>
468334SJose.Borrego@Sun.COM #include <smbsrv/ntstatus.h>
478334SJose.Borrego@Sun.COM #include <lsalib.h>
488334SJose.Borrego@Sun.COM 
498334SJose.Borrego@Sun.COM /*
508334SJose.Borrego@Sun.COM  * Domain cache states
518334SJose.Borrego@Sun.COM  */
528334SJose.Borrego@Sun.COM #define	SMB_DCACHE_STATE_INVALID	0
538334SJose.Borrego@Sun.COM #define	SMB_DCACHE_STATE_UPDATING	1
548334SJose.Borrego@Sun.COM #define	SMB_DCACHE_STATE_VALID		2
558334SJose.Borrego@Sun.COM 
568334SJose.Borrego@Sun.COM typedef struct smb_domain_cache {
578334SJose.Borrego@Sun.COM 	uint32_t	c_state;
588334SJose.Borrego@Sun.COM 	smb_domain_t	c_cache;
598334SJose.Borrego@Sun.COM 	mutex_t		c_mtx;
608334SJose.Borrego@Sun.COM 	cond_t		c_cv;
618334SJose.Borrego@Sun.COM } smb_domain_cache_t;
628334SJose.Borrego@Sun.COM 
638334SJose.Borrego@Sun.COM static smb_domain_cache_t smb_dcache;
648334SJose.Borrego@Sun.COM 
658334SJose.Borrego@Sun.COM /* functions to manipulate the domain cache */
668334SJose.Borrego@Sun.COM static void smb_dcache_init(void);
678334SJose.Borrego@Sun.COM static void smb_dcache_updating(void);
688334SJose.Borrego@Sun.COM static void smb_dcache_invalid(void);
698334SJose.Borrego@Sun.COM static void smb_dcache_valid(smb_domain_t *);
708334SJose.Borrego@Sun.COM static void smb_dcache_set(uint32_t, smb_domain_t *);
718334SJose.Borrego@Sun.COM 
728334SJose.Borrego@Sun.COM /*
738334SJose.Borrego@Sun.COM  * DC Locator
748334SJose.Borrego@Sun.COM  */
758334SJose.Borrego@Sun.COM #define	SMB_DCLOCATOR_TIMEOUT	45
768334SJose.Borrego@Sun.COM #define	SMB_IS_FQDN(domain)	(strchr(domain, '.') != NULL)
778334SJose.Borrego@Sun.COM 
788334SJose.Borrego@Sun.COM typedef struct smb_dclocator {
798334SJose.Borrego@Sun.COM 	char sdl_domain[SMB_PI_MAX_DOMAIN];
808334SJose.Borrego@Sun.COM 	char sdl_dc[MAXHOSTNAMELEN];
818334SJose.Borrego@Sun.COM 	boolean_t sdl_locate;
828334SJose.Borrego@Sun.COM 	mutex_t sdl_mtx;
838334SJose.Borrego@Sun.COM 	cond_t sdl_cv;
848334SJose.Borrego@Sun.COM 	uint32_t sdl_status;
858334SJose.Borrego@Sun.COM } smb_dclocator_t;
868334SJose.Borrego@Sun.COM 
878334SJose.Borrego@Sun.COM static smb_dclocator_t smb_dclocator;
888334SJose.Borrego@Sun.COM static pthread_t smb_dclocator_thr;
898334SJose.Borrego@Sun.COM 
908334SJose.Borrego@Sun.COM static void *smb_dclocator_main(void *);
918334SJose.Borrego@Sun.COM static boolean_t smb_dc_discovery(char *, char *, smb_domain_t *);
928334SJose.Borrego@Sun.COM static boolean_t smb_match_domains(char *, char *, uint32_t);
938334SJose.Borrego@Sun.COM static uint32_t smb_domain_query(char *, char *, smb_domain_t *);
948334SJose.Borrego@Sun.COM static void smb_domain_update_tabent(int, lsa_nt_domaininfo_t *);
958334SJose.Borrego@Sun.COM static void smb_domain_populate_table(char *, char *);
968334SJose.Borrego@Sun.COM static boolean_t smb_domain_use_config(char *, smb_domain_t *);
978334SJose.Borrego@Sun.COM 
988334SJose.Borrego@Sun.COM /*
998334SJose.Borrego@Sun.COM  * ===================================================================
1008334SJose.Borrego@Sun.COM  * API to initialize DC locator thread, trigger DC discovery, and
1018334SJose.Borrego@Sun.COM  * get the discovered DC and/or domain information.
1028334SJose.Borrego@Sun.COM  * ===================================================================
1038334SJose.Borrego@Sun.COM  */
1048334SJose.Borrego@Sun.COM 
1058334SJose.Borrego@Sun.COM /*
1068334SJose.Borrego@Sun.COM  * smb_dclocator_init
1078334SJose.Borrego@Sun.COM  *
1088334SJose.Borrego@Sun.COM  * Initialization of the DC locator thread.
1098334SJose.Borrego@Sun.COM  * Returns 0 on success, an error number if thread creation fails.
1108334SJose.Borrego@Sun.COM  */
1118334SJose.Borrego@Sun.COM int
1128334SJose.Borrego@Sun.COM smb_dclocator_init(void)
1138334SJose.Borrego@Sun.COM {
1148334SJose.Borrego@Sun.COM 	pthread_attr_t tattr;
1158334SJose.Borrego@Sun.COM 	int rc;
1168334SJose.Borrego@Sun.COM 
1178334SJose.Borrego@Sun.COM 	smb_dcache_init();
1188334SJose.Borrego@Sun.COM 	(void) pthread_attr_init(&tattr);
1198334SJose.Borrego@Sun.COM 	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
1208334SJose.Borrego@Sun.COM 	rc = pthread_create(&smb_dclocator_thr, &tattr,
1218334SJose.Borrego@Sun.COM 	    smb_dclocator_main, 0);
1228334SJose.Borrego@Sun.COM 	(void) pthread_attr_destroy(&tattr);
1238334SJose.Borrego@Sun.COM 	return (rc);
1248334SJose.Borrego@Sun.COM }
1258334SJose.Borrego@Sun.COM 
1268334SJose.Borrego@Sun.COM /*
1278334SJose.Borrego@Sun.COM  * smb_locate_dc
1288334SJose.Borrego@Sun.COM  *
1298334SJose.Borrego@Sun.COM  * This is the entry point for discovering a domain controller for the
1308334SJose.Borrego@Sun.COM  * specified domain.
1318334SJose.Borrego@Sun.COM  *
1328334SJose.Borrego@Sun.COM  * The actual work of discovering a DC is handled by DC locator thread.
1338334SJose.Borrego@Sun.COM  * All we do here is signal the request and wait for a DC or a timeout.
1348334SJose.Borrego@Sun.COM  *
1358334SJose.Borrego@Sun.COM  * Input parameters:
1368334SJose.Borrego@Sun.COM  *  domain - domain to be discovered (can either be NetBIOS or DNS domain)
1378334SJose.Borrego@Sun.COM  *  dc - preferred DC. If the preferred DC is set to empty string, it
1388334SJose.Borrego@Sun.COM  *       will attempt to discover any DC in the specified domain.
1398334SJose.Borrego@Sun.COM  *
1408334SJose.Borrego@Sun.COM  * Output parameter:
1418334SJose.Borrego@Sun.COM  *  dp - on success, dp will be filled with the discovered DC and domain
1428334SJose.Borrego@Sun.COM  *       information.
1438334SJose.Borrego@Sun.COM  * Returns B_TRUE if the DC/domain info is available.
1448334SJose.Borrego@Sun.COM  */
1458334SJose.Borrego@Sun.COM boolean_t
1468334SJose.Borrego@Sun.COM smb_locate_dc(char *domain, char *dc, smb_domain_t *dp)
1478334SJose.Borrego@Sun.COM {
1488334SJose.Borrego@Sun.COM 	int rc;
1498334SJose.Borrego@Sun.COM 	timestruc_t to;
1508334SJose.Borrego@Sun.COM 	smb_domain_t domain_info;
1518334SJose.Borrego@Sun.COM 
1528334SJose.Borrego@Sun.COM 	if (domain == NULL || *domain == '\0')
1538334SJose.Borrego@Sun.COM 		return (B_FALSE);
1548334SJose.Borrego@Sun.COM 
1558334SJose.Borrego@Sun.COM 	(void) mutex_lock(&smb_dclocator.sdl_mtx);
1568334SJose.Borrego@Sun.COM 
1578334SJose.Borrego@Sun.COM 	if (!smb_dclocator.sdl_locate) {
1588334SJose.Borrego@Sun.COM 		smb_dclocator.sdl_locate = B_TRUE;
1598334SJose.Borrego@Sun.COM 		(void) strlcpy(smb_dclocator.sdl_domain, domain,
1608334SJose.Borrego@Sun.COM 		    SMB_PI_MAX_DOMAIN);
1618334SJose.Borrego@Sun.COM 		(void) strlcpy(smb_dclocator.sdl_dc, dc,
1628334SJose.Borrego@Sun.COM 		    MAXHOSTNAMELEN);
1638334SJose.Borrego@Sun.COM 		(void) cond_broadcast(&smb_dclocator.sdl_cv);
1648334SJose.Borrego@Sun.COM 	}
1658334SJose.Borrego@Sun.COM 
1668334SJose.Borrego@Sun.COM 	while (smb_dclocator.sdl_locate) {
1678334SJose.Borrego@Sun.COM 		to.tv_sec = SMB_DCLOCATOR_TIMEOUT;
1688334SJose.Borrego@Sun.COM 		to.tv_nsec = 0;
1698334SJose.Borrego@Sun.COM 		rc = cond_reltimedwait(&smb_dclocator.sdl_cv,
1708334SJose.Borrego@Sun.COM 		    &smb_dclocator.sdl_mtx, &to);
1718334SJose.Borrego@Sun.COM 
1728334SJose.Borrego@Sun.COM 		if (rc == ETIME)
1738334SJose.Borrego@Sun.COM 			break;
1748334SJose.Borrego@Sun.COM 	}
1758334SJose.Borrego@Sun.COM 
1768334SJose.Borrego@Sun.COM 	if (dp == NULL)
1778334SJose.Borrego@Sun.COM 		dp = &domain_info;
1788334SJose.Borrego@Sun.COM 	rc = smb_domain_getinfo(dp);
1798334SJose.Borrego@Sun.COM 	(void) mutex_unlock(&smb_dclocator.sdl_mtx);
1808334SJose.Borrego@Sun.COM 
1818334SJose.Borrego@Sun.COM 	return (rc);
1828334SJose.Borrego@Sun.COM }
1838334SJose.Borrego@Sun.COM 
1848334SJose.Borrego@Sun.COM /*
1858334SJose.Borrego@Sun.COM  * smb_domain_getinfo
1868334SJose.Borrego@Sun.COM  *
1878334SJose.Borrego@Sun.COM  * If the DC discovery process is underway, this function will wait on
1888334SJose.Borrego@Sun.COM  * a condition variable until the state of SMB domain cache sets to
1898334SJose.Borrego@Sun.COM  * either VALID/INVALID.
1908334SJose.Borrego@Sun.COM  *
1918334SJose.Borrego@Sun.COM  * Returns a copy of the domain cache.
1928334SJose.Borrego@Sun.COM  */
1938334SJose.Borrego@Sun.COM boolean_t
1948334SJose.Borrego@Sun.COM smb_domain_getinfo(smb_domain_t *dp)
1958334SJose.Borrego@Sun.COM {
1968334SJose.Borrego@Sun.COM 	timestruc_t to;
1978334SJose.Borrego@Sun.COM 	int err;
1988334SJose.Borrego@Sun.COM 	boolean_t rc;
1998334SJose.Borrego@Sun.COM 
2008334SJose.Borrego@Sun.COM 	(void) mutex_lock(&smb_dcache.c_mtx);
2018334SJose.Borrego@Sun.COM 	to.tv_sec = SMB_DCLOCATOR_TIMEOUT;
2028334SJose.Borrego@Sun.COM 	to.tv_nsec = 0;
2038334SJose.Borrego@Sun.COM 	while (smb_dcache.c_state == SMB_DCACHE_STATE_UPDATING) {
2048334SJose.Borrego@Sun.COM 		err = cond_reltimedwait(&smb_dcache.c_cv, &smb_dcache.c_mtx,
2058334SJose.Borrego@Sun.COM 		    &to);
2068334SJose.Borrego@Sun.COM 		if (err == ETIME)
2078334SJose.Borrego@Sun.COM 			break;
2088334SJose.Borrego@Sun.COM 	}
2098334SJose.Borrego@Sun.COM 
2108334SJose.Borrego@Sun.COM 	if (smb_dcache.c_state == SMB_DCACHE_STATE_VALID) {
2118334SJose.Borrego@Sun.COM 		bcopy(&smb_dcache.c_cache, dp, sizeof (smb_domain_t));
2128334SJose.Borrego@Sun.COM 		rc = B_TRUE;
2138334SJose.Borrego@Sun.COM 	} else {
2148334SJose.Borrego@Sun.COM 		bzero(dp, sizeof (smb_domain_t));
2158334SJose.Borrego@Sun.COM 		rc = B_FALSE;
2168334SJose.Borrego@Sun.COM 	}
2178334SJose.Borrego@Sun.COM 
2188334SJose.Borrego@Sun.COM 	(void) mutex_unlock(&smb_dcache.c_mtx);
2198334SJose.Borrego@Sun.COM 	return (rc);
2208334SJose.Borrego@Sun.COM }
2218334SJose.Borrego@Sun.COM 
2228334SJose.Borrego@Sun.COM 
2238334SJose.Borrego@Sun.COM /*
2248334SJose.Borrego@Sun.COM  * =====================================================================
2258334SJose.Borrego@Sun.COM  * Private functions used by DC locator thread to manipulate the domain
2268334SJose.Borrego@Sun.COM  * cache.
2278334SJose.Borrego@Sun.COM  * ======================================================================
2288334SJose.Borrego@Sun.COM  */
2298334SJose.Borrego@Sun.COM 
2308334SJose.Borrego@Sun.COM static void
2318334SJose.Borrego@Sun.COM smb_dcache_init(void)
2328334SJose.Borrego@Sun.COM {
2338334SJose.Borrego@Sun.COM 	(void) mutex_lock(&smb_dcache.c_mtx);
2348334SJose.Borrego@Sun.COM 	smb_dcache.c_state = SMB_DCACHE_STATE_INVALID;
2358334SJose.Borrego@Sun.COM 	bzero(&smb_dcache.c_cache, sizeof (smb_domain_t));
2368334SJose.Borrego@Sun.COM 	(void) mutex_unlock(&smb_dcache.c_mtx);
2378334SJose.Borrego@Sun.COM }
2388334SJose.Borrego@Sun.COM 
2398334SJose.Borrego@Sun.COM /*
2408334SJose.Borrego@Sun.COM  * Set the cache state to UPDATING
2418334SJose.Borrego@Sun.COM  */
2428334SJose.Borrego@Sun.COM static void
2438334SJose.Borrego@Sun.COM smb_dcache_updating(void)
2448334SJose.Borrego@Sun.COM {
2458334SJose.Borrego@Sun.COM 	smb_dcache_set(SMB_DCACHE_STATE_UPDATING, NULL);
2468334SJose.Borrego@Sun.COM }
2478334SJose.Borrego@Sun.COM 
2488334SJose.Borrego@Sun.COM /*
2498334SJose.Borrego@Sun.COM  * Set the cache state to INVALID
2508334SJose.Borrego@Sun.COM  */
2518334SJose.Borrego@Sun.COM static void
2528334SJose.Borrego@Sun.COM smb_dcache_invalid(void)
2538334SJose.Borrego@Sun.COM {
2548334SJose.Borrego@Sun.COM 	smb_dcache_set(SMB_DCACHE_STATE_INVALID, NULL);
2558334SJose.Borrego@Sun.COM }
2568334SJose.Borrego@Sun.COM 
2578334SJose.Borrego@Sun.COM /*
2588334SJose.Borrego@Sun.COM  * Set the cache state to VALID and populate the cache
2598334SJose.Borrego@Sun.COM  */
2608334SJose.Borrego@Sun.COM static void
2618334SJose.Borrego@Sun.COM smb_dcache_valid(smb_domain_t *dp)
2628334SJose.Borrego@Sun.COM {
2638334SJose.Borrego@Sun.COM 	smb_dcache_set(SMB_DCACHE_STATE_VALID, dp);
2648334SJose.Borrego@Sun.COM }
2658334SJose.Borrego@Sun.COM 
2668334SJose.Borrego@Sun.COM /*
2678334SJose.Borrego@Sun.COM  * This function will update both the state and the contents of the
2688334SJose.Borrego@Sun.COM  * SMB domain cache.  If one attempts to set the state to
2698334SJose.Borrego@Sun.COM  * SMB_DCACHE_STATE_UPDATING, the domain cache will be updated based
2708334SJose.Borrego@Sun.COM  * on 'dp' argument. Otherwise, 'dp' is ignored.
2718334SJose.Borrego@Sun.COM  */
2728334SJose.Borrego@Sun.COM static void
2738334SJose.Borrego@Sun.COM smb_dcache_set(uint32_t state, smb_domain_t *dp)
2748334SJose.Borrego@Sun.COM {
2758334SJose.Borrego@Sun.COM 	(void) mutex_lock(&smb_dcache.c_mtx);
2768334SJose.Borrego@Sun.COM 	switch (state) {
2778334SJose.Borrego@Sun.COM 	case  SMB_DCACHE_STATE_INVALID:
2788334SJose.Borrego@Sun.COM 		break;
2798334SJose.Borrego@Sun.COM 
2808334SJose.Borrego@Sun.COM 	case SMB_DCACHE_STATE_UPDATING:
2818334SJose.Borrego@Sun.COM 		bzero(&smb_dcache.c_cache, sizeof (smb_domain_t));
2828334SJose.Borrego@Sun.COM 		break;
2838334SJose.Borrego@Sun.COM 
2848334SJose.Borrego@Sun.COM 	case SMB_DCACHE_STATE_VALID:
2858334SJose.Borrego@Sun.COM 		assert(dp);
2868334SJose.Borrego@Sun.COM 		bcopy(dp, &smb_dcache.c_cache, sizeof (smb_domain_t));
2878334SJose.Borrego@Sun.COM 		break;
2888334SJose.Borrego@Sun.COM 
2898334SJose.Borrego@Sun.COM 	default:
2908334SJose.Borrego@Sun.COM 		(void) mutex_unlock(&smb_dcache.c_mtx);
2918334SJose.Borrego@Sun.COM 		return;
2928334SJose.Borrego@Sun.COM 
2938334SJose.Borrego@Sun.COM 	}
2948334SJose.Borrego@Sun.COM 
2958334SJose.Borrego@Sun.COM 	smb_dcache.c_state = state;
2968334SJose.Borrego@Sun.COM 	(void) cond_broadcast(&smb_dcache.c_cv);
2978334SJose.Borrego@Sun.COM 	(void) mutex_unlock(&smb_dcache.c_mtx);
2988334SJose.Borrego@Sun.COM }
2998334SJose.Borrego@Sun.COM 
3008334SJose.Borrego@Sun.COM /*
3018334SJose.Borrego@Sun.COM  * ==========================================================
3028334SJose.Borrego@Sun.COM  * DC discovery functions
3038334SJose.Borrego@Sun.COM  * ==========================================================
3048334SJose.Borrego@Sun.COM  */
3058334SJose.Borrego@Sun.COM 
3068334SJose.Borrego@Sun.COM /*
3078334SJose.Borrego@Sun.COM  * smb_dclocator_main
3088334SJose.Borrego@Sun.COM  *
3098334SJose.Borrego@Sun.COM  * This is the DC discovery thread: it gets woken up whenever someone
3108334SJose.Borrego@Sun.COM  * wants to locate a domain controller.
3118334SJose.Borrego@Sun.COM  *
3128334SJose.Borrego@Sun.COM  * The state of the SMB domain cache will be initialized to
3138334SJose.Borrego@Sun.COM  * SMB_DCACHE_STATE_UPDATING when the discovery process starts and will be
3148334SJose.Borrego@Sun.COM  * transitioned to SMB_DCACHE_STATE_VALID/INVALID depending on the outcome of
3158334SJose.Borrego@Sun.COM  * the discovery.
3168334SJose.Borrego@Sun.COM  *
3178334SJose.Borrego@Sun.COM  * If the discovery process is underway, callers of smb_domain_getinfo()
3188334SJose.Borrego@Sun.COM  * will wait on a condition variable until the state of SMB domain cache
3198334SJose.Borrego@Sun.COM  * sets to either VALID/INVALID.
3208334SJose.Borrego@Sun.COM  *
3218334SJose.Borrego@Sun.COM  * Upon success, the SMB domain cache will be populated with the discovered DC
3228334SJose.Borrego@Sun.COM  * and domain info.
3238334SJose.Borrego@Sun.COM  */
3248334SJose.Borrego@Sun.COM /*ARGSUSED*/
3258334SJose.Borrego@Sun.COM static void *
3268334SJose.Borrego@Sun.COM smb_dclocator_main(void *arg)
3278334SJose.Borrego@Sun.COM {
3288334SJose.Borrego@Sun.COM 	char domain[SMB_PI_MAX_DOMAIN];
3298334SJose.Borrego@Sun.COM 	char sought_dc[MAXHOSTNAMELEN];
3308334SJose.Borrego@Sun.COM 	smb_domain_t dinfo;
3318334SJose.Borrego@Sun.COM 
3328334SJose.Borrego@Sun.COM 	for (;;) {
3338334SJose.Borrego@Sun.COM 		(void) mutex_lock(&smb_dclocator.sdl_mtx);
3348334SJose.Borrego@Sun.COM 
3358334SJose.Borrego@Sun.COM 		while (!smb_dclocator.sdl_locate)
3368334SJose.Borrego@Sun.COM 			(void) cond_wait(&smb_dclocator.sdl_cv,
3378334SJose.Borrego@Sun.COM 			    &smb_dclocator.sdl_mtx);
3388334SJose.Borrego@Sun.COM 
3398334SJose.Borrego@Sun.COM 		(void) strlcpy(domain, smb_dclocator.sdl_domain,
3408334SJose.Borrego@Sun.COM 		    SMB_PI_MAX_DOMAIN);
3418334SJose.Borrego@Sun.COM 		(void) strlcpy(sought_dc, smb_dclocator.sdl_dc, MAXHOSTNAMELEN);
3428334SJose.Borrego@Sun.COM 		(void) mutex_unlock(&smb_dclocator.sdl_mtx);
3438334SJose.Borrego@Sun.COM 
3448334SJose.Borrego@Sun.COM 		smb_dcache_updating();
3458334SJose.Borrego@Sun.COM 		if (smb_dc_discovery(domain, sought_dc, &dinfo))
3468334SJose.Borrego@Sun.COM 			smb_dcache_valid(&dinfo);
3478334SJose.Borrego@Sun.COM 		else
3488334SJose.Borrego@Sun.COM 			smb_dcache_invalid();
3498334SJose.Borrego@Sun.COM 
3508334SJose.Borrego@Sun.COM 		(void) mutex_lock(&smb_dclocator.sdl_mtx);
3518334SJose.Borrego@Sun.COM 		smb_dclocator.sdl_locate = B_FALSE;
3528334SJose.Borrego@Sun.COM 		(void) cond_broadcast(&smb_dclocator.sdl_cv);
3538334SJose.Borrego@Sun.COM 		(void) mutex_unlock(&smb_dclocator.sdl_mtx);
3548334SJose.Borrego@Sun.COM 	}
3558334SJose.Borrego@Sun.COM 
3568334SJose.Borrego@Sun.COM 	/*NOTREACHED*/
3578334SJose.Borrego@Sun.COM 	return (NULL);
3588334SJose.Borrego@Sun.COM }
3598334SJose.Borrego@Sun.COM 
3608334SJose.Borrego@Sun.COM /*
3618334SJose.Borrego@Sun.COM  * smb_dc_discovery
3628334SJose.Borrego@Sun.COM  *
3638334SJose.Borrego@Sun.COM  * If FQDN is specified, DC discovery will be done via DNS query only.
3648334SJose.Borrego@Sun.COM  * If NetBIOS name of a domain is specified, DC discovery thread will
3658334SJose.Borrego@Sun.COM  * use netlogon protocol to locate a DC. Upon failure, it will
3668334SJose.Borrego@Sun.COM  * try to resolve it via DNS, i.e. find out if it is the first label
3678334SJose.Borrego@Sun.COM  * of a DNS domain name. If the corresponding DNS name is found, DC
3688334SJose.Borrego@Sun.COM  * discovery will be done via DNS query.
3698334SJose.Borrego@Sun.COM  *
3708334SJose.Borrego@Sun.COM  * Once the domain controller is found, it then queries the DC for domain
3718334SJose.Borrego@Sun.COM  * information. If the LSA queries fail, the domain information stored in
3728334SJose.Borrego@Sun.COM  * SMF might be used to set the SMB domain cache if the the discovered domain
3738334SJose.Borrego@Sun.COM  * is the same as the previously joined domain.
3748334SJose.Borrego@Sun.COM  *
3758334SJose.Borrego@Sun.COM  * If the fully-qualified domain name is derived from the DNS config
3768334SJose.Borrego@Sun.COM  * file, the NetBIOS domain name specified by the user will be compared
3778334SJose.Borrego@Sun.COM  * against the NetBIOS domain name obtained via LSA query.  If there is
3788334SJose.Borrego@Sun.COM  * a mismatch, the DC discovery will fail since the discovered DC is
3798334SJose.Borrego@Sun.COM  * actually for another domain, whose first label of its FQDN somehow
3808334SJose.Borrego@Sun.COM  * matches with the NetBIOS name of the domain we're interested in.
3818334SJose.Borrego@Sun.COM  */
3828334SJose.Borrego@Sun.COM static boolean_t
3838334SJose.Borrego@Sun.COM smb_dc_discovery(char *domain, char *server, smb_domain_t *dinfo)
3848334SJose.Borrego@Sun.COM {
3858334SJose.Borrego@Sun.COM 	char derived_dnsdomain[MAXHOSTNAMELEN];
3868334SJose.Borrego@Sun.COM 	boolean_t netlogon_ok = B_FALSE;
3878334SJose.Borrego@Sun.COM 
3888334SJose.Borrego@Sun.COM 	*derived_dnsdomain = '\0';
3898334SJose.Borrego@Sun.COM 	if (!SMB_IS_FQDN(domain)) {
3908334SJose.Borrego@Sun.COM 		if (smb_browser_netlogon(domain, dinfo->d_dc, MAXHOSTNAMELEN))
3918334SJose.Borrego@Sun.COM 			netlogon_ok = B_TRUE;
3928334SJose.Borrego@Sun.COM 		else if (!smb_match_domains(domain, derived_dnsdomain,
3938334SJose.Borrego@Sun.COM 		    MAXHOSTNAMELEN))
3948334SJose.Borrego@Sun.COM 			return (B_FALSE);
3958334SJose.Borrego@Sun.COM 	}
3968334SJose.Borrego@Sun.COM 
3978334SJose.Borrego@Sun.COM 	if (!netlogon_ok && !smb_ads_lookup_msdcs(
3988334SJose.Borrego@Sun.COM 	    (SMB_IS_FQDN(domain) ? domain : derived_dnsdomain), server,
3998334SJose.Borrego@Sun.COM 	    dinfo->d_dc, MAXHOSTNAMELEN))
4008334SJose.Borrego@Sun.COM 		return (B_FALSE);
4018334SJose.Borrego@Sun.COM 
4028334SJose.Borrego@Sun.COM 	if ((smb_domain_query(domain, dinfo->d_dc, dinfo)
4038334SJose.Borrego@Sun.COM 	    != NT_STATUS_SUCCESS) &&
4048334SJose.Borrego@Sun.COM 	    (!smb_domain_use_config(domain, dinfo)))
4058334SJose.Borrego@Sun.COM 			return (B_FALSE);
4068334SJose.Borrego@Sun.COM 
4078334SJose.Borrego@Sun.COM 	if (*derived_dnsdomain != '\0' &&
4088334SJose.Borrego@Sun.COM 	    utf8_strcasecmp(domain, dinfo->d_nbdomain))
4098334SJose.Borrego@Sun.COM 		return (B_FALSE);
4108334SJose.Borrego@Sun.COM 
4118334SJose.Borrego@Sun.COM 	/*
4128334SJose.Borrego@Sun.COM 	 * Now that we get the fully-qualified DNS name of the
4138334SJose.Borrego@Sun.COM 	 * domain via LSA query. Verifies ADS configuration
4148334SJose.Borrego@Sun.COM 	 * if we previously locate a DC via NetBIOS. On success,
4158334SJose.Borrego@Sun.COM 	 * ADS cache will be populated.
4168334SJose.Borrego@Sun.COM 	 */
4178334SJose.Borrego@Sun.COM 	if (netlogon_ok) {
4188334SJose.Borrego@Sun.COM 		if (smb_ads_lookup_msdcs(dinfo->d_fqdomain, server,
4198334SJose.Borrego@Sun.COM 		    dinfo->d_dc, MAXHOSTNAMELEN) == 0)
4208334SJose.Borrego@Sun.COM 			return (B_FALSE);
4218334SJose.Borrego@Sun.COM 	}
4228334SJose.Borrego@Sun.COM 
4238334SJose.Borrego@Sun.COM 	return (B_TRUE);
4248334SJose.Borrego@Sun.COM }
4258334SJose.Borrego@Sun.COM 
4268334SJose.Borrego@Sun.COM /*
4278334SJose.Borrego@Sun.COM  * Tries to find a matching DNS domain for the given NetBIOS domain
4288334SJose.Borrego@Sun.COM  * name by checking the first label of system's configured DNS domains.
4298334SJose.Borrego@Sun.COM  * If a match is found, it'll be returned in the passed buffer.
4308334SJose.Borrego@Sun.COM  */
4318334SJose.Borrego@Sun.COM static boolean_t
4328334SJose.Borrego@Sun.COM smb_match_domains(char *nb_domain, char *buf, uint32_t len)
4338334SJose.Borrego@Sun.COM {
4348334SJose.Borrego@Sun.COM 	struct __res_state res_state;
4358334SJose.Borrego@Sun.COM 	int i;
4368334SJose.Borrego@Sun.COM 	char *entry, *p;
4378334SJose.Borrego@Sun.COM 	char first_label[MAXHOSTNAMELEN];
4388334SJose.Borrego@Sun.COM 	boolean_t found;
4398334SJose.Borrego@Sun.COM 
4408334SJose.Borrego@Sun.COM 	if (!nb_domain || !buf)
4418334SJose.Borrego@Sun.COM 		return (B_FALSE);
4428334SJose.Borrego@Sun.COM 
4438334SJose.Borrego@Sun.COM 	*buf = '\0';
4448334SJose.Borrego@Sun.COM 	bzero(&res_state, sizeof (struct __res_state));
4458334SJose.Borrego@Sun.COM 	if (res_ninit(&res_state))
4468334SJose.Borrego@Sun.COM 		return (B_FALSE);
4478334SJose.Borrego@Sun.COM 
4488334SJose.Borrego@Sun.COM 	found = B_FALSE;
4498334SJose.Borrego@Sun.COM 	entry = res_state.defdname;
4508334SJose.Borrego@Sun.COM 	for (i = 0; entry != NULL; i++) {
4518334SJose.Borrego@Sun.COM 		(void) strlcpy(first_label, entry, MAXHOSTNAMELEN);
4528334SJose.Borrego@Sun.COM 		if ((p = strchr(first_label, '.')) != NULL) {
4538334SJose.Borrego@Sun.COM 			*p = '\0';
4548334SJose.Borrego@Sun.COM 			if (strlen(first_label) > 15)
4558334SJose.Borrego@Sun.COM 				first_label[15] = '\0';
4568334SJose.Borrego@Sun.COM 		}
4578334SJose.Borrego@Sun.COM 
4588334SJose.Borrego@Sun.COM 		if (utf8_strcasecmp(nb_domain, first_label) == 0) {
4598334SJose.Borrego@Sun.COM 			found = B_TRUE;
4608334SJose.Borrego@Sun.COM 			(void) strlcpy(buf, entry, len);
4618334SJose.Borrego@Sun.COM 			break;
4628334SJose.Borrego@Sun.COM 		}
4638334SJose.Borrego@Sun.COM 
4648334SJose.Borrego@Sun.COM 		entry = res_state.dnsrch[i];
4658334SJose.Borrego@Sun.COM 	}
4668334SJose.Borrego@Sun.COM 
4678334SJose.Borrego@Sun.COM 
4688334SJose.Borrego@Sun.COM 	res_ndestroy(&res_state);
4698334SJose.Borrego@Sun.COM 	return (found);
4708334SJose.Borrego@Sun.COM }
4718334SJose.Borrego@Sun.COM 
4728334SJose.Borrego@Sun.COM /*
4738334SJose.Borrego@Sun.COM  * smb_domain_query
4748334SJose.Borrego@Sun.COM  *
4758334SJose.Borrego@Sun.COM  * If the the NetBIOS name of an AD domain doesn't match with the
4768334SJose.Borrego@Sun.COM  * first label of its fully-qualified DNS name, it is not possible
4778334SJose.Borrego@Sun.COM  * to derive one name format from another.
4788334SJose.Borrego@Sun.COM  * The missing domain info can be obtained via LSA query, DNS domain info.
4798334SJose.Borrego@Sun.COM  *
4808334SJose.Borrego@Sun.COM  * domain - either NetBIOS or fully-qualified domain name
4818334SJose.Borrego@Sun.COM  *
4828334SJose.Borrego@Sun.COM  */
4838334SJose.Borrego@Sun.COM static uint32_t
4848334SJose.Borrego@Sun.COM smb_domain_query(char *domain, char *server, smb_domain_t *dp)
4858334SJose.Borrego@Sun.COM {
4868334SJose.Borrego@Sun.COM 	uint32_t rc;
4878334SJose.Borrego@Sun.COM 	lsa_info_t info;
4888334SJose.Borrego@Sun.COM 
4898334SJose.Borrego@Sun.COM 	rc = lsa_query_dns_domain_info(server, domain, &info);
4908334SJose.Borrego@Sun.COM 	if (rc == NT_STATUS_SUCCESS) {
4918334SJose.Borrego@Sun.COM 		lsa_dns_domaininfo_t *dnsinfo = &info.i_domain.di_dns;
4928334SJose.Borrego@Sun.COM 		(void) strlcpy(dp->d_nbdomain, dnsinfo->d_nbdomain,
4938334SJose.Borrego@Sun.COM 		    sizeof (dp->d_nbdomain));
4948334SJose.Borrego@Sun.COM 		(void) strlcpy(dp->d_fqdomain, dnsinfo->d_fqdomain,
4958334SJose.Borrego@Sun.COM 		    sizeof (dp->d_fqdomain));
4968334SJose.Borrego@Sun.COM 		(void) strlcpy(dp->d_forest, dnsinfo->d_forest,
4978334SJose.Borrego@Sun.COM 		    sizeof (dp->d_forest));
4988334SJose.Borrego@Sun.COM 		ndr_uuid_unparse((ndr_uuid_t *)&dnsinfo->d_guid, dp->d_guid);
4998334SJose.Borrego@Sun.COM 		smb_sid_free(dnsinfo->d_sid);
5008334SJose.Borrego@Sun.COM 	}
5018334SJose.Borrego@Sun.COM 
5028334SJose.Borrego@Sun.COM 	smb_domain_populate_table(domain, server);
5038334SJose.Borrego@Sun.COM 	return (rc);
5048334SJose.Borrego@Sun.COM }
5058334SJose.Borrego@Sun.COM 
5068334SJose.Borrego@Sun.COM /*
5078334SJose.Borrego@Sun.COM  * smb_domain_populate_table
5088334SJose.Borrego@Sun.COM  *
5098334SJose.Borrego@Sun.COM  * Populates the domain tablele with primary, account and trusted
5108334SJose.Borrego@Sun.COM  * domain info.
5118334SJose.Borrego@Sun.COM  * domain - either NetBIOS or fully-qualified domain name.
5128334SJose.Borrego@Sun.COM  */
5138334SJose.Borrego@Sun.COM static void
5148334SJose.Borrego@Sun.COM smb_domain_populate_table(char *domain, char *server)
5158334SJose.Borrego@Sun.COM {
5168334SJose.Borrego@Sun.COM 	lsa_info_t info;
5178334SJose.Borrego@Sun.COM 	lsa_nt_domaininfo_t *nt_info;
5188334SJose.Borrego@Sun.COM 	int i;
5198334SJose.Borrego@Sun.COM 
5208334SJose.Borrego@Sun.COM 	if (lsa_query_primary_domain_info(server, domain, &info)
5218334SJose.Borrego@Sun.COM 	    == NT_STATUS_SUCCESS) {
5228334SJose.Borrego@Sun.COM 		nt_info = &info.i_domain.di_primary;
5238334SJose.Borrego@Sun.COM 		smb_domain_update_tabent(NT_DOMAIN_PRIMARY, nt_info);
5248334SJose.Borrego@Sun.COM 		lsa_free_info(&info);
5258334SJose.Borrego@Sun.COM 	}
5268334SJose.Borrego@Sun.COM 
5278334SJose.Borrego@Sun.COM 	if (lsa_query_account_domain_info(server, domain, &info)
5288334SJose.Borrego@Sun.COM 	    == NT_STATUS_SUCCESS) {
5298334SJose.Borrego@Sun.COM 		nt_info = &info.i_domain.di_account;
5308334SJose.Borrego@Sun.COM 		smb_domain_update_tabent(NT_DOMAIN_ACCOUNT, nt_info);
5318334SJose.Borrego@Sun.COM 		lsa_free_info(&info);
5328334SJose.Borrego@Sun.COM 	}
5338334SJose.Borrego@Sun.COM 
5348334SJose.Borrego@Sun.COM 	if (lsa_enum_trusted_domains(server, domain, &info)
5358334SJose.Borrego@Sun.COM 	    == NT_STATUS_SUCCESS) {
5368334SJose.Borrego@Sun.COM 		lsa_trusted_domainlist_t *list = &info.i_domain.di_trust;
5378334SJose.Borrego@Sun.COM 		for (i = 0; i < list->t_num; i++) {
5388334SJose.Borrego@Sun.COM 			nt_info = &list->t_domains[i];
5398334SJose.Borrego@Sun.COM 			smb_domain_update_tabent(NT_DOMAIN_TRUSTED, nt_info);
5408334SJose.Borrego@Sun.COM 		}
5418334SJose.Borrego@Sun.COM 
5428334SJose.Borrego@Sun.COM 		lsa_free_info(&info);
5438334SJose.Borrego@Sun.COM 	}
5448334SJose.Borrego@Sun.COM 
545*8474SJose.Borrego@Sun.COM 	nt_domain_save();
5468334SJose.Borrego@Sun.COM }
5478334SJose.Borrego@Sun.COM 
5488334SJose.Borrego@Sun.COM static void
5498334SJose.Borrego@Sun.COM smb_domain_update_tabent(int domain_type, lsa_nt_domaininfo_t *info)
5508334SJose.Borrego@Sun.COM {
5518334SJose.Borrego@Sun.COM 	nt_domain_t *entry;
5528334SJose.Borrego@Sun.COM 	nt_domain_flush(domain_type);
5538334SJose.Borrego@Sun.COM 	entry = nt_domain_new(domain_type, info->n_domain, info->n_sid);
5548334SJose.Borrego@Sun.COM 	(void) nt_domain_add(entry);
5558334SJose.Borrego@Sun.COM }
5568334SJose.Borrego@Sun.COM 
5578334SJose.Borrego@Sun.COM /*
5588334SJose.Borrego@Sun.COM  * smb_domain_use_config
5598334SJose.Borrego@Sun.COM  *
5608334SJose.Borrego@Sun.COM  * If the domain to be discovered matches the current domain (i.e the
5618334SJose.Borrego@Sun.COM  * value of either domain or fqdn configuration), the output parameter
5628334SJose.Borrego@Sun.COM  * 'dinfo' will be set to the information stored in SMF.
5638334SJose.Borrego@Sun.COM  */
5648334SJose.Borrego@Sun.COM static boolean_t
5658334SJose.Borrego@Sun.COM smb_domain_use_config(char *domain, smb_domain_t *dinfo)
5668334SJose.Borrego@Sun.COM {
5678334SJose.Borrego@Sun.COM 	smb_domain_t orig;
5688334SJose.Borrego@Sun.COM 	boolean_t use;
5698334SJose.Borrego@Sun.COM 
5708334SJose.Borrego@Sun.COM 	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN)
5718334SJose.Borrego@Sun.COM 		return (B_FALSE);
5728334SJose.Borrego@Sun.COM 
5738334SJose.Borrego@Sun.COM 	smb_config_getdomaininfo(orig.d_nbdomain, orig.d_fqdomain,
5748334SJose.Borrego@Sun.COM 	    orig.d_forest, orig.d_guid);
5758334SJose.Borrego@Sun.COM 
5768334SJose.Borrego@Sun.COM 	if (SMB_IS_FQDN(domain)) {
5778334SJose.Borrego@Sun.COM 		use = (utf8_strcasecmp(orig.d_fqdomain, domain) == 0);
5788334SJose.Borrego@Sun.COM 	} else {
5798334SJose.Borrego@Sun.COM 		use = (utf8_strcasecmp(orig.d_nbdomain, domain) == 0);
5808334SJose.Borrego@Sun.COM 	}
5818334SJose.Borrego@Sun.COM 
5828334SJose.Borrego@Sun.COM 	if (use) {
5838334SJose.Borrego@Sun.COM 		(void) strlcpy(dinfo->d_nbdomain, orig.d_nbdomain,
5848334SJose.Borrego@Sun.COM 		    sizeof (dinfo->d_nbdomain));
5858334SJose.Borrego@Sun.COM 		(void) strlcpy(dinfo->d_fqdomain, orig.d_fqdomain,
5868334SJose.Borrego@Sun.COM 		    sizeof (dinfo->d_fqdomain));
5878334SJose.Borrego@Sun.COM 		(void) strlcpy(dinfo->d_forest, orig.d_forest,
5888334SJose.Borrego@Sun.COM 		    sizeof (dinfo->d_forest));
5898334SJose.Borrego@Sun.COM 		(void) bcopy(orig.d_guid, dinfo->d_guid,
5908334SJose.Borrego@Sun.COM 		    sizeof (dinfo->d_guid));
5918334SJose.Borrego@Sun.COM 	}
5928334SJose.Borrego@Sun.COM 
5938334SJose.Borrego@Sun.COM 	return (use);
5948334SJose.Borrego@Sun.COM }
595