}
}
- if (request->proxy && !seen_pass && request->mech_password != NULL) {
- /* we're proxying - send back the password that was
- sent by user (not the password in passdb). */
- auth_stream_reply_add(reply, "pass", request->mech_password);
+ if (request->proxy) {
+ /* we're proxying */
+ if (!seen_pass && request->mech_password != NULL) {
+ /* send back the password that was sent by user
+ (not the password in passdb). */
+ auth_stream_reply_add(reply, "pass",
+ request->mech_password);
+ }
+ if (request->master_user != NULL) {
+ /* the master username needs to be forwarded */
+ auth_stream_reply_add(reply, "master",
+ request->master_user);
+ }
}
}
const char *const *args, bool success)
{
const char *reason = NULL, *host = NULL, *destuser = NULL, *pass = NULL;
+ const char *master_user = NULL;
string_t *reply;
unsigned int port = 143;
bool proxy = FALSE, temp = FALSE, nologin = !success, proxy_self;
destuser = *args + 9;
else if (strncmp(*args, "pass=", 5) == 0)
pass = *args + 5;
+ else if (strncmp(*args, "master=", 7) == 0)
+ master_user = *args + 7;
else if (strncmp(*args, "user=", 5) == 0) {
/* already handled in login-common */
} else if (auth_debug) {
proxy host=.. [port=..] [destuser=..] pass=.. */
if (!success)
return FALSE;
- if (imap_proxy_new(client, host, port, destuser, pass) < 0)
+ if (imap_proxy_new(client, host, port, destuser, master_user,
+ pass) < 0)
client_destroy_internal_failure(client);
return TRUE;
}
client->proxy_password = NULL;
}
- i_free(client->proxy_user);
- client->proxy_user = NULL;
+ i_free_and_null(client->proxy_user);
+ i_free_and_null(client->proxy_master_user);
if (client->proxy != NULL) {
login_proxy_free(client->proxy);
struct timeout *to_idle_disconnect, *to_auth_waiting;
struct login_proxy *proxy;
- char *proxy_user, *proxy_password;
+ char *proxy_user, *proxy_master_user, *proxy_password;
unsigned int bad_counter;
#include "ioloop.h"
#include "istream.h"
#include "ostream.h"
+#include "base64.h"
#include "str.h"
#include "str-sanitize.h"
#include "safe-memset.h"
client->common.local_port);
}
+static void proxy_free_password(struct imap_client *client)
+{
+ safe_memset(client->proxy_password, 0, strlen(client->proxy_password));
+ i_free_and_null(client->proxy_password);
+}
+
+static void get_plain_auth(struct imap_client *client, string_t *dest)
+{
+ string_t *str;
+
+ str = t_str_new(128);
+ str_append(str, client->proxy_user);
+ str_append_c(str, '\0');
+ str_append(str, client->proxy_master_user);
+ str_append_c(str, '\0');
+ str_append(str, client->proxy_password);
+ base64_encode(str_data(str), str_len(str), dest);
+}
+
+static int proxy_input_banner(struct imap_client *client,
+ struct ostream *output, const char *line)
+{
+ string_t *str;
+
+ if (strncmp(line, "* OK ", 5) != 0) {
+ client_syslog(&client->common, t_strdup_printf(
+ "proxy: Remote returned invalid banner: %s",
+ str_sanitize(line, 160)));
+ client_destroy_internal_failure(client);
+ return -1;
+ }
+
+ str = t_str_new(128);
+ if (imap_banner_has_capability(line + 5, "ID"))
+ proxy_write_id(client, str);
+
+ if (client->proxy_master_user == NULL) {
+ /* logging in normally - use LOGIN command */
+ str_append(str, "L LOGIN ");
+ imap_quote_append_string(str, client->proxy_user, FALSE);
+ str_append_c(str, ' ');
+ imap_quote_append_string(str, client->proxy_password, FALSE);
+
+ proxy_free_password(client);
+ } else if (imap_banner_has_capability(line + 5, "SASL-IR")) {
+ /* master user login with SASL initial response support */
+ str_append(str, "L AUTHENTICATE PLAIN ");
+ get_plain_auth(client, str);
+ proxy_free_password(client);
+ } else {
+ /* master user login without SASL initial response */
+ str_append(str, "L AUTHENTICATE PLAIN");
+ }
+
+ str_append(str, "\r\n");
+ (void)o_stream_send(output, str_data(str), str_len(str));
+ client->proxy_login_sent = TRUE;
+ return 0;
+}
+
static int proxy_input_line(struct imap_client *client,
struct ostream *output, const char *line)
{
if (!client->proxy_login_sent) {
/* this is a banner */
- if (strncmp(line, "* OK ", 5) != 0) {
- client_syslog(&client->common, t_strdup_printf(
- "proxy: Remote returned invalid banner: %s",
- str_sanitize(line, 160)));
- client_destroy_internal_failure(client);
- return -1;
- }
-
+ return proxy_input_banner(client, output, line);
+ } else if (*line == '+') {
+ /* AUTHENTICATE started. finish it. */
str = t_str_new(128);
- if (imap_banner_has_capability(line + 5, "ID"))
- proxy_write_id(client, str);
-
- /* send LOGIN command */
- str_append(str, "P LOGIN ");
- imap_quote_append_string(str, client->proxy_user, FALSE);
- str_append_c(str, ' ');
- imap_quote_append_string(str, client->proxy_password, FALSE);
+ get_plain_auth(client, str);
str_append(str, "\r\n");
- (void)o_stream_send(output, str_data(str), str_len(str));
+ proxy_free_password(client);
- safe_memset(client->proxy_password, 0,
- strlen(client->proxy_password));
- i_free(client->proxy_password);
- client->proxy_password = NULL;
- client->proxy_login_sent = TRUE;
+ (void)o_stream_send(output, str_data(str), str_len(str));
return 0;
- } else if (strncmp(line, "P OK ", 5) == 0) {
+ } else if (strncmp(line, "L OK ", 5) == 0) {
/* Login successful. Send this line to client. */
str = t_str_new(128);
str_append(str, client->cmd_tag);
str_append_c(str, '/');
str_append(str, client->proxy_user);
}
+ if (client->proxy_master_user != NULL) {
+ str_printfa(str, " (master %s)",
+ client->proxy_master_user);
+ }
(void)client_skip_line(client);
login_proxy_detach(client->proxy, client->common.input,
client->common.fd = -1;
client_destroy_success(client, str_c(str));
return -1;
- } else if (strncmp(line, "P ", 2) == 0) {
+ } else if (strncmp(line, "L ", 2) == 0) {
/* If the backend server isn't Dovecot, the error message may
be different from Dovecot's "user doesn't exist" error. This
would allow an attacker to find out what users exist in the
str_append_c(str, '/');
str_append(str, client->proxy_user);
}
+ if (client->proxy_master_user != NULL) {
+ str_printfa(str, " (master %s)",
+ client->proxy_master_user);
+ }
str_append(str, ": ");
if (strncasecmp(line + 2, "NO ", 3) == 0)
str_append(str, line + 2 + 3);
login_proxy_free(client->proxy);
client->proxy = NULL;
- i_free(client->proxy_user);
- client->proxy_user = NULL;
+ i_free_and_null(client->proxy_user);
+ i_free_and_null(client->proxy_master_user);
return -1;
} else {
/* probably some untagged reply */
}
int imap_proxy_new(struct imap_client *client, const char *host,
- unsigned int port, const char *user, const char *password)
+ unsigned int port, const char *user, const char *master_user,
+ const char *password)
{
i_assert(user != NULL);
i_assert(!client->destroyed);
client->proxy_login_sent = FALSE;
client->proxy_user = i_strdup(user);
+ client->proxy_master_user = i_strdup(master_user);
client->proxy_password = i_strdup(password);
/* disable input until authentication is finished */
#include "login-proxy.h"
int imap_proxy_new(struct imap_client *client, const char *host,
- unsigned int port, const char *user, const char *password);
+ unsigned int port, const char *user, const char *master_user,
+ const char *password);
#endif
const char *const *args, bool success)
{
const char *reason = NULL, *host = NULL, *destuser = NULL, *pass = NULL;
+ const char *master_user = NULL;
string_t *reply;
unsigned int port = 110;
bool proxy = FALSE, temp = FALSE, nologin = !success;
destuser = *args + 9;
else if (strncmp(*args, "pass=", 5) == 0)
pass = *args + 5;
+ else if (strncmp(*args, "master=", 7) == 0)
+ master_user = *args + 7;
else if (strncmp(*args, "user=", 5) == 0) {
/* already handled in login-common */
} else if (auth_debug) {
proxy host=.. [port=..] [destuser=..] pass=.. */
if (!success)
return FALSE;
- if (pop3_proxy_new(client, host, port, destuser, pass) < 0)
+ if (pop3_proxy_new(client, host, port, destuser, master_user,
+ pass) < 0)
client_destroy_internal_failure(client);
return TRUE;
}
struct timeout *to_idle_disconnect;
struct login_proxy *proxy;
- char *proxy_user, *proxy_password;
+ char *proxy_user, *proxy_master_user, *proxy_password;
int proxy_state;
unsigned int bad_counter;
#include "client.h"
#include "pop3-proxy.h"
+static void get_plain_auth(struct pop3_client *client, string_t *dest)
+{
+ string_t *str;
+
+ str = t_str_new(128);
+ str_append(str, client->proxy_user);
+ str_append_c(str, '\0');
+ str_append(str, client->proxy_master_user);
+ str_append_c(str, '\0');
+ str_append(str, client->proxy_password);
+ base64_encode(str_data(str), str_len(str), dest);
+}
+
static void proxy_input(struct istream *input, struct ostream *output,
struct pop3_client *client)
{
return;
}
- /* send USER command */
str = t_str_new(128);
- str_append(str, "USER ");
- str_append(str, client->proxy_user);
- str_append(str, "\r\n");
+ if (client->proxy_master_user == NULL) {
+ /* send USER command */
+ str_append(str, "USER ");
+ str_append(str, client->proxy_user);
+ str_append(str, "\r\n");
+ } else {
+ /* master user login - use AUTH PLAIN. */
+ str_append(str, "AUTH PLAIN\r\n");
+ }
(void)o_stream_send(output, str_data(str), str_len(str));
client->proxy_state++;
return;
case 1:
- if (strncmp(line, "+OK", 3) != 0)
- break;
-
- /* USER successful, send PASS */
str = t_str_new(128);
- str_append(str, "PASS ");
- str_append(str, client->proxy_password);
- str_append(str, "\r\n");
+ if (client->proxy_master_user == NULL) {
+ if (strncmp(line, "+OK", 3) != 0)
+ break;
+
+ /* USER successful, send PASS */
+ str_append(str, "PASS ");
+ str_append(str, client->proxy_password);
+ str_append(str, "\r\n");
+ } else {
+ if (*line != '+')
+ break;
+ /* AUTH successful, send the authentication data */
+ get_plain_auth(client, str);
+ str_append(str, "\r\n");
+ }
(void)o_stream_send(output, str_data(str),
str_len(str));
safe_memset(client->proxy_password, 0,
strlen(client->proxy_password));
- i_free(client->proxy_password);
- client->proxy_password = NULL;
+ i_free_and_null(client->proxy_password);
client->proxy_state++;
return;
str_append_c(str, '/');
str_append(str, client->proxy_user);
}
+ if (client->proxy_master_user != NULL) {
+ str_printfa(str, " (master %s)",
+ client->proxy_master_user);
+ }
login_proxy_detach(client->proxy, client->common.input,
client->output);
str_append_c(str, '/');
str_append(str, client->proxy_user);
}
+ if (client->proxy_master_user != NULL) {
+ str_printfa(str, " (master %s)",
+ client->proxy_master_user);
+ }
str_append(str, ": ");
if (strncmp(line, "-ERR ", 5) == 0)
str_append(str, line + 5);
if (client->proxy_password != NULL) {
safe_memset(client->proxy_password, 0,
strlen(client->proxy_password));
- i_free(client->proxy_password);
- client->proxy_password = NULL;
+ i_free_and_null(client->proxy_password);
}
- i_free(client->proxy_user);
- client->proxy_user = NULL;
+ i_free_and_null(client->proxy_user);
+ i_free_and_null(client->proxy_master_user);
}
int pop3_proxy_new(struct pop3_client *client, const char *host,
- unsigned int port, const char *user, const char *password)
+ unsigned int port, const char *user, const char *master_user,
+ const char *password)
{
i_assert(user != NULL);
i_assert(!client->destroyed);
client->proxy_state = 0;
client->proxy_user = i_strdup(user);
+ client->proxy_master_user = i_strdup(master_user);
client->proxy_password = i_strdup(password);
/* disable input until authentication is finished */
#include "login-proxy.h"
int pop3_proxy_new(struct pop3_client *client, const char *host,
- unsigned int port, const char *user, const char *password);
+ unsigned int port, const char *user, const char *master_user,
+ const char *password);
#endif