imap-login-client.c revision 2f7c73483ff5474a74a83a646f82e1b60f687680
89a126810703c666309310d0f3189e9834d70b5bTimo Sirainen/* Copyright (c) 2002-2017 Dovecot authors, see the included COPYING file */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen# error LOGIN_MAX_INBUF_SIZE too short to fit all ID command parameters
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen/* maximum length for IMAP command line. */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen/* Disconnect client when it sends too many bad commands */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainenstatic const char *const imap_login_reserved_id_keys[] = {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen "x-originating-ip",
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen "x-originating-port",
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen "x-connected-ip",
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen "x-connected-port",
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen "x-proxy-ttl",
f6c1297c26b355c4aec2a08978f51ec3efecb351Timo Sirainen "x-session-id",
f6c1297c26b355c4aec2a08978f51ec3efecb351Timo Sirainen "x-session-ext-id",
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen/* Skip incoming data until newline is found,
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen returns TRUE if newline was found. */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainenbool client_skip_line(struct imap_client *client)
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen const unsigned char *data;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen data = i_stream_get_data(client->common.input, &data_size);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen for (i = 0; i < data_size; i++) {
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainenstatic bool client_handle_parser_error(struct imap_client *client,
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen const char *msg;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen msg = imap_parser_get_error(parser, &parse_error);
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen client_send_reply(&client->common, IMAP_CMD_REPLY_BAD, msg);
b04e691711fd026fc82ba3e0b411420e7da4ec7eTimo Sirainenstatic bool is_login_cmd_disabled(struct client *client)
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (auth_client_find_mech(auth_client, "PLAIN") == NULL) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen /* no PLAIN authentication, can't use LOGIN command */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (strcmp(client->ssl_set->ssl, "required") == 0)
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainenstatic const char *get_capability(struct client *client)
4d2211dac61c615c5bdfd501ea54d46c89d41b0fTimo Sirainen struct imap_client *imap_client = (struct imap_client *)client;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (*imap_client->set->imap_capability == '\0')
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen str_append(cap_str, CAPABILITY_BANNER_STRING);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen else if (*imap_client->set->imap_capability != '+') {
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen str_append(cap_str, imap_client->set->imap_capability);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen str_append(cap_str, CAPABILITY_BANNER_STRING);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen str_append(cap_str, imap_client->set->imap_capability + 1);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen if (client_is_tls_enabled(client) && !client->tls)
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen client_authenticate_get_capabilities(client, cap_str);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainenstatic int cmd_capability(struct imap_client *imap_client,
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen /* Client is required to send CAPABILITY after STARTTLS, so the
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen capability resp-code workaround checks only pre-STARTTLS
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen CAPABILITY commands. */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen imap_client->client_ignores_capability_resp_code = TRUE;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen "* CAPABILITY ", get_capability(client), "\r\n", NULL));
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen "Pre-login capabilities listed, post-login capabilities have more.");
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainenstatic int cmd_starttls(struct imap_client *client,
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainenimap_client_notify_starttls(struct client *client,
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen client_send_reply(client, IMAP_CMD_REPLY_OK, text);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen client_send_reply(client, IMAP_CMD_REPLY_BAD, text);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen /* do not try to process NIL value */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen /* SYNC WITH imap_login_reserved_id_keys */
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen if (strcasecmp(key, "x-originating-ip") == 0) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen } else if (strcasecmp(key, "x-originating-port") == 0) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen (void)net_str2port(value, &client->common.remote_port);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen } else if (strcasecmp(key, "x-connected-ip") == 0) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen (void)net_addr2ip(value, &client->common.local_ip);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen } else if (strcasecmp(key, "x-connected-port") == 0) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen (void)net_str2port(value, &client->common.local_port);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen } else if (strcasecmp(key, "x-proxy-ttl") == 0) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (str_to_uint(value, &client->common.proxy_ttl) < 0) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen /* nothing */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen } else if (strcasecmp(key, "x-session-id") == 0 ||
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (strlen(value) <= LOGIN_MAX_SESSION_ID_LEN) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainenstatic bool client_id_reserved_word(const char *key)
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen return str_array_icase_find(imap_login_reserved_id_keys, key);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainenstatic void cmd_id_handle_keyvalue(struct imap_client *client,
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen /* length of key + length of value (NIL for NULL) and two set of
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen quotes and space */
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen if (client->common.trusted && !client->id_logged) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen client_id_str = !client_update_info(client, key, value);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen i_assert(client_id_str == !client_id_reserved_word(key));
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen client_id_str = !client_id_reserved_word(key);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen str_len(client->common.client_id) + kvlen < LOGIN_MAX_CLIENT_ID_LEN)) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen client->common.client_id = str_new(client->common.preproxy_pool, 64);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen imap_append_quoted(client->common.client_id, key);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen imap_append_quoted(client->common.client_id, value);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen str_array_icase_find((void *)client->cmd_id->log_keys, key)))
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen imap_id_log_reply_append(client->cmd_id->log_reply, key, value);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainenstatic int cmd_id_handle_args(struct imap_client *client,
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen struct imap_client_cmd_id *id = client->cmd_id;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen /* no ID logging */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen /* already logged the ID reply */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (strcmp(client->set->imap_id_log, "*") == 0) {
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen /* log all keys */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen /* log only specified keys */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen id->log_keys = p_strsplit_spaces(default_pool,
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (i_strocpy(id->key, key, sizeof(id->key)) < 0)
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen cmd_id_handle_keyvalue(client, id->key, value);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainenstatic void cmd_id_finish(struct imap_client *client)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen /* finished handling the parameters */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen "ID sent: %s", str_c(client->cmd_id->log_reply)));
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen imap_id_reply_generate(client->set->imap_id_send)));
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen client_send_reply(&client->common, IMAP_CMD_REPLY_OK, "ID completed.");
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainenstatic void cmd_id_free(struct imap_client *client)
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen struct imap_client_cmd_id *id = client->cmd_id;
int ret;
if (ret > 0) {
ret = 0;
if (ret == 0) {
switch (*tag) {
return FALSE;
return FALSE;
return TRUE;
i_unreached();
bool parsed;
int ret;
return FALSE;
return FALSE;
if (ret == 0)
return FALSE;
if (ret < 0)
if (ret < 0)
return TRUE;
if (ret == 0)
return FALSE;
} else if (ret < 0) {
return FALSE;
T_BEGIN {
if (tagged)
} T_END;
switch (reply) {
case IMAP_CMD_REPLY_OK:
case IMAP_CMD_REPLY_NO:
case IMAP_CMD_REPLY_BAD:
case IMAP_CMD_REPLY_BYE:
const char *text)
if (bad)
const char *text)
static void imap_login_preinit(void)
static void imap_login_init(void)
static void imap_login_deinit(void)
NULL,
NULL,