summaryrefslogtreecommitdiffstats
path: root/src/director/auth-connection.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/director/auth-connection.c')
-rw-r--r--src/director/auth-connection.c141
1 files changed, 141 insertions, 0 deletions
diff --git a/src/director/auth-connection.c b/src/director/auth-connection.c
new file mode 100644
index 0000000..33e58ce
--- /dev/null
+++ b/src/director/auth-connection.c
@@ -0,0 +1,141 @@
+/* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "ioloop.h"
+#include "istream.h"
+#include "ostream.h"
+#include "net.h"
+#include "llist.h"
+#include "safe-memset.h"
+#include "auth-client-interface.h"
+#include "director.h"
+#include "auth-connection.h"
+
+#include <unistd.h>
+
+struct auth_connection {
+ struct auth_connection *prev, *next;
+
+ struct director *dir;
+ char *path;
+ int fd;
+ struct io *io;
+ struct istream *input;
+ struct ostream *output;
+
+ auth_input_callback *callback;
+ void *context;
+};
+
+static struct auth_connection *auth_connections;
+
+static void auth_connection_disconnected(struct auth_connection **conn);
+
+static void auth_connection_input(struct auth_connection *conn)
+{
+ char *line;
+
+ switch (i_stream_read(conn->input)) {
+ case 0:
+ return;
+ case -1:
+ /* disconnected */
+ e_error(conn->dir->event, "Auth server disconnected unexpectedly");
+ auth_connection_disconnected(&conn);
+ return;
+ case -2:
+ /* buffer full */
+ e_error(conn->dir->event,
+ "BUG: Auth server sent us more than %d bytes",
+ (int)AUTH_CLIENT_MAX_LINE_LENGTH);
+ auth_connection_disconnected(&conn);
+ return;
+ }
+
+ while ((line = i_stream_next_line(conn->input)) != NULL) {
+ T_BEGIN {
+ conn->callback(line, conn->context);
+ safe_memset(line, 0, strlen(line));
+ } T_END;
+ }
+}
+
+struct auth_connection *
+auth_connection_init(struct director *dir, const char *path)
+{
+ struct auth_connection *conn;
+
+ conn = i_new(struct auth_connection, 1);
+ conn->dir = dir;
+ conn->fd = -1;
+ conn->path = i_strdup(path);
+ DLLIST_PREPEND(&auth_connections, conn);
+ return conn;
+}
+
+void auth_connection_set_callback(struct auth_connection *conn,
+ auth_input_callback *callback, void *context)
+{
+ conn->callback = callback;
+ conn->context = context;
+}
+
+int auth_connection_connect(struct auth_connection *conn)
+{
+ i_assert(conn->fd == -1);
+
+ conn->fd = net_connect_unix_with_retries(conn->path, 1000);
+ if (conn->fd == -1) {
+ e_error(conn->dir->event, "connect(%s) failed: %m", conn->path);
+ return -1;
+ }
+
+ conn->input = i_stream_create_fd(conn->fd, AUTH_CLIENT_MAX_LINE_LENGTH);
+ conn->output = o_stream_create_fd(conn->fd, SIZE_MAX);
+ o_stream_set_no_error_handling(conn->output, TRUE);
+ conn->io = io_add(conn->fd, IO_READ, auth_connection_input, conn);
+ return 0;
+}
+
+void auth_connection_deinit(struct auth_connection **_conn)
+{
+ struct auth_connection *conn = *_conn;
+
+ *_conn = NULL;
+
+ DLLIST_REMOVE(&auth_connections, conn);
+ if (conn->fd != -1) {
+ io_remove(&conn->io);
+ i_stream_unref(&conn->input);
+ o_stream_unref(&conn->output);
+
+ if (close(conn->fd) < 0)
+ e_error(conn->dir->event, "close(auth connection) failed: %m");
+ }
+ i_free(conn->path);
+ i_free(conn);
+}
+
+static void auth_connection_disconnected(struct auth_connection **_conn)
+{
+ struct auth_connection *conn = *_conn;
+
+ *_conn = NULL;
+ /* notify callback. it should deinit this connection */
+ conn->callback(NULL, conn->context);
+}
+
+struct ostream *auth_connection_get_output(struct auth_connection *conn)
+{
+ i_assert(conn->output != NULL);
+ return conn->output;
+}
+
+void auth_connections_deinit(void)
+{
+ while (auth_connections != NULL) {
+ struct auth_connection *conn = auth_connections;
+
+ auth_connection_disconnected(&conn);
+ }
+}