1
/* Copyright (c) 2002-2009 Dovecot Sieve authors, see the included COPYING file
9
#include "process-title.h"
10
#include "safe-memset.h"
13
#include "strescape.h"
17
#include "managesieve-parser.h"
18
#include "managesieve-quote.h"
21
#include "client-authenticate.h"
23
#include "auth-client.h"
24
#include "ssl-proxy.h"
26
#include "managesieve-capability.h"
27
#include "managesieve-proxy.h"
31
/* max. size of output buffer. if it gets full, the client is disconnected.
32
SASL authentication gives the largest output. */
33
#define MAX_OUTBUF_SIZE 4096
35
/* Disconnect client when it sends too many bad commands */
36
#define CLIENT_MAX_BAD_COMMANDS 10
38
/* When max. number of simultaneous connections is reached, few of the
39
oldest connections are disconnected. Since we have to go through all of the
40
clients, it's faster if we disconnect multiple clients. */
41
#define CLIENT_DESTROY_OLDEST_COUNT 16
43
/* If we've been waiting auth server to respond for over this many milliseconds,
44
send a "waiting" message. */
45
#define AUTH_WAITING_TIMEOUT_MSECS (30*1000)
47
#if CLIENT_LOGIN_IDLE_TIMEOUT_MSECS < AUTH_REQUEST_TIMEOUT*1000
48
# error client idle timeout must be larger than authentication timeout
51
const char *login_protocol = "MANAGESIEVE";
52
const char *capability_string = NULL;
54
const char *managesieve_implementation_string;
56
static void client_set_title(struct managesieve_client *client)
60
if (!verbose_proctitle || !process_per_connection)
63
addr = net_ip2addr(&client->common.ip);
67
process_title_set(t_strdup_printf(client->common.tls ?
68
"[%s TLS]" : "[%s]", addr));
71
static void client_open_streams(struct managesieve_client *client, int fd)
73
client->common.input =
74
i_stream_create_fd(fd, LOGIN_MAX_INBUF_SIZE, FALSE);
75
client->output = o_stream_create_fd(fd, MAX_OUTBUF_SIZE, FALSE);
76
client->parser = managesieve_parser_create(client->common.input, client->output,
77
MAX_MANAGESIEVE_LINE);
80
/* Skip incoming data until newline is found,
81
returns TRUE if newline was found. */
82
bool client_skip_line(struct managesieve_client *client)
84
const unsigned char *data;
87
data = i_stream_get_data(client->common.input, &data_size);
89
for (i = 0; i < data_size; i++) {
90
if (data[i] == '\n') {
91
i_stream_skip(client->common.input, i+1);
99
static void client_send_capabilities(struct managesieve_client *client)
101
const char *saslcap, *sievecap, *notifycap;
104
/* Get capabilities */
105
sievecap = managesieve_capability_sieve;
106
saslcap = client_authenticate_get_capabilities(client->common.secured);
107
notifycap = managesieve_capability_notify;
109
/* Default capabilities */
110
client_send_line(client, t_strconcat("\"IMPLEMENTATION\" \"",
111
managesieve_implementation_string, "\"", NULL));
112
client_send_line(client, t_strconcat("\"SIEVE\" \"",
113
( sievecap == NULL ? "" : sievecap ), "\"", NULL));
114
client_send_line(client, t_strconcat("\"SASL\" \"",
115
saslcap, "\"", NULL));
118
if (ssl_initialized && !client->common.tls)
119
client_send_line(client, "\"STARTTLS\"" );
122
if ( notifycap != NULL ) {
123
client_send_line(client, t_strconcat("\"NOTIFY\" \"",
124
notifycap, "\"", NULL));
127
/* Protocol version */
128
client_send_line(client, "\"VERSION\" \"1.0\"");
132
static int cmd_capability(struct managesieve_client *client)
134
o_stream_cork(client->output);
136
client_send_capabilities(client);
137
client_send_ok(client, "Capability completed.");
139
o_stream_uncork(client->output);
144
static void client_start_tls(struct managesieve_client *client)
149
connection_queue_add(1);
150
if (!client_unref(client) || client->destroyed)
153
fd_ssl = ssl_proxy_new(client->common.fd, &client->common.ip,
154
&client->common.proxy);
156
client_send_bye(client, "TLS initialization failed.");
157
client_destroy(client, "Disconnected: TLS initialization failed.");
161
client->common.tls = TRUE;
162
client->common.secured = TRUE;
163
client_set_title(client);
165
client->common.fd = fd_ssl;
166
i_stream_unref(&client->common.input);
167
o_stream_unref(&client->output);
168
managesieve_parser_destroy(&client->parser);
170
/* CRLF is lost from buffer when streams are reopened. */
171
client->skip_line = FALSE;
173
client_open_streams(client, fd_ssl);
174
client->io = io_add(client->common.fd, IO_READ, client_input, client);
177
static int client_output_starttls(void *context)
179
struct managesieve_client *client = context;
182
if ((ret = o_stream_flush(client->output)) < 0) {
183
client_destroy(client, "Disconnected");
188
o_stream_unset_flush_callback(client->output);
189
client_start_tls(client);
194
static int cmd_starttls(struct managesieve_client *client)
196
if (client->common.tls) {
197
client_send_no(client, "TLS is already active.");
201
if (!ssl_initialized) {
202
client_send_no(client, "TLS support isn't enabled.");
206
/* remove input handler, SSL proxy gives us a new fd. we also have to
207
remove it in case we have to wait for buffer to be flushed */
208
if (client->io != NULL)
209
io_remove(&client->io);
211
client_send_ok(client, "Begin TLS negotiation now.");
213
/* uncork the old fd */
214
o_stream_uncork(client->output);
216
if (o_stream_flush(client->output) <= 0) {
217
/* the buffer has to be flushed */
218
o_stream_set_flush_pending(client->output, TRUE);
219
o_stream_set_flush_callback(client->output,
220
client_output_starttls, client);
222
client_start_tls(client);
225
/* Cork the stream to send the capability data as a single tcp frame
226
* Some naive clients break if we don't.
228
o_stream_cork(client->output);
230
client_send_capabilities(client);
231
client_send_ok(client, "TLS negotiation successful.");
233
o_stream_uncork(client->output);
238
static int cmd_logout(struct managesieve_client *client)
240
client_send_ok(client, "Logout completed.");
241
client_destroy(client, "Aborted login");
245
static int client_command_execute(struct managesieve_client *client, const char *cmd,
246
struct managesieve_arg *args)
248
cmd = t_str_ucase(cmd);
249
if (strcmp(cmd, "AUTHENTICATE") == 0)
250
return cmd_authenticate(client, args);
251
if (strcmp(cmd, "CAPABILITY") == 0)
252
return cmd_capability(client);
253
if (strcmp(cmd, "STARTTLS") == 0)
254
return cmd_starttls(client);
255
if (strcmp(cmd, "LOGOUT") == 0)
256
return cmd_logout(client);
257
if (strcmp(cmd, "NOOP") == 0)
258
return cmd_noop(client);
263
static bool client_handle_input(struct managesieve_client *client)
265
struct managesieve_arg *args;
270
i_assert(!client->common.authenticating);
272
if (client->cmd_finished) {
273
/* clear the previous command from memory. don't do this
274
immediately after handling command since we need the
275
cmd_tag to stay some time after authentication commands. */
276
client->cmd_name = NULL;
277
managesieve_parser_reset(client->parser);
280
if (client->skip_line) {
281
if (!client_skip_line(client))
283
client->skip_line = FALSE;
286
client->cmd_finished = FALSE;
289
if (client->cmd_name == NULL) {
290
client->cmd_name = managesieve_parser_read_word(client->parser);
291
if (client->cmd_name == NULL)
292
return FALSE; /* need more data */
295
switch (managesieve_parser_read_args(client->parser, 0, 0, &args)) {
298
msg = managesieve_parser_get_error(client->parser, &fatal);
300
client_send_bye(client, msg);
301
client_destroy(client, t_strconcat("Disconnected: ",
306
client_send_no(client, msg);
307
client->cmd_finished = TRUE;
308
client->skip_line = TRUE;
311
/* not enough data */
314
/* we read the entire line - skip over the CRLF */
315
if (!client_skip_line(client))
318
ret = client_command_execute(client, client->cmd_name, args);
320
client->cmd_finished = TRUE;
322
if (++client->bad_counter >= CLIENT_MAX_BAD_COMMANDS) {
323
client_send_bye(client,
324
"Too many invalid MANAGESIEVE commands.");
325
client_destroy(client, "Disconnected: "
326
"Too many invalid commands.");
329
client_send_no(client,
330
"Error in MANAGESIEVE command received by server.");
336
bool client_read(struct managesieve_client *client)
338
switch (i_stream_read(client->common.input)) {
341
client_send_bye(client, "Input buffer full, aborting");
342
client_destroy(client, "Disconnected: Input buffer full");
346
client_destroy(client, "Disconnected");
349
/* nothing new read */
352
/* something was read */
353
timeout_reset(client->to_idle_disconnect);
358
void client_input(struct managesieve_client *client)
360
if (!client_read(client))
365
if (!auth_client_is_connected(auth_client)) {
366
/* we're not yet connected to auth process -
367
don't allow any commands */
368
/* FIXME: Can't do this with managesieve. Any other ways?
369
client_send_ok(client, AUTH_WAITING_MSG);
371
if (client->to_auth_waiting != NULL)
372
timeout_remove(&client->to_auth_waiting);
374
client->input_blocked = TRUE;
376
o_stream_cork(client->output);
377
while (client_handle_input(client)) ;
378
o_stream_uncork(client->output);
381
client_unref(client);
384
void client_destroy_oldest(void)
386
struct client *client;
387
struct managesieve_client *destroy_buf[CLIENT_DESTROY_OLDEST_COUNT];
388
unsigned int i, destroy_count;
390
/* find the oldest clients and put them to destroy-buffer */
391
memset(destroy_buf, 0, sizeof(destroy_buf));
393
destroy_count = max_connections > CLIENT_DESTROY_OLDEST_COUNT*2 ?
394
CLIENT_DESTROY_OLDEST_COUNT : I_MIN(max_connections/2, 1);
395
for (client = clients; client != NULL; client = client->next) {
396
struct managesieve_client *msieve_client =
397
(struct managesieve_client *) client;
399
for (i = 0; i < destroy_count; i++) {
400
if (destroy_buf[i] == NULL ||
401
destroy_buf[i]->created > msieve_client->created) {
403
memmove(destroy_buf+i+1, destroy_buf+i,
404
sizeof(destroy_buf) -
405
(i+1) * sizeof(struct managesieve_client *));
406
destroy_buf[i] = msieve_client;
413
for (i = 0; i < destroy_count; i++) {
414
if (destroy_buf[i] == NULL)
417
client_destroy(destroy_buf[i], "Disconnected: Connection queue full");
421
static void client_send_greeting(struct managesieve_client *client)
423
/* Cork the stream to send the capability data as a single tcp frame
424
* Some naive clients break if we don't.
426
o_stream_cork(client->output);
428
/* Send initial capabilities */
429
client_send_capabilities(client);
430
client_send_ok(client, greeting);
431
client->greeting_sent = TRUE;
433
o_stream_uncork(client->output);
436
static void client_idle_disconnect_timeout(struct managesieve_client *client)
438
client_send_bye(client, "Disconnected for inactivity.");
439
client_destroy(client, "Disconnected: Inactivity");
442
static void client_auth_waiting_timeout(struct managesieve_client *client)
444
timeout_remove(&client->to_auth_waiting);
447
void client_set_auth_waiting(struct managesieve_client *client)
449
i_assert(client->to_auth_waiting == NULL);
450
client->to_auth_waiting =
451
timeout_add(AUTH_WAITING_TIMEOUT_MSECS,
452
client_auth_waiting_timeout, client);
455
struct client *client_create(int fd, bool ssl, const struct ip_addr *local_ip,
456
const struct ip_addr *ip)
458
struct managesieve_client *client;
462
connection_queue_add(1);
464
/* always use nonblocking I/O */
465
net_set_nonblock(fd, TRUE);
467
client = i_new(struct managesieve_client, 1);
468
client->created = ioloop_time;
469
client->refcount = 1;
471
client->common.local_ip = *local_ip;
472
client->common.ip = *ip;
473
client->common.fd = fd;
474
client->common.tls = ssl;
475
client->common.trusted = client_is_trusted(&client->common);
476
client->common.secured = ssl || client->common.trusted ||
477
net_ip_compare(ip, local_ip);
479
client_open_streams(client, fd);
480
client->io = io_add(fd, IO_READ, client_input, client);
482
client_link(&client->common);
486
if (auth_client_is_connected(auth_client))
487
client_send_greeting(client);
489
client_set_auth_waiting(client);
490
client_set_title(client);
492
client->to_idle_disconnect =
493
timeout_add(CLIENT_LOGIN_IDLE_TIMEOUT_MSECS,
494
client_idle_disconnect_timeout, client);
495
return &client->common;
498
void client_destroy(struct managesieve_client *client, const char *reason)
500
if (client->destroyed)
502
client->destroyed = TRUE;
504
if (!client->login_success && reason != NULL) {
505
reason = t_strconcat(reason, " ",
506
client_get_extra_disconnect_reason(&client->common),
510
client_syslog(&client->common, reason);
512
client_unlink(&client->common);
514
if (client->common.input != NULL)
515
i_stream_close(client->common.input);
516
if (client->output != NULL)
517
o_stream_close(client->output);
519
if (client->common.master_tag != 0) {
520
i_assert(client->common.auth_request == NULL);
521
i_assert(client->common.authenticating);
522
master_request_abort(&client->common);
523
} else if (client->common.auth_request != NULL) {
524
i_assert(client->common.authenticating);
525
sasl_server_auth_abort(&client->common);
527
i_assert(!client->common.authenticating);
530
if (client->io != NULL)
531
io_remove(&client->io);
532
if (client->to_idle_disconnect != NULL)
533
timeout_remove(&client->to_idle_disconnect);
534
if (client->to_auth_waiting != NULL)
535
timeout_remove(&client->to_auth_waiting);
536
if (client->to_authfail_delay != NULL)
537
timeout_remove(&client->to_authfail_delay);
539
if (client->common.fd != -1) {
540
net_disconnect(client->common.fd);
541
client->common.fd = -1;
544
if (client->proxy_password != NULL) {
545
safe_memset(client->proxy_password, 0, strlen(client->proxy_password));
546
i_free(client->proxy_password);
547
client->proxy_password = NULL;
550
i_free_and_null(client->proxy_user);
551
i_free_and_null(client->proxy_master_user);
553
if (client->proxy != NULL)
554
login_proxy_free(&client->proxy);
556
if (client->common.proxy != NULL) {
557
ssl_proxy_free(client->common.proxy);
558
client->common.proxy = NULL;
561
client_unref(client);
567
void client_destroy_success(struct managesieve_client *client, const char *reason)
569
client->login_success = TRUE;
570
client_destroy(client, reason);
573
bool client_read_args(struct managesieve_client *client, unsigned int count,
574
unsigned int flags, struct managesieve_arg **args)
580
i_assert(count <= INT_MAX);
582
ret = managesieve_parser_read_args(client->parser, count, flags, args);
583
if (ret >= (int)count) {
584
/* all parameters read successfully */
586
} else if (ret == -2) {
590
/* error, or missing arguments */
592
msg = managesieve_parser_get_error(client->parser, &fatal);
593
client_send_no(client, msg);
595
client_send_no(client, "Missing arguments");
601
void client_destroy_internal_failure(struct managesieve_client *client)
603
client_send_byeresp(client, "TRYLATER", "Internal login failure. "
604
"Refer to server log for more information.");
605
client_destroy(client, "Internal login failure");
608
void client_ref(struct managesieve_client *client)
613
bool client_unref(struct managesieve_client *client)
615
i_assert(client->refcount > 0);
616
if (--client->refcount > 0)
619
i_assert(client->destroyed);
621
managesieve_parser_destroy(&client->parser);
623
if (client->common.input != NULL)
624
i_stream_unref(&client->common.input);
625
if (client->output != NULL)
626
o_stream_unref(&client->output);
628
i_free(client->common.virtual_user);
629
i_free(client->common.auth_mech_name);
635
void client_send_line(struct managesieve_client *client, const char *line)
637
struct const_iovec iov[2];
640
iov[0].iov_base = line;
641
iov[0].iov_len = strlen(line);
642
iov[1].iov_base = "\r\n";
645
ret = o_stream_sendv(client->output, iov, 2);
646
if (ret < 0 || (size_t)ret != iov[0].iov_len + iov[1].iov_len) {
647
/* either disconnection or buffer full. in either case we
648
want this connection destroyed. however destroying it here
649
might break things if client is still tried to be accessed
650
without being referenced.. */
651
i_stream_close(client->common.input);
655
void _client_send_response(struct managesieve_client *client,
656
const char *oknobye, const char *resp_code, const char *msg)
660
str = t_str_new(128);
661
str_append(str, oknobye);
663
if ( resp_code != NULL )
665
str_append(str, " (");
666
str_append(str, resp_code);
667
str_append_c(str, ')');
672
str_append_c(str, ' ');
673
managesieve_quote_append_string(str, msg, TRUE);
676
client_send_line(client, str_c(str));
679
void clients_notify_auth_connected(void)
681
struct client *client;
683
for (client = clients; client != NULL; client = client->next) {
684
struct managesieve_client *msieve_client =
685
(struct managesieve_client *)client;
687
if (msieve_client->to_auth_waiting != NULL)
688
timeout_remove(&msieve_client->to_auth_waiting);
689
if (!msieve_client->greeting_sent)
690
client_send_greeting(msieve_client);
691
if (msieve_client->input_blocked) {
692
msieve_client->input_blocked = FALSE;
693
client_input(msieve_client);
698
void clients_destroy_all(void)
700
struct client *client, *next;
702
for (client = clients; client != NULL; client = next) {
703
struct managesieve_client *msieve_client =
704
(struct managesieve_client *) client;
707
client_destroy(msieve_client, "Disconnected: Shutting down");
711
void clients_init(void)
715
/* Specific MANAGESIEVE settings */
716
str = getenv("MANAGESIEVE_IMPLEMENTATION_STRING");
717
managesieve_implementation_string = str != NULL ?
718
str : DEFAULT_MANAGESIEVE_IMPLEMENTATION_STRING;
720
/* Parse CAPABILITY_STRING */
721
managesieve_capabilities_init(capability_string);
724
void clients_deinit(void)
726
clients_destroy_all();
728
/* Free allocated capability strings */
729
managesieve_capabilities_deinit();