smtp: add SMTPS support (-t)

This commit is contained in:
cinap_lenrek 2013-06-12 23:39:41 +02:00
parent 0dbde06bc7
commit 646eb150e1
2 changed files with 41 additions and 19 deletions

View file

@ -6,7 +6,7 @@ smtp, smtpd \- mail transport
.ti -0.5i .ti -0.5i
.B upas/smtp .B upas/smtp
[ [
.B -aAdfips .B -aAdfipst
] [ ] [
.B -b .B -b
.I busted-mx .I busted-mx
@ -119,6 +119,9 @@ don't send any mail.
if the server supports the ESMTP extension to use TLS encryption, turn it on for if the server supports the ESMTP extension to use TLS encryption, turn it on for
this session. See RFC3207 for details. this session. See RFC3207 for details.
.TP .TP
.B -t
preemtively establish TLS connection before SMTP handshake (SMTPS).
.TP
.B -u .B -u
specify a user name to be used in authentication. The default name is specify a user name to be used in authentication. The default name is
the current login id. the current login id.

View file

@ -6,6 +6,7 @@
#include <auth.h> #include <auth.h>
static char* connect(char*); static char* connect(char*);
static char* wraptls(void);
static char* dotls(char*); static char* dotls(char*);
static char* doauth(char*); static char* doauth(char*);
@ -26,7 +27,7 @@ int printheader(void);
void putcrnl(char*, int); void putcrnl(char*, int);
void quit(char*); void quit(char*);
char* rcptto(char*); char* rcptto(char*);
char *rewritezone(char *); char* rewritezone(char *);
#define Retry "Retry, Temporary Failure" #define Retry "Retry, Temporary Failure"
#define Giveup "Permanent Failure" #define Giveup "Permanent Failure"
@ -151,6 +152,9 @@ main(int argc, char **argv)
case 's': case 's':
trysecure = 1; trysecure = 1;
break; break;
case 't':
trysecure = 2;
break;
case 'u': case 'u':
user = EARGF(usage()); user = EARGF(usage());
break; break;
@ -217,7 +221,9 @@ main(int argc, char **argv)
/* 10 minutes to get through the initial handshake */ /* 10 minutes to get through the initial handshake */
atnotify(timeout, 1); atnotify(timeout, 1);
alarm(10*alarmscale); alarm(10*alarmscale);
if((rv = hello(hellodomain, 0)) != 0) if(trysecure > 1 && (rv = wraptls()) != nil)
goto error;
if((rv = hello(hellodomain, trysecure > 1)) != 0)
goto error; goto error;
alarm(10*alarmscale); alarm(10*alarmscale);
if((rv = mailfrom(s_to_c(from))) != 0) if((rv = mailfrom(s_to_c(from))) != 0)
@ -313,13 +319,8 @@ connect(char* net)
static char smtpthumbs[] = "/sys/lib/tls/smtp"; static char smtpthumbs[] = "/sys/lib/tls/smtp";
static char smtpexclthumbs[] = "/sys/lib/tls/smtp.exclude"; static char smtpexclthumbs[] = "/sys/lib/tls/smtp.exclude";
/*
* exchange names with remote host, attempt to
* enable encryption and optionally authenticate.
* not fatal if we can't.
*/
static char * static char *
dotls(char *me) wraptls(void)
{ {
TLSconn *c; TLSconn *c;
Thumbprint *goodcerts; Thumbprint *goodcerts;
@ -327,33 +328,27 @@ dotls(char *me)
int fd; int fd;
uchar hash[SHA1dlen]; uchar hash[SHA1dlen];
c = mallocz(sizeof(*c), 1); /* Note: not freed on success */ c = mallocz(sizeof(*c), 1);
if (c == nil) if (c == nil)
return Giveup; return Giveup;
dBprint("STARTTLS\r\n");
if (getreply() != 2)
return Giveup;
fd = tlsClient(Bfildes(&bout), c); fd = tlsClient(Bfildes(&bout), c);
if (fd < 0) { if (fd < 0) {
syslog(0, "smtp", "tlsClient to %q: %r", ddomain); syslog(0, "smtp", "tlsClient to %q: %r", ddomain);
free(c);
return Giveup; return Giveup;
} }
goodcerts = initThumbprints(smtpthumbs, smtpexclthumbs); goodcerts = initThumbprints(smtpthumbs, smtpexclthumbs);
if (goodcerts == nil) { if (goodcerts == nil) {
free(c);
close(fd);
syslog(0, "smtp", "bad thumbprints in %s", smtpthumbs); syslog(0, "smtp", "bad thumbprints in %s", smtpthumbs);
close(fd);
free(c);
return Giveup; /* how to recover? TLS is started */ return Giveup; /* how to recover? TLS is started */
} }
/* compute sha1 hash of remote's certificate, see if we know it */ /* compute sha1 hash of remote's certificate, see if we know it */
sha1(c->cert, c->certlen, hash, nil); sha1(c->cert, c->certlen, hash, nil);
if (!okThumbprint(hash, goodcerts)) { if (!okThumbprint(hash, goodcerts)) {
/* TODO? if not excluded, add hash to thumb list */ /* TODO? if not excluded, add hash to thumb list */
free(c);
close(fd);
h = malloc(2*sizeof hash + 1); h = malloc(2*sizeof hash + 1);
if (h != nil) { if (h != nil) {
enc16(h, 2*sizeof hash + 1, hash, sizeof hash); enc16(h, 2*sizeof hash + 1, hash, sizeof hash);
@ -363,9 +358,12 @@ dotls(char *me)
h, ddomain); h, ddomain);
free(h); free(h);
} }
close(fd);
free(c);
return Giveup; /* how to recover? TLS is started */ return Giveup; /* how to recover? TLS is started */
} }
freeThumbprints(goodcerts); freeThumbprints(goodcerts);
free(c);
Bterm(&bin); Bterm(&bin);
Bterm(&bout); Bterm(&bout);
@ -378,6 +376,27 @@ dotls(char *me)
Binit(&bout, fd, OWRITE); Binit(&bout, fd, OWRITE);
syslog(0, "smtp", "started TLS to %q", ddomain); syslog(0, "smtp", "started TLS to %q", ddomain);
return nil;
}
/*
* exchange names with remote host, attempt to
* enable encryption and optionally authenticate.
* not fatal if we can't.
*/
static char *
dotls(char *me)
{
char *err;
dBprint("STARTTLS\r\n");
if (getreply() != 2)
return Giveup;
err = wraptls();
if (err != nil)
return err;
return(hello(me, 1)); return(hello(me, 1));
} }