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]
23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
28 * Active Directory Auto-Discovery.
30 * This [project private] API allows the caller to provide whatever
31 * details it knows a priori (i.e., provided via configuration so as to
32 * override auto-discovery) and in any order. Then the caller can ask
33 * for any of the auto-discoverable parameters in any order.
35 * But there is an actual order in which discovery must be done. Given
36 * the discovery mechanism implemented here, that order is:
38 * - the domain name joined must be discovered first
39 * - then the domain controllers
40 * - then the forest name and site name
41 * - then the global catalog servers, and site-specific domain
42 * controllers and global catalog servers.
44 * The API does not require it be called in the same order because there
45 * may be other discovery mechanisms in the future, and exposing
46 * ordering requirements of the current mechanism now can create trouble
47 * down the line. Also, this makes the API easier to use now, which
48 * means less work to do some day when we make this a public API.
50 * Domain discovery is done by res_nsearch() of the DNS SRV RR name for
51 * domain controllers. As long as the joined domain appears in the DNS
52 * resolver's search list then we'll find it.
54 * Domain controller discovery is a matter of formatting the DNS SRV RR
55 * FQDN for domain controllers and doing a lookup for them. Knowledge
56 * of the domain name is not fundamentally required, but we separate the
57 * two processes, which in practice can lead to one more DNS lookup than
58 * is strictly required.
60 * Forest and site name discovery require an LDAP search of the AD
61 * "configuration partition" at a domain controller for the joined
62 * domain. Forest and site name discovery depend on knowing the joined
63 * domain name and domain controllers for that domain.
65 * Global catalog server discovery requires knowledge of the forest
66 * name in order to format the DNS SRV RR FQDN to lookup. Site-specific
67 * domain controller discovery depends on knowing the site name (and,
68 * therefore, joined domain, ...). Site-specific global catalog server
69 * discovery depends on knowledge of the forest and site names, which
72 * All the work of discovering particular items is done by functions
73 * named validate_<item>(). Each such function calls validate_<item>()
74 * for any items that it depends on.
76 * This API is not thread-safe.
87 #include <sys/types.h>
88 #include <sys/socket.h>
89 #include <sys/sockio.h>
90 #include <netinet/in.h>
91 #include <arpa/inet.h>
92 #include <arpa/nameser.h>
99 #include <sasl/sasl.h>
100 #include <sys/u8_textprep.h>
102 #include <uuid/uuid.h>
103 #include <ads/dsgetdc.h>
104 #include "adutils_impl.h"
105 #include "addisc_impl.h"
108 * These set some sanity policies for discovery. After a discovery
109 * cycle, we will consider the results (successful or unsuccessful)
110 * to be valid for at least MINIMUM_TTL seconds, and for at most
111 * MAXIMUM_TTL seconds. Note that the caller is free to request
112 * discovery cycles sooner than MINIMUM_TTL if it has reason to believe
113 * that the situation has changed.
115 #define MINIMUM_TTL (5 * 60)
116 #define MAXIMUM_TTL (20 * 60)
119 #define DNS_MAX_NAME NS_MAXDNAME
123 /* SRV RR names for various queries */
124 #define LDAP_SRV_HEAD "_ldap._tcp."
125 #define SITE_SRV_MIDDLE "%s._sites."
126 #define GC_SRV_TAIL "gc._msdcs"
127 #define DC_SRV_TAIL "dc._msdcs"
128 #define ALL_GC_SRV_TAIL "_gc._tcp"
129 #define PDC_SRV "_ldap._tcp.pdc._msdcs.%s"
131 /* A RR name for all GCs -- last resort this works */
132 #define GC_ALL_A_NAME_FSTR "gc._msdcs.%s."
136 * We try res_ninit() whenever we don't have one. res_ninit() fails if
137 * idmapd is running before the network is up!
139 #define DO_RES_NINIT(ctx) \
140 if (!(ctx)->res_ninitted) \
141 (void) do_res_ninit(ctx)
143 #define DO_GETNAMEINFO(b, l, s) \
144 if (ad_disc_getnameinfo(b, l, s) != 0) \
145 (void) strlcpy(b, "?", l)
147 #define DEBUG1STATUS(ctx, ...) do { \
149 logger(LOG_DEBUG, __VA_ARGS__); \
150 if (ctx->status_fp) { \
151 (void) fprintf(ctx->status_fp, __VA_ARGS__); \
152 (void) fprintf(ctx->status_fp, "\n"); \
157 #define is_fixed(item) \
158 ((item)->state == AD_STATE_FIXED)
160 #define is_changed(item, num, param) \
161 ((item)->param_version[num] != (param)->version)
163 void * uuid_dup(void *);
165 static ad_item_t
*validate_SiteName(ad_disc_t ctx
);
166 static ad_item_t
*validate_PreferredDC(ad_disc_t ctx
);
169 * Function definitions
174 do_res_ninit(ad_disc_t ctx
)
178 rc
= res_ninit(&ctx
->res_state
);
181 ctx
->res_ninitted
= 1;
183 * The SRV records returnd by AD can be larger than 512 bytes,
184 * so we'd like to use TCP for those searches. Unfortunately,
185 * the TCP connect timeout seen by the resolver is very long
186 * (more than a couple minutes) and we can't wait that long.
187 * Don't do use TCP until we can override the timeout.
189 * Note that some queries will try TCP anyway.
192 ctx
->res_state
.options
|= RES_USEVC
;
198 * Private getnameinfo(3socket) variant tailored to our needs.
201 ad_disc_getnameinfo(char *obuf
, int olen
, struct sockaddr_storage
*ss
)
207 switch (sa
->sa_family
) {
209 slen
= sizeof (struct sockaddr_in
);
212 slen
= sizeof (struct sockaddr_in6
);
218 eai
= getnameinfo(sa
, slen
, obuf
, olen
, NULL
, 0, NI_NUMERICHOST
);
224 update_version(ad_item_t
*item
, int num
, ad_item_t
*param
)
226 item
->param_version
[num
] = param
->version
;
232 is_valid(ad_item_t
*item
)
234 if (item
->value
!= NULL
) {
235 if (item
->state
== AD_STATE_FIXED
)
237 if (item
->state
== AD_STATE_AUTO
&&
238 (item
->expires
== 0 || item
->expires
> time(NULL
)))
246 update_item(ad_item_t
*item
, void *value
, enum ad_item_state state
,
249 if (item
->value
!= NULL
&& value
!= NULL
) {
250 if ((item
->type
== AD_STRING
&&
251 strcmp(item
->value
, value
) != 0) ||
252 (item
->type
== AD_UUID
&&
253 ad_disc_compare_uuid(item
->value
, value
) != 0)||
254 (item
->type
== AD_DIRECTORY
&&
255 ad_disc_compare_ds(item
->value
, value
) != 0)||
256 (item
->type
== AD_DOMAINS_IN_FOREST
&&
257 ad_disc_compare_domainsinforest(item
->value
, value
) != 0) ||
258 (item
->type
== AD_TRUSTED_DOMAINS
&&
259 ad_disc_compare_trusteddomains(item
->value
, value
) != 0))
261 } else if (item
->value
!= value
)
272 item
->expires
= time(NULL
) + ttl
;
277 ad_disc_compare_uuid(uuid_t
*u1
, uuid_t
*u2
)
281 rc
= memcmp(u1
, u2
, UUID_LEN
);
289 dst
= malloc(UUID_LEN
);
291 (void) memcpy(dst
, src
, UUID_LEN
);
295 /* Compare DS lists */
297 ad_disc_compare_ds(ad_disc_ds_t
*ds1
, ad_disc_ds_t
*ds2
)
304 for (i
= 0; ds1
[i
].host
[0] != '\0'; i
++)
307 for (j
= 0; ds2
[j
].host
[0] != '\0'; j
++)
310 if (num_ds1
!= num_ds2
)
313 for (i
= 0; i
< num_ds1
; i
++) {
315 for (j
= 0; j
< num_ds2
; j
++) {
316 if (strcmp(ds1
[i
].host
, ds2
[j
].host
) == 0 &&
317 ds1
[i
].port
== ds2
[j
].port
) {
329 /* Copy a list of DSs */
330 static ad_disc_ds_t
*
331 ds_dup(const ad_disc_ds_t
*srv
)
335 ad_disc_ds_t
*new = NULL
;
337 for (i
= 0; srv
[i
].host
[0] != '\0'; i
++)
340 size
= (i
+ 1) * sizeof (ad_disc_ds_t
);
343 (void) memcpy(new, srv
, size
);
349 ad_disc_compare_trusteddomains(ad_disc_trusteddomains_t
*td1
,
350 ad_disc_trusteddomains_t
*td2
)
357 for (i
= 0; td1
[i
].domain
[0] != '\0'; i
++)
361 for (j
= 0; td2
[j
].domain
[0] != '\0'; j
++)
365 if (num_td1
!= num_td2
)
368 for (i
= 0; i
< num_td1
; i
++) {
370 for (j
= 0; j
< num_td2
; j
++) {
371 if (domain_eq(td1
[i
].domain
, td2
[j
].domain
)) {
384 /* Copy a list of Trusted Domains */
385 static ad_disc_trusteddomains_t
*
386 td_dup(const ad_disc_trusteddomains_t
*td
)
390 ad_disc_trusteddomains_t
*new = NULL
;
392 for (i
= 0; td
[i
].domain
[0] != '\0'; i
++)
395 size
= (i
+ 1) * sizeof (ad_disc_trusteddomains_t
);
398 (void) memcpy(new, td
, size
);
405 ad_disc_compare_domainsinforest(ad_disc_domainsinforest_t
*df1
,
406 ad_disc_domainsinforest_t
*df2
)
413 for (i
= 0; df1
[i
].domain
[0] != '\0'; i
++)
417 for (j
= 0; df2
[j
].domain
[0] != '\0'; j
++)
421 if (num_df1
!= num_df2
)
424 for (i
= 0; i
< num_df1
; i
++) {
426 for (j
= 0; j
< num_df2
; j
++) {
427 if (domain_eq(df1
[i
].domain
, df2
[j
].domain
) &&
428 strcmp(df1
[i
].sid
, df2
[j
].sid
) == 0) {
441 /* Copy a list of Trusted Domains */
442 static ad_disc_domainsinforest_t
*
443 df_dup(const ad_disc_domainsinforest_t
*df
)
447 ad_disc_domainsinforest_t
*new = NULL
;
449 for (i
= 0; df
[i
].domain
[0] != '\0'; i
++)
452 size
= (i
+ 1) * sizeof (ad_disc_domainsinforest_t
);
455 (void) memcpy(new, df
, size
);
464 * Returns an array of IPv4 address/prefix length
465 * The last subnet is NULL
472 struct lifreq lifr
, *lifrp
;
476 ad_subnet_t
*results
;
480 if ((sock
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
481 logger(LOG_ERR
, "Failed to open IPv4 socket for "
482 "listing network interfaces (%s)", strerror(errno
));
486 lifn
.lifn_family
= AF_INET
;
488 if (ioctl(sock
, SIOCGLIFNUM
, (char *)&lifn
) < 0) {
490 "Failed to find the number of network interfaces (%s)",
496 if (lifn
.lifn_count
< 1) {
497 logger(LOG_ERR
, "No IPv4 network interfaces found");
502 lifc
.lifc_family
= AF_INET
;
504 lifc
.lifc_len
= lifn
.lifn_count
* sizeof (struct lifreq
);
505 lifc
.lifc_buf
= malloc(lifc
.lifc_len
);
507 if (lifc
.lifc_buf
== NULL
) {
508 logger(LOG_ERR
, "Out of memory");
513 if (ioctl(sock
, SIOCGLIFCONF
, (char *)&lifc
) < 0) {
514 logger(LOG_ERR
, "Failed to list network interfaces (%s)",
521 n
= lifc
.lifc_len
/ (int)sizeof (struct lifreq
);
523 if ((results
= calloc(n
+ 1, sizeof (ad_subnet_t
))) == NULL
) {
529 for (i
= 0, lifrp
= lifc
.lifc_req
; i
< n
; i
++, lifrp
++) {
530 if (ioctl(sock
, SIOCGLIFFLAGS
, lifrp
) < 0)
533 if ((lifrp
->lifr_flags
& IFF_UP
) == 0)
536 if (ioctl(sock
, SIOCGLIFSUBNET
, lifrp
) < 0)
539 prefix_len
= lifrp
->lifr_addrlen
;
541 s
= inet_ntoa(((struct sockaddr_in
*)
542 &lifrp
->lifr_addr
)->sin_addr
);
544 (void) snprintf(results
[i
].subnet
, sizeof (ad_subnet_t
),
545 "%s/%d", s
, prefix_len
);
555 cmpsubnets(ad_subnet_t
*subnets1
, ad_subnet_t
*subnets2
)
562 for (i
= 0; subnets1
[i
].subnet
[0] != '\0'; i
++)
566 for (i
= 0; subnets2
[i
].subnet
[0] != '\0'; i
++)
570 if (num_subnets1
!= num_subnets2
)
573 for (i
= 0; i
< num_subnets1
; i
++) {
575 for (j
= 0; j
< num_subnets2
; j
++) {
576 if (strcmp(subnets1
[i
].subnet
,
577 subnets2
[j
].subnet
) == 0) {
591 /* Convert a DN's DC components into a DNS domainname */
593 DN_to_DNS(const char *dn_name
)
595 char dns
[DNS_MAX_NAME
];
606 * Find all DC=<value> and form DNS name of the
607 * form <value1>.<value2>...
609 while (dn_name
[i
] != '\0') {
610 if (strncasecmp(&dn_name
[i
], "DC=", 3) == 0) {
612 if (dn_name
[i
] != '\0' && num
> 0)
614 while (dn_name
[i
] != '\0' &&
615 dn_name
[i
] != ',' && dn_name
[i
] != '+')
616 dns
[j
++] = dn_name
[i
++];
619 /* Skip attr=value as it is not DC= */
620 while (dn_name
[i
] != '\0' &&
621 dn_name
[i
] != ',' && dn_name
[i
] != '+')
624 /* Skip over separator ',' or '+' */
625 if (dn_name
[i
] != '\0') i
++;
628 dns_name
= malloc(j
+ 1);
629 if (dns_name
!= NULL
)
630 (void) strlcpy(dns_name
, dns
, j
+ 1);
636 * A utility function to bind to a Directory server
641 ldap_lookup_init(ad_disc_ds_t
*ds
)
646 int timeoutms
= 5 * 1000;
647 char *saslmech
= "GSSAPI";
648 uint32_t saslflags
= LDAP_SASL_INTERACTIVE
;
651 for (i
= 0; ds
[i
].host
[0] != '\0'; i
++) {
653 logger(LOG_DEBUG
, "adutils: ldap_lookup_init, host %s",
657 ld
= ldap_init(ds
[i
].host
, ds
[i
].port
);
661 "Couldn't connect to AD DC %s:%d (%s)",
662 ds
[i
].host
, ds
[i
].port
,
668 ldversion
= LDAP_VERSION3
;
669 (void) ldap_set_option(ld
, LDAP_OPT_PROTOCOL_VERSION
,
671 (void) ldap_set_option(ld
, LDAP_OPT_REFERRALS
,
673 (void) ldap_set_option(ld
, LDAP_OPT_TIMELIMIT
, &zero
);
674 (void) ldap_set_option(ld
, LDAP_OPT_SIZELIMIT
, &zero
);
675 /* setup TCP/IP connect timeout */
676 (void) ldap_set_option(ld
, LDAP_X_OPT_CONNECT_TIMEOUT
,
678 (void) ldap_set_option(ld
, LDAP_OPT_RESTART
,
681 rc
= adutils_set_thread_functions(ld
);
682 if (rc
!= LDAP_SUCCESS
) {
683 /* Error has already been logged */
684 (void) ldap_unbind(ld
);
689 rc
= ldap_sasl_interactive_bind_s(ld
, "" /* binddn */,
690 saslmech
, NULL
, NULL
, saslflags
, &saslcallback
,
691 NULL
/* defaults */);
692 if (rc
== LDAP_SUCCESS
)
696 logger(LOG_INFO
, "LDAP: %s:%d: %s",
697 ds
[i
].host
, ds
[i
].port
, ldap_err2string(rc
));
698 ldap_perror(ld
, ds
[i
].host
);
700 (void) ldap_unbind(ld
);
709 * Lookup the trusted domains in the global catalog.
712 * array of trusted domains which is terminated by
713 * an empty trusted domain.
714 * NULL an error occured
716 ad_disc_trusteddomains_t
*
717 ldap_lookup_trusted_domains(LDAP
**ld
, ad_disc_ds_t
*globalCatalog
,
720 int scope
= LDAP_SCOPE_SUBTREE
;
723 LDAPMessage
*results
= NULL
;
726 char **partner
= NULL
;
727 char **direction
= NULL
;
729 ad_disc_trusteddomains_t
*trusted_domains
= NULL
;
732 logger(LOG_DEBUG
, "Looking for trusted domains...");
735 *ld
= ldap_lookup_init(globalCatalog
);
738 logger(LOG_ERR
, "adutils: ldap_lookup_init failed");
742 attrs
[0] = "trustPartner";
743 attrs
[1] = "trustDirection";
747 * Trust direction values:
748 * 1 - inbound (they trust us)
749 * 2 - outbound (we trust them)
750 * 3 - bidirectional (we trust each other)
752 filter
= "(&(objectclass=trustedDomain)"
753 "(|(trustDirection=3)(trustDirection=2)))";
755 rc
= ldap_search_s(*ld
, base_dn
, scope
, filter
, attrs
, 0, &results
);
757 logger(LOG_DEBUG
, "Trusted domains:");
758 if (rc
== LDAP_SUCCESS
) {
759 for (entry
= ldap_first_entry(*ld
, results
);
760 entry
!= NULL
; entry
= ldap_next_entry(*ld
, entry
)) {
761 partner
= ldap_get_values(*ld
, entry
, "trustPartner");
762 direction
= ldap_get_values(
763 *ld
, entry
, "trustDirection");
765 if (partner
!= NULL
&& direction
!= NULL
) {
767 logger(LOG_DEBUG
, " %s (%s)",
768 partner
[0], direction
[0]);
771 void *tmp
= realloc(trusted_domains
,
773 sizeof (ad_disc_trusteddomains_t
));
775 free(trusted_domains
);
776 ldap_value_free(partner
);
777 ldap_value_free(direction
);
778 (void) ldap_msgfree(results
);
781 trusted_domains
= tmp
;
782 /* Last element should be zero */
783 (void) memset(&trusted_domains
[num
], 0,
784 sizeof (ad_disc_trusteddomains_t
));
785 (void) strcpy(trusted_domains
[num
- 1].domain
,
787 trusted_domains
[num
- 1].direction
=
791 ldap_value_free(partner
);
792 if (direction
!= NULL
)
793 ldap_value_free(direction
);
795 } else if (rc
== LDAP_NO_RESULTS_RETURNED
) {
796 /* This is not an error - return empty trusted domain */
797 trusted_domains
= calloc(1, sizeof (ad_disc_trusteddomains_t
));
799 logger(LOG_DEBUG
, " not found");
802 logger(LOG_DEBUG
, " rc=%d", rc
);
805 (void) ldap_msgfree(results
);
807 return (trusted_domains
);
812 * This functions finds all the domains in a forest.
814 ad_disc_domainsinforest_t
*
815 ldap_lookup_domains_in_forest(LDAP
**ld
, ad_disc_ds_t
*globalCatalogs
)
817 static char *attrs
[] = {
822 LDAPMessage
*result
= NULL
;
826 ad_disc_domainsinforest_t
*domains
= NULL
;
829 logger(LOG_DEBUG
, "Looking for domains in forest...");
832 *ld
= ldap_lookup_init(globalCatalogs
);
835 logger(LOG_ERR
, "adutils: ldap_lookup_init failed");
840 rc
= ldap_search_s(*ld
, "", LDAP_SCOPE_SUBTREE
,
841 "(objectClass=Domain)", attrs
, 0, &result
);
842 if (rc
!= LDAP_SUCCESS
) {
843 logger(LOG_ERR
, "adutils: ldap_search, rc=%d", rc
);
847 logger(LOG_DEBUG
, "Domains in forest:");
849 nresults
= ldap_count_entries(*ld
, result
);
850 domains
= calloc(nresults
+ 1, sizeof (*domains
));
851 if (domains
== NULL
) {
853 logger(LOG_DEBUG
, " (nomem)");
857 for (entry
= ldap_first_entry(*ld
, result
);
859 entry
= ldap_next_entry(*ld
, entry
)) {
860 struct berval
**sid_ber
;
866 sid_ber
= ldap_get_values_len(*ld
, entry
,
871 rc
= adutils_getsid(sid_ber
[0], &sid
);
872 ldap_value_free_len(sid_ber
);
876 if ((sid_str
= adutils_sid2txt(&sid
)) == NULL
)
879 (void) strcpy(domains
[ndomains
].sid
, sid_str
);
882 dn
= ldap_get_dn(*ld
, entry
);
883 name
= DN_to_DNS(dn
);
888 (void) strcpy(domains
[ndomains
].domain
, name
);
892 logger(LOG_DEBUG
, " %s", domains
[ndomains
].domain
);
899 logger(LOG_DEBUG
, " not found");
903 if (ndomains
< nresults
) {
904 ad_disc_domainsinforest_t
*tmp
;
905 tmp
= realloc(domains
, (ndomains
+ 1) * sizeof (*domains
));
912 (void) ldap_msgfree(result
);
919 (void) ldap_msgfree(result
);
928 ctx
= calloc(1, sizeof (struct ad_disc
));
932 ctx
->domain_name
.type
= AD_STRING
;
933 ctx
->domain_guid
.type
= AD_UUID
;
934 ctx
->domain_controller
.type
= AD_DIRECTORY
;
935 ctx
->preferred_dc
.type
= AD_DIRECTORY
;
936 ctx
->site_name
.type
= AD_STRING
;
937 ctx
->forest_name
.type
= AD_STRING
;
938 ctx
->global_catalog
.type
= AD_DIRECTORY
;
939 ctx
->domains_in_forest
.type
= AD_DOMAINS_IN_FOREST
;
940 ctx
->trusted_domains
.type
= AD_TRUSTED_DOMAINS
;
941 /* Site specific versions */
942 ctx
->site_domain_controller
.type
= AD_DIRECTORY
;
943 ctx
->site_global_catalog
.type
= AD_DIRECTORY
;
948 ad_disc_fini(ad_disc_t ctx
)
953 if (ctx
->res_ninitted
)
954 res_ndestroy(&ctx
->res_state
);
958 free(ctx
->domain_name
.value
);
960 free(ctx
->domain_guid
.value
);
962 free(ctx
->domain_controller
.value
);
964 free(ctx
->preferred_dc
.value
);
966 free(ctx
->site_name
.value
);
968 free(ctx
->forest_name
.value
);
970 free(ctx
->global_catalog
.value
);
972 free(ctx
->domains_in_forest
.value
);
974 free(ctx
->trusted_domains
.value
);
976 /* Site specific versions */
977 free(ctx
->site_domain_controller
.value
);
979 free(ctx
->site_global_catalog
.value
);
985 ad_disc_refresh(ad_disc_t ctx
)
987 if (ctx
->res_ninitted
) {
988 res_ndestroy(&ctx
->res_state
);
989 ctx
->res_ninitted
= 0;
991 (void) memset(&ctx
->res_state
, 0, sizeof (ctx
->res_state
));
994 if (ctx
->domain_name
.state
== AD_STATE_AUTO
)
995 ctx
->domain_name
.state
= AD_STATE_INVALID
;
997 if (ctx
->domain_guid
.state
== AD_STATE_AUTO
)
998 ctx
->domain_guid
.state
= AD_STATE_INVALID
;
1000 if (ctx
->domain_controller
.state
== AD_STATE_AUTO
)
1001 ctx
->domain_controller
.state
= AD_STATE_INVALID
;
1003 if (ctx
->preferred_dc
.state
== AD_STATE_AUTO
)
1004 ctx
->preferred_dc
.state
= AD_STATE_INVALID
;
1006 if (ctx
->site_name
.state
== AD_STATE_AUTO
)
1007 ctx
->site_name
.state
= AD_STATE_INVALID
;
1009 if (ctx
->forest_name
.state
== AD_STATE_AUTO
)
1010 ctx
->forest_name
.state
= AD_STATE_INVALID
;
1012 if (ctx
->global_catalog
.state
== AD_STATE_AUTO
)
1013 ctx
->global_catalog
.state
= AD_STATE_INVALID
;
1015 if (ctx
->domains_in_forest
.state
== AD_STATE_AUTO
)
1016 ctx
->domains_in_forest
.state
= AD_STATE_INVALID
;
1018 if (ctx
->trusted_domains
.state
== AD_STATE_AUTO
)
1019 ctx
->trusted_domains
.state
= AD_STATE_INVALID
;
1021 if (ctx
->site_domain_controller
.state
== AD_STATE_AUTO
)
1022 ctx
->site_domain_controller
.state
= AD_STATE_INVALID
;
1024 if (ctx
->site_global_catalog
.state
== AD_STATE_AUTO
)
1025 ctx
->site_global_catalog
.state
= AD_STATE_INVALID
;
1030 * Called when the discovery cycle is done. Sets a master TTL
1031 * that will avoid doing new time-based discoveries too soon after
1032 * the last discovery cycle. Most interesting when the discovery
1033 * cycle failed, because then the TTLs on the individual items will
1034 * not be updated and may go stale.
1037 ad_disc_done(ad_disc_t ctx
)
1039 time_t now
= time(NULL
);
1041 ctx
->expires_not_before
= now
+ MINIMUM_TTL
;
1042 ctx
->expires_not_after
= now
+ MAXIMUM_TTL
;
1046 log_cds(ad_disc_t ctx
, ad_disc_cds_t
*cds
)
1048 char buf
[INET6_ADDRSTRLEN
];
1049 struct addrinfo
*ai
;
1051 if (!DBG(DISC
, 1) && ctx
->status_fp
== NULL
)
1054 DEBUG1STATUS(ctx
, "Candidate servers:");
1055 if (cds
->cds_ds
.host
[0] == '\0') {
1056 DEBUG1STATUS(ctx
, " (empty list)");
1060 while (cds
->cds_ds
.host
[0] != '\0') {
1062 DEBUG1STATUS(ctx
, " %s p=%d w=%d",
1064 cds
->cds_ds
.priority
,
1065 cds
->cds_ds
.weight
);
1069 DEBUG1STATUS(ctx
, " (no address)");
1071 while (ai
!= NULL
) {
1074 eai
= getnameinfo(ai
->ai_addr
, ai
->ai_addrlen
,
1075 buf
, sizeof (buf
), NULL
, 0, NI_NUMERICHOST
);
1077 (void) strlcpy(buf
, "?", sizeof (buf
));
1079 DEBUG1STATUS(ctx
, " %s", buf
);
1087 log_ds(ad_disc_t ctx
, ad_disc_ds_t
*ds
)
1089 char buf
[INET6_ADDRSTRLEN
];
1091 if (!DBG(DISC
, 1) && ctx
->status_fp
== NULL
)
1094 DEBUG1STATUS(ctx
, "Responding servers:");
1095 if (ds
->host
[0] == '\0') {
1096 DEBUG1STATUS(ctx
, " (empty list)");
1100 while (ds
->host
[0] != '\0') {
1102 DEBUG1STATUS(ctx
, " %s", ds
->host
);
1103 DO_GETNAMEINFO(buf
, sizeof (buf
), &ds
->addr
);
1104 DEBUG1STATUS(ctx
, " %s", buf
);
1110 /* Discover joined Active Directory domainName */
1112 validate_DomainName(ad_disc_t ctx
)
1114 char *dname
, *srvname
;
1117 if (is_valid(&ctx
->domain_name
))
1118 return (&ctx
->domain_name
);
1121 /* Try to find our domain by searching for DCs for it */
1124 logger(LOG_DEBUG
, "Looking for our AD domain name...");
1125 rc
= srv_getdom(&ctx
->res_state
,
1126 LDAP_SRV_HEAD DC_SRV_TAIL
, &srvname
);
1129 * If we can't find DCs by via res_nsearch() then there's no
1130 * point in trying anything else to discover the AD domain name.
1134 logger(LOG_DEBUG
, "Can't find our domain name.");
1139 * We have the FQDN of the SRV RR name, so now we extract the
1140 * domainname suffix from it.
1142 dname
= strdup(srvname
+ strlen(LDAP_SRV_HEAD DC_SRV_TAIL
) +
1143 1 /* for the dot between RR name and domainname */);
1147 if (dname
== NULL
) {
1148 logger(LOG_ERR
, "Out of memory");
1152 /* Eat any trailing dot */
1153 len
= strlen(dname
);
1154 if (len
> 0 && dname
[len
- 1] == '.')
1155 dname
[len
- 1] = '\0';
1158 logger(LOG_DEBUG
, "Our domain name: %s", dname
);
1161 * There is no "time to live" on the discovered domain,
1162 * so passing zero as TTL here, making it non-expiring.
1163 * Note that current consumers do not auto-discover the
1164 * domain name, though a future installer could.
1166 update_item(&ctx
->domain_name
, dname
, AD_STATE_AUTO
, 0);
1168 return (&ctx
->domain_name
);
1173 ad_disc_get_DomainName(ad_disc_t ctx
, boolean_t
*auto_discovered
)
1175 char *domain_name
= NULL
;
1176 ad_item_t
*domain_name_item
;
1178 domain_name_item
= validate_DomainName(ctx
);
1180 if (domain_name_item
) {
1181 domain_name
= strdup(domain_name_item
->value
);
1182 if (auto_discovered
!= NULL
)
1184 (domain_name_item
->state
== AD_STATE_AUTO
);
1185 } else if (auto_discovered
!= NULL
)
1186 *auto_discovered
= B_FALSE
;
1188 return (domain_name
);
1192 /* Discover domain controllers */
1194 validate_DomainController(ad_disc_t ctx
, enum ad_disc_req req
)
1196 ad_disc_ds_t
*dc
= NULL
;
1197 ad_disc_cds_t
*cdc
= NULL
;
1198 boolean_t validate_global
= B_FALSE
;
1199 boolean_t validate_site
= B_FALSE
;
1200 ad_item_t
*domain_name_item
;
1202 ad_item_t
*site_name_item
= NULL
;
1204 ad_item_t
*prefer_dc_item
;
1205 ad_disc_ds_t
*prefer_dc
= NULL
;
1207 /* If the values is fixed there will not be a site specific version */
1208 if (is_fixed(&ctx
->domain_controller
))
1209 return (&ctx
->domain_controller
);
1211 domain_name_item
= validate_DomainName(ctx
);
1212 if (domain_name_item
== NULL
)
1214 domain_name
= (char *)domain_name_item
->value
;
1216 /* Get (optional) preferred DC. */
1217 prefer_dc_item
= validate_PreferredDC(ctx
);
1218 if (prefer_dc_item
!= NULL
)
1219 prefer_dc
= prefer_dc_item
->value
;
1221 if (req
== AD_DISC_GLOBAL
)
1222 validate_global
= B_TRUE
;
1224 if (is_fixed(&ctx
->site_name
))
1225 validate_site
= B_TRUE
;
1226 else if (req
== AD_DISC_PREFER_SITE
)
1227 validate_global
= B_TRUE
;
1230 if (validate_global
) {
1231 if (!is_valid(&ctx
->domain_controller
) ||
1232 is_changed(&ctx
->domain_controller
, PARAM1
,
1233 domain_name_item
)) {
1236 * Lookup DNS SRV RR named
1237 * _ldap._tcp.dc._msdcs.<DomainName>
1239 DEBUG1STATUS(ctx
, "DNS SRV query, dom=%s",
1242 cdc
= srv_query(&ctx
->res_state
,
1243 LDAP_SRV_HEAD DC_SRV_TAIL
,
1244 domain_name
, prefer_dc
);
1247 DEBUG1STATUS(ctx
, "(no DNS response)");
1253 * Filter out unresponsive servers, and
1254 * save the domain info we get back.
1265 DEBUG1STATUS(ctx
, "(no LDAP response)");
1270 update_item(&ctx
->domain_controller
, dc
,
1271 AD_STATE_AUTO
, dc
->ttl
);
1272 update_version(&ctx
->domain_controller
, PARAM1
,
1275 return (&ctx
->domain_controller
);
1278 if (validate_site
) {
1279 site_name_item
= &ctx
->site_name
;
1280 site_name
= (char *)site_name_item
->value
;
1282 if (!is_valid(&ctx
->site_domain_controller
) ||
1283 is_changed(&ctx
->site_domain_controller
, PARAM1
,
1284 domain_name_item
) ||
1285 is_changed(&ctx
->site_domain_controller
, PARAM2
,
1287 char rr_name
[DNS_MAX_NAME
];
1290 * Lookup DNS SRV RR named
1291 * _ldap._tcp.<SiteName>._sites.dc._msdcs.<DomainName>
1293 DEBUG1STATUS(ctx
, "DNS SRV query, dom=%s, site=%s",
1294 domain_name
, site_name
);
1295 (void) snprintf(rr_name
, sizeof (rr_name
),
1296 LDAP_SRV_HEAD SITE_SRV_MIDDLE DC_SRV_TAIL
,
1299 cdc
= srv_query(&ctx
->res_state
, rr_name
,
1300 domain_name
, prefer_dc
);
1303 DEBUG1STATUS(ctx
, "(no DNS response)");
1309 * Filter out unresponsive servers, and
1310 * save the domain info we get back.
1321 DEBUG1STATUS(ctx
, "(no LDAP response)");
1326 update_item(&ctx
->site_domain_controller
, dc
,
1327 AD_STATE_AUTO
, dc
->ttl
);
1328 update_version(&ctx
->site_domain_controller
, PARAM1
,
1330 update_version(&ctx
->site_domain_controller
, PARAM2
,
1333 return (&ctx
->site_domain_controller
);
1339 ad_disc_get_DomainController(ad_disc_t ctx
, enum ad_disc_req req
,
1340 boolean_t
*auto_discovered
)
1342 ad_item_t
*domain_controller_item
;
1343 ad_disc_ds_t
*domain_controller
= NULL
;
1345 domain_controller_item
= validate_DomainController(ctx
, req
);
1347 if (domain_controller_item
!= NULL
) {
1348 domain_controller
= ds_dup(domain_controller_item
->value
);
1349 if (auto_discovered
!= NULL
)
1351 (domain_controller_item
->state
== AD_STATE_AUTO
);
1352 } else if (auto_discovered
!= NULL
)
1353 *auto_discovered
= B_FALSE
;
1355 return (domain_controller
);
1360 * Discover the Domain GUID
1361 * This info comes from validate_DomainController()
1364 validate_DomainGUID(ad_disc_t ctx
)
1366 ad_item_t
*domain_controller_item
;
1368 if (is_fixed(&ctx
->domain_guid
))
1369 return (&ctx
->domain_guid
);
1371 domain_controller_item
= validate_DomainController(ctx
, AD_DISC_GLOBAL
);
1372 if (domain_controller_item
== NULL
)
1375 if (!is_valid(&ctx
->domain_guid
))
1378 return (&ctx
->domain_guid
);
1383 ad_disc_get_DomainGUID(ad_disc_t ctx
, boolean_t
*auto_discovered
)
1385 ad_item_t
*domain_guid_item
;
1386 uchar_t
*domain_guid
= NULL
;
1388 domain_guid_item
= validate_DomainGUID(ctx
);
1389 if (domain_guid_item
!= NULL
) {
1390 domain_guid
= uuid_dup(domain_guid_item
->value
);
1391 if (auto_discovered
!= NULL
)
1393 (domain_guid_item
->state
== AD_STATE_AUTO
);
1394 } else if (auto_discovered
!= NULL
)
1395 *auto_discovered
= B_FALSE
;
1397 return (domain_guid
);
1402 * Discover site name (for multi-homed systems the first one found wins)
1403 * This info comes from validate_DomainController()
1406 validate_SiteName(ad_disc_t ctx
)
1408 ad_item_t
*domain_controller_item
;
1410 if (is_fixed(&ctx
->site_name
))
1411 return (&ctx
->site_name
);
1413 domain_controller_item
= validate_DomainController(ctx
, AD_DISC_GLOBAL
);
1414 if (domain_controller_item
== NULL
)
1417 if (!is_valid(&ctx
->site_name
))
1420 return (&ctx
->site_name
);
1425 ad_disc_get_SiteName(ad_disc_t ctx
, boolean_t
*auto_discovered
)
1427 ad_item_t
*site_name_item
;
1428 char *site_name
= NULL
;
1430 site_name_item
= validate_SiteName(ctx
);
1431 if (site_name_item
!= NULL
) {
1432 site_name
= strdup(site_name_item
->value
);
1433 if (auto_discovered
!= NULL
)
1435 (site_name_item
->state
== AD_STATE_AUTO
);
1436 } else if (auto_discovered
!= NULL
)
1437 *auto_discovered
= B_FALSE
;
1445 * Discover forest name
1446 * This info comes from validate_DomainController()
1449 validate_ForestName(ad_disc_t ctx
)
1451 ad_item_t
*domain_controller_item
;
1453 if (is_fixed(&ctx
->forest_name
))
1454 return (&ctx
->forest_name
);
1456 domain_controller_item
= validate_DomainController(ctx
, AD_DISC_GLOBAL
);
1457 if (domain_controller_item
== NULL
)
1460 if (!is_valid(&ctx
->forest_name
))
1463 return (&ctx
->forest_name
);
1468 ad_disc_get_ForestName(ad_disc_t ctx
, boolean_t
*auto_discovered
)
1470 ad_item_t
*forest_name_item
;
1471 char *forest_name
= NULL
;
1473 forest_name_item
= validate_ForestName(ctx
);
1475 if (forest_name_item
!= NULL
) {
1476 forest_name
= strdup(forest_name_item
->value
);
1477 if (auto_discovered
!= NULL
)
1479 (forest_name_item
->state
== AD_STATE_AUTO
);
1480 } else if (auto_discovered
!= NULL
)
1481 *auto_discovered
= B_FALSE
;
1483 return (forest_name
);
1487 /* Discover global catalog servers */
1489 validate_GlobalCatalog(ad_disc_t ctx
, enum ad_disc_req req
)
1491 ad_disc_ds_t
*gc
= NULL
;
1492 ad_disc_cds_t
*cgc
= NULL
;
1493 boolean_t validate_global
= B_FALSE
;
1494 boolean_t validate_site
= B_FALSE
;
1496 ad_item_t
*forest_name_item
;
1497 ad_item_t
*site_name_item
;
1501 /* If the values is fixed there will not be a site specific version */
1502 if (is_fixed(&ctx
->global_catalog
))
1503 return (&ctx
->global_catalog
);
1505 forest_name_item
= validate_ForestName(ctx
);
1506 if (forest_name_item
== NULL
)
1508 forest_name
= (char *)forest_name_item
->value
;
1510 if (req
== AD_DISC_GLOBAL
)
1511 validate_global
= B_TRUE
;
1513 if (is_fixed(&ctx
->site_name
))
1514 validate_site
= B_TRUE
;
1515 else if (req
== AD_DISC_PREFER_SITE
)
1516 validate_global
= B_TRUE
;
1519 if (validate_global
) {
1520 if (!is_valid(&ctx
->global_catalog
) ||
1521 is_changed(&ctx
->global_catalog
, PARAM1
,
1522 forest_name_item
)) {
1525 * See if our DC is also a GC.
1527 dc_item
= validate_DomainController(ctx
, req
);
1528 if (dc_item
!= NULL
) {
1529 ad_disc_ds_t
*ds
= dc_item
->value
;
1530 if ((ds
->flags
& DS_GC_FLAG
) != 0) {
1532 "DC is also a GC for %s",
1543 * Lookup DNS SRV RR named:
1544 * _ldap._tcp.gc._msdcs.<ForestName>
1546 DEBUG1STATUS(ctx
, "DNS SRV query, forest=%s",
1549 cgc
= srv_query(&ctx
->res_state
,
1550 LDAP_SRV_HEAD GC_SRV_TAIL
,
1554 DEBUG1STATUS(ctx
, "(no DNS response)");
1560 * Filter out unresponsive servers, and
1561 * save the domain info we get back.
1572 DEBUG1STATUS(ctx
, "(no LDAP response)");
1578 update_item(&ctx
->global_catalog
, gc
,
1579 AD_STATE_AUTO
, gc
->ttl
);
1580 update_version(&ctx
->global_catalog
, PARAM1
,
1583 return (&ctx
->global_catalog
);
1586 if (validate_site
) {
1587 site_name_item
= &ctx
->site_name
;
1588 site_name
= (char *)site_name_item
->value
;
1590 if (!is_valid(&ctx
->site_global_catalog
) ||
1591 is_changed(&ctx
->site_global_catalog
, PARAM1
,
1592 forest_name_item
) ||
1593 is_changed(&ctx
->site_global_catalog
, PARAM2
,
1595 char rr_name
[DNS_MAX_NAME
];
1598 * See if our DC is also a GC.
1600 dc_item
= validate_DomainController(ctx
, req
);
1601 if (dc_item
!= NULL
) {
1602 ad_disc_ds_t
*ds
= dc_item
->value
;
1603 if ((ds
->flags
& DS_GC_FLAG
) != 0) {
1605 "DC is also a GC for %s in %s",
1606 forest_name
, site_name
);
1616 * Lookup DNS SRV RR named:
1617 * _ldap._tcp.<siteName>._sites.gc.
1618 * _msdcs.<ForestName>
1620 DEBUG1STATUS(ctx
, "DNS SRV query, forest=%s, site=%s",
1621 forest_name
, site_name
);
1622 (void) snprintf(rr_name
, sizeof (rr_name
),
1623 LDAP_SRV_HEAD SITE_SRV_MIDDLE GC_SRV_TAIL
,
1626 cgc
= srv_query(&ctx
->res_state
, rr_name
,
1630 DEBUG1STATUS(ctx
, "(no DNS response)");
1636 * Filter out unresponsive servers, and
1637 * save the domain info we get back.
1648 DEBUG1STATUS(ctx
, "(no LDAP response)");
1654 update_item(&ctx
->site_global_catalog
, gc
,
1655 AD_STATE_AUTO
, gc
->ttl
);
1656 update_version(&ctx
->site_global_catalog
, PARAM1
,
1658 update_version(&ctx
->site_global_catalog
, PARAM2
,
1661 return (&ctx
->site_global_catalog
);
1668 ad_disc_get_GlobalCatalog(ad_disc_t ctx
, enum ad_disc_req req
,
1669 boolean_t
*auto_discovered
)
1671 ad_disc_ds_t
*global_catalog
= NULL
;
1672 ad_item_t
*global_catalog_item
;
1674 global_catalog_item
= validate_GlobalCatalog(ctx
, req
);
1676 if (global_catalog_item
!= NULL
) {
1677 global_catalog
= ds_dup(global_catalog_item
->value
);
1678 if (auto_discovered
!= NULL
)
1680 (global_catalog_item
->state
== AD_STATE_AUTO
);
1681 } else if (auto_discovered
!= NULL
)
1682 *auto_discovered
= B_FALSE
;
1684 return (global_catalog
);
1689 validate_TrustedDomains(ad_disc_t ctx
)
1692 ad_item_t
*global_catalog_item
;
1693 ad_item_t
*forest_name_item
;
1694 ad_disc_trusteddomains_t
*trusted_domains
;
1696 char *forest_name_dn
;
1700 if (is_fixed(&ctx
->trusted_domains
))
1701 return (&ctx
->trusted_domains
);
1703 global_catalog_item
= validate_GlobalCatalog(ctx
, AD_DISC_GLOBAL
);
1704 if (global_catalog_item
== NULL
)
1707 forest_name_item
= validate_ForestName(ctx
);
1708 if (forest_name_item
== NULL
)
1711 if (!is_valid(&ctx
->trusted_domains
) ||
1712 is_changed(&ctx
->trusted_domains
, PARAM1
, global_catalog_item
) ||
1713 is_changed(&ctx
->trusted_domains
, PARAM2
, forest_name_item
)) {
1715 forest_name_dn
= ldap_dns_to_dn(forest_name_item
->value
,
1717 if (forest_name_dn
== NULL
)
1720 len
= snprintf(NULL
, 0, "CN=System,%s", forest_name_dn
) + 1;
1723 free(forest_name_dn
);
1726 (void) snprintf(dn
, len
, "CN=System,%s", forest_name_dn
);
1727 free(forest_name_dn
);
1729 trusted_domains
= ldap_lookup_trusted_domains(
1730 &ld
, global_catalog_item
->value
, dn
);
1733 (void) ldap_unbind(ld
);
1736 if (trusted_domains
== NULL
)
1739 update_item(&ctx
->trusted_domains
, trusted_domains
,
1741 update_version(&ctx
->trusted_domains
, PARAM1
,
1742 global_catalog_item
);
1743 update_version(&ctx
->trusted_domains
, PARAM2
,
1747 return (&ctx
->trusted_domains
);
1751 ad_disc_trusteddomains_t
*
1752 ad_disc_get_TrustedDomains(ad_disc_t ctx
, boolean_t
*auto_discovered
)
1754 ad_disc_trusteddomains_t
*trusted_domains
= NULL
;
1755 ad_item_t
*trusted_domains_item
;
1757 trusted_domains_item
= validate_TrustedDomains(ctx
);
1759 if (trusted_domains_item
!= NULL
) {
1760 trusted_domains
= td_dup(trusted_domains_item
->value
);
1761 if (auto_discovered
!= NULL
)
1763 (trusted_domains_item
->state
== AD_STATE_AUTO
);
1764 } else if (auto_discovered
!= NULL
)
1765 *auto_discovered
= B_FALSE
;
1767 return (trusted_domains
);
1772 validate_DomainsInForest(ad_disc_t ctx
)
1774 ad_item_t
*global_catalog_item
;
1776 ad_disc_domainsinforest_t
*domains_in_forest
;
1778 if (is_fixed(&ctx
->domains_in_forest
))
1779 return (&ctx
->domains_in_forest
);
1781 global_catalog_item
= validate_GlobalCatalog(ctx
, AD_DISC_GLOBAL
);
1782 if (global_catalog_item
== NULL
)
1785 if (!is_valid(&ctx
->domains_in_forest
) ||
1786 is_changed(&ctx
->domains_in_forest
, PARAM1
, global_catalog_item
)) {
1788 domains_in_forest
= ldap_lookup_domains_in_forest(
1789 &ld
, global_catalog_item
->value
);
1792 (void) ldap_unbind(ld
);
1794 if (domains_in_forest
== NULL
)
1797 update_item(&ctx
->domains_in_forest
, domains_in_forest
,
1799 update_version(&ctx
->domains_in_forest
, PARAM1
,
1800 global_catalog_item
);
1802 return (&ctx
->domains_in_forest
);
1806 ad_disc_domainsinforest_t
*
1807 ad_disc_get_DomainsInForest(ad_disc_t ctx
, boolean_t
*auto_discovered
)
1809 ad_disc_domainsinforest_t
*domains_in_forest
= NULL
;
1810 ad_item_t
*domains_in_forest_item
;
1812 domains_in_forest_item
= validate_DomainsInForest(ctx
);
1814 if (domains_in_forest_item
!= NULL
) {
1815 domains_in_forest
= df_dup(domains_in_forest_item
->value
);
1816 if (auto_discovered
!= NULL
)
1818 (domains_in_forest_item
->state
== AD_STATE_AUTO
);
1819 } else if (auto_discovered
!= NULL
)
1820 *auto_discovered
= B_FALSE
;
1822 return (domains_in_forest
);
1826 validate_PreferredDC(ad_disc_t ctx
)
1828 if (is_valid(&ctx
->preferred_dc
))
1829 return (&ctx
->preferred_dc
);
1835 ad_disc_get_PreferredDC(ad_disc_t ctx
, boolean_t
*auto_discovered
)
1837 ad_disc_ds_t
*preferred_dc
= NULL
;
1838 ad_item_t
*preferred_dc_item
;
1840 preferred_dc_item
= validate_PreferredDC(ctx
);
1842 if (preferred_dc_item
!= NULL
) {
1843 preferred_dc
= ds_dup(preferred_dc_item
->value
);
1844 if (auto_discovered
!= NULL
)
1846 (preferred_dc_item
->state
== AD_STATE_AUTO
);
1847 } else if (auto_discovered
!= NULL
)
1848 *auto_discovered
= B_FALSE
;
1850 return (preferred_dc
);
1856 ad_disc_set_DomainName(ad_disc_t ctx
, const char *domainName
)
1858 char *domain_name
= NULL
;
1859 if (domainName
!= NULL
) {
1860 domain_name
= strdup(domainName
);
1861 if (domain_name
== NULL
)
1863 update_item(&ctx
->domain_name
, domain_name
,
1865 } else if (ctx
->domain_name
.state
== AD_STATE_FIXED
)
1866 ctx
->domain_name
.state
= AD_STATE_INVALID
;
1871 ad_disc_set_DomainGUID(ad_disc_t ctx
, uchar_t
*u
)
1873 char *domain_guid
= NULL
;
1875 domain_guid
= uuid_dup(u
);
1876 if (domain_guid
== NULL
)
1878 update_item(&ctx
->domain_guid
, domain_guid
,
1880 } else if (ctx
->domain_guid
.state
== AD_STATE_FIXED
)
1881 ctx
->domain_guid
.state
= AD_STATE_INVALID
;
1886 auto_set_DomainGUID(ad_disc_t ctx
, uchar_t
*u
)
1888 char *domain_guid
= NULL
;
1890 if (is_fixed(&ctx
->domain_guid
))
1893 domain_guid
= uuid_dup(u
);
1894 if (domain_guid
== NULL
)
1896 update_item(&ctx
->domain_guid
, domain_guid
, AD_STATE_AUTO
, 0);
1900 ad_disc_set_DomainController(ad_disc_t ctx
,
1901 const ad_disc_ds_t
*domainController
)
1903 ad_disc_ds_t
*domain_controller
= NULL
;
1904 if (domainController
!= NULL
) {
1905 domain_controller
= ds_dup(domainController
);
1906 if (domain_controller
== NULL
)
1908 update_item(&ctx
->domain_controller
, domain_controller
,
1910 } else if (ctx
->domain_controller
.state
== AD_STATE_FIXED
)
1911 ctx
->domain_controller
.state
= AD_STATE_INVALID
;
1916 ad_disc_set_SiteName(ad_disc_t ctx
, const char *siteName
)
1918 char *site_name
= NULL
;
1919 if (siteName
!= NULL
) {
1920 site_name
= strdup(siteName
);
1921 if (site_name
== NULL
)
1923 update_item(&ctx
->site_name
, site_name
, AD_STATE_FIXED
, 0);
1924 } else if (ctx
->site_name
.state
== AD_STATE_FIXED
)
1925 ctx
->site_name
.state
= AD_STATE_INVALID
;
1930 auto_set_SiteName(ad_disc_t ctx
, char *siteName
)
1932 char *site_name
= NULL
;
1934 if (is_fixed(&ctx
->site_name
))
1937 site_name
= strdup(siteName
);
1938 if (site_name
== NULL
)
1940 update_item(&ctx
->site_name
, site_name
, AD_STATE_AUTO
, 0);
1944 ad_disc_set_ForestName(ad_disc_t ctx
, const char *forestName
)
1946 char *forest_name
= NULL
;
1947 if (forestName
!= NULL
) {
1948 forest_name
= strdup(forestName
);
1949 if (forest_name
== NULL
)
1951 update_item(&ctx
->forest_name
, forest_name
,
1953 } else if (ctx
->forest_name
.state
== AD_STATE_FIXED
)
1954 ctx
->forest_name
.state
= AD_STATE_INVALID
;
1959 auto_set_ForestName(ad_disc_t ctx
, char *forestName
)
1961 char *forest_name
= NULL
;
1963 if (is_fixed(&ctx
->forest_name
))
1966 forest_name
= strdup(forestName
);
1967 if (forest_name
== NULL
)
1969 update_item(&ctx
->forest_name
, forest_name
, AD_STATE_AUTO
, 0);
1973 ad_disc_set_GlobalCatalog(ad_disc_t ctx
,
1974 const ad_disc_ds_t
*globalCatalog
)
1976 ad_disc_ds_t
*global_catalog
= NULL
;
1977 if (globalCatalog
!= NULL
) {
1978 global_catalog
= ds_dup(globalCatalog
);
1979 if (global_catalog
== NULL
)
1981 update_item(&ctx
->global_catalog
, global_catalog
,
1983 } else if (ctx
->global_catalog
.state
== AD_STATE_FIXED
)
1984 ctx
->global_catalog
.state
= AD_STATE_INVALID
;
1989 ad_disc_set_PreferredDC(ad_disc_t ctx
, const ad_disc_ds_t
*pref_dc
)
1991 ad_disc_ds_t
*new_pref_dc
= NULL
;
1992 if (pref_dc
!= NULL
) {
1993 new_pref_dc
= ds_dup(pref_dc
);
1994 if (new_pref_dc
== NULL
)
1996 update_item(&ctx
->preferred_dc
, new_pref_dc
,
1998 } else if (ctx
->preferred_dc
.state
== AD_STATE_FIXED
)
1999 ctx
->preferred_dc
.state
= AD_STATE_INVALID
;
2004 ad_disc_set_StatusFP(ad_disc_t ctx
, struct __FILE_TAG
*fp
)
2006 ctx
->status_fp
= fp
;
2011 ad_disc_unset(ad_disc_t ctx
)
2013 if (ctx
->domain_name
.state
== AD_STATE_FIXED
)
2014 ctx
->domain_name
.state
= AD_STATE_INVALID
;
2016 if (ctx
->domain_controller
.state
== AD_STATE_FIXED
)
2017 ctx
->domain_controller
.state
= AD_STATE_INVALID
;
2019 if (ctx
->preferred_dc
.state
== AD_STATE_FIXED
)
2020 ctx
->preferred_dc
.state
= AD_STATE_INVALID
;
2022 if (ctx
->site_name
.state
== AD_STATE_FIXED
)
2023 ctx
->site_name
.state
= AD_STATE_INVALID
;
2025 if (ctx
->forest_name
.state
== AD_STATE_FIXED
)
2026 ctx
->forest_name
.state
= AD_STATE_INVALID
;
2028 if (ctx
->global_catalog
.state
== AD_STATE_FIXED
)
2029 ctx
->global_catalog
.state
= AD_STATE_INVALID
;
2037 * This routines the time to live for AD
2038 * auto discovered items.
2041 * -1 if there are no TTL items
2042 * 0 if there are expired items
2043 * else the number of seconds
2045 * The MIN_GT_ZERO(x, y) macro return the lesser of x and y, provided it
2046 * is positive -- min() greater than zero.
2048 #define MIN_GT_ZERO(x, y) (((x) <= 0) ? (((y) <= 0) ? \
2049 (-1) : (y)) : (((y) <= 0) ? (x) : (((x) > (y)) ? (y) : (x))))
2051 ad_disc_get_TTL(ad_disc_t ctx
)
2056 expires
= MIN_GT_ZERO(ctx
->domain_controller
.expires
,
2057 ctx
->global_catalog
.expires
);
2058 expires
= MIN_GT_ZERO(expires
, ctx
->site_domain_controller
.expires
);
2059 expires
= MIN_GT_ZERO(expires
, ctx
->site_global_catalog
.expires
);
2061 if (expires
== -1) {
2065 if (ctx
->expires_not_before
!= 0 &&
2066 expires
< ctx
->expires_not_before
) {
2067 expires
= ctx
->expires_not_before
;
2070 if (ctx
->expires_not_after
!= 0 &&
2071 expires
> ctx
->expires_not_after
) {
2072 expires
= ctx
->expires_not_after
;
2075 ttl
= expires
- time(NULL
);
2084 ad_disc_SubnetChanged(ad_disc_t ctx
)
2086 ad_subnet_t
*subnets
;
2088 if (ctx
->subnets_changed
|| ctx
->subnets
== NULL
)
2091 if ((subnets
= find_subnets()) != NULL
) {
2092 if (cmpsubnets(subnets
, ctx
->subnets
) != 0)
2093 ctx
->subnets_changed
= B_TRUE
;
2097 return (ctx
->subnets_changed
);