From 0138b83ce7ec454b9398c51c9ede08d97370b32b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Mon, 9 Sep 2013 15:52:03 +0200
Subject: [PATCH 1/8] ad: shortcut if possible during get object by ID or SID

When getByID or getBySID comes from responder, the request doesn't
necessarily have to contain correct domain, since responder iterates
over all domains until it finds a match.

Every domain has its own ID range, so we can simply shortcut if
domain does not match and avoid LDAP round trip. Responder will
continue with next domain until it finds the correct one.
---
 src/providers/ad/ad_id.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 96 insertions(+)

diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c
index 20f9c23fa8d1d272f91c0b886bd1e2e3a2522320..87b69c66892ebfa48a1067c63006f3e3bd2e7444 100644
--- a/src/providers/ad/ad_id.c
+++ b/src/providers/ad/ad_id.c
@@ -20,10 +20,12 @@
     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 #include "util/util.h"
+#include "util/strtonum.h"
 #include "providers/ad/ad_common.h"
 #include "providers/ad/ad_id.h"
 #include "providers/ad/ad_domain_info.h"
 #include "providers/ldap/sdap_async_enum.h"
+#include "providers/ldap/sdap_idmap.h"
 
 struct ad_handle_acct_info_state {
     struct be_req *breq;
@@ -222,6 +224,84 @@ get_conn_list(struct be_req *breq, struct ad_id_ctx *ad_ctx,
     return clist;
 }
 
+static errno_t ad_account_can_shortcut(struct be_ctx *be_ctx,
+                                       struct sdap_idmap_ctx *idmap_ctx,
+                                       int filter_type,
+                                       const char *filter_value,
+                                       const char *filter_domain,
+                                       bool *_shortcut)
+{
+    struct sss_domain_info *domain = be_ctx->domain;
+    struct sss_domain_info *req_dom = NULL;
+    enum idmap_error_code err;
+    char *sid = NULL;
+    const char *csid = NULL;
+    uint32_t id;
+    bool shortcut = false;
+    errno_t ret;
+
+    if (!sdap_idmap_domain_has_algorithmic_mapping(idmap_ctx, domain->name,
+                                                   domain->domain_id)) {
+        shortcut = false;
+        ret = EOK;
+        goto done;
+    }
+
+    switch (filter_type) {
+    case BE_FILTER_IDNUM:
+        /* convert value to ID */
+        errno = 0;
+        id = strtouint32(filter_value, NULL, 10);
+        if (errno != 0) {
+            ret = errno;
+            goto done;
+        }
+
+        /* convert the ID to its SID equivalent */
+        err = sss_idmap_unix_to_sid(idmap_ctx->map, id, &sid);
+        if (err != IDMAP_SUCCESS) {
+            DEBUG(SSSDBG_MINOR_FAILURE, ("Mapping ID [%s] to SID failed: "
+                  "[%s]\n", filter_value, idmap_error_string(err)));
+            ret = EIO;
+            goto done;
+        }
+        /* fall through */
+    case BE_FILTER_SECID:
+        csid = sid == NULL ? filter_value : sid;
+
+        req_dom = find_subdomain_by_sid(domain, csid);
+        if (req_dom == NULL) {
+            DEBUG(SSSDBG_OP_FAILURE, ("Invalid domain\n"));
+            ret = ERR_DOMAIN_NOT_FOUND;
+            goto done;
+        }
+
+        if (strcasecmp(req_dom->name, filter_domain) != 0) {
+            shortcut = true;
+        } else {
+            shortcut = false;
+        }
+        break;
+    default:
+        shortcut = false;
+        break;
+    }
+
+    ret = EOK;
+
+done:
+    if (sid != NULL) {
+        /* FIXME: use library function when #2133 is fixed */
+        talloc_free(sid);
+    }
+
+    if (ret == EOK) {
+        *_shortcut = shortcut;
+    }
+
+    return ret;
+}
+
 static void ad_account_info_complete(struct tevent_req *req);
 
 void
@@ -235,6 +315,7 @@ ad_account_info_handler(struct be_req *be_req)
     struct sss_domain_info *dom;
     struct sdap_domain *sdom;
     struct sdap_id_conn_ctx **clist;
+    bool shortcut;
     errno_t ret;
 
     ad_ctx = talloc_get_type(be_ctx->bet_info[BET_ID].pvt_bet_data,
@@ -246,6 +327,21 @@ ad_account_info_handler(struct be_req *be_req)
         return be_req_terminate(be_req, DP_ERR_OFFLINE, EAGAIN, "Offline");
     }
 
+    /* Try to shortcut if this is ID or SID search and it belongs to
+     * other domain range than is in ar->domain. */
+    ret = ad_account_can_shortcut(be_ctx, sdap_id_ctx->opts->idmap_ctx,
+                                  ar->filter_type, ar->filter_value,
+                                  ar->domain, &shortcut);
+    if (ret != EOK) {
+        goto fail;
+    }
+
+    if (shortcut) {
+        DEBUG(SSSDBG_TRACE_FUNC, ("This ID is from different domain\n"));
+        be_req_terminate(be_req, DP_ERR_OK, EOK, NULL);
+        return;
+    }
+
     dom = be_ctx->domain;
     if (strcasecmp(ar->domain, be_ctx->domain->name) != 0) {
         /* Subdomain request, verify subdomain */
-- 
1.7.11.7

