]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
imap-login: Move ID command handling to its own file.
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Wed, 14 Jun 2017 07:34:57 +0000 (10:34 +0300)
committerVille Savolainen <ville.savolainen@dovecot.fi>
Mon, 28 May 2018 07:33:23 +0000 (10:33 +0300)
src/imap-login/Makefile.am
src/imap-login/imap-login-client.c
src/imap-login/imap-login-client.h
src/imap-login/imap-login-cmd-id.c [new file with mode: 0644]

index 9a6afb817ab6ca87428b34c7904dd3382e55a564..904f530c29acc41f402250a8390add99dd153413 100644 (file)
@@ -25,6 +25,7 @@ imap_login_DEPENDENCIES = \
 imap_login_SOURCES = \
        imap-login-client.c \
        client-authenticate.c \
+       imap-login-cmd-id.c \
        imap-login-commands.c \
        imap-login-settings.c \
        imap-proxy.c
index f529e388301026875857d5b0acf4bbe337049e12..9c37245ef7e68fc3e78960db9f7fd400fd7aef73 100644 (file)
 #  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)
@@ -61,8 +47,8 @@ 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;
@@ -170,226 +156,6 @@ imap_client_notify_starttls(struct client *client,
                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)
 {
@@ -619,7 +385,8 @@ static void imap_client_create(struct client *client, void **other_sets)
        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);
@@ -655,7 +422,8 @@ static void imap_client_starttls(struct client *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;
index 847b2b7f7de057fbfbb74a07f0cef380ce73f4b9..002829ba3a8340f54365ddd7b61cd7b2f9c69c44 100644 (file)
@@ -8,6 +8,9 @@
 /* Master prefix is: <1|0><imap tag><NUL> */
 #define IMAP_TAG_MAX_LEN (LOGIN_MAX_MASTER_PREFIX_LEN-2)
 
+/* maximum length for IMAP command line. */
+#define IMAP_LOGIN_MAX_LINE_LENGTH 8192
+
 enum imap_client_id_state {
        IMAP_CLIENT_ID_STATE_LIST = 0,
        IMAP_CLIENT_ID_STATE_KEY,
@@ -83,9 +86,12 @@ enum imap_cmd_reply {
 
 void client_send_reply(struct client *client,
                       enum imap_cmd_reply reply, const char *text);
-
 void client_send_reply_code(struct client *client,
                            enum imap_cmd_reply reply, const char *resp_code,
                            const char *text) ATTR_NULL(3);
+bool client_handle_parser_error(struct imap_client *client,
+                               struct imap_parser *parser);
+
+int cmd_id(struct imap_client *client);
 
 #endif
diff --git a/src/imap-login/imap-login-cmd-id.c b/src/imap-login/imap-login-cmd-id.c
new file mode 100644 (file)
index 0000000..7bc9947
--- /dev/null
@@ -0,0 +1,239 @@
+/* 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;
+       }
+}