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