This patch finally allows us to define the type for basic options.
It uses a union to store different types, and an enum to list the
allowed types.
It also provides for helper functions that always check the type to
safely retrieve data, or scream loudly if we messed up.

This allowed me to remove all but 1 special option that was a duplicate
made only to avoid converting from string to int every time we needed to
get an option.
The only remaining special case is the schema type, because that is a
special string to special number transaltion. But these kind of options
(another is tls_reqcert) are rare enough that we can avoid trying to
make special handlers for them too.

Currently there are 4 types supported: string, blob, number, boolean.
String has 2 subtypes, const and non const, but they are not enforced
(you can assign a const string and then re-read it as non-const). But
this is not really a problem, as values are always copied in the init
functions, furthermore, although you can get values as non-const they
should always be regarded a immutable strings as the value returned is
the actual string saved in the option, so changing it, means changing
the configuration.

I think we can later take this code and make it generic in the provider
backend code, so that all backends can use it. It should be easy enough
to do.

Simo.

-- 
Simo Sorce * Red Hat, Inc * New York
>From 19dbd03214f9a8f98f0736ee274e04fda3ea651b Mon Sep 17 00:00:00 2001
From: Simo Sorce <[email protected]>
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

_______________________________________________
sssd-devel mailing list
[email protected]
https://fedorahosted.org/mailman/listinfo/sssd-devel

Reply via email to