]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-smtp: test-smtp-server-errors - Add tests for very long AUTH response lines.
authorStephan Bosch <stephan.bosch@open-xchange.com>
Fri, 29 Oct 2021 17:37:16 +0000 (19:37 +0200)
committerStephan Bosch <stephan.bosch@open-xchange.com>
Wed, 3 Nov 2021 21:52:55 +0000 (22:52 +0100)
src/lib-smtp/test-smtp-server-errors.c

index d82e0d39db9241fe7ee2a827a53d9fd718885353..314bde2643141a07c91e8ddc5c693cc1d2ed3be1 100644 (file)
@@ -821,6 +821,313 @@ static void test_long_command(void)
        test_end();
 }
 
+/*
+ * Long auth line
+ */
+
+/* client */
+
+#define _LONG_AUTH_LINE_DATA \
+       "dXNlcj10ZXN0dXNlcjEBYXV0aD1CZWFyZXIgZXlKaGJHY2lPaUpTVXpJMU5pSXNJ" \
+       "blI1Y0NJZ09pQWlTbGRVSWl3aWEybGtJaUE2SUNKdVRIRlVlRnBXWVhKSlgwWndS" \
+       "a0Z3Umt3MloyUnhiak4xV1VSS2R6WnNWVjlMYVZoa2JWazJialpSSW4wLmV5Smxl" \
+       "SEFpT2pFMk16UTJNemMyTlRFc0ltbGhkQ0k2TVRZek5EWXpOek0xTVN3aWFuUnBJ" \
+       "am9pT1RFM1lUYzFaalF0WTJZME9DMDBOVEEyTFRnNVpXSXRNRE13WldaaU5tSTVO" \
+       "MlZrSWl3aWFYTnpJam9pYUhSMGNEb3ZMekU1TWk0eE5qZ3VNUzR5TVRveE9EQTRN" \
+       "QzloZFhSb0wzSmxZV3h0Y3k5eVpXeDBaWE4wSWl3aVlYVmtJam9pWVdOamIzVnVk" \
+       "Q0lzSW5OMVlpSTZJamhsWVRRME1UWTNMVGN6TTJVdE5EVTBZeTFpT0dJMUxXTmpa" \
+       "bVl3WkRnek1URTVaQ0lzSW5SNWNDSTZJa0psWVhKbGNpSXNJbUY2Y0NJNkltUnZk" \
+       "bVZqYjNRaUxDSnpaWE56YVc5dVgzTjBZWFJsSWpvaU1tTTNPVEUzWldJdE16QTFO" \
+       "UzAwTkRZeExXSXdZell0WTJVeFlUbGlNVEZoTWpReklpd2lZV055SWpvaU1TSXNJ" \
+       "bkpsWVd4dFgyRmpZMlZ6Y3lJNmV5SnliMnhsY3lJNld5SnZabVpzYVc1bFgyRmpZ" \
+       "MlZ6Y3lJc0luVnRZVjloZFhSb2IzSnBlbUYwYVc5dUlsMTlMQ0p5WlhOdmRYSmpa" \
+       "VjloWTJObGMzTWlPbnNpWVdOamIzVnVkQ0k2ZXlKeWIyeGxjeUk2V3lKdFlXNWha" \
+       "MlV0WVdOamIzVnVkQ0lzSW0xaGJtRm5aUzFoWTJOdmRXNTBMV3hwYm10eklpd2lk" \
+       "bWxsZHkxd2NtOW1hV3hsSWwxOWZTd2ljMk52Y0dVaU9pSndjbTltYVd4bElHVnRZ" \
+       "V2xzSWl3aVpXMWhhV3hmZG1WeWFXWnBaV1FpT21aaGJITmxMQ0p1WVcxbElqb2lk" \
+       "R1Z6ZEhWelpYSXhJRUYxZEc5SFpXNWxjbUYwWldRaUxDSndjbVZtWlhKeVpXUmZk" \
+       "WE5sY201aGJXVWlPaUowWlhOMGRYTmxjakVpTENKbmFYWmxibDl1WVcxbElqb2lk" \
+       "R1Z6ZEhWelpYSXhJaXdpWm1GdGFXeDVYMjVoYldVaU9pSkJkWFJ2UjJWdVpYSmhk" \
+       "R1ZrSWl3aVpXMWhhV3dpT2lKMFpYTjBkWE5sY2pGQWJYbGtiMjFoYVc0dWIzZ2lm" \
+       "US5ta2JGSURpT0FhbENCcVMwODRhVHJURjBIdDk1c1Z4cGlSbTFqZnhJd0JiN1hM" \
+       "M2gzWUJkdXVrVXlZdDJqX1pqUFlhMDhDcVVYNWFrLVBOSjdSVWRTUXNmUlgwM1Zi" \
+       "cXA4MHFZZjNGYzJpcDR0YmhHLXFEV0R6NzdhZDhWcEFNei16YWlSamZCclZ2R3hB" \
+       "T3ZsZnFDVWhaZTJDR3ZqWjZ1Q3RKTlFaS0dyazZHOXoxX2pqekZkTjBXWjUxbEZs" \
+       "US1JdE5LREpoTjNIekJ5SW93M19qQU9kWEI0R0w4R3JHM1hqU09rSFVRam5GTEQw" \
+       "QUF1QXY4SkxmTXY1NGc1a2tKaklxRFgxZlgyWVo0Y2JQOWV3TUp6UV84ZWdLeW5T" \
+       "VV9XSk8xRU9Qa1NVZjlMX19RX3FwY0dNbzFtTkxuTURKUlU2dmZFY3JrM2k0cVNz" \
+       "MXRPdHdLaHcBAQ"
+
+struct _long_auth_line_client {
+       struct smtp_reply_parser *parser;
+       unsigned int reply;
+
+       bool replied:1;
+};
+
+static void test_long_auth_line_client_input(struct client_connection *conn)
+{
+       struct _long_auth_line_client *ctx = conn->context;
+       struct smtp_reply *reply;
+       const char *error;
+       int ret;
+
+       while ((ret = smtp_reply_parse_next(ctx->parser, FALSE,
+                                           &reply, &error)) > 0) {
+               if (debug)
+                       i_debug("REPLY: %s", smtp_reply_log(reply));
+
+               switch (ctx->reply++) {
+               case 0: /* greeting */
+                       i_assert(reply->status == 220);
+                       break;
+               case 1: /* EHLO reply */
+                       i_assert(reply->status == 250);
+                       break;
+               case 2: /* AUTH continue */
+                       i_assert(reply->status == 334);
+                       break;
+               case 3: /* AUTH reply */
+                       switch (client_index) {
+                       case 0:
+                               i_assert(reply->status == 235);
+                               break;
+                       case 1:
+                               i_assert(reply->status == 235);
+                               break;
+                       case 2:
+                               i_assert(reply->status == 500);
+                               ctx->replied = TRUE;
+                               io_loop_stop(ioloop);
+                               connection_disconnect(&conn->conn);
+                               return;
+                       default:
+                               i_unreached();
+                       }
+                       break;
+               case 4: /* MAIL reply */
+                       i_assert(client_index < 2);
+                       i_assert(reply->status == 250);
+                       break;
+               case 5: /* RCPT reply */
+                       i_assert(client_index < 2);
+                       i_assert(reply->status == 250);
+                       break;
+               case 6: /* DATA initial reply */
+                       i_assert(client_index < 2);
+                       i_assert(reply->status == 354);
+                       break;
+               case 7: /* DATA reply */
+                       i_assert(client_index < 2);
+                       i_assert(reply->status == 250);
+                       break;
+               case 8: /* QUIT reply */
+                       i_assert(client_index < 2);
+                       i_assert(reply->status == 221);
+                       ctx->replied = TRUE;
+                       io_loop_stop(ioloop);
+                       connection_disconnect(&conn->conn);
+                       return;
+               default:
+                       i_unreached();
+               }
+       }
+
+       i_assert(ret >= 0);
+}
+
+static void test_long_auth_line_client_connected(struct client_connection *conn)
+{
+       struct _long_auth_line_client *ctx;
+       unsigned int i;
+
+       ctx = p_new(conn->pool, struct _long_auth_line_client, 1);
+       ctx->parser = smtp_reply_parser_init(conn->conn.input, SIZE_MAX);
+       conn->context = ctx;
+
+       o_stream_nsend_str(
+               conn->conn.output,
+               "EHLO frop\r\n"
+               "AUTH XOAUTH2\r\n");
+       for (i = 0; i < (client_index > 1 ? 6 : 1); i++)
+               o_stream_nsend_str(conn->conn.output, _LONG_AUTH_LINE_DATA);
+       o_stream_nsend_str(
+               conn->conn.output,
+               "==");
+       if (client_index == 1) {
+               o_stream_nsend_str(
+                       conn->conn.output,
+                       "                                      ");
+       }
+       o_stream_nsend_str(
+               conn->conn.output,
+               "\r\n"
+               "MAIL FROM:<user@example.com>\r\n"
+               "RCPT TO:<user@example.com>\r\n"
+               "DATA\r\n"
+               "frop\r\n"
+               ".\r\n"
+               "QUIT\r\n");
+}
+
+static void test_long_auth_line_client_deinit(struct client_connection *conn)
+{
+       struct _long_auth_line_client *ctx = conn->context;
+
+       i_assert(ctx->replied);
+       smtp_reply_parser_deinit(&ctx->parser);
+}
+
+static void test_client_long_auth_line(unsigned int index)
+{
+       test_client_input = test_long_auth_line_client_input;
+       test_client_connected = test_long_auth_line_client_connected;
+       test_client_deinit = test_long_auth_line_client_deinit;
+       test_client_run(index);
+}
+
+/* server */
+
+struct _long_auth_line {
+       struct istream *payload_input;
+};
+
+static void
+test_server_long_auth_line_disconnect(void *context ATTR_UNUSED,
+                                   const char *reason)
+{
+       if (debug)
+               i_debug("Disconnect: %s", reason);
+}
+
+static int
+test_server_long_auth_line_helo(void *conn_ctx ATTR_UNUSED,
+                             struct smtp_server_cmd_ctx *cmd ATTR_UNUSED,
+                             struct smtp_server_cmd_helo *data ATTR_UNUSED)
+{
+       return 1;
+}
+
+static int
+test_server_long_auth_line_auth(void *conn_ctx ATTR_UNUSED,
+                               struct smtp_server_cmd_ctx *cmd,
+                               struct smtp_server_cmd_auth *data ATTR_UNUSED)
+{
+       smtp_server_cmd_auth_send_challenge(cmd, "");
+       return 0;
+}
+
+static int
+test_server_long_auth_line_auth_continue(void *conn_ctx ATTR_UNUSED,
+                                        struct smtp_server_cmd_ctx *cmd,
+                                        const char *response)
+{
+       if (strcmp(response, _LONG_AUTH_LINE_DATA"==") == 0)
+               smtp_server_cmd_auth_success(cmd, "user", NULL);
+       else {
+               smtp_server_reply(cmd, 535, "5.7.8",
+                                 "Authentication credentials invalid");
+       }
+       return 1;
+}
+
+static int
+test_server_long_auth_line_rcpt(void *conn_ctx ATTR_UNUSED,
+                             struct smtp_server_cmd_ctx *cmd ATTR_UNUSED,
+                             struct smtp_server_recipient *rcpt ATTR_UNUSED)
+{
+       if (debug)
+               i_debug("RCPT");
+       return 1;
+}
+
+static int
+test_server_long_auth_line_data_begin(void *conn_ctx ATTR_UNUSED,
+                               struct smtp_server_cmd_ctx *cmd ATTR_UNUSED,
+                               struct smtp_server_transaction *trans,
+                               struct istream *data_input)
+{
+       struct _long_auth_line *ctx;
+
+       if (debug)
+               i_debug("DATA");
+
+       ctx = p_new(trans->pool, struct _long_auth_line, 1);
+       trans->context = ctx;
+
+       ctx->payload_input = data_input;
+       return 0;
+}
+
+static int
+test_server_long_auth_line_data_continue(void *conn_ctx ATTR_UNUSED,
+                                  struct smtp_server_cmd_ctx *cmd,
+                                  struct smtp_server_transaction *trans)
+{
+       struct _long_auth_line *ctx = (struct _long_auth_line *)trans->context;
+       struct istream *data_input = ctx->payload_input;
+       size_t size;
+       ssize_t ret;
+
+       if (debug)
+               i_debug("DATA continue");
+
+       while ((ret = i_stream_read(data_input)) > 0 || ret == -2) {
+               (void)i_stream_get_data(data_input, &size);
+               i_stream_skip(data_input, size);
+               if (!smtp_server_cmd_data_check_size(cmd))
+                       return -1;
+       }
+
+       if (ret == 0)
+               return 0;
+       if (ret < 0 && data_input->stream_errno != 0) {
+               /* Client probably disconnected */
+               return -1;
+       }
+
+       smtp_server_reply_all(cmd, 250, "2.0.0", "Accepted");
+       return 1;
+}
+
+static void
+test_server_long_auth_line(const struct smtp_server_settings *server_set)
+{
+       server_callbacks.conn_disconnect =
+               test_server_long_auth_line_disconnect;
+
+       server_callbacks.conn_cmd_helo =
+               test_server_long_auth_line_helo;
+       server_callbacks.conn_cmd_auth =
+               test_server_long_auth_line_auth;
+       server_callbacks.conn_cmd_auth_continue =
+               test_server_long_auth_line_auth_continue;
+       server_callbacks.conn_cmd_rcpt =
+               test_server_long_auth_line_rcpt;
+       server_callbacks.conn_cmd_data_begin =
+               test_server_long_auth_line_data_begin;
+       server_callbacks.conn_cmd_data_continue =
+               test_server_long_auth_line_data_continue;
+       test_server_run(server_set);
+}
+
+/* test */
+
+static void test_long_auth_line(void)
+{
+       struct smtp_server_settings smtp_server_set;
+
+       test_server_defaults(&smtp_server_set);
+       smtp_server_set.capabilities = SMTP_CAPABILITY_AUTH;
+       smtp_server_set.max_client_idle_time_msecs = 1000;
+
+       test_begin("long auth line");
+       test_run_client_server(&smtp_server_set,
+                              test_server_long_auth_line,
+                              test_client_long_auth_line, 3);
+       test_end();
+}
+
 /*
  * Big data
  */
@@ -3174,6 +3481,7 @@ static void (*const test_functions[])(void) = {
        test_bad_command,
        test_many_bad_commands,
        test_long_command,
+       test_long_auth_line,
        test_big_data,
        test_bad_helo,
        test_bad_mail,