4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
25 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
29 * This file defines the domain environment values and the domain
30 * database interface. The database is a single linked list of
31 * structures containing domain type, name and SID information.
34 #include <sys/types.h>
47 #include <smbsrv/smbinfo.h>
48 #include <smbsrv/string.h>
49 #include <smbsrv/smb_sid.h>
50 #include <smbsrv/libsmb.h>
52 #define SMB_DOMAINS_FILE "domains"
54 #define SMB_DCACHE_UPDATE_WAIT 45 /* seconds */
59 #define SMB_DCACHE_STATE_NONE 0
60 #define SMB_DCACHE_STATE_READY 1
61 #define SMB_DCACHE_STATE_UPDATING 2
62 #define SMB_DCACHE_STATE_DESTROYING 3
67 #define SMB_DCACHE_RDLOCK 0
68 #define SMB_DCACHE_WRLOCK 1
70 typedef struct smb_domain_cache
{
72 rwlock_t dc_cache_lck
;
80 static smb_domain_cache_t smb_dcache
;
82 static uint32_t smb_domain_add(smb_domain_type_t
, smb_domain_t
*);
83 static uint32_t smb_domain_add_local(void);
84 static uint32_t smb_domain_add_primary(uint32_t);
85 static void smb_domain_unlink(void);
87 static void smb_dcache_create(void);
88 static void smb_dcache_destroy(void);
89 static uint32_t smb_dcache_lock(int);
90 static void smb_dcache_unlock(void);
91 static void smb_dcache_remove(smb_domain_t
*);
92 static uint32_t smb_dcache_add(smb_domain_t
*);
93 static boolean_t
smb_dcache_getdc(smb_dcinfo_t
*);
94 static void smb_dcache_setdc(const smb_dcinfo_t
*);
95 static boolean_t
smb_dcache_wait(void);
96 static uint32_t smb_dcache_updating(void);
97 static void smb_dcache_ready(void);
100 * domain cache one time initialization. This function should
101 * only be called during service startup.
103 * Returns 0 on success and an error code on failure.
106 smb_domain_init(uint32_t secmode
)
113 if ((rc
= smb_domain_add_local()) != 0)
116 smb_domain_set_basic_info(NT_BUILTIN_DOMAIN_SIDSTR
, "BUILTIN", "", &di
);
117 (void) smb_domain_add(SMB_DOMAIN_BUILTIN
, &di
);
119 return (smb_domain_add_primary(secmode
));
123 * Destroys the cache upon service termination
126 smb_domain_fini(void)
128 smb_dcache_destroy();
133 * Add a domain structure to domain cache. There is no checking
137 smb_domain_add(smb_domain_type_t type
, smb_domain_t
*di
)
141 if ((di
== NULL
) || (di
->di_sid
== NULL
))
142 return (SMB_DOMAIN_INVALID_ARG
);
144 if ((res
= smb_dcache_lock(SMB_DCACHE_WRLOCK
)) == SMB_DOMAIN_SUCCESS
) {
146 res
= smb_dcache_add(di
);
154 * Lookup a domain by its name. The passed name is the NETBIOS or fully
155 * qualified DNS name or non-qualified DNS name.
157 * If the requested domain is found and given 'di' pointer is not NULL
158 * it'll be filled with the domain information and B_TRUE is returned.
159 * If the caller only needs to check a domain existence it can pass
160 * NULL for 'di' and just check the return value.
162 * If the domain is not in the cache B_FALSE is returned.
165 smb_domain_lookup_name(char *name
, smb_domain_t
*di
)
167 boolean_t found
= B_FALSE
;
168 smb_domain_t
*dcnode
;
171 bzero(di
, sizeof (smb_domain_t
));
173 if (name
== NULL
|| *name
== '\0')
176 if (smb_dcache_lock(SMB_DCACHE_RDLOCK
) != SMB_DOMAIN_SUCCESS
)
179 dcnode
= list_head(&smb_dcache
.dc_cache
);
181 found
= (smb_strcasecmp(dcnode
->di_nbname
, name
, 0) == 0) ||
182 (smb_strcasecmp(dcnode
->di_fqname
, name
, 0) == 0);
190 if ((p
= strchr(dcnode
->di_fqname
, '.')) != NULL
) {
192 found
= (smb_strcasecmp(dcnode
->di_fqname
, name
,
202 dcnode
= list_next(&smb_dcache
.dc_cache
, dcnode
);
210 * Lookup a domain by its SID.
212 * If the requested domain is found and given 'di' pointer is not NULL
213 * it'll be filled with the domain information and B_TRUE is returned.
214 * If the caller only needs to check a domain existence it can pass
215 * NULL for 'di' and just check the return value.
217 * If the domain is not in the cache B_FALSE is returned.
220 smb_domain_lookup_sid(smb_sid_t
*sid
, smb_domain_t
*di
)
222 boolean_t found
= B_FALSE
;
223 smb_domain_t
*dcnode
;
224 char sidstr
[SMB_SID_STRSZ
];
226 bzero(di
, sizeof (smb_domain_t
));
231 smb_sid_tostr(sid
, sidstr
);
233 if (smb_dcache_lock(SMB_DCACHE_RDLOCK
) != SMB_DOMAIN_SUCCESS
)
236 dcnode
= list_head(&smb_dcache
.dc_cache
);
238 found
= (strcmp(dcnode
->di_sid
, sidstr
) == 0);
245 dcnode
= list_next(&smb_dcache
.dc_cache
, dcnode
);
253 * Lookup a domain by its type.
255 * If the requested domain is found and given 'di' pointer is not NULL
256 * it'll be filled with the domain information and B_TRUE is returned.
257 * If the caller only needs to check a domain existence it can pass
258 * NULL for 'di' and just check the return value.
260 * If the domain is not in the cache B_FALSE is returned.
263 smb_domain_lookup_type(smb_domain_type_t type
, smb_domain_t
*di
)
265 boolean_t found
= B_FALSE
;
266 smb_domain_t
*dcnode
;
268 bzero(di
, sizeof (smb_domain_t
));
270 if (smb_dcache_lock(SMB_DCACHE_RDLOCK
) != SMB_DOMAIN_SUCCESS
)
273 dcnode
= list_head(&smb_dcache
.dc_cache
);
275 if (dcnode
->di_type
== type
) {
282 dcnode
= list_next(&smb_dcache
.dc_cache
, dcnode
);
290 * Returns primary domain information plus the name of
291 * the selected domain controller.
294 smb_domain_getinfo(smb_domainex_t
*dxi
)
298 /* Note: this waits for the dcache lock. */
299 rv
= smb_domain_lookup_type(SMB_DOMAIN_PRIMARY
, &dxi
->d_primary
);
301 rv
= smb_dcache_getdc(&dxi
->d_dci
);
307 * Get the name of the current DC (if any)
311 smb_domain_current_dc(smb_dcinfo_t
*dci
)
313 (void) smb_dcache_getdc(dci
);
317 * Transfer the cache to updating state.
318 * In this state any request for reading the cache would
319 * be blocked until the update is finished.
322 smb_domain_start_update(void)
324 return (smb_dcache_updating());
328 * Transfer the cache from updating to ready state.
331 smb_domain_end_update(void)
337 * Updates the cache with given information for the primary
338 * domain, possible trusted domains and the selected domain
341 * Before adding the new entries existing entries of type
342 * primary and trusted will be removed from cache.
345 smb_domain_update(smb_domainex_t
*dxi
)
347 smb_domain_t
*dcnode
;
350 if (smb_dcache_lock(SMB_DCACHE_WRLOCK
) != SMB_DOMAIN_SUCCESS
)
353 dcnode
= list_head(&smb_dcache
.dc_cache
);
355 if ((dcnode
->di_type
== SMB_DOMAIN_PRIMARY
) ||
356 (dcnode
->di_type
== SMB_DOMAIN_TRUSTED
)) {
357 smb_dcache_remove(dcnode
);
358 dcnode
= list_head(&smb_dcache
.dc_cache
);
360 dcnode
= list_next(&smb_dcache
.dc_cache
, dcnode
);
364 if (smb_dcache_add(&dxi
->d_primary
) == SMB_DOMAIN_SUCCESS
) {
365 for (i
= 0; i
< dxi
->d_trusted
.td_num
; i
++)
366 (void) smb_dcache_add(&dxi
->d_trusted
.td_domains
[i
]);
368 smb_dcache_setdc(&dxi
->d_dci
);
375 * Write the list of domains to /var/run/smb/domains.
378 smb_domain_save(void)
380 char fname
[MAXPATHLEN
];
382 smb_domain_t
*domain
;
389 (void) snprintf(fname
, MAXPATHLEN
, "%s/%s",
390 SMB_VARRUN_DIR
, SMB_DOMAINS_FILE
);
392 if ((fp
= fopen(fname
, "w")) == NULL
)
395 pwd
= getpwnam("root");
396 grp
= getgrnam("sys");
397 uid
= (pwd
== NULL
) ? 0 : pwd
->pw_uid
;
398 gid
= (grp
== NULL
) ? 3 : grp
->gr_gid
;
400 (void) lockf(fileno(fp
), F_LOCK
, 0);
401 (void) fchmod(fileno(fp
), 0600);
402 (void) fchown(fileno(fp
), uid
, gid
);
404 if (smb_dcache_lock(SMB_DCACHE_RDLOCK
) != SMB_DOMAIN_SUCCESS
)
407 domain
= list_head(&smb_dcache
.dc_cache
);
409 switch (domain
->di_type
) {
410 case SMB_DOMAIN_PRIMARY
:
414 case SMB_DOMAIN_TRUSTED
:
415 case SMB_DOMAIN_UNTRUSTED
:
419 case SMB_DOMAIN_LOCAL
:
423 domain
= list_next(&smb_dcache
.dc_cache
, domain
);
427 (void) fprintf(fp
, "[%c] [%s] [%s]\n",
428 tag
, domain
->di_nbname
, domain
->di_sid
);
430 domain
= list_next(&smb_dcache
.dc_cache
, domain
);
434 (void) lockf(fileno(fp
), F_ULOCK
, 0);
439 * List the domains in /var/run/smb/domains.
442 smb_domain_show(void)
444 char buf
[MAXPATHLEN
];
448 (void) snprintf(buf
, MAXPATHLEN
, "%s/%s",
449 SMB_VARRUN_DIR
, SMB_DOMAINS_FILE
);
451 if ((fp
= fopen(buf
, "r")) != NULL
) {
452 (void) lockf(fileno(fp
), F_LOCK
, 0);
454 while (fgets(buf
, MAXPATHLEN
, fp
) != NULL
) {
455 if ((p
= strchr(buf
, '\n')) != NULL
)
457 (void) printf("%s\n", buf
);
460 (void) lockf(fileno(fp
), F_ULOCK
, 0);
466 smb_domain_set_basic_info(char *sid
, char *nb_domain
, char *fq_domain
,
469 if (sid
== NULL
|| nb_domain
== NULL
|| fq_domain
== NULL
||
473 (void) strlcpy(di
->di_sid
, sid
, SMB_SID_STRSZ
);
474 (void) strlcpy(di
->di_nbname
, nb_domain
, NETBIOS_NAME_SZ
);
475 (void) smb_strupr(di
->di_nbname
);
476 (void) strlcpy(di
->di_fqname
, fq_domain
, MAXHOSTNAMELEN
);
477 di
->di_binsid
= NULL
;
481 smb_domain_set_dns_info(char *sid
, char *nb_domain
, char *fq_domain
,
482 char *forest
, char *guid
, smb_domain_t
*di
)
484 if (di
== NULL
|| forest
== NULL
|| guid
== NULL
)
487 smb_domain_set_basic_info(sid
, nb_domain
, fq_domain
, di
);
488 (void) strlcpy(di
->di_u
.di_dns
.ddi_forest
, forest
, MAXHOSTNAMELEN
);
489 (void) strlcpy(di
->di_u
.di_dns
.ddi_guid
, guid
,
490 UUID_PRINTABLE_STRING_LENGTH
);
494 smb_domain_set_trust_info(char *sid
, char *nb_domain
, char *fq_domain
,
495 uint32_t trust_dir
, uint32_t trust_type
, uint32_t trust_attrs
,
498 smb_domain_trust_t
*ti
;
503 di
->di_type
= SMB_DOMAIN_TRUSTED
;
504 ti
= &di
->di_u
.di_trust
;
505 smb_domain_set_basic_info(sid
, nb_domain
, fq_domain
, di
);
506 ti
->dti_trust_direction
= trust_dir
;
507 ti
->dti_trust_type
= trust_type
;
508 ti
->dti_trust_attrs
= trust_attrs
;
512 * Remove the /var/run/smb/domains file.
515 smb_domain_unlink(void)
517 char fname
[MAXPATHLEN
];
519 (void) snprintf(fname
, MAXPATHLEN
, "%s/%s",
520 SMB_VARRUN_DIR
, SMB_DOMAINS_FILE
);
521 (void) unlink(fname
);
525 * Add an entry for the local domain to the domain cache
528 smb_domain_add_local(void)
531 char hostname
[NETBIOS_NAME_SZ
];
532 char fq_name
[MAXHOSTNAMELEN
];
535 if ((lsidstr
= smb_config_get_localsid()) == NULL
)
536 return (SMB_DOMAIN_NOMACHINE_SID
);
538 if (smb_getnetbiosname(hostname
, NETBIOS_NAME_SZ
) != 0) {
540 return (SMB_DOMAIN_NOMACHINE_SID
);
544 (void) smb_getfqhostname(fq_name
, MAXHOSTNAMELEN
);
545 smb_domain_set_basic_info(lsidstr
, hostname
, fq_name
, &di
);
546 (void) smb_domain_add(SMB_DOMAIN_LOCAL
, &di
);
549 return (SMB_DOMAIN_SUCCESS
);
553 * Add an entry for the primary domain to the domain cache
556 smb_domain_add_primary(uint32_t secmode
)
558 char sidstr
[SMB_SID_STRSZ
];
559 char fq_name
[MAXHOSTNAMELEN
];
560 char nb_name
[NETBIOS_NAME_SZ
];
564 if (secmode
!= SMB_SECMODE_DOMAIN
)
565 return (SMB_DOMAIN_SUCCESS
);
567 rc
= smb_config_getstr(SMB_CI_DOMAIN_SID
, sidstr
, sizeof (sidstr
));
568 if (rc
!= SMBD_SMF_OK
)
569 return (SMB_DOMAIN_NODOMAIN_SID
);
571 rc
= smb_config_getstr(SMB_CI_DOMAIN_NAME
, nb_name
, NETBIOS_NAME_SZ
);
572 if ((rc
!= SMBD_SMF_OK
) || (*nb_name
== '\0'))
573 return (SMB_DOMAIN_NODOMAIN_NAME
);
575 (void) smb_getfqdomainname(fq_name
, MAXHOSTNAMELEN
);
576 smb_domain_set_basic_info(sidstr
, nb_name
, fq_name
, &di
);
577 (void) smb_domain_add(SMB_DOMAIN_PRIMARY
, &di
);
578 return (SMB_DOMAIN_SUCCESS
);
582 * Initialize the domain cache.
583 * This function does not populate the cache.
586 smb_dcache_create(void)
588 (void) mutex_lock(&smb_dcache
.dc_mtx
);
589 if (smb_dcache
.dc_state
!= SMB_DCACHE_STATE_NONE
) {
590 (void) mutex_unlock(&smb_dcache
.dc_mtx
);
594 list_create(&smb_dcache
.dc_cache
, sizeof (smb_domain_t
),
595 offsetof(smb_domain_t
, di_lnd
));
597 smb_dcache
.dc_nops
= 0;
598 bzero(&smb_dcache
.dc_dci
, sizeof (smb_dcache
.dc_dci
));
599 smb_dcache
.dc_state
= SMB_DCACHE_STATE_READY
;
600 (void) mutex_unlock(&smb_dcache
.dc_mtx
);
604 * Removes and frees all the cache entries
607 smb_dcache_flush(void)
611 (void) rw_wrlock(&smb_dcache
.dc_cache_lck
);
612 while ((di
= list_head(&smb_dcache
.dc_cache
)) != NULL
)
613 smb_dcache_remove(di
);
614 (void) rw_unlock(&smb_dcache
.dc_cache_lck
);
618 * Destroys the cache.
621 smb_dcache_destroy(void)
623 (void) mutex_lock(&smb_dcache
.dc_mtx
);
624 if ((smb_dcache
.dc_state
== SMB_DCACHE_STATE_READY
) ||
625 (smb_dcache
.dc_state
== SMB_DCACHE_STATE_UPDATING
)) {
626 smb_dcache
.dc_state
= SMB_DCACHE_STATE_DESTROYING
;
627 while (smb_dcache
.dc_nops
> 0)
628 (void) cond_wait(&smb_dcache
.dc_cv
,
632 list_destroy(&smb_dcache
.dc_cache
);
634 smb_dcache
.dc_state
= SMB_DCACHE_STATE_NONE
;
636 (void) mutex_unlock(&smb_dcache
.dc_mtx
);
640 * Lock the cache with the specified mode.
641 * If the cache is in updating state and a read lock is
642 * requested, the lock won't be granted until either the
643 * update is finished or SMB_DCACHE_UPDATE_WAIT has passed.
645 * Whenever a lock is granted, the number of inflight cache
646 * operations is incremented.
649 smb_dcache_lock(int mode
)
651 (void) mutex_lock(&smb_dcache
.dc_mtx
);
652 switch (smb_dcache
.dc_state
) {
653 case SMB_DCACHE_STATE_NONE
:
654 case SMB_DCACHE_STATE_DESTROYING
:
655 (void) mutex_unlock(&smb_dcache
.dc_mtx
);
656 return (SMB_DOMAIN_INTERNAL_ERR
);
658 case SMB_DCACHE_STATE_UPDATING
:
659 if (mode
== SMB_DCACHE_RDLOCK
) {
661 * Read operations should wait until the update
664 if (!smb_dcache_wait()) {
665 (void) mutex_unlock(&smb_dcache
.dc_mtx
);
666 return (SMB_DOMAIN_INTERNAL_ERR
);
671 smb_dcache
.dc_nops
++;
674 (void) mutex_unlock(&smb_dcache
.dc_mtx
);
677 * Lock has to be taken outside the mutex otherwise
678 * there could be a deadlock
680 if (mode
== SMB_DCACHE_RDLOCK
)
681 (void) rw_rdlock(&smb_dcache
.dc_cache_lck
);
683 (void) rw_wrlock(&smb_dcache
.dc_cache_lck
);
685 return (SMB_DOMAIN_SUCCESS
);
689 * Decrement the number of inflight operations and then unlock.
692 smb_dcache_unlock(void)
694 (void) mutex_lock(&smb_dcache
.dc_mtx
);
695 assert(smb_dcache
.dc_nops
> 0);
696 smb_dcache
.dc_nops
--;
697 (void) cond_broadcast(&smb_dcache
.dc_cv
);
698 (void) mutex_unlock(&smb_dcache
.dc_mtx
);
700 (void) rw_unlock(&smb_dcache
.dc_cache_lck
);
704 smb_dcache_add(smb_domain_t
*di
)
706 smb_domain_t
*dcnode
;
708 if ((dcnode
= malloc(sizeof (smb_domain_t
))) == NULL
)
709 return (SMB_DOMAIN_NO_MEMORY
);
712 dcnode
->di_binsid
= smb_sid_fromstr(dcnode
->di_sid
);
713 if (dcnode
->di_binsid
== NULL
) {
715 return (SMB_DOMAIN_NO_MEMORY
);
718 list_insert_tail(&smb_dcache
.dc_cache
, dcnode
);
719 return (SMB_DOMAIN_SUCCESS
);
723 smb_dcache_remove(smb_domain_t
*di
)
725 list_remove(&smb_dcache
.dc_cache
, di
);
726 smb_sid_free(di
->di_binsid
);
731 smb_dcache_setdc(const smb_dcinfo_t
*dci
)
733 (void) mutex_lock(&smb_dcache
.dc_mtx
);
734 smb_dcache
.dc_dci
= *dci
; /* struct assignment! */
735 (void) mutex_unlock(&smb_dcache
.dc_mtx
);
739 * Return B_TRUE if we have DC information.
742 smb_dcache_getdc(smb_dcinfo_t
*dci
)
744 (void) mutex_lock(&smb_dcache
.dc_mtx
);
745 *dci
= smb_dcache
.dc_dci
; /* struct assignment! */
746 (void) mutex_unlock(&smb_dcache
.dc_mtx
);
747 return (dci
->dc_name
[0] != '\0');
751 * Waits for SMB_DCACHE_UPDATE_WAIT seconds if cache is in
752 * UPDATING state. Upon wake up returns true if cache is
753 * ready to be used, otherwise it returns false.
756 smb_dcache_wait(void)
761 to
.tv_sec
= SMB_DCACHE_UPDATE_WAIT
;
763 while (smb_dcache
.dc_state
== SMB_DCACHE_STATE_UPDATING
) {
764 err
= cond_reltimedwait(&smb_dcache
.dc_cv
,
765 &smb_dcache
.dc_mtx
, &to
);
770 return (smb_dcache
.dc_state
== SMB_DCACHE_STATE_READY
);
774 * Transfers the cache into UPDATING state, this will ensure
775 * any read access to the cache will be stalled until the
776 * update is finished. This is to avoid providing incomplete,
777 * inconsistent or stale information.
779 * If another thread is already updating the cache, other
780 * callers will wait until cache is no longer in UPDATING
781 * state. The return code is decided based on the new
782 * state of the cache.
785 smb_dcache_updating(void)
789 (void) mutex_lock(&smb_dcache
.dc_mtx
);
790 switch (smb_dcache
.dc_state
) {
791 case SMB_DCACHE_STATE_READY
:
792 smb_dcache
.dc_state
= SMB_DCACHE_STATE_UPDATING
;
793 rc
= SMB_DOMAIN_SUCCESS
;
796 case SMB_DCACHE_STATE_UPDATING
:
797 while (smb_dcache
.dc_state
== SMB_DCACHE_STATE_UPDATING
)
798 (void) cond_wait(&smb_dcache
.dc_cv
,
801 if (smb_dcache
.dc_state
== SMB_DCACHE_STATE_READY
) {
802 smb_dcache
.dc_state
= SMB_DCACHE_STATE_UPDATING
;
803 rc
= SMB_DOMAIN_SUCCESS
;
805 rc
= SMB_DOMAIN_NO_CACHE
;
809 case SMB_DCACHE_STATE_NONE
:
810 case SMB_DCACHE_STATE_DESTROYING
:
811 rc
= SMB_DOMAIN_NO_CACHE
;
818 (void) mutex_unlock(&smb_dcache
.dc_mtx
);
823 * Transfers the cache from UPDATING to READY state.
825 * Nothing will happen if the cache is no longer available
826 * or it is being destroyed.
829 smb_dcache_ready(void)
831 (void) mutex_lock(&smb_dcache
.dc_mtx
);
832 switch (smb_dcache
.dc_state
) {
833 case SMB_DCACHE_STATE_UPDATING
:
834 smb_dcache
.dc_state
= SMB_DCACHE_STATE_READY
;
835 (void) cond_broadcast(&smb_dcache
.dc_cv
);
838 case SMB_DCACHE_STATE_NONE
:
839 case SMB_DCACHE_STATE_DESTROYING
:
845 (void) mutex_unlock(&smb_dcache
.dc_mtx
);