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