client-authenticate.c revision 9eb98cb3f9139afaaaf84b789b70abd1d0890932
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (C) 2002 Timo Sirainen */
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
08d6658a4e2ec8104cd1307f6baa75fdb07a24f8Mark Washenberger#include "common.h"
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen#include "base64.h"
6789ed17e7ca4021713507baf0dcf6979bb42e0cTimo Sirainen#include "buffer.h"
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen#include "ioloop.h"
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen#include "istream.h"
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen#include "ostream.h"
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen#include "safe-memset.h"
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen#include "str.h"
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen#include "imap-parser.h"
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen#include "auth-client.h"
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen#include "../auth/auth-mech-desc.h"
08d6658a4e2ec8104cd1307f6baa75fdb07a24f8Mark Washenberger#include "client.h"
06ff2a72c39cb34cc6425f17fc82c5e93fef2018Timo Sirainen#include "client-authenticate.h"
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen#include "auth-common.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "master.h"
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenconst char *client_authenticate_get_capabilities(int secured)
de76b960297406115cf6bae473f004c08174b16aTimo Sirainen{
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen static enum auth_mech cached_auth_mechs = 0;
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen static char *cached_capability = NULL;
c519de264df14a9d525e2604671c332590ce54e3Timo Sirainen enum auth_mech auth_mechs;
61530b48694398df42744204e35535dbe3f745c4Timo Sirainen string_t *str;
61530b48694398df42744204e35535dbe3f745c4Timo Sirainen int i;
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen
2b3b0df76184799317584b596af8df5afec3ebddTimo Sirainen auth_mechs = auth_client_get_available_mechs(auth_client);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (auth_mechs == cached_auth_mechs)
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen return cached_capability;
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen
6789ed17e7ca4021713507baf0dcf6979bb42e0cTimo Sirainen cached_auth_mechs = auth_mechs;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen i_free(cached_capability);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
6789ed17e7ca4021713507baf0dcf6979bb42e0cTimo Sirainen str = t_str_new(128);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen for (i = 0; i < AUTH_MECH_COUNT; i++) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if ((auth_mechs & auth_mech_desc[i].mech) == 0)
2b3b0df76184799317584b596af8df5afec3ebddTimo Sirainen continue; /* not available */
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen
6789ed17e7ca4021713507baf0dcf6979bb42e0cTimo Sirainen /* a) transport is secured
6789ed17e7ca4021713507baf0dcf6979bb42e0cTimo Sirainen b) auth mechanism isn't plaintext
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen c) we allow insecure authentication
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen - but don't advertise AUTH=PLAIN, as RFC 2595 requires
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen */
d244c6cadd5f077f5d0f1e00c3652d0108a2d908Timo Sirainen if (secured || !auth_mech_desc[i].plaintext ||
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen (!disable_plaintext_auth &&
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen auth_mech_desc[i].mech != AUTH_MECH_PLAIN)) {
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen str_append_c(str, ' ');
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen str_append(str, "AUTH=");
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen str_append(str, auth_mech_desc[i].name);
d244c6cadd5f077f5d0f1e00c3652d0108a2d908Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen cached_capability = i_strdup_empty(str_c(str));
d244c6cadd5f077f5d0f1e00c3652d0108a2d908Timo Sirainen return cached_capability;
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen}
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen
baf1148108b7d9739626b47cc57298c36929586aTimo Sirainenstatic struct auth_mech_desc *auth_mech_find(const char *name)
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen{
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen int i;
baf1148108b7d9739626b47cc57298c36929586aTimo Sirainen
baf1148108b7d9739626b47cc57298c36929586aTimo Sirainen for (i = 0; i < AUTH_MECH_COUNT; i++) {
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen if (auth_mech_desc[i].name != NULL &&
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen strcasecmp(auth_mech_desc[i].name, name) == 0)
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen return &auth_mech_desc[i];
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen }
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen return NULL;
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen}
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainenstatic void client_auth_abort(struct imap_client *client, const char *msg)
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen{
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen client->authenticating = FALSE;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen if (client->common.auth_request != NULL) {
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen auth_client_request_abort(client->common.auth_request);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen client->common.auth_request = NULL;
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen }
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen client_send_tagline(client, msg != NULL ?
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen t_strconcat("NO ", msg, NULL) :
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen "NO Authentication failed.");
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen o_stream_flush(client->output);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen /* get back to normal client input */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (client->common.io != NULL)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen io_remove(client->common.io);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen client->common.io = client->common.fd == -1 ? NULL :
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen io_add(client->common.fd, IO_READ, client_input, client);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen client_unref(client);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen}
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenstatic void master_callback(struct client *_client, int success)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen{
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen struct imap_client *client = (struct imap_client *) _client;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen const char *reason = NULL;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (success) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen reason = t_strconcat("Login: ", client->common.virtual_user,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen NULL);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen } else {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen reason = t_strconcat("Internal login failure: ",
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen client->common.virtual_user, NULL);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen client_send_line(client, "* BYE Internal login failure.");
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen }
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen client_destroy(client, reason);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen}
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenstatic void client_send_auth_data(struct imap_client *client,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen const unsigned char *data, size_t size)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen{
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen buffer_t *buf;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen t_push();
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen buf = buffer_create_dynamic(pool_datastack_create(),
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen size*2, (size_t)-1);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen buffer_append(buf, "+ ", 2);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen base64_encode(data, size, buf);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen buffer_append(buf, "\r\n", 2);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen o_stream_send(client->output, buffer_get_data(buf, NULL),
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen buffer_get_used_size(buf));
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen o_stream_flush(client->output);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen
8039af9679af6fb56116b353fe44f7dd4c08f031Timo Sirainen t_pop();
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen}
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenstatic void login_callback(struct auth_request *request,
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen struct auth_client_request_reply *reply,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen const unsigned char *data, void *context)
3a985b4f3481d7061ee0c6ace3a5bb0bcbcb67adTimo Sirainen{
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen struct imap_client *client = context;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen const char *error;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen const void *ptr;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen size_t size;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen switch (auth_callback(request, reply, data, &client->common,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen master_callback, &error)) {
3a985b4f3481d7061ee0c6ace3a5bb0bcbcb67adTimo Sirainen case -1:
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen /* login failed */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen client_auth_abort(client, error);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen break;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen case 0:
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen /* continue */
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen ptr = buffer_get_data(client->plain_login, &size);
2cfe9983ce7a6280636ee12beccc2e865111967bTimo Sirainen auth_client_request_continue(request, ptr, size);
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen buffer_set_used_size(client->plain_login, 0);
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen break;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen default:
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen /* success, we should be able to log in. if we fail, just
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen disconnect the client. */
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen client->authenticating = FALSE;
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen client_send_tagline(client, "OK Logged in.");
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen client_unref(client);
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen }
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen}
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainenint cmd_login(struct imap_client *client, struct imap_arg *args)
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen{
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen const char *user, *pass, *error;
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen /* two arguments: username and password */
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (args[0].type != IMAP_ARG_ATOM && args[0].type != IMAP_ARG_STRING)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return FALSE;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (args[1].type != IMAP_ARG_ATOM && args[1].type != IMAP_ARG_STRING)
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen return FALSE;
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen if (args[2].type != IMAP_ARG_EOL)
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen return FALSE;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen user = IMAP_ARG_STR(&args[0]);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen pass = IMAP_ARG_STR(&args[1]);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (!client->secured && disable_plaintext_auth) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen client_send_line(client,
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen "* BAD [ALERT] Plaintext authentication is disabled, "
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen "but your client sent password in plaintext anyway. "
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen "If anyone was listening, the password was exposed.");
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen client_send_tagline(client,
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen "NO Plaintext authentication disabled.");
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return TRUE;
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen }
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen /* authorization ID \0 authentication ID \0 pass */
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen buffer_set_used_size(client->plain_login, 0);
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen buffer_append_c(client->plain_login, '\0');
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen buffer_append(client->plain_login, user, strlen(user));
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen buffer_append_c(client->plain_login, '\0');
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen buffer_append(client->plain_login, pass, strlen(pass));
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen client_ref(client);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen client->common.auth_request =
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen auth_client_request_new(auth_client, AUTH_MECH_PLAIN,
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen AUTH_PROTOCOL_IMAP, login_callback,
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen client, &error);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen if (client->common.auth_request == NULL) {
905951e448e0d0f0778f43ce7673d0cac60b9b61Timo Sirainen client_send_tagline(client, t_strconcat(
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen "NO Login failed: ", error, NULL));
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen client_unref(client);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen return TRUE;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen }
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen /* don't read any input from client until login is finished */
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen if (client->common.io != NULL) {
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen io_remove(client->common.io);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen client->common.io = NULL;
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen }
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen
905951e448e0d0f0778f43ce7673d0cac60b9b61Timo Sirainen client->authenticating = TRUE;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen return TRUE;
905951e448e0d0f0778f43ce7673d0cac60b9b61Timo Sirainen}
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainenstatic void authenticate_callback(struct auth_request *request,
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen struct auth_client_request_reply *reply,
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen const unsigned char *data, void *context)
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen{
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen struct imap_client *client = context;
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen const char *error;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen switch (auth_callback(request, reply, data, &client->common,
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen master_callback, &error)) {
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen case -1:
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen /* login failed */
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen client_auth_abort(client, error);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen break;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen case 0:
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen /* continue */
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen client_send_auth_data(client, data, reply->data_size);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen break;
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen default:
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen /* success, we should be able to log in. if we fail, just
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen disconnect the client. */
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen client->authenticating = FALSE;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen client_send_tagline(client, "OK Logged in.");
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen client_unref(client);
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen }
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen}
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainenstatic void client_auth_input(void *context)
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen{
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen struct imap_client *client = context;
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen buffer_t *buf;
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen char *line;
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen size_t linelen, bufsize;
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen if (!client_read(client)) {
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen client_unref(client);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen return;
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen }
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen if (client->skip_line) {
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen if (i_stream_next_line(client->input) == NULL)
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen return;
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen client->skip_line = FALSE;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen }
217cdf98fe6f3e5a9a932e41fa2e956c153a6947Timo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen /* @UNSAFE */
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen line = i_stream_next_line(client->input);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen if (line == NULL)
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen return;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen if (strcmp(line, "*") == 0) {
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen client_auth_abort(client, "Authentication aborted");
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen return;
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen }
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen linelen = strlen(line);
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen buf = buffer_create_static_hard(pool_datastack_create(), linelen);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen if (base64_decode((const unsigned char *) line, linelen,
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen NULL, buf) <= 0) {
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen /* failed */
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen client_auth_abort(client, "Invalid base64 data");
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen } else if (client->common.auth_request == NULL) {
cdc5c81463995a153c57c68c299e98cc3de0b287Timo Sirainen client_auth_abort(client, "Don't send unrequested data");
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen } else {
cdc5c81463995a153c57c68c299e98cc3de0b287Timo Sirainen auth_client_request_continue(client->common.auth_request,
cdc5c81463995a153c57c68c299e98cc3de0b287Timo Sirainen buffer_get_data(buf, NULL),
cdc5c81463995a153c57c68c299e98cc3de0b287Timo Sirainen buffer_get_used_size(buf));
cdc5c81463995a153c57c68c299e98cc3de0b287Timo Sirainen }
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen /* clear sensitive data */
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen safe_memset(line, 0, linelen);
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen bufsize = buffer_get_used_size(buf);
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen safe_memset(buffer_free_without_data(buf), 0, bufsize);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen}
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainenint cmd_authenticate(struct imap_client *client, struct imap_arg *args)
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen{
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen struct auth_mech_desc *mech;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen const char *mech_name, *error;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen /* we want only one argument: authentication mechanism name */
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen if (args[0].type != IMAP_ARG_ATOM && args[0].type != IMAP_ARG_STRING)
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen return FALSE;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen if (args[1].type != IMAP_ARG_EOL)
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen return FALSE;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen mech_name = IMAP_ARG_STR(&args[0]);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen if (*mech_name == '\0')
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen return FALSE;
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen mech = auth_mech_find(mech_name);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen if (mech == NULL) {
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen client_send_tagline(client,
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen "NO Unsupported authentication mechanism.");
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen return TRUE;
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen }
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen if (!client->secured && mech->plaintext && disable_plaintext_auth) {
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen client_send_tagline(client,
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen "NO Plaintext authentication disabled.");
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen return TRUE;
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen }
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen client_ref(client);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen client->common.auth_request =
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen auth_client_request_new(auth_client, mech->mech,
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen AUTH_PROTOCOL_IMAP,
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen authenticate_callback,
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen client, &error);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen if (client->common.auth_request != NULL) {
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen /* following input data will go to authentication */
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen if (client->common.io != NULL)
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen io_remove(client->common.io);
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen client->common.io = io_add(client->common.fd, IO_READ,
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen client_auth_input, client);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen client->authenticating = TRUE;
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen } else {
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen client_send_tagline(client, t_strconcat(
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen "NO Authentication failed: ", error, NULL));
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen client_unref(client);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen }
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen return TRUE;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen}
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen