client.c revision c2fbbf7515aa419dc8b2d62a3c2bb0471d51a391
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher/* Copyright (c) 2002-2010 Dovecot authors, see the included COPYING file */
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek/* maximum length for IMAP command line. */
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek/* Disconnect client when it sends too many bad commands */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher login_set_roots = imap_login_setting_roots;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher/* Skip incoming data until newline is found,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher returns TRUE if newline was found. */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherbool client_skip_line(struct imap_client *client)
f10ebaa51ecdcbbd10f171d19fe8e680e5bc74aaJakub Hrozek const unsigned char *data;
261cdde02b40aa8dabb3d69e43586a5a220647e9Jakub Hrozek data = i_stream_get_data(client->common.input, &data_size);
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek for (i = 0; i < data_size; i++) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstatic const char *get_capability(struct client *client)
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher struct imap_client *imap_client = (struct imap_client *)client;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher cap_str = *imap_client->set->imap_capability != '\0' ?
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher imap_client->set->imap_capability : CAPABILITY_BANNER_STRING;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher auths = client_authenticate_get_capabilities(client);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher (ssl_initialized && !client->tls) ? " STARTTLS" : "",
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozekstatic int cmd_capability(struct imap_client *imap_client)
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek /* Client is required to send CAPABILITY after STARTTLS, so the
9a839b29816c8906d4a6b074cf76df790cac9209Jakub Hrozek capability resp-code workaround checks only pre-STARTTLS
9a839b29816c8906d4a6b074cf76df790cac9209Jakub Hrozek CAPABILITY commands. */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher imap_client->client_ignores_capability_resp_code = TRUE;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher "* CAPABILITY ", get_capability(client), "\r\n", NULL));
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client_send_line(client, CLIENT_CMD_REPLY_OK, "Capability completed.");
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstatic int cmd_starttls(struct imap_client *client)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherclient_update_info(struct imap_client *client, const struct imap_arg *args)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher while (imap_arg_get_string(&args[0], &key) &&
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher if (strcasecmp(key, "x-originating-ip") == 0)
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher (void)net_addr2ip(value, &client->common.ip);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher else if (strcasecmp(key, "x-originating-port") == 0)
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher else if (strcasecmp(key, "x-connected-ip") == 0)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher (void)net_addr2ip(value, &client->common.local_ip);
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher else if (strcasecmp(key, "x-connected-port") == 0)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstatic int cmd_id(struct imap_client *client, const struct imap_arg *args)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher value = imap_id_args_get_log_reply(args, env);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher t_strdup_printf("* ID %s\r\n", imap_id_reply_generate(env)));
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher client_send_line(&client->common, CLIENT_CMD_REPLY_OK, "ID completed.");
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstatic int cmd_noop(struct imap_client *client)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client_send_line(&client->common, CLIENT_CMD_REPLY_OK,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher "NOOP completed.");
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozekstatic int cmd_logout(struct imap_client *client)
9a839b29816c8906d4a6b074cf76df790cac9209Jakub Hrozek client_send_line(&client->common, CLIENT_CMD_REPLY_BYE, "Logging out");
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client_send_line(&client->common, CLIENT_CMD_REPLY_OK,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher "Logout completed.");
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client_destroy(&client->common, "Aborted login");
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozekstatic int cmd_enable(struct imap_client *client)
9a839b29816c8906d4a6b074cf76df790cac9209Jakub Hrozek client_send_raw(&client->common, "* ENABLED\r\n");
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client_send_line(&client->common, CLIENT_CMD_REPLY_OK,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher "ENABLE ignored in non-authenticated state.");
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstatic int client_command_execute(struct imap_client *client, const char *cmd,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstatic bool client_handle_input(struct imap_client *client)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher /* clear the previous command from memory. don't do this
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher immediately after handling command since we need the
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher cmd_tag to stay some time after authentication commands. */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher /* remove \r\n */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client->cmd_tag = imap_parser_read_word(client->parser);
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher client->cmd_name = imap_parser_read_word(client->parser);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher switch (imap_parser_read_args(client->parser, 0, 0, &args)) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher msg = imap_parser_get_error(client->parser, &fatal);
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek client_send_line(&client->common, CLIENT_CMD_REPLY_BAD, msg);
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek /* not enough data */
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek /* we read the entire line - skip over the CRLF */
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek ret = client_command_execute(client, client->cmd_name, args);
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek if (ret == -2 && strcasecmp(client->cmd_tag, "LOGIN") == 0) {
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek client_send_line(&client->common, CLIENT_CMD_REPLY_BAD,
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek "First parameter in line is IMAP's command tag, "
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek "not the command name. Add that before the command, "
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek "like: a login user pass");
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek } else if (ret < 0) {
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek if (++client->common.bad_counter >= CLIENT_MAX_BAD_COMMANDS) {
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek client_send_line(&client->common, CLIENT_CMD_REPLY_BYE,
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek "Too many invalid IMAP commands.");
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek "Disconnected: Too many invalid commands");
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek client_send_line(&client->common, CLIENT_CMD_REPLY_BAD,
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek "Error in IMAP command received by server.");
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozekstatic void imap_client_input(struct client *client)
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek struct imap_client *imap_client = (struct imap_client *)client;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek /* we're not currently connected to auth process -
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek don't allow any commands */
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek client_send_line(client, CLIENT_CMD_REPLY_STATUS,
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozekstatic struct client *imap_client_alloc(pool_t pool)
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek imap_client = p_new(pool, struct imap_client, 1);
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozekstatic void imap_client_create(struct client *client, void **other_sets)
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek struct imap_client *imap_client = (struct imap_client *)client;
9a839b29816c8906d4a6b074cf76df790cac9209Jakub Hrozek client->io = io_add(client->fd, IO_READ, client_input, client);
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozekstatic void imap_client_destroy(struct client *client)
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek struct imap_client *imap_client = (struct imap_client *)client;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek i_free_and_null(imap_client->proxy_backend_capability);
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozekstatic void imap_client_send_greeting(struct client *client)
9a839b29816c8906d4a6b074cf76df790cac9209Jakub Hrozek str_printfa(greet, "[CAPABILITY %s] ", get_capability(client));
7465d6a1ef6e83825dba3a4dc4dda7271671aba0Jakub Hrozek str_append(greet, client->set->login_greeting);
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozekstatic void imap_client_starttls(struct client *client)
7465d6a1ef6e83825dba3a4dc4dda7271671aba0Jakub Hrozek struct imap_client *imap_client = (struct imap_client *)client;
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek /* CRLF is lost from buffer when streams are reopened. */
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozekimap_client_send_line(struct client *client, enum client_cmd_reply reply,
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek const char *text)
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek struct imap_client *imap_client = (struct imap_client *)client;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher resp_code = IMAP_RESP_CODE_PRIVACYREQUIRED;