summaryrefslogtreecommitdiff
path: root/usr/src/cmd/idmap
diff options
context:
space:
mode:
authorKeyur Desai <Keyur.Desai@Sun.COM>2009-09-11 17:22:48 -0600
committerKeyur Desai <Keyur.Desai@Sun.COM>2009-09-11 17:22:48 -0600
commite3f2c991a8548408db0a2787bd8b43d5124821d3 (patch)
tree953b45b77a478c8ee85319e5e96ddb77f98dbd13 /usr/src/cmd/idmap
parentc4ddbbe1ca066fd6662bdb8c477ad412b97c5590 (diff)
downloadillumos-joyent-e3f2c991a8548408db0a2787bd8b43d5124821d3.tar.gz
6861127 Want an RPC function to get the session key
6865745 Consolidate request handlers for query file information requests 6864354 mdb dumps core in an smb dcmd 6841851 [Sparc] Can not make a mapped drive from Windows to any share on CIFS Server 6840783 Support IDMU userid and groupid data for joined domain 6845717 idmapd's scf_value2string unnecessarily complex, incorrect PSARC/2009/398 IDMU Support for idmap 6867994 Rework handling of set and query of file allocation size 6863385 MMC - Unable to use Event Viewer in Windows 2008 - "RPC server is unavailable" 6863390 MMC - Issues with the Services list in Windows 2008 6868501 Unable to map a CIFS share after bfu to cifs nightly build 6870248 Consolidate request handlers for set file information requests 6864074 idmap cannot map computer accounts 6874207 Incorrect access permission check when setting file size 6875658 Need locking around process-wide changes 6877595 eliminate smbd_fs_query() PSARC/2009/375 ABE share property for NFS and SMB 6802736 SMB share support for Access Based Enumeration 6875228 Issue with file copy from a CIFS share to the same share using Windows. --HG-- rename : usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c => usr/src/uts/common/fs/smbsrv/smb_query_fileinfo.c rename : usr/src/uts/common/fs/smbsrv/smb_trans2_set_information.c => usr/src/uts/common/fs/smbsrv/smb_set_fileinfo.c
Diffstat (limited to 'usr/src/cmd/idmap')
-rw-r--r--usr/src/cmd/idmap/idmap/idmap.c19
-rw-r--r--usr/src/cmd/idmap/idmapd/adutils.c454
-rw-r--r--usr/src/cmd/idmap/idmapd/adutils.h17
-rw-r--r--usr/src/cmd/idmap/idmapd/dbutils.c369
-rw-r--r--usr/src/cmd/idmap/idmapd/directory_provider_ad.c4
-rw-r--r--usr/src/cmd/idmap/idmapd/idmap_config.c438
-rw-r--r--usr/src/cmd/idmap/idmapd/idmap_config.h26
-rw-r--r--usr/src/cmd/idmap/idmapd/idmapd.h13
-rw-r--r--usr/src/cmd/idmap/idmapd/init.c164
-rw-r--r--usr/src/cmd/idmap/idmapd/server.c18
10 files changed, 1028 insertions, 494 deletions
diff --git a/usr/src/cmd/idmap/idmap/idmap.c b/usr/src/cmd/idmap/idmap/idmap.c
index 92cd73a2c1..1a57428597 100644
--- a/usr/src/cmd/idmap/idmap/idmap.c
+++ b/usr/src/cmd/idmap/idmap/idmap.c
@@ -1440,6 +1440,15 @@ print_how(idmap_how *how)
case IDMAP_MAP_TYPE_KNOWN_SID:
(void) printf(gettext("Method:\tWell-Known mapping\n"));
break;
+
+ case IDMAP_MAP_TYPE_IDMU:
+ (void) printf(gettext("Method:\tIDMU\n"));
+ (void) printf(gettext("DN:\t%s\n"),
+ CHECK_NULL(how->idmap_how_u.idmu.dn));
+ (void) printf(gettext("Attribute:\t%s=%s\n"),
+ CHECK_NULL(how->idmap_how_u.idmu.attr),
+ CHECK_NULL(how->idmap_how_u.idmu.value));
+ break;
}
}
@@ -1542,6 +1551,16 @@ print_error_info(idmap_info *info)
(void) fprintf(stderr,
gettext("Failed Method:\tWell-Known mapping\n"));
break;
+
+ case IDMAP_MAP_TYPE_IDMU:
+ (void) fprintf(stderr,
+ gettext("Failed Method:\tIDMU\n"));
+ (void) fprintf(stderr, gettext("DN:\t%s\n"),
+ CHECK_NULL(how->idmap_how_u.idmu.dn));
+ (void) fprintf(stderr, gettext("Attribute:\t%s=%s\n"),
+ CHECK_NULL(how->idmap_how_u.idmu.attr),
+ CHECK_NULL(how->idmap_how_u.idmu.value));
+ break;
}
}
diff --git a/usr/src/cmd/idmap/idmapd/adutils.c b/usr/src/cmd/idmap/idmapd/adutils.c
index 554398dfc6..5af08aacbf 100644
--- a/usr/src/cmd/idmap/idmapd/adutils.c
+++ b/usr/src/cmd/idmap/idmapd/adutils.c
@@ -55,7 +55,11 @@
#define SAN "sAMAccountName"
#define OBJSID "objectSid"
#define OBJCLASS "objectClass"
-#define SANFILTER "(sAMAccountName=%.*s)"
+#define UIDNUMBER "uidNumber"
+#define GIDNUMBER "gidNumber"
+#define UIDNUMBERFILTER "(&(objectclass=user)(uidNumber=%u))"
+#define GIDNUMBERFILTER "(&(objectclass=group)(gidNumber=%u))"
+#define SANFILTER "(sAMAccountName=%s)"
#define OBJSIDFILTER "(objectSid=%s)"
void idmap_ldap_res_search_cb(LDAP *ld, LDAPMessage **res, int rc,
@@ -85,6 +89,7 @@ typedef struct idmap_q {
char **dn; /* DN of entry */
char **attr; /* Attr for name mapping */
char **value; /* value for name mapping */
+ posix_id_t *pid; /* Posix ID found via IDMU */
idmap_retcode *rc;
adutils_rc ad_rc;
adutils_result_t *result;
@@ -103,6 +108,8 @@ struct idmap_query_state {
uint32_t qcount; /* Number of queued requests */
const char *ad_unixuser_attr;
const char *ad_unixgroup_attr;
+ int directory_based_mapping; /* enum */
+ char *default_domain;
idmap_q_t queries[1]; /* array of query results */
};
@@ -185,6 +192,7 @@ map_adrc2idmaprc(adutils_rc adrc)
idmap_retcode
idmap_lookup_batch_start(adutils_ad_t *ad, int nqueries,
+ int directory_based_mapping, const char *default_domain,
idmap_query_state_t **state)
{
idmap_query_state_t *new_state;
@@ -202,10 +210,17 @@ idmap_lookup_batch_start(adutils_ad_t *ad, int nqueries,
if ((rc = adutils_lookup_batch_start(ad, nqueries,
idmap_ldap_res_search_cb, new_state, &new_state->qs))
!= ADUTILS_SUCCESS) {
- free(new_state);
+ idmap_lookup_release_batch(&new_state);
return (map_adrc2idmaprc(rc));
}
+ new_state->default_domain = strdup(default_domain);
+ if (new_state->default_domain == NULL) {
+ idmap_lookup_release_batch(&new_state);
+ return (IDMAP_ERR_MEMORY);
+ }
+
+ new_state->directory_based_mapping = directory_based_mapping;
new_state->qsize = nqueries;
*state = new_state;
return (IDMAP_SUCCESS);
@@ -227,12 +242,24 @@ idmap_lookup_batch_set_unixattr(idmap_query_state_t *state,
* it is the result that was desired and, if so, set the result fields
* of the given idmap_q_t.
*
- * Frees the unused char * values.
+ * Except for dn and attr, all strings are consumed, either by transferring
+ * them over into the request results (where the caller will eventually free
+ * them) or by freeing them here. Note that this aligns with the "const"
+ * declarations below.
*/
static
void
-idmap_setqresults(idmap_q_t *q, char *san, char *dn, const char *attr,
- char *sid, rid_t rid, int sid_type, char *unixname)
+idmap_setqresults(
+ idmap_q_t *q,
+ char *san,
+ const char *dn,
+ const char *attr,
+ char *value,
+ char *sid,
+ rid_t rid,
+ int sid_type,
+ char *unixname,
+ posix_id_t pid)
{
char *domain;
int err1;
@@ -263,8 +290,10 @@ idmap_setqresults(idmap_q_t *q, char *san, char *dn, const char *attr,
if (q->attr != NULL && attr != NULL)
*q->attr = strdup(attr);
- if (q->value != NULL && unixname != NULL)
- *q->value = strdup(unixname);
+ if (q->value != NULL && value != NULL) {
+ *q->value = value;
+ value = NULL;
+ }
/* Set results */
if (q->sid) {
@@ -294,6 +323,10 @@ idmap_setqresults(idmap_q_t *q, char *san, char *dn, const char *attr,
san = NULL;
}
+ if (q->pid != NULL && pid != SENTINEL_PID) {
+ *q->pid = pid;
+ }
+
q->ad_rc = ADUTILS_SUCCESS;
out:
@@ -302,6 +335,7 @@ out:
free(sid);
free(domain);
free(unixname);
+ free(value);
}
#define BVAL_CASEEQ(bv, str) \
@@ -323,19 +357,17 @@ idmap_bv_objclass2sidtype(BerValue **bvalues, int *sid_type)
return (0);
/*
- * We iterate over all the values because computer is a
- * sub-class of user.
+ * We consider Computer to be a subclass of User, so we can just
+ * ignore Computer entries and pay attention to the accompanying
+ * User entries.
*/
for (cbval = bvalues; *cbval != NULL; cbval++) {
- if (BVAL_CASEEQ(cbval, "Computer")) {
- *sid_type = _IDMAP_T_COMPUTER;
- break;
- } else if (BVAL_CASEEQ(cbval, "Group")) {
+ if (BVAL_CASEEQ(cbval, "group")) {
*sid_type = _IDMAP_T_GROUP;
break;
- } else if (BVAL_CASEEQ(cbval, "USER")) {
+ } else if (BVAL_CASEEQ(cbval, "user")) {
*sid_type = _IDMAP_T_USER;
- /* Continue looping -- this may be a computer yet */
+ break;
}
/*
* "else if (*sid_type = _IDMAP_T_USER)" then this is a
@@ -354,169 +386,121 @@ void
idmap_extract_object(idmap_query_state_t *state, idmap_q_t *q,
LDAPMessage *res, LDAP *ld)
{
- BerElement *ber = NULL;
BerValue **bvalues;
- char *attr;
- const char *unixuser_attr = NULL;
- const char *unixgroup_attr = NULL;
- char *unixuser = NULL;
- char *unixgroup = NULL;
- char *dn = NULL;
+ const char *attr = NULL;
+ char *value = NULL;
+ char *unix_name = NULL;
+ char *dn;
char *san = NULL;
char *sid = NULL;
rid_t rid = 0;
- int sid_type = _IDMAP_T_UNDEF;
- int has_class, has_san, has_sid;
- int has_unixuser, has_unixgroup;
+ int sid_type;
+ int ok;
+ posix_id_t pid = SENTINEL_PID;
assert(q->rc != NULL);
+ assert(q->domain == NULL || *q->domain == NULL);
if ((dn = ldap_get_dn(ld, res)) == NULL)
return;
- assert(q->domain == NULL || *q->domain == NULL);
-
- /*
- * If the caller has requested unixname then determine the
- * AD attribute name that will have the unixname.
- */
- if (q->unixname != NULL) {
- if (q->eunixtype == _IDMAP_T_USER)
- unixuser_attr = state->ad_unixuser_attr;
- else if (q->eunixtype == _IDMAP_T_GROUP)
- unixgroup_attr = state->ad_unixgroup_attr;
- else if (q->eunixtype == _IDMAP_T_UNDEF) {
- /*
- * This is the case where we don't know
- * before hand whether we need unixuser
- * or unixgroup. This will be determined
- * by the "sid_type" (i.e whether the given
- * winname is user or group). If sid_type
- * turns out to be user we will return
- * unixuser (if found) and if it is a group
- * we will return unixgroup (if found). We
- * lookup for both ad_unixuser_attr and
- * ad_unixgroup_attr and discard one of them
- * after we know the "sidtype". This
- * supports the following type of lookups.
- *
- * Example:
- * $idmap show -c winname:foo
- * In the above example, idmap will
- * return uid if winname is winuser
- * and gid if winname is wingroup.
- */
- unixuser_attr = state->ad_unixuser_attr;
- unixgroup_attr = state->ad_unixgroup_attr;
- }
+ bvalues = ldap_get_values_len(ld, res, OBJCLASS);
+ if (bvalues == NULL) {
+ /*
+ * Didn't find objectclass. Something's wrong with our
+ * AD data.
+ */
+ idmapdlog(LOG_ERR, "%s has no %s", dn, OBJCLASS);
+ goto out;
}
-
- has_class = has_san = has_sid = has_unixuser = has_unixgroup = 0;
- for (attr = ldap_first_attribute(ld, res, &ber); attr != NULL;
- attr = ldap_next_attribute(ld, res, ber)) {
- bvalues = NULL; /* for memory management below */
-
+ ok = idmap_bv_objclass2sidtype(bvalues, &sid_type);
+ ldap_value_free_len(bvalues);
+ if (!ok) {
/*
- * If this is an attribute we are looking for and
- * haven't seen it yet, parse it
+ * Didn't understand objectclass. Something's wrong with our
+ * AD data.
*/
- if (q->sid != NULL && !has_sid &&
- strcasecmp(attr, OBJSID) == 0) {
- bvalues = ldap_get_values_len(ld, res, attr);
- if (bvalues != NULL) {
- sid = adutils_bv_objsid2sidstr(
- bvalues[0], &rid);
- has_sid = (sid != NULL);
- }
- } else if (!has_san && strcasecmp(attr, SAN) == 0) {
+ idmapdlog(LOG_ERR, "%s has unexpected %s", dn, OBJCLASS);
+ goto out;
+ }
+
+ if (state->directory_based_mapping == DIRECTORY_MAPPING_IDMU &&
+ q->pid != NULL) {
+ if (sid_type == _IDMAP_T_USER)
+ attr = UIDNUMBER;
+ else if (sid_type == _IDMAP_T_GROUP)
+ attr = GIDNUMBER;
+ if (attr != NULL) {
bvalues = ldap_get_values_len(ld, res, attr);
if (bvalues != NULL) {
- san = adutils_bv_name2str(bvalues[0]);
- has_san = (san != NULL);
- }
- } else if (!has_class && strcasecmp(attr, OBJCLASS) == 0) {
- bvalues = ldap_get_values_len(ld, res, attr);
- has_class = idmap_bv_objclass2sidtype(bvalues,
- &sid_type);
- if (has_class && q->unixname != NULL &&
- q->eunixtype == _IDMAP_T_UNDEF) {
- /*
- * This is the case where we didn't
- * know whether we wanted unixuser or
- * unixgroup as described above.
- * Now since we know the "sid_type"
- * we discard the unwanted value
- * if it was retrieved before we
- * got here.
- */
- if (sid_type == _IDMAP_T_USER) {
- free(unixgroup);
- unixgroup_attr = unixgroup = NULL;
- } else if (sid_type == _IDMAP_T_GROUP) {
- free(unixuser);
- unixuser_attr = unixuser = NULL;
- } else {
- free(unixuser);
- free(unixgroup);
- unixuser_attr = unixuser = NULL;
- unixgroup_attr = unixgroup = NULL;
+ value = adutils_bv_str(bvalues[0]);
+ if (!adutils_bv_uint(bvalues[0], &pid)) {
+ idmapdlog(LOG_ERR,
+ "%s has Invalid %s value \"%s\"",
+ dn, attr, value);
}
+ ldap_value_free_len(bvalues);
}
- } else if (!has_unixuser && unixuser_attr != NULL &&
- strcasecmp(attr, unixuser_attr) == 0) {
- bvalues = ldap_get_values_len(ld, res, attr);
- if (bvalues != NULL) {
- unixuser = adutils_bv_name2str(bvalues[0]);
- has_unixuser = (unixuser != NULL);
- }
+ }
+ }
+
+ if (state->directory_based_mapping == DIRECTORY_MAPPING_NAME &&
+ q->unixname != NULL) {
+ /*
+ * If the caller has requested unixname then determine the
+ * AD attribute name that will have the unixname, and retrieve
+ * its value.
+ */
+ int unix_type;
+ /*
+ * Determine the target UNIX type.
+ *
+ * If the caller specified one, use that. Otherwise, give the
+ * same type that as we found for the Windows user.
+ */
+ unix_type = q->eunixtype;
+ if (unix_type == _IDMAP_T_UNDEF) {
+ if (sid_type == _IDMAP_T_USER)
+ unix_type = _IDMAP_T_USER;
+ else if (sid_type == _IDMAP_T_GROUP)
+ unix_type = _IDMAP_T_GROUP;
+ }
- } else if (!has_unixgroup && unixgroup_attr != NULL &&
- strcasecmp(attr, unixgroup_attr) == 0) {
+ if (unix_type == _IDMAP_T_USER)
+ attr = state->ad_unixuser_attr;
+ else if (unix_type == _IDMAP_T_GROUP)
+ attr = state->ad_unixgroup_attr;
+
+ if (attr != NULL) {
bvalues = ldap_get_values_len(ld, res, attr);
if (bvalues != NULL) {
- unixgroup = adutils_bv_name2str(bvalues[0]);
- has_unixgroup = (unixgroup != NULL);
+ unix_name = adutils_bv_str(bvalues[0]);
+ ldap_value_free_len(bvalues);
+ value = strdup(unix_name);
}
}
+ }
- if (bvalues != NULL)
- ldap_value_free_len(bvalues);
- ldap_memfree(attr);
-
- if (has_class && has_san &&
- (q->sid == NULL || has_sid) &&
- (unixuser_attr == NULL || has_unixuser) &&
- (unixgroup_attr == NULL || has_unixgroup)) {
- /* Got what we need */
- break;
- }
+ bvalues = ldap_get_values_len(ld, res, SAN);
+ if (bvalues != NULL) {
+ san = adutils_bv_str(bvalues[0]);
+ ldap_value_free_len(bvalues);
}
- if (!has_class) {
- /*
- * Didn't find objectclass. Something's wrong with our
- * AD data.
- */
- free(san);
- free(sid);
- free(unixuser);
- free(unixgroup);
- } else {
- /*
- * Either we got what we needed and came out of the loop
- * early OR we completed the loop in which case we didn't
- * find some attributes that we were looking for. In either
- * case set the result with what we got.
- */
- idmap_setqresults(q, san, dn,
- (unixuser != NULL) ? unixuser_attr : unixgroup_attr,
- sid, rid, sid_type,
- (unixuser != NULL) ? unixuser : unixgroup);
+ if (q->sid != NULL) {
+ bvalues = ldap_get_values_len(ld, res, OBJSID);
+ if (bvalues != NULL) {
+ sid = adutils_bv_objsid2sidstr(bvalues[0], &rid);
+ ldap_value_free_len(bvalues);
+ }
}
- if (ber != NULL)
- ber_free(ber, 0);
+ idmap_setqresults(q, san, dn,
+ attr, value,
+ sid, rid, sid_type,
+ unix_name, pid);
+out:
ldap_memfree(dn);
}
@@ -573,6 +557,7 @@ idmap_lookup_release_batch(idmap_query_state_t **state)
return;
adutils_lookup_batch_release(&(*state)->qs);
idmap_cleanup_batch(*state);
+ free((*state)->default_domain);
free(*state);
*state = NULL;
}
@@ -610,19 +595,13 @@ idmap_batch_add1(idmap_query_state_t *state, const char *filter,
char **dn, char **attr, char **value,
char **canonname, char **dname,
char **sid, rid_t *rid, int *sid_type, char **unixname,
+ posix_id_t *pid,
idmap_retcode *rc)
{
adutils_rc ad_rc;
int qid, i;
idmap_q_t *q;
- static char *attrs[] = {
- SAN,
- OBJSID,
- OBJCLASS,
- NULL, /* placeholder for unixname attr */
- NULL, /* placeholder for unixname attr */
- NULL
- };
+ char *attrs[20]; /* Plenty */
qid = atomic_inc_32_nv(&state->qcount) - 1;
q = &(state->queries[qid]);
@@ -648,18 +627,33 @@ idmap_batch_add1(idmap_query_state_t *state, const char *filter,
q->dn = dn;
q->attr = attr;
q->value = value;
+ q->pid = pid;
+
+ /* Add attributes that are not always needed */
+ i = 0;
+ attrs[i++] = SAN;
+ attrs[i++] = OBJSID;
+ attrs[i++] = OBJCLASS;
- /* Add unixuser/unixgroup attribute names to the attrs list */
if (unixname != NULL) {
- i = 3;
+ /* Add unixuser/unixgroup attribute names to the attrs list */
if (eunixtype != _IDMAP_T_GROUP &&
state->ad_unixuser_attr != NULL)
attrs[i++] = (char *)state->ad_unixuser_attr;
if (eunixtype != _IDMAP_T_USER &&
state->ad_unixgroup_attr != NULL)
- attrs[i] = (char *)state->ad_unixgroup_attr;
+ attrs[i++] = (char *)state->ad_unixgroup_attr;
}
+ if (pid != NULL) {
+ if (eunixtype != _IDMAP_T_GROUP)
+ attrs[i++] = UIDNUMBER;
+ if (eunixtype != _IDMAP_T_USER)
+ attrs[i++] = GIDNUMBER;
+ }
+
+ attrs[i] = NULL;
+
/*
* Provide sane defaults for the results in case we never hear
* back from the DS before closing the connection.
@@ -707,11 +701,11 @@ idmap_name2sid_batch_add1(idmap_query_state_t *state,
const char *name, const char *dname, int eunixtype,
char **dn, char **attr, char **value,
char **canonname, char **sid, rid_t *rid,
- int *sid_type, char **unixname, idmap_retcode *rc)
+ int *sid_type, char **unixname,
+ posix_id_t *pid, idmap_retcode *rc)
{
idmap_retcode retcode;
- int len, samAcctNameLen;
- char *filter = NULL, *s_name;
+ char *filter, *s_name;
char *ecanonname, *edomain; /* expected canonname */
/*
@@ -725,37 +719,16 @@ idmap_name2sid_batch_add1(idmap_query_state_t *state,
* the user/group and whether it is a user or a group.
*/
- /*
- * We need the name and the domain name separately and as
- * name@domain. We also allow the domain to be provided
- * separately.
- */
- samAcctNameLen = strlen(name);
-
if ((ecanonname = strdup(name)) == NULL)
return (IDMAP_ERR_MEMORY);
if (dname == NULL || *dname == '\0') {
- if ((dname = strchr(name, '@')) != NULL) {
- /* 'name' is qualified with a domain name */
- if ((edomain = strdup(dname + 1)) == NULL) {
- free(ecanonname);
- return (IDMAP_ERR_MEMORY);
- }
- *strchr(ecanonname, '@') = '\0';
- } else {
- /* 'name' not qualified and dname not given */
- dname = adutils_lookup_batch_getdefdomain(state->qs);
- assert(dname != NULL);
- if (*dname == '\0') {
- free(ecanonname);
- return (IDMAP_ERR_DOMAIN);
- }
- edomain = strdup(dname);
- if (edomain == NULL) {
- free(ecanonname);
- return (IDMAP_ERR_MEMORY);
- }
+ /* 'name' not qualified and dname not given */
+ dname = state->default_domain;
+ edomain = strdup(dname);
+ if (edomain == NULL) {
+ free(ecanonname);
+ return (IDMAP_ERR_MEMORY);
}
} else {
if ((edomain = strdup(dname)) == NULL) {
@@ -778,21 +751,18 @@ idmap_name2sid_batch_add1(idmap_query_state_t *state,
}
/* Assemble filter */
- len = snprintf(NULL, 0, SANFILTER, samAcctNameLen, s_name) + 1;
- if ((filter = (char *)malloc(len)) == NULL) {
+ (void) asprintf(&filter, SANFILTER, s_name);
+ if (s_name != name)
+ free(s_name);
+ if (filter == NULL) {
free(ecanonname);
free(edomain);
- if (s_name != name)
- free(s_name);
return (IDMAP_ERR_MEMORY);
}
- (void) snprintf(filter, len, SANFILTER, samAcctNameLen, s_name);
- if (s_name != name)
- free(s_name);
retcode = idmap_batch_add1(state, filter, ecanonname, edomain,
eunixtype, dn, attr, value, canonname, NULL, sid, rid, sid_type,
- unixname, rc);
+ unixname, pid, rc);
free(filter);
@@ -804,11 +774,11 @@ idmap_sid2name_batch_add1(idmap_query_state_t *state,
const char *sid, const rid_t *rid, int eunixtype,
char **dn, char **attr, char **value,
char **name, char **dname, int *sid_type,
- char **unixname, idmap_retcode *rc)
+ char **unixname, posix_id_t *pid, idmap_retcode *rc)
{
idmap_retcode retcode;
- int flen, ret;
- char *filter = NULL;
+ int ret;
+ char *filter;
char cbinsid[ADUTILS_MAXHEXBINSID + 1];
/*
@@ -827,13 +797,13 @@ idmap_sid2name_batch_add1(idmap_query_state_t *state,
return (IDMAP_ERR_SID);
/* Assemble filter */
- flen = snprintf(NULL, 0, OBJSIDFILTER, cbinsid) + 1;
- if ((filter = (char *)malloc(flen)) == NULL)
+ (void) asprintf(&filter, OBJSIDFILTER, cbinsid);
+ if (filter == NULL)
return (IDMAP_ERR_MEMORY);
- (void) snprintf(filter, flen, OBJSIDFILTER, cbinsid);
retcode = idmap_batch_add1(state, filter, NULL, NULL, eunixtype,
- dn, attr, value, name, dname, NULL, NULL, sid_type, unixname, rc);
+ dn, attr, value, name, dname, NULL, NULL, sid_type, unixname,
+ pid, rc);
free(filter);
@@ -848,9 +818,8 @@ idmap_unixname2sid_batch_add1(idmap_query_state_t *state,
char **dname, int *sid_type, idmap_retcode *rc)
{
idmap_retcode retcode;
- int len, ulen;
- char *filter = NULL, *s_unixname;
- const char *attrname = NULL;
+ char *filter, *s_unixname;
+ const char *attrname;
/* Get unixuser or unixgroup AD attribute name */
attrname = (is_user) ?
@@ -863,22 +832,17 @@ idmap_unixname2sid_batch_add1(idmap_query_state_t *state,
return (IDMAP_ERR_MEMORY);
/* Assemble filter */
- ulen = strlen(unixname);
- len = snprintf(NULL, 0, "(&(objectclass=%s)(%s=%.*s))",
- is_wuser ? "user" : "group", attrname, ulen, s_unixname) + 1;
- if ((filter = (char *)malloc(len)) == NULL) {
- if (s_unixname != unixname)
- free(s_unixname);
- return (IDMAP_ERR_MEMORY);
- }
- (void) snprintf(filter, len, "(&(objectclass=%s)(%s=%.*s))",
- is_wuser ? "user" : "group", attrname, ulen, s_unixname);
+ (void) asprintf(&filter, "(&(objectclass=%s)(%s=%s))",
+ is_wuser ? "user" : "group", attrname, s_unixname);
if (s_unixname != unixname)
free(s_unixname);
+ if (filter == NULL) {
+ return (IDMAP_ERR_MEMORY);
+ }
retcode = idmap_batch_add1(state, filter, NULL, NULL,
_IDMAP_T_UNDEF, dn, NULL, NULL, name, dname, sid, rid, sid_type,
- NULL, rc);
+ NULL, NULL, rc);
if (retcode == IDMAP_SUCCESS && attr != NULL) {
if ((*attr = strdup(attrname)) == NULL)
@@ -886,12 +850,50 @@ idmap_unixname2sid_batch_add1(idmap_query_state_t *state,
}
if (retcode == IDMAP_SUCCESS && value != NULL) {
- if (ulen > 0) {
- if ((*value = strdup(unixname)) == NULL)
- retcode = IDMAP_ERR_MEMORY;
- }
- else
- *value = NULL;
+ if ((*value = strdup(unixname)) == NULL)
+ retcode = IDMAP_ERR_MEMORY;
+ }
+
+ free(filter);
+
+ return (retcode);
+}
+
+idmap_retcode
+idmap_pid2sid_batch_add1(idmap_query_state_t *state,
+ posix_id_t pid, int is_user,
+ char **dn, char **attr, char **value,
+ char **sid, rid_t *rid, char **name,
+ char **dname, int *sid_type, idmap_retcode *rc)
+{
+ idmap_retcode retcode;
+ char *filter;
+ const char *attrname;
+
+ /* Assemble filter */
+ if (is_user) {
+ (void) asprintf(&filter, UIDNUMBERFILTER, pid);
+ attrname = UIDNUMBER;
+ } else {
+ (void) asprintf(&filter, GIDNUMBERFILTER, pid);
+ attrname = GIDNUMBER;
+ }
+ if (filter == NULL)
+ return (IDMAP_ERR_MEMORY);
+
+ retcode = idmap_batch_add1(state, filter, NULL, NULL,
+ _IDMAP_T_UNDEF, dn, NULL, NULL, name, dname, sid, rid, sid_type,
+ NULL, NULL, rc);
+
+ if (retcode == IDMAP_SUCCESS && attr != NULL) {
+ if ((*attr = strdup(attrname)) == NULL)
+ retcode = IDMAP_ERR_MEMORY;
+ }
+
+ if (retcode == IDMAP_SUCCESS && value != NULL) {
+ (void) asprintf(value, "%u", pid);
+ if (*value == NULL)
+ retcode = IDMAP_ERR_MEMORY;
}
free(filter);
diff --git a/usr/src/cmd/idmap/idmapd/adutils.h b/usr/src/cmd/idmap/idmapd/adutils.h
index a6195bf035..88807f01d8 100644
--- a/usr/src/cmd/idmap/idmapd/adutils.h
+++ b/usr/src/cmd/idmap/idmapd/adutils.h
@@ -65,9 +65,9 @@ extern "C" {
#define _IDMAP_T_USER -1004
#define _IDMAP_T_GROUP -1005
#define _IDMAP_T_DOMAIN -1006
-#define _IDMAP_T_COMPUTER -1007
typedef uint32_t rid_t;
+typedef uid_t posix_id_t;
typedef struct idmap_query_state idmap_query_state_t;
@@ -95,7 +95,8 @@ int idmap_add_ds(adutils_ad_t *ad, const char *host, int port);
/* Start a batch of lookups */
idmap_retcode idmap_lookup_batch_start(adutils_ad_t *ad, int nqueries,
- idmap_query_state_t **state);
+ int directory_based_mapping, const char *default_domain,
+ idmap_query_state_t **state);
/* End a batch and release its idmap_query_state_t object */
idmap_retcode idmap_lookup_batch_end(idmap_query_state_t **state);
@@ -120,7 +121,7 @@ idmap_retcode idmap_name2sid_batch_add1(idmap_query_state_t *state,
const char *name, const char *dname, int eunixtype,
char **dn, char **attr, char **value, char **canonname,
char **sid, rid_t *rid, int *sid_type, char **unixname,
- idmap_retcode *rc);
+ posix_id_t *pid, idmap_retcode *rc);
/*
* Add a SID->name lookup
*
@@ -139,7 +140,7 @@ idmap_retcode idmap_sid2name_batch_add1(idmap_query_state_t *state,
const char *sid, const rid_t *rid, int eunixtype,
char **dn, char **attr, char **value, char **name,
char **dname, int *sid_type, char **unixname,
- idmap_retcode *rc);
+ posix_id_t *pid, idmap_retcode *rc);
/*
* Add a unixname->SID lookup
@@ -150,6 +151,14 @@ idmap_retcode idmap_unixname2sid_batch_add1(idmap_query_state_t *state,
char **name, char **dname, int *sid_type, idmap_retcode *rc);
/*
+ * Add a PID->SID lookup
+ */
+idmap_retcode idmap_pid2sid_batch_add1(idmap_query_state_t *state,
+ posix_id_t pid, int is_user,
+ char **dn, char **attr, char **value, char **sid, rid_t *rid,
+ char **name, char **dname, int *sid_type, idmap_retcode *rc);
+
+/*
* Set unixname attribute names for the batch for AD-based name mapping
*/
void idmap_lookup_batch_set_unixattr(idmap_query_state_t *state,
diff --git a/usr/src/cmd/idmap/idmapd/dbutils.c b/usr/src/cmd/idmap/idmapd/dbutils.c
index 651a364b5d..6b2c3d3723 100644
--- a/usr/src/cmd/idmap/idmapd/dbutils.c
+++ b/usr/src/cmd/idmap/idmapd/dbutils.c
@@ -102,7 +102,12 @@ typedef struct idmap_tsd {
struct idmap_busy db_busy;
} idmap_tsd_t;
-
+/*
+ * Flags to indicate how local the directory we're consulting is.
+ * If neither is set, it means the directory belongs to a remote forest.
+ */
+#define DOMAIN_IS_LOCAL 0x01
+#define FOREST_IS_LOCAL 0x02
static const int cache_delay_table[] =
{ 1, 2, 5, 10, 15, 20, 25, 30, 35, 40,
@@ -1051,13 +1056,13 @@ sql_compile_n_step_once(sqlite *db, char *sql, sqlite_vm **vm, int *ncol,
* requests.
*
* sid2uid/uid2sid:
- * none -> ds_name_mapping_enabled != true
+ * none -> directory_based_mapping != DIRECTORY_MAPPING_NAME
* AD-mode -> !nldap_winname_attr && ad_unixuser_attr
* nldap-mode -> nldap_winname_attr && !ad_unixuser_attr
* mixed-mode -> nldap_winname_attr && ad_unixuser_attr
*
* sid2gid/gid2sid:
- * none -> ds_name_mapping_enabled != true
+ * none -> directory_based_mapping != DIRECTORY_MAPPING_NAME
* AD-mode -> !nldap_winname_attr && ad_unixgroup_attr
* nldap-mode -> nldap_winname_attr && !ad_unixgroup_attr
* mixed-mode -> nldap_winname_attr && ad_unixgroup_attr
@@ -1073,6 +1078,9 @@ load_cfg_in_state(lookup_state_t *state)
if (_idmapdstate.cfg->pgcfg.eph_map_unres_sids)
state->eph_map_unres_sids = 1;
+ state->directory_based_mapping =
+ _idmapdstate.cfg->pgcfg.directory_based_mapping;
+
if (_idmapdstate.cfg->pgcfg.default_domain != NULL) {
state->defdom =
strdup(_idmapdstate.cfg->pgcfg.default_domain);
@@ -1084,10 +1092,13 @@ load_cfg_in_state(lookup_state_t *state)
UNLOCK_CONFIG();
return (IDMAP_SUCCESS);
}
- if (!_idmapdstate.cfg->pgcfg.ds_name_mapping_enabled) {
+
+ if (_idmapdstate.cfg->pgcfg.directory_based_mapping !=
+ DIRECTORY_MAPPING_NAME) {
UNLOCK_CONFIG();
return (IDMAP_SUCCESS);
}
+
if (_idmapdstate.cfg->pgcfg.nldap_winname_attr != NULL) {
state->nm_siduid =
(_idmapdstate.cfg->pgcfg.ad_unixuser_attr != NULL)
@@ -1649,8 +1660,17 @@ out:
case IDMAP_MAP_TYPE_KNOWN_SID:
break;
+ case IDMAP_MAP_TYPE_IDMU:
+ res->info.how.idmap_how_u.idmu.dn =
+ strdup(values[7]);
+ res->info.how.idmap_how_u.idmu.attr =
+ strdup(values[8]);
+ res->info.how.idmap_how_u.idmu.value =
+ strdup(values[9]);
+ break;
+
default:
- /* Unknow mapping type */
+ /* Unknown mapping type */
assert(FALSE);
}
}
@@ -1804,10 +1824,11 @@ lookup_name_cache(sqlite *cache, idmap_mapping *req, idmap_id_res *res)
static int
ad_lookup_batch_int(lookup_state_t *state, idmap_mapping_batch *batch,
- idmap_ids_res *result, int index, int *num_processed)
+ idmap_ids_res *result, adutils_ad_t *dir, int how_local,
+ int *num_processed)
{
idmap_retcode retcode;
- int i, num_queued, type, is_wuser, is_user;
+ int i, num_queued, is_wuser, is_user;
int next_request;
int retries = 0, eunixtype;
char **unixname;
@@ -1829,10 +1850,17 @@ ad_lookup_batch_int(lookup_state_t *state, idmap_mapping_batch *batch,
* call. But why un-necessarily allocate memory. That may
* be an option if req->id2.idtype cannot be re-used in
* future.
+ *
+ * Similarly, we use req->id2.idmap_id_u.uid to return uidNumber
+ * or gidNumber supplied by IDMU, and reset it back to SENTINEL_PID
+ * when we're done. Note that the query always puts the result in
+ * req->id2.idmap_id_u.uid, not .gid.
*/
retry:
- retcode = idmap_lookup_batch_start(_idmapdstate.ads[index],
- state->ad_nqueries, &qs);
+ retcode = idmap_lookup_batch_start(dir, state->ad_nqueries,
+ state->directory_based_mapping,
+ state->defdom,
+ &qs);
if (retcode != IDMAP_SUCCESS) {
if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR &&
retries++ < ADUTILS_DEF_NUM_RETRIES)
@@ -1844,10 +1872,10 @@ retry:
restore_svc();
- if (index == 0) {
+ if (how_local & FOREST_IS_LOCAL) {
/*
* Directory based name mapping is only performed within the
- * joined forest (index == 0). We don't trust other "trusted"
+ * joined forest. We don't trust other "trusted"
* forests to provide DS-based name mapping information because
* AD's definition of "cross-forest trust" does not encompass
* this sort of behavior.
@@ -1863,12 +1891,17 @@ retry:
retcode = IDMAP_SUCCESS;
req->id2.idtype = IDMAP_NONE;
+ req->id2.idmap_id_u.uid = SENTINEL_PID;
- /* Skip if not marked for this AD lookup */
- if (!(req->direction & _IDMAP_F_LOOKUP_AD) ||
- (req->direction & _IDMAP_F_LOOKUP_OTHER_AD))
+ /* Skip if no AD lookup required */
+ if (!(req->direction & _IDMAP_F_LOOKUP_AD))
+ continue;
+
+ /* Skip if we've already tried and gotten a "not found" */
+ if (req->direction & _IDMAP_F_LOOKUP_OTHER_AD)
continue;
+ /* Skip if we've already either succeeded or failed */
if (res->retcode != IDMAP_ERR_RETRIABLE_NET_ERR)
continue;
@@ -1876,9 +1909,12 @@ retry:
/* win2unix request: */
+ posix_id_t *pid = NULL;
unixname = dn = attr = value = NULL;
eunixtype = _IDMAP_T_UNDEF;
- if (req->id2name == NULL) {
+ if (state->directory_based_mapping ==
+ DIRECTORY_MAPPING_NAME &&
+ req->id2name == NULL) {
if (res->id.idtype == IDMAP_UID &&
AD_OR_MIXED(state->nm_siduid)) {
eunixtype = _IDMAP_T_USER;
@@ -1891,21 +1927,39 @@ retry:
AD_OR_MIXED(state->nm_sidgid)) {
unixname = &req->id2name;
}
- }
- if (unixname != NULL) {
+ if (unixname != NULL) {
+ /*
+ * Get how info for DS-based name
+ * mapping only if AD or MIXED
+ * mode is enabled.
+ */
+ idmap_info_free(&res->info);
+ res->info.src = IDMAP_MAP_SRC_NEW;
+ how->map_type = IDMAP_MAP_TYPE_DS_AD;
+ dn = &how->idmap_how_u.ad.dn;
+ attr = &how->idmap_how_u.ad.attr;
+ value = &how->idmap_how_u.ad.value;
+ }
+ } else if (state->directory_based_mapping ==
+ DIRECTORY_MAPPING_IDMU &&
+ (how_local & DOMAIN_IS_LOCAL)) {
/*
- * Get how info for DS-based name
- * mapping only if AD or MIXED
- * mode is enabled.
+ * Ensure that we only do IDMU processing
+ * when querying the domain we've joined.
+ */
+ pid = &req->id2.idmap_id_u.uid;
+ /*
+ * Get how info for IDMU based mapping.
*/
idmap_info_free(&res->info);
res->info.src = IDMAP_MAP_SRC_NEW;
- how->map_type = IDMAP_MAP_TYPE_DS_AD;
- dn = &how->idmap_how_u.ad.dn;
- attr = &how->idmap_how_u.ad.attr;
- value = &how->idmap_how_u.ad.value;
+ how->map_type = IDMAP_MAP_TYPE_IDMU;
+ dn = &how->idmap_how_u.idmu.dn;
+ attr = &how->idmap_how_u.idmu.attr;
+ value = &how->idmap_how_u.idmu.value;
}
+
if (req->id1.idmap_id_u.sid.prefix != NULL) {
/* Lookup AD by SID */
retcode = idmap_sid2name_batch_add1(
@@ -1917,6 +1971,7 @@ retry:
(req->id1domain == NULL) ?
&req->id1domain : NULL,
(int *)&req->id2.idtype, unixname,
+ pid,
&res->retcode);
if (retcode == IDMAP_SUCCESS)
num_queued++;
@@ -1931,6 +1986,7 @@ retry:
&req->id1.idmap_id_u.sid.prefix,
&req->id1.idmap_id_u.sid.rid,
(int *)&req->id2.idtype, unixname,
+ pid,
&res->retcode);
if (retcode == IDMAP_SUCCESS)
num_queued++;
@@ -1963,7 +2019,7 @@ retry:
NULL, NULL, NULL,
&req->id2name,
&req->id2domain, (int *)&req->id2.idtype,
- NULL, &res->retcode);
+ NULL, NULL, &res->retcode);
if (retcode == IDMAP_SUCCESS)
num_queued++;
} else if (req->id2name != NULL) {
@@ -1981,9 +2037,40 @@ retry:
&res->id.idmap_id_u.sid.prefix,
&res->id.idmap_id_u.sid.rid,
(int *)&req->id2.idtype, NULL,
+ NULL,
&res->retcode);
if (retcode == IDMAP_SUCCESS)
num_queued++;
+ } else if (state->directory_based_mapping ==
+ DIRECTORY_MAPPING_IDMU &&
+ (how_local & DOMAIN_IS_LOCAL)) {
+ assert(req->id1.idmap_id_u.uid != SENTINEL_PID);
+ is_user = IS_REQUEST_UID(*req);
+ if (res->id.idtype == IDMAP_USID)
+ is_wuser = 1;
+ else if (res->id.idtype == IDMAP_GSID)
+ is_wuser = 0;
+ else
+ is_wuser = is_user;
+
+ /* IDMU can't do diagonal mappings */
+ if (is_user != is_wuser)
+ continue;
+
+ idmap_info_free(&res->info);
+ res->info.src = IDMAP_MAP_SRC_NEW;
+ how->map_type = IDMAP_MAP_TYPE_IDMU;
+ retcode = idmap_pid2sid_batch_add1(
+ qs, req->id1.idmap_id_u.uid, is_user,
+ &how->idmap_how_u.ad.dn,
+ &how->idmap_how_u.ad.attr,
+ &how->idmap_how_u.ad.value,
+ &res->id.idmap_id_u.sid.prefix,
+ &res->id.idmap_id_u.sid.rid,
+ &req->id2name, &req->id2domain,
+ (int *)&req->id2.idtype, &res->retcode);
+ if (retcode == IDMAP_SUCCESS)
+ num_queued++;
} else if (req->id1name != NULL) {
/*
* No SID and no winname but we've unixname.
@@ -2018,9 +2105,6 @@ retry:
req->direction |= _IDMAP_F_LOOKUP_OTHER_AD;
retcode = IDMAP_SUCCESS;
} else if (retcode != IDMAP_SUCCESS) {
- idmap_lookup_release_batch(&qs);
- num_queued = 0;
- next_request = i + 1;
break;
}
} /* End of for loop */
@@ -2031,6 +2115,10 @@ retry:
retcode = idmap_lookup_batch_end(&qs);
else
idmap_lookup_release_batch(&qs);
+ } else {
+ idmap_lookup_release_batch(&qs);
+ num_queued = 0;
+ next_request = i + 1;
}
if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR &&
@@ -2063,15 +2151,31 @@ out:
* and update the idtype in request.
*/
for (i = 0; i < batch->idmap_mapping_batch_len; i++) {
+ int type;
+ uid_t posix_id;
+
req = &batch->idmap_mapping_batch_val[i];
type = req->id2.idtype;
req->id2.idtype = IDMAP_NONE;
+ posix_id = req->id2.idmap_id_u.uid;
+ req->id2.idmap_id_u.uid = SENTINEL_PID;
res = &result->ids.ids_val[i];
- how = &res->info.how;
- if (!(req->direction & _IDMAP_F_LOOKUP_AD) ||
- (req->direction & _IDMAP_F_LOOKUP_OTHER_AD))
+
+ /*
+ * If it didn't need AD lookup, ignore it.
+ */
+ if (!(req->direction & _IDMAP_F_LOOKUP_AD))
continue;
+ /*
+ * If we deferred it this time, reset for the next
+ * AD server.
+ */
+ if (req->direction & _IDMAP_F_LOOKUP_OTHER_AD) {
+ req->direction &= ~_IDMAP_F_LOOKUP_OTHER_AD;
+ continue;
+ }
+
/* Count number processed */
(*num_processed)++;
@@ -2101,12 +2205,38 @@ out:
case _IDMAP_T_USER:
if (res->id.idtype == IDMAP_POSIXID)
res->id.idtype = IDMAP_UID;
+ /*
+ * We found a user. If we got information
+ * from IDMU and we were expecting a user,
+ * copy the id.
+ */
+ if (posix_id != SENTINEL_PID &&
+ res->id.idtype == IDMAP_UID) {
+ res->id.idmap_id_u.uid = posix_id;
+ res->direction = IDMAP_DIRECTION_BI;
+ res->info.how.map_type =
+ IDMAP_MAP_TYPE_IDMU;
+ res->info.src = IDMAP_MAP_SRC_NEW;
+ }
req->id1.idtype = IDMAP_USID;
break;
case _IDMAP_T_GROUP:
if (res->id.idtype == IDMAP_POSIXID)
res->id.idtype = IDMAP_GID;
+ /*
+ * We found a group. If we got information
+ * from IDMU and we were expecting a group,
+ * copy the id.
+ */
+ if (posix_id != SENTINEL_PID &&
+ res->id.idtype == IDMAP_GID) {
+ res->id.idmap_id_u.gid = posix_id;
+ res->direction = IDMAP_DIRECTION_BI;
+ res->info.how.map_type =
+ IDMAP_MAP_TYPE_IDMU;
+ res->info.src = IDMAP_MAP_SRC_NEW;
+ }
req->id1.idtype = IDMAP_GSID;
break;
@@ -2126,10 +2256,9 @@ out:
if (res->retcode != IDMAP_SUCCESS) {
if ((!(IDMAP_FATAL_ERROR(res->retcode))) &&
res->id.idmap_id_u.sid.prefix == NULL &&
- req->id2name == NULL && /* no winname */
- req->id1name != NULL) /* unixname */
+ req->id2name == NULL) /* no winname */
/*
- * If AD lookup by unixname
+ * If AD lookup by unixname or pid
* failed with non fatal error
* then clear the error (ie set
* res->retcode to success).
@@ -2196,42 +2325,8 @@ ad_lookup_batch(lookup_state_t *state, idmap_mapping_batch *batch,
RDLOCK_CONFIG();
num_queries = state->ad_nqueries;
- if (_idmapdstate.num_ads > 0) {
- for (i = 0; i < _idmapdstate.num_ads && num_queries > 0; i++) {
-
- retcode = ad_lookup_batch_int(state, batch, result, i,
- &num_processed);
- num_queries -= num_processed;
- if (num_queries > 0) {
- for (j = 0; j < batch->idmap_mapping_batch_len;
- j++) {
- req =
- &batch->idmap_mapping_batch_val[j];
- res = &result->ids.ids_val[j];
- if (!(req->direction &
- _IDMAP_F_LOOKUP_AD))
- continue;
- /*
- * Reset the other AD lookup flag so
- * that we can try the next AD
- */
- req->direction &=
- ~(_IDMAP_F_LOOKUP_OTHER_AD);
-
- if ((i + 1) >= _idmapdstate.num_ads) {
- /*
- * There are no more ADs to try
- */
- req->direction &=
- ~(_IDMAP_F_LOOKUP_AD);
- res->retcode =
- IDMAP_ERR_DOMAIN_NOTFOUND;
- }
- }
- }
- }
- } else {
+ if (_idmapdstate.num_gcs == 0 && _idmapdstate.num_dcs == 0) {
/* Case of no ADs */
retcode = IDMAP_ERR_NO_ACTIVEDIRECTORY;
for (i = 0; i < batch->idmap_mapping_batch_len; i++) {
@@ -2242,7 +2337,47 @@ ad_lookup_batch(lookup_state_t *state, idmap_mapping_batch *batch,
req->direction &= ~(_IDMAP_F_LOOKUP_AD);
res->retcode = IDMAP_ERR_NO_ACTIVEDIRECTORY;
}
+ goto out;
}
+
+ if (state->directory_based_mapping == DIRECTORY_MAPPING_IDMU) {
+ for (i = 0; i < _idmapdstate.num_dcs && num_queries > 0; i++) {
+
+ retcode = ad_lookup_batch_int(state, batch,
+ result, _idmapdstate.dcs[i],
+ i == 0 ? DOMAIN_IS_LOCAL|FOREST_IS_LOCAL : 0,
+ &num_processed);
+ num_queries -= num_processed;
+
+ }
+ }
+
+ for (i = 0; i < _idmapdstate.num_gcs && num_queries > 0; i++) {
+
+ retcode = ad_lookup_batch_int(state, batch, result,
+ _idmapdstate.gcs[i],
+ i == 0 ? FOREST_IS_LOCAL : 0,
+ &num_processed);
+ num_queries -= num_processed;
+
+ }
+
+ /*
+ * There are no more ADs to try. Return errors for any
+ * remaining requests.
+ */
+ if (num_queries > 0) {
+ for (j = 0; j < batch->idmap_mapping_batch_len; j++) {
+ req = &batch->idmap_mapping_batch_val[j];
+ res = &result->ids.ids_val[j];
+ if (!(req->direction & _IDMAP_F_LOOKUP_AD))
+ continue;
+ req->direction &= ~(_IDMAP_F_LOOKUP_AD);
+ res->retcode = IDMAP_ERR_DOMAIN_NOTFOUND;
+ }
+ }
+
+out:
UNLOCK_CONFIG();
/* AD lookups done. Reset state->ad_nqueries and return */
@@ -2300,8 +2435,10 @@ ad_lookup_batch(lookup_state_t *state, idmap_mapping_batch *batch,
* sid_type obtained by the batched AD lookups and after
* use resets it to IDMAP_NONE to prevent xdr from
* mis-interpreting the contents of req->id2.
- * req->id2..[uid or gid or sid] =
- * NOT USED
+ * req->id2.idmap_id_u.uid =
+ * INTERNAL USE. If the AD lookup finds IDMU data
+ * (uidNumber or gidNumber, depending on the type of
+ * the entry), it's left here.
*/
/*
@@ -2394,7 +2531,9 @@ sid2pid_first_pass(lookup_state_t *state, idmap_mapping *req,
*/
if (retcode != IDMAP_SUCCESS ||
(!wksid && req->id2name == NULL &&
- AD_OR_MIXED_MODE(res->id.idtype, state))) {
+ AD_OR_MIXED_MODE(res->id.idtype, state)) ||
+ (!wksid && res->id.idmap_id_u.uid == SENTINEL_PID &&
+ state->directory_based_mapping == DIRECTORY_MAPPING_IDMU)) {
retcode = IDMAP_SUCCESS;
req->direction |= _IDMAP_F_LOOKUP_AD;
state->ad_nqueries++;
@@ -3063,6 +3202,28 @@ sid2pid_second_pass(lookup_state_t *state,
goto out;
/*
+ * There are two ways we might get here with a Posix ID:
+ * - It could be from an expired ephemeral cache entry.
+ * - It could be from IDMU.
+ * If it's from IDMU, we need to look up the name, for name-based
+ * requests and the cache.
+ */
+ if (!IS_EPHEMERAL(res->id.idmap_id_u.uid) &&
+ res->id.idmap_id_u.uid != SENTINEL_PID) {
+ if (req->id2name == NULL) {
+ /*
+ * If the lookup fails, go ahead anyway.
+ * The general UNIX rule is that it's OK to
+ * have a UID or GID that isn't in the
+ * name service.
+ */
+ (void) ns_lookup_bypid(res->id.idmap_id_u.uid,
+ res->id.idtype == IDMAP_UID, &req->id2name);
+ }
+ goto out;
+ }
+
+ /*
* If directory-based name mapping is enabled then the unixname
* may already have been retrieved from the AD object (AD-mode or
* mixed-mode) or from native LDAP object (nldap-mode) -- done.
@@ -3197,6 +3358,24 @@ update_cache_pid2sid(lookup_state_t *state,
assert(req->id1.idmap_id_u.uid != SENTINEL_PID);
assert(res->id.idtype != IDMAP_SID);
+ /*
+ * If we've gotten to this point and we *still* don't know the
+ * unixname, well, we'd like to have it now for the cache.
+ *
+ * If we truly always need it for the cache, we should probably
+ * look it up once at the beginning, rather than "at need" in
+ * several places as is now done. However, it's not really clear
+ * that we *do* need it in the cache; there's a decent argument
+ * that the cache should contain only SIDs and PIDs, so we'll
+ * leave our options open by doing it "at need" here too.
+ *
+ * If we can't find it... c'est la vie.
+ */
+ if (req->id1name == NULL) {
+ (void) ns_lookup_bypid(req->id1.idmap_id_u.uid,
+ req->id1.idtype == IDMAP_UID, &req->id1name);
+ }
+
assert(res->info.how.map_type != IDMAP_MAP_TYPE_UNKNOWN);
switch (res->info.how.map_type) {
case IDMAP_MAP_TYPE_DS_AD:
@@ -3224,6 +3403,12 @@ update_cache_pid2sid(lookup_state_t *state,
case IDMAP_MAP_TYPE_LOCAL_SID:
break;
+ case IDMAP_MAP_TYPE_IDMU:
+ map_dn = res->info.how.idmap_how_u.idmu.dn;
+ map_attr = res->info.how.idmap_how_u.idmu.attr;
+ map_value = res->info.how.idmap_how_u.idmu.value;
+ break;
+
default:
/* Dont cache other mapping types */
assert(FALSE);
@@ -3371,6 +3556,12 @@ update_cache_sid2pid(lookup_state_t *state,
case IDMAP_MAP_TYPE_EPHEMERAL:
break;
+ case IDMAP_MAP_TYPE_IDMU:
+ map_dn = res->info.how.idmap_how_u.idmu.dn;
+ map_attr = res->info.how.idmap_how_u.idmu.attr;
+ map_value = res->info.how.idmap_how_u.idmu.value;
+ break;
+
default:
/* Dont cache other mapping types */
assert(FALSE);
@@ -3610,8 +3801,17 @@ lookup_cache_pid2sid(sqlite *cache, idmap_mapping *req, idmap_id_res *res,
case IDMAP_MAP_TYPE_KNOWN_SID:
break;
+ case IDMAP_MAP_TYPE_IDMU:
+ res->info.how.idmap_how_u.idmu.dn =
+ strdup(values[7]);
+ res->info.how.idmap_how_u.idmu.attr =
+ strdup(values[8]);
+ res->info.how.idmap_how_u.idmu.value =
+ strdup(values[9]);
+ break;
+
default:
- /* Unknow mapping type */
+ /* Unknown mapping type */
assert(FALSE);
}
}
@@ -3748,12 +3948,16 @@ ad_lookup_by_winname(lookup_state_t *state,
int found_ad = 0;
RDLOCK_CONFIG();
- if (_idmapdstate.num_ads > 0) {
- for (i = 0; i < _idmapdstate.num_ads && !found_ad; i++) {
+ if (_idmapdstate.num_gcs > 0) {
+ for (i = 0; i < _idmapdstate.num_gcs && !found_ad; i++) {
retries = 0;
retry:
- retcode = idmap_lookup_batch_start(_idmapdstate.ads[i],
- 1, &qs);
+ retcode = idmap_lookup_batch_start(
+ _idmapdstate.gcs[i],
+ 1,
+ _idmapdstate.cfg->pgcfg.directory_based_mapping,
+ _idmapdstate.cfg->pgcfg.default_domain,
+ &qs);
if (retcode != IDMAP_SUCCESS) {
if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR &&
retries++ < ADUTILS_DEF_NUM_RETRIES)
@@ -3782,7 +3986,7 @@ retry:
retcode = idmap_name2sid_batch_add1(qs, name, domain,
eunixtype, dn, attr, value, canonname, sidprefix,
- rid, wintype, unixname, &rc);
+ rid, wintype, unixname, NULL, &rc);
if (retcode == IDMAP_ERR_DOMAIN_NOTFOUND) {
idmap_lookup_release_batch(&qs);
continue;
@@ -4225,7 +4429,10 @@ pid2sid_first_pass(lookup_state_t *state, idmap_mapping *req,
}
/* Set flags for the next stage */
- if (AD_MODE(req->id1.idtype, state)) {
+ if (state->directory_based_mapping == DIRECTORY_MAPPING_IDMU) {
+ req->direction |= _IDMAP_F_LOOKUP_AD;
+ state->ad_nqueries++;
+ } else if (AD_MODE(req->id1.idtype, state)) {
/*
* If AD-based name mapping is enabled then the next stage
* will need to lookup AD using unixname to get the
@@ -4300,7 +4507,9 @@ pid2sid_second_pass(lookup_state_t *state, idmap_mapping *req,
retcode = IDMAP_ERR_NOTFOUND;
goto out;
}
- if (AD_MODE(req->id1.idtype, state))
+ if (state->directory_based_mapping == DIRECTORY_MAPPING_IDMU)
+ res->direction = IDMAP_DIRECTION_BI;
+ else if (AD_MODE(req->id1.idtype, state))
res->direction = IDMAP_DIRECTION_BI;
else if (NLDAP_MODE(req->id1.idtype, state))
res->direction = IDMAP_DIRECTION_BI;
diff --git a/usr/src/cmd/idmap/idmapd/directory_provider_ad.c b/usr/src/cmd/idmap/idmapd/directory_provider_ad.c
index 2626c26ce6..7f45574019 100644
--- a/usr/src/cmd/idmap/idmapd/directory_provider_ad.c
+++ b/usr/src/cmd/idmap/idmapd/directory_provider_ad.c
@@ -146,7 +146,7 @@ directory_provider_ad_get(
/*
* If we don't have any AD servers handy, we can't find anything.
*/
- if (_idmapdstate.num_ads < 1) {
+ if (_idmapdstate.num_gcs < 1) {
return (NULL);
}
@@ -295,7 +295,7 @@ directory_provider_ad_lookup(
* NEEDSWORK: Should eventually handle other forests.
* NEEDSWORK: Should eventually handle non-GC attributes.
*/
- ad = _idmapdstate.ads[0];
+ ad = _idmapdstate.gcs[0];
/* Stash away information for the callback function. */
cbinfo.attrs = attrs;
diff --git a/usr/src/cmd/idmap/idmapd/idmap_config.c b/usr/src/cmd/idmap/idmapd/idmap_config.c
index 493802af5b..e11d0f8d47 100644
--- a/usr/src/cmd/idmap/idmapd/idmap_config.c
+++ b/usr/src/cmd/idmap/idmapd/idmap_config.c
@@ -58,6 +58,13 @@ static pthread_t update_thread_handle = 0;
static int idmapd_ev_port = -1;
static int rt_sock = -1;
+struct enum_lookup_map directory_mapping_map[] = {
+ { DIRECTORY_MAPPING_NONE, "none" },
+ { DIRECTORY_MAPPING_NAME, "name" },
+ { DIRECTORY_MAPPING_IDMU, "idmu" },
+ { 0, NULL },
+};
+
static int
generate_machine_sid(char **machine_sid)
{
@@ -71,7 +78,7 @@ generate_machine_sid(char **machine_sid)
* machine_sid will be of the form S-1-5-21-N1-N2-N3 (that's
* four RIDs altogether).
*
- * Technically we could use upto 14 random RIDs here, but it
+ * Technically we could use up to 14 random RIDs here, but it
* turns out that with some versions of Windows using SIDs with
* more than five RIDs in security descriptors causes problems.
*/
@@ -107,7 +114,7 @@ generate_machine_sid(char **machine_sid)
/* In the case of error, exists is set to FALSE anyway */
static int
-prop_exists(idmap_cfg_handles_t *handles, char *name, boolean_t *exists)
+prop_exists(idmap_cfg_handles_t *handles, const char *name, boolean_t *exists)
{
scf_property_t *scf_prop;
@@ -140,17 +147,18 @@ prop_exists(idmap_cfg_handles_t *handles, char *name, boolean_t *exists)
/* Check if in the case of failure the original value of *val is preserved */
static int
-get_val_int(idmap_cfg_handles_t *handles, char *name,
+get_val_int(idmap_cfg_handles_t *handles, const char *name,
void *val, scf_type_t type)
{
int rc = 0;
scf_property_t *scf_prop;
scf_value_t *value;
+ uint8_t b;
switch (type) {
case SCF_TYPE_BOOLEAN:
- *(uint8_t *)val = 0;
+ *(boolean_t *)val = B_FALSE;
break;
case SCF_TYPE_COUNT:
*(uint64_t *)val = 0;
@@ -189,7 +197,8 @@ get_val_int(idmap_cfg_handles_t *handles, char *name,
switch (type) {
case SCF_TYPE_BOOLEAN:
- rc = scf_value_get_boolean(value, val);
+ rc = scf_value_get_boolean(value, &b);
+ *(boolean_t *)val = b;
break;
case SCF_TYPE_COUNT:
rc = scf_value_get_count(value, val);
@@ -197,8 +206,15 @@ get_val_int(idmap_cfg_handles_t *handles, char *name,
case SCF_TYPE_INTEGER:
rc = scf_value_get_integer(value, val);
break;
+ default:
+ abort(); /* tested above */
+ /* NOTREACHED */
}
+ if (rc != 0) {
+ idmapdlog(LOG_ERR, "Can not retrieve config/%s: %s",
+ name, scf_strerror(scf_error()));
+ }
destruction:
scf_value_destroy(value);
@@ -208,43 +224,25 @@ destruction:
}
static char *
-scf_value2string(scf_value_t *value)
+scf_value2string(const char *name, scf_value_t *value)
{
- int rc = -1;
- char buf_size = 127;
- int length;
- char *buf = NULL;
- buf = (char *) malloc(sizeof (char) * buf_size);
+ static size_t max_val = 0;
- for (;;) {
- length = scf_value_get_astring(value, buf, buf_size);
- if (length < 0) {
- rc = -1;
- goto destruction;
- }
+ if (max_val == 0)
+ max_val = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
- if (length == buf_size - 1) {
- buf_size *= 2;
- buf = (char *)realloc(buf, buf_size * sizeof (char));
- if (!buf) {
- idmapdlog(LOG_ERR, "Out of memory");
- rc = -1;
- goto destruction;
- }
- } else {
- rc = 0;
- break;
- }
+ char buf[max_val + 1];
+ if (scf_value_get_astring(value, buf, max_val + 1) < 0) {
+ idmapdlog(LOG_ERR, "Can not retrieve config/%s: %s",
+ name, scf_strerror(scf_error()));
+ return (NULL);
}
-destruction:
- if (rc < 0) {
- if (buf)
- free(buf);
- buf = NULL;
- }
+ char *s = strdup(buf);
+ if (s == NULL)
+ idmapdlog(LOG_ERR, "Out of memory");
- return (buf);
+ return (s);
}
static int
@@ -327,7 +325,7 @@ restart:
servers[i].priority = 0;
servers[i].weight = 100;
servers[i].port = defport;
- if ((host = scf_value2string(value)) == NULL) {
+ if ((host = scf_value2string(name, value)) == NULL) {
goto destruction;
}
if ((portstr = strchr(host, ':')) != NULL) {
@@ -367,7 +365,7 @@ destruction:
static int
-get_val_astring(idmap_cfg_handles_t *handles, char *name, char **val)
+get_val_astring(idmap_cfg_handles_t *handles, const char *name, char **val)
{
int rc = 0;
@@ -402,7 +400,8 @@ get_val_astring(idmap_cfg_handles_t *handles, char *name, char **val)
goto destruction;
}
- if (!(*val = scf_value2string(value)))
+ *val = scf_value2string(name, value);
+ if (*val == NULL)
rc = -1;
destruction:
@@ -420,7 +419,77 @@ destruction:
static int
-set_val_astring(idmap_cfg_handles_t *handles, char *name, const char *val)
+del_val(idmap_cfg_handles_t *handles, const char *name)
+{
+ int rc = -1;
+ int ret;
+ scf_transaction_t *tx = NULL;
+ scf_transaction_entry_t *ent = NULL;
+
+ if ((tx = scf_transaction_create(handles->main)) == NULL) {
+ idmapdlog(LOG_ERR,
+ "scf_transaction_create() failed: %s",
+ scf_strerror(scf_error()));
+ goto destruction;
+ }
+ if ((ent = scf_entry_create(handles->main)) == NULL) {
+ idmapdlog(LOG_ERR,
+ "scf_entry_create() failed: %s",
+ scf_strerror(scf_error()));
+ goto destruction;
+ }
+
+ do {
+ if (scf_pg_update(handles->config_pg) == -1) {
+ idmapdlog(LOG_ERR,
+ "scf_pg_update(%s) failed: %s",
+ name, scf_strerror(scf_error()));
+ goto destruction;
+ }
+ if (scf_transaction_start(tx, handles->config_pg) != 0) {
+ idmapdlog(LOG_ERR,
+ "scf_transaction_start(%s) failed: %s",
+ name, scf_strerror(scf_error()));
+ goto destruction;
+ }
+
+ if (scf_transaction_property_delete(tx, ent, name) != 0) {
+ /* Don't complain if it already doesn't exist. */
+ if (scf_error() != SCF_ERROR_NOT_FOUND) {
+ idmapdlog(LOG_ERR,
+ "scf_transaction_property_delete() failed:"
+ " %s",
+ scf_strerror(scf_error()));
+ }
+ goto destruction;
+ }
+
+ ret = scf_transaction_commit(tx);
+
+ if (ret == 0)
+ scf_transaction_reset(tx);
+ } while (ret == 0);
+
+ if (ret == -1) {
+ idmapdlog(LOG_ERR,
+ "scf_transaction_commit(%s) failed: %s",
+ name, scf_strerror(scf_error()));
+ goto destruction;
+ }
+
+ rc = 0;
+
+destruction:
+ if (ent != NULL)
+ scf_entry_destroy(ent);
+ if (tx != NULL)
+ scf_transaction_destroy(tx);
+ return (rc);
+}
+
+
+static int
+set_val_astring(idmap_cfg_handles_t *handles, const char *name, const char *val)
{
int rc = -1;
int ret = -2;
@@ -549,6 +618,18 @@ update_string(char **value, char **new, char *name)
return (1);
}
+static int
+update_enum(int *value, int *new, char *name, struct enum_lookup_map *map)
+{
+ if (*value == *new)
+ return (0);
+
+ idmapdlog(LOG_INFO, "change %s=%s", name, enum_lookup(*new, map));
+
+ *value = *new;
+
+ return (1);
+}
/*
* This function updates a directory service structure.
@@ -801,6 +882,16 @@ not_equal:
return (1);
}
+const char *
+enum_lookup(int value, struct enum_lookup_map *map)
+{
+ for (; map->string != NULL; map++) {
+ if (value == map->value) {
+ return (map->string);
+ }
+ }
+ return ("(invalid)");
+}
#define MAX_CHECK_TIME (20 * 60)
@@ -1030,6 +1121,32 @@ valid_ldap_attr(const char *attr) {
return (1);
}
+static
+int
+check_smf_debug_mode(idmap_cfg_handles_t *handles)
+{
+ boolean_t new_debug_mode;
+ int rc;
+
+ rc = prop_exists(handles, "debug", &new_debug_mode);
+ if (rc != 0)
+ return (rc);
+
+ if (_idmapdstate.debug_mode != new_debug_mode) {
+ if (!_idmapdstate.debug_mode) {
+ _idmapdstate.debug_mode = new_debug_mode;
+ idmap_log_stderr(LOG_DEBUG);
+ idmapdlog(LOG_DEBUG, "debug mode enabled");
+ } else {
+ idmapdlog(LOG_DEBUG, "debug mode disabled");
+ idmap_log_stderr(-1);
+ _idmapdstate.debug_mode = new_debug_mode;
+ }
+ }
+
+ return (0);
+}
+
/*
* This is the half of idmap_cfg_load() that loads property values from
* SMF (using the config/ property group of the idmap FMRI).
@@ -1041,12 +1158,12 @@ valid_ldap_attr(const char *attr) {
static
int
idmap_cfg_load_smf(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg,
- int *errors)
+ int * const errors)
{
int rc;
- uint8_t bool_val;
- char *str = NULL;
- boolean_t new_debug_mode;
+ char *s;
+
+ *errors = 0;
if (scf_pg_update(handles->config_pg) < 0) {
idmapdlog(LOG_ERR, "scf_pg_update() failed: %s",
@@ -1060,37 +1177,42 @@ idmap_cfg_load_smf(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg,
return (-2);
}
-
- rc = prop_exists(handles, "debug", &new_debug_mode);
+ rc = check_smf_debug_mode(handles);
if (rc != 0)
- errors++;
-
- if (_idmapdstate.debug_mode != new_debug_mode) {
- if (!_idmapdstate.debug_mode) {
- _idmapdstate.debug_mode = new_debug_mode;
- idmap_log_stderr(LOG_DEBUG);
- idmapdlog(LOG_DEBUG, "debug mode enabled");
- } else {
- idmapdlog(LOG_DEBUG, "debug mode disabled");
- idmap_log_stderr(-1);
- _idmapdstate.debug_mode = new_debug_mode;
- }
- }
+ (*errors)++;
rc = get_val_int(handles, "unresolvable_sid_mapping",
&pgcfg->eph_map_unres_sids, SCF_TYPE_BOOLEAN);
if (rc != 0)
- errors++;
+ (*errors)++;
+
+ rc = get_val_astring(handles, "directory_based_mapping", &s);
+ if (rc != 0)
+ (*errors)++;
+ else if (s == NULL || strcasecmp(s, "none") == 0)
+ pgcfg->directory_based_mapping = DIRECTORY_MAPPING_NONE;
+ else if (strcasecmp(s, "name") == 0)
+ pgcfg->directory_based_mapping = DIRECTORY_MAPPING_NAME;
+ else if (strcasecmp(s, "idmu") == 0)
+ pgcfg->directory_based_mapping = DIRECTORY_MAPPING_IDMU;
+ else {
+ pgcfg->directory_based_mapping = DIRECTORY_MAPPING_NONE;
+ idmapdlog(LOG_ERR,
+ "config/directory_based_mapping: invalid value \"%s\" ignored",
+ s);
+ (*errors)++;
+ }
+ free(s);
rc = get_val_int(handles, "list_size_limit",
&pgcfg->list_size_limit, SCF_TYPE_COUNT);
if (rc != 0)
- errors++;
+ (*errors)++;
rc = get_val_astring(handles, "domain_name",
&pgcfg->domain_name);
if (rc != 0)
- errors++;
+ (*errors)++;
else {
(void) ad_disc_set_DomainName(handles->ad_ctx,
pgcfg->domain_name);
@@ -1108,45 +1230,13 @@ idmap_cfg_load_smf(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg,
return (-2);
}
- rc = get_val_astring(handles, "mapping_domain", &str);
- if (rc != 0)
- errors++;
-
- /*
- * We treat default_domain as having been specified in SMF IFF
- * either (the config/default_domain property was set) or (the
- * old, obsolete, never documented config/mapping_domain
- * property was set and the new config/domain_name property was
- * not set).
- */
- pgcfg->dflt_dom_set_in_smf = B_TRUE;
- if (pgcfg->default_domain == NULL) {
-
- pgcfg->dflt_dom_set_in_smf = B_FALSE;
-
- if (pgcfg->domain_name != NULL) {
- pgcfg->default_domain = strdup(pgcfg->domain_name);
- if (str != NULL) {
- idmapdlog(LOG_WARNING,
- "Ignoring obsolete, undocumented "
- "config/mapping_domain property");
- }
- } else if (str != NULL) {
- pgcfg->default_domain = strdup(str);
- pgcfg->dflt_dom_set_in_smf = B_TRUE;
- idmapdlog(LOG_WARNING,
- "The config/mapping_domain property is "
- "obsolete; support for it will be removed, "
- "please use config/default_domain instead");
- }
+ if (pgcfg->default_domain == NULL && pgcfg->domain_name != NULL) {
+ pgcfg->default_domain = strdup(pgcfg->domain_name);
}
- if (str != NULL)
- free(str);
-
rc = get_val_astring(handles, "machine_sid", &pgcfg->machine_sid);
if (rc != 0)
- errors++;
+ (*errors)++;
if (pgcfg->machine_sid == NULL) {
/* If machine_sid not configured, generate one */
if (generate_machine_sid(&pgcfg->machine_sid) < 0)
@@ -1154,14 +1244,13 @@ idmap_cfg_load_smf(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg,
rc = set_val_astring(handles, "machine_sid",
pgcfg->machine_sid);
if (rc != 0)
- errors++;
+ (*errors)++;
}
- str = NULL;
rc = get_val_ds(handles, "domain_controller", 389,
&pgcfg->domain_controller);
if (rc != 0)
- errors++;
+ (*errors)++;
else {
(void) ad_disc_set_DomainController(handles->ad_ctx,
pgcfg->domain_controller);
@@ -1170,7 +1259,7 @@ idmap_cfg_load_smf(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg,
rc = get_val_astring(handles, "forest_name", &pgcfg->forest_name);
if (rc != 0)
- errors++;
+ (*errors)++;
else {
(void) ad_disc_set_ForestName(handles->ad_ctx,
pgcfg->forest_name);
@@ -1179,33 +1268,24 @@ idmap_cfg_load_smf(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg,
rc = get_val_astring(handles, "site_name", &pgcfg->site_name);
if (rc != 0)
- errors++;
+ (*errors)++;
else
(void) ad_disc_set_SiteName(handles->ad_ctx, pgcfg->site_name);
- str = NULL;
rc = get_val_ds(handles, "global_catalog", 3268,
&pgcfg->global_catalog);
if (rc != 0)
- errors++;
+ (*errors)++;
else {
(void) ad_disc_set_GlobalCatalog(handles->ad_ctx,
pgcfg->global_catalog);
pgcfg->global_catalog_auto_disc = B_FALSE;
}
- /*
- * Read directory-based name mappings related SMF properties
- */
- rc = get_val_int(handles, "ds_name_mapping_enabled",
- &bool_val, SCF_TYPE_BOOLEAN);
- if (rc != 0)
- return (-2);
-
- if (!bool_val)
- return (rc);
+ /* Unless we're doing directory-based name mapping, we're done. */
+ if (pgcfg->directory_based_mapping != DIRECTORY_MAPPING_NAME)
+ return (0);
- pgcfg->ds_name_mapping_enabled = B_TRUE;
rc = get_val_astring(handles, "ad_unixuser_attr",
&pgcfg->ad_unixuser_attr);
if (rc != 0)
@@ -1242,8 +1322,8 @@ idmap_cfg_load_smf(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg,
pgcfg->ad_unixgroup_attr == NULL &&
pgcfg->nldap_winname_attr == NULL) {
idmapdlog(LOG_ERR,
- "If config/ds_name_mapping_enabled property is set to "
- "true then atleast one of the following name mapping "
+ "If config/directory_based_mapping property is set to "
+ "\"name\" then at least one of the following name mapping "
"attributes must be specified. (config/ad_unixuser_attr OR "
"config/ad_unixgroup_attr OR config/nldap_winname_attr)");
return (-3);
@@ -1474,7 +1554,7 @@ int
idmap_cfg_load(idmap_cfg_t *cfg, int flags)
{
int rc = 0;
- int errors = 0;
+ int errors;
int changed = 0;
int ad_reload_required = 0;
idmap_pg_config_t new_pgcfg, *live_pgcfg;
@@ -1504,10 +1584,9 @@ idmap_cfg_load(idmap_cfg_t *cfg, int flags)
changed += update_bool(&live_pgcfg->eph_map_unres_sids,
&new_pgcfg.eph_map_unres_sids, "unresolvable_sid_mapping");
- changed += live_pgcfg->ds_name_mapping_enabled !=
- new_pgcfg.ds_name_mapping_enabled;
- live_pgcfg->ds_name_mapping_enabled =
- new_pgcfg.ds_name_mapping_enabled;
+ changed += update_enum(&live_pgcfg->directory_based_mapping,
+ &new_pgcfg.directory_based_mapping, "directory_based_mapping",
+ directory_mapping_map);
changed += update_string(&live_pgcfg->ad_unixuser_attr,
&new_pgcfg.ad_unixuser_attr, "ad_unixuser_attr");
@@ -1519,9 +1598,8 @@ idmap_cfg_load(idmap_cfg_t *cfg, int flags)
&new_pgcfg.nldap_winname_attr, "nldap_winname_attr");
/* Props that can be discovered and set in SMF updated here */
- if (!live_pgcfg->dflt_dom_set_in_smf)
- changed += update_string(&live_pgcfg->default_domain,
- &new_pgcfg.default_domain, "default_domain");
+ changed += update_string(&live_pgcfg->default_domain,
+ &new_pgcfg.default_domain, "default_domain");
changed += update_string(&live_pgcfg->domain_name,
&new_pgcfg.domain_name, "domain_name");
@@ -1657,6 +1735,9 @@ idmap_cfg_init()
goto error;
}
+ if (check_smf_debug_mode(handles) != 0)
+ goto error;
+
/* Initialize AD Auto Discovery context */
handles->ad_ctx = ad_disc_init();
if (handles->ad_ctx == NULL)
@@ -1756,3 +1837,110 @@ idmap_cfg_hup_handler(int sig)
if (idmapd_ev_port >= 0)
(void) port_send(idmapd_ev_port, RECONFIGURE, NULL);
}
+
+/*
+ * Upgrade the DS mapping flags.
+ *
+ * If the old ds_name_mapping_enabled flag is present, then
+ * if the new directory_based_mapping value is present, then
+ * if the two are compatible, delete the old and note it
+ * else delete the old and warn
+ * else
+ * set the new based on the old, and note it
+ * delete the old
+ */
+static
+int
+upgrade_directory_mapping(idmap_cfg_handles_t *handles)
+{
+ boolean_t legacy_ds_name_mapping_present;
+ const char DS_NAME_MAPPING_ENABLED[] = "ds_name_mapping_enabled";
+ const char DIRECTORY_BASED_MAPPING[] = "directory_based_mapping";
+ int rc;
+
+ rc = prop_exists(handles, DS_NAME_MAPPING_ENABLED,
+ &legacy_ds_name_mapping_present);
+
+ if (rc != 0)
+ return (rc);
+
+ if (!legacy_ds_name_mapping_present)
+ return (0);
+
+ boolean_t legacy_ds_name_mapping_enabled;
+ rc = get_val_int(handles, DS_NAME_MAPPING_ENABLED,
+ &legacy_ds_name_mapping_enabled, SCF_TYPE_BOOLEAN);
+ if (rc != 0)
+ return (rc);
+
+ char *legacy_mode;
+ char *legacy_bool_string;
+ if (legacy_ds_name_mapping_enabled) {
+ legacy_mode = "name";
+ legacy_bool_string = "true";
+ } else {
+ legacy_mode = "none";
+ legacy_bool_string = "false";
+ }
+
+ char *directory_based_mapping;
+ rc = get_val_astring(handles, DIRECTORY_BASED_MAPPING,
+ &directory_based_mapping);
+ if (rc != 0)
+ return (rc);
+
+ if (directory_based_mapping == NULL) {
+ idmapdlog(LOG_INFO,
+ "Upgrading old %s=%s setting\n"
+ "to %s=%s.",
+ DS_NAME_MAPPING_ENABLED, legacy_bool_string,
+ DIRECTORY_BASED_MAPPING, legacy_mode);
+ rc = set_val_astring(handles, DIRECTORY_BASED_MAPPING,
+ legacy_mode);
+ if (rc != 0)
+ return (rc);
+ } else {
+ boolean_t new_name_mapping;
+ if (strcasecmp(directory_based_mapping, "name") == 0)
+ new_name_mapping = B_TRUE;
+ else
+ new_name_mapping = B_FALSE;
+
+ if (legacy_ds_name_mapping_enabled == new_name_mapping) {
+ idmapdlog(LOG_INFO,
+ "Automatically removing old %s=%s setting\n"
+ "in favor of %s=%s.",
+ DS_NAME_MAPPING_ENABLED, legacy_bool_string,
+ DIRECTORY_BASED_MAPPING, directory_based_mapping);
+ } else {
+ idmapdlog(LOG_WARNING,
+ "Removing conflicting %s=%s setting\n"
+ "in favor of %s=%s.",
+ DS_NAME_MAPPING_ENABLED, legacy_bool_string,
+ DIRECTORY_BASED_MAPPING, directory_based_mapping);
+ }
+ free(directory_based_mapping);
+ }
+
+ rc = del_val(handles, DS_NAME_MAPPING_ENABLED);
+ if (rc != 0)
+ return (rc);
+
+ return (0);
+}
+
+/*
+ * Do whatever is necessary to upgrade idmap's configuration before
+ * we load it.
+ */
+int
+idmap_cfg_upgrade(idmap_cfg_t *cfg)
+{
+ int rc;
+
+ rc = upgrade_directory_mapping(&cfg->handles);
+ if (rc != 0)
+ return (rc);
+
+ return (0);
+}
diff --git a/usr/src/cmd/idmap/idmapd/idmap_config.h b/usr/src/cmd/idmap/idmapd/idmap_config.h
index d8a6f4c810..bdee366906 100644
--- a/usr/src/cmd/idmap/idmapd/idmap_config.h
+++ b/usr/src/cmd/idmap/idmapd/idmap_config.h
@@ -38,6 +38,18 @@ extern "C" {
#define MAX_POLICY_SIZE 1023
+#define DIRECTORY_MAPPING_NONE 0
+#define DIRECTORY_MAPPING_NAME 1
+#define DIRECTORY_MAPPING_IDMU 2
+
+struct enum_lookup_map {
+ int value;
+ char *string;
+};
+
+extern struct enum_lookup_map directory_mapping_map[];
+extern const char *enum_lookup(int value, struct enum_lookup_map *map);
+
/* SMF and auto-discovery context handles */
typedef struct idmap_cfg_handles {
pthread_mutex_t mutex;
@@ -63,19 +75,8 @@ typedef struct idmap_trustedforest {
typedef struct idmap_pg_config {
uint64_t list_size_limit;
- /*
- * The idmap_cfg_update_thread() uses the ad_disc_t context in
- * the idmap_cfg_handles_t (see above) to track which values
- * came from SMF and which values didn't. This works for all
- * items that are discoverable, but default_domain (the domain
- * that we qualify unqualified names passed to idmap show) is
- * not discoverable independently of domain_name. So we need to
- * track its procedence separately. The dflt_dom_set_in_smf
- * field does just that.
- */
char *machine_sid; /* machine sid */
char *default_domain; /* default domain name */
- boolean_t dflt_dom_set_in_smf;
char *domain_name; /* AD domain name */
boolean_t domain_name_auto_disc;
idmap_ad_disc_ds_t
@@ -103,7 +104,7 @@ typedef struct idmap_pg_config {
char *ad_unixuser_attr;
char *ad_unixgroup_attr;
char *nldap_winname_attr;
- boolean_t ds_name_mapping_enabled;
+ int directory_based_mapping; /* enum */
boolean_t eph_map_unres_sids;
} idmap_pg_config_t;
@@ -118,6 +119,7 @@ extern void idmap_cfg_unload(idmap_pg_config_t *);
extern int idmap_cfg_load(idmap_cfg_t *, int);
extern idmap_cfg_t *idmap_cfg_init(void);
extern int idmap_cfg_fini(idmap_cfg_t *);
+extern int idmap_cfg_upgrade(idmap_cfg_t *);
extern int idmap_cfg_start_updates(void);
extern void idmap_cfg_poke_updates(void);
extern void idmap_cfg_hup_handler(int);
diff --git a/usr/src/cmd/idmap/idmapd/idmapd.h b/usr/src/cmd/idmap/idmapd/idmapd.h
index 63eb9d4143..738fb0e9a0 100644
--- a/usr/src/cmd/idmap/idmapd/idmapd.h
+++ b/usr/src/cmd/idmap/idmapd/idmapd.h
@@ -62,7 +62,6 @@ typedef enum idmap_namemap_mode {
/*
* Global state of idmapd daemon.
*/
-#define IDMAP_MAX_NAME_LEN 512
typedef struct idmapd_state {
rwlock_t rwlk_cfg; /* config lock */
idmap_cfg_t *cfg; /* config */
@@ -74,9 +73,10 @@ typedef struct idmapd_state {
uid_t limit_uid;
gid_t limit_gid;
int new_eph_db; /* was the ephem ID db [re-]created? */
- bool_t eph_map_unres_sids;
- int num_ads;
- adutils_ad_t **ads;
+ int num_gcs;
+ adutils_ad_t **gcs;
+ int num_dcs;
+ adutils_ad_t **dcs;
} idmapd_state_t;
extern idmapd_state_t _idmapdstate;
@@ -98,6 +98,7 @@ typedef struct lookup_state {
int ad_nqueries;
int nldap_nqueries;
bool_t eph_map_unres_sids;
+ int directory_based_mapping; /* enum */
uint_t curpos;
hashentry_t *sid_history;
uint_t sid_history_size;
@@ -158,7 +159,7 @@ typedef struct wksids_table {
const char *domain;
const char *winname;
int is_wuser;
- uid_t pid;
+ posix_id_t pid;
int is_user;
int direction;
} wksids_table_t;
@@ -303,7 +304,7 @@ extern void idmap_log_stderr(int);
extern void idmap_log_syslog(boolean_t);
extern void idmap_log_degraded(boolean_t);
-extern const wksids_table_t *find_wksid_by_pid(uid_t pid, int is_user);
+extern const wksids_table_t *find_wksid_by_pid(posix_id_t pid, int is_user);
extern const wksids_table_t *find_wksid_by_sid(const char *sid, int rid,
int type);
extern const wksids_table_t *find_wksid_by_name(const char *name,
diff --git a/usr/src/cmd/idmap/idmapd/init.c b/usr/src/cmd/idmap/idmapd/init.c
index 2e60fb40f5..3d18ee5af0 100644
--- a/usr/src/cmd/idmap/idmapd/init.c
+++ b/usr/src/cmd/idmap/idmapd/init.c
@@ -76,6 +76,12 @@ load_config()
return (-1);
}
+ rc = idmap_cfg_upgrade(_idmapdstate.cfg);
+ if (rc != 0) {
+ degrade_svc(0, "fatal error while upgrading configuration");
+ return (rc);
+ }
+
rc = idmap_cfg_load(_idmapdstate.cfg, 0);
if (rc < -1) {
/* Total failure */
@@ -101,13 +107,13 @@ load_config()
void
-reload_ad()
+reload_gcs()
{
int i, j;
- adutils_ad_t **new_ads = NULL;
- adutils_ad_t **old_ads;
- int new_num_ads;
- int old_num_ads;
+ adutils_ad_t **new_gcs;
+ adutils_ad_t **old_gcs;
+ int new_num_gcs;
+ int old_num_gcs;
idmap_pg_config_t *pgcfg = &_idmapdstate.cfg->pgcfg;
idmap_trustedforest_t *trustfor = pgcfg->trusted_forests;
int num_trustfor = pgcfg->num_trusted_forests;
@@ -126,31 +132,31 @@ reload_ad()
return;
}
- old_ads = _idmapdstate.ads;
- old_num_ads = _idmapdstate.num_ads;
+ old_gcs = _idmapdstate.gcs;
+ old_num_gcs = _idmapdstate.num_gcs;
- new_num_ads = 1 + num_trustfor;
- new_ads = calloc(new_num_ads, sizeof (adutils_ad_t *));
- if (new_ads == NULL) {
+ new_num_gcs = 1 + num_trustfor;
+ new_gcs = calloc(new_num_gcs, sizeof (adutils_ad_t *));
+ if (new_gcs == NULL) {
degrade_svc(0, "could not allocate AD context array "
"(out of memory)");
return;
}
- if (adutils_ad_alloc(&new_ads[0], pgcfg->default_domain,
- ADUTILS_AD_GLOBAL_CATALOG) != ADUTILS_SUCCESS) {
- free(new_ads);
+ if (adutils_ad_alloc(&new_gcs[0], NULL, ADUTILS_AD_GLOBAL_CATALOG) !=
+ ADUTILS_SUCCESS) {
+ free(new_gcs);
degrade_svc(0, "could not initialize AD context "
"(out of memory)");
return;
}
for (i = 0; pgcfg->global_catalog[i].host[0] != '\0'; i++) {
- if (idmap_add_ds(new_ads[0],
+ if (idmap_add_ds(new_gcs[0],
pgcfg->global_catalog[i].host,
pgcfg->global_catalog[i].port) != 0) {
- adutils_ad_free(&new_ads[0]);
- free(new_ads);
+ adutils_ad_free(&new_gcs[0]);
+ free(new_gcs);
degrade_svc(0, "could not set AD hosts "
"(out of memory)");
return;
@@ -160,11 +166,11 @@ reload_ad()
if (pgcfg->domains_in_forest != NULL) {
for (i = 0; pgcfg->domains_in_forest[i].domain[0] != '\0';
i++) {
- if (adutils_add_domain(new_ads[0],
+ if (adutils_add_domain(new_gcs[0],
pgcfg->domains_in_forest[i].domain,
pgcfg->domains_in_forest[i].sid) != 0) {
- adutils_ad_free(&new_ads[0]);
- free(new_ads);
+ adutils_ad_free(&new_gcs[0]);
+ free(new_gcs);
degrade_svc(0, "could not set AD domains "
"(out of memory)");
return;
@@ -173,22 +179,22 @@ reload_ad()
}
for (i = 0; i < num_trustfor; i++) {
- if (adutils_ad_alloc(&new_ads[i + 1], NULL,
+ if (adutils_ad_alloc(&new_gcs[i + 1], NULL,
ADUTILS_AD_GLOBAL_CATALOG) != ADUTILS_SUCCESS) {
degrade_svc(0, "could not initialize trusted AD "
"context (out of memory)");
- new_num_ads = i + 1;
+ new_num_gcs = i + 1;
goto out;
}
for (j = 0; trustfor[i].global_catalog[j].host[0] != '\0';
j++) {
- if (idmap_add_ds(new_ads[i + 1],
+ if (idmap_add_ds(new_gcs[i + 1],
trustfor[i].global_catalog[j].host,
trustfor[i].global_catalog[j].port) != 0) {
- adutils_ad_free(&new_ads[i + 1]);
+ adutils_ad_free(&new_gcs[i + 1]);
degrade_svc(0, "could not set trusted "
"AD hosts (out of memory)");
- new_num_ads = i + 1;
+ new_num_gcs = i + 1;
goto out;
}
}
@@ -197,13 +203,13 @@ reload_ad()
domain_in_forest = &trustfor[i].domains_in_forest[j];
/* Only add domains which are marked */
if (domain_in_forest->trusted) {
- if (adutils_add_domain(new_ads[i + 1],
+ if (adutils_add_domain(new_gcs[i + 1],
domain_in_forest->domain,
domain_in_forest->sid) != 0) {
- adutils_ad_free(&new_ads[i + 1]);
+ adutils_ad_free(&new_gcs[i + 1]);
degrade_svc(0, "could not set trusted "
"AD domains (out of memory)");
- new_num_ads = i + 1;
+ new_num_gcs = i + 1;
goto out;
}
}
@@ -211,19 +217,107 @@ reload_ad()
}
out:
- _idmapdstate.ads = new_ads;
- _idmapdstate.num_ads = new_num_ads;
+ _idmapdstate.gcs = new_gcs;
+ _idmapdstate.num_gcs = new_num_gcs;
+
+
+ if (old_gcs != NULL) {
+ for (i = 0; i < old_num_gcs; i++)
+ adutils_ad_free(&old_gcs[i]);
+ free(old_gcs);
+ }
+}
+
+/*
+ * NEEDSWORK: This should load entries for domain servers for all known
+ * domains - the joined domain, other domains in the forest, and trusted
+ * domains in other forests. However, we don't yet discover any DCs other
+ * than the DCs for the joined domain.
+ */
+static
+void
+reload_dcs(void)
+{
+ int i;
+ adutils_ad_t **new_dcs;
+ adutils_ad_t **old_dcs;
+ int new_num_dcs;
+ int old_num_dcs;
+ idmap_pg_config_t *pgcfg = &_idmapdstate.cfg->pgcfg;
+
+ if (pgcfg->domain_controller == NULL ||
+ pgcfg->domain_controller[0].host[0] == '\0') {
+ /*
+ * No DCs. Continue to use the previous AD config in case
+ * that's still good but auto-discovery had a transient failure.
+ * If that stops working we'll go into degraded mode anyways
+ * when it does.
+ */
+ degrade_svc(0,
+ "Domain controller servers not configured/discoverable");
+ return;
+ }
+
+ old_dcs = _idmapdstate.dcs;
+ old_num_dcs = _idmapdstate.num_dcs;
+
+ new_num_dcs = 1;
+ new_dcs = calloc(new_num_dcs, sizeof (adutils_ad_t *));
+ if (new_dcs == NULL)
+ goto nomem;
+
+ if (adutils_ad_alloc(&new_dcs[0], pgcfg->domain_name,
+ ADUTILS_AD_DATA) != ADUTILS_SUCCESS)
+ goto nomem;
+
+ for (i = 0; pgcfg->domain_controller[i].host[0] != '\0'; i++) {
+ if (idmap_add_ds(new_dcs[0],
+ pgcfg->domain_controller[i].host,
+ pgcfg->domain_controller[i].port) != 0)
+ goto nomem;
+ }
+
+ /* NEEDSWORK: isn't there an easier way to find the domain SID? */
+ for (i = 0; pgcfg->domains_in_forest[i].domain[0] != '\0'; i++) {
+ if (domain_eq(pgcfg->domain_name,
+ pgcfg->domains_in_forest[i].domain)) {
+ if (adutils_add_domain(new_dcs[0], pgcfg->domain_name,
+ pgcfg->domains_in_forest[i].sid) != 0)
+ goto nomem;
+ break;
+ }
+ }
+
+ _idmapdstate.dcs = new_dcs;
+ _idmapdstate.num_dcs = new_num_dcs;
+
+ if (old_dcs != NULL) {
+ for (i = 0; i < old_num_dcs; i++)
+ adutils_ad_free(&old_dcs[i]);
+ free(old_dcs);
+ }
+ return;
- if (old_ads != NULL) {
- for (i = 0; i < old_num_ads; i++)
- adutils_ad_free(&old_ads[i]);
- free(old_ads);
+nomem:
+ degrade_svc(0, "out of memory");
+
+ if (new_dcs != NULL) {
+ if (new_dcs[0] != NULL)
+ adutils_ad_free(&new_dcs[0]);
+ free(new_dcs);
}
}
void
+reload_ad(void)
+{
+ reload_gcs();
+ reload_dcs();
+}
+
+void
print_idmapdstate()
{
int i, j;
@@ -302,8 +396,8 @@ print_idmapdstate()
}
}
- idmapdlog(LOG_DEBUG, "ds_name_mapping_enabled=%s",
- (pgcfg->ds_name_mapping_enabled) ? "true" : "false");
+ idmapdlog(LOG_DEBUG, "directory_based_mapping=%s",
+ enum_lookup(pgcfg->directory_based_mapping, directory_mapping_map));
idmapdlog(LOG_DEBUG, "ad_unixuser_attr=%s",
CHECK_NULL(pgcfg->ad_unixuser_attr));
idmapdlog(LOG_DEBUG, "ad_unixgroup_attr=%s",
diff --git a/usr/src/cmd/idmap/idmapd/server.c b/usr/src/cmd/idmap/idmapd/server.c
index 6a14d1dbef..8c26069a9f 100644
--- a/usr/src/cmd/idmap/idmapd/server.c
+++ b/usr/src/cmd/idmap/idmapd/server.c
@@ -524,8 +524,17 @@ list_mappings_cb(void *parg, int argc, char **argv, char **colnames)
case IDMAP_MAP_TYPE_LOCAL_SID:
break;
+ case IDMAP_MAP_TYPE_IDMU:
+ how->idmap_how_u.idmu.dn =
+ strdup(argv[12]);
+ how->idmap_how_u.idmu.attr =
+ strdup(argv[13]);
+ how->idmap_how_u.idmu.value =
+ strdup(argv[14]);
+ break;
+
default:
- /* Unknow mapping type */
+ /* Unknown mapping type */
assert(FALSE);
}
@@ -1069,9 +1078,10 @@ idmap_get_prop_1_svc(idmap_prop_type request,
pgcfg->nldap_winname_attr);
result->auto_discovered = FALSE;
break;
- case PROP_DS_NAME_MAPPING_ENABLED:
- result->value.idmap_prop_val_u.boolval =
- pgcfg->ds_name_mapping_enabled;
+ case PROP_DIRECTORY_BASED_MAPPING:
+ STRDUP_CHECK(result->value.idmap_prop_val_u.utf8val,
+ enum_lookup(pgcfg->directory_based_mapping,
+ directory_mapping_map));
result->auto_discovered = FALSE;
break;
default: