diff options
Diffstat (limited to 'usr/src/lib')
-rw-r--r-- | usr/src/lib/libadutils/common/adutils.c | 98 | ||||
-rw-r--r-- | usr/src/lib/libadutils/common/adutils_impl.h | 19 | ||||
-rw-r--r-- | usr/src/lib/libadutils/common/libadutils.h | 9 | ||||
-rw-r--r-- | usr/src/lib/libadutils/common/mapfile-vers | 3 | ||||
-rw-r--r-- | usr/src/lib/libidmap/common/addisc.c | 1506 | ||||
-rw-r--r-- | usr/src/lib/libidmap/common/addisc.h | 137 | ||||
-rw-r--r-- | usr/src/lib/libidmap/common/idmap_api.c | 27 | ||||
-rw-r--r-- | usr/src/lib/libidmap/common/mapfile-vers | 4 | ||||
-rw-r--r-- | usr/src/lib/libidmap/common/namemaps.c | 4 | ||||
-rw-r--r-- | usr/src/lib/nsswitch/ad/common/ad_common.c | 3 |
10 files changed, 1283 insertions, 527 deletions
diff --git a/usr/src/lib/libadutils/common/adutils.c b/usr/src/lib/libadutils/common/adutils.c index d838858671..d914f109d2 100644 --- a/usr/src/lib/libadutils/common/adutils.c +++ b/usr/src/lib/libadutils/common/adutils.c @@ -66,6 +66,7 @@ static binary_attrs_t binattrs[] = { {NULL, NULL} }; + void adutils_set_log(int pri, bool_t syslog, bool_t degraded) { @@ -74,6 +75,7 @@ adutils_set_log(int pri, bool_t syslog, bool_t degraded) idmap_log_degraded(degraded); } + /* * Turn "foo.bar.com" into "dc=foo,dc=bar,dc=com" */ @@ -85,6 +87,7 @@ adutils_dns2dn(const char *dns) return (ldap_dns_to_dn((char *)dns, &nameparts)); } + /* * Turn "dc=foo,dc=bar,dc=com" into "foo.bar.com"; ignores any other * attributes (CN, etc...). @@ -632,6 +635,8 @@ adutils_ad_free(adutils_ad_t **ad) (void) pthread_mutex_unlock(&(*ad)->lock); (void) pthread_mutex_destroy(&(*ad)->lock); + if ((*ad)->known_domains) + free((*ad)->known_domains); free((*ad)->dflt_w2k_dom); free(*ad); @@ -761,7 +766,8 @@ retry: * around the wrong number of times. */ for (;;) { - if (adh != NULL && adh->ld != NULL && !adh->dead) + if (adh != NULL && adh->owner == ad && adh->ld != NULL && + !adh->dead) break; if (adh == NULL || (adh = adh->next) == NULL) adh = host_head; @@ -919,6 +925,88 @@ delete_ds(adutils_ad_t *ad, const char *host, int port) } } +/* + * Add known domain name and domain SID to AD configuration. + */ + +adutils_rc +adutils_add_domain(adutils_ad_t *ad, const char *domain, const char *sid) +{ + struct known_domain *new; + int num = ad->num_known_domains; + + ad->num_known_domains++; + new = realloc(ad->known_domains, + sizeof (struct known_domain) * ad->num_known_domains); + if (new != NULL) { + ad->known_domains = new; + (void) strlcpy(ad->known_domains[num].name, domain, + sizeof (ad->known_domains[num].name)); + (void) strlcpy(ad->known_domains[num].sid, sid, + sizeof (ad->known_domains[num].sid)); + return (ADUTILS_SUCCESS); + } else { + if (ad->known_domains != NULL) { + free(ad->known_domains); + ad->known_domains = NULL; + } + ad->num_known_domains = 0; + return (ADUTILS_ERR_MEMORY); + } +} + + +/* + * Check that this AD supports this domain. + * If there are no known domains assume that the + * domain is supported by this AD. + * + * Returns 1 if this domain is supported by this AD + * else returns 0; + */ + +int +adutils_lookup_check_domain(adutils_query_state_t *qs, const char *domain) +{ + adutils_ad_t *ad = qs->qadh->owner; + int i, err; + + for (i = 0; i < ad->num_known_domains; i++) { + if (u8_strcmp(domain, ad->known_domains[i].name, 0, + U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &err) == 0 && + err == 0) + return (1); + } + + return ((i == 0) ? 1 : 0); +} + + +/* + * Check that this AD supports the SID prefix. + * The SID prefix should match the domain SID. + * If there are no known domains assume that the + * SID prefix is supported by this AD. + * + * Returns 1 if this sid prefix is supported by this AD + * else returns 0; + */ + +int +adutils_lookup_check_sid_prefix(adutils_query_state_t *qs, const char *sid) +{ + adutils_ad_t *ad = qs->qadh->owner; + int i; + + + for (i = 0; i < ad->num_known_domains; i++) { + if (strcmp(sid, ad->known_domains[i].sid) == 0) + return (1); + } + + return ((i == 0) ? 1 : 0); +} + adutils_rc adutils_lookup_batch_start(adutils_ad_t *ad, int nqueries, @@ -964,9 +1052,9 @@ adutils_lookup_batch_start(adutils_ad_t *ad, int nqueries, new_state->ref_cnt = 1; new_state->qadh = adh; - new_state->qcount = nqueries; + new_state->qsize = nqueries; new_state->qadh_gen = adh->generation; - new_state->qlastsent = 0; + new_state->qcount = 0; new_state->ldap_res_search_cb = ldap_res_search_cb; new_state->ldap_res_search_argp = ldap_res_search_argp; (void) pthread_cond_init(&new_state->cv, NULL); @@ -1588,9 +1676,11 @@ adutils_lookup_batch_add(adutils_query_state_t *state, struct timeval tv; adutils_q_t *q; - qid = atomic_inc_32_nv(&state->qlastsent) - 1; + qid = atomic_inc_32_nv(&state->qcount) - 1; q = &(state->queries[qid]); + assert(qid < state->qsize); + /* * Remember the expected domain so we can check the results * against it diff --git a/usr/src/lib/libadutils/common/adutils_impl.h b/usr/src/lib/libadutils/common/adutils_impl.h index 847d5e384d..530e3a2ca3 100644 --- a/usr/src/lib/libadutils/common/adutils_impl.h +++ b/usr/src/lib/libadutils/common/adutils_impl.h @@ -43,6 +43,14 @@ extern "C" { #define ADUTILS_SEARCH_TIMEOUT 3 #define ADUTILS_LDAP_OPEN_TIMEOUT 1 +/* + * Maximum string SID size. 4 bytes for "S-1-", 15 for 2^48 (max authority), + * another '-', and ridcount (max 15) 10-digit RIDs plus '-' in between, plus + * a null. + */ +#define MAXSID 185 +#define MAXDOMAINNAME 256 + typedef struct adutils_sid { uchar_t version; uchar_t sub_authority_count; @@ -52,10 +60,17 @@ typedef struct adutils_sid { struct adutils_host; +struct known_domain { + char name[MAXDOMAINNAME]; + char sid[MAXSID]; +}; + /* A set of DSs for a given AD partition */ struct adutils_ad { char *dflt_w2k_dom; /* used to qualify bare names */ + int num_known_domains; + struct known_domain *known_domains; pthread_mutex_t lock; uint32_t ref; struct adutils_host *last_adh; @@ -124,10 +139,10 @@ typedef struct adutils_q { /* Batch context structure */ struct adutils_query_state { struct adutils_query_state *next; - int qcount; /* how many queries */ + int qsize; /* Size of queries */ int ref_cnt; /* reference count */ pthread_cond_t cv; /* Condition wait variable */ - uint32_t qlastsent; + uint32_t qcount; /* Number of items queued */ uint32_t qinflight; /* how many queries in flight */ uint16_t qdead; /* oops, lost LDAP connection */ adutils_host_t *qadh; /* LDAP connection */ diff --git a/usr/src/lib/libadutils/common/libadutils.h b/usr/src/lib/libadutils/common/libadutils.h index 9a6d82a0b2..8f88e2d27a 100644 --- a/usr/src/lib/libadutils/common/libadutils.h +++ b/usr/src/lib/libadutils/common/libadutils.h @@ -135,6 +135,9 @@ extern adutils_rc adutils_ad_alloc(adutils_ad_t **new_ad, extern void adutils_ad_free(adutils_ad_t **ad); extern adutils_rc adutils_add_ds(adutils_ad_t *ad, const char *host, int port); +extern adutils_rc adutils_add_domain(adutils_ad_t *ad, + const char *domain_name, + const char *domain_sid); extern void adutils_set_log(int pri, bool_t syslog, bool_t degraded); extern void adutils_freeresult(adutils_result_t **result); @@ -169,6 +172,12 @@ extern void adutils_lookup_batch_release( adutils_query_state_t **state); extern const char *adutils_lookup_batch_getdefdomain( adutils_query_state_t *state); +extern int adutils_lookup_check_domain( + adutils_query_state_t *state, + const char *domain); +extern int adutils_lookup_check_sid_prefix( + adutils_query_state_t *state, + const char *sid); #ifdef __cplusplus } diff --git a/usr/src/lib/libadutils/common/mapfile-vers b/usr/src/lib/libadutils/common/mapfile-vers index 07d0065906..da06606624 100644 --- a/usr/src/lib/libadutils/common/mapfile-vers +++ b/usr/src/lib/libadutils/common/mapfile-vers @@ -37,11 +37,14 @@ SUNWprivate { adutils_lookup_batch_end; adutils_lookup_batch_release; adutils_lookup_batch_getdefdomain; + adutils_lookup_check_domain; + adutils_lookup_check_sid_prefix; adutils_dn2dns; adutils_reap_idle_connections; adutils_ad_alloc; adutils_ad_free; adutils_add_ds; + adutils_add_domain; adutils_set_log; local: *; diff --git a/usr/src/lib/libidmap/common/addisc.c b/usr/src/lib/libidmap/common/addisc.c index 45a74f07fb..be49e53f41 100644 --- a/usr/src/lib/libidmap/common/addisc.c +++ b/usr/src/lib/libidmap/common/addisc.c @@ -24,7 +24,6 @@ * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" /* * Active Directory Auto-Discovery. @@ -83,6 +82,7 @@ #include <string.h> #include <strings.h> #include <unistd.h> +#include <assert.h> #include <stdlib.h> #include <net/if.h> #include <net/if.h> @@ -99,12 +99,70 @@ #include <errno.h> #include <ldap.h> #include <sasl/sasl.h> +#include <sys/u8_textprep.h> #include "addisc.h" +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 ttl; + 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; + int subnets_changed; + time_t subnets_last_check; + 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 */ +} ad_disc; + #define DNS_MAX_NAME NS_MAXDNAME -#define DN_MAX_NAME (DNS_MAX_NAME + 512) /* SRV RR names for various queries */ @@ -124,25 +182,22 @@ * idmapd is running before the network is up! */ #define DO_RES_NINIT(ctx) if (!(ctx)->res_ninitted) \ - (ctx)->res_ninitted = res_ninit(&ctx->state) != -1 + (ctx)->res_ninitted = (res_ninit(&ctx->res_state) != -1) #define is_fixed(item) \ - ((item)->type == AD_TYPE_FIXED) + ((item)->state == AD_STATE_FIXED) #define is_changed(item, num, param) \ ((item)->param_version[num] != (param)->version) -#define is_valid(item) \ - ((item)->type != AD_TYPE_INVALID && (item)->value.str != NULL) - /*LINTLIBRARY*/ /* * Function definitions */ -static void validate_SiteName(ad_disc_t ctx); +static ad_item_t * +validate_SiteName(ad_disc_t ctx); -static idmap_ad_disc_ds_t *dsdup(const idmap_ad_disc_ds_t *); static void @@ -152,33 +207,43 @@ update_version(ad_item_t *item, int num, ad_item_t *param) } + static int -is_expired(ad_item_t *item) +is_valid(ad_item_t *item) { - if (item->type == AD_TYPE_FIXED) - return (FALSE); - if (item->type == AD_TYPE_AUTO && - (item->ttl == 0 || item->ttl > time(NULL))) - return (FALSE); - return (TRUE); + if (item->value != NULL) { + if (item->state == AD_STATE_FIXED) + return (TRUE); + if (item->state == AD_STATE_AUTO && + (item->ttl == 0 || item->ttl > time(NULL))) + return (TRUE); + } + return (FALSE); } static void -update_string(ad_item_t *item, char *value, enum ad_item_type type, +update_item(ad_item_t *item, void *value, enum ad_item_state state, uint32_t ttl) { - if (item->value.str != NULL && value != NULL) { - if (strcmp(item->value.str, value) != 0) + if (item->value != NULL && value != NULL) { + if ((item->type == AD_STRING && + strcmp(item->value, value) != 0) || + (item->type == AD_DIRECTORY && + ad_disc_compare_ds(item->value, value) != 0)|| + (item->type == AD_DOMAINS_IN_FOREST && + ad_disc_compare_domainsinforest(item->value, value) != 0) || + (item->type == AD_TRUSTED_DOMAINS && + ad_disc_compare_trusteddomains(item->value, value) != 0)) item->version++; - } else if (item->value.str != value) + } else if (item->value != value) item->version++; - if (item->value.str != NULL) - free(item->value.str); + if (item->value != NULL) + free(item->value); - item->value.str = value; - item->type = type; + item->value = value; + item->state = state; if (ttl == 0) item->ttl = 0; @@ -187,53 +252,180 @@ update_string(ad_item_t *item, char *value, enum ad_item_type type, } -static void -update_ds(ad_item_t *item, idmap_ad_disc_ds_t *value, enum ad_item_type type, - uint32_t ttl) +/* Compare DS lists */ +int +ad_disc_compare_ds(idmap_ad_disc_ds_t *ds1, idmap_ad_disc_ds_t *ds2) { - if (item->value.ds != NULL && value != NULL) { - if (ad_disc_compare_ds(item->value.ds, value) != 0) - item->version++; - } else if (item->value.ds != value) - item->version++; + int i, j; + int num_ds1; + int num_ds2; + int match; + + for (i = 0; ds1[i].host[0] != '\0'; i++) + continue; + num_ds1 = i; + for (j = 0; ds2[j].host[0] != '\0'; j++) + continue; + num_ds2 = j; + if (num_ds1 != num_ds2) + return (1); + + for (i = 0; i < num_ds1; i++) { + match = FALSE; + for (j = 0; j < num_ds2; j++) { + if (strcmp(ds1[i].host, ds2[i].host) == 0 && + ds1[i].port == ds2[i].port) { + match = TRUE; + break; + } + } + if (!match) + return (1); + } + return (0); +} - if (item->value.ds != NULL) - free(item->value.ds); - item->value.ds = value; - item->type = type; +/* Copy a list of DSs */ +static idmap_ad_disc_ds_t * +ds_dup(const idmap_ad_disc_ds_t *srv) +{ + int i; + int size; + idmap_ad_disc_ds_t *new = NULL; - if (ttl == 0) - item->ttl = 0; - else - item->ttl = time(NULL) + ttl; + for (i = 0; srv[i].host[0] != '\0'; i++) + continue; + + size = (i + 1) * sizeof (idmap_ad_disc_ds_t); + new = malloc(size); + if (new != NULL) + memcpy(new, srv, size); + return (new); } -static ad_item_t * -get_item(ad_item_t *global, ad_item_t *site, enum ad_disc_req req) +int +ad_disc_compare_trusteddomains(ad_disc_trusteddomains_t *td1, + ad_disc_trusteddomains_t *td2) { - ad_item_t *item; - if (is_fixed(global)) - return (global); + int i, j; + int num_td1; + int num_td2; + int match; + int err; - if (req == AD_DISC_GLOBAL) - item = global; - else if (req == AD_DISC_SITE_SPECIFIC) - item = site; - else if (is_valid(site)) - item = site; - else - item = global; + for (i = 0; td1[i].domain[0] != '\0'; i++) + continue; + num_td1 = i; - if (!is_valid(item)) - return (NULL); + for (j = 0; td2[j].domain[0] != '\0'; j++) + continue; + num_td2 = j; + + if (num_td1 != num_td2) + return (1); - return (item); + for (i = 0; i < num_td1; i++) { + match = FALSE; + for (j = 0; j < num_td2; j++) { + if (u8_strcmp(td1[i].domain, td2[i].domain, 0, + U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &err) == 0 && + err == 0) { + match = TRUE; + break; + } + } + if (!match) + return (1); + } + return (0); } +/* Copy a list of Trusted Domains */ +static ad_disc_trusteddomains_t * +td_dup(const ad_disc_trusteddomains_t *td) +{ + int i; + int size; + ad_disc_trusteddomains_t *new = NULL; + + for (i = 0; td[i].domain[0] != '\0'; i++) + continue; + + size = (i + 1) * sizeof (ad_disc_trusteddomains_t); + new = malloc(size); + if (new != NULL) + memcpy(new, td, size); + return (new); +} + + + +int +ad_disc_compare_domainsinforest(ad_disc_domainsinforest_t *df1, + ad_disc_domainsinforest_t *df2) +{ + int i, j; + int num_df1; + int num_df2; + int match; + int err; + + for (i = 0; df1[i].domain[0] != '\0'; i++) + continue; + num_df1 = i; + + for (j = 0; df2[j].domain[0] != '\0'; j++) + continue; + num_df2 = j; + + if (num_df1 != num_df2) + return (1); + + for (i = 0; i < num_df1; i++) { + match = FALSE; + for (j = 0; j < num_df2; j++) { + if (u8_strcmp(df1[i].domain, df2[i].domain, 0, + U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &err) == 0 && + err == 0 && + strcmp(df1[i].sid, df2[i].sid) == 0) { + match = TRUE; + break; + } + } + if (!match) + return (1); + } + return (0); +} + + + +/* Copy a list of Trusted Domains */ +static ad_disc_domainsinforest_t * +df_dup(const ad_disc_domainsinforest_t *df) +{ + int i; + int size; + ad_disc_domainsinforest_t *new = NULL; + + for (i = 0; df[i].domain[0] != '\0'; i++) + continue; + + size = (i + 1) * sizeof (ad_disc_domainsinforest_t); + new = malloc(size); + if (new != NULL) + memcpy(new, df, size); + return (new); +} + + + + + /* * Returns an array of IPv4 address/prefix length * The last subnet is NULL @@ -334,11 +526,11 @@ cmpsubnets(ad_subnet_t *subnets1, ad_subnet_t *subnets2) int i, j; for (i = 0; subnets1[i].subnet[0] != '\0'; i++) - ; + continue; num_subnets1 = i; for (i = 0; subnets2[i].subnet[0] != '\0'; i++) - ; + continue; num_subnets2 = i; if (num_subnets1 != num_subnets2) @@ -374,27 +566,29 @@ DN_to_DNS(const char *dn_name) j = 0; i = 0; + if (dn_name == NULL) + return (NULL); /* * Find all DC=<value> and form DNS name of the * form <value1>.<value2>... */ - while (dn_name[i] != NULL) { + while (dn_name[i] != '\0') { if (strncasecmp(&dn_name[i], "DC=", 3) == 0) { i += 3; - if (dn_name[i] != NULL && num > 0) + if (dn_name[i] != '\0' && num > 0) dns[j++] = '.'; - while (dn_name[i] != NULL && + while (dn_name[i] != '\0' && dn_name[i] != ',' && dn_name[i] != '+') dns[j++] = dn_name[i++]; num++; } else { /* Skip attr=value as it is not DC= */ - while (dn_name[i] != NULL && + while (dn_name[i] != '\0' && dn_name[i] != ',' && dn_name[i] != '+') i++; } /* Skip over separator ',' or '+' */ - if (dn_name[i] != NULL) i++; + if (dn_name[i] != '\0') i++; } dns[j] = '\0'; dns_name = malloc(j + 1); @@ -432,7 +626,7 @@ subnets_to_DNs(ad_subnet_t *subnets, const char *base_dn) int i, j; for (i = 0; subnets[i].subnet[0] != '\0'; i++) - ; + continue; results = calloc(i + 1, sizeof (char *)); if (results == NULL) @@ -451,57 +645,6 @@ subnets_to_DNs(ad_subnet_t *subnets, const char *base_dn) return (results); } -/* Compare DS lists */ -int -ad_disc_compare_ds(idmap_ad_disc_ds_t *ds1, idmap_ad_disc_ds_t *ds2) -{ - int i, j; - int num_ds1; - int num_ds2; - int match; - - for (i = 0; ds1[i].host[0] != '\0'; i++) - ; - num_ds1 = i; - for (j = 0; ds2[j].host[0] != '\0'; j++) - ; - num_ds2 = j; - if (num_ds1 != num_ds2) - return (1); - - for (i = 0; i < num_ds1; i++) { - match = FALSE; - for (j = 0; j < num_ds1; j++) { - if (strcmp(ds1[i].host, ds2[i].host) == 0) { - match = TRUE; - break; - } - } - if (!match) - return (1); - } - return (0); -} - - -/* Copy a list of DSs */ -static idmap_ad_disc_ds_t * -dsdup(const idmap_ad_disc_ds_t *srv) -{ - int i; - int size; - idmap_ad_disc_ds_t *new = NULL; - - for (i = 0; srv[i].host[0] != '\0'; i++) - ; - - size = (i + 1) * sizeof (idmap_ad_disc_ds_t); - new = malloc(size); - if (new != NULL) - memcpy(new, srv, size); - return (new); -} - /* Compare SRC RRs; used with qsort() */ static int @@ -678,6 +821,59 @@ saslcallback(LDAP *ld, unsigned flags, void *defaults, void *prompts) return (LDAP_SUCCESS); } +/* + * A utility function to bind to a Directory server + */ + +static LDAP* +ldap_lookup_init(idmap_ad_disc_ds_t *ds) +{ + int i; + int rc, ldversion; + int zero = 0; + int timeoutms = 5 * 1000; + char *saslmech = "GSSAPI"; + uint32_t saslflags = LDAP_SASL_INTERACTIVE; + LDAP *ld = NULL; + + for (i = 0; ds[i].host[0] != '\0'; i++) { + ld = ldap_init(ds[i].host, ds[i].port); + if (ld == NULL) { + idmapdlog(LOG_DEBUG, "Couldn't connect to " + "AD DC %s:%d (%s)", + ds[i].host, ds[i].port, + strerror(errno)); + continue; + } + + ldversion = LDAP_VERSION3; + (void) ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, + &ldversion); + + (void) ldap_set_option(ld, LDAP_OPT_REFERRALS, + LDAP_OPT_OFF); + (void) ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &zero); + (void) ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &zero); + /* setup TCP/IP connect timeout */ + (void) ldap_set_option(ld, LDAP_X_OPT_CONNECT_TIMEOUT, + &timeoutms); + (void) ldap_set_option(ld, LDAP_OPT_RESTART, + LDAP_OPT_ON); + + rc = ldap_sasl_interactive_bind_s(ld, "" /* binddn */, + saslmech, NULL, NULL, saslflags, &saslcallback, + NULL /* defaults */); + if (rc == LDAP_SUCCESS) + break; + + idmapdlog(LOG_INFO, "LDAP SASL bind to %s:%d failed (%s)", + ds[i].host, ds[i].port, ldap_err2string(rc)); + (void) ldap_unbind(ld); + ld = NULL; + } + return (ld); +} + /* * A utility function to get the value of some attribute of one of one @@ -688,11 +884,7 @@ ldap_lookup_entry_attr(LDAP **ld, idmap_ad_disc_ds_t *domainControllers, char **dn_list, char *attr) { int i; - int rc, ldversion; - int zero = 0; - int timeoutms = 5 * 1000; - char *saslmech = "GSSAPI"; - uint32_t saslflags = LDAP_SASL_INTERACTIVE; + int rc; int scope = LDAP_SCOPE_BASE; char *attrs[2]; LDAPMessage *results = NULL; @@ -703,55 +895,11 @@ ldap_lookup_entry_attr(LDAP **ld, idmap_ad_disc_ds_t *domainControllers, attrs[0] = attr; attrs[1] = NULL; - rc = LDAP_INVALID_CREDENTIALS; + if (*ld == NULL) + *ld = ldap_lookup_init(domainControllers); - if (*ld == NULL) { - for (i = 0; domainControllers[i].host[0] != '\0'; i++) { - *ld = ldap_init(domainControllers[i].host, - domainControllers[i].port); - if (*ld == NULL) { - idmapdlog(LOG_INFO, "Couldn't connect to " - "AD DC %s:%d (%s)", - domainControllers[i].host, - domainControllers[i].port, - strerror(errno)); - continue; - } - - ldversion = LDAP_VERSION3; - (void) ldap_set_option(*ld, LDAP_OPT_PROTOCOL_VERSION, - &ldversion); - - (void) ldap_set_option(*ld, LDAP_OPT_REFERRALS, - LDAP_OPT_OFF); - (void) ldap_set_option(*ld, LDAP_OPT_TIMELIMIT, &zero); - (void) ldap_set_option(*ld, LDAP_OPT_SIZELIMIT, &zero); - /* setup TCP/IP connect timeout */ - (void) ldap_set_option(*ld, LDAP_X_OPT_CONNECT_TIMEOUT, - &timeoutms); - (void) ldap_set_option(*ld, LDAP_OPT_RESTART, - LDAP_OPT_ON); - - rc = ldap_sasl_interactive_bind_s(*ld, "" /* binddn */, - saslmech, NULL, NULL, saslflags, &saslcallback, - NULL /* defaults */); - - if (rc == LDAP_SUCCESS) - break; - idmapdlog(LOG_INFO, "LDAP SASL bind to %s:%d " - "failed (%s)", domainControllers[i].host, - domainControllers[i].port, ldap_err2string(rc)); - (void) ldap_unbind(*ld); - *ld = NULL; - } - } - - if (*ld == NULL) { - idmapdlog(LOG_NOTICE, "Couldn't open and SASL bind LDAP " - "connections to any domain controllers; discovery of " - "some items will fail"); + if (*ld == NULL) return (NULL); - } for (i = 0; dn_list[i] != NULL; i++) { rc = ldap_search_s(*ld, dn_list[i], scope, @@ -776,13 +924,271 @@ ldap_lookup_entry_attr(LDAP **ld, idmap_ad_disc_ds_t *domainControllers, results = NULL; } } - (void) ldap_unbind(*ld); - *ld = NULL; return (NULL); } +/* + * Lookup the trusted domains in the global catalog. + * + * Returns: + * array of trusted domains which is terminated by + * an empty trusted domain. + * NULL an error occured + */ +ad_disc_trusteddomains_t * +ldap_lookup_trusted_domains(LDAP **ld, idmap_ad_disc_ds_t *globalCatalog, + char *base_dn) +{ + int scope = LDAP_SCOPE_SUBTREE; + char *attrs[3]; + int rc; + LDAPMessage *results = NULL; + LDAPMessage *entry; + char *filter; + char **partner = NULL; + char **direction = NULL; + int num = 0; + ad_disc_trusteddomains_t *trusted_domains = NULL; + + + if (*ld == NULL) + *ld = ldap_lookup_init(globalCatalog); + + if (*ld == NULL) + return (NULL); + + attrs[0] = "trustPartner"; + attrs[1] = "trustDirection"; + attrs[2] = NULL; + + /* trustDirection values - inbound = 1 and bidirectional = 3 */ + filter = "(&(objectclass=trustedDomain)" + "(|(trustDirection=3)(trustDirection=1)))"; + + rc = ldap_search_s(*ld, base_dn, scope, filter, attrs, 0, &results); + if (rc == LDAP_SUCCESS) { + for (entry = ldap_first_entry(*ld, results); + entry != NULL; entry = ldap_next_entry(*ld, entry)) { + partner = ldap_get_values(*ld, entry, "trustPartner"); + direction = ldap_get_values( + *ld, entry, "trustDirection"); + + if (partner != NULL && direction != NULL) { + num++; + trusted_domains = realloc(trusted_domains, + (num + 1) * + sizeof (ad_disc_trusteddomains_t)); + if (trusted_domains == NULL) { + ldap_value_free(partner); + ldap_value_free(direction); + ldap_msgfree(results); + return (NULL); + } + /* Last element should be zero */ + memset(&trusted_domains[num], 0, + sizeof (ad_disc_trusteddomains_t)); + strcpy(trusted_domains[num - 1].domain, + partner[0]); + trusted_domains[num - 1].direction = + atoi(direction[0]); + } + if (partner != NULL) + ldap_value_free(partner); + if (direction != NULL) + ldap_value_free(direction); + } + } else if (rc == LDAP_NO_RESULTS_RETURNED) { + /* This is not an error - return empty trusted domain */ + trusted_domains = calloc(1, sizeof (ad_disc_trusteddomains_t)); + } + if (results != NULL) + ldap_msgfree(results); + + return (trusted_domains); +} + +static int +decode_sid(BerValue *bval, char *sid_txt) +{ + int i, j; + uchar_t *v; + uint32_t a; + struct sid { + uchar_t version; + uchar_t sub_authority_count; + uint64_t authority; /* really, 48-bits */ + uint32_t sub_authorities[16]; + } sid; + char *ptr; + int len; + int rlen; + + + /* + * The binary format of a SID is as follows: + * + * byte #0: version, always 0x01 + * byte #1: RID count, always <= 0x0f + * bytes #2-#7: SID authority, big-endian 48-bit unsigned int + * + * followed by RID count RIDs, each a little-endian, unsigned + * 32-bit int. + */ + /* + * Sanity checks: must have at least one RID, version must be + * 0x01, and the length must be 8 + rid count * 4 + */ + if (bval->bv_len > 8 && bval->bv_val[0] == 0x01 && + bval->bv_len == 1 + 1 + 6 + bval->bv_val[1] * 4) { + v = (uchar_t *)bval->bv_val; + sid.version = v[0]; + sid.sub_authority_count = v[1]; + sid.authority = + /* big endian -- so start from the left */ + ((u_longlong_t)v[2] << 40) | + ((u_longlong_t)v[3] << 32) | + ((u_longlong_t)v[4] << 24) | + ((u_longlong_t)v[5] << 16) | + ((u_longlong_t)v[6] << 8) | + (u_longlong_t)v[7]; + for (i = 0; i < sid.sub_authority_count; i++) { + j = 8 + (i * 4); + /* little endian -- so start from the right */ + a = (v[j + 3] << 24) | (v[j + 2] << 16) | + (v[j + 1] << 8) | (v[j]); + sid.sub_authorities[i] = a; + } + + ptr = sid_txt; + len = AD_DISC_MAXSID; + rlen = snprintf(ptr, len, "S-1-%llu", sid.authority); + + ptr += rlen; + len -= rlen; + + for (i = 0; i < sid.sub_authority_count; i++) { + assert(len > 0); + rlen = snprintf( + ptr, len, "-%u", sid.sub_authorities[i]); + ptr += rlen; + len -= rlen; + } + assert(len > 0); + return (0); + } + return (-1); +} + +/* + * This functions finds all the domains in a forest. + * It first finds all the naming contexts by finding the + * root DSE attribute namingContext. For each naming context + * it performes an entry search looking for Domain object class + * returning the attribute objectSid. + */ +ad_disc_domainsinforest_t * +ldap_lookup_domains_in_forest(LDAP **ld, idmap_ad_disc_ds_t *globalCatalogs) +{ + int scope = LDAP_SCOPE_BASE; + char *attrs[2]; + char *root_attrs[2]; + int rc; + LDAPMessage *result = NULL; + LDAPMessage *entry; + char *filter; + char **nc = NULL; + struct berval **sid_ber; + int num = 0; + ad_disc_domainsinforest_t *domains = NULL; + int i; + char *name; + + + if (*ld == NULL) + *ld = ldap_lookup_init(globalCatalogs); + + if (*ld == NULL) { + idmapdlog(LOG_NOTICE, "Couldn't open and SASL bind LDAP " + "connections to any domain controllers; discovery of " + "some items will fail"); + return (NULL); + } + + root_attrs[0] = "namingContexts"; + root_attrs[1] = NULL; + + attrs[0] = "objectSid"; + attrs[1] = NULL; + + filter = "(objectclass=Domain)"; + + /* Find naming contexts */ + rc = ldap_search_s(*ld, LDAP_ROOT_DSE, scope, "(objectClass=*)", + root_attrs, 0, &result); + if (rc == LDAP_SUCCESS) { + entry = ldap_first_entry(*ld, result); + if (entry != NULL) { + nc = ldap_get_values(*ld, entry, "namingContexts"); + } + } + if (result != NULL) + ldap_msgfree(result); + if (nc == NULL) + return (NULL); + + /* Find domains */ + for (i = 0; nc[i] != NULL; i++) { + rc = ldap_search_s(*ld, nc[i], scope, filter, attrs, 0, + &result); + if (rc == LDAP_SUCCESS) { + entry = ldap_first_entry(*ld, result); + if (entry != NULL) { + sid_ber = ldap_get_values_len(*ld, entry, + "objectSid"); + if (sid_ber != NULL) { + num++; + domains = realloc(domains, + (num + 1) * + sizeof (ad_disc_domainsinforest_t)); + if (domains == NULL) { + ldap_value_free_len(sid_ber); + ldap_msgfree(result); + ldap_value_free(nc); + return (NULL); + } + memset(&domains[num], 0, + sizeof (ad_disc_domainsinforest_t)); + if (decode_sid(sid_ber[0], + domains[num - 1].sid) < 0) { + ldap_value_free_len(sid_ber); + ldap_msgfree(result); + ldap_value_free(nc); + return (NULL); + } + ldap_value_free_len(sid_ber); + + name = DN_to_DNS(nc[i]); + if (name == NULL) { + free(domains); + ldap_msgfree(result); + ldap_value_free(nc); + return (NULL); + } + strcpy(domains[num - 1].domain, name); + free(name); + } + } + } + if (result != NULL) + ldap_msgfree(result); + } + ldap_value_free(nc); + + return (domains); +} + ad_disc_t ad_disc_init(void) @@ -791,6 +1197,17 @@ ad_disc_init(void) ctx = calloc(1, sizeof (struct ad_disc)); if (ctx != NULL) DO_RES_NINIT(ctx); + + ctx->domain_name.type = AD_STRING; + ctx->domain_controller.type = AD_DIRECTORY; + ctx->site_name.type = AD_STRING; + ctx->forest_name.type = AD_STRING; + ctx->global_catalog.type = AD_DIRECTORY; + ctx->domains_in_forest.type = AD_DOMAINS_IN_FOREST; + ctx->trusted_domains.type = AD_TRUSTED_DOMAINS; + /* Site specific versions */ + ctx->site_domain_controller.type = AD_DIRECTORY; + ctx->site_global_catalog.type = AD_DIRECTORY; return (ctx); } @@ -802,31 +1219,38 @@ ad_disc_fini(ad_disc_t ctx) return; if (ctx->res_ninitted) - res_ndestroy(&ctx->state); + res_ndestroy(&ctx->res_state); if (ctx->subnets != NULL) free(ctx->subnets); - if (ctx->domain_name.value.str != NULL) - free(ctx->domain_name.value.str); + if (ctx->domain_name.value != NULL) + free(ctx->domain_name.value); + + if (ctx->domain_controller.value != NULL) + free(ctx->domain_controller.value); + + if (ctx->site_name.value != NULL) + free(ctx->site_name.value); - if (ctx->domain_controller.value.str != NULL) - free(ctx->domain_controller.value.str); + if (ctx->forest_name.value != NULL) + free(ctx->forest_name.value); - if (ctx->site_name.value.str != NULL) - free(ctx->site_name.value.str); + if (ctx->global_catalog.value != NULL) + free(ctx->global_catalog.value); - if (ctx->forest_name.value.str != NULL) - free(ctx->forest_name.value.str); + if (ctx->domains_in_forest.value != NULL) + free(ctx->domains_in_forest.value); - if (ctx->global_catalog.value.str != NULL) - free(ctx->global_catalog.value.str); + if (ctx->trusted_domains.value != NULL) + free(ctx->trusted_domains.value); - if (ctx->site_domain_controller.value.str != NULL) - free(ctx->site_domain_controller.value.str); + /* Site specific versions */ + if (ctx->site_domain_controller.value != NULL) + free(ctx->site_domain_controller.value); - if (ctx->site_global_catalog.value.str != NULL) - free(ctx->site_global_catalog.value.str); + if (ctx->site_global_catalog.value != NULL) + free(ctx->site_global_catalog.value); free(ctx); } @@ -835,59 +1259,63 @@ void ad_disc_refresh(ad_disc_t ctx) { if (ctx->res_ninitted) - res_ndestroy(&ctx->state); - (void) memset(&ctx->state, 0, sizeof (ctx->state)); - ctx->res_ninitted = res_ninit(&ctx->state) != -1; + res_ndestroy(&ctx->res_state); + (void) memset(&ctx->res_state, 0, sizeof (ctx->res_state)); + ctx->res_ninitted = res_ninit(&ctx->res_state) != -1; - if (ctx->domain_name.type == AD_TYPE_AUTO) - ctx->domain_name.type = AD_TYPE_INVALID; + if (ctx->domain_name.state == AD_STATE_AUTO) + ctx->domain_name.state = AD_STATE_INVALID; - if (ctx->domain_controller.type == AD_TYPE_AUTO) - ctx->domain_controller.type = AD_TYPE_INVALID; + if (ctx->domain_controller.state == AD_STATE_AUTO) + ctx->domain_controller.state = AD_STATE_INVALID; - if (ctx->site_name.type == AD_TYPE_AUTO) - ctx->site_name.type = AD_TYPE_INVALID; + if (ctx->site_name.state == AD_STATE_AUTO) + ctx->site_name.state = AD_STATE_INVALID; - if (ctx->forest_name.type == AD_TYPE_AUTO) - ctx->forest_name.type = AD_TYPE_INVALID; + if (ctx->forest_name.state == AD_STATE_AUTO) + ctx->forest_name.state = AD_STATE_INVALID; - if (ctx->global_catalog.type == AD_TYPE_AUTO) - ctx->global_catalog.type = AD_TYPE_INVALID; + if (ctx->global_catalog.state == AD_STATE_AUTO) + ctx->global_catalog.state = AD_STATE_INVALID; - if (ctx->site_domain_controller.type == AD_TYPE_AUTO) - ctx->site_domain_controller.type = AD_TYPE_INVALID; + if (ctx->domains_in_forest.state == AD_STATE_AUTO) + ctx->domains_in_forest.state = AD_STATE_INVALID; - if (ctx->site_global_catalog.type == AD_TYPE_AUTO) - ctx->site_global_catalog.type = AD_TYPE_INVALID; + if (ctx->trusted_domains.state == AD_STATE_AUTO) + ctx->trusted_domains.state = AD_STATE_INVALID; + + if (ctx->site_domain_controller.state == AD_STATE_AUTO) + ctx->site_domain_controller.state = AD_STATE_INVALID; + + if (ctx->site_global_catalog.state == AD_STATE_AUTO) + ctx->site_global_catalog.state = AD_STATE_INVALID; } /* Discover joined Active Directory domainName */ -static void +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; - if (is_fixed(&ctx->domain_name)) - return; + if (is_valid(&ctx->domain_name)) + return (&ctx->domain_name); - if (!is_expired(&ctx->domain_name)) - return; /* Try to find our domain by searching for DCs for it */ DO_RES_NINIT(ctx); - domain_controller = srv_query(&ctx->state, LDAP_SRV_HEAD - DC_SRV_TAIL, ctx->domain_name.value.str, &srvname, &ttl); + domain_controller = srv_query(&ctx->res_state, LDAP_SRV_HEAD + DC_SRV_TAIL, ctx->domain_name.value, &srvname, &ttl); /* * 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) - return; + return (NULL); free(domain_controller); /* @@ -901,85 +1329,98 @@ validate_DomainName(ad_disc_t ctx) if (dname == NULL) { idmapdlog(LOG_ERR, "Out of memory"); - return; + return (NULL); } /* Eat any trailing dot */ if (*(dname + strlen(dname)) == '.') *(dname + strlen(dname)) = '\0'; - update_string(&ctx->domain_name, dname, AD_TYPE_AUTO, 0); + update_item(&ctx->domain_name, dname, AD_STATE_AUTO, ttl); + + return (&ctx->domain_name); } char * -ad_disc_get_DomainName(ad_disc_t ctx) +ad_disc_get_DomainName(ad_disc_t ctx, int *auto_discovered) { char *domain_name = NULL; + ad_item_t *domain_name_item; - validate_DomainName(ctx); + domain_name_item = validate_DomainName(ctx); + + if (domain_name_item) { + domain_name = strdup(domain_name_item->value); + if (auto_discovered != NULL) + *auto_discovered = + (domain_name_item->state == AD_STATE_AUTO); + } else if (auto_discovered != NULL) + *auto_discovered = FALSE; - if (is_valid(&ctx->domain_name)) - domain_name = strdup(ctx->domain_name.value.str); return (domain_name); } /* Discover domain controllers */ -static void +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; int validate_global = FALSE; int validate_site = FALSE; + ad_item_t *domain_name_item; + ad_item_t *site_name_item = NULL; + /* If the values is fixed there will not be a site specific version */ if (is_fixed(&ctx->domain_controller)) - return; + return (&ctx->domain_controller); + + domain_name_item = validate_DomainName(ctx); + if (domain_name_item == NULL) + return (NULL); - validate_DomainName(ctx); if (req == AD_DISC_GLOBAL) validate_global = TRUE; else { - validate_SiteName(ctx); - if (is_valid(&ctx->site_name)) + site_name_item = validate_SiteName(ctx); + if (site_name_item != NULL) validate_site = TRUE; - if (req == AD_DISC_PREFER_SITE) + else if (req == AD_DISC_PREFER_SITE) validate_global = TRUE; } - if (validate_global && (is_expired(&ctx->domain_controller) || - is_changed(&ctx->domain_controller, PARAM1, &ctx->domain_name))) { - - update_version(&ctx->domain_controller, PARAM1, - &ctx->domain_name); - - if (is_valid(&ctx->domain_name)) { + if (validate_global) { + if (!is_valid(&ctx->domain_controller) || + is_changed(&ctx->domain_controller, PARAM1, + domain_name_item)) { /* * Lookup DNS SRV RR named * _ldap._tcp.dc._msdcs.<DomainName> */ DO_RES_NINIT(ctx); - domain_controller = srv_query(&ctx->state, + domain_controller = srv_query(&ctx->res_state, LDAP_SRV_HEAD DC_SRV_TAIL, - ctx->domain_name.value.str, NULL, &ttl); - } - update_ds(&ctx->domain_controller, domain_controller, - AD_TYPE_AUTO, ttl); - } + domain_name_item->value, NULL, &ttl); - if (validate_site && (is_expired(&ctx->site_domain_controller) || - is_changed(&ctx->site_domain_controller, PARAM1, - &ctx->domain_name) || - is_changed(&ctx->site_domain_controller, PARAM2, - &ctx->site_name))) { + if (domain_controller == NULL) + return (NULL); - update_version(&ctx->site_domain_controller, PARAM1, - &ctx->domain_name); - update_version(&ctx->site_domain_controller, PARAM2, - &ctx->site_name); + update_item(&ctx->domain_controller, domain_controller, + AD_STATE_AUTO, ttl); + update_version(&ctx->domain_controller, PARAM1, + domain_name_item); + } + return (&ctx->domain_controller); + } - if (is_valid(&ctx->domain_name)) { + if (validate_site) { + 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]; /* * Lookup DNS SRV RR named @@ -987,33 +1428,48 @@ validate_DomainController(ad_disc_t ctx, enum ad_disc_req req) */ (void) snprintf(rr_name, sizeof (rr_name), LDAP_SRV_HEAD SITE_SRV_MIDDLE DC_SRV_TAIL, - ctx->site_name.value.str); + site_name_item->value); DO_RES_NINIT(ctx); - domain_controller = srv_query(&ctx->state, rr_name, - ctx->domain_name.value.str, NULL, &ttl); + domain_controller = srv_query(&ctx->res_state, rr_name, + domain_name_item->value, NULL, &ttl); + if (domain_controller == NULL) + return (NULL); + + update_item(&ctx->site_domain_controller, + domain_controller, AD_STATE_AUTO, ttl); + update_version(&ctx->site_domain_controller, PARAM1, + domain_name_item); + update_version(&ctx->site_domain_controller, PARAM2, + site_name_item); } - update_ds(&ctx->site_domain_controller, domain_controller, - AD_TYPE_AUTO, ttl); + return (&ctx->site_domain_controller); } + return (NULL); } idmap_ad_disc_ds_t * -ad_disc_get_DomainController(ad_disc_t ctx, enum ad_disc_req req) +ad_disc_get_DomainController(ad_disc_t ctx, enum ad_disc_req req, + int *auto_discovered) { + ad_item_t *domain_controller_item; idmap_ad_disc_ds_t *domain_controller = NULL; - ad_item_t *item; - validate_DomainController(ctx, req); - item = get_item(&ctx->domain_controller, - &ctx->site_domain_controller, req); - if (item != NULL && is_valid(item)) - domain_controller = dsdup(item->value.ds); + domain_controller_item = validate_DomainController(ctx, req); + + if (domain_controller_item != NULL) { + domain_controller = ds_dup(domain_controller_item->value); + if (auto_discovered != NULL) + *auto_discovered = + (domain_controller_item->state == AD_STATE_AUTO); + } else if (auto_discovered != NULL) + *auto_discovered = FALSE; + return (domain_controller); } /* Discover site name (for multi-homed systems the first one found wins) */ -static void +static ad_item_t * validate_SiteName(ad_disc_t ctx) { LDAP *ld = NULL; @@ -1027,14 +1483,17 @@ validate_SiteName(ad_disc_t ctx) int len; int i; int update_required = FALSE; + ad_item_t *domain_controller_item; if (is_fixed(&ctx->site_name)) - return; + return (&ctx->site_name); /* Can't rely on site-specific DCs */ - validate_DomainController(ctx, AD_DISC_GLOBAL); + domain_controller_item = validate_DomainController(ctx, AD_DISC_GLOBAL); + if (domain_controller_item == NULL) + return (NULL); - if (is_expired(&ctx->site_name) || + if (!is_valid(&ctx->site_name) || is_changed(&ctx->site_name, PARAM1, &ctx->domain_controller) || ctx->subnets == NULL || ctx->subnets_changed) { subnets = find_subnets(); @@ -1049,86 +1508,77 @@ validate_SiteName(ad_disc_t ctx) if (!update_required) { free(subnets); - return; + return (&ctx->site_name); } - update_version(&ctx->site_name, PARAM1, &ctx->domain_controller); + if (subnets == NULL) + return (NULL); - if (is_valid(&ctx->domain_name) && - is_valid(&ctx->domain_controller) && - subnets != NULL) { - dn_root[0] = ""; - dn_root[1] = NULL; + dn_root[0] = ""; + dn_root[1] = NULL; - config_naming_context = ldap_lookup_entry_attr( - &ld, ctx->domain_controller.value.ds, - dn_root, "configurationNamingContext"); - if (config_naming_context == NULL) - goto out; + 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)) { /* - * configurationNamingContext also provides the Forest - * Name. + * The configurationNamingContext should be of + * form: + * CN=Configuration,<DNforestName> + * Remove the first part and convert to DNS form + * (replace ",DC=" with ".") */ - 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); - update_string(&ctx->forest_name, - forest_name, AD_TYPE_AUTO, 0); - } + 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); + update_item(&ctx->forest_name, forest_name, + AD_STATE_AUTO, 0); } - dn_subnets = subnets_to_DNs(subnets, config_naming_context); - if (dn_subnets == NULL) - goto out; - - site_object = ldap_lookup_entry_attr( - &ld, ctx->domain_controller.value.ds, - dn_subnets, "siteobject"); - if (site_object != NULL) { - /* - * The site object should be of the form - * CN=<site>,CN=Sites,CN=Configuration, - * <DN Domain> - */ - if (strncasecmp(site_object, "CN=", 3) == 0) { - for (len = 0; - site_object[len + 3] != ','; len++) + } + + 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 (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'; - } + site_name = malloc(len + 1); + (void) strncpy(site_name, &site_object[3], len); + site_name[len] = '\0'; + update_item(&ctx->site_name, site_name, + AD_STATE_AUTO, 0); } + } - if (ctx->subnets != NULL) { - free(ctx->subnets); - ctx->subnets = NULL; - } - ctx->subnets = subnets; - subnets = NULL; - ctx->subnets_changed = FALSE; + if (ctx->subnets != NULL) { + free(ctx->subnets); + ctx->subnets = NULL; } + ctx->subnets = subnets; + subnets = NULL; + ctx->subnets_changed = FALSE; + out: if (ld != NULL) (void) ldap_unbind(ld); - update_string(&ctx->site_name, site_name, AD_TYPE_AUTO, 0); - - if (site_name == NULL || *site_name == '\0') { - /* No site name -> no site-specific DSs */ - update_ds(&ctx->site_domain_controller, NULL, AD_TYPE_AUTO, 0); - update_ds(&ctx->site_global_catalog, NULL, AD_TYPE_AUTO, 0); - } - if (dn_subnets != NULL) { for (i = 0; dn_subnets[i] != NULL; i++) free(dn_subnets[i]); @@ -1140,144 +1590,174 @@ out: free(site_object); free(subnets); + if (site_name == NULL) + return (NULL); + return (&ctx->site_name); } char * -ad_disc_get_SiteName(ad_disc_t ctx) +ad_disc_get_SiteName(ad_disc_t ctx, int *auto_discovered) { + ad_item_t *site_name_item; char *site_name = NULL; - validate_SiteName(ctx); - if (is_valid(&ctx->site_name)) - site_name = strdup(ctx->site_name.value.str); + site_name_item = validate_SiteName(ctx); + if (site_name_item != NULL) { + site_name = strdup(site_name_item->value); + if (auto_discovered != NULL) + *auto_discovered = + (site_name_item->state == AD_STATE_AUTO); + } else if (auto_discovered != NULL) + *auto_discovered = FALSE; + return (site_name); } /* Discover forest name */ -static void +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; + 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()?) */ - validate_DomainController(ctx, AD_DISC_GLOBAL); - if (is_expired(&ctx->forest_name) || - is_changed(&ctx->forest_name, PARAM1, &ctx->domain_controller)) { + domain_controller_item = validate_DomainController(ctx, AD_DISC_GLOBAL); + if (domain_controller_item == NULL) + return (NULL); - update_version(&ctx->forest_name, PARAM1, - &ctx->domain_controller); - - if (is_valid(&ctx->domain_controller)) { - dn_list[0] = ""; - dn_list[1] = NULL; - config_naming_context = ldap_lookup_entry_attr( - &ld, ctx->domain_controller.value.ds, - 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 (!is_valid(&ctx->forest_name) || + is_changed(&ctx->forest_name, PARAM1, domain_controller_item)) { + + dn_list[0] = ""; + dn_list[1] = NULL; + 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); } - if (ld != NULL) - (void) ldap_unbind(ld); + free(config_naming_context); } - update_string(&ctx->forest_name, forest_name, AD_TYPE_AUTO, 0); + if (ld != NULL) + (void) ldap_unbind(ld); + + if (forest_name == NULL) + 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); } char * -ad_disc_get_ForestName(ad_disc_t ctx) +ad_disc_get_ForestName(ad_disc_t ctx, int *auto_discovered) { + ad_item_t *forest_name_item; char *forest_name = NULL; - validate_ForestName(ctx); + forest_name_item = validate_ForestName(ctx); + + if (forest_name_item != NULL) { + forest_name = strdup(forest_name_item->value); + if (auto_discovered != NULL) + *auto_discovered = + (forest_name_item->state == AD_STATE_AUTO); + } else if (auto_discovered != NULL) + *auto_discovered = FALSE; - if (is_valid(&ctx->forest_name)) - forest_name = strdup(ctx->forest_name.value.str); return (forest_name); } /* Discover global catalog servers */ -static void +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; int validate_global = FALSE; int validate_site = FALSE; + ad_item_t *forest_name_item; + ad_item_t *site_name_item; + /* If the values is fixed there will not be a site specific version */ if (is_fixed(&ctx->global_catalog)) - return; + return (&ctx->global_catalog); + + forest_name_item = validate_ForestName(ctx); + if (forest_name_item == NULL) + return (NULL); - validate_ForestName(ctx); if (req == AD_DISC_GLOBAL) validate_global = TRUE; else { - validate_SiteName(ctx); - if (is_valid(&ctx->site_name)) + site_name_item = validate_SiteName(ctx); + if (site_name_item != NULL) validate_site = TRUE; - if (req == AD_DISC_PREFER_SITE) + else if (req == AD_DISC_PREFER_SITE) validate_global = TRUE; } - if (validate_global && (is_expired(&ctx->global_catalog) || - is_changed(&ctx->global_catalog, PARAM1, &ctx->forest_name))) { - - update_version(&ctx->global_catalog, PARAM1, &ctx->forest_name); - - if (is_valid(&ctx->forest_name)) { + if (validate_global) { + if (!is_valid(&ctx->global_catalog) || + is_changed(&ctx->global_catalog, PARAM1, + forest_name_item)) { /* * Lookup DNS SRV RR named * _ldap._tcp.gc._msdcs.<ForestName> */ DO_RES_NINIT(ctx); global_catalog = - srv_query(&ctx->state, LDAP_SRV_HEAD GC_SRV_TAIL, - ctx->forest_name.value.str, NULL, &ttl); - } - update_ds(&ctx->global_catalog, global_catalog, - AD_TYPE_AUTO, ttl); - } + srv_query(&ctx->res_state, + LDAP_SRV_HEAD GC_SRV_TAIL, + ctx->forest_name.value, NULL, &ttl); - if (validate_site && (is_expired(&ctx->site_global_catalog) || - is_changed(&ctx->site_global_catalog, PARAM1, &ctx->forest_name) || - is_changed(&ctx->site_global_catalog, PARAM2, &ctx->site_name))) { + if (global_catalog == NULL) + return (NULL); - update_version(&ctx->site_global_catalog, PARAM1, - &ctx->forest_name); - update_version(&ctx->site_global_catalog, PARAM2, - &ctx->site_name); + update_item(&ctx->global_catalog, global_catalog, + AD_STATE_AUTO, ttl); + update_version(&ctx->global_catalog, PARAM1, + forest_name_item); + } + return (&ctx->global_catalog); + } - if (is_valid(&ctx->forest_name) && is_valid(&ctx->site_name)) { + if (validate_site) { + 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]; + /* * Lookup DNS SRV RR named: * _ldap._tcp.<siteName>._sites.gc. @@ -1286,33 +1766,187 @@ validate_GlobalCatalog(ad_disc_t ctx, enum ad_disc_req req) (void) snprintf(rr_name, sizeof (rr_name), LDAP_SRV_HEAD SITE_SRV_MIDDLE GC_SRV_TAIL, - ctx->site_name.value.str); + ctx->site_name.value); DO_RES_NINIT(ctx); - global_catalog = - srv_query(&ctx->state, rr_name, - ctx->forest_name.value.str, NULL, &ttl); + global_catalog = srv_query(&ctx->res_state, rr_name, + ctx->forest_name.value, NULL, &ttl); + + if (global_catalog == NULL) + return (NULL); + update_item(&ctx->site_global_catalog, global_catalog, + AD_STATE_AUTO, ttl); + update_version(&ctx->site_global_catalog, PARAM1, + forest_name_item); + update_version(&ctx->site_global_catalog, PARAM2, + site_name_item); } - update_ds(&ctx->site_global_catalog, global_catalog, - AD_TYPE_AUTO, ttl); + return (&ctx->site_global_catalog); } + return (NULL); } idmap_ad_disc_ds_t * -ad_disc_get_GlobalCatalog(ad_disc_t ctx, enum ad_disc_req req) +ad_disc_get_GlobalCatalog(ad_disc_t ctx, enum ad_disc_req req, + int *auto_discovered) { idmap_ad_disc_ds_t *global_catalog = NULL; - ad_item_t *item; + ad_item_t *global_catalog_item; + + global_catalog_item = validate_GlobalCatalog(ctx, req); - validate_GlobalCatalog(ctx, req); + if (global_catalog_item != NULL) { + global_catalog = ds_dup(global_catalog_item->value); + if (auto_discovered != NULL) + *auto_discovered = + (global_catalog_item->state == AD_STATE_AUTO); + } else if (auto_discovered != NULL) + *auto_discovered = FALSE; - item = get_item(&ctx->global_catalog, &ctx->site_global_catalog, req); - if (item != NULL && is_valid(item)) - global_catalog = dsdup(item->value.ds); return (global_catalog); } +static ad_item_t * +validate_TrustedDomains(ad_disc_t ctx) +{ + LDAP *ld = NULL; + ad_item_t *global_catalog_item; + ad_item_t *forest_name_item; + ad_disc_trusteddomains_t *trusted_domains; + char *dn = NULL; + char *forest_name_dn; + int len; + int num_parts; + + if (is_fixed(&ctx->trusted_domains)) + return (&ctx->trusted_domains); + + global_catalog_item = validate_GlobalCatalog(ctx, AD_DISC_GLOBAL); + if (global_catalog_item == NULL) + return (NULL); + + forest_name_item = validate_ForestName(ctx); + if (forest_name_item == NULL) + return (NULL); + + if (!is_valid(&ctx->trusted_domains) || + is_changed(&ctx->trusted_domains, PARAM1, global_catalog_item) || + is_changed(&ctx->trusted_domains, PARAM2, forest_name_item)) { + + forest_name_dn = ldap_dns_to_dn(forest_name_item->value, + &num_parts); + if (forest_name_dn == NULL) + return (NULL); + + len = snprintf(NULL, 0, "CN=System,%s", forest_name_dn) + 1; + dn = malloc(len); + if (dn == NULL) { + free(forest_name_dn); + return (NULL); + } + (void) snprintf(dn, len, "CN=System,%s", forest_name_dn); + free(forest_name_dn); + + trusted_domains = ldap_lookup_trusted_domains( + &ld, global_catalog_item->value, dn); + + if (ld != NULL) + (void) ldap_unbind(ld); + free(dn); + + if (trusted_domains == NULL) + return (NULL); + + update_item(&ctx->trusted_domains, trusted_domains, + AD_STATE_AUTO, 0); + update_version(&ctx->trusted_domains, PARAM1, + global_catalog_item); + update_version(&ctx->trusted_domains, PARAM2, + forest_name_item); + } + + return (&ctx->trusted_domains); +} + + +ad_disc_trusteddomains_t * +ad_disc_get_TrustedDomains(ad_disc_t ctx, int *auto_discovered) +{ + ad_disc_trusteddomains_t *trusted_domains = NULL; + ad_item_t *trusted_domains_item; + + trusted_domains_item = validate_TrustedDomains(ctx); + + if (trusted_domains_item != NULL) { + trusted_domains = td_dup(trusted_domains_item->value); + if (auto_discovered != NULL) + *auto_discovered = + (trusted_domains_item->state == AD_STATE_AUTO); + } else if (auto_discovered != NULL) + *auto_discovered = FALSE; + + return (trusted_domains); +} + + +static ad_item_t * +validate_DomainsInForest(ad_disc_t ctx) +{ + ad_item_t *global_catalog_item; + LDAP *ld = NULL; + ad_disc_domainsinforest_t *domains_in_forest; + + if (is_fixed(&ctx->domains_in_forest)) + return (&ctx->domains_in_forest); + + global_catalog_item = validate_GlobalCatalog(ctx, AD_DISC_GLOBAL); + if (global_catalog_item == NULL) + return (NULL); + + if (!is_valid(&ctx->domains_in_forest) || + is_changed(&ctx->domains_in_forest, PARAM1, global_catalog_item)) { + + domains_in_forest = ldap_lookup_domains_in_forest( + &ld, global_catalog_item->value); + + if (ld != NULL) + (void) ldap_unbind(ld); + + if (domains_in_forest == NULL) + return (NULL); + + update_item(&ctx->domains_in_forest, domains_in_forest, + AD_STATE_AUTO, 0); + update_version(&ctx->domains_in_forest, PARAM1, + global_catalog_item); + } + return (&ctx->domains_in_forest); +} + + +ad_disc_domainsinforest_t * +ad_disc_get_DomainsInForest(ad_disc_t ctx, int *auto_discovered) +{ + ad_disc_domainsinforest_t *domains_in_forest = NULL; + ad_item_t *domains_in_forest_item; + + domains_in_forest_item = validate_DomainsInForest(ctx); + + if (domains_in_forest_item != NULL) { + domains_in_forest = df_dup(domains_in_forest_item->value); + if (auto_discovered != NULL) + *auto_discovered = + (domains_in_forest_item->state == AD_STATE_AUTO); + } else if (auto_discovered != NULL) + *auto_discovered = FALSE; + + return (domains_in_forest); +} + + + + int ad_disc_set_DomainName(ad_disc_t ctx, const char *domainName) { @@ -1321,10 +1955,10 @@ ad_disc_set_DomainName(ad_disc_t ctx, const char *domainName) domain_name = strdup(domainName); if (domain_name == NULL) return (-1); - update_string(&ctx->domain_name, domain_name, - AD_TYPE_FIXED, 0); - } else if (ctx->domain_name.type == AD_TYPE_FIXED) - ctx->domain_name.type = AD_TYPE_INVALID; + update_item(&ctx->domain_name, domain_name, + AD_STATE_FIXED, 0); + } else if (ctx->domain_name.state == AD_STATE_FIXED) + ctx->domain_name.state = AD_STATE_INVALID; return (0); } @@ -1335,13 +1969,13 @@ ad_disc_set_DomainController(ad_disc_t ctx, { idmap_ad_disc_ds_t *domain_controller = NULL; if (domainController != NULL) { - domain_controller = dsdup(domainController); + domain_controller = ds_dup(domainController); if (domain_controller == NULL) return (-1); - update_ds(&ctx->domain_controller, domain_controller, - AD_TYPE_FIXED, 0); - } else if (ctx->domain_controller.type == AD_TYPE_FIXED) - ctx->domain_controller.type = AD_TYPE_INVALID; + update_item(&ctx->domain_controller, domain_controller, + AD_STATE_FIXED, 0); + } else if (ctx->domain_controller.state == AD_STATE_FIXED) + ctx->domain_controller.state = AD_STATE_INVALID; return (0); } @@ -1354,9 +1988,9 @@ ad_disc_set_SiteName(ad_disc_t ctx, const char *siteName) site_name = strdup(siteName); if (site_name == NULL) return (-1); - update_string(&ctx->site_name, site_name, AD_TYPE_FIXED, 0); - } else if (ctx->site_name.type == AD_TYPE_FIXED) - ctx->site_name.type = AD_TYPE_INVALID; + update_item(&ctx->site_name, site_name, AD_STATE_FIXED, 0); + } else if (ctx->site_name.state == AD_STATE_FIXED) + ctx->site_name.state = AD_STATE_INVALID; return (0); } @@ -1368,10 +2002,10 @@ ad_disc_set_ForestName(ad_disc_t ctx, const char *forestName) forest_name = strdup(forestName); if (forest_name == NULL) return (-1); - update_string(&ctx->forest_name, forest_name, - AD_TYPE_FIXED, 0); - } else if (ctx->forest_name.type == AD_TYPE_FIXED) - ctx->forest_name.type = AD_TYPE_INVALID; + update_item(&ctx->forest_name, forest_name, + AD_STATE_FIXED, 0); + } else if (ctx->forest_name.state == AD_STATE_FIXED) + ctx->forest_name.state = AD_STATE_INVALID; return (0); } @@ -1381,13 +2015,13 @@ ad_disc_set_GlobalCatalog(ad_disc_t ctx, { idmap_ad_disc_ds_t *global_catalog = NULL; if (globalCatalog != NULL) { - global_catalog = dsdup(globalCatalog); + global_catalog = ds_dup(globalCatalog); if (global_catalog == NULL) return (-1); - update_ds(&ctx->global_catalog, global_catalog, - AD_TYPE_FIXED, 0); - } else if (ctx->global_catalog.type == AD_TYPE_FIXED) - ctx->global_catalog.type = AD_TYPE_INVALID; + update_item(&ctx->global_catalog, global_catalog, + AD_STATE_FIXED, 0); + } else if (ctx->global_catalog.state == AD_STATE_FIXED) + ctx->global_catalog.state = AD_STATE_INVALID; return (0); } @@ -1395,20 +2029,20 @@ ad_disc_set_GlobalCatalog(ad_disc_t ctx, int ad_disc_unset(ad_disc_t ctx) { - if (ctx->domain_name.type == AD_TYPE_FIXED) - ctx->domain_name.type = AD_TYPE_INVALID; + if (ctx->domain_name.state == AD_STATE_FIXED) + ctx->domain_name.state = AD_STATE_INVALID; - if (ctx->domain_controller.type == AD_TYPE_FIXED) - ctx->domain_controller.type = AD_TYPE_INVALID; + if (ctx->domain_controller.state == AD_STATE_FIXED) + ctx->domain_controller.state = AD_STATE_INVALID; - if (ctx->site_name.type == AD_TYPE_FIXED) - ctx->site_name.type = AD_TYPE_INVALID; + if (ctx->site_name.state == AD_STATE_FIXED) + ctx->site_name.state = AD_STATE_INVALID; - if (ctx->forest_name.type == AD_TYPE_FIXED) - ctx->forest_name.type = AD_TYPE_INVALID; + if (ctx->forest_name.state == AD_STATE_FIXED) + ctx->forest_name.state = AD_STATE_INVALID; - if (ctx->global_catalog.type == AD_TYPE_FIXED) - ctx->global_catalog.type = AD_TYPE_INVALID; + if (ctx->global_catalog.state == AD_STATE_FIXED) + ctx->global_catalog.state = AD_STATE_INVALID; return (0); } diff --git a/usr/src/lib/libidmap/common/addisc.h b/usr/src/lib/libidmap/common/addisc.h index fd89f2c853..6622965e23 100644 --- a/usr/src/lib/libidmap/common/addisc.h +++ b/usr/src/lib/libidmap/common/addisc.h @@ -27,8 +27,6 @@ #ifndef _ADINFO_H #define _ADINFO_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include "idmap_priv.h" #include "idmap_prot.h" #include "idmap_impl.h" @@ -37,55 +35,32 @@ extern "C" { #endif +/* + * Maximum string SID size. 4 bytes for "S-1-", 15 for 2^48 (max authority), + * another '-', and ridcount (max 15) 10-digit RIDs plus '-' in between, plus + * a null. + */ -enum ad_item_type { - AD_TYPE_INVALID = 0, /* The value is not valid */ - AD_TYPE_FIXED, /* The value was fixed by caller */ - AD_TYPE_AUTO /* The value is auto discovered */ - }; - - -typedef struct ad_subnet { - char subnet[24]; -} ad_subnet_t; - - -typedef struct ad_item { - enum ad_item_type type; - union { - char *str; - idmap_ad_disc_ds_t *ds; - } value; - time_t ttl; - 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 state; - int res_ninitted; - ad_subnet_t *subnets; - int subnets_changed; - time_t subnets_last_check; - ad_item_t domain_name; - ad_item_t domain_controller; - ad_item_t site_name; - ad_item_t forest_name; - ad_item_t global_catalog; - /* Site specfic versions */ - ad_item_t site_domain_controller; - ad_item_t site_global_catalog; -} ad_disc; +#define AD_DISC_MAXSID 185 typedef struct ad_disc *ad_disc_t; +typedef struct ad_disc_domains_in_forest { + char domain[AD_DISC_MAXHOSTNAME]; + char sid[AD_DISC_MAXSID]; + int trusted; /* This is not used by auto */ + /* discovery. It is provided so that */ + /* domains in a forest can be marked */ + /* as trusted. */ +} ad_disc_domainsinforest_t; + + +typedef struct ad_disc_trusted_domains { + char domain[AD_DISC_MAXHOSTNAME]; + int direction; +} ad_disc_trusteddomains_t; + enum ad_disc_req { AD_DISC_PREFER_SITE = 0, /* Prefer Site specific version */ @@ -97,40 +72,78 @@ ad_disc_t ad_disc_init(void); void ad_disc_fini(ad_disc_t); -void ad_disc_refresh(ad_disc_t); +/* + * The following routines auto discover the specific item + */ +char * +ad_disc_get_DomainName(ad_disc_t ctx, int *auto_discovered); -char *ad_disc_get_DomainName(ad_disc_t ctx); +idmap_ad_disc_ds_t * +ad_disc_get_DomainController(ad_disc_t ctx, + enum ad_disc_req req, int *auto_discovered); -idmap_ad_disc_ds_t *ad_disc_get_DomainController(ad_disc_t ctx, - enum ad_disc_req req); +char * +ad_disc_get_SiteName(ad_disc_t ctx, int *auto_discovered); -char *ad_disc_get_SiteName(ad_disc_t ctx); +char * +ad_disc_get_ForestName(ad_disc_t ctx, int *auto_discovered); -char *ad_disc_get_ForestName(ad_disc_t ctx); +idmap_ad_disc_ds_t * +ad_disc_get_GlobalCatalog(ad_disc_t ctx, enum ad_disc_req, + int *auto_discovered); -idmap_ad_disc_ds_t *ad_disc_get_GlobalCatalog(ad_disc_t ctx, enum ad_disc_req); +ad_disc_trusteddomains_t * +ad_disc_get_TrustedDomains(ad_disc_t ctx, int *auto_discovered); -int ad_disc_compare_ds(idmap_ad_disc_ds_t *ds1, idmap_ad_disc_ds_t *ds2); +ad_disc_domainsinforest_t * +ad_disc_get_DomainsInForest(ad_disc_t ctx, int *auto_discovered); -int ad_disc_set_DomainName(ad_disc_t ctx, const char *domainName); -int ad_disc_set_DomainController(ad_disc_t ctx, - const idmap_ad_disc_ds_t *domainController); +/* + * The following routines over ride auto discovery with the + * specified values + */ +int +ad_disc_set_DomainName(ad_disc_t ctx, const char *domainName); -int ad_disc_set_SiteName(ad_disc_t ctx, const char *siteName); +int +ad_disc_set_DomainController(ad_disc_t ctx, + const idmap_ad_disc_ds_t *domainController); -int ad_disc_set_ForestName(ad_disc_t ctx, const char *ForestName); +int +ad_disc_set_SiteName(ad_disc_t ctx, const char *siteName); -int ad_disc_set_GlobalCatalog(ad_disc_t ctx, - const idmap_ad_disc_ds_t *GlobalCatalog); +int +ad_disc_set_ForestName(ad_disc_t ctx, const char *forestName); + +int +ad_disc_set_GlobalCatalog(ad_disc_t ctx, + const idmap_ad_disc_ds_t *globalCatalog); -int ad_disc_unset(ad_disc_t ctx); +/* + * This routine forces all auto discovery item to be recomputed + * on request + */ +void ad_disc_refresh(ad_disc_t); +/* This routine unsets all overridden values */ +int ad_disc_unset(ad_disc_t ctx); + +/* This routine test for subnet changes */ int ad_disc_SubnetChanged(ad_disc_t); +/* This routine returns the Time To Live for auto discovered items */ int ad_disc_get_TTL(ad_disc_t); +int ad_disc_compare_ds(idmap_ad_disc_ds_t *ds1, idmap_ad_disc_ds_t *ds2); + +int ad_disc_compare_trusteddomains(ad_disc_trusteddomains_t *td1, + ad_disc_trusteddomains_t *td2); + +int ad_disc_compare_domainsinforest(ad_disc_domainsinforest_t *td1, + ad_disc_domainsinforest_t *td2); + #ifdef __cplusplus } #endif diff --git a/usr/src/lib/libidmap/common/idmap_api.c b/usr/src/lib/libidmap/common/idmap_api.c index 69ed433d98..0fe0d8f418 100644 --- a/usr/src/lib/libidmap/common/idmap_api.c +++ b/usr/src/lib/libidmap/common/idmap_api.c @@ -224,7 +224,7 @@ idmap_fini(idmap_handle_t *handle) } -idmap_stat +static idmap_stat idmap_get_prop(idmap_handle_t *handle, idmap_prop_type pr, idmap_prop_res *res) { CLIENT *clnt; @@ -243,24 +243,9 @@ idmap_get_prop(idmap_handle_t *handle, idmap_prop_type pr, idmap_prop_res *res) } return (res->retcode); /* This might not be IDMAP_SUCCESS! */ - -#if 0 - (void) memset(&res, 0, sizeof (res)); - pr = PROP_DOMAIN_CONTROLLER; - - clntstat = clnt_call(clnt, IDMAP_GET_PROP, - (xdrproc_t)xdr_idmap_prop_type, (caddr_t)&pr, - (xdrproc_t)xdr_idmap_prop_res, (caddr_t)&res, TIMEOUT); - - if (clntstat != RPC_SUCCESS) { - fprintf(stderr, "clntstat != RPC_SUCCESS\n"); - rc = _idmap_rpc2stat(clnt); - goto cleanup; - } -#endif - } + idmap_stat idmap_get_prop_ds(idmap_handle_t *handle, idmap_prop_type pr, idmap_ad_disc_ds_t *dc) @@ -2066,7 +2051,7 @@ static stat_table_t stattable[] = { {IDMAP_ERR_BAD_UTF8, gettext("Invalid or illegal UTF-8 sequence found in " "a given Windows entity name or domain name"), EINVAL}, - {IDMAP_ERR_NONEGENERATED, + {IDMAP_ERR_NONE_GENERATED, gettext("Mapping not found and none created (see -c option)"), EINVAL}, {IDMAP_ERR_PROP_UNKNOWN, @@ -2080,6 +2065,9 @@ static stat_table_t stattable[] = { gettext("Native LDAP operation failed"), EINVAL}, {IDMAP_ERR_NS_LDAP_BAD_WINNAME, gettext("Improper winname form found in Native LDAP"), EINVAL}, + {IDMAP_ERR_NO_ACTIVEDIRECTORY, + gettext("No AD servers"), + EINVAL}, {-1, NULL, 0} }; #undef gettext @@ -2167,12 +2155,13 @@ idmap_string2stat(const char *str) return_cmp(W2U_NAMERULE_CONFLICT); return_cmp(U2W_NAMERULE_CONFLICT); return_cmp(BAD_UTF8); - return_cmp(NONEGENERATED); + return_cmp(NONE_GENERATED); return_cmp(PROP_UNKNOWN); return_cmp(NS_LDAP_CFG); return_cmp(NS_LDAP_PARTIAL); return_cmp(NS_LDAP_OP_FAILED); return_cmp(NS_LDAP_BAD_WINNAME); + return_cmp(NO_ACTIVEDIRECTORY); #undef return_cmp return (IDMAP_ERR_OTHER); diff --git a/usr/src/lib/libidmap/common/mapfile-vers b/usr/src/lib/libidmap/common/mapfile-vers index 7360322a8a..905cc8b64f 100644 --- a/usr/src/lib/libidmap/common/mapfile-vers +++ b/usr/src/lib/libidmap/common/mapfile-vers @@ -98,6 +98,8 @@ SUNWprivate { ad_disc_get_DomainName; ad_disc_set_DomainName; ad_disc_compare_ds; + ad_disc_compare_trusteddomains; + ad_disc_compare_domainsinforest; ad_disc_SubnetChanged; ad_disc_get_GlobalCatalog; ad_disc_set_GlobalCatalog; @@ -109,6 +111,8 @@ SUNWprivate { ad_disc_set_SiteName; ad_disc_refresh; ad_disc_get_SiteName; + ad_disc_get_TrustedDomains; + ad_disc_get_DomainsInForest; local: *; }; diff --git a/usr/src/lib/libidmap/common/namemaps.c b/usr/src/lib/libidmap/common/namemaps.c index a72a7e360b..ce43ece4ce 100644 --- a/usr/src/lib/libidmap/common/namemaps.c +++ b/usr/src/lib/libidmap/common/namemaps.c @@ -23,14 +23,12 @@ * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" #include <errno.h> #include <ldap.h> #include <sasl/sasl.h> #include <libintl.h> #include <strings.h> -#include <strings.h> #include "idmap_impl.h" #include "ns_sldap.h" @@ -249,7 +247,7 @@ idmap_init_ad(idmap_nm_handle_t *p) goto cleanup; } - dc = ad_disc_get_DomainController(ad_ctx, AD_DISC_GLOBAL); + dc = ad_disc_get_DomainController(ad_ctx, AD_DISC_GLOBAL, NULL); if (dc == NULL) { rc = IDMAP_ERR_ARG; idmapdlog(LOG_ERR, diff --git a/usr/src/lib/nsswitch/ad/common/ad_common.c b/usr/src/lib/nsswitch/ad/common/ad_common.c index 9265defe13..749e269165 100644 --- a/usr/src/lib/nsswitch/ad/common/ad_common.c +++ b/usr/src/lib/nsswitch/ad/common/ad_common.c @@ -62,7 +62,8 @@ nssad_cfg_discover_props(const char *domain, ad_disc_t ad_ctx, return (-1); if (props->domain_controller == NULL) props->domain_controller = - ad_disc_get_DomainController(ad_ctx, AD_DISC_PREFER_SITE); + ad_disc_get_DomainController(ad_ctx, AD_DISC_PREFER_SITE, + NULL); return (0); } |