dovecot-2.0: doveadm: Added simple PLAIN authentication for remo...

dovecot at dovecot.org dovecot at dovecot.org
Fri May 20 13:30:49 EEST 2011


details:   http://hg.dovecot.org/dovecot-2.0/rev/6604f80abb02
changeset: 12814:6604f80abb02
user:      Timo Sirainen <tss at iki.fi>
date:      Fri May 20 13:30:40 2011 +0300
description:
doveadm: Added simple PLAIN authentication for remote connections.
Currently clients are required to use "doveadm" as the username and the
password must match doveadm_password setting. When using doveadm as a
client, it automatically uses these settings when connecting to remote
servers.

diffstat:

 src/doveadm/client-connection.c |  63 +++++++++++++++++++++++++++++++++++-----
 src/doveadm/doveadm-settings.c  |   2 +
 src/doveadm/doveadm-settings.h  |   1 +
 src/doveadm/server-connection.c |  47 ++++++++++++++++++++++++++---
 4 files changed, 98 insertions(+), 15 deletions(-)

diffs (225 lines):

diff -r 9c9f81ad0111 -r 6604f80abb02 src/doveadm/client-connection.c
--- a/src/doveadm/client-connection.c	Fri May 20 13:05:16 2011 +0300
+++ b/src/doveadm/client-connection.c	Fri May 20 13:30:40 2011 +0300
@@ -1,6 +1,7 @@
 /* Copyright (c) 2010-2011 Dovecot authors, see the included COPYING file */
 
 #include "lib.h"
+#include "base64.h"
 #include "ioloop.h"
 #include "istream.h"
 #include "ostream.h"
@@ -11,6 +12,7 @@
 #include "doveadm-server.h"
 #include "doveadm-mail.h"
 #include "doveadm-print.h"
+#include "doveadm-settings.h"
 #include "client-connection.h"
 
 #include <unistd.h>
@@ -147,17 +149,56 @@
 	return TRUE;
 }
 
-static bool
-client_connection_authenticate(struct client_connection *conn ATTR_UNUSED)
+static int
+client_connection_authenticate(struct client_connection *conn)
 {
-	i_fatal("Authentication not supported yet");
-	return FALSE;
+	const char *line, *pass;
+	buffer_t *plain;
+	const unsigned char *data;
+	size_t size;
+
+	if ((line = i_stream_read_next_line(conn->input)) == NULL)
+		return 0;
+
+	if (*doveadm_settings->doveadm_password == '\0') {
+		i_error("doveadm_password not set, "
+			"remote authentication disabled");
+		return -1;
+	}
+
+	/* FIXME: some day we should probably let auth process do this and
+	   support all kinds of authentication */
+	if (strncmp(line, "PLAIN\t", 6) != 0) {
+		i_error("doveadm client attempted non-PLAIN authentication");
+		return -1;
+	}
+
+	plain = buffer_create_dynamic(pool_datastack_create(), 128);
+	if (base64_decode(line + 6, strlen(line + 6), NULL, plain) < 0) {
+		i_error("doveadm client sent invalid base64 auth PLAIN data");
+		return -1;
+	}
+	data = plain->data;
+	size = plain->used;
+
+	if (size < 10 || data[0] != '\0' ||
+	    memcmp(data+1, "doveadm", 7) != 0 || data[8] != '\0') {
+		i_error("doveadm client didn't authenticate as 'doveadm'");
+		return -1;
+	}
+	pass = t_strndup(data + 9, size - 9);
+	if (strcmp(pass, doveadm_settings->doveadm_password) != 0) {
+		i_error("doveadm client authenticated with wrong password");
+		return -1;
+	}
+	return 1;
 }
 
 static void client_connection_input(struct client_connection *conn)
 {
 	const char *line;
-	bool ret = TRUE;
+	bool ok = TRUE;
+	int ret;
 
 	if (!conn->handshaked) {
 		if ((line = i_stream_read_next_line(conn->input)) == NULL) {
@@ -176,19 +217,23 @@
 		conn->handshaked = TRUE;
 	}
 	if (!conn->authenticated) {
-		if (!client_connection_authenticate(conn))
+		if ((ret = client_connection_authenticate(conn)) <= 0) {
+			if (ret < 0)
+				client_connection_destroy(&conn);
 			return;
+		}
+		conn->authenticated = TRUE;
 	}
 
-	while (ret && (line = i_stream_read_next_line(conn->input)) != NULL) {
+	while (ok && (line = i_stream_read_next_line(conn->input)) != NULL) {
 		T_BEGIN {
 			char **args;
 
 			args = p_strsplit(pool_datastack_create(), line, "\t");
-			ret = client_handle_command(conn, args);
+			ok = client_handle_command(conn, args);
 		} T_END;
 	}
-	if (conn->input->eof || conn->input->stream_errno != 0 || !ret)
+	if (conn->input->eof || conn->input->stream_errno != 0 || !ok)
 		client_connection_destroy(&conn);
 }
 
diff -r 9c9f81ad0111 -r 6604f80abb02 src/doveadm/doveadm-settings.c
--- a/src/doveadm/doveadm-settings.c	Fri May 20 13:05:16 2011 +0300
+++ b/src/doveadm/doveadm-settings.c	Fri May 20 13:30:40 2011 +0300
@@ -58,6 +58,7 @@
 	DEF(SET_STR, doveadm_socket_path),
 	DEF(SET_UINT, doveadm_worker_count),
 	DEF(SET_UINT, doveadm_proxy_port),
+	DEF(SET_STR, doveadm_password),
 
 	{ SET_STRLIST, "plugin", offsetof(struct doveadm_settings, plugin_envs), NULL },
 
@@ -71,6 +72,7 @@
 	.doveadm_socket_path = "doveadm-server",
 	.doveadm_worker_count = 0,
 	.doveadm_proxy_port = 0,
+	.doveadm_password = "",
 
 	.plugin_envs = ARRAY_INIT
 };
diff -r 9c9f81ad0111 -r 6604f80abb02 src/doveadm/doveadm-settings.h
--- a/src/doveadm/doveadm-settings.h	Fri May 20 13:05:16 2011 +0300
+++ b/src/doveadm/doveadm-settings.h	Fri May 20 13:30:40 2011 +0300
@@ -8,6 +8,7 @@
 	const char *doveadm_socket_path;
 	unsigned int doveadm_worker_count;
 	unsigned int doveadm_proxy_port;
+	const char *doveadm_password;
 
 	ARRAY_DEFINE(plugin_envs, const char *);
 };
diff -r 9c9f81ad0111 -r 6604f80abb02 src/doveadm/server-connection.c
--- a/src/doveadm/server-connection.c	Fri May 20 13:05:16 2011 +0300
+++ b/src/doveadm/server-connection.c	Fri May 20 13:30:40 2011 +0300
@@ -2,6 +2,7 @@
 
 #include "lib.h"
 #include "array.h"
+#include "base64.h"
 #include "ioloop.h"
 #include "network.h"
 #include "istream.h"
@@ -11,6 +12,7 @@
 #include "doveadm-print.h"
 #include "doveadm-util.h"
 #include "doveadm-server.h"
+#include "doveadm-settings.h"
 #include "server-connection.h"
 
 #include <unistd.h>
@@ -149,10 +151,28 @@
 	i_stream_skip(conn->input, size);
 }
 
-static void
-server_connection_authenticate(struct server_connection *conn ATTR_UNUSED)
+static int
+server_connection_authenticate(struct server_connection *conn)
 {
-	i_fatal("Authentication not supported yet");
+	string_t *plain = t_str_new(128);
+	string_t *cmd = t_str_new(128);
+
+	if (*doveadm_settings->doveadm_password == '\0') {
+		i_error("doveadm_password not set, can't authenticate");
+		return -1;
+	}
+
+	str_append_c(plain, '\0');
+	str_append(plain, "doveadm");
+	str_append_c(plain, '\0');
+	str_append(plain, doveadm_settings->doveadm_password);
+
+	str_append(cmd, "PLAIN\t");
+	base64_encode(plain->data, plain->used, cmd);
+	str_append_c(cmd, '\n');
+
+	o_stream_send(conn->output, cmd->data, cmd->used);
+	return 0;
 }
 
 static void server_connection_input(struct server_connection *conn)
@@ -171,9 +191,12 @@
 		conn->handshaked = TRUE;
 		if (strcmp(line, "+") == 0)
 			conn->authenticated = TRUE;
-		else if (strcmp(line, "-") == 0)
-			server_connection_authenticate(conn);
-		else {
+		else if (strcmp(line, "-") == 0) {
+			if (server_connection_authenticate(conn) < 0) {
+				server_connection_destroy(&conn);
+				return;
+			}
+		} else {
 			i_error("doveadm server sent invalid handshake: %s",
 				line);
 			server_connection_destroy(&conn);
@@ -190,6 +213,18 @@
 	if (size == 0)
 		return;
 
+	if (!conn->authenticated) {
+		if ((line = i_stream_next_line(conn->input)) != NULL)
+			return;
+		if (strcmp(line, "+") == 0)
+			conn->authenticated = TRUE;
+		else {
+			i_error("doveadm authentication failed (%s)", line+1);
+			server_connection_destroy(&conn);
+			return;
+		}
+	}
+
 	switch (conn->state) {
 	case SERVER_REPLY_STATE_DONE:
 		i_error("doveadm server sent unexpected input");


More information about the dovecot-cvs mailing list