client-authenticate.c revision 2e37d45867d081db150ab78dad303b9077aea24f
45312f52ff3a3d4c137447be4c7556500c2f8bf2Timo Sirainen/* Copyright (c) 2002-2011 Dovecot authors, see the included COPYING file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "login-common.h"
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen#include "base64.h"
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen#include "buffer.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "hex-binary.h"
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen#include "ioloop.h"
ffd9a1898a18fadfc5dce399162c25d50548f905Timo Sirainen#include "istream.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "ostream.h"
89b548af722113acb5d63dfffb44423cb60f91e4Timo Sirainen#include "safe-memset.h"
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen#include "str.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "str-sanitize.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "auth-client.h"
66ae183b6e895216037bd921367670f4b0665911Timo Sirainen#include "../pop3/pop3-capability.h"
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen#include "ssl-proxy.h"
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen#include "client.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "client-authenticate.h"
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen#include "pop3-proxy.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <stdlib.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenconst char *capability_string = POP3_CAPABILITY_REPLY;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainenbool cmd_capa(struct pop3_client *client, const char *args ATTR_UNUSED)
46c31f64b9f0949f00b7819f45b22f2d64b2ea27Timo Sirainen{
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen const struct auth_mech_desc *mech;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int i, count;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen string_t *str;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen str = t_str_new(128);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen str_append(str, "+OK\r\n");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen str_append(str, capability_string);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ssl_initialized && !client->common.tls)
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen str_append(str, "STLS\r\n");
8fa41238067c854435884c459963fde6f8c6436bTimo Sirainen if (!client->common.set->disable_plaintext_auth ||
8fa41238067c854435884c459963fde6f8c6436bTimo Sirainen client->common.secured)
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen str_append(str, "USER\r\n");
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen
46c31f64b9f0949f00b7819f45b22f2d64b2ea27Timo Sirainen str_append(str, "SASL");
46c31f64b9f0949f00b7819f45b22f2d64b2ea27Timo Sirainen mech = sasl_server_get_advertised_mechs(&client->common, &count);
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen for (i = 0; i < count; i++) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen str_append_c(str, ' ');
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen str_append(str, mech[i].name);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen }
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen str_append(str, "\r\n.\r\n");
5aeb15e5817fbd4b1d8de540aa7673e3819a8030Timo Sirainen
5aeb15e5817fbd4b1d8de540aa7673e3819a8030Timo Sirainen client_send_raw(&client->common, str_c(str));
41e1c7380edda701719d8ce1fb4d465d2ec4c84dTimo Sirainen return TRUE;
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen}
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainenbool pop3_client_auth_handle_reply(struct client *client,
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen const struct client_auth_reply *reply)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen{
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen if (!reply->nologin)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (reply->reason != NULL) {
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen client_send_line(client, CLIENT_CMD_REPLY_AUTH_FAILED,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen reply->reason);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen } else if (reply->temp) {
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen client_send_line(client, CLIENT_CMD_REPLY_AUTH_FAIL_TEMP,
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen AUTH_TEMP_FAILED_MSG);
ee246b46953e4b94b2f22e093373674fa9155500Timo Sirainen } else {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen client_send_line(client, CLIENT_CMD_REPLY_AUTH_FAILED,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen AUTH_FAILED_MSG);
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen }
648d24583c1574441c4fa0331a90bd4d6e7996c5Timo Sirainen
648d24583c1574441c4fa0331a90bd4d6e7996c5Timo Sirainen if (!client->destroyed)
ee246b46953e4b94b2f22e093373674fa9155500Timo Sirainen client_auth_failed(client);
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen return TRUE;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen}
46c31f64b9f0949f00b7819f45b22f2d64b2ea27Timo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainenbool cmd_auth(struct pop3_client *pop3_client, const char *args)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct client *client = &pop3_client->common;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const struct auth_mech_desc *mech;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *mech_name, *p;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (*args == '\0') {
80fc743146da5130de34174cdaad2576f103723fTimo Sirainen /* Old-style SASL discovery, used by MS Outlook */
80fc743146da5130de34174cdaad2576f103723fTimo Sirainen unsigned int i, count;
80fc743146da5130de34174cdaad2576f103723fTimo Sirainen
80fc743146da5130de34174cdaad2576f103723fTimo Sirainen client_send_raw(client, "+OK\r\n");
80fc743146da5130de34174cdaad2576f103723fTimo Sirainen mech = sasl_server_get_advertised_mechs(client, &count);
80fc743146da5130de34174cdaad2576f103723fTimo Sirainen for (i = 0; i < count; i++) {
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen client_send_raw(client, mech[i].name);
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen client_send_raw(client, "\r\n");
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen }
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen client_send_raw(client, ".\r\n");
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen return TRUE;
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen }
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen /* <mechanism name> <initial response> */
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen p = strchr(args, ' ');
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen if (p == NULL) {
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen mech_name = args;
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen args = NULL;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen } else {
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen mech_name = t_strdup_until(args, p);
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen args = p+1;
d161e3c2cde2bd8d5917840f68823a2259ed426eTimo Sirainen }
ffd9a1898a18fadfc5dce399162c25d50548f905Timo Sirainen
ffd9a1898a18fadfc5dce399162c25d50548f905Timo Sirainen (void)client_auth_begin(client, mech_name, args);
1e923fcf497665fe071a154c31fb452766b0b2deTimo Sirainen return TRUE;
d161e3c2cde2bd8d5917840f68823a2259ed426eTimo Sirainen}
1e923fcf497665fe071a154c31fb452766b0b2deTimo Sirainen
d161e3c2cde2bd8d5917840f68823a2259ed426eTimo Sirainenbool cmd_user(struct pop3_client *pop3_client, const char *args)
d161e3c2cde2bd8d5917840f68823a2259ed426eTimo Sirainen{
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen if (!client_check_plaintext_auth(&pop3_client->common, FALSE))
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen return TRUE;
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen i_free(pop3_client->last_user);
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen pop3_client->last_user = i_strdup(args);
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen client_send_raw(&pop3_client->common, "+OK\r\n");
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen return TRUE;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen}
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainenbool cmd_pass(struct pop3_client *pop3_client, const char *args)
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen{
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen struct client *client = &pop3_client->common;
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen string_t *plain_login, *base64;
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen if (pop3_client->last_user == NULL) {
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen /* client may ignore the USER reply and only display the error
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen message from PASS */
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen if (!client_check_plaintext_auth(client, TRUE))
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen return TRUE;
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen client_send_line(client, CLIENT_CMD_REPLY_BAD,
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen "No username given.");
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen return TRUE;
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen }
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen /* authorization ID \0 authentication ID \0 pass */
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen plain_login = t_str_new(128);
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen str_append_c(plain_login, '\0');
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen str_append(plain_login, pop3_client->last_user);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen str_append_c(plain_login, '\0');
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen str_append(plain_login, args);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen i_free_and_null(pop3_client->last_user);
da985034a708db2f61394b30d117050ae6829ee5Timo Sirainen
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen base64 = buffer_create_dynamic(pool_datastack_create(),
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen MAX_BASE64_ENCODED_SIZE(plain_login->used));
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen base64_encode(plain_login->data, plain_login->used, base64);
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen (void)client_auth_begin(client, "PLAIN", str_c(base64));
7d7b5c98f086ffa8ac9c90f21db17748ca607202Timo Sirainen return TRUE;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen}
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen
da985034a708db2f61394b30d117050ae6829ee5Timo Sirainenbool cmd_apop(struct pop3_client *pop3_client, const char *args)
da985034a708db2f61394b30d117050ae6829ee5Timo Sirainen{
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen struct client *client = &pop3_client->common;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen buffer_t *apop_data, *base64;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen const char *p;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen unsigned int server_pid, connect_uid;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen if (pop3_client->apop_challenge == NULL) {
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen if (client->set->verbose_auth)
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen client_log(client, "APOP failed: APOP not enabled");
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen client_send_line(client, CLIENT_CMD_REPLY_BAD,
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen "APOP not enabled.");
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen return TRUE;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen }
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen /* <username> <md5 sum in hex> */
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen p = strchr(args, ' ');
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen if (p == NULL || strlen(p+1) != 32) {
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen if (client->set->verbose_auth)
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen client_log(client, "APOP failed: Invalid parameters");
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen client_send_line(client, CLIENT_CMD_REPLY_BAD,
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen "Invalid parameters.");
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen return TRUE;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen }
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen /* APOP challenge \0 username \0 APOP response */
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen apop_data = buffer_create_dynamic(pool_datastack_create(), 128);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen buffer_append(apop_data, pop3_client->apop_challenge,
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen strlen(pop3_client->apop_challenge)+1);
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen buffer_append(apop_data, args, (size_t)(p-args));
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen buffer_append_c(apop_data, '\0');
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen if (hex_to_binary(p+1, apop_data) < 0) {
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen if (client->set->verbose_auth) {
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen client_log(client, "APOP failed: "
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen "Invalid characters in MD5 response");
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen }
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen client_send_line(client, CLIENT_CMD_REPLY_BAD,
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen "Invalid characters in MD5 response.");
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen return TRUE;
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen }
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen base64 = buffer_create_dynamic(pool_datastack_create(),
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen MAX_BASE64_ENCODED_SIZE(apop_data->used));
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen base64_encode(apop_data->data, apop_data->used, base64);
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen auth_client_get_connect_id(auth_client, &server_pid, &connect_uid);
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen if (pop3_client->apop_server_pid != server_pid ||
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen pop3_client->apop_connect_uid != connect_uid) {
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen /* we reconnected to auth server and can't authenticate
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen with APOP in this session anymore. disconnecting the user
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen is probably the best solution now. */
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen client_destroy(client,
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen "Reconnected to auth server, can't do APOP");
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen return TRUE;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen }
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen (void)client_auth_begin(client, "APOP", str_c(base64));
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen return TRUE;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen}
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen