>From be64c4245db58200db783623a6eaa791fe4339d6 Mon Sep 17 00:00:00 2001
From: Simo Sorce <ssorce@redhat.com>
Date: Thu, 18 Mar 2010 16:58:02 -0400
Subject: [PATCH 1/2] Store rootdse supported features in sdap_handler

---
 src/providers/ipa/ipa_access.c             |   10 +--
 src/providers/ldap/ldap_common.h           |    3 -
 src/providers/ldap/ldap_id.c               |   15 ++---
 src/providers/ldap/ldap_id_enum.c          |   10 +--
 src/providers/ldap/sdap.c                  |   84 ++++++++++++++++++++++------
 src/providers/ldap/sdap.h                  |   23 +++++++-
 src/providers/ldap/sdap_async.h            |    5 +-
 src/providers/ldap/sdap_async_connection.c |   45 ++++++---------
 8 files changed, 120 insertions(+), 75 deletions(-)

diff --git a/src/providers/ipa/ipa_access.c b/src/providers/ipa/ipa_access.c
index 7dfe1fd..6740f09 100644
--- a/src/providers/ipa/ipa_access.c
+++ b/src/providers/ipa/ipa_access.c
@@ -437,7 +437,7 @@ static struct tevent_req *hbac_get_host_info_send(TALLOC_CTX *memctx,
         }
 
         subreq = sdap_cli_connect_send(state, ev, sdap_ctx->opts,
-                                       sdap_ctx->be, sdap_ctx->service, NULL);
+                                       sdap_ctx->be, sdap_ctx->service, false);
         if (!subreq) {
             DEBUG(1, ("sdap_cli_connect_send failed.\n"));
             ret = ENOMEM;
@@ -482,8 +482,7 @@ static void hbac_get_host_info_connect_done(struct tevent_req *subreq)
                                                struct hbac_get_host_info_state);
     int ret;
 
-    ret = sdap_cli_connect_recv(subreq, state->sdap_ctx, &state->sdap_ctx->gsh,
-                                NULL);
+    ret = sdap_cli_connect_recv(subreq, state->sdap_ctx, &state->sdap_ctx->gsh);
     talloc_zfree(subreq);
     if (ret) {
         tevent_req_error(req, ret);
@@ -946,7 +945,7 @@ static struct tevent_req *hbac_get_rules_send(TALLOC_CTX *memctx,
         }
 
         subreq = sdap_cli_connect_send(state, ev, sdap_ctx->opts,
-                                       sdap_ctx->be, sdap_ctx->service, NULL);
+                                       sdap_ctx->be, sdap_ctx->service, false);
         if (!subreq) {
             DEBUG(1, ("sdap_cli_connect_send failed.\n"));
             ret = ENOMEM;
@@ -991,8 +990,7 @@ static void hbac_get_rules_connect_done(struct tevent_req *subreq)
                                                      struct hbac_get_rules_state);
     int ret;
 
-    ret = sdap_cli_connect_recv(subreq, state->sdap_ctx, &state->sdap_ctx->gsh,
-                                NULL);
+    ret = sdap_cli_connect_recv(subreq, state->sdap_ctx, &state->sdap_ctx->gsh);
     talloc_zfree(subreq);
     if (ret) {
         tevent_req_error(req, ret);
diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h
index ff1ffb7..cbacf83 100644
--- a/src/providers/ldap/ldap_common.h
+++ b/src/providers/ldap/ldap_common.h
@@ -39,9 +39,6 @@ struct sdap_id_ctx {
     struct fo_service *fo_service;
     struct sdap_service *service;
 
-    /* what rootDSE returns */
-    struct sysdb_attrs *rootDSE;
-
     /* global sdap handler */
     struct sdap_handle *gsh;
 
diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c
index 4bbc07a..7a646a3 100644
--- a/src/providers/ldap/ldap_id.c
+++ b/src/providers/ldap/ldap_id.c
@@ -106,7 +106,7 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx,
          * or SASL/GSSAPI, etc ... */
         subreq = sdap_cli_connect_send(state, ev, ctx->opts,
                                        ctx->be, ctx->service,
-                                       &ctx->rootDSE);
+                                       false);
         if (!subreq) {
             ret = ENOMEM;
             goto fail;
@@ -143,8 +143,7 @@ static void users_get_connect_done(struct tevent_req *subreq)
                                                      struct users_get_state);
     int ret;
 
-    ret = sdap_cli_connect_recv(subreq, state->ctx,
-                                &state->ctx->gsh, &state->ctx->rootDSE);
+    ret = sdap_cli_connect_recv(subreq, state->ctx, &state->ctx->gsh);
     talloc_zfree(subreq);
     if (ret) {
         if (ret == ENOTSUP) {
@@ -329,7 +328,7 @@ struct tevent_req *groups_get_send(TALLOC_CTX *memctx,
          * or SASL/GSSAPI, etc ... */
         subreq = sdap_cli_connect_send(state, ev, ctx->opts,
                                        ctx->be, ctx->service,
-                                       &ctx->rootDSE);
+                                       false);
         if (!subreq) {
             ret = ENOMEM;
             goto fail;
@@ -366,8 +365,7 @@ static void groups_get_connect_done(struct tevent_req *subreq)
                                                      struct groups_get_state);
     int ret;
 
-    ret = sdap_cli_connect_recv(subreq, state->ctx,
-                                &state->ctx->gsh, &state->ctx->rootDSE);
+    ret = sdap_cli_connect_recv(subreq, state->ctx, &state->ctx->gsh);
     talloc_zfree(subreq);
     if (ret) {
         if (ret == ENOTSUP) {
@@ -517,7 +515,7 @@ static struct tevent_req *groups_by_user_send(TALLOC_CTX *memctx,
          * or SASL/GSSAPI, etc ... */
         subreq = sdap_cli_connect_send(state, ev, ctx->opts,
                                        ctx->be, ctx->service,
-                                       &ctx->rootDSE);
+                                       false);
         if (!subreq) {
             ret = ENOMEM;
             goto fail;
@@ -555,8 +553,7 @@ static void groups_by_user_connect_done(struct tevent_req *subreq)
                                                      struct groups_by_user_state);
     int ret;
 
-    ret = sdap_cli_connect_recv(subreq, state->ctx,
-                                &state->ctx->gsh, &state->ctx->rootDSE);
+    ret = sdap_cli_connect_recv(subreq, state->ctx, &state->ctx->gsh);
     talloc_zfree(subreq);
     if (ret) {
         if (ret == ENOTSUP) {
diff --git a/src/providers/ldap/ldap_id_enum.c b/src/providers/ldap/ldap_id_enum.c
index bc06e8b..cf01a5b 100644
--- a/src/providers/ldap/ldap_id_enum.c
+++ b/src/providers/ldap/ldap_id_enum.c
@@ -363,7 +363,7 @@ static struct tevent_req *enum_users_send(TALLOC_CTX *memctx,
          * or SASL/GSSAPI, etc ... */
         subreq = sdap_cli_connect_send(state, ev, ctx->opts,
                                        ctx->be, ctx->service,
-                                       &ctx->rootDSE);
+                                       false);
         if (!subreq) {
             ret = ENOMEM;
             goto fail;
@@ -402,8 +402,7 @@ static void enum_users_connect_done(struct tevent_req *subreq)
                                                      struct enum_users_state);
     int ret;
 
-    ret = sdap_cli_connect_recv(subreq, state->ctx,
-                                &state->ctx->gsh, &state->ctx->rootDSE);
+    ret = sdap_cli_connect_recv(subreq, state->ctx, &state->ctx->gsh);
     talloc_zfree(subreq);
     if (ret) {
         if (ret == ENOTSUP) {
@@ -518,7 +517,7 @@ static struct tevent_req *enum_groups_send(TALLOC_CTX *memctx,
          * or SASL/GSSAPI, etc ... */
         subreq = sdap_cli_connect_send(state, ev, ctx->opts,
                                        ctx->be, ctx->service,
-                                       &ctx->rootDSE);
+                                       false);
         if (!subreq) {
             ret = ENOMEM;
             goto fail;
@@ -556,8 +555,7 @@ static void enum_groups_connect_done(struct tevent_req *subreq)
                                                  struct enum_groups_state);
     int ret;
 
-    ret = sdap_cli_connect_recv(subreq, state->ctx,
-                                &state->ctx->gsh, &state->ctx->rootDSE);
+    ret = sdap_cli_connect_recv(subreq, state->ctx, &state->ctx->gsh);
     talloc_zfree(subreq);
     if (ret) {
         if (ret == ENOTSUP) {
diff --git a/src/providers/ldap/sdap.c b/src/providers/ldap/sdap.c
index 39c67cc..e0f5038 100644
--- a/src/providers/ldap/sdap.c
+++ b/src/providers/ldap/sdap.c
@@ -325,37 +325,85 @@ errno_t setup_tls_config(struct dp_option *basic_opts)
 }
 
 
-bool sdap_rootdse_sasl_mech_is_supported(struct sysdb_attrs *rootdse,
-                                         const char *sasl_mech)
+bool sdap_check_sup_list(struct sup_list *l, const char *val)
 {
-    struct ldb_message_element *el = NULL;
-    struct ldb_val *val;
     int i;
 
-    if (!sasl_mech) return false;
+    if (!val) {
+        return false;
+    }
 
-    for (i = 0; i < rootdse->num; i++) {
-        if (strcasecmp(rootdse->a[i].name, "supportedSASLMechanisms")) {
+    for (i = 0; i < l->num_vals; i++) {
+        if (strcasecmp(val, (char *)l->vals[i])) {
             continue;
         }
-        el = &rootdse->a[i];
-        break;
+        return true;
     }
 
-    if (!el) {
-        /* no supported SASL Mechanism at all ? */
-        return false;
+    return false;
+}
+
+static int sdap_init_sup_list(TALLOC_CTX *memctx,
+                              struct sup_list *list,
+                              int num, struct ldb_val *vals)
+{
+    int i;
+
+    list->vals = talloc_array(memctx, char *, num);
+    if (!list->vals) {
+        return ENOMEM;
     }
 
-    for (i = 0; i < el->num_values; i++) {
-        val = &el->values[i];
-        if (strncasecmp(sasl_mech, (const char *)val->data, val->length)) {
-            continue;
+    for (i = 0; i < num; i++) {
+        list->vals[i] = talloc_strndup(list->vals,
+                                       (char *)vals[i].data, vals[i].length);
+        if (!list->vals[i]) {
+            return ENOMEM;
         }
-        return true;
     }
 
-    return false;
+    list->num_vals = num;
+
+    return EOK;
+}
+
+int sdap_set_rootdse_supported_lists(struct sysdb_attrs *rootdse,
+                                     struct sdap_handle *sh)
+{
+    struct ldb_message_element *el = NULL;
+    int ret;
+    int i;
+
+    for (i = 0; i < rootdse->num; i++) {
+        el = &rootdse->a[i];
+        if (strcasecmp(el->name, "supportedControl") == 0) {
+
+            ret = sdap_init_sup_list(sh, &sh->supported_controls,
+                                     el->num_values, el->values);
+            if (ret) {
+                return ret;
+            }
+        }
+        if (strcasecmp(el->name, "supportedExtension") == 0) {
+
+            ret = sdap_init_sup_list(sh, &sh->supported_extensions,
+                                     el->num_values, el->values);
+            if (ret) {
+                return ret;
+            }
+        }
+        if (strcasecmp(el->name, "supportedSASLMechanisms") == 0) {
+
+            ret = sdap_init_sup_list(sh, &sh->supported_saslmechs,
+                                     el->num_values, el->values);
+            if (ret) {
+                return ret;
+            }
+        }
+    }
+
+    return EOK;
+
 }
 
 int build_attrs_from_map(TALLOC_CTX *memctx,
diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
index 007185f..a5574fc 100644
--- a/src/providers/ldap/sdap.h
+++ b/src/providers/ldap/sdap.h
@@ -67,6 +67,11 @@ struct ldap_cb_data {
     struct fd_event_item *fd_list;
 };
 
+struct sup_list {
+    int num_vals;
+    char **vals;
+};
+
 struct sdap_handle {
     LDAP *ldap;
     bool connected;
@@ -77,6 +82,10 @@ struct sdap_handle {
     struct tevent_fd *fde;
 #endif
 
+    struct sup_list supported_saslmechs;
+    struct sup_list supported_controls;
+    struct sup_list supported_extensions;
+
     struct sdap_op *ops;
 };
 
@@ -250,8 +259,18 @@ int sdap_get_msg_dn(TALLOC_CTX *memctx, struct sdap_handle *sh,
 
 errno_t setup_tls_config(struct dp_option *basic_opts);
 
-bool sdap_rootdse_sasl_mech_is_supported(struct sysdb_attrs *rootdse,
-                                         const char *sasl_mech);
+int sdap_set_rootdse_supported_lists(struct sysdb_attrs *rootdse,
+                                     struct sdap_handle *sh);
+bool sdap_check_sup_list(struct sup_list *l, const char *val);
+
+#define sdap_is_sasl_mech_supported(sh, sasl_mech) \
+    sdap_check_sup_list(&((sh)->supported_saslmechs), sasl_mech)
+
+#define sdap_is_control_supported(sh, ctrl_oid) \
+    sdap_check_sup_list(&((sh)->supported_controls), ctrl_oid)
+
+#define sdap_is_extension_supported(sh, ext_oid) \
+    sdap_check_sup_list(&((sh)->supported_extensions), ext_oid)
 
 int build_attrs_from_map(TALLOC_CTX *memctx,
                          struct sdap_attr_map *map,
diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h
index 3c52d23..1139d46 100644
--- a/src/providers/ldap/sdap_async.h
+++ b/src/providers/ldap/sdap_async.h
@@ -103,11 +103,10 @@ struct tevent_req *sdap_cli_connect_send(TALLOC_CTX *memctx,
                                          struct sdap_options *opts,
                                          struct be_ctx *be,
                                          struct sdap_service *service,
-                                         struct sysdb_attrs **rootdse);
+                                         bool skip_rootdse);
 int sdap_cli_connect_recv(struct tevent_req *req,
                           TALLOC_CTX *memctx,
-                          struct sdap_handle **gsh,
-                          struct sysdb_attrs **rootdse);
+                          struct sdap_handle **gsh);
 
 struct tevent_req *sdap_get_generic_send(TALLOC_CTX *memctx,
                                          struct tevent_context *ev,
diff --git a/src/providers/ldap/sdap_async_connection.c b/src/providers/ldap/sdap_async_connection.c
index 586733f..f0b8c2e 100644
--- a/src/providers/ldap/sdap_async_connection.c
+++ b/src/providers/ldap/sdap_async_connection.c
@@ -810,7 +810,6 @@ struct sdap_cli_connect_state {
     struct sdap_service *service;
 
     bool use_rootdse;
-    struct sysdb_attrs *rootdse;
 
     struct sdap_handle *sh;
 
@@ -831,7 +830,7 @@ struct tevent_req *sdap_cli_connect_send(TALLOC_CTX *memctx,
                                          struct sdap_options *opts,
                                          struct be_ctx *be,
                                          struct sdap_service *service,
-                                         struct sysdb_attrs **rootdse)
+                                         bool skip_rootdse)
 {
     struct tevent_req *req, *subreq;
     struct sdap_cli_connect_state *state;
@@ -844,12 +843,10 @@ struct tevent_req *sdap_cli_connect_send(TALLOC_CTX *memctx,
     state->service = service;
     state->srv = NULL;
 
-    if (rootdse) {
-        state->use_rootdse = true;
-        state->rootdse = *rootdse;
-    } else {
+    if (skip_rootdse) {
         state->use_rootdse = false;
-        state->rootdse = NULL;
+    } else {
+        state->use_rootdse = true;
     }
 
     /* NOTE: this call may cause service->uri to be refreshed
@@ -908,7 +905,7 @@ static void sdap_cli_connect_done(struct tevent_req *subreq)
         return;
     }
 
-    if (state->use_rootdse && !state->rootdse) {
+    if (state->use_rootdse) {
         /* fetch the rootDSE this time */
         sdap_cli_rootdse_step(req);
         return;
@@ -918,8 +915,7 @@ static void sdap_cli_connect_done(struct tevent_req *subreq)
 
     if (sasl_mech && state->use_rootdse) {
         /* check if server claims to support GSSAPI */
-        if (!sdap_rootdse_sasl_mech_is_supported(state->rootdse,
-                                                 sasl_mech)) {
+        if (!sdap_is_sasl_mech_supported(state->sh, sasl_mech)) {
             tevent_req_error(req, ENOTSUP);
             return;
         }
@@ -970,22 +966,29 @@ static void sdap_cli_rootdse_done(struct tevent_req *subreq)
                                                       struct tevent_req);
     struct sdap_cli_connect_state *state = tevent_req_data(req,
                                              struct sdap_cli_connect_state);
+    struct sysdb_attrs *rootdse;
     const char *sasl_mech;
     int ret;
 
-    ret = sdap_get_rootdse_recv(subreq, state, &state->rootdse);
+    ret = sdap_get_rootdse_recv(subreq, state, &rootdse);
     talloc_zfree(subreq);
     if (ret) {
         tevent_req_error(req, ret);
         return;
     }
 
+    /* save rootdse data about supported features */
+    ret = sdap_set_rootdse_supported_lists(rootdse, state->sh);
+    if (ret) {
+        tevent_req_error(req, ret);
+        return;
+    }
+
     sasl_mech = dp_opt_get_string(state->opts->basic, SDAP_SASL_MECH);
 
     if (sasl_mech && state->use_rootdse) {
         /* check if server claims to support GSSAPI */
-        if (!sdap_rootdse_sasl_mech_is_supported(state->rootdse,
-                                                 sasl_mech)) {
+        if (!sdap_is_sasl_mech_supported(state->sh, sasl_mech)) {
             tevent_req_error(req, ENOTSUP);
             return;
         }
@@ -1094,8 +1097,7 @@ static void sdap_cli_auth_done(struct tevent_req *subreq)
 
 int sdap_cli_connect_recv(struct tevent_req *req,
                           TALLOC_CTX *memctx,
-                          struct sdap_handle **gsh,
-                          struct sysdb_attrs **rootdse)
+                          struct sdap_handle **gsh)
 {
     struct sdap_cli_connect_state *state = tevent_req_data(req,
                                              struct sdap_cli_connect_state);
@@ -1125,19 +1127,6 @@ int sdap_cli_connect_recv(struct tevent_req *req,
         talloc_zfree(state->sh);
     }
 
-    if (rootdse) {
-        if (state->use_rootdse) {
-            *rootdse = talloc_steal(memctx, state->rootdse);
-            if (!*rootdse) {
-                return ENOMEM;
-            }
-        } else {
-            *rootdse = NULL;
-        }
-    } else {
-        talloc_zfree(rootdse);
-    }
-
     return EOK;
 }
 
-- 
1.6.6.1

