]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
dovecot-auth can now be run by itself, it listens in UNIX sockets specified
authorTimo Sirainen <tss@iki.fi>
Sat, 29 May 2004 16:43:22 +0000 (19:43 +0300)
committerTimo Sirainen <tss@iki.fi>
Sat, 29 May 2004 16:43:22 +0000 (19:43 +0300)
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

src/auth/auth-master-connection.c
src/auth/auth-master-connection.h
src/auth/main.c
src/auth/mech.c
src/master/auth-process.c
src/master/master-settings.c
src/master/master-settings.h

index 018c7d09737e58189e65a996c45e400d8ea89e57..1d23f4ef584bfc5868af094bc88bd6d541d24fc9 100644 (file)
@@ -11,6 +11,8 @@
 #include "auth-client-connection.h"
 #include "auth-master-connection.h"
 
+#include <unistd.h>
+
 #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));
+}
index 6eb0bc4597d722cf57322ad0153a36ec7f448eef..27c4f6c33c0b4848276051710c04f2315aeedd5d 100644 (file)
@@ -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
index 67e2a4f0142ad96e2e4d07997b15117d8b3fe6d6..efa7fe703ef3fb8bad8664fef4d64c2b296acf58 100644 (file)
@@ -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"
 #include "auth-client-connection.h"
 
 #include <stdlib.h>
+#include <unistd.h>
 #include <syslog.h>
 
 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();
index 93fdb2359bd58a0531e375b3ff73522e6ce157ba..e1cacc6b77f0bee84e26a369bab85380a7198e91 100644 (file)
@@ -7,6 +7,7 @@
 #include "mech.h"
 #include "var-expand.h"
 #include "auth-client-connection.h"
+#include "auth-master-connection.h"
 
 #include <stdlib.h>
 
@@ -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)
index e6b0fb07d19730ea2c0274c051d863a754ab47d3..a444bb8d159405b2a01fceaa8cc91ddecf920bf1 100644 (file)
@@ -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");
index afc6d951db52e83e769f72e755f409d730b7f6cc..2264639e0731b1f63fc5b06731ead984a85a4e0c 100644 (file)
@@ -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,
index 29825a7a0e0814a65bed73c71c3ecbee04a3026c..b82d3d8e1e71883841fd3b2d609a9b7af482d59d 100644 (file)
@@ -116,6 +116,7 @@ struct auth_settings {
 
        unsigned int count;
        unsigned int process_size;
+       const char *extra_sockets;
 
        /* .. */
        uid_t uid;