auth-connection.c revision 0388fd5e0bf6654ea25299fd63f2ee8e5ce2913f
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher/* Copyright (c) 2010-2015 Dovecot authors, see the included COPYING file */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher#include "lib.h"
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher#include "ioloop.h"
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher#include "istream.h"
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher#include "ostream.h"
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher#include "net.h"
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher#include "llist.h"
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher#include "safe-memset.h"
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher#include "auth-client-interface.h"
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher#include "auth-connection.h"
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher#include <unistd.h>
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstruct auth_connection {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct auth_connection *prev, *next;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher char *path;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher int fd;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct io *io;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct istream *input;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct ostream *output;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher auth_input_callback *callback;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher void *context;
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek};
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
55d80b1301fe969fb4ba2b9481027887b9462dbbJakub Hrozekstatic struct auth_connection *auth_connections;
55d80b1301fe969fb4ba2b9481027887b9462dbbJakub Hrozek
55d80b1301fe969fb4ba2b9481027887b9462dbbJakub Hrozekstatic void auth_connection_disconnected(struct auth_connection **conn);
55d80b1301fe969fb4ba2b9481027887b9462dbbJakub Hrozek
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozekstatic void auth_connection_input(struct auth_connection *conn)
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek{
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek char *line;
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek switch (i_stream_read(conn->input)) {
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek case 0:
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek return;
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek case -1:
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek /* disconnected */
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek i_error("Auth server disconnected unexpectedly");
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek auth_connection_disconnected(&conn);
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek return;
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek case -2:
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek /* buffer full */
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek i_error("BUG: Auth server sent us more than %d bytes",
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek (int)AUTH_CLIENT_MAX_LINE_LENGTH);
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek auth_connection_disconnected(&conn);
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek return;
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek }
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek while ((line = i_stream_next_line(conn->input)) != NULL) {
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek T_BEGIN {
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek conn->callback(line, conn->context);
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek safe_memset(line, 0, strlen(line));
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek } T_END;
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek }
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek}
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozekstruct auth_connection *auth_connection_init(const char *path)
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek{
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek struct auth_connection *conn;
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek conn = i_new(struct auth_connection, 1);
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek conn->fd = -1;
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek conn->path = i_strdup(path);
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek DLLIST_PREPEND(&auth_connections, conn);
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek return conn;
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek}
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozekvoid auth_connection_set_callback(struct auth_connection *conn,
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek auth_input_callback *callback, void *context)
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek{
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek conn->callback = callback;
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek conn->context = context;
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek}
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozekint auth_connection_connect(struct auth_connection *conn)
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek{
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek i_assert(conn->fd == -1);
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek conn->fd = net_connect_unix_with_retries(conn->path, 1000);
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek if (conn->fd == -1) {
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek i_error("connect(%s) failed: %m", conn->path);
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek return -1;
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek }
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek conn->input = i_stream_create_fd(conn->fd, AUTH_CLIENT_MAX_LINE_LENGTH,
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek FALSE);
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek conn->output = o_stream_create_fd(conn->fd, (size_t)-1, FALSE);
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek o_stream_set_no_error_handling(conn->output, TRUE);
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek conn->io = io_add(conn->fd, IO_READ, auth_connection_input, conn);
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek return 0;
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek}
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozekvoid auth_connection_deinit(struct auth_connection **_conn)
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek{
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek struct auth_connection *conn = *_conn;
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek *_conn = NULL;
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek DLLIST_REMOVE(&auth_connections, conn);
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek if (conn->fd != -1) {
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek io_remove(&conn->io);
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek i_stream_unref(&conn->input);
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek o_stream_unref(&conn->output);
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek if (close(conn->fd) < 0)
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek i_error("close(auth connection) failed: %m");
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek }
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek i_free(conn->path);
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek i_free(conn);
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek}
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozekstatic void auth_connection_disconnected(struct auth_connection **_conn)
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek{
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek struct auth_connection *conn = *_conn;
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek *_conn = NULL;
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek /* notify callback. it should deinit this connection */
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek conn->callback(NULL, conn->context);
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek}
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozekstruct ostream *auth_connection_send(struct auth_connection *conn)
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek{
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek i_assert(conn->output != NULL);
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek return conn->output;
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek}
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozekvoid auth_connections_deinit(void)
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek{
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek while (auth_connections != NULL) {
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek struct auth_connection *conn = auth_connections;
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek auth_connection_disconnected(&conn);
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek }
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek}
ebc6ab564dc2a0a2b08c42d727fc403dde4a2dc9Jakub Hrozek