]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
submission-login: submission-proxy - Send XCLIENT data in multiple commands if line...
authorStephan Bosch <stephan.bosch@open-xchange.com>
Sun, 4 Jul 2021 22:36:36 +0000 (00:36 +0200)
committertimo.sirainen <timo.sirainen@open-xchange.com>
Fri, 23 Jul 2021 06:47:02 +0000 (06:47 +0000)
When the proxy talks to non-Dovecot software, failures could occur otherwise. Particularly Postfix will fail.

src/submission-login/client.h
src/submission-login/submission-proxy.c

index d9fbfa25badef18cde4adad2afd0ee1edd3d29b3..109bfd80fc4c9ab274c96fb8825d0c54d2815667 100644 (file)
@@ -31,6 +31,7 @@ struct submission_client {
        unsigned int proxy_reply_status;
        struct smtp_server_reply *proxy_reply;
        const char **proxy_xclient;
+       unsigned int proxy_xclient_replies_expected;
 };
 
 #endif
index 6bda27a7622deb29b1164c7949a794e012301d0a..6600c04c534c1c77017a5f0d4ee9d9ee49cd8f11 100644 (file)
@@ -66,6 +66,40 @@ proxy_compose_xclient_forward(struct submission_client *client)
        return t_base64_encode(0, 0, str_data(str), str_len(str));
 }
 
+static void
+proxy_send_xclient_more_data(struct submission_client *client,
+                            struct ostream *output, string_t *buf,
+                            const char *field, const unsigned char *value,
+                            size_t value_size)
+{
+       static const size_t cmd_len = strlen("XCLIENT");
+       size_t prev_len = str_len(buf);
+
+       str_append_c(buf, ' ');
+       str_append(buf, field);
+       str_append_c(buf, '=');
+       smtp_xtext_encode(buf, value, value_size);
+
+       if (str_len(buf) > 512) {
+               if (prev_len <= cmd_len)
+                       prev_len = str_len(buf);
+               o_stream_nsend(output, str_data(buf), prev_len);
+               o_stream_nsend(output, "\r\n", 2);
+               client->proxy_xclient_replies_expected++;
+               str_delete(buf, cmd_len, prev_len - cmd_len);
+       }
+}
+
+static void
+proxy_send_xclient_more(struct submission_client *client,
+                       struct ostream *output, string_t *buf,
+                       const char *field, const char *value)
+{
+       proxy_send_xclient_more_data(client, output, buf, field,
+                                    (const unsigned char *)value,
+                                    strlen(value));
+}
+
 static int
 proxy_send_xclient(struct submission_client *client, struct ostream *output)
 {
@@ -81,56 +115,67 @@ proxy_send_xclient(struct submission_client *client, struct ostream *output)
        i_assert(client->common.proxy_ttl > 1);
 
        /* remote supports XCLIENT, send it */
+       client->proxy_xclient_replies_expected = 0;
        str = t_str_new(128);
        str_append(str, "XCLIENT");
        if (str_array_icase_find(client->proxy_xclient, "HELO")) {
                if (proxy_data.helo != NULL) {
-                       str_append(str, " HELO=");
-                       smtp_xtext_encode_cstr(str, proxy_data.helo);
+                       proxy_send_xclient_more(client, output, str, "HELO",
+                                               proxy_data.helo);
                } else {
-                       str_append(str, " HELO=[UNAVAILABLE]");
+                       proxy_send_xclient_more(client, output, str, "HELO",
+                                               "[UNAVAILABLE]");
                }
        }
        if (str_array_icase_find(client->proxy_xclient, "PROTO")) {
+               const char *proto = "[UNAVAILABLE]";
+
                switch (proxy_data.proto) {
                case SMTP_PROXY_PROTOCOL_UNKNOWN:
-                       str_append(str, " PROTO=[UNAVAILABLE]");
                        break;
                case SMTP_PROXY_PROTOCOL_SMTP:
-                       str_append(str, " PROTO=SMTP");
+                       proto = "SMTP";
                        break;
                case SMTP_PROXY_PROTOCOL_ESMTP:
-                       str_append(str, " PROTO=ESMTP");
+                       proto = "ESMTP";
                        break;
                case SMTP_PROXY_PROTOCOL_LMTP:
-                       str_append(str, " PROTO=LMTP");
+                       proto = "LMTP";
                        break;
                }
+               proxy_send_xclient_more(client, output, str, "PROTO", proto);
+       }
+       if (str_array_icase_find(client->proxy_xclient, "TTL")) {
+               proxy_send_xclient_more(
+                       client, output, str, "TTL",
+                       t_strdup_printf("%u",client->common.proxy_ttl - 1));
+       }
+       if (str_array_icase_find(client->proxy_xclient, "PORT")) {
+               proxy_send_xclient_more(
+                       client, output, str, "PORT",
+                       t_strdup_printf("%u", client->common.remote_port));
        }
-       if (str_array_icase_find(client->proxy_xclient, "TTL"))
-               str_printfa(str, " TTL=%u", client->common.proxy_ttl - 1);
-       if (str_array_icase_find(client->proxy_xclient, "PORT"))
-               str_printfa(str, " PORT=%u", client->common.remote_port);
        if (str_array_icase_find(client->proxy_xclient, "ADDR")) {
-               str_append(str, " ADDR=");
-               str_append(str, net_ip2addr(&client->common.ip));
+               proxy_send_xclient_more(client, output, str, "ADDR",
+                                       net_ip2addr(&client->common.ip));
        }
        if (str_array_icase_find(client->proxy_xclient, "SESSION")) {
-               str_append(str, " SESSION=");
-               smtp_xtext_encode_cstr(
-                       str, client_get_session_id(&client->common));
+               proxy_send_xclient_more(client, output, str, "SESSION",
+                                       client_get_session_id(&client->common));
        }
        if (str_array_icase_find(client->proxy_xclient, "FORWARD")) {
                buffer_t *fwd = proxy_compose_xclient_forward(client);
 
                if (fwd != NULL) {
-                       str_append(str, " FORWARD=");
-                       smtp_xtext_encode(str, fwd->data, fwd->used);
+                       proxy_send_xclient_more_data(
+                               client, output, str, "FORWARD",
+                               fwd->data, fwd->used);
                }
        }
        str_append(str, "\r\n");
        o_stream_nsend(output, str_data(str), str_len(str));
        client->proxy_state = SUBMISSION_PROXY_XCLIENT;
+       client->proxy_xclient_replies_expected++;
        return 1;
 }
 
@@ -442,6 +487,9 @@ int submission_proxy_parse_line(struct client *client, const char *line)
                }
                if (!last_line)
                        return 0;
+               i_assert(subm_client->proxy_xclient_replies_expected > 0);
+               if (--subm_client->proxy_xclient_replies_expected > 0)
+                       return 0;
                subm_client->proxy_state = SUBMISSION_PROXY_XCLIENT_EHLO;
                return 0;
        case SUBMISSION_PROXY_AUTHENTICATE: