From: Timo Sirainen Date: Tue, 16 Mar 2010 16:26:25 +0000 (+0200) Subject: auth worker: Verify that both client and server see the same passdb/userdb IDs. X-Git-Tag: 2.0.beta4~44 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=be5c76fabc7439fd33bc799bc3ab3f570799977b;p=thirdparty%2Fdovecot%2Fcore.git auth worker: Verify that both client and server see the same passdb/userdb IDs. --HG-- branch : HEAD --- diff --git a/src/auth/auth-worker-client.c b/src/auth/auth-worker-client.c index 3751cd7bef..25ff972e91 100644 --- a/src/auth/auth-worker-client.c +++ b/src/auth/auth-worker-client.c @@ -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 { diff --git a/src/auth/auth-worker-client.h b/src/auth/auth-worker-client.h index d683c5f83a..8790f29fe0 100644 --- a/src/auth/auth-worker-client.h +++ b/src/auth/auth-worker-client.h @@ -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; diff --git a/src/auth/auth-worker-server.c b/src/auth/auth-worker-server.c index 7767b44096..0867e56cc5 100644 --- a/src/auth/auth-worker-server.c +++ b/src/auth/auth-worker-server.c @@ -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; } diff --git a/src/auth/passdb.c b/src/auth/passdb.c index 4c93041730..c892845223 100644 --- a/src/auth/passdb.c +++ b/src/auth/passdb.c @@ -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; diff --git a/src/auth/passdb.h b/src/auth/passdb.h index a83105bf65..a6351458a4 100644 --- a/src/auth/passdb.h +++ b/src/auth/passdb.h @@ -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); diff --git a/src/auth/userdb.c b/src/auth/userdb.c index 7480e9fc01..7e7e498baf 100644 --- a/src/auth/userdb.c +++ b/src/auth/userdb.c @@ -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; diff --git a/src/auth/userdb.h b/src/auth/userdb.h index 928afaf8f4..820aa61856 100644 --- a/src/auth/userdb.h +++ b/src/auth/userdb.h @@ -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);