client-authenticate.c revision 46552a931924c2d743f045e95b08c3ce6beda91a
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (c) 2002-2009 Dovecot authors, see the included COPYING file */
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "login-common.h"
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen#include "base64.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "buffer.h"
ea5f188fc29dfaa0c4071e6413e16e1d04263722Timo Sirainen#include "hex-binary.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "ioloop.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "istream.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "ostream.h"
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen#include "safe-memset.h"
63a61b7a739ae0f3f520215137d9c50f94d0f34fTimo Sirainen#include "str.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "str-sanitize.h"
18565c69efcd7db003dbf27cf625ed822e889fb1Timo Sirainen#include "auth-client.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "../pop3/pop3-capability.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "ssl-proxy.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "client.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "client-authenticate.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "pop3-proxy.h"
d22301419109ed4a38351715e6760011421dadecTimo Sirainen
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen#include <stdlib.h>
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen
d22301419109ed4a38351715e6760011421dadecTimo Sirainenconst char *capability_string = POP3_CAPABILITY_REPLY;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainenbool cmd_capa(struct pop3_client *client, const char *args ATTR_UNUSED)
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen{
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen const struct auth_mech_desc *mech;
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen unsigned int i, count;
b66d803de86bfb411165b3465b0d9ef64ecfe2a1Timo Sirainen string_t *str;
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen str = t_str_new(128);
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen str_append(str, "+OK\r\n");
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen str_append(str, capability_string);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen if (ssl_initialized && !client->common.tls)
af1f4b17a92ca7b2661737e65c7849df289d3070Timo Sirainen str_append(str, "STLS\r\n");
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen if (!client->common.set->disable_plaintext_auth ||
d22301419109ed4a38351715e6760011421dadecTimo Sirainen client->common.secured)
d22301419109ed4a38351715e6760011421dadecTimo Sirainen str_append(str, "USER\r\n");
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen str_append(str, "SASL");
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen mech = sasl_server_get_advertised_mechs(&client->common, &count);
01cbf4ac5d44137ab434791be7f838d98d0fcf3bTimo Sirainen for (i = 0; i < count; i++) {
d22301419109ed4a38351715e6760011421dadecTimo Sirainen str_append_c(str, ' ');
4b41116563110d00330896a568eff1078c382827Timo Sirainen str_append(str, mech[i].name);
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen }
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen str_append(str, "\r\n.\r\n");
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen client_send_raw(&client->common, str_c(str));
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen return TRUE;
ebe6df72f1309135f02b6a4d2aef1e81a073f91cTimo Sirainen}
b12a6d0e54318273acf0d0fb8b3f4c29f67b62b0Timo Sirainen
b12a6d0e54318273acf0d0fb8b3f4c29f67b62b0Timo Sirainenbool pop3_client_auth_handle_reply(struct client *client,
b12a6d0e54318273acf0d0fb8b3f4c29f67b62b0Timo Sirainen const struct client_auth_reply *reply)
b12a6d0e54318273acf0d0fb8b3f4c29f67b62b0Timo Sirainen{
b12a6d0e54318273acf0d0fb8b3f4c29f67b62b0Timo Sirainen if (!reply->nologin)
b12a6d0e54318273acf0d0fb8b3f4c29f67b62b0Timo Sirainen return FALSE;
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen if (reply->reason != NULL) {
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen client_send_line(client, CLIENT_CMD_REPLY_AUTH_FAILED,
d22301419109ed4a38351715e6760011421dadecTimo Sirainen reply->reason);
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen } else if (reply->temp) {
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen client_send_line(client, CLIENT_CMD_REPLY_AUTH_FAIL_TEMP,
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen AUTH_TEMP_FAILED_MSG);
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen } else {
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen client_send_line(client, CLIENT_CMD_REPLY_AUTH_FAILED,
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen AUTH_FAILED_MSG);
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen }
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen if (!client->destroyed)
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen client_auth_failed(client);
d22301419109ed4a38351715e6760011421dadecTimo Sirainen return TRUE;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen}
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainenbool cmd_auth(struct pop3_client *pop3_client, const char *args)
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen{
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen struct client *client = &pop3_client->common;
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen const struct auth_mech_desc *mech;
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen const char *mech_name, *p;
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen if (*args == '\0') {
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen /* Old-style SASL discovery, used by MS Outlook */
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen unsigned int i, count;
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen client_send_raw(client, "+OK\r\n");
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen mech = sasl_server_get_advertised_mechs(client, &count);
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen for (i = 0; i < count; i++) {
597dce34068d603fb759b4dff404b34049213e51Timo Sirainen client_send_raw(client, mech[i].name);
63a61b7a739ae0f3f520215137d9c50f94d0f34fTimo Sirainen client_send_raw(client, "\r\n");
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen }
d22301419109ed4a38351715e6760011421dadecTimo Sirainen client_send_raw(client, ".\r\n");
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen return TRUE;
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen }
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen /* <mechanism name> <initial response> */
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen p = strchr(args, ' ');
4b41116563110d00330896a568eff1078c382827Timo Sirainen if (p == NULL) {
d22301419109ed4a38351715e6760011421dadecTimo Sirainen mech_name = args;
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen args = NULL;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen } else {
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen mech_name = t_strdup_until(args, p);
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen args = p+1;
6060b7c8edf8fce73470d0df6a2479b69b01c537Timo Sirainen }
7f773564b94e6054a40d3785cb63c29f1e4d4deeTimo Sirainen
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen (void)client_auth_begin(client, mech_name, args);
ccc895c0358108d2304239063e940b7d75f364abTimo Sirainen return TRUE;
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen}
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainenbool cmd_user(struct pop3_client *pop3_client, const char *args)
4b41116563110d00330896a568eff1078c382827Timo Sirainen{
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen if (!client_check_plaintext_auth(&pop3_client->common, FALSE))
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen return TRUE;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen i_free(pop3_client->last_user);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen pop3_client->last_user = i_strdup(args);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
d22301419109ed4a38351715e6760011421dadecTimo Sirainen client_send_raw(&pop3_client->common, "+OK\r\n");
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen return TRUE;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen}
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainenbool cmd_pass(struct pop3_client *pop3_client, const char *args)
4b41116563110d00330896a568eff1078c382827Timo Sirainen{
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen struct client *client = &pop3_client->common;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen string_t *plain_login, *base64;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen if (pop3_client->last_user == NULL) {
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen /* client may ignore the USER reply and only display the error
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen message from PASS */
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen if (!client_check_plaintext_auth(client, TRUE))
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen return TRUE;
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen client_send_line(client, CLIENT_CMD_REPLY_BAD,
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen "No username given.");
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen return TRUE;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen }
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen /* authorization ID \0 authentication ID \0 pass */
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen plain_login = t_str_new(128);
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen str_append_c(plain_login, '\0');
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen str_append(plain_login, pop3_client->last_user);
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen str_append_c(plain_login, '\0');
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen str_append(plain_login, args);
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen i_free_and_null(pop3_client->last_user);
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen base64 = buffer_create_dynamic(pool_datastack_create(),
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen MAX_BASE64_ENCODED_SIZE(plain_login->used));
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen base64_encode(plain_login->data, plain_login->used, base64);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen (void)client_auth_begin(client, "PLAIN", str_c(base64));
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen return TRUE;
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen}
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainenbool cmd_apop(struct pop3_client *pop3_client, const char *args)
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen{
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen struct client *client = &pop3_client->common;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen buffer_t *apop_data, *base64;
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen const char *p;
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen unsigned int server_pid, connect_uid;
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen
e6aa82aeb50948cb47a45a1b61a9c16d6a162388Timo Sirainen if (pop3_client->apop_challenge == NULL) {
e6aa82aeb50948cb47a45a1b61a9c16d6a162388Timo Sirainen if (client->set->verbose_auth)
e6aa82aeb50948cb47a45a1b61a9c16d6a162388Timo Sirainen client_log(client, "APOP failed: APOP not enabled");
e6aa82aeb50948cb47a45a1b61a9c16d6a162388Timo Sirainen client_send_line(client, CLIENT_CMD_REPLY_BAD,
bf9402875418faf11825cf11fbe06326b6086e3dTimo Sirainen "APOP not enabled.");
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen return TRUE;
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen }
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen /* <username> <md5 sum in hex> */
bf9402875418faf11825cf11fbe06326b6086e3dTimo Sirainen p = strchr(args, ' ');
bf9402875418faf11825cf11fbe06326b6086e3dTimo Sirainen if (p == NULL || strlen(p+1) != 32) {
bf9402875418faf11825cf11fbe06326b6086e3dTimo Sirainen if (client->set->verbose_auth)
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen client_log(client, "APOP failed: Invalid parameters");
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen client_send_line(client, CLIENT_CMD_REPLY_BAD,
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen "Invalid parameters.");
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen return TRUE;
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen }
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen /* APOP challenge \0 username \0 APOP response */
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen apop_data = buffer_create_dynamic(pool_datastack_create(), 128);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen buffer_append(apop_data, pop3_client->apop_challenge,
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen strlen(pop3_client->apop_challenge)+1);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen buffer_append(apop_data, args, (size_t)(p-args));
d22301419109ed4a38351715e6760011421dadecTimo Sirainen buffer_append_c(apop_data, '\0');
f140f88a5ab3e2194f214c11f9f418559e949c83Timo Sirainen
36f4f01d56ec9156ab75bc2047a8388192df3178Timo Sirainen if (hex_to_binary(p+1, apop_data) < 0) {
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen if (client->set->verbose_auth) {
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen client_log(client, "APOP failed: "
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen "Invalid characters in MD5 response");
4b41116563110d00330896a568eff1078c382827Timo Sirainen }
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen client_send_line(client, CLIENT_CMD_REPLY_BAD,
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen "Invalid characters in MD5 response.");
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen return TRUE;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen }
ee3e01f75b1db691bf20dd4e2558965421b8f937Timo Sirainen
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen base64 = buffer_create_dynamic(pool_datastack_create(),
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen MAX_BASE64_ENCODED_SIZE(apop_data->used));
ea5f188fc29dfaa0c4071e6413e16e1d04263722Timo Sirainen base64_encode(apop_data->data, apop_data->used, base64);
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen
ea5f188fc29dfaa0c4071e6413e16e1d04263722Timo Sirainen auth_client_get_connect_id(auth_client, &server_pid, &connect_uid);
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen if (pop3_client->apop_server_pid != server_pid ||
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen pop3_client->apop_connect_uid != connect_uid) {
36f4f01d56ec9156ab75bc2047a8388192df3178Timo Sirainen /* we reconnected to auth server and can't authenticate
36f4f01d56ec9156ab75bc2047a8388192df3178Timo Sirainen with APOP in this session anymore. disconnecting the user
36f4f01d56ec9156ab75bc2047a8388192df3178Timo Sirainen is probably the best solution now. */
36f4f01d56ec9156ab75bc2047a8388192df3178Timo Sirainen client_destroy(client,
36f4f01d56ec9156ab75bc2047a8388192df3178Timo Sirainen "Reconnected to auth server, can't do APOP");
36f4f01d56ec9156ab75bc2047a8388192df3178Timo Sirainen return TRUE;
36f4f01d56ec9156ab75bc2047a8388192df3178Timo Sirainen }
36f4f01d56ec9156ab75bc2047a8388192df3178Timo Sirainen
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen (void)client_auth_begin(client, "APOP", str_c(base64));
f140f88a5ab3e2194f214c11f9f418559e949c83Timo Sirainen return TRUE;
f140f88a5ab3e2194f214c11f9f418559e949c83Timo Sirainen}
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen