From: Timo Sirainen Date: Thu, 27 May 2010 11:16:36 +0000 (+0100) Subject: lib-master API changed to avoid accidentally leaking client connections. X-Git-Tag: 2.0.beta6~142 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=db693bf6fcae96d834567f1782257517b7207655;p=thirdparty%2Fdovecot%2Fcore.git lib-master API changed to avoid accidentally leaking client connections. This change also fixes many such leaks. --HG-- branch : HEAD --- diff --git a/src/anvil/main.c b/src/anvil/main.c index 2ba01c9538..8c8c77e560 100644 --- a/src/anvil/main.c +++ b/src/anvil/main.c @@ -18,10 +18,11 @@ struct connect_limit *connect_limit; struct penalty *penalty; static struct io *log_fdpass_io; -static void client_connected(const struct master_service_connection *conn) +static void client_connected(struct master_service_connection *conn) { bool master = conn->listen_fd == MASTER_LISTEN_FD_FIRST; + master_service_client_connection_accept(conn); anvil_connection_create(conn->fd, master, conn->fifo); } diff --git a/src/auth/main.c b/src/auth/main.c index 4acf2cf4af..9c58a2fa78 100644 --- a/src/auth/main.c +++ b/src/auth/main.c @@ -182,18 +182,18 @@ static void main_deinit(void) pool_unref(&auth_set_pool); } -static void worker_connected(const struct master_service_connection *conn) +static void worker_connected(struct master_service_connection *conn) { if (auth_worker_client != NULL) { i_error("Auth workers can handle only a single client"); - (void)close(conn->fd); return; } + master_service_client_connection_accept(conn); (void)auth_worker_client_create(auth_find_service(NULL), conn->fd); } -static void client_connected(const struct master_service_connection *conn) +static void client_connected(struct master_service_connection *conn) { enum auth_socket_type *type; const char *path, *name, *suffix; @@ -245,6 +245,7 @@ static void client_connected(const struct master_service_connection *conn) default: i_unreached(); } + master_service_client_connection_accept(conn); } diff --git a/src/config/main.c b/src/config/main.c index c1616f341b..7db4deeede 100644 --- a/src/config/main.c +++ b/src/config/main.c @@ -8,8 +8,9 @@ #include "config-parser.h" #include "config-request.h" -static void client_connected(const struct master_service_connection *conn) +static void client_connected(struct master_service_connection *conn) { + master_service_client_connection_accept(conn); config_connection_create(conn->fd); } diff --git a/src/dict/main.c b/src/dict/main.c index 61379ec748..683122743b 100644 --- a/src/dict/main.c +++ b/src/dict/main.c @@ -20,8 +20,9 @@ static void dict_die(void) /* hope that other processes relying on us will die first. */ } -static void client_connected(const struct master_service_connection *conn) +static void client_connected(struct master_service_connection *conn) { + master_service_client_connection_accept(conn); dict_connection_create(conn->fd); } diff --git a/src/director/main.c b/src/director/main.c index 099ef8d1ee..37596f6808 100644 --- a/src/director/main.c +++ b/src/director/main.c @@ -37,7 +37,7 @@ static int director_client_connected(int fd, const struct ip_addr *ip) return 0; } -static void client_connected(const struct master_service_connection *conn) +static void client_connected(struct master_service_connection *conn) { struct auth_connection *auth; const char *path, *name; @@ -47,9 +47,9 @@ static void client_connected(const struct master_service_connection *conn) if (conn->fifo) { if (notify_conn != NULL) { i_error("Received another proxy-notify connection"); - (void)close(conn->fd); return; } + master_service_client_connection_accept(conn); notify_conn = notify_connection_init(director, conn->fd); return; } @@ -57,8 +57,8 @@ static void client_connected(const struct master_service_connection *conn) if (net_getpeername(conn->fd, &ip, &port) == 0 && (IPADDR_IS_V4(&ip) || IPADDR_IS_V6(&ip))) { /* TCP/IP connection - this is another director */ - if (director_client_connected(conn->fd, &ip) < 0) - (void)close(conn->fd); + if (director_client_connected(conn->fd, &ip) == 0) + master_service_client_connection_accept(conn); return; } @@ -74,14 +74,15 @@ static void client_connected(const struct master_service_connection *conn) len = strlen(name); if (len > 6 && strcmp(name + len - 6, "-admin") == 0) { /* doveadm connection */ + master_service_client_connection_accept(conn); (void)doveadm_connection_init(director, conn->fd); } else { /* login connection */ auth = auth_connection_init(auth_socket_path); - if (auth_connection_connect(auth) == 0) + if (auth_connection_connect(auth) == 0) { + master_service_client_connection_accept(conn); login_connection_init(director, conn->fd, auth); - else { - (void)close(conn->fd); + } else { auth_connection_deinit(&auth); } } diff --git a/src/dns/dns-client.c b/src/dns/dns-client.c index fc44b606e6..fdbccbbcea 100644 --- a/src/dns/dns-client.c +++ b/src/dns/dns-client.c @@ -115,13 +115,14 @@ static void dns_client_destroy(struct dns_client **_client) master_service_client_connection_destroyed(master_service); } -static void client_connected(const struct master_service_connection *conn) +static void client_connected(struct master_service_connection *conn) { if (dns_client != NULL) { i_error("dns-client must be configured with client_limit=1"); - (void)close(conn->fd); return; } + + master_service_client_connection_accept(conn); dns_client = dns_client_create(conn->fd); } diff --git a/src/dsync/dsync.c b/src/dsync/dsync.c index 169cf53418..2719444fe4 100644 --- a/src/dsync/dsync.c +++ b/src/dsync/dsync.c @@ -67,7 +67,7 @@ usage(void) } static void -dsync_connected(const struct master_service_connection *conn ATTR_UNUSED) +dsync_connected(struct master_service_connection *conn ATTR_UNUSED) { i_fatal("Running as service not supported currently"); } diff --git a/src/imap/main.c b/src/imap/main.c index 5ddf8c3266..bf9f084fa0 100644 --- a/src/imap/main.c +++ b/src/imap/main.c @@ -276,12 +276,12 @@ static void login_client_failed(const struct master_login_client *client, } } -static void client_connected(const struct master_service_connection *conn) +static void client_connected(struct master_service_connection *conn) { if (master_login == NULL) { /* running standalone, we shouldn't even get here */ - (void)close(conn->fd); } else { + master_service_client_connection_accept(conn); master_login_add(master_login, conn->fd); } } diff --git a/src/lib-master/master-service.c b/src/lib-master/master-service.c index d09c0d1367..48a087cc35 100644 --- a/src/lib-master/master-service.c +++ b/src/lib-master/master-service.c @@ -537,6 +537,11 @@ void master_service_anvil_send(struct master_service *service, const char *cmd) } } +void master_service_client_connection_accept(struct master_service_connection *conn) +{ + conn->accepted = TRUE; +} + void master_service_client_connection_destroyed(struct master_service *service) { /* we can listen again */ @@ -711,6 +716,12 @@ static void master_service_listen(struct master_service_listener *l) master_status_update(service); service->callback(&conn); + + if (!conn.accepted) { + if (close(conn.fd) < 0) + i_error("close(service connection) failed: %m"); + master_service_client_connection_destroyed(service); + } } static void io_listeners_init(struct master_service *service) diff --git a/src/lib-master/master-service.h b/src/lib-master/master-service.h index ddbc08eb7e..16e08f5ed3 100644 --- a/src/lib-master/master-service.h +++ b/src/lib-master/master-service.h @@ -29,10 +29,12 @@ struct master_service_connection { unsigned int fifo:1; unsigned int ssl:1; + + unsigned int accepted:1; }; typedef void -master_service_connection_callback_t(const struct master_service_connection *conn); +master_service_connection_callback_t(struct master_service_connection *conn); extern struct master_service *master_service; @@ -109,6 +111,8 @@ void master_service_stop_new_connections(struct master_service *service); /* Send command to anvil process, if we have fd to it. */ void master_service_anvil_send(struct master_service *service, const char *cmd); +/* Call to accept the client connection. Otherwise the connection is closed. */ +void master_service_client_connection_accept(struct master_service_connection *conn); /* Call whenever a client connection is destroyed. */ void master_service_client_connection_destroyed(struct master_service *service); diff --git a/src/lmtp/main.c b/src/lmtp/main.c index 09d90e2b78..5e5419a079 100644 --- a/src/lmtp/main.c +++ b/src/lmtp/main.c @@ -28,8 +28,9 @@ const char *dns_client_socket_path; struct mail_storage_service_ctx *storage_service; -static void client_connected(const struct master_service_connection *conn) +static void client_connected(struct master_service_connection *conn) { + master_service_client_connection_accept(conn); (void)client_create(conn->fd, conn->fd, conn); } diff --git a/src/log/main.c b/src/log/main.c index 8ae655d904..54990bb397 100644 --- a/src/log/main.c +++ b/src/log/main.c @@ -28,8 +28,9 @@ static void main_deinit(void) log_connections_deinit(); } -static void client_connected(const struct master_service_connection *conn) +static void client_connected(struct master_service_connection *conn) { + master_service_client_connection_accept(conn); log_connection_create(conn->fd, conn->listen_fd); } diff --git a/src/login-common/main.c b/src/login-common/main.c index 9b2783e8b1..c8dafe4455 100644 --- a/src/login-common/main.c +++ b/src/login-common/main.c @@ -206,12 +206,14 @@ static void client_input_error(struct login_access_lookup *lookup) } } -static void client_connected(const struct master_service_connection *conn) +static void client_connected(struct master_service_connection *conn) { const char *access_sockets = global_login_settings->login_access_sockets; struct login_access_lookup *lookup; + master_service_client_connection_accept(conn); + /* make sure we're connected (or attempting to connect) to auth */ auth_client_connect(auth_client); diff --git a/src/pop3/main.c b/src/pop3/main.c index dc577a7cbe..a9f7d43e48 100644 --- a/src/pop3/main.c +++ b/src/pop3/main.c @@ -172,12 +172,12 @@ static void login_client_failed(const struct master_login_client *client, } } -static void client_connected(const struct master_service_connection *conn) +static void client_connected(struct master_service_connection *conn) { if (master_login == NULL) { /* running standalone, we shouldn't even get here */ - (void)close(conn->fd); } else { + master_service_client_connection_accept(conn); master_login_add(master_login, conn->fd); } } diff --git a/src/ssl-params/main.c b/src/ssl-params/main.c index 25b0cc5c1f..76cd4b8060 100644 --- a/src/ssl-params/main.c +++ b/src/ssl-params/main.c @@ -54,8 +54,9 @@ static void client_handle(int fd) } } -static void client_connected(const struct master_service_connection *conn) +static void client_connected(struct master_service_connection *conn) { + master_service_client_connection_accept(conn); if (ssl_params->used == 0) { /* waiting for parameter building to finish */ if (!array_is_created(&delayed_fds)) diff --git a/src/util/script.c b/src/util/script.c index 881c1a70d0..1787ec9121 100644 --- a/src/util/script.c +++ b/src/util/script.c @@ -22,7 +22,7 @@ static const char **exec_args; static bool drop_privileges = FALSE; -static void client_connected(const struct master_service_connection *conn) +static void client_connected(struct master_service_connection *conn) { enum mail_storage_service_flags flags = MAIL_STORAGE_SERVICE_FLAG_NO_PLUGINS; @@ -53,8 +53,6 @@ static void client_connected(const struct master_service_connection *conn) i_fatal("read() failed: %m"); else i_fatal("read() failed: disconnected"); - (void)close(conn->fd); - return; } if (fd == -1) i_fatal("client fd not received"); diff --git a/src/util/tcpwrap.c b/src/util/tcpwrap.c index b1d3d8db63..82414e1a5e 100644 --- a/src/util/tcpwrap.c +++ b/src/util/tcpwrap.c @@ -103,9 +103,10 @@ static void client_connected(const struct master_service_connection *conn) { if (tcpwrap_client != NULL) { i_error("tcpwrap must be configured with client_limit=1"); - (void)close(conn->fd); return; } + + master_service_client_connection_accept(conn); tcpwrap_client = tcpwrap_client_create(conn->fd); }