]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
auth worker: Verify that both client and server see the same passdb/userdb IDs.
authorTimo Sirainen <tss@iki.fi>
Tue, 16 Mar 2010 16:26:25 +0000 (18:26 +0200)
committerTimo Sirainen <tss@iki.fi>
Tue, 16 Mar 2010 16:26:25 +0000 (18:26 +0200)
--HG--
branch : HEAD

src/auth/auth-worker-client.c
src/auth/auth-worker-client.h
src/auth/auth-worker-server.c
src/auth/passdb.c
src/auth/passdb.h
src/auth/userdb.c
src/auth/userdb.h

index 3751cd7bef597aa73d50ffb2646cbd94ce83cd78..25ff972e9151e03c77bcdc2a77ada37f428363db 100644 (file)
@@ -6,6 +6,7 @@
 #include "network.h"
 #include "istream.h"
 #include "ostream.h"
+#include "hex-binary.h"
 #include "str.h"
 #include "master-service.h"
 #include "auth-request.h"
@@ -23,6 +24,9 @@ struct auth_worker_client {
        struct io *io;
        struct istream *input;
        struct ostream *output;
+
+       unsigned int version_received:1;
+       unsigned int dbhash_received:1;
 };
 
 struct auth_worker_list_context {
@@ -550,6 +554,24 @@ auth_worker_handle_line(struct auth_worker_client *client, const char *line)
         return ret;
 }
 
+static bool auth_worker_verify_db_hash(const char *line)
+{
+       string_t *str;
+       unsigned char passdb_md5[MD5_RESULTLEN];
+       unsigned char userdb_md5[MD5_RESULTLEN];
+
+       passdbs_generate_md5(passdb_md5);
+       userdbs_generate_md5(userdb_md5);
+
+       str = t_str_new(128);
+       str_append(str, "DBHASH\t");
+       binary_to_hex_append(str, passdb_md5, sizeof(passdb_md5));
+       str_append_c(str, '\t');
+       binary_to_hex_append(str, userdb_md5, sizeof(userdb_md5));
+
+       return strcmp(line, str_c(str)) == 0;
+}
+
 static void auth_worker_input(struct auth_worker_client *client)
 {
        char *line;
@@ -570,6 +592,36 @@ static void auth_worker_input(struct auth_worker_client *client)
                return;
        }
 
+       if (!client->version_received) {
+               line = i_stream_next_line(client->input);
+               if (line == NULL)
+                       return;
+
+               if (strncmp(line, "VERSION\tauth-worker\t", 20) != 0 ||
+                   atoi(t_strcut(line + 20, '\t')) !=
+                   AUTH_WORKER_PROTOCOL_MAJOR_VERSION) {
+                       i_error("Auth worker not compatible with this server "
+                               "(mixed old and new binaries?)");
+                       auth_worker_client_destroy(&client);
+                       return;
+               }
+               client->version_received = TRUE;
+       }
+       if (!client->dbhash_received) {
+               line = i_stream_next_line(client->input);
+               if (line == NULL)
+                       return;
+
+               if (!auth_worker_verify_db_hash(line)) {
+                       i_error("Auth worker sees different passdbs/userdbs "
+                               "than auth server. Maybe config just changed "
+                               "and this goes away automatically?");
+                       auth_worker_client_destroy(&client);
+                       return;
+               }
+               client->dbhash_received = TRUE;
+       }
+
         client->refcount++;
        while ((line = i_stream_next_line(client->input)) != NULL) {
                T_BEGIN {
index d683c5f83aeff71b18c177e2438443588710cb14..8790f29fe08a35955e7423c195e6a5a1c8e760d5 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef AUTH_WORKER_CLIENT_H
 #define AUTH_WORKER_CLIENT_H
 
+#define AUTH_WORKER_PROTOCOL_MAJOR_VERSION 1
+#define AUTH_WORKER_PROTOCOL_MINOR_VERSION 0
 #define AUTH_WORKER_MAX_LINE_LENGTH 8192
 
 extern struct auth_worker_client *auth_worker_client;
index 7767b4409602ba28919a2f986ccbe74cb49bf782..0867e56cc528de1c0f07dc816ad9074178ef5da5 100644 (file)
@@ -119,6 +119,28 @@ static void auth_worker_request_send_next(struct auth_worker_connection *conn)
        auth_worker_request_send(conn, request);
 }
 
+static void auth_worker_send_handshake(struct auth_worker_connection *conn)
+{
+       string_t *str;
+       unsigned char passdb_md5[MD5_RESULTLEN];
+       unsigned char userdb_md5[MD5_RESULTLEN];
+
+       str = t_str_new(128);
+       str_printfa(str, "VERSION\tauth-worker\t%u\t%u\n",
+                   AUTH_WORKER_PROTOCOL_MAJOR_VERSION,
+                   AUTH_WORKER_PROTOCOL_MINOR_VERSION);
+
+       passdbs_generate_md5(passdb_md5);
+       userdbs_generate_md5(userdb_md5);
+       str_append(str, "DBHASH\t");
+       binary_to_hex_append(str, passdb_md5, sizeof(passdb_md5));
+       str_append_c(str, '\t');
+       binary_to_hex_append(str, userdb_md5, sizeof(userdb_md5));
+       str_append_c(str, '\n');
+
+       o_stream_send(conn->output, str_data(str), str_len(str));
+}
+
 static struct auth_worker_connection *auth_worker_create(void)
 {
        struct auth_worker_connection *conn;
@@ -141,9 +163,9 @@ static struct auth_worker_connection *auth_worker_create(void)
        conn->io = io_add(fd, IO_READ, worker_input, conn);
        conn->to = timeout_add(AUTH_WORKER_MAX_IDLE_SECS * 1000,
                               auth_worker_idle_timeout, conn);
+       auth_worker_send_handshake(conn);
 
        idle_count++;
-
        array_append(&connections, &conn, 1);
        return conn;
 }
index 4c9304173085253dcc160fc8f15d739d73c1686b..c892845223f8d38e19ad4b6ac6a5dfb3499af62a 100644 (file)
@@ -232,6 +232,23 @@ void passdb_deinit(struct passdb_module *passdb)
                passdb->iface.deinit(passdb);
 }
 
+void passdbs_generate_md5(unsigned char md5[MD5_RESULTLEN])
+{
+       struct md5_context ctx;
+       struct passdb_module *const *passdbs;
+       unsigned int i, count;
+
+       md5_init(&ctx);
+       passdbs = array_get(&passdb_modules, &count);
+       for (i = 0; i < count; i++) {
+               md5_update(&ctx, &passdbs[i]->id, sizeof(passdbs[i]->id));
+               md5_update(&ctx, passdbs[i]->iface.name,
+                          strlen(passdbs[i]->iface.name));
+               md5_update(&ctx, passdbs[i]->args, strlen(passdbs[i]->args));
+       }
+       md5_final(&ctx, md5);
+}
+
 extern struct passdb_module_interface passdb_passwd;
 extern struct passdb_module_interface passdb_bsdauth;
 extern struct passdb_module_interface passdb_shadow;
index a83105bf650ae8f5a1c23194daf6a8af67c4056a..a6351458a493ff3d877c3fc652105dc3aacc0083 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef PASSDB_H
 #define PASSDB_H
 
+#include "md5.h"
+
 #define IS_VALID_PASSWD(pass) \
        ((pass)[0] != '\0' && (pass)[0] != '*' && (pass)[0] != '!')
 
@@ -93,6 +95,8 @@ void passdb_deinit(struct passdb_module *passdb);
 void passdb_register_module(struct passdb_module_interface *iface);
 void passdb_unregister_module(struct passdb_module_interface *iface);
 
+void passdbs_generate_md5(unsigned char md5[MD5_RESULTLEN]);
+
 void passdbs_init(void);
 void passdbs_deinit(void);
 
index 7480e9fc01d5f07d70a11e358ebd5cc0c488ef26..7e7e498baf2f8c92906a19acb3caf144799748d5 100644 (file)
@@ -181,6 +181,23 @@ void userdb_deinit(struct userdb_module *userdb)
                userdb->iface->deinit(userdb);
 }
 
+void userdbs_generate_md5(unsigned char md5[MD5_RESULTLEN])
+{
+       struct md5_context ctx;
+       struct userdb_module *const *userdbs;
+       unsigned int i, count;
+
+       md5_init(&ctx);
+       userdbs = array_get(&userdb_modules, &count);
+       for (i = 0; i < count; i++) {
+               md5_update(&ctx, &userdbs[i]->id, sizeof(userdbs[i]->id));
+               md5_update(&ctx, userdbs[i]->iface->name,
+                          strlen(userdbs[i]->iface->name));
+               md5_update(&ctx, userdbs[i]->args, strlen(userdbs[i]->args));
+       }
+       md5_final(&ctx, md5);
+}
+
 extern struct userdb_module_interface userdb_prefetch;
 extern struct userdb_module_interface userdb_static;
 extern struct userdb_module_interface userdb_passwd;
index 928afaf8f48b6e02868c707a2ba21b420d98976d..820aa61856244bc86828329af511bc9e296a1ea6 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef USERDB_H
 #define USERDB_H
 
+#include "md5.h"
 #include "auth-stream.h"
 
 struct auth;
@@ -71,6 +72,8 @@ void userdb_deinit(struct userdb_module *userdb);
 void userdb_register_module(struct userdb_module_interface *iface);
 void userdb_unregister_module(struct userdb_module_interface *iface);
 
+void userdbs_generate_md5(unsigned char md5[MD5_RESULTLEN]);
+
 void userdbs_init(void);
 void userdbs_deinit(void);