From: Timo Sirainen Date: Sat, 29 May 2004 16:43:22 +0000 (+0300) Subject: dovecot-auth can now be run by itself, it listens in UNIX sockets specified X-Git-Tag: 1.1.alpha1~4031 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=76213404317a7ed17bec0beadb5137c82785d816;p=thirdparty%2Fdovecot%2Fcore.git dovecot-auth can now be run by itself, it listens in UNIX sockets specified in AUTH_SOCKETS environment. Added extra_sockets auth setting which can be used to do the same thing while started through dovecot master. --HG-- branch : HEAD --- diff --git a/src/auth/auth-master-connection.c b/src/auth/auth-master-connection.c index 018c7d0973..1d23f4ef58 100644 --- a/src/auth/auth-master-connection.c +++ b/src/auth/auth-master-connection.c @@ -11,6 +11,8 @@ #include "auth-client-connection.h" #include "auth-master-connection.h" +#include + #define MAX_OUTBUF_SIZE (1024*50) static struct auth_master_reply failure_reply = @@ -189,26 +191,56 @@ auth_master_connection_new(int fd, unsigned int pid) conn->refcount = 1; conn->pid = pid; conn->fd = fd; - conn->output = o_stream_create_file(MASTER_SOCKET_FD, default_pool, - MAX_OUTBUF_SIZE, FALSE); - conn->io = io_add(MASTER_SOCKET_FD, IO_READ, master_input, conn); + conn->listeners_buf = + buffer_create_dynamic(default_pool, 64, (size_t)-1); + if (fd != -1) { + conn->output = o_stream_create_file(fd, default_pool, + MAX_OUTBUF_SIZE, FALSE); + conn->io = io_add(fd, IO_READ, master_input, conn); + } + return conn; +} +void auth_master_connection_send_handshake(struct auth_master_connection *conn) +{ /* just a note to master that we're ok. if we die before, master should shutdown itself. */ - o_stream_send(conn->output, "O", 1); - return conn; + if (conn->output != NULL) + o_stream_send(conn->output, "O", 1); } void auth_master_connection_free(struct auth_master_connection *conn) { - if (conn->fd == -1) + struct auth_client_listener **l; + size_t i, size; + + if (conn->destroyed) return; + conn->destroyed = TRUE; + + if (conn->fd != -1) { + if (close(conn->fd) < 0) + i_error("close(): %m"); + conn->fd = -1; + + o_stream_close(conn->output); - conn->fd = -1; - o_stream_close(conn->output); + io_remove(conn->io); + conn->io = NULL; + } - io_remove(conn->io); - conn->io = NULL; + l = buffer_get_modifyable_data(conn->listeners_buf, &size); + size /= sizeof(*l); + for (i = 0; i < size; i++) { + net_disconnect(l[i]->fd); + io_remove(l[i]->io); + if (l[i]->path != NULL) { + (void)unlink(l[i]->path); + i_free(l[i]->path); + } + i_free(l[i]); + } + buffer_free(conn->listeners_buf); auth_master_connection_unref(conn); } @@ -218,7 +250,37 @@ static int auth_master_connection_unref(struct auth_master_connection *conn) if (--conn->refcount > 0) return TRUE; - o_stream_unref(conn->output); + if (conn->output != NULL) + o_stream_unref(conn->output); i_free(conn); return FALSE; } + +static void auth_accept(void *context) +{ + struct auth_client_listener *l = context; + int fd; + + fd = net_accept(l->fd, NULL, NULL); + if (fd < 0) { + if (fd < -1) + i_fatal("accept() failed: %m"); + } else { + net_set_nonblock(fd, TRUE); + (void)auth_client_connection_create(l->master, fd); + } +} + +void auth_master_connection_add_listener(struct auth_master_connection *conn, + int fd, const char *path) +{ + struct auth_client_listener *l; + + l = i_new(struct auth_client_listener, 1); + l->master = conn; + l->fd = fd; + l->path = i_strdup(path); + l->io = io_add(fd, IO_READ, auth_accept, &l); + + buffer_append(conn->listeners_buf, &l, sizeof(l)); +} diff --git a/src/auth/auth-master-connection.h b/src/auth/auth-master-connection.h index 6eb0bc4597..27c4f6c33c 100644 --- a/src/auth/auth-master-connection.h +++ b/src/auth/auth-master-connection.h @@ -10,6 +10,7 @@ struct auth_master_connection { int fd; struct ostream *output; struct io *io; + buffer_t *listeners_buf; unsigned int request_pos; unsigned char request_buf[sizeof(struct auth_master_request)]; @@ -17,10 +18,25 @@ struct auth_master_connection { struct auth_client_handshake_reply handshake_reply; struct auth_client_connection *clients; struct timeout *to_clients; + + unsigned int destroyed:1; }; +struct auth_client_listener { + struct auth_master_connection *master; + int fd; + char *path; + struct io *io; +}; + +#define AUTH_MASTER_IS_DUMMY(master) (master->fd == -1) + struct auth_master_connection * auth_master_connection_new(int fd, unsigned int pid); +void auth_master_connection_send_handshake(struct auth_master_connection *conn); void auth_master_connection_free(struct auth_master_connection *conn); +void auth_master_connection_add_listener(struct auth_master_connection *conn, + int fd, const char *path); + #endif diff --git a/src/auth/main.c b/src/auth/main.c index 67e2a4f014..efa7fe703e 100644 --- a/src/auth/main.c +++ b/src/auth/main.c @@ -1,6 +1,7 @@ /* Copyright (C) 2002 Timo Sirainen */ #include "common.h" +#include "buffer.h" #include "ioloop.h" #include "network.h" #include "lib-signals.h" @@ -14,36 +15,42 @@ #include "auth-client-connection.h" #include +#include #include struct ioloop *ioloop; int verbose = FALSE, verbose_debug = FALSE; -static struct auth_master_connection *master; -static struct io *io_listen; +static buffer_t *masters_buf; static void sig_quit(int signo __attr_unused__) { io_loop_stop(ioloop); } -static void auth_accept(void *context __attr_unused__) +static void open_logfile(void) { - int fd; + if (getenv("LOG_TO_MASTER") != NULL) { + i_set_failure_internal(); + return; + } - fd = net_accept(LOGIN_LISTEN_FD, NULL, NULL); - if (fd < 0) { - if (fd < -1) - i_fatal("accept() failed: %m"); - } else { - net_set_nonblock(fd, TRUE); - (void)auth_client_connection_create(master, fd); + if (getenv("USE_SYSLOG") != NULL) + i_set_failure_syslog("dovecot-auth", LOG_NDELAY, LOG_MAIL); + else { + /* log to file or stderr */ + i_set_failure_file(getenv("LOGFILE"), "dovecot-auth"); } + + if (getenv("INFOLOGFILE") != NULL) + i_set_info_file(getenv("INFOLOGFILE")); + + i_set_failure_timestamp_format(getenv("LOGSTAMP")); } static void drop_privileges(void) { - i_set_failure_internal(); + open_logfile(); /* Open /dev/urandom before chrooting */ random_init(); @@ -52,8 +59,29 @@ static void drop_privileges(void) restrict_access_by_env(FALSE); } +static void master_add_unix_listeners(struct auth_master_connection *master, + const char *sockets_list) +{ + const char *const *sockets; + int fd; + + sockets = t_strsplit(sockets_list, ":"); + while (*sockets != NULL) { + fd = net_listen_unix(*sockets); + if (fd == -1) { + i_fatal("net_listen_unix(%s) failed: %m", + *sockets); + } + + auth_master_connection_add_listener(master, fd, *sockets); + sockets++; + } +} + static void main_init(void) { + struct auth_master_connection *master, **master_p; + size_t i, size; const char *env; unsigned int pid; @@ -62,39 +90,81 @@ static void main_init(void) verbose = getenv("VERBOSE") != NULL; verbose_debug = getenv("VERBOSE_DEBUG") != NULL; - env = getenv("AUTH_PROCESS"); - if (env == NULL) - i_fatal("AUTH_PROCESS environment is unset"); - - pid = atoi(env); - if (pid == 0) - i_fatal("AUTH_PROCESS can't be 0"); - mech_init(); userdb_init(); passdb_init(); - io_listen = io_add(LOGIN_LISTEN_FD, IO_READ, auth_accept, NULL); + masters_buf = buffer_create_dynamic(default_pool, 64, (size_t)-1); + + env = getenv("AUTH_PROCESS"); + if (env == NULL) { + /* starting standalone */ + env = getenv("AUTH_SOCKETS"); + if (env == NULL) + i_fatal("AUTH_SOCKETS environment not set"); + + switch (fork()) { + case -1: + i_fatal("fork() failed: %m"); + case 0: + break; + default: + exit(0); + } + + if (setsid() < 0) + i_fatal("setsid() failed: %m"); + + if (chdir("/") < 0) + i_fatal("chdir(/) failed: %m"); + } else { + pid = atoi(env); + if (pid == 0) + i_fatal("AUTH_PROCESS can't be 0"); + + master = auth_master_connection_new(MASTER_SOCKET_FD, pid); + auth_master_connection_add_listener(master, LOGIN_LISTEN_FD, + NULL); + auth_client_connections_init(master); + buffer_append(masters_buf, &master, sizeof(master)); + + /* accept also alternative listeners under dummy master */ + env = getenv("AUTH_SOCKETS"); + } - /* initialize master last - it sends the "we're ok" notification */ - master = auth_master_connection_new(MASTER_SOCKET_FD, pid); - auth_client_connections_init(master); + if (env != NULL) { + master = auth_master_connection_new(-1, 0); + master_add_unix_listeners(master, env); + auth_client_connections_init(master); + buffer_append(masters_buf, &master, sizeof(master)); + } + + /* everything initialized, notify masters that all is well */ + master_p = buffer_get_modifyable_data(masters_buf, &size); + size /= sizeof(*master_p); + for (i = 0; i < size; i++) + auth_master_connection_send_handshake(master_p[i]); } static void main_deinit(void) { + struct auth_master_connection **master; + size_t i, size; + if (lib_signal_kill != 0) i_warning("Killed with signal %d", lib_signal_kill); - io_remove(io_listen); - - auth_client_connections_deinit(master); + master = buffer_get_modifyable_data(masters_buf, &size); + size /= sizeof(*master); + for (i = 0; i < size; i++) { + auth_client_connections_deinit(master[i]); + auth_master_connection_free(master[i]); + } passdb_deinit(); userdb_deinit(); mech_deinit(); - auth_master_connection_free(master); random_deinit(); closelog(); diff --git a/src/auth/mech.c b/src/auth/mech.c index 93fdb2359b..e1cacc6b77 100644 --- a/src/auth/mech.c +++ b/src/auth/mech.c @@ -7,6 +7,7 @@ #include "mech.h" #include "var-expand.h" #include "auth-client-connection.h" +#include "auth-master-connection.h" #include @@ -196,8 +197,12 @@ void mech_auth_finish(struct auth_request *auth_request, auth_request->callback(&reply, reply_data, auth_request->conn); - if (!success) + if (!success || AUTH_MASTER_IS_DUMMY(auth_request->conn->master)) { + /* request is no longer needed, either because the + authentication failed or because we don't have master + process */ mech_request_free(auth_request, auth_request->id); + } } int mech_is_valid_username(const char *username) diff --git a/src/master/auth-process.c b/src/master/auth-process.c index e6b0fb07d1..a444bb8d15 100644 --- a/src/master/auth-process.c +++ b/src/master/auth-process.c @@ -336,6 +336,7 @@ static pid_t create_auth_process(struct auth_process_group *group) env_put(t_strconcat("USERNAME_CHARS=", group->set->username_chars, NULL)); env_put(t_strconcat("ANONYMOUS_USERNAME=", group->set->anonymous_username, NULL)); + env_put(t_strconcat("AUTH_SOCKETS=", group->set->extra_sockets)); if (group->set->use_cyrus_sasl) env_put("USE_CYRUS_SASL=1"); diff --git a/src/master/master-settings.c b/src/master/master-settings.c index afc6d951db..2264639e07 100644 --- a/src/master/master-settings.c +++ b/src/master/master-settings.c @@ -139,6 +139,7 @@ static struct setting_def auth_setting_defs[] = { DEF(SET_INT, count), DEF(SET_INT, process_size), + DEF(SET_STR, extra_sockets), { 0, NULL, 0 } }; @@ -274,6 +275,7 @@ struct auth_settings default_auth_settings = { MEMBER(count) 1, MEMBER(process_size) 256, + MEMBER(extra_sockets) NULL, /* .. */ MEMBER(uid) 0, diff --git a/src/master/master-settings.h b/src/master/master-settings.h index 29825a7a0e..b82d3d8e1e 100644 --- a/src/master/master-settings.h +++ b/src/master/master-settings.h @@ -116,6 +116,7 @@ struct auth_settings { unsigned int count; unsigned int process_size; + const char *extra_sockets; /* .. */ uid_t uid;