]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
login-proxy: login_proxy_new() - Add failure callback
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Sun, 3 May 2020 14:42:29 +0000 (17:42 +0300)
committeraki.tuomi <aki.tuomi@open-xchange.com>
Mon, 25 May 2020 08:38:55 +0000 (08:38 +0000)
src/login-common/client-common-auth.c
src/login-common/login-proxy.c
src/login-common/login-proxy.h

index 73f0246df342393466c66341d6c6254376f1f254..797e150b4cd8625a7e63f2c1d245555fbb26d37f 100644 (file)
@@ -382,6 +382,26 @@ static void proxy_input(struct client *client)
        o_stream_unref(&output);
 }
 
+static void proxy_failed(struct client *client,
+                        enum login_proxy_failure_type type,
+                        const char *reason ATTR_UNUSED,
+                        bool reconnecting ATTR_UNUSED)
+{
+       switch (type) {
+       case LOGIN_PROXY_FAILURE_TYPE_CONNECT:
+       case LOGIN_PROXY_FAILURE_TYPE_INTERNAL:
+       case LOGIN_PROXY_FAILURE_TYPE_INTERNAL_CONFIG:
+       case LOGIN_PROXY_FAILURE_TYPE_REMOTE:
+       case LOGIN_PROXY_FAILURE_TYPE_REMOTE_CONFIG:
+       case LOGIN_PROXY_FAILURE_TYPE_PROTOCOL:
+               client_proxy_failed(client, TRUE);
+               break;
+       case LOGIN_PROXY_FAILURE_TYPE_AUTH:
+               client_proxy_failed(client, FALSE);
+               break;
+       }
+}
+
 static bool
 proxy_check_start(struct client *client, struct event *event,
                  const struct client_auth_reply *reply,
@@ -478,7 +498,8 @@ static int proxy_start(struct client *client,
                "proxy(%s,%s:%u): ", client->virtual_user,
                net_ip2addr(&proxy_set.ip), proxy_set.port));
 
-       if (login_proxy_new(client, event, &proxy_set, proxy_input) < 0) {
+       if (login_proxy_new(client, event, &proxy_set, proxy_input,
+                           proxy_failed) < 0) {
                event_unref(&event);
                client_proxy_error(client, PROXY_FAILURE_MSG);
                return -1;
index c6e97c626cccf40eb38da44b8e4ef095d62bb3d8..b0e4c421eff8a17b5180f49d5e2fe3d45a098569 100644 (file)
@@ -65,6 +65,7 @@ struct login_proxy {
        enum login_proxy_ssl_flags ssl_flags;
 
        login_proxy_input_callback_t *input_callback;
+       login_proxy_failure_callback_t *failure_callback;
 
        bool connected:1;
        bool detached:1;
@@ -340,7 +341,8 @@ static int login_proxy_connect(struct login_proxy *proxy)
 
 int login_proxy_new(struct client *client, struct event *event,
                    const struct login_proxy_settings *set,
-                   login_proxy_input_callback_t *input_callback)
+                   login_proxy_input_callback_t *input_callback,
+                   login_proxy_failure_callback_t *failure_callback)
 {
        struct login_proxy *proxy;
 
@@ -377,6 +379,7 @@ int login_proxy_new(struct client *client, struct event *event,
        DLLIST_PREPEND(&login_proxies_pending, proxy);
 
        proxy->input_callback = input_callback;
+       proxy->failure_callback = failure_callback;
        client->login_proxy = proxy;
        return 0;
 }
@@ -547,6 +550,38 @@ void login_proxy_free(struct login_proxy **_proxy)
        login_proxy_free_full(_proxy, NULL, 0);
 }
 
+void login_proxy_failed(struct login_proxy *proxy, struct event *event,
+                       enum login_proxy_failure_type type, const char *reason)
+{
+       const char *log_prefix;
+
+       switch (type) {
+       case LOGIN_PROXY_FAILURE_TYPE_INTERNAL:
+               log_prefix = "Aborting due to internal error: ";
+               break;
+       case LOGIN_PROXY_FAILURE_TYPE_INTERNAL_CONFIG:
+       case LOGIN_PROXY_FAILURE_TYPE_CONNECT:
+               log_prefix = "";
+               break;
+       case LOGIN_PROXY_FAILURE_TYPE_REMOTE:
+       case LOGIN_PROXY_FAILURE_TYPE_REMOTE_CONFIG:
+               log_prefix = "Aborting due to remote server: ";
+               break;
+       case LOGIN_PROXY_FAILURE_TYPE_PROTOCOL:
+               log_prefix = "Remote server sent invalid input: ";
+               break;
+       case LOGIN_PROXY_FAILURE_TYPE_AUTH:
+               log_prefix = "";
+               break;
+       default:
+               i_unreached();
+       }
+
+       if (reason != NULL)
+               e_error(event, "%s%s", log_prefix, reason);
+       proxy->failure_callback(proxy->client, type, reason, FALSE);
+}
+
 bool login_proxy_is_ourself(const struct client *client, const char *host,
                            in_port_t port, const char *destuser)
 {
@@ -668,6 +703,7 @@ void login_proxy_detach(struct login_proxy *proxy)
        }
 
        proxy->input_callback = NULL;
+       proxy->failure_callback = NULL;
 
        if (login_proxy_ipc_server == NULL) {
                login_proxy_ipc_server =
index 41b730b3e8ff3a3031c46e329b20133b4255cee9..df964ae4e0d8692e03cc7e61a8160be061edf270 100644 (file)
@@ -22,6 +22,25 @@ enum login_proxy_ssl_flags {
        PROXY_SSL_FLAG_ANY_CERT = 0x04
 };
 
+enum login_proxy_failure_type {
+       /* connect() failed or remote disconnected us. */
+       LOGIN_PROXY_FAILURE_TYPE_CONNECT,
+       /* Internal error. */
+       LOGIN_PROXY_FAILURE_TYPE_INTERNAL,
+       /* Internal configuration error. */
+       LOGIN_PROXY_FAILURE_TYPE_INTERNAL_CONFIG,
+       /* Remote command failed unexpectedly. */
+       LOGIN_PROXY_FAILURE_TYPE_REMOTE,
+       /* Remote isn't configured as expected (e.g. STARTTLS required, but
+          no such capability). */
+       LOGIN_PROXY_FAILURE_TYPE_REMOTE_CONFIG,
+       /* Remote server is unexpectedly violating the protocol standard. */
+       LOGIN_PROXY_FAILURE_TYPE_PROTOCOL,
+       /* Authentication failed to backend. The LOGIN/AUTH command reply was
+          already sent to the client. */
+       LOGIN_PROXY_FAILURE_TYPE_AUTH,
+};
+
 struct login_proxy_settings {
        const char *host;
        struct ip_addr ip, source_ip;
@@ -35,15 +54,27 @@ struct login_proxy_settings {
 
 /* Called when new input comes from proxy. */
 typedef void login_proxy_input_callback_t(struct client *client);
+/* Called when proxying fails. If reconnecting=TRUE, this is just an
+   intermediate notification that the proxying will attempt to reconnect soon
+   before failing. */
+typedef void login_proxy_failure_callback_t(struct client *client,
+                                           enum login_proxy_failure_type type,
+                                           const char *reason,
+                                           bool reconnecting);
 
 /* Create a proxy to given host. Returns NULL if failed. Given callback is
    called when new input is available from proxy. */
 int login_proxy_new(struct client *client, struct event *event,
                    const struct login_proxy_settings *set,
-                   login_proxy_input_callback_t *input_callback);
+                   login_proxy_input_callback_t *input_callback,
+                   login_proxy_failure_callback_t *failure_callback);
 /* Free the proxy. This should be called if authentication fails. */
 void login_proxy_free(struct login_proxy **proxy);
 
+/* Login proxying session has failed. */
+void login_proxy_failed(struct login_proxy *proxy, struct event *event,
+                       enum login_proxy_failure_type type, const char *reason);
+
 /* Return TRUE if host/port/destuser combination points to same as current
    connection. */
 bool login_proxy_is_ourself(const struct client *client, const char *host,