client-authenticate.c revision e95dba8921087afebb8a92c592af3b8ca22ae796
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2002-2009 Dovecot authors, see the included COPYING file */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenconst char *client_authenticate_get_capabilities(bool secured)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen unsigned int i, count;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen mech = auth_client_get_available_mechs(auth_client, &count);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen for (i = 0; i < count; i++) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* a) transport is secured
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen b) auth mechanism isn't plaintext
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen c) we allow insecure authentication
04870054863757edf048c81dcce3c5e7dec453cdTimo Sirainen if ((mech[i].flags & MECH_SEC_PRIVATE) == 0 &&
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen (secured || !login_settings->disable_plaintext_auth ||
6882df5fbca4a09cdaa95f54d70bb31b5920528cTimo Sirainenstatic void client_auth_input(struct imap_client *client)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (i_stream_next_line(client->common.input) == NULL)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* @UNSAFE */
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen line = i_stream_next_line(client->common.input);
4145cbac82bfc0c8bfeceeca0ef841700117930cTimo Sirainen sasl_server_auth_client_error(&client->common,
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen "Authentication aborted");
eacce2276278ce6a8176a9a100807dba50bbfb36Timo Sirainen auth_client_request_continue(client->common.auth_request, line);
eacce2276278ce6a8176a9a100807dba50bbfb36Timo Sirainen /* clear sensitive data */
eacce2276278ce6a8176a9a100807dba50bbfb36Timo Sirainenstatic void client_authfail_delay_timeout(struct imap_client *client)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* get back to normal client input. */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen client->io = io_add(client->common.fd, IO_READ, client_input, client);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenvoid client_auth_failed(struct imap_client *client, bool nodelay)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen client->io = io_add(client->common.fd, IO_READ,
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen /* increase the timeout after each unsuccessful attempt, but don't
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen increase it so high that the idle timeout would be triggered */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (delay_msecs > CLIENT_LOGIN_IDLE_TIMEOUT_MSECS)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen delay_msecs = CLIENT_LOGIN_IDLE_TIMEOUT_MSECS - 1000;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen timeout_add(delay_msecs, client_authfail_delay_timeout, client);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenstatic bool client_handle_args(struct imap_client *client,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen const char *reason = NULL, *host = NULL, *destuser = NULL, *pass = NULL;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen bool proxy = FALSE, temp = FALSE, nologin = !success;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* already handled in login-common */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen i_info("Ignoring unknown passdb extra field: %s", key);
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen /* we want to proxy the connection to another server.
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen don't do this unless authentication succeeded. with
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen master user proxying we can get FAIL with proxy still set.
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen proxy host=.. [port=..] [destuser=..] pass=.. */
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen if (imap_proxy_new(client, host, port, destuser, master_user,
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen /* IMAP referral
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen [nologin] referral host=.. [port=..] [destuser=..]
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen NO [REFERRAL imap://destuser;AUTH=..@host:port/] Can't login.
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen OK [...] Logged in, but you should use this server instead.
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen .. [REFERRAL ..] (Reason from auth server)
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen str_printfa(reply, "[REFERRAL imap://%s;AUTH=%s@%s",
45c872f65e4f327ef166c6e2b71bb43e188ac562Timo Sirainen str_append(reply, "Try this server instead.");
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen str_append(reply, "Logged in, but you should use "
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen "this server instead.");
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen client_destroy_success(client, "Login with referral");
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen } else if (nologin) {
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen /* Authentication went ok, but for some reason user isn't
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen allowed to log in. Shouldn't probably happen. */
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen str_append(reply, "NO ["IMAP_RESP_CODE_UNAVAILABLE"] "
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen str_append(reply, "NO "IMAP_AUTHZ_FAILED_MSG);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenstatic void sasl_callback(struct client *_client, enum sasl_server_reply reply,
34015eb0b74735f2fac07c12697bde20a94735e6Timo Sirainen struct imap_client *client = (struct imap_client *)_client;
34015eb0b74735f2fac07c12697bde20a94735e6Timo Sirainen const char *msg;
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen if (client_handle_args(client, args, TRUE, &nodelay))
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (client_handle_args(client, args, FALSE, &nodelay))
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen msg = reply == SASL_SERVER_REPLY_AUTH_FAILED ? "NO " : "BAD ";
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* authentication itself succeeded, we just hit some
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen internal failure. */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* don't check return value here. it gets tricky if we try
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen to call client_destroy() in here. */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen client->io = io_add(client->common.fd, IO_READ,
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainenstatic int client_auth_begin(struct imap_client *client, const char *mech_name,
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen client->common.auth_command_tag = client->cmd_tag;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen sasl_server_auth_begin(&client->common, IMAP_SERVICE_NAME, mech_name,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* don't handle input until we get the initial auth reply */
04870054863757edf048c81dcce3c5e7dec453cdTimo Sirainenint cmd_authenticate(struct imap_client *client, const struct imap_arg *args)
e10d8b1291090c26b9ef499637e6e632485ca5beTimo Sirainen /* we want only one argument: authentication mechanism name */
e1203014de25c8c3d3975a9f4b4a04616df4bba2Timo Sirainen if (args[0].type != IMAP_ARG_ATOM && args[0].type != IMAP_ARG_STRING)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* optional SASL initial response */
e10d8b1291090c26b9ef499637e6e632485ca5beTimo Sirainen strcmp(login_settings->ssl, "required") == 0) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen client_syslog(&client->common, "Login failed: "
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen "SSL required for authentication");
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen "Authentication not allowed until SSL/TLS is enabled.");
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen return client_auth_begin(client, mech_name, init_resp);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenint cmd_login(struct imap_client *client, const struct imap_arg *args)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* two arguments: username and password */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (args[0].type != IMAP_ARG_ATOM && args[0].type != IMAP_ARG_STRING)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (args[1].type != IMAP_ARG_ATOM && args[1].type != IMAP_ARG_STRING)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (!client->common.secured && login_settings->disable_plaintext_auth) {
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen client_syslog(&client->common, "Login failed: "
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen "Plaintext authentication disabled");
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen client->common.auth_tried_disabled_plaintext = TRUE;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen "* BAD [ALERT] Plaintext authentication not allowed "
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen "without SSL/TLS, but your client did it anyway. "
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen "If anyone was listening, the password was exposed.");
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen client_send_tagline(client, "NO ["IMAP_RESP_CODE_CLIENTBUG"] "
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* authorization ID \0 authentication ID \0 pass */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen plain_login = buffer_create_dynamic(pool_datastack_create(), 64);
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen buffer_append(plain_login, user, strlen(user));
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen buffer_append(plain_login, pass, strlen(pass));
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen base64 = buffer_create_dynamic(pool_datastack_create(),
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen base64_encode(plain_login->data, plain_login->used, base64);
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen return client_auth_begin(client, "PLAIN", str_c(base64));