c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat#include "login-common.h"
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat#include "base64.h"
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat#include "buffer.h"
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat#include "ioloop.h"
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat#include "istream.h"
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat#include "ostream.h"
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat#include "randgen.h"
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat#include "hostpid.h"
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat#include "safe-memset.h"
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat#include "str.h"
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat#include "strescape.h"
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat#include "master-service.h"
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat#include "client.h"
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat#include "client-authenticate.h"
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat#include "auth-client.h"
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat#include "pop3-proxy.h"
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat#include "pop3-login-settings.h"
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat/* Disconnect client when it sends too many bad commands */
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat#define CLIENT_MAX_BAD_COMMANDS 3
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozatstatic bool cmd_stls(struct pop3_client *client)
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat{
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat client_cmd_starttls(&client->common);
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat return TRUE;
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat}
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozatstatic bool cmd_quit(struct pop3_client *client)
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat{
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat client_send_reply(&client->common, POP3_CMD_REPLY_OK, "Logging out");
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat client_destroy(&client->common, "Aborted login");
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat return TRUE;
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat}
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozatstatic bool cmd_xclient(struct pop3_client *client, const char *args)
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat{
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat const char *const *tmp;
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat in_port_t remote_port;
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat bool args_ok = TRUE;
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat if (!client->common.trusted) {
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat client_send_reply(&client->common, POP3_CMD_REPLY_OK,
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat "You are not from trusted IP - ignoring");
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat return TRUE;
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat }
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat for (tmp = t_strsplit(args, " "); *tmp != NULL; tmp++) {
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat if (strncasecmp(*tmp, "ADDR=", 5) == 0) {
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat if (net_addr2ip(*tmp + 5, &client->common.ip) < 0)
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat args_ok = FALSE;
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat } else if (strncasecmp(*tmp, "PORT=", 5) == 0) {
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat if (net_str2port(*tmp + 5, &remote_port) < 0)
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat args_ok = FALSE;
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat else
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat client->common.remote_port = remote_port;
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat } else if (strncasecmp(*tmp, "SESSION=", 8) == 0) {
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat const char *value = *tmp + 8;
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat if (strlen(value) <= LOGIN_MAX_SESSION_ID_LEN) {
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat client->common.session_id =
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat p_strdup(client->common.pool, value);
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat }
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat } else if (strncasecmp(*tmp, "TTL=", 4) == 0) {
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat if (str_to_uint(*tmp + 4, &client->common.proxy_ttl) < 0)
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat args_ok = FALSE;
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat } else if (strncasecmp(*tmp, "FORWARD=", 8) == 0) {
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat size_t value_len = strlen((*tmp)+8);
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat client->common.forward_fields =
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat str_new(client->common.preproxy_pool,
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat MAX_BASE64_DECODED_SIZE(value_len));
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat if (base64_decode((*tmp)+8, value_len, NULL,
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat client->common.forward_fields) < 0)
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat args_ok = FALSE;
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat }
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat }
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat if (!args_ok) {
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat client_send_reply(&client->common, POP3_CMD_REPLY_ERROR,
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat "Invalid parameters");
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat return TRUE;
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat }
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat /* args ok, set them and reset the state */
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat client_send_reply(&client->common, POP3_CMD_REPLY_OK, "Updated");
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat return TRUE;
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat}
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozatstatic bool client_command_execute(struct pop3_client *client, const char *cmd,
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat const char *args)
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat{
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat cmd = t_str_ucase(cmd);
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat if (strcmp(cmd, "CAPA") == 0)
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat return cmd_capa(client, args);
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat if (strcmp(cmd, "USER") == 0)
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat return cmd_user(client, args);
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat if (strcmp(cmd, "PASS") == 0)
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat return cmd_pass(client, args);
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat if (strcmp(cmd, "AUTH") == 0)
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat return cmd_auth(client, args);
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat if (strcmp(cmd, "APOP") == 0)
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat return cmd_apop(client, args);
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat if (strcmp(cmd, "STLS") == 0)
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat return cmd_stls(client);
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat if (strcmp(cmd, "QUIT") == 0)
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat return cmd_quit(client);
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat if (strcmp(cmd, "XCLIENT") == 0)
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat return cmd_xclient(client, args);
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat if (strcmp(cmd, "XOIP") == 0) {
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat /* Compatibility with Zimbra's patched nginx */
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat return cmd_xclient(client, t_strconcat("ADDR=", args, NULL));
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat }
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat client_send_reply(&client->common, POP3_CMD_REPLY_ERROR,
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat "Unknown command.");
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat return FALSE;
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat}
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozatstatic void pop3_client_input(struct client *client)
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat{
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat i_assert(!client->authenticating);
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat if (!client_read(client))
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat return;
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat client_ref(client);
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat o_stream_cork(client->output);
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat /* if a command starts an authentication, stop processing further
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat commands until the authentication is finished. */
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat while (!client->output->closed && !client->authenticating &&
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat auth_client_is_connected(auth_client)) {
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat if (!client->v.input_next_cmd(client))
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat break;
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat }
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat if (auth_client != NULL && !auth_client_is_connected(auth_client))
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat client->input_blocked = TRUE;
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat o_stream_uncork(client->output);
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat client_unref(&client);
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat}
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozatstatic bool pop3_client_input_next_cmd(struct client *client)
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat{
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat struct pop3_client *pop3_client = (struct pop3_client *)client;
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat char *line, *args;
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat if ((line = i_stream_next_line(client->input)) == NULL)
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat return FALSE;
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat args = strchr(line, ' ');
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat if (args != NULL)
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat *args++ = '\0';
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat if (client_command_execute(pop3_client, line,
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat args != NULL ? args : ""))
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat client->bad_counter = 0;
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat else if (++client->bad_counter >= CLIENT_MAX_BAD_COMMANDS) {
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat client_send_reply(client, POP3_CMD_REPLY_ERROR,
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat "Too many invalid bad commands.");
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat client_destroy(client,
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat "Disconnected: Too many bad commands");
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat return FALSE;
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat }
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat return TRUE;
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat}
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozatstatic struct client *pop3_client_alloc(pool_t pool)
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat{
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat struct pop3_client *pop3_client;
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat pop3_client = p_new(pool, struct pop3_client, 1);
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat return &pop3_client->common;
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat}
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozatstatic void pop3_client_create(struct client *client ATTR_UNUSED,
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat void **other_sets ATTR_UNUSED)
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat{
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat}
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozatstatic void pop3_client_destroy(struct client *client)
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat{
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat struct pop3_client *pop3_client = (struct pop3_client *)client;
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat i_free_and_null(pop3_client->last_user);
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat i_free_and_null(pop3_client->apop_challenge);
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat}
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozatstatic char *get_apop_challenge(struct pop3_client *client)
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat{
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat unsigned char buffer[16];
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat unsigned char buffer_base64[MAX_BASE64_ENCODED_SIZE(sizeof(buffer)) + 1];
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat buffer_t buf;
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat if (auth_client_find_mech(auth_client, "APOP") == NULL) {
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat /* disabled, no need to present the challenge */
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat return NULL;
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat }
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat auth_client_get_connect_id(auth_client, &client->apop_server_pid,
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat &client->apop_connect_uid);
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat random_fill(buffer, sizeof(buffer));
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat buffer_create_from_data(&buf, buffer_base64, sizeof(buffer_base64));
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat base64_encode(buffer, sizeof(buffer), &buf);
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat buffer_append_c(&buf, '\0');
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat return i_strdup_printf("<%x.%x.%lx.%s@%s>",
6d8ac56b658a7aa35a46580c2df060c58ef02821Serge Hallyn client->apop_server_pid,
44d397891e691ab994a69766cc72e57265b62da1Serge Hallyn client->apop_connect_uid,
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat (unsigned long)ioloop_time,
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat (const char *)buf.data, my_hostname);
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat}
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozatstatic void pop3_client_notify_auth_ready(struct client *client)
e29bf450cafa2ce2564aeb0b64d2014c17228407Dwight Engen{
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat struct pop3_client *pop3_client = (struct pop3_client *)client;
e29bf450cafa2ce2564aeb0b64d2014c17228407Dwight Engen string_t *str;
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat
add1d11833394aaa3a3497c2fdf548e5b14c80d4Serge Hallyn client->io = io_add_istream(client->input, client_input, client);
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat str = t_str_new(128);
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat if (client->trusted) {
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat /* Dovecot extension to avoid extra roundtrip for CAPA */
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat str_append(str, "[XCLIENT] ");
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat }
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat str_append(str, client->set->login_greeting);
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat pop3_client->apop_challenge = get_apop_challenge(pop3_client);
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat if (pop3_client->apop_challenge != NULL)
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat str_printfa(str, " %s", pop3_client->apop_challenge);
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat client_send_reply(client, POP3_CMD_REPLY_OK, str_c(str));
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat client->banner_sent = TRUE;
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat}
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozatstatic void
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozatpop3_client_notify_starttls(struct client *client,
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat bool success, const char *text)
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat{
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat if (success)
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat client_send_reply(client, POP3_CMD_REPLY_OK, text);
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat else
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat client_send_reply(client, POP3_CMD_REPLY_ERROR, text);
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat}
e29bf450cafa2ce2564aeb0b64d2014c17228407Dwight Engen
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozatstatic void pop3_client_starttls(struct client *client ATTR_UNUSED)
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat{
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat}
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozatvoid client_send_reply(struct client *client, enum pop3_cmd_reply reply,
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat const char *text)
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat{
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat const char *prefix = "-ERR";
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat switch (reply) {
1881820ae4ff9004beef1bf7f04553580840441dSerge Hallyn case POP3_CMD_REPLY_OK:
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat prefix = "+OK";
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat break;
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat case POP3_CMD_REPLY_TEMPFAIL:
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat prefix = "-ERR [SYS/TEMP]";
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat break;
eba7df9ee0a1963984ef212e7ddfc0e0835af288Stéphane Graber case POP3_CMD_REPLY_AUTH_ERROR:
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat if (text[0] == '[')
f02ce27d4b1a9d01b88d0ffaf626e5bafa671bf0Stéphane Graber prefix = "-ERR";
f02ce27d4b1a9d01b88d0ffaf626e5bafa671bf0Stéphane Graber else
f02ce27d4b1a9d01b88d0ffaf626e5bafa671bf0Stéphane Graber prefix = "-ERR [AUTH]";
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat break;
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat case POP3_CMD_REPLY_ERROR:
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat break;
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat }
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat T_BEGIN {
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat string_t *line = t_str_new(256);
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat str_append(line, prefix);
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat str_append_c(line, ' ');
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat str_append(line, text);
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat str_append(line, "\r\n");
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat client_send_raw_data(client, str_data(line), str_len(line));
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat } T_END;
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat}
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozatstatic void
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozatpop3_client_notify_disconnect(struct client *client,
80a881b232b8955b85b360d4def99e6e680ff61bSerge Hallyn enum client_disconnect_reason reason,
80a881b232b8955b85b360d4def99e6e680ff61bSerge Hallyn const char *text)
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat{
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat if (reason == CLIENT_DISCONNECT_INTERNAL_ERROR)
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat client_send_reply(client, POP3_CMD_REPLY_TEMPFAIL, text);
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat else
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat client_send_reply(client, POP3_CMD_REPLY_ERROR, text);
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat}
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozatstatic void pop3_login_die(void)
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat{
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat /* do nothing. pop3 connections typically die pretty quick anyway. */
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat}
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat
e29bf450cafa2ce2564aeb0b64d2014c17228407Dwight Engenstatic void pop3_login_preinit(void)
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat{
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat login_set_roots = pop3_login_setting_roots;
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat}
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozatstatic void pop3_login_init(void)
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat{
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat /* override the default login_die() */
add1d11833394aaa3a3497c2fdf548e5b14c80d4Serge Hallyn master_service_set_die_callback(master_service, pop3_login_die);
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat}
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozatstatic void pop3_login_deinit(void)
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat{
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat clients_destroy_all();
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat}
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozatstatic struct client_vfuncs pop3_client_vfuncs = {
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat pop3_client_alloc,
e29bf450cafa2ce2564aeb0b64d2014c17228407Dwight Engen pop3_client_create,
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat pop3_client_destroy,
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat pop3_client_notify_auth_ready,
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat pop3_client_notify_disconnect,
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat NULL,
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat pop3_client_notify_starttls,
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat pop3_client_starttls,
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat pop3_client_input,
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat NULL,
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat NULL,
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat pop3_client_auth_result,
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat pop3_proxy_reset,
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat pop3_proxy_parse_line,
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat pop3_proxy_error,
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat pop3_proxy_get_state,
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat client_common_send_raw_data,
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat pop3_client_input_next_cmd,
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat client_common_default_free,
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat};
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozatstatic const struct login_binary pop3_login_binary = {
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat .protocol = "pop3",
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat .process_name = "pop3-login",
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat .default_port = 110,
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat .default_ssl_port = 995,
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat .client_vfuncs = &pop3_client_vfuncs,
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat .preinit = pop3_login_preinit,
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat .init = pop3_login_init,
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat .deinit = pop3_login_deinit,
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat .sasl_support_final_reply = FALSE
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat};
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozatint main(int argc, char *argv[])
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat{
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat return login_binary_run(&pop3_login_binary, argc, argv);
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat}
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat