client.c revision d5cebe7f98e63d4e2822863ef2faa4971e8b3a5d
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (C) 2002 Timo Sirainen */
1d4f710106fb498750456724628da6063e012e6dTimo Sirainen
46552a931924c2d743f045e95b08c3ce6beda91aTimo Sirainen#include "common.h"
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen#include "buffer.h"
d3d769026fae5d21c2d29614d3bc4579e8d79e81Timo Sirainen#include "hash.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include "ioloop.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include "istream.h"
baebb412a9a5a44b1756e01cfa3b99f5d8a846b6Timo Sirainen#include "ostream.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include "process-title.h"
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen#include "safe-memset.h"
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen#include "str.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include "strescape.h"
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen#include "imap-parser.h"
92c49f3005f4dff1a6f576fffa8112ef6d1cae7fTimo Sirainen#include "client.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include "client-authenticate.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include "auth-client.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include "ssl-proxy.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include "imap-proxy.h"
4ead43ecc06d10047998966c4dc0b142ecce4b66Timo Sirainen
1d4f710106fb498750456724628da6063e012e6dTimo Sirainen/* max. size of one parameter in line, or max reply length in SASL
1d4f710106fb498750456724628da6063e012e6dTimo Sirainen authentication */
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen#define MAX_INBUF_SIZE 4096
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen/* max. size of output buffer. if it gets full, the client is disconnected.
ab0d9eecd85f74acae18fe88529302e0776cc500Timo Sirainen SASL authentication gives the largest output. */
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainen#define MAX_OUTBUF_SIZE 4096
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen/* maximum length for IMAP command line. */
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen#define MAX_IMAP_LINE 8192
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen/* Disconnect client after idling this many seconds */
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen#define CLIENT_LOGIN_IDLE_TIMEOUT 60
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen/* Disconnect client when it sends too many bad commands */
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen#define CLIENT_MAX_BAD_COMMANDS 10
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen/* When max. number of simultaneous connections is reached, few of the
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen oldest connections are disconnected. Since we have to go through the whole
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen client hash, it's faster if we disconnect multiple clients. */
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen#define CLIENT_DESTROY_OLDEST_COUNT 16
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen#if CLIENT_LOGIN_IDLE_TIMEOUT >= AUTH_REQUEST_TIMEOUT
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen# error client idle timeout must be smaller than authentication timeout
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen#endif
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainenconst char *login_protocol = "IMAP";
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainenstatic struct hash_table *clients;
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainenstatic struct timeout *to_idle;
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainenstatic void client_set_title(struct imap_client *client)
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen{
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen const char *addr;
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen if (!verbose_proctitle || !process_per_connection)
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen return;
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen addr = net_ip2addr(&client->common.ip);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (addr == NULL)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen addr = "??";
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainen process_title_set(t_strdup_printf(client->common.tls ?
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen "[%s TLS]" : "[%s]", addr));
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic void client_open_streams(struct imap_client *client, int fd)
baebb412a9a5a44b1756e01cfa3b99f5d8a846b6Timo Sirainen{
baebb412a9a5a44b1756e01cfa3b99f5d8a846b6Timo Sirainen client->input = i_stream_create_file(fd, default_pool,
baebb412a9a5a44b1756e01cfa3b99f5d8a846b6Timo Sirainen MAX_INBUF_SIZE, FALSE);
baebb412a9a5a44b1756e01cfa3b99f5d8a846b6Timo Sirainen client->output = o_stream_create_file(fd, default_pool, MAX_OUTBUF_SIZE,
baebb412a9a5a44b1756e01cfa3b99f5d8a846b6Timo Sirainen FALSE);
baebb412a9a5a44b1756e01cfa3b99f5d8a846b6Timo Sirainen client->parser = imap_parser_create(client->input, client->output,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen MAX_IMAP_LINE);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
f059a046515f4b2b15a6c2a10a6f12f6166e39a5Timo Sirainen
f059a046515f4b2b15a6c2a10a6f12f6166e39a5Timo Sirainen/* Skip incoming data until newline is found,
f059a046515f4b2b15a6c2a10a6f12f6166e39a5Timo Sirainen returns TRUE if newline was found. */
f059a046515f4b2b15a6c2a10a6f12f6166e39a5Timo Sirainenbool client_skip_line(struct imap_client *client)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const unsigned char *data;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen size_t i, data_size;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen data = i_stream_get_data(client->input, &data_size);
5a250816ffc4cc5db203f9410ea99b6601c7b91aTimo Sirainen
5a250816ffc4cc5db203f9410ea99b6601c7b91aTimo Sirainen for (i = 0; i < data_size; i++) {
46ec792dd4ccf6c34706c4774228301fafde6aa9Timo Sirainen if (data[i] == '\n') {
46ec792dd4ccf6c34706c4774228301fafde6aa9Timo Sirainen i_stream_skip(client->input, i+1);
46ec792dd4ccf6c34706c4774228301fafde6aa9Timo Sirainen return TRUE;
46ec792dd4ccf6c34706c4774228301fafde6aa9Timo Sirainen }
4c6ddf2491104f917d00e6900e833e80ea02c7b6Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return FALSE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic const char *get_capability(struct imap_client *client)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const char *auths;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen auths = client_authenticate_get_capabilities(client->common.secured);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return t_strconcat(CAPABILITY_STRING,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen (ssl_initialized && !client->common.tls) ?
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen " STARTTLS" : "",
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen disable_plaintext_auth && !client->common.secured ?
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen " LOGINDISABLED" : "", auths, NULL);
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen}
d3d769026fae5d21c2d29614d3bc4579e8d79e81Timo Sirainen
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainenstatic int cmd_capability(struct imap_client *client)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
5a9e240ebf8d0daaf029973973b52e415148070bTimo Sirainen client_send_line(client, t_strconcat("* CAPABILITY ",
5a9e240ebf8d0daaf029973973b52e415148070bTimo Sirainen get_capability(client), NULL));
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_send_tagline(client, "OK Capability completed.");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return 1;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
f059a046515f4b2b15a6c2a10a6f12f6166e39a5Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic void client_start_tls(struct imap_client *client)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen int fd_ssl;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen fd_ssl = ssl_proxy_new(client->common.fd, &client->common.ip,
54533aa265f5c87730022cc7576090bc51370f97Timo Sirainen &client->common.proxy);
54533aa265f5c87730022cc7576090bc51370f97Timo Sirainen if (fd_ssl == -1) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_send_line(client, "* BYE TLS initialization failed.");
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainen client_destroy(client, "TLS initialization failed.");
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainen return;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->common.tls = TRUE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->common.secured = TRUE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_set_title(client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->common.fd = fd_ssl;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_stream_unref(&client->input);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen o_stream_unref(&client->output);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen imap_parser_destroy(&client->parser);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* CRLF is lost from buffer when streams are reopened. */
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainen client->skip_line = FALSE;
54533aa265f5c87730022cc7576090bc51370f97Timo Sirainen
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen client_open_streams(client, fd_ssl);
d3d769026fae5d21c2d29614d3bc4579e8d79e81Timo Sirainen client->io = io_add(client->common.fd, IO_READ, client_input, client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic int client_output_starttls(void *context)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct imap_client *client = context;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen int ret;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if ((ret = o_stream_flush(client->output)) < 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_destroy(client, "Disconnected");
c7fca6cbb32388556d9f6d8313486cc4e4a3c058Timo Sirainen return 1;
c7fca6cbb32388556d9f6d8313486cc4e4a3c058Timo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
c7fca6cbb32388556d9f6d8313486cc4e4a3c058Timo Sirainen if (ret > 0)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_start_tls(client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return 1;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic int cmd_starttls(struct imap_client *client)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (client->common.tls) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_send_tagline(client, "BAD TLS is already active.");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return 1;
5a9e240ebf8d0daaf029973973b52e415148070bTimo Sirainen }
5a9e240ebf8d0daaf029973973b52e415148070bTimo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (!ssl_initialized) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_send_tagline(client, "BAD TLS support isn't enabled.");
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen return 1;
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* remove input handler, SSL proxy gives us a new fd. we also have to
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen remove it in case we have to wait for buffer to be flushed */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (client->io != NULL)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen io_remove(&client->io);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_send_tagline(client, "OK Begin TLS negotiation now.");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* uncork the old fd */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen o_stream_uncork(client->output);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (o_stream_flush(client->output) <= 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* the buffer has to be flushed */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen o_stream_set_flush_pending(client->output, TRUE);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen o_stream_set_flush_callback(client->output,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_output_starttls, client);
05e55893a799de645fc8cd2203d6013f0e0f1b79Timo Sirainen } else {
2aac7ca853f63b62ea79ef8eae9ded83ed6063a5Timo Sirainen client_start_tls(client);
4de2a17e0a2aed3b57a6c1057329b6a132b56ae2Timo Sirainen }
4de2a17e0a2aed3b57a6c1057329b6a132b56ae2Timo Sirainen return 1;
2aac7ca853f63b62ea79ef8eae9ded83ed6063a5Timo Sirainen}
2aac7ca853f63b62ea79ef8eae9ded83ed6063a5Timo Sirainen
2aac7ca853f63b62ea79ef8eae9ded83ed6063a5Timo Sirainenstatic int cmd_noop(struct imap_client *client)
9ddd3d7d8651985e373a6c48e0ddc76b8a4ef1c7Timo Sirainen{
4de2a17e0a2aed3b57a6c1057329b6a132b56ae2Timo Sirainen client_send_tagline(client, "OK NOOP completed.");
5d2e7ec2ea725c8a6a63f56b771e746f93e782ecTimo Sirainen return 1;
54533aa265f5c87730022cc7576090bc51370f97Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic int cmd_logout(struct imap_client *client)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_send_line(client, "* BYE Logging out");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_send_tagline(client, "OK Logout completed.");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_destroy(client, "Aborted login");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return 1;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic int client_command_execute(struct imap_client *client, const char *cmd,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct imap_arg *args)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen cmd = t_str_ucase(cmd);
bdb9f7f7fbf828fb85a393bd2803167b1bb8ff0dTimo Sirainen if (strcmp(cmd, "LOGIN") == 0)
bdb9f7f7fbf828fb85a393bd2803167b1bb8ff0dTimo Sirainen return cmd_login(client, args);
bdb9f7f7fbf828fb85a393bd2803167b1bb8ff0dTimo Sirainen if (strcmp(cmd, "AUTHENTICATE") == 0)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return cmd_authenticate(client, args);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (strcmp(cmd, "CAPABILITY") == 0)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return cmd_capability(client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (strcmp(cmd, "STARTTLS") == 0)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return cmd_starttls(client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (strcmp(cmd, "NOOP") == 0)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return cmd_noop(client);
ec23e16ed879e289d12c6e1a5f9745dd3979004aTimo Sirainen if (strcmp(cmd, "LOGOUT") == 0)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return cmd_logout(client);
ec23e16ed879e289d12c6e1a5f9745dd3979004aTimo Sirainen
ec23e16ed879e289d12c6e1a5f9745dd3979004aTimo Sirainen return -1;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic bool client_handle_input(struct imap_client *client)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
ec23e16ed879e289d12c6e1a5f9745dd3979004aTimo Sirainen struct imap_arg *args;
ec23e16ed879e289d12c6e1a5f9745dd3979004aTimo Sirainen const char *msg;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen int ret;
ec23e16ed879e289d12c6e1a5f9745dd3979004aTimo Sirainen bool fatal;
ec23e16ed879e289d12c6e1a5f9745dd3979004aTimo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_assert(!client->common.authenticating);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (client->cmd_finished) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* clear the previous command from memory. don't do this
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen immediately after handling command since we need the
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen cmd_tag to stay some time after authentication commands. */
6303191abcb37164f435ccdc56e9dbddf1288851Timo Sirainen client->cmd_tag = NULL;
6303191abcb37164f435ccdc56e9dbddf1288851Timo Sirainen client->cmd_name = NULL;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen imap_parser_reset(client->parser);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* remove \r\n */
ec23e16ed879e289d12c6e1a5f9745dd3979004aTimo Sirainen if (client->skip_line) {
54533aa265f5c87730022cc7576090bc51370f97Timo Sirainen if (!client_skip_line(client))
54533aa265f5c87730022cc7576090bc51370f97Timo Sirainen return FALSE;
54533aa265f5c87730022cc7576090bc51370f97Timo Sirainen client->skip_line = FALSE;
ec23e16ed879e289d12c6e1a5f9745dd3979004aTimo Sirainen }
54533aa265f5c87730022cc7576090bc51370f97Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->cmd_finished = FALSE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (client->cmd_tag == NULL) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->cmd_tag = imap_parser_read_word(client->parser);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (client->cmd_tag == NULL)
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen return FALSE; /* need more data */
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen }
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen if (client->cmd_name == NULL) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->cmd_name = imap_parser_read_word(client->parser);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (client->cmd_name == NULL)
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen return FALSE; /* need more data */
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen }
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen switch (imap_parser_read_args(client->parser, 0, 0, &args)) {
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen case -1:
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* error */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen msg = imap_parser_get_error(client->parser, &fatal);
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen if (fatal) {
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen client_send_line(client, t_strconcat("* BYE ",
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen msg, NULL));
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen client_destroy(client, t_strconcat("Disconnected: ",
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen msg, NULL));
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return FALSE;
717bb0dbaf4bd3f745669570647845e6d493bfe0Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_send_tagline(client, t_strconcat("BAD ", msg, NULL));
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->cmd_finished = TRUE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->skip_line = TRUE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return TRUE;
717bb0dbaf4bd3f745669570647845e6d493bfe0Timo Sirainen case -2:
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* not enough data */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return FALSE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
717bb0dbaf4bd3f745669570647845e6d493bfe0Timo Sirainen client->skip_line = TRUE;
717bb0dbaf4bd3f745669570647845e6d493bfe0Timo Sirainen
717bb0dbaf4bd3f745669570647845e6d493bfe0Timo Sirainen if (*client->cmd_tag == '\0')
717bb0dbaf4bd3f745669570647845e6d493bfe0Timo Sirainen ret = -1;
717bb0dbaf4bd3f745669570647845e6d493bfe0Timo Sirainen else
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen ret = client_command_execute(client, client->cmd_name, args);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->cmd_finished = TRUE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (ret < 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (*client->cmd_tag == '\0')
ec23e16ed879e289d12c6e1a5f9745dd3979004aTimo Sirainen client->cmd_tag = "*";
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (++client->bad_counter >= CLIENT_MAX_BAD_COMMANDS) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_send_line(client,
cec3230c9b2a96bac1ea42c69475e8aea4b91eabTimo Sirainen "* BYE Too many invalid IMAP commands.");
cec3230c9b2a96bac1ea42c69475e8aea4b91eabTimo Sirainen client_destroy(client, "Disconnected: "
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen "Too many invalid commands");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return FALSE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_send_tagline(client,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen "BAD Error in IMAP command received by server.");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
ec23e16ed879e289d12c6e1a5f9745dd3979004aTimo Sirainen return ret != 0;
cec3230c9b2a96bac1ea42c69475e8aea4b91eabTimo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenbool client_read(struct imap_client *client)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen switch (i_stream_read(client->input)) {
54533aa265f5c87730022cc7576090bc51370f97Timo Sirainen case -2:
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* buffer full */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_send_line(client, "* BYE Input buffer full, aborting");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_destroy(client, "Disconnected: Input buffer full");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return FALSE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen case -1:
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* disconnected */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_destroy(client, "Disconnected");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return FALSE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen default:
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* something was read */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return TRUE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenvoid client_input(void *context)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct imap_client *client = context;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->last_input = ioloop_time;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (!client_read(client))
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_ref(client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (!auth_client_is_connected(auth_client)) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* we're not yet connected to auth process -
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen don't allow any commands */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_send_line(client,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen "* OK Waiting for authentication process to respond..");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->input_blocked = TRUE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen } else {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen o_stream_cork(client->output);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen while (client_handle_input(client)) ;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen o_stream_uncork(client->output);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_unref(client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic void client_destroy_oldest(void)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct hash_iterate_context *iter;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen void *key, *value;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct imap_client *destroy_buf[CLIENT_DESTROY_OLDEST_COUNT];
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen int i;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* find the oldest clients and put them to destroy-buffer */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen memset(destroy_buf, 0, sizeof(destroy_buf));
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen iter = hash_iterate_init(clients);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen while (hash_iterate(iter, &key, &value)) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct imap_client *client = key;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen for (i = 0; i < CLIENT_DESTROY_OLDEST_COUNT; i++) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (destroy_buf[i] == NULL ||
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen destroy_buf[i]->created > client->created) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* @UNSAFE */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen memmove(destroy_buf+i+1, destroy_buf+i,
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainen sizeof(destroy_buf) -
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainen (i+1) * sizeof(struct imap_client *));
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainen destroy_buf[i] = client;
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainen break;
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainen }
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainen }
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainen }
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen hash_iterate_deinit(iter);
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen /* then kill them */
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen for (i = 0; i < CLIENT_DESTROY_OLDEST_COUNT; i++) {
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen if (destroy_buf[i] == NULL)
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen break;
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen client_destroy(destroy_buf[i],
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen "Disconnected: Connection queue full");
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen }
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen}
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainenstatic void client_send_greeting(struct imap_client *client)
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen{
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen string_t *greet;
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen greet = t_str_new(128);
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen str_append(greet, "* OK ");
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen if (greeting_capability) {
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen i_assert(auth_client_is_connected(auth_client));
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen str_printfa(greet, "[CAPABILITY %s] ", get_capability(client));
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen }
45155bb1250cf5a120278f349465aded513a100fTimo Sirainen str_append(greet, greeting);
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen client_send_line(client, str_c(greet));
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen client->greeting_sent = TRUE;
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen}
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainenstruct client *client_create(int fd, bool ssl, const struct ip_addr *local_ip,
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen const struct ip_addr *ip)
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen{
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen struct imap_client *client;
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen const char *addr;
45155bb1250cf5a120278f349465aded513a100fTimo Sirainen
45155bb1250cf5a120278f349465aded513a100fTimo Sirainen if (max_logging_users > CLIENT_DESTROY_OLDEST_COUNT &&
45155bb1250cf5a120278f349465aded513a100fTimo Sirainen hash_size(clients) >= max_logging_users) {
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen /* reached max. users count, kill few of the
5a250816ffc4cc5db203f9410ea99b6601c7b91aTimo Sirainen oldest connections */
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen client_destroy_oldest();
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen }
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen /* always use nonblocking I/O */
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen net_set_nonblock(fd, TRUE);
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen
12cf3d0e03fc70fb0c8b91bc8fd83b4e14d7cdefTimo Sirainen client = i_new(struct imap_client, 1);
12cf3d0e03fc70fb0c8b91bc8fd83b4e14d7cdefTimo Sirainen client->created = ioloop_time;
4ead43ecc06d10047998966c4dc0b142ecce4b66Timo Sirainen client->refcount = 1;
12cf3d0e03fc70fb0c8b91bc8fd83b4e14d7cdefTimo Sirainen client->common.tls = ssl;
4e35bae013cee5a06d281776a347b534b958aaa4Timo Sirainen
4ead43ecc06d10047998966c4dc0b142ecce4b66Timo Sirainen addr = net_ip2addr(ip);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->common.secured = ssl ||
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen (IPADDR_IS_V4(ip) && strncmp(addr, "127.", 4) == 0) ||
bb8d0ec26bdd548624d7a7424071cca693b72f55Timo Sirainen (IPADDR_IS_V6(ip) && (strcmp(addr, "::1") == 0 ||
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen strncmp(addr, "::ffff:127.", 11) == 0));
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
bb8d0ec26bdd548624d7a7424071cca693b72f55Timo Sirainen client->common.local_ip = *local_ip;
bb8d0ec26bdd548624d7a7424071cca693b72f55Timo Sirainen client->common.ip = *ip;
bb8d0ec26bdd548624d7a7424071cca693b72f55Timo Sirainen client->common.fd = fd;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_open_streams(client, fd);
4ead43ecc06d10047998966c4dc0b142ecce4b66Timo Sirainen client->io = io_add(fd, IO_READ, client_input, client);
506e41a4efbc7f4bba93cd295ca4dba18ed3cf09Timo Sirainen
506e41a4efbc7f4bba93cd295ca4dba18ed3cf09Timo Sirainen client->last_input = ioloop_time;
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen hash_insert(clients, client, client);
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen main_ref();
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen
1d4f710106fb498750456724628da6063e012e6dTimo Sirainen if (!greeting_capability || auth_client_is_connected(auth_client))
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen client_send_greeting(client);
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen client_set_title(client);
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen client->created = TRUE;
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen return &client->common;
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen}
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen
88c92ce2caa8f9fa34708471c6ed4e974d5a7953Timo Sirainenvoid client_destroy(struct imap_client *client, const char *reason)
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen{
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen if (client->destroyed)
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen return;
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen client->destroyed = TRUE;
1d4f710106fb498750456724628da6063e012e6dTimo Sirainen
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen if (reason != NULL)
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen client_syslog(&client->common, reason);
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen hash_remove(clients, client);
f77ffa31038d46ca9c6d24d93e3d76c9aa8d4d0cTimo Sirainen
f77ffa31038d46ca9c6d24d93e3d76c9aa8d4d0cTimo Sirainen if (client->input != NULL)
f77ffa31038d46ca9c6d24d93e3d76c9aa8d4d0cTimo Sirainen i_stream_close(client->input);
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen if (client->output != NULL)
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen o_stream_close(client->output);
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen
97db4761382024093f441e4bc78ba8b6a056504dTimo Sirainen if (client->common.auth_request != NULL) {
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen auth_client_request_abort(client->common.auth_request);
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen client->common.auth_request = NULL;
1d4f710106fb498750456724628da6063e012e6dTimo Sirainen }
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen if (client->common.master_tag != 0)
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen master_request_abort(&client->common);
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen if (client->io != NULL)
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen io_remove(&client->io);
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen
97db4761382024093f441e4bc78ba8b6a056504dTimo Sirainen if (client->common.fd != -1) {
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen net_disconnect(client->common.fd);
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen client->common.fd = -1;
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen }
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen if (client->proxy_password != NULL) {
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen safe_memset(client->proxy_password, 0,
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen strlen(client->proxy_password));
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen i_free(client->proxy_password);
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen client->proxy_password = NULL;
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen }
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen i_free(client->proxy_user);
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen client->proxy_user = NULL;
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen if (client->proxy != NULL) {
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen login_proxy_free(client->proxy);
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen client->proxy = NULL;
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen }
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen if (client->common.proxy != NULL) {
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen ssl_proxy_free(client->common.proxy);
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen client->common.proxy = NULL;
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen }
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen client_unref(client);
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen}
97db4761382024093f441e4bc78ba8b6a056504dTimo Sirainen
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainenvoid client_destroy_internal_failure(struct imap_client *client)
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen{
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen client_send_line(client, "* BYE Internal login failure. "
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen "Refer to server log for more information.");
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen client_destroy(client, "Internal login failure");
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen}
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainenvoid client_ref(struct imap_client *client)
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen{
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen client->refcount++;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainenbool client_unref(struct imap_client *client)
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen{
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen if (--client->refcount > 0)
1d4f710106fb498750456724628da6063e012e6dTimo Sirainen return TRUE;
89795c6bbbc52bb382e88bc8617d22092223e9a5Timo Sirainen
b9c76fe9d9ca194816606342da1ddbd9be6bc8abTimo Sirainen imap_parser_destroy(&client->parser);
b9c76fe9d9ca194816606342da1ddbd9be6bc8abTimo Sirainen
b9c76fe9d9ca194816606342da1ddbd9be6bc8abTimo Sirainen if (client->input != NULL)
b9c76fe9d9ca194816606342da1ddbd9be6bc8abTimo Sirainen i_stream_unref(&client->input);
b9c76fe9d9ca194816606342da1ddbd9be6bc8abTimo Sirainen if (client->output != NULL)
b9c76fe9d9ca194816606342da1ddbd9be6bc8abTimo Sirainen o_stream_unref(&client->output);
b9c76fe9d9ca194816606342da1ddbd9be6bc8abTimo Sirainen
89795c6bbbc52bb382e88bc8617d22092223e9a5Timo Sirainen i_free(client->common.virtual_user);
89795c6bbbc52bb382e88bc8617d22092223e9a5Timo Sirainen i_free(client->common.auth_mech_name);
89795c6bbbc52bb382e88bc8617d22092223e9a5Timo Sirainen i_free(client);
89795c6bbbc52bb382e88bc8617d22092223e9a5Timo Sirainen
89795c6bbbc52bb382e88bc8617d22092223e9a5Timo Sirainen main_unref();
89795c6bbbc52bb382e88bc8617d22092223e9a5Timo Sirainen return FALSE;
97db4761382024093f441e4bc78ba8b6a056504dTimo Sirainen}
89795c6bbbc52bb382e88bc8617d22092223e9a5Timo Sirainen
89795c6bbbc52bb382e88bc8617d22092223e9a5Timo Sirainenvoid client_send_line(struct imap_client *client, const char *line)
97db4761382024093f441e4bc78ba8b6a056504dTimo Sirainen{
89795c6bbbc52bb382e88bc8617d22092223e9a5Timo Sirainen struct const_iovec iov[2];
89795c6bbbc52bb382e88bc8617d22092223e9a5Timo Sirainen ssize_t ret;
89795c6bbbc52bb382e88bc8617d22092223e9a5Timo Sirainen
89795c6bbbc52bb382e88bc8617d22092223e9a5Timo Sirainen iov[0].iov_base = line;
89795c6bbbc52bb382e88bc8617d22092223e9a5Timo Sirainen iov[0].iov_len = strlen(line);
89795c6bbbc52bb382e88bc8617d22092223e9a5Timo Sirainen iov[1].iov_base = "\r\n";
89795c6bbbc52bb382e88bc8617d22092223e9a5Timo Sirainen iov[1].iov_len = 2;
89795c6bbbc52bb382e88bc8617d22092223e9a5Timo Sirainen
89795c6bbbc52bb382e88bc8617d22092223e9a5Timo Sirainen ret = o_stream_sendv(client->output, iov, 2);
89795c6bbbc52bb382e88bc8617d22092223e9a5Timo Sirainen if (ret < 0 || (size_t)ret != iov[0].iov_len + iov[1].iov_len) {
89795c6bbbc52bb382e88bc8617d22092223e9a5Timo Sirainen /* either disconnection or buffer full. in either case we
89795c6bbbc52bb382e88bc8617d22092223e9a5Timo Sirainen want this connection destroyed. however destroying it here
38318f5e82662615cd88e99e398efe4a630ce020Timo Sirainen might break things if client is still tried to be accessed
38318f5e82662615cd88e99e398efe4a630ce020Timo Sirainen without being referenced.. */
38318f5e82662615cd88e99e398efe4a630ce020Timo Sirainen i_stream_close(client->input);
28dae6a0064e79f86da091625b0f2b92336a2a91Timo Sirainen }
28dae6a0064e79f86da091625b0f2b92336a2a91Timo Sirainen}
28dae6a0064e79f86da091625b0f2b92336a2a91Timo Sirainen
434abef12f61881a5cfa28d27193d0854a9639a0Timo Sirainenvoid client_send_tagline(struct imap_client *client, const char *line)
434abef12f61881a5cfa28d27193d0854a9639a0Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_send_line(client, t_strconcat(client->cmd_tag, " ", line, NULL));
38318f5e82662615cd88e99e398efe4a630ce020Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
38318f5e82662615cd88e99e398efe4a630ce020Timo Sirainenstatic void client_check_idle(struct imap_client *client)
38318f5e82662615cd88e99e398efe4a630ce020Timo Sirainen{
38318f5e82662615cd88e99e398efe4a630ce020Timo Sirainen if (ioloop_time - client->last_input >= CLIENT_LOGIN_IDLE_TIMEOUT) {
b9c76fe9d9ca194816606342da1ddbd9be6bc8abTimo Sirainen client_send_line(client, "* BYE Disconnected for inactivity.");
b9c76fe9d9ca194816606342da1ddbd9be6bc8abTimo Sirainen client_destroy(client, "Disconnected: Inactivity");
b9c76fe9d9ca194816606342da1ddbd9be6bc8abTimo Sirainen }
b9c76fe9d9ca194816606342da1ddbd9be6bc8abTimo Sirainen}
b9c76fe9d9ca194816606342da1ddbd9be6bc8abTimo Sirainen
28dae6a0064e79f86da091625b0f2b92336a2a91Timo Sirainenstatic void idle_timeout(void *context __attr_unused__)
28dae6a0064e79f86da091625b0f2b92336a2a91Timo Sirainen{
28dae6a0064e79f86da091625b0f2b92336a2a91Timo Sirainen struct hash_iterate_context *iter;
28dae6a0064e79f86da091625b0f2b92336a2a91Timo Sirainen void *key, *value;
38318f5e82662615cd88e99e398efe4a630ce020Timo Sirainen
38318f5e82662615cd88e99e398efe4a630ce020Timo Sirainen iter = hash_iterate_init(clients);
38318f5e82662615cd88e99e398efe4a630ce020Timo Sirainen while (hash_iterate(iter, &key, &value)) {
38318f5e82662615cd88e99e398efe4a630ce020Timo Sirainen struct imap_client *client = key;
b4b87fa19d26aadb2ea9e8a9ae7af6cfdaab4cfbTimo Sirainen
b4b87fa19d26aadb2ea9e8a9ae7af6cfdaab4cfbTimo Sirainen client_check_idle(client);
38318f5e82662615cd88e99e398efe4a630ce020Timo Sirainen }
3ffb7fd86484c474b42f3f1e981ab0f7168b5df9Timo Sirainen hash_iterate_deinit(iter);
3ffb7fd86484c474b42f3f1e981ab0f7168b5df9Timo Sirainen}
6998ca95b4947c90647ac5d4794ebd6311acada2Timo Sirainen
6998ca95b4947c90647ac5d4794ebd6311acada2Timo Sirainenunsigned int clients_get_count(void)
6998ca95b4947c90647ac5d4794ebd6311acada2Timo Sirainen{
6998ca95b4947c90647ac5d4794ebd6311acada2Timo Sirainen return hash_size(clients);
28dae6a0064e79f86da091625b0f2b92336a2a91Timo Sirainen}
28dae6a0064e79f86da091625b0f2b92336a2a91Timo Sirainen
28dae6a0064e79f86da091625b0f2b92336a2a91Timo Sirainenvoid clients_notify_auth_connected(void)
28dae6a0064e79f86da091625b0f2b92336a2a91Timo Sirainen{
28dae6a0064e79f86da091625b0f2b92336a2a91Timo Sirainen struct hash_iterate_context *iter;
28dae6a0064e79f86da091625b0f2b92336a2a91Timo Sirainen void *key, *value;
28dae6a0064e79f86da091625b0f2b92336a2a91Timo Sirainen
28dae6a0064e79f86da091625b0f2b92336a2a91Timo Sirainen iter = hash_iterate_init(clients);
3ffb7fd86484c474b42f3f1e981ab0f7168b5df9Timo Sirainen while (hash_iterate(iter, &key, &value)) {
3ffb7fd86484c474b42f3f1e981ab0f7168b5df9Timo Sirainen struct imap_client *client = key;
7c849dbc7be089175c1a83a84ee7249ed695810dTimo Sirainen
7c849dbc7be089175c1a83a84ee7249ed695810dTimo Sirainen if (!client->greeting_sent)
38318f5e82662615cd88e99e398efe4a630ce020Timo Sirainen client_send_greeting(client);
80980955bb1bbcc1bd73623fe0912f334194ddd2Timo Sirainen if (client->input_blocked) {
80980955bb1bbcc1bd73623fe0912f334194ddd2Timo Sirainen client->input_blocked = FALSE;
843640f0ca224bb9999acb290bca5f76037ab984Timo Sirainen client_input(client);
843640f0ca224bb9999acb290bca5f76037ab984Timo Sirainen }
843640f0ca224bb9999acb290bca5f76037ab984Timo Sirainen }
843640f0ca224bb9999acb290bca5f76037ab984Timo Sirainen hash_iterate_deinit(iter);
28dae6a0064e79f86da091625b0f2b92336a2a91Timo Sirainen}
28dae6a0064e79f86da091625b0f2b92336a2a91Timo Sirainen
38318f5e82662615cd88e99e398efe4a630ce020Timo Sirainenvoid clients_destroy_all(void)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct hash_iterate_context *iter;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen void *key, *value;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen iter = hash_iterate_init(clients);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen while (hash_iterate(iter, &key, &value)) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct imap_client *client = key;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_destroy(client, NULL);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen hash_iterate_deinit(iter);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenvoid clients_init(void)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen clients = hash_create(default_pool, default_pool, 128, NULL, NULL);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen to_idle = timeout_add(1000, idle_timeout, NULL);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenvoid clients_deinit(void)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen clients_destroy_all();
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen hash_destroy(clients);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen timeout_remove(&to_idle);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen