summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormanuel <manuel@mausz.at>2026-01-19 22:40:44 +0100
committermanuel <manuel@mausz.at>2026-01-19 22:40:44 +0100
commit859afd6c154625e18be4b2f8123e40cd9e0cce05 (patch)
treec963f65cdba725be2e3627d4b59ebabc983fd9d4
parent0cd96fce7e5477aebed341e996fcc903f0e6a835 (diff)
downloadqmail-master.tar.gz
qmail-master.tar.bz2
qmail-master.zip
qmail-remote: show EHLO response even after connection has been droppedHEADmaster
this was actually way harder than assumed. turns out we need to issue HELO after EHLO, in case EHLO is not supported. however qmail overwrites the old reply as soon as we issue the next command. furthermore some mail servers drop the connection after issueing a 5xx reply. we only notice this after reading from the socket which usually happens on the next smtp commmand. so we need to run HELO to determine if the connection has been dropped, however running HELO truncates the EHLO reply we want to show in the bounce message. and we have TLS-required as possible variants. so after EHLO fails.. * in TLS-required: show EHLO reponse in case EHLO code is non-success * in non-TLS: copy EHLO response, issue HELO, show EHLO response in case connection dies, otherwise show HELO response
-rw-r--r--qmail-remote.c52
1 files changed, 29 insertions, 23 deletions
diff --git a/qmail-remote.c b/qmail-remote.c
index ee2c6a8..dbeef95 100644
--- a/qmail-remote.c
+++ b/qmail-remote.c
@@ -138,6 +138,20 @@ void outhost()
138} 138}
139 139
140int flagcritical = 0; 140int flagcritical = 0;
141stralloc smtptext = {0};
142stralloc smtptextdropped = {0};
143
144void outsmtptext(stralloc *smtptext)
145{
146 int i;
147 if (smtptext->s && smtptext->len) {
148 out("Remote host said: ");
149 for (i = 0;i < smtptext->len;++i)
150 if (!smtptext->s[i]) smtptext->s[i] = '?';
151 if (substdio_put(subfdoutsmall,smtptext->s,smtptext->len) == -1) _exit(0);
152 smtptext->len = 0;
153 }
154}
141 155
142void dropped() { 156void dropped() {
143 out("ZConnected to "); 157 out("ZConnected to ");
@@ -148,6 +162,7 @@ void dropped() {
148 if (ssl_err_str) { out(ssl_err_str); out(" "); } 162 if (ssl_err_str) { out(ssl_err_str); out(" "); }
149#endif 163#endif
150 out("(#4.4.2)\n"); 164 out("(#4.4.2)\n");
165 outsmtptext(&smtptextdropped);
151 zerodie(); 166 zerodie();
152} 167}
153 168
@@ -176,7 +191,7 @@ ssize_t safewrite(fd,buf,len) int fd; char *buf; int len;
176 r = ssl_timeoutwrite(timeout, smtpfd, smtpfd, ssl, buf, len); 191 r = ssl_timeoutwrite(timeout, smtpfd, smtpfd, ssl, buf, len);
177 if (r < 0) ssl_err_str = ssl_error_str(); 192 if (r < 0) ssl_err_str = ssl_error_str();
178 } else 193 } else
179#endif 194#endif
180 r = timeoutwrite(timeout,smtpfd,buf,len); 195 r = timeoutwrite(timeout,smtpfd,buf,len);
181 if (r <= 0) dropped(); 196 if (r <= 0) dropped();
182 return r; 197 return r;
@@ -189,8 +204,6 @@ substdio smtpto = SUBSTDIO_FDBUF(safewrite,-1,smtptobuf,sizeof smtptobuf);
189char smtpfrombuf[128]; 204char smtpfrombuf[128];
190substdio smtpfrom = SUBSTDIO_FDBUF(saferead,-1,smtpfrombuf,sizeof smtpfrombuf); 205substdio smtpfrom = SUBSTDIO_FDBUF(saferead,-1,smtpfrombuf,sizeof smtpfrombuf);
191 206
192stralloc smtptext = {0};
193
194void get(ch) 207void get(ch)
195char *ch; 208char *ch;
196{ 209{
@@ -276,18 +289,6 @@ unsigned long ehlo()
276 return 250; 289 return 250;
277} 290}
278 291
279void outsmtptext()
280{
281 int i;
282 if (smtptext.s) if (smtptext.len) {
283 out("Remote host said: ");
284 for (i = 0;i < smtptext.len;++i)
285 if (!smtptext.s[i]) smtptext.s[i] = '?';
286 if (substdio_put(subfdoutsmall,smtptext.s,smtptext.len) == -1) _exit(0);
287 smtptext.len = 0;
288 }
289}
290
291void smtp_quit() 292void smtp_quit()
292{ 293{
293#ifdef TLS 294#ifdef TLS
@@ -306,7 +307,7 @@ void quit2(const char *prepend, const char *append, int flagdie)
306 outhost(); 307 outhost();
307 if (append) out(append); 308 if (append) out(append);
308 out(".\n"); 309 out(".\n");
309 outsmtptext(); 310 outsmtptext(&smtptext);
310 311
311#if defined(TLS) && defined(DEBUG) 312#if defined(TLS) && defined(DEBUG)
312 if (ssl) { 313 if (ssl) {
@@ -394,7 +395,7 @@ int verify_cb(int preverify_ok, X509_STORE_CTX *ctx) { return 1; }
394 * @return 0 ...TLS failed, continue plaintext 395 * @return 0 ...TLS failed, continue plaintext
395 * @return -1 ...skip to next MX 396 * @return -1 ...skip to next MX
396 */ 397 */
397static int tls_init(struct ip_mx *current_mx) 398static int tls_init(unsigned long code, struct ip_mx *current_mx)
398{ 399{
399 int i; 400 int i;
400 SSL *myssl; 401 SSL *myssl;
@@ -476,7 +477,9 @@ static int tls_init(struct ip_mx *current_mx)
476 if (!tls_required) return 0; 477 if (!tls_required) return 0;
477 out(failure_class); 478 out(failure_class);
478 out("TLS is required, but was not offered by host"); 479 out("TLS is required, but was not offered by host");
479 smtptext.len = 0; 480 /* only hide SMTP EHLO reply in bounce message on success */
481 if (code == 250)
482 smtptext.len = 0;
480 TLS_QUIT; 483 TLS_QUIT;
481 } 484 }
482 } 485 }
@@ -634,7 +637,7 @@ static int tls_init(struct ip_mx *current_mx)
634 637
635 /* read the responce to STARTTLS */ 638 /* read the responce to STARTTLS */
636 if (!smtps) { 639 if (!smtps) {
637 unsigned int code = smtpcode(); 640 unsigned long code = smtpcode();
638 if (code != 220) { 641 if (code != 220) {
639 SSL_free(myssl); 642 SSL_free(myssl);
640 if (!tls_required) return 0; 643 if (!tls_required) return 0;
@@ -731,7 +734,7 @@ static int tls_init(struct ip_mx *current_mx)
731 } 734 }
732 735
733 if (smtps) { 736 if (smtps) {
734 unsigned int code = smtpcode(); 737 unsigned long code = smtpcode();
735 if (code >= 500 && code < 600) quit("DTLS connected to "," but greeting failed"); 738 if (code >= 500 && code < 600) quit("DTLS connected to "," but greeting failed");
736 if (code >= 400 && code < 500) return -1; /* try next MX, see RFC-2821 */ 739 if (code >= 400 && code < 500) return -1; /* try next MX, see RFC-2821 */
737 if (code != 220) quit("ZTLS connected to "," but greeting failed"); 740 if (code != 220) quit("ZTLS connected to "," but greeting failed");
@@ -823,7 +826,7 @@ static void smtp(struct ip_mx *current_mx)
823#endif 826#endif
824 827
825#ifdef TLS 828#ifdef TLS
826 int tls = tls_init(current_mx); 829 int tls = tls_init(code, current_mx);
827 if (tls == -1) { 830 if (tls == -1) {
828 if (ssl) 831 if (ssl)
829 ssl_free(ssl); 832 ssl_free(ssl);
@@ -842,11 +845,14 @@ static void smtp(struct ip_mx *current_mx)
842 845
843 /* and if EHLO failed, use HELO */ 846 /* and if EHLO failed, use HELO */
844 } else { 847 } else {
848 /* copy EHLO reply for bounce message in case the connection has already been dropped */
849 if (!stralloc_copy(&smtptextdropped,&smtptext)) temp_nomem();
845 substdio_puts(&smtpto,"HELO "); 850 substdio_puts(&smtpto,"HELO ");
846 substdio_put(&smtpto,helohost.s,helohost.len); 851 substdio_put(&smtpto,helohost.s,helohost.len);
847 substdio_puts(&smtpto,"\r\n"); 852 substdio_puts(&smtpto,"\r\n");
848 substdio_flush(&smtpto); 853 substdio_flush(&smtpto);
849 code = smtpcode(); 854 code = smtpcode();
855 if (!stralloc_copys(&smtptextdropped,"")) temp_nomem();
850 if (code >= 500) quit("DConnected to "," but my name was rejected"); 856 if (code >= 500) quit("DConnected to "," but my name was rejected");
851 if (code != 250) quit("ZConnected to "," but my name was rejected"); 857 if (code != 250) quit("ZConnected to "," but my name was rejected");
852 } 858 }
@@ -911,12 +917,12 @@ static void smtp(struct ip_mx *current_mx)
911 if (code >= 500) { 917 if (code >= 500) {
912 out("h"); out(auth_status.s); outhost(); 918 out("h"); out(auth_status.s); outhost();
913 out(" does not like recipient.\n"); 919 out(" does not like recipient.\n");
914 outsmtptext(); zero(); 920 outsmtptext(&smtptext); zero();
915 } 921 }
916 else if (code >= 400) { 922 else if (code >= 400) {
917 out("s"); out(auth_status.s); outhost(); 923 out("s"); out(auth_status.s); outhost();
918 out(" does not like recipient.\n"); 924 out(" does not like recipient.\n");
919 outsmtptext(); zero(); 925 outsmtptext(&smtptext); zero();
920 } 926 }
921 else { 927 else {
922 /* 928 /*