15331Samw /* 25331Samw * CDDL HEADER START 35331Samw * 45331Samw * The contents of this file are subject to the terms of the 55331Samw * Common Development and Distribution License (the "License"). 65331Samw * You may not use this file except in compliance with the License. 75331Samw * 85331Samw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95331Samw * or http://www.opensolaris.org/os/licensing. 105331Samw * See the License for the specific language governing permissions 115331Samw * and limitations under the License. 125331Samw * 135331Samw * When distributing Covered Code, include this CDDL HEADER in each 145331Samw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155331Samw * If applicable, add the following below this CDDL HEADER, with the 165331Samw * fields enclosed by brackets "[]" replaced with your own identifying 175331Samw * information: Portions Copyright [yyyy] [name of copyright owner] 185331Samw * 195331Samw * CDDL HEADER END 205331Samw */ 215331Samw /* 229832Samw@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 235331Samw * Use is subject to license terms. 245331Samw */ 255331Samw 265331Samw #include <syslog.h> 275331Samw #include <synch.h> 285331Samw #include <pthread.h> 295331Samw #include <unistd.h> 305331Samw #include <string.h> 315331Samw #include <strings.h> 325331Samw #include <sys/errno.h> 335331Samw 345331Samw #include <smbsrv/libsmb.h> 355331Samw #include <smbsrv/libsmbns.h> 365331Samw #include <smbsrv/libmlsvc.h> 375331Samw #include <smbsrv/smbinfo.h> 385331Samw #include <smbsrv/ntstatus.h> 398334SJose.Borrego@Sun.COM #include "smbd.h" 408334SJose.Borrego@Sun.COM 415331Samw 425331Samw /* 438334SJose.Borrego@Sun.COM * This is a short-lived thread that triggers the initial DC discovery 448334SJose.Borrego@Sun.COM * at startup. 455331Samw */ 468334SJose.Borrego@Sun.COM static pthread_t smb_locate_dc_thr; 478334SJose.Borrego@Sun.COM 488334SJose.Borrego@Sun.COM static void *smbd_locate_dc_thread(void *); 498334SJose.Borrego@Sun.COM static int smbd_get_kpasswd_srv(char *, size_t); 508334SJose.Borrego@Sun.COM static uint32_t smbd_join_workgroup(smb_joininfo_t *); 518334SJose.Borrego@Sun.COM static uint32_t smbd_join_domain(smb_joininfo_t *); 525331Samw 535331Samw /* 548334SJose.Borrego@Sun.COM * smbd_join 558334SJose.Borrego@Sun.COM * 568334SJose.Borrego@Sun.COM * Joins the specified domain/workgroup. 578334SJose.Borrego@Sun.COM * 588334SJose.Borrego@Sun.COM * If the security mode or domain name is being changed, 598334SJose.Borrego@Sun.COM * the caller must restart the service. 605331Samw */ 618334SJose.Borrego@Sun.COM uint32_t 628334SJose.Borrego@Sun.COM smbd_join(smb_joininfo_t *info) 638334SJose.Borrego@Sun.COM { 648334SJose.Borrego@Sun.COM uint32_t status; 656139Sjb150015 668334SJose.Borrego@Sun.COM dssetup_clear_domain_info(); 678334SJose.Borrego@Sun.COM if (info->mode == SMB_SECMODE_WORKGRP) 688334SJose.Borrego@Sun.COM status = smbd_join_workgroup(info); 698334SJose.Borrego@Sun.COM else 708334SJose.Borrego@Sun.COM status = smbd_join_domain(info); 715331Samw 728334SJose.Borrego@Sun.COM return (status); 735331Samw } 745331Samw 755331Samw /* 768334SJose.Borrego@Sun.COM * smbd_set_netlogon_cred 778334SJose.Borrego@Sun.COM * 788334SJose.Borrego@Sun.COM * If the system is joined to an AD domain via kclient, SMB daemon will need 798334SJose.Borrego@Sun.COM * to establish the NETLOGON credential chain. 808334SJose.Borrego@Sun.COM * 818334SJose.Borrego@Sun.COM * Since the kclient has updated the machine password stored in SMF 828334SJose.Borrego@Sun.COM * repository, the cached ipc_info must be updated accordingly by calling 8310717Samw@Sun.COM * smb_ipc_commit. 848334SJose.Borrego@Sun.COM * 858334SJose.Borrego@Sun.COM * Due to potential replication delays in a multiple DC environment, the 868334SJose.Borrego@Sun.COM * NETLOGON rpc request must be sent to the DC, to which the KPASSWD request 878334SJose.Borrego@Sun.COM * is sent. If the DC discovered by the SMB daemon is different than the 888334SJose.Borrego@Sun.COM * kpasswd server, the current connection with the DC will be torn down 898334SJose.Borrego@Sun.COM * and a DC discovery process will be triggered to locate the kpasswd 908334SJose.Borrego@Sun.COM * server. 918334SJose.Borrego@Sun.COM * 928334SJose.Borrego@Sun.COM * If joining a new domain, the domain_name property must be set after a 938334SJose.Borrego@Sun.COM * successful credential chain setup. 948334SJose.Borrego@Sun.COM */ 958334SJose.Borrego@Sun.COM boolean_t 968334SJose.Borrego@Sun.COM smbd_set_netlogon_cred(void) 978334SJose.Borrego@Sun.COM { 988334SJose.Borrego@Sun.COM char kpasswd_srv[MAXHOSTNAMELEN]; 998334SJose.Borrego@Sun.COM char kpasswd_domain[MAXHOSTNAMELEN]; 1008334SJose.Borrego@Sun.COM char sam_acct[SMB_SAMACCT_MAXLEN]; 10110717Samw@Sun.COM char ipc_usr[SMB_USERNAME_MAXLEN]; 10210717Samw@Sun.COM char *dom; 1038334SJose.Borrego@Sun.COM boolean_t new_domain = B_FALSE; 10410717Samw@Sun.COM smb_domainex_t dxi; 10510717Samw@Sun.COM smb_domain_t *di; 1068334SJose.Borrego@Sun.COM 1078334SJose.Borrego@Sun.COM if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN) 1088334SJose.Borrego@Sun.COM return (B_FALSE); 1098334SJose.Borrego@Sun.COM 1108334SJose.Borrego@Sun.COM if (smb_match_netlogon_seqnum()) 1118334SJose.Borrego@Sun.COM return (B_FALSE); 1128334SJose.Borrego@Sun.COM 1138334SJose.Borrego@Sun.COM (void) smb_config_getstr(SMB_CI_KPASSWD_SRV, kpasswd_srv, 1148334SJose.Borrego@Sun.COM sizeof (kpasswd_srv)); 1158334SJose.Borrego@Sun.COM 1168334SJose.Borrego@Sun.COM if (*kpasswd_srv == '\0') 1178334SJose.Borrego@Sun.COM return (B_FALSE); 1188334SJose.Borrego@Sun.COM 1198334SJose.Borrego@Sun.COM /* 1208334SJose.Borrego@Sun.COM * If the domain join initiated by smbadm join CLI is in 1218334SJose.Borrego@Sun.COM * progress, don't do anything. 1228334SJose.Borrego@Sun.COM */ 1238334SJose.Borrego@Sun.COM (void) smb_getsamaccount(sam_acct, sizeof (sam_acct)); 12410717Samw@Sun.COM smb_ipc_get_user(ipc_usr, SMB_USERNAME_MAXLEN); 125*10966SJordan.Brown@Sun.COM if (smb_strcasecmp(ipc_usr, sam_acct, 0)) 1268334SJose.Borrego@Sun.COM return (B_FALSE); 1278334SJose.Borrego@Sun.COM 12810717Samw@Sun.COM di = &dxi.d_primary; 12910717Samw@Sun.COM if (!smb_domain_getinfo(&dxi)) 1309832Samw@Sun.COM (void) smb_getfqdomainname(di->di_fqname, MAXHOSTNAMELEN); 1318334SJose.Borrego@Sun.COM 1328334SJose.Borrego@Sun.COM (void) smb_config_getstr(SMB_CI_KPASSWD_DOMAIN, kpasswd_domain, 1338334SJose.Borrego@Sun.COM sizeof (kpasswd_domain)); 1348334SJose.Borrego@Sun.COM 1358334SJose.Borrego@Sun.COM if (*kpasswd_domain != '\0' && 136*10966SJordan.Brown@Sun.COM smb_strcasecmp(kpasswd_domain, di->di_fqname, 0)) { 1378334SJose.Borrego@Sun.COM dom = kpasswd_domain; 1388334SJose.Borrego@Sun.COM new_domain = B_TRUE; 1398334SJose.Borrego@Sun.COM } else { 1409832Samw@Sun.COM dom = di->di_fqname; 1418334SJose.Borrego@Sun.COM } 1428334SJose.Borrego@Sun.COM 1438334SJose.Borrego@Sun.COM /* 1448334SJose.Borrego@Sun.COM * DC discovery will be triggered if the domain info is not 1458334SJose.Borrego@Sun.COM * currently cached or the SMB daemon has previously discovered a DC 1468334SJose.Borrego@Sun.COM * that is different than the kpasswd server. 1478334SJose.Borrego@Sun.COM */ 148*10966SJordan.Brown@Sun.COM if (new_domain || smb_strcasecmp(dxi.d_dc, kpasswd_srv, 0) != 0) { 14910717Samw@Sun.COM if (*dxi.d_dc != '\0') 15010717Samw@Sun.COM mlsvc_disconnect(dxi.d_dc); 1518334SJose.Borrego@Sun.COM 15210717Samw@Sun.COM if (!smb_locate_dc(dom, kpasswd_srv, &dxi)) { 15310717Samw@Sun.COM if (!smb_locate_dc(di->di_fqname, "", &dxi)) { 15410717Samw@Sun.COM smb_ipc_commit(); 1558334SJose.Borrego@Sun.COM return (B_FALSE); 1568334SJose.Borrego@Sun.COM } 1578334SJose.Borrego@Sun.COM } 1588334SJose.Borrego@Sun.COM } 1598334SJose.Borrego@Sun.COM 16010717Samw@Sun.COM smb_ipc_commit(); 16110717Samw@Sun.COM if (mlsvc_netlogon(dxi.d_dc, di->di_nbname)) { 1628334SJose.Borrego@Sun.COM syslog(LOG_ERR, 1638334SJose.Borrego@Sun.COM "failed to establish NETLOGON credential chain"); 1648334SJose.Borrego@Sun.COM return (B_TRUE); 1658334SJose.Borrego@Sun.COM } else { 1668334SJose.Borrego@Sun.COM if (new_domain) { 1679832Samw@Sun.COM smb_config_setdomaininfo(di->di_nbname, di->di_fqname, 1689832Samw@Sun.COM di->di_sid, 1699832Samw@Sun.COM di->di_u.di_dns.ddi_forest, 1709832Samw@Sun.COM di->di_u.di_dns.ddi_guid); 1718334SJose.Borrego@Sun.COM (void) smb_config_setstr(SMB_CI_KPASSWD_DOMAIN, ""); 1728334SJose.Borrego@Sun.COM } 1738334SJose.Borrego@Sun.COM } 1748334SJose.Borrego@Sun.COM 1758334SJose.Borrego@Sun.COM return (new_domain); 1768334SJose.Borrego@Sun.COM } 1778334SJose.Borrego@Sun.COM 1788334SJose.Borrego@Sun.COM /* 1798334SJose.Borrego@Sun.COM * smbd_locate_dc_start() 1808334SJose.Borrego@Sun.COM * 1818334SJose.Borrego@Sun.COM * Initialization of the thread that triggers the initial DC discovery 1828334SJose.Borrego@Sun.COM * when SMB daemon starts up. 1838334SJose.Borrego@Sun.COM * Returns 0 on success, an error number if thread creation fails. 1848334SJose.Borrego@Sun.COM */ 1858334SJose.Borrego@Sun.COM int 1868334SJose.Borrego@Sun.COM smbd_locate_dc_start(void) 1878334SJose.Borrego@Sun.COM { 1888334SJose.Borrego@Sun.COM pthread_attr_t tattr; 1898334SJose.Borrego@Sun.COM int rc; 1908334SJose.Borrego@Sun.COM 1918334SJose.Borrego@Sun.COM (void) pthread_attr_init(&tattr); 1928334SJose.Borrego@Sun.COM (void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); 1938334SJose.Borrego@Sun.COM rc = pthread_create(&smb_locate_dc_thr, &tattr, smbd_locate_dc_thread, 1948334SJose.Borrego@Sun.COM NULL); 1958334SJose.Borrego@Sun.COM (void) pthread_attr_destroy(&tattr); 1968334SJose.Borrego@Sun.COM return (rc); 1978334SJose.Borrego@Sun.COM } 1988334SJose.Borrego@Sun.COM 1998334SJose.Borrego@Sun.COM /* 2008334SJose.Borrego@Sun.COM * smbd_locate_dc_thread() 2018334SJose.Borrego@Sun.COM * 2028334SJose.Borrego@Sun.COM * If necessary, set up Netlogon credential chain and locate a 2038334SJose.Borrego@Sun.COM * domain controller in the given resource domain. 2048334SJose.Borrego@Sun.COM * 2058334SJose.Borrego@Sun.COM * The domain configuration will be updated upon a successful DC discovery. 2068334SJose.Borrego@Sun.COM */ 2078334SJose.Borrego@Sun.COM /*ARGSUSED*/ 2088334SJose.Borrego@Sun.COM static void * 2098334SJose.Borrego@Sun.COM smbd_locate_dc_thread(void *arg) 2108334SJose.Borrego@Sun.COM { 2118334SJose.Borrego@Sun.COM char domain[MAXHOSTNAMELEN]; 21210717Samw@Sun.COM smb_domainex_t new_domain; 21310717Samw@Sun.COM smb_domain_t *di; 2148334SJose.Borrego@Sun.COM 2158334SJose.Borrego@Sun.COM if (!smb_match_netlogon_seqnum()) { 2168334SJose.Borrego@Sun.COM (void) smbd_set_netlogon_cred(); 2178334SJose.Borrego@Sun.COM } else { 2188334SJose.Borrego@Sun.COM if (smb_getfqdomainname(domain, MAXHOSTNAMELEN) != 0) { 2198334SJose.Borrego@Sun.COM (void) smb_getdomainname(domain, MAXHOSTNAMELEN); 220*10966SJordan.Brown@Sun.COM (void) smb_strupr(domain); 2218334SJose.Borrego@Sun.COM } 2228334SJose.Borrego@Sun.COM 2239832Samw@Sun.COM if (smb_locate_dc(domain, "", &new_domain)) { 22410717Samw@Sun.COM di = &new_domain.d_primary; 2259832Samw@Sun.COM smb_config_setdomaininfo(di->di_nbname, di->di_fqname, 2269832Samw@Sun.COM di->di_sid, 2279832Samw@Sun.COM di->di_u.di_dns.ddi_forest, 2289832Samw@Sun.COM di->di_u.di_dns.ddi_guid); 2299832Samw@Sun.COM } 2308334SJose.Borrego@Sun.COM } 2318334SJose.Borrego@Sun.COM 2328334SJose.Borrego@Sun.COM return (NULL); 2338334SJose.Borrego@Sun.COM } 2348334SJose.Borrego@Sun.COM 2358334SJose.Borrego@Sun.COM 2368334SJose.Borrego@Sun.COM /* 2376139Sjb150015 * Retrieve the kpasswd server from krb5.conf. 2388334SJose.Borrego@Sun.COM * 2398334SJose.Borrego@Sun.COM * Initialization of the locate dc thread. 2408334SJose.Borrego@Sun.COM * Returns 0 on success, an error number if thread creation fails. 2416139Sjb150015 */ 2426139Sjb150015 static int 2436139Sjb150015 smbd_get_kpasswd_srv(char *srv, size_t len) 2446139Sjb150015 { 2456139Sjb150015 FILE *fp; 2466139Sjb150015 static char buf[512]; 2476139Sjb150015 char *p; 2486139Sjb150015 2496139Sjb150015 *srv = '\0'; 2506139Sjb150015 p = getenv("KRB5_CONFIG"); 2516139Sjb150015 if (p == NULL || *p == '\0') 2526139Sjb150015 p = "/etc/krb5/krb5.conf"; 2536139Sjb150015 2546139Sjb150015 if ((fp = fopen(p, "r")) == NULL) 2556139Sjb150015 return (-1); 2566139Sjb150015 2576139Sjb150015 while (fgets(buf, sizeof (buf), fp)) { 2586139Sjb150015 2596139Sjb150015 /* Weed out any comment text */ 2606139Sjb150015 (void) trim_whitespace(buf); 2616139Sjb150015 if (*buf == '#') 2626139Sjb150015 continue; 2636139Sjb150015 2646139Sjb150015 if ((p = strstr(buf, "kpasswd_server")) != NULL) { 2656139Sjb150015 if ((p = strchr(p, '=')) != NULL) { 2666139Sjb150015 (void) trim_whitespace(++p); 2676139Sjb150015 (void) strlcpy(srv, p, len); 2686139Sjb150015 } 2696139Sjb150015 break; 2706139Sjb150015 } 2716139Sjb150015 } 2726139Sjb150015 2738334SJose.Borrego@Sun.COM 2746139Sjb150015 (void) fclose(fp); 2756139Sjb150015 return ((*srv == '\0') ? -1 : 0); 2766139Sjb150015 } 2776139Sjb150015 2788334SJose.Borrego@Sun.COM static uint32_t 2798334SJose.Borrego@Sun.COM smbd_join_workgroup(smb_joininfo_t *info) 2805331Samw { 2818334SJose.Borrego@Sun.COM char nb_domain[SMB_PI_MAX_DOMAIN]; 2828334SJose.Borrego@Sun.COM 2838334SJose.Borrego@Sun.COM (void) smb_config_getstr(SMB_CI_DOMAIN_NAME, nb_domain, 2848334SJose.Borrego@Sun.COM sizeof (nb_domain)); 2858334SJose.Borrego@Sun.COM 2868334SJose.Borrego@Sun.COM smbd_set_secmode(SMB_SECMODE_WORKGRP); 2879832Samw@Sun.COM smb_config_setdomaininfo(info->domain_name, "", "", "", ""); 2888334SJose.Borrego@Sun.COM 2898334SJose.Borrego@Sun.COM if (strcasecmp(nb_domain, info->domain_name)) 2908334SJose.Borrego@Sun.COM smb_browser_reconfig(); 2918334SJose.Borrego@Sun.COM 2928334SJose.Borrego@Sun.COM return (NT_STATUS_SUCCESS); 2938334SJose.Borrego@Sun.COM } 2948334SJose.Borrego@Sun.COM 2958334SJose.Borrego@Sun.COM static uint32_t 2968334SJose.Borrego@Sun.COM smbd_join_domain(smb_joininfo_t *info) 2978334SJose.Borrego@Sun.COM { 2985331Samw uint32_t status; 2995331Samw unsigned char passwd_hash[SMBAUTH_HASH_SZ]; 3006139Sjb150015 char dc[MAXHOSTNAMELEN]; 30110717Samw@Sun.COM smb_domainex_t dxi; 30210717Samw@Sun.COM smb_domain_t *di; 3035331Samw 3045331Samw /* 3055331Samw * Ensure that any previous membership of this domain has 3065331Samw * been cleared from the environment before we start. This 3075331Samw * will ensure that we don't attempt a NETLOGON_SAMLOGON 3085331Samw * when attempting to find the PDC. 3095331Samw */ 3108334SJose.Borrego@Sun.COM 3115772Sas200622 (void) smb_config_setbool(SMB_CI_DOMAIN_MEMB, B_FALSE); 3125772Sas200622 3138334SJose.Borrego@Sun.COM if (smb_auth_ntlm_hash(info->domain_passwd, passwd_hash) 3148334SJose.Borrego@Sun.COM != SMBAUTH_SUCCESS) { 3158334SJose.Borrego@Sun.COM syslog(LOG_ERR, "smbd: could not compute ntlm hash for '%s'", 3168334SJose.Borrego@Sun.COM info->domain_username); 3175772Sas200622 return (NT_STATUS_INTERNAL_ERROR); 3185772Sas200622 } 3195331Samw 32010717Samw@Sun.COM smb_ipc_set(info->domain_username, passwd_hash); 3215331Samw 3226139Sjb150015 (void) smbd_get_kpasswd_srv(dc, sizeof (dc)); 3238334SJose.Borrego@Sun.COM /* info->domain_name could either be NetBIOS domain name or FQDN */ 32410717Samw@Sun.COM if (smb_locate_dc(info->domain_name, dc, &dxi)) { 32510717Samw@Sun.COM status = mlsvc_join(&dxi, info->domain_username, 3268334SJose.Borrego@Sun.COM info->domain_passwd); 3275331Samw 3285331Samw if (status == NT_STATUS_SUCCESS) { 32910717Samw@Sun.COM di = &dxi.d_primary; 3308334SJose.Borrego@Sun.COM smbd_set_secmode(SMB_SECMODE_DOMAIN); 3319832Samw@Sun.COM smb_config_setdomaininfo(di->di_nbname, di->di_fqname, 3329832Samw@Sun.COM di->di_sid, 3339832Samw@Sun.COM di->di_u.di_dns.ddi_forest, 3349832Samw@Sun.COM di->di_u.di_dns.ddi_guid); 33510717Samw@Sun.COM smb_ipc_commit(); 3365331Samw return (status); 3375331Samw } 3385331Samw 33910717Samw@Sun.COM smb_ipc_rollback(); 3405331Samw syslog(LOG_ERR, "smbd: failed joining %s (%s)", 3415331Samw info->domain_name, xlate_nt_status(status)); 3425331Samw return (status); 3435331Samw } 3445331Samw 34510717Samw@Sun.COM smb_ipc_rollback(); 3465331Samw syslog(LOG_ERR, "smbd: failed locating domain controller for %s", 3475331Samw info->domain_name); 3485331Samw return (NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND); 3495331Samw } 350