From: Aki Tuomi Date: Fri, 28 Apr 2017 09:51:20 +0000 (+0300) Subject: auth: Add username_filter for passdb block X-Git-Tag: 2.3.0.rc1~1681 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=268a76700330d159c805c70d1e3eae2e21f1cb9e;p=thirdparty%2Fdovecot%2Fcore.git auth: Add username_filter for passdb block 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. --- diff --git a/src/auth/auth-request.c b/src/auth/auth-request.c index 7f11d4fc2c..ce810496c8 100644 --- a/src/auth/auth-request.c +++ b/src/auth/auth-request.c @@ -27,6 +27,7 @@ #include "userdb-blocking.h" #include "userdb-template.h" #include "password-scheme.h" +#include "wildcard-match.h" #include @@ -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; diff --git a/src/auth/auth-request.h b/src/auth/auth-request.h index 8ca2c6ebc4..cb400dd74b 100644 --- a/src/auth/auth-request.h +++ b/src/auth/auth-request.h @@ -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 diff --git a/src/auth/auth-settings.c b/src/auth/auth-settings.c index 43105e1a52..0c4d630a3e 100644 --- a/src/auth/auth-settings.c +++ b/src/auth/auth-settings.c @@ -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", diff --git a/src/auth/auth-settings.h b/src/auth/auth-settings.h index 52af364e5d..3c69a6733d 100644 --- a/src/auth/auth-settings.h +++ b/src/auth/auth-settings.h @@ -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; diff --git a/src/auth/passdb.c b/src/auth/passdb.c index 3999c12103..293dbf68e9 100644 --- a/src/auth/passdb.c +++ b/src/auth/passdb.c @@ -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; } diff --git a/src/auth/passdb.h b/src/auth/passdb.h index f26c188065..ea07dbb6b4 100644 --- a/src/auth/passdb.h +++ b/src/auth/passdb.h @@ -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. */