]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
auth: Identify clients using a 128bit random cookie on top of the existing PID.
authorTimo Sirainen <tss@iki.fi>
Wed, 14 Oct 2009 22:25:29 +0000 (18:25 -0400)
committerTimo Sirainen <tss@iki.fi>
Wed, 14 Oct 2009 22:25:29 +0000 (18:25 -0400)
When master is finishing the login, it must give this cookie to REQUEST
command and it must match what auth process knows. This change makes it safe
to do client/master login without a dedicated master process.

--HG--
branch : HEAD

src/auth/auth-client-connection.c
src/auth/auth-client-connection.h
src/auth/auth-master-connection.c
src/lib-auth/auth-client.c
src/lib-auth/auth-client.h
src/lib-auth/auth-server-connection.c
src/lib-auth/auth-server-connection.h
src/lib-master/master-interface.h
src/login-common/sasl-server.c
src/master/service-auth-source.c

index 1ebc1c28d1bf2d560a43dd4b2a06c2c909db049b..df3692e1018df5260e04301c82f34a36b7e85e8b 100644 (file)
@@ -6,9 +6,11 @@
 #include "istream.h"
 #include "ostream.h"
 #include "network.h"
+#include "hex-binary.h"
 #include "hostpid.h"
 #include "str.h"
 #include "str-sanitize.h"
+#include "randgen.h"
 #include "safe-memset.h"
 #include "master-service.h"
 #include "auth-stream.h"
@@ -274,6 +276,7 @@ auth_client_connection_create(struct auth *auth, int fd)
        conn->auth = auth;
        conn->refcount = 1;
        conn->connect_uid = ++connect_uid_counter;
+       random_fill(conn->cookie, sizeof(conn->cookie));
 
        conn->fd = fd;
        conn->input = i_stream_create_fd(fd, AUTH_CLIENT_MAX_LINE_LENGTH,
@@ -285,11 +288,13 @@ auth_client_connection_create(struct auth *auth, int fd)
        array_append(&auth_client_connections, &conn, 1);
 
        str = t_str_new(128);
-       str_printfa(str, "VERSION\t%u\t%u\n%sSPID\t%s\nCUID\t%u\nDONE\n",
+       str_printfa(str, "VERSION\t%u\t%u\n%sSPID\t%s\nCUID\t%u\nCOOKIE\t",
                     AUTH_CLIENT_PROTOCOL_MAJOR_VERSION,
                     AUTH_CLIENT_PROTOCOL_MINOR_VERSION,
                    str_c(conn->auth->mech_handshake),
                    my_pid, conn->connect_uid);
+       binary_to_hex_append(str, conn->cookie, sizeof(conn->cookie));
+       str_append(str, "\nDONE\n");
 
        if (o_stream_send(conn->output, str_data(str), str_len(str)) < 0)
                auth_client_connection_destroy(&conn);
index 475c67fa48983d0bcbe84fafa09dfe38d73a1e00..583617f187e176db96e00859c885b0a740497595 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef AUTH_CLIENT_CONNECTION_H
 #define AUTH_CLIENT_CONNECTION_H
 
+#include "master-interface.h"
+
 struct auth_client_connection {
        struct auth *auth;
        int refcount;
@@ -12,6 +14,7 @@ struct auth_client_connection {
 
        unsigned int pid;
        unsigned int connect_uid;
+       uint8_t cookie[MASTER_AUTH_COOKIE_SIZE];
        struct auth_request_handler *request_handler;
 
        unsigned int version_received:1;
index ddfbe450b6ff4454a8a1762b202f6ee40a18bf1b..1ba468a162beeea475f73caa2dcb8de3211316a3 100644 (file)
@@ -5,8 +5,9 @@
 #include "hash.h"
 #include "str.h"
 #include "strescape.h"
-#include "hostpid.h"
 #include "str-sanitize.h"
+#include "hostpid.h"
+#include "hex-binary.h"
 #include "ioloop.h"
 #include "network.h"
 #include "istream.h"
@@ -69,10 +70,12 @@ master_input_request(struct auth_master_connection *conn, const char *args)
        struct auth_client_connection *client_conn;
        const char *const *list;
        unsigned int id, client_pid, client_id;
+       uint8_t cookie[MASTER_AUTH_COOKIE_SIZE];
+       buffer_t buf;
 
-       /* <id> <client-pid> <client-id> */
+       /* <id> <client-pid> <client-id> <cookie> */
        list = t_strsplit(args, "\t");
-       if (list[0] == NULL || list[1] == NULL || list[2] == NULL) {
+       if (str_array_length(list) < 4) {
                i_error("BUG: Master sent broken REQUEST");
                return FALSE;
        }
@@ -80,6 +83,11 @@ master_input_request(struct auth_master_connection *conn, const char *args)
        id = (unsigned int)strtoul(list[0], NULL, 10);
        client_pid = (unsigned int)strtoul(list[1], NULL, 10);
        client_id = (unsigned int)strtoul(list[2], NULL, 10);
+       buffer_create_data(&buf, cookie, sizeof(cookie));
+       if (hex_to_binary(list[3], &buf) < 0) {
+               i_error("BUG: Master sent broken REQUEST cookie");
+               return FALSE;
+       }
 
        client_conn = auth_client_connection_lookup(client_pid);
        if (client_conn == NULL) {
@@ -87,6 +95,11 @@ master_input_request(struct auth_master_connection *conn, const char *args)
                        client_pid);
                (void)o_stream_send_str(conn->output,
                                        t_strdup_printf("NOTFOUND\t%u\n", id));
+       } else if (memcmp(client_conn->cookie, cookie, sizeof(cookie)) != 0) {
+               i_error("Master requested auth for client %u with invalid cookie",
+                       client_pid);
+               (void)o_stream_send_str(conn->output,
+                                       t_strdup_printf("NOTFOUND\t%u\n", id));
        } else {
                auth_request_handler_master_request(
                        client_conn->request_handler, conn, id, client_id);
index 579c94967c21419be489859bd4d5e60cbec3ae2a..a5c48460917b440d75c735f975b1fe230624be29 100644 (file)
@@ -70,3 +70,8 @@ void auth_client_get_connect_id(struct auth_client *client,
        *server_pid_r = client->conn->server_pid;
        *connect_uid_r = client->conn->connect_uid;
 }
+
+const char *auth_client_get_cookie(struct auth_client *client)
+{
+       return client->conn->cookie;
+}
index 613a77a35bbc20e6274462b3b9d48a664d375965..3bbe71a9d684a4fcac596ce0658a34d3879ef5a5 100644 (file)
@@ -68,6 +68,7 @@ auth_client_find_mech(struct auth_client *client, const char *name);
 void auth_client_get_connect_id(struct auth_client *client,
                                unsigned int *server_pid_r,
                                unsigned int *connect_uid_r);
+const char *auth_client_get_cookie(struct auth_client *client);
 
 /* Create a new authentication request. callback is called whenever something
    happens for the request. */
index 11dc411df6831a22a3537bc923fab4c867f95b0d..d2f2f32c4201afeb5bc64837d73e96af27ea7a9a 100644 (file)
@@ -84,17 +84,37 @@ auth_server_input_cuid(struct auth_server_connection *conn,
                i_error("BUG: Authentication server already sent handshake");
                return -1;
        }
+       if (args[0] == NULL) {
+               i_error("BUG: Authentication server sent broken CUID line");
+               return -1;
+       }
 
        conn->connect_uid = (unsigned int)strtoul(args[0], NULL, 10);
        return 0;
 }
 
+static int
+auth_server_input_cookie(struct auth_server_connection *conn,
+                        const char *const *args)
+{
+       if (conn->cookie != NULL) {
+               i_error("BUG: Authentication server already sent cookie");
+               return -1;
+       }
+       conn->cookie = p_strdup(conn->pool, args[0]);
+       return 0;
+}
+
 static int auth_server_input_done(struct auth_server_connection *conn)
 {
        if (array_count(&conn->available_auth_mechs) == 0) {
                i_error("BUG: Authentication server returned no mechanisms");
                return -1;
        }
+       if (conn->cookie == NULL) {
+               i_error("BUG: Authentication server didn't send a cookie");
+               return -1;
+       }
 
        if (conn->to != NULL)
                timeout_remove(&conn->to);
@@ -197,6 +217,8 @@ auth_server_connection_input_line(struct auth_server_connection *conn,
                return auth_server_input_spid(conn, args + 1);
        else if (strcmp(args[0], "CUID") == 0)
                return auth_server_input_cuid(conn, args + 1);
+       else if (strcmp(args[0], "COOKIE") == 0)
+               return auth_server_input_cookie(conn, args + 1);
        else if (strcmp(args[0], "DONE") == 0)
                return auth_server_input_done(conn);
        else {
index b8e924ff664cb12141a9781ee1c3d9c8eac1065c..b7e7b6c798bb5651b67dc9f85d2fa9b8b87ca001 100644 (file)
@@ -15,6 +15,7 @@ struct auth_server_connection {
 
        unsigned int server_pid;
        unsigned int connect_uid;
+       char *cookie;
 
        ARRAY_DEFINE(available_auth_mechs, struct auth_mech_desc);
 
index a35275f722ab2a8f1489e4cb1334ce1b75641aee..fbde493e231cffb21cada6977b1cc71b2177ac93 100644 (file)
@@ -34,15 +34,19 @@ struct log_service_handshake {
    to make sure there's space to transfer the command tag  */
 #define MASTER_AUTH_MAX_DATA_SIZE (1024*2)
 
+/* Authentication client process's cookie size */
+#define MASTER_AUTH_COOKIE_SIZE (128/8)
+
 /* Authentication request. File descriptor may be sent along with the
    request. */
 struct master_auth_request {
        /* Request tag. Reply is sent back using same tag. */
        unsigned int tag;
 
-       /* Authentication process and authentication ID. */
+       /* Authentication process, authentication ID and auth cookie. */
        pid_t auth_pid;
        unsigned int auth_id;
+       uint8_t cookie[MASTER_AUTH_COOKIE_SIZE];
 
        /* Local and remote IPs of the connection. The file descriptor
           itself may be a local socketpair. */
index 0a82fedffa655f55a15369e6aa12c0a31a5e04bd..c771ed3285debb22834857bf5d3622404f5c260d 100644 (file)
@@ -3,6 +3,7 @@
 #include "common.h"
 #include "base64.h"
 #include "buffer.h"
+#include "hex-binary.h"
 #include "istream.h"
 #include "write-full.h"
 #include "strescape.h"
@@ -102,16 +103,23 @@ master_send_request(struct client *client, struct auth_client_request *request)
 {
        struct master_auth_request req;
        const unsigned char *data;
+       const char *cookie;
        size_t size;
        buffer_t *buf;
 
+       buf = buffer_create_dynamic(pool_datastack_create(), 256);
+
        memset(&req, 0, sizeof(req));
        req.auth_pid = auth_client_request_get_server_pid(request);
        req.auth_id = auth_client_request_get_id(request);
        req.local_ip = client->local_ip;
        req.remote_ip = client->ip;
 
-       buf = buffer_create_dynamic(pool_datastack_create(), 256);
+       cookie = auth_client_get_cookie(auth_client);
+       if (hex_to_binary(cookie, buf) == 0 && buf->used == sizeof(req.cookie))
+               memcpy(req.cookie, buf->data, sizeof(req.cookie));
+
+       buffer_set_used_size(buf, 0);
        buffer_append(buf, client->master_data_prefix,
                      client->master_data_prefix_len);
 
index 17c53f43551dcd53a3e761d21bb70d4532a4ffe8..d6b5c120746c417e9ed816b6389bf89b72d97d85 100644 (file)
@@ -3,6 +3,7 @@
 #include "common.h"
 #include "hash.h"
 #include "str.h"
+#include "hex-binary.h"
 #include "ioloop.h"
 #include "ostream.h"
 #include "fdpass.h"
@@ -85,7 +86,8 @@ void service_process_auth_source_send_reply(struct service_process_auth_source *
 static unsigned int
 auth_server_send_request(struct service_process_auth_server *server_process,
                         struct service_process_auth_source *source_process,
-                        unsigned int auth_id)
+                        unsigned int auth_id,
+                        const uint8_t cookie[MASTER_AUTH_COOKIE_SIZE])
 {
        unsigned int tag = 0;
        string_t *str;
@@ -104,8 +106,11 @@ auth_server_send_request(struct service_process_auth_server *server_process,
                str_truncate(str, 0);
        }
 
-       str_printfa(str, "REQUEST\t%u\t%s\t%u\n",
+       str_printfa(str, "REQUEST\t%u\t%s\t%u\t",
                    tag, dec2str(source_process->process.pid), auth_id);
+       binary_to_hex_append(str, cookie, MASTER_AUTH_COOKIE_SIZE);
+       str_append_c(str, '\n');
+
        o_stream_send(server_process->auth_output, str_data(str), str_len(str));
        return tag;
 }
@@ -241,7 +246,8 @@ service_process_auth_source_input(struct service_process_auth_source *process)
        auth_req->data_size = req.data_size;
        memcpy(auth_req->data, data, req.data_size);
 
-       tag = auth_server_send_request(auth_process, process, req.auth_id);
+       tag = auth_server_send_request(auth_process, process, req.auth_id,
+                                      req.cookie);
 
        service_process_ref(&process->process);
        hash_table_insert(auth_process->auth_requests,