xref: /titanic_51/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_domain.c (revision b3700b074e637f8c6991b70754c88a2cfffb246b)
18d7e4166Sjose borrego /*
28d7e4166Sjose borrego  * CDDL HEADER START
38d7e4166Sjose borrego  *
48d7e4166Sjose borrego  * The contents of this file are subject to the terms of the
58d7e4166Sjose borrego  * Common Development and Distribution License (the "License").
68d7e4166Sjose borrego  * You may not use this file except in compliance with the License.
78d7e4166Sjose borrego  *
88d7e4166Sjose borrego  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
98d7e4166Sjose borrego  * or http://www.opensolaris.org/os/licensing.
108d7e4166Sjose borrego  * See the License for the specific language governing permissions
118d7e4166Sjose borrego  * and limitations under the License.
128d7e4166Sjose borrego  *
138d7e4166Sjose borrego  * When distributing Covered Code, include this CDDL HEADER in each
148d7e4166Sjose borrego  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
158d7e4166Sjose borrego  * If applicable, add the following below this CDDL HEADER, with the
168d7e4166Sjose borrego  * fields enclosed by brackets "[]" replaced with your own identifying
178d7e4166Sjose borrego  * information: Portions Copyright [yyyy] [name of copyright owner]
188d7e4166Sjose borrego  *
198d7e4166Sjose borrego  * CDDL HEADER END
208d7e4166Sjose borrego  */
21148c5f43SAlan Wright 
228d7e4166Sjose borrego /*
23148c5f43SAlan Wright  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24*b3700b07SGordon Ross  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
258d7e4166Sjose borrego  */
268d7e4166Sjose borrego 
278d7e4166Sjose borrego #include <syslog.h>
288d7e4166Sjose borrego #include <synch.h>
298d7e4166Sjose borrego #include <pthread.h>
308d7e4166Sjose borrego #include <unistd.h>
318d7e4166Sjose borrego #include <string.h>
328d7e4166Sjose borrego #include <strings.h>
338d7e4166Sjose borrego #include <sys/errno.h>
348d7e4166Sjose borrego #include <sys/types.h>
358d7e4166Sjose borrego #include <netinet/in.h>
368d7e4166Sjose borrego #include <arpa/nameser.h>
378d7e4166Sjose borrego #include <resolv.h>
388d7e4166Sjose borrego #include <netdb.h>
398d7e4166Sjose borrego #include <assert.h>
408d7e4166Sjose borrego 
418d7e4166Sjose borrego #include <smbsrv/libsmb.h>
428d7e4166Sjose borrego #include <smbsrv/libsmbns.h>
438d7e4166Sjose borrego #include <smbsrv/libmlsvc.h>
448d7e4166Sjose borrego 
458d7e4166Sjose borrego #include <smbsrv/smbinfo.h>
468d7e4166Sjose borrego #include <lsalib.h>
47*b3700b07SGordon Ross #include <mlsvc.h>
488d7e4166Sjose borrego 
498d7e4166Sjose borrego /*
508d7e4166Sjose borrego  * DC Locator
518d7e4166Sjose borrego  */
52a0aa776eSAlan Wright #define	SMB_DCLOCATOR_TIMEOUT	45	/* seconds */
538d7e4166Sjose borrego #define	SMB_IS_FQDN(domain)	(strchr(domain, '.') != NULL)
548d7e4166Sjose borrego 
558d7e4166Sjose borrego typedef struct smb_dclocator {
56*b3700b07SGordon Ross 	smb_dcinfo_t	sdl_dci; /* .dc_name .dc_addr */
578d7e4166Sjose borrego 	char		sdl_domain[SMB_PI_MAX_DOMAIN];
588d7e4166Sjose borrego 	boolean_t	sdl_locate;
59*b3700b07SGordon Ross 	boolean_t	sdl_bad_dc;
60*b3700b07SGordon Ross 	boolean_t	sdl_cfg_chg;
618d7e4166Sjose borrego 	mutex_t		sdl_mtx;
628d7e4166Sjose borrego 	cond_t		sdl_cv;
638d7e4166Sjose borrego 	uint32_t	sdl_status;
648d7e4166Sjose borrego } smb_dclocator_t;
658d7e4166Sjose borrego 
668d7e4166Sjose borrego static smb_dclocator_t smb_dclocator;
678d7e4166Sjose borrego static pthread_t smb_dclocator_thr;
688d7e4166Sjose borrego 
69a0aa776eSAlan Wright static void *smb_ddiscover_service(void *);
70a0aa776eSAlan Wright static uint32_t smb_ddiscover_qinfo(char *, char *, smb_domainex_t *);
71a0aa776eSAlan Wright static void smb_ddiscover_enum_trusted(char *, char *, smb_domainex_t *);
72a0aa776eSAlan Wright static uint32_t smb_ddiscover_use_config(char *, smb_domainex_t *);
73a0aa776eSAlan Wright static void smb_domainex_free(smb_domainex_t *);
74*b3700b07SGordon Ross static void smb_set_krb5_realm(char *);
758d7e4166Sjose borrego 
768d7e4166Sjose borrego /*
778d7e4166Sjose borrego  * ===================================================================
788d7e4166Sjose borrego  * API to initialize DC locator thread, trigger DC discovery, and
798d7e4166Sjose borrego  * get the discovered DC and/or domain information.
808d7e4166Sjose borrego  * ===================================================================
818d7e4166Sjose borrego  */
828d7e4166Sjose borrego 
838d7e4166Sjose borrego /*
848d7e4166Sjose borrego  * Initialization of the DC locator thread.
858d7e4166Sjose borrego  * Returns 0 on success, an error number if thread creation fails.
868d7e4166Sjose borrego  */
878d7e4166Sjose borrego int
888d7e4166Sjose borrego smb_dclocator_init(void)
898d7e4166Sjose borrego {
908d7e4166Sjose borrego 	pthread_attr_t tattr;
918d7e4166Sjose borrego 	int rc;
928d7e4166Sjose borrego 
938d7e4166Sjose borrego 	(void) pthread_attr_init(&tattr);
948d7e4166Sjose borrego 	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
958d7e4166Sjose borrego 	rc = pthread_create(&smb_dclocator_thr, &tattr,
96*b3700b07SGordon Ross 	    smb_ddiscover_service, &smb_dclocator);
978d7e4166Sjose borrego 	(void) pthread_attr_destroy(&tattr);
988d7e4166Sjose borrego 	return (rc);
998d7e4166Sjose borrego }
1008d7e4166Sjose borrego 
1018d7e4166Sjose borrego /*
1028d7e4166Sjose borrego  * This is the entry point for discovering a domain controller for the
103*b3700b07SGordon Ross  * specified domain.  Called during join domain, and then periodically
104*b3700b07SGordon Ross  * by smbd_dc_update (the "DC monitor" thread).
1058d7e4166Sjose borrego  *
1068d7e4166Sjose borrego  * The actual work of discovering a DC is handled by DC locator thread.
1078d7e4166Sjose borrego  * All we do here is signal the request and wait for a DC or a timeout.
1088d7e4166Sjose borrego  *
1098d7e4166Sjose borrego  * Input parameters:
1108d7e4166Sjose borrego  *  domain - domain to be discovered (can either be NetBIOS or DNS domain)
1118d7e4166Sjose borrego  *
1128d7e4166Sjose borrego  * Output parameter:
1138d7e4166Sjose borrego  *  dp - on success, dp will be filled with the discovered DC and domain
1148d7e4166Sjose borrego  *       information.
115*b3700b07SGordon Ross  *
1168d7e4166Sjose borrego  * Returns B_TRUE if the DC/domain info is available.
1178d7e4166Sjose borrego  */
1188d7e4166Sjose borrego boolean_t
119*b3700b07SGordon Ross smb_locate_dc(char *domain, smb_domainex_t *dp)
1208d7e4166Sjose borrego {
1218d7e4166Sjose borrego 	int rc;
122*b3700b07SGordon Ross 	boolean_t rv;
1238d7e4166Sjose borrego 	timestruc_t to;
124a0aa776eSAlan Wright 	smb_domainex_t domain_info;
1258d7e4166Sjose borrego 
126*b3700b07SGordon Ross 	if (domain == NULL || *domain == '\0') {
127*b3700b07SGordon Ross 		syslog(LOG_DEBUG, "smb_locate_dc NULL dom");
128*b3700b07SGordon Ross 		smb_set_krb5_realm(NULL);
1298d7e4166Sjose borrego 		return (B_FALSE);
130*b3700b07SGordon Ross 	}
1318d7e4166Sjose borrego 
1328d7e4166Sjose borrego 	(void) mutex_lock(&smb_dclocator.sdl_mtx);
1338d7e4166Sjose borrego 
134*b3700b07SGordon Ross 	if (strcmp(smb_dclocator.sdl_domain, domain)) {
135*b3700b07SGordon Ross 		(void) strlcpy(smb_dclocator.sdl_domain, domain,
136*b3700b07SGordon Ross 		    sizeof (smb_dclocator.sdl_domain));
137*b3700b07SGordon Ross 		smb_dclocator.sdl_cfg_chg = B_TRUE;
138*b3700b07SGordon Ross 		syslog(LOG_DEBUG, "smb_locate_dc new dom=%s", domain);
139*b3700b07SGordon Ross 		smb_set_krb5_realm(domain);
140*b3700b07SGordon Ross 	}
141*b3700b07SGordon Ross 
1428d7e4166Sjose borrego 	if (!smb_dclocator.sdl_locate) {
1438d7e4166Sjose borrego 		smb_dclocator.sdl_locate = B_TRUE;
1448d7e4166Sjose borrego 		(void) cond_broadcast(&smb_dclocator.sdl_cv);
1458d7e4166Sjose borrego 	}
1468d7e4166Sjose borrego 
1478d7e4166Sjose borrego 	while (smb_dclocator.sdl_locate) {
1488d7e4166Sjose borrego 		to.tv_sec = SMB_DCLOCATOR_TIMEOUT;
1498d7e4166Sjose borrego 		to.tv_nsec = 0;
1508d7e4166Sjose borrego 		rc = cond_reltimedwait(&smb_dclocator.sdl_cv,
1518d7e4166Sjose borrego 		    &smb_dclocator.sdl_mtx, &to);
1528d7e4166Sjose borrego 
153*b3700b07SGordon Ross 		if (rc == ETIME) {
154*b3700b07SGordon Ross 			syslog(LOG_NOTICE, "smb_locate_dc timeout");
155*b3700b07SGordon Ross 			rv = B_FALSE;
156*b3700b07SGordon Ross 			goto out;
157*b3700b07SGordon Ross 		}
158*b3700b07SGordon Ross 	}
159*b3700b07SGordon Ross 	if (smb_dclocator.sdl_status != 0) {
160*b3700b07SGordon Ross 		syslog(LOG_NOTICE, "smb_locate_dc status 0x%x",
161*b3700b07SGordon Ross 		    smb_dclocator.sdl_status);
162*b3700b07SGordon Ross 		rv = B_FALSE;
163*b3700b07SGordon Ross 		goto out;
1648d7e4166Sjose borrego 	}
1658d7e4166Sjose borrego 
1668d7e4166Sjose borrego 	if (dp == NULL)
1678d7e4166Sjose borrego 		dp = &domain_info;
168*b3700b07SGordon Ross 	rv = smb_domain_getinfo(dp);
16929bd2886SAlan Wright 
170*b3700b07SGordon Ross out:
1718d7e4166Sjose borrego 	(void) mutex_unlock(&smb_dclocator.sdl_mtx);
1728d7e4166Sjose borrego 
173*b3700b07SGordon Ross 	return (rv);
174*b3700b07SGordon Ross }
175*b3700b07SGordon Ross 
176*b3700b07SGordon Ross /*
177*b3700b07SGordon Ross  * Tell the domain discovery service to run again now,
178*b3700b07SGordon Ross  * and assume changed configuration (i.e. a new DC).
179*b3700b07SGordon Ross  * Like the first part of smb_locate_dc().
180*b3700b07SGordon Ross  *
181*b3700b07SGordon Ross  * Note: This is called from the service refresh handler
182*b3700b07SGordon Ross  * and the door handler to tell the ddiscover thread to
183*b3700b07SGordon Ross  * request the new DC from idmap.  Therefore, we must not
184*b3700b07SGordon Ross  * trigger a new idmap discovery run from here, or that
185*b3700b07SGordon Ross  * would start a ping-pong match.
186*b3700b07SGordon Ross  */
187*b3700b07SGordon Ross /* ARGSUSED */
188*b3700b07SGordon Ross void
189*b3700b07SGordon Ross smb_ddiscover_refresh()
190*b3700b07SGordon Ross {
191*b3700b07SGordon Ross 
192*b3700b07SGordon Ross 	(void) mutex_lock(&smb_dclocator.sdl_mtx);
193*b3700b07SGordon Ross 
194*b3700b07SGordon Ross 	if (smb_dclocator.sdl_cfg_chg == B_FALSE) {
195*b3700b07SGordon Ross 		smb_dclocator.sdl_cfg_chg = B_TRUE;
196*b3700b07SGordon Ross 		syslog(LOG_DEBUG, "smb_ddiscover_refresh set cfg changed");
197*b3700b07SGordon Ross 	}
198*b3700b07SGordon Ross 	if (!smb_dclocator.sdl_locate) {
199*b3700b07SGordon Ross 		smb_dclocator.sdl_locate = B_TRUE;
200*b3700b07SGordon Ross 		(void) cond_broadcast(&smb_dclocator.sdl_cv);
201*b3700b07SGordon Ross 	}
202*b3700b07SGordon Ross 
203*b3700b07SGordon Ross 	(void) mutex_unlock(&smb_dclocator.sdl_mtx);
204*b3700b07SGordon Ross }
205*b3700b07SGordon Ross 
206*b3700b07SGordon Ross /*
207*b3700b07SGordon Ross  * Called by our client-side threads after they fail to connect to
208*b3700b07SGordon Ross  * the DC given to them by smb_locate_dc().  This is often called
209*b3700b07SGordon Ross  * after some delay, because the connection timeout delays these
210*b3700b07SGordon Ross  * threads for a while, so it's quite common that the DC locator
211*b3700b07SGordon Ross  * service has already started looking for a new DC.  These late
212*b3700b07SGordon Ross  * notifications should not continually restart the DC locator.
213*b3700b07SGordon Ross  */
214*b3700b07SGordon Ross void
215*b3700b07SGordon Ross smb_ddiscover_bad_dc(char *bad_dc)
216*b3700b07SGordon Ross {
217*b3700b07SGordon Ross 
218*b3700b07SGordon Ross 	assert(bad_dc[0] != '\0');
219*b3700b07SGordon Ross 
220*b3700b07SGordon Ross 	(void) mutex_lock(&smb_dclocator.sdl_mtx);
221*b3700b07SGordon Ross 
222*b3700b07SGordon Ross 	syslog(LOG_DEBUG, "smb_ddiscover_bad_dc, cur=%s, bad=%s",
223*b3700b07SGordon Ross 	    smb_dclocator.sdl_dci.dc_name, bad_dc);
224*b3700b07SGordon Ross 
225*b3700b07SGordon Ross 	if (strcmp(smb_dclocator.sdl_dci.dc_name, bad_dc)) {
226*b3700b07SGordon Ross 		/*
227*b3700b07SGordon Ross 		 * The "bad" DC is no longer the current one.
228*b3700b07SGordon Ross 		 * Probably a late "bad DC" report.
229*b3700b07SGordon Ross 		 */
230*b3700b07SGordon Ross 		goto out;
231*b3700b07SGordon Ross 	}
232*b3700b07SGordon Ross 	if (smb_dclocator.sdl_bad_dc) {
233*b3700b07SGordon Ross 		/* Someone already marked the current DC as "bad". */
234*b3700b07SGordon Ross 		syslog(LOG_DEBUG, "smb_ddiscover_bad_dc repeat");
235*b3700b07SGordon Ross 		goto out;
236*b3700b07SGordon Ross 	}
237*b3700b07SGordon Ross 
238*b3700b07SGordon Ross 	/*
239*b3700b07SGordon Ross 	 * Mark the current DC as "bad" and let the DC Locator
240*b3700b07SGordon Ross 	 * run again if it's not already.
241*b3700b07SGordon Ross 	 */
242*b3700b07SGordon Ross 	syslog(LOG_INFO, "smb_ddiscover, bad DC: %s", bad_dc);
243*b3700b07SGordon Ross 	smb_dclocator.sdl_bad_dc = B_TRUE;
244*b3700b07SGordon Ross 
245*b3700b07SGordon Ross 	/* In-line smb_ddiscover_kick */
246*b3700b07SGordon Ross 	if (!smb_dclocator.sdl_locate) {
247*b3700b07SGordon Ross 		smb_dclocator.sdl_locate = B_TRUE;
248*b3700b07SGordon Ross 		(void) cond_broadcast(&smb_dclocator.sdl_cv);
249*b3700b07SGordon Ross 	}
250*b3700b07SGordon Ross 
251*b3700b07SGordon Ross out:
252*b3700b07SGordon Ross 	(void) mutex_unlock(&smb_dclocator.sdl_mtx);
2538d7e4166Sjose borrego }
2548d7e4166Sjose borrego 
2558d7e4166Sjose borrego /*
256380acbbeSGordon Ross  * If domain discovery is running, wait for it to finish.
257380acbbeSGordon Ross  */
258380acbbeSGordon Ross int
259380acbbeSGordon Ross smb_ddiscover_wait(void)
260380acbbeSGordon Ross {
261380acbbeSGordon Ross 	timestruc_t to;
262380acbbeSGordon Ross 	int rc = 0;
263380acbbeSGordon Ross 
264380acbbeSGordon Ross 	(void) mutex_lock(&smb_dclocator.sdl_mtx);
265380acbbeSGordon Ross 
266380acbbeSGordon Ross 	if (smb_dclocator.sdl_locate) {
267380acbbeSGordon Ross 		to.tv_sec = SMB_DCLOCATOR_TIMEOUT;
268380acbbeSGordon Ross 		to.tv_nsec = 0;
269380acbbeSGordon Ross 		rc = cond_reltimedwait(&smb_dclocator.sdl_cv,
270380acbbeSGordon Ross 		    &smb_dclocator.sdl_mtx, &to);
271380acbbeSGordon Ross 	}
272380acbbeSGordon Ross 
273380acbbeSGordon Ross 	(void) mutex_unlock(&smb_dclocator.sdl_mtx);
274380acbbeSGordon Ross 
275380acbbeSGordon Ross 	return (rc);
276380acbbeSGordon Ross }
277380acbbeSGordon Ross 
278380acbbeSGordon Ross 
279380acbbeSGordon Ross /*
2808d7e4166Sjose borrego  * ==========================================================
2818d7e4166Sjose borrego  * DC discovery functions
2828d7e4166Sjose borrego  * ==========================================================
2838d7e4166Sjose borrego  */
2848d7e4166Sjose borrego 
2858d7e4166Sjose borrego /*
286a0aa776eSAlan Wright  * This is the domain and DC discovery service: it gets woken up whenever
287a0aa776eSAlan Wright  * there is need to locate a domain controller.
2888d7e4166Sjose borrego  *
28929bd2886SAlan Wright  * Upon success, the SMB domain cache will be populated with the discovered
29029bd2886SAlan Wright  * DC and domain info.
2918d7e4166Sjose borrego  */
2928d7e4166Sjose borrego /*ARGSUSED*/
2938d7e4166Sjose borrego static void *
294a0aa776eSAlan Wright smb_ddiscover_service(void *arg)
2958d7e4166Sjose borrego {
296*b3700b07SGordon Ross 	smb_domainex_t dxi;
297*b3700b07SGordon Ross 	smb_dclocator_t *sdl = arg;
298*b3700b07SGordon Ross 	uint32_t status;
299*b3700b07SGordon Ross 	boolean_t bad_dc;
300*b3700b07SGordon Ross 	boolean_t cfg_chg;
3018d7e4166Sjose borrego 
3028d7e4166Sjose borrego 	for (;;) {
303*b3700b07SGordon Ross 		/*
304*b3700b07SGordon Ross 		 * Wait to be signaled for work by one of:
305*b3700b07SGordon Ross 		 * smb_locate_dc(), smb_ddiscover_refresh(),
306*b3700b07SGordon Ross 		 * smb_ddiscover_bad_dc()
307*b3700b07SGordon Ross 		 */
308*b3700b07SGordon Ross 		syslog(LOG_DEBUG, "smb_ddiscover_service waiting");
3098d7e4166Sjose borrego 
310*b3700b07SGordon Ross 		(void) mutex_lock(&sdl->sdl_mtx);
311*b3700b07SGordon Ross 		while (!sdl->sdl_locate)
312*b3700b07SGordon Ross 			(void) cond_wait(&sdl->sdl_cv,
313*b3700b07SGordon Ross 			    &sdl->sdl_mtx);
3148d7e4166Sjose borrego 
315*b3700b07SGordon Ross 		if (!smb_config_getbool(SMB_CI_DOMAIN_MEMB)) {
316*b3700b07SGordon Ross 			sdl->sdl_status = NT_STATUS_INVALID_SERVER_STATE;
317*b3700b07SGordon Ross 			syslog(LOG_DEBUG, "smb_ddiscover_service: "
318*b3700b07SGordon Ross 			    "not a domain member");
319*b3700b07SGordon Ross 			goto wait_again;
320*b3700b07SGordon Ross 		}
3218d7e4166Sjose borrego 
322*b3700b07SGordon Ross 		/*
323*b3700b07SGordon Ross 		 * Want to know if these change below.
324*b3700b07SGordon Ross 		 * Note: mutex held here
325*b3700b07SGordon Ross 		 */
326*b3700b07SGordon Ross 	find_again:
327*b3700b07SGordon Ross 		bad_dc = sdl->sdl_bad_dc;
328*b3700b07SGordon Ross 		sdl->sdl_bad_dc = B_FALSE;
329*b3700b07SGordon Ross 		if (bad_dc) {
330*b3700b07SGordon Ross 			/*
331*b3700b07SGordon Ross 			 * Need to clear the current DC name or
332*b3700b07SGordon Ross 			 * ddiscover_bad_dc will keep setting bad_dc
333*b3700b07SGordon Ross 			 */
334*b3700b07SGordon Ross 			sdl->sdl_dci.dc_name[0] = '\0';
335*b3700b07SGordon Ross 		}
336*b3700b07SGordon Ross 		cfg_chg = sdl->sdl_cfg_chg;
337*b3700b07SGordon Ross 		sdl->sdl_cfg_chg = B_FALSE;
3388d7e4166Sjose borrego 
339*b3700b07SGordon Ross 		(void) mutex_unlock(&sdl->sdl_mtx);
340*b3700b07SGordon Ross 
341*b3700b07SGordon Ross 		syslog(LOG_DEBUG, "smb_ddiscover_service running "
342*b3700b07SGordon Ross 		    "cfg_chg=%d bad_dc=%d", (int)cfg_chg, (int)bad_dc);
343*b3700b07SGordon Ross 
344*b3700b07SGordon Ross 		/*
345*b3700b07SGordon Ross 		 * Clear the cached DC now so that we'll ask idmap again.
346*b3700b07SGordon Ross 		 * If our current DC gave us errors, force rediscovery.
347*b3700b07SGordon Ross 		 */
348*b3700b07SGordon Ross 		smb_ads_refresh(bad_dc);
349*b3700b07SGordon Ross 
350*b3700b07SGordon Ross 		/*
351*b3700b07SGordon Ross 		 * Search for the DC, save the result.
352*b3700b07SGordon Ross 		 */
353*b3700b07SGordon Ross 		bzero(&dxi, sizeof (dxi));
354*b3700b07SGordon Ross 		status = smb_ddiscover_main(sdl->sdl_domain, &dxi);
355*b3700b07SGordon Ross 		if (status == 0)
356*b3700b07SGordon Ross 			smb_domain_save();
357*b3700b07SGordon Ross 		(void) mutex_lock(&sdl->sdl_mtx);
358*b3700b07SGordon Ross 		sdl->sdl_status = status;
359*b3700b07SGordon Ross 		if (status == 0)
360*b3700b07SGordon Ross 			sdl->sdl_dci = dxi.d_dci;
361*b3700b07SGordon Ross 
362*b3700b07SGordon Ross 		/*
363*b3700b07SGordon Ross 		 * Run again if either of cfg_chg or bad_dc
364*b3700b07SGordon Ross 		 * was turned on during smb_ddiscover_main().
365*b3700b07SGordon Ross 		 * Note: mutex held here.
366*b3700b07SGordon Ross 		 */
367*b3700b07SGordon Ross 		if (sdl->sdl_bad_dc) {
368*b3700b07SGordon Ross 			syslog(LOG_DEBUG, "smb_ddiscover_service "
369*b3700b07SGordon Ross 			    "restart because bad_dc was set");
370*b3700b07SGordon Ross 			goto find_again;
371*b3700b07SGordon Ross 		}
372*b3700b07SGordon Ross 		if (sdl->sdl_cfg_chg) {
373*b3700b07SGordon Ross 			syslog(LOG_DEBUG, "smb_ddiscover_service "
374*b3700b07SGordon Ross 			    "restart because cfg_chg was set");
375*b3700b07SGordon Ross 			goto find_again;
376*b3700b07SGordon Ross 		}
377*b3700b07SGordon Ross 
378*b3700b07SGordon Ross 	wait_again:
379*b3700b07SGordon Ross 		sdl->sdl_locate = B_FALSE;
380*b3700b07SGordon Ross 		sdl->sdl_bad_dc = B_FALSE;
381*b3700b07SGordon Ross 		sdl->sdl_cfg_chg = B_FALSE;
382*b3700b07SGordon Ross 		(void) cond_broadcast(&sdl->sdl_cv);
383*b3700b07SGordon Ross 		(void) mutex_unlock(&sdl->sdl_mtx);
3848d7e4166Sjose borrego 	}
3858d7e4166Sjose borrego 
3868d7e4166Sjose borrego 	/*NOTREACHED*/
3878d7e4166Sjose borrego 	return (NULL);
3888d7e4166Sjose borrego }
3898d7e4166Sjose borrego 
3908d7e4166Sjose borrego /*
391*b3700b07SGordon Ross  * Discovers a domain controller for the specified domain via DNS.
392*b3700b07SGordon Ross  * After the domain controller is discovered successfully primary and
393*b3700b07SGordon Ross  * trusted domain infromation will be queried using RPC queries.
394*b3700b07SGordon Ross  *
395*b3700b07SGordon Ross  * Caller should zero out *dxi before calling, and after a
396*b3700b07SGordon Ross  * successful return should call:  smb_domain_save()
39729bd2886SAlan Wright  */
398*b3700b07SGordon Ross uint32_t
399*b3700b07SGordon Ross smb_ddiscover_main(char *domain, smb_domainex_t *dxi)
40029bd2886SAlan Wright {
4011ed6b69aSGordon Ross 	uint32_t status;
40229bd2886SAlan Wright 
403*b3700b07SGordon Ross 	if (domain[0] == '\0') {
404*b3700b07SGordon Ross 		syslog(LOG_DEBUG, "smb_ddiscover_main NULL domain");
405*b3700b07SGordon Ross 		return (NT_STATUS_INTERNAL_ERROR);
4061ed6b69aSGordon Ross 	}
40729bd2886SAlan Wright 
408*b3700b07SGordon Ross 	if (smb_domain_start_update() != SMB_DOMAIN_SUCCESS) {
409*b3700b07SGordon Ross 		syslog(LOG_DEBUG, "smb_ddiscover_main can't get lock");
410*b3700b07SGordon Ross 		return (NT_STATUS_INTERNAL_ERROR);
411*b3700b07SGordon Ross 	}
41229bd2886SAlan Wright 
413*b3700b07SGordon Ross 	status = smb_ads_lookup_msdcs(domain, &dxi->d_dci);
414*b3700b07SGordon Ross 	if (status != 0) {
415*b3700b07SGordon Ross 		syslog(LOG_DEBUG, "smb_ddiscover_main can't find DC (%s)",
416*b3700b07SGordon Ross 		    xlate_nt_status(status));
417*b3700b07SGordon Ross 		goto out;
418*b3700b07SGordon Ross 	}
419*b3700b07SGordon Ross 
420*b3700b07SGordon Ross 	status = smb_ddiscover_qinfo(domain, dxi->d_dci.dc_name, dxi);
421*b3700b07SGordon Ross 	if (status != 0) {
422*b3700b07SGordon Ross 		syslog(LOG_DEBUG,
423*b3700b07SGordon Ross 		    "smb_ddiscover_main can't get domain info (%s)",
424*b3700b07SGordon Ross 		    xlate_nt_status(status));
425*b3700b07SGordon Ross 		goto out;
426*b3700b07SGordon Ross 	}
427*b3700b07SGordon Ross 
428*b3700b07SGordon Ross 	smb_domain_update(dxi);
429*b3700b07SGordon Ross 
430*b3700b07SGordon Ross out:
431a0aa776eSAlan Wright 	smb_domain_end_update();
43229bd2886SAlan Wright 
433*b3700b07SGordon Ross 	/* Don't need the trusted domain list anymore. */
434*b3700b07SGordon Ross 	smb_domainex_free(dxi);
43529bd2886SAlan Wright 
4361ed6b69aSGordon Ross 	return (status);
43729bd2886SAlan Wright }
43829bd2886SAlan Wright 
43929bd2886SAlan Wright /*
44029bd2886SAlan Wright  * Obtain primary and trusted domain information using LSA queries.
4418d7e4166Sjose borrego  *
4428d7e4166Sjose borrego  * domain - either NetBIOS or fully-qualified domain name
4438d7e4166Sjose borrego  */
4448d7e4166Sjose borrego static uint32_t
445a0aa776eSAlan Wright smb_ddiscover_qinfo(char *domain, char *server, smb_domainex_t *dxi)
4468d7e4166Sjose borrego {
447*b3700b07SGordon Ross 	uint32_t ret, tmp;
4488d7e4166Sjose borrego 
449*b3700b07SGordon Ross 	/* If we must return failure, use this first one. */
450*b3700b07SGordon Ross 	ret = lsa_query_dns_domain_info(server, domain, &dxi->d_primary);
451*b3700b07SGordon Ross 	if (ret == NT_STATUS_SUCCESS)
452*b3700b07SGordon Ross 		goto success;
453*b3700b07SGordon Ross 	tmp = smb_ddiscover_use_config(domain, dxi);
454*b3700b07SGordon Ross 	if (tmp == NT_STATUS_SUCCESS)
455*b3700b07SGordon Ross 		goto success;
456*b3700b07SGordon Ross 	tmp = lsa_query_primary_domain_info(server, domain, &dxi->d_primary);
457*b3700b07SGordon Ross 	if (tmp == NT_STATUS_SUCCESS)
458*b3700b07SGordon Ross 		goto success;
45929bd2886SAlan Wright 
460*b3700b07SGordon Ross 	/* All of the above failed. */
461*b3700b07SGordon Ross 	return (ret);
4628d7e4166Sjose borrego 
463*b3700b07SGordon Ross success:
464a0aa776eSAlan Wright 	smb_ddiscover_enum_trusted(domain, server, dxi);
465*b3700b07SGordon Ross 	return (NT_STATUS_SUCCESS);
4668d7e4166Sjose borrego }
4678d7e4166Sjose borrego 
4688d7e4166Sjose borrego /*
46929bd2886SAlan Wright  * Obtain trusted domains information using LSA queries.
4708d7e4166Sjose borrego  *
4718d7e4166Sjose borrego  * domain - either NetBIOS or fully-qualified domain name.
4728d7e4166Sjose borrego  */
4738d7e4166Sjose borrego static void
474a0aa776eSAlan Wright smb_ddiscover_enum_trusted(char *domain, char *server, smb_domainex_t *dxi)
4758d7e4166Sjose borrego {
476a0aa776eSAlan Wright 	smb_trusted_domains_t *list;
47729bd2886SAlan Wright 	uint32_t status;
4788d7e4166Sjose borrego 
479a0aa776eSAlan Wright 	list = &dxi->d_trusted;
48029bd2886SAlan Wright 	status = lsa_enum_trusted_domains_ex(server, domain, list);
48129bd2886SAlan Wright 	if (status != NT_STATUS_SUCCESS)
48229bd2886SAlan Wright 		(void) lsa_enum_trusted_domains(server, domain, list);
4838d7e4166Sjose borrego }
4848d7e4166Sjose borrego 
4858d7e4166Sjose borrego /*
4868d7e4166Sjose borrego  * If the domain to be discovered matches the current domain (i.e the
487a0aa776eSAlan Wright  * value of either domain or fqdn configuration), then get the primary
488a0aa776eSAlan Wright  * domain information from SMF.
4898d7e4166Sjose borrego  */
49029bd2886SAlan Wright static uint32_t
491a0aa776eSAlan Wright smb_ddiscover_use_config(char *domain, smb_domainex_t *dxi)
4928d7e4166Sjose borrego {
4938d7e4166Sjose borrego 	boolean_t use;
494a0aa776eSAlan Wright 	smb_domain_t *dinfo;
4958d7e4166Sjose borrego 
496a0aa776eSAlan Wright 	dinfo = &dxi->d_primary;
497a0aa776eSAlan Wright 	bzero(dinfo, sizeof (smb_domain_t));
49829bd2886SAlan Wright 
4998d7e4166Sjose borrego 	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN)
50029bd2886SAlan Wright 		return (NT_STATUS_UNSUCCESSFUL);
5018d7e4166Sjose borrego 
50229bd2886SAlan Wright 	smb_config_getdomaininfo(dinfo->di_nbname, dinfo->di_fqname,
50329bd2886SAlan Wright 	    NULL, NULL, NULL);
5048d7e4166Sjose borrego 
50529bd2886SAlan Wright 	if (SMB_IS_FQDN(domain))
506bbf6f00cSJordan Brown 		use = (smb_strcasecmp(dinfo->di_fqname, domain, 0) == 0);
50729bd2886SAlan Wright 	else
508bbf6f00cSJordan Brown 		use = (smb_strcasecmp(dinfo->di_nbname, domain, 0) == 0);
50929bd2886SAlan Wright 
51029bd2886SAlan Wright 	if (use)
51129bd2886SAlan Wright 		smb_config_getdomaininfo(NULL, NULL, dinfo->di_sid,
51229bd2886SAlan Wright 		    dinfo->di_u.di_dns.ddi_forest,
51329bd2886SAlan Wright 		    dinfo->di_u.di_dns.ddi_guid);
51429bd2886SAlan Wright 
51529bd2886SAlan Wright 	return ((use) ? NT_STATUS_SUCCESS : NT_STATUS_UNSUCCESSFUL);
5168d7e4166Sjose borrego }
5178d7e4166Sjose borrego 
51829bd2886SAlan Wright static void
519a0aa776eSAlan Wright smb_domainex_free(smb_domainex_t *dxi)
52029bd2886SAlan Wright {
521a0aa776eSAlan Wright 	free(dxi->d_trusted.td_domains);
522*b3700b07SGordon Ross 	dxi->d_trusted.td_domains = NULL;
523*b3700b07SGordon Ross }
524*b3700b07SGordon Ross 
525*b3700b07SGordon Ross static void
526*b3700b07SGordon Ross smb_set_krb5_realm(char *domain)
527*b3700b07SGordon Ross {
528*b3700b07SGordon Ross 	static char realm[MAXHOSTNAMELEN];
529*b3700b07SGordon Ross 
530*b3700b07SGordon Ross 	if (domain == NULL || domain[0] == '\0') {
531*b3700b07SGordon Ross 		(void) unsetenv("KRB5_DEFAULT_REALM");
532*b3700b07SGordon Ross 		return;
533*b3700b07SGordon Ross 	}
534*b3700b07SGordon Ross 
535*b3700b07SGordon Ross 	/* In case krb5.conf is not configured, set the default realm. */
536*b3700b07SGordon Ross 	(void) strlcpy(realm, domain, sizeof (realm));
537*b3700b07SGordon Ross 	(void) smb_strupr(realm);
538*b3700b07SGordon Ross 
539*b3700b07SGordon Ross 	(void) setenv("KRB5_DEFAULT_REALM", realm, 1);
5408d7e4166Sjose borrego }
541