]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
imap-login now advertises only pre-login capabilities.
authorTimo Sirainen <tss@iki.fi>
Thu, 28 May 2009 16:57:15 +0000 (12:57 -0400)
committerTimo Sirainen <tss@iki.fi>
Thu, 28 May 2009 16:57:15 +0000 (12:57 -0400)
If client had used CAPABILITY command before logging in, untagged CAPABILITY
is sent to client in the hope that client understands this. This change
could get reverted if it breaks too many clients.

--HG--
branch : HEAD

src/imap-login/client-authenticate.c
src/imap-login/client.c
src/imap-login/imap-proxy.c
src/imap/main.c
src/login-common/client-common.h
src/login-common/login-settings.c
src/login-common/login-settings.h
src/login-common/sasl-server.c

index 63f32e7204be9edaab93810906a5ae92b04a59ab..0dafd36eff1fc16de8a51590030b0562cdc07916 100644 (file)
@@ -94,7 +94,7 @@ void client_auth_failed(struct imap_client *client, bool nodelay)
 {
        unsigned int delay_msecs;
 
-       client->common.auth_command_tag = NULL;
+       i_free_and_null(client->common.master_data_prefix);
 
        if (client->auth_initializing)
                return;
@@ -325,7 +325,14 @@ static void sasl_callback(struct client *_client, enum sasl_server_reply reply,
 static int client_auth_begin(struct imap_client *client, const char *mech_name,
                             const char *init_resp)
 {
-       client->common.auth_command_tag = client->cmd_tag;
+       char *prefix;
+
+       prefix = i_strdup_printf("%d%s", client->capability_command_used,
+                                client->cmd_tag);
+
+       i_free(client->common.master_data_prefix);
+       client->common.master_data_prefix = (void *)prefix;
+       client->common.master_data_prefix_len = strlen(prefix)+1;
 
        client_ref(client);
        client->auth_initializing = TRUE;
index 247057b0a78517069d0f87a29c453aad7bedfb41..63d5ef04ab29a3c52802fe3d4d44e145f966fce1 100644 (file)
@@ -96,13 +96,12 @@ bool client_skip_line(struct imap_client *client)
        return FALSE;
 }
 
-static const char *get_capability(struct imap_client *client, bool full)
+static const char *get_capability(struct imap_client *client)
 {
        const char *auths;
 
        auths = client_authenticate_get_capabilities(client);
-       return t_strconcat(full ? client->common.set->capability_string :
-                          CAPABILITY_BANNER_STRING,
+       return t_strconcat(CAPABILITY_BANNER_STRING,
                           (ssl_initialized && !client->common.tls) ?
                           " STARTTLS" : "",
                           client->common.set->disable_plaintext_auth &&
@@ -114,7 +113,7 @@ 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));
+               "* CAPABILITY ", get_capability(client), NULL));
        client_send_tagline(client, "OK Capability completed.");
        return 1;
 }
@@ -474,7 +473,7 @@ static void client_send_greeting(struct imap_client *client)
 
        greet = t_str_new(128);
        str_append(greet, "* OK ");
-       str_printfa(greet, "[CAPABILITY %s] ", get_capability(client, FALSE));
+       str_printfa(greet, "[CAPABILITY %s] ", get_capability(client));
        str_append(greet, client->common.set->login_greeting);
 
        client_send_line(client, str_c(greet));
index a0c5d9dbde8a25e398c6e57461e07061d1e77d66..79095f731221e639fb22485fa06633e8acbddae9 100644 (file)
 #define PROXY_FAILURE_MSG \
        "NO ["IMAP_RESP_CODE_UNAVAILABLE"] "AUTH_TEMP_FAILED_MSG
 
-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)
 {
        str_printfa(str, "I ID ("
@@ -95,24 +69,10 @@ static void get_plain_auth(struct imap_client *client, string_t *dest)
        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;
 
@@ -121,18 +81,8 @@ client_send_capability_if_needed(struct imap_client *client, string_t *str,
        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(client->common.set->capability_string, " "));
-
-       if (str_array_icmp(backend_capabilities, proxy_capabilities))
-               return;
-
+          capabilities in the banner. send the backend's untagged CAPABILITY
+          reply and hope that the client understands it */
        str_printfa(str, "* CAPABILITY %s\r\n", capability);
 }
 
index ce14875c7a33100095d82129d1e5c2f8c20eacf5..4edbabebcdfe060cd334b2e6f8d38e9a2895a491 100644 (file)
@@ -75,10 +75,20 @@ static void client_add_input(struct client *client, const char *input)
        buffer_t *buf;
        const char *tag;
        unsigned int data_pos;
+       bool send_untagged_capability = FALSE;
 
        buf = input == NULL ? NULL : t_base64_decode_str(input);
        if (buf != NULL && buf->used > 0) {
                tag = t_strndup(buf->data, buf->used);
+               switch (*tag) {
+               case '0':
+                       tag++;
+                       break;
+               case '1':
+                       send_untagged_capability = TRUE;
+                       tag++;
+                       break;
+               }
                data_pos = strlen(tag) + 1;
                if (data_pos > buf->used &&
                    !i_stream_add_data(client->input,
@@ -95,6 +105,12 @@ static void client_add_input(struct client *client, const char *input)
                        "* PREAUTH [CAPABILITY ",
                        str_c(client->capability_string), "] "
                        "Logged in as ", client->user->username, NULL));
+       } else if (send_untagged_capability) {
+               /* client doesn't seem to understand tagged capabilities. send
+                  untagged instead and hope that it works. */
+               client_send_line(client, t_strconcat("* CAPABILITY ",
+                       str_c(client->capability_string), NULL));
+               client_send_line(client, t_strconcat(tag, " Logged in", NULL));
        } else {
                client_send_line(client, t_strconcat(
                        tag, " OK [CAPABILITY ",
index 4216ad89e24e23ee26b579dd8960dc97d61cc456..9c744106721ad1b885882f4db98ca0f463efc0b9 100644 (file)
@@ -24,7 +24,8 @@ struct client {
 
        int fd;
        struct istream *input;
-       const char *auth_command_tag;
+       unsigned char *master_data_prefix;
+       unsigned int master_data_prefix_len;
 
        char *auth_mech_name;
        struct auth_request *auth_request;
index 4547e56ed637b2d10b813c3510d389538b5efd52..d24029d440ba245492416758904aaf2ce860ef4c 100644 (file)
@@ -22,7 +22,6 @@ static struct setting_define login_setting_defines[] = {
        DEF(SET_STR, login_log_format),
 
        DEF(SET_BOOL, login_process_per_connection),
-       DEF(SET_STR, capability_string),
 
        DEF(SET_ENUM, ssl),
        DEF(SET_STR, ssl_ca_file),
@@ -56,7 +55,6 @@ static struct login_settings login_default_settings = {
        MEMBER(login_log_format) "%$: %s",
 
        MEMBER(login_process_per_connection) TRUE,
-       MEMBER(capability_string) NULL,
 
        MEMBER(ssl) "yes:no:required",
        MEMBER(ssl_ca_file) "",
index bb8ca59300f53cc6a3bff6bfdd8a74a587cb095b..634adc200bdb6334010443d4a49310dfed92f962 100644 (file)
@@ -10,7 +10,6 @@ struct login_settings {
        const char *login_log_format_elements, *login_log_format;
 
        bool login_process_per_connection;
-       const char *capability_string;
 
        const char *ssl;
        const char *ssl_ca_file;
index 4932b663e47fd9973c695582c1a3992c662c18e2..bed8f46ad1b69dc0efa0030404f9929fff53f7a7 100644 (file)
@@ -84,10 +84,8 @@ master_send_request(struct client *client, struct auth_request *request)
        req.remote_ip = client->ip;
 
        buf = buffer_create_dynamic(pool_datastack_create(), 256);
-       if (client->auth_command_tag != NULL) {
-               buffer_append(buf, client->auth_command_tag,
-                             strlen(client->auth_command_tag)+1);
-       }
+       buffer_append(buf, client->master_data_prefix,
+                     client->master_data_prefix_len);
 
        data = i_stream_get_data(client->input, &size);
        buffer_append(buf, data, size);