5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 *
25 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
26 */
27
28 /*
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.
32 */
33
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <sys/list.h>
37 #include <stdio.h>
38 #include <strings.h>
39 #include <string.h>
40 #include <unistd.h>
41 #include <stdlib.h>
42 #include <synch.h>
43 #include <pwd.h>
44 #include <grp.h>
45 #include <assert.h>
46
47 #include <smbsrv/smbinfo.h>
48 #include <smbsrv/string.h>
49 #include <smbsrv/smb_sid.h>
50 #include <smbsrv/libsmb.h>
51
52 #define SMB_DOMAINS_FILE "domains"
53
54 #define SMB_DCACHE_UPDATE_WAIT 45 /* seconds */
55
56 /*
57 * Domain cache states
58 */
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
63
64 /*
65 * Cache lock modes
66 */
67 #define SMB_DCACHE_RDLOCK 0
68 #define SMB_DCACHE_WRLOCK 1
69
70 typedef struct smb_domain_cache {
71 list_t dc_cache;
72 rwlock_t dc_cache_lck;
73 mutex_t dc_mtx;
74 cond_t dc_cv;
75 uint32_t dc_state;
76 uint32_t dc_nops;
77 smb_dcinfo_t dc_dci;
78 } smb_domain_cache_t;
79
80 static smb_domain_cache_t smb_dcache;
81
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);
86
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);
98
99 /*
100 * domain cache one time initialization. This function should
101 * only be called during service startup.
102 *
103 * Returns 0 on success and an error code on failure.
104 */
105 int
106 smb_domain_init(uint32_t secmode)
107 {
108 smb_domain_t di;
109 int rc;
110
111 smb_dcache_create();
112
113 if ((rc = smb_domain_add_local()) != 0)
114 return (rc);
115
116 smb_domain_set_basic_info(NT_BUILTIN_DOMAIN_SIDSTR, "BUILTIN", "", &di);
117 (void) smb_domain_add(SMB_DOMAIN_BUILTIN, &di);
118
119 return (smb_domain_add_primary(secmode));
120 }
121
122 /*
123 * Destroys the cache upon service termination
124 */
125 void
126 smb_domain_fini(void)
127 {
128 smb_dcache_destroy();
129 smb_domain_unlink();
130 }
131
132 /*
133 * Add a domain structure to domain cache. There is no checking
134 * for duplicates.
135 */
272
273 dcnode = list_head(&smb_dcache.dc_cache);
274 while (dcnode) {
275 if (dcnode->di_type == type) {
276 found = B_TRUE;
277 if (di)
278 *di = *dcnode;
279 break;
280 }
281
282 dcnode = list_next(&smb_dcache.dc_cache, dcnode);
283 }
284
285 smb_dcache_unlock();
286 return (found);
287 }
288
289 /*
290 * Returns primary domain information plus the name of
291 * the selected domain controller.
292 */
293 boolean_t
294 smb_domain_getinfo(smb_domainex_t *dxi)
295 {
296 boolean_t rv;
297
298 /* Note: this waits for the dcache lock. */
299 rv = smb_domain_lookup_type(SMB_DOMAIN_PRIMARY, &dxi->d_primary);
300 if (rv)
301 rv = smb_dcache_getdc(&dxi->d_dci);
302
303 return (rv);
304 }
305
306 /*
307 * Get the name of the current DC (if any)
308 * Does NOT block.
309 */
310 void
311 smb_domain_current_dc(smb_dcinfo_t *dci)
312 {
313 (void) smb_dcache_getdc(dci);
314 }
315
316 /*
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.
320 */
321 uint32_t
322 smb_domain_start_update(void)
323 {
324 return (smb_dcache_updating());
325 }
326
327 /*
328 * Transfer the cache from updating to ready state.
329 */
330 void
331 smb_domain_end_update(void)
332 {
333 smb_dcache_ready();
334 }
335
336 /*
337 * Updates the cache with given information for the primary
338 * domain, possible trusted domains and the selected domain
339 * controller.
340 *
341 * Before adding the new entries existing entries of type
342 * primary and trusted will be removed from cache.
343 */
344 void
345 smb_domain_update(smb_domainex_t *dxi)
346 {
347 smb_domain_t *dcnode;
348 int i;
349
350 if (smb_dcache_lock(SMB_DCACHE_WRLOCK) != SMB_DOMAIN_SUCCESS)
351 return;
352
353 dcnode = list_head(&smb_dcache.dc_cache);
354 while (dcnode) {
355 if ((dcnode->di_type == SMB_DOMAIN_PRIMARY) ||
356 (dcnode->di_type == SMB_DOMAIN_TRUSTED)) {
467 smb_domain_t *di)
468 {
469 if (sid == NULL || nb_domain == NULL || fq_domain == NULL ||
470 di == NULL)
471 return;
472
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;
478 }
479
480 void
481 smb_domain_set_dns_info(char *sid, char *nb_domain, char *fq_domain,
482 char *forest, char *guid, smb_domain_t *di)
483 {
484 if (di == NULL || forest == NULL || guid == NULL)
485 return;
486
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);
491 }
492
493 void
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,
496 smb_domain_t *di)
497 {
498 smb_domain_trust_t *ti;
499
500 if (di == NULL)
501 return;
502
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;
509 }
510
511 /*
512 * Remove the /var/run/smb/domains file.
513 */
514 static void
515 smb_domain_unlink(void)
516 {
517 char fname[MAXPATHLEN];
518
519 (void) snprintf(fname, MAXPATHLEN, "%s/%s",
520 SMB_VARRUN_DIR, SMB_DOMAINS_FILE);
521 (void) unlink(fname);
522 }
523
524 /*
525 * Add an entry for the local domain to the domain cache
526 */
527 static uint32_t
528 smb_domain_add_local(void)
529 {
530 char *lsidstr;
531 char hostname[NETBIOS_NAME_SZ];
532 char fq_name[MAXHOSTNAMELEN];
533 smb_domain_t di;
534
535 if ((lsidstr = smb_config_get_localsid()) == NULL)
536 return (SMB_DOMAIN_NOMACHINE_SID);
537
538 if (smb_getnetbiosname(hostname, NETBIOS_NAME_SZ) != 0) {
539 free(lsidstr);
540 return (SMB_DOMAIN_NOMACHINE_SID);
541 }
542
543 *fq_name = '\0';
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);
547
548 free(lsidstr);
549 return (SMB_DOMAIN_SUCCESS);
550 }
551
552 /*
553 * Add an entry for the primary domain to the domain cache
554 */
555 static uint32_t
556 smb_domain_add_primary(uint32_t secmode)
557 {
558 char sidstr[SMB_SID_STRSZ];
559 char fq_name[MAXHOSTNAMELEN];
560 char nb_name[NETBIOS_NAME_SZ];
561 smb_domain_t di;
562 int rc;
563
564 if (secmode != SMB_SECMODE_DOMAIN)
565 return (SMB_DOMAIN_SUCCESS);
566
567 rc = smb_config_getstr(SMB_CI_DOMAIN_SID, sidstr, sizeof (sidstr));
568 if (rc != SMBD_SMF_OK)
569 return (SMB_DOMAIN_NODOMAIN_SID);
570
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);
574
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);
579 }
580
581 /*
582 * Initialize the domain cache.
583 * This function does not populate the cache.
584 */
585 static void
586 smb_dcache_create(void)
587 {
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);
591 return;
592 }
593
594 list_create(&smb_dcache.dc_cache, sizeof (smb_domain_t),
595 offsetof(smb_domain_t, di_lnd));
596
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);
601 }
602
603 /*
604 * Removes and frees all the cache entries
605 */
606 static void
607 smb_dcache_flush(void)
608 {
609 smb_domain_t *di;
610
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);
615 }
616
617 /*
618 * Destroys the cache.
635 }
636 (void) mutex_unlock(&smb_dcache.dc_mtx);
637 }
638
639 /*
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.
644 *
645 * Whenever a lock is granted, the number of inflight cache
646 * operations is incremented.
647 */
648 static uint32_t
649 smb_dcache_lock(int mode)
650 {
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);
657
658 case SMB_DCACHE_STATE_UPDATING:
659 if (mode == SMB_DCACHE_RDLOCK) {
660 /*
661 * Read operations should wait until the update
662 * is completed.
663 */
664 if (!smb_dcache_wait()) {
665 (void) mutex_unlock(&smb_dcache.dc_mtx);
666 return (SMB_DOMAIN_INTERNAL_ERR);
667 }
668 }
669
670 default:
671 smb_dcache.dc_nops++;
672 break;
673 }
674 (void) mutex_unlock(&smb_dcache.dc_mtx);
675
676 /*
677 * Lock has to be taken outside the mutex otherwise
678 * there could be a deadlock
679 */
680 if (mode == SMB_DCACHE_RDLOCK)
681 (void) rw_rdlock(&smb_dcache.dc_cache_lck);
682 else
683 (void) rw_wrlock(&smb_dcache.dc_cache_lck);
684
685 return (SMB_DOMAIN_SUCCESS);
686 }
687
688 /*
689 * Decrement the number of inflight operations and then unlock.
690 */
715 return (SMB_DOMAIN_NO_MEMORY);
716 }
717
718 list_insert_tail(&smb_dcache.dc_cache, dcnode);
719 return (SMB_DOMAIN_SUCCESS);
720 }
721
722 static void
723 smb_dcache_remove(smb_domain_t *di)
724 {
725 list_remove(&smb_dcache.dc_cache, di);
726 smb_sid_free(di->di_binsid);
727 free(di);
728 }
729
730 static void
731 smb_dcache_setdc(const smb_dcinfo_t *dci)
732 {
733 (void) mutex_lock(&smb_dcache.dc_mtx);
734 smb_dcache.dc_dci = *dci; /* struct assignment! */
735 (void) mutex_unlock(&smb_dcache.dc_mtx);
736 }
737
738 /*
739 * Return B_TRUE if we have DC information.
740 */
741 static boolean_t
742 smb_dcache_getdc(smb_dcinfo_t *dci)
743 {
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');
748 }
749
750 /*
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.
754 */
755 static boolean_t
756 smb_dcache_wait(void)
757 {
758 timestruc_t to;
759 int err;
760
761 to.tv_sec = SMB_DCACHE_UPDATE_WAIT;
762 to.tv_nsec = 0;
763 while (smb_dcache.dc_state == SMB_DCACHE_STATE_UPDATING) {
764 err = cond_reltimedwait(&smb_dcache.dc_cv,
765 &smb_dcache.dc_mtx, &to);
766 if (err == ETIME)
767 break;
768 }
769
770 return (smb_dcache.dc_state == SMB_DCACHE_STATE_READY);
771 }
772
773 /*
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.
778 *
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.
783 */
784 static uint32_t
|
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 *
25 * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
26 */
27
28 /*
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.
32 */
33
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <sys/list.h>
37 #include <stdio.h>
38 #include <strings.h>
39 #include <string.h>
40 #include <syslog.h>
41 #include <unistd.h>
42 #include <stdlib.h>
43 #include <synch.h>
44 #include <pwd.h>
45 #include <grp.h>
46 #include <assert.h>
47
48 #include <smbsrv/smbinfo.h>
49 #include <smbsrv/string.h>
50 #include <smbsrv/smb_sid.h>
51 #include <smbsrv/libsmb.h>
52
53 #define SMB_DOMAINS_FILE "domains"
54
55 #define SMB_DCACHE_UPDATE_WAIT 45 /* seconds */
56
57 /*
58 * Domain cache states
59 */
60 #define SMB_DCACHE_STATE_NONE 0
61 #define SMB_DCACHE_STATE_READY 1
62 #define SMB_DCACHE_STATE_UPDATING 2
63 #define SMB_DCACHE_STATE_DESTROYING 3
64
65 /*
66 * Cache lock modes
67 */
68 #define SMB_DCACHE_RDLOCK 0
69 #define SMB_DCACHE_WRLOCK 1
70
71 typedef struct smb_domain_cache {
72 list_t dc_cache;
73 rwlock_t dc_cache_lck;
74 uint32_t dc_state;
75 uint32_t dc_nops;
76 mutex_t dc_mtx;
77 cond_t dc_cv;
78 /* domain controller information */
79 cond_t dc_dci_cv;
80 boolean_t dc_dci_valid;
81 smb_dcinfo_t dc_dci;
82 } smb_domain_cache_t;
83
84 static smb_domain_cache_t smb_dcache;
85
86 static uint32_t smb_domain_add(smb_domain_type_t, smb_domain_t *);
87 static uint32_t smb_domain_add_local(void);
88 static uint32_t smb_domain_add_primary(uint32_t);
89 static void smb_domain_unlink(void);
90
91 static void smb_dcache_create(void);
92 static void smb_dcache_destroy(void);
93 static uint32_t smb_dcache_lock(int);
94 static void smb_dcache_unlock(void);
95 static void smb_dcache_remove(smb_domain_t *);
96 static uint32_t smb_dcache_add(smb_domain_t *);
97 static boolean_t smb_dcache_getdc(smb_dcinfo_t *, boolean_t);
98 static void smb_dcache_setdc(const smb_dcinfo_t *);
99 static boolean_t smb_dcache_wait(void);
100 static uint32_t smb_dcache_updating(void);
101 static void smb_dcache_ready(void);
102
103 /*
104 * domain cache one time initialization. This function should
105 * only be called during service startup.
106 *
107 * Returns 0 on success and an error code on failure.
108 */
109 int
110 smb_domain_init(uint32_t secmode)
111 {
112 smb_domain_t di;
113 int rc;
114
115 smb_dcache_create();
116
117 if ((rc = smb_domain_add_local()) != 0)
118 return (rc);
119
120 bzero(&di, sizeof (di));
121 smb_domain_set_basic_info(NT_BUILTIN_DOMAIN_SIDSTR, "BUILTIN", "", &di);
122 (void) smb_domain_add(SMB_DOMAIN_BUILTIN, &di);
123
124 return (smb_domain_add_primary(secmode));
125 }
126
127 /*
128 * Destroys the cache upon service termination
129 */
130 void
131 smb_domain_fini(void)
132 {
133 smb_dcache_destroy();
134 smb_domain_unlink();
135 }
136
137 /*
138 * Add a domain structure to domain cache. There is no checking
139 * for duplicates.
140 */
277
278 dcnode = list_head(&smb_dcache.dc_cache);
279 while (dcnode) {
280 if (dcnode->di_type == type) {
281 found = B_TRUE;
282 if (di)
283 *di = *dcnode;
284 break;
285 }
286
287 dcnode = list_next(&smb_dcache.dc_cache, dcnode);
288 }
289
290 smb_dcache_unlock();
291 return (found);
292 }
293
294 /*
295 * Returns primary domain information plus the name of
296 * the selected domain controller.
297 *
298 * Returns TRUE on success.
299 */
300 boolean_t
301 smb_domain_getinfo(smb_domainex_t *dxi)
302 {
303 boolean_t rv;
304
305 /* Note: this waits for the dcache lock. */
306 rv = smb_domain_lookup_type(SMB_DOMAIN_PRIMARY, &dxi->d_primary);
307 if (!rv) {
308 syslog(LOG_ERR, "smb_domain_getinfo: no primary domain");
309 return (B_FALSE);
310 }
311
312 /*
313 * The 2nd arg TRUE means this will wait for DC info.
314 *
315 * Note that we do NOT hold the dcache rwlock here
316 * (not even as reader) because we already have what we
317 * need from the dcache (our primary domain) and we don't
318 * want to interfere with the DC locator which will take
319 * the dcache lock as write to update the domain info.
320 */
321 rv = smb_dcache_getdc(&dxi->d_dci, B_TRUE);
322 if (!rv) {
323 syslog(LOG_ERR, "smb_domain_getinfo: no DC info");
324 return (B_FALSE);
325 }
326
327 return (B_TRUE);
328 }
329
330 /*
331 * Get the name of the current DC (if any)
332 * Does NOT block.
333 */
334 void
335 smb_domain_current_dc(smb_dcinfo_t *dci)
336 {
337 (void) smb_dcache_getdc(dci, B_FALSE);
338 }
339
340 /*
341 * Transfer the cache to updating state.
342 * In this state any request for reading the cache would
343 * be blocked until the update is finished.
344 */
345 uint32_t
346 smb_domain_start_update(void)
347 {
348 return (smb_dcache_updating());
349 }
350
351 /*
352 * Transfer the cache from updating to ready state.
353 */
354 void
355 smb_domain_end_update(void)
356 {
357 smb_dcache_ready();
358 }
359
360 /*
361 * Mark the current domain controller (DC) info invalid
362 * until the DC locator call smb_domain_update().
363 */
364 void
365 smb_domain_bad_dc(void)
366 {
367 (void) mutex_lock(&smb_dcache.dc_mtx);
368 smb_dcache.dc_dci_valid = B_FALSE;
369 (void) mutex_unlock(&smb_dcache.dc_mtx);
370 }
371
372 /*
373 * Updates the cache with given information for the primary
374 * domain, possible trusted domains and the selected domain
375 * controller.
376 *
377 * Before adding the new entries existing entries of type
378 * primary and trusted will be removed from cache.
379 */
380 void
381 smb_domain_update(smb_domainex_t *dxi)
382 {
383 smb_domain_t *dcnode;
384 int i;
385
386 if (smb_dcache_lock(SMB_DCACHE_WRLOCK) != SMB_DOMAIN_SUCCESS)
387 return;
388
389 dcnode = list_head(&smb_dcache.dc_cache);
390 while (dcnode) {
391 if ((dcnode->di_type == SMB_DOMAIN_PRIMARY) ||
392 (dcnode->di_type == SMB_DOMAIN_TRUSTED)) {
503 smb_domain_t *di)
504 {
505 if (sid == NULL || nb_domain == NULL || fq_domain == NULL ||
506 di == NULL)
507 return;
508
509 (void) strlcpy(di->di_sid, sid, SMB_SID_STRSZ);
510 (void) strlcpy(di->di_nbname, nb_domain, NETBIOS_NAME_SZ);
511 (void) smb_strupr(di->di_nbname);
512 (void) strlcpy(di->di_fqname, fq_domain, MAXHOSTNAMELEN);
513 di->di_binsid = NULL;
514 }
515
516 void
517 smb_domain_set_dns_info(char *sid, char *nb_domain, char *fq_domain,
518 char *forest, char *guid, smb_domain_t *di)
519 {
520 if (di == NULL || forest == NULL || guid == NULL)
521 return;
522
523 /* Caller zeros out *di before this. */
524 smb_domain_set_basic_info(sid, nb_domain, fq_domain, di);
525 (void) strlcpy(di->di_u.di_dns.ddi_forest, forest, MAXHOSTNAMELEN);
526 (void) strlcpy(di->di_u.di_dns.ddi_guid, guid,
527 UUID_PRINTABLE_STRING_LENGTH);
528 }
529
530 void
531 smb_domain_set_trust_info(char *sid, char *nb_domain, char *fq_domain,
532 uint32_t trust_dir, uint32_t trust_type, uint32_t trust_attrs,
533 smb_domain_t *di)
534 {
535 smb_domain_trust_t *ti;
536
537 if (di == NULL)
538 return;
539
540 /* Caller zeros out *di before this. */
541 di->di_type = SMB_DOMAIN_TRUSTED;
542 ti = &di->di_u.di_trust;
543 smb_domain_set_basic_info(sid, nb_domain, fq_domain, di);
544 ti->dti_trust_direction = trust_dir;
545 ti->dti_trust_type = trust_type;
546 ti->dti_trust_attrs = trust_attrs;
547 }
548
549 /*
550 * Remove the /var/run/smb/domains file.
551 */
552 static void
553 smb_domain_unlink(void)
554 {
555 char fname[MAXPATHLEN];
556
557 (void) snprintf(fname, MAXPATHLEN, "%s/%s",
558 SMB_VARRUN_DIR, SMB_DOMAINS_FILE);
559 (void) unlink(fname);
560 }
561
562 /*
563 * Add an entry for the local domain to the domain cache
564 */
565 static uint32_t
566 smb_domain_add_local(void)
567 {
568 char *lsidstr;
569 char hostname[NETBIOS_NAME_SZ];
570 char fq_name[MAXHOSTNAMELEN];
571 smb_domain_t di;
572
573 if ((lsidstr = smb_config_get_localsid()) == NULL)
574 return (SMB_DOMAIN_NOMACHINE_SID);
575
576 if (smb_getnetbiosname(hostname, NETBIOS_NAME_SZ) != 0) {
577 free(lsidstr);
578 return (SMB_DOMAIN_NOMACHINE_SID);
579 }
580
581 bzero(&di, sizeof (di));
582 *fq_name = '\0';
583 (void) smb_getfqhostname(fq_name, MAXHOSTNAMELEN);
584 smb_domain_set_basic_info(lsidstr, hostname, fq_name, &di);
585 (void) smb_domain_add(SMB_DOMAIN_LOCAL, &di);
586
587 free(lsidstr);
588 return (SMB_DOMAIN_SUCCESS);
589 }
590
591 /*
592 * Add an entry for the primary domain to the domain cache
593 */
594 static uint32_t
595 smb_domain_add_primary(uint32_t secmode)
596 {
597 char sidstr[SMB_SID_STRSZ];
598 char fq_name[MAXHOSTNAMELEN];
599 char nb_name[NETBIOS_NAME_SZ];
600 smb_domain_t di;
601 int rc;
602
603 if (secmode != SMB_SECMODE_DOMAIN)
604 return (SMB_DOMAIN_SUCCESS);
605
606 rc = smb_config_getstr(SMB_CI_DOMAIN_SID, sidstr, sizeof (sidstr));
607 if (rc != SMBD_SMF_OK)
608 return (SMB_DOMAIN_NODOMAIN_SID);
609
610 rc = smb_config_getstr(SMB_CI_DOMAIN_NAME, nb_name, NETBIOS_NAME_SZ);
611 if ((rc != SMBD_SMF_OK) || (*nb_name == '\0'))
612 return (SMB_DOMAIN_NODOMAIN_NAME);
613
614 bzero(&di, sizeof (di));
615 (void) smb_getfqdomainname(fq_name, MAXHOSTNAMELEN);
616 smb_domain_set_basic_info(sidstr, nb_name, fq_name, &di);
617 (void) smb_domain_add(SMB_DOMAIN_PRIMARY, &di);
618 return (SMB_DOMAIN_SUCCESS);
619 }
620
621 /*
622 * Initialize the domain cache.
623 * This function does not populate the cache.
624 */
625 static void
626 smb_dcache_create(void)
627 {
628 (void) mutex_lock(&smb_dcache.dc_mtx);
629 if (smb_dcache.dc_state != SMB_DCACHE_STATE_NONE) {
630 (void) mutex_unlock(&smb_dcache.dc_mtx);
631 return;
632 }
633
634 list_create(&smb_dcache.dc_cache, sizeof (smb_domain_t),
635 offsetof(smb_domain_t, di_lnd));
636
637 smb_dcache.dc_nops = 0;
638 bzero(&smb_dcache.dc_dci, sizeof (smb_dcache.dc_dci));
639 smb_dcache.dc_dci_valid = B_FALSE;
640 smb_dcache.dc_state = SMB_DCACHE_STATE_READY;
641 (void) mutex_unlock(&smb_dcache.dc_mtx);
642 }
643
644 /*
645 * Removes and frees all the cache entries
646 */
647 static void
648 smb_dcache_flush(void)
649 {
650 smb_domain_t *di;
651
652 (void) rw_wrlock(&smb_dcache.dc_cache_lck);
653 while ((di = list_head(&smb_dcache.dc_cache)) != NULL)
654 smb_dcache_remove(di);
655 (void) rw_unlock(&smb_dcache.dc_cache_lck);
656 }
657
658 /*
659 * Destroys the cache.
676 }
677 (void) mutex_unlock(&smb_dcache.dc_mtx);
678 }
679
680 /*
681 * Lock the cache with the specified mode.
682 * If the cache is in updating state and a read lock is
683 * requested, the lock won't be granted until either the
684 * update is finished or SMB_DCACHE_UPDATE_WAIT has passed.
685 *
686 * Whenever a lock is granted, the number of inflight cache
687 * operations is incremented.
688 */
689 static uint32_t
690 smb_dcache_lock(int mode)
691 {
692 (void) mutex_lock(&smb_dcache.dc_mtx);
693 switch (smb_dcache.dc_state) {
694 case SMB_DCACHE_STATE_NONE:
695 case SMB_DCACHE_STATE_DESTROYING:
696 default:
697 (void) mutex_unlock(&smb_dcache.dc_mtx);
698 return (SMB_DOMAIN_INTERNAL_ERR);
699
700 case SMB_DCACHE_STATE_UPDATING:
701 if (mode == SMB_DCACHE_RDLOCK) {
702 /*
703 * Read operations should wait until the update
704 * is completed.
705 */
706 if (!smb_dcache_wait()) {
707 (void) mutex_unlock(&smb_dcache.dc_mtx);
708 return (SMB_DOMAIN_INTERNAL_ERR);
709 }
710 }
711 /* FALLTHROUGH */
712
713 case SMB_DCACHE_STATE_READY:
714 smb_dcache.dc_nops++;
715 break;
716 }
717 (void) mutex_unlock(&smb_dcache.dc_mtx);
718
719 /*
720 * Lock has to be taken outside the mutex otherwise
721 * there could be a deadlock
722 */
723 if (mode == SMB_DCACHE_RDLOCK)
724 (void) rw_rdlock(&smb_dcache.dc_cache_lck);
725 else
726 (void) rw_wrlock(&smb_dcache.dc_cache_lck);
727
728 return (SMB_DOMAIN_SUCCESS);
729 }
730
731 /*
732 * Decrement the number of inflight operations and then unlock.
733 */
758 return (SMB_DOMAIN_NO_MEMORY);
759 }
760
761 list_insert_tail(&smb_dcache.dc_cache, dcnode);
762 return (SMB_DOMAIN_SUCCESS);
763 }
764
765 static void
766 smb_dcache_remove(smb_domain_t *di)
767 {
768 list_remove(&smb_dcache.dc_cache, di);
769 smb_sid_free(di->di_binsid);
770 free(di);
771 }
772
773 static void
774 smb_dcache_setdc(const smb_dcinfo_t *dci)
775 {
776 (void) mutex_lock(&smb_dcache.dc_mtx);
777 smb_dcache.dc_dci = *dci; /* struct assignment! */
778 smb_dcache.dc_dci_valid = B_TRUE;
779 (void) cond_broadcast(&smb_dcache.dc_dci_cv);
780 (void) mutex_unlock(&smb_dcache.dc_mtx);
781 }
782
783 /*
784 * Get information about our domain controller. If the wait arg
785 * is true, wait for the DC locator to finish before copying.
786 * Returns TRUE on success (have DC info).
787 */
788 static boolean_t
789 smb_dcache_getdc(smb_dcinfo_t *dci, boolean_t wait)
790 {
791 timestruc_t to;
792 boolean_t rv;
793 int err;
794
795 to.tv_sec = time(NULL) + SMB_DCACHE_UPDATE_WAIT;
796 to.tv_nsec = 0;
797
798 (void) mutex_lock(&smb_dcache.dc_mtx);
799
800 while (wait && !smb_dcache.dc_dci_valid) {
801 err = cond_timedwait(&smb_dcache.dc_dci_cv,
802 &smb_dcache.dc_mtx, &to);
803 if (err == ETIME)
804 break;
805 }
806 *dci = smb_dcache.dc_dci; /* struct assignment! */
807 rv = smb_dcache.dc_dci_valid;
808
809 (void) mutex_unlock(&smb_dcache.dc_mtx);
810
811 return (rv);
812 }
813
814 /*
815 * Waits for SMB_DCACHE_UPDATE_WAIT seconds if cache is in
816 * UPDATING state. Upon wake up returns true if cache is
817 * ready to be used, otherwise it returns false.
818 */
819 static boolean_t
820 smb_dcache_wait(void)
821 {
822 timestruc_t to;
823 int err;
824
825 assert(MUTEX_HELD(&smb_dcache.dc_mtx));
826
827 to.tv_sec = time(NULL) + SMB_DCACHE_UPDATE_WAIT;
828 to.tv_nsec = 0;
829 while (smb_dcache.dc_state == SMB_DCACHE_STATE_UPDATING) {
830 err = cond_timedwait(&smb_dcache.dc_cv,
831 &smb_dcache.dc_mtx, &to);
832 if (err == ETIME)
833 break;
834 }
835
836 return (smb_dcache.dc_state == SMB_DCACHE_STATE_READY);
837 }
838
839 /*
840 * Transfers the cache into UPDATING state, this will ensure
841 * any read access to the cache will be stalled until the
842 * update is finished. This is to avoid providing incomplete,
843 * inconsistent or stale information.
844 *
845 * If another thread is already updating the cache, other
846 * callers will wait until cache is no longer in UPDATING
847 * state. The return code is decided based on the new
848 * state of the cache.
849 */
850 static uint32_t
|