client.c revision 00fa8dcbc66f56daa737487c9dec7166c37de79e
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher/* Copyright (c) 2002-2009 Dovecot authors, see the included COPYING file */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher#include "common.h"
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher#include "buffer.h"
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher#include "ioloop.h"
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher#include "istream.h"
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher#include "ostream.h"
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher#include "process-title.h"
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher#include "safe-memset.h"
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher#include "str.h"
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek#include "strescape.h"
7a14e8f66c0e932fe2954d792614a3b61d444bd1Jakub Hrozek#include "imap-parser.h"
7797e361155f7ce937085fd98e360469d7baf1b6Jakub Hrozek#include "imap-id.h"
64a424ec1b268427822c646f7781e26e56c197f6Jakub Hrozek#include "imap-resp-code.h"
2ea6196484055397cc4bc011c5960f790431fa9dStephen Gallagher#include "master-service.h"
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher#include "master-auth.h"
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher#include "client.h"
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher#include "client-authenticate.h"
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher#include "auth-client.h"
7a14e8f66c0e932fe2954d792614a3b61d444bd1Jakub Hrozek#include "ssl-proxy.h"
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher#include "imap-proxy.h"
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher#include <stdlib.h>
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek/* max. size of output buffer. if it gets full, the client is disconnected.
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek SASL authentication gives the largest output. */
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek#define MAX_OUTBUF_SIZE 4096
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek/* maximum length for IMAP command line. */
2ea6196484055397cc4bc011c5960f790431fa9dStephen Gallagher#define MAX_IMAP_LINE 8192
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher/* Disconnect client when it sends too many bad commands */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher#define CLIENT_MAX_BAD_COMMANDS 10
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher/* When max. number of simultaneous connections is reached, few of the
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher oldest connections are disconnected. Since we have to go through all of the
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher clients, it's faster if we disconnect multiple clients. */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher#define CLIENT_DESTROY_OLDEST_COUNT 16
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher/* If we've been waiting auth server to respond for over this many milliseconds,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher send a "waiting" message. */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher#define AUTH_WAITING_TIMEOUT_MSECS (30*1000)
2ea6196484055397cc4bc011c5960f790431fa9dStephen Gallagher
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek#if CLIENT_LOGIN_IDLE_TIMEOUT_MSECS < AUTH_REQUEST_TIMEOUT*1000
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher# error client idle timeout must be larger than authentication timeout
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher#endif
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher#define AUTH_SERVER_WAITING_MSG \
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher "Waiting for authentication process to respond.."
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher#define AUTH_MASTER_WAITING_MSG \
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher "Waiting for authentication master process to respond.."
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherconst char *login_protocol = "imap";
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherconst char *login_process_name = "imap-login";
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagherstatic void client_set_title(struct imap_client *client)
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher{
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher const char *addr;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher if (!client->common.set->verbose_proctitle ||
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher !client->common.set->login_process_per_connection)
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher return;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher addr = net_ip2addr(&client->common.ip);
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher if (addr == NULL)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher addr = "??";
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek process_title_set(t_strdup_printf(client->common.tls ?
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek "[%s TLS]" : "[%s]", addr));
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek}
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek
2ea6196484055397cc4bc011c5960f790431fa9dStephen Gallagherstatic void client_open_streams(struct imap_client *client, int fd)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client->common.input =
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher i_stream_create_fd(fd, LOGIN_MAX_INBUF_SIZE, FALSE);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client->output = o_stream_create_fd(fd, MAX_OUTBUF_SIZE, FALSE);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client->parser = imap_parser_create(client->common.input,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client->output, MAX_IMAP_LINE);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher}
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
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)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher const unsigned char *data;
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher size_t i, data_size;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher data = i_stream_get_data(client->common.input, &data_size);
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek
ea929f1b022fc2cb77dec89b0e12accef983ec85Jakub Hrozek for (i = 0; i < data_size; i++) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (data[i] == '\n') {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher i_stream_skip(client->common.input, i+1);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return TRUE;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher return FALSE;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher}
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagherstatic const char *get_capability(struct imap_client *client)
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher{
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher const char *auths;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher auths = client_authenticate_get_capabilities(client);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return t_strconcat(CAPABILITY_BANNER_STRING,
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher (ssl_initialized && !client->common.tls) ?
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher " STARTTLS" : "",
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher client->common.set->disable_plaintext_auth &&
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher !client->common.secured ?
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher " LOGINDISABLED" : "", auths, NULL);
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher}
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstatic int cmd_capability(struct imap_client *client)
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher{
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher /* Client is required to send CAPABILITY after STARTTLS, so the
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher capability resp-code workaround checks only pre-STARTTLS
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher CAPABILITY commands. */
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher if (!client->starttls)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client->client_ignores_capability_resp_code = TRUE;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher client_send_raw(client, t_strconcat(
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher "* CAPABILITY ", get_capability(client), "\r\n", NULL));
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client_send_line(&client->common, CLIENT_CMD_REPLY_OK,
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher "Capability completed.");
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return 1;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher}
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagherstatic void client_start_tls(struct imap_client *client)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher int fd_ssl;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client_ref(client);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (!client_unref(client) || client->destroyed)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher fd_ssl = ssl_proxy_new(client->common.fd, &client->common.ip,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client->common.set, &client->common.proxy);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (fd_ssl == -1) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client_send_line(&client->common, CLIENT_CMD_REPLY_BYE,
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek "TLS initialization failed.");
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client_destroy(client,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher "Disconnected: TLS initialization failed.");
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek client->starttls = TRUE;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client->common.proxying = TRUE;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client->common.tls = TRUE;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client->common.secured = TRUE;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client_set_title(client);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek client->common.fd = fd_ssl;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher i_stream_unref(&client->common.input);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher o_stream_unref(&client->output);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher imap_parser_destroy(&client->parser);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher /* CRLF is lost from buffer when streams are reopened. */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client->skip_line = FALSE;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client_open_streams(client, fd_ssl);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client->io = io_add(client->common.fd, IO_READ, client_input, client);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher}
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstatic int client_output_starttls(struct imap_client *client)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher int ret;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if ((ret = o_stream_flush(client->output)) < 0) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client_destroy(client, "Disconnected");
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return 1;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (ret > 0) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher o_stream_unset_flush_callback(client->output);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client_start_tls(client);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return 1;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher}
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagherstatic int cmd_starttls(struct imap_client *client)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (client->common.tls) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client_send_line(&client->common, CLIENT_CMD_REPLY_BAD,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher "TLS is already active.");
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return 1;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher }
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (!ssl_initialized) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client_send_line(&client->common, CLIENT_CMD_REPLY_BAD,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher "TLS support isn't enabled.");
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return 1;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher /* remove input handler, SSL proxy gives us a new fd. we also have to
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher remove it in case we have to wait for buffer to be flushed */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (client->io != NULL)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher io_remove(&client->io);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client_send_line(&client->common, CLIENT_CMD_REPLY_OK,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher "Begin TLS negotiation now.");
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher /* uncork the old fd */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher o_stream_uncork(client->output);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (o_stream_flush(client->output) <= 0) {
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher /* the buffer has to be flushed */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher o_stream_set_flush_pending(client->output, TRUE);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher o_stream_set_flush_callback(client->output,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client_output_starttls, client);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher } else {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client_start_tls(client);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return 1;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher}
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstatic void
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherclient_update_info(struct imap_client *client, const struct imap_arg *args)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher const char *key, *value;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (args->type != IMAP_ARG_LIST)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher args = IMAP_ARG_LIST_ARGS(args);
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher while (args->type == IMAP_ARG_STRING &&
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher args[1].type == IMAP_ARG_STRING) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher key = IMAP_ARG_STR_NONULL(&args[0]);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher value = IMAP_ARG_STR_NONULL(&args[1]);
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher if (strcasecmp(key, "x-originating-ip") == 0)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher (void)net_addr2ip(value, &client->common.ip);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher else if (strcasecmp(key, "x-originating-port") == 0)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client->common.remote_port = atoi(value);
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher else if (strcasecmp(key, "x-connected-ip") == 0)
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek (void)net_addr2ip(value, &client->common.local_ip);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher else if (strcasecmp(key, "x-connected-port") == 0)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client->common.local_port = atoi(value);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher args += 2;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher }
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher}
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstatic int cmd_id(struct imap_client *client, const struct imap_arg *args)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher const char *env, *value;
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (!client->id_logged) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client->id_logged = TRUE;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (client->common.trusted)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client_update_info(client, args);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher env = getenv("IMAP_ID_LOG");
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher value = imap_id_args_get_log_reply(args, env);
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher if (value != NULL) {
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher client_syslog(&client->common,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher t_strdup_printf("ID sent: %s", value));
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher env = getenv("IMAP_ID_SEND");
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client_send_raw(client,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher t_strdup_printf("* ID %s\r\n", imap_id_reply_generate(env)));
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client_send_line(&client->common, CLIENT_CMD_REPLY_OK, "ID completed.");
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return 1;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher}
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagherstatic int cmd_noop(struct imap_client *client)
056302a92862fda16351d7192600746746f38e5dStephen Gallagher{
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher client_send_line(&client->common, CLIENT_CMD_REPLY_OK,
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher "NOOP completed.");
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher return 1;
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher}
056302a92862fda16351d7192600746746f38e5dStephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstatic int cmd_logout(struct imap_client *client)
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher{
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek client_send_line(&client->common, CLIENT_CMD_REPLY_BYE,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher "Logging out");
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client_send_line(&client->common, CLIENT_CMD_REPLY_OK,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher "Logout completed.");
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher client_destroy(client, "Aborted login");
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek return 1;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher}
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstatic int cmd_enable(struct imap_client *client)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client_send_raw(client, "* ENABLED\r\n");
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client_send_line(&client->common, CLIENT_CMD_REPLY_OK,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher "ENABLE ignored in non-authenticated state.");
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher return 1;
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek}
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstatic int client_command_execute(struct imap_client *client, const char *cmd,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher const struct imap_arg *args)
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher{
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher cmd = t_str_ucase(cmd);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (strcmp(cmd, "LOGIN") == 0)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return cmd_login(client, args);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (strcmp(cmd, "AUTHENTICATE") == 0)
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher return cmd_authenticate(client, args);
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher if (strcmp(cmd, "CAPABILITY") == 0)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return cmd_capability(client);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (strcmp(cmd, "STARTTLS") == 0)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return cmd_starttls(client);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (strcmp(cmd, "ID") == 0)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return cmd_id(client, args);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (strcmp(cmd, "NOOP") == 0)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return cmd_noop(client);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (strcmp(cmd, "LOGOUT") == 0)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return cmd_logout(client);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (strcmp(cmd, "ENABLE") == 0)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return cmd_enable(client);
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek return -1;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher}
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstatic bool client_handle_input(struct imap_client *client)
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher{
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher const struct imap_arg *args;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher const char *msg;
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher int ret;
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher bool fatal;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher i_assert(!client->common.authenticating);
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek if (client->cmd_finished) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher /* clear the previous command from memory. don't do this
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek immediately after handling command since we need the
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek cmd_tag to stay some time after authentication commands. */
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek client->cmd_tag = NULL;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client->cmd_name = NULL;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher imap_parser_reset(client->parser);
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek /* remove \r\n */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (client->skip_line) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (!client_skip_line(client))
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return FALSE;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher client->skip_line = FALSE;
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher client->cmd_finished = FALSE;
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher }
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (client->cmd_tag == NULL) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client->cmd_tag = imap_parser_read_word(client->parser);
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher if (client->cmd_tag == NULL)
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek return FALSE; /* need more data */
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher }
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher if (client->cmd_name == NULL) {
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher client->cmd_name = imap_parser_read_word(client->parser);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (client->cmd_name == NULL)
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher return FALSE; /* need more data */
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher switch (imap_parser_read_args(client->parser, 0, 0, &args)) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher case -1:
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher /* error */
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek msg = imap_parser_get_error(client->parser, &fatal);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (fatal) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client_send_line(&client->common,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher CLIENT_CMD_REPLY_BYE, msg);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client_destroy(client,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher t_strconcat("Disconnected: ", msg, NULL));
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return FALSE;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher }
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client_send_line(&client->common, CLIENT_CMD_REPLY_BAD, msg);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client->cmd_finished = TRUE;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client->skip_line = TRUE;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher return TRUE;
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek case -2:
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher /* not enough data */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return FALSE;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher /* we read the entire line - skip over the CRLF */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (!client_skip_line(client))
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher i_unreached();
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher if (*client->cmd_tag == '\0')
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher ret = -1;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher else
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek ret = client_command_execute(client, client->cmd_name, args);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client->cmd_finished = TRUE;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (ret < 0) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (*client->cmd_tag == '\0')
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client->cmd_tag = "*";
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (++client->bad_counter >= CLIENT_MAX_BAD_COMMANDS) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client_send_line(&client->common, CLIENT_CMD_REPLY_BYE,
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher "Too many invalid IMAP commands.");
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek client_destroy(client,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher "Disconnected: Too many invalid commands");
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return FALSE;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client_send_line(&client->common, CLIENT_CMD_REPLY_BAD,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher "Error in IMAP command received by server.");
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher }
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return ret != 0;
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher}
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagherbool client_read(struct imap_client *client)
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher{
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher switch (i_stream_read(client->common.input)) {
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher case -2:
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek /* buffer full */
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher client_send_line(&client->common, CLIENT_CMD_REPLY_BYE,
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher "Input buffer full, aborting");
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher client_destroy(client, "Disconnected: Input buffer full");
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher return FALSE;
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher case -1:
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher /* disconnected */
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher client_destroy(client, "Disconnected");
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher return FALSE;
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek case 0:
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher /* nothing new read */
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher return TRUE;
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher default:
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher /* something was read */
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher timeout_reset(client->to_idle_disconnect);
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher return TRUE;
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek }
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher}
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallaghervoid client_input(struct imap_client *client)
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher{
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher if (!client_read(client))
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher return;
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher client_ref(client);
486237ee009f1d84fc4c85665dce80ade76f7079Stephen Gallagher
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher if (!auth_client_is_connected(auth_client)) {
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher /* we're not yet connected to auth process -
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek don't allow any commands */
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher client_send_line(&client->common, CLIENT_CMD_REPLY_STATUS,
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher AUTH_SERVER_WAITING_MSG);
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher if (client->to_auth_waiting != NULL)
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher timeout_remove(&client->to_auth_waiting);
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher client->input_blocked = TRUE;
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher } else {
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher o_stream_cork(client->output);
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher while (client_handle_input(client)) ;
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek o_stream_uncork(client->output);
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek }
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher client_unref(client);
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher}
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozekvoid client_destroy_oldest(void)
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek{
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek unsigned int max_connections =
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek global_login_settings->login_max_connections;
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek struct client *client;
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek struct imap_client *destroy_buf[CLIENT_DESTROY_OLDEST_COUNT];
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek unsigned int i, destroy_count;
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek /* find the oldest clients and put them to destroy-buffer */
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek memset(destroy_buf, 0, sizeof(destroy_buf));
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek destroy_count = max_connections > CLIENT_DESTROY_OLDEST_COUNT*2 ?
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek CLIENT_DESTROY_OLDEST_COUNT : I_MIN(max_connections/2, 1);
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek for (client = clients; client != NULL; client = client->next) {
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek struct imap_client *imap_client = (struct imap_client *)client;
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek for (i = 0; i < destroy_count; i++) {
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek if (destroy_buf[i] == NULL ||
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek destroy_buf[i]->created > imap_client->created) {
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek /* @UNSAFE */
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek memmove(destroy_buf+i+1, destroy_buf+i,
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek sizeof(destroy_buf) -
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek (i+1) * sizeof(struct imap_client *));
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek destroy_buf[i] = imap_client;
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek break;
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek }
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek }
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek }
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher /* then kill them */
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher for (i = 0; i < destroy_count; i++) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (destroy_buf[i] == NULL)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher break;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client_destroy(destroy_buf[i],
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher "Disconnected: Connection queue full");
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher }
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher}
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstatic void client_send_greeting(struct imap_client *client)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek string_t *greet;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher greet = t_str_new(128);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher str_append(greet, "* OK ");
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher str_printfa(greet, "[CAPABILITY %s] ", get_capability(client));
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek str_append(greet, client->common.set->login_greeting);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher str_append(greet, "\r\n");
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client_send_raw(client, str_c(greet));
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher client->greeting_sent = TRUE;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher}
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstatic void client_idle_disconnect_timeout(struct imap_client *client)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek client_send_line(&client->common, CLIENT_CMD_REPLY_BAD,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher "Disconnected for inactivity.");
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client_destroy(client, "Disconnected: Inactivity");
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher}
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozekstatic void client_auth_waiting_timeout(struct imap_client *client)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client_send_line(&client->common, CLIENT_CMD_REPLY_STATUS,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client->common.master_tag == 0 ?
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher AUTH_SERVER_WAITING_MSG : AUTH_MASTER_WAITING_MSG);
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek timeout_remove(&client->to_auth_waiting);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher}
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallaghervoid client_set_auth_waiting(struct imap_client *client)
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher{
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek i_assert(client->to_auth_waiting == NULL);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client->to_auth_waiting =
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher timeout_add(AUTH_WAITING_TIMEOUT_MSECS,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client_auth_waiting_timeout, client);
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher}
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherstruct client *client_create(int fd, bool ssl, pool_t pool,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher const struct login_settings *set,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher const struct ip_addr *local_ip,
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher const struct ip_addr *remote_ip)
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek{
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek struct imap_client *client;
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher i_assert(fd != -1);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (clients_get_count() >= set->login_max_connections) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher /* reached max. users count, kill few of the
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher oldest connections */
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek client_destroy_oldest();
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher }
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher /* always use nonblocking I/O */
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher net_set_nonblock(fd, TRUE);
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher client = p_new(pool, struct imap_client, 1);
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher client->created = ioloop_time;
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher client->refcount = 1;
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek client->common.pool = pool;
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek client->common.set = set;
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek client->common.local_ip = *local_ip;
64a424ec1b268427822c646f7781e26e56c197f6Jakub Hrozek client->common.ip = *remote_ip;
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher client->common.fd = fd;
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher client->common.tls = ssl;
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher client->common.trusted = client_is_trusted(&client->common);
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher client->common.secured = ssl || client->common.trusted ||
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek net_ip_compare(remote_ip, local_ip);
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher
2ea6196484055397cc4bc011c5960f790431fa9dStephen Gallagher client_open_streams(client, fd);
2ea6196484055397cc4bc011c5960f790431fa9dStephen Gallagher client->io = io_add(fd, IO_READ, client_input, client);
2ea6196484055397cc4bc011c5960f790431fa9dStephen Gallagher
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek client_link(&client->common);
2ea6196484055397cc4bc011c5960f790431fa9dStephen Gallagher
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher if (auth_client_is_connected(auth_client))
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher client_send_greeting(client);
2ea6196484055397cc4bc011c5960f790431fa9dStephen Gallagher else
2ea6196484055397cc4bc011c5960f790431fa9dStephen Gallagher client_set_auth_waiting(client);
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher client_set_title(client);
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher client->to_idle_disconnect =
2ea6196484055397cc4bc011c5960f790431fa9dStephen Gallagher timeout_add(CLIENT_LOGIN_IDLE_TIMEOUT_MSECS,
2ea6196484055397cc4bc011c5960f790431fa9dStephen Gallagher client_idle_disconnect_timeout, client);
2ea6196484055397cc4bc011c5960f790431fa9dStephen Gallagher return &client->common;
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek}
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallaghervoid client_destroy(struct imap_client *client, const char *reason)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher if (client->destroyed)
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek return;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client->destroyed = TRUE;
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher if (!client->login_success && reason != NULL) {
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher reason = t_strconcat(reason, " ",
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher client_get_extra_disconnect_reason(&client->common),
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher NULL);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (reason != NULL)
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher client_syslog(&client->common, reason);
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher client_unlink(&client->common);
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (client->common.input != NULL)
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher i_stream_close(client->common.input);
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek if (client->output != NULL)
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher o_stream_close(client->output);
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher if (client->common.master_tag != 0) {
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher i_assert(client->common.auth_request == NULL);
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek i_assert(client->common.authenticating);
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher master_auth_request_abort(master_service,
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher client->common.master_tag);
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher } else if (client->common.auth_request != NULL) {
7797e361155f7ce937085fd98e360469d7baf1b6Jakub Hrozek i_assert(client->common.authenticating);
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher sasl_server_auth_abort(&client->common);
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher } else {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher i_assert(!client->common.authenticating);
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (client->io != NULL)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher io_remove(&client->io);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (client->to_idle_disconnect != NULL)
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek timeout_remove(&client->to_idle_disconnect);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (client->to_auth_waiting != NULL)
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher timeout_remove(&client->to_auth_waiting);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (client->to_authfail_delay != NULL)
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher timeout_remove(&client->to_authfail_delay);
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (client->common.fd != -1) {
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher net_disconnect(client->common.fd);
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek client->common.fd = -1;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (client->proxy_password != NULL) {
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher safe_memset(client->proxy_password, 0,
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek strlen(client->proxy_password));
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher i_free(client->proxy_password);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client->proxy_password = NULL;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher i_free_and_null(client->proxy_user);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher i_free_and_null(client->proxy_master_user);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher i_free_and_null(client->proxy_backend_capability);
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek if (client->proxy != NULL)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher login_proxy_free(&client->proxy);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (client->common.proxy != NULL) {
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher ssl_proxy_free(client->common.proxy);
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek client->common.proxy = NULL;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client_unref(client);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher}
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozekvoid client_destroy_success(struct imap_client *client, const char *reason)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher client->login_success = TRUE;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher client_destroy(client, reason);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher}
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallaghervoid client_destroy_internal_failure(struct imap_client *client)
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher{
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek client_send_line(&client->common, CLIENT_CMD_REPLY_BYE,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher "Internal login failure. "
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher "Refer to server log for more information.");
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client_destroy(client, "Internal login failure");
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher}
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallaghervoid client_ref(struct imap_client *client)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client->refcount++;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher}
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherbool client_unref(struct imap_client *client)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher i_assert(client->refcount > 0);
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher if (--client->refcount > 0)
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher return TRUE;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher i_assert(client->destroyed);
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek imap_parser_destroy(&client->parser);
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher if (client->common.input != NULL)
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher i_stream_unref(&client->common.input);
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher if (client->output != NULL)
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek o_stream_unref(&client->output);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (!client->common.proxying) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher i_assert(client->common.proxy == NULL);
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher master_service_client_connection_destroyed(master_service);
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher i_free(client->common.virtual_user);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher i_free(client->common.auth_mech_name);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher pool_unref(&client->common.pool);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher return FALSE;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher}
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozekstatic void
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagherclient_send_raw_data(struct imap_client *client, const void *data, size_t size)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher ssize_t ret;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek ret = o_stream_send(client->output, data, size);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (ret < 0 || (size_t)ret != size) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher /* either disconnection or buffer full. in either case we want
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher this connection destroyed. however destroying it here might
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher break things if client is still tried to be accessed without
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek being referenced.. */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher i_stream_close(client->common.input);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher }
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher}
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallaghervoid client_send_raw(struct imap_client *client, const char *data)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher client_send_raw_data(client, data, strlen(data));
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher}
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallaghervoid client_send_line(struct client *client, enum client_cmd_reply reply,
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher const char *text)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher{
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher struct imap_client *imap_client = (struct imap_client *)client;
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek const char *resp_code = NULL;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher const char *prefix = "NO";
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher bool tagged = TRUE;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher switch (reply) {
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek case CLIENT_CMD_REPLY_OK:
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher prefix = "OK";
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher break;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher case CLIENT_CMD_REPLY_AUTH_FAILED:
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher resp_code = IMAP_RESP_CODE_AUTHFAILED;
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek break;
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek case CLIENT_CMD_REPLY_AUTHZ_FAILED:
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher resp_code = IMAP_RESP_CODE_AUTHZFAILED;
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher break;
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher case CLIENT_CMD_REPLY_AUTH_FAIL_TEMP:
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher resp_code = IMAP_RESP_CODE_UNAVAILABLE;
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek break;
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher case CLIENT_CMD_REPLY_AUTH_FAIL_REASON:
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher resp_code = "ALERT";
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher break;
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher case CLIENT_CMD_REPLY_AUTH_FAIL_NOSSL:
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek resp_code = IMAP_RESP_CODE_PRIVACYREQUIRED;
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher break;
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher case CLIENT_CMD_REPLY_BAD:
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher prefix = "BAD";
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher break;
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek case CLIENT_CMD_REPLY_BYE:
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher prefix = "BYE";
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher tagged = FALSE;
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher break;
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek case CLIENT_CMD_REPLY_STATUS:
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek prefix = "OK";
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher tagged = FALSE;
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher break;
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher }
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek T_BEGIN {
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher string_t *line = t_str_new(256);
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher if (tagged)
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek str_append(line, imap_client->cmd_tag);
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek else
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher str_append_c(line, '*');
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher str_append_c(line, ' ');
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher str_append(line, prefix);
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek str_append_c(line, ' ');
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek if (resp_code != NULL)
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher str_printfa(line, "[%s] ", resp_code);
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher str_append(line, text);
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher str_append(line, "\r\n");
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek client_send_raw_data(imap_client, str_data(line),
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher str_len(line));
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher } T_END;
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher}
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozekvoid clients_notify_auth_connected(void)
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher{
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher struct client *client;
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher for (client = clients; client != NULL; client = client->next) {
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek struct imap_client *imap_client = (struct imap_client *)client;
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher if (imap_client->to_auth_waiting != NULL)
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher timeout_remove(&imap_client->to_auth_waiting);
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek if (!imap_client->greeting_sent)
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek client_send_greeting(imap_client);
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher if (imap_client->input_blocked) {
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher imap_client->input_blocked = FALSE;
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher client_input(imap_client);
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher }
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher }
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher}
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozekvoid clients_destroy_all(void)
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher{
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher struct client *client, *next;
9643e7da1a54a9edb2360ab8f855664a8b4397caStephen Gallagher
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek for (client = clients; client != NULL; client = next) {
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek struct imap_client *imap_client = (struct imap_client *)client;
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek next = client->next;
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek client_destroy(imap_client, "Disconnected: Shutting down");
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek }
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek}
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozekvoid clients_init(void)
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek{
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek /* Nothing to initialize for IMAP */
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek}
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozekvoid clients_deinit(void)
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek{
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek clients_destroy_all();
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek}
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek