diff options
Diffstat (limited to 'usr/src/lib/libadutils/common/addisc.c')
-rw-r--r-- | usr/src/lib/libadutils/common/addisc.c | 1238 |
1 files changed, 560 insertions, 678 deletions
diff --git a/usr/src/lib/libadutils/common/addisc.c b/usr/src/lib/libadutils/common/addisc.c index a0bbfe1c0f..f6ac98d11a 100644 --- a/usr/src/lib/libadutils/common/addisc.c +++ b/usr/src/lib/libadutils/common/addisc.c @@ -21,6 +21,7 @@ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2014 Nexenta Systems, Inc. All rights reserved. */ /* @@ -83,12 +84,10 @@ #include <assert.h> #include <stdlib.h> #include <net/if.h> -#include <net/if.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/sockio.h> #include <netinet/in.h> -#include <netinet/in.h> #include <arpa/inet.h> #include <arpa/nameser.h> #include <resolv.h> @@ -96,11 +95,14 @@ #include <ctype.h> #include <errno.h> #include <ldap.h> +#include <note.h> #include <sasl/sasl.h> #include <sys/u8_textprep.h> #include <syslog.h> +#include <uuid/uuid.h> +#include <ads/dsgetdc.h> #include "adutils_impl.h" -#include "addisc.h" +#include "addisc_impl.h" /* * These set some sanity policies for discovery. After a discovery @@ -113,70 +115,10 @@ #define MINIMUM_TTL (5 * 60) #define MAXIMUM_TTL (20 * 60) -enum ad_item_state { - AD_STATE_INVALID = 0, /* The value is not valid */ - AD_STATE_FIXED, /* The value was fixed by caller */ - AD_STATE_AUTO /* The value is auto discovered */ - }; - -enum ad_data_type { - AD_STRING = 123, - AD_DIRECTORY, - AD_DOMAINS_IN_FOREST, - AD_TRUSTED_DOMAINS - }; - - -typedef struct ad_subnet { - char subnet[24]; -} ad_subnet_t; - - -typedef struct ad_item { - enum ad_item_state state; - enum ad_data_type type; - void *value; - time_t expires; - unsigned int version; /* Version is only changed */ - /* if the value changes */ -#define PARAM1 0 -#define PARAM2 1 - int param_version[2]; - /* These holds the version of */ - /* dependents so that a dependent */ - /* change can be detected */ -} ad_item_t; - -typedef struct ad_disc { - struct __res_state res_state; - int res_ninitted; - ad_subnet_t *subnets; - boolean_t subnets_changed; - time_t subnets_last_check; - time_t expires_not_before; - time_t expires_not_after; - ad_item_t domain_name; /* DNS hostname string */ - ad_item_t domain_controller; /* Directory hostname and */ - /* port array */ - ad_item_t site_name; /* String */ - ad_item_t forest_name; /* DNS forestname string */ - ad_item_t global_catalog; /* Directory hostname and */ - /* port array */ - ad_item_t domains_in_forest; /* DNS domainname and SID */ - /* array */ - ad_item_t trusted_domains; /* DNS domainname and trust */ - /* direction array */ - /* Site specfic versions */ - ad_item_t site_domain_controller; /* Directory hostname and */ - /* port array */ - ad_item_t site_global_catalog; /* Directory hostname and */ - /* port array */ - int debug[AD_DEBUG_MAX+1]; /* Debug levels */ -} ad_disc; - #define DNS_MAX_NAME NS_MAXDNAME +#define GC_PORT 3268 /* SRV RR names for various queries */ #define LDAP_SRV_HEAD "_ldap._tcp." @@ -194,8 +136,23 @@ typedef struct ad_disc { * We try res_ninit() whenever we don't have one. res_ninit() fails if * idmapd is running before the network is up! */ -#define DO_RES_NINIT(ctx) if (!(ctx)->res_ninitted) \ - (ctx)->res_ninitted = (res_ninit(&ctx->res_state) != -1) +#define DO_RES_NINIT(ctx) \ + if (!(ctx)->res_ninitted) \ + (void) do_res_ninit(ctx) + +#define DO_GETNAMEINFO(b, l, s) \ + if (ad_disc_getnameinfo(b, l, s) != 0) \ + (void) strlcpy(b, "?", l) + +#define DEBUG1STATUS(ctx, ...) do { \ + if (DBG(DISC, 1)) \ + logger(LOG_DEBUG, __VA_ARGS__); \ + if (ctx->status_fp) { \ + (void) fprintf(ctx->status_fp, __VA_ARGS__); \ + (void) fprintf(ctx->status_fp, "\n"); \ + } \ + _NOTE(CONSTCOND) \ +} while (0) #define is_fixed(item) \ ((item)->state == AD_STATE_FIXED) @@ -203,13 +160,65 @@ typedef struct ad_disc { #define is_changed(item, num, param) \ ((item)->param_version[num] != (param)->version) +void * uuid_dup(void *); + +static ad_item_t *validate_SiteName(ad_disc_t ctx); +static ad_item_t *validate_PreferredDC(ad_disc_t ctx); + /* * Function definitions */ -static ad_item_t * -validate_SiteName(ad_disc_t ctx); +static int +do_res_ninit(ad_disc_t ctx) +{ + int rc; + + rc = res_ninit(&ctx->res_state); + if (rc != 0) + return (rc); + ctx->res_ninitted = 1; + /* + * The SRV records returnd by AD can be larger than 512 bytes, + * so we'd like to use TCP for those searches. Unfortunately, + * the TCP connect timeout seen by the resolver is very long + * (more than a couple minutes) and we can't wait that long. + * Don't do use TCP until we can override the timeout. + * + * Note that some queries will try TCP anyway. + */ +#if 0 + ctx->res_state.options |= RES_USEVC; +#endif + return (0); +} + +/* + * Private getnameinfo(3socket) variant tailored to our needs. + */ +int +ad_disc_getnameinfo(char *obuf, int olen, struct sockaddr_storage *ss) +{ + struct sockaddr *sa; + int eai, slen; + + sa = (void *)ss; + switch (sa->sa_family) { + case AF_INET: + slen = sizeof (struct sockaddr_in); + break; + case AF_INET6: + slen = sizeof (struct sockaddr_in6); + break; + default: + return (EAI_FAMILY); + } + + eai = getnameinfo(sa, slen, obuf, olen, NULL, 0, NI_NUMERICHOST); + + return (eai); +} static void update_version(ad_item_t *item, int num, ad_item_t *param) @@ -240,6 +249,8 @@ update_item(ad_item_t *item, void *value, enum ad_item_state state, if (item->value != NULL && value != NULL) { if ((item->type == AD_STRING && strcmp(item->value, value) != 0) || + (item->type == AD_UUID && + ad_disc_compare_uuid(item->value, value) != 0)|| (item->type == AD_DIRECTORY && ad_disc_compare_ds(item->value, value) != 0)|| (item->type == AD_DOMAINS_IN_FOREST && @@ -262,10 +273,29 @@ update_item(ad_item_t *item, void *value, enum ad_item_state state, item->expires = time(NULL) + ttl; } +/* Compare UUIDs */ +int +ad_disc_compare_uuid(uuid_t *u1, uuid_t *u2) +{ + int rc; + + rc = memcmp(u1, u2, UUID_LEN); + return (rc); +} + +void * +uuid_dup(void *src) +{ + void *dst; + dst = malloc(UUID_LEN); + if (dst != NULL) + (void) memcpy(dst, src, UUID_LEN); + return (dst); +} /* Compare DS lists */ int -ad_disc_compare_ds(idmap_ad_disc_ds_t *ds1, idmap_ad_disc_ds_t *ds2) +ad_disc_compare_ds(ad_disc_ds_t *ds1, ad_disc_ds_t *ds2) { int i, j; int num_ds1; @@ -298,17 +328,17 @@ ad_disc_compare_ds(idmap_ad_disc_ds_t *ds1, idmap_ad_disc_ds_t *ds2) /* Copy a list of DSs */ -static idmap_ad_disc_ds_t * -ds_dup(const idmap_ad_disc_ds_t *srv) +static ad_disc_ds_t * +ds_dup(const ad_disc_ds_t *srv) { int i; int size; - idmap_ad_disc_ds_t *new = NULL; + ad_disc_ds_t *new = NULL; for (i = 0; srv[i].host[0] != '\0'; i++) continue; - size = (i + 1) * sizeof (idmap_ad_disc_ds_t); + size = (i + 1) * sizeof (ad_disc_ds_t); new = malloc(size); if (new != NULL) (void) memcpy(new, srv, size); @@ -603,237 +633,13 @@ DN_to_DNS(const char *dn_name) } -/* Make a list of subnet object DNs from a list of subnets */ -static char ** -subnets_to_DNs(ad_subnet_t *subnets, const char *base_dn) -{ - char **results; - int i, j; - - for (i = 0; subnets[i].subnet[0] != '\0'; i++) - continue; - - results = calloc(i + 1, sizeof (char *)); - if (results == NULL) - return (NULL); - - for (i = 0; subnets[i].subnet[0] != '\0'; i++) { - (void) asprintf(&results[i], "CN=%s,CN=Subnets,CN=Sites,%s", - subnets[i].subnet, base_dn); - if (results[i] == NULL) { - for (j = 0; j < i; j++) - free(results[j]); - free(results); - return (NULL); - } - } - - return (results); -} - - -/* Compare SRC RRs; used with qsort() */ -static int -srvcmp(idmap_ad_disc_ds_t *s1, idmap_ad_disc_ds_t *s2) -{ - if (s1->priority < s2->priority) - return (1); - else if (s1->priority > s2->priority) - return (-1); - - if (s1->weight < s2->weight) - return (1); - else if (s1->weight > s2->weight) - return (-1); - - return (0); -} - - -/* - * Query or search the SRV RRs for a given name. - * - * If name == NULL then search (as in res_nsearch(3RESOLV), honoring any - * search list/option), else query (as in res_nquery(3RESOLV)). - * - * The output TTL will be the one of the SRV RR with the lowest TTL. - */ -idmap_ad_disc_ds_t * -srv_query(res_state state, const char *svc_name, const char *dname, - char **rrname, uint32_t *ttl) -{ - idmap_ad_disc_ds_t *srv; - idmap_ad_disc_ds_t *srv_res = NULL; - union { - HEADER hdr; - uchar_t buf[NS_MAXMSG]; - } msg; - int len, cnt, qdcount, ancount; - uchar_t *ptr, *eom; - uchar_t *end; - uint16_t type; - /* LINTED E_FUNC_SET_NOT_USED */ - uint16_t class; - uint32_t rttl; - uint16_t size; - char namebuf[NS_MAXDNAME]; - - if (state == NULL) - return (NULL); - - /* Set negative result TTL */ - *ttl = 5 * 60; - - /* 1. query necessary resource records */ - - /* Search, querydomain or query */ - if (rrname != NULL) { - *rrname = NULL; - if (DBG(DNS, 1)) { - logger(LOG_DEBUG, "Looking for SRV RRs '%s.*'", - svc_name); - } - len = res_nsearch(state, svc_name, C_IN, T_SRV, - msg.buf, sizeof (msg.buf)); - if (len < 0) { - if (DBG(DNS, 0)) { - logger(LOG_DEBUG, - "DNS search for '%s' failed (%s)", - svc_name, hstrerror(state->res_h_errno)); - } - return (NULL); - } - } else if (dname != NULL) { - if (DBG(DNS, 1)) { - logger(LOG_DEBUG, "Looking for SRV RRs '%s.%s' ", - svc_name, dname); - } - - len = res_nquerydomain(state, svc_name, dname, C_IN, T_SRV, - msg.buf, sizeof (msg.buf)); - - if (len < 0) { - if (DBG(DNS, 0)) { - logger(LOG_DEBUG, "DNS: %s.%s: %s", - svc_name, dname, - hstrerror(state->res_h_errno)); - } - return (NULL); - } - } - - if (len > sizeof (msg.buf)) { - logger(LOG_ERR, - "DNS query %ib message doesn't fit into %ib buffer", - len, sizeof (msg.buf)); - return (NULL); - } - - /* 2. parse the reply, skip header and question sections */ - - ptr = msg.buf + sizeof (msg.hdr); - eom = msg.buf + len; - qdcount = ntohs(msg.hdr.qdcount); - ancount = ntohs(msg.hdr.ancount); - - for (cnt = qdcount; cnt > 0; --cnt) { - if ((len = dn_skipname(ptr, eom)) < 0) { - logger(LOG_ERR, "DNS query invalid message format"); - return (NULL); - } - ptr += len + QFIXEDSZ; - } - - /* 3. walk through the answer section */ - - srv_res = calloc(ancount + 1, sizeof (idmap_ad_disc_ds_t)); - if (srv_res == NULL) { - logger(LOG_ERR, "Out of memory"); - return (NULL); - } - - *ttl = (uint32_t)-1; - - for (srv = srv_res, cnt = ancount; - cnt > 0; --cnt, srv++) { - - len = dn_expand(msg.buf, eom, ptr, namebuf, - sizeof (namebuf)); - if (len < 0) { - logger(LOG_ERR, "DNS query invalid message format"); - goto err; - } - if (rrname != NULL && *rrname == NULL) { - *rrname = strdup(namebuf); - if (*rrname == NULL) { - logger(LOG_ERR, "Out of memory"); - goto err; - } - } - ptr += len; - NS_GET16(type, ptr); - NS_GET16(class, ptr); - NS_GET32(rttl, ptr); - NS_GET16(size, ptr); - if ((end = ptr + size) > eom) { - logger(LOG_ERR, "DNS query invalid message format"); - goto err; - } - - if (type != T_SRV) { - ptr = end; - continue; - } - - NS_GET16(srv->priority, ptr); - NS_GET16(srv->weight, ptr); - NS_GET16(srv->port, ptr); - len = dn_expand(msg.buf, eom, ptr, srv->host, - sizeof (srv->host)); - if (len < 0) { - logger(LOG_ERR, "DNS query invalid SRV record"); - goto err; - } - - if (rttl < *ttl) - *ttl = rttl; - - if (DBG(DNS, 1)) { - logger(LOG_DEBUG, " %s", namebuf); - logger(LOG_DEBUG, - " ttl=%d pri=%d weight=%d %s:%d", - rttl, srv->priority, srv->weight, - srv->host, srv->port); - } - - /* 3. move ptr to the end of current record */ - - ptr = end; - } - - if (ancount > 1) - qsort(srv_res, ancount, sizeof (*srv_res), - (int (*)(const void *, const void *))srvcmp); - - return (srv_res); - -err: - free(srv_res); - if (rrname != NULL) { - free(*rrname); - *rrname = NULL; - } - return (NULL); -} - - /* * A utility function to bind to a Directory server */ static LDAP * -ldap_lookup_init(idmap_ad_disc_ds_t *ds) +ldap_lookup_init(ad_disc_ds_t *ds) { int i; int rc, ldversion; @@ -844,6 +650,11 @@ ldap_lookup_init(idmap_ad_disc_ds_t *ds) LDAP *ld = NULL; for (i = 0; ds[i].host[0] != '\0'; i++) { + if (DBG(LDAP, 2)) { + logger(LOG_DEBUG, "adutils: ldap_lookup_init, host %s", + ds[i].host); + } + ld = ldap_init(ds[i].host, ds[i].port); if (ld == NULL) { if (DBG(LDAP, 1)) { @@ -896,60 +707,6 @@ ldap_lookup_init(idmap_ad_disc_ds_t *ds) /* - * A utility function to get the value of some attribute of one of one - * or more AD LDAP objects named by the dn_list; first found one wins. - */ -static char * -ldap_lookup_entry_attr(LDAP **ld, idmap_ad_disc_ds_t *domainControllers, - char **dn_list, char *attr) -{ - int i; - int rc; - int scope = LDAP_SCOPE_BASE; - char *attrs[2]; - LDAPMessage *results = NULL; - LDAPMessage *entry; - char **values = NULL; - char *val = NULL; - - attrs[0] = attr; - attrs[1] = NULL; - - if (*ld == NULL) - *ld = ldap_lookup_init(domainControllers); - - if (*ld == NULL) - return (NULL); - - for (i = 0; dn_list[i] != NULL; i++) { - rc = ldap_search_s(*ld, dn_list[i], scope, - "(objectclass=*)", attrs, 0, &results); - if (rc == LDAP_SUCCESS) { - for (entry = ldap_first_entry(*ld, results); - entry != NULL && values == NULL; - entry = ldap_next_entry(*ld, entry)) { - values = ldap_get_values( - *ld, entry, attr); - } - - if (values != NULL) { - (void) ldap_msgfree(results); - val = strdup(values[0]); - ldap_value_free(values); - return (val); - } - } - if (results != NULL) { - (void) ldap_msgfree(results); - results = NULL; - } - } - - return (NULL); -} - - -/* * Lookup the trusted domains in the global catalog. * * Returns: @@ -958,7 +715,7 @@ ldap_lookup_entry_attr(LDAP **ld, idmap_ad_disc_ds_t *domainControllers, * NULL an error occured */ ad_disc_trusteddomains_t * -ldap_lookup_trusted_domains(LDAP **ld, idmap_ad_disc_ds_t *globalCatalog, +ldap_lookup_trusted_domains(LDAP **ld, ad_disc_ds_t *globalCatalog, char *base_dn) { int scope = LDAP_SCOPE_SUBTREE; @@ -978,8 +735,10 @@ ldap_lookup_trusted_domains(LDAP **ld, idmap_ad_disc_ds_t *globalCatalog, if (*ld == NULL) *ld = ldap_lookup_init(globalCatalog); - if (*ld == NULL) + if (*ld == NULL) { + logger(LOG_ERR, "adutils: ldap_lookup_init failed"); return (NULL); + } attrs[0] = "trustPartner"; attrs[1] = "trustDirection"; @@ -1039,6 +798,9 @@ ldap_lookup_trusted_domains(LDAP **ld, idmap_ad_disc_ds_t *globalCatalog, trusted_domains = calloc(1, sizeof (ad_disc_trusteddomains_t)); if (DBG(DISC, 1)) logger(LOG_DEBUG, " not found"); + } else { + if (DBG(DISC, 1)) + logger(LOG_DEBUG, " rc=%d", rc); } if (results != NULL) (void) ldap_msgfree(results); @@ -1051,7 +813,7 @@ ldap_lookup_trusted_domains(LDAP **ld, idmap_ad_disc_ds_t *globalCatalog, * This functions finds all the domains in a forest. */ ad_disc_domainsinforest_t * -ldap_lookup_domains_in_forest(LDAP **ld, idmap_ad_disc_ds_t *globalCatalogs) +ldap_lookup_domains_in_forest(LDAP **ld, ad_disc_ds_t *globalCatalogs) { static char *attrs[] = { "objectSid", @@ -1064,27 +826,34 @@ ldap_lookup_domains_in_forest(LDAP **ld, idmap_ad_disc_ds_t *globalCatalogs) int nresults; ad_disc_domainsinforest_t *domains = NULL; - if (DBG(DISC, 2)) + if (DBG(DISC, 1)) logger(LOG_DEBUG, "Looking for domains in forest..."); if (*ld == NULL) *ld = ldap_lookup_init(globalCatalogs); - if (*ld == NULL) + if (*ld == NULL) { + logger(LOG_ERR, "adutils: ldap_lookup_init failed"); return (NULL); + } /* Find domains */ rc = ldap_search_s(*ld, "", LDAP_SCOPE_SUBTREE, "(objectClass=Domain)", attrs, 0, &result); + if (rc != LDAP_SUCCESS) { + logger(LOG_ERR, "adutils: ldap_search, rc=%d", rc); + goto err; + } if (DBG(DISC, 1)) logger(LOG_DEBUG, "Domains in forest:"); - if (rc != LDAP_SUCCESS) - goto err; nresults = ldap_count_entries(*ld, result); domains = calloc(nresults + 1, sizeof (*domains)); - if (domains == NULL) + if (domains == NULL) { + if (DBG(DISC, 1)) + logger(LOG_DEBUG, " (nomem)"); goto err; + } for (entry = ldap_first_entry(*ld, result); entry != NULL; @@ -1162,7 +931,9 @@ ad_disc_init(void) DO_RES_NINIT(ctx); ctx->domain_name.type = AD_STRING; + ctx->domain_guid.type = AD_UUID; ctx->domain_controller.type = AD_DIRECTORY; + ctx->preferred_dc.type = AD_DIRECTORY; ctx->site_name.type = AD_STRING; ctx->forest_name.type = AD_STRING; ctx->global_catalog.type = AD_DIRECTORY; @@ -1189,9 +960,15 @@ ad_disc_fini(ad_disc_t ctx) if (ctx->domain_name.value != NULL) free(ctx->domain_name.value); + if (ctx->domain_guid.value != NULL) + free(ctx->domain_guid.value); + if (ctx->domain_controller.value != NULL) free(ctx->domain_controller.value); + if (ctx->preferred_dc.value != NULL) + free(ctx->preferred_dc.value); + if (ctx->site_name.value != NULL) free(ctx->site_name.value); @@ -1220,17 +997,25 @@ ad_disc_fini(ad_disc_t ctx) void ad_disc_refresh(ad_disc_t ctx) { - if (ctx->res_ninitted) + if (ctx->res_ninitted) { res_ndestroy(&ctx->res_state); + ctx->res_ninitted = 0; + } (void) memset(&ctx->res_state, 0, sizeof (ctx->res_state)); - ctx->res_ninitted = res_ninit(&ctx->res_state) != -1; + DO_RES_NINIT(ctx); if (ctx->domain_name.state == AD_STATE_AUTO) ctx->domain_name.state = AD_STATE_INVALID; + if (ctx->domain_guid.state == AD_STATE_AUTO) + ctx->domain_guid.state = AD_STATE_INVALID; + if (ctx->domain_controller.state == AD_STATE_AUTO) ctx->domain_controller.state = AD_STATE_INVALID; + if (ctx->preferred_dc.state == AD_STATE_AUTO) + ctx->preferred_dc.state = AD_STATE_INVALID; + if (ctx->site_name.state == AD_STATE_AUTO) ctx->site_name.state = AD_STATE_INVALID; @@ -1270,15 +1055,77 @@ ad_disc_done(ad_disc_t ctx) ctx->expires_not_after = now + MAXIMUM_TTL; } +static void +log_cds(ad_disc_t ctx, ad_disc_cds_t *cds) +{ + char buf[INET6_ADDRSTRLEN]; + struct addrinfo *ai; + + if (!DBG(DISC, 1) && ctx->status_fp == NULL) + return; + + DEBUG1STATUS(ctx, "Candidate servers:"); + if (cds->cds_ds.host[0] == '\0') { + DEBUG1STATUS(ctx, " (empty list)"); + return; + } + + while (cds->cds_ds.host[0] != '\0') { + + DEBUG1STATUS(ctx, " %s p=%d w=%d", + cds->cds_ds.host, + cds->cds_ds.priority, + cds->cds_ds.weight); + + ai = cds->cds_ai; + if (ai == NULL) { + DEBUG1STATUS(ctx, " (no address)"); + } + while (ai != NULL) { + int eai; + + eai = getnameinfo(ai->ai_addr, ai->ai_addrlen, + buf, sizeof (buf), NULL, 0, NI_NUMERICHOST); + if (eai != 0) + (void) strlcpy(buf, "?", sizeof (buf)); + + DEBUG1STATUS(ctx, " %s", buf); + ai = ai->ai_next; + } + cds++; + } +} + +static void +log_ds(ad_disc_t ctx, ad_disc_ds_t *ds) +{ + char buf[INET6_ADDRSTRLEN]; + + if (!DBG(DISC, 1) && ctx->status_fp == NULL) + return; + + DEBUG1STATUS(ctx, "Responding servers:"); + if (ds->host[0] == '\0') { + DEBUG1STATUS(ctx, " (empty list)"); + return; + } + + while (ds->host[0] != '\0') { + + DEBUG1STATUS(ctx, " %s", ds->host); + DO_GETNAMEINFO(buf, sizeof (buf), &ds->addr); + DEBUG1STATUS(ctx, " %s", buf); + + ds++; + } +} /* Discover joined Active Directory domainName */ static ad_item_t * validate_DomainName(ad_disc_t ctx) { - idmap_ad_disc_ds_t *domain_controller = NULL; char *dname, *srvname; - uint32_t ttl = 0; - int len; + int len, rc; if (is_valid(&ctx->domain_name)) return (&ctx->domain_name); @@ -1286,23 +1133,21 @@ validate_DomainName(ad_disc_t ctx) /* Try to find our domain by searching for DCs for it */ DO_RES_NINIT(ctx); - if (DBG(DISC, 2)) + if (DBG(DISC, 1)) logger(LOG_DEBUG, "Looking for our AD domain name..."); - domain_controller = srv_query(&ctx->res_state, - LDAP_SRV_HEAD DC_SRV_TAIL, - ctx->domain_name.value, &srvname, &ttl); + rc = srv_getdom(&ctx->res_state, + LDAP_SRV_HEAD DC_SRV_TAIL, &srvname); /* * If we can't find DCs by via res_nsearch() then there's no * point in trying anything else to discover the AD domain name. */ - if (domain_controller == NULL) { + if (rc < 0) { if (DBG(DISC, 1)) logger(LOG_DEBUG, "Can't find our domain name."); return (NULL); } - free(domain_controller); /* * We have the FQDN of the SRV RR name, so now we extract the * domainname suffix from it. @@ -1324,7 +1169,14 @@ validate_DomainName(ad_disc_t ctx) if (DBG(DISC, 1)) logger(LOG_DEBUG, "Our domain name: %s", dname); - update_item(&ctx->domain_name, dname, AD_STATE_AUTO, ttl); + + /* + * There is no "time to live" on the discovered domain, + * so passing zero as TTL here, making it non-expiring. + * Note that current consumers do not auto-discover the + * domain name, though a future installer could. + */ + update_item(&ctx->domain_name, dname, AD_STATE_AUTO, 0); return (&ctx->domain_name); } @@ -1354,12 +1206,16 @@ ad_disc_get_DomainName(ad_disc_t ctx, boolean_t *auto_discovered) static ad_item_t * validate_DomainController(ad_disc_t ctx, enum ad_disc_req req) { - uint32_t ttl = 0; - idmap_ad_disc_ds_t *domain_controller = NULL; + ad_disc_ds_t *dc = NULL; + ad_disc_cds_t *cdc = NULL; boolean_t validate_global = B_FALSE; boolean_t validate_site = B_FALSE; ad_item_t *domain_name_item; + char *domain_name; ad_item_t *site_name_item = NULL; + char *site_name; + ad_item_t *prefer_dc_item; + ad_disc_ds_t *prefer_dc = NULL; /* If the values is fixed there will not be a site specific version */ if (is_fixed(&ctx->domain_controller)) @@ -1368,12 +1224,17 @@ validate_DomainController(ad_disc_t ctx, enum ad_disc_req req) domain_name_item = validate_DomainName(ctx); if (domain_name_item == NULL) return (NULL); + domain_name = (char *)domain_name_item->value; + + /* Get (optional) preferred DC. */ + prefer_dc_item = validate_PreferredDC(ctx); + if (prefer_dc_item != NULL) + prefer_dc = prefer_dc_item->value; if (req == AD_DISC_GLOBAL) validate_global = B_TRUE; else { - site_name_item = validate_SiteName(ctx); - if (site_name_item != NULL) + if (is_fixed(&ctx->site_name)) validate_site = B_TRUE; else if (req == AD_DISC_PREFER_SITE) validate_global = B_TRUE; @@ -1383,43 +1244,44 @@ validate_DomainController(ad_disc_t ctx, enum ad_disc_req req) if (!is_valid(&ctx->domain_controller) || is_changed(&ctx->domain_controller, PARAM1, domain_name_item)) { - if (DBG(DISC, 2)) { - logger(LOG_DEBUG, "Looking for DCs for %s", - domain_name_item->value); - } + /* * Lookup DNS SRV RR named * _ldap._tcp.dc._msdcs.<DomainName> */ + DEBUG1STATUS(ctx, "DNS SRV query, dom=%s", + domain_name); DO_RES_NINIT(ctx); - domain_controller = srv_query(&ctx->res_state, + cdc = srv_query(&ctx->res_state, LDAP_SRV_HEAD DC_SRV_TAIL, - domain_name_item->value, NULL, &ttl); + domain_name, prefer_dc); - if (DBG(DISC, 1)) { - logger(LOG_DEBUG, "DCs for %s:", - domain_name_item->value); - } - if (domain_controller == NULL) { - if (DBG(DISC, 1)) - logger(LOG_DEBUG, " not found"); + if (cdc == NULL) { + DEBUG1STATUS(ctx, "(no DNS response)"); return (NULL); } + log_cds(ctx, cdc); - if (DBG(DISC, 1)) { - int i; - - for (i = 0; - domain_controller[i].host[0] != '\0'; - i++) { - logger(LOG_DEBUG, " %s:%d", - domain_controller[i].host, - domain_controller[i].port); - } + /* + * Filter out unresponsive servers, and + * save the domain info we get back. + */ + dc = ldap_ping( + ctx, + cdc, + domain_name, + DS_DS_FLAG); + srv_free(cdc); + cdc = NULL; + + if (dc == NULL) { + DEBUG1STATUS(ctx, "(no LDAP response)"); + return (NULL); } + log_ds(ctx, dc); - update_item(&ctx->domain_controller, domain_controller, - AD_STATE_AUTO, ttl); + update_item(&ctx->domain_controller, dc, + AD_STATE_AUTO, dc->ttl); update_version(&ctx->domain_controller, PARAM1, domain_name_item); } @@ -1427,54 +1289,55 @@ validate_DomainController(ad_disc_t ctx, enum ad_disc_req req) } if (validate_site) { + site_name_item = &ctx->site_name; + site_name = (char *)site_name_item->value; + if (!is_valid(&ctx->site_domain_controller) || is_changed(&ctx->site_domain_controller, PARAM1, domain_name_item) || is_changed(&ctx->site_domain_controller, PARAM2, site_name_item)) { char rr_name[DNS_MAX_NAME]; - if (DBG(DISC, 2)) { - logger(LOG_DEBUG, - "Looking for DCs for %s in %s", - domain_name_item->value, - site_name_item->value); - } + /* * Lookup DNS SRV RR named * _ldap._tcp.<SiteName>._sites.dc._msdcs.<DomainName> */ + DEBUG1STATUS(ctx, "DNS SRV query, dom=%s, site=%s", + domain_name, site_name); (void) snprintf(rr_name, sizeof (rr_name), LDAP_SRV_HEAD SITE_SRV_MIDDLE DC_SRV_TAIL, - site_name_item->value); + site_name); DO_RES_NINIT(ctx); - domain_controller = srv_query(&ctx->res_state, rr_name, - domain_name_item->value, NULL, &ttl); - if (DBG(DISC, 1)) { - logger(LOG_DEBUG, - "DCs for %s in %s", - domain_name_item->value, - site_name_item->value); - } - if (domain_controller == NULL) { - if (DBG(DISC, 1)) - logger(LOG_DEBUG, " not found"); + cdc = srv_query(&ctx->res_state, rr_name, + domain_name, prefer_dc); + + if (cdc == NULL) { + DEBUG1STATUS(ctx, "(no DNS response)"); return (NULL); } + log_cds(ctx, cdc); - if (DBG(DISC, 1)) { - int i; - - for (i = 0; - domain_controller[i].host[0] != '\0'; - i++) { - logger(LOG_DEBUG, " %s:%d", - domain_controller[i].host, - domain_controller[i].port); - } + /* + * Filter out unresponsive servers, and + * save the domain info we get back. + */ + dc = ldap_ping( + ctx, + cdc, + domain_name, + DS_DS_FLAG); + srv_free(cdc); + cdc = NULL; + + if (dc == NULL) { + DEBUG1STATUS(ctx, "(no LDAP response)"); + return (NULL); } + log_ds(ctx, dc); - update_item(&ctx->site_domain_controller, - domain_controller, AD_STATE_AUTO, ttl); + update_item(&ctx->site_domain_controller, dc, + AD_STATE_AUTO, dc->ttl); update_version(&ctx->site_domain_controller, PARAM1, domain_name_item); update_version(&ctx->site_domain_controller, PARAM2, @@ -1485,12 +1348,12 @@ validate_DomainController(ad_disc_t ctx, enum ad_disc_req req) return (NULL); } -idmap_ad_disc_ds_t * +ad_disc_ds_t * ad_disc_get_DomainController(ad_disc_t ctx, enum ad_disc_req req, - boolean_t *auto_discovered) + boolean_t *auto_discovered) { ad_item_t *domain_controller_item; - idmap_ad_disc_ds_t *domain_controller = NULL; + ad_disc_ds_t *domain_controller = NULL; domain_controller_item = validate_DomainController(ctx, req); @@ -1506,161 +1369,68 @@ ad_disc_get_DomainController(ad_disc_t ctx, enum ad_disc_req req, } -/* Discover site name (for multi-homed systems the first one found wins) */ +/* + * Discover the Domain GUID + * This info comes from validate_DomainController() + */ static ad_item_t * -validate_SiteName(ad_disc_t ctx) +validate_DomainGUID(ad_disc_t ctx) { - LDAP *ld = NULL; - ad_subnet_t *subnets = NULL; - char **dn_subnets = NULL; - char *dn_root[2]; - char *config_naming_context = NULL; - char *site_object = NULL; - char *site_name = NULL; - char *forest_name; - int len; - boolean_t update_required = B_FALSE; ad_item_t *domain_controller_item; - if (is_fixed(&ctx->site_name)) - return (&ctx->site_name); + if (is_fixed(&ctx->domain_guid)) + return (&ctx->domain_guid); - /* Can't rely on site-specific DCs */ domain_controller_item = validate_DomainController(ctx, AD_DISC_GLOBAL); if (domain_controller_item == NULL) return (NULL); - if (!is_valid(&ctx->site_name) || - is_changed(&ctx->site_name, PARAM1, domain_controller_item) || - ctx->subnets == NULL || ctx->subnets_changed) { - subnets = find_subnets(); - ctx->subnets_last_check = time(NULL); - update_required = B_TRUE; - } else if (ctx->subnets_last_check + 60 < time(NULL)) { - /* NEEDSWORK magic constant 60 above */ - subnets = find_subnets(); - ctx->subnets_last_check = time(NULL); - if (cmpsubnets(ctx->subnets, subnets) != 0) - update_required = B_TRUE; - } - - if (!update_required) { - free(subnets); - return (&ctx->site_name); - } - - if (subnets == NULL) + if (!is_valid(&ctx->domain_guid)) return (NULL); - dn_root[0] = ""; - dn_root[1] = NULL; + return (&ctx->domain_guid); +} - if (DBG(DISC, 1)) - logger(LOG_DEBUG, "Getting site name"); - config_naming_context = ldap_lookup_entry_attr( - &ld, ctx->domain_controller.value, - dn_root, "configurationNamingContext"); - if (config_naming_context == NULL) - goto out; - /* - * configurationNamingContext also provides the Forest - * Name. - */ - if (!is_fixed(&ctx->forest_name)) { - /* - * The configurationNamingContext should be of - * form: - * CN=Configuration,<DNforestName> - * Remove the first part and convert to DNS form - * (replace ",DC=" with ".") - */ - char *str = "CN=Configuration,"; - int len = strlen(str); - if (strncasecmp(config_naming_context, str, len) == 0) { - forest_name = DN_to_DNS(config_naming_context + len); - if (DBG(DISC, 1)) { - logger(LOG_DEBUG, " forest: %s", - forest_name); - } - update_item(&ctx->forest_name, forest_name, - AD_STATE_AUTO, 0); - update_version(&ctx->forest_name, PARAM1, - domain_controller_item); - } - } +uchar_t * +ad_disc_get_DomainGUID(ad_disc_t ctx, boolean_t *auto_discovered) +{ + ad_item_t *domain_guid_item; + uchar_t *domain_guid = NULL; - if (DBG(DISC, 2)) - logger(LOG_DEBUG, " CNC: %s", config_naming_context); + domain_guid_item = validate_DomainGUID(ctx); + if (domain_guid_item != NULL) { + domain_guid = uuid_dup(domain_guid_item->value); + if (auto_discovered != NULL) + *auto_discovered = + (domain_guid_item->state == AD_STATE_AUTO); + } else if (auto_discovered != NULL) + *auto_discovered = B_FALSE; - if (DBG(DISC, 2)) { - int i; - logger(LOG_DEBUG, " Looking for sites for subnets:"); - for (i = 0; subnets[i].subnet[0] != '\0'; i++) { - logger(LOG_DEBUG, " %s", subnets[i].subnet); - } - } + return (domain_guid); +} - dn_subnets = subnets_to_DNs(subnets, config_naming_context); - if (dn_subnets == NULL) - goto out; - - site_object = ldap_lookup_entry_attr( - &ld, domain_controller_item->value, - dn_subnets, "siteobject"); - if (site_object != NULL) { - /* - * The site object should be of the form - * CN=<site>,CN=Sites,CN=Configuration, - * <DN Domain> - */ - if (DBG(DISC, 2)) - logger(LOG_DEBUG, " Site object: %s", site_object); - if (strncasecmp(site_object, "CN=", 3) == 0) { - for (len = 0; site_object[len + 3] != ','; len++) - ; - site_name = malloc(len + 1); - (void) strncpy(site_name, &site_object[3], len); - site_name[len] = '\0'; - if (DBG(DISC, 1)) { - logger(LOG_DEBUG, " Site name \"%s\"", - site_name); - } - update_item(&ctx->site_name, site_name, - AD_STATE_AUTO, 0); - update_version(&ctx->site_name, PARAM1, - domain_controller_item); - } - } - if (ctx->subnets != NULL) { - free(ctx->subnets); - ctx->subnets = NULL; - } - ctx->subnets = subnets; - subnets = NULL; - ctx->subnets_changed = B_FALSE; +/* + * Discover site name (for multi-homed systems the first one found wins) + * This info comes from validate_DomainController() + */ +static ad_item_t * +validate_SiteName(ad_disc_t ctx) +{ + ad_item_t *domain_controller_item; -out: - if (ld != NULL) - (void) ldap_unbind(ld); + if (is_fixed(&ctx->site_name)) + return (&ctx->site_name); - if (dn_subnets != NULL) { - int i; - for (i = 0; dn_subnets[i] != NULL; i++) - free(dn_subnets[i]); - free(dn_subnets); - } - if (config_naming_context != NULL) - free(config_naming_context); - if (site_object != NULL) - free(site_object); + domain_controller_item = validate_DomainController(ctx, AD_DISC_GLOBAL); + if (domain_controller_item == NULL) + return (NULL); - free(subnets); - if (site_name == NULL) + if (!is_valid(&ctx->site_name)) return (NULL); - return (&ctx->site_name); + return (&ctx->site_name); } @@ -1684,69 +1454,25 @@ ad_disc_get_SiteName(ad_disc_t ctx, boolean_t *auto_discovered) -/* Discover forest name */ +/* + * Discover forest name + * This info comes from validate_DomainController() + */ static ad_item_t * validate_ForestName(ad_disc_t ctx) { - LDAP *ld = NULL; - char *config_naming_context; - char *forest_name = NULL; - char *dn_list[2]; ad_item_t *domain_controller_item; if (is_fixed(&ctx->forest_name)) return (&ctx->forest_name); - /* - * We may not have a site name yet, so we won't rely on - * site-specific DCs. (But maybe we could replace - * validate_ForestName() with validate_siteName()?) - */ + domain_controller_item = validate_DomainController(ctx, AD_DISC_GLOBAL); if (domain_controller_item == NULL) return (NULL); - if (!is_valid(&ctx->forest_name) || - is_changed(&ctx->forest_name, PARAM1, domain_controller_item)) { - - dn_list[0] = ""; - dn_list[1] = NULL; - if (DBG(DISC, 1)) - logger(LOG_DEBUG, "Getting forest name"); - config_naming_context = ldap_lookup_entry_attr( - &ld, ctx->domain_controller.value, - dn_list, "configurationNamingContext"); - if (config_naming_context != NULL) { - /* - * The configurationNamingContext should be of - * form: - * CN=Configuration,<DNforestName> - * Remove the first part and convert to DNS form - * (replace ",DC=" with ".") - */ - char *str = "CN=Configuration,"; - int len = strlen(str); - if (strncasecmp(config_naming_context, str, len) == 0) { - forest_name = DN_to_DNS( - config_naming_context + len); - } - free(config_naming_context); - } - if (ld != NULL) - (void) ldap_unbind(ld); - - if (forest_name == NULL) { - if (DBG(DISC, 1)) - logger(LOG_DEBUG, " not found"); - return (NULL); - } - - if (DBG(DISC, 1)) - logger(LOG_DEBUG, " %s", forest_name); + if (!is_valid(&ctx->forest_name)) + return (NULL); - update_item(&ctx->forest_name, forest_name, AD_STATE_AUTO, 0); - update_version(&ctx->forest_name, PARAM1, - domain_controller_item); - } return (&ctx->forest_name); } @@ -1775,12 +1501,15 @@ ad_disc_get_ForestName(ad_disc_t ctx, boolean_t *auto_discovered) static ad_item_t * validate_GlobalCatalog(ad_disc_t ctx, enum ad_disc_req req) { - idmap_ad_disc_ds_t *global_catalog = NULL; - uint32_t ttl = 0; + ad_disc_ds_t *gc = NULL; + ad_disc_cds_t *cgc = NULL; boolean_t validate_global = B_FALSE; boolean_t validate_site = B_FALSE; + ad_item_t *dc_item; ad_item_t *forest_name_item; ad_item_t *site_name_item; + char *forest_name; + char *site_name; /* If the values is fixed there will not be a site specific version */ if (is_fixed(&ctx->global_catalog)) @@ -1789,12 +1518,12 @@ validate_GlobalCatalog(ad_disc_t ctx, enum ad_disc_req req) forest_name_item = validate_ForestName(ctx); if (forest_name_item == NULL) return (NULL); + forest_name = (char *)forest_name_item->value; if (req == AD_DISC_GLOBAL) validate_global = B_TRUE; else { - site_name_item = validate_SiteName(ctx); - if (site_name_item != NULL) + if (is_fixed(&ctx->site_name)) validate_site = B_TRUE; else if (req == AD_DISC_PREFER_SITE) validate_global = B_TRUE; @@ -1804,40 +1533,63 @@ validate_GlobalCatalog(ad_disc_t ctx, enum ad_disc_req req) if (!is_valid(&ctx->global_catalog) || is_changed(&ctx->global_catalog, PARAM1, forest_name_item)) { + /* - * Lookup DNS SRV RR named + * See if our DC is also a GC. + */ + dc_item = validate_DomainController(ctx, req); + if (dc_item != NULL) { + ad_disc_ds_t *ds = dc_item->value; + if ((ds->flags & DS_GC_FLAG) != 0) { + DEBUG1STATUS(ctx, + "DC is also a GC for %s", + forest_name); + gc = ds_dup(ds); + if (gc != NULL) { + gc->port = GC_PORT; + goto update_global; + } + } + } + + /* + * Lookup DNS SRV RR named: * _ldap._tcp.gc._msdcs.<ForestName> */ + DEBUG1STATUS(ctx, "DNS SRV query, forest=%s", + forest_name); DO_RES_NINIT(ctx); - global_catalog = - srv_query(&ctx->res_state, + cgc = srv_query(&ctx->res_state, LDAP_SRV_HEAD GC_SRV_TAIL, - ctx->forest_name.value, NULL, &ttl); + forest_name, NULL); - if (DBG(DISC, 1)) { - logger(LOG_DEBUG, - "GC servers for %s:", - ctx->forest_name.value); - } - if (global_catalog == NULL) { - if (DBG(DISC, 1)) - logger(LOG_DEBUG, " not found"); + if (cgc == NULL) { + DEBUG1STATUS(ctx, "(no DNS response)"); return (NULL); } + log_cds(ctx, cgc); - if (DBG(DISC, 1)) { - int i; - for (i = 0; - global_catalog[i].host[0] != '\0'; - i++) { - logger(LOG_DEBUG, " %s:%d", - global_catalog[i].host, - global_catalog[i].port); - } + /* + * Filter out unresponsive servers, and + * save the domain info we get back. + */ + gc = ldap_ping( + NULL, + cgc, + forest_name, + DS_GC_FLAG); + srv_free(cgc); + cgc = NULL; + + if (gc == NULL) { + DEBUG1STATUS(ctx, "(no LDAP response)"); + return (NULL); } + log_ds(ctx, gc); - update_item(&ctx->global_catalog, global_catalog, - AD_STATE_AUTO, ttl); + update_global: + update_item(&ctx->global_catalog, gc, + AD_STATE_AUTO, gc->ttl); update_version(&ctx->global_catalog, PARAM1, forest_name_item); } @@ -1845,51 +1597,75 @@ validate_GlobalCatalog(ad_disc_t ctx, enum ad_disc_req req) } if (validate_site) { + site_name_item = &ctx->site_name; + site_name = (char *)site_name_item->value; + if (!is_valid(&ctx->site_global_catalog) || is_changed(&ctx->site_global_catalog, PARAM1, forest_name_item) || is_changed(&ctx->site_global_catalog, PARAM2, site_name_item)) { - char rr_name[DNS_MAX_NAME]; + char rr_name[DNS_MAX_NAME]; + + /* + * See if our DC is also a GC. + */ + dc_item = validate_DomainController(ctx, req); + if (dc_item != NULL) { + ad_disc_ds_t *ds = dc_item->value; + if ((ds->flags & DS_GC_FLAG) != 0) { + DEBUG1STATUS(ctx, + "DC is also a GC for %s in %s", + forest_name, site_name); + gc = ds_dup(ds); + if (gc != NULL) { + gc->port = GC_PORT; + goto update_site; + } + } + } /* * Lookup DNS SRV RR named: * _ldap._tcp.<siteName>._sites.gc. * _msdcs.<ForestName> */ - (void) snprintf(rr_name, - sizeof (rr_name), + DEBUG1STATUS(ctx, "DNS SRV query, forest=%s, site=%s", + forest_name, site_name); + (void) snprintf(rr_name, sizeof (rr_name), LDAP_SRV_HEAD SITE_SRV_MIDDLE GC_SRV_TAIL, - ctx->site_name.value); + site_name); DO_RES_NINIT(ctx); - global_catalog = srv_query(&ctx->res_state, rr_name, - ctx->forest_name.value, NULL, &ttl); + cgc = srv_query(&ctx->res_state, rr_name, + forest_name, NULL); - if (DBG(DISC, 1)) { - logger(LOG_DEBUG, - "GC servers for %s in %s", - ctx->forest_name.value, - ctx->site_name.value); - } - if (global_catalog == NULL) { - if (DBG(DISC, 1)) - logger(LOG_DEBUG, " not found"); + if (cgc == NULL) { + DEBUG1STATUS(ctx, "(no DNS response)"); return (NULL); } + log_cds(ctx, cgc); - if (DBG(DISC, 1)) { - int i; - for (i = 0; - global_catalog[i].host[0] != '\0'; - i++) { - logger(LOG_DEBUG, " %s:%d", - global_catalog[i].host, - global_catalog[i].port); - } + /* + * Filter out unresponsive servers, and + * save the domain info we get back. + */ + gc = ldap_ping( + NULL, + cgc, + forest_name, + DS_GC_FLAG); + srv_free(cgc); + cgc = NULL; + + if (gc == NULL) { + DEBUG1STATUS(ctx, "(no LDAP response)"); + return (NULL); } + log_ds(ctx, gc); - update_item(&ctx->site_global_catalog, global_catalog, - AD_STATE_AUTO, ttl); + update_site: + update_item(&ctx->site_global_catalog, gc, + AD_STATE_AUTO, gc->ttl); update_version(&ctx->site_global_catalog, PARAM1, forest_name_item); update_version(&ctx->site_global_catalog, PARAM2, @@ -1901,11 +1677,11 @@ validate_GlobalCatalog(ad_disc_t ctx, enum ad_disc_req req) } -idmap_ad_disc_ds_t * +ad_disc_ds_t * ad_disc_get_GlobalCatalog(ad_disc_t ctx, enum ad_disc_req req, boolean_t *auto_discovered) { - idmap_ad_disc_ds_t *global_catalog = NULL; + ad_disc_ds_t *global_catalog = NULL; ad_item_t *global_catalog_item; global_catalog_item = validate_GlobalCatalog(ctx, req); @@ -2059,6 +1835,33 @@ ad_disc_get_DomainsInForest(ad_disc_t ctx, boolean_t *auto_discovered) return (domains_in_forest); } +static ad_item_t * +validate_PreferredDC(ad_disc_t ctx) +{ + if (is_valid(&ctx->preferred_dc)) + return (&ctx->preferred_dc); + + return (NULL); +} + +ad_disc_ds_t * +ad_disc_get_PreferredDC(ad_disc_t ctx, boolean_t *auto_discovered) +{ + ad_disc_ds_t *preferred_dc = NULL; + ad_item_t *preferred_dc_item; + + preferred_dc_item = validate_PreferredDC(ctx); + + if (preferred_dc_item != NULL) { + preferred_dc = ds_dup(preferred_dc_item->value); + if (auto_discovered != NULL) + *auto_discovered = + (preferred_dc_item->state == AD_STATE_AUTO); + } else if (auto_discovered != NULL) + *auto_discovered = B_FALSE; + + return (preferred_dc); +} @@ -2077,12 +1880,40 @@ ad_disc_set_DomainName(ad_disc_t ctx, const char *domainName) return (0); } +int +ad_disc_set_DomainGUID(ad_disc_t ctx, uchar_t *u) +{ + char *domain_guid = NULL; + if (u != NULL) { + domain_guid = uuid_dup(u); + if (domain_guid == NULL) + return (-1); + update_item(&ctx->domain_guid, domain_guid, + AD_STATE_FIXED, 0); + } else if (ctx->domain_guid.state == AD_STATE_FIXED) + ctx->domain_guid.state = AD_STATE_INVALID; + return (0); +} + +void +auto_set_DomainGUID(ad_disc_t ctx, uchar_t *u) +{ + char *domain_guid = NULL; + + if (is_fixed(&ctx->domain_guid)) + return; + + domain_guid = uuid_dup(u); + if (domain_guid == NULL) + return; + update_item(&ctx->domain_guid, domain_guid, AD_STATE_AUTO, 0); +} int ad_disc_set_DomainController(ad_disc_t ctx, - const idmap_ad_disc_ds_t *domainController) + const ad_disc_ds_t *domainController) { - idmap_ad_disc_ds_t *domain_controller = NULL; + ad_disc_ds_t *domain_controller = NULL; if (domainController != NULL) { domain_controller = ds_dup(domainController); if (domain_controller == NULL) @@ -2094,7 +1925,6 @@ ad_disc_set_DomainController(ad_disc_t ctx, return (0); } - int ad_disc_set_SiteName(ad_disc_t ctx, const char *siteName) { @@ -2109,6 +1939,20 @@ ad_disc_set_SiteName(ad_disc_t ctx, const char *siteName) return (0); } +void +auto_set_SiteName(ad_disc_t ctx, char *siteName) +{ + char *site_name = NULL; + + if (is_fixed(&ctx->site_name)) + return; + + site_name = strdup(siteName); + if (site_name == NULL) + return; + update_item(&ctx->site_name, site_name, AD_STATE_AUTO, 0); +} + int ad_disc_set_ForestName(ad_disc_t ctx, const char *forestName) { @@ -2124,11 +1968,25 @@ ad_disc_set_ForestName(ad_disc_t ctx, const char *forestName) return (0); } +void +auto_set_ForestName(ad_disc_t ctx, char *forestName) +{ + char *forest_name = NULL; + + if (is_fixed(&ctx->forest_name)) + return; + + forest_name = strdup(forestName); + if (forest_name == NULL) + return; + update_item(&ctx->forest_name, forest_name, AD_STATE_AUTO, 0); +} + int ad_disc_set_GlobalCatalog(ad_disc_t ctx, - const idmap_ad_disc_ds_t *globalCatalog) + const ad_disc_ds_t *globalCatalog) { - idmap_ad_disc_ds_t *global_catalog = NULL; + ad_disc_ds_t *global_catalog = NULL; if (globalCatalog != NULL) { global_catalog = ds_dup(globalCatalog); if (global_catalog == NULL) @@ -2140,6 +1998,27 @@ ad_disc_set_GlobalCatalog(ad_disc_t ctx, return (0); } +int +ad_disc_set_PreferredDC(ad_disc_t ctx, const ad_disc_ds_t *pref_dc) +{ + ad_disc_ds_t *new_pref_dc = NULL; + if (pref_dc != NULL) { + new_pref_dc = ds_dup(pref_dc); + if (new_pref_dc == NULL) + return (-1); + update_item(&ctx->preferred_dc, new_pref_dc, + AD_STATE_FIXED, 0); + } else if (ctx->preferred_dc.state == AD_STATE_FIXED) + ctx->preferred_dc.state = AD_STATE_INVALID; + return (0); +} + +void +ad_disc_set_StatusFP(ad_disc_t ctx, struct __FILE_TAG *fp) +{ + ctx->status_fp = fp; +} + int ad_disc_unset(ad_disc_t ctx) @@ -2150,6 +2029,9 @@ ad_disc_unset(ad_disc_t ctx) if (ctx->domain_controller.state == AD_STATE_FIXED) ctx->domain_controller.state = AD_STATE_INVALID; + if (ctx->preferred_dc.state == AD_STATE_FIXED) + ctx->preferred_dc.state = AD_STATE_INVALID; + if (ctx->site_name.state == AD_STATE_FIXED) ctx->site_name.state = AD_STATE_INVALID; |