Mercurial > dovecot > original-hg > dovecot-1.2
changeset 2236:43b82a35888d HEAD
Dovecot can now connect to externally running dovecot-auth.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Wed, 23 Jun 2004 20:50:43 +0300 |
parents | dcff4c088f1a |
children | 6b05e30c669a |
files | dovecot-example.conf src/auth/auth-master-connection.c src/auth/auth-master-connection.h src/auth/auth-master-interface.h src/auth/common.h src/auth/main.c src/master/auth-process.c src/master/master-settings.c src/master/master-settings.h |
diffstat | 9 files changed, 492 insertions(+), 115 deletions(-) [+] |
line wrap: on
line diff
--- a/dovecot-example.conf Wed Jun 23 20:48:35 2004 +0300 +++ b/dovecot-example.conf Wed Jun 23 20:50:43 2004 +0300 @@ -484,3 +484,43 @@ # passdb = passwd-file /etc/passwd.imap # user = dovecot-auth #} + +# It's possible to export the authentication interface to other programs, +# for example SMTP server which supports talking to Dovecot. Client socket +# handles the actual authentication - you give it a username and password +# and it returns OK or failure. So it's pretty safe to allow anyone access to +# it. Master socket is used to a) query if given client was successfully +# authenticated, b) userdb lookups. + +# listener sockets will be created by Dovecot's master process using the +# settings given inside the auth section +#auth default_with_listener { +# mechanisms = plain +# passdb = passwd +# userdb = pam +# socket listen { +# master { +# path = /var/run/dovecot/auth-master +# #mode = 0600 +# # Default user/group is the one who started dovecot-auth (root) +# #user = +# #group = +# } +# client { +# path = /var/run/dovecot-auth-client +# mode = 0660 +# } +# } +#} + +# connect sockets are assumed to be already running, Dovecot's master +# process only tries to connect to them. They don't need any other settings +# than path for the master socket, as the configuration is done elsewhere. +# Note that the client sockets must exist in login_dir. +#auth external { +# socket connect { +# master { +# path = /var/run/dovecot/auth-master +# } +# } +#}
--- a/src/auth/auth-master-connection.c Wed Jun 23 20:48:35 2004 +0300 +++ b/src/auth/auth-master-connection.c Wed Jun 23 20:50:43 2004 +0300 @@ -18,11 +18,20 @@ static struct auth_master_reply failure_reply = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +struct auth_listener { + struct auth_master_connection *master; + int client_listener; + int fd; + char *path; + struct io *io; +}; + struct master_userdb_request { struct auth_master_connection *conn; unsigned int tag; }; +static void auth_master_connection_close(struct auth_master_connection *conn); static int auth_master_connection_unref(struct auth_master_connection *conn); static size_t reply_add(buffer_t *buf, const char *str) @@ -89,7 +98,7 @@ ret = o_stream_send(conn->output, reply, reply_size); if (ret < 0) { /* master died, kill ourself too */ - io_loop_stop(ioloop); + auth_master_connection_close(conn); break; } @@ -100,7 +109,7 @@ i_warning("Master transmit buffer full, blocking.."); if (o_stream_flush(conn->output) < 0) { /* transmit error, probably master died */ - io_loop_stop(ioloop); + auth_master_connection_close(conn); break; } } @@ -169,7 +178,7 @@ sizeof(conn->request_buf) - conn->request_pos); if (ret < 0) { /* master died, kill ourself too */ - io_loop_stop(ioloop); + auth_master_connection_close(conn); return; } @@ -224,8 +233,23 @@ master->handshake_reply = buffer_free_without_data(buf); } +static void +auth_master_connection_set_fd(struct auth_master_connection *conn, int fd) +{ + if (conn->output != NULL) + o_stream_unref(conn->output); + if (conn->io != NULL) + io_remove(conn->io); + + conn->output = o_stream_create_file(fd, default_pool, + MAX_OUTBUF_SIZE, FALSE); + conn->io = io_add(fd, IO_READ, master_input, conn); + + conn->fd = fd; +} + struct auth_master_connection * -auth_master_connection_new(int fd, unsigned int pid) +auth_master_connection_create(int fd, unsigned int pid) { struct auth_master_connection *conn; @@ -235,42 +259,54 @@ conn->fd = fd; 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); - } + if (fd != -1) + auth_master_connection_set_fd(conn, fd); master_get_handshake_reply(conn); return conn; } void auth_master_connection_send_handshake(struct auth_master_connection *conn) { + struct auth_master_handshake_reply reply; + /* just a note to master that we're ok. if we die before, master should shutdown itself. */ - if (conn->output != NULL) - o_stream_send(conn->output, "O", 1); + if (conn->output != NULL) { + memset(&reply, 0, sizeof(reply)); + reply.server_pid = conn->pid; + o_stream_send(conn->output, &reply, sizeof(reply)); + } } -void auth_master_connection_free(struct auth_master_connection *conn) +static void auth_master_connection_close(struct auth_master_connection *conn) { - struct auth_client_listener **l; + if (!standalone) + io_loop_stop(ioloop); + + if (close(conn->fd) < 0) + i_error("close(): %m"); + conn->fd = -1; + + o_stream_close(conn->output); + conn->output = NULL; + + io_remove(conn->io); + conn->io = NULL; +} + +void auth_master_connection_destroy(struct auth_master_connection *conn) +{ + struct auth_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; + auth_client_connections_deinit(conn); - o_stream_close(conn->output); - - io_remove(conn->io); - conn->io = NULL; - } + if (conn->fd != -1) + auth_master_connection_close(conn); l = buffer_get_modifyable_data(conn->listeners_buf, &size); size /= sizeof(*l); @@ -303,7 +339,7 @@ static void auth_accept(void *context) { - struct auth_client_listener *l = context; + struct auth_listener *l = context; int fd; fd = net_accept(l->fd, NULL, NULL); @@ -312,17 +348,24 @@ i_fatal("accept() failed: %m"); } else { net_set_nonblock(fd, TRUE); - (void)auth_client_connection_create(l->master, fd); + if (l->client_listener) + (void)auth_client_connection_create(l->master, fd); + else { + /* we'll just replace the previous master.. */ + auth_master_connection_set_fd(l->master, fd); + auth_master_connection_send_handshake(l->master); + } } } void auth_master_connection_add_listener(struct auth_master_connection *conn, - int fd, const char *path) + int fd, const char *path, int client) { - struct auth_client_listener *l; + struct auth_listener *l; - l = i_new(struct auth_client_listener, 1); + l = i_new(struct auth_listener, 1); l->master = conn; + l->client_listener = client; l->fd = fd; l->path = i_strdup(path); l->io = io_add(fd, IO_READ, auth_accept, l);
--- a/src/auth/auth-master-connection.h Wed Jun 23 20:48:35 2004 +0300 +++ b/src/auth/auth-master-connection.h Wed Jun 23 20:50:43 2004 +0300 @@ -22,21 +22,14 @@ 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); +auth_master_connection_create(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_destroy(struct auth_master_connection *conn); void auth_master_connection_add_listener(struct auth_master_connection *conn, - int fd, const char *path); + int fd, const char *path, int client); #endif
--- a/src/auth/auth-master-interface.h Wed Jun 23 20:48:35 2004 +0300 +++ b/src/auth/auth-master-interface.h Wed Jun 23 20:50:43 2004 +0300 @@ -3,6 +3,11 @@ #define AUTH_MASTER_MAX_REPLY_DATA_SIZE 4096 +/* Server -> Master */ +struct auth_master_handshake_reply { + unsigned int server_pid; +}; + struct auth_master_request { unsigned int tag;
--- a/src/auth/common.h Wed Jun 23 20:48:35 2004 +0300 +++ b/src/auth/common.h Wed Jun 23 20:50:43 2004 +0300 @@ -8,5 +8,6 @@ extern struct ioloop *ioloop; extern int verbose, verbose_debug; +extern int standalone; #endif
--- a/src/auth/main.c Wed Jun 23 20:48:35 2004 +0300 +++ b/src/auth/main.c Wed Jun 23 20:50:43 2004 +0300 @@ -15,12 +15,17 @@ #include "auth-master-connection.h" #include "auth-client-connection.h" +#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <syslog.h> +#include <pwd.h> +#include <grp.h> +#include <sys/stat.h> struct ioloop *ioloop; int verbose = FALSE, verbose_debug = FALSE; +int standalone = FALSE; static buffer_t *masters_buf; @@ -64,26 +69,120 @@ restrict_access_by_env(FALSE); } -static void master_add_unix_listeners(struct auth_master_connection *master, - const char *sockets_list) +static uid_t get_uid(const char *user) +{ + struct passwd *pw; + + if (user == NULL) + return (uid_t)-1; + + if ((pw = getpwnam(user)) == NULL) + i_fatal("User doesn't exist: %s", user); + return pw->pw_uid; +} + +static gid_t get_gid(const char *group) { - const char *const *sockets; - int fd; + struct group *gr; + + if (group == NULL) + return (gid_t)-1; + + if ((gr = getgrnam(group)) == NULL) + i_fatal("Group doesn't exist: %s", group); + return gr->gr_gid; +} + +static int create_unix_listener(const char *env) +{ + const char *path, *mode, *user, *group; + mode_t old_umask; + unsigned int mask; + uid_t uid; + gid_t gid; + int fd, i; + + path = getenv(env); + if (path == NULL) + return -1; + + mode = getenv(t_strdup_printf("%s_MODE", env)); + if (mode == NULL) + mask = 0177; /* default to 0600 */ + else { + if (sscanf(mode, "%o", &mask) != 1) + i_fatal("%s: Invalid mode %s", env, mode); + mask = (mask ^ 0777) & 0777; + } - 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); + old_umask = umask(mask); + for (i = 0; i < 5; i++) { + fd = net_listen_unix(path); + if (fd != -1) + break; + + if (errno != EADDRINUSE) + i_fatal("net_listen_unix(%s) failed: %m", path); + + /* see if it really exists */ + if (net_connect_unix(path) != -1 || errno != ECONNREFUSED) + i_fatal("Socket already exists: %s", path); + + /* delete and try again */ + if (unlink(path) < 0) + i_fatal("unlink(%s) failed: %m", path); + } + umask(old_umask); + + user = getenv(t_strdup_printf("%s_USER", env)); + group = getenv(t_strdup_printf("%s_GROUP", env)); + + uid = get_uid(user); gid = get_gid(group); + if (chown(path, uid, gid) < 0) { + i_fatal("chown(%s, %s, %s) failed: %m", + path, dec2str(uid), dec2str(gid)); + } + + return fd; +} + +static void add_extra_listeners(void) +{ + struct auth_master_connection *master; + const char *str, *client_path, *master_path; + int client_fd, master_fd; + unsigned int i; + + for (i = 1;; i++) { + t_push(); + client_path = getenv(t_strdup_printf("AUTH_%u", i)); + master_path = getenv(t_strdup_printf("AUTH_%u_MASTER", i)); + if (client_path == NULL && master_path == NULL) { + t_pop(); + break; } - auth_master_connection_add_listener(master, fd, *sockets); - sockets++; + str = t_strdup_printf("AUTH_%u", i); + client_fd = create_unix_listener(str); + str = t_strdup_printf("AUTH_%u_MASTER", i); + master_fd = create_unix_listener(str); + + master = auth_master_connection_create(-1, getpid()); + if (master_fd != -1) { + auth_master_connection_add_listener(master, master_fd, + master_path, FALSE); + } + if (client_fd != -1) { + auth_master_connection_add_listener(master, client_fd, + client_path, TRUE); + } + auth_client_connections_init(master); + buffer_append(masters_buf, &master, sizeof(master)); + t_pop(); } } -static void main_init(void) +static void main_init(int nodaemon) { struct auth_master_connection *master, **master_p; size_t i, size; @@ -103,48 +202,46 @@ masters_buf = buffer_create_dynamic(default_pool, 64, (size_t)-1); env = getenv("AUTH_PROCESS"); - if (env == NULL) { + standalone = env == NULL; + if (standalone) { /* 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 (getenv("AUTH_1") == NULL) { + i_fatal("dovecot-auth is usually started through " + "dovecot master process. If you wish to run " + "it standalone, you'll need to set AUTH_* " + "environment variables (AUTH_1 isn't set)."); } - if (setsid() < 0) - i_fatal("setsid() failed: %m"); + if (!nodaemon) { + switch (fork()) { + case -1: + i_fatal("fork() failed: %m"); + case 0: + break; + default: + exit(0); + } - if (chdir("/") < 0) - i_fatal("chdir(/) failed: %m"); + 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); + master = auth_master_connection_create(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"); - } - - if (env != NULL && *env != '\0') { - master = auth_master_connection_new(-1, 0); - master_add_unix_listeners(master, env); + NULL, TRUE); auth_client_connections_init(master); buffer_append(masters_buf, &master, sizeof(master)); } + add_extra_listeners(); + /* everything initialized, notify masters that all is well */ master_p = buffer_get_modifyable_data(masters_buf, &size); size /= sizeof(*master_p); @@ -164,10 +261,8 @@ 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]); - } + for (i = 0; i < size; i++) + auth_master_connection_destroy(master[i]); password_schemes_deinit(); passdb_deinit(); @@ -179,10 +274,11 @@ closelog(); } -int main(int argc __attr_unused__, char *argv[] __attr_unused__) +int main(int argc, char *argv[]) { #ifdef DEBUG - fd_debug_verify_leaks(4, 1024); + if (getenv("GDB") == NULL) + fd_debug_verify_leaks(4, 1024); #endif /* NOTE: we start rooted, so keep the code minimal until restrict_access_by_env() is called */ @@ -191,7 +287,7 @@ ioloop = io_loop_create(system_pool); - main_init(); + main_init(argc > 1 && strcmp(argv[1], "-F") == 0); io_loop_run(ioloop); main_deinit();
--- a/src/master/auth-process.c Wed Jun 23 20:48:35 2004 +0300 +++ b/src/master/auth-process.c Wed Jun 23 20:50:43 2004 +0300 @@ -45,6 +45,7 @@ struct hash_table *requests; + unsigned int external:1; unsigned int initialized:1; unsigned int in_auth_reply:1; }; @@ -152,16 +153,21 @@ } if (!p->initialized) { + struct auth_master_handshake_reply rec; + data = i_stream_get_data(p->input, &size); - i_assert(size > 0); + if (size < sizeof(rec)) + return; - if (data[0] != 'O') { + memcpy(&rec, data, sizeof(rec)); + i_stream_skip(p->input, sizeof(rec)); + + if (rec.server_pid == 0) { i_fatal("Auth process sent invalid initialization " "notification"); } - i_stream_skip(p->input, 1); - + p->pid = rec.server_pid; p->initialized = TRUE; } @@ -197,7 +203,8 @@ { struct auth_process *p; - PID_ADD_PROCESS_TYPE(pid, PROCESS_TYPE_AUTH); + if (pid != 0) + PID_ADD_PROCESS_TYPE(pid, PROCESS_TYPE_AUTH); p = i_new(struct auth_process, 1); p->group = group; @@ -223,7 +230,7 @@ void *key, *value; struct auth_process **pos; - if (!p->initialized && io_loop_is_running(ioloop)) { + if (!p->initialized && io_loop_is_running(ioloop) && !p->external) { i_error("Auth process died too early - shutting down"); io_loop_stop(ioloop); } @@ -250,14 +257,54 @@ i_free(p); } -static pid_t create_auth_process(struct auth_process_group *group) +static void +socket_settings_env_put(const char *env_base, struct socket_settings *set) +{ + if (env_base == NULL) + return; + + env_put(t_strdup_printf("%s_PATH=%s", env_base, set->path)); + if (set->mode != 0) + env_put(t_strdup_printf("%s_MODE=%u", env_base, set->mode)); + if (set->user != NULL) + env_put(t_strdup_printf("%s_USER=%s", env_base, set->user)); + if (set->group != NULL) + env_put(t_strdup_printf("%s_GROUP=%s", env_base, set->group)); +} + +static int connect_auth_socket(struct auth_process_group *group, + const char *path) +{ + struct auth_process *auth; + int fd; + + fd = net_connect_unix(path); + if (fd == -1) { + i_error("net_connect_unix(%s) failed: %m", path); + return -1; + } + + net_set_nonblock(fd, TRUE); + fd_close_on_exec(fd, TRUE); + auth = auth_process_new(0, fd, group); + auth->external = TRUE; + return 0; +} + +static int create_auth_process(struct auth_process_group *group) { static char *argv[] = { NULL, NULL }; - const char *prefix; + struct auth_socket_settings *as; + const char *prefix, *str; struct log_io *log; pid_t pid; int fd[2], log_fd, i; + /* see if this is a connect socket */ + as = group->set->sockets; + if (as != NULL && strcmp(as->type, "connect") == 0) + return connect_auth_socket(group, as->master.path); + /* create communication to process with a socket pair */ if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0) { i_error("socketpair() failed: %m"); @@ -290,7 +337,7 @@ auth_process_new(pid, fd[0], group); (void)close(fd[1]); (void)close(log_fd); - return pid; + return 0; } prefix = t_strdup_printf("master-auth(%s): ", group->set->name); @@ -337,7 +384,16 @@ 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)); + + for (as = group->set->sockets, i = 1; as != NULL; as = as->next, i++) { + if (strcmp(as->type, "listen") != 0) + continue; + + str = t_strdup_printf("AUTH_%u", i); + socket_settings_env_put(str, &as->client); + socket_settings_env_put(t_strconcat(str, "_MASTER", NULL), + &as->master); + } if (group->set->use_cyrus_sasl) env_put("USE_CYRUS_SASL=1"); @@ -390,6 +446,13 @@ group = i_new(struct auth_process_group, 1); group->set = auth_set; + group->next = process_groups; + process_groups = group; + + if (auth_set->sockets != NULL && + strcmp(auth_set->sockets->type, "connect") == 0) + return; + /* create socket for listening auth requests from login */ path = t_strconcat(auth_set->parent->defaults->login_dir, "/", auth_set->name, NULL); @@ -410,9 +473,6 @@ path, dec2str(master_uid), dec2str(auth_set->parent->login_gid)); } - - group->next = process_groups; - process_groups = group; } static void auth_process_group_destroy(struct auth_process_group *group)
--- a/src/master/master-settings.c Wed Jun 23 20:48:35 2004 +0300 +++ b/src/master/master-settings.c Wed Jun 23 20:50:43 2004 +0300 @@ -16,7 +16,9 @@ SETTINGS_TYPE_ROOT, SETTINGS_TYPE_SERVER, SETTINGS_TYPE_AUTH, - SETTINGS_TYPE_NAMESPACE + SETTINGS_TYPE_AUTH_SOCKET, + SETTINGS_TYPE_NAMESPACE, + SETTINGS_TYPE_SOCKET }; struct settings_parse_ctx { @@ -25,6 +27,8 @@ struct server_settings *root, *server; struct auth_settings *auth; + struct socket_settings *socket; + struct auth_socket_settings *auth_socket; struct namespace_settings *namespace; int level; @@ -142,7 +146,29 @@ DEF(SET_INT, count), DEF(SET_INT, process_size), - DEF(SET_STR, extra_sockets), + + { 0, NULL, 0 } +}; + +#undef DEF +#define DEF(type, name) \ + { type, #name, offsetof(struct socket_settings, name) } + +static struct setting_def socket_setting_defs[] = { + DEF(SET_STR, path), + DEF(SET_INT, mode), + DEF(SET_STR, user), + DEF(SET_STR, group), + + { 0, NULL, 0 } +}; + +#undef DEF +#define DEF(type, name) \ + { type, #name, offsetof(struct auth_socket_settings, name) } + +static struct setting_def auth_socket_setting_defs[] = { + DEF(SET_STR, type), { 0, NULL, 0 } }; @@ -281,11 +307,11 @@ MEMBER(count) 1, MEMBER(process_size) 256, - MEMBER(extra_sockets) NULL, /* .. */ MEMBER(uid) 0, - MEMBER(gid) 0 + MEMBER(gid) 0, + MEMBER(sockets) NULL }; static pool_t settings_pool, settings2_pool; @@ -406,6 +432,22 @@ return TRUE; } +static int settings_have_connect_sockets(struct settings *set) +{ + struct auth_settings *auth; + struct server_settings *server; + + for (server = set->server; server != NULL; server = server->next) { + for (auth = server->auths; auth != NULL; auth = auth->next) { + if (auth->sockets != NULL && + strcmp(auth->sockets->type, "connect") == 0) + return TRUE; + } + } + + return FALSE; +} + static int settings_verify(struct settings *set) { const char *dir; @@ -484,10 +526,15 @@ PKG_RUNDIR); } - /* wipe out contents of login directory, if it exists */ - if (unlink_directory(set->login_dir, FALSE) < 0) { - i_error("unlink_directory() failed for %s: %m", set->login_dir); - return FALSE; + /* wipe out contents of login directory, if it exists. + except if we're using external authentication - then we would + otherwise wipe existing auth sockets */ + if (!settings_have_connect_sockets(set)) { + if (unlink_directory(set->login_dir, FALSE) < 0) { + i_error("unlink_directory() failed for %s: %m", + set->login_dir); + return FALSE; + } } if (safe_mkdir(set->login_dir, 0750, @@ -570,6 +617,44 @@ return auth_settings_new(server, name); } +static struct auth_socket_settings * +auth_socket_settings_new(struct auth_settings *auth, const char *type) +{ + struct auth_socket_settings *as, **as_p; + + as = p_new(settings_pool, struct auth_socket_settings, 1); + + as->parent = auth; + as->type = str_lcase(p_strdup(settings_pool, type)); + + as_p = &auth->sockets; + while (*as_p != NULL) + as_p = &(*as_p)->next; + *as_p = as; + + return as; +} + +static struct auth_socket_settings * +parse_new_auth_socket(struct auth_settings *auth, const char *name, + const char **errormsg) +{ + if (strcmp(name, "connect") != 0 && strcmp(name, "listen") != 0) { + *errormsg = "Unknown auth socket type"; + return NULL; + } + + if ((auth->sockets != NULL && strcmp(name, "connect") == 0) || + (auth->sockets != NULL && + strcmp(auth->sockets->type, "listen") == 0)) { + *errormsg = "With connect auth socket no other sockets " + "can be used in same auth section"; + return NULL; + } + + return auth_socket_settings_new(auth, name); +} + static struct namespace_settings * namespace_settings_new(struct server_settings *server, const char *type) { @@ -657,10 +742,18 @@ key += 5; return parse_setting_from_defs(settings_pool, auth_setting_defs, ctx->auth, key, value); + case SETTINGS_TYPE_AUTH_SOCKET: + return parse_setting_from_defs(settings_pool, + auth_socket_setting_defs, + ctx->auth_socket, key, value); case SETTINGS_TYPE_NAMESPACE: return parse_setting_from_defs(settings_pool, namespace_setting_defs, ctx->namespace, key, value); + case SETTINGS_TYPE_SOCKET: + return parse_setting_from_defs(settings_pool, + socket_setting_defs, + ctx->socket, key, value); } i_unreached(); @@ -705,12 +798,20 @@ if (type == NULL) { /* section closing */ - if (ctx->level > 0) { - ctx->level--; + if (--ctx->level > 0) { + ctx->type = ctx->parent_type; ctx->protocol = MAIL_PROTOCOL_ANY; + + switch (ctx->type) { + case SETTINGS_TYPE_AUTH_SOCKET: + ctx->parent_type = SETTINGS_TYPE_AUTH; + break; + default: + ctx->parent_type = SETTINGS_TYPE_ROOT; + break; + } } else { - ctx->type = ctx->parent_type; - ctx->parent_type = SETTINGS_TYPE_ROOT; + ctx->type = SETTINGS_TYPE_ROOT; ctx->server = ctx->root; ctx->auth = &ctx->root->auth_defaults; ctx->namespace = NULL; @@ -718,15 +819,16 @@ return TRUE; } + ctx->level++; + ctx->parent_type = ctx->type; + if (strcmp(type, "server") == 0) { if (ctx->type != SETTINGS_TYPE_ROOT) { *errormsg = "Server section not allowed here"; return FALSE; } - ctx->parent_type = ctx->type; ctx->type = SETTINGS_TYPE_SERVER; - ctx->server = create_new_server(name, ctx->server->imap, ctx->server->pop3); server = ctx->root; @@ -739,7 +841,7 @@ if (strcmp(type, "protocol") == 0) { if ((ctx->type != SETTINGS_TYPE_ROOT && ctx->type != SETTINGS_TYPE_SERVER) || - ctx->level != 0) { + ctx->level != 1) { *errormsg = "Protocol section not allowed here"; return FALSE; } @@ -752,7 +854,6 @@ *errormsg = "Unknown protocol name"; return FALSE; } - ctx->level++; return TRUE; } @@ -768,6 +869,28 @@ return ctx->auth != NULL; } + if (ctx->type == SETTINGS_TYPE_AUTH && + strcmp(type, "socket") == 0) { + ctx->type = SETTINGS_TYPE_AUTH_SOCKET; + ctx->auth_socket = parse_new_auth_socket(ctx->auth, + name, errormsg); + return ctx->auth_socket != NULL; + } + + if (ctx->type == SETTINGS_TYPE_AUTH_SOCKET) { + ctx->type = SETTINGS_TYPE_SOCKET; + + if (strcmp(type, "master") == 0) { + ctx->socket = &ctx->auth_socket->master; + return TRUE; + } + + if (strcmp(type, "client") == 0) { + ctx->socket = &ctx->auth_socket->client; + return TRUE; + } + } + if (strcmp(type, "namespace") == 0) { if (ctx->type != SETTINGS_TYPE_ROOT && ctx->type != SETTINGS_TYPE_SERVER) {
--- a/src/master/master-settings.h Wed Jun 23 20:48:35 2004 +0300 +++ b/src/master/master-settings.h Wed Jun 23 20:50:43 2004 +0300 @@ -98,6 +98,22 @@ int listen_fd, ssl_listen_fd; }; +struct socket_settings { + const char *path; + unsigned int mode; + const char *user; + const char *group; +}; + +struct auth_socket_settings { + struct auth_settings *parent; + struct auth_socket_settings *next; + + const char *type; + struct socket_settings master; + struct socket_settings client; +}; + struct auth_settings { struct server_settings *parent; struct auth_settings *next; @@ -119,11 +135,11 @@ unsigned int count; unsigned int process_size; - const char *extra_sockets; /* .. */ uid_t uid; gid_t gid; + struct auth_socket_settings *sockets; }; struct namespace_settings {