From: Timo Sirainen Date: Thu, 28 May 2009 16:57:15 +0000 (-0400) Subject: imap-login now advertises only pre-login capabilities. X-Git-Tag: 2.0.alpha1~650 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=bbba7d0fce1b6ce5baa2d7ef946eb1b63e2ab518;p=thirdparty%2Fdovecot%2Fcore.git imap-login now advertises only pre-login capabilities. 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 --- diff --git a/src/imap-login/client-authenticate.c b/src/imap-login/client-authenticate.c index 63f32e7204..0dafd36eff 100644 --- a/src/imap-login/client-authenticate.c +++ b/src/imap-login/client-authenticate.c @@ -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; diff --git a/src/imap-login/client.c b/src/imap-login/client.c index 247057b0a7..63d5ef04ab 100644 --- a/src/imap-login/client.c +++ b/src/imap-login/client.c @@ -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)); diff --git a/src/imap-login/imap-proxy.c b/src/imap-login/imap-proxy.c index a0c5d9dbde..79095f7312 100644 --- a/src/imap-login/imap-proxy.c +++ b/src/imap-login/imap-proxy.c @@ -20,32 +20,6 @@ #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); } diff --git a/src/imap/main.c b/src/imap/main.c index ce14875c7a..4edbabebcd 100644 --- a/src/imap/main.c +++ b/src/imap/main.c @@ -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 ", diff --git a/src/login-common/client-common.h b/src/login-common/client-common.h index 4216ad89e2..9c74410672 100644 --- a/src/login-common/client-common.h +++ b/src/login-common/client-common.h @@ -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; diff --git a/src/login-common/login-settings.c b/src/login-common/login-settings.c index 4547e56ed6..d24029d440 100644 --- a/src/login-common/login-settings.c +++ b/src/login-common/login-settings.c @@ -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) "", diff --git a/src/login-common/login-settings.h b/src/login-common/login-settings.h index bb8ca59300..634adc200b 100644 --- a/src/login-common/login-settings.h +++ b/src/login-common/login-settings.h @@ -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; diff --git a/src/login-common/sasl-server.c b/src/login-common/sasl-server.c index 4932b663e4..bed8f46ad1 100644 --- a/src/login-common/sasl-server.c +++ b/src/login-common/sasl-server.c @@ -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);