client-authenticate.c revision 02ccba3d3be96444abd15b5254864c9151bbeb30
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2002-2007 Dovecot authors, see the included COPYING file */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "common.h"
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen#include "base64.h"
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen#include "buffer.h"
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen#include "ioloop.h"
0536ccb51d41e3078c3a9fa33e509fb4b2420f95Timo Sirainen#include "istream.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "ostream.h"
c2cda8cd0043443566efc5da30f79865508a1947Timo Sirainen#include "safe-memset.h"
c2cda8cd0043443566efc5da30f79865508a1947Timo Sirainen#include "str.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "str-sanitize.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "imap-parser.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "auth-client.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "client.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "client-authenticate.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "imap-proxy.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include <stdlib.h>
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#define IMAP_SERVICE_NAME "imap"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainenconst char *client_authenticate_get_capabilities(bool secured)
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen{
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen const struct auth_mech_desc *mech;
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen unsigned int i, count;
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen string_t *str;
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen str = t_str_new(128);
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen mech = auth_client_get_available_mechs(auth_client, &count);
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen for (i = 0; i < count; i++) {
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen /* a) transport is secured
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen b) auth mechanism isn't plaintext
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen c) we allow insecure authentication
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen */
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen if ((mech[i].flags & MECH_SEC_PRIVATE) == 0 &&
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen (secured || !disable_plaintext_auth ||
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen (mech[i].flags & MECH_SEC_PLAINTEXT) == 0)) {
d6684856fb99e51bc22a6346e08b2d81c996f963Josef 'Jeff' Sipek str_append_c(str, ' ');
d6684856fb99e51bc22a6346e08b2d81c996f963Josef 'Jeff' Sipek str_append(str, "AUTH=");
d6684856fb99e51bc22a6346e08b2d81c996f963Josef 'Jeff' Sipek str_append(str, mech[i].name);
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen }
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen }
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen return str_c(str);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainenstatic void client_auth_input(struct imap_client *client)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen char *line;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (!client_read(client))
b3fc5293379feb3640b23622bcc8f5f8d7f1e81dJosef 'Jeff' Sipek return;
b3fc5293379feb3640b23622bcc8f5f8d7f1e81dJosef 'Jeff' Sipek
b3fc5293379feb3640b23622bcc8f5f8d7f1e81dJosef 'Jeff' Sipek if (client->skip_line) {
b3fc5293379feb3640b23622bcc8f5f8d7f1e81dJosef 'Jeff' Sipek if (i_stream_next_line(client->input) == NULL)
b3fc5293379feb3640b23622bcc8f5f8d7f1e81dJosef 'Jeff' Sipek return;
b3fc5293379feb3640b23622bcc8f5f8d7f1e81dJosef 'Jeff' Sipek
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen client->skip_line = FALSE;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen }
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen /* @UNSAFE */
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen line = i_stream_next_line(client->input);
5a1b498b646b5c5dbd1b3f3861df766f560578c5Timo Sirainen if (line == NULL)
204ee6ed414f5e4eeb6f6c10763b55daf56f11acJosef 'Jeff' Sipek return;
5a1b498b646b5c5dbd1b3f3861df766f560578c5Timo Sirainen
5a1b498b646b5c5dbd1b3f3861df766f560578c5Timo Sirainen if (strcmp(line, "*") == 0) {
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen sasl_server_auth_client_error(&client->common,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen "Authentication aborted");
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen } else {
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen auth_client_request_continue(client->common.auth_request, line);
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen io_remove(&client->io);
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen /* clear sensitive data */
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen safe_memset(line, 0, strlen(line));
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen }
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen}
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainenstatic bool client_handle_args(struct imap_client *client,
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen const char *const *args, bool success)
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen{
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen const char *reason = NULL, *host = NULL, *destuser = NULL, *pass = NULL;
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen string_t *reply;
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen unsigned int port = 143;
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen bool proxy = FALSE, temp = FALSE, nologin = !success;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen for (; *args != NULL; args++) {
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen if (strcmp(*args, "nologin") == 0)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen nologin = TRUE;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen else if (strcmp(*args, "proxy") == 0)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen proxy = TRUE;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen else if (strcmp(*args, "temp") == 0)
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen temp = TRUE;
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen else if (strncmp(*args, "reason=", 7) == 0)
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen reason = *args + 7;
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen else if (strncmp(*args, "host=", 5) == 0)
46ce4d9273e6df12ef1912bbdb1c8b84b104f394Timo Sirainen host = *args + 5;
46ce4d9273e6df12ef1912bbdb1c8b84b104f394Timo Sirainen else if (strncmp(*args, "port=", 5) == 0)
46ce4d9273e6df12ef1912bbdb1c8b84b104f394Timo Sirainen port = atoi(*args + 5);
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen else if (strncmp(*args, "destuser=", 9) == 0)
46ce4d9273e6df12ef1912bbdb1c8b84b104f394Timo Sirainen destuser = *args + 9;
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen else if (strncmp(*args, "pass=", 5) == 0)
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen pass = *args + 5;
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen }
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen if (destuser == NULL)
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen destuser = client->common.virtual_user;
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen if (proxy &&
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen !login_proxy_is_ourself(&client->common, host, port, destuser)) {
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen /* we want to proxy the connection to another server.
5af5137f6dc0c9f358b7813e941e26f7bd735b3aTimo Sirainen don't do this unless authentication succeeded. with
5af5137f6dc0c9f358b7813e941e26f7bd735b3aTimo Sirainen master user proxying we can get FAIL with proxy still set.
5af5137f6dc0c9f358b7813e941e26f7bd735b3aTimo Sirainen
5af5137f6dc0c9f358b7813e941e26f7bd735b3aTimo Sirainen proxy host=.. [port=..] [destuser=..] pass=.. */
5af5137f6dc0c9f358b7813e941e26f7bd735b3aTimo Sirainen if (!success)
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen return FALSE;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (imap_proxy_new(client, host, port, destuser, pass) < 0)
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen client_destroy_internal_failure(client);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return TRUE;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen if (!proxy && host != NULL) {
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen /* IMAP referral
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen [nologin] referral host=.. [port=..] [destuser=..]
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen [reason=..]
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen NO [REFERRAL imap://destuser;AUTH=..@host:port/] Can't login.
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen OK [...] Logged in, but you should use this server instead.
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen .. [REFERRAL ..] (Reason from auth server)
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainen */
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainen reply = t_str_new(128);
71aed7ba87b5fd5e96e97a22d89ac025b883d60aTimo Sirainen str_append(reply, nologin ? "NO " : "OK ");
71aed7ba87b5fd5e96e97a22d89ac025b883d60aTimo Sirainen str_printfa(reply, "[REFERRAL imap://%s;AUTH=%s@%s",
71aed7ba87b5fd5e96e97a22d89ac025b883d60aTimo Sirainen destuser, client->common.auth_mech_name, host);
71aed7ba87b5fd5e96e97a22d89ac025b883d60aTimo Sirainen if (port != 143)
71aed7ba87b5fd5e96e97a22d89ac025b883d60aTimo Sirainen str_printfa(reply, ":%u", port);
71aed7ba87b5fd5e96e97a22d89ac025b883d60aTimo Sirainen str_append(reply, "/] ");
71aed7ba87b5fd5e96e97a22d89ac025b883d60aTimo Sirainen if (reason != NULL)
71aed7ba87b5fd5e96e97a22d89ac025b883d60aTimo Sirainen str_append(reply, reason);
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainen else if (nologin)
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainen str_append(reply, "Try this server instead.");
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen else {
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen str_append(reply, "Logged in, but you should use "
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen "this server instead.");
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen }
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen client_send_tagline(client, str_c(reply));
463f6ea04af934a68facaca0ff089bc306de3f98Timo Sirainen if (!nologin) {
463f6ea04af934a68facaca0ff089bc306de3f98Timo Sirainen client_destroy(client, "Login with referral");
463f6ea04af934a68facaca0ff089bc306de3f98Timo Sirainen return TRUE;
463f6ea04af934a68facaca0ff089bc306de3f98Timo Sirainen }
463f6ea04af934a68facaca0ff089bc306de3f98Timo Sirainen } else if (nologin) {
463f6ea04af934a68facaca0ff089bc306de3f98Timo Sirainen /* Authentication went ok, but for some reason user isn't
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen allowed to log in. Shouldn't probably happen. */
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen reply = t_str_new(128);
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen if (reason != NULL)
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen str_printfa(reply, "NO %s", reason);
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen else if (temp)
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen str_append(reply, "NO "AUTH_TEMP_FAILED_MSG);
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen else
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen str_append(reply, "NO "AUTH_FAILED_MSG);
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen client_send_tagline(client, str_c(reply));
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen } else {
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen /* normal login/failure */
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen return FALSE;
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen }
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen i_assert(nologin);
463f6ea04af934a68facaca0ff089bc306de3f98Timo Sirainen
463f6ea04af934a68facaca0ff089bc306de3f98Timo Sirainen if (!client->destroyed) {
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen /* get back to normal client input. */
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen if (client->io != NULL)
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen io_remove(&client->io);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen client->io = io_add(client->common.fd, IO_READ,
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen client_input, client);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen }
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen return TRUE;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen}
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainenstatic void sasl_callback(struct client *_client, enum sasl_server_reply reply,
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen const char *data, const char *const *args)
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct imap_client *client = (struct imap_client *)_client;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct const_iovec iov[3];
0892446b45c195461bb7be6599f02d97e1e2c9b2Timo Sirainen const char *msg;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen size_t data_len;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
a2738cdb6d2733fb3e186331d68009421a19ea00Timo Sirainen i_assert(!client->destroyed ||
fb502495e9306fe51e9d2c0019e622a98e9803abTimo Sirainen reply == SASL_SERVER_REPLY_CLIENT_ERROR ||
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen reply == SASL_SERVER_REPLY_MASTER_FAILED);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen switch (reply) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen case SASL_SERVER_REPLY_SUCCESS:
9e095dd6a77097356aca8216356d4d71ef1bea45Timo Sirainen if (args != NULL) {
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen if (client_handle_args(client, args, TRUE))
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen break;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen }
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
0892446b45c195461bb7be6599f02d97e1e2c9b2Timo Sirainen client_send_tagline(client, "OK Logged in.");
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen client_destroy(client, "Login");
7af4788b402346c94496095dd819f95ce03fe431Timo Sirainen break;
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen case SASL_SERVER_REPLY_AUTH_FAILED:
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen case SASL_SERVER_REPLY_CLIENT_ERROR:
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen if (args != NULL) {
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen if (client_handle_args(client, args, FALSE))
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen break;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen }
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen msg = reply == SASL_SERVER_REPLY_AUTH_FAILED ? "NO " : "BAD ";
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen msg = t_strconcat(msg, data != NULL ? data : AUTH_FAILED_MSG,
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen NULL);
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen client_send_tagline(client, msg);
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen
c24ef531ca58abad996482f5c2e8992be9ae8981Timo Sirainen if (!client->destroyed) {
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen /* get back to normal client input. */
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen if (client->io != NULL)
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen io_remove(&client->io);
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen client->io = io_add(client->common.fd, IO_READ,
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen client_input, client);
e4c81823af1fc43ca3f2ce9eb4af7fc8f57b13a5Timo Sirainen }
e4c81823af1fc43ca3f2ce9eb4af7fc8f57b13a5Timo Sirainen break;
2524ef7b34965a1b1895d6140fd8296bf57c78d2Timo Sirainen case SASL_SERVER_REPLY_MASTER_FAILED:
0892446b45c195461bb7be6599f02d97e1e2c9b2Timo Sirainen if (data == NULL)
e4c81823af1fc43ca3f2ce9eb4af7fc8f57b13a5Timo Sirainen client_destroy_internal_failure(client);
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen else {
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen client_send_tagline(client,
fb502495e9306fe51e9d2c0019e622a98e9803abTimo Sirainen t_strconcat("NO ", data, NULL));
fb502495e9306fe51e9d2c0019e622a98e9803abTimo Sirainen client_destroy(client, data);
fb502495e9306fe51e9d2c0019e622a98e9803abTimo Sirainen }
fb502495e9306fe51e9d2c0019e622a98e9803abTimo Sirainen break;
fb502495e9306fe51e9d2c0019e622a98e9803abTimo Sirainen case SASL_SERVER_REPLY_CONTINUE:
fb502495e9306fe51e9d2c0019e622a98e9803abTimo Sirainen data_len = strlen(data);
fb502495e9306fe51e9d2c0019e622a98e9803abTimo Sirainen iov[0].iov_base = "+ ";
fb502495e9306fe51e9d2c0019e622a98e9803abTimo Sirainen iov[0].iov_len = 2;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen iov[1].iov_base = data;
c2cda8cd0043443566efc5da30f79865508a1947Timo Sirainen iov[1].iov_len = data_len;
c2cda8cd0043443566efc5da30f79865508a1947Timo Sirainen iov[2].iov_base = "\r\n";
c2cda8cd0043443566efc5da30f79865508a1947Timo Sirainen iov[2].iov_len = 2;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* don't check return value here. it gets tricky if we try
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen to call client_destroy() in here. */
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen (void)o_stream_sendv(client->output, iov, 3);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen i_assert(client->io == NULL);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen client->io = io_add(client->common.fd, IO_READ,
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen client_auth_input, client);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen client_auth_input(client);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen return;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen }
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen client_unref(client);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen}
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainenint cmd_authenticate(struct imap_client *client, const struct imap_arg *args)
66dc739bb67d678770e1b7a7bc75f4f6f9523d2aTimo Sirainen{
66dc739bb67d678770e1b7a7bc75f4f6f9523d2aTimo Sirainen const char *mech_name, *init_resp = NULL;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
66dc739bb67d678770e1b7a7bc75f4f6f9523d2aTimo Sirainen /* we want only one argument: authentication mechanism name */
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen if (args[0].type != IMAP_ARG_ATOM && args[0].type != IMAP_ARG_STRING)
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen return -1;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen if (args[1].type != IMAP_ARG_EOL) {
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen /* optional SASL initial response */
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen if (args[1].type != IMAP_ARG_ATOM ||
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen args[2].type != IMAP_ARG_EOL)
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen return -1;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen init_resp = IMAP_ARG_STR(&args[1]);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen }
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen mech_name = IMAP_ARG_STR(&args[0]);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen if (*mech_name == '\0')
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen return -1;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
c6b6ac7819931dfa92c0182ffaa7db07ac6ab0daTimo Sirainen client_ref(client);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen sasl_server_auth_begin(&client->common, IMAP_SERVICE_NAME, mech_name,
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen init_resp, sasl_callback);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen if (!client->common.authenticating)
785ee8becdb11e41abaaf64c28eb3923215d1f27Timo Sirainen return 1;
785ee8becdb11e41abaaf64c28eb3923215d1f27Timo Sirainen
785ee8becdb11e41abaaf64c28eb3923215d1f27Timo Sirainen /* don't handle input until we get the initial auth reply */
785ee8becdb11e41abaaf64c28eb3923215d1f27Timo Sirainen if (client->io != NULL)
785ee8becdb11e41abaaf64c28eb3923215d1f27Timo Sirainen io_remove(&client->io);
785ee8becdb11e41abaaf64c28eb3923215d1f27Timo Sirainen return 0;
785ee8becdb11e41abaaf64c28eb3923215d1f27Timo Sirainen}
785ee8becdb11e41abaaf64c28eb3923215d1f27Timo Sirainen
785ee8becdb11e41abaaf64c28eb3923215d1f27Timo Sirainenint cmd_login(struct imap_client *client, const struct imap_arg *args)
785ee8becdb11e41abaaf64c28eb3923215d1f27Timo Sirainen{
785ee8becdb11e41abaaf64c28eb3923215d1f27Timo Sirainen const char *user, *pass;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen string_t *plain_login, *base64;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen /* two arguments: username and password */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (args[0].type != IMAP_ARG_ATOM && args[0].type != IMAP_ARG_STRING)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return -1;
20344c0e814139e3c365fbb9287478f91512089eTimo Sirainen if (args[1].type != IMAP_ARG_ATOM && args[1].type != IMAP_ARG_STRING)
20344c0e814139e3c365fbb9287478f91512089eTimo Sirainen return -1;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (args[2].type != IMAP_ARG_EOL)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return -1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
463f6ea04af934a68facaca0ff089bc306de3f98Timo Sirainen user = IMAP_ARG_STR(&args[0]);
463f6ea04af934a68facaca0ff089bc306de3f98Timo Sirainen pass = IMAP_ARG_STR(&args[1]);
463f6ea04af934a68facaca0ff089bc306de3f98Timo Sirainen
54bd0fec0be357266e299466a582f3c9269884e9Timo Sirainen if (!client->common.secured && disable_plaintext_auth) {
463f6ea04af934a68facaca0ff089bc306de3f98Timo Sirainen if (verbose_auth) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen client_syslog(&client->common, "Login failed: "
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen "Plaintext authentication disabled");
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen client->common.auth_tried_disabled_plaintext = TRUE;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen client_send_line(client,
20344c0e814139e3c365fbb9287478f91512089eTimo Sirainen "* BAD [ALERT] Plaintext authentication is disabled, "
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen "but your client sent password in plaintext anyway. "
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen "If anyone was listening, the password was exposed.");
52041ed691a26ca80e4e805765e9f55ec097c8f1Martti Rannanjärvi client_send_tagline(client, "NO "AUTH_PLAINTEXT_DISABLED_MSG);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen return 1;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen }
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* authorization ID \0 authentication ID \0 pass */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen plain_login = buffer_create_dynamic(pool_datastack_create(), 64);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen buffer_append_c(plain_login, '\0');
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen buffer_append(plain_login, user, strlen(user));
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen buffer_append_c(plain_login, '\0');
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen buffer_append(plain_login, pass, strlen(pass));
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen base64 = buffer_create_dynamic(pool_datastack_create(),
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen MAX_BASE64_ENCODED_SIZE(plain_login->used));
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen base64_encode(plain_login->data, plain_login->used, base64);
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen client_ref(client);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen sasl_server_auth_begin(&client->common, IMAP_SERVICE_NAME, "PLAIN",
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen str_c(base64), sasl_callback);
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen if (!client->common.authenticating)
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen return 1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen /* don't read any input from client until login is finished */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (client->io != NULL)
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen io_remove(&client->io);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
601f5f14c6cde28f0e0c6ca7c5d735315d3d48dfTimo Sirainen return 0;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen}
a85c629c5d75a5fd9489ba14d5d4f54f3cddd591Aki Tuomi