client.c revision 183bea41fa640dc8117f3eb45ff935cd81377a84
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz/* Copyright (c) 2002-2011 Dovecot authors, see the included COPYING file */
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz/* maximum length for IMAP command line. */
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz/* Disconnect client when it sends too many bad commands */
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)
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz const unsigned char *data;
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz data = i_stream_get_data(client->common.input, &data_size);
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz for (i = 0; i < data_size; i++) {
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarzstatic const char *get_capability(struct client *client)
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz struct imap_client *imap_client = (struct imap_client *)client;
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 str_append(cap_str, CAPABILITY_BANNER_STRING);
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz str_append(cap_str, imap_client->set->imap_capability + 1);
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarz if (client->set->disable_plaintext_auth && !client->secured)
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz client_authenticate_get_capabilities(client, cap_str);
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarzstatic int cmd_capability(struct imap_client *imap_client)
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz struct client *client = &imap_client->common;
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 imap_client->client_ignores_capability_resp_code = TRUE;
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 Slusarzstatic int cmd_starttls(struct imap_client *client)
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarzclient_update_info(struct imap_client *client, const struct imap_arg *args)
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz while (imap_arg_get_string(&args[0], &key) &&
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 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 Slusarzstatic int cmd_id(struct imap_client *client, const struct imap_arg *args)
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz value = imap_id_args_get_log_reply(args, env);
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 Slusarzstatic int cmd_noop(struct imap_client *client)
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz client_send_line(&client->common, CLIENT_CMD_REPLY_OK,
4ee5a85e75d520497bd43dbfcc6fc273f3e57ceaMichael Slusarz "NOOP completed.");
4ee5a85e75d520497bd43dbfcc6fc273f3e57ceaMichael Slusarzstatic int cmd_logout(struct imap_client *client)
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 Slusarzstatic int cmd_enable(struct imap_client *client)
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.");
f6fb60c7dcfc88895c8c45514c3fc424d3126336Michael Slusarzstatic int client_command_execute(struct imap_client *client, const char *cmd,
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarzstatic bool client_handle_input(struct imap_client *client)
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. */
41dc355b0d4e20037a36ec05206e7880f49f4ca9Michael Slusarz /* remove \r\n */
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz client->cmd_tag = imap_parser_read_word(client->parser);
33cbadf0114f3a5cb83bdb5a8bc07035f807e466Timo Sirainen client->cmd_name = imap_parser_read_word(client->parser);
e7e9ca33af09b6ab77633bcafe27d751adf09c93Michael Slusarz switch (imap_parser_read_args(client->parser, 0, 0, &args)) {
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz msg = imap_parser_get_error(client->parser, &fatal);
33cbadf0114f3a5cb83bdb5a8bc07035f807e466Timo Sirainen client_send_line(&client->common, CLIENT_CMD_REPLY_BAD, msg);
e7e9ca33af09b6ab77633bcafe27d751adf09c93Michael Slusarz /* not enough data */
e7e9ca33af09b6ab77633bcafe27d751adf09c93Michael Slusarz /* we read the entire line - skip over the CRLF */
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz ret = client_command_execute(client, client->cmd_name, args);
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) {
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 "Disconnected: Too many invalid commands");
33cbadf0114f3a5cb83bdb5a8bc07035f807e466Timo Sirainen client_send_line(&client->common, CLIENT_CMD_REPLY_BAD,
33cbadf0114f3a5cb83bdb5a8bc07035f807e466Timo Sirainen "Error in IMAP command received by server.");
e7e9ca33af09b6ab77633bcafe27d751adf09c93Michael Slusarz return ret != 0 && !client->common.destroyed;
33cbadf0114f3a5cb83bdb5a8bc07035f807e466Timo Sirainenstatic void imap_client_input(struct client *client)
e7e9ca33af09b6ab77633bcafe27d751adf09c93Michael Slusarz struct imap_client *imap_client = (struct imap_client *)client;
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz o_stream_cork(imap_client->common.output);
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 o_stream_uncork(imap_client->common.output);
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarzstatic struct client *imap_client_alloc(pool_t pool)
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz imap_client = p_new(pool, struct imap_client, 1);
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarzstatic void imap_client_create(struct client *client, void **other_sets)
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz struct imap_client *imap_client = (struct imap_client *)client;
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 Slusarzstatic void imap_client_destroy(struct client *client)
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz struct imap_client *imap_client = (struct imap_client *)client;
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz i_free_and_null(imap_client->proxy_backend_capability);
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarz imap_parser_destroy(&imap_client->parser);
51ed197520dd9ea534fbc3bc1790ebe3cb5421e2Michael M Slusarzstatic void imap_client_send_greeting(struct client *client)
const char *text)
switch (reply) {
case CLIENT_CMD_REPLY_OK:
case CLIENT_CMD_REPLY_BAD:
case CLIENT_CMD_REPLY_BYE:
case CLIENT_CMD_REPLY_STATUS:
T_BEGIN {
if (tagged)
} T_END;
void clients_init(void)
void clients_deinit(void)
NULL,
NULL,