client-authenticate.c revision e95dba8921087afebb8a92c592af3b8ca22ae796
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2002-2009 Dovecot authors, see the included COPYING file */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
08d6658a4e2ec8104cd1307f6baa75fdb07a24f8Mark Washenberger#include "common.h"
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen#include "base64.h"
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen#include "buffer.h"
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen#include "ioloop.h"
08d6658a4e2ec8104cd1307f6baa75fdb07a24f8Mark Washenberger#include "istream.h"
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen#include "ostream.h"
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen#include "safe-memset.h"
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen#include "str.h"
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen#include "str-sanitize.h"
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen#include "imap-resp-code.h"
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen#include "imap-parser.h"
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen#include "auth-client.h"
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen#include "client.h"
25d624dd86700c82cd28427f3d3bebe7c8f7f459Timo Sirainen#include "client-authenticate.h"
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen#include "imap-proxy.h"
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen#include <stdlib.h>
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen#define AUTH_FAILURE_DELAY_INCREASE_MSECS 5000
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen#define IMAP_SERVICE_NAME "imap"
714e2da5096fb52b8845d3c79f9bb26225a606c9Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenconst char *client_authenticate_get_capabilities(bool secured)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen{
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen const struct auth_mech_desc *mech;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen unsigned int i, count;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen string_t *str;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen str = t_str_new(128);
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
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen */
04870054863757edf048c81dcce3c5e7dec453cdTimo Sirainen if ((mech[i].flags & MECH_SEC_PRIVATE) == 0 &&
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen (secured || !login_settings->disable_plaintext_auth ||
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen (mech[i].flags & MECH_SEC_PLAINTEXT) == 0)) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen str_append_c(str, ' ');
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen str_append(str, "AUTH=");
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen str_append(str, mech[i].name);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen }
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen }
bd63b5b860658b01b1f46f26d406e1e4a9dc019aTimo Sirainen
15a07b47846c47a81d69a14d649564e222d6f742Timo Sirainen return str_c(str);
cd2cd224d3216a243d55c71c298a5b7684de0ac4Timo Sirainen}
c1faff067b29fb48426cb84260adba563e93189aTimo Sirainen
6882df5fbca4a09cdaa95f54d70bb31b5920528cTimo Sirainenstatic void client_auth_input(struct imap_client *client)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen{
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen char *line;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (!client_read(client))
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen return;
eacce2276278ce6a8176a9a100807dba50bbfb36Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (client->skip_line) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (i_stream_next_line(client->common.input) == NULL)
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen return;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen client->skip_line = FALSE;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen }
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* @UNSAFE */
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen line = i_stream_next_line(client->common.input);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (line == NULL)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen return;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (strcmp(line, "*") == 0) {
4145cbac82bfc0c8bfeceeca0ef841700117930cTimo Sirainen sasl_server_auth_client_error(&client->common,
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen "Authentication aborted");
eacce2276278ce6a8176a9a100807dba50bbfb36Timo Sirainen } else {
eacce2276278ce6a8176a9a100807dba50bbfb36Timo Sirainen auth_client_request_continue(client->common.auth_request, line);
eacce2276278ce6a8176a9a100807dba50bbfb36Timo Sirainen io_remove(&client->io);
eacce2276278ce6a8176a9a100807dba50bbfb36Timo Sirainen
eacce2276278ce6a8176a9a100807dba50bbfb36Timo Sirainen /* clear sensitive data */
eacce2276278ce6a8176a9a100807dba50bbfb36Timo Sirainen safe_memset(line, 0, strlen(line));
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen }
eacce2276278ce6a8176a9a100807dba50bbfb36Timo Sirainen}
eacce2276278ce6a8176a9a100807dba50bbfb36Timo Sirainen
eacce2276278ce6a8176a9a100807dba50bbfb36Timo Sirainenstatic void client_authfail_delay_timeout(struct imap_client *client)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen{
e1203014de25c8c3d3975a9f4b4a04616df4bba2Timo Sirainen timeout_remove(&client->to_authfail_delay);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* get back to normal client input. */
e1203014de25c8c3d3975a9f4b4a04616df4bba2Timo Sirainen i_assert(client->io == NULL);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen client->io = io_add(client->common.fd, IO_READ, client_input, client);
e10d8b1291090c26b9ef499637e6e632485ca5beTimo Sirainen client_input(client);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen}
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenvoid client_auth_failed(struct imap_client *client, bool nodelay)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen{
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen unsigned int delay_msecs;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen client->common.auth_command_tag = NULL;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (client->auth_initializing)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen return;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (client->io != NULL)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen io_remove(&client->io);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (nodelay) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen client->io = io_add(client->common.fd, IO_READ,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen client_input, client);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen client_input(client);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen return;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen }
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen
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 delay_msecs = client->common.auth_attempts *
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen AUTH_FAILURE_DELAY_INCREASE_MSECS;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (delay_msecs > CLIENT_LOGIN_IDLE_TIMEOUT_MSECS)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen delay_msecs = CLIENT_LOGIN_IDLE_TIMEOUT_MSECS - 1000;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen i_assert(client->to_authfail_delay == NULL);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen client->to_authfail_delay =
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen timeout_add(delay_msecs, client_authfail_delay_timeout, client);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen}
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenstatic bool client_handle_args(struct imap_client *client,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen const char *const *args, bool success,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen bool *nodelay_r)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen{
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen const char *reason = NULL, *host = NULL, *destuser = NULL, *pass = NULL;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen const char *master_user = NULL;
411f318ed3a25fa66c1b932e10df43841e2725c9Timo Sirainen const char *key, *value, *p;
411f318ed3a25fa66c1b932e10df43841e2725c9Timo Sirainen enum login_proxy_ssl_flags ssl_flags = 0;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen string_t *reply;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen unsigned int port = 143;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen bool proxy = FALSE, temp = FALSE, nologin = !success;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen bool authz_failure = FALSE;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen *nodelay_r = FALSE;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen for (; *args != NULL; args++) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen p = strchr(*args, '=');
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (p == NULL) {
3a9eb305fd4aad5502cb7e64625874385ab5bc19Timo Sirainen key = *args;
714e2da5096fb52b8845d3c79f9bb26225a606c9Timo Sirainen value = "";
714e2da5096fb52b8845d3c79f9bb26225a606c9Timo Sirainen } else {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen key = t_strdup_until(*args, p);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen value = p + 1;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen }
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (strcmp(key, "nologin") == 0)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen nologin = TRUE;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen else if (strcmp(key, "nodelay") == 0)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen *nodelay_r = TRUE;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen else if (strcmp(key, "proxy") == 0)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen proxy = TRUE;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen else if (strcmp(key, "temp") == 0)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen temp = TRUE;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen else if (strcmp(key, "authz") == 0)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen authz_failure = TRUE;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen else if (strcmp(key, "reason") == 0)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen reason = value;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen else if (strcmp(key, "host") == 0)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen host = value;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen else if (strcmp(key, "port") == 0)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen port = atoi(value);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen else if (strcmp(key, "destuser") == 0)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen destuser = value;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen else if (strcmp(key, "pass") == 0)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen pass = value;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen else if (strcmp(key, "master") == 0)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen master_user = value;
44f93baa7b8dca7d00bf187cd3db1c15eed384d2Timo Sirainen else if (strcmp(key, "user") == 0) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* already handled in login-common */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen } else if (login_settings->auth_debug)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen i_info("Ignoring unknown passdb extra field: %s", key);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen }
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen if (destuser == NULL)
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen destuser = client->common.virtual_user;
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen if (proxy) {
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
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen proxy host=.. [port=..] [destuser=..] pass=.. */
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen if (!success)
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen return FALSE;
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen if (imap_proxy_new(client, host, port, destuser, master_user,
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen pass, ssl_flags) < 0)
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen client_auth_failed(client, TRUE);
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen return TRUE;
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen }
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen if (host != NULL) {
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen /* IMAP referral
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen [nologin] referral host=.. [port=..] [destuser=..]
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen [reason=..]
c7f6992db44e9cd33b3b0d754833a1503ee9a53fAki Tuomi
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 */
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen reply = t_str_new(128);
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen str_append(reply, nologin ? "NO " : "OK ");
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen str_printfa(reply, "[REFERRAL imap://%s;AUTH=%s@%s",
c7f6992db44e9cd33b3b0d754833a1503ee9a53fAki Tuomi destuser, client->common.auth_mech_name, host);
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen if (port != 143)
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen str_printfa(reply, ":%u", port);
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen str_append(reply, "/] ");
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen if (reason != NULL)
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen str_append(reply, reason);
45c872f65e4f327ef166c6e2b71bb43e188ac562Timo Sirainen else if (nologin)
45c872f65e4f327ef166c6e2b71bb43e188ac562Timo Sirainen str_append(reply, "Try this server instead.");
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen else {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen str_append(reply, "Logged in, but you should use "
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen "this server instead.");
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen }
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen client_send_tagline(client, str_c(reply));
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen if (!nologin) {
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen client_destroy_success(client, "Login with referral");
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen return TRUE;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen }
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. */
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen reply = t_str_new(128);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (reason != NULL)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen str_printfa(reply, "NO %s", reason);
c7f6992db44e9cd33b3b0d754833a1503ee9a53fAki Tuomi else if (temp) {
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen str_append(reply, "NO ["IMAP_RESP_CODE_UNAVAILABLE"] "
4530cfa7456c10cd03fe9120c75f8bcb2f623ba4Timo Sirainen AUTH_TEMP_FAILED_MSG);
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen } else if (authz_failure) {
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen str_append(reply, "NO "IMAP_AUTHZ_FAILED_MSG);
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen } else {
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen str_append(reply, "NO "IMAP_AUTH_FAILED_MSG);
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen }
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen client_send_tagline(client, str_c(reply));
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen } else {
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen /* normal login/failure */
45c872f65e4f327ef166c6e2b71bb43e188ac562Timo Sirainen return FALSE;
45c872f65e4f327ef166c6e2b71bb43e188ac562Timo Sirainen }
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen i_assert(nologin);
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen if (!client->destroyed)
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen client_auth_failed(client, *nodelay_r);
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen return TRUE;
34015eb0b74735f2fac07c12697bde20a94735e6Timo Sirainen}
34015eb0b74735f2fac07c12697bde20a94735e6Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenstatic void sasl_callback(struct client *_client, enum sasl_server_reply reply,
34015eb0b74735f2fac07c12697bde20a94735e6Timo Sirainen const char *data, const char *const *args)
34015eb0b74735f2fac07c12697bde20a94735e6Timo Sirainen{
34015eb0b74735f2fac07c12697bde20a94735e6Timo Sirainen struct imap_client *client = (struct imap_client *)_client;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen struct const_iovec iov[3];
34015eb0b74735f2fac07c12697bde20a94735e6Timo Sirainen const char *msg;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen size_t data_len;
c7f6992db44e9cd33b3b0d754833a1503ee9a53fAki Tuomi bool nodelay;
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen
45c872f65e4f327ef166c6e2b71bb43e188ac562Timo Sirainen i_assert(!client->destroyed ||
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen reply == SASL_SERVER_REPLY_CLIENT_ERROR ||
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch reply == SASL_SERVER_REPLY_MASTER_FAILED);
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen switch (reply) {
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen case SASL_SERVER_REPLY_SUCCESS:
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen if (client->to_auth_waiting != NULL)
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen timeout_remove(&client->to_auth_waiting);
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen if (args != NULL) {
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen if (client_handle_args(client, args, TRUE, &nodelay))
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen break;
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen }
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen client_destroy_success(client, "Login");
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen break;
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen case SASL_SERVER_REPLY_AUTH_FAILED:
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen case SASL_SERVER_REPLY_CLIENT_ERROR:
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (client->to_auth_waiting != NULL)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen timeout_remove(&client->to_auth_waiting);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (args != NULL) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (client_handle_args(client, args, FALSE, &nodelay))
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen break;
45c872f65e4f327ef166c6e2b71bb43e188ac562Timo Sirainen }
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen msg = reply == SASL_SERVER_REPLY_AUTH_FAILED ? "NO " : "BAD ";
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen msg = t_strconcat(msg, data != NULL ? data :
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen IMAP_AUTH_FAILED_MSG, NULL);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen client_send_tagline(client, msg);
04a7b696e5255aa956277a0f7cabee736c69ec96Timo Sirainen
04a7b696e5255aa956277a0f7cabee736c69ec96Timo Sirainen if (!client->destroyed)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen client_auth_failed(client, nodelay);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen break;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen case SASL_SERVER_REPLY_MASTER_FAILED:
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (data == NULL)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen client_destroy_internal_failure(client);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen else {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen client_send_tagline(client,
44f93baa7b8dca7d00bf187cd3db1c15eed384d2Timo Sirainen t_strconcat("NO ", data, NULL));
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* authentication itself succeeded, we just hit some
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen internal failure. */
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen client_destroy_success(client, data);
0b2f7be9fadfd4026a9174e51170890cde3edf48Timo Sirainen }
45c872f65e4f327ef166c6e2b71bb43e188ac562Timo Sirainen break;
3e0bae44b65f5c46989fcef3d1e07203f496327eTimo Sirainen case SASL_SERVER_REPLY_CONTINUE:
75771bd32a86b7360d28f1254ffba99f63d763d9Aki Tuomi data_len = strlen(data);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen iov[0].iov_base = "+ ";
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen iov[0].iov_len = 2;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen iov[1].iov_base = data;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen iov[1].iov_len = data_len;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen iov[2].iov_base = "\r\n";
e10d8b1291090c26b9ef499637e6e632485ca5beTimo Sirainen iov[2].iov_len = 2;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* don't check return value here. it gets tricky if we try
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen to call client_destroy() in here. */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen (void)o_stream_sendv(client->output, iov, 3);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen i_assert(client->io == NULL);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen client->io = io_add(client->common.fd, IO_READ,
ec5fec7eab19e134a2607b7e224b3e14a1771ee0Timo Sirainen client_auth_input, client);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen client_auth_input(client);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen return;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen }
04a7b696e5255aa956277a0f7cabee736c69ec96Timo Sirainen
04a7b696e5255aa956277a0f7cabee736c69ec96Timo Sirainen client_unref(client);
ec5fec7eab19e134a2607b7e224b3e14a1771ee0Timo Sirainen}
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainenstatic int client_auth_begin(struct imap_client *client, const char *mech_name,
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen const char *init_resp)
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen{
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen client->common.auth_command_tag = client->cmd_tag;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen client_ref(client);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen client->auth_initializing = TRUE;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen sasl_server_auth_begin(&client->common, IMAP_SERVICE_NAME, mech_name,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen init_resp, sasl_callback);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen client->auth_initializing = FALSE;
4145cbac82bfc0c8bfeceeca0ef841700117930cTimo Sirainen if (!client->common.authenticating)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen return 1;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* don't handle input until we get the initial auth reply */
e10d8b1291090c26b9ef499637e6e632485ca5beTimo Sirainen if (client->io != NULL)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen io_remove(&client->io);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen client_set_auth_waiting(client);
04870054863757edf048c81dcce3c5e7dec453cdTimo Sirainen return 0;
04870054863757edf048c81dcce3c5e7dec453cdTimo Sirainen}
04870054863757edf048c81dcce3c5e7dec453cdTimo Sirainen
04870054863757edf048c81dcce3c5e7dec453cdTimo Sirainenint cmd_authenticate(struct imap_client *client, const struct imap_arg *args)
e1203014de25c8c3d3975a9f4b4a04616df4bba2Timo Sirainen{
e1203014de25c8c3d3975a9f4b4a04616df4bba2Timo Sirainen const char *mech_name, *init_resp = NULL;
e593e507ee5ea3869271a631874c5c4b5c7a294dTimo Sirainen
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)
e1203014de25c8c3d3975a9f4b4a04616df4bba2Timo Sirainen return -1;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (args[1].type != IMAP_ARG_EOL) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* optional SASL initial response */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (args[1].type != IMAP_ARG_ATOM ||
44f93baa7b8dca7d00bf187cd3db1c15eed384d2Timo Sirainen args[2].type != IMAP_ARG_EOL)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen return -1;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen init_resp = IMAP_ARG_STR(&args[1]);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen }
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (!client->common.secured &&
e10d8b1291090c26b9ef499637e6e632485ca5beTimo Sirainen strcmp(login_settings->ssl, "required") == 0) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (login_settings->verbose_auth) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen client_syslog(&client->common, "Login failed: "
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen "SSL required for authentication");
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen }
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen client->common.auth_attempts++;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen client_send_tagline(client,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen "NO ["IMAP_RESP_CODE_PRIVACYREQUIRED"] "
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen "Authentication not allowed until SSL/TLS is enabled.");
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen return 1;
04a7b696e5255aa956277a0f7cabee736c69ec96Timo Sirainen }
04a7b696e5255aa956277a0f7cabee736c69ec96Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen mech_name = IMAP_ARG_STR(&args[0]);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (*mech_name == '\0')
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen return -1;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen return client_auth_begin(client, mech_name, init_resp);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen}
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenint cmd_login(struct imap_client *client, const struct imap_arg *args)
44f93baa7b8dca7d00bf187cd3db1c15eed384d2Timo Sirainen{
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen const char *user, *pass;
44f93baa7b8dca7d00bf187cd3db1c15eed384d2Timo Sirainen string_t *plain_login, *base64;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* two arguments: username and password */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (args[0].type != IMAP_ARG_ATOM && args[0].type != IMAP_ARG_STRING)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen return -1;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (args[1].type != IMAP_ARG_ATOM && args[1].type != IMAP_ARG_STRING)
e10d8b1291090c26b9ef499637e6e632485ca5beTimo Sirainen return -1;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (args[2].type != IMAP_ARG_EOL)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen return -1;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen user = IMAP_ARG_STR(&args[0]);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen pass = IMAP_ARG_STR(&args[1]);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (!client->common.secured && login_settings->disable_plaintext_auth) {
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen if (login_settings->verbose_auth) {
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen client_syslog(&client->common, "Login failed: "
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen "Plaintext authentication disabled");
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen }
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen client->common.auth_tried_disabled_plaintext = TRUE;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen client->common.auth_attempts++;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen client_send_line(client,
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 AUTH_PLAINTEXT_DISABLED_MSG);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen return 1;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen }
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* authorization ID \0 authentication ID \0 pass */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen plain_login = buffer_create_dynamic(pool_datastack_create(), 64);
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen buffer_append_c(plain_login, '\0');
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen buffer_append(plain_login, user, strlen(user));
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen buffer_append_c(plain_login, '\0');
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen buffer_append(plain_login, pass, strlen(pass));
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen base64 = buffer_create_dynamic(pool_datastack_create(),
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen MAX_BASE64_ENCODED_SIZE(plain_login->used));
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen base64_encode(plain_login->data, plain_login->used, base64);
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen return client_auth_begin(client, "PLAIN", str_c(base64));
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen}
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen