]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
auth: ldap - Restore db_ldap_field_hide_password() functionality
authorMarco Bettini <marco.bettini@open-xchange.com>
Wed, 10 Jul 2024 14:47:09 +0000 (14:47 +0000)
committerAki Tuomi <aki.tuomi@open-xchange.com>
Wed, 12 Feb 2025 10:34:13 +0000 (12:34 +0200)
src/auth/db-ldap.c
src/auth/db-ldap.h
src/auth/passdb-ldap.c
src/auth/userdb-ldap.c

index 3801b3616b0e9bb64af63b26eec890f3ada15aee..52eec16ddbe7c07008c3aa309fadd5d18bbe1f84 100644 (file)
@@ -69,6 +69,7 @@ struct db_ldap_result_iterate_context {
 
        struct ldap_request *ldap_request;
        const char *const *attr_next;
+       const char *const *sensitive_attr_names;
 
        /* attribute name => value */
        HASH_TABLE(char *, struct db_ldap_value *) ldap_attrs;
@@ -1052,8 +1053,9 @@ static void db_ldap_conn_close(struct ldap_connection *conn)
 }
 
 struct ldap_field_find_context {
-       ARRAY_TYPE(const_string) attr_names;
        pool_t pool;
+       ARRAY_TYPE(const_string) attr_names;
+       ARRAY_TYPE(const_string) sensitive_attr_names;
 };
 
 static int
@@ -1072,12 +1074,23 @@ db_ldap_field_find(const char *data, void *context,
        return 1;
 }
 
+static bool
+db_ldap_is_sensitive_field(const char *name)
+{
+       return strstr(name, "nonce") != NULL ||
+              strstr(name, "password") != NULL ||
+              strstr(name, "secret") != NULL ||
+              str_ends_with(name, "key") ||
+              str_ends_with(name, "pass");
+}
+
 void db_ldap_get_attribute_names(pool_t pool,
                                 const ARRAY_TYPE(const_string) *attrlist,
                                 const char *const **attr_names_r,
+                                const char *const **sensitive_r,
                                 const char *skip_attr)
 {
-       static struct var_expand_func_table var_funcs_table[] = {
+       static const struct var_expand_func_table var_funcs_table[] = {
                { "ldap", db_ldap_field_find },
                { "ldap_multi", db_ldap_field_find },
                { NULL, NULL }
@@ -1089,6 +1102,7 @@ void db_ldap_get_attribute_names(pool_t pool,
        struct ldap_field_find_context ctx;
        ctx.pool = pool;
        p_array_init(&ctx.attr_names, pool, count / 2);
+       p_array_init(&ctx.sensitive_attr_names, pool, 2);
        string_t *tmp_str = t_str_new(128);
 
        for (unsigned int index = 0; index < count; ) {
@@ -1101,10 +1115,36 @@ void db_ldap_get_attribute_names(pool_t pool,
                const char *error ATTR_UNUSED;
                str_truncate(tmp_str, 0);
 
+               /* Mark the current end of the array before adding the elements
+                  from the expansion of the field expression. This will be
+                  used later to see which elements have been added. */
+               unsigned int index = array_count(&ctx.attr_names);
                (void)var_expand_with_funcs(tmp_str, value, NULL, var_funcs_table, &ctx, &error);
+
+               if (!db_ldap_is_sensitive_field(name))
+                       continue;
+
+               /* We want to mark as sensitive ALL the LDAP attributes involved
+                  in the creation of the "password" field. Typically this this
+                  will be a single attribute, but the field value expression
+                  allows for multiple attributes to be used. In this case, we
+                  mark them all. */
+
+               unsigned int count = array_count(&ctx.attr_names);
+               /* Now index points to the first attribute newly added to
+                  attr_names, and count points to the end of attr_names. */
+
+               for (; index < count; index++) {
+                       const char *const *src = array_idx(&ctx.attr_names, index);
+                       array_push_back(&ctx.sensitive_attr_names, src);
+               }
        }
        array_append_zero(&ctx.attr_names);
+       array_append_zero(&ctx.sensitive_attr_names);
+
        *attr_names_r = array_front(&ctx.attr_names);
+       if (sensitive_r != NULL)
+               *sensitive_r = array_front(&ctx.sensitive_attr_names);
 }
 
 #define IS_LDAP_ESCAPED_CHAR(c) \
@@ -1130,10 +1170,17 @@ const char *ldap_escape(const char *str,
 }
 
 static bool
-ldap_field_hide_password(struct db_ldap_result_iterate_context *ctx ATTR_UNUSED,
-                        const char *attr ATTR_UNUSED)
+db_ldap_field_hide_password(struct db_ldap_result_iterate_context *ctx,
+                           const char *attr)
 {
-       return FALSE;
+       struct auth_request *request = ctx->ldap_request->auth_request;
+       if (request->set->debug_passwords)
+               return FALSE;
+
+       if (ctx->sensitive_attr_names == NULL)
+               return FALSE;
+
+       return str_array_find(ctx->sensitive_attr_names, attr);
 }
 
 static void
@@ -1165,7 +1212,7 @@ get_ldap_fields(struct db_ldap_result_iterate_context *ctx,
                str_printfa(ctx->debug, " %s%s=", attr, suffix);
                if (count == 0)
                        str_append(ctx->debug, "<no values>");
-               else if (ldap_field_hide_password(ctx, attr))
+               else if (db_ldap_field_hide_password(ctx, attr))
                        str_append(ctx->debug, PASSWORD_HIDDEN_STR);
                else {
                        str_append(ctx->debug, ldap_value->values[0]);
@@ -1200,6 +1247,7 @@ db_ldap_result_iterate_init_full(struct ldap_connection *conn,
        ctx->pool = pool;
        ctx->ldap_request = &ldap_request->request;
        ctx->attr_next = ldap_request->attributes;
+       ctx->sensitive_attr_names = ldap_request->sensitive_attr_names;
        ctx->skip_null_values = skip_null_values;
        hash_table_create(&ctx->ldap_attrs, pool, 0, strcase_hash, strcasecmp);
        ctx->var = str_new(ctx->pool, 256);
index e9aaaf637bc33bee8d58ce59092d1ea33915b086..b1a4f916ff1e48b677289a118fba3c26a447e1cc 100644 (file)
@@ -86,6 +86,7 @@ struct ldap_request_search {
        const char *base;
        const char *filter;
        const char *const *attributes; /* points to (pass|user) module attributes */
+       const char *const *sensitive_attr_names;  /* same */
 
        struct db_ldap_result *result;
        ARRAY(struct ldap_request_named_result) named_results;
@@ -155,8 +156,9 @@ void db_ldap_request(struct ldap_connection *conn,
 
 void db_ldap_get_attribute_names(pool_t pool,
                                 const ARRAY_TYPE(const_string) *attrlist,
-                                const char *const **attr_names_r,
-                                const char *skip_attr) ATTR_NULL(4);
+                                const char *const **attributes_r,
+                                const char *const **sensitive_r,
+                                const char *skip_attr) ATTR_NULL(4,5);
 
 struct ldap_connection *db_ldap_init(struct event *event);
 void db_ldap_unref(struct ldap_connection **conn);
index aa9d79f40d1e8d819623f8a0f43e799419985f46..4d13b7c77f40d64a04f281f31fdcbfa38669ee09 100644 (file)
@@ -23,6 +23,7 @@ struct ldap_passdb_module {
 
        struct ldap_connection *conn;
        const char *const *attributes;
+       const char *const *sensitive_attr_names;
 };
 
 struct passdb_ldap_request {
@@ -290,6 +291,7 @@ static void ldap_lookup_pass(struct auth_request *auth_request,
        srequest->base = p_strdup(auth_request->pool, ldap_set->base);
        srequest->filter = p_strdup(auth_request->pool, ldap_set->filter);
        srequest->attributes = module->attributes;
+       srequest->sensitive_attr_names = module->sensitive_attr_names;
 
        e_debug(authdb_event(auth_request), "pass search: "
                "base=%s scope=%s filter=%s fields=%s",
@@ -319,6 +321,7 @@ static void ldap_bind_lookup_dn(struct auth_request *auth_request,
           may contain some extra parameters. if a password is returned,
           it's just ignored. */
        srequest->attributes = module->attributes;
+       srequest->sensitive_attr_names = module->sensitive_attr_names;
 
        e_debug(authdb_event(auth_request),
                "bind search: base=%s filter=%s",
@@ -442,7 +445,9 @@ static int passdb_ldap_preinit(pool_t pool, struct event *event,
 
        db_ldap_get_attribute_names(pool, &auth_post->fields,
                                    &module->attributes,
-                                   ldap_pre->passdb_ldap_bind ? "password" : NULL);
+                                   &module->sensitive_attr_names,
+                                   ldap_pre->passdb_ldap_bind ?
+                                       "password" : NULL);
 
        module->module.default_cache_key = auth_cache_parse_key_and_fields(
                pool, t_strconcat(ldap_pre->base, ldap_pre->filter, NULL),
index 6e6eb270bcf3deefcbe0a4c621954e038ea89041..dcd54fc878b62a9f62f70740085c7414e24d7bbe 100644 (file)
@@ -22,6 +22,7 @@ struct ldap_userdb_module {
 
        struct ldap_connection *conn;
        const char *const *attributes;
+       const char *const *sensitive_attr_names;
        const char *const *iterate_attributes;
 };
 
@@ -135,6 +136,7 @@ static void userdb_ldap_lookup(struct auth_request *auth_request,
        request->request.base = p_strdup(auth_request->pool, ldap_pre->base);
        request->request.filter = p_strdup(auth_request->pool, ldap_pre->filter);
        request->request.attributes = module->attributes;
+       request->request.sensitive_attr_names = module->sensitive_attr_names;
 
        settings_free(ldap_pre);
 
@@ -263,6 +265,7 @@ userdb_ldap_iterate_init(struct auth_request *auth_request,
        request->request.base = p_strdup(auth_request->pool, ldap_pre->base);
        request->request.filter = p_strdup(auth_request->pool, ldap_pre->iterate_filter);
        request->request.attributes = module->iterate_attributes;
+       request->request.sensitive_attr_names = module->sensitive_attr_names;
        request->request.multi_entry = TRUE;
        settings_free(ldap_pre);
 
@@ -326,9 +329,10 @@ static int userdb_ldap_preinit(pool_t pool, struct event *event,
        module->conn = conn = db_ldap_init(event);
 
        db_ldap_get_attribute_names(pool, &auth_post->fields,
-                                   &module->attributes, NULL);
+                                   &module->attributes,
+                                   &module->sensitive_attr_names, NULL);
        db_ldap_get_attribute_names(pool, &ldap_post->iterate_fields,
-                                   &module->iterate_attributes, NULL);
+                                   &module->iterate_attributes, NULL, NULL);
 
        module->module.default_cache_key = auth_cache_parse_key_and_fields(
                pool, t_strconcat(ldap_pre->base, ldap_pre->filter, NULL),