client-authenticate.c revision afe367fbbb7e1c7b3d1f82eae517bfee80a00738
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (c) 2002-2008 Dovecot authors, see the included COPYING file */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
c977374bd4651cafc1626ebe308aa66dfd8b30e0Timo Sirainen#include "common.h"
c977374bd4651cafc1626ebe308aa66dfd8b30e0Timo Sirainen#include "base64.h"
c977374bd4651cafc1626ebe308aa66dfd8b30e0Timo Sirainen#include "buffer.h"
c977374bd4651cafc1626ebe308aa66dfd8b30e0Timo Sirainen#include "ioloop.h"
65b94e73c305dcb209cf958f938b93ec061c67a9Timo Sirainen#include "istream.h"
c977374bd4651cafc1626ebe308aa66dfd8b30e0Timo Sirainen#include "ostream.h"
65b94e73c305dcb209cf958f938b93ec061c67a9Timo Sirainen#include "safe-memset.h"
c977374bd4651cafc1626ebe308aa66dfd8b30e0Timo Sirainen#include "str.h"
65b94e73c305dcb209cf958f938b93ec061c67a9Timo Sirainen#include "str-sanitize.h"
c977374bd4651cafc1626ebe308aa66dfd8b30e0Timo Sirainen#include "imap-parser.h"
c977374bd4651cafc1626ebe308aa66dfd8b30e0Timo Sirainen#include "auth-client.h"
c977374bd4651cafc1626ebe308aa66dfd8b30e0Timo Sirainen#include "client.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "client-authenticate.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "imap-proxy.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include <stdlib.h>
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#define IMAP_SERVICE_NAME "imap"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic void client_auth_failed(struct imap_client *client);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenconst char *client_authenticate_get_capabilities(bool secured)
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainen{
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainen const struct auth_mech_desc *mech;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int i, count;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen string_t *str;
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str = t_str_new(128);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mech = auth_client_get_available_mechs(auth_client, &count);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen for (i = 0; i < count; i++) {
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen /* a) transport is secured
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen b) auth mechanism isn't plaintext
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen c) we allow insecure authentication
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen */
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen if ((mech[i].flags & MECH_SEC_PRIVATE) == 0 &&
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen (secured || !disable_plaintext_auth ||
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen (mech[i].flags & MECH_SEC_PLAINTEXT) == 0)) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_append_c(str, ' ');
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_append(str, "AUTH=");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_append(str, mech[i].name);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
d22301419109ed4a38351715e6760011421dadecTimo Sirainen }
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen
5b62dea2f88165f3f4d87bba9011343f3ff415ffTimo Sirainen return str_c(str);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic void client_auth_input(struct imap_client *client)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen char *line;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (!client_read(client))
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return;
461ffead9720d1e516b959d5e41f049c73d38c7cTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (client->skip_line) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (i_stream_next_line(client->input) == NULL)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen client->skip_line = FALSE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* @UNSAFE */
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen line = i_stream_next_line(client->input);
73a87c2ff65c6116cde6fb158dfddb8ef7346901Timo Sirainen if (line == NULL)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (strcmp(line, "*") == 0) {
73a87c2ff65c6116cde6fb158dfddb8ef7346901Timo Sirainen sasl_server_auth_client_error(&client->common,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen "Authentication aborted");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen } else {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen auth_client_request_continue(client->common.auth_request, line);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen io_remove(&client->io);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* clear sensitive data */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen safe_memset(line, 0, strlen(line));
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic void client_auth_failed(struct imap_client *client)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* get back to normal client input. */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (client->io != NULL)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen io_remove(&client->io);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen client->io = io_add(client->common.fd, IO_READ,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen client_input, client);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen timeout_remove(&client->to_auth_waiting);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic bool client_handle_args(struct imap_client *client,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char *const *args, bool success)
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char *reason = NULL, *host = NULL, *destuser = NULL, *pass = NULL;
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen string_t *reply;
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen unsigned int port = 143;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen bool proxy = FALSE, temp = FALSE, nologin = !success;
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen for (; *args != NULL; args++) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (strcmp(*args, "nologin") == 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen nologin = TRUE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen else if (strcmp(*args, "proxy") == 0)
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen proxy = TRUE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen else if (strcmp(*args, "temp") == 0)
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen temp = TRUE;
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen else if (strncmp(*args, "reason=", 7) == 0)
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen reason = *args + 7;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen else if (strncmp(*args, "host=", 5) == 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen host = *args + 5;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen else if (strncmp(*args, "port=", 5) == 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen port = atoi(*args + 5);
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen else if (strncmp(*args, "destuser=", 9) == 0)
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen destuser = *args + 9;
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen else if (strncmp(*args, "pass=", 5) == 0)
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen pass = *args + 5;
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen if (destuser == NULL)
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen destuser = client->common.virtual_user;
6ae329de09afb7214c906d762320847e05469d53Timo Sirainen
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen if (proxy &&
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen !login_proxy_is_ourself(&client->common, host, port, destuser)) {
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen /* we want to proxy the connection to another server.
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen don't do this unless authentication succeeded. with
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen master user proxying we can get FAIL with proxy still set.
6ae329de09afb7214c906d762320847e05469d53Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen proxy host=.. [port=..] [destuser=..] pass=.. */
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen if (!success)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return FALSE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (imap_proxy_new(client, host, port, destuser, pass) < 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen client_destroy_internal_failure(client);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return TRUE;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (!proxy && host != NULL) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* IMAP referral
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen [nologin] referral host=.. [port=..] [destuser=..]
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen [reason=..]
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen NO [REFERRAL imap://destuser;AUTH=..@host:port/] Can't login.
e790c9b1fc56bca7ebd59dc289cb5035e3afcee5Timo Sirainen OK [...] Logged in, but you should use this server instead.
e790c9b1fc56bca7ebd59dc289cb5035e3afcee5Timo Sirainen .. [REFERRAL ..] (Reason from auth server)
e790c9b1fc56bca7ebd59dc289cb5035e3afcee5Timo Sirainen */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen reply = t_str_new(128);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_append(reply, nologin ? "NO " : "OK ");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_printfa(reply, "[REFERRAL imap://%s;AUTH=%s@%s",
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen destuser, client->common.auth_mech_name, host);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (port != 143)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_printfa(reply, ":%u", port);
d22301419109ed4a38351715e6760011421dadecTimo Sirainen str_append(reply, "/] ");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (reason != NULL)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_append(reply, reason);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen else if (nologin)
65b94e73c305dcb209cf958f938b93ec061c67a9Timo Sirainen str_append(reply, "Try this server instead.");
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen else {
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen str_append(reply, "Logged in, but you should use "
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen "this server instead.");
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen client_send_tagline(client, str_c(reply));
73a87c2ff65c6116cde6fb158dfddb8ef7346901Timo Sirainen if (!nologin) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen client_destroy(client, "Login with referral");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return TRUE;
73a87c2ff65c6116cde6fb158dfddb8ef7346901Timo Sirainen }
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen } else if (nologin) {
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen /* Authentication went ok, but for some reason user isn't
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen allowed to log in. Shouldn't probably happen. */
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen reply = t_str_new(128);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen if (reason != NULL)
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen str_printfa(reply, "NO %s", reason);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen else if (temp)
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen str_append(reply, "NO "AUTH_TEMP_FAILED_MSG);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen else
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen str_append(reply, "NO "AUTH_FAILED_MSG);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen client_send_tagline(client, str_c(reply));
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen } else {
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen /* normal login/failure */
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen return FALSE;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen }
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_assert(nologin);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (!client->destroyed)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen client_auth_failed(client);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return TRUE;
5b62dea2f88165f3f4d87bba9011343f3ff415ffTimo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic void sasl_callback(struct client *_client, enum sasl_server_reply reply,
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen const char *data, const char *const *args)
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct imap_client *client = (struct imap_client *)_client;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen struct const_iovec iov[3];
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char *msg;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen size_t data_len;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen i_assert(!client->destroyed ||
d0b2bd9e2246eb68ed952c7f2e13d1969d657c8fTimo Sirainen reply == SASL_SERVER_REPLY_CLIENT_ERROR ||
d0b2bd9e2246eb68ed952c7f2e13d1969d657c8fTimo Sirainen reply == SASL_SERVER_REPLY_MASTER_FAILED);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
1f1ee8db68d9ae1604350801cd8dc33ebe29fe8aTimo Sirainen switch (reply) {
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen case SASL_SERVER_REPLY_SUCCESS:
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen if (args != NULL) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (client_handle_args(client, args, TRUE))
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen break;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen client_send_tagline(client, "OK Logged in.");
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen client_destroy(client, "Login");
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen break;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen case SASL_SERVER_REPLY_AUTH_FAILED:
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen case SASL_SERVER_REPLY_CLIENT_ERROR:
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen if (args != NULL) {
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen if (client_handle_args(client, args, FALSE))
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen break;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen }
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen msg = reply == SASL_SERVER_REPLY_AUTH_FAILED ? "NO " : "BAD ";
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen msg = t_strconcat(msg, data != NULL ? data : AUTH_FAILED_MSG,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen NULL);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen client_send_tagline(client, msg);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (!client->destroyed)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen client_auth_failed(client);
d22301419109ed4a38351715e6760011421dadecTimo Sirainen break;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen case SASL_SERVER_REPLY_MASTER_FAILED:
3f91e60401495a4046c73992fabaa5e77200a451Timo Sirainen if (data == NULL)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen client_destroy_internal_failure(client);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen else {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen client_send_tagline(client,
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen t_strconcat("NO ", data, NULL));
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen client_destroy(client, data);
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen }
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen break;
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen case SASL_SERVER_REPLY_CONTINUE:
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen data_len = strlen(data);
f71c2d4e6b802bf8e622bcd5df29286262d05d5aTimo Sirainen iov[0].iov_base = "+ ";
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen iov[0].iov_len = 2;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen iov[1].iov_base = data;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen iov[1].iov_len = data_len;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen iov[2].iov_base = "\r\n";
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen iov[2].iov_len = 2;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* don't check return value here. it gets tricky if we try
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen to call client_destroy() in here. */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen (void)o_stream_sendv(client->output, iov, 3);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_assert(client->io == NULL);
3f91e60401495a4046c73992fabaa5e77200a451Timo Sirainen client->io = io_add(client->common.fd, IO_READ,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen client_auth_input, client);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen client_auth_input(client);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen client_unref(client);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainenstatic int client_auth_begin(struct imap_client *client, const char *mech_name,
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen const char *init_resp)
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen{
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen client_ref(client);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen sasl_server_auth_begin(&client->common, IMAP_SERVICE_NAME, mech_name,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen init_resp, sasl_callback);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen if (!client->common.authenticating)
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen return 1;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* don't handle input until we get the initial auth reply */
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen if (client->io != NULL)
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen io_remove(&client->io);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen client_set_auth_waiting(client);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen return 0;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
ddb018bc886680f462463b2c87f983fdedbf6cf0Timo Sirainenint cmd_authenticate(struct imap_client *client, const struct imap_arg *args)
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char *mech_name, *init_resp = NULL;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen /* we want only one argument: authentication mechanism name */
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen if (args[0].type != IMAP_ARG_ATOM && args[0].type != IMAP_ARG_STRING)
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen return -1;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen if (args[1].type != IMAP_ARG_EOL) {
37ee89f3cba22cd975912a882f0d3097fa5031e1Timo Sirainen /* optional SASL initial response */
37ee89f3cba22cd975912a882f0d3097fa5031e1Timo Sirainen if (args[1].type != IMAP_ARG_ATOM ||
37ee89f3cba22cd975912a882f0d3097fa5031e1Timo Sirainen args[2].type != IMAP_ARG_EOL)
37ee89f3cba22cd975912a882f0d3097fa5031e1Timo Sirainen return -1;
37ee89f3cba22cd975912a882f0d3097fa5031e1Timo Sirainen init_resp = IMAP_ARG_STR(&args[1]);
37ee89f3cba22cd975912a882f0d3097fa5031e1Timo Sirainen }
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mech_name = IMAP_ARG_STR(&args[0]);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (*mech_name == '\0')
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return client_auth_begin(client, mech_name, init_resp);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenint cmd_login(struct imap_client *client, const struct imap_arg *args)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char *user, *pass;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen string_t *plain_login, *base64;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* two arguments: username and password */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (args[0].type != IMAP_ARG_ATOM && args[0].type != IMAP_ARG_STRING)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (args[1].type != IMAP_ARG_ATOM && args[1].type != IMAP_ARG_STRING)
1f1ee8db68d9ae1604350801cd8dc33ebe29fe8aTimo Sirainen return -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (args[2].type != IMAP_ARG_EOL)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen user = IMAP_ARG_STR(&args[0]);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen pass = IMAP_ARG_STR(&args[1]);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (!client->common.secured && disable_plaintext_auth) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (verbose_auth) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen client_syslog(&client->common, "Login failed: "
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen "Plaintext authentication disabled");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen client->common.auth_tried_disabled_plaintext = TRUE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen client_send_line(client,
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen "* BAD [ALERT] Plaintext authentication is disabled, "
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen "but your client sent password in plaintext anyway. "
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen "If anyone was listening, the password was exposed.");
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen client_send_tagline(client, "NO "AUTH_PLAINTEXT_DISABLED_MSG);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen return 1;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen }
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
4fded1eec06aba9ce37887ac30619768760cd0d0Timo Sirainen /* authorization ID \0 authentication ID \0 pass */
4fded1eec06aba9ce37887ac30619768760cd0d0Timo Sirainen plain_login = buffer_create_dynamic(pool_datastack_create(), 64);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen buffer_append_c(plain_login, '\0');
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen buffer_append(plain_login, user, strlen(user));
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen buffer_append_c(plain_login, '\0');
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen buffer_append(plain_login, pass, strlen(pass));
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen base64 = buffer_create_dynamic(pool_datastack_create(),
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen MAX_BASE64_ENCODED_SIZE(plain_login->used));
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen base64_encode(plain_login->data, plain_login->used, base64);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return client_auth_begin(client, "PLAIN", str_c(base64));
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen