From: Timo Sirainen Date: Wed, 14 Oct 2009 22:25:29 +0000 (-0400) Subject: auth: Identify clients using a 128bit random cookie on top of the existing PID. X-Git-Tag: 2.0.alpha2~104 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=419baa2c17c63ae516b2df6cc5695f15aaccbff8;p=thirdparty%2Fdovecot%2Fcore.git auth: Identify clients using a 128bit random cookie on top of the existing PID. 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 --- diff --git a/src/auth/auth-client-connection.c b/src/auth/auth-client-connection.c index 1ebc1c28d1..df3692e101 100644 --- a/src/auth/auth-client-connection.c +++ b/src/auth/auth-client-connection.c @@ -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); diff --git a/src/auth/auth-client-connection.h b/src/auth/auth-client-connection.h index 475c67fa48..583617f187 100644 --- a/src/auth/auth-client-connection.h +++ b/src/auth/auth-client-connection.h @@ -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; diff --git a/src/auth/auth-master-connection.c b/src/auth/auth-master-connection.c index ddfbe450b6..1ba468a162 100644 --- a/src/auth/auth-master-connection.c +++ b/src/auth/auth-master-connection.c @@ -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; - /* */ + /* */ 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); diff --git a/src/lib-auth/auth-client.c b/src/lib-auth/auth-client.c index 579c94967c..a5c4846091 100644 --- a/src/lib-auth/auth-client.c +++ b/src/lib-auth/auth-client.c @@ -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; +} diff --git a/src/lib-auth/auth-client.h b/src/lib-auth/auth-client.h index 613a77a35b..3bbe71a9d6 100644 --- a/src/lib-auth/auth-client.h +++ b/src/lib-auth/auth-client.h @@ -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. */ diff --git a/src/lib-auth/auth-server-connection.c b/src/lib-auth/auth-server-connection.c index 11dc411df6..d2f2f32c42 100644 --- a/src/lib-auth/auth-server-connection.c +++ b/src/lib-auth/auth-server-connection.c @@ -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 { diff --git a/src/lib-auth/auth-server-connection.h b/src/lib-auth/auth-server-connection.h index b8e924ff66..b7e7b6c798 100644 --- a/src/lib-auth/auth-server-connection.h +++ b/src/lib-auth/auth-server-connection.h @@ -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); diff --git a/src/lib-master/master-interface.h b/src/lib-master/master-interface.h index a35275f722..fbde493e23 100644 --- a/src/lib-master/master-interface.h +++ b/src/lib-master/master-interface.h @@ -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. */ diff --git a/src/login-common/sasl-server.c b/src/login-common/sasl-server.c index 0a82fedffa..c771ed3285 100644 --- a/src/login-common/sasl-server.c +++ b/src/login-common/sasl-server.c @@ -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); diff --git a/src/master/service-auth-source.c b/src/master/service-auth-source.c index 17c53f4355..d6b5c12074 100644 --- a/src/master/service-auth-source.c +++ b/src/master/service-auth-source.c @@ -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,