client.c revision 183bea41fa640dc8117f3eb45ff935cd81377a84
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz/* Copyright (c) 2002-2011 Dovecot authors, see the included COPYING file */
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz#include "login-common.h"
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz#include "buffer.h"
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz#include "ioloop.h"
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz#include "istream.h"
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz#include "ostream.h"
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz#include "safe-memset.h"
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz#include "str.h"
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz#include "strescape.h"
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz#include "imap-parser.h"
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz#include "imap-id.h"
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz#include "imap-resp-code.h"
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz#include "master-service.h"
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz#include "master-auth.h"
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz#include "client.h"
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz#include "client-authenticate.h"
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz#include "auth-client.h"
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz#include "ssl-proxy.h"
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz#include "imap-proxy.h"
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz#include "imap-login-settings.h"
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz#include <stdlib.h>
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz/* maximum length for IMAP command line. */
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz#define MAX_IMAP_LINE 8192
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz/* Disconnect client when it sends too many bad commands */
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz#define CLIENT_MAX_BAD_COMMANDS 10
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarzconst struct login_binary login_binary = {
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz .protocol = "imap",
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz .process_name = "imap-login",
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz .default_port = 143,
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz .default_ssl_port = 993
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz};
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarzvoid login_process_preinit(void)
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz{
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz login_set_roots = imap_login_setting_roots;
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz}
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz/* Skip incoming data until newline is found,
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz returns TRUE if newline was found. */
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarzbool client_skip_line(struct imap_client *client)
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz{
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz const unsigned char *data;
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz size_t i, data_size;
e7e9ca33af09b6ab77633bcafe27d751adf09c93Michael Slusarz
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz data = i_stream_get_data(client->common.input, &data_size);
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz for (i = 0; i < data_size; i++) {
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz if (data[i] == '\n') {
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz i_stream_skip(client->common.input, i+1);
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz return TRUE;
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz }
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz }
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz return FALSE;
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz}
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarzstatic const char *get_capability(struct client *client)
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz{
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz struct imap_client *imap_client = (struct imap_client *)client;
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz string_t *cap_str = t_str_new(256);
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz if (*imap_client->set->imap_capability == '\0')
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz str_append(cap_str, CAPABILITY_BANNER_STRING);
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz else if (*imap_client->set->imap_capability != '+')
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz str_append(cap_str, imap_client->set->imap_capability);
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz else {
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz str_append(cap_str, CAPABILITY_BANNER_STRING);
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz str_append_c(cap_str, ' ');
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz str_append(cap_str, imap_client->set->imap_capability + 1);
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz }
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz if (ssl_initialized && !client->tls)
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz str_append(cap_str, " STARTTLS");
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz if (client->set->disable_plaintext_auth && !client->secured)
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz str_append(cap_str, " LOGINDISABLED");
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz client_authenticate_get_capabilities(client, cap_str);
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz return str_c(cap_str);
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz}
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarzstatic int cmd_capability(struct imap_client *imap_client)
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz{
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz struct client *client = &imap_client->common;
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz /* Client is required to send CAPABILITY after STARTTLS, so the
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz capability resp-code workaround checks only pre-STARTTLS
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz CAPABILITY commands. */
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz if (!client->starttls)
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz imap_client->client_ignores_capability_resp_code = TRUE;
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz client_send_raw(client, t_strconcat(
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz "* CAPABILITY ", get_capability(client), "\r\n", NULL));
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz client_send_line(client, CLIENT_CMD_REPLY_OK, "Capability completed.");
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz return 1;
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz}
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarzstatic int cmd_starttls(struct imap_client *client)
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz{
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz client_cmd_starttls(&client->common);
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz return 1;
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz}
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarzstatic void
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarzclient_update_info(struct imap_client *client, const struct imap_arg *args)
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz{
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz const char *key, *value;
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz if (!imap_arg_get_list(args, &args))
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz return;
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz while (imap_arg_get_string(&args[0], &key) &&
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz imap_arg_get_nstring(&args[1], &value)) {
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz if (strcasecmp(key, "x-originating-ip") == 0)
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz (void)net_addr2ip(value, &client->common.ip);
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz else if (strcasecmp(key, "x-originating-port") == 0)
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz client->common.remote_port = atoi(value);
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz else if (strcasecmp(key, "x-connected-ip") == 0)
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz (void)net_addr2ip(value, &client->common.local_ip);
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz else if (strcasecmp(key, "x-connected-port") == 0)
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz client->common.local_port = atoi(value);
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz args += 2;
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz }
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz}
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarzstatic int cmd_id(struct imap_client *client, const struct imap_arg *args)
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz{
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz const char *env, *value;
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz if (!client->id_logged) {
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz client->id_logged = TRUE;
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz if (client->common.trusted)
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz client_update_info(client, args);
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz env = getenv("IMAP_ID_LOG");
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz value = imap_id_args_get_log_reply(args, env);
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz if (value != NULL) {
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz client_log(&client->common,
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz t_strdup_printf("ID sent: %s", value));
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz }
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz }
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz env = getenv("IMAP_ID_SEND");
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz client_send_raw(&client->common,
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz t_strdup_printf("* ID %s\r\n", imap_id_reply_generate(env)));
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz client_send_line(&client->common, CLIENT_CMD_REPLY_OK, "ID completed.");
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz return 1;
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz}
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarzstatic int cmd_noop(struct imap_client *client)
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz{
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz client_send_line(&client->common, CLIENT_CMD_REPLY_OK,
4ee5a85e75d520497bd43dbfcc6fc273f3e57ceaMichael Slusarz "NOOP completed.");
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz return 1;
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz}
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz
4ee5a85e75d520497bd43dbfcc6fc273f3e57ceaMichael Slusarzstatic int cmd_logout(struct imap_client *client)
4ee5a85e75d520497bd43dbfcc6fc273f3e57ceaMichael Slusarz{
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz client_send_line(&client->common, CLIENT_CMD_REPLY_BYE, "Logging out");
4ee5a85e75d520497bd43dbfcc6fc273f3e57ceaMichael Slusarz client_send_line(&client->common, CLIENT_CMD_REPLY_OK,
4ee5a85e75d520497bd43dbfcc6fc273f3e57ceaMichael Slusarz "Logout completed.");
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz client_destroy(&client->common, "Aborted login");
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz return 1;
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz}
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarzstatic int cmd_enable(struct imap_client *client)
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz{
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz client_send_raw(&client->common, "* ENABLED\r\n");
4ee5a85e75d520497bd43dbfcc6fc273f3e57ceaMichael Slusarz client_send_line(&client->common, CLIENT_CMD_REPLY_OK,
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz "ENABLE ignored in non-authenticated state.");
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz return 1;
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz}
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarzstatic int client_command_execute(struct imap_client *client, const char *cmd,
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz const struct imap_arg *args)
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz{
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz cmd = t_str_ucase(cmd);
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz if (strcmp(cmd, "LOGIN") == 0)
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz return cmd_login(client, args);
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz if (strcmp(cmd, "AUTHENTICATE") == 0)
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz return cmd_authenticate(client, args);
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz if (strcmp(cmd, "CAPABILITY") == 0)
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz return cmd_capability(client);
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz if (strcmp(cmd, "STARTTLS") == 0)
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz return cmd_starttls(client);
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz if (strcmp(cmd, "ID") == 0)
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz return cmd_id(client, args);
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz if (strcmp(cmd, "NOOP") == 0)
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz return cmd_noop(client);
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz if (strcmp(cmd, "LOGOUT") == 0)
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz return cmd_logout(client);
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz if (strcmp(cmd, "ENABLE") == 0)
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz return cmd_enable(client);
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz return -2;
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz}
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarzstatic bool client_handle_input(struct imap_client *client)
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz{
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz const struct imap_arg *args;
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz const char *msg;
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz int ret;
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz bool fatal;
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz i_assert(!client->common.authenticating);
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz if (client->cmd_finished) {
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz /* clear the previous command from memory. don't do this
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz immediately after handling command since we need the
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz cmd_tag to stay some time after authentication commands. */
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz client->cmd_tag = NULL;
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz client->cmd_name = NULL;
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz imap_parser_reset(client->parser);
e7e9ca33af09b6ab77633bcafe27d751adf09c93Michael Slusarz
41dc355b0d4e20037a36ec05206e7880f49f4ca9Michael Slusarz /* remove \r\n */
41dc355b0d4e20037a36ec05206e7880f49f4ca9Michael Slusarz if (client->skip_line) {
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz if (!client_skip_line(client))
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz return FALSE;
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz client->skip_line = FALSE;
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz }
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz client->cmd_finished = FALSE;
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz }
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz if (client->cmd_tag == NULL) {
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz client->cmd_tag = imap_parser_read_word(client->parser);
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz if (client->cmd_tag == NULL)
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz return FALSE; /* need more data */
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz }
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz if (client->cmd_name == NULL) {
33cbadf0114f3a5cb83bdb5a8bc07035f807e466Timo Sirainen client->cmd_name = imap_parser_read_word(client->parser);
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz if (client->cmd_name == NULL)
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz return FALSE; /* need more data */
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz }
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz
e7e9ca33af09b6ab77633bcafe27d751adf09c93Michael Slusarz switch (imap_parser_read_args(client->parser, 0, 0, &args)) {
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz case -1:
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz /* error */
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz msg = imap_parser_get_error(client->parser, &fatal);
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz if (fatal) {
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz client_send_line(&client->common,
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz CLIENT_CMD_REPLY_BYE, msg);
33cbadf0114f3a5cb83bdb5a8bc07035f807e466Timo Sirainen client_destroy(&client->common,
33cbadf0114f3a5cb83bdb5a8bc07035f807e466Timo Sirainen t_strconcat("Disconnected: ", msg, NULL));
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz return FALSE;
33cbadf0114f3a5cb83bdb5a8bc07035f807e466Timo Sirainen }
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz
33cbadf0114f3a5cb83bdb5a8bc07035f807e466Timo Sirainen client_send_line(&client->common, CLIENT_CMD_REPLY_BAD, msg);
33cbadf0114f3a5cb83bdb5a8bc07035f807e466Timo Sirainen client->cmd_finished = TRUE;
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz client->skip_line = TRUE;
e7e9ca33af09b6ab77633bcafe27d751adf09c93Michael Slusarz return TRUE;
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz case -2:
e7e9ca33af09b6ab77633bcafe27d751adf09c93Michael Slusarz /* not enough data */
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz return FALSE;
e7e9ca33af09b6ab77633bcafe27d751adf09c93Michael Slusarz }
e7e9ca33af09b6ab77633bcafe27d751adf09c93Michael Slusarz /* we read the entire line - skip over the CRLF */
e7e9ca33af09b6ab77633bcafe27d751adf09c93Michael Slusarz if (!client_skip_line(client))
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz i_unreached();
33cbadf0114f3a5cb83bdb5a8bc07035f807e466Timo Sirainen
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz if (*client->cmd_tag == '\0')
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz ret = -1;
33cbadf0114f3a5cb83bdb5a8bc07035f807e466Timo Sirainen else
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz ret = client_command_execute(client, client->cmd_name, args);
33cbadf0114f3a5cb83bdb5a8bc07035f807e466Timo Sirainen
33cbadf0114f3a5cb83bdb5a8bc07035f807e466Timo Sirainen client->cmd_finished = TRUE;
33cbadf0114f3a5cb83bdb5a8bc07035f807e466Timo Sirainen if (ret == -2 && strcasecmp(client->cmd_tag, "LOGIN") == 0) {
33cbadf0114f3a5cb83bdb5a8bc07035f807e466Timo Sirainen client_send_line(&client->common, CLIENT_CMD_REPLY_BAD,
33cbadf0114f3a5cb83bdb5a8bc07035f807e466Timo Sirainen "First parameter in line is IMAP's command tag, "
33cbadf0114f3a5cb83bdb5a8bc07035f807e466Timo Sirainen "not the command name. Add that before the command, "
33cbadf0114f3a5cb83bdb5a8bc07035f807e466Timo Sirainen "like: a login user pass");
33cbadf0114f3a5cb83bdb5a8bc07035f807e466Timo Sirainen } else if (ret < 0) {
e7e9ca33af09b6ab77633bcafe27d751adf09c93Michael Slusarz if (*client->cmd_tag == '\0')
33cbadf0114f3a5cb83bdb5a8bc07035f807e466Timo Sirainen client->cmd_tag = "*";
33cbadf0114f3a5cb83bdb5a8bc07035f807e466Timo Sirainen if (++client->common.bad_counter >= CLIENT_MAX_BAD_COMMANDS) {
33cbadf0114f3a5cb83bdb5a8bc07035f807e466Timo Sirainen client_send_line(&client->common, CLIENT_CMD_REPLY_BYE,
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz "Too many invalid IMAP commands.");
33cbadf0114f3a5cb83bdb5a8bc07035f807e466Timo Sirainen client_destroy(&client->common,
33cbadf0114f3a5cb83bdb5a8bc07035f807e466Timo Sirainen "Disconnected: Too many invalid commands");
33cbadf0114f3a5cb83bdb5a8bc07035f807e466Timo Sirainen return FALSE;
33cbadf0114f3a5cb83bdb5a8bc07035f807e466Timo Sirainen }
33cbadf0114f3a5cb83bdb5a8bc07035f807e466Timo Sirainen client_send_line(&client->common, CLIENT_CMD_REPLY_BAD,
33cbadf0114f3a5cb83bdb5a8bc07035f807e466Timo Sirainen "Error in IMAP command received by server.");
33cbadf0114f3a5cb83bdb5a8bc07035f807e466Timo Sirainen }
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz
e7e9ca33af09b6ab77633bcafe27d751adf09c93Michael Slusarz return ret != 0 && !client->common.destroyed;
33cbadf0114f3a5cb83bdb5a8bc07035f807e466Timo Sirainen}
33cbadf0114f3a5cb83bdb5a8bc07035f807e466Timo Sirainen
33cbadf0114f3a5cb83bdb5a8bc07035f807e466Timo Sirainenstatic void imap_client_input(struct client *client)
33cbadf0114f3a5cb83bdb5a8bc07035f807e466Timo Sirainen{
e7e9ca33af09b6ab77633bcafe27d751adf09c93Michael Slusarz struct imap_client *imap_client = (struct imap_client *)client;
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz if (!client_read(client))
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz return;
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz client_ref(client);
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz o_stream_cork(imap_client->common.output);
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz for (;;) {
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz if (!auth_client_is_connected(auth_client)) {
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz /* we're not currently connected to auth process -
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz don't allow any commands */
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz client_send_line(client, CLIENT_CMD_REPLY_STATUS,
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz AUTH_SERVER_WAITING_MSG);
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz if (client->to_auth_waiting != NULL)
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz timeout_remove(&client->to_auth_waiting);
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz client->input_blocked = TRUE;
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz break;
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz } else {
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz if (!client_handle_input(imap_client))
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz break;
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz }
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz }
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz o_stream_uncork(imap_client->common.output);
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz client_unref(&client);
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz}
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarzstatic struct client *imap_client_alloc(pool_t pool)
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz{
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz struct imap_client *imap_client;
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz imap_client = p_new(pool, struct imap_client, 1);
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz return &imap_client->common;
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz}
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarzstatic void imap_client_create(struct client *client, void **other_sets)
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz{
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz struct imap_client *imap_client = (struct imap_client *)client;
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz imap_client->set = other_sets[0];
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz imap_client->parser =
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz imap_parser_create(imap_client->common.input,
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz imap_client->common.output, MAX_IMAP_LINE);
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz client->io = io_add(client->fd, IO_READ, client_input, client);
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz}
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarzstatic void imap_client_destroy(struct client *client)
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz{
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz struct imap_client *imap_client = (struct imap_client *)client;
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz i_free_and_null(imap_client->proxy_backend_capability);
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz imap_parser_destroy(&imap_client->parser);
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz}
da2423165d31474f5384833fdaa6dc4c0cee28f4Timo Sirainen
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarzstatic void imap_client_send_greeting(struct client *client)
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz{
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz string_t *greet;
greet = t_str_new(128);
str_append(greet, "* OK ");
str_printfa(greet, "[CAPABILITY %s] ", get_capability(client));
str_append(greet, client->set->login_greeting);
str_append(greet, "\r\n");
client_send_raw(client, str_c(greet));
client->greeting_sent = TRUE;
}
static void imap_client_starttls(struct client *client)
{
struct imap_client *imap_client = (struct imap_client *)client;
imap_parser_destroy(&imap_client->parser);
imap_client->parser =
imap_parser_create(imap_client->common.input,
imap_client->common.output, MAX_IMAP_LINE);
/* CRLF is lost from buffer when streams are reopened. */
imap_client->skip_line = FALSE;
}
static void
imap_client_send_line(struct client *client, enum client_cmd_reply reply,
const char *text)
{
struct imap_client *imap_client = (struct imap_client *)client;
const char *resp_code = NULL;
const char *prefix = "NO";
bool tagged = TRUE;
switch (reply) {
case CLIENT_CMD_REPLY_OK:
prefix = "OK";
break;
case CLIENT_CMD_REPLY_AUTH_FAILED:
resp_code = IMAP_RESP_CODE_AUTHFAILED;
break;
case CLIENT_CMD_REPLY_AUTHZ_FAILED:
resp_code = IMAP_RESP_CODE_AUTHZFAILED;
break;
case CLIENT_CMD_REPLY_AUTH_FAIL_TEMP:
resp_code = IMAP_RESP_CODE_UNAVAILABLE;
break;
case CLIENT_CMD_REPLY_AUTH_FAIL_REASON:
resp_code = "ALERT";
break;
case CLIENT_CMD_REPLY_AUTH_FAIL_NOSSL:
resp_code = IMAP_RESP_CODE_PRIVACYREQUIRED;
break;
case CLIENT_CMD_REPLY_BAD:
prefix = "BAD";
break;
case CLIENT_CMD_REPLY_BYE:
prefix = "BYE";
tagged = FALSE;
break;
case CLIENT_CMD_REPLY_STATUS:
prefix = "OK";
tagged = FALSE;
break;
case CLIENT_CMD_REPLY_STATUS_BAD:
prefix = "BAD";
tagged = FALSE;
resp_code = "ALERT";
break;
}
T_BEGIN {
string_t *line = t_str_new(256);
if (tagged)
str_append(line, imap_client->cmd_tag);
else
str_append_c(line, '*');
str_append_c(line, ' ');
str_append(line, prefix);
str_append_c(line, ' ');
if (resp_code != NULL)
str_printfa(line, "[%s] ", resp_code);
str_append(line, text);
str_append(line, "\r\n");
client_send_raw_data(client, str_data(line),
str_len(line));
} T_END;
}
void clients_init(void)
{
}
void clients_deinit(void)
{
clients_destroy_all();
}
struct client_vfuncs client_vfuncs = {
imap_client_alloc,
imap_client_create,
imap_client_destroy,
imap_client_send_greeting,
imap_client_starttls,
imap_client_input,
imap_client_send_line,
imap_client_auth_handle_reply,
NULL,
NULL,
imap_proxy_reset,
imap_proxy_parse_line
};