client.c revision 2e37d45867d081db150ab78dad303b9077aea24f
e59faf65ce864fe95dc00f5d52b8323cdbd0608aTimo Sirainen/* Copyright (c) 2002-2011 Dovecot authors, see the included COPYING file */
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen#include "login-common.h"
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen#include "base64.h"
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen#include "buffer.h"
7a7d2aa11e46195e2d92d6c337d7e78052a5ce67Timo Sirainen#include "ioloop.h"
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen#include "istream.h"
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen#include "ostream.h"
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen#include "randgen.h"
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen#include "hostpid.h"
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen#include "safe-memset.h"
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen#include "str.h"
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen#include "strescape.h"
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen#include "master-service.h"
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen#include "client.h"
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen#include "client-authenticate.h"
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen#include "auth-client.h"
f7539a17ea306191b53b8f5e752e228937df9ec3Timo Sirainen#include "ssl-proxy.h"
f7539a17ea306191b53b8f5e752e228937df9ec3Timo Sirainen#include "pop3-proxy.h"
f7539a17ea306191b53b8f5e752e228937df9ec3Timo Sirainen#include "pop3-login-settings.h"
f7539a17ea306191b53b8f5e752e228937df9ec3Timo Sirainen
f7539a17ea306191b53b8f5e752e228937df9ec3Timo Sirainen/* Disconnect client when it sends too many bad commands */
f7539a17ea306191b53b8f5e752e228937df9ec3Timo Sirainen#define CLIENT_MAX_BAD_COMMANDS 10
f7539a17ea306191b53b8f5e752e228937df9ec3Timo Sirainen
f7539a17ea306191b53b8f5e752e228937df9ec3Timo Sirainenconst struct login_binary login_binary = {
f7539a17ea306191b53b8f5e752e228937df9ec3Timo Sirainen .protocol = "pop3",
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen .process_name = "pop3-login",
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen .default_port = 110,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen .default_ssl_port = 995
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen};
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenvoid login_process_preinit(void)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen{
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen login_set_roots = pop3_login_setting_roots;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen}
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainenstatic bool cmd_stls(struct pop3_client *client)
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen{
e5fd6dfd0a492e4708d4dbb7971d7fc5d7b8fd85Timo Sirainen client_cmd_starttls(&client->common);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen return TRUE;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen}
d22301419109ed4a38351715e6760011421dadecTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainenstatic bool cmd_quit(struct pop3_client *client)
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen{
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen client_send_line(&client->common, CLIENT_CMD_REPLY_OK, "Logging out");
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen client_destroy(&client->common, "Aborted login");
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen return TRUE;
3b32bc12710240f86465a00fbb2bd1ef030e6c40Timo Sirainen}
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
d22301419109ed4a38351715e6760011421dadecTimo Sirainenstatic bool client_command_execute(struct pop3_client *client, const char *cmd,
d22301419109ed4a38351715e6760011421dadecTimo Sirainen const char *args)
d22301419109ed4a38351715e6760011421dadecTimo Sirainen{
d22301419109ed4a38351715e6760011421dadecTimo Sirainen cmd = t_str_ucase(cmd);
d22301419109ed4a38351715e6760011421dadecTimo Sirainen if (strcmp(cmd, "CAPA") == 0)
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen return cmd_capa(client, args);
e5fd6dfd0a492e4708d4dbb7971d7fc5d7b8fd85Timo Sirainen if (strcmp(cmd, "USER") == 0)
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen return cmd_user(client, args);
d22301419109ed4a38351715e6760011421dadecTimo Sirainen if (strcmp(cmd, "PASS") == 0)
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen return cmd_pass(client, args);
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen if (strcmp(cmd, "AUTH") == 0)
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen return cmd_auth(client, args);
d22301419109ed4a38351715e6760011421dadecTimo Sirainen if (strcmp(cmd, "APOP") == 0)
d22301419109ed4a38351715e6760011421dadecTimo Sirainen return cmd_apop(client, args);
d22301419109ed4a38351715e6760011421dadecTimo Sirainen if (strcmp(cmd, "STLS") == 0)
d22301419109ed4a38351715e6760011421dadecTimo Sirainen return cmd_stls(client);
d22301419109ed4a38351715e6760011421dadecTimo Sirainen if (strcmp(cmd, "QUIT") == 0)
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen return cmd_quit(client);
d22301419109ed4a38351715e6760011421dadecTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen client_send_line(&client->common, CLIENT_CMD_REPLY_BAD,
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen "Unknown command.");
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen return FALSE;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen}
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainenstatic void pop3_client_input(struct client *client)
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen{
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen struct pop3_client *pop3_client = (struct pop3_client *)client;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen char *line, *args;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen i_assert(!client->authenticating);
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen
b42697a5749b85659a24316d97f1c208d469e4e8Timo Sirainen if (!client_read(client))
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen return;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen client_ref(client);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen o_stream_cork(client->output);
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen /* if a command starts an authentication, stop processing further
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen commands until the authentication is finished. */
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen while (!client->output->closed && !client->authenticating &&
d22301419109ed4a38351715e6760011421dadecTimo Sirainen auth_client_is_connected(auth_client) &&
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen (line = i_stream_next_line(client->input)) != NULL) {
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen args = strchr(line, ' ');
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen if (args != NULL)
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen *args++ = '\0';
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen if (client_command_execute(pop3_client, line,
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen args != NULL ? args : ""))
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen client->bad_counter = 0;
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen else if (++client->bad_counter > CLIENT_MAX_BAD_COMMANDS) {
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen client_send_line(client, CLIENT_CMD_REPLY_BYE,
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen "Too many invalid bad commands.");
9ffdc9d18870acef2e4dde99715d8528ff4b080dTimo Sirainen client_destroy(client,
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen "Disconnected: Too many bad commands");
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen }
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainen }
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen if (auth_client != NULL && !auth_client_is_connected(auth_client))
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen client->input_blocked = TRUE;
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainen
d22301419109ed4a38351715e6760011421dadecTimo Sirainen if (client_unref(&client))
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainen o_stream_uncork(client->output);
d22301419109ed4a38351715e6760011421dadecTimo Sirainen}
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainenstatic struct client *pop3_client_alloc(pool_t pool)
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen{
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen struct pop3_client *pop3_client;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen pop3_client = p_new(pool, struct pop3_client, 1);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen return &pop3_client->common;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen}
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainenstatic void pop3_client_create(struct client *client ATTR_UNUSED,
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen void **other_sets ATTR_UNUSED)
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen{
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen}
1108376e39a19912e8394e64e19b1bc6f6691cf6Timo Sirainen
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainenstatic void pop3_client_destroy(struct client *client)
3e564425db51f3921ce4de11859777135fdedd15Timo Sirainen{
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen struct pop3_client *pop3_client = (struct pop3_client *)client;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen i_free_and_null(pop3_client->last_user);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen i_free_and_null(pop3_client->apop_challenge);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen}
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainenstatic char *get_apop_challenge(struct pop3_client *client)
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen{
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen unsigned char buffer[16];
09c08fad8e7cc694a6c8d1711e67839acd3a2f04Timo Sirainen unsigned char buffer_base64[MAX_BASE64_ENCODED_SIZE(sizeof(buffer)) + 1];
438f12d7a776da695019114884b48188d94613efTimo Sirainen buffer_t buf;
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen
9ffdc9d18870acef2e4dde99715d8528ff4b080dTimo Sirainen if (auth_client_find_mech(auth_client, "APOP") == NULL) {
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen /* disabled, no need to present the challenge */
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen return NULL;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen }
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen auth_client_get_connect_id(auth_client, &client->apop_server_pid,
fbd918f47f591f8084fd52b207ef29515ddd11b9Timo Sirainen &client->apop_connect_uid);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen random_fill(buffer, sizeof(buffer));
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen buffer_create_data(&buf, buffer_base64, sizeof(buffer_base64));
5137d2d80255938a0f5fb8f3c1a21b34cf11ada3Timo Sirainen base64_encode(buffer, sizeof(buffer), &buf);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen buffer_append_c(&buf, '\0');
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen return i_strdup_printf("<%x.%x.%lx.%s@%s>",
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen client->apop_server_pid,
48270badadd82279bfe50ae3d187aea8b0b2b30eTimo Sirainen client->apop_connect_uid,
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen (unsigned long)ioloop_time,
14ab4610b6038da6c5d0814fecabc6b74bc81a6bTimo Sirainen (const char *)buf.data, my_hostname);
84ed9f8f3d0e5ed47607ef417618e49e4f865557Timo Sirainen}
84ed9f8f3d0e5ed47607ef417618e49e4f865557Timo Sirainen
e3796bfd2bc0fd5ba664893d346df9334a5b3af0Timo Sirainenstatic void pop3_client_send_greeting(struct client *client)
5afa8e2edf4f313cd56e5909f92f39c3b5b7b4d3Timo Sirainen{
408e5be344c9131fdebe771718a5bf49f88cc51cTimo Sirainen struct pop3_client *pop3_client = (struct pop3_client *)client;
370b60cfccff7c50586fc30f4f591499a55301a8Timo Sirainen
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen client->io = io_add(client->fd, IO_READ, client_input, client);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen pop3_client->apop_challenge = get_apop_challenge(pop3_client);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen if (pop3_client->apop_challenge == NULL) {
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen client_send_line(client, CLIENT_CMD_REPLY_OK,
de58be41126e5d68008d2ea706d62ccdc1f29337Timo Sirainen client->set->login_greeting);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen } else {
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen client_send_line(client, CLIENT_CMD_REPLY_OK,
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen t_strconcat(client->set->login_greeting, " ",
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen pop3_client->apop_challenge, NULL));
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen }
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen client->greeting_sent = TRUE;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen}
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainenstatic void pop3_client_starttls(struct client *client ATTR_UNUSED)
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen{
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen}
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainenstatic void
pop3_client_send_line(struct client *client, enum client_cmd_reply reply,
const char *text)
{
const char *prefix = "-ERR";
switch (reply) {
case CLIENT_CMD_REPLY_OK:
prefix = "+OK";
break;
case CLIENT_CMD_REPLY_AUTH_FAIL_TEMP:
prefix = "-ERR [IN-USE]";
break;
case CLIENT_CMD_REPLY_AUTH_FAILED:
case CLIENT_CMD_REPLY_AUTHZ_FAILED:
case CLIENT_CMD_REPLY_AUTH_FAIL_REASON:
case CLIENT_CMD_REPLY_AUTH_FAIL_NOSSL:
case CLIENT_CMD_REPLY_BAD:
case CLIENT_CMD_REPLY_BYE:
break;
case CLIENT_CMD_REPLY_STATUS:
case CLIENT_CMD_REPLY_STATUS_BAD:
/* can't send status notifications */
return;
}
T_BEGIN {
string_t *line = t_str_new(256);
str_append(line, prefix);
str_append_c(line, ' ');
str_append(line, text);
str_append(line, "\r\n");
client_send_raw_data(client, str_data(line),
str_len(line));
} T_END;
}
static void pop3_login_die(void)
{
/* do nothing. pop3 connections typically die pretty quick anyway. */
}
void clients_init(void)
{
/* override the default login_die() */
master_service_set_die_callback(master_service, pop3_login_die);
}
void clients_deinit(void)
{
clients_destroy_all();
}
struct client_vfuncs client_vfuncs = {
pop3_client_alloc,
pop3_client_create,
pop3_client_destroy,
pop3_client_send_greeting,
pop3_client_starttls,
pop3_client_input,
pop3_client_send_line,
pop3_client_auth_handle_reply,
NULL,
NULL,
pop3_proxy_reset,
pop3_proxy_parse_line
};