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
)
264 if (item
->value
!= NULL
)
273 item
->expires
= time(NULL
) + ttl
;
278 ad_disc_compare_uuid(uuid_t
*u1
, uuid_t
*u2
)
282 rc
= memcmp(u1
, u2
, UUID_LEN
);
290 dst
= malloc(UUID_LEN
);
292 (void) memcpy(dst
, src
, UUID_LEN
);
296 /* Compare DS lists */
298 ad_disc_compare_ds(ad_disc_ds_t
*ds1
, ad_disc_ds_t
*ds2
)
305 for (i
= 0; ds1
[i
].host
[0] != '\0'; i
++)
308 for (j
= 0; ds2
[j
].host
[0] != '\0'; j
++)
311 if (num_ds1
!= num_ds2
)
314 for (i
= 0; i
< num_ds1
; i
++) {
316 for (j
= 0; j
< num_ds2
; j
++) {
317 if (strcmp(ds1
[i
].host
, ds2
[j
].host
) == 0 &&
318 ds1
[i
].port
== ds2
[j
].port
) {
330 /* Copy a list of DSs */
331 static ad_disc_ds_t
*
332 ds_dup(const ad_disc_ds_t
*srv
)
336 ad_disc_ds_t
*new = NULL
;
338 for (i
= 0; srv
[i
].host
[0] != '\0'; i
++)
341 size
= (i
+ 1) * sizeof (ad_disc_ds_t
);
344 (void) memcpy(new, srv
, size
);
350 ad_disc_compare_trusteddomains(ad_disc_trusteddomains_t
*td1
,
351 ad_disc_trusteddomains_t
*td2
)
358 for (i
= 0; td1
[i
].domain
[0] != '\0'; i
++)
362 for (j
= 0; td2
[j
].domain
[0] != '\0'; j
++)
366 if (num_td1
!= num_td2
)
369 for (i
= 0; i
< num_td1
; i
++) {
371 for (j
= 0; j
< num_td2
; j
++) {
372 if (domain_eq(td1
[i
].domain
, td2
[j
].domain
)) {
385 /* Copy a list of Trusted Domains */
386 static ad_disc_trusteddomains_t
*
387 td_dup(const ad_disc_trusteddomains_t
*td
)
391 ad_disc_trusteddomains_t
*new = NULL
;
393 for (i
= 0; td
[i
].domain
[0] != '\0'; i
++)
396 size
= (i
+ 1) * sizeof (ad_disc_trusteddomains_t
);
399 (void) memcpy(new, td
, size
);
406 ad_disc_compare_domainsinforest(ad_disc_domainsinforest_t
*df1
,
407 ad_disc_domainsinforest_t
*df2
)
414 for (i
= 0; df1
[i
].domain
[0] != '\0'; i
++)
418 for (j
= 0; df2
[j
].domain
[0] != '\0'; j
++)
422 if (num_df1
!= num_df2
)
425 for (i
= 0; i
< num_df1
; i
++) {
427 for (j
= 0; j
< num_df2
; j
++) {
428 if (domain_eq(df1
[i
].domain
, df2
[j
].domain
) &&
429 strcmp(df1
[i
].sid
, df2
[j
].sid
) == 0) {
442 /* Copy a list of Trusted Domains */
443 static ad_disc_domainsinforest_t
*
444 df_dup(const ad_disc_domainsinforest_t
*df
)
448 ad_disc_domainsinforest_t
*new = NULL
;
450 for (i
= 0; df
[i
].domain
[0] != '\0'; i
++)
453 size
= (i
+ 1) * sizeof (ad_disc_domainsinforest_t
);
456 (void) memcpy(new, df
, size
);
465 * Returns an array of IPv4 address/prefix length
466 * The last subnet is NULL
473 struct lifreq lifr
, *lifrp
;
477 ad_subnet_t
*results
;
481 if ((sock
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
482 logger(LOG_ERR
, "Failed to open IPv4 socket for "
483 "listing network interfaces (%s)", strerror(errno
));
487 lifn
.lifn_family
= AF_INET
;
489 if (ioctl(sock
, SIOCGLIFNUM
, (char *)&lifn
) < 0) {
491 "Failed to find the number of network interfaces (%s)",
497 if (lifn
.lifn_count
< 1) {
498 logger(LOG_ERR
, "No IPv4 network interfaces found");
503 lifc
.lifc_family
= AF_INET
;
505 lifc
.lifc_len
= lifn
.lifn_count
* sizeof (struct lifreq
);
506 lifc
.lifc_buf
= malloc(lifc
.lifc_len
);
508 if (lifc
.lifc_buf
== NULL
) {
509 logger(LOG_ERR
, "Out of memory");
514 if (ioctl(sock
, SIOCGLIFCONF
, (char *)&lifc
) < 0) {
515 logger(LOG_ERR
, "Failed to list network interfaces (%s)",
522 n
= lifc
.lifc_len
/ (int)sizeof (struct lifreq
);
524 if ((results
= calloc(n
+ 1, sizeof (ad_subnet_t
))) == NULL
) {
530 for (i
= 0, lifrp
= lifc
.lifc_req
; i
< n
; i
++, lifrp
++) {
531 if (ioctl(sock
, SIOCGLIFFLAGS
, lifrp
) < 0)
534 if ((lifrp
->lifr_flags
& IFF_UP
) == 0)
537 if (ioctl(sock
, SIOCGLIFSUBNET
, lifrp
) < 0)
540 prefix_len
= lifrp
->lifr_addrlen
;
542 s
= inet_ntoa(((struct sockaddr_in
*)
543 &lifrp
->lifr_addr
)->sin_addr
);
545 (void) snprintf(results
[i
].subnet
, sizeof (ad_subnet_t
),
546 "%s/%d", s
, prefix_len
);
556 cmpsubnets(ad_subnet_t
*subnets1
, ad_subnet_t
*subnets2
)
563 for (i
= 0; subnets1
[i
].subnet
[0] != '\0'; i
++)
567 for (i
= 0; subnets2
[i
].subnet
[0] != '\0'; i
++)
571 if (num_subnets1
!= num_subnets2
)
574 for (i
= 0; i
< num_subnets1
; i
++) {
576 for (j
= 0; j
< num_subnets2
; j
++) {
577 if (strcmp(subnets1
[i
].subnet
,
578 subnets2
[j
].subnet
) == 0) {
592 /* Convert a DN's DC components into a DNS domainname */
594 DN_to_DNS(const char *dn_name
)
596 char dns
[DNS_MAX_NAME
];
607 * Find all DC=<value> and form DNS name of the
608 * form <value1>.<value2>...
610 while (dn_name
[i
] != '\0') {
611 if (strncasecmp(&dn_name
[i
], "DC=", 3) == 0) {
613 if (dn_name
[i
] != '\0' && num
> 0)
615 while (dn_name
[i
] != '\0' &&
616 dn_name
[i
] != ',' && dn_name
[i
] != '+')
617 dns
[j
++] = dn_name
[i
++];
620 /* Skip attr=value as it is not DC= */
621 while (dn_name
[i
] != '\0' &&
622 dn_name
[i
] != ',' && dn_name
[i
] != '+')
625 /* Skip over separator ',' or '+' */
626 if (dn_name
[i
] != '\0') i
++;
629 dns_name
= malloc(j
+ 1);
630 if (dns_name
!= NULL
)
631 (void) strlcpy(dns_name
, dns
, j
+ 1);
637 * A utility function to bind to a Directory server
642 ldap_lookup_init(ad_disc_ds_t
*ds
)
647 int timeoutms
= 5 * 1000;
648 char *saslmech
= "GSSAPI";
649 uint32_t saslflags
= LDAP_SASL_INTERACTIVE
;
652 for (i
= 0; ds
[i
].host
[0] != '\0'; i
++) {
654 logger(LOG_DEBUG
, "adutils: ldap_lookup_init, host %s",
658 ld
= ldap_init(ds
[i
].host
, ds
[i
].port
);
662 "Couldn't connect to AD DC %s:%d (%s)",
663 ds
[i
].host
, ds
[i
].port
,
669 ldversion
= LDAP_VERSION3
;
670 (void) ldap_set_option(ld
, LDAP_OPT_PROTOCOL_VERSION
,
672 (void) ldap_set_option(ld
, LDAP_OPT_REFERRALS
,
674 (void) ldap_set_option(ld
, LDAP_OPT_TIMELIMIT
, &zero
);
675 (void) ldap_set_option(ld
, LDAP_OPT_SIZELIMIT
, &zero
);
676 /* setup TCP/IP connect timeout */
677 (void) ldap_set_option(ld
, LDAP_X_OPT_CONNECT_TIMEOUT
,
679 (void) ldap_set_option(ld
, LDAP_OPT_RESTART
,
682 rc
= adutils_set_thread_functions(ld
);
683 if (rc
!= LDAP_SUCCESS
) {
684 /* Error has already been logged */
685 (void) ldap_unbind(ld
);
690 rc
= ldap_sasl_interactive_bind_s(ld
, "" /* binddn */,
691 saslmech
, NULL
, NULL
, saslflags
, &saslcallback
,
692 NULL
/* defaults */);
693 if (rc
== LDAP_SUCCESS
)
697 logger(LOG_INFO
, "LDAP: %s:%d: %s",
698 ds
[i
].host
, ds
[i
].port
, ldap_err2string(rc
));
699 ldap_perror(ld
, ds
[i
].host
);
701 (void) ldap_unbind(ld
);
710 * Lookup the trusted domains in the global catalog.
713 * array of trusted domains which is terminated by
714 * an empty trusted domain.
715 * NULL an error occured
717 ad_disc_trusteddomains_t
*
718 ldap_lookup_trusted_domains(LDAP
**ld
, ad_disc_ds_t
*globalCatalog
,
721 int scope
= LDAP_SCOPE_SUBTREE
;
724 LDAPMessage
*results
= NULL
;
727 char **partner
= NULL
;
728 char **direction
= NULL
;
730 ad_disc_trusteddomains_t
*trusted_domains
= NULL
;
733 logger(LOG_DEBUG
, "Looking for trusted domains...");
736 *ld
= ldap_lookup_init(globalCatalog
);
739 logger(LOG_ERR
, "adutils: ldap_lookup_init failed");
743 attrs
[0] = "trustPartner";
744 attrs
[1] = "trustDirection";
748 * Trust direction values:
749 * 1 - inbound (they trust us)
750 * 2 - outbound (we trust them)
751 * 3 - bidirectional (we trust each other)
753 filter
= "(&(objectclass=trustedDomain)"
754 "(|(trustDirection=3)(trustDirection=2)))";
756 rc
= ldap_search_s(*ld
, base_dn
, scope
, filter
, attrs
, 0, &results
);
758 logger(LOG_DEBUG
, "Trusted domains:");
759 if (rc
== LDAP_SUCCESS
) {
760 for (entry
= ldap_first_entry(*ld
, results
);
761 entry
!= NULL
; entry
= ldap_next_entry(*ld
, entry
)) {
762 partner
= ldap_get_values(*ld
, entry
, "trustPartner");
763 direction
= ldap_get_values(
764 *ld
, entry
, "trustDirection");
766 if (partner
!= NULL
&& direction
!= NULL
) {
768 logger(LOG_DEBUG
, " %s (%s)",
769 partner
[0], direction
[0]);
772 void *tmp
= realloc(trusted_domains
,
774 sizeof (ad_disc_trusteddomains_t
));
776 free(trusted_domains
);
777 ldap_value_free(partner
);
778 ldap_value_free(direction
);
779 (void) ldap_msgfree(results
);
782 trusted_domains
= tmp
;
783 /* Last element should be zero */
784 (void) memset(&trusted_domains
[num
], 0,
785 sizeof (ad_disc_trusteddomains_t
));
786 (void) strcpy(trusted_domains
[num
- 1].domain
,
788 trusted_domains
[num
- 1].direction
=
792 ldap_value_free(partner
);
793 if (direction
!= NULL
)
794 ldap_value_free(direction
);
796 } else if (rc
== LDAP_NO_RESULTS_RETURNED
) {
797 /* This is not an error - return empty trusted domain */
798 trusted_domains
= calloc(1, sizeof (ad_disc_trusteddomains_t
));
800 logger(LOG_DEBUG
, " not found");
803 logger(LOG_DEBUG
, " rc=%d", rc
);
806 (void) ldap_msgfree(results
);
808 return (trusted_domains
);
813 * This functions finds all the domains in a forest.
815 ad_disc_domainsinforest_t
*
816 ldap_lookup_domains_in_forest(LDAP
**ld
, ad_disc_ds_t
*globalCatalogs
)
818 static char *attrs
[] = {
823 LDAPMessage
*result
= NULL
;
827 ad_disc_domainsinforest_t
*domains
= NULL
;
830 logger(LOG_DEBUG
, "Looking for domains in forest...");
833 *ld
= ldap_lookup_init(globalCatalogs
);
836 logger(LOG_ERR
, "adutils: ldap_lookup_init failed");
841 rc
= ldap_search_s(*ld
, "", LDAP_SCOPE_SUBTREE
,
842 "(objectClass=Domain)", attrs
, 0, &result
);
843 if (rc
!= LDAP_SUCCESS
) {
844 logger(LOG_ERR
, "adutils: ldap_search, rc=%d", rc
);
848 logger(LOG_DEBUG
, "Domains in forest:");
850 nresults
= ldap_count_entries(*ld
, result
);
851 domains
= calloc(nresults
+ 1, sizeof (*domains
));
852 if (domains
== NULL
) {
854 logger(LOG_DEBUG
, " (nomem)");
858 for (entry
= ldap_first_entry(*ld
, result
);
860 entry
= ldap_next_entry(*ld
, entry
)) {
861 struct berval
**sid_ber
;
867 sid_ber
= ldap_get_values_len(*ld
, entry
,
872 rc
= adutils_getsid(sid_ber
[0], &sid
);
873 ldap_value_free_len(sid_ber
);
877 if ((sid_str
= adutils_sid2txt(&sid
)) == NULL
)
880 (void) strcpy(domains
[ndomains
].sid
, sid_str
);
883 dn
= ldap_get_dn(*ld
, entry
);
884 name
= DN_to_DNS(dn
);
889 (void) strcpy(domains
[ndomains
].domain
, name
);
893 logger(LOG_DEBUG
, " %s", domains
[ndomains
].domain
);
900 logger(LOG_DEBUG
, " not found");
904 if (ndomains
< nresults
) {
905 ad_disc_domainsinforest_t
*tmp
;
906 tmp
= realloc(domains
, (ndomains
+ 1) * sizeof (*domains
));
913 (void) ldap_msgfree(result
);
920 (void) ldap_msgfree(result
);
929 ctx
= calloc(1, sizeof (struct ad_disc
));
933 ctx
->domain_name
.type
= AD_STRING
;
934 ctx
->domain_guid
.type
= AD_UUID
;
935 ctx
->domain_controller
.type
= AD_DIRECTORY
;
936 ctx
->preferred_dc
.type
= AD_DIRECTORY
;
937 ctx
->site_name
.type
= AD_STRING
;
938 ctx
->forest_name
.type
= AD_STRING
;
939 ctx
->global_catalog
.type
= AD_DIRECTORY
;
940 ctx
->domains_in_forest
.type
= AD_DOMAINS_IN_FOREST
;
941 ctx
->trusted_domains
.type
= AD_TRUSTED_DOMAINS
;
942 /* Site specific versions */
943 ctx
->site_domain_controller
.type
= AD_DIRECTORY
;
944 ctx
->site_global_catalog
.type
= AD_DIRECTORY
;
949 ad_disc_fini(ad_disc_t ctx
)
954 if (ctx
->res_ninitted
)
955 res_ndestroy(&ctx
->res_state
);
957 if (ctx
->subnets
!= NULL
)
960 if (ctx
->domain_name
.value
!= NULL
)
961 free(ctx
->domain_name
.value
);
963 if (ctx
->domain_guid
.value
!= NULL
)
964 free(ctx
->domain_guid
.value
);
966 if (ctx
->domain_controller
.value
!= NULL
)
967 free(ctx
->domain_controller
.value
);
969 if (ctx
->preferred_dc
.value
!= NULL
)
970 free(ctx
->preferred_dc
.value
);
972 if (ctx
->site_name
.value
!= NULL
)
973 free(ctx
->site_name
.value
);
975 if (ctx
->forest_name
.value
!= NULL
)
976 free(ctx
->forest_name
.value
);
978 if (ctx
->global_catalog
.value
!= NULL
)
979 free(ctx
->global_catalog
.value
);
981 if (ctx
->domains_in_forest
.value
!= NULL
)
982 free(ctx
->domains_in_forest
.value
);
984 if (ctx
->trusted_domains
.value
!= NULL
)
985 free(ctx
->trusted_domains
.value
);
987 /* Site specific versions */
988 if (ctx
->site_domain_controller
.value
!= NULL
)
989 free(ctx
->site_domain_controller
.value
);
991 if (ctx
->site_global_catalog
.value
!= NULL
)
992 free(ctx
->site_global_catalog
.value
);
998 ad_disc_refresh(ad_disc_t ctx
)
1000 if (ctx
->res_ninitted
) {
1001 res_ndestroy(&ctx
->res_state
);
1002 ctx
->res_ninitted
= 0;
1004 (void) memset(&ctx
->res_state
, 0, sizeof (ctx
->res_state
));
1007 if (ctx
->domain_name
.state
== AD_STATE_AUTO
)
1008 ctx
->domain_name
.state
= AD_STATE_INVALID
;
1010 if (ctx
->domain_guid
.state
== AD_STATE_AUTO
)
1011 ctx
->domain_guid
.state
= AD_STATE_INVALID
;
1013 if (ctx
->domain_controller
.state
== AD_STATE_AUTO
)
1014 ctx
->domain_controller
.state
= AD_STATE_INVALID
;
1016 if (ctx
->preferred_dc
.state
== AD_STATE_AUTO
)
1017 ctx
->preferred_dc
.state
= AD_STATE_INVALID
;
1019 if (ctx
->site_name
.state
== AD_STATE_AUTO
)
1020 ctx
->site_name
.state
= AD_STATE_INVALID
;
1022 if (ctx
->forest_name
.state
== AD_STATE_AUTO
)
1023 ctx
->forest_name
.state
= AD_STATE_INVALID
;
1025 if (ctx
->global_catalog
.state
== AD_STATE_AUTO
)
1026 ctx
->global_catalog
.state
= AD_STATE_INVALID
;
1028 if (ctx
->domains_in_forest
.state
== AD_STATE_AUTO
)
1029 ctx
->domains_in_forest
.state
= AD_STATE_INVALID
;
1031 if (ctx
->trusted_domains
.state
== AD_STATE_AUTO
)
1032 ctx
->trusted_domains
.state
= AD_STATE_INVALID
;
1034 if (ctx
->site_domain_controller
.state
== AD_STATE_AUTO
)
1035 ctx
->site_domain_controller
.state
= AD_STATE_INVALID
;
1037 if (ctx
->site_global_catalog
.state
== AD_STATE_AUTO
)
1038 ctx
->site_global_catalog
.state
= AD_STATE_INVALID
;
1043 * Called when the discovery cycle is done. Sets a master TTL
1044 * that will avoid doing new time-based discoveries too soon after
1045 * the last discovery cycle. Most interesting when the discovery
1046 * cycle failed, because then the TTLs on the individual items will
1047 * not be updated and may go stale.
1050 ad_disc_done(ad_disc_t ctx
)
1052 time_t now
= time(NULL
);
1054 ctx
->expires_not_before
= now
+ MINIMUM_TTL
;
1055 ctx
->expires_not_after
= now
+ MAXIMUM_TTL
;
1059 log_cds(ad_disc_t ctx
, ad_disc_cds_t
*cds
)
1061 char buf
[INET6_ADDRSTRLEN
];
1062 struct addrinfo
*ai
;
1064 if (!DBG(DISC
, 1) && ctx
->status_fp
== NULL
)
1067 DEBUG1STATUS(ctx
, "Candidate servers:");
1068 if (cds
->cds_ds
.host
[0] == '\0') {
1069 DEBUG1STATUS(ctx
, " (empty list)");
1073 while (cds
->cds_ds
.host
[0] != '\0') {
1075 DEBUG1STATUS(ctx
, " %s p=%d w=%d",
1077 cds
->cds_ds
.priority
,
1078 cds
->cds_ds
.weight
);
1082 DEBUG1STATUS(ctx
, " (no address)");
1084 while (ai
!= NULL
) {
1087 eai
= getnameinfo(ai
->ai_addr
, ai
->ai_addrlen
,
1088 buf
, sizeof (buf
), NULL
, 0, NI_NUMERICHOST
);
1090 (void) strlcpy(buf
, "?", sizeof (buf
));
1092 DEBUG1STATUS(ctx
, " %s", buf
);
1100 log_ds(ad_disc_t ctx
, ad_disc_ds_t
*ds
)
1102 char buf
[INET6_ADDRSTRLEN
];
1104 if (!DBG(DISC
, 1) && ctx
->status_fp
== NULL
)
1107 DEBUG1STATUS(ctx
, "Responding servers:");
1108 if (ds
->host
[0] == '\0') {
1109 DEBUG1STATUS(ctx
, " (empty list)");
1113 while (ds
->host
[0] != '\0') {
1115 DEBUG1STATUS(ctx
, " %s", ds
->host
);
1116 DO_GETNAMEINFO(buf
, sizeof (buf
), &ds
->addr
);
1117 DEBUG1STATUS(ctx
, " %s", buf
);
1123 /* Discover joined Active Directory domainName */
1125 validate_DomainName(ad_disc_t ctx
)
1127 char *dname
, *srvname
;
1130 if (is_valid(&ctx
->domain_name
))
1131 return (&ctx
->domain_name
);
1134 /* Try to find our domain by searching for DCs for it */
1137 logger(LOG_DEBUG
, "Looking for our AD domain name...");
1138 rc
= srv_getdom(&ctx
->res_state
,
1139 LDAP_SRV_HEAD DC_SRV_TAIL
, &srvname
);
1142 * If we can't find DCs by via res_nsearch() then there's no
1143 * point in trying anything else to discover the AD domain name.
1147 logger(LOG_DEBUG
, "Can't find our domain name.");
1152 * We have the FQDN of the SRV RR name, so now we extract the
1153 * domainname suffix from it.
1155 dname
= strdup(srvname
+ strlen(LDAP_SRV_HEAD DC_SRV_TAIL
) +
1156 1 /* for the dot between RR name and domainname */);
1160 if (dname
== NULL
) {
1161 logger(LOG_ERR
, "Out of memory");
1165 /* Eat any trailing dot */
1166 len
= strlen(dname
);
1167 if (len
> 0 && dname
[len
- 1] == '.')
1168 dname
[len
- 1] = '\0';
1171 logger(LOG_DEBUG
, "Our domain name: %s", dname
);
1174 * There is no "time to live" on the discovered domain,
1175 * so passing zero as TTL here, making it non-expiring.
1176 * Note that current consumers do not auto-discover the
1177 * domain name, though a future installer could.
1179 update_item(&ctx
->domain_name
, dname
, AD_STATE_AUTO
, 0);
1181 return (&ctx
->domain_name
);
1186 ad_disc_get_DomainName(ad_disc_t ctx
, boolean_t
*auto_discovered
)
1188 char *domain_name
= NULL
;
1189 ad_item_t
*domain_name_item
;
1191 domain_name_item
= validate_DomainName(ctx
);
1193 if (domain_name_item
) {
1194 domain_name
= strdup(domain_name_item
->value
);
1195 if (auto_discovered
!= NULL
)
1197 (domain_name_item
->state
== AD_STATE_AUTO
);
1198 } else if (auto_discovered
!= NULL
)
1199 *auto_discovered
= B_FALSE
;
1201 return (domain_name
);
1205 /* Discover domain controllers */
1207 validate_DomainController(ad_disc_t ctx
, enum ad_disc_req req
)
1209 ad_disc_ds_t
*dc
= NULL
;
1210 ad_disc_cds_t
*cdc
= NULL
;
1211 boolean_t validate_global
= B_FALSE
;
1212 boolean_t validate_site
= B_FALSE
;
1213 ad_item_t
*domain_name_item
;
1215 ad_item_t
*site_name_item
= NULL
;
1217 ad_item_t
*prefer_dc_item
;
1218 ad_disc_ds_t
*prefer_dc
= NULL
;
1220 /* If the values is fixed there will not be a site specific version */
1221 if (is_fixed(&ctx
->domain_controller
))
1222 return (&ctx
->domain_controller
);
1224 domain_name_item
= validate_DomainName(ctx
);
1225 if (domain_name_item
== NULL
)
1227 domain_name
= (char *)domain_name_item
->value
;
1229 /* Get (optional) preferred DC. */
1230 prefer_dc_item
= validate_PreferredDC(ctx
);
1231 if (prefer_dc_item
!= NULL
)
1232 prefer_dc
= prefer_dc_item
->value
;
1234 if (req
== AD_DISC_GLOBAL
)
1235 validate_global
= B_TRUE
;
1237 if (is_fixed(&ctx
->site_name
))
1238 validate_site
= B_TRUE
;
1239 else if (req
== AD_DISC_PREFER_SITE
)
1240 validate_global
= B_TRUE
;
1243 if (validate_global
) {
1244 if (!is_valid(&ctx
->domain_controller
) ||
1245 is_changed(&ctx
->domain_controller
, PARAM1
,
1246 domain_name_item
)) {
1249 * Lookup DNS SRV RR named
1250 * _ldap._tcp.dc._msdcs.<DomainName>
1252 DEBUG1STATUS(ctx
, "DNS SRV query, dom=%s",
1255 cdc
= srv_query(&ctx
->res_state
,
1256 LDAP_SRV_HEAD DC_SRV_TAIL
,
1257 domain_name
, prefer_dc
);
1260 DEBUG1STATUS(ctx
, "(no DNS response)");
1266 * Filter out unresponsive servers, and
1267 * save the domain info we get back.
1278 DEBUG1STATUS(ctx
, "(no LDAP response)");
1283 update_item(&ctx
->domain_controller
, dc
,
1284 AD_STATE_AUTO
, dc
->ttl
);
1285 update_version(&ctx
->domain_controller
, PARAM1
,
1288 return (&ctx
->domain_controller
);
1291 if (validate_site
) {
1292 site_name_item
= &ctx
->site_name
;
1293 site_name
= (char *)site_name_item
->value
;
1295 if (!is_valid(&ctx
->site_domain_controller
) ||
1296 is_changed(&ctx
->site_domain_controller
, PARAM1
,
1297 domain_name_item
) ||
1298 is_changed(&ctx
->site_domain_controller
, PARAM2
,
1300 char rr_name
[DNS_MAX_NAME
];
1303 * Lookup DNS SRV RR named
1304 * _ldap._tcp.<SiteName>._sites.dc._msdcs.<DomainName>
1306 DEBUG1STATUS(ctx
, "DNS SRV query, dom=%s, site=%s",
1307 domain_name
, site_name
);
1308 (void) snprintf(rr_name
, sizeof (rr_name
),
1309 LDAP_SRV_HEAD SITE_SRV_MIDDLE DC_SRV_TAIL
,
1312 cdc
= srv_query(&ctx
->res_state
, rr_name
,
1313 domain_name
, prefer_dc
);
1316 DEBUG1STATUS(ctx
, "(no DNS response)");
1322 * Filter out unresponsive servers, and
1323 * save the domain info we get back.
1334 DEBUG1STATUS(ctx
, "(no LDAP response)");
1339 update_item(&ctx
->site_domain_controller
, dc
,
1340 AD_STATE_AUTO
, dc
->ttl
);
1341 update_version(&ctx
->site_domain_controller
, PARAM1
,
1343 update_version(&ctx
->site_domain_controller
, PARAM2
,
1346 return (&ctx
->site_domain_controller
);
1352 ad_disc_get_DomainController(ad_disc_t ctx
, enum ad_disc_req req
,
1353 boolean_t
*auto_discovered
)
1355 ad_item_t
*domain_controller_item
;
1356 ad_disc_ds_t
*domain_controller
= NULL
;
1358 domain_controller_item
= validate_DomainController(ctx
, req
);
1360 if (domain_controller_item
!= NULL
) {
1361 domain_controller
= ds_dup(domain_controller_item
->value
);
1362 if (auto_discovered
!= NULL
)
1364 (domain_controller_item
->state
== AD_STATE_AUTO
);
1365 } else if (auto_discovered
!= NULL
)
1366 *auto_discovered
= B_FALSE
;
1368 return (domain_controller
);
1373 * Discover the Domain GUID
1374 * This info comes from validate_DomainController()
1377 validate_DomainGUID(ad_disc_t ctx
)
1379 ad_item_t
*domain_controller_item
;
1381 if (is_fixed(&ctx
->domain_guid
))
1382 return (&ctx
->domain_guid
);
1384 domain_controller_item
= validate_DomainController(ctx
, AD_DISC_GLOBAL
);
1385 if (domain_controller_item
== NULL
)
1388 if (!is_valid(&ctx
->domain_guid
))
1391 return (&ctx
->domain_guid
);
1396 ad_disc_get_DomainGUID(ad_disc_t ctx
, boolean_t
*auto_discovered
)
1398 ad_item_t
*domain_guid_item
;
1399 uchar_t
*domain_guid
= NULL
;
1401 domain_guid_item
= validate_DomainGUID(ctx
);
1402 if (domain_guid_item
!= NULL
) {
1403 domain_guid
= uuid_dup(domain_guid_item
->value
);
1404 if (auto_discovered
!= NULL
)
1406 (domain_guid_item
->state
== AD_STATE_AUTO
);
1407 } else if (auto_discovered
!= NULL
)
1408 *auto_discovered
= B_FALSE
;
1410 return (domain_guid
);
1415 * Discover site name (for multi-homed systems the first one found wins)
1416 * This info comes from validate_DomainController()
1419 validate_SiteName(ad_disc_t ctx
)
1421 ad_item_t
*domain_controller_item
;
1423 if (is_fixed(&ctx
->site_name
))
1424 return (&ctx
->site_name
);
1426 domain_controller_item
= validate_DomainController(ctx
, AD_DISC_GLOBAL
);
1427 if (domain_controller_item
== NULL
)
1430 if (!is_valid(&ctx
->site_name
))
1433 return (&ctx
->site_name
);
1438 ad_disc_get_SiteName(ad_disc_t ctx
, boolean_t
*auto_discovered
)
1440 ad_item_t
*site_name_item
;
1441 char *site_name
= NULL
;
1443 site_name_item
= validate_SiteName(ctx
);
1444 if (site_name_item
!= NULL
) {
1445 site_name
= strdup(site_name_item
->value
);
1446 if (auto_discovered
!= NULL
)
1448 (site_name_item
->state
== AD_STATE_AUTO
);
1449 } else if (auto_discovered
!= NULL
)
1450 *auto_discovered
= B_FALSE
;
1458 * Discover forest name
1459 * This info comes from validate_DomainController()
1462 validate_ForestName(ad_disc_t ctx
)
1464 ad_item_t
*domain_controller_item
;
1466 if (is_fixed(&ctx
->forest_name
))
1467 return (&ctx
->forest_name
);
1469 domain_controller_item
= validate_DomainController(ctx
, AD_DISC_GLOBAL
);
1470 if (domain_controller_item
== NULL
)
1473 if (!is_valid(&ctx
->forest_name
))
1476 return (&ctx
->forest_name
);
1481 ad_disc_get_ForestName(ad_disc_t ctx
, boolean_t
*auto_discovered
)
1483 ad_item_t
*forest_name_item
;
1484 char *forest_name
= NULL
;
1486 forest_name_item
= validate_ForestName(ctx
);
1488 if (forest_name_item
!= NULL
) {
1489 forest_name
= strdup(forest_name_item
->value
);
1490 if (auto_discovered
!= NULL
)
1492 (forest_name_item
->state
== AD_STATE_AUTO
);
1493 } else if (auto_discovered
!= NULL
)
1494 *auto_discovered
= B_FALSE
;
1496 return (forest_name
);
1500 /* Discover global catalog servers */
1502 validate_GlobalCatalog(ad_disc_t ctx
, enum ad_disc_req req
)
1504 ad_disc_ds_t
*gc
= NULL
;
1505 ad_disc_cds_t
*cgc
= NULL
;
1506 boolean_t validate_global
= B_FALSE
;
1507 boolean_t validate_site
= B_FALSE
;
1509 ad_item_t
*forest_name_item
;
1510 ad_item_t
*site_name_item
;
1514 /* If the values is fixed there will not be a site specific version */
1515 if (is_fixed(&ctx
->global_catalog
))
1516 return (&ctx
->global_catalog
);
1518 forest_name_item
= validate_ForestName(ctx
);
1519 if (forest_name_item
== NULL
)
1521 forest_name
= (char *)forest_name_item
->value
;
1523 if (req
== AD_DISC_GLOBAL
)
1524 validate_global
= B_TRUE
;
1526 if (is_fixed(&ctx
->site_name
))
1527 validate_site
= B_TRUE
;
1528 else if (req
== AD_DISC_PREFER_SITE
)
1529 validate_global
= B_TRUE
;
1532 if (validate_global
) {
1533 if (!is_valid(&ctx
->global_catalog
) ||
1534 is_changed(&ctx
->global_catalog
, PARAM1
,
1535 forest_name_item
)) {
1538 * See if our DC is also a GC.
1540 dc_item
= validate_DomainController(ctx
, req
);
1541 if (dc_item
!= NULL
) {
1542 ad_disc_ds_t
*ds
= dc_item
->value
;
1543 if ((ds
->flags
& DS_GC_FLAG
) != 0) {
1545 "DC is also a GC for %s",
1556 * Lookup DNS SRV RR named:
1557 * _ldap._tcp.gc._msdcs.<ForestName>
1559 DEBUG1STATUS(ctx
, "DNS SRV query, forest=%s",
1562 cgc
= srv_query(&ctx
->res_state
,
1563 LDAP_SRV_HEAD GC_SRV_TAIL
,
1567 DEBUG1STATUS(ctx
, "(no DNS response)");
1573 * Filter out unresponsive servers, and
1574 * save the domain info we get back.
1585 DEBUG1STATUS(ctx
, "(no LDAP response)");
1591 update_item(&ctx
->global_catalog
, gc
,
1592 AD_STATE_AUTO
, gc
->ttl
);
1593 update_version(&ctx
->global_catalog
, PARAM1
,
1596 return (&ctx
->global_catalog
);
1599 if (validate_site
) {
1600 site_name_item
= &ctx
->site_name
;
1601 site_name
= (char *)site_name_item
->value
;
1603 if (!is_valid(&ctx
->site_global_catalog
) ||
1604 is_changed(&ctx
->site_global_catalog
, PARAM1
,
1605 forest_name_item
) ||
1606 is_changed(&ctx
->site_global_catalog
, PARAM2
,
1608 char rr_name
[DNS_MAX_NAME
];
1611 * See if our DC is also a GC.
1613 dc_item
= validate_DomainController(ctx
, req
);
1614 if (dc_item
!= NULL
) {
1615 ad_disc_ds_t
*ds
= dc_item
->value
;
1616 if ((ds
->flags
& DS_GC_FLAG
) != 0) {
1618 "DC is also a GC for %s in %s",
1619 forest_name
, site_name
);
1629 * Lookup DNS SRV RR named:
1630 * _ldap._tcp.<siteName>._sites.gc.
1631 * _msdcs.<ForestName>
1633 DEBUG1STATUS(ctx
, "DNS SRV query, forest=%s, site=%s",
1634 forest_name
, site_name
);
1635 (void) snprintf(rr_name
, sizeof (rr_name
),
1636 LDAP_SRV_HEAD SITE_SRV_MIDDLE GC_SRV_TAIL
,
1639 cgc
= srv_query(&ctx
->res_state
, rr_name
,
1643 DEBUG1STATUS(ctx
, "(no DNS response)");
1649 * Filter out unresponsive servers, and
1650 * save the domain info we get back.
1661 DEBUG1STATUS(ctx
, "(no LDAP response)");
1667 update_item(&ctx
->site_global_catalog
, gc
,
1668 AD_STATE_AUTO
, gc
->ttl
);
1669 update_version(&ctx
->site_global_catalog
, PARAM1
,
1671 update_version(&ctx
->site_global_catalog
, PARAM2
,
1674 return (&ctx
->site_global_catalog
);
1681 ad_disc_get_GlobalCatalog(ad_disc_t ctx
, enum ad_disc_req req
,
1682 boolean_t
*auto_discovered
)
1684 ad_disc_ds_t
*global_catalog
= NULL
;
1685 ad_item_t
*global_catalog_item
;
1687 global_catalog_item
= validate_GlobalCatalog(ctx
, req
);
1689 if (global_catalog_item
!= NULL
) {
1690 global_catalog
= ds_dup(global_catalog_item
->value
);
1691 if (auto_discovered
!= NULL
)
1693 (global_catalog_item
->state
== AD_STATE_AUTO
);
1694 } else if (auto_discovered
!= NULL
)
1695 *auto_discovered
= B_FALSE
;
1697 return (global_catalog
);
1702 validate_TrustedDomains(ad_disc_t ctx
)
1705 ad_item_t
*global_catalog_item
;
1706 ad_item_t
*forest_name_item
;
1707 ad_disc_trusteddomains_t
*trusted_domains
;
1709 char *forest_name_dn
;
1713 if (is_fixed(&ctx
->trusted_domains
))
1714 return (&ctx
->trusted_domains
);
1716 global_catalog_item
= validate_GlobalCatalog(ctx
, AD_DISC_GLOBAL
);
1717 if (global_catalog_item
== NULL
)
1720 forest_name_item
= validate_ForestName(ctx
);
1721 if (forest_name_item
== NULL
)
1724 if (!is_valid(&ctx
->trusted_domains
) ||
1725 is_changed(&ctx
->trusted_domains
, PARAM1
, global_catalog_item
) ||
1726 is_changed(&ctx
->trusted_domains
, PARAM2
, forest_name_item
)) {
1728 forest_name_dn
= ldap_dns_to_dn(forest_name_item
->value
,
1730 if (forest_name_dn
== NULL
)
1733 len
= snprintf(NULL
, 0, "CN=System,%s", forest_name_dn
) + 1;
1736 free(forest_name_dn
);
1739 (void) snprintf(dn
, len
, "CN=System,%s", forest_name_dn
);
1740 free(forest_name_dn
);
1742 trusted_domains
= ldap_lookup_trusted_domains(
1743 &ld
, global_catalog_item
->value
, dn
);
1746 (void) ldap_unbind(ld
);
1749 if (trusted_domains
== NULL
)
1752 update_item(&ctx
->trusted_domains
, trusted_domains
,
1754 update_version(&ctx
->trusted_domains
, PARAM1
,
1755 global_catalog_item
);
1756 update_version(&ctx
->trusted_domains
, PARAM2
,
1760 return (&ctx
->trusted_domains
);
1764 ad_disc_trusteddomains_t
*
1765 ad_disc_get_TrustedDomains(ad_disc_t ctx
, boolean_t
*auto_discovered
)
1767 ad_disc_trusteddomains_t
*trusted_domains
= NULL
;
1768 ad_item_t
*trusted_domains_item
;
1770 trusted_domains_item
= validate_TrustedDomains(ctx
);
1772 if (trusted_domains_item
!= NULL
) {
1773 trusted_domains
= td_dup(trusted_domains_item
->value
);
1774 if (auto_discovered
!= NULL
)
1776 (trusted_domains_item
->state
== AD_STATE_AUTO
);
1777 } else if (auto_discovered
!= NULL
)
1778 *auto_discovered
= B_FALSE
;
1780 return (trusted_domains
);
1785 validate_DomainsInForest(ad_disc_t ctx
)
1787 ad_item_t
*global_catalog_item
;
1789 ad_disc_domainsinforest_t
*domains_in_forest
;
1791 if (is_fixed(&ctx
->domains_in_forest
))
1792 return (&ctx
->domains_in_forest
);
1794 global_catalog_item
= validate_GlobalCatalog(ctx
, AD_DISC_GLOBAL
);
1795 if (global_catalog_item
== NULL
)
1798 if (!is_valid(&ctx
->domains_in_forest
) ||
1799 is_changed(&ctx
->domains_in_forest
, PARAM1
, global_catalog_item
)) {
1801 domains_in_forest
= ldap_lookup_domains_in_forest(
1802 &ld
, global_catalog_item
->value
);
1805 (void) ldap_unbind(ld
);
1807 if (domains_in_forest
== NULL
)
1810 update_item(&ctx
->domains_in_forest
, domains_in_forest
,
1812 update_version(&ctx
->domains_in_forest
, PARAM1
,
1813 global_catalog_item
);
1815 return (&ctx
->domains_in_forest
);
1819 ad_disc_domainsinforest_t
*
1820 ad_disc_get_DomainsInForest(ad_disc_t ctx
, boolean_t
*auto_discovered
)
1822 ad_disc_domainsinforest_t
*domains_in_forest
= NULL
;
1823 ad_item_t
*domains_in_forest_item
;
1825 domains_in_forest_item
= validate_DomainsInForest(ctx
);
1827 if (domains_in_forest_item
!= NULL
) {
1828 domains_in_forest
= df_dup(domains_in_forest_item
->value
);
1829 if (auto_discovered
!= NULL
)
1831 (domains_in_forest_item
->state
== AD_STATE_AUTO
);
1832 } else if (auto_discovered
!= NULL
)
1833 *auto_discovered
= B_FALSE
;
1835 return (domains_in_forest
);
1839 validate_PreferredDC(ad_disc_t ctx
)
1841 if (is_valid(&ctx
->preferred_dc
))
1842 return (&ctx
->preferred_dc
);
1848 ad_disc_get_PreferredDC(ad_disc_t ctx
, boolean_t
*auto_discovered
)
1850 ad_disc_ds_t
*preferred_dc
= NULL
;
1851 ad_item_t
*preferred_dc_item
;
1853 preferred_dc_item
= validate_PreferredDC(ctx
);
1855 if (preferred_dc_item
!= NULL
) {
1856 preferred_dc
= ds_dup(preferred_dc_item
->value
);
1857 if (auto_discovered
!= NULL
)
1859 (preferred_dc_item
->state
== AD_STATE_AUTO
);
1860 } else if (auto_discovered
!= NULL
)
1861 *auto_discovered
= B_FALSE
;
1863 return (preferred_dc
);
1869 ad_disc_set_DomainName(ad_disc_t ctx
, const char *domainName
)
1871 char *domain_name
= NULL
;
1872 if (domainName
!= NULL
) {
1873 domain_name
= strdup(domainName
);
1874 if (domain_name
== NULL
)
1876 update_item(&ctx
->domain_name
, domain_name
,
1878 } else if (ctx
->domain_name
.state
== AD_STATE_FIXED
)
1879 ctx
->domain_name
.state
= AD_STATE_INVALID
;
1884 ad_disc_set_DomainGUID(ad_disc_t ctx
, uchar_t
*u
)
1886 char *domain_guid
= NULL
;
1888 domain_guid
= uuid_dup(u
);
1889 if (domain_guid
== NULL
)
1891 update_item(&ctx
->domain_guid
, domain_guid
,
1893 } else if (ctx
->domain_guid
.state
== AD_STATE_FIXED
)
1894 ctx
->domain_guid
.state
= AD_STATE_INVALID
;
1899 auto_set_DomainGUID(ad_disc_t ctx
, uchar_t
*u
)
1901 char *domain_guid
= NULL
;
1903 if (is_fixed(&ctx
->domain_guid
))
1906 domain_guid
= uuid_dup(u
);
1907 if (domain_guid
== NULL
)
1909 update_item(&ctx
->domain_guid
, domain_guid
, AD_STATE_AUTO
, 0);
1913 ad_disc_set_DomainController(ad_disc_t ctx
,
1914 const ad_disc_ds_t
*domainController
)
1916 ad_disc_ds_t
*domain_controller
= NULL
;
1917 if (domainController
!= NULL
) {
1918 domain_controller
= ds_dup(domainController
);
1919 if (domain_controller
== NULL
)
1921 update_item(&ctx
->domain_controller
, domain_controller
,
1923 } else if (ctx
->domain_controller
.state
== AD_STATE_FIXED
)
1924 ctx
->domain_controller
.state
= AD_STATE_INVALID
;
1929 ad_disc_set_SiteName(ad_disc_t ctx
, const char *siteName
)
1931 char *site_name
= NULL
;
1932 if (siteName
!= NULL
) {
1933 site_name
= strdup(siteName
);
1934 if (site_name
== NULL
)
1936 update_item(&ctx
->site_name
, site_name
, AD_STATE_FIXED
, 0);
1937 } else if (ctx
->site_name
.state
== AD_STATE_FIXED
)
1938 ctx
->site_name
.state
= AD_STATE_INVALID
;
1943 auto_set_SiteName(ad_disc_t ctx
, char *siteName
)
1945 char *site_name
= NULL
;
1947 if (is_fixed(&ctx
->site_name
))
1950 site_name
= strdup(siteName
);
1951 if (site_name
== NULL
)
1953 update_item(&ctx
->site_name
, site_name
, AD_STATE_AUTO
, 0);
1957 ad_disc_set_ForestName(ad_disc_t ctx
, const char *forestName
)
1959 char *forest_name
= NULL
;
1960 if (forestName
!= NULL
) {
1961 forest_name
= strdup(forestName
);
1962 if (forest_name
== NULL
)
1964 update_item(&ctx
->forest_name
, forest_name
,
1966 } else if (ctx
->forest_name
.state
== AD_STATE_FIXED
)
1967 ctx
->forest_name
.state
= AD_STATE_INVALID
;
1972 auto_set_ForestName(ad_disc_t ctx
, char *forestName
)
1974 char *forest_name
= NULL
;
1976 if (is_fixed(&ctx
->forest_name
))
1979 forest_name
= strdup(forestName
);
1980 if (forest_name
== NULL
)
1982 update_item(&ctx
->forest_name
, forest_name
, AD_STATE_AUTO
, 0);
1986 ad_disc_set_GlobalCatalog(ad_disc_t ctx
,
1987 const ad_disc_ds_t
*globalCatalog
)
1989 ad_disc_ds_t
*global_catalog
= NULL
;
1990 if (globalCatalog
!= NULL
) {
1991 global_catalog
= ds_dup(globalCatalog
);
1992 if (global_catalog
== NULL
)
1994 update_item(&ctx
->global_catalog
, global_catalog
,
1996 } else if (ctx
->global_catalog
.state
== AD_STATE_FIXED
)
1997 ctx
->global_catalog
.state
= AD_STATE_INVALID
;
2002 ad_disc_set_PreferredDC(ad_disc_t ctx
, const ad_disc_ds_t
*pref_dc
)
2004 ad_disc_ds_t
*new_pref_dc
= NULL
;
2005 if (pref_dc
!= NULL
) {
2006 new_pref_dc
= ds_dup(pref_dc
);
2007 if (new_pref_dc
== NULL
)
2009 update_item(&ctx
->preferred_dc
, new_pref_dc
,
2011 } else if (ctx
->preferred_dc
.state
== AD_STATE_FIXED
)
2012 ctx
->preferred_dc
.state
= AD_STATE_INVALID
;
2017 ad_disc_set_StatusFP(ad_disc_t ctx
, struct __FILE_TAG
*fp
)
2019 ctx
->status_fp
= fp
;
2024 ad_disc_unset(ad_disc_t ctx
)
2026 if (ctx
->domain_name
.state
== AD_STATE_FIXED
)
2027 ctx
->domain_name
.state
= AD_STATE_INVALID
;
2029 if (ctx
->domain_controller
.state
== AD_STATE_FIXED
)
2030 ctx
->domain_controller
.state
= AD_STATE_INVALID
;
2032 if (ctx
->preferred_dc
.state
== AD_STATE_FIXED
)
2033 ctx
->preferred_dc
.state
= AD_STATE_INVALID
;
2035 if (ctx
->site_name
.state
== AD_STATE_FIXED
)
2036 ctx
->site_name
.state
= AD_STATE_INVALID
;
2038 if (ctx
->forest_name
.state
== AD_STATE_FIXED
)
2039 ctx
->forest_name
.state
= AD_STATE_INVALID
;
2041 if (ctx
->global_catalog
.state
== AD_STATE_FIXED
)
2042 ctx
->global_catalog
.state
= AD_STATE_INVALID
;
2050 * This routines the time to live for AD
2051 * auto discovered items.
2054 * -1 if there are no TTL items
2055 * 0 if there are expired items
2056 * else the number of seconds
2058 * The MIN_GT_ZERO(x, y) macro return the lesser of x and y, provided it
2059 * is positive -- min() greater than zero.
2061 #define MIN_GT_ZERO(x, y) (((x) <= 0) ? (((y) <= 0) ? \
2062 (-1) : (y)) : (((y) <= 0) ? (x) : (((x) > (y)) ? (y) : (x))))
2064 ad_disc_get_TTL(ad_disc_t ctx
)
2069 expires
= MIN_GT_ZERO(ctx
->domain_controller
.expires
,
2070 ctx
->global_catalog
.expires
);
2071 expires
= MIN_GT_ZERO(expires
, ctx
->site_domain_controller
.expires
);
2072 expires
= MIN_GT_ZERO(expires
, ctx
->site_global_catalog
.expires
);
2074 if (expires
== -1) {
2078 if (ctx
->expires_not_before
!= 0 &&
2079 expires
< ctx
->expires_not_before
) {
2080 expires
= ctx
->expires_not_before
;
2083 if (ctx
->expires_not_after
!= 0 &&
2084 expires
> ctx
->expires_not_after
) {
2085 expires
= ctx
->expires_not_after
;
2088 ttl
= expires
- time(NULL
);
2097 ad_disc_SubnetChanged(ad_disc_t ctx
)
2099 ad_subnet_t
*subnets
;
2101 if (ctx
->subnets_changed
|| ctx
->subnets
== NULL
)
2104 if ((subnets
= find_subnets()) != NULL
) {
2105 if (cmpsubnets(subnets
, ctx
->subnets
) != 0)
2106 ctx
->subnets_changed
= B_TRUE
;
2110 return (ctx
->subnets_changed
);