changeset 22008:700d5e6f041d

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.
author Aki Tuomi <aki.tuomi@dovecot.fi>
date Fri, 28 Apr 2017 12:51:20 +0300
parents 5849b30422cc
children 2d5018651d64
files 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
diffstat 6 files changed, 51 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/src/auth/auth-request.c	Thu Apr 27 11:53:13 2017 +0300
+++ b/src/auth/auth-request.c	Fri Apr 28 12:51:20 2017 +0300
@@ -27,6 +27,7 @@
 #include "userdb-blocking.h"
 #include "userdb-template.h"
 #include "password-scheme.h"
+#include "wildcard-match.h"
 
 #include <sys/stat.h>
 
@@ -630,16 +631,55 @@
 	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;
--- a/src/auth/auth-request.h	Thu Apr 27 11:53:13 2017 +0300
+++ b/src/auth/auth-request.h	Fri Apr 28 12:51:20 2017 +0300
@@ -268,5 +268,6 @@
 
 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
--- a/src/auth/auth-settings.c	Thu Apr 27 11:53:13 2017 +0300
+++ b/src/auth/auth-settings.c	Fri Apr 28 12:51:20 2017 +0300
@@ -114,6 +114,7 @@
 	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 @@
 	.default_fields = "",
 	.override_fields = "",
 	.mechanisms = "",
+	.username_filter = "",
 
 	.skip = "never:authenticated:unauthenticated",
 	.result_success = "return-ok:return:return-fail:continue:continue-ok:continue-fail",
--- a/src/auth/auth-settings.h	Thu Apr 27 11:53:13 2017 +0300
+++ b/src/auth/auth-settings.h	Fri Apr 28 12:51:20 2017 +0300
@@ -11,6 +11,7 @@
 	const char *default_fields;
 	const char *override_fields;
 	const char *mechanisms;
+	const char *username_filter;
 
 	const char *skip;
 	const char *result_success;
--- a/src/auth/passdb.c	Thu Apr 27 11:53:13 2017 +0300
+++ b/src/auth/passdb.c	Fri Apr 28 12:51:20 2017 +0300
@@ -231,6 +231,11 @@
 		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;
 }
--- a/src/auth/passdb.h	Thu Apr 27 11:53:13 2017 +0300
+++ b/src/auth/passdb.h	Fri Apr 28 12:51:20 2017 +0300
@@ -64,6 +64,8 @@
 	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. */