]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
*-login: Fixes to SSL/login proxy connection counting.
authorTimo Sirainen <tss@iki.fi>
Fri, 11 Sep 2009 17:43:37 +0000 (13:43 -0400)
committerTimo Sirainen <tss@iki.fi>
Fri, 11 Sep 2009 17:43:37 +0000 (13:43 -0400)
--HG--
branch : HEAD

src/imap-login/client.c
src/login-common/client-common-auth.c
src/login-common/client-common.c
src/login-common/client-common.h
src/login-common/login-proxy.c
src/login-common/login-proxy.h
src/login-common/main.c
src/login-common/ssl-proxy-openssl.c
src/login-common/ssl-proxy.c
src/login-common/ssl-proxy.h
src/pop3-login/client.c

index e53b2aa6265f5f9e134710504b08a489c064d17b..d36565ebb9211b7659c937341c9145fba06297cd 100644 (file)
@@ -291,7 +291,7 @@ static void imap_client_input(struct client *client)
                o_stream_uncork(imap_client->common.output);
        }
 
-       client_unref(client);
+       client_unref(&client);
 }
 
 static struct client *imap_client_alloc(pool_t pool)
index 7673e520219f48b701f8b5e266ddce01a088bdb3..f69d90b88e07e149e653d191fef6bf2f8b53024a 100644 (file)
@@ -164,13 +164,7 @@ void client_proxy_finish_destroy_client(struct client *client)
        if (client->proxy_master_user != NULL)
                str_printfa(str, " (master %s)", client->proxy_master_user);
 
-       login_proxy_detach(client->login_proxy, client->input, client->output);
-
-       client->login_proxy = NULL;
-       client->input = NULL;
-       client->output = NULL;
-       client->fd = -1;
-       client->proxying = TRUE;
+       login_proxy_detach(client->login_proxy);
        client_destroy_success(client, str_c(str));
 }
 
@@ -480,7 +474,7 @@ sasl_callback(struct client *client, enum sasl_server_reply sasl_reply,
                return;
        }
 
-       client_unref(client);
+       client_unref(&client);
 }
 
 int client_auth_begin(struct client *client, const char *mech_name,
index 9fe3bed6b97c2296763070099ce7cfc148abcd5c..ee9fc0b2b96b1d1774ebd1d4d106704c78c4cccf 100644 (file)
@@ -160,7 +160,7 @@ void client_destroy(struct client *client, const char *reason)
        if (client->ssl_proxy != NULL)
                ssl_proxy_free(&client->ssl_proxy);
        client->v.destroy(client);
-       client_unref(client);
+       client_unref(&client);
 }
 
 void client_destroy_success(struct client *client, const char *reason)
@@ -182,27 +182,30 @@ void client_ref(struct client *client)
        client->refcount++;
 }
 
-bool client_unref(struct client *client)
+bool client_unref(struct client **_client)
 {
+       struct client *client = *_client;
+
        i_assert(client->refcount > 0);
        if (--client->refcount > 0)
                return TRUE;
 
+       *_client = NULL;
+
        i_assert(client->destroyed);
+       i_assert(client->ssl_proxy == NULL);
+       i_assert(client->login_proxy == NULL);
 
        if (client->input != NULL)
                i_stream_unref(&client->input);
        if (client->output != NULL)
                o_stream_unref(&client->output);
 
-       if (!client->proxying) {
-               i_assert(client->ssl_proxy == NULL);
-               master_service_client_connection_destroyed(master_service);
-       }
-
        i_free(client->virtual_user);
        i_free(client->auth_mech_name);
        pool_unref(&client->pool);
+
+       master_service_client_connection_destroyed(master_service);
        return FALSE;
 }
 
@@ -243,7 +246,7 @@ static void client_start_tls(struct client *client)
        int fd_ssl;
 
        client_ref(client);
-       if (!client_unref(client) || client->destroyed)
+       if (!client_unref(&client) || client->destroyed)
                return;
 
        fd_ssl = ssl_proxy_new(client->fd, &client->ip,
@@ -255,9 +258,9 @@ static void client_start_tls(struct client *client)
                               "Disconnected: TLS initialization failed.");
                return;
        }
+       ssl_proxy_set_client(client->ssl_proxy, client);
 
        client->starttls = TRUE;
-       client->proxying = TRUE;
        client->tls = TRUE;
        client->secured = TRUE;
        client_set_title(client);
index 9bbc8afa97d35390ed85e311fb2c5d9576710d8f..0eedca2ffdc2ac7cc98c362e511e8324ab7963c8 100644 (file)
@@ -115,7 +115,6 @@ struct client {
        unsigned int tls:1;
        unsigned int secured:1;
        unsigned int trusted:1;
-       unsigned int proxying:1;
        unsigned int authenticating:1;
        unsigned int auth_tried_disabled_plaintext:1;
        unsigned int auth_initializing:1;
@@ -134,7 +133,7 @@ void client_destroy_success(struct client *client, const char *reason);
 void client_destroy_internal_failure(struct client *client);
 
 void client_ref(struct client *client);
-bool client_unref(struct client *client);
+bool client_unref(struct client **client);
 
 void client_cmd_starttls(struct client *client);
 
index 9b9b864f83ef8c17787e18187f8c160163ba2f1c..743aed55c1369bc65e48a70d0305b962b1f0e9e9 100644 (file)
 struct login_proxy {
        struct login_proxy *prev, *next;
 
-       struct client *prelogin_client;
+       struct client *client;
        int client_fd, server_fd;
        struct io *client_io, *server_io;
        struct istream *server_input;
        struct ostream *client_output, *server_output;
-       struct ip_addr ip;
-       struct ssl_proxy *ssl_proxy;
+       struct ssl_proxy *ssl_server_proxy;
 
        struct timeval created;
        struct timeout *to;
@@ -226,7 +225,8 @@ login_proxy_new(struct client *client, const struct login_proxy_settings *set,
        proxy->user = i_strdup(client->virtual_user);
        proxy->port = set->port;
        proxy->ssl_flags = set->ssl_flags;
-       proxy->prelogin_client = client;
+       proxy->client = client;
+       client_ref(client);
 
        proxy->server_fd = fd;
        proxy->server_io = io_add(fd, IO_WRITE, proxy_wait_connect, proxy);
@@ -238,7 +238,6 @@ login_proxy_new(struct client *client, const struct login_proxy_settings *set,
        proxy->callback = callback;
        proxy->context = context;
 
-       proxy->ip = client->ip;
        proxy->client_fd = -1;
 
        proxy->state_rec = rec;
@@ -249,6 +248,7 @@ login_proxy_new(struct client *client, const struct login_proxy_settings *set,
 void login_proxy_free(struct login_proxy **_proxy)
 {
        struct login_proxy *proxy = *_proxy;
+       struct client *client = proxy->client;
        const char *ipstr;
 
        *_proxy = NULL;
@@ -276,7 +276,7 @@ void login_proxy_free(struct login_proxy **_proxy)
                /* detached proxy */
                DLLIST_REMOVE(&login_proxies, proxy);
 
-               ipstr = net_ip2addr(&proxy->ip);
+               ipstr = net_ip2addr(&proxy->client->ip);
                i_info("proxy(%s): disconnecting %s",
                       str_sanitize(proxy->user, 80),
                       ipstr != NULL ? ipstr : "");
@@ -293,15 +293,16 @@ void login_proxy_free(struct login_proxy **_proxy)
                proxy->callback(proxy->context);
        }
 
-       if (proxy->ssl_proxy != NULL)
-               ssl_proxy_free(&proxy->ssl_proxy);
        net_disconnect(proxy->server_fd);
 
+       if (proxy->ssl_server_proxy != NULL)
+               ssl_proxy_free(&proxy->ssl_server_proxy);
        i_free(proxy->host);
        i_free(proxy->user);
        i_free(proxy);
 
-       master_service_client_connection_destroyed(master_service);
+       client->login_proxy = NULL;
+       client_unref(&client);
 }
 
 bool login_proxy_is_ourself(const struct client *client, const char *host,
@@ -346,27 +347,26 @@ login_proxy_get_ssl_flags(const struct login_proxy *proxy)
        return proxy->ssl_flags;
 }
 
-void login_proxy_detach(struct login_proxy *proxy, struct istream *client_input,
-                       struct ostream *client_output)
+void login_proxy_detach(struct login_proxy *proxy)
 {
+       struct client *client = proxy->client;
        const unsigned char *data;
        size_t size;
 
        i_assert(proxy->client_fd == -1);
        i_assert(proxy->server_output != NULL);
 
-       proxy->prelogin_client = NULL;
-       proxy->client_fd = i_stream_get_fd(client_input);
-       proxy->client_output = client_output;
+       proxy->client_fd = i_stream_get_fd(client->input);
+       proxy->client_output = client->output;
 
-       o_stream_set_max_buffer_size(client_output, (size_t)-1);
-       o_stream_set_flush_callback(client_output, proxy_client_output, proxy);
+       o_stream_set_max_buffer_size(client->output, (size_t)-1);
+       o_stream_set_flush_callback(client->output, proxy_client_output, proxy);
+       client->output = NULL;
 
        /* send all pending client input to proxy and get rid of the stream */
-       data = i_stream_get_data(client_input, &size);
+       data = i_stream_get_data(client->input, &size);
        if (size != 0)
                (void)o_stream_send(proxy->server_output, data, size);
-       i_stream_unref(&client_input);
 
        /* from now on, just do dummy proxying */
        io_remove(&proxy->server_io);
@@ -381,6 +381,9 @@ void login_proxy_detach(struct login_proxy *proxy, struct istream *client_input,
        proxy->context = NULL;
 
        DLLIST_PREPEND(&login_proxies, proxy);
+
+       client->fd = -1;
+       client->login_proxy = NULL;
 }
 
 static int login_proxy_ssl_handshaked(void *context)
@@ -388,15 +391,15 @@ static int login_proxy_ssl_handshaked(void *context)
        struct login_proxy *proxy = context;
 
        if ((proxy->ssl_flags & PROXY_SSL_FLAG_ANY_CERT) != 0 ||
-           ssl_proxy_has_valid_client_cert(proxy->ssl_proxy))
+           ssl_proxy_has_valid_client_cert(proxy->ssl_server_proxy))
                return 0;
 
-       if (!ssl_proxy_has_broken_client_cert(proxy->ssl_proxy)) {
-               client_log_err(proxy->prelogin_client, t_strdup_printf(
+       if (!ssl_proxy_has_broken_client_cert(proxy->ssl_server_proxy)) {
+               client_log_err(proxy->client, t_strdup_printf(
                        "proxy: SSL certificate not received from %s:%u",
                        proxy->host, proxy->port));
        } else {
-               client_log_err(proxy->prelogin_client, t_strdup_printf(
+               client_log_err(proxy->client, t_strdup_printf(
                        "proxy: Received invalid SSL certificate from %s:%u",
                        proxy->host, proxy->port));
        }
@@ -414,16 +417,17 @@ int login_proxy_starttls(struct login_proxy *proxy)
                o_stream_destroy(&proxy->server_output);
        io_remove(&proxy->server_io);
 
-       fd = ssl_proxy_client_new(proxy->server_fd, &proxy->ip,
-                                 proxy->prelogin_client->set,
+       fd = ssl_proxy_client_new(proxy->server_fd, &proxy->client->ip,
+                                 proxy->client->set,
                                  login_proxy_ssl_handshaked, proxy,
-                                 &proxy->ssl_proxy);
+                                 &proxy->ssl_server_proxy);
        if (fd < 0) {
-               client_log_err(proxy->prelogin_client, t_strdup_printf(
+               client_log_err(proxy->client, t_strdup_printf(
                        "proxy: SSL handshake failed to %s:%u",
                        proxy->host, proxy->port));
                return -1;
        }
+       ssl_proxy_set_client(proxy->ssl_server_proxy, proxy->client);
 
        proxy->server_fd = fd;
        proxy_plain_connected(proxy);
index f9b5a6e5880db569beaa83a55d0a68c91ce00275..658100a0504b146b2bbbc0c22bd8746e9b899f50 100644 (file)
@@ -47,8 +47,7 @@ bool login_proxy_is_ourself(const struct client *client, const char *host,
 
 /* Detach proxy from client. This is done after the authentication is
    successful and all that is left is the dummy proxying. */
-void login_proxy_detach(struct login_proxy *proxy, struct istream *client_input,
-                       struct ostream *client_output);
+void login_proxy_detach(struct login_proxy *proxy);
 
 /* STARTTLS command was issued. */
 int login_proxy_starttls(struct login_proxy *proxy);
index d308d4e8addeeb39348f2a081903e0851ef6fae4..af6f84a622d5aa0fa4bc3ee3a25fde1088d37e70 100644 (file)
@@ -58,8 +58,8 @@ static void client_connected(const struct master_service_connection *conn)
 
                client = client_create(fd_ssl, TRUE, pool, set,
                                       &local_ip, &conn->remote_ip);
-               client->proxying = TRUE;
                client->ssl_proxy = proxy;
+               ssl_proxy_set_client(proxy, client);
        }
 
        client->remote_port = conn->remote_port;
index 0d2df23fc112f46e15928f9310ff8ba19d75aea1..76dab6ce6fceef7dab81bba5350c72891ec07815 100644 (file)
@@ -10,6 +10,7 @@
 #include "llist.h"
 #include "master-service.h"
 #include "master-interface.h"
+#include "client-common.h"
 #include "ssl-proxy.h"
 
 #include <fcntl.h>
@@ -42,6 +43,7 @@ struct ssl_proxy {
        struct ssl_proxy *prev, *next;
 
        SSL *ssl;
+       struct client *client;
        struct ip_addr ip;
        const struct login_settings *set;
 
@@ -62,7 +64,7 @@ struct ssl_proxy {
        unsigned int destroyed:1;
        unsigned int cert_received:1;
        unsigned int cert_broken:1;
-       unsigned int client:1;
+       unsigned int client_proxy:1;
 };
 
 struct ssl_parameters {
@@ -413,7 +415,7 @@ static void ssl_handshake(struct ssl_proxy *proxy)
 {
        int ret;
 
-       if (proxy->client) {
+       if (proxy->client_proxy) {
                ret = SSL_connect(proxy->ssl);
                if (ret != 1) {
                        ssl_handle_error(proxy, ret, "SSL_connect()");
@@ -596,11 +598,19 @@ int ssl_proxy_client_new(int fd, struct ip_addr *ip,
 
        (*proxy_r)->handshake_callback = callback;
        (*proxy_r)->handshake_context = context;
-       (*proxy_r)->client = TRUE;
+       (*proxy_r)->client_proxy = TRUE;
        ssl_step(*proxy_r);
        return ret;
 }
 
+void ssl_proxy_set_client(struct ssl_proxy *proxy, struct client *client)
+{
+       i_assert(proxy->client == NULL);
+
+       client_ref(client);
+       proxy->client = client;
+}
+
 bool ssl_proxy_has_valid_client_cert(const struct ssl_proxy *proxy)
 {
        return proxy->cert_received && !proxy->cert_broken;
@@ -685,6 +695,9 @@ static void ssl_proxy_unref(struct ssl_proxy *proxy)
        i_assert(proxy->refcount == 0);
 
        SSL_free(proxy->ssl);
+
+       if (proxy->client != NULL)
+               client_unref(&proxy->client);
        i_free(proxy);
 }
 
@@ -712,8 +725,6 @@ static void ssl_proxy_destroy(struct ssl_proxy *proxy)
        (void)net_disconnect(proxy->fd_plain);
 
        ssl_proxy_unref(proxy);
-
-        master_service_client_connection_destroyed(master_service);
 }
 
 static RSA *ssl_gen_rsa_key(SSL *ssl ATTR_UNUSED,
index 5670844b88c39687c187d89da4f09b02417ad48c..d4d4443103a321743636b954aadbb4645d070aeb 100644 (file)
@@ -27,6 +27,11 @@ int ssl_proxy_client_new(int fd ATTR_UNUSED, struct ip_addr *ip ATTR_UNUSED,
        return -1;
 }
 
+void ssl_proxy_set_client(struct ssl_proxy *proxy ATTR_UNUSED,
+                         struct client *client ATTR_UNUSED)
+{
+}
+
 bool ssl_proxy_has_valid_client_cert(const struct ssl_proxy *proxy ATTR_UNUSED)
 {
        return FALSE;
index 0a2f15b90cffc50bb86deec50837bca8f3d9d9cb..0c9942898643ae23222d6482bb23982b9146ec53 100644 (file)
@@ -1,11 +1,10 @@
 #ifndef SSL_PROXY_H
 #define SSL_PROXY_H
 
-#include "ioloop.h"
-
 struct ip_addr;
 struct ssl_proxy;
 struct login_settings;
+struct client;
 
 extern bool ssl_initialized;
 
@@ -20,6 +19,7 @@ int ssl_proxy_client_new(int fd, struct ip_addr *ip,
                         const struct login_settings *set,
                         ssl_handshake_callback_t *callback, void *context,
                         struct ssl_proxy **proxy_r);
+void ssl_proxy_set_client(struct ssl_proxy *proxy, struct client *client);
 bool ssl_proxy_has_valid_client_cert(const struct ssl_proxy *proxy) ATTR_PURE;
 bool ssl_proxy_has_broken_client_cert(struct ssl_proxy *proxy);
 const char *ssl_proxy_get_peer_name(struct ssl_proxy *proxy);
index bc4ce91b6826c1a4b85973ab381dfc4290af26bd..b64ed60398fae9211af7013442d63d94cd39d7b4 100644 (file)
@@ -93,7 +93,7 @@ static void pop3_client_input(struct client *client)
                }
        }
 
-       if (client_unref(client))
+       if (client_unref(&client))
                o_stream_uncork(client->output);
 }