client.c revision a64adf62fa33f2463a86f990217b0c9078531a40
/* Copyright (c) 2002-2009 Dovecot authors, see the included COPYING file */
#include "common.h"
#include "buffer.h"
#include "ioloop.h"
#include "istream.h"
#include "ostream.h"
#include "process-title.h"
#include "safe-memset.h"
#include "str.h"
#include "strescape.h"
#include "imap-parser.h"
#include "imap-id.h"
#include "client.h"
#include "client-authenticate.h"
#include "auth-client.h"
#include "ssl-proxy.h"
#include "imap-proxy.h"
#include <stdlib.h>
/* max. size of output buffer. if it gets full, the client is disconnected.
SASL authentication gives the largest output. */
#define MAX_OUTBUF_SIZE 4096
/* maximum length for IMAP command line. */
#define MAX_IMAP_LINE 8192
/* Disconnect client when it sends too many bad commands */
#define CLIENT_MAX_BAD_COMMANDS 10
/* When max. number of simultaneous connections is reached, few of the
oldest connections are disconnected. Since we have to go through all of the
clients, it's faster if we disconnect multiple clients. */
#define CLIENT_DESTROY_OLDEST_COUNT 16
/* If we've been waiting auth server to respond for over this many milliseconds,
send a "waiting" message. */
#endif
#define AUTH_WAITING_MSG \
"* OK Waiting for authentication process to respond.."
const char *login_protocol = "IMAP";
const char *capability_string = CAPABILITY_STRING;
{
const char *addr;
if (!login_settings->verbose_proctitle ||
return;
addr = "??";
}
{
}
/* Skip incoming data until newline is found,
returns TRUE if newline was found. */
{
const unsigned char *data;
for (i = 0; i < data_size; i++) {
if (data[i] == '\n') {
return TRUE;
}
}
return FALSE;
}
{
const char *auths;
" STARTTLS" : "",
}
{
return 1;
}
{
int fd_ssl;
return;
if (fd_ssl == -1) {
"Disconnected: TLS initialization failed.");
return;
}
/* CRLF is lost from buffer when streams are reopened. */
}
{
int ret;
return 1;
}
if (ret > 0) {
}
return 1;
}
{
return 1;
}
if (!ssl_initialized) {
return 1;
}
/* remove input handler, SSL proxy gives us a new fd. we also have to
remove it in case we have to wait for buffer to be flushed */
/* uncork the old fd */
/* the buffer has to be flushed */
} else {
}
return 1;
}
static void
{
return;
args += 2;
}
}
{
}
}
return 1;
}
{
return 1;
}
{
return 1;
}
{
"OK ENABLE ignored in non-authenticated state.");
return 1;
}
{
return cmd_capability(client);
return cmd_starttls(client);
return cmd_logout(client);
return cmd_enable(client);
return -1;
}
{
const char *msg;
int ret;
bool fatal;
if (client->cmd_finished) {
/* clear the previous command from memory. don't do this
immediately after handling command since we need the
cmd_tag to stay some time after authentication commands. */
/* remove \r\n */
if (!client_skip_line(client))
return FALSE;
}
}
return FALSE; /* need more data */
}
return FALSE; /* need more data */
}
case -1:
/* error */
if (fatal) {
return FALSE;
}
return TRUE;
case -2:
/* not enough data */
return FALSE;
}
/* we read the entire line - skip over the CRLF */
if (!client_skip_line(client))
i_unreached();
ret = -1;
else
if (ret < 0) {
"* BYE Too many invalid IMAP commands.");
"Disconnected: Too many invalid commands");
return FALSE;
}
"BAD Error in IMAP command received by server.");
}
return ret != 0;
}
{
case -2:
/* buffer full */
return FALSE;
case -1:
/* disconnected */
return FALSE;
case 0:
/* nothing new read */
return TRUE;
default:
/* something was read */
return TRUE;
}
}
{
if (!client_read(client))
return;
if (!auth_client_is_connected(auth_client)) {
/* we're not yet connected to auth process -
don't allow any commands */
} else {
while (client_handle_input(client)) ;
}
}
void client_destroy_oldest(void)
{
unsigned int i, destroy_count;
/* find the oldest clients and put them to destroy-buffer */
for (i = 0; i < destroy_count; i++) {
if (destroy_buf[i] == NULL ||
/* @UNSAFE */
sizeof(destroy_buf) -
(i+1) * sizeof(struct imap_client *));
destroy_buf[i] = imap_client;
break;
}
}
}
/* then kill them */
for (i = 0; i < destroy_count; i++) {
if (destroy_buf[i] == NULL)
break;
"Disconnected: Connection queue full");
}
}
{
}
{
}
{
}
{
}
{
struct imap_client *client;
/* always use nonblocking I/O */
main_ref();
else
}
{
return;
NULL);
}
} else {
}
}
}
}
main_unref();
}
{
}
{
"Refer to server log for more information.");
}
{
}
{
return TRUE;
return FALSE;
}
{
/* either disconnection or buffer full. in either case we
want this connection destroyed. however destroying it here
might break things if client is still tried to be accessed
without being referenced.. */
}
}
{
}
void clients_notify_auth_connected(void)
{
if (!imap_client->greeting_sent)
if (imap_client->input_blocked) {
}
}
}
void clients_destroy_all(void)
{
}
}
void clients_init(void)
{
/* Nothing to initialize for IMAP */
}
void clients_deinit(void)
{
}