Mercurial > dovecot > original-hg > dovecot-1.2
changeset 1275:af685269ead0 HEAD
login: Wait until we're connected to auth process before executing command
from client.
inetd usage: --group=name can now specify which login group to use. Default
is the binary name before '-' character (ie. imap or pop3).
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Wed, 05 Mar 2003 00:38:07 +0200 |
parents | f7fc5d52ac7c |
children | 3607a2b4f011 |
files | src/imap-login/client-authenticate.c src/imap-login/client.c src/imap-login/client.h src/login-common/Makefile.am src/login-common/auth-connection.c src/login-common/client-common.h src/login-common/main.c src/login-common/master.c src/login-common/master.h src/master/login-process.c src/pop3-login/client.c src/pop3-login/client.h |
diffstat | 12 files changed, 244 insertions(+), 80 deletions(-) [+] |
line wrap: on
line diff
--- a/src/imap-login/client-authenticate.c Tue Mar 04 20:51:02 2003 +0200 +++ b/src/imap-login/client-authenticate.c Wed Mar 05 00:38:07 2003 +0200 @@ -130,6 +130,7 @@ master_callback, &error)) { case -1: /* login failed */ + client->authenticating = FALSE; client_auth_abort(client, error); break; @@ -143,6 +144,7 @@ default: /* success, we should be able to log in. if we fail, just disconnect the client. */ + client->authenticating = FALSE; client_send_tagline(client, "OK Logged in."); } } @@ -183,6 +185,7 @@ io_remove(client->common.io); client->common.io = NULL; } + client->authenticating = TRUE; return TRUE; } else { client_send_tagline(client, t_strconcat( @@ -204,6 +207,7 @@ master_callback, &error)) { case -1: /* login failed */ + client->authenticating = FALSE; client_auth_abort(client, error); break; @@ -214,6 +218,7 @@ default: /* success, we should be able to log in. if we fail, just disconnect the client. */ + client->authenticating = FALSE; client_send_tagline(client, "OK Logged in."); } } @@ -303,6 +308,7 @@ io_remove(client->common.io); client->common.io = io_add(client->common.fd, IO_READ, client_auth_input, client); + client->authenticating = TRUE; } else { client_send_tagline(client, t_strconcat( "NO Authentication failed: ", error, NULL));
--- a/src/imap-login/client.c Tue Mar 04 20:51:02 2003 +0200 +++ b/src/imap-login/client.c Wed Mar 05 00:38:07 2003 +0200 @@ -12,6 +12,7 @@ #include "imap-parser.h" #include "client.h" #include "client-authenticate.h" +#include "auth-connection.h" #include "ssl-proxy.h" /* max. size of one parameter in line */ @@ -184,10 +185,13 @@ return FALSE; } -static void client_handle_input(struct imap_client *client) +static int client_handle_input(struct imap_client *client) { struct imap_arg *args; + if (client->authenticating) + return FALSE; /* wait until authentication is finished */ + if (client->cmd_finished) { /* clear the previous command from memory. don't do this immediately after handling command since we need the @@ -199,7 +203,7 @@ /* remove \r\n */ if (client->skip_line) { if (!client_skip_line(client)) - return; + return TRUE; client->skip_line = FALSE; } @@ -209,23 +213,23 @@ if (client->cmd_tag == NULL) { client->cmd_tag = imap_parser_read_word(client->parser); if (client->cmd_tag == NULL) - return; /* need more data */ + return FALSE; /* need more data */ } if (client->cmd_name == NULL) { client->cmd_name = imap_parser_read_word(client->parser); if (client->cmd_name == NULL) - return; /* need more data */ + return FALSE; /* need more data */ } switch (imap_parser_read_args(client->parser, 0, 0, &args)) { case -1: /* error */ client_destroy(client, NULL); - return; + return TRUE; case -2: /* not enough data */ - return; + return FALSE; } client->skip_line = TRUE; @@ -236,13 +240,14 @@ "* BYE Too many invalid IMAP commands."); client_destroy(client, "Disconnected: " "Too many invalid commands"); - return; + return FALSE; } client_send_tagline(client, "BAD Error in IMAP command received by server."); } client->cmd_finished = TRUE; + return TRUE; } int client_read(struct imap_client *client) @@ -272,10 +277,19 @@ if (!client_read(client)) return; + if (!auth_is_connected()) { + /* we're not yet connected to auth process - + don't allow any commands */ + client_send_line(client, + "* OK Waiting for authentication process to respond.."); + client->input_blocked = TRUE; + return; + } + client_ref(client); o_stream_cork(client->output); - client_handle_input(client); + while (client_handle_input(client)) ; if (client_unref(client)) o_stream_flush(client->output); @@ -454,6 +468,22 @@ return hash_size(clients); } +static void client_hash_check_io(void *key, void *value __attr_unused__, + void *context __attr_unused__) +{ + struct imap_client *client = key; + + if (client->input_blocked) { + client->input_blocked = FALSE; + client_input(client); + } +} + +void clients_notify_auth_process(void) +{ + hash_foreach(clients, client_hash_check_io, NULL); +} + static void client_hash_destroy(void *key, void *value __attr_unused__, void *context __attr_unused__) {
--- a/src/imap-login/client.h Tue Mar 04 20:51:02 2003 +0200 +++ b/src/imap-login/client.h Wed Mar 05 00:38:07 2003 +0200 @@ -25,6 +25,8 @@ unsigned int tls:1; unsigned int cmd_finished:1; unsigned int skip_line:1; + unsigned int input_blocked:1; + unsigned int authenticating:1; unsigned int destroyed:1; }; @@ -41,9 +43,6 @@ int client_read(struct imap_client *client); void client_input(void *context); -unsigned int clients_get_count(void); -void clients_destroy_all(void); - void clients_init(void); void clients_deinit(void);
--- a/src/login-common/Makefile.am Tue Mar 04 20:51:02 2003 +0200 +++ b/src/login-common/Makefile.am Wed Mar 05 00:38:07 2003 +0200 @@ -17,7 +17,7 @@ noinst_HEADERS = \ auth-common.h \ auth-connection.h \ + client-common.h \ common.h \ - client-common.h \ master.h \ ssl-proxy.h
--- a/src/login-common/auth-connection.c Tue Mar 04 20:51:02 2003 +0200 +++ b/src/login-common/auth-connection.c Wed Mar 05 00:38:07 2003 +0200 @@ -6,6 +6,7 @@ #include "network.h" #include "istream.h" #include "ostream.h" +#include "client-common.h" #include "auth-connection.h" #include <unistd.h> @@ -130,6 +131,9 @@ hash_foreach(conn->requests, request_hash_remove, NULL); auth_connection_unref(conn); + + if (auth_is_connected()) + clients_notify_auth_process(); } static void auth_connection_unref(struct auth_connection *conn) @@ -200,8 +204,11 @@ conn->available_auth_mechs = handshake->auth_mechanisms; conn->handshake_received = TRUE; - auth_waiting_handshake_count--; + auth_waiting_handshake_count--; update_available_auth_mechs(); + + if (auth_is_connected()) + clients_notify_auth_process(); } static void auth_handle_reply(struct auth_connection *conn,
--- a/src/login-common/client-common.h Tue Mar 04 20:51:02 2003 +0200 +++ b/src/login-common/client-common.h Wed Mar 05 00:38:07 2003 +0200 @@ -20,6 +20,7 @@ struct client *client_create(int fd, struct ip_addr *ip, int ssl); unsigned int clients_get_count(void); +void clients_notify_auth_process(void); void clients_destroy_all(void); void clients_init(void);
--- a/src/login-common/main.c Tue Mar 04 20:51:02 2003 +0200 +++ b/src/login-common/main.c Wed Mar 05 00:38:07 2003 +0200 @@ -64,7 +64,8 @@ } closing_down = TRUE; - master_notify_finished(); + if (!is_inetd) + master_notify_finished(); } static void sig_quit(int signo __attr_unused__) @@ -77,13 +78,6 @@ struct ip_addr ip; int fd; - if (!auth_is_connected()) { - /* we're not yet connected to auth process - - don't accept client connections. FIXME: eats CPU if - none of the other login processes accept it either.. */ - return; - } - fd = net_accept(LOGIN_LISTEN_FD, &ip, NULL); if (fd < 0) { if (fd < -1) @@ -102,13 +96,6 @@ struct ip_addr ip; int fd, fd_ssl; - if (!auth_is_connected()) { - /* we're not yet connected to auth process - - don't accept client connections. FIXME: eats CPU if - none of the other login processes accept it either.. */ - return; - } - fd = net_accept(LOGIN_SSL_LISTEN_FD, &ip, NULL); if (fd < 0) { if (fd < -1) @@ -205,7 +192,7 @@ /* initialize master last - it sends the "we're ok" notification */ - master_init(LOGIN_MASTER_SOCKET_FD); + master_init(LOGIN_MASTER_SOCKET_FD, TRUE); } } @@ -228,9 +215,9 @@ int main(int argc __attr_unused__, char *argv[], char *envp[]) { - const char *name; + const char *name, *group_name; struct ip_addr ip; - int fd = -1, master_fd = -1; + int i, fd = -1, master_fd = -1; is_inetd = getenv("DOVECOT_MASTER") == NULL; @@ -244,8 +231,19 @@ if (is_inetd) { /* running from inetd. create master process before - dropping privileges */ - master_fd = master_connect(); + dropping privileges. */ + group_name = strrchr(argv[0], '/'); + group_name = group_name == NULL ? argv[0] : group_name+1; + group_name = t_strcut(group_name, '-'); + + for (i = 1; i < argc; i++) { + if (strncmp(argv[i], "--group=", 8) == 0) { + group_name = argv[1]+8; + break; + } + } + + master_fd = master_connect(group_name); } name = strrchr(argv[0], '/'); @@ -253,30 +251,34 @@ process_title_init(argv, envp); ioloop = io_loop_create(system_pool); + main_init(); if (is_inetd) { - master_init(master_fd); - if (net_getsockname(1, &ip, NULL) < 0) { i_fatal("%s can be started only through dovecot " "master process, inetd or equilevant", argv[0]); } - if (argc < 2 || strcmp(argv[1], "--ssl") != 0) - fd = 1; - else - fd = ssl_proxy_new(fd, &ip); + fd = 1; + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "--ssl") == 0) { + fd = ssl_proxy_new(fd, &ip); + if (fd == -1) + i_fatal("SSL initialization failed"); + } else if (strncmp(argv[i], "--group=", 8) != 0) + i_fatal("Unknown parameter: %s", argv[i]); + } + + master_init(master_fd, FALSE); } - if (fd != -1 || !is_inetd) { - main_init(); + main_close_listen(); - if (fd != -1) - (void)client_create(fd, &ip, TRUE); + if (fd != -1) + (void)client_create(fd, &ip, TRUE); - io_loop_run(ioloop); - main_deinit(); - } + io_loop_run(ioloop); + main_deinit(); io_loop_destroy(ioloop); lib_deinit();
--- a/src/login-common/master.c Tue Mar 04 20:51:02 2003 +0200 +++ b/src/login-common/master.c Wed Mar 05 00:38:07 2003 +0200 @@ -7,6 +7,7 @@ #include "fdpass.h" #include "istream.h" #include "env-util.h" +#include "write-full.h" #include "master.h" #include "client-common.h" @@ -133,7 +134,7 @@ i_stream_unref(input); } -int master_connect(void) +int master_connect(const char *group_name) { const char *path = PKG_RUNDIR"/master"; int i, fd = -1; @@ -164,6 +165,19 @@ if (fd == -1) i_fatal("Couldn't use/create UNIX socket %s", path); + if (group_name[0] == '\0') + i_fatal("No login group name set"); + + if (strlen(group_name) >= 256) + i_fatal("Login group name too large: %s", group_name); + + /* group_name length is now guaranteed to be in range of 1..255 so we + can send <length byte><name> */ + group_name = t_strdup_printf("%c%s", (unsigned char)strlen(group_name), + group_name); + if (write_full(fd, group_name, strlen(group_name)) < 0) + i_fatal("write_full(master_fd) failed: %m"); + master_read_env(fd); return fd; } @@ -189,7 +203,7 @@ master_pos = 0; } -void master_init(int fd) +void master_init(int fd, int notify) { main_ref(); @@ -200,9 +214,11 @@ master_pos = 0; io_master = io_add(master_fd, IO_READ, master_input, NULL); - /* just a note to master that we're ok. if we die before, - master should shutdown itself. */ - master_notify_finished(); + if (notify) { + /* just a note to master that we're ok. if we die before, + master should shutdown itself. */ + master_notify_finished(); + } } void master_deinit(void)
--- a/src/login-common/master.h Tue Mar 04 20:51:02 2003 +0200 +++ b/src/login-common/master.h Wed Mar 05 00:38:07 2003 +0200 @@ -17,9 +17,9 @@ void master_close(void); /* inetd: Connect to existing master process, or create new one. */ -int master_connect(void); +int master_connect(const char *group_name); -void master_init(int fd); +void master_init(int fd, int notify); void master_deinit(void); #endif
--- a/src/master/login-process.c Tue Mar 04 20:51:02 2003 +0200 +++ b/src/master/login-process.c Wed Mar 05 00:38:07 2003 +0200 @@ -67,6 +67,7 @@ static void login_process_destroy(struct login_process *p); static void login_process_unref(struct login_process *p); +static int login_process_init_group(struct login_process *p); static void login_group_create(struct login_settings *login_set) { @@ -142,16 +143,76 @@ } p->listening = FALSE; - p->group->listening_processes--; + + if (p->group != NULL) { + p->group->listening_processes--; + p->prev_nonlisten = p->group->newest_nonlisten_process; + + if (p->group->newest_nonlisten_process != NULL) + p->group->newest_nonlisten_process->next_nonlisten = p; + p->group->newest_nonlisten_process = p; + + if (p->group->oldest_nonlisten_process == NULL) + p->group->oldest_nonlisten_process = p; + } +} - p->prev_nonlisten = p->group->newest_nonlisten_process; +static struct login_group *login_group_process_find(const char *name) +{ + struct login_group *group; + struct login_settings *login; + + if (login_groups == NULL) { + for (login = set->logins; login != NULL; login = login->next) + login_group_create(login); + } + + for (group = login_groups; group != NULL; group = group->next) { + if (strcmp(group->set->name, name) == 0) + return group; + } + + return NULL; +} - if (p->group->newest_nonlisten_process != NULL) - p->group->newest_nonlisten_process->next_nonlisten = p; - p->group->newest_nonlisten_process = p; +static int login_process_read_group(struct login_process *p) +{ + struct login_group *group; + const char *name; + char buf[256]; + unsigned int len; + ssize_t ret; + + /* read length */ + ret = read(p->fd, buf, 1); + if (ret != 1) + len = 0; + else { + len = buf[0]; + if (len >= sizeof(buf)) { + i_error("login: Process name length too large"); + return FALSE; + } - if (p->group->oldest_nonlisten_process == NULL) - p->group->oldest_nonlisten_process = p; + ret = read(p->fd, buf, len); + } + + if (ret < 0) + i_error("login: read() failed: %m"); + else if (len == 0 || (size_t)ret != len) + i_error("login: Process name wasn't sent"); + else { + name = t_strndup(buf, len); + group = login_group_process_find(name); + if (group == NULL) { + i_error("login: Unknown process group '%s'", name); + return FALSE; + } + + p->group = group; + return login_process_init_group(p); + } + return FALSE; } static void login_process_input(void *context) @@ -160,7 +221,15 @@ struct auth_process *auth_process; struct login_auth_request *authreq; struct master_login_request req; - int client_fd, ret; + int client_fd; + ssize_t ret; + + if (p->group == NULL) { + /* we want to read the group */ + if (!login_process_read_group(p)) + login_process_destroy(p); + return; + } ret = fd_read(p->fd, &req, sizeof(req), &client_fd); if (ret != sizeof(req)) { @@ -222,7 +291,6 @@ struct login_process *p; i_assert(pid != 0); - i_assert(group != NULL); p = i_new(struct login_process, 1); p->group = group; @@ -238,13 +306,18 @@ PID_ADD_PROCESS_TYPE(pid, PROCESS_TYPE_LOGIN); hash_insert(processes, POINTER_CAST(pid), p); - p->group->processes++; - p->group->listening_processes++; + if (p->group != NULL) { + p->group->processes++; + p->group->listening_processes++; + } return p; } static void login_process_remove_from_lists(struct login_process *p) { + if (p->group == NULL) + return; + if (p == p->group->oldest_nonlisten_process) p->group->oldest_nonlisten_process = p->next_nonlisten; else @@ -268,7 +341,8 @@ i_error("Login process died too early - shutting down"); io_loop_stop(ioloop); } - if (p->listening) + + if (p->listening && p->group != NULL) p->group->listening_processes--; o_stream_close(p->output); @@ -279,7 +353,9 @@ if (!p->listening) login_process_remove_from_lists(p); - p->group->processes--; + if (p->group != NULL) + p->group->processes--; + if (p->pid != 0) hash_remove(processes, POINTER_CAST(p->pid)); @@ -421,7 +497,7 @@ /* don't start raising the process count if they're dying all the time */ p = hash_lookup(processes, POINTER_CAST(pid)); - if (p != NULL) + if (p != NULL && p->group != NULL) p->group->wanted_processes_count = 0; } @@ -516,6 +592,19 @@ return ret; } +static int login_process_init_group(struct login_process *p) +{ + p->group->processes++; + p->group->listening_processes++; + + if (login_process_send_env(p) < 0) { + i_error("login: Couldn't send environment"); + return FALSE; + } + + return TRUE; +} + static void inetd_login_accept(void *context __attr_unused__) { struct login_process *p; @@ -529,13 +618,8 @@ net_set_nonblock(fd, TRUE); fd_close_on_exec(fd, TRUE); - p = login_process_new(login_groups, ++login_pid_counter, fd); - p->initialized = TRUE;; - - if (login_process_send_env(p) < 0) { - i_warning("Couldn't send environment to login process"); - login_process_destroy(p); - } + p = login_process_new(NULL, ++login_pid_counter, fd); + p->initialized = TRUE; } } @@ -550,9 +634,6 @@ to = timeout_add(1000, login_processes_start_missing, NULL); io_listen = NULL; } else { - /* use the first login group for everyone */ - login_group_create(set->logins); - to = NULL; io_listen = io_add(inetd_login_fd, IO_READ, inetd_login_accept, NULL);
--- a/src/pop3-login/client.c Tue Mar 04 20:51:02 2003 +0200 +++ b/src/pop3-login/client.c Wed Mar 05 00:38:07 2003 +0200 @@ -11,6 +11,7 @@ #include "strescape.h" #include "client.h" #include "client-authenticate.h" +#include "auth-connection.h" #include "ssl-proxy.h" /* max. length of input command line (spec says 512) */ @@ -157,6 +158,13 @@ if (!client_read(client)) return; + if (!auth_is_connected()) { + /* we're not yet connected to auth process - + don't allow any commands */ + client->input_blocked = TRUE; + return; + } + client_ref(client); o_stream_cork(client->output); @@ -341,6 +349,22 @@ return hash_size(clients); } +static void client_hash_check_io(void *key, void *value __attr_unused__, + void *context __attr_unused__) +{ + struct pop3_client *client = key; + + if (client->input_blocked) { + client->input_blocked = FALSE; + client_input(client); + } +} + +void clients_notify_auth_process(void) +{ + hash_foreach(clients, client_hash_check_io, NULL); +} + static void client_hash_destroy(void *key, void *value __attr_unused__, void *context __attr_unused__) {
--- a/src/pop3-login/client.h Tue Mar 04 20:51:02 2003 +0200 +++ b/src/pop3-login/client.h Wed Mar 05 00:38:07 2003 +0200 @@ -20,6 +20,7 @@ buffer_t *plain_login; unsigned int tls:1; + unsigned int input_blocked:1; unsigned int destroyed:1; }; @@ -35,9 +36,6 @@ int client_read(struct pop3_client *client); void client_input(void *context); -unsigned int clients_get_count(void); -void clients_destroy_all(void); - void clients_init(void); void clients_deinit(void);