dovecot-1.2: imap-proxy: Send backend's CAPABILITY if it's diffe...
dovecot at dovecot.org
dovecot at dovecot.org
Wed Apr 22 20:54:59 EEST 2009
details: http://hg.dovecot.org/dovecot-1.2/rev/f8404c0f14de
changeset: 8979:f8404c0f14de
user: Timo Sirainen <tss at iki.fi>
date: Wed Apr 22 13:54:54 2009 -0400
description:
imap-proxy: Send backend's CAPABILITY if it's different from what was sent to client before.
diffstat:
3 files changed, 89 insertions(+), 20 deletions(-)
src/imap-login/client.c | 2
src/imap-login/client.h | 2
src/imap-login/imap-proxy.c | 105 ++++++++++++++++++++++++++++++++++---------
diffs (218 lines):
diff -r 2e3baa171e20 -r f8404c0f14de src/imap-login/client.c
--- a/src/imap-login/client.c Wed Apr 22 12:28:22 2009 -0400
+++ b/src/imap-login/client.c Wed Apr 22 13:54:54 2009 -0400
@@ -105,6 +105,7 @@ static const char *get_capability(struct
static int cmd_capability(struct imap_client *client)
{
+ client->capability_command_used = TRUE;
client_send_line(client, t_strconcat(
"* CAPABILITY ", get_capability(client, TRUE), NULL));
client_send_tagline(client, "OK Capability completed.");
@@ -588,6 +589,7 @@ void client_destroy(struct imap_client *
i_free_and_null(client->proxy_user);
i_free_and_null(client->proxy_master_user);
+ i_free_and_null(client->proxy_backend_capability);
if (client->proxy != NULL)
login_proxy_free(&client->proxy);
diff -r 2e3baa171e20 -r f8404c0f14de src/imap-login/client.h
--- a/src/imap-login/client.h Wed Apr 22 12:28:22 2009 -0400
+++ b/src/imap-login/client.h Wed Apr 22 13:54:54 2009 -0400
@@ -22,6 +22,7 @@ struct imap_client {
struct login_proxy *proxy;
char *proxy_user, *proxy_master_user, *proxy_password;
+ char *proxy_backend_capability;
unsigned int bad_counter;
@@ -36,6 +37,7 @@ struct imap_client {
unsigned int greeting_sent:1;
unsigned int id_logged:1;
unsigned int auth_initializing:1;
+ unsigned int capability_command_used:1;
};
void client_destroy(struct imap_client *client, const char *reason);
diff -r 2e3baa171e20 -r f8404c0f14de src/imap-login/imap-proxy.c
--- a/src/imap-login/imap-proxy.c Wed Apr 22 12:28:22 2009 -0400
+++ b/src/imap-login/imap-proxy.c Wed Apr 22 13:54:54 2009 -0400
@@ -1,6 +1,7 @@
/* Copyright (c) 2004-2009 Dovecot authors, see the included COPYING file */
#include "common.h"
+#include "array.h"
#include "ioloop.h"
#include "istream.h"
#include "ostream.h"
@@ -14,26 +15,35 @@
#include "imap-quote.h"
#include "imap-proxy.h"
+#include <stdlib.h>
+
#define PROXY_FAILURE_MSG \
"NO ["IMAP_RESP_CODE_UNAVAILABLE"] "AUTH_TEMP_FAILED_MSG
-static bool imap_banner_has_capability(const char *line, const char *capability)
-{
- unsigned int capability_len = strlen(capability);
-
- while (strncasecmp(line, capability, capability_len) != 0 ||
- (line[capability_len] != ' ' &&
- line[capability_len] != '\0' &&
- line[capability_len] != ']')) {
- /* skip over the capability */
- while (*line != ' ') {
- if (*line == '\0')
- return FALSE;
- line++;
- }
- line++;
- }
- return TRUE;
+static const char *const *
+capabilities_strip_prelogin(const char *const *capabilities)
+{
+ ARRAY_TYPE(const_string) new_caps_arr;
+ const char **new_caps, *str;
+ unsigned int count;
+
+ t_array_init(&new_caps_arr, 64);
+ for (; *capabilities != NULL; capabilities++) {
+ if (strncasecmp(*capabilities, "AUTH=", 5) == 0 ||
+ strcasecmp(*capabilities, "STARTTLS") == 0 ||
+ strcasecmp(*capabilities, "SASL-IR") == 0 ||
+ strcasecmp(*capabilities, "LOGINDISABLED") == 0 ||
+ strcasecmp(*capabilities, "LOGIN-REFERRALS") == 0)
+ continue;
+
+ str = *capabilities;
+ array_append(&new_caps_arr, &str, 1);
+ }
+ new_caps = array_get_modifiable(&new_caps_arr, &count);
+ qsort(new_caps, count, sizeof(*new_caps), i_strcasecmp_p);
+
+ (void)array_append_space(&new_caps_arr);
+ return array_idx(&new_caps_arr, 0);
}
static void proxy_write_id(struct imap_client *client, string_t *str)
@@ -85,9 +95,51 @@ static void get_plain_auth(struct imap_c
base64_encode(str_data(str), str_len(str), dest);
}
+static bool str_array_icmp(const char *const *arr1, const char *const *arr2)
+{
+ unsigned int i;
+
+ for (i = 0; arr1[i] != NULL; i++) {
+ if (arr2[i] == NULL || strcasecmp(arr1[i], arr2[i]) != 0)
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static void
+client_send_capability_if_needed(struct imap_client *client, string_t *str,
+ const char *capability)
+{
+ const char *const *backend_capabilities;
+ const char *const *proxy_capabilities;
+
+ if (!client->capability_command_used || capability == NULL)
+ return;
+
+ /* reset this so that we don't re-send the CAPABILITY in case server
+ sends it multiple times */
+ client->capability_command_used = FALSE;
+
+ /* client has used CAPABILITY command, so it didn't understand the
+ capabilities in the banner. if backend server has different
+ capabilities than we advertised already, there's a problem.
+ to solve that we'll send the backend's untagged CAPABILITY reply
+ and hope that the client understands it */
+ backend_capabilities =
+ capabilities_strip_prelogin(t_strsplit(capability, " "));
+ proxy_capabilities =
+ capabilities_strip_prelogin(t_strsplit(capability_string, " "));
+
+ if (str_array_icmp(backend_capabilities, proxy_capabilities))
+ return;
+
+ str_printfa(str, "* CAPABILITY %s\r\n", capability);
+}
+
static int proxy_input_banner(struct imap_client *client,
struct ostream *output, const char *line)
{
+ const char *const *capabilities = NULL;
string_t *str;
if (strncmp(line, "* OK ", 5) != 0) {
@@ -99,9 +151,12 @@ static int proxy_input_banner(struct ima
str = t_str_new(128);
if (strncmp(line + 5, "[CAPABILITY ", 12) == 0) {
- if (imap_banner_has_capability(line + 5 + 12, "ID"))
+ capabilities = t_strsplit(t_strcut(line + 5 + 12, ']'), " ");
+ if (str_array_icase_find(capabilities, "ID"))
proxy_write_id(client, str);
}
+ if (client->capability_command_used)
+ str_append(str, "C CAPABILITY\r\n");
if (client->proxy_master_user == NULL) {
/* logging in normally - use LOGIN command */
@@ -111,7 +166,8 @@ static int proxy_input_banner(struct ima
imap_quote_append_string(str, client->proxy_password, FALSE);
proxy_free_password(client);
- } else if (imap_banner_has_capability(line + 5, "SASL-IR")) {
+ } else if (capabilities != NULL &&
+ str_array_icase_find(capabilities, "SASL-IR")) {
/* master user login with SASL initial response support */
str_append(str, "L AUTHENTICATE PLAIN ");
get_plain_auth(client, str);
@@ -120,7 +176,6 @@ static int proxy_input_banner(struct ima
/* 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;
@@ -130,6 +185,7 @@ static int proxy_input_line(struct imap_
static int proxy_input_line(struct imap_client *client,
struct ostream *output, const char *line)
{
+ const char *capability;
string_t *str;
i_assert(!client->destroyed);
@@ -152,7 +208,12 @@ static int proxy_input_line(struct imap_
return 0;
} else if (strncmp(line, "L OK ", 5) == 0) {
/* Login successful. Send this line to client. */
+ capability = client->proxy_backend_capability;
+ if (strncmp(line + 5, "[CAPABILITY ", 12) == 0)
+ capability = t_strcut(line + 5 + 12, ']');
+
str = t_str_new(128);
+ client_send_capability_if_needed(client, str, capability);
str_append(str, client->cmd_tag);
str_append(str, line + 1);
str_append(str, "\r\n");
@@ -235,6 +296,10 @@ static int proxy_input_line(struct imap_
proxy_failed(client, FALSE);
return -1;
+ } else if (strncasecmp(line, "* CAPABILITY ", 13) == 0) {
+ i_free(client->proxy_backend_capability);
+ client->proxy_backend_capability = i_strdup(line + 13);
+ return 0;
} else {
/* probably some untagged reply */
return 0;
More information about the dovecot-cvs
mailing list