1*5331Samw /* 2*5331Samw * CDDL HEADER START 3*5331Samw * 4*5331Samw * The contents of this file are subject to the terms of the 5*5331Samw * Common Development and Distribution License (the "License"). 6*5331Samw * You may not use this file except in compliance with the License. 7*5331Samw * 8*5331Samw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*5331Samw * or http://www.opensolaris.org/os/licensing. 10*5331Samw * See the License for the specific language governing permissions 11*5331Samw * and limitations under the License. 12*5331Samw * 13*5331Samw * When distributing Covered Code, include this CDDL HEADER in each 14*5331Samw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*5331Samw * If applicable, add the following below this CDDL HEADER, with the 16*5331Samw * fields enclosed by brackets "[]" replaced with your own identifying 17*5331Samw * information: Portions Copyright [yyyy] [name of copyright owner] 18*5331Samw * 19*5331Samw * CDDL HEADER END 20*5331Samw */ 21*5331Samw /* 22*5331Samw * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23*5331Samw * Use is subject to license terms. 24*5331Samw */ 25*5331Samw 26*5331Samw #pragma ident "%Z%%M% %I% %E% SMI" 27*5331Samw 28*5331Samw #include <syslog.h> 29*5331Samw #include <synch.h> 30*5331Samw #include <pthread.h> 31*5331Samw #include <unistd.h> 32*5331Samw #include <string.h> 33*5331Samw #include <strings.h> 34*5331Samw #include <sys/errno.h> 35*5331Samw 36*5331Samw #include <smbsrv/libsmb.h> 37*5331Samw #include <smbsrv/libsmbrdr.h> 38*5331Samw #include <smbsrv/libsmbns.h> 39*5331Samw #include <smbsrv/libmlsvc.h> 40*5331Samw 41*5331Samw #include <smbsrv/smbinfo.h> 42*5331Samw #include <smbsrv/ntstatus.h> 43*5331Samw #include <smbsrv/lsalib.h> 44*5331Samw 45*5331Samw /* 46*5331Samw * Local protocol flags used to indicate which version of the 47*5331Samw * netlogon protocol to use when attempting to find the PDC. 48*5331Samw */ 49*5331Samw #define NETLOGON_PROTO_NETLOGON 0x01 50*5331Samw #define NETLOGON_PROTO_SAMLOGON 0x02 51*5331Samw 52*5331Samw /* 53*5331Samw * Maximum time to wait for a domain controller (30 seconds). 54*5331Samw */ 55*5331Samw #define SMB_NETLOGON_TIMEOUT 30 56*5331Samw 57*5331Samw /* 58*5331Samw * Flags used in conjunction with the location and query condition 59*5331Samw * variables. 60*5331Samw */ 61*5331Samw #define SMB_NETLF_LOCATE_DC 0x00000001 62*5331Samw #define SMB_NETLF_LSA_QUERY 0x00000002 63*5331Samw 64*5331Samw typedef struct smb_netlogon_info { 65*5331Samw char snli_domain[SMB_PI_MAX_DOMAIN]; 66*5331Samw unsigned snli_flags; 67*5331Samw mutex_t snli_locate_mtx; 68*5331Samw cond_t snli_locate_cv; 69*5331Samw mutex_t snli_query_mtx; 70*5331Samw cond_t snli_query_cv; 71*5331Samw uint32_t snli_status; 72*5331Samw } smb_netlogon_info_t; 73*5331Samw 74*5331Samw static smb_netlogon_info_t smb_netlogon_info; 75*5331Samw 76*5331Samw static pthread_t lsa_monitor_thr; 77*5331Samw static pthread_t dc_browser_thr; 78*5331Samw 79*5331Samw static void *smb_netlogon_lsa_monitor(void *arg); 80*5331Samw static void *smb_netlogon_dc_browser(void *arg); 81*5331Samw 82*5331Samw /* 83*5331Samw * Inline convenience function to find out if the domain information is 84*5331Samw * valid. The caller can decide whether or not to wait. 85*5331Samw */ 86*5331Samw static boolean_t 87*5331Samw smb_ntdomain_is_valid(uint32_t timeout) 88*5331Samw { 89*5331Samw smb_ntdomain_t *info; 90*5331Samw 91*5331Samw if ((info = smb_getdomaininfo(timeout)) != 0) { 92*5331Samw if (info->ipaddr != 0) 93*5331Samw return (B_TRUE); 94*5331Samw } 95*5331Samw 96*5331Samw return (B_FALSE); 97*5331Samw } 98*5331Samw 99*5331Samw /* 100*5331Samw * smbd_join 101*5331Samw * 102*5331Samw * Joins the specified domain/workgroup 103*5331Samw */ 104*5331Samw uint32_t 105*5331Samw smbd_join(smb_joininfo_t *info) 106*5331Samw { 107*5331Samw smb_ntdomain_t *pi; 108*5331Samw uint32_t status; 109*5331Samw unsigned char passwd_hash[SMBAUTH_HASH_SZ]; 110*5331Samw char plain_passwd[PASS_LEN + 1]; 111*5331Samw char plain_user[PASS_LEN + 1]; 112*5331Samw 113*5331Samw if (info->mode == SMB_SECMODE_WORKGRP) { 114*5331Samw smb_config_wrlock(); 115*5331Samw (void) smb_config_set_secmode(info->mode); 116*5331Samw (void) smb_config_set(SMB_CI_DOMAIN_NAME, info->domain_name); 117*5331Samw smb_config_unlock(); 118*5331Samw return (NT_STATUS_SUCCESS); 119*5331Samw } 120*5331Samw 121*5331Samw /* 122*5331Samw * Ensure that any previous membership of this domain has 123*5331Samw * been cleared from the environment before we start. This 124*5331Samw * will ensure that we don't attempt a NETLOGON_SAMLOGON 125*5331Samw * when attempting to find the PDC. 126*5331Samw */ 127*5331Samw smb_set_domain_member(0); 128*5331Samw 129*5331Samw (void) strcpy(plain_user, info->domain_username); 130*5331Samw (void) strcpy(plain_passwd, info->domain_passwd); 131*5331Samw 132*5331Samw if (smb_auth_ntlm_hash(plain_passwd, passwd_hash) != SMBAUTH_SUCCESS) { 133*5331Samw status = NT_STATUS_INTERNAL_ERROR; 134*5331Samw syslog(LOG_ERR, "smbd: could not compute ntlm hash for '%s'", 135*5331Samw plain_user); 136*5331Samw return (status); 137*5331Samw } 138*5331Samw 139*5331Samw smbrdr_ipc_set(plain_user, passwd_hash); 140*5331Samw 141*5331Samw if (locate_resource_pdc(info->domain_name)) { 142*5331Samw if ((pi = smb_getdomaininfo(0)) == 0) { 143*5331Samw status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO; 144*5331Samw syslog(LOG_ERR, "smbd: could not get domain controller" 145*5331Samw "information for '%s'", info->domain_name); 146*5331Samw return (status); 147*5331Samw } 148*5331Samw 149*5331Samw /* 150*5331Samw * Temporary delay before creating 151*5331Samw * the workstation trust account. 152*5331Samw */ 153*5331Samw (void) sleep(2); 154*5331Samw status = mlsvc_validate_user(pi->server, pi->domain, 155*5331Samw plain_user, plain_passwd); 156*5331Samw 157*5331Samw if (status == NT_STATUS_SUCCESS) { 158*5331Samw smb_config_wrlock(); 159*5331Samw (void) smb_config_set_secmode(SMB_SECMODE_DOMAIN); 160*5331Samw (void) smb_config_set(SMB_CI_DOMAIN_NAME, 161*5331Samw info->domain_name); 162*5331Samw smb_config_unlock(); 163*5331Samw smbrdr_ipc_commit(); 164*5331Samw return (status); 165*5331Samw } 166*5331Samw 167*5331Samw smbrdr_ipc_rollback(); 168*5331Samw syslog(LOG_ERR, "smbd: failed joining %s (%s)", 169*5331Samw info->domain_name, xlate_nt_status(status)); 170*5331Samw return (status); 171*5331Samw } 172*5331Samw 173*5331Samw smbrdr_ipc_rollback(); 174*5331Samw syslog(LOG_ERR, "smbd: failed locating domain controller for %s", 175*5331Samw info->domain_name); 176*5331Samw return (NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND); 177*5331Samw } 178*5331Samw 179*5331Samw /* 180*5331Samw * locate_resource_pdc 181*5331Samw * 182*5331Samw * This is the entry point for discovering a domain controller for the 183*5331Samw * specified domain. The caller may block here for around 30 seconds if 184*5331Samw * the system has to go to the network and find a domain controller. 185*5331Samw * Sometime it would be good to change this to smb_locate_pdc and allow 186*5331Samw * the caller to specify whether or not he wants to wait for a response. 187*5331Samw * 188*5331Samw * The actual work of discovering a DC is handled by other threads. 189*5331Samw * All we do here is signal the request and wait for a DC or a timeout. 190*5331Samw * 191*5331Samw * Returns B_TRUE if a domain controller is available. 192*5331Samw */ 193*5331Samw boolean_t 194*5331Samw locate_resource_pdc(char *domain) 195*5331Samw { 196*5331Samw int rc; 197*5331Samw timestruc_t to; 198*5331Samw 199*5331Samw if (domain == NULL || *domain == '\0') 200*5331Samw return (B_FALSE); 201*5331Samw 202*5331Samw (void) mutex_lock(&smb_netlogon_info.snli_locate_mtx); 203*5331Samw 204*5331Samw if ((smb_netlogon_info.snli_flags & SMB_NETLF_LOCATE_DC) == 0) { 205*5331Samw smb_netlogon_info.snli_flags |= SMB_NETLF_LOCATE_DC; 206*5331Samw (void) strlcpy(smb_netlogon_info.snli_domain, domain, 207*5331Samw SMB_PI_MAX_DOMAIN); 208*5331Samw (void) cond_broadcast(&smb_netlogon_info.snli_locate_cv); 209*5331Samw } 210*5331Samw 211*5331Samw while (smb_netlogon_info.snli_flags & SMB_NETLF_LOCATE_DC) { 212*5331Samw to.tv_sec = SMB_NETLOGON_TIMEOUT; 213*5331Samw to.tv_nsec = 0; 214*5331Samw rc = cond_reltimedwait(&smb_netlogon_info.snli_locate_cv, 215*5331Samw &smb_netlogon_info.snli_locate_mtx, &to); 216*5331Samw 217*5331Samw if (rc == ETIME) 218*5331Samw break; 219*5331Samw } 220*5331Samw 221*5331Samw (void) mutex_unlock(&smb_netlogon_info.snli_locate_mtx); 222*5331Samw 223*5331Samw return (smb_ntdomain_is_valid(0)); 224*5331Samw } 225*5331Samw 226*5331Samw /* 227*5331Samw * smb_netlogon_init 228*5331Samw * 229*5331Samw * Initialization of the DC browser and LSA monitor threads. 230*5331Samw * Returns 0 on success, an error number if thread creation fails. 231*5331Samw */ 232*5331Samw int 233*5331Samw smb_netlogon_init(void) 234*5331Samw { 235*5331Samw pthread_attr_t tattr; 236*5331Samw int rc; 237*5331Samw 238*5331Samw (void) pthread_attr_init(&tattr); 239*5331Samw (void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); 240*5331Samw rc = pthread_create(&lsa_monitor_thr, &tattr, 241*5331Samw smb_netlogon_lsa_monitor, 0); 242*5331Samw if (rc != 0) 243*5331Samw goto nli_exit; 244*5331Samw rc = pthread_create(&dc_browser_thr, &tattr, 245*5331Samw smb_netlogon_dc_browser, 0); 246*5331Samw if (rc != 0) { 247*5331Samw (void) pthread_cancel(lsa_monitor_thr); 248*5331Samw (void) pthread_join(lsa_monitor_thr, NULL); 249*5331Samw } 250*5331Samw 251*5331Samw nli_exit: 252*5331Samw (void) pthread_attr_destroy(&tattr); 253*5331Samw return (rc); 254*5331Samw } 255*5331Samw 256*5331Samw /* 257*5331Samw * smb_netlogon_dc_browser 258*5331Samw * 259*5331Samw * This is the DC browser thread: it gets woken up whenever someone 260*5331Samw * wants to locate a domain controller. 261*5331Samw * 262*5331Samw * With the introduction of Windows 2000, NetBIOS is no longer a 263*5331Samw * requirement for NT domains. If NetBIOS has been disabled on the 264*5331Samw * network there will be no browsers and we won't get any response 265*5331Samw * to netlogon requests. So we try to find a DC controller via ADS 266*5331Samw * first. If ADS is disabled or the DNS query fails, we drop back 267*5331Samw * to the netlogon protocol. 268*5331Samw * 269*5331Samw * This function will block for up to 30 seconds waiting for the PDC 270*5331Samw * to be discovered. Sometime it would be good to change this to 271*5331Samw * smb_locate_pdc and allow the caller to specify whether or not he 272*5331Samw * wants to wait for a response. 273*5331Samw * 274*5331Samw */ 275*5331Samw /*ARGSUSED*/ 276*5331Samw static void * 277*5331Samw smb_netlogon_dc_browser(void *arg) 278*5331Samw { 279*5331Samw boolean_t rc; 280*5331Samw char resource_domain[SMB_PI_MAX_DOMAIN]; 281*5331Samw int net, smb_nc_cnt; 282*5331Samw int protocol; 283*5331Samw 284*5331Samw for (;;) { 285*5331Samw (void) mutex_lock(&smb_netlogon_info.snli_locate_mtx); 286*5331Samw 287*5331Samw while ((smb_netlogon_info.snli_flags & SMB_NETLF_LOCATE_DC) == 288*5331Samw 0) { 289*5331Samw (void) cond_wait(&smb_netlogon_info.snli_locate_cv, 290*5331Samw &smb_netlogon_info.snli_locate_mtx); 291*5331Samw } 292*5331Samw 293*5331Samw (void) mutex_unlock(&smb_netlogon_info.snli_locate_mtx); 294*5331Samw 295*5331Samw (void) strlcpy(resource_domain, smb_netlogon_info.snli_domain, 296*5331Samw SMB_PI_MAX_DOMAIN); 297*5331Samw 298*5331Samw smb_setdomaininfo(NULL, NULL, 0); 299*5331Samw if (msdcs_lookup_ads() == 0) { 300*5331Samw if (smb_is_domain_member()) 301*5331Samw protocol = NETLOGON_PROTO_SAMLOGON; 302*5331Samw else 303*5331Samw protocol = NETLOGON_PROTO_NETLOGON; 304*5331Samw 305*5331Samw smb_nc_cnt = smb_nic_get_num(); 306*5331Samw for (net = 0; net < smb_nc_cnt; net++) { 307*5331Samw smb_netlogon_request(net, protocol, 308*5331Samw resource_domain); 309*5331Samw } 310*5331Samw } 311*5331Samw 312*5331Samw rc = smb_ntdomain_is_valid(SMB_NETLOGON_TIMEOUT); 313*5331Samw 314*5331Samw (void) mutex_lock(&smb_netlogon_info.snli_locate_mtx); 315*5331Samw smb_netlogon_info.snli_flags &= ~SMB_NETLF_LOCATE_DC; 316*5331Samw (void) cond_broadcast(&smb_netlogon_info.snli_locate_cv); 317*5331Samw (void) mutex_unlock(&smb_netlogon_info.snli_locate_mtx); 318*5331Samw 319*5331Samw if (rc != B_TRUE) { 320*5331Samw /* 321*5331Samw * Notify the LSA monitor to update the 322*5331Samw * primary and trusted domain information. 323*5331Samw */ 324*5331Samw (void) mutex_lock(&smb_netlogon_info.snli_query_mtx); 325*5331Samw smb_netlogon_info.snli_flags |= SMB_NETLF_LSA_QUERY; 326*5331Samw (void) cond_broadcast(&smb_netlogon_info.snli_query_cv); 327*5331Samw (void) mutex_unlock(&smb_netlogon_info.snli_query_mtx); 328*5331Samw } 329*5331Samw } 330*5331Samw 331*5331Samw /*NOTREACHED*/ 332*5331Samw return (NULL); 333*5331Samw } 334*5331Samw 335*5331Samw /* 336*5331Samw * smb_netlogon_lsa_monitor 337*5331Samw * 338*5331Samw * This monitor should run as a separate thread. It waits on a condition 339*5331Samw * variable until someone indicates that the LSA domain information needs 340*5331Samw * to be refreshed. It then queries the DC for the NT domain information: 341*5331Samw * primary, account and trusted domains. The condition variable should be 342*5331Samw * signaled whenever a DC is selected. 343*5331Samw * 344*5331Samw * Note that the LSA query calls require the DC information and this task 345*5331Samw * may end up blocked on the DC location protocol, which is why this 346*5331Samw * monitor is run as a separate thread. This should only happen if the DC 347*5331Samw * goes down immediately after we located it. 348*5331Samw */ 349*5331Samw /*ARGSUSED*/ 350*5331Samw static void * 351*5331Samw smb_netlogon_lsa_monitor(void *arg) 352*5331Samw { 353*5331Samw uint32_t status; 354*5331Samw 355*5331Samw for (;;) { 356*5331Samw (void) mutex_lock(&smb_netlogon_info.snli_query_mtx); 357*5331Samw 358*5331Samw while ((smb_netlogon_info.snli_flags & SMB_NETLF_LSA_QUERY) == 359*5331Samw 0) { 360*5331Samw (void) cond_wait(&smb_netlogon_info.snli_query_cv, 361*5331Samw &smb_netlogon_info.snli_query_mtx); 362*5331Samw } 363*5331Samw 364*5331Samw smb_netlogon_info.snli_flags &= ~SMB_NETLF_LSA_QUERY; 365*5331Samw (void) mutex_unlock(&smb_netlogon_info.snli_query_mtx); 366*5331Samw 367*5331Samw /* 368*5331Samw * Skip the LSA query if Authenticated IPC is supported 369*5331Samw * and the credential is not yet set. 370*5331Samw */ 371*5331Samw if (smbrdr_ipc_skip_lsa_query() == 0) { 372*5331Samw status = lsa_query_primary_domain_info(); 373*5331Samw if (status == NT_STATUS_SUCCESS) { 374*5331Samw if (lsa_query_account_domain_info() 375*5331Samw != NT_STATUS_SUCCESS) { 376*5331Samw syslog(LOG_DEBUG, 377*5331Samw "NetlogonLSAMonitor: query " 378*5331Samw "account info failed"); 379*5331Samw } 380*5331Samw if (lsa_enum_trusted_domains() 381*5331Samw != NT_STATUS_SUCCESS) { 382*5331Samw syslog(LOG_DEBUG, 383*5331Samw "NetlogonLSAMonitor: enum " 384*5331Samw "trusted domain failed"); 385*5331Samw } 386*5331Samw } else { 387*5331Samw syslog(LOG_DEBUG, 388*5331Samw "NetlogonLSAMonitor: update failed"); 389*5331Samw } 390*5331Samw } 391*5331Samw } 392*5331Samw 393*5331Samw /*NOTREACHED*/ 394*5331Samw return (NULL); 395*5331Samw } 396