client-authenticate.c revision f0339f522dc9c8e2e8a29ef9a3f937c431c6bd1b
b9f30617c2c96d54acbc4f85ed17b939c4f28916Timo Sirainen/* Copyright (c) 2002-2016 Dovecot authors, see the included COPYING file */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "login-common.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "base64.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "buffer.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "ioloop.h"
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen#include "istream.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "ostream.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "safe-memset.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "str.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "str-sanitize.h"
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen#include "net.h"
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen#include "imap-resp-code.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "imap-parser.h"
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen#include "imap-url.h"
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen#include "auth-client.h"
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen#include "imap-login-client.h"
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen#include "client-authenticate.h"
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen#include "imap-proxy.h"
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainenvoid client_authenticate_get_capabilities(struct client *client, string_t *str)
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen{
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen const struct auth_mech_desc *mech;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen unsigned int i, count;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen mech = sasl_server_get_advertised_mechs(client, &count);
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen for (i = 0; i < count; i++) {
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen str_append_c(str, ' ');
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen str_append(str, "AUTH=");
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen str_append(str, mech[i].name);
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen }
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen}
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainenvoid imap_client_auth_result(struct client *client,
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen enum client_auth_result result,
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen const struct client_auth_reply *reply,
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen const char *text)
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen{
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen struct imap_url url;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen string_t *referral;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen switch (result) {
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen case CLIENT_AUTH_RESULT_SUCCESS:
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen /* nothing to be done for IMAP */
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen break;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen case CLIENT_AUTH_RESULT_REFERRAL_SUCCESS:
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen case CLIENT_AUTH_RESULT_REFERRAL_NOLOGIN:
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen /* IMAP referral
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen [nologin] referral host=.. [port=..] [destuser=..]
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen [reason=..]
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen NO [REFERRAL imap://destuser;AUTH=..@host:port/] Can't login.
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen OK [...] Logged in, but you should use this server instead.
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen .. [REFERRAL ..] (Reason from auth server)
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen */
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen referral = t_str_new(128);
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen memset(&url, 0, sizeof(url));
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen url.userid = reply->destuser;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen url.auth_type = client->auth_mech_name;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen url.host.name = reply->host;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen if (reply->port != 143)
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen url.port = reply->port;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen str_append(referral, "REFERRAL ");
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen str_append(referral, imap_url_create(&url));
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen if (result == CLIENT_AUTH_RESULT_REFERRAL_SUCCESS) {
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen client_send_reply_code(client, IMAP_CMD_REPLY_OK,
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen str_c(referral), text);
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen } else {
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen client_send_reply_code(client, IMAP_CMD_REPLY_NO,
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen str_c(referral), text);
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen }
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen break;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen case CLIENT_AUTH_RESULT_ABORTED:
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen client_send_reply(client, IMAP_CMD_REPLY_BAD, text);
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen break;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen case CLIENT_AUTH_RESULT_AUTHFAILED_REASON:
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen if (text[0] == '[')
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen client_send_reply(client, IMAP_CMD_REPLY_NO, text);
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen else {
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen client_send_reply_code(client, IMAP_CMD_REPLY_NO,
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen "ALERT", text);
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen }
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen break;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen case CLIENT_AUTH_RESULT_AUTHZFAILED:
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen client_send_reply_code(client, IMAP_CMD_REPLY_NO,
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen IMAP_RESP_CODE_AUTHZFAILED, text);
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen break;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen case CLIENT_AUTH_RESULT_TEMPFAIL:
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen client_send_reply_code(client, IMAP_CMD_REPLY_NO,
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen IMAP_RESP_CODE_UNAVAILABLE, text);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen break;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen case CLIENT_AUTH_RESULT_SSL_REQUIRED:
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen client_send_reply_code(client, IMAP_CMD_REPLY_NO,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen IMAP_RESP_CODE_PRIVACYREQUIRED, text);
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen break;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen case CLIENT_AUTH_RESULT_AUTHFAILED:
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen client_send_reply_code(client, IMAP_CMD_REPLY_NO,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen IMAP_RESP_CODE_AUTHFAILED, text);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen break;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen}
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainenstatic int
1cfdcb36985904eff281fc6d7ea2d13b3c375980Timo Sirainenimap_client_auth_begin(struct imap_client *imap_client, const char *mech_name,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen const char *init_resp)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen{
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen char *prefix;
383d0e8c24451468d6bea17e4b55d74de744abe6Timo Sirainen
383d0e8c24451468d6bea17e4b55d74de744abe6Timo Sirainen prefix = i_strdup_printf("%d%s",
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen imap_client->client_ignores_capability_resp_code ? 1 : 0,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen imap_client->cmd_tag);
383d0e8c24451468d6bea17e4b55d74de744abe6Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen i_free(imap_client->common.master_data_prefix);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen imap_client->common.master_data_prefix = (void *)prefix;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen imap_client->common.master_data_prefix_len = strlen(prefix)+1;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return client_auth_begin(&imap_client->common, mech_name, init_resp);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen}
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenint cmd_authenticate(struct imap_client *imap_client, bool *parsed_r)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen{
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen /* NOTE: This command's input is handled specially because the
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen SASL-IR can be large. */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen struct client *client = &imap_client->common;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen const unsigned char *data;
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen size_t i, size;
1cfdcb36985904eff281fc6d7ea2d13b3c375980Timo Sirainen int ret;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen *parsed_r = FALSE;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
383d0e8c24451468d6bea17e4b55d74de744abe6Timo Sirainen /* <auth mechanism name> [<initial SASL response>] */
383d0e8c24451468d6bea17e4b55d74de744abe6Timo Sirainen if (!imap_client->auth_mech_name_parsed) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen data = i_stream_get_data(client->input, &size);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen for (i = 0; i < size; i++) {
383d0e8c24451468d6bea17e4b55d74de744abe6Timo Sirainen if (data[i] == ' ' ||
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen data[i] == '\r' || data[i] == '\n')
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen break;
57d2429fae575e96ca276355af675deb66b76d00Timo Sirainen }
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (i == size)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return 0;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (i == 0) {
57d2429fae575e96ca276355af675deb66b76d00Timo Sirainen /* empty mechanism name */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen imap_client->skip_line = TRUE;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return -1;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen i_free(client->auth_mech_name);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen client->auth_mech_name = i_strndup(data, i);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen imap_client->auth_mech_name_parsed = TRUE;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (data[i] == ' ')
61618d4c58080570f689614fec204ae14e90cef2Timo Sirainen i++;
50e20db49f29917fe9adcf1b56b11badf28bd0e4Timo Sirainen i_stream_skip(client->input, i);
50e20db49f29917fe9adcf1b56b11badf28bd0e4Timo Sirainen }
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen /* get SASL-IR, if any */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if ((ret = client_auth_read_line(client)) <= 0)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return ret;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen *parsed_r = TRUE;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen imap_client->auth_mech_name_parsed = FALSE;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return imap_client_auth_begin(imap_client,
50e20db49f29917fe9adcf1b56b11badf28bd0e4Timo Sirainen t_strdup(client->auth_mech_name),
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen t_strdup(str_c(client->auth_response)));
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen}
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenint cmd_login(struct imap_client *imap_client, const struct imap_arg *args)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen{
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen struct client *client = &imap_client->common;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen const char *user, *pass;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen string_t *plain_login, *base64;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen /* two arguments: username and password */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (!imap_arg_get_astring(&args[0], &user) ||
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen !imap_arg_get_astring(&args[1], &pass) ||
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen !IMAP_ARG_IS_EOL(&args[2]))
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return -1;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (!client_check_plaintext_auth(client, TRUE)) {
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen if (client->virtual_user == NULL)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen client->virtual_user = i_strdup(user);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return 1;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
50e20db49f29917fe9adcf1b56b11badf28bd0e4Timo Sirainen /* authorization ID \0 authentication ID \0 pass */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen plain_login = buffer_create_dynamic(pool_datastack_create(), 64);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen buffer_append_c(plain_login, '\0');
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen buffer_append(plain_login, user, strlen(user));
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen buffer_append_c(plain_login, '\0');
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen buffer_append(plain_login, pass, strlen(pass));
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen base64 = buffer_create_dynamic(pool_datastack_create(),
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen MAX_BASE64_ENCODED_SIZE(plain_login->used));
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen base64_encode(plain_login->data, plain_login->used, base64);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return imap_client_auth_begin(imap_client, "PLAIN", str_c(base64));
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen}
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen