# error LOGIN_MAX_INBUF_SIZE too short to fit all ID command parameters
#endif
-/* 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 3
-static const char *const imap_login_reserved_id_keys[] = {
- "x-originating-ip",
- "x-originating-port",
- "x-connected-ip",
- "x-connected-port",
- "x-proxy-ttl",
- "x-session-id",
- "x-session-ext-id",
- NULL
-};
-
/* Skip incoming data until newline is found,
returns TRUE if newline was found. */
bool client_skip_line(struct imap_client *client)
return FALSE;
}
-static bool client_handle_parser_error(struct imap_client *client,
- struct imap_parser *parser)
+bool client_handle_parser_error(struct imap_client *client,
+ struct imap_parser *parser)
{
const char *msg;
enum imap_parser_error parse_error;
client_send_reply(client, IMAP_CMD_REPLY_BAD, text);
}
-static bool
-client_update_info(struct imap_client *client,
- const char *key, const char *value)
-{
- i_assert(value != NULL);
-
- /* SYNC WITH imap_login_reserved_id_keys */
-
- if (strcasecmp(key, "x-originating-ip") == 0) {
- (void)net_addr2ip(value, &client->common.ip);
- } else if (strcasecmp(key, "x-originating-port") == 0) {
- (void)net_str2port(value, &client->common.remote_port);
- } else if (strcasecmp(key, "x-connected-ip") == 0) {
- (void)net_addr2ip(value, &client->common.local_ip);
- } else if (strcasecmp(key, "x-connected-port") == 0) {
- (void)net_str2port(value, &client->common.local_port);
- } else if (strcasecmp(key, "x-proxy-ttl") == 0) {
- if (str_to_uint(value, &client->common.proxy_ttl) < 0) {
- /* nothing */
- }
- } else if (strcasecmp(key, "x-session-id") == 0 ||
- strcasecmp(key, "x-session-ext-id") == 0) {
- if (strlen(value) <= LOGIN_MAX_SESSION_ID_LEN) {
- client->common.session_id =
- p_strdup(client->common.pool, value);
- }
- } else if (strncasecmp(key, "x-forward-", 10) == 0) {
- /* handle extra field */
- client_add_forward_field(&client->common, key+10, value);
- } else {
- return FALSE;
- }
- return TRUE;
-}
-
-static bool client_id_reserved_word(const char *key)
-{
- i_assert(key != NULL);
- return (strncasecmp(key, "x-forward-", 10) == 0 ||
- str_array_icase_find(imap_login_reserved_id_keys, key));
-}
-
-static void cmd_id_handle_keyvalue(struct imap_client *client,
- const char *key, const char *value)
-{
- bool client_id_str;
- /* length of key + length of value (NIL for NULL) and two set of
- quotes and space */
- size_t kvlen = strlen(key) + 2 + 1 +
- (value == NULL ? 3 : strlen(value)) + 2;
-
- if (client->common.trusted && !client->id_logged) {
- if (value == NULL) {
- /* do not try to process NIL values as client-info,
- but store them for non-reserved keys */
- client_id_str = !client_id_reserved_word(key);
- } else {
- client_id_str = !client_update_info(client, key, value);
- i_assert(client_id_str == !client_id_reserved_word(key));
- }
- } else {
- client_id_str = !client_id_reserved_word(key);
- }
-
- if (client->set->imap_id_retain && client_id_str &&
- (client->common.client_id == NULL ||
- str_len(client->common.client_id) + kvlen < LOGIN_MAX_CLIENT_ID_LEN)) {
- if (client->common.client_id == NULL) {
- client->common.client_id = str_new(client->common.preproxy_pool, 64);
- } else {
- str_append_c(client->common.client_id, ' ');
- }
- imap_append_quoted(client->common.client_id, key);
- str_append_c(client->common.client_id, ' ');
- if (value == NULL)
- str_append(client->common.client_id, "NIL");
- else
- imap_append_quoted(client->common.client_id, value);
- }
-
- if (client->cmd_id->log_reply != NULL &&
- (client->cmd_id->log_keys == NULL ||
- str_array_icase_find((void *)client->cmd_id->log_keys, key)))
- imap_id_log_reply_append(client->cmd_id->log_reply, key, value);
-}
-
-static int cmd_id_handle_args(struct imap_client *client,
- const struct imap_arg *arg)
-{
- struct imap_client_cmd_id *id = client->cmd_id;
- const char *key, *value;
-
- switch (id->state) {
- case IMAP_CLIENT_ID_STATE_LIST:
- if (arg->type == IMAP_ARG_NIL)
- return 1;
- if (arg->type != IMAP_ARG_LIST)
- return -1;
- if (client->set->imap_id_log[0] == '\0') {
- /* no ID logging */
- } else if (client->id_logged) {
- /* already logged the ID reply */
- } else {
- id->log_reply = str_new(default_pool, 64);
- if (strcmp(client->set->imap_id_log, "*") == 0) {
- /* log all keys */
- } else {
- /* log only specified keys */
- id->log_keys = p_strsplit_spaces(default_pool,
- client->set->imap_id_log, " ");
- }
- }
- id->state = IMAP_CLIENT_ID_STATE_KEY;
- break;
- case IMAP_CLIENT_ID_STATE_KEY:
- if (!imap_arg_get_string(arg, &key))
- return -1;
- if (i_strocpy(id->key, key, sizeof(id->key)) < 0)
- return -1;
- id->state = IMAP_CLIENT_ID_STATE_VALUE;
- break;
- case IMAP_CLIENT_ID_STATE_VALUE:
- if (!imap_arg_get_nstring(arg, &value))
- return -1;
- cmd_id_handle_keyvalue(client, id->key, value);
- id->state = IMAP_CLIENT_ID_STATE_KEY;
- break;
- }
- return 0;
-}
-
-static void cmd_id_finish(struct imap_client *client)
-{
- /* finished handling the parameters */
- if (!client->id_logged) {
- client->id_logged = TRUE;
-
- if (client->cmd_id->log_reply != NULL) {
- client_log(&client->common, t_strdup_printf(
- "ID sent: %s", str_c(client->cmd_id->log_reply)));
- }
- }
-
- client_send_raw(&client->common,
- t_strdup_printf("* ID %s\r\n",
- imap_id_reply_generate(client->set->imap_id_send)));
- client_send_reply(&client->common, IMAP_CMD_REPLY_OK, "ID completed.");
-}
-
-static void cmd_id_free(struct imap_client *client)
-{
- struct imap_client_cmd_id *id = client->cmd_id;
-
- if (id->log_reply != NULL)
- str_free(&id->log_reply);
- if (id->log_keys != NULL)
- p_strsplit_free(default_pool, id->log_keys);
- imap_parser_unref(&id->parser);
-
- i_free_and_null(client->cmd_id);
- client->skip_line = TRUE;
-}
-
-static int cmd_id(struct imap_client *client)
-{
- struct imap_client_cmd_id *id;
- enum imap_parser_flags parser_flags;
- const struct imap_arg *args;
- int ret;
-
- if (client->common.client_id != NULL)
- str_truncate(client->common.client_id, 0);
-
- if (client->cmd_id == NULL) {
- client->cmd_id = id = i_new(struct imap_client_cmd_id, 1);
- id->parser = imap_parser_create(client->common.input,
- client->common.output,
- MAX_IMAP_LINE);
- if (client->set->imap_literal_minus)
- imap_parser_enable_literal_minus(id->parser);
- parser_flags = IMAP_PARSE_FLAG_STOP_AT_LIST;
- } else {
- id = client->cmd_id;
- parser_flags = IMAP_PARSE_FLAG_INSIDE_LIST;
- }
-
- while ((ret = imap_parser_read_args(id->parser, 1, parser_flags, &args)) > 0) {
- i_assert(ret == 1);
-
- if ((ret = cmd_id_handle_args(client, args)) < 0) {
- client_send_reply(&client->common,
- IMAP_CMD_REPLY_BAD,
- "Invalid ID parameters");
- cmd_id_free(client);
- return -1;
- }
- if (ret > 0) {
- /* NIL parameter */
- ret = 0;
- break;
- }
- imap_parser_reset(id->parser);
- parser_flags = IMAP_PARSE_FLAG_INSIDE_LIST;
- }
- if (ret == 0) {
- /* finished the line */
- cmd_id_finish(client);
- cmd_id_free(client);
- return 1;
- } else if (ret == -1) {
- if (!client_handle_parser_error(client, id->parser))
- return 0;
- cmd_id_free(client);
- return -1;
- } else {
- i_assert(ret == -2);
- return 0;
- }
-}
-
static int cmd_noop(struct imap_client *client,
const struct imap_arg *args ATTR_UNUSED)
{
imap_client->set = other_sets[0];
imap_client->parser =
imap_parser_create(imap_client->common.input,
- imap_client->common.output, MAX_IMAP_LINE);
+ imap_client->common.output,
+ IMAP_LOGIN_MAX_LINE_LENGTH);
if (imap_client->set->imap_literal_minus)
imap_parser_enable_literal_minus(imap_client->parser);
client->io = io_add_istream(client->input, client_input, client);
imap_parser_unref(&imap_client->parser);
imap_client->parser =
imap_parser_create(imap_client->common.input,
- imap_client->common.output, MAX_IMAP_LINE);
+ imap_client->common.output,
+ IMAP_LOGIN_MAX_LINE_LENGTH);
/* CRLF is lost from buffer when streams are reopened. */
imap_client->skip_line = FALSE;
--- /dev/null
+/* Copyright (c) 2002-2017 Dovecot authors, see the included COPYING file */
+
+#include "login-common.h"
+#include "str.h"
+#include "imap-parser.h"
+#include "imap-quote.h"
+#include "imap-login-settings.h"
+#include "imap-login-client.h"
+
+static const char *const imap_login_reserved_id_keys[] = {
+ "x-originating-ip",
+ "x-originating-port",
+ "x-connected-ip",
+ "x-connected-port",
+ "x-proxy-ttl",
+ "x-session-id",
+ "x-session-ext-id",
+ NULL
+};
+
+static bool
+client_update_info(struct imap_client *client,
+ const char *key, const char *value)
+{
+ i_assert(value != NULL);
+
+ /* SYNC WITH imap_login_reserved_id_keys */
+
+ if (strcasecmp(key, "x-originating-ip") == 0) {
+ (void)net_addr2ip(value, &client->common.ip);
+ } else if (strcasecmp(key, "x-originating-port") == 0) {
+ (void)net_str2port(value, &client->common.remote_port);
+ } else if (strcasecmp(key, "x-connected-ip") == 0) {
+ (void)net_addr2ip(value, &client->common.local_ip);
+ } else if (strcasecmp(key, "x-connected-port") == 0) {
+ (void)net_str2port(value, &client->common.local_port);
+ } else if (strcasecmp(key, "x-proxy-ttl") == 0) {
+ if (str_to_uint(value, &client->common.proxy_ttl) < 0) {
+ /* nothing */
+ }
+ } else if (strcasecmp(key, "x-session-id") == 0 ||
+ strcasecmp(key, "x-session-ext-id") == 0) {
+ if (strlen(value) <= LOGIN_MAX_SESSION_ID_LEN) {
+ client->common.session_id =
+ p_strdup(client->common.pool, value);
+ }
+ } else if (strncasecmp(key, "x-forward-", 10) == 0) {
+ /* handle extra field */
+ client_add_forward_field(&client->common, key+10, value);
+ } else {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static bool client_id_reserved_word(const char *key)
+{
+ i_assert(key != NULL);
+ return (strncasecmp(key, "x-forward-", 10) == 0 ||
+ str_array_icase_find(imap_login_reserved_id_keys, key));
+}
+
+static void cmd_id_handle_keyvalue(struct imap_client *client,
+ const char *key, const char *value)
+{
+ bool client_id_str;
+ /* length of key + length of value (NIL for NULL) and two set of
+ quotes and space */
+ size_t kvlen = strlen(key) + 2 + 1 +
+ (value == NULL ? 3 : strlen(value)) + 2;
+
+ if (client->common.trusted && !client->id_logged) {
+ if (value == NULL) {
+ /* do not try to process NIL values as client-info,
+ but store them for non-reserved keys */
+ client_id_str = !client_id_reserved_word(key);
+ } else {
+ client_id_str = !client_update_info(client, key, value);
+ i_assert(client_id_str == !client_id_reserved_word(key));
+ }
+ } else {
+ client_id_str = !client_id_reserved_word(key);
+ }
+
+ if (client->set->imap_id_retain && client_id_str &&
+ (client->common.client_id == NULL ||
+ str_len(client->common.client_id) + kvlen < LOGIN_MAX_CLIENT_ID_LEN)) {
+ if (client->common.client_id == NULL) {
+ client->common.client_id = str_new(client->common.preproxy_pool, 64);
+ } else {
+ str_append_c(client->common.client_id, ' ');
+ }
+ imap_append_quoted(client->common.client_id, key);
+ str_append_c(client->common.client_id, ' ');
+ if (value == NULL)
+ str_append(client->common.client_id, "NIL");
+ else
+ imap_append_quoted(client->common.client_id, value);
+ }
+
+ if (client->cmd_id->log_reply != NULL &&
+ (client->cmd_id->log_keys == NULL ||
+ str_array_icase_find((void *)client->cmd_id->log_keys, key)))
+ imap_id_log_reply_append(client->cmd_id->log_reply, key, value);
+}
+
+static int cmd_id_handle_args(struct imap_client *client,
+ const struct imap_arg *arg)
+{
+ struct imap_client_cmd_id *id = client->cmd_id;
+ const char *key, *value;
+
+ switch (id->state) {
+ case IMAP_CLIENT_ID_STATE_LIST:
+ if (arg->type == IMAP_ARG_NIL)
+ return 1;
+ if (arg->type != IMAP_ARG_LIST)
+ return -1;
+ if (client->set->imap_id_log[0] == '\0') {
+ /* no ID logging */
+ } else if (client->id_logged) {
+ /* already logged the ID reply */
+ } else {
+ id->log_reply = str_new(default_pool, 64);
+ if (strcmp(client->set->imap_id_log, "*") == 0) {
+ /* log all keys */
+ } else {
+ /* log only specified keys */
+ id->log_keys = p_strsplit_spaces(default_pool,
+ client->set->imap_id_log, " ");
+ }
+ }
+ id->state = IMAP_CLIENT_ID_STATE_KEY;
+ break;
+ case IMAP_CLIENT_ID_STATE_KEY:
+ if (!imap_arg_get_string(arg, &key))
+ return -1;
+ if (i_strocpy(id->key, key, sizeof(id->key)) < 0)
+ return -1;
+ id->state = IMAP_CLIENT_ID_STATE_VALUE;
+ break;
+ case IMAP_CLIENT_ID_STATE_VALUE:
+ if (!imap_arg_get_nstring(arg, &value))
+ return -1;
+ cmd_id_handle_keyvalue(client, id->key, value);
+ id->state = IMAP_CLIENT_ID_STATE_KEY;
+ break;
+ }
+ return 0;
+}
+
+static void cmd_id_finish(struct imap_client *client)
+{
+ /* finished handling the parameters */
+ if (!client->id_logged) {
+ client->id_logged = TRUE;
+
+ if (client->cmd_id->log_reply != NULL) {
+ client_log(&client->common, t_strdup_printf(
+ "ID sent: %s", str_c(client->cmd_id->log_reply)));
+ }
+ }
+
+ client_send_raw(&client->common,
+ t_strdup_printf("* ID %s\r\n",
+ imap_id_reply_generate(client->set->imap_id_send)));
+ client_send_reply(&client->common, IMAP_CMD_REPLY_OK, "ID completed.");
+}
+
+static void cmd_id_free(struct imap_client *client)
+{
+ struct imap_client_cmd_id *id = client->cmd_id;
+
+ if (id->log_reply != NULL)
+ str_free(&id->log_reply);
+ if (id->log_keys != NULL)
+ p_strsplit_free(default_pool, id->log_keys);
+ imap_parser_unref(&id->parser);
+
+ i_free_and_null(client->cmd_id);
+ client->skip_line = TRUE;
+}
+
+int cmd_id(struct imap_client *client)
+{
+ struct imap_client_cmd_id *id;
+ enum imap_parser_flags parser_flags;
+ const struct imap_arg *args;
+ int ret;
+
+ if (client->common.client_id != NULL)
+ str_truncate(client->common.client_id, 0);
+
+ if (client->cmd_id == NULL) {
+ client->cmd_id = id = i_new(struct imap_client_cmd_id, 1);
+ id->parser = imap_parser_create(client->common.input,
+ client->common.output,
+ IMAP_LOGIN_MAX_LINE_LENGTH);
+ if (client->set->imap_literal_minus)
+ imap_parser_enable_literal_minus(id->parser);
+ parser_flags = IMAP_PARSE_FLAG_STOP_AT_LIST;
+ } else {
+ id = client->cmd_id;
+ parser_flags = IMAP_PARSE_FLAG_INSIDE_LIST;
+ }
+
+ while ((ret = imap_parser_read_args(id->parser, 1, parser_flags, &args)) > 0) {
+ i_assert(ret == 1);
+
+ if ((ret = cmd_id_handle_args(client, args)) < 0) {
+ client_send_reply(&client->common,
+ IMAP_CMD_REPLY_BAD,
+ "Invalid ID parameters");
+ cmd_id_free(client);
+ return -1;
+ }
+ if (ret > 0) {
+ /* NIL parameter */
+ ret = 0;
+ break;
+ }
+ imap_parser_reset(id->parser);
+ parser_flags = IMAP_PARSE_FLAG_INSIDE_LIST;
+ }
+ if (ret == 0) {
+ /* finished the line */
+ cmd_id_finish(client);
+ cmd_id_free(client);
+ return 1;
+ } else if (ret == -1) {
+ if (!client_handle_parser_error(client, id->parser))
+ return 0;
+ cmd_id_free(client);
+ return -1;
+ } else {
+ i_assert(ret == -2);
+ return 0;
+ }
+}