changeset 10059:aa30fc7d771a HEAD

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.
author Timo Sirainen <tss@iki.fi>
date Wed, 14 Oct 2009 18:25:29 -0400
parents b81f4a4076de
children 957dd8eb1e5a
files 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
diffstat 10 files changed, 77 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/src/auth/auth-client-connection.c	Wed Oct 14 16:35:16 2009 -0400
+++ b/src/auth/auth-client-connection.c	Wed Oct 14 18:25:29 2009 -0400
@@ -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 @@
 	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 @@
 	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);
--- a/src/auth/auth-client-connection.h	Wed Oct 14 16:35:16 2009 -0400
+++ b/src/auth/auth-client-connection.h	Wed Oct 14 18:25:29 2009 -0400
@@ -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 @@
 
 	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;
--- a/src/auth/auth-master-connection.c	Wed Oct 14 16:35:16 2009 -0400
+++ b/src/auth/auth-master-connection.c	Wed Oct 14 18:25:29 2009 -0400
@@ -5,8 +5,9 @@
 #include "hash.h"
 #include "str.h"
 #include "strescape.h"
+#include "str-sanitize.h"
 #include "hostpid.h"
-#include "str-sanitize.h"
+#include "hex-binary.h"
 #include "ioloop.h"
 #include "network.h"
 #include "istream.h"
@@ -69,10 +70,12 @@
 	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 @@
 	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 @@
 			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);
--- a/src/lib-auth/auth-client.c	Wed Oct 14 16:35:16 2009 -0400
+++ b/src/lib-auth/auth-client.c	Wed Oct 14 18:25:29 2009 -0400
@@ -70,3 +70,8 @@
 	*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;
+}
--- a/src/lib-auth/auth-client.h	Wed Oct 14 16:35:16 2009 -0400
+++ b/src/lib-auth/auth-client.h	Wed Oct 14 18:25:29 2009 -0400
@@ -68,6 +68,7 @@
 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. */
--- a/src/lib-auth/auth-server-connection.c	Wed Oct 14 16:35:16 2009 -0400
+++ b/src/lib-auth/auth-server-connection.c	Wed Oct 14 18:25:29 2009 -0400
@@ -84,17 +84,37 @@
 		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 @@
 		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 {
--- a/src/lib-auth/auth-server-connection.h	Wed Oct 14 16:35:16 2009 -0400
+++ b/src/lib-auth/auth-server-connection.h	Wed Oct 14 18:25:29 2009 -0400
@@ -15,6 +15,7 @@
 
 	unsigned int server_pid;
 	unsigned int connect_uid;
+	char *cookie;
 
 	ARRAY_DEFINE(available_auth_mechs, struct auth_mech_desc);
 
--- a/src/lib-master/master-interface.h	Wed Oct 14 16:35:16 2009 -0400
+++ b/src/lib-master/master-interface.h	Wed Oct 14 18:25:29 2009 -0400
@@ -34,15 +34,19 @@
    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. */
--- a/src/login-common/sasl-server.c	Wed Oct 14 16:35:16 2009 -0400
+++ b/src/login-common/sasl-server.c	Wed Oct 14 18:25:29 2009 -0400
@@ -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 @@
 {
 	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);
 
--- a/src/master/service-auth-source.c	Wed Oct 14 16:35:16 2009 -0400
+++ b/src/master/service-auth-source.c	Wed Oct 14 18:25:29 2009 -0400
@@ -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 @@
 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 @@
 		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 @@
 	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,