[SSSD] [PATCH] added generic LDAP search sdap_get_generic_send/_recv

Sumit Bose sbose at redhat.com
Mon Oct 19 12:45:41 UTC 2009


On Fri, Oct 16, 2009 at 02:47:38PM -0400, Simo Sorce wrote:
> On Fri, 2009-10-16 at 11:58 +0200, Sumit Bose wrote:
> > Hi,
> > 
> > currently the sdap interface is only used by the ID provider and
> > consequently only offers special search for users and groups. This
> > patch
> > adds a generic search, i.e. the caller can specify the search base and
> > and an attribute list. This will be used by the IPA access provider to
> > load HABC rules from the IPA server.
> 
> Mostly ok but I have a few remarks.
> 
> 1. please move sdap_parse_generic_entry() in another section, only
> forward function declarations should stay between the state structure
> and the _send() function.

moved to sdap.h

> 
> 2. In _send() make sure you set to 0 any structure member that is not
> initialized with a value as tevent_req_create() does not zero the state
> structure, therefore you may find uninitialized values.

done

> 
> 3. Use SDAP_NETWORK_TIMEOUT with dp_opt_get_int for the timeouts, no
> FIXMEs please :)

done

> 
> 4. Why do you return a list of reply_item structures instead of an array
> of sysdb_attrs and and a counter ?
> 

done, new patch attached.

bye,
Sumit
-------------- next part --------------
>From c9cd8e2c0c103a0a91adc165504b17d7d14ca113 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Thu, 17 Sep 2009 11:12:36 +0200
Subject: [PATCH] added generic LDAP search sdap_get_generic_send/_recv

---
 server/providers/ldap/sdap.c       |   85 +++++++++++++++
 server/providers/ldap/sdap.h       |    5 +
 server/providers/ldap/sdap_async.c |  201 ++++++++++++++++++++++++++++++++++++
 server/providers/ldap/sdap_async.h |   13 +++
 4 files changed, 304 insertions(+), 0 deletions(-)

diff --git a/server/providers/ldap/sdap.c b/server/providers/ldap/sdap.c
index 7eaa1e9..9268692 100644
--- a/server/providers/ldap/sdap.c
+++ b/server/providers/ldap/sdap.c
@@ -191,6 +191,91 @@ fail:
     return ret;
 }
 
+int sdap_parse_generic_entry(TALLOC_CTX *memctx,
+                                    struct sdap_handle *sh,
+                                    struct sdap_msg *sm,
+                                    struct sysdb_attrs **_attrs)
+{
+    struct sysdb_attrs *attrs;
+    BerElement *ber = NULL;
+    struct berval **vals;
+    struct ldb_val v;
+    char *str;
+    int lerrno;
+    int i;
+    int ret;
+
+    lerrno = 0;
+    ldap_set_option(sh->ldap, LDAP_OPT_RESULT_CODE, &lerrno);
+
+    attrs = sysdb_new_attrs(memctx);
+    if (!attrs) return ENOMEM;
+
+    str = ldap_get_dn(sh->ldap, sm->msg);
+    if (!str) {
+        ldap_get_option(sh->ldap, LDAP_OPT_RESULT_CODE, &lerrno);
+        DEBUG(1, ("ldap_get_dn failed: %d(%s)\n",
+                  lerrno, ldap_err2string(lerrno)));
+        ret = EIO;
+        goto fail;
+    }
+
+    DEBUG(9, ("OriginalDN: [%s].\n", str));
+    ret = sysdb_attrs_add_string(attrs, SYSDB_ORIG_DN, str);
+    if (ret) goto fail;
+    ldap_memfree(str);
+
+    str = ldap_first_attribute(sh->ldap, sm->msg, &ber);
+    if (!str) {
+        ldap_get_option(sh->ldap, LDAP_OPT_RESULT_CODE, &lerrno);
+        DEBUG(9, ("Entry has no attributes [%d(%s)]!?\n",
+                  lerrno, ldap_err2string(lerrno)));
+    }
+    while (str) {
+        vals = ldap_get_values_len(sh->ldap, sm->msg, str);
+        if (!vals) {
+            ldap_get_option(sh->ldap, LDAP_OPT_RESULT_CODE, &lerrno);
+            DEBUG(1, ("LDAP Library error: %d(%s)",
+                      lerrno, ldap_err2string(lerrno)));
+            ret = EIO;
+            goto fail;
+        }
+        if (!vals[0]) {
+            DEBUG(1, ("Missing value after ldap_get_values() ??\n"));
+            ret = EINVAL;
+            goto fail;
+        }
+        for (i = 0; vals[i]; i++) {
+            v.data = (uint8_t *) vals[i]->bv_val;
+            v.length = vals[i]->bv_len;
+
+            ret = sysdb_attrs_add_val(attrs, str, &v);
+            if (ret) goto fail;
+        }
+        ldap_value_free_len(vals);
+
+        ldap_memfree(str);
+        str = ldap_next_attribute(sh->ldap, sm->msg, ber);
+    }
+    ber_free(ber, 0);
+
+    ldap_get_option(sh->ldap, LDAP_OPT_RESULT_CODE, &lerrno);
+    if (lerrno) {
+        DEBUG(1, ("LDAP Library error: %d(%s)",
+                  lerrno, ldap_err2string(lerrno)));
+        ret = EIO;
+        goto fail;
+    }
+
+    *_attrs = attrs;
+    return EOK;
+
+fail:
+    if (ber) ber_free(ber, 0);
+    talloc_free(attrs);
+    return ret;
+}
+
 /* This function converts an ldap message into a sysdb_attrs structure.
  * It converts only known user attributes, the rest are ignored.
  * If the entry is not that of an user an error is returned.
diff --git a/server/providers/ldap/sdap.h b/server/providers/ldap/sdap.h
index 31c7289..3abe2d6 100644
--- a/server/providers/ldap/sdap.h
+++ b/server/providers/ldap/sdap.h
@@ -203,6 +203,11 @@ 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);
 
+int sdap_parse_generic_entry(TALLOC_CTX *memctx,
+                                    struct sdap_handle *sh,
+                                    struct sdap_msg *sm,
+                                    struct sysdb_attrs **_attrs);
+
 int sdap_get_msg_dn(TALLOC_CTX *memctx, struct sdap_handle *sh,
                     struct sdap_msg *sm, char **_dn);
 
diff --git a/server/providers/ldap/sdap_async.c b/server/providers/ldap/sdap_async.c
index f088e51..6350433 100644
--- a/server/providers/ldap/sdap_async.c
+++ b/server/providers/ldap/sdap_async.c
@@ -30,6 +30,8 @@
 
 #define LDAP_X_SSSD_PASSWORD_EXPIRED 0x555D
 
+#define REPLY_REALLOC_INCREMENT 10
+
 static void make_realm_upper_case(const char *upn)
 {
     char *c;
@@ -3020,3 +3022,202 @@ int sdap_cli_connect_recv(struct tevent_req *req, TALLOC_CTX *memctx,
     }
     return EOK;
 }
+
+/* ==Generic Search============================================ */
+
+struct sdap_get_generic_state {
+    struct tevent_context *ev;
+    struct sdap_options *opts;
+    struct sdap_handle *sh;
+    struct sss_domain_info *dom;
+    const char **attrs;
+    const char *filter;
+    const char *search_base;
+    struct sysdb_attrs **reply;
+    size_t reply_max;
+    size_t reply_count;
+
+    struct sysdb_handle *handle;
+    struct sdap_op *op;
+};
+
+static errno_t add_to_reply(TALLOC_CTX *memctx,
+                            struct sdap_get_generic_state *state,
+                            struct sysdb_attrs *msg);
+
+static void sdap_get_generic_done(struct sdap_op *op,
+                                 struct sdap_msg *reply,
+                                 int error, void *pvt);
+
+struct tevent_req *sdap_get_generic_send(TALLOC_CTX *memctx,
+                                       struct tevent_context *ev,
+                                       struct sss_domain_info *dom,
+                                       struct sysdb_ctx *sysdb,
+                                       struct sdap_options *opts,
+                                       struct sdap_handle *sh,
+                                       const char **attrs,
+                                       const char *filter,
+                                       const char *search_base)
+{
+    struct tevent_req *req = NULL;
+    struct sdap_get_generic_state *state = NULL;
+    int lret;
+    int ret;
+    int msgid;
+
+    req = tevent_req_create(memctx, &state, struct sdap_get_generic_state);
+    if (!req) return NULL;
+
+    state->ev = ev;
+    state->opts = opts;
+    state->dom = dom;
+    state->sh = sh;
+    state->filter = filter;
+    state->attrs = attrs;
+    state->search_base = search_base;
+    state->reply = NULL;
+    state->reply_max = 0;
+    state->reply_count = 0;
+    state->op = NULL;
+    state->handle = NULL;
+
+    DEBUG(7, ("calling ldap_search_ext with [%s][%s].\n", state->filter,
+                                                          state->search_base));
+    if (debug_level >= 7) {
+        int i;
+
+        for (i = 0; state->attrs[i]; i++) {
+            DEBUG(7, ("Requesting attrs: [%s]\n", state->attrs[i]));
+        }
+    }
+
+    lret = ldap_search_ext(state->sh->ldap, state->search_base,
+                           LDAP_SCOPE_SUBTREE, state->filter,
+                           discard_const(state->attrs),
+                           false, NULL, NULL, NULL, 0, &msgid);
+    if (lret != LDAP_SUCCESS) {
+        DEBUG(3, ("ldap_search_ext failed: %s\n", ldap_err2string(lret)));
+        ret = EIO;
+        goto fail;
+    }
+    DEBUG(8, ("ldap_search_ext called, msgid = %d\n", msgid));
+
+    ret = sdap_op_add(state, state->ev, state->sh, msgid,
+                      sdap_get_generic_done, req,
+                      dp_opt_get_int(state->opts->basic,SDAP_SEARCH_TIMEOUT),
+                      &state->op);
+    if (ret != EOK) {
+        DEBUG(1, ("Failed to set up operation!\n"));
+        goto fail;
+    }
+
+    return req;
+
+fail:
+    tevent_req_error(req, ret);
+    tevent_req_post(req, ev);
+    return req;
+}
+
+
+static void sdap_get_generic_done(struct sdap_op *op,
+                                 struct sdap_msg *reply,
+                                 int error, void *pvt)
+{
+    struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
+    struct sdap_get_generic_state *state = tevent_req_data(req,
+                                            struct sdap_get_generic_state);
+    int ret;
+    struct sysdb_attrs *attrs;
+
+    if (error) {
+        tevent_req_error(req, error);
+        return;
+    }
+
+    switch (ldap_msgtype(reply->msg)) {
+    case LDAP_RES_SEARCH_REFERENCE:
+        /* ignore references for now */
+        talloc_free(reply);
+
+        /* unlock the operation so that we can proceed with the next result */
+        sdap_unlock_next_reply(state->op);
+        break;
+
+    case LDAP_RES_SEARCH_ENTRY:
+        ret = sdap_parse_generic_entry(state, state->sh, reply, &attrs);
+        if (ret != EOK) {
+            DEBUG(1, ("sdap_parse_generic_entry failed.\n"));
+            tevent_req_error(req, ENOMEM);
+            return;
+        }
+
+        ret = add_to_reply(state, state, attrs);
+        if (ret != EOK) {
+            DEBUG(1, ("add_to_reply failed.\n"));
+            tevent_req_error(req, ret);
+            return;
+        }
+
+        sdap_unlock_next_reply(state->op);
+        break;
+    case LDAP_RES_SEARCH_RESULT:
+        tevent_req_done(req);
+        return;
+
+        break;
+    default:
+        /* what is going on here !? */
+        tevent_req_error(req, EIO);
+        return;
+    }
+
+    return;
+}
+
+int sdap_get_generic_recv(struct tevent_req *req,
+                          TALLOC_CTX *mem_ctx,
+                          size_t *reply_count,
+                          struct sysdb_attrs ***reply)
+{
+    struct sdap_get_generic_state *state = tevent_req_data(req,
+                                            struct sdap_get_generic_state);
+    enum tevent_req_state tstate;
+    uint64_t err;
+    int i;
+
+    if (tevent_req_is_error(req, &tstate, &err)) {
+        if (err) return err;
+        return EIO;
+    }
+
+    *reply_count = state->reply_count;
+    *reply = talloc_steal(mem_ctx, state->reply);
+    for (i = 0; i < state->reply_count; i++) {
+        talloc_steal(mem_ctx, state->reply[i]);
+    }
+
+    return EOK;
+}
+
+static errno_t add_to_reply(TALLOC_CTX *memctx,
+                            struct sdap_get_generic_state *state,
+                            struct sysdb_attrs *msg)
+{
+    struct sysdb_attrs **dummy;
+
+    if (state->reply == NULL || state->reply_max == state->reply_count) {
+        state->reply_max += REPLY_REALLOC_INCREMENT;
+        dummy = talloc_realloc(memctx, state->reply, struct sysdb_attrs *,
+                               state->reply_max);
+        if (dummy == NULL) {
+            DEBUG(1, ("talloc_realloc failed.\n"));
+            return ENOMEM;
+        }
+        state->reply = dummy;
+    }
+
+    state->reply[state->reply_count++] = talloc_steal(state->reply, msg);
+
+    return EOK;
+}
diff --git a/server/providers/ldap/sdap_async.h b/server/providers/ldap/sdap_async.h
index c50133c..8410f3d 100644
--- a/server/providers/ldap/sdap_async.h
+++ b/server/providers/ldap/sdap_async.h
@@ -95,3 +95,16 @@ struct tevent_req *sdap_cli_connect_send(TALLOC_CTX *memctx,
                                                 struct sdap_options *opts);
 int sdap_cli_connect_recv(struct tevent_req *req, TALLOC_CTX *memctx,
                                  struct sdap_handle **gsh);
+
+struct tevent_req *sdap_get_generic_send(TALLOC_CTX *memctx,
+                                       struct tevent_context *ev,
+                                       struct sss_domain_info *dom,
+                                       struct sysdb_ctx *sysdb,
+                                       struct sdap_options *opts,
+                                       struct sdap_handle *sh,
+                                       const char **attrs,
+                                       const char *filter,
+                                       const char *search_base);
+int sdap_get_generic_recv(struct tevent_req *req,
+                         TALLOC_CTX *mem_ctx, size_t *reply_count,
+                         struct sysdb_attrs ***reply_list);
-- 
1.6.2.5



More information about the sssd-devel mailing list