>From 19dbd03214f9a8f98f0736ee274e04fda3ea651b Mon Sep 17 00:00:00 2001
From: Simo Sorce <ssorce@redhat.com>
Date: Sat, 12 Sep 2009 20:03:57 -0400
Subject: [PATCH] Trun ldap driver options into multitype

This patch makes basic options multiype, the init function assigns
a type from the initialization array, and processes values fetched
from confdb accordingly.
4 types are supported so far: string, number, blob and boolean

Also convert defines into enums where appropriate.
Add fetch functions that check the requested type.
---
 server/providers/ldap/ldap_auth.c  |   48 ++++---
 server/providers/ldap/ldap_id.c    |  106 +++++++++++----
 server/providers/ldap/sdap.c       |  257 ++++++++++++++++++++++++++----------
 server/providers/ldap/sdap.h       |  141 ++++++++++++--------
 server/providers/ldap/sdap_async.c |   45 ++++---
 server/providers/ldap/sdap_async.h |    2 +-
 6 files changed, 402 insertions(+), 197 deletions(-)

diff --git a/server/providers/ldap/ldap_auth.c b/server/providers/ldap/ldap_auth.c
index 9f65d12..8652f6e 100644
--- a/server/providers/ldap/ldap_auth.c
+++ b/server/providers/ldap/ldap_auth.c
@@ -126,7 +126,8 @@ static void get_user_dn_done(void *pvt, int err, struct ldb_result *res)
             dn = talloc_asprintf(state, "%s=%s,%s",
                         state->ctx->opts->user_map[SDAP_AT_USER_NAME].name,
                         state->name,
-                        state->ctx->opts->basic[SDAP_USER_SEARCH_BASE].value);
+                        sdap_go_get_string(state->ctx->opts->basic,
+                                           SDAP_USER_SEARCH_BASE));
             if (!dn) {
                 tevent_req_error(req, ENOMEM);
                 break;
@@ -173,7 +174,7 @@ struct auth_state {
     struct tevent_context *ev;
     struct sdap_auth_ctx *ctx;
     const char *username;
-    const char *password;
+    struct sdap_blob password;
 
     struct sdap_handle *sh;
 
@@ -185,11 +186,11 @@ static void auth_connect_done(struct tevent_req *subreq);
 static void auth_get_user_dn_done(struct tevent_req *subreq);
 static void auth_bind_user_done(struct tevent_req *subreq);
 
-struct tevent_req *auth_send(TALLOC_CTX *memctx,
-                             struct tevent_context *ev,
-                             struct sdap_auth_ctx *ctx,
-                             const char *username,
-                             const char *password)
+static struct tevent_req *auth_send(TALLOC_CTX *memctx,
+                                    struct tevent_context *ev,
+                                    struct sdap_auth_ctx *ctx,
+                                    const char *username,
+                                    struct sdap_blob password)
 {
     struct tevent_req *req, *subreq;
     struct auth_state *state;
@@ -333,6 +334,7 @@ static void sdap_pam_chpass_send(struct be_req *breq)
     struct sdap_auth_ctx *ctx;
     struct tevent_req *subreq;
     struct pam_data *pd;
+    struct sdap_blob authtok;
 
     ctx = talloc_get_type(breq->be_ctx->bet_info[BET_CHPASS].pvt_bet_data,
                           struct sdap_auth_ctx);
@@ -371,8 +373,10 @@ static void sdap_pam_chpass_send(struct be_req *breq)
     talloc_set_destructor((TALLOC_CTX *)state->new_password,
                           password_destructor);
 
+    authtok.data = (uint8_t *)state->password;
+    authtok.length = strlen(state->password);
     subreq = auth_send(breq, breq->be_ctx->ev,
-                       ctx, state->username, state->password);
+                       ctx, state->username, authtok);
     if (!subreq) goto done;
 
     tevent_req_set_callback(subreq, sdap_auth4chpass_done, state);
@@ -454,7 +458,7 @@ struct sdap_pam_auth_state {
     struct be_req *breq;
     struct pam_data *pd;
     const char *username;
-    char *password;
+    struct sdap_blob password;
 };
 
 static void sdap_pam_auth_done(struct tevent_req *req);
@@ -489,14 +493,11 @@ static void sdap_pam_auth_send(struct be_req *breq)
         state->breq = breq;
         state->pd = pd;
         state->username = pd->user;
-        state->password = talloc_strndup(state,
-                                         (char *)pd->authtok, pd->authtok_size);
-        if (!state->password) goto done;
-        talloc_set_destructor((TALLOC_CTX *)state->password,
-                              password_destructor);
-
-        subreq = auth_send(breq, breq->be_ctx->ev,
-                                ctx, state->username, state->password);
+        state->password.data = pd->authtok;
+        state->password.length = pd->authtok_size;
+
+        subreq = auth_send(breq, breq->be_ctx->ev, ctx,
+                           state->username, state->password);
         if (!subreq) goto done;
 
         tevent_req_set_callback(subreq, sdap_pam_auth_done, state);
@@ -546,12 +547,21 @@ static void sdap_pam_auth_done(struct tevent_req *req)
     if (result == SDAP_AUTH_SUCCESS &&
         state->breq->be_ctx->domain->cache_credentials) {
 
+        char *password = talloc_strndup(state, (char *)
+                                        state->password.data,
+                                        state->password.length);
+        if (!password) {
+            DEBUG(2, ("Failed to cache password for %s\n", state->username));
+            goto done;
+        }
+        talloc_set_destructor((TALLOC_CTX *)password, password_destructor);
+
         subreq = sysdb_cache_password_send(state,
                                            state->breq->be_ctx->ev,
                                            state->breq->be_ctx->sysdb,
                                            NULL,
                                            state->breq->be_ctx->domain,
-                                           state->username, state->password);
+                                           state->username, password);
 
         /* password caching failures are not fatal errors */
         if (!subreq) {
@@ -628,7 +638,7 @@ int sssm_ldap_auth_init(struct be_ctx *bectx,
                               &ctx->opts);
     if (ret != EOK) goto done;
 
-    tls_reqcert = ctx->opts->basic[SDAP_TLS_REQCERT].value;
+    tls_reqcert = sdap_go_get_string(ctx->opts->basic, SDAP_TLS_REQCERT);
     if (tls_reqcert) {
         if (strcasecmp(tls_reqcert, "never") == 0) {
             ldap_opt_x_tls_require_cert = LDAP_OPT_X_TLS_NEVER;
diff --git a/server/providers/ldap/ldap_id.c b/server/providers/ldap/ldap_id.c
index 1984582..2d85cb9 100644
--- a/server/providers/ldap/ldap_id.c
+++ b/server/providers/ldap/ldap_id.c
@@ -98,7 +98,7 @@ struct sdap_id_connect_state {
     bool use_start_tls;
     char *defaultBindDn;
     char *defaultAuthtokType;
-    char *defaultAuthtok;
+    struct sdap_blob defaultAuthtok;
 
     struct sdap_handle *sh;
 };
@@ -106,13 +106,13 @@ struct sdap_id_connect_state {
 static void sdap_id_connect_done(struct tevent_req *subreq);
 static void sdap_id_bind_done(struct tevent_req *subreq);
 
-struct tevent_req *sdap_id_connect_send(TALLOC_CTX *memctx,
-                                        struct tevent_context *ev,
-                                        struct sdap_id_ctx *ctx,
-                                        bool use_start_tls,
-                                        char *defaultBindDn,
-                                        char *defaultAuthtokType,
-                                        char *defaultAuthtok)
+static struct tevent_req *sdap_id_connect_send(TALLOC_CTX *memctx,
+                                               struct tevent_context *ev,
+                                               struct sdap_id_ctx *ctx,
+                                               bool use_start_tls,
+                                               char *defaultBindDn,
+                                               char *defaultAuthtokType,
+                                               struct sdap_blob defaultAuthtok)
 {
     struct tevent_req *req, *subreq;
     struct sdap_id_connect_state *state;
@@ -268,9 +268,12 @@ static struct tevent_req *users_get_send(TALLOC_CTX *memctx,
         /* FIXME: add option to decide if tls should be used
          * or SASL/GSSAPI, etc ... */
         subreq = sdap_id_connect_send(state, ev, ctx, false,
-                              ctx->opts->basic[SDAP_DEFAULT_BIND_DN].value,
-                              ctx->opts->basic[SDAP_DEFAULT_AUTHTOK_TYPE].value,
-                              ctx->opts->basic[SDAP_DEFAULT_AUTHTOK].value);
+                             sdap_go_get_string(ctx->opts->basic,
+                                                SDAP_DEFAULT_BIND_DN),
+                             sdap_go_get_string(ctx->opts->basic,
+                                                SDAP_DEFAULT_AUTHTOK_TYPE),
+                             sdap_go_get_blob(ctx->opts->basic,
+                                                SDAP_DEFAULT_AUTHTOK));
         if (!subreq) {
             ret = ENOMEM;
             goto fail;
@@ -434,9 +437,12 @@ static struct tevent_req *groups_get_send(TALLOC_CTX *memctx,
         /* FIXME: add option to decide if tls should be used
          * or SASL/GSSAPI, etc ... */
         subreq = sdap_id_connect_send(state, ev, ctx, false,
-                              ctx->opts->basic[SDAP_DEFAULT_BIND_DN].value,
-                              ctx->opts->basic[SDAP_DEFAULT_AUTHTOK_TYPE].value,
-                              ctx->opts->basic[SDAP_DEFAULT_AUTHTOK].value);
+                             sdap_go_get_string(ctx->opts->basic,
+                                                SDAP_DEFAULT_BIND_DN),
+                             sdap_go_get_string(ctx->opts->basic,
+                                                SDAP_DEFAULT_AUTHTOK_TYPE),
+                             sdap_go_get_blob(ctx->opts->basic,
+                                                SDAP_DEFAULT_AUTHTOK));
         if (!subreq) {
             ret = ENOMEM;
             goto fail;
@@ -574,9 +580,12 @@ static struct tevent_req *groups_by_user_send(TALLOC_CTX *memctx,
         /* FIXME: add option to decide if tls should be used
          * or SASL/GSSAPI, etc ... */
         subreq = sdap_id_connect_send(state, ev, ctx, false,
-                              ctx->opts->basic[SDAP_DEFAULT_BIND_DN].value,
-                              ctx->opts->basic[SDAP_DEFAULT_AUTHTOK_TYPE].value,
-                              ctx->opts->basic[SDAP_DEFAULT_AUTHTOK].value);
+                             sdap_go_get_string(ctx->opts->basic,
+                                                SDAP_DEFAULT_BIND_DN),
+                             sdap_go_get_string(ctx->opts->basic,
+                                                SDAP_DEFAULT_AUTHTOK_TYPE),
+                             sdap_go_get_blob(ctx->opts->basic,
+                                                SDAP_DEFAULT_AUTHTOK));
         if (!subreq) {
             ret = ENOMEM;
             goto fail;
@@ -789,6 +798,7 @@ static void ldap_id_enumerate(struct tevent_context *ev,
     struct sdap_id_ctx *ctx = talloc_get_type(pvt, struct sdap_id_ctx);
     struct tevent_timer *timeout;
     struct tevent_req *req;
+    int ert;
 
     if (be_is_offline(ctx->be)) {
         DEBUG(4, ("Backend is marked offline, retry later!\n"));
@@ -811,7 +821,8 @@ static void ldap_id_enumerate(struct tevent_context *ev,
     /* if enumeration takes so long, either we try to enumerate too
      * frequently, or something went seriously wrong */
     tv = tevent_timeval_current();
-    tv = tevent_timeval_add(&tv, ctx->opts->enum_refresh_timeout, 0);
+    ert = sdap_go_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT);
+    tv = tevent_timeval_add(&tv, ert, 0);
     timeout = tevent_add_timer(ctx->be->ev, req, tv,
                                ldap_id_enumerate_timeout, req);
     return;
@@ -824,9 +835,10 @@ static void ldap_id_enumerate_timeout(struct tevent_context *ev,
     struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
     struct sdap_id_ctx *ctx = tevent_req_callback_data(req,
                                                        struct sdap_id_ctx);
+    int ert;
 
-    DEBUG(1, ("Enumeration timed out! Timeout too small? (%ds)!\n",
-              ctx->opts->enum_refresh_timeout));
+    ert = sdap_go_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT);
+    DEBUG(1, ("Enumeration timed out! Timeout too small? (%ds)!\n", ert));
     ldap_id_enumerate_set_timer(ctx, tevent_timeval_current());
 
     talloc_zfree(req);
@@ -855,8 +867,10 @@ static void ldap_id_enumerate_set_timer(struct sdap_id_ctx *ctx,
                                         struct timeval tv)
 {
     struct tevent_timer *enum_task;
+    int ert;
 
-    tv = tevent_timeval_add(&tv, ctx->opts->enum_refresh_timeout, 0);
+    ert = sdap_go_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT);
+    tv = tevent_timeval_add(&tv, ert, 0);
     enum_task = tevent_add_timer(ctx->be->ev, ctx, tv, ldap_id_enumerate, ctx);
     if (!enum_task) {
         DEBUG(0, ("FATAL: failed to setup enumeration task!\n"));
@@ -965,6 +979,33 @@ fail:
     tevent_req_done(req);
 }
 
+static void ldap_id_cleanup_done(struct tevent_req *subreq)
+{
+    struct tevent_req *req = tevent_req_callback_data(subreq,
+                                                      struct tevent_req);
+    struct global_enum_state *state = tevent_req_data(req,
+                                                 struct global_enum_state);
+    enum tevent_req_state tstate;
+    uint64_t err;
+
+    if (tevent_req_is_error(subreq, &tstate, &err)) {
+        goto fail;
+    }
+    talloc_zfree(subreq);
+
+    tevent_req_done(req);
+    return;
+
+fail:
+    if (err == ETIMEDOUT) {
+        be_mark_offline(state->ctx->be);
+    }
+
+    DEBUG(1, ("Failed to clean-up old entries, retrying later!\n"));
+    tevent_req_done(req);
+}
+
+
 /* ==User-Enumeration===================================================== */
 
 struct enum_users_state {
@@ -1025,9 +1066,12 @@ static struct tevent_req *enum_users_send(TALLOC_CTX *memctx,
         /* FIXME: add option to decide if tls should be used
          * or SASL/GSSAPI, etc ... */
         subreq = sdap_id_connect_send(state, ev, ctx, false,
-                              ctx->opts->basic[SDAP_DEFAULT_BIND_DN].value,
-                              ctx->opts->basic[SDAP_DEFAULT_AUTHTOK_TYPE].value,
-                              ctx->opts->basic[SDAP_DEFAULT_AUTHTOK].value);
+                             sdap_go_get_string(ctx->opts->basic,
+                                                SDAP_DEFAULT_BIND_DN),
+                             sdap_go_get_string(ctx->opts->basic,
+                                                SDAP_DEFAULT_AUTHTOK_TYPE),
+                             sdap_go_get_blob(ctx->opts->basic,
+                                                SDAP_DEFAULT_AUTHTOK));
         if (!subreq) {
             ret = ENOMEM;
             goto fail;
@@ -1175,9 +1219,12 @@ static struct tevent_req *enum_groups_send(TALLOC_CTX *memctx,
         /* FIXME: add option to decide if tls should be used
          * or SASL/GSSAPI, etc ... */
         subreq = sdap_id_connect_send(state, ev, ctx, false,
-                              ctx->opts->basic[SDAP_DEFAULT_BIND_DN].value,
-                              ctx->opts->basic[SDAP_DEFAULT_AUTHTOK_TYPE].value,
-                              ctx->opts->basic[SDAP_DEFAULT_AUTHTOK].value);
+                             sdap_go_get_string(ctx->opts->basic,
+                                                SDAP_DEFAULT_BIND_DN),
+                             sdap_go_get_string(ctx->opts->basic,
+                                                SDAP_DEFAULT_AUTHTOK_TYPE),
+                             sdap_go_get_blob(ctx->opts->basic,
+                                                SDAP_DEFAULT_AUTHTOK));
         if (!subreq) {
             ret = ENOMEM;
             goto fail;
@@ -1291,10 +1338,9 @@ int sssm_ldap_init(struct be_ctx *bectx,
 
     ctx->be = bectx;
 
-    ret = sdap_get_options(ctx, bectx->cdb, bectx->conf_path,
-                           &ctx->opts);
+    ret = sdap_get_options(ctx, bectx->cdb, bectx->conf_path, &ctx->opts);
 
-    tls_reqcert = ctx->opts->basic[SDAP_TLS_REQCERT].value;
+    tls_reqcert = sdap_go_get_string(ctx->opts->basic, SDAP_TLS_REQCERT);
     if (tls_reqcert) {
         if (strcasecmp(tls_reqcert, "never") == 0) {
             ldap_opt_x_tls_require_cert = LDAP_OPT_X_TLS_NEVER;
diff --git a/server/providers/ldap/sdap.c b/server/providers/ldap/sdap.c
index 616e4a3..710fdf3 100644
--- a/server/providers/ldap/sdap.c
+++ b/server/providers/ldap/sdap.c
@@ -25,24 +25,31 @@
 #include "confdb/confdb.h"
 #include "providers/ldap/sdap.h"
 
+#define NULL_STRING { .string = NULL }
+#define NULL_BLOB { .blob = { NULL, 0 } }
+#define NULL_NUMBER { .number = 0 }
+#define BOOL_FALSE { .boolean = false }
+#define BOOL_TRUE { .boolean = true }
+
 struct sdap_gen_opts default_basic_opts[] = {
-    { "ldapUri", "ldap://localhost", NULL },
-    { "defaultBindDn", NULL, NULL },
-    { "defaultAuthtokType", NULL, NULL },
-    { "defaultAuthtok", NULL, NULL },
-    { "network_timeout", "5", NULL },
-    { "opt_timeout", "5", NULL },
-    { "tls_reqcert", "hard", NULL },
-    { "userSearchBase", "ou=People,dc=example,dc=com", NULL },
-    { "userSearchScope", "sub", NULL },
-    { "userSearchFilter", NULL, NULL },
-    { "groupSearchBase", "ou=Group,dc=example,dc=com", NULL },
-    { "groupSearchScope", "sub", NULL },
-    { "groupSearchFilter", NULL, NULL },
-    { "ldapSchema", "rfc2307", NULL },
-    { "offline_timeout", "60", NULL },
-    { "force_upper_case_realm", "0", NULL },
-    { "enumeration_refresh_timeout", "300", NULL }
+    { "ldapUri", SDAP_STRING, { "ldap://localhost" }, NULL_STRING },
+    { "defaultBindDn", SDAP_STRING, NULL_STRING, NULL_STRING },
+    { "defaultAuthtokType", SDAP_STRING, NULL_STRING, NULL_STRING},
+    { "defaultAuthtok", SDAP_BLOB, NULL_BLOB, NULL_BLOB },
+    { "network_timeout", SDAP_NUMBER, { .number = 5 }, NULL_NUMBER },
+    { "opt_timeout", SDAP_NUMBER, { .number = 5 }, NULL_NUMBER },
+    { "tls_reqcert", SDAP_STRING, { "hard" }, NULL_STRING },
+    { "userSearchBase", SDAP_STRING, { "ou=People,dc=example,dc=com" }, NULL_STRING },
+    { "userSearchScope", SDAP_STRING, { "sub" }, NULL_STRING },
+    { "userSearchFilter", SDAP_STRING, NULL_STRING, NULL_STRING },
+    { "groupSearchBase", SDAP_STRING, { "ou=Group,dc=example,dc=com" }, NULL_STRING },
+    { "groupSearchScope", SDAP_STRING, { "sub" }, NULL_STRING },
+    { "groupSearchFilter", SDAP_STRING, NULL_STRING, NULL_STRING },
+    { "ldapSchema", SDAP_STRING, { "rfc2307" }, NULL_STRING },
+    { "offline_timeout", SDAP_NUMBER, { .number = 60 }, NULL_NUMBER },
+    { "force_upper_case_realm", SDAP_BOOL, BOOL_FALSE, BOOL_FALSE },
+    { "enumeration_refresh_timeout", SDAP_NUMBER, { .number = 300 }, NULL_NUMBER },
+    { "stale_time", SDAP_NUMBER, { .number = 1800 }, NULL_NUMBER }
 };
 
 struct sdap_id_map rfc2307_user_map[] = {
@@ -109,6 +116,7 @@ int sdap_get_options(TALLOC_CTX *memctx,
     struct sdap_id_map *default_user_map;
     struct sdap_id_map *default_group_map;
     struct sdap_options *opts;
+    char *schema;
     int i, ret;
 
     opts = talloc_zero(memctx, struct sdap_options);
@@ -124,76 +132,95 @@ int sdap_get_options(TALLOC_CTX *memctx,
     if (!opts) return ENOMEM;
 
     for (i = 0; i < SDAP_OPTS_BASIC; i++) {
+        char *tmp;
 
         opts->basic[i].opt_name = default_basic_opts[i].opt_name;
-        opts->basic[i].def_value = default_basic_opts[i].def_value;
-
-        ret = confdb_get_string(cdb, opts, conf_path,
-                                opts->basic[i].opt_name,
-                                opts->basic[i].def_value,
-                                &opts->basic[i].value);
-        if (ret != EOK ||
-            (opts->basic[i].def_value && !opts->basic[i].value)) {
-            DEBUG(0, ("Failed to retrieve a value (%s)\n",
-                      opts->basic[i].opt_name));
-            if (ret != EOK) ret = EINVAL;
-            goto done;
-        }
-
-        DEBUG(5, ("Option %s has value %s\n",
-                  opts->basic[i].opt_name, opts->basic[i].value));
-    }
-
-    /* re-read special options that are easier to be consumed after they are
-     * transformed */
-
-/* TODO: better to have a blob object than a string here */
-    ret = confdb_get_string(cdb, opts, conf_path,
-                            "defaultAuthtok", NULL,
-                            &opts->default_authtok);
-    if (ret != EOK) goto done;
-    if (opts->default_authtok) {
-        opts->default_authtok_size = strlen(opts->default_authtok);
-    }
+        opts->basic[i].type = default_basic_opts[i].type;
+        opts->basic[i].def_val = default_basic_opts[i].def_val;
+        ret = EOK;
+
+        switch (default_basic_opts[i].type) {
+        case SDAP_STRING:
+            ret = confdb_get_string(cdb, opts, conf_path,
+                                    opts->basic[i].opt_name,
+                                    opts->basic[i].def_val.cstring,
+                                    &opts->basic[i].val.string);
+            if (ret != EOK ||
+                ((opts->basic[i].def_val.string != NULL) &&
+                 (opts->basic[i].val.string == NULL))) {
+                DEBUG(0, ("Failed to retrieve value for option (%s)\n",
+                          opts->basic[i].opt_name));
+                if (ret == EOK) ret = EINVAL;
+                goto done;
+            }
+            DEBUG(6, ("Option %s has value %s\n",
+                  opts->basic[i].opt_name, opts->basic[i].val.cstring));
+            break;
 
-    ret = confdb_get_int(cdb, opts, conf_path,
-                         "network_timeout", 5,
-                         &opts->network_timeout);
-    if (ret != EOK) goto done;
+        case SDAP_BLOB:
+            ret = confdb_get_string(cdb, opts, conf_path,
+                                    opts->basic[i].opt_name,
+                                    NULL, &tmp);
+            if (ret != EOK) {
+                DEBUG(0, ("Failed to retrieve value for option (%s)\n",
+                          opts->basic[i].opt_name));
+                goto done;
+            }
 
-    ret = confdb_get_int(cdb, opts, conf_path,
-                         "opt_timeout", 5,
-                         &opts->opt_timeout);
-    if (ret != EOK) goto done;
+            if (tmp) {
+                opts->basic[i].val.blob.data = (uint8_t *)tmp;
+                opts->basic[i].val.blob.length = strlen(tmp);
+            }
 
-    ret = confdb_get_int(cdb, opts, conf_path,
-                         "offline_timeout", 60,
-                         &opts->offline_timeout);
-    if (ret != EOK) goto done;
+            DEBUG(6, ("Option %s has %s value\n",
+                      opts->basic[i].opt_name,
+                      opts->basic[i].val.blob.length?"a":"no"));
+            break;
 
-    ret = confdb_get_bool(cdb, opts, conf_path,
-                         "force_upper_case_realm", false,
-                         &opts->force_upper_case_realm);
-    if (ret != EOK) goto done;
+        case SDAP_NUMBER:
+            ret = confdb_get_int(cdb, opts, conf_path,
+                                 opts->basic[i].opt_name,
+                                 opts->basic[i].def_val.number,
+                                 &opts->basic[i].val.number);
+            if (ret != EOK) {
+                DEBUG(0, ("Failed to retrieve value for option (%s)\n",
+                          opts->basic[i].opt_name));
+                goto done;
+            }
+            DEBUG(6, ("Option %s has value %d\n",
+                  opts->basic[i].opt_name, opts->basic[i].val.number));
+            break;
 
-    ret = confdb_get_int(cdb, opts, conf_path,
-                         "enumeration_refresh_timeout", 300,
-                         &opts->enum_refresh_timeout);
-    if (ret != EOK) goto done;
+        case SDAP_BOOL:
+            ret = confdb_get_bool(cdb, opts, conf_path,
+                                  opts->basic[i].opt_name,
+                                  opts->basic[i].def_val.boolean,
+                                  &opts->basic[i].val.boolean);
+            if (ret != EOK) {
+                DEBUG(0, ("Failed to retrieve value for option (%s)\n",
+                          opts->basic[i].opt_name));
+                goto done;
+            }
+            DEBUG(6, ("Option %s is %s\n",
+                      opts->basic[i].opt_name,
+                      opts->basic[i].val.boolean?"TRUE":"FALSE"));
+            break;
+        }
+    }
 
     /* schema type */
-    if (strcasecmp(opts->basic[SDAP_SCHEMA].value, "rfc2307") == 0) {
+    schema = sdap_go_get_string(opts->basic, SDAP_SCHEMA);
+    if (strcasecmp(schema, "rfc2307") == 0) {
         opts->schema_type = SDAP_SCHEMA_RFC2307;
         default_user_map = rfc2307_user_map;
         default_group_map = rfc2307_group_map;
     } else
-    if (strcasecmp(opts->basic[SDAP_SCHEMA].value, "rfc2307bis") == 0) {
+    if (strcasecmp(schema, "rfc2307bis") == 0) {
         opts->schema_type = SDAP_SCHEMA_RFC2307BIS;
         default_user_map = rfc2307bis_user_map;
         default_group_map = rfc2307bis_group_map;
     } else {
-        DEBUG(0, ("Unrecognized schema type: %s\n",
-                  opts->basic[SDAP_SCHEMA].value));
+        DEBUG(0, ("Unrecognized schema type: %s\n", schema));
         ret = EINVAL;
         goto done;
     }
@@ -250,6 +277,90 @@ done:
     return ret;
 }
 
+/* =Basic-Option-Helpers================================================== */
+
+static const char *sdap_type_to_string(enum sdap_type type)
+{
+    switch (type) {
+    case SDAP_STRING:
+        return "String";
+    case SDAP_BLOB:
+        return "Blob";
+    case SDAP_NUMBER:
+        return "Number";
+    case SDAP_BOOL:
+        return "Boolean";
+    }
+    return NULL;
+}
+
+const char *_sdap_go_get_cstring(struct sdap_gen_opts *opts,
+                                 int id, const char *location)
+{
+    if (opts[id].type != SDAP_STRING) {
+        DEBUG(0, ("[%s] Requested type 'String' for option '%s'"
+                  " but value is of type '%s'!\n",
+                  location, opts[id].opt_name,
+                  sdap_type_to_string(opts[id].type)));
+        return NULL;
+    }
+    return opts[id].val.cstring;
+}
+
+char *_sdap_go_get_string(struct sdap_gen_opts *opts,
+                          int id, const char *location)
+{
+    if (opts[id].type != SDAP_STRING) {
+        DEBUG(0, ("[%s] Requested type 'String' for option '%s'"
+                  " but value is of type '%s'!\n",
+                  location, opts[id].opt_name,
+                  sdap_type_to_string(opts[id].type)));
+        return NULL;
+    }
+    return opts[id].val.string;
+}
+
+struct sdap_blob _sdap_go_get_blob(struct sdap_gen_opts *opts,
+                                   int id, const char *location)
+{
+    struct sdap_blob null_blob = { NULL, 0 };
+    if (opts[id].type != SDAP_BLOB) {
+        DEBUG(0, ("[%s] Requested type 'Blob' for option '%s'"
+                  " but value is of type '%s'!\n",
+                  location, opts[id].opt_name,
+                  sdap_type_to_string(opts[id].type)));
+        return null_blob;
+    }
+    return opts[id].val.blob;
+}
+
+int _sdap_go_get_int(struct sdap_gen_opts *opts,
+                     int id, const char *location)
+{
+    if (opts[id].type != SDAP_NUMBER) {
+        DEBUG(0, ("[%s] Requested type 'Number' for option '%s'"
+                  " but value is of type '%s'!\n",
+                  location, opts[id].opt_name,
+                  sdap_type_to_string(opts[id].type)));
+        return 0;
+    }
+    return opts[id].val.number;
+}
+
+bool _sdap_go_get_bool(struct sdap_gen_opts *opts,
+                       int id, const char *location)
+{
+    if (opts[id].type != SDAP_BOOL) {
+        DEBUG(0, ("[%s] Requested type 'Boolean' for option '%s'"
+                  " but value is of type '%s'!\n",
+                  location, opts[id].opt_name,
+                  sdap_type_to_string(opts[id].type)));
+        return false;
+    }
+    return opts[id].val.boolean;
+}
+
+
 /* =Parse-msg============================================================= */
 
 static int sdap_parse_entry(TALLOC_CTX *memctx,
diff --git a/server/providers/ldap/sdap.h b/server/providers/ldap/sdap.h
index a39eef5..7168a5a 100644
--- a/server/providers/ldap/sdap.h
+++ b/server/providers/ldap/sdap.h
@@ -69,60 +69,88 @@ enum sdap_result {
     SDAP_AUTH_FAILED
 };
 
-#define SDAP_URI 0
-#define SDAP_DEFAULT_BIND_DN 1
-#define SDAP_DEFAULT_AUTHTOK_TYPE 2
-#define SDAP_DEFAULT_AUTHTOK 3
-#define SDAP_NETWROK_TIMEOUT 4
-#define SDAP_OPT_TIMEOUT 5
-#define SDAP_TLS_REQCERT 6
-#define SDAP_USER_SEARCH_BASE 7
-#define SDAP_USER_SEARCH_SCOPE 8
-#define SDAP_USER_SEARCH_FILTER 9
-#define SDAP_GROUP_SEARCH_BASE 10
-#define SDAP_GROUP_SEARCH_SCOPE 11
-#define SDAP_GROUP_SEARCH_FILTER 12
-#define SDAP_SCHEMA 13
-#define SDAP_OFFLINE_TIMEOUT 14
-#define SDAP_FORCE_UPPER_CASE_REALM 15
-#define SDAP_ENUM_REFRESH_TIMEOUT 16
-
-#define SDAP_OPTS_BASIC 17 /* opts counter */
+enum sdap_basic_opt {
+    SDAP_URI = 0,
+    SDAP_DEFAULT_BIND_DN,
+    SDAP_DEFAULT_AUTHTOK_TYPE,
+    SDAP_DEFAULT_AUTHTOK,
+    SDAP_NETWORK_TIMEOUT,
+    SDAP_OPT_TIMEOUT,
+    SDAP_TLS_REQCERT,
+    SDAP_USER_SEARCH_BASE,
+    SDAP_USER_SEARCH_SCOPE,
+    SDAP_USER_SEARCH_FILTER,
+    SDAP_GROUP_SEARCH_BASE,
+    SDAP_GROUP_SEARCH_SCOPE,
+    SDAP_GROUP_SEARCH_FILTER,
+    SDAP_SCHEMA,
+    SDAP_OFFLINE_TIMEOUT,
+    SDAP_FORCE_UPPER_CASE_REALM,
+    SDAP_ENUM_REFRESH_TIMEOUT,
+    SDAP_STALE_TIME,
+
+    SDAP_OPTS_BASIC /* opts counter */
+};
 
 /* the objectclass must be the first attribute.
  * Functions depend on this */
-#define SDAP_OC_USER 0
-#define SDAP_AT_USER_NAME 1
-#define SDAP_AT_USER_PWD 2
-#define SDAP_AT_USER_UID 3
-#define SDAP_AT_USER_GID 4
-#define SDAP_AT_USER_GECOS 5
-#define SDAP_AT_USER_HOME 6
-#define SDAP_AT_USER_SHELL 7
-#define SDAP_AT_USER_PRINC 8
-#define SDAP_AT_USER_FULLNAME 9
-#define SDAP_AT_USER_MEMBEROF 10
-#define SDAP_AT_USER_UUID 11
-#define SDAP_AT_USER_MODSTAMP 12
-
-#define SDAP_OPTS_USER 13 /* attrs counter */
+enum sdap_user_opt {
+    SDAP_OC_USER = 0,
+    SDAP_AT_USER_NAME,
+    SDAP_AT_USER_PWD,
+    SDAP_AT_USER_UID,
+    SDAP_AT_USER_GID,
+    SDAP_AT_USER_GECOS,
+    SDAP_AT_USER_HOME,
+    SDAP_AT_USER_SHELL,
+    SDAP_AT_USER_PRINC,
+    SDAP_AT_USER_FULLNAME,
+    SDAP_AT_USER_MEMBEROF,
+    SDAP_AT_USER_UUID,
+    SDAP_AT_USER_MODSTAMP,
+
+    SDAP_OPTS_USER /* attrs counter */
+};
 
 /* the objectclass must be the first attribute.
  * Functions depend on this */
-#define SDAP_OC_GROUP 0
-#define SDAP_AT_GROUP_NAME 1
-#define SDAP_AT_GROUP_PWD 2
-#define SDAP_AT_GROUP_GID 3
-#define SDAP_AT_GROUP_MEMBER 4
-#define SDAP_AT_GROUP_UUID 5
-#define SDAP_AT_GROUP_MODSTAMP 6
+enum sdap_group_opt {
+    SDAP_OC_GROUP = 0,
+    SDAP_AT_GROUP_NAME,
+    SDAP_AT_GROUP_PWD,
+    SDAP_AT_GROUP_GID,
+    SDAP_AT_GROUP_MEMBER,
+    SDAP_AT_GROUP_UUID,
+    SDAP_AT_GROUP_MODSTAMP,
+
+    SDAP_OPTS_GROUP /* attrs counter */
+};
+
+enum sdap_type {
+    SDAP_STRING,
+    SDAP_BLOB,
+    SDAP_NUMBER,
+    SDAP_BOOL
+};
 
-#define SDAP_OPTS_GROUP 7 /* attrs counter */
+struct sdap_blob {
+    uint8_t *data;
+    size_t length;
+};
+
+union sdap_value {
+    const char *cstring;
+    char *string;
+    struct sdap_blob blob;
+    int number;
+    bool boolean;
+};
 
 struct sdap_gen_opts {
     const char *opt_name;
-    const char *def_value;
-    char *value;
+    enum sdap_type type;
+    union sdap_value def_val;
+    union sdap_value val;
 };
 
 struct sdap_id_map {
@@ -137,15 +165,6 @@ struct sdap_options {
     struct sdap_id_map *user_map;
     struct sdap_id_map *group_map;
 
-    /* transformed for easier consumption */
-    uint32_t default_authtok_size;
-    char *default_authtok; /* todo: turn into uint8_t */
-    int network_timeout;
-    int opt_timeout;
-    int offline_timeout;
-    int enum_refresh_timeout;
-    bool force_upper_case_realm;
-
     /* supported schema types */
     enum schema_type {
         SDAP_SCHEMA_RFC2307 = 1,    /* memberUid = uid */
@@ -162,6 +181,22 @@ int sdap_get_options(TALLOC_CTX *memctx,
                      const char *conf_path,
                      struct sdap_options **_opts);
 
+const char *_sdap_go_get_cstring(struct sdap_gen_opts *opts,
+                                 int id, const char *location);
+char *_sdap_go_get_string(struct sdap_gen_opts *opts,
+                          int id, const char *location);
+struct sdap_blob _sdap_go_get_blob(struct sdap_gen_opts *opts,
+                                   int id, const char *location);
+int _sdap_go_get_int(struct sdap_gen_opts *opts,
+                     int id, const char *location);
+bool _sdap_go_get_bool(struct sdap_gen_opts *opts,
+                       int id, const char *location);
+#define sdap_go_get_cstring(o, i) _sdap_go_get_cstring(o, i, __FUNCTION__)
+#define sdap_go_get_string(o, i) _sdap_go_get_string(o, i, __FUNCTION__)
+#define sdap_go_get_blob(o, i) _sdap_go_get_blob(o, i, __FUNCTION__)
+#define sdap_go_get_int(o, i) _sdap_go_get_int(o, i, __FUNCTION__)
+#define sdap_go_get_bool(o, i) _sdap_go_get_bool(o, i, __FUNCTION__)
+
 int sdap_parse_user(TALLOC_CTX *memctx, struct sdap_options *opts,
                     struct sdap_handle *sh, struct sdap_msg *sm,
                     struct sysdb_attrs **_attrs, char **_dn);
diff --git a/server/providers/ldap/sdap_async.c b/server/providers/ldap/sdap_async.c
index bcdf22a..1a0faf4 100644
--- a/server/providers/ldap/sdap_async.c
+++ b/server/providers/ldap/sdap_async.c
@@ -472,7 +472,8 @@ struct tevent_req *sdap_connect_send(TALLOC_CTX *memctx,
         return NULL;
     }
     /* Initialize LDAP handler */
-    lret = ldap_initialize(&state->sh->ldap, opts->basic[SDAP_URI].value);
+    lret = ldap_initialize(&state->sh->ldap,
+                           sdap_go_get_string(opts->basic, SDAP_URI));
     if (lret != LDAP_SUCCESS) {
         DEBUG(1, ("ldap_initialize failed: %s\n", ldap_err2string(ret)));
         goto fail;
@@ -487,22 +488,22 @@ struct tevent_req *sdap_connect_send(TALLOC_CTX *memctx,
     }
 
     /* Set Network Timeout */
-    tv.tv_sec = opts->network_timeout;
+    tv.tv_sec = sdap_go_get_int(opts->basic, SDAP_NETWORK_TIMEOUT);
     tv.tv_usec = 0;
     lret = ldap_set_option(state->sh->ldap, LDAP_OPT_NETWORK_TIMEOUT, &tv);
     if (lret != LDAP_OPT_SUCCESS) {
         DEBUG(1, ("Failed to set network timeout to %d\n",
-                  opts->network_timeout));
+                  sdap_go_get_int(opts->basic, SDAP_NETWORK_TIMEOUT)));
         goto fail;
     }
 
     /* Set Default Timeout */
-    tv.tv_sec = opts->opt_timeout;
+    tv.tv_sec = sdap_go_get_int(opts->basic, SDAP_OPT_TIMEOUT);
     tv.tv_usec = 0;
     lret = ldap_set_option(state->sh->ldap, LDAP_OPT_TIMEOUT, &tv);
     if (lret != LDAP_OPT_SUCCESS) {
         DEBUG(1, ("Failed to set default timeout to %d\n",
-                  opts->opt_timeout));
+                  sdap_go_get_int(opts->basic, SDAP_OPT_TIMEOUT)));
         goto fail;
     }
 
@@ -766,7 +767,7 @@ struct tevent_req *sdap_auth_send(TALLOC_CTX *memctx,
                                   struct sdap_handle *sh,
                                   const char *user_dn,
                                   const char *authtok_type,
-                                  const char *password)
+                                  struct sdap_blob authtok)
 {
     struct tevent_req *req, *subreq;
     struct sdap_auth_state *state;
@@ -780,13 +781,8 @@ struct tevent_req *sdap_auth_send(TALLOC_CTX *memctx,
     if (!req) return NULL;
 
     state->user_dn = user_dn;
-    if (password) {
-        state->pw.bv_val = discard_const(password);
-        state->pw.bv_len = strlen(password);
-    } else {
-        state->pw.bv_val = NULL;
-        state->pw.bv_len = 0;
-    }
+    state->pw.bv_val = (char *)authtok.data;
+    state->pw.bv_len = authtok.length;
 
     subreq = simple_bind_send(state, ev, sh, user_dn, &state->pw);
     if (!subreq) {
@@ -1020,7 +1016,7 @@ static struct tevent_req *sdap_save_user_send(TALLOC_CTX *memctx,
             ret = ENOMEM;
             goto fail;
         }
-        if (opts->force_upper_case_realm) {
+        if (sdap_go_get_bool(opts->basic, SDAP_FORCE_UPPER_CASE_REALM)) {
             make_realm_upper_case(upn);
         }
         DEBUG(7, ("Adding user principle [%s] to attributes of [%s].\n",
@@ -1234,10 +1230,12 @@ static struct tevent_req *sdap_save_group_send(TALLOC_CTX *memctx,
         if (!opts->users_base) {
             opts->users_base = ldb_dn_new_fmt(opts,
                                     sysdb_handle_get_ldb(state->handle), "%s",
-                                    opts->basic[SDAP_USER_SEARCH_BASE].value);
+                                    sdap_go_get_string(opts->basic,
+                                                      SDAP_USER_SEARCH_BASE));
             if (!opts->users_base) {
                 DEBUG(1, ("Unable to get casefold Users Base DN from [%s]\n",
-                          opts->basic[SDAP_USER_SEARCH_BASE].value));
+                          sdap_go_get_string(opts->basic,
+                                             SDAP_USER_SEARCH_BASE)));
                 DEBUG(1, ("Out of memory?!\n"));
                 ret = ENOMEM;
                 goto fail;
@@ -1246,10 +1244,12 @@ static struct tevent_req *sdap_save_group_send(TALLOC_CTX *memctx,
         if (!opts->groups_base) {
             opts->groups_base = ldb_dn_new_fmt(state->handle,
                                     sysdb_handle_get_ldb(state->handle), "%s",
-                                    opts->basic[SDAP_GROUP_SEARCH_BASE].value);
+                                    sdap_go_get_string(opts->basic,
+                                                      SDAP_GROUP_SEARCH_BASE));
             if (!opts->users_base) {
                 DEBUG(1, ("Unable to get casefold Users Base DN from [%s]\n",
-                          opts->basic[SDAP_USER_SEARCH_BASE].value));
+                          sdap_go_get_string(opts->basic,
+                                             SDAP_GROUP_SEARCH_BASE)));
                 DEBUG(1, ("Out of memory?!\n"));
                 ret = ENOMEM;
                 goto fail;
@@ -1500,7 +1500,8 @@ static void sdap_get_users_transaction(struct tevent_req *subreq)
     DEBUG(5, ("calling ldap_search_ext with [%s].\n", state->filter));
 
     lret = ldap_search_ext(state->sh->ldap,
-                           state->opts->basic[SDAP_USER_SEARCH_BASE].value,
+                           sdap_go_get_string(state->opts->basic,
+                                              SDAP_USER_SEARCH_BASE),
                            LDAP_SCOPE_SUBTREE, state->filter,
                            discard_const(state->attrs),
                            false, NULL, NULL, NULL, 0, &msgid);
@@ -1723,7 +1724,8 @@ static void sdap_get_groups_transaction(struct tevent_req *subreq)
     }
 
     lret = ldap_search_ext(state->sh->ldap,
-                           state->opts->basic[SDAP_GROUP_SEARCH_BASE].value,
+                           sdap_go_get_string(state->opts->basic,
+                                              SDAP_GROUP_SEARCH_BASE),
                            LDAP_SCOPE_SUBTREE, state->filter,
                            discard_const(state->attrs),
                            false, NULL, NULL, NULL, 0, &msgid);
@@ -2053,7 +2055,8 @@ static void sdap_get_initgr_transaction(struct tevent_req *subreq)
     DEBUG(5, ("calling ldap_search_ext with filter:[%s].\n", state->filter));
 
     lret = ldap_search_ext(state->sh->ldap,
-                           state->opts->basic[SDAP_GROUP_SEARCH_BASE].value,
+                           sdap_go_get_string(state->opts->basic,
+                                              SDAP_GROUP_SEARCH_BASE),
                            LDAP_SCOPE_SUBTREE, state->filter,
                            discard_const(state->grp_attrs),
                            false, NULL, NULL, NULL, 0, &msgid);
diff --git a/server/providers/ldap/sdap_async.h b/server/providers/ldap/sdap_async.h
index c9af750..08b84d8 100644
--- a/server/providers/ldap/sdap_async.h
+++ b/server/providers/ldap/sdap_async.h
@@ -59,7 +59,7 @@ struct tevent_req *sdap_auth_send(TALLOC_CTX *memctx,
                                   struct sdap_handle *sh,
                                   const char *user_dn,
                                   const char *authtok_type,
-                                  const char *password);
+                                  struct sdap_blob authtok);
 int sdap_auth_recv(struct tevent_req *req, enum sdap_result *result);
 
 struct tevent_req *sdap_get_initgr_send(TALLOC_CTX *memctx,
-- 
1.6.2.5

