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,
"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;
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;
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;
DLLIST_PREPEND(&login_proxies_pending, proxy);
proxy->input_callback = input_callback;
+ proxy->failure_callback = failure_callback;
client->login_proxy = proxy;
return 0;
}
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)
{
}
proxy->input_callback = NULL;
+ proxy->failure_callback = NULL;
if (login_proxy_ipc_server == NULL) {
login_proxy_ipc_server =
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;
/* 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,