diff -r 8f7dc71ad982 src/auth/userdb-passwd.c
--- a/src/auth/userdb-passwd.c	Fri Feb 01 17:46:08 2013 +0000
+++ b/src/auth/userdb-passwd.c	Fri Feb 01 18:13:31 2013 +0000
@@ -20,6 +20,8 @@
 	struct userdb_module module;
 	struct userdb_template *tmpl;
 
+        unsigned int nologin:1;
+
 	unsigned int fast_count, slow_count;
 	unsigned int slow_warned:1;
 };
@@ -27,6 +29,8 @@
 struct passwd_userdb_iterate_context {
 	struct userdb_iterate_context ctx;
 	struct passwd_userdb_iterate_context *next_waiting;
+
+        unsigned int nologin:1;
 };
 
 static struct passwd_userdb_iterate_context *cur_userdb_iter = NULL;
@@ -76,6 +80,29 @@
 	}
 }
 
+static bool
+passwd_want_pw(struct passwd *pw, const struct auth_settings *set,
+                unsigned int nologin)
+{
+	/* skip entries not in valid UID range.
+	   they're users for daemons and such. */
+	if (pw->pw_uid < (uid_t)set->first_valid_uid)
+		return FALSE;
+	if (pw->pw_uid > (uid_t)set->last_valid_uid && set->last_valid_uid != 0)
+		return FALSE;
+
+        if (nologin) {
+            /* skip entries that don't have a valid shell.
+               they're again probably not real users. */
+            if (strcmp(pw->pw_shell, "/bin/false") == 0 ||
+                strcmp(pw->pw_shell, "/sbin/nologin") == 0 ||
+                strcmp(pw->pw_shell, "/usr/sbin/nologin") == 0)
+                    return FALSE;
+        }
+
+	return TRUE;
+}
+
 static void passwd_lookup(struct auth_request *auth_request,
 			  userdb_callback_t *callback)
 {
@@ -106,6 +133,13 @@
 		return;
 	}
 
+        if (!passwd_want_pw(&pw, auth_request->set, module->nologin)) {
+                auth_request_log_info(auth_request, "passwd",
+                                      "user has bad uid or shell");
+                callback(USERDB_RESULT_USER_UNKNOWN, auth_request);
+                return;
+        }
+
 	auth_request_set_field(auth_request, "user", pw.pw_name, NULL);
 
 	auth_request_init_userdb_reply(auth_request);
@@ -125,11 +159,15 @@
 		    userdb_iter_callback_t *callback, void *context)
 {
 	struct passwd_userdb_iterate_context *ctx;
+	struct userdb_module *_module = auth_request->userdb->userdb;
+	struct passwd_userdb_module *module =
+		(struct passwd_userdb_module *)_module;
 
 	ctx = i_new(struct passwd_userdb_iterate_context, 1);
 	ctx->ctx.auth_request = auth_request;
 	ctx->ctx.callback = callback;
 	ctx->ctx.context = context;
+        ctx->nologin = module->nologin;
 	setpwent();
 
 	if (cur_userdb_iter == NULL)
@@ -137,25 +175,6 @@
 	return &ctx->ctx;
 }
 
-static bool
-passwd_iterate_want_pw(struct passwd *pw, const struct auth_settings *set)
-{
-	/* skip entries not in valid UID range.
-	   they're users for daemons and such. */
-	if (pw->pw_uid < (uid_t)set->first_valid_uid)
-		return FALSE;
-	if (pw->pw_uid > (uid_t)set->last_valid_uid && set->last_valid_uid != 0)
-		return FALSE;
-
-	/* skip entries that don't have a valid shell.
-	   they're again probably not real users. */
-	if (strcmp(pw->pw_shell, "/bin/false") == 0 ||
-	    strcmp(pw->pw_shell, "/sbin/nologin") == 0 ||
-	    strcmp(pw->pw_shell, "/usr/sbin/nologin") == 0)
-		return FALSE;
-	return TRUE;
-}
-
 static void passwd_iterate_next(struct userdb_iterate_context *_ctx)
 {
 	struct passwd_userdb_iterate_context *ctx =
@@ -173,7 +192,7 @@
 
 	errno = 0;
 	while ((pw = getpwent()) != NULL) {
-		if (passwd_iterate_want_pw(pw, set)) {
+		if (passwd_want_pw(pw, set, ctx->nologin)) {
 			_ctx->callback(pw->pw_name, _ctx->context);
 			return;
 		}
@@ -217,9 +236,12 @@
 	module->module.cache_key = USER_CACHE_KEY;
 	module->tmpl = userdb_template_build(pool, "passwd", args);
 	module->module.blocking = TRUE;
+        module->nologin = TRUE;
 
 	if (userdb_template_remove(module->tmpl, "blocking", &value))
 		module->module.blocking = strcasecmp(value, "yes") == 0;
+        if (userdb_template_remove(module->tmpl, "nologin", &value))
+                module->nologin = strcasecmp(value, "yes") == 0;
 	/* FIXME: backwards compatibility */
 	if (!userdb_template_is_empty(module->tmpl))
 		i_warning("userdb passwd: Move templates args to override_fields setting");
