-I$(top_srcdir)/src/lib \
-I$(top_srcdir)/src/lib-settings \
-I$(top_srcdir)/src/lib-auth \
+ -I$(top_srcdir)/src/lib-sasl \
-I$(top_srcdir)/src/lib-imap \
-I$(top_srcdir)/src/lib-master \
-I$(top_srcdir)/src/login-common
unsigned int cmd_finished:1;
unsigned int proxy_sasl_ir:1;
unsigned int proxy_seen_banner:1;
- unsigned int proxy_wait_auth_continue:1;
unsigned int skip_line:1;
unsigned int id_logged:1;
unsigned int client_ignores_capability_resp_code:1;
#include "str.h"
#include "str-sanitize.h"
#include "safe-memset.h"
+#include "sasl-client.h"
#include "client.h"
#include "client-authenticate.h"
#include "imap-resp-code.h"
i_free_and_null(client->proxy_password);
}
-static void get_plain_auth(struct client *client, string_t *dest)
+static int proxy_write_login(struct imap_client *client, string_t *str)
{
- 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);
-}
+ struct sasl_client_settings sasl_set;
+ const unsigned char *output;
+ unsigned int len;
+ const char *mech_name, *error;
-static void proxy_write_login(struct imap_client *client, string_t *str)
-{
str_append(str, "C CAPABILITY\r\n");
- if (client->common.proxy_master_user == NULL) {
+ if (client->common.proxy_mech == NULL) {
/* logging in normally - use LOGIN command */
str_append(str, "L LOGIN ");
imap_append_string(str, client->common.proxy_user);
str_append_c(str, ' ');
imap_append_string(str, client->common.proxy_password);
+ str_append(str, "\r\n");
proxy_free_password(&client->common);
- } else if (client->proxy_sasl_ir) {
- /* master user login with SASL initial response support */
- str_append(str, "L AUTHENTICATE PLAIN ");
- get_plain_auth(&client->common, str);
- proxy_free_password(&client->common);
- } else {
- /* master user login without SASL initial response */
- str_append(str, "L AUTHENTICATE PLAIN");
- client->proxy_wait_auth_continue = TRUE;
+ return 0;
+ }
+
+ i_assert(client->common.proxy_sasl_client == NULL);
+ memset(&sasl_set, 0, sizeof(sasl_set));
+ sasl_set.authid = client->common.proxy_user;
+ sasl_set.authzid = client->common.proxy_master_user;
+ sasl_set.password = client->common.proxy_password;
+ client->common.proxy_sasl_client =
+ sasl_client_new(client->common.proxy_mech, &sasl_set);
+ mech_name = sasl_client_mech_get_name(client->common.proxy_mech);
+
+ str_append(str, "L AUTHENTICATE ");
+ str_append(str, mech_name);
+ if (client->proxy_sasl_ir) {
+ if (sasl_client_output(client->common.proxy_sasl_client,
+ &output, &len, &error) < 0) {
+ client_log_err(&client->common, t_strdup_printf(
+ "proxy: SASL mechanism %s init failed: %s",
+ mech_name, error));
+ return -1;
+ }
+ str_append_c(str, ' ');
+ if (len == 0)
+ str_append_c(str, '=');
+ else
+ base64_encode(output, len, str);
}
str_append(str, "\r\n");
+ proxy_free_password(&client->common);
+ return 0;
}
static int proxy_input_banner(struct imap_client *client,
}
str_append(str, "S STARTTLS\r\n");
} else {
- proxy_write_login(client, str);
+ if (proxy_write_login(client, str) < 0)
+ return -1;
}
o_stream_nsend(output, str_data(str), str_len(str));
struct imap_client *imap_client = (struct imap_client *)client;
struct ostream *output;
string_t *str;
+ const unsigned char *data;
+ unsigned int data_len;
+ const char *error;
+ int ret;
i_assert(!client->destroyed);
return 0;
} else if (*line == '+') {
/* AUTHENTICATE started. finish it. */
- if (!imap_client->proxy_wait_auth_continue) {
+ if (client->proxy_sasl_client == NULL) {
/* used literals with LOGIN command, just ignore. */
return 0;
}
client->proxy_state = IMAP_PROXY_STATE_AUTH_CONTINUE;
- imap_client->proxy_wait_auth_continue = FALSE;
str = t_str_new(128);
- get_plain_auth(client, str);
+ if (line[1] != ' ' ||
+ base64_decode(line+2, strlen(line+2), NULL, str) < 0) {
+ client_log_err(client,
+ "proxy: Server sent invalid base64 data in AUTHENTICATE response");
+ client_proxy_failed(client, TRUE);
+ return -1;
+ }
+ ret = sasl_client_input(client->proxy_sasl_client,
+ str_data(str), str_len(str), &error);
+ if (ret == 0) {
+ ret = sasl_client_output(client->proxy_sasl_client,
+ &data, &data_len, &error);
+ }
+ if (ret < 0) {
+ client_log_err(client, t_strdup_printf(
+ "proxy: Server sent invalid authentication data: %s",
+ error));
+ client_proxy_failed(client, TRUE);
+ return -1;
+ }
+
+ str_truncate(str, 0);
+ base64_encode(data, data_len, str);
str_append(str, "\r\n");
- proxy_free_password(client);
o_stream_nsend(output, str_data(str), str_len(str));
return 0;
/* i/ostreams changed. */
output = login_proxy_get_ostream(client->login_proxy);
str = t_str_new(128);
- proxy_write_login(imap_client, str);
+ if (proxy_write_login(imap_client, str) < 0) {
+ client_proxy_failed(client, TRUE);
+ return -1;
+ }
o_stream_nsend(output, str_data(str), str_len(str));
return 1;
} else if (strncmp(line, "L OK ", 5) == 0) {
imap_client->proxy_sasl_ir = FALSE;
imap_client->proxy_seen_banner = FALSE;
- imap_client->proxy_wait_auth_continue = FALSE;
client->proxy_state = IMAP_PROXY_STATE_NONE;
}
-I$(top_srcdir)/src/lib \
-I$(top_srcdir)/src/lib-settings \
-I$(top_srcdir)/src/lib-auth \
+ -I$(top_srcdir)/src/lib-sasl \
-I$(top_srcdir)/src/lib-master \
-I$(top_srcdir)/src/lib-ssl-iostream \
-I$(top_srcdir)/src/lib-mail \
#include "time-util.h"
#include "login-proxy.h"
#include "auth-client.h"
+#include "sasl-client.h"
#include "master-service-ssl-settings.h"
#include "client-common.h"
reply_r->proxy_timeout_msecs = 1000*atoi(value);
else if (strcmp(key, "proxy_refresh") == 0)
reply_r->proxy_refresh_secs = atoi(value);
+ else if (strcmp(key, "proxy_mech") == 0)
+ reply_r->proxy_mech = value;
else if (strcmp(key, "master") == 0)
reply_r->master_user = value;
else if (strcmp(key, "ssl") == 0) {
client_proxy_error(client, PROXY_FAILURE_MSG);
}
+ if (client->proxy_sasl_client != NULL)
+ sasl_client_free(&client->proxy_sasl_client);
login_proxy_free(&client->login_proxy);
proxy_free_password(client);
i_free_and_null(client->proxy_user);
const struct client_auth_reply *reply)
{
struct login_proxy_settings proxy_set;
+ const struct sasl_client_mech *sasl_mech = NULL;
i_assert(reply->destuser != NULL);
i_assert(!client->destroyed);
+ i_assert(client->proxy_sasl_client == NULL);
+ client->proxy_mech = NULL;
client->v.proxy_reset(client);
if (reply->password == NULL) {
return -1;
}
+ if (reply->proxy_mech != NULL) {
+ sasl_mech = sasl_client_mech_find(reply->proxy_mech);
+ if (sasl_mech == NULL) {
+ client_log_err(client, t_strdup_printf(
+ "proxy: Unsupported SASL mechanism %s",
+ reply->proxy_mech));
+ client_proxy_error(client, PROXY_FAILURE_MSG);
+ return -1;
+ }
+ } else if (reply->master_user != NULL) {
+ /* have to use PLAIN authentication with master user logins */
+ sasl_mech = &sasl_client_mech_plain;
+ }
+
i_assert(client->refcount > 1);
if (client->destroyed) {
return -1;
}
+ client->proxy_mech = sasl_mech;
client->proxy_user = i_strdup(reply->destuser);
client->proxy_master_user = i_strdup(reply->master_user);
client->proxy_password = i_strdup(reply->password);
#include "master-service-ssl-settings.h"
#include "master-auth.h"
#include "auth-client.h"
+#include "sasl-client.h"
#include "login-proxy.h"
#include "ssl-proxy.h"
#include "client-common.h"
i_free_and_null(client->proxy_password);
}
+ if (client->proxy_sasl_client != NULL)
+ sasl_client_free(&client->proxy_sasl_client);
if (client->login_proxy != NULL)
login_proxy_free(&client->login_proxy);
if (client->v.destroy != NULL)
struct client_auth_reply {
const char *master_user, *reason;
/* for proxying */
- const char *host, *hostip, *destuser, *password;
+ const char *host, *hostip, *destuser, *password, *proxy_mech;
unsigned int port;
unsigned int proxy_timeout_msecs;
unsigned int proxy_refresh_secs;
struct login_proxy *login_proxy;
char *proxy_user, *proxy_master_user, *proxy_password;
+ const struct sasl_client_mech *proxy_mech;
+ struct sasl_client *proxy_sasl_client;
unsigned int proxy_state;
unsigned int proxy_ttl;
#include "access-lookup.h"
#include "anvil-client.h"
#include "auth-client.h"
+#include "sasl-client.h"
#include "master-service-ssl-settings.h"
#include "ssl-proxy.h"
#include "login-proxy.h"
/* Initialize SSL proxy so it can read certificate and private
key file. */
ssl_proxy_init();
+ sasl_clients_init();
/* set the number of fds we want to use. it may get increased or
decreased. leave a couple of extra fds for auth sockets and such.
anvil_client_deinit(&anvil);
if (auth_client_to != NULL)
timeout_remove(&auth_client_to);
+ sasl_clients_deinit();
login_settings_deinit();
}
-I$(top_srcdir)/src/lib \
-I$(top_srcdir)/src/lib-settings \
-I$(top_srcdir)/src/lib-auth \
+ -I$(top_srcdir)/src/lib-sasl \
-I$(top_srcdir)/src/lib-master \
-I$(top_srcdir)/src/login-common
#include "safe-memset.h"
#include "str.h"
#include "str-sanitize.h"
+#include "sasl-client.h"
#include "client.h"
#include "pop3-proxy.h"
i_free_and_null(client->proxy_password);
}
-static void get_plain_auth(struct 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_send_login(struct pop3_client *client, struct ostream *output)
+static int proxy_send_login(struct pop3_client *client, struct ostream *output)
{
+ struct sasl_client_settings sasl_set;
+ const unsigned char *sasl_output;
+ unsigned int len;
+ const char *mech_name, *error;
string_t *str;
i_assert(client->common.proxy_ttl > 1);
}
str = t_str_new(128);
- if (client->common.proxy_master_user == NULL) {
+ if (client->common.proxy_mech == NULL) {
/* send USER command */
str_append(str, "USER ");
str_append(str, client->common.proxy_user);
str_append(str, "\r\n");
- } else {
- /* master user login - use AUTH PLAIN. */
- str_append(str, "AUTH PLAIN\r\n");
+ o_stream_nsend(output, str_data(str), str_len(str));
+ return 0;
}
+
+ i_assert(client->common.proxy_sasl_client == NULL);
+ memset(&sasl_set, 0, sizeof(sasl_set));
+ sasl_set.authid = client->common.proxy_user;
+ sasl_set.authzid = client->common.proxy_master_user;
+ sasl_set.password = client->common.proxy_password;
+ client->common.proxy_sasl_client =
+ sasl_client_new(client->common.proxy_mech, &sasl_set);
+ mech_name = sasl_client_mech_get_name(client->common.proxy_mech);
+
+ str_printfa(str, "AUTH %s ", mech_name);
+ if (sasl_client_output(client->common.proxy_sasl_client,
+ &sasl_output, &len, &error) < 0) {
+ client_log_err(&client->common, t_strdup_printf(
+ "proxy: SASL mechanism %s init failed: %s",
+ mech_name, error));
+ return -1;
+ }
+ if (len == 0)
+ str_append_c(str, '=');
+ else
+ base64_encode(sasl_output, len, str);
+ str_append(str, "\r\n");
o_stream_nsend(output, str_data(str), str_len(str));
+
+ proxy_free_password(&client->common);
+ if (client->common.proxy_state != POP3_PROXY_XCLIENT)
+ client->common.proxy_state = POP3_PROXY_LOGIN2;
+ return 0;
+}
+
+static int
+pop3_proxy_continue_sasl_auth(struct client *client, struct ostream *output,
+ const char *line)
+{
+ string_t *str;
+ const unsigned char *data;
+ unsigned int data_len;
+ const char *error;
+ int ret;
+
+ str = t_str_new(128);
+ if (base64_decode(line, strlen(line), NULL, str) < 0) {
+ client_log_err(client, "proxy: Server sent invalid base64 data in AUTH response");
+ return -1;
+ }
+ ret = sasl_client_input(client->proxy_sasl_client,
+ str_data(str), str_len(str), &error);
+ if (ret == 0) {
+ ret = sasl_client_output(client->proxy_sasl_client,
+ &data, &data_len, &error);
+ }
+ if (ret < 0) {
+ client_log_err(client, t_strdup_printf(
+ "proxy: Server sent invalid authentication data: %s",
+ error));
+ return -1;
+ }
+
+ str_truncate(str, 0);
+ base64_encode(data, data_len, str);
+ str_append(str, "\r\n");
+
+ o_stream_nsend(output, str_data(str), str_len(str));
+ return 0;
}
int pop3_proxy_parse_line(struct client *client, const char *line)
struct pop3_client *pop3_client = (struct pop3_client *)client;
struct ostream *output;
enum login_proxy_ssl_flags ssl_flags;
- string_t *str;
i_assert(!client->destroyed);
ssl_flags = login_proxy_get_ssl_flags(client->login_proxy);
if ((ssl_flags & PROXY_SSL_FLAG_STARTTLS) == 0) {
- proxy_send_login(pop3_client, output);
+ if (proxy_send_login(pop3_client, output) < 0) {
+ client_proxy_failed(client, TRUE);
+ return -1;
+ }
} else {
o_stream_nsend_str(output, "STLS\r\n");
client->proxy_state = POP3_PROXY_STARTTLS;
}
/* i/ostreams changed. */
output = login_proxy_get_ostream(client->login_proxy);
- proxy_send_login(pop3_client, output);
+ if (proxy_send_login(pop3_client, output) < 0) {
+ client_proxy_failed(client, TRUE);
+ return -1;
+ }
return 1;
case POP3_PROXY_XCLIENT:
if (strncmp(line, "+OK", 3) != 0) {
client_proxy_failed(client, TRUE);
return -1;
}
- client->proxy_state = POP3_PROXY_LOGIN1;
+ client->proxy_state = client->proxy_sasl_client == NULL ?
+ POP3_PROXY_LOGIN1 : POP3_PROXY_LOGIN2;
return 0;
case POP3_PROXY_LOGIN1:
- str = t_str_new(128);
- 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");
- }
- o_stream_nsend(output, str_data(str), str_len(str));
+ i_assert(client->proxy_sasl_client == NULL);
+ if (strncmp(line, "+OK", 3) != 0)
+ break;
+
+ /* USER successful, send PASS */
+ o_stream_nsend_str(output, t_strdup_printf(
+ "PASS %s\r\n", client->proxy_password));
proxy_free_password(client);
client->proxy_state = POP3_PROXY_LOGIN2;
return 0;
case POP3_PROXY_LOGIN2:
+ if (strncmp(line, "+ ", 2) == 0 &&
+ client->proxy_sasl_client != NULL) {
+ /* continue SASL authentication */
+ if (pop3_proxy_continue_sasl_auth(client, output,
+ line+2) < 0) {
+ client_proxy_failed(client, TRUE);
+ return -1;
+ }
+ return 0;
+ }
if (strncmp(line, "+OK", 3) != 0)
break;