Blob Blame History Raw
From 431198674303beea2a6a25af6d3fa4e852995b26 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Mon, 16 Dec 2013 02:41:53 +0100
Subject: [PATCH 67/71] LDAP: Add enum request with custom connection

This commit changes the enumerate-sdap-domain request to accept a
connection context per object that can be enumerated. Internally in the
request, an sdap_id_op is also created per enumerated object type.

This change will allow i.e. users to be enumerated using GC connection,
while keeping the LDAP connection for groups and services.
---
 src/providers/ldap/sdap_async_enum.c | 309 +++++++++++++++++++++--------------
 src/providers/ldap/sdap_async_enum.h |  11 ++
 2 files changed, 193 insertions(+), 127 deletions(-)

diff --git a/src/providers/ldap/sdap_async_enum.c b/src/providers/ldap/sdap_async_enum.c
index 8487f9a13b279bc71f633590bbab163945fc8f7c..cbc56be20526e6c2323f9fd1b49038dd4bf13fe5 100644
--- a/src/providers/ldap/sdap_async_enum.c
+++ b/src/providers/ldap/sdap_async_enum.c
@@ -47,49 +47,56 @@ static struct tevent_req *enum_groups_send(TALLOC_CTX *memctx,
                                           bool purge);
 static errno_t enum_groups_recv(struct tevent_req *req);
 
-/* ==Enumeration-Request==================================================== */
-struct sdap_dom_enum_state {
+/* ==Enumeration-Request-with-connections=================================== */
+struct sdap_dom_enum_ex_state {
     struct tevent_context *ev;
     struct sdap_id_ctx *ctx;
     struct sdap_domain *sdom;
-    struct sdap_id_conn_ctx *conn;
-    struct sdap_id_op *op;
+
+    struct sdap_id_conn_ctx *user_conn;
+    struct sdap_id_conn_ctx *group_conn;
+    struct sdap_id_conn_ctx *svc_conn;
+    struct sdap_id_op *user_op;
+    struct sdap_id_op *group_op;
+    struct sdap_id_op *svc_op;
 
     bool purge;
 };
 
-static errno_t sdap_dom_enum_retry(struct tevent_req *req);
-static void sdap_dom_enum_conn_done(struct tevent_req *subreq);
-static void sdap_dom_enum_users_done(struct tevent_req *subreq);
-static void sdap_dom_enum_groups_done(struct tevent_req *subreq);
-static void sdap_dom_enum_services_done(struct tevent_req *subreq);
+static errno_t sdap_dom_enum_ex_retry(struct tevent_req *req,
+                                      struct sdap_id_op *op,
+                                      tevent_req_fn tcb);
+static bool sdap_dom_enum_ex_connected(struct tevent_req *subreq);
+static void sdap_dom_enum_ex_get_users(struct tevent_req *subreq);
+static void sdap_dom_enum_ex_users_done(struct tevent_req *subreq);
+static void sdap_dom_enum_ex_get_groups(struct tevent_req *subreq);
+static void sdap_dom_enum_ex_groups_done(struct tevent_req *subreq);
+static void sdap_dom_enum_ex_get_svcs(struct tevent_req *subreq);
+static void sdap_dom_enum_ex_svcs_done(struct tevent_req *subreq);
 
 struct tevent_req *
-sdap_dom_enum_send(TALLOC_CTX *memctx,
-                   struct tevent_context *ev,
-                   struct sdap_id_ctx *ctx,
-                   struct sdap_domain *sdom,
-                   struct sdap_id_conn_ctx *conn)
+sdap_dom_enum_ex_send(TALLOC_CTX *memctx,
+                      struct tevent_context *ev,
+                      struct sdap_id_ctx *ctx,
+                      struct sdap_domain *sdom,
+                      struct sdap_id_conn_ctx *user_conn,
+                      struct sdap_id_conn_ctx *group_conn,
+                      struct sdap_id_conn_ctx *svc_conn)
 {
     struct tevent_req *req;
-    struct sdap_dom_enum_state *state;
+    struct sdap_dom_enum_ex_state *state;
     int t;
     errno_t ret;
 
-    req = tevent_req_create(ctx, &state, struct sdap_dom_enum_state);
-    if (!req) return NULL;
+    req = tevent_req_create(ctx, &state, struct sdap_dom_enum_ex_state);
+    if (req == NULL) return NULL;
 
     state->ev = ev;
     state->ctx = ctx;
     state->sdom = sdom;
-    state->conn = conn;
-    state->op = sdap_id_op_create(state, state->ctx->conn->conn_cache);
-    if (!state->op) {
-        DEBUG(SSSDBG_CRIT_FAILURE, ("sdap_id_op_create failed\n"));
-        ret = EIO;
-        goto fail;
-    }
-
+    state->user_conn = user_conn;
+    state->group_conn = group_conn;
+    state->svc_conn = svc_conn;
     sdom->last_enum = tevent_timeval_current();
 
     t = dp_opt_get_int(ctx->opts->basic, SDAP_CACHE_PURGE_TIMEOUT);
@@ -97,9 +104,17 @@ sdap_dom_enum_send(TALLOC_CTX *memctx,
         state->purge = true;
     }
 
-    ret = sdap_dom_enum_retry(req);
+    state->user_op = sdap_id_op_create(state, user_conn->conn_cache);
+    if (state->user_op == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("sdap_id_op_create failed for users\n"));
+        ret = EIO;
+        goto fail;
+    }
+
+    ret = sdap_dom_enum_ex_retry(req, state->user_op,
+                                 sdap_dom_enum_ex_get_users);
     if (ret != EOK) {
-        DEBUG(SSSDBG_OP_FAILURE, ("ldap_id_enumerate_retry failed\n"));
+        DEBUG(SSSDBG_OP_FAILURE, ("sdap_dom_enum_ex_retry failed\n"));
         goto fail;
     }
 
@@ -111,31 +126,32 @@ fail:
     return req;
 }
 
-static errno_t sdap_dom_enum_retry(struct tevent_req *req)
+static errno_t sdap_dom_enum_ex_retry(struct tevent_req *req,
+                                      struct sdap_id_op *op,
+                                      tevent_req_fn tcb)
 {
-    struct sdap_dom_enum_state *state = tevent_req_data(req,
-                                                   struct sdap_dom_enum_state);
+    struct sdap_dom_enum_ex_state *state = tevent_req_data(req,
+                                                struct sdap_dom_enum_ex_state);
     struct tevent_req *subreq;
     errno_t ret;
 
-    subreq = sdap_id_op_connect_send(state->op, state, &ret);
+    subreq = sdap_id_op_connect_send(op, state, &ret);
     if (subreq == NULL) {
         DEBUG(SSSDBG_OP_FAILURE,
               ("sdap_id_op_connect_send failed: %d\n", ret));
         return ret;
     }
 
-    tevent_req_set_callback(subreq, sdap_dom_enum_conn_done, req);
+    tevent_req_set_callback(subreq, tcb, req);
     return EOK;
 }
 
-static void sdap_dom_enum_conn_done(struct tevent_req *subreq)
+static bool sdap_dom_enum_ex_connected(struct tevent_req *subreq)
 {
+    errno_t ret;
+    int dp_error;
     struct tevent_req *req = tevent_req_callback_data(subreq,
                                                       struct tevent_req);
-    struct sdap_dom_enum_state *state = tevent_req_data(req,
-                                                   struct sdap_dom_enum_state);
-    int ret, dp_error;
 
     ret = sdap_id_op_connect_recv(subreq, &dp_error);
     talloc_zfree(subreq);
@@ -150,150 +166,173 @@ static void sdap_dom_enum_conn_done(struct tevent_req *subreq)
                    "LDAP server: (%d)[%s]\n", ret, strerror(ret)));
             tevent_req_error(req, ret);
         }
+        return false;
+    }
+
+    return true;
+}
+
+static void sdap_dom_enum_ex_get_users(struct tevent_req *subreq)
+{
+    struct tevent_req *req = tevent_req_callback_data(subreq,
+                                                      struct tevent_req);
+    struct sdap_dom_enum_ex_state *state = tevent_req_data(req,
+                                                struct sdap_dom_enum_ex_state);
+
+    if (sdap_dom_enum_ex_connected(subreq) == false) {
         return;
     }
 
     subreq = enum_users_send(state, state->ev,
                              state->ctx, state->sdom,
-                             state->op, state->purge);
+                             state->user_op, state->purge);
     if (subreq == NULL) {
         tevent_req_error(req, ENOMEM);
         return;
     }
-    tevent_req_set_callback(subreq, sdap_dom_enum_users_done, req);
+    tevent_req_set_callback(subreq, sdap_dom_enum_ex_users_done, req);
 }
 
-static void sdap_dom_enum_users_done(struct tevent_req *subreq)
+static void sdap_dom_enum_ex_users_done(struct tevent_req *subreq)
 {
     struct tevent_req *req = tevent_req_callback_data(subreq,
                                                       struct tevent_req);
-    struct sdap_dom_enum_state *state = tevent_req_data(req,
-                                                   struct sdap_dom_enum_state);
-    uint64_t err = 0;
-    int ret, dp_error = DP_ERR_FATAL;
+    struct sdap_dom_enum_ex_state *state = tevent_req_data(req,
+                                                struct sdap_dom_enum_ex_state);
+    errno_t ret;
+    int dp_error;
 
-    err = enum_users_recv(subreq);
+    ret = enum_users_recv(subreq);
     talloc_zfree(subreq);
-    if (err != EOK && err != ENOENT) {
-        /* We call sdap_id_op_done only on error
-         * as the connection is reused by groups enumeration */
-        ret = sdap_id_op_done(state->op, (int)err, &dp_error);
-        if (dp_error == DP_ERR_OK) {
-            /* retry */
-            ret = sdap_dom_enum_retry(req);
-            if (ret == EOK) {
-                return;
-            }
-
-            dp_error = DP_ERR_FATAL;
-        }
-
-        if (dp_error == DP_ERR_OFFLINE) {
-            tevent_req_done(req);
-        } else {
-            DEBUG(SSSDBG_OP_FAILURE,
-                  ("User enumeration failed with: (%d)[%s]\n",
-                   ret, strerror(ret)));
+    ret = sdap_id_op_done(state->user_op, ret, &dp_error);
+    if (dp_error == DP_ERR_OK && ret != EOK) {
+        /* retry */
+        ret = sdap_dom_enum_ex_retry(req, state->user_op,
+                                     sdap_dom_enum_ex_get_users);
+        if (ret != EOK) {
             tevent_req_error(req, ret);
+            return;
         }
         return;
     }
 
+    state->group_op = sdap_id_op_create(state, state->group_conn->conn_cache);
+    if (state->group_op == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("sdap_id_op_create failed for groups\n"));
+        tevent_req_error(req, EIO);
+        return;
+    }
+
+    ret = sdap_dom_enum_ex_retry(req, state->group_op,
+                                 sdap_dom_enum_ex_get_groups);
+    if (ret != EOK) {
+        tevent_req_error(req, ret);
+        return;
+    }
+
+    /* Continues to sdap_dom_enum_ex_get_groups */
+}
+
+static void sdap_dom_enum_ex_get_groups(struct tevent_req *subreq)
+{
+    struct tevent_req *req = tevent_req_callback_data(subreq,
+                                                      struct tevent_req);
+    struct sdap_dom_enum_ex_state *state = tevent_req_data(req,
+                                                struct sdap_dom_enum_ex_state);
+
+    if (sdap_dom_enum_ex_connected(subreq) == false) {
+        return;
+    }
+
     subreq = enum_groups_send(state, state->ev, state->ctx,
                               state->sdom,
-                              state->op, state->purge);
+                              state->group_op, state->purge);
     if (subreq == NULL) {
         tevent_req_error(req, ENOMEM);
         return;
     }
-    tevent_req_set_callback(subreq, sdap_dom_enum_groups_done, req);
+    tevent_req_set_callback(subreq, sdap_dom_enum_ex_groups_done, req);
 }
 
-static void sdap_dom_enum_groups_done(struct tevent_req *subreq)
+static void sdap_dom_enum_ex_groups_done(struct tevent_req *subreq)
 {
     struct tevent_req *req = tevent_req_callback_data(subreq,
                                                       struct tevent_req);
-    struct sdap_dom_enum_state *state = tevent_req_data(req,
-                                                   struct sdap_dom_enum_state);
-    uint64_t err = 0;
-    int ret, dp_error = DP_ERR_FATAL;
+    struct sdap_dom_enum_ex_state *state = tevent_req_data(req,
+                                                struct sdap_dom_enum_ex_state);
+    int ret;
+    int dp_error;
 
-    err = enum_groups_recv(subreq);
+    ret = enum_groups_recv(subreq);
     talloc_zfree(subreq);
-    if (err != EOK && err != ENOENT) {
-        /* We call sdap_id_op_done only on error
-         * as the connection is reused by services enumeration */
-        ret = sdap_id_op_done(state->op, (int)err, &dp_error);
-        if (dp_error == DP_ERR_OK && ret != EOK) {
-            /* retry */
-            ret = sdap_dom_enum_retry(req);
-            if (ret == EOK) {
-                return;
-            }
-
-            dp_error = DP_ERR_FATAL;
-        }
-
+    ret = sdap_id_op_done(state->group_op, ret, &dp_error);
+    if (dp_error == DP_ERR_OK && ret != EOK) {
+        /* retry */
+        ret = sdap_dom_enum_ex_retry(req, state->group_op,
+                                     sdap_dom_enum_ex_get_groups);
         if (ret != EOK) {
-            if (dp_error == DP_ERR_OFFLINE) {
-                tevent_req_done(req);
-            } else {
-                DEBUG(SSSDBG_OP_FAILURE,
-                      ("Group enumeration failed with: (%d)[%s]\n",
-                       ret, strerror(ret)));
-                tevent_req_error(req, ret);
-            }
-
+            tevent_req_error(req, ret);
             return;
         }
+        return;
+    }
+
+
+    state->svc_op = sdap_id_op_create(state, state->svc_conn->conn_cache);
+    if (state->svc_op == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("sdap_id_op_create failed for svcs\n"));
+        tevent_req_error(req, EIO);
+        return;
+    }
+
+    ret = sdap_dom_enum_ex_retry(req, state->svc_op,
+                                 sdap_dom_enum_ex_get_svcs);
+    if (ret != EOK) {
+        tevent_req_error(req, ret);
+        return;
+    }
+}
+
+static void sdap_dom_enum_ex_get_svcs(struct tevent_req *subreq)
+{
+    struct tevent_req *req = tevent_req_callback_data(subreq,
+                                                      struct tevent_req);
+    struct sdap_dom_enum_ex_state *state = tevent_req_data(req,
+                                                struct sdap_dom_enum_ex_state);
+
+    if (sdap_dom_enum_ex_connected(subreq) == false) {
+        return;
     }
 
     subreq = enum_services_send(state, state->ev, state->ctx,
-                                state->op, state->purge);
+                                state->svc_op, state->purge);
     if (!subreq) {
         tevent_req_error(req, ENOMEM);
         return;
     }
-    tevent_req_set_callback(subreq, sdap_dom_enum_services_done, req);
+    tevent_req_set_callback(subreq, sdap_dom_enum_ex_svcs_done, req);
 }
 
-static void sdap_dom_enum_services_done(struct tevent_req *subreq)
+static void sdap_dom_enum_ex_svcs_done(struct tevent_req *subreq)
 {
-    errno_t ret;
-    int dp_error = DP_ERR_FATAL;
     struct tevent_req *req = tevent_req_callback_data(subreq,
                                                       struct tevent_req);
-    struct sdap_dom_enum_state *state = tevent_req_data(req,
-                                                   struct sdap_dom_enum_state);
+    struct sdap_dom_enum_ex_state *state = tevent_req_data(req,
+                                                struct sdap_dom_enum_ex_state);
+    int ret;
+    int dp_error;
 
     ret = enum_services_recv(subreq);
     talloc_zfree(subreq);
-    if (ret == ENOENT) ret = EOK;
-
-    /* All enumerations are complete, so conclude the
-     * id_op
-     */
-    ret = sdap_id_op_done(state->op, ret, &dp_error);
+    ret = sdap_id_op_done(state->svc_op, ret, &dp_error);
     if (dp_error == DP_ERR_OK && ret != EOK) {
         /* retry */
-        ret = sdap_dom_enum_retry(req);
-        if (ret == EOK) {
-            return;
-        }
-
-        dp_error = DP_ERR_FATAL;
-    }
-
-    if (ret != EOK) {
-        if (dp_error == DP_ERR_OFFLINE) {
-            tevent_req_done(req);
-        } else {
-            DEBUG(SSSDBG_MINOR_FAILURE,
-                  ("Service enumeration failed with: (%d)[%s]\n",
-                   ret, strerror(ret)));
+        ret = sdap_dom_enum_ex_retry(req, state->user_op,
+                                     sdap_dom_enum_ex_get_svcs);
+        if (ret != EOK) {
             tevent_req_error(req, ret);
+            return;
         }
-
         return;
     }
 
@@ -323,11 +362,27 @@ static void sdap_dom_enum_services_done(struct tevent_req *subreq)
     tevent_req_done(req);
 }
 
+errno_t sdap_dom_enum_ex_recv(struct tevent_req *req)
+{
+    TEVENT_REQ_RETURN_ON_ERROR(req);
+
+    return EOK;
+}
+
+/* ==Enumeration-Request==================================================== */
+struct tevent_req *
+sdap_dom_enum_send(TALLOC_CTX *memctx,
+                   struct tevent_context *ev,
+                   struct sdap_id_ctx *ctx,
+                   struct sdap_domain *sdom,
+                   struct sdap_id_conn_ctx *conn)
+{
+    return sdap_dom_enum_ex_send(memctx, ev, ctx, sdom, conn, conn, conn);
+}
+
 errno_t sdap_dom_enum_recv(struct tevent_req *req)
 {
-    TEVENT_REQ_RETURN_ON_ERROR(req);
-
-    return EOK;
+    return sdap_dom_enum_ex_recv(req);
 }
 
 /* ==User-Enumeration===================================================== */
diff --git a/src/providers/ldap/sdap_async_enum.h b/src/providers/ldap/sdap_async_enum.h
index 04ec8c6dcbec4bcce0de67b9e10acc857c9e9416..2da38f988913fa0d6f252697925e50e05eb794a6 100644
--- a/src/providers/ldap/sdap_async_enum.h
+++ b/src/providers/ldap/sdap_async_enum.h
@@ -27,6 +27,17 @@
 #define _SDAP_ASYNC_ENUM_H_
 
 struct tevent_req *
+sdap_dom_enum_ex_send(TALLOC_CTX *memctx,
+                      struct tevent_context *ev,
+                      struct sdap_id_ctx *ctx,
+                      struct sdap_domain *sdom,
+                      struct sdap_id_conn_ctx *user_conn,
+                      struct sdap_id_conn_ctx *group_conn,
+                      struct sdap_id_conn_ctx *svc_conn);
+
+errno_t sdap_dom_enum_ex_recv(struct tevent_req *req);
+
+struct tevent_req *
 sdap_dom_enum_send(TALLOC_CTX *memctx,
                    struct tevent_context *ev,
                    struct sdap_id_ctx *ctx,
-- 
1.8.4.2