client-authenticate.c revision b12eeefe58793031ebf4cff240a39ca33680b6e8
2e37d45867d081db150ab78dad303b9077aea24fTimo Sirainen/* Copyright (C) 2002-2004 Timo Sirainen */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "common.h"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "base64.h"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "buffer.h"
472369cba85d9f7c995dda60e7cd01d78b4a960aTimo Sirainen#include "ioloop.h"
e28fa207d1a097fa6e4a867f74ee0761472ef1ceTimo Sirainen#include "istream.h"
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen#include "ostream.h"
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen#include "safe-memset.h"
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen#include "str.h"
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen#include "str-sanitize.h"
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen#include "imap-parser.h"
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen#include "auth-client.h"
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen#include "ssl-proxy.h"
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen#include "client.h"
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen#include "client-authenticate.h"
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen#include "auth-common.h"
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen#include "master.h"
e28fa207d1a097fa6e4a867f74ee0761472ef1ceTimo Sirainen
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen/* Used only for string sanitization while verbose_auth is set. */
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen#define MAX_MECH_NAME 64
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenconst char *client_authenticate_get_capabilities(int secured)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen{
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen const struct auth_mech_desc *mech;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen unsigned int i, count;
5694eeb99b69dea8033ca77ad69743c6b4871370Timo Sirainen string_t *str;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
5694eeb99b69dea8033ca77ad69743c6b4871370Timo Sirainen str = t_str_new(128);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mech = auth_client_get_available_mechs(auth_client, &count);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen for (i = 0; i < count; i++) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* a) transport is secured
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen b) auth mechanism isn't plaintext
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen c) we allow insecure authentication
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen - but don't advertise AUTH=PLAIN, as RFC 2595 requires
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (mech[i].advertise &&
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen (secured || !mech[i].plaintext)) {
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen str_append_c(str, ' ');
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen str_append(str, "AUTH=");
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen str_append(str, mech[i].name);
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen }
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen }
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen return str_c(str);
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen}
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainenstatic void client_auth_abort(struct imap_client *client, const char *msg)
220e21750948941dc6e33b8f11b552fa21d7f81eTimo Sirainen{
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen client->authenticating = FALSE;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen if (client->common.auth_request != NULL) {
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen auth_client_request_abort(client->common.auth_request);
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen client->common.auth_request = NULL;
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen }
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen if (msg != NULL && verbose_auth)
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen client_syslog(client, "Authentication failed: %s", msg);
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen client_send_tagline(client, msg != NULL ?
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen t_strconcat("NO ", msg, NULL) :
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen "NO Authentication failed.");
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* get back to normal client input */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (client->common.io != NULL)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen io_remove(client->common.io);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen client->common.io = client->common.fd == -1 ? NULL :
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen io_add(client->common.fd, IO_READ, client_input, client);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen client_unref(client);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen}
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic void master_callback(struct client *_client, int success)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen{
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct imap_client *client = (struct imap_client *) _client;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen const char *reason = NULL;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (success) {
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen reason = t_strconcat("Login: ", client->common.virtual_user,
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen NULL);
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen } else {
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen reason = t_strconcat("Internal login failure: ",
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen client->common.virtual_user, NULL);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen client_send_line(client, "* BYE Internal login failure. "
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen "Error report written to server log.");
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen client_destroy(client, reason);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen}
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic void client_send_auth_data(struct imap_client *client,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen const unsigned char *data, size_t size)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen{
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen buffer_t *buf;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen const void *buf_data;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen size_t buf_size;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen ssize_t ret;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen t_push();
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen buf = buffer_create_dynamic(pool_datastack_create(),
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen size*2, (size_t)-1);
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen buffer_append(buf, "+ ", 2);
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen base64_encode(data, size, buf);
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen buffer_append(buf, "\r\n", 2);
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen buf_data = buffer_get_data(buf, &buf_size);
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen if ((ret = o_stream_send(client->output, buf_data, buf_size)) < 0)
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen client_destroy(client, "Disconnected");
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen else if ((size_t)ret != buf_size)
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen client_destroy(client, "Transmit buffer full");
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen t_pop();
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen}
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainenstatic void login_callback(struct auth_request *request,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct auth_client_request_reply *reply,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen const unsigned char *data, void *context)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen{
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct imap_client *client = context;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen const char *error;
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen switch (auth_callback(request, reply, data, &client->common,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen master_callback, &error)) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen case -1:
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen case 0:
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* login failed */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen client_auth_abort(client, error);
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen break;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen default:
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* success, we should be able to log in. if we fail, just
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen disconnect the client. */
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen client->authenticating = FALSE;
6600c05e2ab38e9f662582b63c56b0c980a03748Timo Sirainen client_send_tagline(client, "OK Logged in.");
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen client_unref(client);
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen }
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen}
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainenstatic enum auth_client_request_new_flags
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainenclient_get_auth_flags(struct imap_client *client)
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen{
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen enum auth_client_request_new_flags auth_flags = 0;
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen if (client->common.proxy != NULL &&
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen ssl_proxy_has_valid_client_cert(client->common.proxy))
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen auth_flags |= AUTH_CLIENT_FLAG_SSL_VALID_CLIENT_CERT;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (client->tls)
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen auth_flags |= AUTH_CLIENT_FLAG_SSL_ENABLED;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen return auth_flags;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen}
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenint cmd_login(struct imap_client *client, struct imap_arg *args)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen{
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen const char *user, *pass, *error;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen struct auth_request_info info;
3fe67ec75ccae1230bb9eb9f16affc48377f6441Timo Sirainen string_t *plain_login;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* two arguments: username and password */
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen if (args[0].type != IMAP_ARG_ATOM && args[0].type != IMAP_ARG_STRING)
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen return FALSE;
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen if (args[1].type != IMAP_ARG_ATOM && args[1].type != IMAP_ARG_STRING)
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen return FALSE;
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen if (args[2].type != IMAP_ARG_EOL)
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen return FALSE;
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen user = IMAP_ARG_STR(&args[0]);
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen pass = IMAP_ARG_STR(&args[1]);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (!client->secured && disable_plaintext_auth) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (verbose_auth) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen client_syslog(client, "Login failed: "
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen "Plaintext authentication disabled");
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen }
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen client_send_line(client,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen "* BAD [ALERT] Plaintext authentication is disabled, "
27586e4785d56aeb76e1fd96af8db799688dc64aTimo Sirainen "but your client sent password in plaintext anyway. "
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen "If anyone was listening, the password was exposed.");
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen client_send_tagline(client,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen "NO Plaintext authentication disabled.");
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen return TRUE;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen }
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* authorization ID \0 authentication ID \0 pass */
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen plain_login = t_str_new(64);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen str_append_c(plain_login, '\0');
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen str_append(plain_login, user);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen str_append_c(plain_login, '\0');
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen str_append(plain_login, pass);
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk memset(&info, 0, sizeof(info));
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk info.mech = "PLAIN";
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk info.protocol = "IMAP";
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk info.flags = client_get_auth_flags(client);
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk info.local_ip = client->common.local_ip;
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk info.remote_ip = client->common.ip;
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk info.initial_resp_data = str_data(plain_login);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen info.initial_resp_size = str_len(plain_login);
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen client_ref(client);
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen client->common.auth_request =
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen auth_client_request_new(auth_client, NULL, &info,
5666a3d6a7ea89362b8d9e8b39b15424cd9d6388Timo Sirainen login_callback, client, &error);
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen if (client->common.auth_request == NULL) {
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen if (verbose_auth)
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen client_syslog(client, "Login failed: %s", error);
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen client_send_tagline(client, t_strconcat(
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen "NO Login failed: ", error, NULL));
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen client_unref(client);
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen return TRUE;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen }
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen /* don't read any input from client until login is finished */
9abf5be0962538e1f6f5c73c838ff677341da0c9Timo Sirainen if (client->common.io != NULL) {
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen io_remove(client->common.io);
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen client->common.io = NULL;
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen }
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen client->authenticating = TRUE;
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen return TRUE;
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen}
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainenstatic void authenticate_callback(struct auth_request *request,
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen struct auth_client_request_reply *reply,
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen const unsigned char *data, void *context)
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen{
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen struct imap_client *client = context;
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen const char *error;
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen if (!client->authenticating) {
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen /* client aborted */
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen i_assert(reply == NULL);
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen return;
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen }
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen switch (auth_callback(request, reply, data, &client->common,
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen master_callback, &error)) {
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen case -1:
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen /* login failed */
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen client_auth_abort(client, error);
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen break;
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen
5c597df6aa8d81de4053c6986fab7739f3b44b20Timo Sirainen case 0:
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen /* continue */
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen client_send_auth_data(client, data, reply->data_size);
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen break;
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen default:
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen /* success, we should be able to log in. if we fail, just
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen disconnect the client. */
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen client->authenticating = FALSE;
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen client_send_tagline(client, "OK Logged in.");
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen client_unref(client);
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen }
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen}
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainenstatic void client_auth_input(void *context)
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen{
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen struct imap_client *client = context;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen buffer_t *buf;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen char *line;
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen size_t linelen, bufsize;
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (!client_read(client))
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen return;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen if (client->skip_line) {
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen if (i_stream_next_line(client->input) == NULL)
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen return;
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen client->skip_line = FALSE;
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen }
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen /* @UNSAFE */
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen line = i_stream_next_line(client->input);
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen if (line == NULL)
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen return;
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen if (strcmp(line, "*") == 0) {
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen client_auth_abort(client, "Authentication aborted");
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen return;
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen }
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen linelen = strlen(line);
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen buf = buffer_create_static_hard(pool_datastack_create(), linelen);
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen if (base64_decode(line, linelen, NULL, buf) <= 0) {
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen /* failed */
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen client_auth_abort(client, "Invalid base64 data");
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen } else if (client->common.auth_request == NULL) {
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen client_auth_abort(client, "Don't send unrequested data");
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen } else {
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen auth_client_request_continue(client->common.auth_request,
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen buffer_get_data(buf, NULL),
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen buffer_get_used_size(buf));
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen }
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* clear sensitive data */
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen safe_memset(line, 0, linelen);
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen bufsize = buffer_get_used_size(buf);
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen safe_memset(buffer_free_without_data(buf), 0, bufsize);
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen}
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainenint cmd_authenticate(struct imap_client *client, struct imap_arg *args)
5494a6bc149da8f02fd25c0434a9d612ac33f659Timo Sirainen{
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen const struct auth_mech_desc *mech;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen const char *mech_name, *error;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen struct auth_request_info info;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen /* we want only one argument: authentication mechanism name */
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen if (args[0].type != IMAP_ARG_ATOM && args[0].type != IMAP_ARG_STRING)
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen return FALSE;
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen if (args[1].type != IMAP_ARG_EOL)
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen return FALSE;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen mech_name = IMAP_ARG_STR(&args[0]);
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen if (*mech_name == '\0')
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen return FALSE;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen mech = auth_client_find_mech(auth_client, mech_name);
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen if (mech == NULL) {
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (verbose_auth) {
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen client_syslog(client, "Authenticate %s failed: "
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen "Unsupported mechanism",
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen str_sanitize(mech_name, MAX_MECH_NAME));
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen }
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen client_send_tagline(client,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen "NO Unsupported authentication mechanism.");
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen return TRUE;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen }
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen
1433bf361ddb0bba8878c8ada5726d0284edad57Timo Sirainen if (!client->secured && mech->plaintext && disable_plaintext_auth) {
1433bf361ddb0bba8878c8ada5726d0284edad57Timo Sirainen if (verbose_auth) {
1433bf361ddb0bba8878c8ada5726d0284edad57Timo Sirainen client_syslog(client, "Authenticate %s failed: "
1433bf361ddb0bba8878c8ada5726d0284edad57Timo Sirainen "Plaintext authentication disabled",
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen str_sanitize(mech_name, MAX_MECH_NAME));
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen }
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen client_send_tagline(client,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen "NO Plaintext authentication disabled.");
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen return TRUE;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen }
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen memset(&info, 0, sizeof(info));
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen info.mech = mech->name;
4a514fb20e04df397842cde11cc9ea92abfe9728Timo Sirainen info.protocol = "IMAP";
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen info.flags = client_get_auth_flags(client);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen info.local_ip = client->common.local_ip;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen info.remote_ip = client->common.ip;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen client_ref(client);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen o_stream_uncork(client->output);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen client->common.auth_request =
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen auth_client_request_new(auth_client, NULL, &info,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen authenticate_callback, client, &error);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (client->common.auth_request != NULL) {
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* following input data will go to authentication */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (client->common.io != NULL)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen io_remove(client->common.io);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen client->common.io = io_add(client->common.fd, IO_READ,
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen client_auth_input, client);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen client->authenticating = TRUE;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen } else {
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen if (verbose_auth) {
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen client_syslog(client, "Authenticate %s failed: %s",
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen str_sanitize(mech_name, MAX_MECH_NAME),
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen error);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen }
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen client_send_tagline(client, t_strconcat(
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen "NO Authentication failed: ", error, NULL));
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen client_unref(client);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen }
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen return TRUE;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen}
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen