summaryrefslogtreecommitdiffstats
path: root/qmail-remote.c
diff options
context:
space:
mode:
authormanuel <manuel@mausz.at>2015-07-04 19:28:30 +0200
committermanuel <manuel@mausz.at>2015-07-04 19:28:30 +0200
commit8f9afec35595f7c376876aa04dee08666614103c (patch)
tree155e0ad1c1b7b1a343a4f745ff0d44c4b6544783 /qmail-remote.c
parent4796b02569701548f2bfd3f2738d0fe437f3ae5b (diff)
downloadqmail-8f9afec35595f7c376876aa04dee08666614103c.tar.gz
qmail-8f9afec35595f7c376876aa04dee08666614103c.tar.bz2
qmail-8f9afec35595f7c376876aa04dee08666614103c.zip
add SMTP DANE support
Diffstat (limited to 'qmail-remote.c')
-rw-r--r--qmail-remote.c161
1 files changed, 110 insertions, 51 deletions
diff --git a/qmail-remote.c b/qmail-remote.c
index b5b93d5..4227718 100644
--- a/qmail-remote.c
+++ b/qmail-remote.c
@@ -62,16 +62,24 @@ struct ip_address partner;
62# include "tls.h" 62# include "tls.h"
63# include "ssl_timeoutio.h" 63# include "ssl_timeoutio.h"
64# include <openssl/x509v3.h> 64# include <openssl/x509v3.h>
65# include <validator/validator.h>
66# include <validator/val_dane.h>
67
65# define EHLO 1 68# define EHLO 1
69# define CLIENTCERT "control/clientcert.pem"
66 70
67int tls_init(); 71int tls_init();
68const char *ssl_err_str = 0; 72const char *ssl_err_str = 0;
69char **myargv; 73char **myargv;
70#endif 74val_context_t *dane_context = NULL;
75int dane_context_failed = 0;
76struct val_danestatus *dane_status = NULL;
77#endif
71 78
72void out(s) char *s; { if (substdio_puts(subfdoutsmall,s) == -1) _exit(0); } 79void out(s) char *s; { if (substdio_puts(subfdoutsmall,s) == -1) _exit(0); }
73void zero() { if (substdio_put(subfdoutsmall,"\0",1) == -1) _exit(0); } 80void zero() { if (substdio_put(subfdoutsmall,"\0",1) == -1) _exit(0); }
74void zerodie() { zero(); substdio_flush(subfdoutsmall); _exit(0); } 81void zeroflush() { zero(); substdio_flush(subfdoutsmall); }
82void zerodie() { zeroflush(); _exit(0); }
75void outsafe(sa) stralloc *sa; { int i; char ch; 83void outsafe(sa) stralloc *sa; { int i; char ch;
76for (i = 0;i < sa->len;++i) { 84for (i = 0;i < sa->len;++i) {
77ch = sa->s[i]; if (ch < 33) ch = '?'; if (ch > 126) ch = '?'; 85ch = sa->s[i]; if (ch < 33) ch = '?'; if (ch > 126) ch = '?';
@@ -213,7 +221,6 @@ unsigned long smtpcode()
213 return code; 221 return code;
214} 222}
215 223
216#ifdef EHLO
217saa ehlokw = {0}; /* list of EHLO keywords and parameters */ 224saa ehlokw = {0}; /* list of EHLO keywords and parameters */
218int maxehlokwlen = 0; 225int maxehlokwlen = 0;
219 226
@@ -270,7 +277,6 @@ unsigned long ehlo()
270 277
271 return 250; 278 return 250;
272} 279}
273#endif
274 280
275void outsmtptext() 281void outsmtptext()
276{ 282{
@@ -284,9 +290,7 @@ void outsmtptext()
284 } 290 }
285} 291}
286 292
287void quit(prepend,append) 293void smtp_quit()
288char *prepend;
289char *append;
290{ 294{
291#ifdef TLS 295#ifdef TLS
292 /* shouldn't talk to the client unless in an appropriate state */ 296 /* shouldn't talk to the client unless in an appropriate state */
@@ -295,9 +299,14 @@ char *append;
295#endif 299#endif
296 substdio_putsflush(&smtpto,"QUIT\r\n"); 300 substdio_putsflush(&smtpto,"QUIT\r\n");
297 /* waiting for remote side is just too ridiculous */ 301 /* waiting for remote side is just too ridiculous */
302}
303
304void quit2(char *prepend, char *append, int flagdie)
305{
306 smtp_quit();
298 out(prepend); 307 out(prepend);
299 outhost(); 308 outhost();
300 out(append); 309 if (append) out(append);
301 out(".\n"); 310 out(".\n");
302 outsmtptext(); 311 outsmtptext();
303 312
@@ -324,7 +333,11 @@ char *append;
324 } 333 }
325#endif 334#endif
326 335
327 zerodie(); 336 (flagdie) ? zerodie() : zeroflush();
337}
338
339void quit(char *prepend, char *append) {
340 quit2(prepend, append, 1);
328} 341}
329 342
330void blast() 343void blast()
@@ -355,7 +368,7 @@ void blast()
355#ifdef TLS 368#ifdef TLS
356char *partner_fqdn = 0; 369char *partner_fqdn = 0;
357 370
358# define TLS_QUIT quit(ssl ? "; connected to " : "; connecting to ", "") 371# define TLS_QUIT quit(ssl ? "; connected to " : "; connecting to ", NULL)
359void tls_quit(const char *s1, const char *s2) 372void tls_quit(const char *s1, const char *s2)
360{ 373{
361 out(s1); if (s2) { out(": "); out(s2); } TLS_QUIT; 374 out(s1); if (s2) { out(": "); out(s2); } TLS_QUIT;
@@ -376,6 +389,11 @@ int match_partner(const char *s, int len)
376/* don't want to fail handshake if certificate can't be verified */ 389/* don't want to fail handshake if certificate can't be verified */
377int verify_cb(int preverify_ok, X509_STORE_CTX *ctx) { return 1; } 390int verify_cb(int preverify_ok, X509_STORE_CTX *ctx) { return 1; }
378 391
392/*
393 * @return 1 ...on success
394 * @return 0 ...TLS failed, continue plaintext
395 * @return -1 ...skip to next MX
396 */
379int tls_init() 397int tls_init()
380{ 398{
381 int i; 399 int i;
@@ -402,26 +420,52 @@ int tls_init()
402 return 0; 420 return 0;
403 } 421 }
404 alloc_free(tmp.s); 422 alloc_free(tmp.s);
423
405 if (env_get("NOTLS")) return 0; 424 if (env_get("NOTLS")) return 0;
406 } 425 }
407 } 426 }
408 427
428 /* DANE starts here */
429 int dane_retval = VAL_DANE_INTERNAL_ERROR;
430 int tls_required = (smtps || servercert != NULL);
431
432 if (partner_fqdn && !servercert && !dane_context_failed) {
433 if (val_create_context(NULL, &dane_context) != VAL_NO_ERROR) {
434 dane_context_failed = 1;
435 out("lUnable to initialize libval context\n");
436 zeroflush();
437 }
438
439 /* DANE lookup TLSA records */
440 if (dane_context) {
441 if (dane_status != NULL)
442 val_free_dane(dane_status);
443 struct val_daneparams dane_params = {
444 .port = smtp_port,
445 .proto = DANE_PARAM_PROTO_TCP
446 };
447 dane_retval = val_getdaneinfo(dane_context, partner_fqdn, &dane_params, &dane_status);
448 if (dane_retval == VAL_DANE_NOERROR)
449 tls_required = 1;
450 }
451 }
452
409 if (!smtps) { 453 if (!smtps) {
410 stralloc *sa = ehlokw.sa; 454 stralloc *sa = ehlokw.sa;
411 unsigned int len = ehlokw.len; 455 unsigned int len = ehlokw.len;
412 /* look for STARTTLS among EHLO keywords */ 456 /* look for STARTTLS among EHLO keywords */
413 for ( ; len && case_diffs(sa->s, "STARTTLS"); ++sa, --len) ; 457 for ( ; len && case_diffs(sa->s, "STARTTLS"); ++sa, --len) ;
414 if (!len) { 458 if (!len) {
415 if (!servercert) return 0; 459 if (!tls_required) return 0;
416 out("ZNo TLS achieved while "); out(servercert); 460 out("ZNo TLS achieved while TLS is required by configuration");
417 out(" exists"); smtptext.len = 0; TLS_QUIT; 461 smtptext.len = 0; TLS_QUIT;
418 } 462 }
419 } 463 }
420 464
421 SSL_library_init(); 465 SSL_library_init();
422 ctx = SSL_CTX_new(SSLv23_client_method()); 466 ctx = SSL_CTX_new(SSLv23_client_method());
423 if (!ctx) { 467 if (!ctx) {
424 if (!smtps && !servercert) return 0; 468 if (!tls_required) return 0;
425 smtptext.len = 0; 469 smtptext.len = 0;
426 tls_quit_error("ZTLS error initializing ctx"); 470 tls_quit_error("ZTLS error initializing ctx");
427 } 471 }
@@ -437,20 +481,19 @@ int tls_init()
437 } 481 }
438 482
439 /* let the other side complain if it needs a cert and we don't have one */ 483 /* let the other side complain if it needs a cert and we don't have one */
440# define CLIENTCERT "control/clientcert.pem"
441 if (SSL_CTX_use_certificate_chain_file(ctx, CLIENTCERT)) 484 if (SSL_CTX_use_certificate_chain_file(ctx, CLIENTCERT))
442 SSL_CTX_use_RSAPrivateKey_file(ctx, CLIENTCERT, SSL_FILETYPE_PEM); 485 SSL_CTX_use_RSAPrivateKey_file(ctx, CLIENTCERT, SSL_FILETYPE_PEM);
443# undef CLIENTCERT
444 486
445 myssl = SSL_new(ctx); 487 myssl = SSL_new(ctx);
446 SSL_CTX_free(ctx); 488 SSL_CTX_free(ctx);
447 if (!myssl) { 489 if (!myssl) {
448 if (!smtps && !servercert) return 0; 490 if (!tls_required) return 0;
449 smtptext.len = 0; 491 smtptext.len = 0;
450 tls_quit_error("ZTLS error initializing ssl"); 492 tls_quit_error("ZTLS error initializing ssl");
451 } 493 }
452 494
453 if (!smtps) substdio_putsflush(&smtpto, "STARTTLS\r\n"); 495 if (!smtps)
496 substdio_putsflush(&smtpto, "STARTTLS\r\n");
454 497
455 /* while the server is preparing a responce, do something else */ 498 /* while the server is preparing a responce, do something else */
456 if (control_readfile(&saciphers, "control/tlsclientciphers", 0) == -1) 499 if (control_readfile(&saciphers, "control/tlsclientciphers", 0) == -1)
@@ -460,10 +503,15 @@ int tls_init()
460 if (!saciphers.s[i]) saciphers.s[i] = ':'; 503 if (!saciphers.s[i]) saciphers.s[i] = ':';
461 ciphers = saciphers.s; 504 ciphers = saciphers.s;
462 } 505 }
463 else ciphers = "DEFAULT"; 506 else
507 ciphers = "DEFAULT";
464 SSL_set_cipher_list(myssl, ciphers); 508 SSL_set_cipher_list(myssl, ciphers);
465 alloc_free(saciphers.s); 509 alloc_free(saciphers.s);
466 510
511 /* set SNI hostname */
512 if (partner_fqdn)
513 SSL_set_tlsext_host_name(myssl, partner_fqdn);
514
467 /* SSL_set_options(myssl, SSL_OP_NO_TLSv1); */ 515 /* SSL_set_options(myssl, SSL_OP_NO_TLSv1); */
468 SSL_set_fd(myssl, smtpfd); 516 SSL_set_fd(myssl, smtpfd);
469 517
@@ -471,31 +519,29 @@ int tls_init()
471 if (!smtps) { 519 if (!smtps) {
472 if (smtpcode() != 220) { 520 if (smtpcode() != 220) {
473 SSL_free(myssl); 521 SSL_free(myssl);
474 if (!servercert) return 0; 522 if (!tls_required) return 0;
475 out("ZSTARTTLS rejected while "); 523 out("ZSTARTTLS rejected while TLS is required by configuration");
476 out(servercert); out(" exists"); TLS_QUIT; 524 TLS_QUIT;
477 } 525 }
478 smtptext.len = 0; 526 smtptext.len = 0;
479 } 527 }
480 528
481 ssl = myssl; 529 ssl = myssl;
482 if (ssl_timeoutconn(timeout, smtpfd, smtpfd, ssl) <= 0) { 530 if (ssl_timeoutconn(timeout, smtpfd, smtpfd, ssl) <= 0) {
483 if (servercert) 531 if (tls_required)
484 tls_quit("ZTLS connect failed", ssl_error_str()); 532 tls_quit("ZTLS connect failed", ssl_error_str());
485 else { 533 else {
486 /* shouldn't talk to the client unless in an appropriate state */ 534 smtp_quit();
487 int state = ssl ? ssl->state : SSL_ST_BEFORE;
488 if (state & SSL_ST_OK || (!smtps && state & SSL_ST_BEFORE))
489 substdio_putsflush(&smtpto,"QUIT\r\n");
490 535
491 out("lTLS connect failed: "); 536 out("lTLS connect failed: ");
492 out(ssl_error_str()); 537 out(ssl_error_str());
493 out("; retrying without TLS\n"); 538 out("; retrying without TLS\n");
494 zero(); 539 zeroflush();
495 substdio_flush(subfdoutsmall);
496 540
497 env_put("NOTLS=1"); 541 env_put("NOTLS=1");
498 execvp(*myargv, myargv); 542 execvp(*myargv, myargv); //FIXME this will cause all mx to be retried
543 out("DUnable to execute myself\n");
544 zerodie();
499 } 545 }
500 } 546 }
501 547
@@ -550,6 +596,17 @@ int tls_init()
550 596
551 X509_free(peercert); 597 X509_free(peercert);
552 } 598 }
599 /* DANE verify tls connection */
600 else if (dane_retval == VAL_DANE_NOERROR) {
601 int do_certcheck = 0; // ignored. DANE SMTP doesn't do any PKIX checks
602 dane_retval = val_dane_check(dane_context, ssl, dane_status, &do_certcheck);
603 if (dane_retval != VAL_DANE_NOERROR) {
604 out("lNo TLSA record matched: ");
605 out(partner_fqdn);
606 quit2("/", NULL, 0);
607 return -1;
608 }
609 }
553 610
554 if (smtps) if (smtpcode() != 220) 611 if (smtps) if (smtpcode() != 220)
555 quit("ZTLS Connected to "," but greeting failed"); 612 quit("ZTLS Connected to "," but greeting failed");
@@ -587,44 +644,46 @@ void smtp()
587 if (port == 465) smtps = 1; 644 if (port == 465) smtps = 1;
588 if (!smtps) 645 if (!smtps)
589#endif 646#endif
590 647
591 code = smtpcode(); 648 code = smtpcode();
592 if (code >= 500 && code < 600) quit("DConnected to "," but greeting failed"); 649 if (code >= 500 && code < 600) quit("DConnected to "," but greeting failed");
593 if (code >= 400 && code < 500) return; /* try next MX, see RFC-2821 */ 650 if (code >= 400 && code < 500) return; /* try next MX, see RFC-2821 */
594 if (code != 220) quit("ZConnected to "," but greeting failed"); 651 if (code != 220) quit("ZConnected to "," but greeting failed");
595 652
596#ifdef EHLO 653#ifdef TLS
597# ifdef TLS
598 if (!smtps) 654 if (!smtps)
599# endif 655#endif
600 code = ehlo(); 656 code = ehlo();
601 657
602# ifdef TLS 658#ifdef TLS
603 if (tls_init()) 659 int tls = tls_init();
660 if (tls == -1) {
661 if (ssl)
662 ssl_free(ssl);
663 ssl = NULL;
664 return; /* try next MX */
665 }
666 else if (tls)
604 /* RFC2487 says we should issue EHLO (even if we might not need 667 /* RFC2487 says we should issue EHLO (even if we might not need
605 * extensions); at the same time, it does not prohibit a server 668 * extensions); at the same time, it does not prohibit a server
606 * to reject the EHLO and make us fallback to HELO */ 669 * to reject the EHLO and make us fallback to HELO */
607 code = ehlo(); 670 code = ehlo();
608# endif 671#endif
609 672
610 if (code == 250) { 673 if (code == 250) {
611 /* add EHLO response checks here */ 674 /* add EHLO response checks here */
612 675
613 /* and if EHLO failed, use HELO */ 676 /* and if EHLO failed, use HELO */
614 } else { 677 } else {
615#endif 678 substdio_puts(&smtpto,"HELO ");
616 679 substdio_put(&smtpto,helohost.s,helohost.len);
617 substdio_puts(&smtpto,"HELO "); 680 substdio_puts(&smtpto,"\r\n");
618 substdio_put(&smtpto,helohost.s,helohost.len); 681 substdio_flush(&smtpto);
619 substdio_puts(&smtpto,"\r\n"); 682 code = smtpcode();
620 substdio_flush(&smtpto); 683 if (code >= 500) quit("DConnected to "," but my name was rejected");
621 code = smtpcode(); 684 if (code != 250) quit("ZConnected to "," but my name was rejected");
622 if (code >= 500) quit("DConnected to "," but my name was rejected");
623 if (code != 250) quit("ZConnected to "," but my name was rejected");
624
625#ifdef EHLO
626 } 685 }
627#endif 686
628 i = 0; 687 i = 0;
629 if (auth_smtp_user.len && auth_smtp_pass.len) { 688 if (auth_smtp_user.len && auth_smtp_pass.len) {
630 while((i += str_chr(smtptext.s+i,'\n') + 1) && 689 while((i += str_chr(smtptext.s+i,'\n') + 1) &&