From 1091b6f06584aaab5f8efea6b974223c0864cadc Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Sun, 3 May 2020 17:42:29 +0300 Subject: [PATCH] login-proxy: login_proxy_new() - Add failure callback --- src/login-common/client-common-auth.c | 23 +++++++++++++++- src/login-common/login-proxy.c | 38 ++++++++++++++++++++++++++- src/login-common/login-proxy.h | 33 ++++++++++++++++++++++- 3 files changed, 91 insertions(+), 3 deletions(-) diff --git a/src/login-common/client-common-auth.c b/src/login-common/client-common-auth.c index 73f0246df3..797e150b4c 100644 --- a/src/login-common/client-common-auth.c +++ b/src/login-common/client-common-auth.c @@ -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; diff --git a/src/login-common/login-proxy.c b/src/login-common/login-proxy.c index c6e97c626c..b0e4c421ef 100644 --- a/src/login-common/login-proxy.c +++ b/src/login-common/login-proxy.c @@ -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 = diff --git a/src/login-common/login-proxy.h b/src/login-common/login-proxy.h index 41b730b3e8..df964ae4e0 100644 --- a/src/login-common/login-proxy.h +++ b/src/login-common/login-proxy.h @@ -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, -- 2.47.3