changeset 3656:fda241fa5d77 HEAD

Make auth caching work with non-sql/ldap passdbs too.
author Timo Sirainen <tss@iki.fi>
date Sun, 16 Oct 2005 15:49:14 +0300
parents 62fc6883faeb
children 0c10475d9968
files dovecot-example.conf src/auth/auth-request.c src/auth/passdb-bsdauth.c src/auth/passdb-pam.c src/auth/passdb-passwd-file.c src/auth/passdb-passwd.c src/auth/passdb-shadow.c src/auth/passdb-vpopmail.c
diffstat 8 files changed, 111 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- a/dovecot-example.conf	Sun Oct 16 15:03:37 2005 +0300
+++ b/dovecot-example.conf	Sun Oct 16 15:49:14 2005 +0300
@@ -513,10 +513,13 @@
 # Set max. process size in megabytes.
 #auth_process_size = 256
 
-# Authentication cache size in kilobytes.
+# Authentication cache size in kilobytes. 0 means it's disabled.
+# Note that bsdauth, PAM and vpopmail require cache_key to be set for caching
+# to be used.
 #auth_cache_size = 0
-# Time to live in seconds for cached data. After this many seconds a cached
-# record is forced out of cache.
+# Time to live in seconds for cached data. After this many seconds the cached
+# record is no longer used, *except* if the main database lookup returns
+# internal failure.
 #auth_cache_ttl = 3600
 
 # Space separated list of realms for SASL authentication mechanisms that need
@@ -586,10 +589,21 @@
   # so it can't be used as userdb. If you don't want to use a separate user
   # database (passwd usually), you can use static userdb.
   passdb pam {
-    # [-session] [<service name>]
+    # [-session] [cache_key=<key>] [<service name>]
     #
     # -session makes Dovecot open and immediately close PAM session. Some
     # PAM plugins need this to work.
+    #
+    # cache_key can be used to enable authentication caching for PAM
+    # (auth_cache_size also needs to be set). It isn't enabled by default
+    # because PAM modules can do all kinds of checks besides checking password,
+    # such as checking IP address. Dovecot can't know about these checks
+    # without some help. cache_key is simply a list of variables (see
+    # doc/variables.txt) which must match for the cached data to be used.
+    # Here are some examples:
+    #   %u - Username must match. Probably sufficient for most uses.
+    #   %u%r - Username and remote IP address must match.
+    #   %u%s - Username and service (ie. IMAP, POP3) must match.
     # 
     # If service name is "*", it means the authenticating service name
     # is used, eg. pop3 or imap.
@@ -606,6 +620,12 @@
   #passdb shadow {
   #}
 
+  # BSD authentication. Used by at least OpenBSD.
+  #passdb bsdauth {
+    # [cache_key=<key>] - See cache_key in PAM for explanation.
+    #args =
+  #}
+
   # passwd-like file with specified location
   #passdb passwd-file {
     # Path for passwd-file
@@ -633,6 +653,8 @@
 
   # vpopmail authentication
   #passdb vpopmail {
+    # [cache_key=<key>] - See cache_key in PAM for explanation.
+    #args =
   #}
 
   #
--- a/src/auth/auth-request.c	Sun Oct 16 15:03:37 2005 +0300
+++ b/src/auth/auth-request.c	Sun Oct 16 15:49:14 2005 +0300
@@ -202,8 +202,13 @@
 	}
 
 	if (request->passdb_password == NULL) {
-		/* save to cache only if we know the password */
-		return;
+		/* passdb didn't provide the correct password */
+		if (result != PASSDB_RESULT_OK ||
+		    request->mech_password == NULL)
+			return;
+
+		/* we can still cache valid password lookups though */
+		request->passdb_password = request->mech_password;
 	}
 
 	/* save all except the currently given password in cache */
@@ -323,6 +328,8 @@
 
 	if (request->mech_password == NULL)
 		request->mech_password = p_strdup(request->pool, password);
+	else
+		i_assert(request->mech_password == password);
 	request->private_callback.verify_plain = callback;
 
 	cache_key = passdb_cache == NULL ? NULL : passdb->cache_key;
--- a/src/auth/passdb-bsdauth.c	Sun Oct 16 15:03:37 2005 +0300
+++ b/src/auth/passdb-bsdauth.c	Sun Oct 16 15:49:14 2005 +0300
@@ -12,6 +12,9 @@
 #include <bsd_auth.h>
 #include <pwd.h>
 
+extern struct passdb_module passdb_bsdauth;
+static char *bsdauth_cache_key;
+
 static void
 bsdauth_verify_plain(struct auth_request *request, const char *password,
 		    verify_plain_callback_t *callback)
@@ -52,16 +55,28 @@
 	callback(PASSDB_RESULT_OK, request);
 }
 
+static void bsdauth_init(const char *args)
+{
+	bsdauth_cache_key = NULL;
+
+	if (strncmp(args, "cache_key=", 10) == 0)
+		bsdauth_cache_key = i_strdup(args + 10);
+
+	passdb_bsdauth.cache_key = bsdauth_cache_key;
+}
+
 static void bsdauth_deinit(void)
 {
 	endpwent();
+	i_free(bsdauth_cache_key);
 }
 
 struct passdb_module passdb_bsdauth = {
 	"bsdauth",
-	"%u", "CRYPT", FALSE,
+	NULL, NULL, FALSE,
 
-	NULL, NULL,
+	NULL,
+	bsdauth_init,
 	bsdauth_deinit,
 
 	bsdauth_verify_plain,
--- a/src/auth/passdb-pam.c	Sun Oct 16 15:03:37 2005 +0300
+++ b/src/auth/passdb-pam.c	Sun Oct 16 15:49:14 2005 +0300
@@ -71,8 +71,10 @@
 	const char *pass;
 };
 
+extern struct passdb_module passdb_pam;
+
 static int pam_session;
-static char *service_name;
+static char *service_name, *pam_cache_key;
 static struct timeout *to_wait;
 
 static int pam_userpass_conv(int num_msg, linux_const struct pam_message **msg,
@@ -409,13 +411,17 @@
 
 	pam_session = FALSE;
 	service_name = i_strdup("dovecot");
+        pam_cache_key = NULL;
 
 	t_push();
 	t_args = t_strsplit(args, " ");
         for(i = 0; t_args[i] != NULL; i++) {
 		if (strcmp(t_args[i], "-session") == 0)
 			pam_session = TRUE;
-		else if (strcmp(t_args[i], "*") == 0) {
+		else if (strncmp(t_args[i], "cache_key=", 10) == 0) {
+			i_free(pam_cache_key);
+			pam_cache_key = i_strdup(t_args[i] + 10);
+		} else if (strcmp(t_args[i], "*") == 0) {
 			i_free(service_name);
 			service_name = NULL;
 		} else {
@@ -428,6 +434,7 @@
 	t_pop();
 
 	to_wait = NULL;
+        passdb_pam.cache_key = pam_cache_key;
 }
 
 static void pam_deinit(void)
@@ -435,6 +442,7 @@
 	if (to_wait != NULL)
 		timeout_remove(to_wait);
 	i_free(service_name);
+	i_free(pam_cache_key);
 }
 
 struct passdb_module passdb_pam = {
--- a/src/auth/passdb-passwd-file.c	Sun Oct 16 15:03:37 2005 +0300
+++ b/src/auth/passdb-passwd-file.c	Sun Oct 16 15:49:14 2005 +0300
@@ -8,6 +8,9 @@
 #include "password-scheme.h"
 #include "db-passwd-file.h"
 
+#define PASSWD_FILE_CACHE_KEY "%u"
+#define PASSWD_FILE_DEFAULT_SCHEME "CRYPT"
+
 struct db_passwd_file *passdb_pwf = NULL;
 
 static void
@@ -26,7 +29,10 @@
 
 	crypted_pass = pu->password;
 	scheme = password_get_scheme(&crypted_pass);
-	if (scheme == NULL) scheme = "CRYPT";
+	if (scheme == NULL) scheme = PASSWD_FILE_DEFAULT_SCHEME;
+
+	/* save the password so cache can use it */
+	auth_request_set_field(request, "password", crypted_pass, scheme);
 
 	ret = password_verify(password, crypted_pass, scheme,
 			      request->user);
@@ -81,7 +87,9 @@
 
 struct passdb_module passdb_passwd_file = {
 	"passwd-file",
-	NULL, NULL, FALSE,
+	PASSWD_FILE_CACHE_KEY,
+	NULL,
+	FALSE,
 
 	NULL,
 	passwd_file_init,
--- a/src/auth/passdb-passwd.c	Sun Oct 16 15:03:37 2005 +0300
+++ b/src/auth/passdb-passwd.c	Sun Oct 16 15:49:14 2005 +0300
@@ -10,6 +10,9 @@
 
 #include <pwd.h>
 
+#define PASSWD_CACHE_KEY "%u"
+#define PASSWD_PASS_SCHEME "CRYPT"
+
 static void
 passwd_verify_plain(struct auth_request *request, const char *password,
 		    verify_plain_callback_t *callback)
@@ -31,6 +34,10 @@
 		return;
 	}
 
+	/* save the password so cache can use it */
+	auth_request_set_field(request, "password", pw->pw_passwd,
+			       PASSWD_PASS_SCHEME);
+
 	/* check if the password is valid */
 	result = strcmp(mycrypt(password, pw->pw_passwd), pw->pw_passwd) == 0;
 
@@ -56,7 +63,9 @@
 
 struct passdb_module passdb_passwd = {
 	"passwd",
-	"%u", "CRYPT", FALSE,
+        PASSWD_CACHE_KEY,
+        PASSWD_PASS_SCHEME,
+	FALSE,
 
 	NULL, NULL,
 	passwd_deinit,
--- a/src/auth/passdb-shadow.c	Sun Oct 16 15:03:37 2005 +0300
+++ b/src/auth/passdb-shadow.c	Sun Oct 16 15:49:14 2005 +0300
@@ -10,6 +10,9 @@
 
 #include <shadow.h>
 
+#define SHADOW_CACHE_KEY "%u"
+#define SHADOW_PASS_SCHEME "CRYPT"
+
 static void
 shadow_verify_plain(struct auth_request *request, const char *password,
 		    verify_plain_callback_t *callback)
@@ -31,6 +34,10 @@
 		return;
 	}
 
+	/* save the password so cache can use it */
+	auth_request_set_field(request, "password", spw->sp_pwdp,
+			       SHADOW_PASS_SCHEME);
+
 	/* check if the password is valid */
 	result = strcmp(mycrypt(password, spw->sp_pwdp), spw->sp_pwdp) == 0;
 
@@ -56,7 +63,9 @@
 
 struct passdb_module passdb_shadow = {
 	"shadow",
-	"%u", "CRYPT", FALSE,
+        SHADOW_CACHE_KEY,
+        SHADOW_PASS_SCHEME,
+	FALSE,
 
 	NULL, NULL,
 	shadow_deinit,
--- a/src/auth/passdb-vpopmail.c	Sun Oct 16 15:03:37 2005 +0300
+++ b/src/auth/passdb-vpopmail.c	Sun Oct 16 15:49:14 2005 +0300
@@ -14,7 +14,10 @@
 
 #include <stdlib.h>
 
+#define VPOPMAIL_DEFAULT_PASS_SCHEME "CRYPT"
+
 extern struct passdb_module passdb_vpopmail;
+static char *vpopmail_cache_key;
 
 static void
 vpopmail_verify_plain(struct auth_request *request, const char *password,
@@ -91,16 +94,30 @@
 	callback(PASSDB_RESULT_OK, request);
 }
 
+static void vpopmail_init(const char *args)
+{
+	vpopmail_cache_key = NULL;
+
+	if (strncmp(args, "cache_key=", 10) == 0)
+		vpopmail_cache_key = i_strdup(args + 10);
+
+	passdb_vpopmail.cache_key = vpopmail_cache_key;
+}
+
 static void vpopmail_deinit(void)
 {
 	vclose();
+	i_free(vpopmail_cache_key);
 }
 
 struct passdb_module passdb_vpopmail = {
 	"vpopmail",
-	"%u", "CRYPT", FALSE,
+	NULL,
+	VPOPMAIL_DEFAULT_PASS_SCHEME,
+	FALSE,
 
-	NULL, NULL,
+	NULL,
+	vpopmail_init,
 	vpopmail_deinit,
 
 	vpopmail_verify_plain,