changeset 5121:cf996f8e9c89 HEAD

Added blocking=yes to PAM passdb to use auth workers instead of forking a new process for each lookup.
author Timo Sirainen <tss@iki.fi>
date Mon, 12 Feb 2007 23:41:07 +0200
parents e4acabdc0de0
children 419b206fd10c
files dovecot-example.conf src/auth/passdb-pam.c
diffstat 2 files changed, 38 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/dovecot-example.conf	Mon Feb 12 23:07:42 2007 +0200
+++ b/dovecot-example.conf	Mon Feb 12 23:41:07 2007 +0200
@@ -780,7 +780,12 @@
   # authentication to actually work.
   # http://wiki.dovecot.org/PasswordDatabase/PAM
   passdb pam {
-    #  [session=yes] [setcred=yes] [cache_key=<key>] [<service name>]
+    # [blocking=yes] [session=yes] [setcred=yes]
+    # [cache_key=<key>] [<service name>]
+    #
+    # By default a new process is forked from dovecot-auth for each PAM lookup.
+    # Setting blocking=yes uses the alternative way: dovecot-auth worker
+    # processes do the PAM lookups.
     #
     # session=yes makes Dovecot open and immediately close PAM session. Some
     # PAM plugins need this to work, such as pam_mkhomedir.
--- a/src/auth/passdb-pam.c	Mon Feb 12 23:07:42 2007 +0200
+++ b/src/auth/passdb-pam.c	Mon Feb 12 23:41:07 2007 +0200
@@ -243,7 +243,7 @@
 	return PAM_SUCCESS;
 }
 
-static void
+static enum passdb_result 
 pam_verify_plain_child(struct auth_request *request, const char *service,
 		       const char *password, int fd)
 {
@@ -301,6 +301,11 @@
 		}
 	}
 
+	if (worker) {
+		/* blocking=yes code path in auth worker */
+		return result;
+	}
+
 	buf = buffer_create_dynamic(pool_datastack_create(), 512);
 	buffer_append(buf, &result, sizeof(result));
 
@@ -318,6 +323,7 @@
 				ret, buf->used);
 		}
 	}
+	return result;
 }
 
 static void pam_child_input(struct pam_auth_request *request)
@@ -417,12 +423,21 @@
         struct passdb_module *_module = request->passdb->passdb;
         struct pam_passdb_module *module = (struct pam_passdb_module *)_module;
         struct pam_auth_request *pam_auth_request;
+	enum passdb_result result;
 	const char *service;
 	int fd[2];
 	pid_t pid;
 
 	service = module->service_name != NULL ?
 		module->service_name : request->service;
+
+	if (worker) {
+		/* blocking=yes code path in auth worker */
+		result = pam_verify_plain_child(request, service, password, -1);
+		callback(result, request);
+		return;
+	}
+
 	if (pipe(fd) < 0) {
 		auth_request_log_error(request, "pam", "pipe() failed: %m");
 		callback(PASSDB_RESULT_INTERNAL_FAILURE, request);
@@ -486,6 +501,8 @@
 			module->module.cache_key =
 				p_strdup(auth_passdb->auth->pool,
 					 t_args[i] + 10);
+		} else if (strcmp(t_args[i], "blocking=yes") == 0) {
+			module->module.blocking = TRUE;
 		} else if (strcmp(t_args[i], "*") == 0) {
 			module->service_name = NULL;
 		} else if (t_args[i+1] == NULL) {
@@ -534,20 +551,27 @@
 	if (pam_requests != NULL)
 		i_fatal("Can't support more than one PAM passdb");
 
-	pam_requests = hash_create(default_pool, default_pool, 0, NULL, NULL);
-	to = timeout_add(PAM_CHILD_CHECK_TIMEOUT, pam_child_timeout, NULL);
-
-	lib_signals_set_handler(SIGCHLD, TRUE, sigchld_handler, NULL);
 	/* we're caching the password by using directly the plaintext password
 	   given by the auth mechanism */
 	_module->default_pass_scheme = "PLAIN";
+
+	if (!_module->blocking) {
+		pam_requests = hash_create(default_pool, default_pool, 0,
+					   NULL, NULL);
+		to = timeout_add(PAM_CHILD_CHECK_TIMEOUT,
+				 pam_child_timeout, NULL);
+
+		lib_signals_set_handler(SIGCHLD, TRUE, sigchld_handler, NULL);
+	}
 }
 
 static void pam_deinit(struct passdb_module *_module __attr_unused__)
 {
-	lib_signals_unset_handler(SIGCHLD, sigchld_handler, NULL);
-	hash_destroy(pam_requests);
-	timeout_remove(&to);
+	if (!_module->blocking) {
+		lib_signals_unset_handler(SIGCHLD, sigchld_handler, NULL);
+		hash_destroy(pam_requests);
+		timeout_remove(&to);
+	}
 }
 
 struct passdb_module_interface passdb_pam = {