diff options
| -rw-r--r-- | qmail-remote.c | 51 |
1 files changed, 23 insertions, 28 deletions
diff --git a/qmail-remote.c b/qmail-remote.c index c353bec..edfdb60 100644 --- a/qmail-remote.c +++ b/qmail-remote.c | |||
| @@ -67,7 +67,6 @@ struct ip_address partner; | |||
| 67 | # define EHLO 1 | 67 | # define EHLO 1 |
| 68 | # define CLIENTCERT "control/clientcert.pem" | 68 | # define CLIENTCERT "control/clientcert.pem" |
| 69 | 69 | ||
| 70 | int tls_init(); | ||
| 71 | const char *ssl_err_str = 0; | 70 | const char *ssl_err_str = 0; |
| 72 | char **myargv; | 71 | char **myargv; |
| 73 | #endif | 72 | #endif |
| @@ -368,8 +367,6 @@ void blast() | |||
| 368 | } | 367 | } |
| 369 | 368 | ||
| 370 | #ifdef TLS | 369 | #ifdef TLS |
| 371 | char *partner_fqdn = 0; | ||
| 372 | |||
| 373 | # define TLS_QUIT quit(ssl ? "; connected to " : "; connecting to ", NULL) | 370 | # define TLS_QUIT quit(ssl ? "; connected to " : "; connecting to ", NULL) |
| 374 | void tls_quit(const char *s1, const char *s2) | 371 | void tls_quit(const char *s1, const char *s2) |
| 375 | { | 372 | { |
| @@ -377,12 +374,12 @@ void tls_quit(const char *s1, const char *s2) | |||
| 377 | } | 374 | } |
| 378 | # define tls_quit_error(s) tls_quit(s, ssl_error()) | 375 | # define tls_quit_error(s) tls_quit(s, ssl_error()) |
| 379 | 376 | ||
| 380 | int match_partner(const char *s, int len) | 377 | int match_mx_host(const char *mx_host, const char *s, int len) |
| 381 | { | 378 | { |
| 382 | if (!case_diffb(partner_fqdn, len, s) && !partner_fqdn[len]) return 1; | 379 | if (!case_diffb(mx_host, len, s) && !mx_host[len]) return 1; |
| 383 | /* we also match if the name is *.domainname */ | 380 | /* we also match if the name is *.domainname */ |
| 384 | if (*s == '*') { | 381 | if (*s == '*') { |
| 385 | const char *domain = partner_fqdn + str_chr(partner_fqdn, '.'); | 382 | const char *domain = mx_host + str_chr(mx_host, '.'); |
| 386 | if (!case_diffb(domain, --len, ++s) && !domain[len]) return 1; | 383 | if (!case_diffb(domain, --len, ++s) && !domain[len]) return 1; |
| 387 | } | 384 | } |
| 388 | return 0; | 385 | return 0; |
| @@ -396,25 +393,26 @@ int verify_cb(int preverify_ok, X509_STORE_CTX *ctx) { return 1; } | |||
| 396 | * @return 0 ...TLS failed, continue plaintext | 393 | * @return 0 ...TLS failed, continue plaintext |
| 397 | * @return -1 ...skip to next MX | 394 | * @return -1 ...skip to next MX |
| 398 | */ | 395 | */ |
| 399 | int tls_init() | 396 | static int tls_init(struct ip_mx *current_mx) |
| 400 | { | 397 | { |
| 401 | int i; | 398 | int i; |
| 402 | SSL *myssl; | 399 | SSL *myssl; |
| 403 | SSL_CTX *ctx; | 400 | SSL_CTX *ctx; |
| 404 | stralloc saciphers = {0}; | 401 | stralloc saciphers = {0}; |
| 405 | const char *ciphers, *servercert = 0; | 402 | const char *ciphers, *servercert = 0; |
| 403 | const char *mx_host = current_mx->fqdn; | ||
| 406 | 404 | ||
| 407 | if (partner_fqdn) { | 405 | if (mx_host) { |
| 408 | struct stat st; | 406 | struct stat st; |
| 409 | stralloc tmp = {0}; | 407 | stralloc tmp = {0}; |
| 410 | if (!stralloc_copys(&tmp, "control/tlshosts/") | 408 | if (!stralloc_copys(&tmp, "control/tlshosts/") |
| 411 | || !stralloc_catb(&tmp, partner_fqdn, str_len(partner_fqdn)) | 409 | || !stralloc_catb(&tmp, mx_host, str_len(mx_host)) |
| 412 | || !stralloc_catb(&tmp, ".pem", 5)) temp_nomem(); | 410 | || !stralloc_catb(&tmp, ".pem", 5)) temp_nomem(); |
| 413 | if (stat(tmp.s, &st) == 0) | 411 | if (stat(tmp.s, &st) == 0) |
| 414 | servercert = tmp.s; | 412 | servercert = tmp.s; |
| 415 | else { | 413 | else { |
| 416 | if (!stralloc_copys(&tmp, "control/notlshosts/") | 414 | if (!stralloc_copys(&tmp, "control/notlshosts/") |
| 417 | || !stralloc_catb(&tmp, partner_fqdn, str_len(partner_fqdn)+1)) | 415 | || !stralloc_catb(&tmp, mx_host, str_len(mx_host)+1)) |
| 418 | temp_nomem(); | 416 | temp_nomem(); |
| 419 | if ((stat("control/tlshosts/exhaustivelist", &st) == 0) || | 417 | if ((stat("control/tlshosts/exhaustivelist", &st) == 0) || |
| 420 | (stat(tmp.s, &st) == 0)) { | 418 | (stat(tmp.s, &st) == 0)) { |
| @@ -431,7 +429,7 @@ int tls_init() | |||
| 431 | int tls_required = (smtps || servercert != NULL); | 429 | int tls_required = (smtps || servercert != NULL); |
| 432 | stralloc tlsa_rr = { 0 }; | 430 | stralloc tlsa_rr = { 0 }; |
| 433 | 431 | ||
| 434 | if (partner_fqdn && !servercert) { | 432 | if (mx_host && !servercert && current_mx->validated) { |
| 435 | stralloc tlsa_label = { 0 }; | 433 | stralloc tlsa_label = { 0 }; |
| 436 | char port[FMT_ULONG]; | 434 | char port[FMT_ULONG]; |
| 437 | 435 | ||
| @@ -439,7 +437,7 @@ int tls_init() | |||
| 439 | port[fmt_ulong(port, smtp_port)] = 0; | 437 | port[fmt_ulong(port, smtp_port)] = 0; |
| 440 | if (!stralloc_cats(&tlsa_label, port)) temp_nomem(); | 438 | if (!stralloc_cats(&tlsa_label, port)) temp_nomem(); |
| 441 | if (!stralloc_cats(&tlsa_label, "._tcp.")) temp_nomem(); | 439 | if (!stralloc_cats(&tlsa_label, "._tcp.")) temp_nomem(); |
| 442 | if (!stralloc_cats(&tlsa_label, partner_fqdn)) temp_nomem(); | 440 | if (!stralloc_cats(&tlsa_label, mx_host)) temp_nomem(); |
| 443 | 441 | ||
| 444 | switch (dns_tlsa(&tlsa_rr, &tlsa_label)) { | 442 | switch (dns_tlsa(&tlsa_rr, &tlsa_label)) { |
| 445 | case DNS_MEM: temp_nomem(); | 443 | case DNS_MEM: temp_nomem(); |
| @@ -447,7 +445,7 @@ int tls_init() | |||
| 447 | case DNS_HARD: tlsa_rr.len = 0; // no record found | 445 | case DNS_HARD: tlsa_rr.len = 0; // no record found |
| 448 | } | 446 | } |
| 449 | 447 | ||
| 450 | if (tlsa_rr.len) | 448 | if (tlsa_rr.len && dns_last_query_validated()) |
| 451 | tls_required = 1; | 449 | tls_required = 1; |
| 452 | } | 450 | } |
| 453 | 451 | ||
| @@ -549,12 +547,12 @@ int tls_init() | |||
| 549 | } | 547 | } |
| 550 | 548 | ||
| 551 | /* set SNI hostname */ | 549 | /* set SNI hostname */ |
| 552 | if (partner_fqdn) | 550 | if (mx_host) |
| 553 | SSL_set_tlsext_host_name(myssl, partner_fqdn); | 551 | SSL_set_tlsext_host_name(myssl, mx_host); |
| 554 | 552 | ||
| 555 | /* DANE: enable + add records */ | 553 | /* DANE: enable + add records */ |
| 556 | if (tlsa_rr.len) { | 554 | if (tlsa_rr.len) { |
| 557 | if (SSL_dane_enable(myssl, partner_fqdn) <= 0) { | 555 | if (SSL_dane_enable(myssl, mx_host) <= 0) { |
| 558 | smtptext.len = 0; | 556 | smtptext.len = 0; |
| 559 | tls_quit_error("ZTLS error enabling dane"); | 557 | tls_quit_error("ZTLS error enabling dane"); |
| 560 | } | 558 | } |
| @@ -657,7 +655,7 @@ int tls_init() | |||
| 657 | peercert = SSL_get_peer_certificate(myssl); | 655 | peercert = SSL_get_peer_certificate(myssl); |
| 658 | if (!peercert) { | 656 | if (!peercert) { |
| 659 | out("ZTLS unable to verify server "); | 657 | out("ZTLS unable to verify server "); |
| 660 | tls_quit(partner_fqdn, "no certificate provided"); | 658 | tls_quit(mx_host, "no certificate provided"); |
| 661 | } | 659 | } |
| 662 | 660 | ||
| 663 | /* RFC 2595 section 2.4: find a matching name | 661 | /* RFC 2595 section 2.4: find a matching name |
| @@ -668,7 +666,7 @@ int tls_init() | |||
| 668 | { | 666 | { |
| 669 | const GENERAL_NAME *gn = sk_GENERAL_NAME_value(gens, i); | 667 | const GENERAL_NAME *gn = sk_GENERAL_NAME_value(gens, i); |
| 670 | if (gn->type == GEN_DNS) | 668 | if (gn->type == GEN_DNS) |
| 671 | if (match_partner(gn->d.ia5->data, gn->d.ia5->length)) break; | 669 | if (match_mx_host(mx_host, gn->d.ia5->data, gn->d.ia5->length)) break; |
| 672 | } | 670 | } |
| 673 | sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free); | 671 | sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free); |
| 674 | } | 672 | } |
| @@ -685,10 +683,10 @@ int tls_init() | |||
| 685 | } | 683 | } |
| 686 | if (peer.len <= 0) { | 684 | if (peer.len <= 0) { |
| 687 | out("ZTLS unable to verify server "); | 685 | out("ZTLS unable to verify server "); |
| 688 | tls_quit(partner_fqdn, "certificate contains no valid commonName"); | 686 | tls_quit(mx_host, "certificate contains no valid commonName"); |
| 689 | } | 687 | } |
| 690 | if (!match_partner(peer.s, peer.len)) { | 688 | if (!match_mx_host(mx_host, peer.s, peer.len)) { |
| 691 | out("ZTLS unable to verify server "); out(partner_fqdn); | 689 | out("ZTLS unable to verify server "); out(mx_host); |
| 692 | out(": received certificate for "); outsafe(&peer); TLS_QUIT; | 690 | out(": received certificate for "); outsafe(&peer); TLS_QUIT; |
| 693 | } | 691 | } |
| 694 | } | 692 | } |
| @@ -699,7 +697,7 @@ int tls_init() | |||
| 699 | else if (tlsa_rr.len) { | 697 | else if (tlsa_rr.len) { |
| 700 | if (!SSL_get_peer_certificate(myssl) || SSL_get_verify_result(myssl) != X509_V_OK) { | 698 | if (!SSL_get_peer_certificate(myssl) || SSL_get_verify_result(myssl) != X509_V_OK) { |
| 701 | out("lNo TLSA record matched: "); | 699 | out("lNo TLSA record matched: "); |
| 702 | out(partner_fqdn); | 700 | out(mx_host); |
| 703 | quit2("/", NULL, 0); | 701 | quit2("/", NULL, 0); |
| 704 | return -1; | 702 | return -1; |
| 705 | } | 703 | } |
| @@ -771,7 +769,7 @@ void mail_without_auth() | |||
| 771 | substdio_flush(&smtpto); | 769 | substdio_flush(&smtpto); |
| 772 | } | 770 | } |
| 773 | 771 | ||
| 774 | void smtp() | 772 | static void smtp(struct ip_mx *current_mx) |
| 775 | { | 773 | { |
| 776 | unsigned long code = 0; | 774 | unsigned long code = 0; |
| 777 | int flagbother; | 775 | int flagbother; |
| @@ -791,7 +789,7 @@ void smtp() | |||
| 791 | #endif | 789 | #endif |
| 792 | 790 | ||
| 793 | #ifdef TLS | 791 | #ifdef TLS |
| 794 | int tls = tls_init(); | 792 | int tls = tls_init(current_mx); |
| 795 | if (tls == -1) { | 793 | if (tls == -1) { |
| 796 | if (ssl) | 794 | if (ssl) |
| 797 | ssl_free(ssl); | 795 | ssl_free(ssl); |
| @@ -1194,10 +1192,7 @@ char **argv; | |||
| 1194 | if (timeoutconn(smtpfd,&ip.ix[i].ip,(unsigned int) smtp_port,timeoutconnect) == 0) { | 1192 | if (timeoutconn(smtpfd,&ip.ix[i].ip,(unsigned int) smtp_port,timeoutconnect) == 0) { |
| 1195 | tcpto_err(&ip.ix[i].ip,0); | 1193 | tcpto_err(&ip.ix[i].ip,0); |
| 1196 | partner = ip.ix[i].ip; | 1194 | partner = ip.ix[i].ip; |
| 1197 | #ifdef TLS | 1195 | smtp(&ip.ix[i]); /* only returns when the next MX is to be tried */ |
| 1198 | partner_fqdn = ip.ix[i].fqdn; | ||
| 1199 | #endif | ||
| 1200 | smtp(); /* only returns when the next MX is to be tried */ | ||
| 1201 | } | 1196 | } |
| 1202 | tcpto_err(&ip.ix[i].ip,errno == error_timeout || errno == error_refused); | 1197 | tcpto_err(&ip.ix[i].ip,errno == error_timeout || errno == error_refused); |
| 1203 | close(smtpfd); | 1198 | close(smtpfd); |
