summaryrefslogtreecommitdiff
path: root/usr/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib')
-rw-r--r--usr/src/lib/libadutils/common/adutils.c98
-rw-r--r--usr/src/lib/libadutils/common/adutils_impl.h19
-rw-r--r--usr/src/lib/libadutils/common/libadutils.h9
-rw-r--r--usr/src/lib/libadutils/common/mapfile-vers3
-rw-r--r--usr/src/lib/libidmap/common/addisc.c1506
-rw-r--r--usr/src/lib/libidmap/common/addisc.h137
-rw-r--r--usr/src/lib/libidmap/common/idmap_api.c27
-rw-r--r--usr/src/lib/libidmap/common/mapfile-vers4
-rw-r--r--usr/src/lib/libidmap/common/namemaps.c4
-rw-r--r--usr/src/lib/nsswitch/ad/common/ad_common.c3
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);
}