From: Timo Sirainen Date: Wed, 13 May 2015 02:25:31 +0000 (+0300) Subject: director: Added a new DIRECTOR-LOOKUP command that auth connections can use. X-Git-Tag: 2.2.17~16 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0388fd5e0bf6654ea25299fd63f2ee8e5ce2913f;p=thirdparty%2Fdovecot%2Fcore.git 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. --- diff --git a/src/director/auth-connection.c b/src/director/auth-connection.c index ec2acc9fef..cf679ddd01 100644 --- a/src/director/auth-connection.c +++ b/src/director/auth-connection.c @@ -121,12 +121,10 @@ static void auth_connection_disconnected(struct auth_connection **_conn) 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 --git a/src/director/auth-connection.h b/src/director/auth-connection.h index c5d5063aa1..27e01467bf 100644 --- a/src/director/auth-connection.h +++ b/src/director/auth-connection.h @@ -13,9 +13,8 @@ void auth_connection_set_callback(struct auth_connection *conn, /* 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 --git a/src/director/login-connection.c b/src/director/login-connection.c index 2f31ea98c4..0cd9e2862d 100644 --- a/src/director/login-connection.c +++ b/src/director/login-connection.c @@ -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 @@ struct login_connection { 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 @@ struct login_host_request { 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; - - 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"); + const unsigned char *data, *p; + size_t size; + struct ostream *auth_output; + + 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; + } + + 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); } - auth_connection_send(conn->auth, buf, ret); + o_stream_uncork(auth_output); } static void @@ -215,10 +260,12 @@ login_connection_init(struct director *dir, int fd, 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 @@ void login_connection_deinit(struct login_connection **_conn) 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");