client-authenticate.c revision 0442399c3ad313d6f5267c182ddb9012e525941d
e59faf65ce864fe95dc00f5d52b8323cdbd0608aTimo Sirainen/* Copyright (C) 2002-2004 Timo Sirainen */
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
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenconst char *client_authenticate_get_capabilities(int secured)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const struct auth_mech_desc *mech;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int i, count;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen string_t *str;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo 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++) {
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainen /* a) transport is secured
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainen b) auth mechanism isn't plaintext
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen c) we allow insecure authentication
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((mech[i].flags & MECH_SEC_PRIVATE) == 0 &&
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen (secured || !disable_plaintext_auth ||
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo 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 }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return str_c(str);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic void client_auth_input(void *context)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
d22301419109ed4a38351715e6760011421dadecTimo Sirainen struct imap_client *client = context;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen char *line;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
5b62dea2f88165f3f4d87bba9011343f3ff415ffTimo Sirainen if (!client_read(client))
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo 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 }
8f4d8c489a992a5f0dca8a263968544c1c669779Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* @UNSAFE */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen line = i_stream_next_line(client->input);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (line == NULL)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (strcmp(line, "*") == 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen sasl_server_auth_cancel(&client->common,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen "Authentication aborted");
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen return;
73a87c2ff65c6116cde6fb158dfddb8ef7346901Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (client->common.auth_request == NULL) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen sasl_server_auth_cancel(&client->common,
73a87c2ff65c6116cde6fb158dfddb8ef7346901Timo Sirainen "Don't send unrequested data");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen } else {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen auth_client_request_continue(client->common.auth_request, line);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* clear sensitive data */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen safe_memset(line, 0, strlen(line));
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic int client_handle_success_args(struct imap_client *client,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char *const *args, int nologin)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char *reason = NULL, *referral = NULL;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen string_t *reply;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen for (; *args != NULL; args++) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (strcmp(*args, "nologin") == 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen nologin = TRUE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen else if (strncmp(*args, "reason=", 7) == 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen reason = *args + 7;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen else if (strncmp(*args, "referral=", 9) == 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen referral = *args + 9;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen if (!nologin && referral == NULL)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return FALSE;
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen reply = t_str_new(128);
d22301419109ed4a38351715e6760011421dadecTimo Sirainen str_append(reply, nologin ? "NO " : "OK ");
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen if (referral != NULL)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_printfa(reply, "[REFERRAL %s] ", referral);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (reason != NULL)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_append(reply, reason);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen else if (!nologin)
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen str_append(reply, "Logged in.");
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen else if (referral != NULL)
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen str_append(reply, "Try this server instead.");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen else
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_append(reply, "Login disabled.");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen client_send_tagline(client, str_c(reply));
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (!nologin) {
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen client_destroy(client, t_strconcat(
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen "Login: ", client->common.virtual_user, NULL));
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen } else {
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen /* get back to normal client input. */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (client->io != NULL)
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen io_remove(client->io);
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen client->io = io_add(client->common.fd, IO_READ,
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen client_input, client);
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen }
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen return TRUE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic void sasl_callback(struct client *_client, enum sasl_server_reply reply,
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen const char *data, const char *const *args)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct imap_client *client = (struct imap_client *)_client;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct const_iovec iov[3];
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen size_t data_len;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen ssize_t ret;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen switch (reply) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen case SASL_SERVER_REPLY_SUCCESS:
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (args != NULL) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (client_handle_success_args(client, args, FALSE))
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen break;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen client_send_tagline(client, "OK Logged in.");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen client_destroy(client, t_strconcat(
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen "Login: ", client->common.virtual_user, NULL));
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen break;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen case SASL_SERVER_REPLY_AUTH_FAILED:
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (args != NULL) {
d22301419109ed4a38351715e6760011421dadecTimo Sirainen if (client_handle_success_args(client, args, TRUE))
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen break;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
65b94e73c305dcb209cf958f938b93ec061c67a9Timo Sirainen if (data == NULL)
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen client_send_tagline(client, "Authentication failed");
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen else {
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen client_send_tagline(client, t_strconcat(
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen "NO Authentication failed: ", data, NULL));
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
73a87c2ff65c6116cde6fb158dfddb8ef7346901Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* get back to normal client input. */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (client->io != NULL)
73a87c2ff65c6116cde6fb158dfddb8ef7346901Timo Sirainen io_remove(client->io);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen client->io = io_add(client->common.fd, IO_READ,
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen client_input, client);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen break;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen case SASL_SERVER_REPLY_MASTER_FAILED:
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen client_send_line(client, "* BYE Internal login failure. "
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen "Refer to server log for more information.");
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen client_destroy(client, t_strconcat("Internal login failure: ",
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen client->common.virtual_user,
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen NULL));
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen break;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen case SASL_SERVER_REPLY_CONTINUE:
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen data_len = strlen(data);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen iov[0].iov_base = "+ ";
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen iov[0].iov_len = 2;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen iov[1].iov_base = data;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo 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 ret = o_stream_sendv(client->output, iov, 3);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (ret < 0)
5b62dea2f88165f3f4d87bba9011343f3ff415ffTimo Sirainen client_destroy(client, "Disconnected");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen else if ((size_t)ret != 2 + data_len + 2)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen client_destroy(client, "Transmit buffer full");
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen else {
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen /* continue */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen break;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen client_unref(client);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen}
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainenint cmd_authenticate(struct imap_client *client, struct imap_arg *args)
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char *mech_name;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen /* we want only one argument: authentication mechanism name */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo 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)
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen return -1;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen mech_name = IMAP_ARG_STR(&args[0]);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen if (*mech_name == '\0')
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen return FALSE;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen client_ref(client);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen sasl_server_auth_begin(&client->common, "IMAP", mech_name, NULL,
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen sasl_callback);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (!client->common.authenticating)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return 1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen /* following input data will go to authentication */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (client->io != NULL)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen io_remove(client->io);
d22301419109ed4a38351715e6760011421dadecTimo Sirainen client->io = io_add(client->common.fd, IO_READ,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen client_auth_input, client);
3f91e60401495a4046c73992fabaa5e77200a451Timo Sirainen return 0;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenint cmd_login(struct imap_client *client, struct imap_arg *args)
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen{
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen const char *user, *pass;
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen string_t *plain_login, *base64;
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo 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;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen if (args[1].type != IMAP_ARG_ATOM && args[1].type != IMAP_ARG_STRING)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
d22301419109ed4a38351715e6760011421dadecTimo 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) {
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen if (verbose_auth) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen client_syslog(&client->common, "Login failed: "
3f91e60401495a4046c73992fabaa5e77200a451Timo Sirainen "Plaintext authentication disabled");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen client_send_line(client,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen "* BAD [ALERT] Plaintext authentication is disabled, "
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen "but your client sent password in plaintext anyway. "
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen "If anyone was listening, the password was exposed.");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen client_send_tagline(client,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen "NO Plaintext authentication disabled.");
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen return 1;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen }
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen /* authorization ID \0 authentication ID \0 pass */
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen plain_login = buffer_create_dynamic(pool_datastack_create(), 64);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen buffer_append_c(plain_login, '\0');
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen buffer_append(plain_login, user, strlen(user));
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen buffer_append_c(plain_login, '\0');
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen buffer_append(plain_login, pass, strlen(pass));
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen base64 = buffer_create_dynamic(pool_datastack_create(),
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen MAX_BASE64_ENCODED_SIZE(plain_login->used));
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen base64_encode(plain_login->data, plain_login->used, base64);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen client_ref(client);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen sasl_server_auth_begin(&client->common, "IMAP", "PLAIN",
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_c(base64), sasl_callback);
ddb018bc886680f462463b2c87f983fdedbf6cf0Timo Sirainen if (!client->common.authenticating)
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen return 1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* don't read any input from client until login is finished */
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen if (client->io != NULL) {
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen io_remove(client->io);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen client->io = NULL;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen }
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return 0;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen