]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
auth: Add username_filter for passdb block
authorAki Tuomi <aki.tuomi@dovecot.fi>
Fri, 28 Apr 2017 09:51:20 +0000 (12:51 +0300)
committerAki Tuomi <aki.tuomi@dovecot.fi>
Fri, 28 Apr 2017 09:58:02 +0000 (12:58 +0300)
username_filter lets you specify one or more pattern(s) for
including or excluding users. exclusion patterns are denoted
with ! prefix.

if any exclude matches the username, passdb will be skipped.
if any inclusions is specified, and the username does not match
one of them, passdb will be skipped.

src/auth/auth-request.c
src/auth/auth-request.h
src/auth/auth-settings.c
src/auth/auth-settings.h
src/auth/passdb.c
src/auth/passdb.h

index 7f11d4fc2c2d7b5ea81755169fa6fe5b8b33371d..ce810496c85cd23e3ad8fb8d94618d1eb50be3a4 100644 (file)
@@ -27,6 +27,7 @@
 #include "userdb-blocking.h"
 #include "userdb-template.h"
 #include "password-scheme.h"
+#include "wildcard-match.h"
 
 #include <sys/stat.h>
 
@@ -638,16 +639,55 @@ auth_request_mechanism_accepted(const char *const *mechs,
        return str_array_icase_find(mechs, mech->mech_name);
 }
 
+/**
+
+Check if username is included in the filter. Logic is that if the username
+is not excluded by anything, and is included by something, it will be accepted.
+By default, all usernames are included, unless there is a inclusion item, when
+username will be excluded if there is no inclusion for it.
+
+Exclusions are denoted with a ! in front of the pattern.
+*/
+bool auth_request_username_accepted(const char *const *filter, const char *username)
+{
+       bool have_includes = FALSE;
+       bool matched_inc = FALSE;
+
+       for(;*filter != NULL; filter++) {
+               /* if filter has ! it means the pattern will be refused */
+               bool exclude = (**filter == '!');
+               if (!exclude)
+                       have_includes = TRUE;
+               if (wildcard_match(username, (*filter)+(exclude?1:0))) {
+                       if (exclude) {
+                               return FALSE;
+                       } else {
+                               matched_inc = TRUE;
+                       }
+               }
+       }
+
+       return matched_inc || !have_includes;
+}
+
 static bool
 auth_request_want_skip_passdb(struct auth_request *request,
                              struct auth_passdb *passdb)
 {
        /* if mechanism is not supported, skip */
        const char *const *mechs = passdb->passdb->mechanisms;
+       const char *const *username_filter = passdb->passdb->username_filter;
+       const char *username;
+
+       username = request->user;
 
        if (!auth_request_mechanism_accepted(mechs, request->mech))
                return TRUE;
 
+       if (passdb->passdb->username_filter != NULL &&
+           !auth_request_username_accepted(username_filter, username))
+               return TRUE;
+
        /* skip_password_check basically specifies if authentication is
           finished */
        bool authenticated = request->skip_password_check;
index 8ca2c6ebc47a1b264b11163a61e432f9801780a5..cb400dd74b7ff1aa8fe604deace82d35c6440321 100644 (file)
@@ -268,5 +268,6 @@ void auth_request_userdb_callback(enum userdb_result result,
 
 void auth_request_refresh_last_access(struct auth_request *request);
 void auth_str_append(string_t *dest, const char *key, const char *value);
+bool auth_request_username_accepted(const char *const *filter, const char *username);
 
 #endif
index 43105e1a5266b3a49bd1a9ecbd31fac612b9a2c0..0c4d630a3ec892c674d4aa47db409ac75208b94f 100644 (file)
@@ -114,6 +114,7 @@ static const struct setting_define auth_passdb_setting_defines[] = {
        DEF(SET_STR, default_fields),
        DEF(SET_STR, override_fields),
        DEF(SET_STR, mechanisms),
+       DEF(SET_STR, username_filter),
 
        DEF(SET_ENUM, skip),
        DEF(SET_ENUM, result_success),
@@ -135,6 +136,7 @@ static const struct auth_passdb_settings auth_passdb_default_settings = {
        .default_fields = "",
        .override_fields = "",
        .mechanisms = "",
+       .username_filter = "",
 
        .skip = "never:authenticated:unauthenticated",
        .result_success = "return-ok:return:return-fail:continue:continue-ok:continue-fail",
index 52af364e5d38c99c377ea0a7f5ef9defad101648..3c69a6733de42ba21373f5474df24f0aec228afd 100644 (file)
@@ -11,6 +11,7 @@ struct auth_passdb_settings {
        const char *default_fields;
        const char *override_fields;
        const char *mechanisms;
+       const char *username_filter;
 
        const char *skip;
        const char *result_success;
index 3999c12103b356e2bd7b690662e99e9f3031a240..293dbf68e9a4ead30e9d3f78fc54a8fd283f8689 100644 (file)
@@ -231,6 +231,11 @@ passdb_preinit(pool_t pool, const struct auth_passdb_settings *set)
                passdb->mechanisms = (const char* const*)p_strsplit_spaces(pool, set->mechanisms, " ,");
        }
 
+       if (*set->username_filter == '\0') {
+               passdb->username_filter = NULL;
+       } else {
+               passdb->username_filter = (const char* const*)p_strsplit_spaces(pool, set->username_filter, " ,");
+       }
        array_append(&passdb_modules, &passdb, 1);
        return passdb;
 }
index f26c1880658ecd78b11e77edf0f60d9b6b2e9ecd..ea07dbb6b4019f20566f66e7d0aad3f80382283d 100644 (file)
@@ -63,6 +63,8 @@ struct passdb_module {
        const char *default_pass_scheme;
        /* Supported authentication mechanisms, NULL is all, [NULL] is none*/
        const char *const *mechanisms;
+       /* Username filter, NULL is no filter */
+       const char *const *username_filter;
 
        /* If blocking is set to TRUE, use child processes to access
           this passdb. */