]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
We now support checking the password against all defined auth processes and
authorTimo Sirainen <tss@iki.fi>
Fri, 22 Aug 2003 04:42:13 +0000 (07:42 +0300)
committerTimo Sirainen <tss@iki.fi>
Fri, 22 Aug 2003 04:42:13 +0000 (07:42 +0300)
use the one that matches.

--HG--
branch : HEAD

dovecot-example.conf
src/lib-auth/auth-server-request.c

index d1a8034853d02ae75fc129331539f700cb1645ad..34841b648b5ec5676bec2601529e7cf31e9d364a 100644 (file)
@@ -337,15 +337,11 @@ protocol pop3 {
 ## 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 @@ protocol pop3 {
 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 @@ auth default {
   #   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 @@ auth default {
   #   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
+#}
index 3a6cfd399d719d9356235715c05c95f41e7248e6..ca756abe0824e5dce1b145627a94ed164151def7 100644 (file)
@@ -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 @@ void auth_server_request_handle_reply(struct auth_server_connection *conn,
                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 @@ auth_client_request_new(struct auth_client *client,
 {
        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->mech = mech;
        request->conn = conn;
+       request->mech = mech;
+       request->protocol = protocol;
        request->id = ++client->request_id_counter;
        if (request->id == 0) {
                /* wrapped - ID 0 not allowed */
@@ -81,17 +161,8 @@ auth_client_request_new(struct auth_client *client,
 
        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 @@ void auth_client_request_continue(struct auth_request *request,
 {
        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 auth_client_request_abort(struct auth_request *request)
 {
        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);
 }