changeset 1707:ba70d60987e2 HEAD

We now support checking the password against all defined auth processes and use the one that matches.
author Timo Sirainen <tss@iki.fi>
date Fri, 22 Aug 2003 07:42:13 +0300
parents cdf53841c4af
children 0731fc436585
files dovecot-example.conf src/lib-auth/auth-server-request.c
diffstat 2 files changed, 139 insertions(+), 42 deletions(-) [+]
line wrap: on
line diff
--- a/dovecot-example.conf	Fri Aug 22 06:52:25 2003 +0300
+++ b/dovecot-example.conf	Fri Aug 22 07:42:13 2003 +0300
@@ -337,15 +337,11 @@
 ## Authentication processes
 ##
 
-# You can have multiple processes; each time "auth = xx" is seen, a new
-# process definition is started. The point of multiple processes is to be
-# able to set stricter permissions to others. For example, plain/PAM
-# authentication requires roots, but if you also use digest-md5 authentication
-# for some users, you can authenticate them without any privileges in a
-# separate auth process. Just remember that only one auth process is asked
-# for the password, so you can't have different passwords with different
-# processes (unless they have different auth mechanisms, and you're ok with
-# having different password for each mechanism).
+# You can have multiple authentication processes. With plaintext authentication
+# the password is checked against each process, the first one which succeeds is
+# used. This is useful if you want to allow both system users (/etc/passwd)
+# and virtual users to login without duplicating the system users into virtual
+# database.
 
 # Executable location
 #auth_executable = /usr/libexec/dovecot/dovecot-auth
@@ -379,7 +375,7 @@
 auth default {
   # Space separated list of wanted authentication mechanisms:
   #   plain digest-md5 anonymous
-  auth_mechanisms = plain
+  mechanisms = plain
 
   # Where user database is kept:
   #   passwd: /etc/passwd or similiar, using getpwnam()
@@ -388,7 +384,7 @@
   #   vpopmail: vpopmail library
   #   ldap <config path>: LDAP, see doc/dovecot-ldap.conf
   #   pgsql <config path>: a PostgreSQL database, see doc/dovecot-pgsql.conf
-  auth_userdb = passwd
+  userdb = passwd
 
   # Where password database is kept:
   #   passwd: /etc/passwd or similiar, using getpwnam()
@@ -398,34 +394,44 @@
   #   vpopmail: vpopmail authentication
   #   ldap <config path>: LDAP, see doc/dovecot-ldap.conf
   #   pgsql <config path>: a PostgreSQL database, see doc/dovecot-pgsql.conf
-  auth_passdb = pam
+  passdb = pam
 
   # User to use for the process. This user needs access to only user and
   # password databases, nothing else. Only shadow and pam authentication
   # requires roots, so use something else if possible. Note that passwd
   # authentication with BSDs internally accesses shadow files, which also
   # requires roots.
-  auth_user = root
+  user = root
 
   # Directory where to chroot the process. Most authentication backends don't
   # work if this is set, and there's no point chrooting if auth_user is root.
-  #auth_chroot = 
+  #chroot = 
 
   # Number of authentication processes to create
-  #auth_count = 1
+  #count = 1
 }
 
-# digest-md5 authentication process. It requires special MD5 passwords which
-# /etc/shadow and PAM doesn't support, so we never need roots to handle it.
-# Note that the passwd-file is opened before chrooting and dropping root
-# privileges, so it may be 0600-root owned file.
+# PAM doesn't provide a way to get uid, gid or home directory. If you don't
+# want to use a separate user database (passwd usually), you can use static
+# userdb.
 
-#auth digest_md5 {
-#  auth_mechanisms = digest-md5
-#  auth_userdb = passwd-file /etc/passwd.imap
-#  auth_passdb = passwd-file /etc/passwd.imap
-#  auth_user = imapauth
+#auth onlypam {
+#  mechanisms = plain
+#  userdb = static uid=500 gid=500 home=/var/mail/%u
+#  passdb = pam
+#  user = dovecot-auth
 #}
 
-# if you plan to use only passwd-file, you don't need the two auth processes,
-# simply set "auth_mechanisms = plain digest-md5"
+#auth ldap {
+#  mechanisms = plain
+#  userdb = ldap /etc/dovecot-ldap.conf
+#  passdb = ldap /etc/dovecot-ldap.conf
+#  user = dovecot-auth
+#}
+
+#auth virtualfile {
+#  mechanisms = plain digest-md5
+#  userdb = passwd-file /etc/passwd.imap
+#  passdb = passwd-file /etc/passwd.imap
+#  user = dovecot-auth
+#}
--- a/src/lib-auth/auth-server-request.c	Fri Aug 22 06:52:25 2003 +0300
+++ b/src/lib-auth/auth-server-request.c	Fri Aug 22 07:42:13 2003 +0300
@@ -8,22 +8,63 @@
 #include "auth-server-request.h"
 
 struct auth_request {
-        enum auth_mech mech;
         struct auth_server_connection *conn;
 
+	enum auth_mech mech;
+        enum auth_protocol protocol;
+
 	unsigned int id;
 
 	auth_request_callback_t *callback;
 	void *context;
 
+        struct auth_server_connection *next_conn;
+	unsigned char *plaintext_data; /* for resending to other servers */
+        size_t plaintext_data_size;
+
 	unsigned int init_sent:1;
+	unsigned int retrying:1;
 };
 
+static int auth_server_send_new_request(struct auth_server_connection *conn,
+					struct auth_request *request)
+{
+	struct auth_client_request_new auth_request;
+
+	auth_request.type = AUTH_CLIENT_REQUEST_NEW;
+	auth_request.id = request->id;
+	auth_request.protocol = request->protocol;
+	auth_request.mech = request->mech;
+
+	if (o_stream_send(conn->output, &auth_request,
+			  sizeof(auth_request)) < 0) {
+		errno = conn->output->stream_errno;
+		i_warning("Error sending request to auth server: %m");
+		auth_server_connection_destroy(conn, TRUE);
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static struct auth_server_connection *
+get_next_plain_server(struct auth_server_connection *conn)
+{
+	conn = conn->next;
+	while (conn != NULL) {
+		if ((conn->available_auth_mechs & AUTH_MECH_PLAIN) != 0)
+			return conn;
+		conn = conn->next;
+	}
+	return NULL;
+}
+
 void auth_server_request_handle_reply(struct auth_server_connection *conn,
 				      struct auth_client_request_reply *reply,
 				      const unsigned char *data)
 {
 	struct auth_request *request;
+        struct auth_server_connection *next;
 
 	request = hash_lookup(conn->requests, POINTER_CAST(reply->id));
 	if (request == NULL) {
@@ -32,10 +73,49 @@
 		return;
 	}
 
+	switch (reply->result) {
+	case AUTH_CLIENT_RESULT_SUCCESS:
+		if (conn == request->conn)
+			request->next_conn = NULL;
+		else {
+			i_assert(request->next_conn == conn);
+			request->conn = request->next_conn;
+			request->next_conn = NULL;
+		}
+		break;
+	case AUTH_CLIENT_RESULT_FAILURE:
+		if (request->plaintext_data == NULL)
+			break;
+
+		next = get_next_plain_server(conn);
+		if (next == NULL)
+			break;
+
+		hash_remove(conn->requests, POINTER_CAST(request->id));
+		hash_insert(next->requests, POINTER_CAST(request->id), request);
+
+		if (conn == request->conn)
+			request->conn = request->next_conn;
+
+		request->next_conn = next;
+		request->retrying = TRUE;
+
+		auth_server_send_new_request(next, request);
+		return;
+	case AUTH_CLIENT_RESULT_CONTINUE:
+		if (!request->retrying)
+			break;
+
+		auth_client_request_continue(request, request->plaintext_data,
+					     request->plaintext_data_size);
+		return;
+	}
+
 	request->callback(request, reply, data, request->context);
 
 	if (reply->result != AUTH_CLIENT_RESULT_CONTINUE) {
 		hash_remove(conn->requests, POINTER_CAST(request->id));
+		i_free(request->plaintext_data);
 		i_free(request);
 	}
 }
@@ -62,15 +142,15 @@
 {
 	struct auth_server_connection *conn;
 	struct auth_request *request;
-	struct auth_client_request_new auth_request;
 
 	conn = auth_server_connection_find_mech(client, mech, error_r);
 	if (conn == NULL)
 		return NULL;
 
 	request = i_new(struct auth_request, 1);
+	request->conn = conn;
 	request->mech = mech;
-	request->conn = conn;
+	request->protocol = protocol;
 	request->id = ++client->request_id_counter;
 	if (request->id == 0) {
 		/* wrapped - ID 0 not allowed */
@@ -81,17 +161,8 @@
 
 	hash_insert(conn->requests, POINTER_CAST(request->id), request);
 
-	/* send request to auth */
-	auth_request.type = AUTH_CLIENT_REQUEST_NEW;
-	auth_request.id = request->id;
-	auth_request.protocol = protocol;
-	auth_request.mech = request->mech;
-	if (o_stream_send(request->conn->output, &auth_request,
-			  sizeof(auth_request)) < 0) {
-		errno = request->conn->output->stream_errno;
-		i_warning("Error sending request to auth server: %m");
-		auth_server_connection_destroy(request->conn, TRUE);
-	}
+	if (!auth_server_send_new_request(conn, request))
+		request = NULL;
 	return request;
 }
 
@@ -100,6 +171,23 @@
 {
 	struct auth_client_request_continue auth_request;
 
+	if (request->mech == AUTH_MECH_PLAIN &&
+	    request->plaintext_data == NULL) {
+		request->next_conn = get_next_plain_server(request->conn);
+		if (request->next_conn != NULL) {
+			/* plaintext authentication - save the data so we can
+			   try it for the next */
+			request->plaintext_data = i_malloc(data_size);
+			memcpy(request->plaintext_data, data, data_size);
+			request->plaintext_data_size = data_size;
+
+			hash_insert(request->next_conn->requests,
+				    POINTER_CAST(request->id), request);
+			auth_server_send_new_request(request->next_conn,
+						     request);
+		}
+	}
+
 	/* send continued request to auth */
 	auth_request.type = AUTH_CLIENT_REQUEST_CONTINUE;
 	auth_request.id = request->id;
@@ -118,8 +206,11 @@
 {
 	void *id = POINTER_CAST(request->id);
 
-	if (hash_lookup(request->conn->requests, id) != NULL)
-		hash_remove(request->conn->requests, id);
+	hash_remove(request->conn->requests, id);
+	if (request->next_conn != NULL)
+		hash_remove(request->next_conn->requests, id);
+
+	i_free(request->plaintext_data);
 	i_free(request);
 }