dovecot-2.2: director: Added a new DIRECTOR-LOOKUP command that ...

dovecot at dovecot.org dovecot at dovecot.org
Wed May 13 02:27:36 UTC 2015


details:   http://hg.dovecot.org/dovecot-2.2/rev/e178413a905d
changeset: 18666:e178413a905d
user:      Timo Sirainen <tss at iki.fi>
date:      Wed May 13 05:25:31 2015 +0300
description:
director: Added a new DIRECTOR-LOOKUP command that auth connections can use.
The parameters are the same as what auth lookup would receive from auth
process. So the idea is that a proxy could do an auth lookup, then forward
the reply to director, which would return back the updated reply with the
host field added.

diffstat:

 src/director/auth-connection.c  |   8 +---
 src/director/auth-connection.h  |   5 +-
 src/director/login-connection.c |  68 ++++++++++++++++++++++++++++++++++------
 3 files changed, 63 insertions(+), 18 deletions(-)

diffs (161 lines):

diff -r b7aed6290e7e -r e178413a905d src/director/auth-connection.c
--- a/src/director/auth-connection.c	Wed May 13 05:22:22 2015 +0300
+++ b/src/director/auth-connection.c	Wed May 13 05:25:31 2015 +0300
@@ -121,12 +121,10 @@
 	conn->callback(NULL, conn->context);
 }
 
-void auth_connection_send(struct auth_connection *conn,
-			  const void *data, size_t size)
+struct ostream *auth_connection_send(struct auth_connection *conn)
 {
-	i_assert(conn->fd != -1);
-
-	o_stream_nsend(conn->output, data, size);
+	i_assert(conn->output != NULL);
+	return conn->output;
 }
 
 void auth_connections_deinit(void)
diff -r b7aed6290e7e -r e178413a905d src/director/auth-connection.h
--- a/src/director/auth-connection.h	Wed May 13 05:22:22 2015 +0300
+++ b/src/director/auth-connection.h	Wed May 13 05:25:31 2015 +0300
@@ -13,9 +13,8 @@
 
 /* Start connecting. Returns 0 if ok, -1 if connect failed. */
 int auth_connection_connect(struct auth_connection *conn);
-/* Send data to auth connection. */
-void auth_connection_send(struct auth_connection *conn,
-			  const void *data, size_t size);
+/* Get auth connection's output stream. */
+struct ostream *auth_connection_send(struct auth_connection *conn);
 
 void auth_connections_deinit(void);
 
diff -r b7aed6290e7e -r e178413a905d src/director/login-connection.c
--- a/src/director/login-connection.c	Wed May 13 05:22:22 2015 +0300
+++ b/src/director/login-connection.c	Wed May 13 05:25:31 2015 +0300
@@ -3,8 +3,10 @@
 #include "lib.h"
 #include "ioloop.h"
 #include "net.h"
+#include "istream.h"
 #include "ostream.h"
 #include "llist.h"
+#include "str.h"
 #include "master-service.h"
 #include "director.h"
 #include "director-request.h"
@@ -20,12 +22,14 @@
 
 	int fd;
 	struct io *io;
+	struct istream *input;
 	struct ostream *output;
 	struct auth_connection *auth;
 	struct director *dir;
 
 	unsigned int destroyed:1;
 	unsigned int userdb:1;
+	unsigned int input_newline:1;
 };
 
 struct login_host_request {
@@ -40,25 +44,66 @@
 
 static struct login_connection *login_connections;
 
+static void auth_input_line(const char *line, void *context);
 static void login_connection_unref(struct login_connection **_conn);
 
+static void
+login_connection_director_lookup(struct login_connection *conn,
+				 const unsigned char *data, size_t size)
+{
+	T_BEGIN {
+		string_t *line = t_str_new(128);
+		str_append(line, "OK\t");
+		str_append_n(line, data, size);
+		auth_input_line(str_c(line), conn);
+	} T_END;
+}
+
 static void login_connection_input(struct login_connection *conn)
 {
-	unsigned char buf[4096];
-	ssize_t ret;
+	const unsigned char *data, *p;
+	size_t size;
+	struct ostream *auth_output;
 
-	ret = read(conn->fd, buf, sizeof(buf));
-	if (ret <= 0) {
-		if (ret < 0) {
-			if (errno == EAGAIN)
-				return;
-			if (errno != ECONNRESET)
-				i_error("read(login connection) failed: %m");
+	auth_output = auth_connection_send(conn->auth);
+	switch (i_stream_read(conn->input)) {
+	case -2:
+		data = i_stream_get_data(conn->input, &size);
+		o_stream_nsend(auth_output, data, size);
+		i_stream_skip(conn->input, size);
+		conn->input_newline = FALSE;
+		return;
+	case -1:
+		if (conn->input->stream_errno != 0 &&
+		    conn->input->stream_errno != ECONNRESET) {
+			i_error("read(login connection) failed: %s",
+				i_stream_get_error(conn->input));
 		}
 		login_connection_deinit(&conn);
 		return;
+	case 0:
+		return;
+	default:
+		break;
 	}
-	auth_connection_send(conn->auth, buf, ret);
+
+	o_stream_cork(auth_output);
+	data = i_stream_get_data(conn->input, &size);
+	while ((p = memchr(data, '\n', size)) != NULL) {
+		size_t linelen = p-data;
+
+		if (!conn->input_newline || linelen <= 16 ||
+		    memcmp(data, "DIRECTOR-LOOKUP\t", 16) != 0) {
+			/* forward data to auth process */
+			o_stream_nsend(auth_output, data, linelen+1);
+			conn->input_newline = TRUE;
+		} else {
+			login_connection_director_lookup(conn, data+16, linelen-16);
+		}
+		i_stream_skip(conn->input, linelen+1);
+		data = i_stream_get_data(conn->input, &size);
+	}
+	o_stream_uncork(auth_output);
 }
 
 static void
@@ -215,10 +260,12 @@
 	conn->fd = fd;
 	conn->auth = auth;
 	conn->dir = dir;
+	conn->input = i_stream_create_fd(conn->fd, IO_BLOCK_SIZE, FALSE);
 	conn->output = o_stream_create_fd(conn->fd, (size_t)-1, FALSE);
 	o_stream_set_no_error_handling(conn->output, TRUE);
 	conn->io = io_add(conn->fd, IO_READ, login_connection_input, conn);
 	conn->userdb = userdb;
+	conn->input_newline = TRUE;
 
 	auth_connection_set_callback(conn->auth, auth_input_line, conn);
 	DLLIST_PREPEND(&login_connections, conn);
@@ -237,6 +284,7 @@
 
 	DLLIST_REMOVE(&login_connections, conn);
 	io_remove(&conn->io);
+	i_stream_destroy(&conn->input);
 	o_stream_destroy(&conn->output);
 	if (close(conn->fd) < 0)
 		i_error("close(login connection) failed: %m");


More information about the dovecot-cvs mailing list