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.
241ed6b69aSGordon Ross * Copyright 2014 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>
33da6c28aaSamw #include <sys/errno.h>
34da6c28aaSamw
35da6c28aaSamw #include <smbsrv/libsmb.h>
36da6c28aaSamw #include <smbsrv/libsmbns.h>
37da6c28aaSamw #include <smbsrv/libmlsvc.h>
38da6c28aaSamw #include <smbsrv/smbinfo.h>
398d7e4166Sjose borrego #include "smbd.h"
408d7e4166Sjose borrego
411fdeec65Sjoyce mcintosh #define SMBD_DC_MONITOR_ATTEMPTS 3
421fdeec65Sjoyce mcintosh #define SMBD_DC_MONITOR_RETRY_INTERVAL 3 /* seconds */
431fdeec65Sjoyce mcintosh #define SMBD_DC_MONITOR_INTERVAL 60 /* seconds */
44da6c28aaSamw
451fdeec65Sjoyce mcintosh extern smbd_t smbd;
468d7e4166Sjose borrego
47fd9ee8b5Sjoyce mcintosh static mutex_t smbd_dc_mutex;
48fd9ee8b5Sjoyce mcintosh static cond_t smbd_dc_cv;
49fd9ee8b5Sjoyce mcintosh
501fdeec65Sjoyce mcintosh static void *smbd_dc_monitor(void *);
511fdeec65Sjoyce mcintosh static void smbd_dc_update(void);
521ed6b69aSGordon Ross /* Todo: static boolean_t smbd_set_netlogon_cred(void); */
538d7e4166Sjose borrego static uint32_t smbd_join_workgroup(smb_joininfo_t *);
548d7e4166Sjose borrego static uint32_t smbd_join_domain(smb_joininfo_t *);
55da6c28aaSamw
56da6c28aaSamw /*
571fdeec65Sjoyce mcintosh * Launch the DC discovery and monitor thread.
581fdeec65Sjoyce mcintosh */
591fdeec65Sjoyce mcintosh int
smbd_dc_monitor_init(void)601fdeec65Sjoyce mcintosh smbd_dc_monitor_init(void)
611fdeec65Sjoyce mcintosh {
621fdeec65Sjoyce mcintosh pthread_attr_t attr;
631fdeec65Sjoyce mcintosh int rc;
641fdeec65Sjoyce mcintosh
65fd9ee8b5Sjoyce mcintosh (void) smb_config_getstr(SMB_CI_ADS_SITE, smbd.s_site,
66fd9ee8b5Sjoyce mcintosh MAXHOSTNAMELEN);
67fd9ee8b5Sjoyce mcintosh (void) smb_config_getip(SMB_CI_DOMAIN_SRV, &smbd.s_pdc);
681fdeec65Sjoyce mcintosh smb_ads_init();
691fdeec65Sjoyce mcintosh
701fdeec65Sjoyce mcintosh if (smbd.s_secmode != SMB_SECMODE_DOMAIN)
711fdeec65Sjoyce mcintosh return (0);
721fdeec65Sjoyce mcintosh
731fdeec65Sjoyce mcintosh (void) pthread_attr_init(&attr);
741fdeec65Sjoyce mcintosh (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
751fdeec65Sjoyce mcintosh rc = pthread_create(&smbd.s_dc_monitor_tid, &attr, smbd_dc_monitor,
761fdeec65Sjoyce mcintosh NULL);
771fdeec65Sjoyce mcintosh (void) pthread_attr_destroy(&attr);
781fdeec65Sjoyce mcintosh return (rc);
791fdeec65Sjoyce mcintosh }
801fdeec65Sjoyce mcintosh
81fd9ee8b5Sjoyce mcintosh void
smbd_dc_monitor_refresh(void)82fd9ee8b5Sjoyce mcintosh smbd_dc_monitor_refresh(void)
83fd9ee8b5Sjoyce mcintosh {
84fd9ee8b5Sjoyce mcintosh char site[MAXHOSTNAMELEN];
85fd9ee8b5Sjoyce mcintosh smb_inaddr_t pdc;
86fd9ee8b5Sjoyce mcintosh
87fd9ee8b5Sjoyce mcintosh site[0] = '\0';
88fd9ee8b5Sjoyce mcintosh bzero(&pdc, sizeof (smb_inaddr_t));
89fd9ee8b5Sjoyce mcintosh (void) smb_config_getstr(SMB_CI_ADS_SITE, site, MAXHOSTNAMELEN);
90fd9ee8b5Sjoyce mcintosh (void) smb_config_getip(SMB_CI_DOMAIN_SRV, &pdc);
91fd9ee8b5Sjoyce mcintosh
92fd9ee8b5Sjoyce mcintosh (void) mutex_lock(&smbd_dc_mutex);
93fd9ee8b5Sjoyce mcintosh
94fd9ee8b5Sjoyce mcintosh if ((bcmp(&smbd.s_pdc, &pdc, sizeof (smb_inaddr_t)) != 0) ||
95fd9ee8b5Sjoyce mcintosh (smb_strcasecmp(smbd.s_site, site, 0) != 0)) {
96fd9ee8b5Sjoyce mcintosh bcopy(&pdc, &smbd.s_pdc, sizeof (smb_inaddr_t));
97fd9ee8b5Sjoyce mcintosh (void) strlcpy(smbd.s_site, site, MAXHOSTNAMELEN);
98fd9ee8b5Sjoyce mcintosh smbd.s_pdc_changed = B_TRUE;
99fd9ee8b5Sjoyce mcintosh (void) cond_signal(&smbd_dc_cv);
100fd9ee8b5Sjoyce mcintosh }
101fd9ee8b5Sjoyce mcintosh
102fd9ee8b5Sjoyce mcintosh (void) mutex_unlock(&smbd_dc_mutex);
103fd9ee8b5Sjoyce mcintosh }
104fd9ee8b5Sjoyce mcintosh
1051fdeec65Sjoyce mcintosh /*ARGSUSED*/
1061fdeec65Sjoyce mcintosh static void *
smbd_dc_monitor(void * arg)1071fdeec65Sjoyce mcintosh smbd_dc_monitor(void *arg)
1081fdeec65Sjoyce mcintosh {
1091fdeec65Sjoyce mcintosh boolean_t ds_not_responding = B_FALSE;
110fd9ee8b5Sjoyce mcintosh boolean_t ds_cfg_changed = B_FALSE;
111fd9ee8b5Sjoyce mcintosh timestruc_t delay;
1121fdeec65Sjoyce mcintosh int i;
1131fdeec65Sjoyce mcintosh
1141fdeec65Sjoyce mcintosh smbd_dc_update();
1151fdeec65Sjoyce mcintosh smbd_online_wait("smbd_dc_monitor");
1161fdeec65Sjoyce mcintosh
1171fdeec65Sjoyce mcintosh while (smbd_online()) {
118fd9ee8b5Sjoyce mcintosh delay.tv_sec = SMBD_DC_MONITOR_INTERVAL;
119fd9ee8b5Sjoyce mcintosh delay.tv_nsec = 0;
120fd9ee8b5Sjoyce mcintosh
121fd9ee8b5Sjoyce mcintosh (void) mutex_lock(&smbd_dc_mutex);
122fd9ee8b5Sjoyce mcintosh (void) cond_reltimedwait(&smbd_dc_cv, &smbd_dc_mutex, &delay);
123fd9ee8b5Sjoyce mcintosh
124fd9ee8b5Sjoyce mcintosh if (smbd.s_pdc_changed) {
125fd9ee8b5Sjoyce mcintosh smbd.s_pdc_changed = B_FALSE;
126fd9ee8b5Sjoyce mcintosh ds_cfg_changed = B_TRUE;
127fd9ee8b5Sjoyce mcintosh }
128fd9ee8b5Sjoyce mcintosh
129fd9ee8b5Sjoyce mcintosh (void) mutex_unlock(&smbd_dc_mutex);
1301fdeec65Sjoyce mcintosh
1311fdeec65Sjoyce mcintosh for (i = 0; i < SMBD_DC_MONITOR_ATTEMPTS; ++i) {
1321fdeec65Sjoyce mcintosh if (dssetup_check_service() == 0) {
1331fdeec65Sjoyce mcintosh ds_not_responding = B_FALSE;
1341fdeec65Sjoyce mcintosh break;
1351fdeec65Sjoyce mcintosh }
1361fdeec65Sjoyce mcintosh
1371fdeec65Sjoyce mcintosh ds_not_responding = B_TRUE;
1381fdeec65Sjoyce mcintosh (void) sleep(SMBD_DC_MONITOR_RETRY_INTERVAL);
1391fdeec65Sjoyce mcintosh }
1401fdeec65Sjoyce mcintosh
141fd9ee8b5Sjoyce mcintosh if (ds_not_responding)
142*b819cea2SGordon Ross syslog(LOG_NOTICE,
1431fdeec65Sjoyce mcintosh "smbd_dc_monitor: domain service not responding");
1441fdeec65Sjoyce mcintosh
145fd9ee8b5Sjoyce mcintosh if (ds_not_responding || ds_cfg_changed) {
146fd9ee8b5Sjoyce mcintosh ds_cfg_changed = B_FALSE;
1471fdeec65Sjoyce mcintosh smb_ads_refresh();
1481fdeec65Sjoyce mcintosh smbd_dc_update();
1491fdeec65Sjoyce mcintosh }
1501fdeec65Sjoyce mcintosh }
1511fdeec65Sjoyce mcintosh
1521fdeec65Sjoyce mcintosh smbd.s_dc_monitor_tid = 0;
1531fdeec65Sjoyce mcintosh return (NULL);
1541fdeec65Sjoyce mcintosh }
1551fdeec65Sjoyce mcintosh
1561fdeec65Sjoyce mcintosh /*
1571fdeec65Sjoyce mcintosh * Locate a domain controller in the current resource domain and Update
1581fdeec65Sjoyce mcintosh * the Netlogon credential chain.
1591fdeec65Sjoyce mcintosh *
1601fdeec65Sjoyce mcintosh * The domain configuration will be updated upon successful DC discovery.
1611fdeec65Sjoyce mcintosh */
1621fdeec65Sjoyce mcintosh static void
smbd_dc_update(void)1631fdeec65Sjoyce mcintosh smbd_dc_update(void)
1641fdeec65Sjoyce mcintosh {
1651fdeec65Sjoyce mcintosh char domain[MAXHOSTNAMELEN];
1661fdeec65Sjoyce mcintosh smb_domainex_t info;
1671ed6b69aSGordon Ross smb_domain_t *di;
1681ed6b69aSGordon Ross DWORD status;
1691fdeec65Sjoyce mcintosh
1701fdeec65Sjoyce mcintosh if (smb_getfqdomainname(domain, MAXHOSTNAMELEN) != 0) {
1711fdeec65Sjoyce mcintosh (void) smb_getdomainname(domain, MAXHOSTNAMELEN);
1721fdeec65Sjoyce mcintosh (void) smb_strupr(domain);
1731fdeec65Sjoyce mcintosh }
1741fdeec65Sjoyce mcintosh
1751fdeec65Sjoyce mcintosh if (!smb_locate_dc(domain, "", &info)) {
176*b819cea2SGordon Ross syslog(LOG_NOTICE,
1771fdeec65Sjoyce mcintosh "smbd_dc_update: %s: locate failed", domain);
1781ed6b69aSGordon Ross return;
1791fdeec65Sjoyce mcintosh }
1801fdeec65Sjoyce mcintosh
1811ed6b69aSGordon Ross di = &info.d_primary;
182*b819cea2SGordon Ross syslog(LOG_INFO,
1831ed6b69aSGordon Ross "smbd_dc_update: %s: located %s", domain, info.d_dc);
1841ed6b69aSGordon Ross
1851ed6b69aSGordon Ross status = mlsvc_netlogon(info.d_dc, di->di_nbname);
1861ed6b69aSGordon Ross if (status != NT_STATUS_SUCCESS) {
1871ed6b69aSGordon Ross syslog(LOG_NOTICE,
1881ed6b69aSGordon Ross "failed to establish NETLOGON credential chain");
1891ed6b69aSGordon Ross
1901fdeec65Sjoyce mcintosh /*
1911fdeec65Sjoyce mcintosh * Restart required because the domain changed
1921fdeec65Sjoyce mcintosh * or the credential chain setup failed.
1931fdeec65Sjoyce mcintosh */
194*b819cea2SGordon Ross syslog(LOG_NOTICE,
1951ed6b69aSGordon Ross "smbd_dc_update: smb/server restart required");
1961fdeec65Sjoyce mcintosh
1971fdeec65Sjoyce mcintosh if (smb_smf_restart_service() != 0)
198*b819cea2SGordon Ross syslog(LOG_ERR,
1991fdeec65Sjoyce mcintosh "restart failed: run 'svcs -xv smb/server'"
2001fdeec65Sjoyce mcintosh " for more information");
2011fdeec65Sjoyce mcintosh }
2021fdeec65Sjoyce mcintosh }
2031fdeec65Sjoyce mcintosh
2041fdeec65Sjoyce mcintosh /*
2058d7e4166Sjose borrego * smbd_join
2068d7e4166Sjose borrego *
2078d7e4166Sjose borrego * Joins the specified domain/workgroup.
2088d7e4166Sjose borrego *
2098d7e4166Sjose borrego * If the security mode or domain name is being changed,
2108d7e4166Sjose borrego * the caller must restart the service.
211da6c28aaSamw */
2128d7e4166Sjose borrego uint32_t
smbd_join(smb_joininfo_t * info)2138d7e4166Sjose borrego smbd_join(smb_joininfo_t *info)
214da6c28aaSamw {
2158d7e4166Sjose borrego uint32_t status;
216da6c28aaSamw
2178d7e4166Sjose borrego dssetup_clear_domain_info();
2188d7e4166Sjose borrego if (info->mode == SMB_SECMODE_WORKGRP)
2198d7e4166Sjose borrego status = smbd_join_workgroup(info);
2208d7e4166Sjose borrego else
2218d7e4166Sjose borrego status = smbd_join_domain(info);
2228d7e4166Sjose borrego
2238d7e4166Sjose borrego return (status);
224da6c28aaSamw }
225da6c28aaSamw
2268d7e4166Sjose borrego static uint32_t
smbd_join_workgroup(smb_joininfo_t * info)2278d7e4166Sjose borrego smbd_join_workgroup(smb_joininfo_t *info)
228da6c28aaSamw {
2298d7e4166Sjose borrego char nb_domain[SMB_PI_MAX_DOMAIN];
230faa1795aSjb150015
2318d7e4166Sjose borrego (void) smb_config_getstr(SMB_CI_DOMAIN_NAME, nb_domain,
2328d7e4166Sjose borrego sizeof (nb_domain));
233da6c28aaSamw
2348d7e4166Sjose borrego smbd_set_secmode(SMB_SECMODE_WORKGRP);
23529bd2886SAlan Wright smb_config_setdomaininfo(info->domain_name, "", "", "", "");
2367b59d02dSjb150015
2378d7e4166Sjose borrego if (strcasecmp(nb_domain, info->domain_name))
2387b59d02dSjb150015 smb_browser_reconfig();
2397b59d02dSjb150015
240da6c28aaSamw return (NT_STATUS_SUCCESS);
241da6c28aaSamw }
242da6c28aaSamw
2438d7e4166Sjose borrego static uint32_t
smbd_join_domain(smb_joininfo_t * info)2448d7e4166Sjose borrego smbd_join_domain(smb_joininfo_t *info)
2458d7e4166Sjose borrego {
2461ed6b69aSGordon Ross static unsigned char zero_hash[SMBAUTH_HASH_SZ];
247a0aa776eSAlan Wright smb_domainex_t dxi;
248a0aa776eSAlan Wright smb_domain_t *di;
2491ed6b69aSGordon Ross uint32_t status;
2508d7e4166Sjose borrego
251da6c28aaSamw /*
252da6c28aaSamw * Ensure that any previous membership of this domain has
253da6c28aaSamw * been cleared from the environment before we start. This
254da6c28aaSamw * will ensure that we don't attempt a NETLOGON_SAMLOGON
255da6c28aaSamw * when attempting to find the PDC.
256da6c28aaSamw */
257dc20a302Sas200622 (void) smb_config_setbool(SMB_CI_DOMAIN_MEMB, B_FALSE);
258da6c28aaSamw
2591ed6b69aSGordon Ross /* Clear DNS local (ADS) lookup cache too. */
2601ed6b69aSGordon Ross smb_ads_refresh();
2611ed6b69aSGordon Ross
2621ed6b69aSGordon Ross /*
2631ed6b69aSGordon Ross * Use a NULL session while searching for a DC, and
2641ed6b69aSGordon Ross * while getting information about the domain.
2651ed6b69aSGordon Ross */
2661ed6b69aSGordon Ross smb_ipc_set(MLSVC_ANON_USER, zero_hash);
2671ed6b69aSGordon Ross
2681ed6b69aSGordon Ross if (!smb_locate_dc(info->domain_name, "", &dxi)) {
2691ed6b69aSGordon Ross syslog(LOG_ERR, "smbd: failed locating "
2701ed6b69aSGordon Ross "domain controller for %s",
2711ed6b69aSGordon Ross info->domain_name);
2721ed6b69aSGordon Ross status = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
2731ed6b69aSGordon Ross goto errout;
274dc20a302Sas200622 }
275da6c28aaSamw
2768d7e4166Sjose borrego /* info->domain_name could either be NetBIOS domain name or FQDN */
2771ed6b69aSGordon Ross status = mlsvc_join(&dxi, info->domain_username, info->domain_passwd);
2781ed6b69aSGordon Ross if (status != NT_STATUS_SUCCESS) {
2791ed6b69aSGordon Ross syslog(LOG_ERR, "smbd: failed joining %s (%s)",
2801ed6b69aSGordon Ross info->domain_name, xlate_nt_status(status));
2811ed6b69aSGordon Ross goto errout;
2821ed6b69aSGordon Ross }
283da6c28aaSamw
2841ed6b69aSGordon Ross /*
2851ed6b69aSGordon Ross * Success!
2861ed6b69aSGordon Ross *
2871ed6b69aSGordon Ross * Strange, mlsvc_join does some of the work to
2881ed6b69aSGordon Ross * save the config, then the rest happens here.
2891ed6b69aSGordon Ross * Todo: Do the config update all in one place.
2901ed6b69aSGordon Ross */
291a0aa776eSAlan Wright di = &dxi.d_primary;
2928d7e4166Sjose borrego smbd_set_secmode(SMB_SECMODE_DOMAIN);
29329bd2886SAlan Wright smb_config_setdomaininfo(di->di_nbname, di->di_fqname,
29429bd2886SAlan Wright di->di_sid,
29529bd2886SAlan Wright di->di_u.di_dns.ddi_forest,
29629bd2886SAlan Wright di->di_u.di_dns.ddi_guid);
297a0aa776eSAlan Wright smb_ipc_commit();
298da6c28aaSamw return (status);
299da6c28aaSamw
3001ed6b69aSGordon Ross errout:
301a0aa776eSAlan Wright smb_ipc_rollback();
302da6c28aaSamw return (status);
303da6c28aaSamw }
304