--- /sys/man/8/smtp Thu Nov 19 21:33:21 2009 +++ /sys/man/8/smtp Thu Aug 22 00:46:20 2013 @@ -6,7 +6,7 @@ .ti -0.5i .B upas/smtp [ -.B -aAdfips +.B -aAdfiops ] [ .B -b .I busted-mx @@ -107,6 +107,11 @@ under .BR -a , authenticate even if we can't start TLS. +.TP +.B -o +under +.BR -s , +use TLS even if we don't know the remote system. .TP .B -p ping: just verify that the users named in the --- /sys/src/cmd/upas/smtp/mxdial.c Sat Feb 23 06:56:03 2008 +++ /sys/src/cmd/upas/smtp/mxdial.c Thu Aug 22 00:47:09 2013 @@ -4,28 +4,29 @@ enum { - Nmx= 16, + Nmx= 16, Maxstring= 256, + Maxipstr= 8*5, /* ipv6 */ }; typedef struct Mx Mx; struct Mx { - char host[256]; - char ip[24]; - int pref; + char host[Maxstring]; + char ip[Maxipstr]; + int pref; }; char *bustedmxs[Maxbustedmx]; Ndb *db; +static Mx mx[Nmx]; + +static int callmx(DS*, char*, char*); +static int compar(void*, void*); +static void expand_meta(DS *ds); static int mxlookup(DS*, char*); static int mxlookup1(DS*, char*); -static int compar(void*, void*); -static int callmx(DS*, char*, char*); -static void expand_meta(DS *ds); - -static Mx mx[Nmx]; int mxdial(char *addr, char *ddomain, char *gdomain) @@ -80,6 +81,12 @@ return n; } +static int +isloopback(char *ip) +{ + return strcmp(ip, "127.0.0.1") == 0 || strcmp(ip, "::1") == 0; +} + /* * take an address and return all the mx entries for it, * most preferred first @@ -88,6 +95,7 @@ callmx(DS *ds, char *dest, char *domain) { int fd, i, nmx; + char *ip; char addr[Maxstring]; /* get a list of mx entries */ @@ -102,14 +110,21 @@ return dial(dest, 0, 0, 0); } - /* refuse to honor loopback addresses given by dns */ - for(i = 0; i < nmx; i++) - if(strcmp(mx[i].ip, "127.0.0.1") == 0){ + /* refuse to honor loopback addresses given by dns. catch \n too. */ + for(i = 0; i < nmx; i++) { + ip = mx[i].ip; + if(strchr(ip, '\n') != nil){ + if(debug) + fprint(2, "mxlookup ip contains newline\n"); + werrstr("illegal: newline in mail server ip"); + return -1; + }else if(isloopback(ip)){ if(debug) fprint(2, "mxlookup returns loopback\n"); - werrstr("illegal: domain lists 127.0.0.1 as mail server"); + werrstr("illegal: domain lists %s as mail server", ip); return -1; } + } /* sort by preference */ if(nmx > 1) @@ -122,6 +137,11 @@ fprint(2, "mxdial skipping busted mx %s\n", mx[i].host); continue; + }else if(isloopback(mx[i].host)){ + if(debug) + fprint(2, "host ip %s is loopback\n", + mx[i].host); + continue; } snprint(addr, sizeof(addr), "%s/%s!%s!%s", ds->netdir, ds->proto, mx[i].host, ds->service); @@ -170,8 +190,9 @@ mxlookup1(DS *ds, char *domain) { int i, n, fd, nmx; - char buf[1024], dnsname[Maxstring]; + char buf[Maxdomain], dnsname[Maxstring]; char *fields[4]; + Mx *mxp; snprint(dnsname, sizeof dnsname, "%s/dns", ds->netdir); @@ -202,6 +223,7 @@ */ seek(fd, 0, 0); while(nmx < Nmx && (n = read(fd, buf, sizeof buf-1)) > 0){ + mxp = &mx[nmx]; buf[n] = 0; if(debug) fprint(2, "dns mx: %s\n", buf); @@ -212,8 +234,9 @@ if(strchr(domain, '.') == 0) strcpy(domain, fields[0]); - strncpy(mx[nmx].host, fields[3], sizeof(mx[n].host)-1); - mx[nmx].pref = atoi(fields[2]); + strncpy(mxp->host, fields[3], sizeof mxp->host - 1); + mxp->host[sizeof mxp->host - 1] = '\0'; + mxp->pref = atoi(fields[2]); nmx++; } if(debug) @@ -238,9 +261,10 @@ * look up all ip addresses */ for(i = 0; i < nmx; i++){ + mxp = &mx[i]; seek(fd, 0, 0); - snprint(buf, sizeof buf, "%s ip", mx[i].host); - mx[i].ip[0] = 0; + snprint(buf, sizeof buf, "%s ip", mxp->host); + mxp->ip[0] = 0; /* * don't hang indefinitely in the write to /net/dns. */ @@ -252,13 +276,14 @@ buf[n] = 0; if(getfields(buf, fields, 4, 1, " \t") < 3) goto no; - strncpy(mx[i].ip, fields[2], sizeof(mx[i].ip)-1); + strncpy(mxp->ip, fields[2], sizeof mxp->ip - 1); + mxp->ip[sizeof mxp->ip - 1] = '\0'; continue; no: /* remove mx[i] and go around again */ nmx--; - mx[i] = mx[nmx]; + *mxp = mx[nmx]; i--; } return nmx; --- /sys/src/cmd/upas/smtp/rmtdns.c Thu Aug 30 23:29:56 2007 +++ /sys/src/cmd/upas/smtp/rmtdns.c Thu Aug 22 00:00:44 2013 @@ -1,11 +1,12 @@ #include "common.h" +#include "smtp.h" #include int rmtdns(char *net, char *path) { int fd, n, nb, r; - char *domain, *cp, buf[1024]; + char *domain, *cp, buf[Maxdomain + 5]; if(net == 0 || path == 0) return 0; --- /sys/src/cmd/upas/smtp/smtp.c Fri Aug 27 20:02:56 2010 +++ /sys/src/cmd/upas/smtp/smtp.c Thu Aug 22 00:21:09 2013 @@ -44,9 +44,10 @@ int quitting; /* when error occurs in quit */ int tryauth; /* Try to authenticate, if supported */ int trysecure; /* Try to use TLS if the other side supports it */ +int okunksecure; /* okay to use TLS to unknown servers */ char *quitrv; /* deferred return value when in quit */ -char ddomain[1024]; /* domain name of destination machine */ +char ddomain[Maxdomain]; /* domain name of destination machine */ char *gdomain; /* domain name of gateway */ char *uneaten; /* first character after rfc822 headers */ char *farend; /* system we are trying to send to */ @@ -144,6 +145,9 @@ case 'i': insecure = 1; break; + case 'o': + okunksecure = 1; + break; case 'p': alarmscale = 10*1000; /* tens of seconds */ ping = 1; @@ -313,6 +317,37 @@ static char smtpthumbs[] = "/sys/lib/tls/smtp"; static char smtpexclthumbs[] = "/sys/lib/tls/smtp.exclude"; +static char * +ckthumbs(TLSconn *c) +{ + Thumbprint *goodcerts; + char *h, *err; + uchar hash[SHA1dlen]; + + err = nil; + goodcerts = initThumbprints(smtpthumbs, smtpexclthumbs); + if (goodcerts == nil) { + if (!okunksecure) + syslog(0, "smtp", "bad thumbprints in %s", smtpthumbs); + return Giveup; /* how to recover? TLS is started */ + } + + /* compute sha1 hash of remote's certificate, see if we know it */ + sha1(c->cert, c->certlen, hash, nil); + if (!okThumbprint(hash, goodcerts) && !okunksecure) { + h = malloc(2*sizeof hash + 1); + if (h != nil) { + enc16(h, 2*sizeof hash + 1, hash, sizeof hash); + syslog(0, "smtp", "remote cert. has bad thumbprint: " + "x509 sha1=%s server=%q", h, ddomain); + free(h); + } + err = Giveup; /* how to recover? TLS is started */ + } + freeThumbprints(goodcerts); + return err; +} + /* * exchange names with remote host, attempt to * enable encryption and optionally authenticate. @@ -322,10 +357,8 @@ dotls(char *me) { TLSconn *c; - Thumbprint *goodcerts; - char *h; + char *err; int fd; - uchar hash[SHA1dlen]; c = mallocz(sizeof(*c), 1); /* Note: not freed on success */ if (c == nil) @@ -340,32 +373,14 @@ syslog(0, "smtp", "tlsClient to %q: %r", ddomain); return Giveup; } - goodcerts = initThumbprints(smtpthumbs, smtpexclthumbs); - if (goodcerts == nil) { - free(c); - close(fd); - syslog(0, "smtp", "bad thumbprints in %s", smtpthumbs); - return Giveup; /* how to recover? TLS is started */ - } - /* compute sha1 hash of remote's certificate, see if we know it */ - sha1(c->cert, c->certlen, hash, nil); - if (!okThumbprint(hash, goodcerts)) { - /* TODO? if not excluded, add hash to thumb list */ + err = ckthumbs(c); + if (err && !okunksecure) { free(c); close(fd); - h = malloc(2*sizeof hash + 1); - if (h != nil) { - enc16(h, 2*sizeof hash + 1, hash, sizeof hash); - // fprint(2, "x509 sha1=%s", h); - syslog(0, "smtp", - "remote cert. has bad thumbprint: x509 sha1=%s server=%q", - h, ddomain); - free(h); - } - return Giveup; /* how to recover? TLS is started */ + return err; /* how to recover? TLS is started */ } - freeThumbprints(goodcerts); + Bterm(&bin); Bterm(&bout); --- /sys/src/cmd/upas/smtp/smtp.h Thu Aug 30 23:29:56 2007 +++ /sys/src/cmd/upas/smtp/smtp.h Thu Aug 22 00:00:56 2013 @@ -1,5 +1,6 @@ enum { Maxbustedmx = 100, + Maxdomain = 1024, }; typedef struct Node Node; @@ -46,22 +47,22 @@ extern int messageid; extern char *bustedmxs[Maxbustedmx]; -Node* anonymous(Node*); Node* address(Node*); +Node* anonymous(Node*); int badfieldname(Node*); Node* bang(Node*, Node*); -Node* colon(Node*, Node*); int cistrcmp(char*, char*); +Node* colon(Node*, Node*); +void dial_string_parse(char*, DS*); +void freefield(Field*); +void freenode(Node*); Node* link2(Node*, Node*); Node* link3(Node*, Node*, Node*); -void freenode(Node*); +int mxdial(char*, char*, char*); void newfield(Node*, int); -void freefield(Field*); +Node* whiten(Node*); +void yycleanup(void); void yyinit(char*, int); -int yyparse(void); int yylex(void); +int yyparse(void); String* yywhite(void); -Node* whiten(Node*); -void yycleanup(void); -int mxdial(char*, char*, char*); -void dial_string_parse(char*, DS*);