client-authenticate.c revision bc6294e4f0d7a54ff601257adaa44331a91b234e
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen/* Copyright (C) 2002 Timo Sirainen */
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "common.h"
49e358eebea107aad9919dcc4bd88cee8519ba2eTimo Sirainen#include "base64.h"
49e358eebea107aad9919dcc4bd88cee8519ba2eTimo Sirainen#include "buffer.h"
49e358eebea107aad9919dcc4bd88cee8519ba2eTimo Sirainen#include "ioloop.h"
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen#include "istream.h"
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen#include "ostream.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "safe-memset.h"
87a6b7df39d6822a5a8289a62f32deabff9b75e4Timo Sirainen#include "str.h"
87a6b7df39d6822a5a8289a62f32deabff9b75e4Timo Sirainen#include "imap-parser.h"
87a6b7df39d6822a5a8289a62f32deabff9b75e4Timo Sirainen#include "auth-client.h"
87a6b7df39d6822a5a8289a62f32deabff9b75e4Timo Sirainen#include "ssl-proxy.h"
87a6b7df39d6822a5a8289a62f32deabff9b75e4Timo Sirainen#include "client.h"
87a6b7df39d6822a5a8289a62f32deabff9b75e4Timo Sirainen#include "client-authenticate.h"
87a6b7df39d6822a5a8289a62f32deabff9b75e4Timo Sirainen#include "auth-common.h"
87a6b7df39d6822a5a8289a62f32deabff9b75e4Timo Sirainen#include "master.h"
87a6b7df39d6822a5a8289a62f32deabff9b75e4Timo Sirainen
7b29ccd796fc75af86f827192d2f8c0e8f0087bbTimo Sirainenconst char *client_authenticate_get_capabilities(int secured)
7b29ccd796fc75af86f827192d2f8c0e8f0087bbTimo Sirainen{
87a6b7df39d6822a5a8289a62f32deabff9b75e4Timo Sirainen const struct auth_mech_desc *mech;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen unsigned int i, count;
87a6b7df39d6822a5a8289a62f32deabff9b75e4Timo Sirainen string_t *str;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen str = t_str_new(128);
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen mech = auth_client_get_available_mechs(auth_client, &count);
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen for (i = 0; i < count; i++) {
da2aa032ccfa8e7e4a4380ef738014549f4d2c2dTimo Sirainen /* a) transport is secured
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen b) auth mechanism isn't plaintext
7b29ccd796fc75af86f827192d2f8c0e8f0087bbTimo Sirainen c) we allow insecure authentication
7b29ccd796fc75af86f827192d2f8c0e8f0087bbTimo Sirainen - but don't advertise AUTH=PLAIN, as RFC 2595 requires
7b29ccd796fc75af86f827192d2f8c0e8f0087bbTimo Sirainen */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (mech[i].advertise &&
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen (secured || !mech[i].plaintext)) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen str_append_c(str, ' ');
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen str_append(str, "AUTH=");
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen str_append(str, mech[i].name);
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen }
e93184a9055c2530366dfe617e07199603c399ddMartti Rannanjärvi }
43834f87bf431198f986e86052a4f6e558fdb07dTimo Sirainen
43834f87bf431198f986e86052a4f6e558fdb07dTimo Sirainen return str_c(str);
09801f106cd531a28b4e03ec665e44c421264560Timo Sirainen}
09801f106cd531a28b4e03ec665e44c421264560Timo Sirainen
09801f106cd531a28b4e03ec665e44c421264560Timo Sirainenstatic void client_auth_abort(struct imap_client *client, const char *msg)
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen{
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen client->authenticating = FALSE;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen
a9a928e40e3b691924c8e5e444e3e1a4320aa3bdStephan Bosch if (client->common.auth_request != NULL) {
a9a928e40e3b691924c8e5e444e3e1a4320aa3bdStephan Bosch auth_client_request_abort(client->common.auth_request);
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen client->common.auth_request = NULL;
212a34c06ff45952c008ae9eec387ced783de6cfPhil Carmody }
212a34c06ff45952c008ae9eec387ced783de6cfPhil Carmody
212a34c06ff45952c008ae9eec387ced783de6cfPhil Carmody client_send_tagline(client, msg != NULL ?
212a34c06ff45952c008ae9eec387ced783de6cfPhil Carmody t_strconcat("NO ", msg, NULL) :
a9a928e40e3b691924c8e5e444e3e1a4320aa3bdStephan Bosch "NO Authentication failed.");
a9a928e40e3b691924c8e5e444e3e1a4320aa3bdStephan Bosch o_stream_flush(client->output);
a9a928e40e3b691924c8e5e444e3e1a4320aa3bdStephan Bosch
a9a928e40e3b691924c8e5e444e3e1a4320aa3bdStephan Bosch /* get back to normal client input */
a9a928e40e3b691924c8e5e444e3e1a4320aa3bdStephan Bosch if (client->common.io != NULL)
a9a928e40e3b691924c8e5e444e3e1a4320aa3bdStephan Bosch io_remove(client->common.io);
a9a928e40e3b691924c8e5e444e3e1a4320aa3bdStephan Bosch client->common.io = client->common.fd == -1 ? NULL :
a9a928e40e3b691924c8e5e444e3e1a4320aa3bdStephan Bosch io_add(client->common.fd, IO_READ, client_input, client);
a9a928e40e3b691924c8e5e444e3e1a4320aa3bdStephan Bosch
10c96a244935de4add8213ba0b894178dfb889a5Timo Sirainen client_unref(client);
bdcb00145ad87765e3fd22d4ebc4d2c029a326b9Timo Sirainen}
bdcb00145ad87765e3fd22d4ebc4d2c029a326b9Timo Sirainen
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainenstatic void master_callback(struct client *_client, int success)
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen{
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen struct imap_client *client = (struct imap_client *) _client;
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen const char *reason = NULL;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen if (success) {
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen reason = t_strconcat("Login: ", client->common.virtual_user,
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen NULL);
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen } else {
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen reason = t_strconcat("Internal login failure: ",
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen client->common.virtual_user, NULL);
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen client_send_line(client, "* BYE Internal login failure.");
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen }
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen client_destroy(client, reason);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenstatic void client_send_auth_data(struct imap_client *client,
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen const unsigned char *data, size_t size)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen{
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen buffer_t *buf;
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen t_push();
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen buf = buffer_create_dynamic(pool_datastack_create(),
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen size*2, (size_t)-1);
27a44fcfd8d19bffe0f267f20a2b5d3fe7600fddTimo Sirainen buffer_append(buf, "+ ", 2);
27a44fcfd8d19bffe0f267f20a2b5d3fe7600fddTimo Sirainen base64_encode(data, size, buf);
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen buffer_append(buf, "\r\n", 2);
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen o_stream_send(client->output, buffer_get_data(buf, NULL),
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen buffer_get_used_size(buf));
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen o_stream_flush(client->output);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
46ce4d9273e6df12ef1912bbdb1c8b84b104f394Timo Sirainen t_pop();
46ce4d9273e6df12ef1912bbdb1c8b84b104f394Timo Sirainen}
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen
5af5137f6dc0c9f358b7813e941e26f7bd735b3aTimo Sirainenstatic void login_callback(struct auth_request *request,
5af5137f6dc0c9f358b7813e941e26f7bd735b3aTimo Sirainen struct auth_client_request_reply *reply,
5af5137f6dc0c9f358b7813e941e26f7bd735b3aTimo Sirainen const unsigned char *data, void *context)
5af5137f6dc0c9f358b7813e941e26f7bd735b3aTimo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct imap_client *client = context;
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen const char *error;
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen const void *ptr;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen size_t size;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen switch (auth_callback(request, reply, data, &client->common,
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen master_callback, &error)) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen case -1:
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen case 0:
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen /* login failed */
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen client_auth_abort(client, error);
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen break;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
71aed7ba87b5fd5e96e97a22d89ac025b883d60aTimo Sirainen default:
71aed7ba87b5fd5e96e97a22d89ac025b883d60aTimo Sirainen /* success, we should be able to log in. if we fail, just
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen disconnect the client. */
71aed7ba87b5fd5e96e97a22d89ac025b883d60aTimo Sirainen client->authenticating = FALSE;
19557f192d37cd54a1a090a8a26d9d47265e4413Aki Tuomi client_send_tagline(client, "OK Logged in.");
71aed7ba87b5fd5e96e97a22d89ac025b883d60aTimo Sirainen client_unref(client);
71aed7ba87b5fd5e96e97a22d89ac025b883d60aTimo Sirainen }
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainen}
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainenstatic enum auth_client_request_new_flags
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainenclient_get_auth_flags(struct imap_client *client)
463f6ea04af934a68facaca0ff089bc306de3f98Timo Sirainen{
463f6ea04af934a68facaca0ff089bc306de3f98Timo Sirainen enum auth_client_request_new_flags auth_flags = 0;
463f6ea04af934a68facaca0ff089bc306de3f98Timo Sirainen
463f6ea04af934a68facaca0ff089bc306de3f98Timo Sirainen if (client->common.proxy != NULL &&
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen ssl_proxy_has_valid_client_cert(client->common.proxy))
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen auth_flags |= AUTH_CLIENT_FLAG_SSL_VALID_CLIENT_CERT;
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen return auth_flags;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainenint cmd_login(struct imap_client *client, struct imap_arg *args)
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen{
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen const char *user, *pass, *error;
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen string_t *str;
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen /* two arguments: username and password */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (args[0].type != IMAP_ARG_ATOM && args[0].type != IMAP_ARG_STRING)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return FALSE;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen if (args[1].type != IMAP_ARG_ATOM && args[1].type != IMAP_ARG_STRING)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return FALSE;
87a6b7df39d6822a5a8289a62f32deabff9b75e4Timo Sirainen if (args[2].type != IMAP_ARG_EOL)
87a6b7df39d6822a5a8289a62f32deabff9b75e4Timo Sirainen return FALSE;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen user = IMAP_ARG_STR(&args[0]);
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen pass = IMAP_ARG_STR(&args[1]);
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen if (!client->secured && disable_plaintext_auth) {
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen client_send_line(client,
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen "* BAD [ALERT] Plaintext authentication is disabled, "
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen "but your client sent password in plaintext anyway. "
7d207b1e77a7b5e3fda640e353acfc86d261fedfTimo Sirainen "If anyone was listening, the password was exposed.");
7d207b1e77a7b5e3fda640e353acfc86d261fedfTimo Sirainen client_send_tagline(client,
7d207b1e77a7b5e3fda640e353acfc86d261fedfTimo Sirainen "NO Plaintext authentication disabled.");
7d207b1e77a7b5e3fda640e353acfc86d261fedfTimo Sirainen return TRUE;
7d207b1e77a7b5e3fda640e353acfc86d261fedfTimo Sirainen }
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen /* authorization ID \0 authentication ID \0 pass */
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen str = t_str_new(64);
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen str_append_c(str, '\0');
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen str_append(str, user);
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen str_append_c(str, '\0');
6a170d6d781094bdc75f027b6456dde160fbde39Timo Sirainen str_append(str, pass);
6a170d6d781094bdc75f027b6456dde160fbde39Timo Sirainen
6a170d6d781094bdc75f027b6456dde160fbde39Timo Sirainen client_ref(client);
6a170d6d781094bdc75f027b6456dde160fbde39Timo Sirainen
1bc075e2e4ed422f9590c95c3ae223422b97ce6aTimo Sirainen client->common.auth_request =
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainen auth_client_request_new(auth_client, "PLAIN", "IMAP",
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainen client_get_auth_flags(client),
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainen str_data(str), str_len(str),
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen login_callback,
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen client, &error);
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen if (client->common.auth_request == NULL) {
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen client_send_tagline(client, t_strconcat(
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen "NO Login failed: ", error, NULL));
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen client_unref(client);
a0b6b441fc679e562e79be0fb2819ffc24ab5b74Timo Sirainen return TRUE;
a0b6b441fc679e562e79be0fb2819ffc24ab5b74Timo Sirainen }
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen /* don't read any input from client until login is finished */
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen if (client->common.io != NULL) {
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen io_remove(client->common.io);
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen client->common.io = NULL;
6657aee0bb6c603b4ee5111388b93c1a8a9ad680Martti Rannanjärvi }
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen client->authenticating = TRUE;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return TRUE;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainenstatic void authenticate_callback(struct auth_request *request,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct auth_client_request_reply *reply,
699fdc186f982f70d990820796eaa0f12133e27cTimo Sirainen const unsigned char *data, void *context)
699fdc186f982f70d990820796eaa0f12133e27cTimo Sirainen{
699fdc186f982f70d990820796eaa0f12133e27cTimo Sirainen struct imap_client *client = context;
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen const char *error;
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen
09142ea11662746ea07475b1a4f69a6a406fb996Phil Carmody switch (auth_callback(request, reply, data, &client->common,
09142ea11662746ea07475b1a4f69a6a406fb996Phil Carmody master_callback, &error)) {
09142ea11662746ea07475b1a4f69a6a406fb996Phil Carmody case -1:
09142ea11662746ea07475b1a4f69a6a406fb996Phil Carmody /* login failed */
09142ea11662746ea07475b1a4f69a6a406fb996Phil Carmody client_auth_abort(client, error);
09142ea11662746ea07475b1a4f69a6a406fb996Phil Carmody break;
09142ea11662746ea07475b1a4f69a6a406fb996Phil Carmody
09142ea11662746ea07475b1a4f69a6a406fb996Phil Carmody case 0:
09142ea11662746ea07475b1a4f69a6a406fb996Phil Carmody /* continue */
573424407a2d3c1453638a643583a7cf10c129e1Phil Carmody client_send_auth_data(client, data, reply->data_size);
09142ea11662746ea07475b1a4f69a6a406fb996Phil Carmody break;
09142ea11662746ea07475b1a4f69a6a406fb996Phil Carmody default:
09142ea11662746ea07475b1a4f69a6a406fb996Phil Carmody /* success, we should be able to log in. if we fail, just
09142ea11662746ea07475b1a4f69a6a406fb996Phil Carmody disconnect the client. */
09142ea11662746ea07475b1a4f69a6a406fb996Phil Carmody client->authenticating = FALSE;
09142ea11662746ea07475b1a4f69a6a406fb996Phil Carmody client_send_tagline(client, "OK Logged in.");
09142ea11662746ea07475b1a4f69a6a406fb996Phil Carmody client_unref(client);
09142ea11662746ea07475b1a4f69a6a406fb996Phil Carmody }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainenstatic void client_auth_input(void *context)
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen{
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen struct imap_client *client = context;
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen buffer_t *buf;
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen char *line;
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen size_t linelen, bufsize;
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen if (!client_read(client)) {
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen client_unref(client);
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen return;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
if (client->skip_line) {
if (i_stream_next_line(client->input) == NULL)
return;
client->skip_line = FALSE;
}
/* @UNSAFE */
line = i_stream_next_line(client->input);
if (line == NULL)
return;
if (strcmp(line, "*") == 0) {
client_auth_abort(client, "Authentication aborted");
return;
}
linelen = strlen(line);
buf = buffer_create_static_hard(pool_datastack_create(), linelen);
if (base64_decode((const unsigned char *) line, linelen,
NULL, buf) <= 0) {
/* failed */
client_auth_abort(client, "Invalid base64 data");
} else if (client->common.auth_request == NULL) {
client_auth_abort(client, "Don't send unrequested data");
} else {
auth_client_request_continue(client->common.auth_request,
buffer_get_data(buf, NULL),
buffer_get_used_size(buf));
}
/* clear sensitive data */
safe_memset(line, 0, linelen);
bufsize = buffer_get_used_size(buf);
safe_memset(buffer_free_without_data(buf), 0, bufsize);
}
int cmd_authenticate(struct imap_client *client, struct imap_arg *args)
{
const struct auth_mech_desc *mech;
const char *mech_name, *error;
/* we want only one argument: authentication mechanism name */
if (args[0].type != IMAP_ARG_ATOM && args[0].type != IMAP_ARG_STRING)
return FALSE;
if (args[1].type != IMAP_ARG_EOL)
return FALSE;
mech_name = IMAP_ARG_STR(&args[0]);
if (*mech_name == '\0')
return FALSE;
mech = auth_client_find_mech(auth_client, mech_name);
if (mech == NULL) {
client_send_tagline(client,
"NO Unsupported authentication mechanism.");
return TRUE;
}
if (!client->secured && mech->plaintext && disable_plaintext_auth) {
client_send_tagline(client,
"NO Plaintext authentication disabled.");
return TRUE;
}
client_ref(client);
client->common.auth_request =
auth_client_request_new(auth_client, mech->name, "IMAP",
client_get_auth_flags(client),
NULL, 0, authenticate_callback,
client, &error);
if (client->common.auth_request != NULL) {
/* following input data will go to authentication */
if (client->common.io != NULL)
io_remove(client->common.io);
client->common.io = io_add(client->common.fd, IO_READ,
client_auth_input, client);
client->authenticating = TRUE;
} else {
client_send_tagline(client, t_strconcat(
"NO Authentication failed: ", error, NULL));
client_unref(client);
}
return TRUE;
}