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  */
21da6c28aaSamw /*
2289dc44ceSjose borrego  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23da6c28aaSamw  * Use is subject to license terms.
24380acbbeSGordon Ross  *
25975041ddSGordon Ross  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
26b78b1474SGordon Ross  * Copyright 2022 RackTop Systems, Inc.
27da6c28aaSamw  */
28da6c28aaSamw 
29da6c28aaSamw /*
3029bd2886SAlan Wright  * This file defines the domain environment values and the domain
31da6c28aaSamw  * database interface. The database is a single linked list of
32da6c28aaSamw  * structures containing domain type, name and SID information.
33da6c28aaSamw  */
34da6c28aaSamw 
3589dc44ceSjose borrego #include <sys/types.h>
3689dc44ceSjose borrego #include <sys/stat.h>
3729bd2886SAlan Wright #include <sys/list.h>
3889dc44ceSjose borrego #include <stdio.h>
39da6c28aaSamw #include <strings.h>
4089dc44ceSjose borrego #include <string.h>
41975041ddSGordon Ross #include <syslog.h>
42da6c28aaSamw #include <unistd.h>
4389dc44ceSjose borrego #include <stdlib.h>
44da6c28aaSamw #include <synch.h>
4589dc44ceSjose borrego #include <pwd.h>
4689dc44ceSjose borrego #include <grp.h>
4729bd2886SAlan Wright #include <assert.h>
48da6c28aaSamw 
49da6c28aaSamw #include <smbsrv/smbinfo.h>
50da6c28aaSamw #include <smbsrv/string.h>
516537f381Sas #include <smbsrv/smb_sid.h>
52da6c28aaSamw #include <smbsrv/libsmb.h>
53da6c28aaSamw 
5489dc44ceSjose borrego #define	SMB_DOMAINS_FILE	"domains"
55da6c28aaSamw 
5629bd2886SAlan Wright #define	SMB_DCACHE_UPDATE_WAIT	45	/* seconds */
57da6c28aaSamw 
58da6c28aaSamw /*
5929bd2886SAlan Wright  * Domain cache states
60da6c28aaSamw  */
6129bd2886SAlan Wright #define	SMB_DCACHE_STATE_NONE		0
6229bd2886SAlan Wright #define	SMB_DCACHE_STATE_READY		1
6329bd2886SAlan Wright #define	SMB_DCACHE_STATE_UPDATING	2
6429bd2886SAlan Wright #define	SMB_DCACHE_STATE_DESTROYING	3
65da6c28aaSamw 
66da6c28aaSamw /*
6729bd2886SAlan Wright  * Cache lock modes
68da6c28aaSamw  */
6929bd2886SAlan Wright #define	SMB_DCACHE_RDLOCK	0
7029bd2886SAlan Wright #define	SMB_DCACHE_WRLOCK	1
7129bd2886SAlan Wright 
7229bd2886SAlan Wright typedef struct smb_domain_cache {
7329bd2886SAlan Wright 	list_t		dc_cache;
7429bd2886SAlan Wright 	rwlock_t	dc_cache_lck;
7529bd2886SAlan Wright 	uint32_t	dc_state;
7629bd2886SAlan Wright 	uint32_t	dc_nops;
77975041ddSGordon Ross 	mutex_t		dc_mtx;
78975041ddSGordon Ross 	cond_t		dc_cv;
79975041ddSGordon Ross 	/* domain controller information */
80975041ddSGordon Ross 	cond_t		dc_dci_cv;
81975041ddSGordon Ross 	boolean_t	dc_dci_valid;
82b3700b07SGordon Ross 	smb_dcinfo_t	dc_dci;
8329bd2886SAlan Wright } smb_domain_cache_t;
8429bd2886SAlan Wright 
8529bd2886SAlan Wright static smb_domain_cache_t smb_dcache;
8629bd2886SAlan Wright 
87a0aa776eSAlan Wright static uint32_t smb_domain_add(smb_domain_type_t, smb_domain_t *);
88a0aa776eSAlan Wright static uint32_t smb_domain_add_local(void);
89a0aa776eSAlan Wright static uint32_t smb_domain_add_primary(uint32_t);
90a0aa776eSAlan Wright static void smb_domain_unlink(void);
9129bd2886SAlan Wright 
9229bd2886SAlan Wright static void smb_dcache_create(void);
9329bd2886SAlan Wright static void smb_dcache_destroy(void);
9429bd2886SAlan Wright static uint32_t smb_dcache_lock(int);
9529bd2886SAlan Wright static void smb_dcache_unlock(void);
96a0aa776eSAlan Wright static void smb_dcache_remove(smb_domain_t *);
97a0aa776eSAlan Wright static uint32_t smb_dcache_add(smb_domain_t *);
98975041ddSGordon Ross static boolean_t smb_dcache_getdc(smb_dcinfo_t *, boolean_t);
99b3700b07SGordon Ross static void smb_dcache_setdc(const smb_dcinfo_t *);
10029bd2886SAlan Wright static boolean_t smb_dcache_wait(void);
101a0aa776eSAlan Wright static uint32_t smb_dcache_updating(void);
10229bd2886SAlan Wright static void smb_dcache_ready(void);
103da6c28aaSamw 
104da6c28aaSamw /*
10529bd2886SAlan Wright  * domain cache one time initialization. This function should
10629bd2886SAlan Wright  * only be called during service startup.
107da6c28aaSamw  *
10829bd2886SAlan Wright  * Returns 0 on success and an error code on failure.
109da6c28aaSamw  */
11029bd2886SAlan Wright int
smb_domain_init(uint32_t secmode)111a0aa776eSAlan Wright smb_domain_init(uint32_t secmode)
112da6c28aaSamw {
113a0aa776eSAlan Wright 	smb_domain_t di;
11429bd2886SAlan Wright 	int rc;
115da6c28aaSamw 
11629bd2886SAlan Wright 	smb_dcache_create();
117da6c28aaSamw 
118a0aa776eSAlan Wright 	if ((rc = smb_domain_add_local()) != 0)
11929bd2886SAlan Wright 		return (rc);
120da6c28aaSamw 
121975041ddSGordon Ross 	bzero(&di, sizeof (di));
122a0aa776eSAlan Wright 	smb_domain_set_basic_info(NT_BUILTIN_DOMAIN_SIDSTR, "BUILTIN", "", &di);
123a0aa776eSAlan Wright 	(void) smb_domain_add(SMB_DOMAIN_BUILTIN, &di);
124da6c28aaSamw 
125a0aa776eSAlan Wright 	return (smb_domain_add_primary(secmode));
126da6c28aaSamw }
127da6c28aaSamw 
128da6c28aaSamw /*
12929bd2886SAlan Wright  * Destroys the cache upon service termination
130da6c28aaSamw  */
131da6c28aaSamw void
smb_domain_fini(void)132a0aa776eSAlan Wright smb_domain_fini(void)
133da6c28aaSamw {
13429bd2886SAlan Wright 	smb_dcache_destroy();
135a0aa776eSAlan Wright 	smb_domain_unlink();
136da6c28aaSamw }
137da6c28aaSamw 
138da6c28aaSamw /*
13929bd2886SAlan Wright  * Add a domain structure to domain cache. There is no checking
14029bd2886SAlan Wright  * for duplicates.
141da6c28aaSamw  */
14229bd2886SAlan Wright static uint32_t
smb_domain_add(smb_domain_type_t type,smb_domain_t * di)143a0aa776eSAlan Wright smb_domain_add(smb_domain_type_t type, smb_domain_t *di)
144da6c28aaSamw {
14529bd2886SAlan Wright 	uint32_t res;
146da6c28aaSamw 
147fb2301dbSToomas Soome 	if (di == NULL || di->di_sid[0] == '\0')
14829bd2886SAlan Wright 		return (SMB_DOMAIN_INVALID_ARG);
149da6c28aaSamw 
15029bd2886SAlan Wright 	if ((res = smb_dcache_lock(SMB_DCACHE_WRLOCK)) == SMB_DOMAIN_SUCCESS) {
15129bd2886SAlan Wright 		di->di_type = type;
15229bd2886SAlan Wright 		res = smb_dcache_add(di);
15329bd2886SAlan Wright 		smb_dcache_unlock();
154da6c28aaSamw 	}
155da6c28aaSamw 
15629bd2886SAlan Wright 	return (res);
157da6c28aaSamw }
158da6c28aaSamw 
159da6c28aaSamw /*
16029bd2886SAlan Wright  * Lookup a domain by its name. The passed name is the NETBIOS or fully
16129bd2886SAlan Wright  * qualified DNS name or non-qualified DNS name.
16229bd2886SAlan Wright  *
16329bd2886SAlan Wright  * If the requested domain is found and given 'di' pointer is not NULL
16429bd2886SAlan Wright  * it'll be filled with the domain information and B_TRUE is returned.
16529bd2886SAlan Wright  * If the caller only needs to check a domain existence it can pass
16629bd2886SAlan Wright  * NULL for 'di' and just check the return value.
167da6c28aaSamw  *
16829bd2886SAlan Wright  * If the domain is not in the cache B_FALSE is returned.
169da6c28aaSamw  */
17029bd2886SAlan Wright boolean_t
smb_domain_lookup_name(char * name,smb_domain_t * di)171a0aa776eSAlan Wright smb_domain_lookup_name(char *name, smb_domain_t *di)
172da6c28aaSamw {
17329bd2886SAlan Wright 	boolean_t found = B_FALSE;
174a0aa776eSAlan Wright 	smb_domain_t *dcnode;
17529bd2886SAlan Wright 	char *p;
176da6c28aaSamw 
177a0aa776eSAlan Wright 	bzero(di, sizeof (smb_domain_t));
178da6c28aaSamw 
17929bd2886SAlan Wright 	if (name == NULL || *name == '\0')
18029bd2886SAlan Wright 		return (B_FALSE);
181da6c28aaSamw 
18229bd2886SAlan Wright 	if (smb_dcache_lock(SMB_DCACHE_RDLOCK) != SMB_DOMAIN_SUCCESS)
18329bd2886SAlan Wright 		return (B_FALSE);
184da6c28aaSamw 
18529bd2886SAlan Wright 	dcnode = list_head(&smb_dcache.dc_cache);
18629bd2886SAlan Wright 	while (dcnode) {
187bbf6f00cSJordan Brown 		found = (smb_strcasecmp(dcnode->di_nbname, name, 0) == 0) ||
188bbf6f00cSJordan Brown 		    (smb_strcasecmp(dcnode->di_fqname, name, 0) == 0);
189da6c28aaSamw 
19029bd2886SAlan Wright 		if (found) {
19129bd2886SAlan Wright 			if (di)
19229bd2886SAlan Wright 				*di = *dcnode;
19329bd2886SAlan Wright 			break;
19429bd2886SAlan Wright 		}
195da6c28aaSamw 
19629bd2886SAlan Wright 		if ((p = strchr(dcnode->di_fqname, '.')) != NULL) {
19729bd2886SAlan Wright 			*p = '\0';
198bbf6f00cSJordan Brown 			found = (smb_strcasecmp(dcnode->di_fqname, name,
199bbf6f00cSJordan Brown 			    0) == 0);
20029bd2886SAlan Wright 			*p = '.';
20129bd2886SAlan Wright 			if (found) {
20229bd2886SAlan Wright 				if (di)
20329bd2886SAlan Wright 					*di = *dcnode;
20429bd2886SAlan Wright 				break;
20529bd2886SAlan Wright 			}
20629bd2886SAlan Wright 		}
207da6c28aaSamw 
20829bd2886SAlan Wright 		dcnode = list_next(&smb_dcache.dc_cache, dcnode);
20929bd2886SAlan Wright 	}
210da6c28aaSamw 
21129bd2886SAlan Wright 	smb_dcache_unlock();
21229bd2886SAlan Wright 	return (found);
213da6c28aaSamw }
214da6c28aaSamw 
215da6c28aaSamw /*
21629bd2886SAlan Wright  * Lookup a domain by its SID.
21729bd2886SAlan Wright  *
21829bd2886SAlan Wright  * If the requested domain is found and given 'di' pointer is not NULL
21929bd2886SAlan Wright  * it'll be filled with the domain information and B_TRUE is returned.
22029bd2886SAlan Wright  * If the caller only needs to check a domain existence it can pass
22129bd2886SAlan Wright  * NULL for 'di' and just check the return value.
222da6c28aaSamw  *
22329bd2886SAlan Wright  * If the domain is not in the cache B_FALSE is returned.
224da6c28aaSamw  */
22529bd2886SAlan Wright boolean_t
smb_domain_lookup_sid(smb_sid_t * sid,smb_domain_t * di)226a0aa776eSAlan Wright smb_domain_lookup_sid(smb_sid_t *sid, smb_domain_t *di)
227da6c28aaSamw {
22829bd2886SAlan Wright 	boolean_t found = B_FALSE;
229a0aa776eSAlan Wright 	smb_domain_t *dcnode;
23029bd2886SAlan Wright 	char sidstr[SMB_SID_STRSZ];
2317f667e74Sjose borrego 
232a0aa776eSAlan Wright 	bzero(di, sizeof (smb_domain_t));
2337f667e74Sjose borrego 
23429bd2886SAlan Wright 	if (sid == NULL)
23529bd2886SAlan Wright 		return (B_FALSE);
236da6c28aaSamw 
23729bd2886SAlan Wright 	smb_sid_tostr(sid, sidstr);
23829bd2886SAlan Wright 
23929bd2886SAlan Wright 	if (smb_dcache_lock(SMB_DCACHE_RDLOCK) != SMB_DOMAIN_SUCCESS)
24029bd2886SAlan Wright 		return (B_FALSE);
24129bd2886SAlan Wright 
24229bd2886SAlan Wright 	dcnode = list_head(&smb_dcache.dc_cache);
24329bd2886SAlan Wright 	while (dcnode) {
24429bd2886SAlan Wright 		found = (strcmp(dcnode->di_sid, sidstr) == 0);
24529bd2886SAlan Wright 		if (found) {
24629bd2886SAlan Wright 			if (di)
24729bd2886SAlan Wright 				*di = *dcnode;
248da6c28aaSamw 			break;
24929bd2886SAlan Wright 		}
250da6c28aaSamw 
25129bd2886SAlan Wright 		dcnode = list_next(&smb_dcache.dc_cache, dcnode);
252da6c28aaSamw 	}
253da6c28aaSamw 
25429bd2886SAlan Wright 	smb_dcache_unlock();
25529bd2886SAlan Wright 	return (found);
256da6c28aaSamw }
257da6c28aaSamw 
258da6c28aaSamw /*
25929bd2886SAlan Wright  * Lookup a domain by its type.
260da6c28aaSamw  *
26129bd2886SAlan Wright  * If the requested domain is found and given 'di' pointer is not NULL
26229bd2886SAlan Wright  * it'll be filled with the domain information and B_TRUE is returned.
26329bd2886SAlan Wright  * If the caller only needs to check a domain existence it can pass
26429bd2886SAlan Wright  * NULL for 'di' and just check the return value.
26529bd2886SAlan Wright  *
26629bd2886SAlan Wright  * If the domain is not in the cache B_FALSE is returned.
267da6c28aaSamw  */
26829bd2886SAlan Wright boolean_t
smb_domain_lookup_type(smb_domain_type_t type,smb_domain_t * di)269a0aa776eSAlan Wright smb_domain_lookup_type(smb_domain_type_t type, smb_domain_t *di)
270da6c28aaSamw {
27129bd2886SAlan Wright 	boolean_t found = B_FALSE;
272a0aa776eSAlan Wright 	smb_domain_t *dcnode;
273da6c28aaSamw 
274a0aa776eSAlan Wright 	bzero(di, sizeof (smb_domain_t));
27529bd2886SAlan Wright 
27629bd2886SAlan Wright 	if (smb_dcache_lock(SMB_DCACHE_RDLOCK) != SMB_DOMAIN_SUCCESS)
27729bd2886SAlan Wright 		return (B_FALSE);
27829bd2886SAlan Wright 
27929bd2886SAlan Wright 	dcnode = list_head(&smb_dcache.dc_cache);
28029bd2886SAlan Wright 	while (dcnode) {
28129bd2886SAlan Wright 		if (dcnode->di_type == type) {
28229bd2886SAlan Wright 			found = B_TRUE;
28329bd2886SAlan Wright 			if (di)
28429bd2886SAlan Wright 				*di = *dcnode;
285da6c28aaSamw 			break;
28629bd2886SAlan Wright 		}
287da6c28aaSamw 
28829bd2886SAlan Wright 		dcnode = list_next(&smb_dcache.dc_cache, dcnode);
289da6c28aaSamw 	}
290da6c28aaSamw 
29129bd2886SAlan Wright 	smb_dcache_unlock();
29229bd2886SAlan Wright 	return (found);
293da6c28aaSamw }
294da6c28aaSamw 
295da6c28aaSamw /*
29629bd2886SAlan Wright  * Returns primary domain information plus the name of
29729bd2886SAlan Wright  * the selected domain controller.
298975041ddSGordon Ross  *
299975041ddSGordon Ross  * Returns TRUE on success.
300da6c28aaSamw  */
30129bd2886SAlan Wright boolean_t
smb_domain_getinfo(smb_domainex_t * dxi)302a0aa776eSAlan Wright smb_domain_getinfo(smb_domainex_t *dxi)
303da6c28aaSamw {
304b3700b07SGordon Ross 	boolean_t rv;
305da6c28aaSamw 
306b3700b07SGordon Ross 	/* Note: this waits for the dcache lock. */
307b3700b07SGordon Ross 	rv = smb_domain_lookup_type(SMB_DOMAIN_PRIMARY, &dxi->d_primary);
308975041ddSGordon Ross 	if (!rv) {
309975041ddSGordon Ross 		syslog(LOG_ERR, "smb_domain_getinfo: no primary domain");
310975041ddSGordon Ross 		return (B_FALSE);
311975041ddSGordon Ross 	}
312da6c28aaSamw 
313975041ddSGordon Ross 	/*
314975041ddSGordon Ross 	 * The 2nd arg TRUE means this will wait for DC info.
315975041ddSGordon Ross 	 *
316975041ddSGordon Ross 	 * Note that we do NOT hold the dcache rwlock here
317975041ddSGordon Ross 	 * (not even as reader) because we already have what we
318975041ddSGordon Ross 	 * need from the dcache (our primary domain) and we don't
319975041ddSGordon Ross 	 * want to interfere with the DC locator which will take
320975041ddSGordon Ross 	 * the dcache lock as writer to update the domain info.
321975041ddSGordon Ross 	 */
322975041ddSGordon Ross 	rv = smb_dcache_getdc(&dxi->d_dci, B_TRUE);
323975041ddSGordon Ross 	if (!rv) {
324975041ddSGordon Ross 		syslog(LOG_ERR, "smb_domain_getinfo: no DC info");
325975041ddSGordon Ross 		return (B_FALSE);
326975041ddSGordon Ross 	}
327975041ddSGordon Ross 
328975041ddSGordon Ross 	return (B_TRUE);
32929bd2886SAlan Wright }
330da6c28aaSamw 
331380acbbeSGordon Ross /*
332380acbbeSGordon Ross  * Get the name of the current DC (if any)
333380acbbeSGordon Ross  * Does NOT block.
334380acbbeSGordon Ross  */
335380acbbeSGordon Ross void
smb_domain_current_dc(smb_dcinfo_t * dci)336b3700b07SGordon Ross smb_domain_current_dc(smb_dcinfo_t *dci)
337380acbbeSGordon Ross {
338975041ddSGordon Ross 	(void) smb_dcache_getdc(dci, B_FALSE);
339380acbbeSGordon Ross }
340380acbbeSGordon Ross 
34129bd2886SAlan Wright /*
34229bd2886SAlan Wright  * Transfer the cache to updating state.
34329bd2886SAlan Wright  * In this state any request for reading the cache would
34429bd2886SAlan Wright  * be blocked until the update is finished.
34529bd2886SAlan Wright  */
346a0aa776eSAlan Wright uint32_t
smb_domain_start_update(void)347a0aa776eSAlan Wright smb_domain_start_update(void)
34829bd2886SAlan Wright {
349a0aa776eSAlan Wright 	return (smb_dcache_updating());
350da6c28aaSamw }
351da6c28aaSamw 
35229bd2886SAlan Wright /*
35329bd2886SAlan Wright  * Transfer the cache from updating to ready state.
35429bd2886SAlan Wright  */
35529bd2886SAlan Wright void
smb_domain_end_update(void)356a0aa776eSAlan Wright smb_domain_end_update(void)
35729bd2886SAlan Wright {
35829bd2886SAlan Wright 	smb_dcache_ready();
35929bd2886SAlan Wright }
360da6c28aaSamw 
361975041ddSGordon Ross /*
362975041ddSGordon Ross  * Mark the current domain controller (DC) info invalid
363975041ddSGordon Ross  * until the DC locator calls smb_domain_update().
364975041ddSGordon Ross  */
365975041ddSGordon Ross void
smb_domain_bad_dc(void)366975041ddSGordon Ross smb_domain_bad_dc(void)
367975041ddSGordon Ross {
368975041ddSGordon Ross 	(void) mutex_lock(&smb_dcache.dc_mtx);
369975041ddSGordon Ross 	smb_dcache.dc_dci_valid = B_FALSE;
370975041ddSGordon Ross 	(void) mutex_unlock(&smb_dcache.dc_mtx);
371975041ddSGordon Ross }
372975041ddSGordon Ross 
373da6c28aaSamw /*
37429bd2886SAlan Wright  * Updates the cache with given information for the primary
37529bd2886SAlan Wright  * domain, possible trusted domains and the selected domain
37629bd2886SAlan Wright  * controller.
377da6c28aaSamw  *
37829bd2886SAlan Wright  * Before adding the new entries existing entries of type
37929bd2886SAlan Wright  * primary and trusted will be removed from cache.
380da6c28aaSamw  */
38129bd2886SAlan Wright void
smb_domain_update(smb_domainex_t * dxi)382a0aa776eSAlan Wright smb_domain_update(smb_domainex_t *dxi)
383da6c28aaSamw {
384a0aa776eSAlan Wright 	smb_domain_t *dcnode;
38529bd2886SAlan Wright 	int i;
386da6c28aaSamw 
38729bd2886SAlan Wright 	if (smb_dcache_lock(SMB_DCACHE_WRLOCK) != SMB_DOMAIN_SUCCESS)
38829bd2886SAlan Wright 		return;
389da6c28aaSamw 
39029bd2886SAlan Wright 	dcnode = list_head(&smb_dcache.dc_cache);
39129bd2886SAlan Wright 	while (dcnode) {
392a0aa776eSAlan Wright 		if ((dcnode->di_type == SMB_DOMAIN_PRIMARY) ||
393a0aa776eSAlan Wright 		    (dcnode->di_type == SMB_DOMAIN_TRUSTED)) {
39429bd2886SAlan Wright 			smb_dcache_remove(dcnode);
39529bd2886SAlan Wright 			dcnode = list_head(&smb_dcache.dc_cache);
39629bd2886SAlan Wright 		} else {
39729bd2886SAlan Wright 			dcnode = list_next(&smb_dcache.dc_cache, dcnode);
39829bd2886SAlan Wright 		}
399da6c28aaSamw 	}
400da6c28aaSamw 
401b78b1474SGordon Ross 	dxi->d_primary.di_type = SMB_DOMAIN_PRIMARY;
402a0aa776eSAlan Wright 	if (smb_dcache_add(&dxi->d_primary) == SMB_DOMAIN_SUCCESS) {
403b78b1474SGordon Ross 		for (i = 0, dcnode = dxi->d_trusted.td_domains;
404b78b1474SGordon Ross 		    i < dxi->d_trusted.td_num;
405b78b1474SGordon Ross 		    i++, dcnode++) {
406b78b1474SGordon Ross 			dcnode->di_type = SMB_DOMAIN_TRUSTED;
407b78b1474SGordon Ross 			(void) smb_dcache_add(dcnode);
408b78b1474SGordon Ross 		}
409b3700b07SGordon Ross 		smb_dcache_setdc(&dxi->d_dci);
410da6c28aaSamw 	}
41129bd2886SAlan Wright 
41229bd2886SAlan Wright 	smb_dcache_unlock();
413da6c28aaSamw }
41489dc44ceSjose borrego 
41589dc44ceSjose borrego /*
41689dc44ceSjose borrego  * Write the list of domains to /var/run/smb/domains.
41789dc44ceSjose borrego  */
41889dc44ceSjose borrego void
smb_domain_save(void)419a0aa776eSAlan Wright smb_domain_save(void)
42089dc44ceSjose borrego {
42189dc44ceSjose borrego 	char		fname[MAXPATHLEN];
42289dc44ceSjose borrego 	char		tag;
423a0aa776eSAlan Wright 	smb_domain_t	*domain;
42489dc44ceSjose borrego 	FILE		*fp;
42589dc44ceSjose borrego 	struct passwd	*pwd;
42689dc44ceSjose borrego 	struct group	*grp;
42789dc44ceSjose borrego 	uid_t		uid;
42889dc44ceSjose borrego 	gid_t		gid;
42989dc44ceSjose borrego 
43089dc44ceSjose borrego 	(void) snprintf(fname, MAXPATHLEN, "%s/%s",
43189dc44ceSjose borrego 	    SMB_VARRUN_DIR, SMB_DOMAINS_FILE);
43289dc44ceSjose borrego 
43389dc44ceSjose borrego 	if ((fp = fopen(fname, "w")) == NULL)
43489dc44ceSjose borrego 		return;
43589dc44ceSjose borrego 
43689dc44ceSjose borrego 	pwd = getpwnam("root");
43789dc44ceSjose borrego 	grp = getgrnam("sys");
43889dc44ceSjose borrego 	uid = (pwd == NULL) ? 0 : pwd->pw_uid;
43989dc44ceSjose borrego 	gid = (grp == NULL) ? 3 : grp->gr_gid;
44089dc44ceSjose borrego 
44189dc44ceSjose borrego 	(void) lockf(fileno(fp), F_LOCK, 0);
44289dc44ceSjose borrego 	(void) fchmod(fileno(fp), 0600);
44389dc44ceSjose borrego 	(void) fchown(fileno(fp), uid, gid);
44489dc44ceSjose borrego 
44529bd2886SAlan Wright 	if (smb_dcache_lock(SMB_DCACHE_RDLOCK) != SMB_DOMAIN_SUCCESS)
44629bd2886SAlan Wright 		return;
44789dc44ceSjose borrego 
44829bd2886SAlan Wright 	domain = list_head(&smb_dcache.dc_cache);
44989dc44ceSjose borrego 	while (domain) {
45029bd2886SAlan Wright 		switch (domain->di_type) {
451a0aa776eSAlan Wright 		case SMB_DOMAIN_PRIMARY:
45289dc44ceSjose borrego 			tag = '*';
45389dc44ceSjose borrego 			break;
45489dc44ceSjose borrego 
455a0aa776eSAlan Wright 		case SMB_DOMAIN_TRUSTED:
456a0aa776eSAlan Wright 		case SMB_DOMAIN_UNTRUSTED:
45789dc44ceSjose borrego 			tag = '-';
45889dc44ceSjose borrego 			break;
45989dc44ceSjose borrego 
460a0aa776eSAlan Wright 		case SMB_DOMAIN_LOCAL:
46189dc44ceSjose borrego 			tag = '.';
46289dc44ceSjose borrego 			break;
46389dc44ceSjose borrego 		default:
46429bd2886SAlan Wright 			domain = list_next(&smb_dcache.dc_cache, domain);
46589dc44ceSjose borrego 			continue;
46689dc44ceSjose borrego 		}
46789dc44ceSjose borrego 
46889dc44ceSjose borrego 		(void) fprintf(fp, "[%c] [%s] [%s]\n",
46929bd2886SAlan Wright 		    tag, domain->di_nbname, domain->di_sid);
47089dc44ceSjose borrego 
47129bd2886SAlan Wright 		domain = list_next(&smb_dcache.dc_cache, domain);
47289dc44ceSjose borrego 	}
47389dc44ceSjose borrego 
47429bd2886SAlan Wright 	smb_dcache_unlock();
47589dc44ceSjose borrego 	(void) lockf(fileno(fp), F_ULOCK, 0);
47689dc44ceSjose borrego 	(void) fclose(fp);
47789dc44ceSjose borrego }
47889dc44ceSjose borrego 
47989dc44ceSjose borrego /*
48089dc44ceSjose borrego  * List the domains in /var/run/smb/domains.
48189dc44ceSjose borrego  */
48289dc44ceSjose borrego void
smb_domain_show(void)483a0aa776eSAlan Wright smb_domain_show(void)
48489dc44ceSjose borrego {
48589dc44ceSjose borrego 	char buf[MAXPATHLEN];
48689dc44ceSjose borrego 	char *p;
48789dc44ceSjose borrego 	FILE *fp;
48889dc44ceSjose borrego 
48989dc44ceSjose borrego 	(void) snprintf(buf, MAXPATHLEN, "%s/%s",
49089dc44ceSjose borrego 	    SMB_VARRUN_DIR, SMB_DOMAINS_FILE);
49189dc44ceSjose borrego 
49289dc44ceSjose borrego 	if ((fp = fopen(buf, "r")) != NULL) {
49389dc44ceSjose borrego 		(void) lockf(fileno(fp), F_LOCK, 0);
49489dc44ceSjose borrego 
49589dc44ceSjose borrego 		while (fgets(buf, MAXPATHLEN, fp) != NULL) {
49689dc44ceSjose borrego 			if ((p = strchr(buf, '\n')) != NULL)
49789dc44ceSjose borrego 				*p = '\0';
49889dc44ceSjose borrego 			(void) printf("%s\n", buf);
49989dc44ceSjose borrego 		}
50089dc44ceSjose borrego 
50189dc44ceSjose borrego 		(void) lockf(fileno(fp), F_ULOCK, 0);
50289dc44ceSjose borrego 		(void) fclose(fp);
50389dc44ceSjose borrego 	}
50489dc44ceSjose borrego }
50589dc44ceSjose borrego 
50629bd2886SAlan Wright void
smb_domain_set_basic_info(char * sid,char * nb_domain,char * fq_domain,smb_domain_t * di)507a0aa776eSAlan Wright smb_domain_set_basic_info(char *sid, char *nb_domain, char *fq_domain,
508a0aa776eSAlan Wright     smb_domain_t *di)
50929bd2886SAlan Wright {
51029bd2886SAlan Wright 	if (sid == NULL || nb_domain == NULL || fq_domain == NULL ||
51129bd2886SAlan Wright 	    di == NULL)
51229bd2886SAlan Wright 		return;
51329bd2886SAlan Wright 
51429bd2886SAlan Wright 	(void) strlcpy(di->di_sid, sid, SMB_SID_STRSZ);
51529bd2886SAlan Wright 	(void) strlcpy(di->di_nbname, nb_domain, NETBIOS_NAME_SZ);
516bbf6f00cSJordan Brown 	(void) smb_strupr(di->di_nbname);
51729bd2886SAlan Wright 	(void) strlcpy(di->di_fqname, fq_domain, MAXHOSTNAMELEN);
51829bd2886SAlan Wright 	di->di_binsid = NULL;
51929bd2886SAlan Wright }
52029bd2886SAlan Wright 
52129bd2886SAlan Wright void
smb_domain_set_dns_info(char * sid,char * nb_domain,char * fq_domain,char * forest,char * guid,smb_domain_t * di)522a0aa776eSAlan Wright smb_domain_set_dns_info(char *sid, char *nb_domain, char *fq_domain,
523a0aa776eSAlan Wright     char *forest, char *guid, smb_domain_t *di)
52429bd2886SAlan Wright {
52529bd2886SAlan Wright 	if (di == NULL || forest == NULL || guid == NULL)
52629bd2886SAlan Wright 		return;
52729bd2886SAlan Wright 
528975041ddSGordon Ross 	/* Caller zeros out *di before this. */
529a0aa776eSAlan Wright 	smb_domain_set_basic_info(sid, nb_domain, fq_domain, di);
53029bd2886SAlan Wright 	(void) strlcpy(di->di_u.di_dns.ddi_forest, forest, MAXHOSTNAMELEN);
53129bd2886SAlan Wright 	(void) strlcpy(di->di_u.di_dns.ddi_guid, guid,
53229bd2886SAlan Wright 	    UUID_PRINTABLE_STRING_LENGTH);
53329bd2886SAlan Wright }
53429bd2886SAlan Wright 
53529bd2886SAlan Wright void
smb_domain_set_trust_info(char * sid,char * nb_domain,char * fq_domain,uint32_t trust_dir,uint32_t trust_type,uint32_t trust_attrs,smb_domain_t * di)536a0aa776eSAlan Wright smb_domain_set_trust_info(char *sid, char *nb_domain, char *fq_domain,
53729bd2886SAlan Wright     uint32_t trust_dir, uint32_t trust_type, uint32_t trust_attrs,
538a0aa776eSAlan Wright     smb_domain_t *di)
53929bd2886SAlan Wright {
54029bd2886SAlan Wright 	smb_domain_trust_t *ti;
54129bd2886SAlan Wright 
54229bd2886SAlan Wright 	if (di == NULL)
54329bd2886SAlan Wright 		return;
54429bd2886SAlan Wright 
545975041ddSGordon Ross 	/* Caller zeros out *di before this. */
546a0aa776eSAlan Wright 	di->di_type = SMB_DOMAIN_TRUSTED;
54729bd2886SAlan Wright 	ti = &di->di_u.di_trust;
548a0aa776eSAlan Wright 	smb_domain_set_basic_info(sid, nb_domain, fq_domain, di);
54929bd2886SAlan Wright 	ti->dti_trust_direction = trust_dir;
55029bd2886SAlan Wright 	ti->dti_trust_type = trust_type;
55129bd2886SAlan Wright 	ti->dti_trust_attrs = trust_attrs;
55229bd2886SAlan Wright }
55329bd2886SAlan Wright 
55489dc44ceSjose borrego /*
55589dc44ceSjose borrego  * Remove the /var/run/smb/domains file.
55689dc44ceSjose borrego  */
55729bd2886SAlan Wright static void
smb_domain_unlink(void)558a0aa776eSAlan Wright smb_domain_unlink(void)
55989dc44ceSjose borrego {
56089dc44ceSjose borrego 	char fname[MAXPATHLEN];
56189dc44ceSjose borrego 
56289dc44ceSjose borrego 	(void) snprintf(fname, MAXPATHLEN, "%s/%s",
56389dc44ceSjose borrego 	    SMB_VARRUN_DIR, SMB_DOMAINS_FILE);
56489dc44ceSjose borrego 	(void) unlink(fname);
56589dc44ceSjose borrego }
56629bd2886SAlan Wright 
56729bd2886SAlan Wright /*
56829bd2886SAlan Wright  * Add an entry for the local domain to the domain cache
56929bd2886SAlan Wright  */
57029bd2886SAlan Wright static uint32_t
smb_domain_add_local(void)571a0aa776eSAlan Wright smb_domain_add_local(void)
57229bd2886SAlan Wright {
57329bd2886SAlan Wright 	char *lsidstr;
57429bd2886SAlan Wright 	char hostname[NETBIOS_NAME_SZ];
57529bd2886SAlan Wright 	char fq_name[MAXHOSTNAMELEN];
576a0aa776eSAlan Wright 	smb_domain_t di;
57729bd2886SAlan Wright 
57829bd2886SAlan Wright 	if ((lsidstr = smb_config_get_localsid()) == NULL)
57929bd2886SAlan Wright 		return (SMB_DOMAIN_NOMACHINE_SID);
58029bd2886SAlan Wright 
58129bd2886SAlan Wright 	if (smb_getnetbiosname(hostname, NETBIOS_NAME_SZ) != 0) {
58229bd2886SAlan Wright 		free(lsidstr);
58329bd2886SAlan Wright 		return (SMB_DOMAIN_NOMACHINE_SID);
58429bd2886SAlan Wright 	}
58529bd2886SAlan Wright 
586975041ddSGordon Ross 	bzero(&di, sizeof (di));
58729bd2886SAlan Wright 	*fq_name = '\0';
58829bd2886SAlan Wright 	(void) smb_getfqhostname(fq_name, MAXHOSTNAMELEN);
589a0aa776eSAlan Wright 	smb_domain_set_basic_info(lsidstr, hostname, fq_name, &di);
590a0aa776eSAlan Wright 	(void) smb_domain_add(SMB_DOMAIN_LOCAL, &di);
59129bd2886SAlan Wright 
59229bd2886SAlan Wright 	free(lsidstr);
59329bd2886SAlan Wright 	return (SMB_DOMAIN_SUCCESS);
59429bd2886SAlan Wright }
59529bd2886SAlan Wright 
59629bd2886SAlan Wright /*
59729bd2886SAlan Wright  * Add an entry for the primary domain to the domain cache
59829bd2886SAlan Wright  */
59929bd2886SAlan Wright static uint32_t
smb_domain_add_primary(uint32_t secmode)600a0aa776eSAlan Wright smb_domain_add_primary(uint32_t secmode)
60129bd2886SAlan Wright {
60229bd2886SAlan Wright 	char sidstr[SMB_SID_STRSZ];
60329bd2886SAlan Wright 	char fq_name[MAXHOSTNAMELEN];
60429bd2886SAlan Wright 	char nb_name[NETBIOS_NAME_SZ];
605a0aa776eSAlan Wright 	smb_domain_t di;
60629bd2886SAlan Wright 	int rc;
60729bd2886SAlan Wright 
60829bd2886SAlan Wright 	if (secmode != SMB_SECMODE_DOMAIN)
60929bd2886SAlan Wright 		return (SMB_DOMAIN_SUCCESS);
61029bd2886SAlan Wright 
61129bd2886SAlan Wright 	rc = smb_config_getstr(SMB_CI_DOMAIN_SID, sidstr, sizeof (sidstr));
61229bd2886SAlan Wright 	if (rc != SMBD_SMF_OK)
61329bd2886SAlan Wright 		return (SMB_DOMAIN_NODOMAIN_SID);
61429bd2886SAlan Wright 
61529bd2886SAlan Wright 	rc = smb_config_getstr(SMB_CI_DOMAIN_NAME, nb_name, NETBIOS_NAME_SZ);
61629bd2886SAlan Wright 	if ((rc != SMBD_SMF_OK) || (*nb_name == '\0'))
61729bd2886SAlan Wright 		return (SMB_DOMAIN_NODOMAIN_NAME);
61829bd2886SAlan Wright 
619975041ddSGordon Ross 	bzero(&di, sizeof (di));
62029bd2886SAlan Wright 	(void) smb_getfqdomainname(fq_name, MAXHOSTNAMELEN);
621a0aa776eSAlan Wright 	smb_domain_set_basic_info(sidstr, nb_name, fq_name, &di);
622a0aa776eSAlan Wright 	(void) smb_domain_add(SMB_DOMAIN_PRIMARY, &di);
62329bd2886SAlan Wright 	return (SMB_DOMAIN_SUCCESS);
62429bd2886SAlan Wright }
62529bd2886SAlan Wright 
62629bd2886SAlan Wright /*
62729bd2886SAlan Wright  * Initialize the domain cache.
62829bd2886SAlan Wright  * This function does not populate the cache.
62929bd2886SAlan Wright  */
63029bd2886SAlan Wright static void
smb_dcache_create(void)63129bd2886SAlan Wright smb_dcache_create(void)
63229bd2886SAlan Wright {
63329bd2886SAlan Wright 	(void) mutex_lock(&smb_dcache.dc_mtx);
63429bd2886SAlan Wright 	if (smb_dcache.dc_state != SMB_DCACHE_STATE_NONE) {
63529bd2886SAlan Wright 		(void) mutex_unlock(&smb_dcache.dc_mtx);
63629bd2886SAlan Wright 		return;
63729bd2886SAlan Wright 	}
63829bd2886SAlan Wright 
639a0aa776eSAlan Wright 	list_create(&smb_dcache.dc_cache, sizeof (smb_domain_t),
640a0aa776eSAlan Wright 	    offsetof(smb_domain_t, di_lnd));
64129bd2886SAlan Wright 
64229bd2886SAlan Wright 	smb_dcache.dc_nops = 0;
643b3700b07SGordon Ross 	bzero(&smb_dcache.dc_dci, sizeof (smb_dcache.dc_dci));
644975041ddSGordon Ross 	smb_dcache.dc_dci_valid = B_FALSE;
64529bd2886SAlan Wright 	smb_dcache.dc_state = SMB_DCACHE_STATE_READY;
64629bd2886SAlan Wright 	(void) mutex_unlock(&smb_dcache.dc_mtx);
64729bd2886SAlan Wright }
64829bd2886SAlan Wright 
64929bd2886SAlan Wright /*
65029bd2886SAlan Wright  * Removes and frees all the cache entries
65129bd2886SAlan Wright  */
65229bd2886SAlan Wright static void
smb_dcache_flush(void)65329bd2886SAlan Wright smb_dcache_flush(void)
65429bd2886SAlan Wright {
655a0aa776eSAlan Wright 	smb_domain_t *di;
65629bd2886SAlan Wright 
65729bd2886SAlan Wright 	(void) rw_wrlock(&smb_dcache.dc_cache_lck);
65829bd2886SAlan Wright 	while ((di = list_head(&smb_dcache.dc_cache)) != NULL)
65929bd2886SAlan Wright 		smb_dcache_remove(di);
66029bd2886SAlan Wright 	(void) rw_unlock(&smb_dcache.dc_cache_lck);
66129bd2886SAlan Wright }
66229bd2886SAlan Wright 
66329bd2886SAlan Wright /*
66429bd2886SAlan Wright  * Destroys the cache.
66529bd2886SAlan Wright  */
66629bd2886SAlan Wright static void
smb_dcache_destroy(void)66729bd2886SAlan Wright smb_dcache_destroy(void)
66829bd2886SAlan Wright {
66929bd2886SAlan Wright 	(void) mutex_lock(&smb_dcache.dc_mtx);
67029bd2886SAlan Wright 	if ((smb_dcache.dc_state == SMB_DCACHE_STATE_READY) ||
67129bd2886SAlan Wright 	    (smb_dcache.dc_state == SMB_DCACHE_STATE_UPDATING)) {
67229bd2886SAlan Wright 		smb_dcache.dc_state = SMB_DCACHE_STATE_DESTROYING;
67329bd2886SAlan Wright 		while (smb_dcache.dc_nops > 0)
67429bd2886SAlan Wright 			(void) cond_wait(&smb_dcache.dc_cv,
67529bd2886SAlan Wright 			    &smb_dcache.dc_mtx);
67629bd2886SAlan Wright 
67729bd2886SAlan Wright 		smb_dcache_flush();
67829bd2886SAlan Wright 		list_destroy(&smb_dcache.dc_cache);
67929bd2886SAlan Wright 
68029bd2886SAlan Wright 		smb_dcache.dc_state = SMB_DCACHE_STATE_NONE;
68129bd2886SAlan Wright 	}
68229bd2886SAlan Wright 	(void) mutex_unlock(&smb_dcache.dc_mtx);
68329bd2886SAlan Wright }
68429bd2886SAlan Wright 
68529bd2886SAlan Wright /*
68629bd2886SAlan Wright  * Lock the cache with the specified mode.
68729bd2886SAlan Wright  * If the cache is in updating state and a read lock is
68829bd2886SAlan Wright  * requested, the lock won't be granted until either the
68929bd2886SAlan Wright  * update is finished or SMB_DCACHE_UPDATE_WAIT has passed.
69029bd2886SAlan Wright  *
69129bd2886SAlan Wright  * Whenever a lock is granted, the number of inflight cache
69229bd2886SAlan Wright  * operations is incremented.
69329bd2886SAlan Wright  */
69429bd2886SAlan Wright static uint32_t
smb_dcache_lock(int mode)69529bd2886SAlan Wright smb_dcache_lock(int mode)
69629bd2886SAlan Wright {
69729bd2886SAlan Wright 	(void) mutex_lock(&smb_dcache.dc_mtx);
69829bd2886SAlan Wright 	switch (smb_dcache.dc_state) {
69929bd2886SAlan Wright 	case SMB_DCACHE_STATE_NONE:
70029bd2886SAlan Wright 	case SMB_DCACHE_STATE_DESTROYING:
701975041ddSGordon Ross 	default:
70229bd2886SAlan Wright 		(void) mutex_unlock(&smb_dcache.dc_mtx);
70329bd2886SAlan Wright 		return (SMB_DOMAIN_INTERNAL_ERR);
70429bd2886SAlan Wright 
70529bd2886SAlan Wright 	case SMB_DCACHE_STATE_UPDATING:
70629bd2886SAlan Wright 		if (mode == SMB_DCACHE_RDLOCK) {
70729bd2886SAlan Wright 			/*
70829bd2886SAlan Wright 			 * Read operations should wait until the update
70929bd2886SAlan Wright 			 * is completed.
71029bd2886SAlan Wright 			 */
71129bd2886SAlan Wright 			if (!smb_dcache_wait()) {
71229bd2886SAlan Wright 				(void) mutex_unlock(&smb_dcache.dc_mtx);
71329bd2886SAlan Wright 				return (SMB_DOMAIN_INTERNAL_ERR);
71429bd2886SAlan Wright 			}
71529bd2886SAlan Wright 		}
716bdb589c6SToomas Soome 		/* FALLTHROUGH */
71729bd2886SAlan Wright 
718975041ddSGordon Ross 	case SMB_DCACHE_STATE_READY:
71929bd2886SAlan Wright 		smb_dcache.dc_nops++;
72029bd2886SAlan Wright 		break;
72129bd2886SAlan Wright 	}
72229bd2886SAlan Wright 	(void) mutex_unlock(&smb_dcache.dc_mtx);
72329bd2886SAlan Wright 
72429bd2886SAlan Wright 	/*
72529bd2886SAlan Wright 	 * Lock has to be taken outside the mutex otherwise
72629bd2886SAlan Wright 	 * there could be a deadlock
72729bd2886SAlan Wright 	 */
72829bd2886SAlan Wright 	if (mode == SMB_DCACHE_RDLOCK)
72929bd2886SAlan Wright 		(void) rw_rdlock(&smb_dcache.dc_cache_lck);
73029bd2886SAlan Wright 	else
73129bd2886SAlan Wright 		(void) rw_wrlock(&smb_dcache.dc_cache_lck);
73229bd2886SAlan Wright 
73329bd2886SAlan Wright 	return (SMB_DOMAIN_SUCCESS);
73429bd2886SAlan Wright }
73529bd2886SAlan Wright 
73629bd2886SAlan Wright /*
73729bd2886SAlan Wright  * Decrement the number of inflight operations and then unlock.
73829bd2886SAlan Wright  */
73929bd2886SAlan Wright static void
smb_dcache_unlock(void)74029bd2886SAlan Wright smb_dcache_unlock(void)
74129bd2886SAlan Wright {
74229bd2886SAlan Wright 	(void) mutex_lock(&smb_dcache.dc_mtx);
74329bd2886SAlan Wright 	assert(smb_dcache.dc_nops > 0);
74429bd2886SAlan Wright 	smb_dcache.dc_nops--;
74529bd2886SAlan Wright 	(void) cond_broadcast(&smb_dcache.dc_cv);
74629bd2886SAlan Wright 	(void) mutex_unlock(&smb_dcache.dc_mtx);
74729bd2886SAlan Wright 
74829bd2886SAlan Wright 	(void) rw_unlock(&smb_dcache.dc_cache_lck);
74929bd2886SAlan Wright }
75029bd2886SAlan Wright 
75129bd2886SAlan Wright static uint32_t
smb_dcache_add(smb_domain_t * di)752a0aa776eSAlan Wright smb_dcache_add(smb_domain_t *di)
75329bd2886SAlan Wright {
754a0aa776eSAlan Wright 	smb_domain_t *dcnode;
75529bd2886SAlan Wright 
756b78b1474SGordon Ross 	assert(di->di_type != 0);
757b78b1474SGordon Ross 
758a0aa776eSAlan Wright 	if ((dcnode = malloc(sizeof (smb_domain_t))) == NULL)
75929bd2886SAlan Wright 		return (SMB_DOMAIN_NO_MEMORY);
76029bd2886SAlan Wright 
76129bd2886SAlan Wright 	*dcnode = *di;
76229bd2886SAlan Wright 	dcnode->di_binsid = smb_sid_fromstr(dcnode->di_sid);
76329bd2886SAlan Wright 	if (dcnode->di_binsid == NULL) {
76429bd2886SAlan Wright 		free(dcnode);
76529bd2886SAlan Wright 		return (SMB_DOMAIN_NO_MEMORY);
76629bd2886SAlan Wright 	}
76729bd2886SAlan Wright 
76829bd2886SAlan Wright 	list_insert_tail(&smb_dcache.dc_cache, dcnode);
76929bd2886SAlan Wright 	return (SMB_DOMAIN_SUCCESS);
77029bd2886SAlan Wright }
77129bd2886SAlan Wright 
77229bd2886SAlan Wright static void
smb_dcache_remove(smb_domain_t * di)773a0aa776eSAlan Wright smb_dcache_remove(smb_domain_t *di)
77429bd2886SAlan Wright {
77529bd2886SAlan Wright 	list_remove(&smb_dcache.dc_cache, di);
77629bd2886SAlan Wright 	smb_sid_free(di->di_binsid);
77729bd2886SAlan Wright 	free(di);
77829bd2886SAlan Wright }
77929bd2886SAlan Wright 
78029bd2886SAlan Wright static void
smb_dcache_setdc(const smb_dcinfo_t * dci)781b3700b07SGordon Ross smb_dcache_setdc(const smb_dcinfo_t *dci)
78229bd2886SAlan Wright {
78329bd2886SAlan Wright 	(void) mutex_lock(&smb_dcache.dc_mtx);
784b3700b07SGordon Ross 	smb_dcache.dc_dci = *dci; /* struct assignment! */
785975041ddSGordon Ross 	smb_dcache.dc_dci_valid = B_TRUE;
786975041ddSGordon Ross 	(void) cond_broadcast(&smb_dcache.dc_dci_cv);
78729bd2886SAlan Wright 	(void) mutex_unlock(&smb_dcache.dc_mtx);
78829bd2886SAlan Wright }
78929bd2886SAlan Wright 
790b3700b07SGordon Ross /*
791975041ddSGordon Ross  * Get information about our domain controller.  If the wait arg
792975041ddSGordon Ross  * is true, wait for the DC locator to finish before copying.
793975041ddSGordon Ross  * Returns TRUE on success (have DC info).
794b3700b07SGordon Ross  */
795b3700b07SGordon Ross static boolean_t
smb_dcache_getdc(smb_dcinfo_t * dci,boolean_t wait)796975041ddSGordon Ross smb_dcache_getdc(smb_dcinfo_t *dci, boolean_t wait)
79729bd2886SAlan Wright {
798975041ddSGordon Ross 	timestruc_t to;
799975041ddSGordon Ross 	boolean_t rv;
800975041ddSGordon Ross 	int err;
801975041ddSGordon Ross 
802975041ddSGordon Ross 	to.tv_sec = time(NULL) + SMB_DCACHE_UPDATE_WAIT;
803975041ddSGordon Ross 	to.tv_nsec = 0;
804975041ddSGordon Ross 
80529bd2886SAlan Wright 	(void) mutex_lock(&smb_dcache.dc_mtx);
806975041ddSGordon Ross 
807975041ddSGordon Ross 	while (wait && !smb_dcache.dc_dci_valid) {
808975041ddSGordon Ross 		err = cond_timedwait(&smb_dcache.dc_dci_cv,
809975041ddSGordon Ross 		    &smb_dcache.dc_mtx, &to);
810975041ddSGordon Ross 		if (err == ETIME)
811975041ddSGordon Ross 			break;
812975041ddSGordon Ross 	}
813b3700b07SGordon Ross 	*dci = smb_dcache.dc_dci; /* struct assignment! */
814975041ddSGordon Ross 	rv = smb_dcache.dc_dci_valid;
815975041ddSGordon Ross 
81629bd2886SAlan Wright 	(void) mutex_unlock(&smb_dcache.dc_mtx);
817975041ddSGordon Ross 
818975041ddSGordon Ross 	return (rv);
81929bd2886SAlan Wright }
82029bd2886SAlan Wright 
821a0aa776eSAlan Wright /*
822a0aa776eSAlan Wright  * Waits for SMB_DCACHE_UPDATE_WAIT seconds if cache is in
823a0aa776eSAlan Wright  * UPDATING state. Upon wake up returns true if cache is
824a0aa776eSAlan Wright  * ready to be used, otherwise it returns false.
825a0aa776eSAlan Wright  */
82629bd2886SAlan Wright static boolean_t
smb_dcache_wait(void)82729bd2886SAlan Wright smb_dcache_wait(void)
82829bd2886SAlan Wright {
82929bd2886SAlan Wright 	timestruc_t to;
83029bd2886SAlan Wright 	int err;
83129bd2886SAlan Wright 
832975041ddSGordon Ross 	assert(MUTEX_HELD(&smb_dcache.dc_mtx));
833975041ddSGordon Ross 
834975041ddSGordon Ross 	to.tv_sec = time(NULL) + SMB_DCACHE_UPDATE_WAIT;
83529bd2886SAlan Wright 	to.tv_nsec = 0;
83629bd2886SAlan Wright 	while (smb_dcache.dc_state == SMB_DCACHE_STATE_UPDATING) {
837975041ddSGordon Ross 		err = cond_timedwait(&smb_dcache.dc_cv,
83829bd2886SAlan Wright 		    &smb_dcache.dc_mtx, &to);
83929bd2886SAlan Wright 		if (err == ETIME)
84029bd2886SAlan Wright 			break;
84129bd2886SAlan Wright 	}
84229bd2886SAlan Wright 
84329bd2886SAlan Wright 	return (smb_dcache.dc_state == SMB_DCACHE_STATE_READY);
84429bd2886SAlan Wright }
84529bd2886SAlan Wright 
846a0aa776eSAlan Wright /*
847a0aa776eSAlan Wright  * Transfers the cache into UPDATING state, this will ensure
848a0aa776eSAlan Wright  * any read access to the cache will be stalled until the
849a0aa776eSAlan Wright  * update is finished. This is to avoid providing incomplete,
850a0aa776eSAlan Wright  * inconsistent or stale information.
851a0aa776eSAlan Wright  *
852a0aa776eSAlan Wright  * If another thread is already updating the cache, other
853a0aa776eSAlan Wright  * callers will wait until cache is no longer in UPDATING
854a0aa776eSAlan Wright  * state. The return code is decided based on the new
855a0aa776eSAlan Wright  * state of the cache.
856a0aa776eSAlan Wright  */
857a0aa776eSAlan Wright static uint32_t
smb_dcache_updating(void)85829bd2886SAlan Wright smb_dcache_updating(void)
85929bd2886SAlan Wright {
860a0aa776eSAlan Wright 	uint32_t rc;
861a0aa776eSAlan Wright 
86229bd2886SAlan Wright 	(void) mutex_lock(&smb_dcache.dc_mtx);
863a0aa776eSAlan Wright 	switch (smb_dcache.dc_state) {
864a0aa776eSAlan Wright 	case SMB_DCACHE_STATE_READY:
86529bd2886SAlan Wright 		smb_dcache.dc_state = SMB_DCACHE_STATE_UPDATING;
866a0aa776eSAlan Wright 		rc = SMB_DOMAIN_SUCCESS;
867a0aa776eSAlan Wright 		break;
868a0aa776eSAlan Wright 
869a0aa776eSAlan Wright 	case SMB_DCACHE_STATE_UPDATING:
870a0aa776eSAlan Wright 		while (smb_dcache.dc_state == SMB_DCACHE_STATE_UPDATING)
871a0aa776eSAlan Wright 			(void) cond_wait(&smb_dcache.dc_cv,
872a0aa776eSAlan Wright 			    &smb_dcache.dc_mtx);
873a0aa776eSAlan Wright 
874a0aa776eSAlan Wright 		if (smb_dcache.dc_state == SMB_DCACHE_STATE_READY) {
875a0aa776eSAlan Wright 			smb_dcache.dc_state = SMB_DCACHE_STATE_UPDATING;
876a0aa776eSAlan Wright 			rc = SMB_DOMAIN_SUCCESS;
877a0aa776eSAlan Wright 		} else {
878a0aa776eSAlan Wright 			rc = SMB_DOMAIN_NO_CACHE;
879a0aa776eSAlan Wright 		}
880a0aa776eSAlan Wright 		break;
881a0aa776eSAlan Wright 
882a0aa776eSAlan Wright 	case SMB_DCACHE_STATE_NONE:
883a0aa776eSAlan Wright 	case SMB_DCACHE_STATE_DESTROYING:
884a0aa776eSAlan Wright 		rc = SMB_DOMAIN_NO_CACHE;
885a0aa776eSAlan Wright 		break;
886a0aa776eSAlan Wright 
887a0aa776eSAlan Wright 	default:
888*83163ba8SToomas Soome 		rc = SMB_DOMAIN_SUCCESS;
889a0aa776eSAlan Wright 		break;
890a0aa776eSAlan Wright 	}
891a0aa776eSAlan Wright 
89229bd2886SAlan Wright 	(void) mutex_unlock(&smb_dcache.dc_mtx);
893a0aa776eSAlan Wright 	return (rc);
89429bd2886SAlan Wright }
89529bd2886SAlan Wright 
896a0aa776eSAlan Wright /*
897a0aa776eSAlan Wright  * Transfers the cache from UPDATING to READY state.
898a0aa776eSAlan Wright  *
899a0aa776eSAlan Wright  * Nothing will happen if the cache is no longer available
900a0aa776eSAlan Wright  * or it is being destroyed.
901a0aa776eSAlan Wright  */
90229bd2886SAlan Wright static void
smb_dcache_ready(void)90329bd2886SAlan Wright smb_dcache_ready(void)
90429bd2886SAlan Wright {
90529bd2886SAlan Wright 	(void) mutex_lock(&smb_dcache.dc_mtx);
906a0aa776eSAlan Wright 	switch (smb_dcache.dc_state) {
907a0aa776eSAlan Wright 	case SMB_DCACHE_STATE_UPDATING:
90829bd2886SAlan Wright 		smb_dcache.dc_state = SMB_DCACHE_STATE_READY;
909a0aa776eSAlan Wright 		(void) cond_broadcast(&smb_dcache.dc_cv);
910a0aa776eSAlan Wright 		break;
911a0aa776eSAlan Wright 
912a0aa776eSAlan Wright 	case SMB_DCACHE_STATE_NONE:
913a0aa776eSAlan Wright 	case SMB_DCACHE_STATE_DESTROYING:
914a0aa776eSAlan Wright 		break;
915a0aa776eSAlan Wright 
916a0aa776eSAlan Wright 	default:
91729bd2886SAlan Wright 		assert(0);
918a0aa776eSAlan Wright 	}
91929bd2886SAlan Wright 	(void) mutex_unlock(&smb_dcache.dc_mtx);
92029bd2886SAlan Wright }
921