summaryrefslogtreecommitdiffstats
path: root/qmail-remote.c
diff options
context:
space:
mode:
Diffstat (limited to 'qmail-remote.c')
-rw-r--r--qmail-remote.c444
1 files changed, 435 insertions, 9 deletions
diff --git a/qmail-remote.c b/qmail-remote.c
index 7d65473..dae884d 100644
--- a/qmail-remote.c
+++ b/qmail-remote.c
@@ -28,6 +28,7 @@
28#include "timeoutconn.h" 28#include "timeoutconn.h"
29#include "timeoutread.h" 29#include "timeoutread.h"
30#include "timeoutwrite.h" 30#include "timeoutwrite.h"
31#include "base64.h"
31 32
32#define HUGESMTPTEXT 5000 33#define HUGESMTPTEXT 5000
33 34
@@ -43,11 +44,27 @@ stralloc routes = {0};
43struct constmap maproutes; 44struct constmap maproutes;
44stralloc host = {0}; 45stralloc host = {0};
45stralloc sender = {0}; 46stralloc sender = {0};
47stralloc auth_smtp_user = {0};
48stralloc auth_smtp_pass = {0};
49stralloc auth_b64_user = {0};
50stralloc auth_b64_pass = {0};
51stralloc auth_status = {0};
46 52
47saa reciplist = {0}; 53saa reciplist = {0};
48 54
49struct ip_address partner; 55struct ip_address partner;
50 56
57#ifdef TLS
58# include <sys/stat.h>
59# include "tls.h"
60# include "ssl_timeoutio.h"
61# include <openssl/x509v3.h>
62# define EHLO 1
63
64int tls_init();
65const char *ssl_err_str = 0;
66#endif
67
51void out(s) char *s; { if (substdio_puts(subfdoutsmall,s) == -1) _exit(0); } 68void out(s) char *s; { if (substdio_puts(subfdoutsmall,s) == -1) _exit(0); }
52void zero() { if (substdio_put(subfdoutsmall,"\0",1) == -1) _exit(0); } 69void zero() { if (substdio_put(subfdoutsmall,"\0",1) == -1) _exit(0); }
53void zerodie() { zero(); substdio_flush(subfdoutsmall); _exit(0); } 70void zerodie() { zero(); substdio_flush(subfdoutsmall); _exit(0); }
@@ -85,6 +102,18 @@ void perm_ambigmx() { out("D\
85Sorry. Although I'm listed as a best-preference MX or A for that host,\n\ 102Sorry. Although I'm listed as a best-preference MX or A for that host,\n\
86it isn't in my control/locals file, so I don't treat it as local. (#5.4.6)\n"); 103it isn't in my control/locals file, so I don't treat it as local. (#5.4.6)\n");
87zerodie(); } 104zerodie(); }
105void auth_user_not_set() {
106 if(!stralloc_copys(&auth_status, \
107 "User and password not set, continuing without authentication.\n"))
108 temp_nomem();
109 if(!stralloc_0(&auth_status)) temp_nomem();
110}
111void no_supported_auth() {
112 if(!stralloc_copys(&auth_status, \
113 "No supported AUTH method found, continuing without authentication.\n"))
114 temp_nomem();
115 if(!stralloc_0(&auth_status)) temp_nomem();
116}
88 117
89void outhost() 118void outhost()
90{ 119{
@@ -99,6 +128,9 @@ void dropped() {
99 outhost(); 128 outhost();
100 out(" but connection died. "); 129 out(" but connection died. ");
101 if (flagcritical) out("Possible duplicate! "); 130 if (flagcritical) out("Possible duplicate! ");
131#ifdef TLS
132 if (ssl_err_str) { out(ssl_err_str); out(" "); }
133#endif
102 out("(#4.4.2)\n"); 134 out("(#4.4.2)\n");
103 zerodie(); 135 zerodie();
104} 136}
@@ -110,6 +142,12 @@ int timeout = 1200;
110int saferead(fd,buf,len) int fd; char *buf; int len; 142int saferead(fd,buf,len) int fd; char *buf; int len;
111{ 143{
112 int r; 144 int r;
145#ifdef TLS
146 if (ssl) {
147 r = ssl_timeoutread(timeout, smtpfd, smtpfd, ssl, buf, len);
148 if (r < 0) ssl_err_str = ssl_error_str();
149 } else
150#endif
113 r = timeoutread(timeout,smtpfd,buf,len); 151 r = timeoutread(timeout,smtpfd,buf,len);
114 if (r <= 0) dropped(); 152 if (r <= 0) dropped();
115 return r; 153 return r;
@@ -117,6 +155,12 @@ int saferead(fd,buf,len) int fd; char *buf; int len;
117int safewrite(fd,buf,len) int fd; char *buf; int len; 155int safewrite(fd,buf,len) int fd; char *buf; int len;
118{ 156{
119 int r; 157 int r;
158#ifdef TLS
159 if (ssl) {
160 r = ssl_timeoutwrite(timeout, smtpfd, smtpfd, ssl, buf, len);
161 if (r < 0) ssl_err_str = ssl_error_str();
162 } else
163#endif
120 r = timeoutwrite(timeout,smtpfd,buf,len); 164 r = timeoutwrite(timeout,smtpfd,buf,len);
121 if (r <= 0) dropped(); 165 if (r <= 0) dropped();
122 return r; 166 return r;
@@ -163,6 +207,65 @@ unsigned long smtpcode()
163 return code; 207 return code;
164} 208}
165 209
210#ifdef EHLO
211saa ehlokw = {0}; /* list of EHLO keywords and parameters */
212int maxehlokwlen = 0;
213
214unsigned long ehlo()
215{
216 stralloc *sa;
217 char *s, *e, *p;
218 unsigned long code;
219
220 if (ehlokw.len > maxehlokwlen) maxehlokwlen = ehlokw.len;
221 ehlokw.len = 0;
222
223# ifdef MXPS
224 if (type == 's') return 0;
225# endif
226
227 substdio_puts(&smtpto, "EHLO ");
228 substdio_put(&smtpto, helohost.s, helohost.len);
229 substdio_puts(&smtpto, "\r\n");
230 substdio_flush(&smtpto);
231
232 code = smtpcode();
233 if (code != 250) return code;
234
235 s = smtptext.s;
236 while (*s++ != '\n') ; /* skip the first line: contains the domain */
237
238 e = smtptext.s + smtptext.len - 6; /* 250-?\n */
239 while (s <= e)
240 {
241 int wasspace = 0;
242
243 if (!saa_readyplus(&ehlokw, 1)) temp_nomem();
244 sa = ehlokw.sa + ehlokw.len++;
245 if (ehlokw.len > maxehlokwlen) *sa = sauninit; else sa->len = 0;
246
247 /* smtptext is known to end in a '\n' */
248 for (p = (s += 4); ; ++p)
249 if (*p == '\n' || *p == ' ' || *p == '\t') {
250 if (!wasspace)
251 if (!stralloc_catb(sa, s, p - s) || !stralloc_0(sa)) temp_nomem();
252 if (*p == '\n') break;
253 wasspace = 1;
254 } else if (wasspace == 1) {
255 wasspace = 0;
256 s = p;
257 }
258 s = ++p;
259
260 /* keyword should consist of alpha-num and '-'
261 * broken AUTH might use '=' instead of space */
262 for (p = sa->s; *p; ++p) if (*p == '=') { *p = 0; break; }
263 }
264
265 return 250;
266}
267#endif
268
166void outsmtptext() 269void outsmtptext()
167{ 270{
168 int i; 271 int i;
@@ -179,6 +282,11 @@ void quit(prepend,append)
179char *prepend; 282char *prepend;
180char *append; 283char *append;
181{ 284{
285#ifdef TLS
286 /* shouldn't talk to the client unless in an appropriate state */
287 int state = ssl ? ssl->state : SSL_ST_BEFORE;
288 if (state & SSL_ST_OK || (!smtps && state & SSL_ST_BEFORE))
289#endif
182 substdio_putsflush(&smtpto,"QUIT\r\n"); 290 substdio_putsflush(&smtpto,"QUIT\r\n");
183 /* waiting for remote side is just too ridiculous */ 291 /* waiting for remote side is just too ridiculous */
184 out(prepend); 292 out(prepend);
@@ -186,6 +294,30 @@ char *append;
186 out(append); 294 out(append);
187 out(".\n"); 295 out(".\n");
188 outsmtptext(); 296 outsmtptext();
297
298#if defined(TLS) && defined(DEBUG)
299 if (ssl) {
300 X509 *peercert;
301
302 out("STARTTLS proto="); out(SSL_get_version(ssl));
303 out("; cipher="); out(SSL_get_cipher(ssl));
304
305 /* we want certificate details */
306 if (peercert = SSL_get_peer_certificate(ssl)) {
307 char *str;
308
309 str = X509_NAME_oneline(X509_get_subject_name(peercert), NULL, 0);
310 out("; subject="); out(str); OPENSSL_free(str);
311
312 str = X509_NAME_oneline(X509_get_issuer_name(peercert), NULL, 0);
313 out("; issuer="); out(str); OPENSSL_free(str);
314
315 X509_free(peercert);
316 }
317 out(";\n");
318 }
319#endif
320
189 zerodie(); 321 zerodie();
190} 322}
191 323
@@ -214,26 +346,297 @@ void blast()
214 substdio_flush(&smtpto); 346 substdio_flush(&smtpto);
215} 347}
216 348
349#ifdef TLS
350char *partner_fqdn = 0;
351
352# define TLS_QUIT quit(ssl ? "; connected to " : "; connecting to ", "")
353void tls_quit(const char *s1, const char *s2)
354{
355 out(s1); if (s2) { out(": "); out(s2); } TLS_QUIT;
356}
357# define tls_quit_error(s) tls_quit(s, ssl_error())
358
359int match_partner(const char *s, int len)
360{
361 if (!case_diffb(partner_fqdn, len, s) && !partner_fqdn[len]) return 1;
362 /* we also match if the name is *.domainname */
363 if (*s == '*') {
364 const char *domain = partner_fqdn + str_chr(partner_fqdn, '.');
365 if (!case_diffb(domain, --len, ++s) && !domain[len]) return 1;
366 }
367 return 0;
368}
369
370/* don't want to fail handshake if certificate can't be verified */
371int verify_cb(int preverify_ok, X509_STORE_CTX *ctx) { return 1; }
372
373int tls_init()
374{
375 int i;
376 SSL *myssl;
377 SSL_CTX *ctx;
378 stralloc saciphers = {0};
379 const char *ciphers, *servercert = 0;
380
381 if (partner_fqdn) {
382 struct stat st;
383 stralloc tmp = {0};
384 if (!stralloc_copys(&tmp, "control/tlshosts/")
385 || !stralloc_catb(&tmp, partner_fqdn, str_len(partner_fqdn))
386 || !stralloc_catb(&tmp, ".pem", 5)) temp_nomem();
387 if (stat(tmp.s, &st) == 0)
388 servercert = tmp.s;
389 else {
390 if (!stralloc_copys(&tmp, "control/notlshosts/")
391 || !stralloc_catb(&tmp, partner_fqdn, str_len(partner_fqdn)+1))
392 temp_nomem();
393 if ((stat("control/tlshosts/exhaustivelist", &st) == 0) ||
394 (stat(tmp.s, &st) == 0)) {
395 alloc_free(tmp.s);
396 return 0;
397 }
398 alloc_free(tmp.s);
399 }
400 }
401
402 if (!smtps) {
403 stralloc *sa = ehlokw.sa;
404 unsigned int len = ehlokw.len;
405 /* look for STARTTLS among EHLO keywords */
406 for ( ; len && case_diffs(sa->s, "STARTTLS"); ++sa, --len) ;
407 if (!len) {
408 if (!servercert) return 0;
409 out("ZNo TLS achieved while "); out(servercert);
410 out(" exists"); smtptext.len = 0; TLS_QUIT;
411 }
412 }
413
414 SSL_library_init();
415 ctx = SSL_CTX_new(SSLv23_client_method());
416 if (!ctx) {
417 if (!smtps && !servercert) return 0;
418 smtptext.len = 0;
419 tls_quit_error("ZTLS error initializing ctx");
420 }
421
422 if (servercert) {
423 if (!SSL_CTX_load_verify_locations(ctx, servercert, NULL)) {
424 SSL_CTX_free(ctx);
425 smtptext.len = 0;
426 out("ZTLS unable to load "); tls_quit_error(servercert);
427 }
428 /* set the callback here; SSL_set_verify didn't work before 0.9.6c */
429 SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_cb);
430 }
431
432 /* let the other side complain if it needs a cert and we don't have one */
433# define CLIENTCERT "control/clientcert.pem"
434 if (SSL_CTX_use_certificate_chain_file(ctx, CLIENTCERT))
435 SSL_CTX_use_RSAPrivateKey_file(ctx, CLIENTCERT, SSL_FILETYPE_PEM);
436# undef CLIENTCERT
437
438 myssl = SSL_new(ctx);
439 SSL_CTX_free(ctx);
440 if (!myssl) {
441 if (!smtps && !servercert) return 0;
442 smtptext.len = 0;
443 tls_quit_error("ZTLS error initializing ssl");
444 }
445
446 if (!smtps) substdio_putsflush(&smtpto, "STARTTLS\r\n");
447
448 /* while the server is preparing a responce, do something else */
449 if (control_readfile(&saciphers, "control/tlsclientciphers", 0) == -1)
450 { SSL_free(myssl); temp_control(); }
451 if (saciphers.len) {
452 for (i = 0; i < saciphers.len - 1; ++i)
453 if (!saciphers.s[i]) saciphers.s[i] = ':';
454 ciphers = saciphers.s;
455 }
456 else ciphers = "DEFAULT";
457 SSL_set_cipher_list(myssl, ciphers);
458 alloc_free(saciphers.s);
459
460 /* SSL_set_options(myssl, SSL_OP_NO_TLSv1); */
461 SSL_set_fd(myssl, smtpfd);
462
463 /* read the responce to STARTTLS */
464 if (!smtps) {
465 if (smtpcode() != 220) {
466 SSL_free(myssl);
467 if (!servercert) return 0;
468 out("ZSTARTTLS rejected while ");
469 out(servercert); out(" exists"); TLS_QUIT;
470 }
471 smtptext.len = 0;
472 }
473
474 ssl = myssl;
475 if (ssl_timeoutconn(timeout, smtpfd, smtpfd, ssl) <= 0)
476 tls_quit("ZTLS connect failed", ssl_error_str());
477
478 if (servercert) {
479 X509 *peercert;
480 STACK_OF(GENERAL_NAME) *gens;
481
482 int r = SSL_get_verify_result(ssl);
483 if (r != X509_V_OK) {
484 out("ZTLS unable to verify server with ");
485 tls_quit(servercert, X509_verify_cert_error_string(r));
486 }
487 alloc_free(servercert);
488
489 peercert = SSL_get_peer_certificate(ssl);
490 if (!peercert) {
491 out("ZTLS unable to verify server ");
492 tls_quit(partner_fqdn, "no certificate provided");
493 }
494
495 /* RFC 2595 section 2.4: find a matching name
496 * first find a match among alternative names */
497 gens = X509_get_ext_d2i(peercert, NID_subject_alt_name, 0, 0);
498 if (gens) {
499 for (i = 0, r = sk_GENERAL_NAME_num(gens); i < r; ++i)
500 {
501 const GENERAL_NAME *gn = sk_GENERAL_NAME_value(gens, i);
502 if (gn->type == GEN_DNS)
503 if (match_partner(gn->d.ia5->data, gn->d.ia5->length)) break;
504 }
505 sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
506 }
507
508 /* no alternative name matched, look up commonName */
509 if (!gens || i >= r) {
510 stralloc peer = {0};
511 X509_NAME *subj = X509_get_subject_name(peercert);
512 i = X509_NAME_get_index_by_NID(subj, NID_commonName, -1);
513 if (i >= 0) {
514 const ASN1_STRING *s = X509_NAME_get_entry(subj, i)->value;
515 if (s) { peer.len = s->length; peer.s = s->data; }
516 }
517 if (peer.len <= 0) {
518 out("ZTLS unable to verify server ");
519 tls_quit(partner_fqdn, "certificate contains no valid commonName");
520 }
521 if (!match_partner(peer.s, peer.len)) {
522 out("ZTLS unable to verify server "); out(partner_fqdn);
523 out(": received certificate for "); outsafe(&peer); TLS_QUIT;
524 }
525 }
526
527 X509_free(peercert);
528 }
529
530 if (smtps) if (smtpcode() != 220)
531 quit("ZTLS Connected to "," but greeting failed");
532
533 return 1;
534}
535#endif
536
217stralloc recip = {0}; 537stralloc recip = {0};
218 538
539void mail_without_auth()
540{
541 substdio_puts(&smtpto,"MAIL FROM:<");
542 substdio_put(&smtpto,sender.s,sender.len);
543 substdio_puts(&smtpto,">\r\n");
544 substdio_flush(&smtpto);
545}
546
219void smtp() 547void smtp()
220{ 548{
221 unsigned long code; 549 unsigned long code;
222 int flagbother; 550 int flagbother;
223 int i; 551 int i, j;
552
553#ifndef PORT_SMTP
554 /* the qmtpc patch uses smtp_port and undefines PORT_SMTP */
555# define port smtp_port
556#endif
557
558#ifdef TLS
559# ifdef MXPS
560 if (type == 'S') smtps = 1;
561 else if (type != 's')
562# endif
563 if (port == 465) smtps = 1;
564 if (!smtps)
565#endif
224 566
225 if (smtpcode() != 220) quit("ZConnected to "," but greeting failed"); 567 if (smtpcode() != 220) quit("ZConnected to "," but greeting failed");
226 568
569#ifdef EHLO
570# ifdef TLS
571 if (!smtps)
572# endif
573 code = ehlo();
574
575# ifdef TLS
576 if (tls_init())
577 /* RFC2487 says we should issue EHLO (even if we might not need
578 * extensions); at the same time, it does not prohibit a server
579 * to reject the EHLO and make us fallback to HELO */
580 code = ehlo();
581# endif
582
583 if (code == 250) {
584 /* add EHLO response checks here */
585
586 /* and if EHLO failed, use HELO */
587 } else {
588#endif
589
227 substdio_puts(&smtpto,"HELO "); 590 substdio_puts(&smtpto,"HELO ");
228 substdio_put(&smtpto,helohost.s,helohost.len); 591 substdio_put(&smtpto,helohost.s,helohost.len);
229 substdio_puts(&smtpto,"\r\n"); 592 substdio_puts(&smtpto,"\r\n");
230 substdio_flush(&smtpto); 593 substdio_flush(&smtpto);
231 if (smtpcode() != 250) quit("ZConnected to "," but my name was rejected"); 594 if (smtpcode() != 250) quit("ZConnected to "," but my name was rejected");
232 595
233 substdio_puts(&smtpto,"MAIL FROM:<"); 596#ifdef EHLO
234 substdio_put(&smtpto,sender.s,sender.len); 597 }
235 substdio_puts(&smtpto,">\r\n"); 598#endif
236 substdio_flush(&smtpto); 599 i = 0;
600 if (auth_smtp_user.len && auth_smtp_pass.len) {
601 while((i += str_chr(smtptext.s+i,'\n') + 1) &&
602 (i+8 < smtptext.len) &&
603 str_diffn(smtptext.s+i+4,"AUTH",4));
604 if (((i+9 < smtptext.len) &&
605 (str_diffn(smtptext.s+i+9," ",1) ||
606 str_diffn(smtptext.s+i+9,"=",1))) &&
607 ( i += str_chr(smtptext.s+i,'L') + 1 ) &&
608 str_diffn(smtptext.s+i+1,"OGIN",4)) {
609
610 if (b64encode(&auth_smtp_user,&auth_b64_user)) quit("ZConnected to "," but unable to base64encode user");
611 if (b64encode(&auth_smtp_pass,&auth_b64_pass)) quit("ZConnected to "," but unable to base64encode pass");
612
613 substdio_puts(&smtpto,"AUTH LOGIN\r\n");
614 substdio_flush(&smtpto);
615 if (smtpcode() != 334) quit("ZConnected to "," but authentication was rejected (AUTH LOGIN)");
616 substdio_put(&smtpto,auth_b64_user.s,auth_b64_user.len);
617 substdio_puts(&smtpto,"\r\n");
618 substdio_flush(&smtpto);
619 if (smtpcode() != 334) quit("ZConnected to "," but authentication was rejected (username)");
620 substdio_put(&smtpto,auth_b64_pass.s,auth_b64_pass.len);
621 substdio_puts(&smtpto,"\r\n");
622 substdio_flush(&smtpto);
623 if (smtpcode() != 235) quit("ZConnected to "," but authentication was rejected (password)");
624 substdio_puts(&smtpto,"MAIL FROM:<");
625 substdio_put(&smtpto,sender.s,sender.len);
626 substdio_puts(&smtpto,"> AUTH=<");
627 substdio_put(&smtpto,sender.s,sender.len);
628 substdio_puts(&smtpto,">\r\n");
629 substdio_flush(&smtpto);
630 if(!stralloc_copys(&auth_status, "Delivered with authenticated connection to \n")) temp_nomem();
631 if(!stralloc_0(&auth_status)) temp_nomem();
632 } else {
633 no_supported_auth();
634 mail_without_auth();
635 }
636 } else {
637 auth_user_not_set();
638 mail_without_auth();
639 }
237 code = smtpcode(); 640 code = smtpcode();
238 if (code >= 500) quit("DConnected to "," but sender was rejected"); 641 if (code >= 500) quit("DConnected to "," but sender was rejected");
239 if (code >= 400) quit("ZConnected to "," but sender was rejected"); 642 if (code >= 400) quit("ZConnected to "," but sender was rejected");
@@ -246,15 +649,22 @@ void smtp()
246 substdio_flush(&smtpto); 649 substdio_flush(&smtpto);
247 code = smtpcode(); 650 code = smtpcode();
248 if (code >= 500) { 651 if (code >= 500) {
249 out("h"); outhost(); out(" does not like recipient.\n"); 652 out("h"); out(auth_status.s); outhost();
653 out(" does not like recipient.\n");
250 outsmtptext(); zero(); 654 outsmtptext(); zero();
251 } 655 }
252 else if (code >= 400) { 656 else if (code >= 400) {
253 out("s"); outhost(); out(" does not like recipient.\n"); 657 out("s"); out(auth_status.s); outhost();
658 out(" does not like recipient.\n");
254 outsmtptext(); zero(); 659 outsmtptext(); zero();
255 } 660 }
256 else { 661 else {
257 out("r"); zero(); 662 /*
663 * James Raftery <james@now.ie>
664 * Log _real_ envelope recipient, post canonicalisation.
665 */
666 out("r"); out(auth_status.s);
667 out("<"); outsafe(&reciplist.sa[i]); out("> "); zero();
258 flagbother = 1; 668 flagbother = 1;
259 } 669 }
260 } 670 }
@@ -331,7 +741,7 @@ int argc;
331char **argv; 741char **argv;
332{ 742{
333 static ipalloc ip = {0}; 743 static ipalloc ip = {0};
334 int i; 744 int i,j;
335 unsigned long random; 745 unsigned long random;
336 char **recips; 746 char **recips;
337 unsigned long prefme; 747 unsigned long prefme;
@@ -347,6 +757,9 @@ char **argv;
347 757
348 if (!stralloc_copys(&host,argv[1])) temp_nomem(); 758 if (!stralloc_copys(&host,argv[1])) temp_nomem();
349 759
760 if (!stralloc_copys(&auth_smtp_user,"")) temp_nomem();
761 if (!stralloc_copys(&auth_smtp_pass,"")) temp_nomem();
762
350 relayhost = 0; 763 relayhost = 0;
351 for (i = 0;i <= host.len;++i) 764 for (i = 0;i <= host.len;++i)
352 if ((i == 0) || (i == host.len) || (host.s[i] == '.')) 765 if ((i == 0) || (i == host.len) || (host.s[i] == '.'))
@@ -355,6 +768,16 @@ char **argv;
355 if (relayhost && !*relayhost) relayhost = 0; 768 if (relayhost && !*relayhost) relayhost = 0;
356 769
357 if (relayhost) { 770 if (relayhost) {
771 i = str_chr(relayhost,' ');
772 if (relayhost[i]) {
773 j = str_chr(relayhost + i + 1,' ');
774 if (relayhost[j]) {
775 relayhost[i] = 0;
776 relayhost[i + j + 1] = 0;
777 if (!stralloc_copys(&auth_smtp_user,relayhost + i + 1)) temp_nomem();
778 if (!stralloc_copys(&auth_smtp_pass,relayhost + i + j + 2)) temp_nomem();
779 }
780 }
358 i = str_chr(relayhost,':'); 781 i = str_chr(relayhost,':');
359 if (relayhost[i]) { 782 if (relayhost[i]) {
360 scan_ulong(relayhost + i + 1,&port); 783 scan_ulong(relayhost + i + 1,&port);
@@ -417,6 +840,9 @@ char **argv;
417 if (timeoutconn(smtpfd,&ip.ix[i].ip,(unsigned int) port,timeoutconnect) == 0) { 840 if (timeoutconn(smtpfd,&ip.ix[i].ip,(unsigned int) port,timeoutconnect) == 0) {
418 tcpto_err(&ip.ix[i].ip,0); 841 tcpto_err(&ip.ix[i].ip,0);
419 partner = ip.ix[i].ip; 842 partner = ip.ix[i].ip;
843#ifdef TLS
844 partner_fqdn = ip.ix[i].fqdn;
845#endif
420 smtp(); /* does not return */ 846 smtp(); /* does not return */
421 } 847 }
422 tcpto_err(&ip.ix[i].ip,errno == error_timeout); 848 tcpto_err(&ip.ix[i].ip,errno == error_timeout);