xref: /titanic_51/usr/src/cmd/smbsrv/smbd/smbd_join.c (revision b3700b074e637f8c6991b70754c88a2cfffb246b)
1da6c28aaSamw /*
2da6c28aaSamw  * CDDL HEADER START
3da6c28aaSamw  *
4da6c28aaSamw  * The contents of this file are subject to the terms of the
5da6c28aaSamw  * Common Development and Distribution License (the "License").
6da6c28aaSamw  * You may not use this file except in compliance with the License.
7da6c28aaSamw  *
8da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw  * See the License for the specific language governing permissions
11da6c28aaSamw  * and limitations under the License.
12da6c28aaSamw  *
13da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw  *
19da6c28aaSamw  * CDDL HEADER END
20da6c28aaSamw  */
21148c5f43SAlan Wright 
22da6c28aaSamw /*
23148c5f43SAlan Wright  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24*b3700b07SGordon Ross  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
25da6c28aaSamw  */
26da6c28aaSamw 
27da6c28aaSamw #include <syslog.h>
28da6c28aaSamw #include <synch.h>
29da6c28aaSamw #include <pthread.h>
30da6c28aaSamw #include <unistd.h>
31da6c28aaSamw #include <string.h>
32da6c28aaSamw #include <strings.h>
33*b3700b07SGordon Ross #include <errno.h>
34*b3700b07SGordon Ross #include <netinet/in.h>
35*b3700b07SGordon Ross #include <netinet/tcp.h>
36da6c28aaSamw 
37da6c28aaSamw #include <smbsrv/libsmb.h>
38da6c28aaSamw #include <smbsrv/libsmbns.h>
39da6c28aaSamw #include <smbsrv/libmlsvc.h>
40da6c28aaSamw #include <smbsrv/smbinfo.h>
418d7e4166Sjose borrego #include "smbd.h"
428d7e4166Sjose borrego 
431fdeec65Sjoyce mcintosh #define	SMBD_DC_MONITOR_ATTEMPTS		3
441fdeec65Sjoyce mcintosh #define	SMBD_DC_MONITOR_RETRY_INTERVAL		3	/* seconds */
451fdeec65Sjoyce mcintosh #define	SMBD_DC_MONITOR_INTERVAL		60	/* seconds */
46da6c28aaSamw 
471fdeec65Sjoyce mcintosh extern smbd_t smbd;
488d7e4166Sjose borrego 
49fd9ee8b5Sjoyce mcintosh static mutex_t smbd_dc_mutex;
50fd9ee8b5Sjoyce mcintosh static cond_t smbd_dc_cv;
51fd9ee8b5Sjoyce mcintosh 
521fdeec65Sjoyce mcintosh static void *smbd_dc_monitor(void *);
531fdeec65Sjoyce mcintosh static void smbd_dc_update(void);
54*b3700b07SGordon Ross static int smbd_dc_check(smb_domainex_t *);
551ed6b69aSGordon Ross /* Todo: static boolean_t smbd_set_netlogon_cred(void); */
56*b3700b07SGordon Ross static void smbd_join_workgroup(smb_joininfo_t *, smb_joinres_t *);
57*b3700b07SGordon Ross static void smbd_join_domain(smb_joininfo_t *, smb_joinres_t *);
58da6c28aaSamw 
59da6c28aaSamw /*
601fdeec65Sjoyce mcintosh  * Launch the DC discovery and monitor thread.
611fdeec65Sjoyce mcintosh  */
621fdeec65Sjoyce mcintosh int
631fdeec65Sjoyce mcintosh smbd_dc_monitor_init(void)
641fdeec65Sjoyce mcintosh {
651fdeec65Sjoyce mcintosh 	pthread_attr_t	attr;
661fdeec65Sjoyce mcintosh 	int		rc;
671fdeec65Sjoyce mcintosh 
68fd9ee8b5Sjoyce mcintosh 	(void) smb_config_getstr(SMB_CI_ADS_SITE, smbd.s_site,
69fd9ee8b5Sjoyce mcintosh 	    MAXHOSTNAMELEN);
70fd9ee8b5Sjoyce mcintosh 	(void) smb_config_getip(SMB_CI_DOMAIN_SRV, &smbd.s_pdc);
711fdeec65Sjoyce mcintosh 	smb_ads_init();
721fdeec65Sjoyce mcintosh 
731fdeec65Sjoyce mcintosh 	if (smbd.s_secmode != SMB_SECMODE_DOMAIN)
741fdeec65Sjoyce mcintosh 		return (0);
751fdeec65Sjoyce mcintosh 
761fdeec65Sjoyce mcintosh 	(void) pthread_attr_init(&attr);
771fdeec65Sjoyce mcintosh 	(void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
781fdeec65Sjoyce mcintosh 	rc = pthread_create(&smbd.s_dc_monitor_tid, &attr, smbd_dc_monitor,
791fdeec65Sjoyce mcintosh 	    NULL);
801fdeec65Sjoyce mcintosh 	(void) pthread_attr_destroy(&attr);
811fdeec65Sjoyce mcintosh 	return (rc);
821fdeec65Sjoyce mcintosh }
831fdeec65Sjoyce mcintosh 
84*b3700b07SGordon Ross /*
85*b3700b07SGordon Ross  * Refresh the DC monitor.  Called from SMF refresh and when idmap
86*b3700b07SGordon Ross  * finds a different DC from what we were using previously.
87*b3700b07SGordon Ross  * Update our domain (and current DC) information.
88*b3700b07SGordon Ross  */
89fd9ee8b5Sjoyce mcintosh void
90fd9ee8b5Sjoyce mcintosh smbd_dc_monitor_refresh(void)
91fd9ee8b5Sjoyce mcintosh {
92fd9ee8b5Sjoyce mcintosh 
93*b3700b07SGordon Ross 	syslog(LOG_INFO, "smbd_dc_monitor_refresh");
94*b3700b07SGordon Ross 
95*b3700b07SGordon Ross 	smb_ddiscover_refresh();
96fd9ee8b5Sjoyce mcintosh 
97fd9ee8b5Sjoyce mcintosh 	(void) mutex_lock(&smbd_dc_mutex);
98fd9ee8b5Sjoyce mcintosh 
99fd9ee8b5Sjoyce mcintosh 	smbd.s_pdc_changed = B_TRUE;
100fd9ee8b5Sjoyce mcintosh 	(void) cond_signal(&smbd_dc_cv);
101fd9ee8b5Sjoyce mcintosh 
102fd9ee8b5Sjoyce mcintosh 	(void) mutex_unlock(&smbd_dc_mutex);
103fd9ee8b5Sjoyce mcintosh }
104fd9ee8b5Sjoyce mcintosh 
1051fdeec65Sjoyce mcintosh /*ARGSUSED*/
1061fdeec65Sjoyce mcintosh static void *
1071fdeec65Sjoyce mcintosh smbd_dc_monitor(void *arg)
1081fdeec65Sjoyce mcintosh {
109*b3700b07SGordon Ross 	smb_domainex_t	di;
110*b3700b07SGordon Ross 	boolean_t	ds_not_responding;
111*b3700b07SGordon Ross 	boolean_t	ds_cfg_changed;
112fd9ee8b5Sjoyce mcintosh 	timestruc_t	delay;
1131fdeec65Sjoyce mcintosh 	int		i;
1141fdeec65Sjoyce mcintosh 
115*b3700b07SGordon Ross 	/* Wait for smb_dclocator_init() to complete. */
1161fdeec65Sjoyce mcintosh 	smbd_online_wait("smbd_dc_monitor");
117*b3700b07SGordon Ross 	smbd_dc_update();
1181fdeec65Sjoyce mcintosh 
1191fdeec65Sjoyce mcintosh 	while (smbd_online()) {
120*b3700b07SGordon Ross 		ds_not_responding = B_FALSE;
121*b3700b07SGordon Ross 		ds_cfg_changed = B_FALSE;
122fd9ee8b5Sjoyce mcintosh 		delay.tv_sec = SMBD_DC_MONITOR_INTERVAL;
123fd9ee8b5Sjoyce mcintosh 		delay.tv_nsec = 0;
124fd9ee8b5Sjoyce mcintosh 
125fd9ee8b5Sjoyce mcintosh 		(void) mutex_lock(&smbd_dc_mutex);
126fd9ee8b5Sjoyce mcintosh 		(void) cond_reltimedwait(&smbd_dc_cv, &smbd_dc_mutex, &delay);
127fd9ee8b5Sjoyce mcintosh 
128fd9ee8b5Sjoyce mcintosh 		if (smbd.s_pdc_changed) {
129fd9ee8b5Sjoyce mcintosh 			smbd.s_pdc_changed = B_FALSE;
130fd9ee8b5Sjoyce mcintosh 			ds_cfg_changed = B_TRUE;
131*b3700b07SGordon Ross 			/* NB: smb_ddiscover_refresh was called. */
132fd9ee8b5Sjoyce mcintosh 		}
133fd9ee8b5Sjoyce mcintosh 
134fd9ee8b5Sjoyce mcintosh 		(void) mutex_unlock(&smbd_dc_mutex);
1351fdeec65Sjoyce mcintosh 
136*b3700b07SGordon Ross 		if (ds_cfg_changed) {
137*b3700b07SGordon Ross 			syslog(LOG_DEBUG, "smbd_dc_monitor: config changed");
138*b3700b07SGordon Ross 			goto rediscover;
139*b3700b07SGordon Ross 		}
140*b3700b07SGordon Ross 
141*b3700b07SGordon Ross 		if (!smb_domain_getinfo(&di)) {
142*b3700b07SGordon Ross 			syslog(LOG_DEBUG, "smbd_dc_monitor: no domain info");
143*b3700b07SGordon Ross 			goto rediscover;
144*b3700b07SGordon Ross 		}
145*b3700b07SGordon Ross 
146*b3700b07SGordon Ross 		if (di.d_dci.dc_name[0] == '\0') {
147*b3700b07SGordon Ross 			syslog(LOG_DEBUG, "smbd_dc_monitor: no DC name");
148*b3700b07SGordon Ross 			goto rediscover;
149*b3700b07SGordon Ross 		}
150*b3700b07SGordon Ross 
1511fdeec65Sjoyce mcintosh 		for (i = 0; i < SMBD_DC_MONITOR_ATTEMPTS; ++i) {
152*b3700b07SGordon Ross 			if (smbd_dc_check(&di) == 0) {
1531fdeec65Sjoyce mcintosh 				ds_not_responding = B_FALSE;
1541fdeec65Sjoyce mcintosh 				break;
1551fdeec65Sjoyce mcintosh 			}
1561fdeec65Sjoyce mcintosh 
1571fdeec65Sjoyce mcintosh 			ds_not_responding = B_TRUE;
1581fdeec65Sjoyce mcintosh 			(void) sleep(SMBD_DC_MONITOR_RETRY_INTERVAL);
1591fdeec65Sjoyce mcintosh 		}
1601fdeec65Sjoyce mcintosh 
161*b3700b07SGordon Ross 		if (ds_not_responding) {
162b819cea2SGordon Ross 			syslog(LOG_NOTICE,
163*b3700b07SGordon Ross 			    "smbd_dc_monitor: DC not responding: %s",
164*b3700b07SGordon Ross 			    di.d_dci.dc_name);
165*b3700b07SGordon Ross 			smb_ddiscover_bad_dc(di.d_dci.dc_name);
166*b3700b07SGordon Ross 		}
1671fdeec65Sjoyce mcintosh 
168fd9ee8b5Sjoyce mcintosh 		if (ds_not_responding || ds_cfg_changed) {
169*b3700b07SGordon Ross 		rediscover:
170*b3700b07SGordon Ross 			/*
171*b3700b07SGordon Ross 			 * An smb_ads_refresh will be done by the
172*b3700b07SGordon Ross 			 * smb_ddiscover_service when necessary.
173*b3700b07SGordon Ross 			 * Note: smbd_dc_monitor_refresh was already
174*b3700b07SGordon Ross 			 * called if appropriate.
175*b3700b07SGordon Ross 			 */
1761fdeec65Sjoyce mcintosh 			smbd_dc_update();
1771fdeec65Sjoyce mcintosh 		}
1781fdeec65Sjoyce mcintosh 	}
1791fdeec65Sjoyce mcintosh 
1801fdeec65Sjoyce mcintosh 	smbd.s_dc_monitor_tid = 0;
1811fdeec65Sjoyce mcintosh 	return (NULL);
1821fdeec65Sjoyce mcintosh }
1831fdeec65Sjoyce mcintosh 
1841fdeec65Sjoyce mcintosh /*
185*b3700b07SGordon Ross  * Simply attempt a connection to the DC.
186*b3700b07SGordon Ross  */
187*b3700b07SGordon Ross static int
188*b3700b07SGordon Ross smbd_dc_check(smb_domainex_t *di)
189*b3700b07SGordon Ross {
190*b3700b07SGordon Ross 	struct sockaddr sa;
191*b3700b07SGordon Ross 	int salen = 0;
192*b3700b07SGordon Ross 	int sock = -1;
193*b3700b07SGordon Ross 	int tmo = 5 * 1000;	/* 5 sec. */
194*b3700b07SGordon Ross 	int rc;
195*b3700b07SGordon Ross 
196*b3700b07SGordon Ross 	bzero(&sa, sizeof (sa));
197*b3700b07SGordon Ross 	switch (di->d_dci.dc_addr.a_family) {
198*b3700b07SGordon Ross 	case AF_INET: {
199*b3700b07SGordon Ross 		struct sockaddr_in *sin = (void *)&sa;
200*b3700b07SGordon Ross 		sin->sin_family = AF_INET;
201*b3700b07SGordon Ross 		sin->sin_port = htons(IPPORT_SMB);
202*b3700b07SGordon Ross 		sin->sin_addr.s_addr = di->d_dci.dc_addr.a_ipv4;
203*b3700b07SGordon Ross 		salen = sizeof (*sin);
204*b3700b07SGordon Ross 		break;
205*b3700b07SGordon Ross 	}
206*b3700b07SGordon Ross 	case AF_INET6: {
207*b3700b07SGordon Ross 		struct sockaddr_in6 *sin6 = (void *)&sa;
208*b3700b07SGordon Ross 		sin6->sin6_family = AF_INET6;
209*b3700b07SGordon Ross 		sin6->sin6_port = htons(IPPORT_SMB);
210*b3700b07SGordon Ross 		(void) memcpy(&sin6->sin6_addr,
211*b3700b07SGordon Ross 		    &di->d_dci.dc_addr.a_ipv6,
212*b3700b07SGordon Ross 		    sizeof (in6_addr_t));
213*b3700b07SGordon Ross 		salen = sizeof (*sin6);
214*b3700b07SGordon Ross 		break;
215*b3700b07SGordon Ross 	}
216*b3700b07SGordon Ross 	default:
217*b3700b07SGordon Ross 		return (-1);
218*b3700b07SGordon Ross 	}
219*b3700b07SGordon Ross 
220*b3700b07SGordon Ross 	sock = socket(di->d_dci.dc_addr.a_family, SOCK_STREAM, 0);
221*b3700b07SGordon Ross 	if (sock < 0)
222*b3700b07SGordon Ross 		return (errno);
223*b3700b07SGordon Ross 	(void) setsockopt(sock, IPPROTO_TCP,
224*b3700b07SGordon Ross 	    TCP_CONN_ABORT_THRESHOLD, &tmo, sizeof (tmo));
225*b3700b07SGordon Ross 
226*b3700b07SGordon Ross 	rc = connect(sock, &sa, salen);
227*b3700b07SGordon Ross 	if (rc < 0)
228*b3700b07SGordon Ross 		rc = errno;
229*b3700b07SGordon Ross 
230*b3700b07SGordon Ross 	(void) close(sock);
231*b3700b07SGordon Ross 	return (rc);
232*b3700b07SGordon Ross }
233*b3700b07SGordon Ross 
234*b3700b07SGordon Ross /*
2351fdeec65Sjoyce mcintosh  * Locate a domain controller in the current resource domain and Update
2361fdeec65Sjoyce mcintosh  * the Netlogon credential chain.
2371fdeec65Sjoyce mcintosh  *
2381fdeec65Sjoyce mcintosh  * The domain configuration will be updated upon successful DC discovery.
2391fdeec65Sjoyce mcintosh  */
2401fdeec65Sjoyce mcintosh static void
2411fdeec65Sjoyce mcintosh smbd_dc_update(void)
2421fdeec65Sjoyce mcintosh {
2431fdeec65Sjoyce mcintosh 	char		domain[MAXHOSTNAMELEN];
2441fdeec65Sjoyce mcintosh 	smb_domainex_t	info;
2451ed6b69aSGordon Ross 	smb_domain_t	*di;
2461ed6b69aSGordon Ross 	DWORD		status;
2471fdeec65Sjoyce mcintosh 
248*b3700b07SGordon Ross 	/*
249*b3700b07SGordon Ross 	 * Don't want this active until we're a domain member.
250*b3700b07SGordon Ross 	 */
251*b3700b07SGordon Ross 	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN)
252*b3700b07SGordon Ross 		return;
253*b3700b07SGordon Ross 
254*b3700b07SGordon Ross 	if (smb_getfqdomainname(domain, MAXHOSTNAMELEN) != 0)
255*b3700b07SGordon Ross 		return;
256*b3700b07SGordon Ross 
257*b3700b07SGordon Ross 	if (domain[0] == '\0') {
258*b3700b07SGordon Ross 		syslog(LOG_NOTICE,
259*b3700b07SGordon Ross 		    "smbd_dc_update: no domain name set");
260*b3700b07SGordon Ross 		return;
2611fdeec65Sjoyce mcintosh 	}
2621fdeec65Sjoyce mcintosh 
263*b3700b07SGordon Ross 	if (!smb_locate_dc(domain, &info)) {
264b819cea2SGordon Ross 		syslog(LOG_NOTICE,
2651fdeec65Sjoyce mcintosh 		    "smbd_dc_update: %s: locate failed", domain);
2661ed6b69aSGordon Ross 		return;
2671fdeec65Sjoyce mcintosh 	}
2681fdeec65Sjoyce mcintosh 
2691ed6b69aSGordon Ross 	di = &info.d_primary;
270b819cea2SGordon Ross 	syslog(LOG_INFO,
271*b3700b07SGordon Ross 	    "smbd_dc_update: %s: located %s", domain, info.d_dci.dc_name);
2721ed6b69aSGordon Ross 
273*b3700b07SGordon Ross 	status = mlsvc_netlogon(info.d_dci.dc_name, di->di_nbname);
2741ed6b69aSGordon Ross 	if (status != NT_STATUS_SUCCESS) {
2751ed6b69aSGordon Ross 		syslog(LOG_NOTICE,
2761ed6b69aSGordon Ross 		    "failed to establish NETLOGON credential chain");
277*b3700b07SGordon Ross 		syslog(LOG_NOTICE, " with server %s for domain %s (%s)",
278*b3700b07SGordon Ross 		    info.d_dci.dc_name, domain,
279*b3700b07SGordon Ross 		    xlate_nt_status(status));
2801fdeec65Sjoyce mcintosh 	}
2811fdeec65Sjoyce mcintosh }
2821fdeec65Sjoyce mcintosh 
2831fdeec65Sjoyce mcintosh /*
2848d7e4166Sjose borrego  * smbd_join
2858d7e4166Sjose borrego  *
2868d7e4166Sjose borrego  * Joins the specified domain/workgroup.
2878d7e4166Sjose borrego  *
2888d7e4166Sjose borrego  * If the security mode or domain name is being changed,
2898d7e4166Sjose borrego  * the caller must restart the service.
290da6c28aaSamw  */
291*b3700b07SGordon Ross void
292*b3700b07SGordon Ross smbd_join(smb_joininfo_t *info, smb_joinres_t *res)
293da6c28aaSamw {
2948d7e4166Sjose borrego 	dssetup_clear_domain_info();
2958d7e4166Sjose borrego 	if (info->mode == SMB_SECMODE_WORKGRP)
296*b3700b07SGordon Ross 		smbd_join_workgroup(info, res);
2978d7e4166Sjose borrego 	else
298*b3700b07SGordon Ross 		smbd_join_domain(info, res);
299da6c28aaSamw }
300da6c28aaSamw 
301*b3700b07SGordon Ross static void
302*b3700b07SGordon Ross smbd_join_workgroup(smb_joininfo_t *info, smb_joinres_t *res)
303da6c28aaSamw {
3048d7e4166Sjose borrego 	char nb_domain[SMB_PI_MAX_DOMAIN];
305faa1795aSjb150015 
306*b3700b07SGordon Ross 	syslog(LOG_DEBUG, "smbd: join workgroup: %s", info->domain_name);
307*b3700b07SGordon Ross 
3088d7e4166Sjose borrego 	(void) smb_config_getstr(SMB_CI_DOMAIN_NAME, nb_domain,
3098d7e4166Sjose borrego 	    sizeof (nb_domain));
310da6c28aaSamw 
3118d7e4166Sjose borrego 	smbd_set_secmode(SMB_SECMODE_WORKGRP);
31229bd2886SAlan Wright 	smb_config_setdomaininfo(info->domain_name, "", "", "", "");
313*b3700b07SGordon Ross 	(void) smb_config_set_idmap_domain("");
314*b3700b07SGordon Ross 	(void) smb_config_refresh_idmap();
3157b59d02dSjb150015 
3168d7e4166Sjose borrego 	if (strcasecmp(nb_domain, info->domain_name))
3177b59d02dSjb150015 		smb_browser_reconfig();
3187b59d02dSjb150015 
319*b3700b07SGordon Ross 	res->status = NT_STATUS_SUCCESS;
320da6c28aaSamw }
321da6c28aaSamw 
322*b3700b07SGordon Ross static void
323*b3700b07SGordon Ross smbd_join_domain(smb_joininfo_t *info, smb_joinres_t *res)
3248d7e4166Sjose borrego {
3258d7e4166Sjose borrego 
326*b3700b07SGordon Ross 	syslog(LOG_DEBUG, "smbd: join domain: %s", info->domain_name);
327da6c28aaSamw 
3288d7e4166Sjose borrego 	/* info->domain_name could either be NetBIOS domain name or FQDN */
329*b3700b07SGordon Ross 	mlsvc_join(info, res);
330*b3700b07SGordon Ross 	if (res->status == 0) {
3318d7e4166Sjose borrego 		smbd_set_secmode(SMB_SECMODE_DOMAIN);
332*b3700b07SGordon Ross 	} else {
333*b3700b07SGordon Ross 		syslog(LOG_ERR, "smbd: failed joining %s (%s)",
334*b3700b07SGordon Ross 		    info->domain_name, xlate_nt_status(res->status));
335*b3700b07SGordon Ross 	}
336da6c28aaSamw }
337