18334SJose.Borrego@Sun.COM /* 28334SJose.Borrego@Sun.COM * CDDL HEADER START 38334SJose.Borrego@Sun.COM * 48334SJose.Borrego@Sun.COM * The contents of this file are subject to the terms of the 58334SJose.Borrego@Sun.COM * Common Development and Distribution License (the "License"). 68334SJose.Borrego@Sun.COM * You may not use this file except in compliance with the License. 78334SJose.Borrego@Sun.COM * 88334SJose.Borrego@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 98334SJose.Borrego@Sun.COM * or http://www.opensolaris.org/os/licensing. 108334SJose.Borrego@Sun.COM * See the License for the specific language governing permissions 118334SJose.Borrego@Sun.COM * and limitations under the License. 128334SJose.Borrego@Sun.COM * 138334SJose.Borrego@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 148334SJose.Borrego@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 158334SJose.Borrego@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 168334SJose.Borrego@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 178334SJose.Borrego@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 188334SJose.Borrego@Sun.COM * 198334SJose.Borrego@Sun.COM * CDDL HEADER END 208334SJose.Borrego@Sun.COM */ 218334SJose.Borrego@Sun.COM /* 22*8474SJose.Borrego@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 238334SJose.Borrego@Sun.COM * Use is subject to license terms. 248334SJose.Borrego@Sun.COM */ 258334SJose.Borrego@Sun.COM 268334SJose.Borrego@Sun.COM #include <syslog.h> 278334SJose.Borrego@Sun.COM #include <synch.h> 288334SJose.Borrego@Sun.COM #include <pthread.h> 298334SJose.Borrego@Sun.COM #include <unistd.h> 308334SJose.Borrego@Sun.COM #include <string.h> 318334SJose.Borrego@Sun.COM #include <strings.h> 328334SJose.Borrego@Sun.COM #include <sys/errno.h> 338334SJose.Borrego@Sun.COM #include <sys/types.h> 348334SJose.Borrego@Sun.COM #include <netinet/in.h> 358334SJose.Borrego@Sun.COM #include <arpa/nameser.h> 368334SJose.Borrego@Sun.COM #include <resolv.h> 378334SJose.Borrego@Sun.COM #include <netdb.h> 388334SJose.Borrego@Sun.COM #include <assert.h> 398334SJose.Borrego@Sun.COM 408334SJose.Borrego@Sun.COM #include <smbsrv/libsmb.h> 418334SJose.Borrego@Sun.COM #include <smbsrv/libsmbrdr.h> 428334SJose.Borrego@Sun.COM #include <smbsrv/libsmbns.h> 438334SJose.Borrego@Sun.COM #include <smbsrv/libmlsvc.h> 448334SJose.Borrego@Sun.COM 458334SJose.Borrego@Sun.COM #include <smbsrv/smbinfo.h> 468334SJose.Borrego@Sun.COM #include <smbsrv/ntstatus.h> 478334SJose.Borrego@Sun.COM #include <lsalib.h> 488334SJose.Borrego@Sun.COM 498334SJose.Borrego@Sun.COM /* 508334SJose.Borrego@Sun.COM * Domain cache states 518334SJose.Borrego@Sun.COM */ 528334SJose.Borrego@Sun.COM #define SMB_DCACHE_STATE_INVALID 0 538334SJose.Borrego@Sun.COM #define SMB_DCACHE_STATE_UPDATING 1 548334SJose.Borrego@Sun.COM #define SMB_DCACHE_STATE_VALID 2 558334SJose.Borrego@Sun.COM 568334SJose.Borrego@Sun.COM typedef struct smb_domain_cache { 578334SJose.Borrego@Sun.COM uint32_t c_state; 588334SJose.Borrego@Sun.COM smb_domain_t c_cache; 598334SJose.Borrego@Sun.COM mutex_t c_mtx; 608334SJose.Borrego@Sun.COM cond_t c_cv; 618334SJose.Borrego@Sun.COM } smb_domain_cache_t; 628334SJose.Borrego@Sun.COM 638334SJose.Borrego@Sun.COM static smb_domain_cache_t smb_dcache; 648334SJose.Borrego@Sun.COM 658334SJose.Borrego@Sun.COM /* functions to manipulate the domain cache */ 668334SJose.Borrego@Sun.COM static void smb_dcache_init(void); 678334SJose.Borrego@Sun.COM static void smb_dcache_updating(void); 688334SJose.Borrego@Sun.COM static void smb_dcache_invalid(void); 698334SJose.Borrego@Sun.COM static void smb_dcache_valid(smb_domain_t *); 708334SJose.Borrego@Sun.COM static void smb_dcache_set(uint32_t, smb_domain_t *); 718334SJose.Borrego@Sun.COM 728334SJose.Borrego@Sun.COM /* 738334SJose.Borrego@Sun.COM * DC Locator 748334SJose.Borrego@Sun.COM */ 758334SJose.Borrego@Sun.COM #define SMB_DCLOCATOR_TIMEOUT 45 768334SJose.Borrego@Sun.COM #define SMB_IS_FQDN(domain) (strchr(domain, '.') != NULL) 778334SJose.Borrego@Sun.COM 788334SJose.Borrego@Sun.COM typedef struct smb_dclocator { 798334SJose.Borrego@Sun.COM char sdl_domain[SMB_PI_MAX_DOMAIN]; 808334SJose.Borrego@Sun.COM char sdl_dc[MAXHOSTNAMELEN]; 818334SJose.Borrego@Sun.COM boolean_t sdl_locate; 828334SJose.Borrego@Sun.COM mutex_t sdl_mtx; 838334SJose.Borrego@Sun.COM cond_t sdl_cv; 848334SJose.Borrego@Sun.COM uint32_t sdl_status; 858334SJose.Borrego@Sun.COM } smb_dclocator_t; 868334SJose.Borrego@Sun.COM 878334SJose.Borrego@Sun.COM static smb_dclocator_t smb_dclocator; 888334SJose.Borrego@Sun.COM static pthread_t smb_dclocator_thr; 898334SJose.Borrego@Sun.COM 908334SJose.Borrego@Sun.COM static void *smb_dclocator_main(void *); 918334SJose.Borrego@Sun.COM static boolean_t smb_dc_discovery(char *, char *, smb_domain_t *); 928334SJose.Borrego@Sun.COM static boolean_t smb_match_domains(char *, char *, uint32_t); 938334SJose.Borrego@Sun.COM static uint32_t smb_domain_query(char *, char *, smb_domain_t *); 948334SJose.Borrego@Sun.COM static void smb_domain_update_tabent(int, lsa_nt_domaininfo_t *); 958334SJose.Borrego@Sun.COM static void smb_domain_populate_table(char *, char *); 968334SJose.Borrego@Sun.COM static boolean_t smb_domain_use_config(char *, smb_domain_t *); 978334SJose.Borrego@Sun.COM 988334SJose.Borrego@Sun.COM /* 998334SJose.Borrego@Sun.COM * =================================================================== 1008334SJose.Borrego@Sun.COM * API to initialize DC locator thread, trigger DC discovery, and 1018334SJose.Borrego@Sun.COM * get the discovered DC and/or domain information. 1028334SJose.Borrego@Sun.COM * =================================================================== 1038334SJose.Borrego@Sun.COM */ 1048334SJose.Borrego@Sun.COM 1058334SJose.Borrego@Sun.COM /* 1068334SJose.Borrego@Sun.COM * smb_dclocator_init 1078334SJose.Borrego@Sun.COM * 1088334SJose.Borrego@Sun.COM * Initialization of the DC locator thread. 1098334SJose.Borrego@Sun.COM * Returns 0 on success, an error number if thread creation fails. 1108334SJose.Borrego@Sun.COM */ 1118334SJose.Borrego@Sun.COM int 1128334SJose.Borrego@Sun.COM smb_dclocator_init(void) 1138334SJose.Borrego@Sun.COM { 1148334SJose.Borrego@Sun.COM pthread_attr_t tattr; 1158334SJose.Borrego@Sun.COM int rc; 1168334SJose.Borrego@Sun.COM 1178334SJose.Borrego@Sun.COM smb_dcache_init(); 1188334SJose.Borrego@Sun.COM (void) pthread_attr_init(&tattr); 1198334SJose.Borrego@Sun.COM (void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); 1208334SJose.Borrego@Sun.COM rc = pthread_create(&smb_dclocator_thr, &tattr, 1218334SJose.Borrego@Sun.COM smb_dclocator_main, 0); 1228334SJose.Borrego@Sun.COM (void) pthread_attr_destroy(&tattr); 1238334SJose.Borrego@Sun.COM return (rc); 1248334SJose.Borrego@Sun.COM } 1258334SJose.Borrego@Sun.COM 1268334SJose.Borrego@Sun.COM /* 1278334SJose.Borrego@Sun.COM * smb_locate_dc 1288334SJose.Borrego@Sun.COM * 1298334SJose.Borrego@Sun.COM * This is the entry point for discovering a domain controller for the 1308334SJose.Borrego@Sun.COM * specified domain. 1318334SJose.Borrego@Sun.COM * 1328334SJose.Borrego@Sun.COM * The actual work of discovering a DC is handled by DC locator thread. 1338334SJose.Borrego@Sun.COM * All we do here is signal the request and wait for a DC or a timeout. 1348334SJose.Borrego@Sun.COM * 1358334SJose.Borrego@Sun.COM * Input parameters: 1368334SJose.Borrego@Sun.COM * domain - domain to be discovered (can either be NetBIOS or DNS domain) 1378334SJose.Borrego@Sun.COM * dc - preferred DC. If the preferred DC is set to empty string, it 1388334SJose.Borrego@Sun.COM * will attempt to discover any DC in the specified domain. 1398334SJose.Borrego@Sun.COM * 1408334SJose.Borrego@Sun.COM * Output parameter: 1418334SJose.Borrego@Sun.COM * dp - on success, dp will be filled with the discovered DC and domain 1428334SJose.Borrego@Sun.COM * information. 1438334SJose.Borrego@Sun.COM * Returns B_TRUE if the DC/domain info is available. 1448334SJose.Borrego@Sun.COM */ 1458334SJose.Borrego@Sun.COM boolean_t 1468334SJose.Borrego@Sun.COM smb_locate_dc(char *domain, char *dc, smb_domain_t *dp) 1478334SJose.Borrego@Sun.COM { 1488334SJose.Borrego@Sun.COM int rc; 1498334SJose.Borrego@Sun.COM timestruc_t to; 1508334SJose.Borrego@Sun.COM smb_domain_t domain_info; 1518334SJose.Borrego@Sun.COM 1528334SJose.Borrego@Sun.COM if (domain == NULL || *domain == '\0') 1538334SJose.Borrego@Sun.COM return (B_FALSE); 1548334SJose.Borrego@Sun.COM 1558334SJose.Borrego@Sun.COM (void) mutex_lock(&smb_dclocator.sdl_mtx); 1568334SJose.Borrego@Sun.COM 1578334SJose.Borrego@Sun.COM if (!smb_dclocator.sdl_locate) { 1588334SJose.Borrego@Sun.COM smb_dclocator.sdl_locate = B_TRUE; 1598334SJose.Borrego@Sun.COM (void) strlcpy(smb_dclocator.sdl_domain, domain, 1608334SJose.Borrego@Sun.COM SMB_PI_MAX_DOMAIN); 1618334SJose.Borrego@Sun.COM (void) strlcpy(smb_dclocator.sdl_dc, dc, 1628334SJose.Borrego@Sun.COM MAXHOSTNAMELEN); 1638334SJose.Borrego@Sun.COM (void) cond_broadcast(&smb_dclocator.sdl_cv); 1648334SJose.Borrego@Sun.COM } 1658334SJose.Borrego@Sun.COM 1668334SJose.Borrego@Sun.COM while (smb_dclocator.sdl_locate) { 1678334SJose.Borrego@Sun.COM to.tv_sec = SMB_DCLOCATOR_TIMEOUT; 1688334SJose.Borrego@Sun.COM to.tv_nsec = 0; 1698334SJose.Borrego@Sun.COM rc = cond_reltimedwait(&smb_dclocator.sdl_cv, 1708334SJose.Borrego@Sun.COM &smb_dclocator.sdl_mtx, &to); 1718334SJose.Borrego@Sun.COM 1728334SJose.Borrego@Sun.COM if (rc == ETIME) 1738334SJose.Borrego@Sun.COM break; 1748334SJose.Borrego@Sun.COM } 1758334SJose.Borrego@Sun.COM 1768334SJose.Borrego@Sun.COM if (dp == NULL) 1778334SJose.Borrego@Sun.COM dp = &domain_info; 1788334SJose.Borrego@Sun.COM rc = smb_domain_getinfo(dp); 1798334SJose.Borrego@Sun.COM (void) mutex_unlock(&smb_dclocator.sdl_mtx); 1808334SJose.Borrego@Sun.COM 1818334SJose.Borrego@Sun.COM return (rc); 1828334SJose.Borrego@Sun.COM } 1838334SJose.Borrego@Sun.COM 1848334SJose.Borrego@Sun.COM /* 1858334SJose.Borrego@Sun.COM * smb_domain_getinfo 1868334SJose.Borrego@Sun.COM * 1878334SJose.Borrego@Sun.COM * If the DC discovery process is underway, this function will wait on 1888334SJose.Borrego@Sun.COM * a condition variable until the state of SMB domain cache sets to 1898334SJose.Borrego@Sun.COM * either VALID/INVALID. 1908334SJose.Borrego@Sun.COM * 1918334SJose.Borrego@Sun.COM * Returns a copy of the domain cache. 1928334SJose.Borrego@Sun.COM */ 1938334SJose.Borrego@Sun.COM boolean_t 1948334SJose.Borrego@Sun.COM smb_domain_getinfo(smb_domain_t *dp) 1958334SJose.Borrego@Sun.COM { 1968334SJose.Borrego@Sun.COM timestruc_t to; 1978334SJose.Borrego@Sun.COM int err; 1988334SJose.Borrego@Sun.COM boolean_t rc; 1998334SJose.Borrego@Sun.COM 2008334SJose.Borrego@Sun.COM (void) mutex_lock(&smb_dcache.c_mtx); 2018334SJose.Borrego@Sun.COM to.tv_sec = SMB_DCLOCATOR_TIMEOUT; 2028334SJose.Borrego@Sun.COM to.tv_nsec = 0; 2038334SJose.Borrego@Sun.COM while (smb_dcache.c_state == SMB_DCACHE_STATE_UPDATING) { 2048334SJose.Borrego@Sun.COM err = cond_reltimedwait(&smb_dcache.c_cv, &smb_dcache.c_mtx, 2058334SJose.Borrego@Sun.COM &to); 2068334SJose.Borrego@Sun.COM if (err == ETIME) 2078334SJose.Borrego@Sun.COM break; 2088334SJose.Borrego@Sun.COM } 2098334SJose.Borrego@Sun.COM 2108334SJose.Borrego@Sun.COM if (smb_dcache.c_state == SMB_DCACHE_STATE_VALID) { 2118334SJose.Borrego@Sun.COM bcopy(&smb_dcache.c_cache, dp, sizeof (smb_domain_t)); 2128334SJose.Borrego@Sun.COM rc = B_TRUE; 2138334SJose.Borrego@Sun.COM } else { 2148334SJose.Borrego@Sun.COM bzero(dp, sizeof (smb_domain_t)); 2158334SJose.Borrego@Sun.COM rc = B_FALSE; 2168334SJose.Borrego@Sun.COM } 2178334SJose.Borrego@Sun.COM 2188334SJose.Borrego@Sun.COM (void) mutex_unlock(&smb_dcache.c_mtx); 2198334SJose.Borrego@Sun.COM return (rc); 2208334SJose.Borrego@Sun.COM } 2218334SJose.Borrego@Sun.COM 2228334SJose.Borrego@Sun.COM 2238334SJose.Borrego@Sun.COM /* 2248334SJose.Borrego@Sun.COM * ===================================================================== 2258334SJose.Borrego@Sun.COM * Private functions used by DC locator thread to manipulate the domain 2268334SJose.Borrego@Sun.COM * cache. 2278334SJose.Borrego@Sun.COM * ====================================================================== 2288334SJose.Borrego@Sun.COM */ 2298334SJose.Borrego@Sun.COM 2308334SJose.Borrego@Sun.COM static void 2318334SJose.Borrego@Sun.COM smb_dcache_init(void) 2328334SJose.Borrego@Sun.COM { 2338334SJose.Borrego@Sun.COM (void) mutex_lock(&smb_dcache.c_mtx); 2348334SJose.Borrego@Sun.COM smb_dcache.c_state = SMB_DCACHE_STATE_INVALID; 2358334SJose.Borrego@Sun.COM bzero(&smb_dcache.c_cache, sizeof (smb_domain_t)); 2368334SJose.Borrego@Sun.COM (void) mutex_unlock(&smb_dcache.c_mtx); 2378334SJose.Borrego@Sun.COM } 2388334SJose.Borrego@Sun.COM 2398334SJose.Borrego@Sun.COM /* 2408334SJose.Borrego@Sun.COM * Set the cache state to UPDATING 2418334SJose.Borrego@Sun.COM */ 2428334SJose.Borrego@Sun.COM static void 2438334SJose.Borrego@Sun.COM smb_dcache_updating(void) 2448334SJose.Borrego@Sun.COM { 2458334SJose.Borrego@Sun.COM smb_dcache_set(SMB_DCACHE_STATE_UPDATING, NULL); 2468334SJose.Borrego@Sun.COM } 2478334SJose.Borrego@Sun.COM 2488334SJose.Borrego@Sun.COM /* 2498334SJose.Borrego@Sun.COM * Set the cache state to INVALID 2508334SJose.Borrego@Sun.COM */ 2518334SJose.Borrego@Sun.COM static void 2528334SJose.Borrego@Sun.COM smb_dcache_invalid(void) 2538334SJose.Borrego@Sun.COM { 2548334SJose.Borrego@Sun.COM smb_dcache_set(SMB_DCACHE_STATE_INVALID, NULL); 2558334SJose.Borrego@Sun.COM } 2568334SJose.Borrego@Sun.COM 2578334SJose.Borrego@Sun.COM /* 2588334SJose.Borrego@Sun.COM * Set the cache state to VALID and populate the cache 2598334SJose.Borrego@Sun.COM */ 2608334SJose.Borrego@Sun.COM static void 2618334SJose.Borrego@Sun.COM smb_dcache_valid(smb_domain_t *dp) 2628334SJose.Borrego@Sun.COM { 2638334SJose.Borrego@Sun.COM smb_dcache_set(SMB_DCACHE_STATE_VALID, dp); 2648334SJose.Borrego@Sun.COM } 2658334SJose.Borrego@Sun.COM 2668334SJose.Borrego@Sun.COM /* 2678334SJose.Borrego@Sun.COM * This function will update both the state and the contents of the 2688334SJose.Borrego@Sun.COM * SMB domain cache. If one attempts to set the state to 2698334SJose.Borrego@Sun.COM * SMB_DCACHE_STATE_UPDATING, the domain cache will be updated based 2708334SJose.Borrego@Sun.COM * on 'dp' argument. Otherwise, 'dp' is ignored. 2718334SJose.Borrego@Sun.COM */ 2728334SJose.Borrego@Sun.COM static void 2738334SJose.Borrego@Sun.COM smb_dcache_set(uint32_t state, smb_domain_t *dp) 2748334SJose.Borrego@Sun.COM { 2758334SJose.Borrego@Sun.COM (void) mutex_lock(&smb_dcache.c_mtx); 2768334SJose.Borrego@Sun.COM switch (state) { 2778334SJose.Borrego@Sun.COM case SMB_DCACHE_STATE_INVALID: 2788334SJose.Borrego@Sun.COM break; 2798334SJose.Borrego@Sun.COM 2808334SJose.Borrego@Sun.COM case SMB_DCACHE_STATE_UPDATING: 2818334SJose.Borrego@Sun.COM bzero(&smb_dcache.c_cache, sizeof (smb_domain_t)); 2828334SJose.Borrego@Sun.COM break; 2838334SJose.Borrego@Sun.COM 2848334SJose.Borrego@Sun.COM case SMB_DCACHE_STATE_VALID: 2858334SJose.Borrego@Sun.COM assert(dp); 2868334SJose.Borrego@Sun.COM bcopy(dp, &smb_dcache.c_cache, sizeof (smb_domain_t)); 2878334SJose.Borrego@Sun.COM break; 2888334SJose.Borrego@Sun.COM 2898334SJose.Borrego@Sun.COM default: 2908334SJose.Borrego@Sun.COM (void) mutex_unlock(&smb_dcache.c_mtx); 2918334SJose.Borrego@Sun.COM return; 2928334SJose.Borrego@Sun.COM 2938334SJose.Borrego@Sun.COM } 2948334SJose.Borrego@Sun.COM 2958334SJose.Borrego@Sun.COM smb_dcache.c_state = state; 2968334SJose.Borrego@Sun.COM (void) cond_broadcast(&smb_dcache.c_cv); 2978334SJose.Borrego@Sun.COM (void) mutex_unlock(&smb_dcache.c_mtx); 2988334SJose.Borrego@Sun.COM } 2998334SJose.Borrego@Sun.COM 3008334SJose.Borrego@Sun.COM /* 3018334SJose.Borrego@Sun.COM * ========================================================== 3028334SJose.Borrego@Sun.COM * DC discovery functions 3038334SJose.Borrego@Sun.COM * ========================================================== 3048334SJose.Borrego@Sun.COM */ 3058334SJose.Borrego@Sun.COM 3068334SJose.Borrego@Sun.COM /* 3078334SJose.Borrego@Sun.COM * smb_dclocator_main 3088334SJose.Borrego@Sun.COM * 3098334SJose.Borrego@Sun.COM * This is the DC discovery thread: it gets woken up whenever someone 3108334SJose.Borrego@Sun.COM * wants to locate a domain controller. 3118334SJose.Borrego@Sun.COM * 3128334SJose.Borrego@Sun.COM * The state of the SMB domain cache will be initialized to 3138334SJose.Borrego@Sun.COM * SMB_DCACHE_STATE_UPDATING when the discovery process starts and will be 3148334SJose.Borrego@Sun.COM * transitioned to SMB_DCACHE_STATE_VALID/INVALID depending on the outcome of 3158334SJose.Borrego@Sun.COM * the discovery. 3168334SJose.Borrego@Sun.COM * 3178334SJose.Borrego@Sun.COM * If the discovery process is underway, callers of smb_domain_getinfo() 3188334SJose.Borrego@Sun.COM * will wait on a condition variable until the state of SMB domain cache 3198334SJose.Borrego@Sun.COM * sets to either VALID/INVALID. 3208334SJose.Borrego@Sun.COM * 3218334SJose.Borrego@Sun.COM * Upon success, the SMB domain cache will be populated with the discovered DC 3228334SJose.Borrego@Sun.COM * and domain info. 3238334SJose.Borrego@Sun.COM */ 3248334SJose.Borrego@Sun.COM /*ARGSUSED*/ 3258334SJose.Borrego@Sun.COM static void * 3268334SJose.Borrego@Sun.COM smb_dclocator_main(void *arg) 3278334SJose.Borrego@Sun.COM { 3288334SJose.Borrego@Sun.COM char domain[SMB_PI_MAX_DOMAIN]; 3298334SJose.Borrego@Sun.COM char sought_dc[MAXHOSTNAMELEN]; 3308334SJose.Borrego@Sun.COM smb_domain_t dinfo; 3318334SJose.Borrego@Sun.COM 3328334SJose.Borrego@Sun.COM for (;;) { 3338334SJose.Borrego@Sun.COM (void) mutex_lock(&smb_dclocator.sdl_mtx); 3348334SJose.Borrego@Sun.COM 3358334SJose.Borrego@Sun.COM while (!smb_dclocator.sdl_locate) 3368334SJose.Borrego@Sun.COM (void) cond_wait(&smb_dclocator.sdl_cv, 3378334SJose.Borrego@Sun.COM &smb_dclocator.sdl_mtx); 3388334SJose.Borrego@Sun.COM 3398334SJose.Borrego@Sun.COM (void) strlcpy(domain, smb_dclocator.sdl_domain, 3408334SJose.Borrego@Sun.COM SMB_PI_MAX_DOMAIN); 3418334SJose.Borrego@Sun.COM (void) strlcpy(sought_dc, smb_dclocator.sdl_dc, MAXHOSTNAMELEN); 3428334SJose.Borrego@Sun.COM (void) mutex_unlock(&smb_dclocator.sdl_mtx); 3438334SJose.Borrego@Sun.COM 3448334SJose.Borrego@Sun.COM smb_dcache_updating(); 3458334SJose.Borrego@Sun.COM if (smb_dc_discovery(domain, sought_dc, &dinfo)) 3468334SJose.Borrego@Sun.COM smb_dcache_valid(&dinfo); 3478334SJose.Borrego@Sun.COM else 3488334SJose.Borrego@Sun.COM smb_dcache_invalid(); 3498334SJose.Borrego@Sun.COM 3508334SJose.Borrego@Sun.COM (void) mutex_lock(&smb_dclocator.sdl_mtx); 3518334SJose.Borrego@Sun.COM smb_dclocator.sdl_locate = B_FALSE; 3528334SJose.Borrego@Sun.COM (void) cond_broadcast(&smb_dclocator.sdl_cv); 3538334SJose.Borrego@Sun.COM (void) mutex_unlock(&smb_dclocator.sdl_mtx); 3548334SJose.Borrego@Sun.COM } 3558334SJose.Borrego@Sun.COM 3568334SJose.Borrego@Sun.COM /*NOTREACHED*/ 3578334SJose.Borrego@Sun.COM return (NULL); 3588334SJose.Borrego@Sun.COM } 3598334SJose.Borrego@Sun.COM 3608334SJose.Borrego@Sun.COM /* 3618334SJose.Borrego@Sun.COM * smb_dc_discovery 3628334SJose.Borrego@Sun.COM * 3638334SJose.Borrego@Sun.COM * If FQDN is specified, DC discovery will be done via DNS query only. 3648334SJose.Borrego@Sun.COM * If NetBIOS name of a domain is specified, DC discovery thread will 3658334SJose.Borrego@Sun.COM * use netlogon protocol to locate a DC. Upon failure, it will 3668334SJose.Borrego@Sun.COM * try to resolve it via DNS, i.e. find out if it is the first label 3678334SJose.Borrego@Sun.COM * of a DNS domain name. If the corresponding DNS name is found, DC 3688334SJose.Borrego@Sun.COM * discovery will be done via DNS query. 3698334SJose.Borrego@Sun.COM * 3708334SJose.Borrego@Sun.COM * Once the domain controller is found, it then queries the DC for domain 3718334SJose.Borrego@Sun.COM * information. If the LSA queries fail, the domain information stored in 3728334SJose.Borrego@Sun.COM * SMF might be used to set the SMB domain cache if the the discovered domain 3738334SJose.Borrego@Sun.COM * is the same as the previously joined domain. 3748334SJose.Borrego@Sun.COM * 3758334SJose.Borrego@Sun.COM * If the fully-qualified domain name is derived from the DNS config 3768334SJose.Borrego@Sun.COM * file, the NetBIOS domain name specified by the user will be compared 3778334SJose.Borrego@Sun.COM * against the NetBIOS domain name obtained via LSA query. If there is 3788334SJose.Borrego@Sun.COM * a mismatch, the DC discovery will fail since the discovered DC is 3798334SJose.Borrego@Sun.COM * actually for another domain, whose first label of its FQDN somehow 3808334SJose.Borrego@Sun.COM * matches with the NetBIOS name of the domain we're interested in. 3818334SJose.Borrego@Sun.COM */ 3828334SJose.Borrego@Sun.COM static boolean_t 3838334SJose.Borrego@Sun.COM smb_dc_discovery(char *domain, char *server, smb_domain_t *dinfo) 3848334SJose.Borrego@Sun.COM { 3858334SJose.Borrego@Sun.COM char derived_dnsdomain[MAXHOSTNAMELEN]; 3868334SJose.Borrego@Sun.COM boolean_t netlogon_ok = B_FALSE; 3878334SJose.Borrego@Sun.COM 3888334SJose.Borrego@Sun.COM *derived_dnsdomain = '\0'; 3898334SJose.Borrego@Sun.COM if (!SMB_IS_FQDN(domain)) { 3908334SJose.Borrego@Sun.COM if (smb_browser_netlogon(domain, dinfo->d_dc, MAXHOSTNAMELEN)) 3918334SJose.Borrego@Sun.COM netlogon_ok = B_TRUE; 3928334SJose.Borrego@Sun.COM else if (!smb_match_domains(domain, derived_dnsdomain, 3938334SJose.Borrego@Sun.COM MAXHOSTNAMELEN)) 3948334SJose.Borrego@Sun.COM return (B_FALSE); 3958334SJose.Borrego@Sun.COM } 3968334SJose.Borrego@Sun.COM 3978334SJose.Borrego@Sun.COM if (!netlogon_ok && !smb_ads_lookup_msdcs( 3988334SJose.Borrego@Sun.COM (SMB_IS_FQDN(domain) ? domain : derived_dnsdomain), server, 3998334SJose.Borrego@Sun.COM dinfo->d_dc, MAXHOSTNAMELEN)) 4008334SJose.Borrego@Sun.COM return (B_FALSE); 4018334SJose.Borrego@Sun.COM 4028334SJose.Borrego@Sun.COM if ((smb_domain_query(domain, dinfo->d_dc, dinfo) 4038334SJose.Borrego@Sun.COM != NT_STATUS_SUCCESS) && 4048334SJose.Borrego@Sun.COM (!smb_domain_use_config(domain, dinfo))) 4058334SJose.Borrego@Sun.COM return (B_FALSE); 4068334SJose.Borrego@Sun.COM 4078334SJose.Borrego@Sun.COM if (*derived_dnsdomain != '\0' && 4088334SJose.Borrego@Sun.COM utf8_strcasecmp(domain, dinfo->d_nbdomain)) 4098334SJose.Borrego@Sun.COM return (B_FALSE); 4108334SJose.Borrego@Sun.COM 4118334SJose.Borrego@Sun.COM /* 4128334SJose.Borrego@Sun.COM * Now that we get the fully-qualified DNS name of the 4138334SJose.Borrego@Sun.COM * domain via LSA query. Verifies ADS configuration 4148334SJose.Borrego@Sun.COM * if we previously locate a DC via NetBIOS. On success, 4158334SJose.Borrego@Sun.COM * ADS cache will be populated. 4168334SJose.Borrego@Sun.COM */ 4178334SJose.Borrego@Sun.COM if (netlogon_ok) { 4188334SJose.Borrego@Sun.COM if (smb_ads_lookup_msdcs(dinfo->d_fqdomain, server, 4198334SJose.Borrego@Sun.COM dinfo->d_dc, MAXHOSTNAMELEN) == 0) 4208334SJose.Borrego@Sun.COM return (B_FALSE); 4218334SJose.Borrego@Sun.COM } 4228334SJose.Borrego@Sun.COM 4238334SJose.Borrego@Sun.COM return (B_TRUE); 4248334SJose.Borrego@Sun.COM } 4258334SJose.Borrego@Sun.COM 4268334SJose.Borrego@Sun.COM /* 4278334SJose.Borrego@Sun.COM * Tries to find a matching DNS domain for the given NetBIOS domain 4288334SJose.Borrego@Sun.COM * name by checking the first label of system's configured DNS domains. 4298334SJose.Borrego@Sun.COM * If a match is found, it'll be returned in the passed buffer. 4308334SJose.Borrego@Sun.COM */ 4318334SJose.Borrego@Sun.COM static boolean_t 4328334SJose.Borrego@Sun.COM smb_match_domains(char *nb_domain, char *buf, uint32_t len) 4338334SJose.Borrego@Sun.COM { 4348334SJose.Borrego@Sun.COM struct __res_state res_state; 4358334SJose.Borrego@Sun.COM int i; 4368334SJose.Borrego@Sun.COM char *entry, *p; 4378334SJose.Borrego@Sun.COM char first_label[MAXHOSTNAMELEN]; 4388334SJose.Borrego@Sun.COM boolean_t found; 4398334SJose.Borrego@Sun.COM 4408334SJose.Borrego@Sun.COM if (!nb_domain || !buf) 4418334SJose.Borrego@Sun.COM return (B_FALSE); 4428334SJose.Borrego@Sun.COM 4438334SJose.Borrego@Sun.COM *buf = '\0'; 4448334SJose.Borrego@Sun.COM bzero(&res_state, sizeof (struct __res_state)); 4458334SJose.Borrego@Sun.COM if (res_ninit(&res_state)) 4468334SJose.Borrego@Sun.COM return (B_FALSE); 4478334SJose.Borrego@Sun.COM 4488334SJose.Borrego@Sun.COM found = B_FALSE; 4498334SJose.Borrego@Sun.COM entry = res_state.defdname; 4508334SJose.Borrego@Sun.COM for (i = 0; entry != NULL; i++) { 4518334SJose.Borrego@Sun.COM (void) strlcpy(first_label, entry, MAXHOSTNAMELEN); 4528334SJose.Borrego@Sun.COM if ((p = strchr(first_label, '.')) != NULL) { 4538334SJose.Borrego@Sun.COM *p = '\0'; 4548334SJose.Borrego@Sun.COM if (strlen(first_label) > 15) 4558334SJose.Borrego@Sun.COM first_label[15] = '\0'; 4568334SJose.Borrego@Sun.COM } 4578334SJose.Borrego@Sun.COM 4588334SJose.Borrego@Sun.COM if (utf8_strcasecmp(nb_domain, first_label) == 0) { 4598334SJose.Borrego@Sun.COM found = B_TRUE; 4608334SJose.Borrego@Sun.COM (void) strlcpy(buf, entry, len); 4618334SJose.Borrego@Sun.COM break; 4628334SJose.Borrego@Sun.COM } 4638334SJose.Borrego@Sun.COM 4648334SJose.Borrego@Sun.COM entry = res_state.dnsrch[i]; 4658334SJose.Borrego@Sun.COM } 4668334SJose.Borrego@Sun.COM 4678334SJose.Borrego@Sun.COM 4688334SJose.Borrego@Sun.COM res_ndestroy(&res_state); 4698334SJose.Borrego@Sun.COM return (found); 4708334SJose.Borrego@Sun.COM } 4718334SJose.Borrego@Sun.COM 4728334SJose.Borrego@Sun.COM /* 4738334SJose.Borrego@Sun.COM * smb_domain_query 4748334SJose.Borrego@Sun.COM * 4758334SJose.Borrego@Sun.COM * If the the NetBIOS name of an AD domain doesn't match with the 4768334SJose.Borrego@Sun.COM * first label of its fully-qualified DNS name, it is not possible 4778334SJose.Borrego@Sun.COM * to derive one name format from another. 4788334SJose.Borrego@Sun.COM * The missing domain info can be obtained via LSA query, DNS domain info. 4798334SJose.Borrego@Sun.COM * 4808334SJose.Borrego@Sun.COM * domain - either NetBIOS or fully-qualified domain name 4818334SJose.Borrego@Sun.COM * 4828334SJose.Borrego@Sun.COM */ 4838334SJose.Borrego@Sun.COM static uint32_t 4848334SJose.Borrego@Sun.COM smb_domain_query(char *domain, char *server, smb_domain_t *dp) 4858334SJose.Borrego@Sun.COM { 4868334SJose.Borrego@Sun.COM uint32_t rc; 4878334SJose.Borrego@Sun.COM lsa_info_t info; 4888334SJose.Borrego@Sun.COM 4898334SJose.Borrego@Sun.COM rc = lsa_query_dns_domain_info(server, domain, &info); 4908334SJose.Borrego@Sun.COM if (rc == NT_STATUS_SUCCESS) { 4918334SJose.Borrego@Sun.COM lsa_dns_domaininfo_t *dnsinfo = &info.i_domain.di_dns; 4928334SJose.Borrego@Sun.COM (void) strlcpy(dp->d_nbdomain, dnsinfo->d_nbdomain, 4938334SJose.Borrego@Sun.COM sizeof (dp->d_nbdomain)); 4948334SJose.Borrego@Sun.COM (void) strlcpy(dp->d_fqdomain, dnsinfo->d_fqdomain, 4958334SJose.Borrego@Sun.COM sizeof (dp->d_fqdomain)); 4968334SJose.Borrego@Sun.COM (void) strlcpy(dp->d_forest, dnsinfo->d_forest, 4978334SJose.Borrego@Sun.COM sizeof (dp->d_forest)); 4988334SJose.Borrego@Sun.COM ndr_uuid_unparse((ndr_uuid_t *)&dnsinfo->d_guid, dp->d_guid); 4998334SJose.Borrego@Sun.COM smb_sid_free(dnsinfo->d_sid); 5008334SJose.Borrego@Sun.COM } 5018334SJose.Borrego@Sun.COM 5028334SJose.Borrego@Sun.COM smb_domain_populate_table(domain, server); 5038334SJose.Borrego@Sun.COM return (rc); 5048334SJose.Borrego@Sun.COM } 5058334SJose.Borrego@Sun.COM 5068334SJose.Borrego@Sun.COM /* 5078334SJose.Borrego@Sun.COM * smb_domain_populate_table 5088334SJose.Borrego@Sun.COM * 5098334SJose.Borrego@Sun.COM * Populates the domain tablele with primary, account and trusted 5108334SJose.Borrego@Sun.COM * domain info. 5118334SJose.Borrego@Sun.COM * domain - either NetBIOS or fully-qualified domain name. 5128334SJose.Borrego@Sun.COM */ 5138334SJose.Borrego@Sun.COM static void 5148334SJose.Borrego@Sun.COM smb_domain_populate_table(char *domain, char *server) 5158334SJose.Borrego@Sun.COM { 5168334SJose.Borrego@Sun.COM lsa_info_t info; 5178334SJose.Borrego@Sun.COM lsa_nt_domaininfo_t *nt_info; 5188334SJose.Borrego@Sun.COM int i; 5198334SJose.Borrego@Sun.COM 5208334SJose.Borrego@Sun.COM if (lsa_query_primary_domain_info(server, domain, &info) 5218334SJose.Borrego@Sun.COM == NT_STATUS_SUCCESS) { 5228334SJose.Borrego@Sun.COM nt_info = &info.i_domain.di_primary; 5238334SJose.Borrego@Sun.COM smb_domain_update_tabent(NT_DOMAIN_PRIMARY, nt_info); 5248334SJose.Borrego@Sun.COM lsa_free_info(&info); 5258334SJose.Borrego@Sun.COM } 5268334SJose.Borrego@Sun.COM 5278334SJose.Borrego@Sun.COM if (lsa_query_account_domain_info(server, domain, &info) 5288334SJose.Borrego@Sun.COM == NT_STATUS_SUCCESS) { 5298334SJose.Borrego@Sun.COM nt_info = &info.i_domain.di_account; 5308334SJose.Borrego@Sun.COM smb_domain_update_tabent(NT_DOMAIN_ACCOUNT, nt_info); 5318334SJose.Borrego@Sun.COM lsa_free_info(&info); 5328334SJose.Borrego@Sun.COM } 5338334SJose.Borrego@Sun.COM 5348334SJose.Borrego@Sun.COM if (lsa_enum_trusted_domains(server, domain, &info) 5358334SJose.Borrego@Sun.COM == NT_STATUS_SUCCESS) { 5368334SJose.Borrego@Sun.COM lsa_trusted_domainlist_t *list = &info.i_domain.di_trust; 5378334SJose.Borrego@Sun.COM for (i = 0; i < list->t_num; i++) { 5388334SJose.Borrego@Sun.COM nt_info = &list->t_domains[i]; 5398334SJose.Borrego@Sun.COM smb_domain_update_tabent(NT_DOMAIN_TRUSTED, nt_info); 5408334SJose.Borrego@Sun.COM } 5418334SJose.Borrego@Sun.COM 5428334SJose.Borrego@Sun.COM lsa_free_info(&info); 5438334SJose.Borrego@Sun.COM } 5448334SJose.Borrego@Sun.COM 545*8474SJose.Borrego@Sun.COM nt_domain_save(); 5468334SJose.Borrego@Sun.COM } 5478334SJose.Borrego@Sun.COM 5488334SJose.Borrego@Sun.COM static void 5498334SJose.Borrego@Sun.COM smb_domain_update_tabent(int domain_type, lsa_nt_domaininfo_t *info) 5508334SJose.Borrego@Sun.COM { 5518334SJose.Borrego@Sun.COM nt_domain_t *entry; 5528334SJose.Borrego@Sun.COM nt_domain_flush(domain_type); 5538334SJose.Borrego@Sun.COM entry = nt_domain_new(domain_type, info->n_domain, info->n_sid); 5548334SJose.Borrego@Sun.COM (void) nt_domain_add(entry); 5558334SJose.Borrego@Sun.COM } 5568334SJose.Borrego@Sun.COM 5578334SJose.Borrego@Sun.COM /* 5588334SJose.Borrego@Sun.COM * smb_domain_use_config 5598334SJose.Borrego@Sun.COM * 5608334SJose.Borrego@Sun.COM * If the domain to be discovered matches the current domain (i.e the 5618334SJose.Borrego@Sun.COM * value of either domain or fqdn configuration), the output parameter 5628334SJose.Borrego@Sun.COM * 'dinfo' will be set to the information stored in SMF. 5638334SJose.Borrego@Sun.COM */ 5648334SJose.Borrego@Sun.COM static boolean_t 5658334SJose.Borrego@Sun.COM smb_domain_use_config(char *domain, smb_domain_t *dinfo) 5668334SJose.Borrego@Sun.COM { 5678334SJose.Borrego@Sun.COM smb_domain_t orig; 5688334SJose.Borrego@Sun.COM boolean_t use; 5698334SJose.Borrego@Sun.COM 5708334SJose.Borrego@Sun.COM if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN) 5718334SJose.Borrego@Sun.COM return (B_FALSE); 5728334SJose.Borrego@Sun.COM 5738334SJose.Borrego@Sun.COM smb_config_getdomaininfo(orig.d_nbdomain, orig.d_fqdomain, 5748334SJose.Borrego@Sun.COM orig.d_forest, orig.d_guid); 5758334SJose.Borrego@Sun.COM 5768334SJose.Borrego@Sun.COM if (SMB_IS_FQDN(domain)) { 5778334SJose.Borrego@Sun.COM use = (utf8_strcasecmp(orig.d_fqdomain, domain) == 0); 5788334SJose.Borrego@Sun.COM } else { 5798334SJose.Borrego@Sun.COM use = (utf8_strcasecmp(orig.d_nbdomain, domain) == 0); 5808334SJose.Borrego@Sun.COM } 5818334SJose.Borrego@Sun.COM 5828334SJose.Borrego@Sun.COM if (use) { 5838334SJose.Borrego@Sun.COM (void) strlcpy(dinfo->d_nbdomain, orig.d_nbdomain, 5848334SJose.Borrego@Sun.COM sizeof (dinfo->d_nbdomain)); 5858334SJose.Borrego@Sun.COM (void) strlcpy(dinfo->d_fqdomain, orig.d_fqdomain, 5868334SJose.Borrego@Sun.COM sizeof (dinfo->d_fqdomain)); 5878334SJose.Borrego@Sun.COM (void) strlcpy(dinfo->d_forest, orig.d_forest, 5888334SJose.Borrego@Sun.COM sizeof (dinfo->d_forest)); 5898334SJose.Borrego@Sun.COM (void) bcopy(orig.d_guid, dinfo->d_guid, 5908334SJose.Borrego@Sun.COM sizeof (dinfo->d_guid)); 5918334SJose.Borrego@Sun.COM } 5928334SJose.Borrego@Sun.COM 5938334SJose.Borrego@Sun.COM return (use); 5948334SJose.Borrego@Sun.COM } 595