From 04eb0abcf8f8b0c014499b5c5bae89484553613f Mon Sep 17 00:00:00 2001 From: Stephan Bosch Date: Wed, 2 Nov 2016 01:31:40 +0100 Subject: [PATCH] login-common: Added result codes for mechanism-related failures. --- src/imap-login/client-authenticate.c | 2 ++ src/lib-auth/auth-client-interface.h | 4 ++++ src/login-common/client-common-auth.c | 25 ++++++++++++++++++++---- src/login-common/client-common.c | 9 +++++---- src/login-common/client-common.h | 6 ++++-- src/login-common/sasl-server.c | 28 ++++++++++++++++++--------- src/login-common/sasl-server.h | 3 ++- src/pop3-login/client-authenticate.c | 2 ++ 8 files changed, 59 insertions(+), 20 deletions(-) diff --git a/src/imap-login/client-authenticate.c b/src/imap-login/client-authenticate.c index 8dc689aae8..add783ac6a 100644 --- a/src/imap-login/client-authenticate.c +++ b/src/imap-login/client-authenticate.c @@ -78,6 +78,7 @@ void imap_client_auth_result(struct client *client, client_send_reply(client, IMAP_CMD_REPLY_BAD, text); break; case CLIENT_AUTH_RESULT_AUTHFAILED_REASON: + case CLIENT_AUTH_RESULT_MECH_INVALID: if (text[0] == '[') client_send_reply(client, IMAP_CMD_REPLY_NO, text); else { @@ -94,6 +95,7 @@ void imap_client_auth_result(struct client *client, IMAP_RESP_CODE_UNAVAILABLE, text); break; case CLIENT_AUTH_RESULT_SSL_REQUIRED: + case CLIENT_AUTH_RESULT_MECH_SSL_REQUIRED: client_send_reply_code(client, IMAP_CMD_REPLY_NO, IMAP_RESP_CODE_PRIVACYREQUIRED, text); break; diff --git a/src/lib-auth/auth-client-interface.h b/src/lib-auth/auth-client-interface.h index 493f6ec120..c58c7bc1d9 100644 --- a/src/lib-auth/auth-client-interface.h +++ b/src/lib-auth/auth-client-interface.h @@ -32,4 +32,8 @@ enum mech_security_flags { #define AUTH_CLIENT_FAIL_CODE_USER_DISABLED "user_disabled" #define AUTH_CLIENT_FAIL_CODE_PASS_EXPIRED "pass_expired" +/* not actually returned from auth service */ +#define AUTH_CLIENT_FAIL_CODE_MECH_INVALID "auth_mech_invalid" +#define AUTH_CLIENT_FAIL_CODE_MECH_SSL_REQUIRED "auth_mech_ssl_required" + #endif diff --git a/src/login-common/client-common-auth.c b/src/login-common/client-common-auth.c index a18f5419cd..8bc59e4fce 100644 --- a/src/login-common/client-common-auth.c +++ b/src/login-common/client-common-auth.c @@ -37,6 +37,10 @@ static const struct client_auth_fail_code_id client_auth_fail_codes[] = { CLIENT_AUTH_FAIL_CODE_USER_DISABLED }, { AUTH_CLIENT_FAIL_CODE_PASS_EXPIRED, CLIENT_AUTH_FAIL_CODE_PASS_EXPIRED }, + { AUTH_CLIENT_FAIL_CODE_MECH_INVALID, + CLIENT_AUTH_FAIL_CODE_MECH_INVALID }, + { AUTH_CLIENT_FAIL_CODE_MECH_SSL_REQUIRED, + CLIENT_AUTH_FAIL_CODE_MECH_SSL_REQUIRED }, { NULL, CLIENT_AUTH_FAIL_CODE_NONE } }; @@ -527,6 +531,12 @@ client_auth_handle_reply(struct client *client, case CLIENT_AUTH_FAIL_CODE_PASS_EXPIRED: result = CLIENT_AUTH_RESULT_PASS_EXPIRED; break; + case CLIENT_AUTH_FAIL_CODE_MECH_INVALID: + result = CLIENT_AUTH_RESULT_MECH_INVALID; + break; + case CLIENT_AUTH_FAIL_CODE_MECH_SSL_REQUIRED: + result = CLIENT_AUTH_RESULT_MECH_SSL_REQUIRED; + break; case CLIENT_AUTH_FAIL_CODE_LOGIN_DISABLED: result = CLIENT_AUTH_RESULT_LOGIN_DISABLED; if (reason == NULL) @@ -570,7 +580,7 @@ void client_auth_abort(struct client *client) void client_auth_fail(struct client *client, const char *text) { - sasl_server_auth_failed(client, text); + sasl_server_auth_failed(client, text, NULL); } int client_auth_read_line(struct client *client) @@ -768,8 +778,10 @@ int client_auth_begin(struct client *client, const char *mech_name, bool client_check_plaintext_auth(struct client *client, bool pass_sent) { + bool ssl_required = (strcmp(client->ssl_set->ssl, "required") == 0); + if (client->secured || (!client->set->disable_plaintext_auth && - strcmp(client->ssl_set->ssl, "required") != 0)) + !ssl_required)) return TRUE; if (client->set->auth_verbose) { @@ -782,9 +794,14 @@ bool client_check_plaintext_auth(struct client *client, bool pass_sent) "without SSL/TLS, but your client did it anyway. " "If anyone was listening, the password was exposed."); } - client_auth_result(client, CLIENT_AUTH_RESULT_SSL_REQUIRED, NULL, + + if (ssl_required) { + client_auth_result(client, CLIENT_AUTH_RESULT_SSL_REQUIRED, NULL, + AUTH_PLAINTEXT_DISABLED_MSG); + } else { + client_auth_result(client, CLIENT_AUTH_RESULT_MECH_SSL_REQUIRED, NULL, AUTH_PLAINTEXT_DISABLED_MSG); - client->auth_tried_disabled_plaintext = TRUE; + } client->auth_attempts++; return FALSE; } diff --git a/src/login-common/client-common.c b/src/login-common/client-common.c index c8bbca801f..ecadbd24ad 100644 --- a/src/login-common/client-common.c +++ b/src/login-common/client-common.c @@ -720,13 +720,10 @@ const char *client_get_extra_disconnect_reason(struct client *client) } /* some auth attempts without SSL/TLS */ - if (client->auth_tried_disabled_plaintext) - return "(tried to use disallowed plaintext auth)"; if (client->set->auth_ssl_require_client_cert && client->ssl_proxy == NULL) return "(cert required, client didn't start TLS)"; - if (client->auth_tried_unsupported_mech) - return "(tried to use unsupported auth mechanism)"; + if (client->auth_waiting && client->auth_attempts == 1) { return t_strdup_printf("(client didn't finish SASL auth, " "waited %u secs)", auth_secs); @@ -764,6 +761,10 @@ const char *client_get_extra_disconnect_reason(struct client *client) return "(password expired)"; case CLIENT_AUTH_FAIL_CODE_LOGIN_DISABLED: return "(login disabled)"; + case CLIENT_AUTH_FAIL_CODE_MECH_INVALID: + return "(tried to use unsupported auth mechanism)"; + case CLIENT_AUTH_FAIL_CODE_MECH_SSL_REQUIRED: + return "(tried to use disallowed plaintext auth)"; default: break; } diff --git a/src/login-common/client-common.h b/src/login-common/client-common.h index e6ec6f60a7..da0a7b298c 100644 --- a/src/login-common/client-common.h +++ b/src/login-common/client-common.h @@ -50,6 +50,8 @@ enum client_auth_fail_code { CLIENT_AUTH_FAIL_CODE_USER_DISABLED, CLIENT_AUTH_FAIL_CODE_PASS_EXPIRED, CLIENT_AUTH_FAIL_CODE_LOGIN_DISABLED, + CLIENT_AUTH_FAIL_CODE_MECH_INVALID, + CLIENT_AUTH_FAIL_CODE_MECH_SSL_REQUIRED, }; enum client_auth_result { @@ -64,6 +66,8 @@ enum client_auth_result { CLIENT_AUTH_RESULT_PASS_EXPIRED, CLIENT_AUTH_RESULT_SSL_REQUIRED, CLIENT_AUTH_RESULT_LOGIN_DISABLED, + CLIENT_AUTH_RESULT_MECH_INVALID, + CLIENT_AUTH_RESULT_MECH_SSL_REQUIRED }; struct client_auth_reply { @@ -182,8 +186,6 @@ struct client { bool trusted:1; bool ssl_servername_settings_read:1; bool authenticating:1; - bool auth_tried_disabled_plaintext:1; - bool auth_tried_unsupported_mech:1; bool auth_try_aborted:1; bool auth_initializing:1; bool auth_process_comm_fail:1; diff --git a/src/login-common/sasl-server.c b/src/login-common/sasl-server.c index 097b83db93..d01d62abb0 100644 --- a/src/login-common/sasl-server.c +++ b/src/login-common/sasl-server.c @@ -336,17 +336,17 @@ void sasl_server_auth_begin(struct client *client, mech = auth_client_find_mech(auth_client, mech_name); if (mech == NULL) { - client->auth_tried_unsupported_mech = TRUE; sasl_server_auth_failed(client, - "Unsupported authentication mechanism."); + "Unsupported authentication mechanism.", + AUTH_CLIENT_FAIL_CODE_MECH_INVALID); return; } if (!client->secured && client->set->disable_plaintext_auth && (mech->flags & MECH_SEC_PLAINTEXT) != 0) { - client->auth_tried_disabled_plaintext = TRUE; sasl_server_auth_failed(client, - "Plaintext authentication disabled."); + "Plaintext authentication disabled.", + AUTH_CLIENT_FAIL_CODE_MECH_SSL_REQUIRED); return; } @@ -373,9 +373,9 @@ void sasl_server_auth_begin(struct client *client, authenticate_callback, client); } -static void ATTR_NULL(2) +static void ATTR_NULL(2, 3) sasl_server_auth_cancel(struct client *client, const char *reason, - enum sasl_server_reply reply) + const char *code, enum sasl_server_reply reply) { i_assert(client->authenticating); @@ -390,16 +390,26 @@ sasl_server_auth_cancel(struct client *client, const char *reason, if (client->auth_request != NULL) auth_client_request_abort(&client->auth_request); + if (code != NULL) { + const char *args[2]; + + args[0] = t_strconcat("code=", code, NULL); + args[1] = NULL; + call_client_callback(client, reply, reason, args); + return; + } + call_client_callback(client, reply, reason, NULL); } -void sasl_server_auth_failed(struct client *client, const char *reason) +void sasl_server_auth_failed(struct client *client, const char *reason, + const char *code) { - sasl_server_auth_cancel(client, reason, SASL_SERVER_REPLY_AUTH_FAILED); + sasl_server_auth_cancel(client, reason, code, SASL_SERVER_REPLY_AUTH_FAILED); } void sasl_server_auth_abort(struct client *client) { client->auth_try_aborted = TRUE; - sasl_server_auth_cancel(client, NULL, SASL_SERVER_REPLY_AUTH_ABORTED); + sasl_server_auth_cancel(client, NULL, NULL, SASL_SERVER_REPLY_AUTH_ABORTED); } diff --git a/src/login-common/sasl-server.h b/src/login-common/sasl-server.h index 7c8940ba18..bd5103ac00 100644 --- a/src/login-common/sasl-server.h +++ b/src/login-common/sasl-server.h @@ -22,7 +22,8 @@ void sasl_server_auth_begin(struct client *client, const char *service, const char *mech_name, const char *initial_resp_base64, sasl_server_callback_t *callback); -void sasl_server_auth_failed(struct client *client, const char *reason); +void sasl_server_auth_failed(struct client *client, const char *reason, + const char *code) ATTR_NULL(3); void sasl_server_auth_abort(struct client *client); #endif diff --git a/src/pop3-login/client-authenticate.c b/src/pop3-login/client-authenticate.c index b3e1e23621..6d90e5cc2b 100644 --- a/src/pop3-login/client-authenticate.c +++ b/src/pop3-login/client-authenticate.c @@ -66,6 +66,8 @@ void pop3_client_auth_result(struct client *client, case CLIENT_AUTH_RESULT_PASS_EXPIRED: case CLIENT_AUTH_RESULT_SSL_REQUIRED: case CLIENT_AUTH_RESULT_LOGIN_DISABLED: + case CLIENT_AUTH_RESULT_MECH_INVALID: + case CLIENT_AUTH_RESULT_MECH_SSL_REQUIRED: client_send_reply(client, POP3_CMD_REPLY_AUTH_ERROR, text); break; default: -- 2.47.3