summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJakub Hrozek <jhrozek@redhat.com>2011-04-07 11:44:40 +0200
committerStephen Gallagher <sgallagh@redhat.com>2011-05-20 07:21:45 -0400
commit258d4b400f72e89f4428302d82c886f9c4c45c3e (patch)
treea14a5585819f306de562223ee29dd8812386e363
parent2cc60b61c8d487221f88703b1784a92d9a1525e4 (diff)
downloadsssd-258d4b400f72e89f4428302d82c886f9c4c45c3e.tar.gz
sssd-258d4b400f72e89f4428302d82c886f9c4c45c3e.tar.xz
sssd-258d4b400f72e89f4428302d82c886f9c4c45c3e.zip
OpenLDAP dereference searches
This dereference method is supported at least by OpenLDAP and 389DS/RHDS For more details, see: http://tools.ietf.org/html/draft-masarati-ldap-deref-00
-rw-r--r--src/providers/ldap/sdap.c159
-rw-r--r--src/providers/ldap/sdap.h7
-rw-r--r--src/providers/ldap/sdap_async.c210
3 files changed, 376 insertions, 0 deletions
diff --git a/src/providers/ldap/sdap.c b/src/providers/ldap/sdap.c
index e82720929..61044bb58 100644
--- a/src/providers/ldap/sdap.c
+++ b/src/providers/ldap/sdap.c
@@ -277,6 +277,165 @@ int sdap_parse_group(TALLOC_CTX *memctx, struct sdap_options *opts,
SDAP_OPTS_GROUP, _attrs, _dn);
}
+/* Parses an LDAPDerefRes into sdap_deref_attrs structure */
+errno_t sdap_parse_deref(TALLOC_CTX *mem_ctx,
+ struct sdap_attr_map_info *minfo,
+ size_t num_maps,
+ struct sdap_handle *sh,
+ LDAPDerefRes *dref,
+ struct sdap_deref_attrs ***_res)
+{
+ TALLOC_CTX *tmp_ctx;
+ LDAPDerefVal *dval;
+ const char *orig_dn;
+ const char **ocs;
+ struct sdap_attr_map *map;
+ int num_attrs;
+ struct ldb_val v;
+ int ret, i, a, mi;
+ const char *name;
+ size_t len;
+ struct sdap_deref_attrs **res;
+
+ if (!dref || !minfo) return EINVAL;
+
+ tmp_ctx = talloc_new(NULL);
+ if (!tmp_ctx) return ENOMEM;
+
+ res = talloc_array(tmp_ctx, struct sdap_deref_attrs *, num_maps);
+ if (!res) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ for (i=0; i < num_maps; i++) {
+ res[i] = talloc_zero(res, struct sdap_deref_attrs);
+ if (!res[i]) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ res[i]->map = minfo[i].map;
+ }
+
+ if (!dref->derefVal.bv_val) {
+ DEBUG(2, ("Entry has no DN?\n"));
+ ret = EINVAL;
+ goto done;
+ }
+
+ if (!dref->attrVals) {
+ DEBUG(2, ("Dereferenced entry has no attributes\n"));
+ ret = EINVAL;
+ goto done;
+ }
+
+ orig_dn = dref->derefVal.bv_val;
+ DEBUG(7, ("Dereferenced DN: %s\n", orig_dn));
+
+ ocs = NULL;
+ for (dval = dref->attrVals; dval != NULL; dval = dval->next) {
+ if (strcasecmp("objectClass", dval->type) == 0) {
+ if (dval->vals == NULL) {
+ DEBUG(4, ("No value for objectClass, skipping\n"));
+ continue;
+ }
+
+ for(len=0; dval->vals[len].bv_val; len++);
+
+ ocs = talloc_array(tmp_ctx, const char *, len+1);
+ if (!ocs) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ for (i=0; i<len; i++) {
+ DEBUG(9, ("Dereferenced objectClass value: %s\n",
+ dval->vals[i].bv_val));
+ ocs[i] = talloc_strdup(ocs, dval->vals[i].bv_val);
+ if (!ocs[i]) {
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+ ocs[i] = NULL;
+ break;
+ }
+ }
+ if (!ocs) {
+ DEBUG(1, ("Unknown entry type, no objectClasses found!\n"));
+ ret = EINVAL;
+ goto done;
+ }
+
+ for (mi = 0; mi < num_maps; mi++) {
+ map = NULL;
+
+ for (i=0; ocs[i]; i++) {
+ /* the objectclass is always the first name in the map */
+ if (strcasecmp(minfo[mi].map[0].name, ocs[i]) == 0) {
+ DEBUG(9, ("Found map for objectclass '%s'\n", ocs[i]));
+ map = minfo[mi].map;
+ num_attrs = minfo[mi].num_attrs;
+ break;
+ }
+ }
+ if (!map) continue;
+
+ res[mi]->attrs = sysdb_new_attrs(res[mi]);
+ if (!res[mi]->attrs) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = sysdb_attrs_add_string(res[mi]->attrs, SYSDB_ORIG_DN,
+ orig_dn);
+ if (ret) {
+ goto done;
+ }
+
+ for (dval = dref->attrVals; dval != NULL; dval = dval->next) {
+ DEBUG(8, ("Dereferenced attribute: %s\n", dval->type));
+
+ for (a = 1; a < num_attrs; a++) {
+ /* check if this attr is valid with the chosen schema */
+ if (!map[a].name) continue;
+ /* check if it is an attr we are interested in */
+ if (strcasecmp(dval->type, map[a].name) == 0) break;
+ }
+
+ /* interesting attr */
+ if (a < num_attrs) {
+ name = map[a].sys_name;
+ } else {
+ continue;
+ }
+
+ if (dval->vals == NULL) {
+ DEBUG(4, ("No value for attribute %s, skipping\n", name));
+ continue;
+ }
+
+ for (i=0; dval->vals[i].bv_val; i++) {
+ DEBUG(9, ("Dereferenced attribute value: %s\n",
+ dval->vals[i].bv_val));
+ v.data = (uint8_t *) dval->vals[i].bv_val;
+ v.length = dval->vals[i].bv_len;
+
+ ret = sysdb_attrs_add_val(res[mi]->attrs, name, &v);
+ if (ret) goto done;
+ }
+ }
+ }
+
+
+ *_res = talloc_steal(mem_ctx, res);
+ ret = EOK;
+done:
+ talloc_zfree(tmp_ctx);
+ return ret;
+}
+
/* =Get-DN-from-message=================================================== */
int sdap_get_msg_dn(TALLOC_CTX *memctx, struct sdap_handle *sh,
diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
index cef2d23ae..e98b27bce 100644
--- a/src/providers/ldap/sdap.h
+++ b/src/providers/ldap/sdap.h
@@ -335,6 +335,13 @@ int sdap_parse_group(TALLOC_CTX *memctx, struct sdap_options *opts,
struct sdap_handle *sh, struct sdap_msg *sm,
struct sysdb_attrs **_attrs, char **_dn);
+errno_t sdap_parse_deref(TALLOC_CTX *mem_ctx,
+ struct sdap_attr_map_info *minfo,
+ size_t num_maps,
+ struct sdap_handle *sh,
+ LDAPDerefRes *dref,
+ struct sdap_deref_attrs ***_res);
+
int sdap_get_msg_dn(TALLOC_CTX *memctx, struct sdap_handle *sh,
struct sdap_msg *sm, char **_dn);
diff --git a/src/providers/ldap/sdap_async.c b/src/providers/ldap/sdap_async.c
index bcc18135f..9d319bf33 100644
--- a/src/providers/ldap/sdap_async.c
+++ b/src/providers/ldap/sdap_async.c
@@ -1285,6 +1285,216 @@ int sdap_get_generic_recv(struct tevent_req *req,
return EOK;
}
+/* ==OpenLDAP deref search============================================== */
+static int sdap_x_deref_create_control(struct sdap_handle *sh,
+ const char *deref_attr,
+ const char **attrs,
+ LDAPControl **ctrl);
+
+static void sdap_x_deref_search_done(struct tevent_req *subreq);
+
+static errno_t sdap_x_deref_parse_entry(struct sdap_handle *sh,
+ struct sdap_msg *msg,
+ void *pvt);
+struct sdap_x_deref_search_state {
+ struct sdap_handle *sh;
+ struct sdap_op *op;
+ struct sdap_attr_map_info *maps;
+
+ struct sdap_deref_reply dreply;
+ int num_maps;
+};
+
+static struct tevent_req *
+sdap_x_deref_search_send(TALLOC_CTX *memctx, struct tevent_context *ev,
+ struct sdap_options *opts, struct sdap_handle *sh,
+ const char *base_dn, const char *deref_attr,
+ const char **attrs, struct sdap_attr_map_info *maps,
+ int num_maps, int timeout)
+{
+ struct tevent_req *req = NULL;
+ struct tevent_req *subreq = NULL;
+ struct sdap_x_deref_search_state *state;
+ LDAPControl *ctrls[2] = { NULL, NULL };
+ int ret;
+
+ req = tevent_req_create(memctx, &state, struct sdap_x_deref_search_state);
+ if (!req) return NULL;
+
+ state->sh = sh;
+ state->maps = maps;
+ state->op = NULL;
+ state->num_maps = num_maps;
+
+ ret = sdap_x_deref_create_control(sh, deref_attr, attrs, &ctrls[0]);
+ if (ret != EOK) {
+ DEBUG(1, ("Could not create OpenLDAP deref control\n"));
+ talloc_zfree(req);
+ return NULL;
+ }
+
+ DEBUG(6, ("Dereferencing entry [%s] using OpenLDAP deref\n", base_dn));
+ subreq = sdap_get_generic_ext_send(state, ev, opts, sh, base_dn,
+ LDAP_SCOPE_BASE, NULL, attrs,
+ false, ctrls, NULL, 0, timeout,
+ sdap_x_deref_parse_entry,
+ state);
+ ldap_control_free(ctrls[0]);
+ if (!subreq) {
+ talloc_zfree(req);
+ return NULL;
+ }
+ tevent_req_set_callback(subreq, sdap_x_deref_search_done, req);
+
+ return req;
+}
+
+static int sdap_x_deref_create_control(struct sdap_handle *sh,
+ const char *deref_attr,
+ const char **attrs,
+ LDAPControl **ctrl)
+{
+ struct berval derefval;
+ int ret;
+ static LDAPDerefSpec ds;
+
+ ds.derefAttr = discard_const(deref_attr);
+ ds.attributes = discard_const(attrs);
+
+ ret = ldap_create_deref_control_value(sh->ldap, &ds, &derefval);
+ if (ret != LDAP_SUCCESS) {
+ DEBUG(1, ("sss_ldap_control_create failed: %s\n",
+ ldap_err2string(ret)));
+ return ret;
+ }
+
+ ret = sdap_control_create(sh, LDAP_CONTROL_X_DEREF,
+ 1, &derefval, 1, ctrl);
+ ldap_memfree(derefval.bv_val);
+ if (ret != EOK) {
+ DEBUG(1, ("sss_ldap_control_create failed\n"));
+ return ret;
+ }
+
+ return EOK;
+}
+
+static errno_t sdap_x_deref_parse_entry(struct sdap_handle *sh,
+ struct sdap_msg *msg,
+ void *pvt)
+{
+ errno_t ret;
+ LDAPControl **ctrls = NULL;
+ LDAPControl **next = NULL;
+ LDAPControl **start = NULL;
+ LDAPControl *derefctrl = NULL;
+ LDAPDerefRes *deref_res;
+ LDAPDerefRes *dref;
+ struct sdap_deref_attrs **res;
+ TALLOC_CTX *tmp_ctx;
+
+ struct sdap_x_deref_search_state *state = talloc_get_type(pvt,
+ struct sdap_x_deref_search_state);
+
+ tmp_ctx = talloc_new(NULL);
+ if (!tmp_ctx) return ENOMEM;
+
+ ret = ldap_get_entry_controls(state->sh->ldap, msg->msg,
+ &ctrls);
+ if (ret != LDAP_SUCCESS) {
+ DEBUG(1, ("ldap_parse_result failed\n"));
+ goto done;
+ }
+
+ if (!ctrls) {
+ DEBUG(4, ("No controls found for entry\n"));
+ ret = ENOENT;
+ goto done;
+ }
+
+ start = ctrls;
+ res = NULL;
+ do {
+ derefctrl = ldap_control_find(LDAP_CONTROL_X_DEREF, start, &next);
+ if (!derefctrl) break;
+
+ DEBUG(9, ("Got deref control\n"));
+ start = next;
+
+ ret = ldap_parse_derefresponse_control(state->sh->ldap,
+ derefctrl,
+ &deref_res);
+ if (ret != LDAP_SUCCESS) {
+ DEBUG(1, ("ldap_parse_derefresponse_control failed: %s\n",
+ ldap_err2string(ret)));
+ goto done;
+ }
+
+ for (dref = deref_res; dref; dref=dref->next) {
+ ret = sdap_parse_deref(tmp_ctx, state->maps, state->num_maps,
+ state->sh, dref, &res);
+ if (ret) {
+ DEBUG(1, ("sdap_parse_deref failed [%d]: %s\n",
+ ret, strerror(ret)));
+ goto done;
+ }
+
+ ret = add_to_deref_reply(state, state->num_maps,
+ &state->dreply, res);
+ if (ret != EOK) {
+ DEBUG(1, ("add_to_deref_reply failed.\n"));
+ goto done;
+ }
+ }
+
+ DEBUG(9, ("All deref results from a single control parsed\n"));
+ ldap_derefresponse_free(deref_res);
+ deref_res = NULL;
+ } while (derefctrl);
+
+ ret = EOK;
+done:
+ talloc_zfree(tmp_ctx);
+ ldap_controls_free(ctrls);
+ ldap_derefresponse_free(deref_res);
+ return ret;
+}
+
+static void sdap_x_deref_search_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ int ret;
+
+ ret = sdap_get_generic_ext_recv(subreq);
+ talloc_zfree(subreq);
+ if (ret) {
+ DEBUG(4, ("sdap_get_generic_ext_recv failed [%d]: %s\n",
+ ret, strerror(ret)));
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+static int
+sdap_x_deref_search_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ size_t *reply_count,
+ struct sdap_deref_attrs ***reply)
+{
+ struct sdap_x_deref_search_state *state = tevent_req_data(req,
+ struct sdap_x_deref_search_state);
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ *reply_count = state->dreply.reply_count;
+ *reply = talloc_steal(mem_ctx, state->dreply.reply);
+
+ return EOK;
+}
+
/* ==Attribute scoped search============================================ */
struct sdap_asq_search_state {
struct sdap_attr_map_info *maps;