xref: /titanic_53/usr/src/lib/smbsrv/libsmb/common/smb_domain.c (revision b3700b074e637f8c6991b70754c88a2cfffb246b)
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  *
25*b3700b07SGordon Ross  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
26da6c28aaSamw  */
27da6c28aaSamw 
28da6c28aaSamw /*
2929bd2886SAlan Wright  * This file defines the domain environment values and the domain
30da6c28aaSamw  * database interface. The database is a single linked list of
31da6c28aaSamw  * structures containing domain type, name and SID information.
32da6c28aaSamw  */
33da6c28aaSamw 
3489dc44ceSjose borrego #include <sys/types.h>
3589dc44ceSjose borrego #include <sys/stat.h>
3629bd2886SAlan Wright #include <sys/list.h>
3789dc44ceSjose borrego #include <stdio.h>
38da6c28aaSamw #include <strings.h>
3989dc44ceSjose borrego #include <string.h>
40da6c28aaSamw #include <unistd.h>
4189dc44ceSjose borrego #include <stdlib.h>
42da6c28aaSamw #include <synch.h>
4389dc44ceSjose borrego #include <pwd.h>
4489dc44ceSjose borrego #include <grp.h>
4529bd2886SAlan Wright #include <assert.h>
46da6c28aaSamw 
47da6c28aaSamw #include <smbsrv/smbinfo.h>
48da6c28aaSamw #include <smbsrv/string.h>
496537f381Sas200622 #include <smbsrv/smb_sid.h>
50da6c28aaSamw #include <smbsrv/libsmb.h>
51da6c28aaSamw 
5289dc44ceSjose borrego #define	SMB_DOMAINS_FILE	"domains"
53da6c28aaSamw 
5429bd2886SAlan Wright #define	SMB_DCACHE_UPDATE_WAIT	45	/* seconds */
55da6c28aaSamw 
56da6c28aaSamw /*
5729bd2886SAlan Wright  * Domain cache states
58da6c28aaSamw  */
5929bd2886SAlan Wright #define	SMB_DCACHE_STATE_NONE		0
6029bd2886SAlan Wright #define	SMB_DCACHE_STATE_READY		1
6129bd2886SAlan Wright #define	SMB_DCACHE_STATE_UPDATING	2
6229bd2886SAlan Wright #define	SMB_DCACHE_STATE_DESTROYING	3
63da6c28aaSamw 
64da6c28aaSamw /*
6529bd2886SAlan Wright  * Cache lock modes
6629bd2886SAlan Wright  */
6729bd2886SAlan Wright #define	SMB_DCACHE_RDLOCK	0
6829bd2886SAlan Wright #define	SMB_DCACHE_WRLOCK	1
6929bd2886SAlan Wright 
7029bd2886SAlan Wright typedef struct smb_domain_cache {
7129bd2886SAlan Wright 	list_t		dc_cache;
7229bd2886SAlan Wright 	rwlock_t	dc_cache_lck;
7329bd2886SAlan Wright 	mutex_t		dc_mtx;
7429bd2886SAlan Wright 	cond_t		dc_cv;
7529bd2886SAlan Wright 	uint32_t	dc_state;
7629bd2886SAlan Wright 	uint32_t	dc_nops;
77*b3700b07SGordon Ross 	smb_dcinfo_t	dc_dci;
7829bd2886SAlan Wright } smb_domain_cache_t;
7929bd2886SAlan Wright 
8029bd2886SAlan Wright static smb_domain_cache_t smb_dcache;
8129bd2886SAlan Wright 
82a0aa776eSAlan Wright static uint32_t smb_domain_add(smb_domain_type_t, smb_domain_t *);
83a0aa776eSAlan Wright static uint32_t smb_domain_add_local(void);
84a0aa776eSAlan Wright static uint32_t smb_domain_add_primary(uint32_t);
85a0aa776eSAlan Wright static void smb_domain_unlink(void);
8629bd2886SAlan Wright 
8729bd2886SAlan Wright static void smb_dcache_create(void);
8829bd2886SAlan Wright static void smb_dcache_destroy(void);
8929bd2886SAlan Wright static uint32_t smb_dcache_lock(int);
9029bd2886SAlan Wright static void smb_dcache_unlock(void);
91a0aa776eSAlan Wright static void smb_dcache_remove(smb_domain_t *);
92a0aa776eSAlan Wright static uint32_t smb_dcache_add(smb_domain_t *);
93*b3700b07SGordon Ross static boolean_t smb_dcache_getdc(smb_dcinfo_t *);
94*b3700b07SGordon Ross static void smb_dcache_setdc(const smb_dcinfo_t *);
9529bd2886SAlan Wright static boolean_t smb_dcache_wait(void);
96a0aa776eSAlan Wright static uint32_t smb_dcache_updating(void);
9729bd2886SAlan Wright static void smb_dcache_ready(void);
9829bd2886SAlan Wright 
9929bd2886SAlan Wright /*
10029bd2886SAlan Wright  * domain cache one time initialization. This function should
10129bd2886SAlan Wright  * only be called during service startup.
102da6c28aaSamw  *
10329bd2886SAlan Wright  * Returns 0 on success and an error code on failure.
104da6c28aaSamw  */
105da6c28aaSamw int
smb_domain_init(uint32_t secmode)106a0aa776eSAlan Wright smb_domain_init(uint32_t secmode)
107da6c28aaSamw {
108a0aa776eSAlan Wright 	smb_domain_t di;
109dc20a302Sas200622 	int rc;
110da6c28aaSamw 
11129bd2886SAlan Wright 	smb_dcache_create();
112da6c28aaSamw 
113a0aa776eSAlan Wright 	if ((rc = smb_domain_add_local()) != 0)
11429bd2886SAlan Wright 		return (rc);
115da6c28aaSamw 
116a0aa776eSAlan Wright 	smb_domain_set_basic_info(NT_BUILTIN_DOMAIN_SIDSTR, "BUILTIN", "", &di);
117a0aa776eSAlan Wright 	(void) smb_domain_add(SMB_DOMAIN_BUILTIN, &di);
118da6c28aaSamw 
119a0aa776eSAlan Wright 	return (smb_domain_add_primary(secmode));
120da6c28aaSamw }
121da6c28aaSamw 
122da6c28aaSamw /*
12329bd2886SAlan Wright  * Destroys the cache upon service termination
124da6c28aaSamw  */
125da6c28aaSamw void
smb_domain_fini(void)126a0aa776eSAlan Wright smb_domain_fini(void)
127da6c28aaSamw {
12829bd2886SAlan Wright 	smb_dcache_destroy();
129a0aa776eSAlan Wright 	smb_domain_unlink();
130da6c28aaSamw }
131da6c28aaSamw 
132da6c28aaSamw /*
13329bd2886SAlan Wright  * Add a domain structure to domain cache. There is no checking
13429bd2886SAlan Wright  * for duplicates.
135da6c28aaSamw  */
13629bd2886SAlan Wright static uint32_t
smb_domain_add(smb_domain_type_t type,smb_domain_t * di)137a0aa776eSAlan Wright smb_domain_add(smb_domain_type_t type, smb_domain_t *di)
138da6c28aaSamw {
13929bd2886SAlan Wright 	uint32_t res;
14029bd2886SAlan Wright 
14129bd2886SAlan Wright 	if ((di == NULL) || (di->di_sid == NULL))
14229bd2886SAlan Wright 		return (SMB_DOMAIN_INVALID_ARG);
14329bd2886SAlan Wright 
14429bd2886SAlan Wright 	if ((res = smb_dcache_lock(SMB_DCACHE_WRLOCK)) == SMB_DOMAIN_SUCCESS) {
14529bd2886SAlan Wright 		di->di_type = type;
14629bd2886SAlan Wright 		res = smb_dcache_add(di);
14729bd2886SAlan Wright 		smb_dcache_unlock();
148da6c28aaSamw 	}
149da6c28aaSamw 
15029bd2886SAlan Wright 	return (res);
151da6c28aaSamw }
152da6c28aaSamw 
153da6c28aaSamw /*
15429bd2886SAlan Wright  * Lookup a domain by its name. The passed name is the NETBIOS or fully
15529bd2886SAlan Wright  * qualified DNS name or non-qualified DNS name.
156da6c28aaSamw  *
15729bd2886SAlan Wright  * If the requested domain is found and given 'di' pointer is not NULL
15829bd2886SAlan Wright  * it'll be filled with the domain information and B_TRUE is returned.
15929bd2886SAlan Wright  * If the caller only needs to check a domain existence it can pass
16029bd2886SAlan Wright  * NULL for 'di' and just check the return value.
16129bd2886SAlan Wright  *
16229bd2886SAlan Wright  * If the domain is not in the cache B_FALSE is returned.
163da6c28aaSamw  */
16429bd2886SAlan Wright boolean_t
smb_domain_lookup_name(char * name,smb_domain_t * di)165a0aa776eSAlan Wright smb_domain_lookup_name(char *name, smb_domain_t *di)
166da6c28aaSamw {
16729bd2886SAlan Wright 	boolean_t found = B_FALSE;
168a0aa776eSAlan Wright 	smb_domain_t *dcnode;
1697f667e74Sjose borrego 	char *p;
1707f667e74Sjose borrego 
171a0aa776eSAlan Wright 	bzero(di, sizeof (smb_domain_t));
1727f667e74Sjose borrego 
17329bd2886SAlan Wright 	if (name == NULL || *name == '\0')
17429bd2886SAlan Wright 		return (B_FALSE);
17529bd2886SAlan Wright 
17629bd2886SAlan Wright 	if (smb_dcache_lock(SMB_DCACHE_RDLOCK) != SMB_DOMAIN_SUCCESS)
17729bd2886SAlan Wright 		return (B_FALSE);
17829bd2886SAlan Wright 
17929bd2886SAlan Wright 	dcnode = list_head(&smb_dcache.dc_cache);
18029bd2886SAlan Wright 	while (dcnode) {
181bbf6f00cSJordan Brown 		found = (smb_strcasecmp(dcnode->di_nbname, name, 0) == 0) ||
182bbf6f00cSJordan Brown 		    (smb_strcasecmp(dcnode->di_fqname, name, 0) == 0);
18329bd2886SAlan Wright 
18429bd2886SAlan Wright 		if (found) {
18529bd2886SAlan Wright 			if (di)
18629bd2886SAlan Wright 				*di = *dcnode;
18729bd2886SAlan Wright 			break;
18829bd2886SAlan Wright 		}
18929bd2886SAlan Wright 
19029bd2886SAlan Wright 		if ((p = strchr(dcnode->di_fqname, '.')) != NULL) {
1917f667e74Sjose borrego 			*p = '\0';
192bbf6f00cSJordan Brown 			found = (smb_strcasecmp(dcnode->di_fqname, name,
193bbf6f00cSJordan Brown 			    0) == 0);
19429bd2886SAlan Wright 			*p = '.';
19529bd2886SAlan Wright 			if (found) {
19629bd2886SAlan Wright 				if (di)
19729bd2886SAlan Wright 					*di = *dcnode;
198da6c28aaSamw 				break;
199da6c28aaSamw 			}
200da6c28aaSamw 		}
201da6c28aaSamw 
20229bd2886SAlan Wright 		dcnode = list_next(&smb_dcache.dc_cache, dcnode);
20329bd2886SAlan Wright 	}
20429bd2886SAlan Wright 
20529bd2886SAlan Wright 	smb_dcache_unlock();
20629bd2886SAlan Wright 	return (found);
20729bd2886SAlan Wright }
208da6c28aaSamw 
209da6c28aaSamw /*
21029bd2886SAlan Wright  * Lookup a domain by its SID.
211da6c28aaSamw  *
21229bd2886SAlan Wright  * If the requested domain is found and given 'di' pointer is not NULL
21329bd2886SAlan Wright  * it'll be filled with the domain information and B_TRUE is returned.
21429bd2886SAlan Wright  * If the caller only needs to check a domain existence it can pass
21529bd2886SAlan Wright  * NULL for 'di' and just check the return value.
21629bd2886SAlan Wright  *
21729bd2886SAlan Wright  * If the domain is not in the cache B_FALSE is returned.
218da6c28aaSamw  */
21929bd2886SAlan Wright boolean_t
smb_domain_lookup_sid(smb_sid_t * sid,smb_domain_t * di)220a0aa776eSAlan Wright smb_domain_lookup_sid(smb_sid_t *sid, smb_domain_t *di)
221da6c28aaSamw {
22229bd2886SAlan Wright 	boolean_t found = B_FALSE;
223a0aa776eSAlan Wright 	smb_domain_t *dcnode;
22429bd2886SAlan Wright 	char sidstr[SMB_SID_STRSZ];
225da6c28aaSamw 
226a0aa776eSAlan Wright 	bzero(di, sizeof (smb_domain_t));
22729bd2886SAlan Wright 
22829bd2886SAlan Wright 	if (sid == NULL)
22929bd2886SAlan Wright 		return (B_FALSE);
23029bd2886SAlan Wright 
23129bd2886SAlan Wright 	smb_sid_tostr(sid, sidstr);
23229bd2886SAlan Wright 
23329bd2886SAlan Wright 	if (smb_dcache_lock(SMB_DCACHE_RDLOCK) != SMB_DOMAIN_SUCCESS)
23429bd2886SAlan Wright 		return (B_FALSE);
23529bd2886SAlan Wright 
23629bd2886SAlan Wright 	dcnode = list_head(&smb_dcache.dc_cache);
23729bd2886SAlan Wright 	while (dcnode) {
23829bd2886SAlan Wright 		found = (strcmp(dcnode->di_sid, sidstr) == 0);
23929bd2886SAlan Wright 		if (found) {
24029bd2886SAlan Wright 			if (di)
24129bd2886SAlan Wright 				*di = *dcnode;
242da6c28aaSamw 			break;
243da6c28aaSamw 		}
244da6c28aaSamw 
24529bd2886SAlan Wright 		dcnode = list_next(&smb_dcache.dc_cache, dcnode);
24629bd2886SAlan Wright 	}
24729bd2886SAlan Wright 
24829bd2886SAlan Wright 	smb_dcache_unlock();
24929bd2886SAlan Wright 	return (found);
25029bd2886SAlan Wright }
251da6c28aaSamw 
252da6c28aaSamw /*
25329bd2886SAlan Wright  * Lookup a domain by its type.
254da6c28aaSamw  *
25529bd2886SAlan Wright  * If the requested domain is found and given 'di' pointer is not NULL
25629bd2886SAlan Wright  * it'll be filled with the domain information and B_TRUE is returned.
25729bd2886SAlan Wright  * If the caller only needs to check a domain existence it can pass
25829bd2886SAlan Wright  * NULL for 'di' and just check the return value.
25929bd2886SAlan Wright  *
26029bd2886SAlan Wright  * If the domain is not in the cache B_FALSE is returned.
261da6c28aaSamw  */
26229bd2886SAlan Wright boolean_t
smb_domain_lookup_type(smb_domain_type_t type,smb_domain_t * di)263a0aa776eSAlan Wright smb_domain_lookup_type(smb_domain_type_t type, smb_domain_t *di)
264da6c28aaSamw {
26529bd2886SAlan Wright 	boolean_t found = B_FALSE;
266a0aa776eSAlan Wright 	smb_domain_t *dcnode;
267da6c28aaSamw 
268a0aa776eSAlan Wright 	bzero(di, sizeof (smb_domain_t));
26929bd2886SAlan Wright 
27029bd2886SAlan Wright 	if (smb_dcache_lock(SMB_DCACHE_RDLOCK) != SMB_DOMAIN_SUCCESS)
27129bd2886SAlan Wright 		return (B_FALSE);
27229bd2886SAlan Wright 
27329bd2886SAlan Wright 	dcnode = list_head(&smb_dcache.dc_cache);
27429bd2886SAlan Wright 	while (dcnode) {
27529bd2886SAlan Wright 		if (dcnode->di_type == type) {
27629bd2886SAlan Wright 			found = B_TRUE;
27729bd2886SAlan Wright 			if (di)
27829bd2886SAlan Wright 				*di = *dcnode;
279da6c28aaSamw 			break;
280da6c28aaSamw 		}
281da6c28aaSamw 
28229bd2886SAlan Wright 		dcnode = list_next(&smb_dcache.dc_cache, dcnode);
28329bd2886SAlan Wright 	}
28429bd2886SAlan Wright 
28529bd2886SAlan Wright 	smb_dcache_unlock();
28629bd2886SAlan Wright 	return (found);
28729bd2886SAlan Wright }
288da6c28aaSamw 
289da6c28aaSamw /*
29029bd2886SAlan Wright  * Returns primary domain information plus the name of
29129bd2886SAlan Wright  * the selected domain controller.
292da6c28aaSamw  */
29329bd2886SAlan Wright boolean_t
smb_domain_getinfo(smb_domainex_t * dxi)294a0aa776eSAlan Wright smb_domain_getinfo(smb_domainex_t *dxi)
295da6c28aaSamw {
296*b3700b07SGordon Ross 	boolean_t rv;
297da6c28aaSamw 
298*b3700b07SGordon Ross 	/* Note: this waits for the dcache lock. */
299*b3700b07SGordon Ross 	rv = smb_domain_lookup_type(SMB_DOMAIN_PRIMARY, &dxi->d_primary);
300*b3700b07SGordon Ross 	if (rv)
301*b3700b07SGordon Ross 		rv = smb_dcache_getdc(&dxi->d_dci);
302da6c28aaSamw 
303*b3700b07SGordon Ross 	return (rv);
304da6c28aaSamw }
305da6c28aaSamw 
30629bd2886SAlan Wright /*
307380acbbeSGordon Ross  * Get the name of the current DC (if any)
308380acbbeSGordon Ross  * Does NOT block.
309380acbbeSGordon Ross  */
310380acbbeSGordon Ross void
smb_domain_current_dc(smb_dcinfo_t * dci)311*b3700b07SGordon Ross smb_domain_current_dc(smb_dcinfo_t *dci)
312380acbbeSGordon Ross {
313*b3700b07SGordon Ross 	(void) smb_dcache_getdc(dci);
314380acbbeSGordon Ross }
315380acbbeSGordon Ross 
316380acbbeSGordon Ross /*
31729bd2886SAlan Wright  * Transfer the cache to updating state.
31829bd2886SAlan Wright  * In this state any request for reading the cache would
31929bd2886SAlan Wright  * be blocked until the update is finished.
32029bd2886SAlan Wright  */
321a0aa776eSAlan Wright uint32_t
smb_domain_start_update(void)322a0aa776eSAlan Wright smb_domain_start_update(void)
323da6c28aaSamw {
324a0aa776eSAlan Wright 	return (smb_dcache_updating());
32529bd2886SAlan Wright }
326da6c28aaSamw 
32729bd2886SAlan Wright /*
32829bd2886SAlan Wright  * Transfer the cache from updating to ready state.
32929bd2886SAlan Wright  */
33029bd2886SAlan Wright void
smb_domain_end_update(void)331a0aa776eSAlan Wright smb_domain_end_update(void)
33229bd2886SAlan Wright {
33329bd2886SAlan Wright 	smb_dcache_ready();
33429bd2886SAlan Wright }
33529bd2886SAlan Wright 
33629bd2886SAlan Wright /*
33729bd2886SAlan Wright  * Updates the cache with given information for the primary
33829bd2886SAlan Wright  * domain, possible trusted domains and the selected domain
33929bd2886SAlan Wright  * controller.
34029bd2886SAlan Wright  *
34129bd2886SAlan Wright  * Before adding the new entries existing entries of type
34229bd2886SAlan Wright  * primary and trusted will be removed from cache.
34329bd2886SAlan Wright  */
34429bd2886SAlan Wright void
smb_domain_update(smb_domainex_t * dxi)345a0aa776eSAlan Wright smb_domain_update(smb_domainex_t *dxi)
34629bd2886SAlan Wright {
347a0aa776eSAlan Wright 	smb_domain_t *dcnode;
34829bd2886SAlan Wright 	int i;
34929bd2886SAlan Wright 
35029bd2886SAlan Wright 	if (smb_dcache_lock(SMB_DCACHE_WRLOCK) != SMB_DOMAIN_SUCCESS)
351da6c28aaSamw 		return;
35229bd2886SAlan Wright 
35329bd2886SAlan Wright 	dcnode = list_head(&smb_dcache.dc_cache);
35429bd2886SAlan Wright 	while (dcnode) {
355a0aa776eSAlan Wright 		if ((dcnode->di_type == SMB_DOMAIN_PRIMARY) ||
356a0aa776eSAlan Wright 		    (dcnode->di_type == SMB_DOMAIN_TRUSTED)) {
35729bd2886SAlan Wright 			smb_dcache_remove(dcnode);
35829bd2886SAlan Wright 			dcnode = list_head(&smb_dcache.dc_cache);
35929bd2886SAlan Wright 		} else {
36029bd2886SAlan Wright 			dcnode = list_next(&smb_dcache.dc_cache, dcnode);
361da6c28aaSamw 		}
362da6c28aaSamw 	}
36329bd2886SAlan Wright 
364a0aa776eSAlan Wright 	if (smb_dcache_add(&dxi->d_primary) == SMB_DOMAIN_SUCCESS) {
365a0aa776eSAlan Wright 		for (i = 0; i < dxi->d_trusted.td_num; i++)
366a0aa776eSAlan Wright 			(void) smb_dcache_add(&dxi->d_trusted.td_domains[i]);
36729bd2886SAlan Wright 
368*b3700b07SGordon Ross 		smb_dcache_setdc(&dxi->d_dci);
36929bd2886SAlan Wright 	}
37029bd2886SAlan Wright 
37129bd2886SAlan Wright 	smb_dcache_unlock();
372da6c28aaSamw }
37389dc44ceSjose borrego 
37489dc44ceSjose borrego /*
37589dc44ceSjose borrego  * Write the list of domains to /var/run/smb/domains.
37689dc44ceSjose borrego  */
37789dc44ceSjose borrego void
smb_domain_save(void)378a0aa776eSAlan Wright smb_domain_save(void)
37989dc44ceSjose borrego {
38089dc44ceSjose borrego 	char		fname[MAXPATHLEN];
38189dc44ceSjose borrego 	char		tag;
382a0aa776eSAlan Wright 	smb_domain_t	*domain;
38389dc44ceSjose borrego 	FILE		*fp;
38489dc44ceSjose borrego 	struct passwd	*pwd;
38589dc44ceSjose borrego 	struct group	*grp;
38689dc44ceSjose borrego 	uid_t		uid;
38789dc44ceSjose borrego 	gid_t		gid;
38889dc44ceSjose borrego 
38989dc44ceSjose borrego 	(void) snprintf(fname, MAXPATHLEN, "%s/%s",
39089dc44ceSjose borrego 	    SMB_VARRUN_DIR, SMB_DOMAINS_FILE);
39189dc44ceSjose borrego 
39289dc44ceSjose borrego 	if ((fp = fopen(fname, "w")) == NULL)
39389dc44ceSjose borrego 		return;
39489dc44ceSjose borrego 
39589dc44ceSjose borrego 	pwd = getpwnam("root");
39689dc44ceSjose borrego 	grp = getgrnam("sys");
39789dc44ceSjose borrego 	uid = (pwd == NULL) ? 0 : pwd->pw_uid;
39889dc44ceSjose borrego 	gid = (grp == NULL) ? 3 : grp->gr_gid;
39989dc44ceSjose borrego 
40089dc44ceSjose borrego 	(void) lockf(fileno(fp), F_LOCK, 0);
40189dc44ceSjose borrego 	(void) fchmod(fileno(fp), 0600);
40289dc44ceSjose borrego 	(void) fchown(fileno(fp), uid, gid);
40389dc44ceSjose borrego 
40429bd2886SAlan Wright 	if (smb_dcache_lock(SMB_DCACHE_RDLOCK) != SMB_DOMAIN_SUCCESS)
40529bd2886SAlan Wright 		return;
40689dc44ceSjose borrego 
40729bd2886SAlan Wright 	domain = list_head(&smb_dcache.dc_cache);
40889dc44ceSjose borrego 	while (domain) {
40929bd2886SAlan Wright 		switch (domain->di_type) {
410a0aa776eSAlan Wright 		case SMB_DOMAIN_PRIMARY:
41189dc44ceSjose borrego 			tag = '*';
41289dc44ceSjose borrego 			break;
41389dc44ceSjose borrego 
414a0aa776eSAlan Wright 		case SMB_DOMAIN_TRUSTED:
415a0aa776eSAlan Wright 		case SMB_DOMAIN_UNTRUSTED:
41689dc44ceSjose borrego 			tag = '-';
41789dc44ceSjose borrego 			break;
41889dc44ceSjose borrego 
419a0aa776eSAlan Wright 		case SMB_DOMAIN_LOCAL:
42089dc44ceSjose borrego 			tag = '.';
42189dc44ceSjose borrego 			break;
42289dc44ceSjose borrego 		default:
42329bd2886SAlan Wright 			domain = list_next(&smb_dcache.dc_cache, domain);
42489dc44ceSjose borrego 			continue;
42589dc44ceSjose borrego 		}
42689dc44ceSjose borrego 
42789dc44ceSjose borrego 		(void) fprintf(fp, "[%c] [%s] [%s]\n",
42829bd2886SAlan Wright 		    tag, domain->di_nbname, domain->di_sid);
42989dc44ceSjose borrego 
43029bd2886SAlan Wright 		domain = list_next(&smb_dcache.dc_cache, domain);
43189dc44ceSjose borrego 	}
43289dc44ceSjose borrego 
43329bd2886SAlan Wright 	smb_dcache_unlock();
43489dc44ceSjose borrego 	(void) lockf(fileno(fp), F_ULOCK, 0);
43589dc44ceSjose borrego 	(void) fclose(fp);
43689dc44ceSjose borrego }
43789dc44ceSjose borrego 
43889dc44ceSjose borrego /*
43989dc44ceSjose borrego  * List the domains in /var/run/smb/domains.
44089dc44ceSjose borrego  */
44189dc44ceSjose borrego void
smb_domain_show(void)442a0aa776eSAlan Wright smb_domain_show(void)
44389dc44ceSjose borrego {
44489dc44ceSjose borrego 	char buf[MAXPATHLEN];
44589dc44ceSjose borrego 	char *p;
44689dc44ceSjose borrego 	FILE *fp;
44789dc44ceSjose borrego 
44889dc44ceSjose borrego 	(void) snprintf(buf, MAXPATHLEN, "%s/%s",
44989dc44ceSjose borrego 	    SMB_VARRUN_DIR, SMB_DOMAINS_FILE);
45089dc44ceSjose borrego 
45189dc44ceSjose borrego 	if ((fp = fopen(buf, "r")) != NULL) {
45289dc44ceSjose borrego 		(void) lockf(fileno(fp), F_LOCK, 0);
45389dc44ceSjose borrego 
45489dc44ceSjose borrego 		while (fgets(buf, MAXPATHLEN, fp) != NULL) {
45589dc44ceSjose borrego 			if ((p = strchr(buf, '\n')) != NULL)
45689dc44ceSjose borrego 				*p = '\0';
45789dc44ceSjose borrego 			(void) printf("%s\n", buf);
45889dc44ceSjose borrego 		}
45989dc44ceSjose borrego 
46089dc44ceSjose borrego 		(void) lockf(fileno(fp), F_ULOCK, 0);
46189dc44ceSjose borrego 		(void) fclose(fp);
46289dc44ceSjose borrego 	}
46389dc44ceSjose borrego }
46489dc44ceSjose borrego 
46529bd2886SAlan Wright void
smb_domain_set_basic_info(char * sid,char * nb_domain,char * fq_domain,smb_domain_t * di)466a0aa776eSAlan Wright smb_domain_set_basic_info(char *sid, char *nb_domain, char *fq_domain,
467a0aa776eSAlan Wright     smb_domain_t *di)
46829bd2886SAlan Wright {
46929bd2886SAlan Wright 	if (sid == NULL || nb_domain == NULL || fq_domain == NULL ||
47029bd2886SAlan Wright 	    di == NULL)
47129bd2886SAlan Wright 		return;
47229bd2886SAlan Wright 
47329bd2886SAlan Wright 	(void) strlcpy(di->di_sid, sid, SMB_SID_STRSZ);
47429bd2886SAlan Wright 	(void) strlcpy(di->di_nbname, nb_domain, NETBIOS_NAME_SZ);
475bbf6f00cSJordan Brown 	(void) smb_strupr(di->di_nbname);
47629bd2886SAlan Wright 	(void) strlcpy(di->di_fqname, fq_domain, MAXHOSTNAMELEN);
47729bd2886SAlan Wright 	di->di_binsid = NULL;
47829bd2886SAlan Wright }
47929bd2886SAlan Wright 
48029bd2886SAlan Wright void
smb_domain_set_dns_info(char * sid,char * nb_domain,char * fq_domain,char * forest,char * guid,smb_domain_t * di)481a0aa776eSAlan Wright smb_domain_set_dns_info(char *sid, char *nb_domain, char *fq_domain,
482a0aa776eSAlan Wright     char *forest, char *guid, smb_domain_t *di)
48329bd2886SAlan Wright {
48429bd2886SAlan Wright 	if (di == NULL || forest == NULL || guid == NULL)
48529bd2886SAlan Wright 		return;
48629bd2886SAlan Wright 
487a0aa776eSAlan Wright 	smb_domain_set_basic_info(sid, nb_domain, fq_domain, di);
48829bd2886SAlan Wright 	(void) strlcpy(di->di_u.di_dns.ddi_forest, forest, MAXHOSTNAMELEN);
48929bd2886SAlan Wright 	(void) strlcpy(di->di_u.di_dns.ddi_guid, guid,
49029bd2886SAlan Wright 	    UUID_PRINTABLE_STRING_LENGTH);
49129bd2886SAlan Wright }
49229bd2886SAlan Wright 
49329bd2886SAlan 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)494a0aa776eSAlan Wright smb_domain_set_trust_info(char *sid, char *nb_domain, char *fq_domain,
49529bd2886SAlan Wright     uint32_t trust_dir, uint32_t trust_type, uint32_t trust_attrs,
496a0aa776eSAlan Wright     smb_domain_t *di)
49729bd2886SAlan Wright {
49829bd2886SAlan Wright 	smb_domain_trust_t *ti;
49929bd2886SAlan Wright 
50029bd2886SAlan Wright 	if (di == NULL)
50129bd2886SAlan Wright 		return;
50229bd2886SAlan Wright 
503a0aa776eSAlan Wright 	di->di_type = SMB_DOMAIN_TRUSTED;
50429bd2886SAlan Wright 	ti = &di->di_u.di_trust;
505a0aa776eSAlan Wright 	smb_domain_set_basic_info(sid, nb_domain, fq_domain, di);
50629bd2886SAlan Wright 	ti->dti_trust_direction = trust_dir;
50729bd2886SAlan Wright 	ti->dti_trust_type = trust_type;
50829bd2886SAlan Wright 	ti->dti_trust_attrs = trust_attrs;
50929bd2886SAlan Wright }
51029bd2886SAlan Wright 
51189dc44ceSjose borrego /*
51289dc44ceSjose borrego  * Remove the /var/run/smb/domains file.
51389dc44ceSjose borrego  */
51429bd2886SAlan Wright static void
smb_domain_unlink(void)515a0aa776eSAlan Wright smb_domain_unlink(void)
51689dc44ceSjose borrego {
51789dc44ceSjose borrego 	char fname[MAXPATHLEN];
51889dc44ceSjose borrego 
51989dc44ceSjose borrego 	(void) snprintf(fname, MAXPATHLEN, "%s/%s",
52089dc44ceSjose borrego 	    SMB_VARRUN_DIR, SMB_DOMAINS_FILE);
52189dc44ceSjose borrego 	(void) unlink(fname);
52289dc44ceSjose borrego }
52329bd2886SAlan Wright 
52429bd2886SAlan Wright /*
52529bd2886SAlan Wright  * Add an entry for the local domain to the domain cache
52629bd2886SAlan Wright  */
52729bd2886SAlan Wright static uint32_t
smb_domain_add_local(void)528a0aa776eSAlan Wright smb_domain_add_local(void)
52929bd2886SAlan Wright {
53029bd2886SAlan Wright 	char *lsidstr;
53129bd2886SAlan Wright 	char hostname[NETBIOS_NAME_SZ];
53229bd2886SAlan Wright 	char fq_name[MAXHOSTNAMELEN];
533a0aa776eSAlan Wright 	smb_domain_t di;
53429bd2886SAlan Wright 
53529bd2886SAlan Wright 	if ((lsidstr = smb_config_get_localsid()) == NULL)
53629bd2886SAlan Wright 		return (SMB_DOMAIN_NOMACHINE_SID);
53729bd2886SAlan Wright 
53829bd2886SAlan Wright 	if (smb_getnetbiosname(hostname, NETBIOS_NAME_SZ) != 0) {
53929bd2886SAlan Wright 		free(lsidstr);
54029bd2886SAlan Wright 		return (SMB_DOMAIN_NOMACHINE_SID);
54129bd2886SAlan Wright 	}
54229bd2886SAlan Wright 
54329bd2886SAlan Wright 	*fq_name = '\0';
54429bd2886SAlan Wright 	(void) smb_getfqhostname(fq_name, MAXHOSTNAMELEN);
545a0aa776eSAlan Wright 	smb_domain_set_basic_info(lsidstr, hostname, fq_name, &di);
546a0aa776eSAlan Wright 	(void) smb_domain_add(SMB_DOMAIN_LOCAL, &di);
54729bd2886SAlan Wright 
54829bd2886SAlan Wright 	free(lsidstr);
54929bd2886SAlan Wright 	return (SMB_DOMAIN_SUCCESS);
55029bd2886SAlan Wright }
55129bd2886SAlan Wright 
55229bd2886SAlan Wright /*
55329bd2886SAlan Wright  * Add an entry for the primary domain to the domain cache
55429bd2886SAlan Wright  */
55529bd2886SAlan Wright static uint32_t
smb_domain_add_primary(uint32_t secmode)556a0aa776eSAlan Wright smb_domain_add_primary(uint32_t secmode)
55729bd2886SAlan Wright {
55829bd2886SAlan Wright 	char sidstr[SMB_SID_STRSZ];
55929bd2886SAlan Wright 	char fq_name[MAXHOSTNAMELEN];
56029bd2886SAlan Wright 	char nb_name[NETBIOS_NAME_SZ];
561a0aa776eSAlan Wright 	smb_domain_t di;
56229bd2886SAlan Wright 	int rc;
56329bd2886SAlan Wright 
56429bd2886SAlan Wright 	if (secmode != SMB_SECMODE_DOMAIN)
56529bd2886SAlan Wright 		return (SMB_DOMAIN_SUCCESS);
56629bd2886SAlan Wright 
56729bd2886SAlan Wright 	rc = smb_config_getstr(SMB_CI_DOMAIN_SID, sidstr, sizeof (sidstr));
56829bd2886SAlan Wright 	if (rc != SMBD_SMF_OK)
56929bd2886SAlan Wright 		return (SMB_DOMAIN_NODOMAIN_SID);
57029bd2886SAlan Wright 
57129bd2886SAlan Wright 	rc = smb_config_getstr(SMB_CI_DOMAIN_NAME, nb_name, NETBIOS_NAME_SZ);
57229bd2886SAlan Wright 	if ((rc != SMBD_SMF_OK) || (*nb_name == '\0'))
57329bd2886SAlan Wright 		return (SMB_DOMAIN_NODOMAIN_NAME);
57429bd2886SAlan Wright 
57529bd2886SAlan Wright 	(void) smb_getfqdomainname(fq_name, MAXHOSTNAMELEN);
576a0aa776eSAlan Wright 	smb_domain_set_basic_info(sidstr, nb_name, fq_name, &di);
577a0aa776eSAlan Wright 	(void) smb_domain_add(SMB_DOMAIN_PRIMARY, &di);
57829bd2886SAlan Wright 	return (SMB_DOMAIN_SUCCESS);
57929bd2886SAlan Wright }
58029bd2886SAlan Wright 
58129bd2886SAlan Wright /*
58229bd2886SAlan Wright  * Initialize the domain cache.
58329bd2886SAlan Wright  * This function does not populate the cache.
58429bd2886SAlan Wright  */
58529bd2886SAlan Wright static void
smb_dcache_create(void)58629bd2886SAlan Wright smb_dcache_create(void)
58729bd2886SAlan Wright {
58829bd2886SAlan Wright 	(void) mutex_lock(&smb_dcache.dc_mtx);
58929bd2886SAlan Wright 	if (smb_dcache.dc_state != SMB_DCACHE_STATE_NONE) {
59029bd2886SAlan Wright 		(void) mutex_unlock(&smb_dcache.dc_mtx);
59129bd2886SAlan Wright 		return;
59229bd2886SAlan Wright 	}
59329bd2886SAlan Wright 
594a0aa776eSAlan Wright 	list_create(&smb_dcache.dc_cache, sizeof (smb_domain_t),
595a0aa776eSAlan Wright 	    offsetof(smb_domain_t, di_lnd));
59629bd2886SAlan Wright 
59729bd2886SAlan Wright 	smb_dcache.dc_nops = 0;
598*b3700b07SGordon Ross 	bzero(&smb_dcache.dc_dci, sizeof (smb_dcache.dc_dci));
59929bd2886SAlan Wright 	smb_dcache.dc_state = SMB_DCACHE_STATE_READY;
60029bd2886SAlan Wright 	(void) mutex_unlock(&smb_dcache.dc_mtx);
60129bd2886SAlan Wright }
60229bd2886SAlan Wright 
60329bd2886SAlan Wright /*
60429bd2886SAlan Wright  * Removes and frees all the cache entries
60529bd2886SAlan Wright  */
60629bd2886SAlan Wright static void
smb_dcache_flush(void)60729bd2886SAlan Wright smb_dcache_flush(void)
60829bd2886SAlan Wright {
609a0aa776eSAlan Wright 	smb_domain_t *di;
61029bd2886SAlan Wright 
61129bd2886SAlan Wright 	(void) rw_wrlock(&smb_dcache.dc_cache_lck);
61229bd2886SAlan Wright 	while ((di = list_head(&smb_dcache.dc_cache)) != NULL)
61329bd2886SAlan Wright 		smb_dcache_remove(di);
61429bd2886SAlan Wright 	(void) rw_unlock(&smb_dcache.dc_cache_lck);
61529bd2886SAlan Wright }
61629bd2886SAlan Wright 
61729bd2886SAlan Wright /*
61829bd2886SAlan Wright  * Destroys the cache.
61929bd2886SAlan Wright  */
62029bd2886SAlan Wright static void
smb_dcache_destroy(void)62129bd2886SAlan Wright smb_dcache_destroy(void)
62229bd2886SAlan Wright {
62329bd2886SAlan Wright 	(void) mutex_lock(&smb_dcache.dc_mtx);
62429bd2886SAlan Wright 	if ((smb_dcache.dc_state == SMB_DCACHE_STATE_READY) ||
62529bd2886SAlan Wright 	    (smb_dcache.dc_state == SMB_DCACHE_STATE_UPDATING)) {
62629bd2886SAlan Wright 		smb_dcache.dc_state = SMB_DCACHE_STATE_DESTROYING;
62729bd2886SAlan Wright 		while (smb_dcache.dc_nops > 0)
62829bd2886SAlan Wright 			(void) cond_wait(&smb_dcache.dc_cv,
62929bd2886SAlan Wright 			    &smb_dcache.dc_mtx);
63029bd2886SAlan Wright 
63129bd2886SAlan Wright 		smb_dcache_flush();
63229bd2886SAlan Wright 		list_destroy(&smb_dcache.dc_cache);
63329bd2886SAlan Wright 
63429bd2886SAlan Wright 		smb_dcache.dc_state = SMB_DCACHE_STATE_NONE;
63529bd2886SAlan Wright 	}
63629bd2886SAlan Wright 	(void) mutex_unlock(&smb_dcache.dc_mtx);
63729bd2886SAlan Wright }
63829bd2886SAlan Wright 
63929bd2886SAlan Wright /*
64029bd2886SAlan Wright  * Lock the cache with the specified mode.
64129bd2886SAlan Wright  * If the cache is in updating state and a read lock is
64229bd2886SAlan Wright  * requested, the lock won't be granted until either the
64329bd2886SAlan Wright  * update is finished or SMB_DCACHE_UPDATE_WAIT has passed.
64429bd2886SAlan Wright  *
64529bd2886SAlan Wright  * Whenever a lock is granted, the number of inflight cache
64629bd2886SAlan Wright  * operations is incremented.
64729bd2886SAlan Wright  */
64829bd2886SAlan Wright static uint32_t
smb_dcache_lock(int mode)64929bd2886SAlan Wright smb_dcache_lock(int mode)
65029bd2886SAlan Wright {
65129bd2886SAlan Wright 	(void) mutex_lock(&smb_dcache.dc_mtx);
65229bd2886SAlan Wright 	switch (smb_dcache.dc_state) {
65329bd2886SAlan Wright 	case SMB_DCACHE_STATE_NONE:
65429bd2886SAlan Wright 	case SMB_DCACHE_STATE_DESTROYING:
65529bd2886SAlan Wright 		(void) mutex_unlock(&smb_dcache.dc_mtx);
65629bd2886SAlan Wright 		return (SMB_DOMAIN_INTERNAL_ERR);
65729bd2886SAlan Wright 
65829bd2886SAlan Wright 	case SMB_DCACHE_STATE_UPDATING:
65929bd2886SAlan Wright 		if (mode == SMB_DCACHE_RDLOCK) {
66029bd2886SAlan Wright 			/*
66129bd2886SAlan Wright 			 * Read operations should wait until the update
66229bd2886SAlan Wright 			 * is completed.
66329bd2886SAlan Wright 			 */
66429bd2886SAlan Wright 			if (!smb_dcache_wait()) {
66529bd2886SAlan Wright 				(void) mutex_unlock(&smb_dcache.dc_mtx);
66629bd2886SAlan Wright 				return (SMB_DOMAIN_INTERNAL_ERR);
66729bd2886SAlan Wright 			}
66829bd2886SAlan Wright 		}
66929bd2886SAlan Wright 
67029bd2886SAlan Wright 	default:
67129bd2886SAlan Wright 		smb_dcache.dc_nops++;
67229bd2886SAlan Wright 		break;
67329bd2886SAlan Wright 	}
67429bd2886SAlan Wright 	(void) mutex_unlock(&smb_dcache.dc_mtx);
67529bd2886SAlan Wright 
67629bd2886SAlan Wright 	/*
67729bd2886SAlan Wright 	 * Lock has to be taken outside the mutex otherwise
67829bd2886SAlan Wright 	 * there could be a deadlock
67929bd2886SAlan Wright 	 */
68029bd2886SAlan Wright 	if (mode == SMB_DCACHE_RDLOCK)
68129bd2886SAlan Wright 		(void) rw_rdlock(&smb_dcache.dc_cache_lck);
68229bd2886SAlan Wright 	else
68329bd2886SAlan Wright 		(void) rw_wrlock(&smb_dcache.dc_cache_lck);
68429bd2886SAlan Wright 
68529bd2886SAlan Wright 	return (SMB_DOMAIN_SUCCESS);
68629bd2886SAlan Wright }
68729bd2886SAlan Wright 
68829bd2886SAlan Wright /*
68929bd2886SAlan Wright  * Decrement the number of inflight operations and then unlock.
69029bd2886SAlan Wright  */
69129bd2886SAlan Wright static void
smb_dcache_unlock(void)69229bd2886SAlan Wright smb_dcache_unlock(void)
69329bd2886SAlan Wright {
69429bd2886SAlan Wright 	(void) mutex_lock(&smb_dcache.dc_mtx);
69529bd2886SAlan Wright 	assert(smb_dcache.dc_nops > 0);
69629bd2886SAlan Wright 	smb_dcache.dc_nops--;
69729bd2886SAlan Wright 	(void) cond_broadcast(&smb_dcache.dc_cv);
69829bd2886SAlan Wright 	(void) mutex_unlock(&smb_dcache.dc_mtx);
69929bd2886SAlan Wright 
70029bd2886SAlan Wright 	(void) rw_unlock(&smb_dcache.dc_cache_lck);
70129bd2886SAlan Wright }
70229bd2886SAlan Wright 
70329bd2886SAlan Wright static uint32_t
smb_dcache_add(smb_domain_t * di)704a0aa776eSAlan Wright smb_dcache_add(smb_domain_t *di)
70529bd2886SAlan Wright {
706a0aa776eSAlan Wright 	smb_domain_t *dcnode;
70729bd2886SAlan Wright 
708a0aa776eSAlan Wright 	if ((dcnode = malloc(sizeof (smb_domain_t))) == NULL)
70929bd2886SAlan Wright 		return (SMB_DOMAIN_NO_MEMORY);
71029bd2886SAlan Wright 
71129bd2886SAlan Wright 	*dcnode = *di;
71229bd2886SAlan Wright 	dcnode->di_binsid = smb_sid_fromstr(dcnode->di_sid);
71329bd2886SAlan Wright 	if (dcnode->di_binsid == NULL) {
71429bd2886SAlan Wright 		free(dcnode);
71529bd2886SAlan Wright 		return (SMB_DOMAIN_NO_MEMORY);
71629bd2886SAlan Wright 	}
71729bd2886SAlan Wright 
71829bd2886SAlan Wright 	list_insert_tail(&smb_dcache.dc_cache, dcnode);
71929bd2886SAlan Wright 	return (SMB_DOMAIN_SUCCESS);
72029bd2886SAlan Wright }
72129bd2886SAlan Wright 
72229bd2886SAlan Wright static void
smb_dcache_remove(smb_domain_t * di)723a0aa776eSAlan Wright smb_dcache_remove(smb_domain_t *di)
72429bd2886SAlan Wright {
72529bd2886SAlan Wright 	list_remove(&smb_dcache.dc_cache, di);
72629bd2886SAlan Wright 	smb_sid_free(di->di_binsid);
72729bd2886SAlan Wright 	free(di);
72829bd2886SAlan Wright }
72929bd2886SAlan Wright 
73029bd2886SAlan Wright static void
smb_dcache_setdc(const smb_dcinfo_t * dci)731*b3700b07SGordon Ross smb_dcache_setdc(const smb_dcinfo_t *dci)
73229bd2886SAlan Wright {
73329bd2886SAlan Wright 	(void) mutex_lock(&smb_dcache.dc_mtx);
734*b3700b07SGordon Ross 	smb_dcache.dc_dci = *dci; /* struct assignment! */
73529bd2886SAlan Wright 	(void) mutex_unlock(&smb_dcache.dc_mtx);
73629bd2886SAlan Wright }
73729bd2886SAlan Wright 
738*b3700b07SGordon Ross /*
739*b3700b07SGordon Ross  * Return B_TRUE if we have DC information.
740*b3700b07SGordon Ross  */
741*b3700b07SGordon Ross static boolean_t
smb_dcache_getdc(smb_dcinfo_t * dci)742*b3700b07SGordon Ross smb_dcache_getdc(smb_dcinfo_t *dci)
74329bd2886SAlan Wright {
74429bd2886SAlan Wright 	(void) mutex_lock(&smb_dcache.dc_mtx);
745*b3700b07SGordon Ross 	*dci = smb_dcache.dc_dci; /* struct assignment! */
74629bd2886SAlan Wright 	(void) mutex_unlock(&smb_dcache.dc_mtx);
747*b3700b07SGordon Ross 	return (dci->dc_name[0] != '\0');
74829bd2886SAlan Wright }
74929bd2886SAlan Wright 
750a0aa776eSAlan Wright /*
751a0aa776eSAlan Wright  * Waits for SMB_DCACHE_UPDATE_WAIT seconds if cache is in
752a0aa776eSAlan Wright  * UPDATING state. Upon wake up returns true if cache is
753a0aa776eSAlan Wright  * ready to be used, otherwise it returns false.
754a0aa776eSAlan Wright  */
75529bd2886SAlan Wright static boolean_t
smb_dcache_wait(void)75629bd2886SAlan Wright smb_dcache_wait(void)
75729bd2886SAlan Wright {
75829bd2886SAlan Wright 	timestruc_t to;
75929bd2886SAlan Wright 	int err;
76029bd2886SAlan Wright 
76129bd2886SAlan Wright 	to.tv_sec = SMB_DCACHE_UPDATE_WAIT;
76229bd2886SAlan Wright 	to.tv_nsec = 0;
76329bd2886SAlan Wright 	while (smb_dcache.dc_state == SMB_DCACHE_STATE_UPDATING) {
76429bd2886SAlan Wright 		err = cond_reltimedwait(&smb_dcache.dc_cv,
76529bd2886SAlan Wright 		    &smb_dcache.dc_mtx, &to);
76629bd2886SAlan Wright 		if (err == ETIME)
76729bd2886SAlan Wright 			break;
76829bd2886SAlan Wright 	}
76929bd2886SAlan Wright 
77029bd2886SAlan Wright 	return (smb_dcache.dc_state == SMB_DCACHE_STATE_READY);
77129bd2886SAlan Wright }
77229bd2886SAlan Wright 
773a0aa776eSAlan Wright /*
774a0aa776eSAlan Wright  * Transfers the cache into UPDATING state, this will ensure
775a0aa776eSAlan Wright  * any read access to the cache will be stalled until the
776a0aa776eSAlan Wright  * update is finished. This is to avoid providing incomplete,
777a0aa776eSAlan Wright  * inconsistent or stale information.
778a0aa776eSAlan Wright  *
779a0aa776eSAlan Wright  * If another thread is already updating the cache, other
780a0aa776eSAlan Wright  * callers will wait until cache is no longer in UPDATING
781a0aa776eSAlan Wright  * state. The return code is decided based on the new
782a0aa776eSAlan Wright  * state of the cache.
783a0aa776eSAlan Wright  */
784a0aa776eSAlan Wright static uint32_t
smb_dcache_updating(void)78529bd2886SAlan Wright smb_dcache_updating(void)
78629bd2886SAlan Wright {
787a0aa776eSAlan Wright 	uint32_t rc;
788a0aa776eSAlan Wright 
78929bd2886SAlan Wright 	(void) mutex_lock(&smb_dcache.dc_mtx);
790a0aa776eSAlan Wright 	switch (smb_dcache.dc_state) {
791a0aa776eSAlan Wright 	case SMB_DCACHE_STATE_READY:
79229bd2886SAlan Wright 		smb_dcache.dc_state = SMB_DCACHE_STATE_UPDATING;
793a0aa776eSAlan Wright 		rc = SMB_DOMAIN_SUCCESS;
794a0aa776eSAlan Wright 		break;
795a0aa776eSAlan Wright 
796a0aa776eSAlan Wright 	case SMB_DCACHE_STATE_UPDATING:
797a0aa776eSAlan Wright 		while (smb_dcache.dc_state == SMB_DCACHE_STATE_UPDATING)
798a0aa776eSAlan Wright 			(void) cond_wait(&smb_dcache.dc_cv,
799a0aa776eSAlan Wright 			    &smb_dcache.dc_mtx);
800a0aa776eSAlan Wright 
801a0aa776eSAlan Wright 		if (smb_dcache.dc_state == SMB_DCACHE_STATE_READY) {
802a0aa776eSAlan Wright 			smb_dcache.dc_state = SMB_DCACHE_STATE_UPDATING;
803a0aa776eSAlan Wright 			rc = SMB_DOMAIN_SUCCESS;
804a0aa776eSAlan Wright 		} else {
805a0aa776eSAlan Wright 			rc = SMB_DOMAIN_NO_CACHE;
806a0aa776eSAlan Wright 		}
807a0aa776eSAlan Wright 		break;
808a0aa776eSAlan Wright 
809a0aa776eSAlan Wright 	case SMB_DCACHE_STATE_NONE:
810a0aa776eSAlan Wright 	case SMB_DCACHE_STATE_DESTROYING:
811a0aa776eSAlan Wright 		rc = SMB_DOMAIN_NO_CACHE;
812a0aa776eSAlan Wright 		break;
813a0aa776eSAlan Wright 
814a0aa776eSAlan Wright 	default:
815a0aa776eSAlan Wright 		break;
81629bd2886SAlan Wright 	}
81729bd2886SAlan Wright 
818a0aa776eSAlan Wright 	(void) mutex_unlock(&smb_dcache.dc_mtx);
819a0aa776eSAlan Wright 	return (rc);
820a0aa776eSAlan Wright }
821a0aa776eSAlan Wright 
822a0aa776eSAlan Wright /*
823a0aa776eSAlan Wright  * Transfers the cache from UPDATING to READY state.
824a0aa776eSAlan Wright  *
825a0aa776eSAlan Wright  * Nothing will happen if the cache is no longer available
826a0aa776eSAlan Wright  * or it is being destroyed.
827a0aa776eSAlan Wright  */
82829bd2886SAlan Wright static void
smb_dcache_ready(void)82929bd2886SAlan Wright smb_dcache_ready(void)
83029bd2886SAlan Wright {
83129bd2886SAlan Wright 	(void) mutex_lock(&smb_dcache.dc_mtx);
832a0aa776eSAlan Wright 	switch (smb_dcache.dc_state) {
833a0aa776eSAlan Wright 	case SMB_DCACHE_STATE_UPDATING:
83429bd2886SAlan Wright 		smb_dcache.dc_state = SMB_DCACHE_STATE_READY;
835a0aa776eSAlan Wright 		(void) cond_broadcast(&smb_dcache.dc_cv);
836a0aa776eSAlan Wright 		break;
837a0aa776eSAlan Wright 
838a0aa776eSAlan Wright 	case SMB_DCACHE_STATE_NONE:
839a0aa776eSAlan Wright 	case SMB_DCACHE_STATE_DESTROYING:
840a0aa776eSAlan Wright 		break;
841a0aa776eSAlan Wright 
842a0aa776eSAlan Wright 	default:
84329bd2886SAlan Wright 		assert(0);
844a0aa776eSAlan Wright 	}
84529bd2886SAlan Wright 	(void) mutex_unlock(&smb_dcache.dc_mtx);
84629bd2886SAlan Wright }
847