xref: /titanic_44/usr/src/lib/smbsrv/libsmb/common/smb_domain.c (revision 380acbbe9da7dc2cbab5b6db169ec6968dd927fa)
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.
24*380acbbeSGordon Ross  *
25*380acbbeSGordon Ross  * Copyright 2011 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;
7729bd2886SAlan Wright 	char		dc_server[MAXHOSTNAMELEN];
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 *);
9329bd2886SAlan Wright static void smb_dcache_getdc(char *, size_t);
9429bd2886SAlan Wright static void smb_dcache_setdc(char *);
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 {
29629bd2886SAlan Wright 	boolean_t success;
297da6c28aaSamw 
298a0aa776eSAlan Wright 	success = smb_domain_lookup_type(SMB_DOMAIN_PRIMARY, &dxi->d_primary);
29929bd2886SAlan Wright 	if (success)
300a0aa776eSAlan Wright 		smb_dcache_getdc(dxi->d_dc, sizeof (dxi->d_dc));
301da6c28aaSamw 
30229bd2886SAlan Wright 	return (success);
303da6c28aaSamw }
304da6c28aaSamw 
30529bd2886SAlan Wright /*
306*380acbbeSGordon Ross  * Get the name of the current DC (if any)
307*380acbbeSGordon Ross  * Does NOT block.
308*380acbbeSGordon Ross  */
309*380acbbeSGordon Ross void
smb_domain_current_dc(char * buf,size_t len)310*380acbbeSGordon Ross smb_domain_current_dc(char *buf, size_t len)
311*380acbbeSGordon Ross {
312*380acbbeSGordon Ross 	smb_dcache_getdc(buf, len);
313*380acbbeSGordon Ross }
314*380acbbeSGordon Ross 
315*380acbbeSGordon Ross /*
31629bd2886SAlan Wright  * Transfer the cache to updating state.
31729bd2886SAlan Wright  * In this state any request for reading the cache would
31829bd2886SAlan Wright  * be blocked until the update is finished.
31929bd2886SAlan Wright  */
320a0aa776eSAlan Wright uint32_t
smb_domain_start_update(void)321a0aa776eSAlan Wright smb_domain_start_update(void)
322da6c28aaSamw {
323a0aa776eSAlan Wright 	return (smb_dcache_updating());
32429bd2886SAlan Wright }
325da6c28aaSamw 
32629bd2886SAlan Wright /*
32729bd2886SAlan Wright  * Transfer the cache from updating to ready state.
32829bd2886SAlan Wright  */
32929bd2886SAlan Wright void
smb_domain_end_update(void)330a0aa776eSAlan Wright smb_domain_end_update(void)
33129bd2886SAlan Wright {
33229bd2886SAlan Wright 	smb_dcache_ready();
33329bd2886SAlan Wright }
33429bd2886SAlan Wright 
33529bd2886SAlan Wright /*
33629bd2886SAlan Wright  * Updates the cache with given information for the primary
33729bd2886SAlan Wright  * domain, possible trusted domains and the selected domain
33829bd2886SAlan Wright  * controller.
33929bd2886SAlan Wright  *
34029bd2886SAlan Wright  * Before adding the new entries existing entries of type
34129bd2886SAlan Wright  * primary and trusted will be removed from cache.
34229bd2886SAlan Wright  */
34329bd2886SAlan Wright void
smb_domain_update(smb_domainex_t * dxi)344a0aa776eSAlan Wright smb_domain_update(smb_domainex_t *dxi)
34529bd2886SAlan Wright {
346a0aa776eSAlan Wright 	smb_domain_t *dcnode;
34729bd2886SAlan Wright 	int i;
34829bd2886SAlan Wright 
34929bd2886SAlan Wright 	if (smb_dcache_lock(SMB_DCACHE_WRLOCK) != SMB_DOMAIN_SUCCESS)
350da6c28aaSamw 		return;
35129bd2886SAlan Wright 
35229bd2886SAlan Wright 	dcnode = list_head(&smb_dcache.dc_cache);
35329bd2886SAlan Wright 	while (dcnode) {
354a0aa776eSAlan Wright 		if ((dcnode->di_type == SMB_DOMAIN_PRIMARY) ||
355a0aa776eSAlan Wright 		    (dcnode->di_type == SMB_DOMAIN_TRUSTED)) {
35629bd2886SAlan Wright 			smb_dcache_remove(dcnode);
35729bd2886SAlan Wright 			dcnode = list_head(&smb_dcache.dc_cache);
35829bd2886SAlan Wright 		} else {
35929bd2886SAlan Wright 			dcnode = list_next(&smb_dcache.dc_cache, dcnode);
360da6c28aaSamw 		}
361da6c28aaSamw 	}
36229bd2886SAlan Wright 
363a0aa776eSAlan Wright 	if (smb_dcache_add(&dxi->d_primary) == SMB_DOMAIN_SUCCESS) {
364a0aa776eSAlan Wright 		for (i = 0; i < dxi->d_trusted.td_num; i++)
365a0aa776eSAlan Wright 			(void) smb_dcache_add(&dxi->d_trusted.td_domains[i]);
36629bd2886SAlan Wright 
367a0aa776eSAlan Wright 		smb_dcache_setdc(dxi->d_dc);
36829bd2886SAlan Wright 	}
36929bd2886SAlan Wright 
37029bd2886SAlan Wright 	smb_dcache_unlock();
371da6c28aaSamw }
37289dc44ceSjose borrego 
37389dc44ceSjose borrego /*
37489dc44ceSjose borrego  * Write the list of domains to /var/run/smb/domains.
37589dc44ceSjose borrego  */
37689dc44ceSjose borrego void
smb_domain_save(void)377a0aa776eSAlan Wright smb_domain_save(void)
37889dc44ceSjose borrego {
37989dc44ceSjose borrego 	char		fname[MAXPATHLEN];
38089dc44ceSjose borrego 	char		tag;
381a0aa776eSAlan Wright 	smb_domain_t	*domain;
38289dc44ceSjose borrego 	FILE		*fp;
38389dc44ceSjose borrego 	struct passwd	*pwd;
38489dc44ceSjose borrego 	struct group	*grp;
38589dc44ceSjose borrego 	uid_t		uid;
38689dc44ceSjose borrego 	gid_t		gid;
38789dc44ceSjose borrego 
38889dc44ceSjose borrego 	(void) snprintf(fname, MAXPATHLEN, "%s/%s",
38989dc44ceSjose borrego 	    SMB_VARRUN_DIR, SMB_DOMAINS_FILE);
39089dc44ceSjose borrego 
39189dc44ceSjose borrego 	if ((fp = fopen(fname, "w")) == NULL)
39289dc44ceSjose borrego 		return;
39389dc44ceSjose borrego 
39489dc44ceSjose borrego 	pwd = getpwnam("root");
39589dc44ceSjose borrego 	grp = getgrnam("sys");
39689dc44ceSjose borrego 	uid = (pwd == NULL) ? 0 : pwd->pw_uid;
39789dc44ceSjose borrego 	gid = (grp == NULL) ? 3 : grp->gr_gid;
39889dc44ceSjose borrego 
39989dc44ceSjose borrego 	(void) lockf(fileno(fp), F_LOCK, 0);
40089dc44ceSjose borrego 	(void) fchmod(fileno(fp), 0600);
40189dc44ceSjose borrego 	(void) fchown(fileno(fp), uid, gid);
40289dc44ceSjose borrego 
40329bd2886SAlan Wright 	if (smb_dcache_lock(SMB_DCACHE_RDLOCK) != SMB_DOMAIN_SUCCESS)
40429bd2886SAlan Wright 		return;
40589dc44ceSjose borrego 
40629bd2886SAlan Wright 	domain = list_head(&smb_dcache.dc_cache);
40789dc44ceSjose borrego 	while (domain) {
40829bd2886SAlan Wright 		switch (domain->di_type) {
409a0aa776eSAlan Wright 		case SMB_DOMAIN_PRIMARY:
41089dc44ceSjose borrego 			tag = '*';
41189dc44ceSjose borrego 			break;
41289dc44ceSjose borrego 
413a0aa776eSAlan Wright 		case SMB_DOMAIN_TRUSTED:
414a0aa776eSAlan Wright 		case SMB_DOMAIN_UNTRUSTED:
41589dc44ceSjose borrego 			tag = '-';
41689dc44ceSjose borrego 			break;
41789dc44ceSjose borrego 
418a0aa776eSAlan Wright 		case SMB_DOMAIN_LOCAL:
41989dc44ceSjose borrego 			tag = '.';
42089dc44ceSjose borrego 			break;
42189dc44ceSjose borrego 		default:
42229bd2886SAlan Wright 			domain = list_next(&smb_dcache.dc_cache, domain);
42389dc44ceSjose borrego 			continue;
42489dc44ceSjose borrego 		}
42589dc44ceSjose borrego 
42689dc44ceSjose borrego 		(void) fprintf(fp, "[%c] [%s] [%s]\n",
42729bd2886SAlan Wright 		    tag, domain->di_nbname, domain->di_sid);
42889dc44ceSjose borrego 
42929bd2886SAlan Wright 		domain = list_next(&smb_dcache.dc_cache, domain);
43089dc44ceSjose borrego 	}
43189dc44ceSjose borrego 
43229bd2886SAlan Wright 	smb_dcache_unlock();
43389dc44ceSjose borrego 	(void) lockf(fileno(fp), F_ULOCK, 0);
43489dc44ceSjose borrego 	(void) fclose(fp);
43589dc44ceSjose borrego }
43689dc44ceSjose borrego 
43789dc44ceSjose borrego /*
43889dc44ceSjose borrego  * List the domains in /var/run/smb/domains.
43989dc44ceSjose borrego  */
44089dc44ceSjose borrego void
smb_domain_show(void)441a0aa776eSAlan Wright smb_domain_show(void)
44289dc44ceSjose borrego {
44389dc44ceSjose borrego 	char buf[MAXPATHLEN];
44489dc44ceSjose borrego 	char *p;
44589dc44ceSjose borrego 	FILE *fp;
44689dc44ceSjose borrego 
44789dc44ceSjose borrego 	(void) snprintf(buf, MAXPATHLEN, "%s/%s",
44889dc44ceSjose borrego 	    SMB_VARRUN_DIR, SMB_DOMAINS_FILE);
44989dc44ceSjose borrego 
45089dc44ceSjose borrego 	if ((fp = fopen(buf, "r")) != NULL) {
45189dc44ceSjose borrego 		(void) lockf(fileno(fp), F_LOCK, 0);
45289dc44ceSjose borrego 
45389dc44ceSjose borrego 		while (fgets(buf, MAXPATHLEN, fp) != NULL) {
45489dc44ceSjose borrego 			if ((p = strchr(buf, '\n')) != NULL)
45589dc44ceSjose borrego 				*p = '\0';
45689dc44ceSjose borrego 			(void) printf("%s\n", buf);
45789dc44ceSjose borrego 		}
45889dc44ceSjose borrego 
45989dc44ceSjose borrego 		(void) lockf(fileno(fp), F_ULOCK, 0);
46089dc44ceSjose borrego 		(void) fclose(fp);
46189dc44ceSjose borrego 	}
46289dc44ceSjose borrego }
46389dc44ceSjose borrego 
46429bd2886SAlan Wright void
smb_domain_set_basic_info(char * sid,char * nb_domain,char * fq_domain,smb_domain_t * di)465a0aa776eSAlan Wright smb_domain_set_basic_info(char *sid, char *nb_domain, char *fq_domain,
466a0aa776eSAlan Wright     smb_domain_t *di)
46729bd2886SAlan Wright {
46829bd2886SAlan Wright 	if (sid == NULL || nb_domain == NULL || fq_domain == NULL ||
46929bd2886SAlan Wright 	    di == NULL)
47029bd2886SAlan Wright 		return;
47129bd2886SAlan Wright 
47229bd2886SAlan Wright 	(void) strlcpy(di->di_sid, sid, SMB_SID_STRSZ);
47329bd2886SAlan Wright 	(void) strlcpy(di->di_nbname, nb_domain, NETBIOS_NAME_SZ);
474bbf6f00cSJordan Brown 	(void) smb_strupr(di->di_nbname);
47529bd2886SAlan Wright 	(void) strlcpy(di->di_fqname, fq_domain, MAXHOSTNAMELEN);
47629bd2886SAlan Wright 	di->di_binsid = NULL;
47729bd2886SAlan Wright }
47829bd2886SAlan Wright 
47929bd2886SAlan Wright void
smb_domain_set_dns_info(char * sid,char * nb_domain,char * fq_domain,char * forest,char * guid,smb_domain_t * di)480a0aa776eSAlan Wright smb_domain_set_dns_info(char *sid, char *nb_domain, char *fq_domain,
481a0aa776eSAlan Wright     char *forest, char *guid, smb_domain_t *di)
48229bd2886SAlan Wright {
48329bd2886SAlan Wright 	if (di == NULL || forest == NULL || guid == NULL)
48429bd2886SAlan Wright 		return;
48529bd2886SAlan Wright 
486a0aa776eSAlan Wright 	smb_domain_set_basic_info(sid, nb_domain, fq_domain, di);
48729bd2886SAlan Wright 	(void) strlcpy(di->di_u.di_dns.ddi_forest, forest, MAXHOSTNAMELEN);
48829bd2886SAlan Wright 	(void) strlcpy(di->di_u.di_dns.ddi_guid, guid,
48929bd2886SAlan Wright 	    UUID_PRINTABLE_STRING_LENGTH);
49029bd2886SAlan Wright }
49129bd2886SAlan Wright 
49229bd2886SAlan 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)493a0aa776eSAlan Wright smb_domain_set_trust_info(char *sid, char *nb_domain, char *fq_domain,
49429bd2886SAlan Wright     uint32_t trust_dir, uint32_t trust_type, uint32_t trust_attrs,
495a0aa776eSAlan Wright     smb_domain_t *di)
49629bd2886SAlan Wright {
49729bd2886SAlan Wright 	smb_domain_trust_t *ti;
49829bd2886SAlan Wright 
49929bd2886SAlan Wright 	if (di == NULL)
50029bd2886SAlan Wright 		return;
50129bd2886SAlan Wright 
502a0aa776eSAlan Wright 	di->di_type = SMB_DOMAIN_TRUSTED;
50329bd2886SAlan Wright 	ti = &di->di_u.di_trust;
504a0aa776eSAlan Wright 	smb_domain_set_basic_info(sid, nb_domain, fq_domain, di);
50529bd2886SAlan Wright 	ti->dti_trust_direction = trust_dir;
50629bd2886SAlan Wright 	ti->dti_trust_type = trust_type;
50729bd2886SAlan Wright 	ti->dti_trust_attrs = trust_attrs;
50829bd2886SAlan Wright }
50929bd2886SAlan Wright 
51089dc44ceSjose borrego /*
51189dc44ceSjose borrego  * Remove the /var/run/smb/domains file.
51289dc44ceSjose borrego  */
51329bd2886SAlan Wright static void
smb_domain_unlink(void)514a0aa776eSAlan Wright smb_domain_unlink(void)
51589dc44ceSjose borrego {
51689dc44ceSjose borrego 	char fname[MAXPATHLEN];
51789dc44ceSjose borrego 
51889dc44ceSjose borrego 	(void) snprintf(fname, MAXPATHLEN, "%s/%s",
51989dc44ceSjose borrego 	    SMB_VARRUN_DIR, SMB_DOMAINS_FILE);
52089dc44ceSjose borrego 	(void) unlink(fname);
52189dc44ceSjose borrego }
52229bd2886SAlan Wright 
52329bd2886SAlan Wright /*
52429bd2886SAlan Wright  * Add an entry for the local domain to the domain cache
52529bd2886SAlan Wright  */
52629bd2886SAlan Wright static uint32_t
smb_domain_add_local(void)527a0aa776eSAlan Wright smb_domain_add_local(void)
52829bd2886SAlan Wright {
52929bd2886SAlan Wright 	char *lsidstr;
53029bd2886SAlan Wright 	char hostname[NETBIOS_NAME_SZ];
53129bd2886SAlan Wright 	char fq_name[MAXHOSTNAMELEN];
532a0aa776eSAlan Wright 	smb_domain_t di;
53329bd2886SAlan Wright 
53429bd2886SAlan Wright 	if ((lsidstr = smb_config_get_localsid()) == NULL)
53529bd2886SAlan Wright 		return (SMB_DOMAIN_NOMACHINE_SID);
53629bd2886SAlan Wright 
53729bd2886SAlan Wright 	if (smb_getnetbiosname(hostname, NETBIOS_NAME_SZ) != 0) {
53829bd2886SAlan Wright 		free(lsidstr);
53929bd2886SAlan Wright 		return (SMB_DOMAIN_NOMACHINE_SID);
54029bd2886SAlan Wright 	}
54129bd2886SAlan Wright 
54229bd2886SAlan Wright 	*fq_name = '\0';
54329bd2886SAlan Wright 	(void) smb_getfqhostname(fq_name, MAXHOSTNAMELEN);
544a0aa776eSAlan Wright 	smb_domain_set_basic_info(lsidstr, hostname, fq_name, &di);
545a0aa776eSAlan Wright 	(void) smb_domain_add(SMB_DOMAIN_LOCAL, &di);
54629bd2886SAlan Wright 
54729bd2886SAlan Wright 	free(lsidstr);
54829bd2886SAlan Wright 	return (SMB_DOMAIN_SUCCESS);
54929bd2886SAlan Wright }
55029bd2886SAlan Wright 
55129bd2886SAlan Wright /*
55229bd2886SAlan Wright  * Add an entry for the primary domain to the domain cache
55329bd2886SAlan Wright  */
55429bd2886SAlan Wright static uint32_t
smb_domain_add_primary(uint32_t secmode)555a0aa776eSAlan Wright smb_domain_add_primary(uint32_t secmode)
55629bd2886SAlan Wright {
55729bd2886SAlan Wright 	char sidstr[SMB_SID_STRSZ];
55829bd2886SAlan Wright 	char fq_name[MAXHOSTNAMELEN];
55929bd2886SAlan Wright 	char nb_name[NETBIOS_NAME_SZ];
560a0aa776eSAlan Wright 	smb_domain_t di;
56129bd2886SAlan Wright 	int rc;
56229bd2886SAlan Wright 
56329bd2886SAlan Wright 	if (secmode != SMB_SECMODE_DOMAIN)
56429bd2886SAlan Wright 		return (SMB_DOMAIN_SUCCESS);
56529bd2886SAlan Wright 
56629bd2886SAlan Wright 	rc = smb_config_getstr(SMB_CI_DOMAIN_SID, sidstr, sizeof (sidstr));
56729bd2886SAlan Wright 	if (rc != SMBD_SMF_OK)
56829bd2886SAlan Wright 		return (SMB_DOMAIN_NODOMAIN_SID);
56929bd2886SAlan Wright 
57029bd2886SAlan Wright 	rc = smb_config_getstr(SMB_CI_DOMAIN_NAME, nb_name, NETBIOS_NAME_SZ);
57129bd2886SAlan Wright 	if ((rc != SMBD_SMF_OK) || (*nb_name == '\0'))
57229bd2886SAlan Wright 		return (SMB_DOMAIN_NODOMAIN_NAME);
57329bd2886SAlan Wright 
57429bd2886SAlan Wright 	(void) smb_getfqdomainname(fq_name, MAXHOSTNAMELEN);
575a0aa776eSAlan Wright 	smb_domain_set_basic_info(sidstr, nb_name, fq_name, &di);
576a0aa776eSAlan Wright 	(void) smb_domain_add(SMB_DOMAIN_PRIMARY, &di);
57729bd2886SAlan Wright 	return (SMB_DOMAIN_SUCCESS);
57829bd2886SAlan Wright }
57929bd2886SAlan Wright 
58029bd2886SAlan Wright /*
58129bd2886SAlan Wright  * Initialize the domain cache.
58229bd2886SAlan Wright  * This function does not populate the cache.
58329bd2886SAlan Wright  */
58429bd2886SAlan Wright static void
smb_dcache_create(void)58529bd2886SAlan Wright smb_dcache_create(void)
58629bd2886SAlan Wright {
58729bd2886SAlan Wright 	(void) mutex_lock(&smb_dcache.dc_mtx);
58829bd2886SAlan Wright 	if (smb_dcache.dc_state != SMB_DCACHE_STATE_NONE) {
58929bd2886SAlan Wright 		(void) mutex_unlock(&smb_dcache.dc_mtx);
59029bd2886SAlan Wright 		return;
59129bd2886SAlan Wright 	}
59229bd2886SAlan Wright 
593a0aa776eSAlan Wright 	list_create(&smb_dcache.dc_cache, sizeof (smb_domain_t),
594a0aa776eSAlan Wright 	    offsetof(smb_domain_t, di_lnd));
59529bd2886SAlan Wright 
59629bd2886SAlan Wright 	smb_dcache.dc_nops = 0;
59729bd2886SAlan Wright 	*smb_dcache.dc_server = '\0';
59829bd2886SAlan Wright 	smb_dcache.dc_state = SMB_DCACHE_STATE_READY;
59929bd2886SAlan Wright 	(void) mutex_unlock(&smb_dcache.dc_mtx);
60029bd2886SAlan Wright }
60129bd2886SAlan Wright 
60229bd2886SAlan Wright /*
60329bd2886SAlan Wright  * Removes and frees all the cache entries
60429bd2886SAlan Wright  */
60529bd2886SAlan Wright static void
smb_dcache_flush(void)60629bd2886SAlan Wright smb_dcache_flush(void)
60729bd2886SAlan Wright {
608a0aa776eSAlan Wright 	smb_domain_t *di;
60929bd2886SAlan Wright 
61029bd2886SAlan Wright 	(void) rw_wrlock(&smb_dcache.dc_cache_lck);
61129bd2886SAlan Wright 	while ((di = list_head(&smb_dcache.dc_cache)) != NULL)
61229bd2886SAlan Wright 		smb_dcache_remove(di);
61329bd2886SAlan Wright 	(void) rw_unlock(&smb_dcache.dc_cache_lck);
61429bd2886SAlan Wright }
61529bd2886SAlan Wright 
61629bd2886SAlan Wright /*
61729bd2886SAlan Wright  * Destroys the cache.
61829bd2886SAlan Wright  */
61929bd2886SAlan Wright static void
smb_dcache_destroy(void)62029bd2886SAlan Wright smb_dcache_destroy(void)
62129bd2886SAlan Wright {
62229bd2886SAlan Wright 	(void) mutex_lock(&smb_dcache.dc_mtx);
62329bd2886SAlan Wright 	if ((smb_dcache.dc_state == SMB_DCACHE_STATE_READY) ||
62429bd2886SAlan Wright 	    (smb_dcache.dc_state == SMB_DCACHE_STATE_UPDATING)) {
62529bd2886SAlan Wright 		smb_dcache.dc_state = SMB_DCACHE_STATE_DESTROYING;
62629bd2886SAlan Wright 		while (smb_dcache.dc_nops > 0)
62729bd2886SAlan Wright 			(void) cond_wait(&smb_dcache.dc_cv,
62829bd2886SAlan Wright 			    &smb_dcache.dc_mtx);
62929bd2886SAlan Wright 
63029bd2886SAlan Wright 		smb_dcache_flush();
63129bd2886SAlan Wright 		list_destroy(&smb_dcache.dc_cache);
63229bd2886SAlan Wright 
63329bd2886SAlan Wright 		smb_dcache.dc_state = SMB_DCACHE_STATE_NONE;
63429bd2886SAlan Wright 	}
63529bd2886SAlan Wright 	(void) mutex_unlock(&smb_dcache.dc_mtx);
63629bd2886SAlan Wright }
63729bd2886SAlan Wright 
63829bd2886SAlan Wright /*
63929bd2886SAlan Wright  * Lock the cache with the specified mode.
64029bd2886SAlan Wright  * If the cache is in updating state and a read lock is
64129bd2886SAlan Wright  * requested, the lock won't be granted until either the
64229bd2886SAlan Wright  * update is finished or SMB_DCACHE_UPDATE_WAIT has passed.
64329bd2886SAlan Wright  *
64429bd2886SAlan Wright  * Whenever a lock is granted, the number of inflight cache
64529bd2886SAlan Wright  * operations is incremented.
64629bd2886SAlan Wright  */
64729bd2886SAlan Wright static uint32_t
smb_dcache_lock(int mode)64829bd2886SAlan Wright smb_dcache_lock(int mode)
64929bd2886SAlan Wright {
65029bd2886SAlan Wright 	(void) mutex_lock(&smb_dcache.dc_mtx);
65129bd2886SAlan Wright 	switch (smb_dcache.dc_state) {
65229bd2886SAlan Wright 	case SMB_DCACHE_STATE_NONE:
65329bd2886SAlan Wright 	case SMB_DCACHE_STATE_DESTROYING:
65429bd2886SAlan Wright 		(void) mutex_unlock(&smb_dcache.dc_mtx);
65529bd2886SAlan Wright 		return (SMB_DOMAIN_INTERNAL_ERR);
65629bd2886SAlan Wright 
65729bd2886SAlan Wright 	case SMB_DCACHE_STATE_UPDATING:
65829bd2886SAlan Wright 		if (mode == SMB_DCACHE_RDLOCK) {
65929bd2886SAlan Wright 			/*
66029bd2886SAlan Wright 			 * Read operations should wait until the update
66129bd2886SAlan Wright 			 * is completed.
66229bd2886SAlan Wright 			 */
66329bd2886SAlan Wright 			if (!smb_dcache_wait()) {
66429bd2886SAlan Wright 				(void) mutex_unlock(&smb_dcache.dc_mtx);
66529bd2886SAlan Wright 				return (SMB_DOMAIN_INTERNAL_ERR);
66629bd2886SAlan Wright 			}
66729bd2886SAlan Wright 		}
66829bd2886SAlan Wright 
66929bd2886SAlan Wright 	default:
67029bd2886SAlan Wright 		smb_dcache.dc_nops++;
67129bd2886SAlan Wright 		break;
67229bd2886SAlan Wright 	}
67329bd2886SAlan Wright 	(void) mutex_unlock(&smb_dcache.dc_mtx);
67429bd2886SAlan Wright 
67529bd2886SAlan Wright 	/*
67629bd2886SAlan Wright 	 * Lock has to be taken outside the mutex otherwise
67729bd2886SAlan Wright 	 * there could be a deadlock
67829bd2886SAlan Wright 	 */
67929bd2886SAlan Wright 	if (mode == SMB_DCACHE_RDLOCK)
68029bd2886SAlan Wright 		(void) rw_rdlock(&smb_dcache.dc_cache_lck);
68129bd2886SAlan Wright 	else
68229bd2886SAlan Wright 		(void) rw_wrlock(&smb_dcache.dc_cache_lck);
68329bd2886SAlan Wright 
68429bd2886SAlan Wright 	return (SMB_DOMAIN_SUCCESS);
68529bd2886SAlan Wright }
68629bd2886SAlan Wright 
68729bd2886SAlan Wright /*
68829bd2886SAlan Wright  * Decrement the number of inflight operations and then unlock.
68929bd2886SAlan Wright  */
69029bd2886SAlan Wright static void
smb_dcache_unlock(void)69129bd2886SAlan Wright smb_dcache_unlock(void)
69229bd2886SAlan Wright {
69329bd2886SAlan Wright 	(void) mutex_lock(&smb_dcache.dc_mtx);
69429bd2886SAlan Wright 	assert(smb_dcache.dc_nops > 0);
69529bd2886SAlan Wright 	smb_dcache.dc_nops--;
69629bd2886SAlan Wright 	(void) cond_broadcast(&smb_dcache.dc_cv);
69729bd2886SAlan Wright 	(void) mutex_unlock(&smb_dcache.dc_mtx);
69829bd2886SAlan Wright 
69929bd2886SAlan Wright 	(void) rw_unlock(&smb_dcache.dc_cache_lck);
70029bd2886SAlan Wright }
70129bd2886SAlan Wright 
70229bd2886SAlan Wright static uint32_t
smb_dcache_add(smb_domain_t * di)703a0aa776eSAlan Wright smb_dcache_add(smb_domain_t *di)
70429bd2886SAlan Wright {
705a0aa776eSAlan Wright 	smb_domain_t *dcnode;
70629bd2886SAlan Wright 
707a0aa776eSAlan Wright 	if ((dcnode = malloc(sizeof (smb_domain_t))) == NULL)
70829bd2886SAlan Wright 		return (SMB_DOMAIN_NO_MEMORY);
70929bd2886SAlan Wright 
71029bd2886SAlan Wright 	*dcnode = *di;
71129bd2886SAlan Wright 	dcnode->di_binsid = smb_sid_fromstr(dcnode->di_sid);
71229bd2886SAlan Wright 	if (dcnode->di_binsid == NULL) {
71329bd2886SAlan Wright 		free(dcnode);
71429bd2886SAlan Wright 		return (SMB_DOMAIN_NO_MEMORY);
71529bd2886SAlan Wright 	}
71629bd2886SAlan Wright 
71729bd2886SAlan Wright 	list_insert_tail(&smb_dcache.dc_cache, dcnode);
71829bd2886SAlan Wright 	return (SMB_DOMAIN_SUCCESS);
71929bd2886SAlan Wright }
72029bd2886SAlan Wright 
72129bd2886SAlan Wright static void
smb_dcache_remove(smb_domain_t * di)722a0aa776eSAlan Wright smb_dcache_remove(smb_domain_t *di)
72329bd2886SAlan Wright {
72429bd2886SAlan Wright 	list_remove(&smb_dcache.dc_cache, di);
72529bd2886SAlan Wright 	smb_sid_free(di->di_binsid);
72629bd2886SAlan Wright 	free(di);
72729bd2886SAlan Wright }
72829bd2886SAlan Wright 
72929bd2886SAlan Wright static void
smb_dcache_setdc(char * dc)73029bd2886SAlan Wright smb_dcache_setdc(char *dc)
73129bd2886SAlan Wright {
73229bd2886SAlan Wright 	(void) mutex_lock(&smb_dcache.dc_mtx);
73329bd2886SAlan Wright 	(void) strlcpy(smb_dcache.dc_server, dc, sizeof (smb_dcache.dc_server));
73429bd2886SAlan Wright 	(void) mutex_unlock(&smb_dcache.dc_mtx);
73529bd2886SAlan Wright }
73629bd2886SAlan Wright 
73729bd2886SAlan Wright static void
smb_dcache_getdc(char * buf,size_t buflen)73829bd2886SAlan Wright smb_dcache_getdc(char *buf, size_t buflen)
73929bd2886SAlan Wright {
74029bd2886SAlan Wright 	(void) mutex_lock(&smb_dcache.dc_mtx);
74129bd2886SAlan Wright 	(void) strlcpy(buf, smb_dcache.dc_server, buflen);
74229bd2886SAlan Wright 	(void) mutex_unlock(&smb_dcache.dc_mtx);
74329bd2886SAlan Wright }
74429bd2886SAlan Wright 
745a0aa776eSAlan Wright /*
746a0aa776eSAlan Wright  * Waits for SMB_DCACHE_UPDATE_WAIT seconds if cache is in
747a0aa776eSAlan Wright  * UPDATING state. Upon wake up returns true if cache is
748a0aa776eSAlan Wright  * ready to be used, otherwise it returns false.
749a0aa776eSAlan Wright  */
75029bd2886SAlan Wright static boolean_t
smb_dcache_wait(void)75129bd2886SAlan Wright smb_dcache_wait(void)
75229bd2886SAlan Wright {
75329bd2886SAlan Wright 	timestruc_t to;
75429bd2886SAlan Wright 	int err;
75529bd2886SAlan Wright 
75629bd2886SAlan Wright 	to.tv_sec = SMB_DCACHE_UPDATE_WAIT;
75729bd2886SAlan Wright 	to.tv_nsec = 0;
75829bd2886SAlan Wright 	while (smb_dcache.dc_state == SMB_DCACHE_STATE_UPDATING) {
75929bd2886SAlan Wright 		err = cond_reltimedwait(&smb_dcache.dc_cv,
76029bd2886SAlan Wright 		    &smb_dcache.dc_mtx, &to);
76129bd2886SAlan Wright 		if (err == ETIME)
76229bd2886SAlan Wright 			break;
76329bd2886SAlan Wright 	}
76429bd2886SAlan Wright 
76529bd2886SAlan Wright 	return (smb_dcache.dc_state == SMB_DCACHE_STATE_READY);
76629bd2886SAlan Wright }
76729bd2886SAlan Wright 
768a0aa776eSAlan Wright /*
769a0aa776eSAlan Wright  * Transfers the cache into UPDATING state, this will ensure
770a0aa776eSAlan Wright  * any read access to the cache will be stalled until the
771a0aa776eSAlan Wright  * update is finished. This is to avoid providing incomplete,
772a0aa776eSAlan Wright  * inconsistent or stale information.
773a0aa776eSAlan Wright  *
774a0aa776eSAlan Wright  * If another thread is already updating the cache, other
775a0aa776eSAlan Wright  * callers will wait until cache is no longer in UPDATING
776a0aa776eSAlan Wright  * state. The return code is decided based on the new
777a0aa776eSAlan Wright  * state of the cache.
778a0aa776eSAlan Wright  */
779a0aa776eSAlan Wright static uint32_t
smb_dcache_updating(void)78029bd2886SAlan Wright smb_dcache_updating(void)
78129bd2886SAlan Wright {
782a0aa776eSAlan Wright 	uint32_t rc;
783a0aa776eSAlan Wright 
78429bd2886SAlan Wright 	(void) mutex_lock(&smb_dcache.dc_mtx);
785a0aa776eSAlan Wright 	switch (smb_dcache.dc_state) {
786a0aa776eSAlan Wright 	case SMB_DCACHE_STATE_READY:
78729bd2886SAlan Wright 		smb_dcache.dc_state = SMB_DCACHE_STATE_UPDATING;
788a0aa776eSAlan Wright 		rc = SMB_DOMAIN_SUCCESS;
789a0aa776eSAlan Wright 		break;
790a0aa776eSAlan Wright 
791a0aa776eSAlan Wright 	case SMB_DCACHE_STATE_UPDATING:
792a0aa776eSAlan Wright 		while (smb_dcache.dc_state == SMB_DCACHE_STATE_UPDATING)
793a0aa776eSAlan Wright 			(void) cond_wait(&smb_dcache.dc_cv,
794a0aa776eSAlan Wright 			    &smb_dcache.dc_mtx);
795a0aa776eSAlan Wright 
796a0aa776eSAlan Wright 		if (smb_dcache.dc_state == SMB_DCACHE_STATE_READY) {
797a0aa776eSAlan Wright 			smb_dcache.dc_state = SMB_DCACHE_STATE_UPDATING;
798a0aa776eSAlan Wright 			rc = SMB_DOMAIN_SUCCESS;
799a0aa776eSAlan Wright 		} else {
800a0aa776eSAlan Wright 			rc = SMB_DOMAIN_NO_CACHE;
801a0aa776eSAlan Wright 		}
802a0aa776eSAlan Wright 		break;
803a0aa776eSAlan Wright 
804a0aa776eSAlan Wright 	case SMB_DCACHE_STATE_NONE:
805a0aa776eSAlan Wright 	case SMB_DCACHE_STATE_DESTROYING:
806a0aa776eSAlan Wright 		rc = SMB_DOMAIN_NO_CACHE;
807a0aa776eSAlan Wright 		break;
808a0aa776eSAlan Wright 
809a0aa776eSAlan Wright 	default:
810a0aa776eSAlan Wright 		break;
81129bd2886SAlan Wright 	}
81229bd2886SAlan Wright 
813a0aa776eSAlan Wright 	(void) mutex_unlock(&smb_dcache.dc_mtx);
814a0aa776eSAlan Wright 	return (rc);
815a0aa776eSAlan Wright }
816a0aa776eSAlan Wright 
817a0aa776eSAlan Wright /*
818a0aa776eSAlan Wright  * Transfers the cache from UPDATING to READY state.
819a0aa776eSAlan Wright  *
820a0aa776eSAlan Wright  * Nothing will happen if the cache is no longer available
821a0aa776eSAlan Wright  * or it is being destroyed.
822a0aa776eSAlan Wright  */
82329bd2886SAlan Wright static void
smb_dcache_ready(void)82429bd2886SAlan Wright smb_dcache_ready(void)
82529bd2886SAlan Wright {
82629bd2886SAlan Wright 	(void) mutex_lock(&smb_dcache.dc_mtx);
827a0aa776eSAlan Wright 	switch (smb_dcache.dc_state) {
828a0aa776eSAlan Wright 	case SMB_DCACHE_STATE_UPDATING:
82929bd2886SAlan Wright 		smb_dcache.dc_state = SMB_DCACHE_STATE_READY;
830a0aa776eSAlan Wright 		(void) cond_broadcast(&smb_dcache.dc_cv);
831a0aa776eSAlan Wright 		break;
832a0aa776eSAlan Wright 
833a0aa776eSAlan Wright 	case SMB_DCACHE_STATE_NONE:
834a0aa776eSAlan Wright 	case SMB_DCACHE_STATE_DESTROYING:
835a0aa776eSAlan Wright 		break;
836a0aa776eSAlan Wright 
837a0aa776eSAlan Wright 	default:
83829bd2886SAlan Wright 		assert(0);
839a0aa776eSAlan Wright 	}
84029bd2886SAlan Wright 	(void) mutex_unlock(&smb_dcache.dc_mtx);
84129bd2886SAlan Wright }
842