Browse Source

Plan 9 from Bell Labs 2004-03-15

David du Colombier 20 years ago
parent
commit
5a727ca299
4 changed files with 197 additions and 12 deletions
  1. 2 2
      dist/replica/plan9.db
  2. 2 0
      dist/replica/plan9.log
  3. 154 7
      sys/src/cmd/upas/smtp/smtpd.c
  4. 39 3
      sys/src/cmd/upas/vf/vf.c

+ 2 - 2
dist/replica/plan9.db

@@ -10920,7 +10920,7 @@ sys/src/cmd/upas/smtp/rfc822.y - 664 sys sys 1064589606 13417
 sys/src/cmd/upas/smtp/rmtdns.c - 664 sys sys 1015013150 1069
 sys/src/cmd/upas/smtp/smtp.c - 664 sys sys 1072561144 18914
 sys/src/cmd/upas/smtp/smtp.h - 664 sys sys 1064589597 1084
-sys/src/cmd/upas/smtp/smtpd.c - 664 sys sys 1072561144 24496
+sys/src/cmd/upas/smtp/smtpd.c - 664 sys sys 1079323038 27764
 sys/src/cmd/upas/smtp/smtpd.h - 664 sys sys 1067722781 1111
 sys/src/cmd/upas/smtp/smtpd.y - 664 sys sys 1061836986 6949
 sys/src/cmd/upas/smtp/spam.c - 664 sys sys 1067722785 9661
@@ -10929,7 +10929,7 @@ sys/src/cmd/upas/unesc/mkfile - 664 sys sys 1075080255 164
 sys/src/cmd/upas/unesc/unesc.c - 664 sys sys 1075080255 789
 sys/src/cmd/upas/vf - 20000000775 sys sys 1015096796 0
 sys/src/cmd/upas/vf/mkfile - 664 sys sys 1064393881 241
-sys/src/cmd/upas/vf/vf.c - 664 sys sys 1064589607 16851
+sys/src/cmd/upas/vf/vf.c - 664 sys sys 1079323044 17391
 sys/src/cmd/usb - 20000000775 sys sys 1017802022 0
 sys/src/cmd/usb/audio - 20000000775 sys sys 1017802021 0
 sys/src/cmd/usb/audio/audioclass.h - 664 sys sys 1017802021 5463

+ 2 - 0
dist/replica/plan9.log

@@ -14646,3 +14646,5 @@
 1079103607 3 c sys/src/cmd/acme/util.c - 664 sys sys 1079102916 7412
 1079105409 0 c lib/face/48x48x8/.dict - 664 sys sys 1079103826 2117
 1079116211 0 c sys/src/cmd/acme/text.c - 664 sys sys 1079115968 27284
+1079323248 0 c sys/src/cmd/upas/smtp/smtpd.c - 664 sys sys 1079323038 27764
+1079323248 1 c sys/src/cmd/upas/vf/vf.c - 664 sys sys 1079323044 17391

+ 154 - 7
sys/src/cmd/upas/smtp/smtpd.c

@@ -1,7 +1,9 @@
 #include "common.h"
 #include "smtpd.h"
 #include "smtp.h"
+#include <ctype.h>
 #include <ip.h>
+#include <ndb.h>
 #include <mp.h>
 #include <libsec.h>
 #include <auth.h>
@@ -340,10 +342,127 @@ sender(String *path)
 	reply("250 sender is %s\r\n", s_to_c(path));
 }
 
+enum { Rcpt, Domain, Ntoks };
+
+typedef struct Sender Sender;
+struct Sender {
+	Sender	*next;
+	char	*rcpt;
+	char	*domain;
+};
+static Sender *sendlist, *sendlast;
+static uchar rsysip[IPaddrlen];
+
+static int
+rdsenders(void)
+{
+	int lnlen, nf, ok = 1;
+	char *line, *senderfile;
+	char *toks[Ntoks];
+	Biobuf *sf;
+	Sender *snd;
+	static int beenhere = 0;
+
+	if (beenhere)
+		return 1;
+	beenhere = 1;
+
+	fmtinstall('I', eipfmt);
+	parseip(rsysip, nci->rsys);
+
+	/*
+	 * we're sticking with a system-wide sender list because
+	 * per-user lists would require fully resolving recipient
+	 * addresses to determine which users they correspond to
+	 * (barring syntactic conventions).
+	 */
+	senderfile = smprint("%s/senders", UPASLIB);
+	sf = Bopen(senderfile, OREAD);
+	free(senderfile);
+	if (sf == nil)
+		return 1;
+	while ((line = Brdline(sf, '\n')) != nil) {
+		if (line[0] == '#' || line[0] == '\n')
+			continue;
+		lnlen = Blinelen(sf);
+		line[lnlen-1] = '\0';		/* clobber newline */
+		nf = tokenize(line, toks, nelem(toks));
+		if (nf != nelem(toks))
+			continue;		/* malformed line */
+
+		snd = malloc(sizeof *snd);
+		if (snd == nil)
+			sysfatal("out of memory: %r");
+		memset(snd, 0, sizeof *snd);
+		snd->next = nil;
+
+		if (sendlast == nil)
+			sendlist = snd;
+		else
+			sendlast->next = snd;
+		sendlast = snd;
+		snd->rcpt = strdup(toks[Rcpt]);
+		snd->domain = strdup(toks[Domain]);
+	}
+	Bterm(sf);
+	return ok;
+}
+
+/*
+ * read (recipient, sender's DNS) pairs from /mail/lib/senders.
+ * Only allow mail to recipient from any of sender's IPs.
+ * A recipient not mentioned in the file is always permitted.
+ */
+static int
+senderok(char *rcpt)
+{
+	int mentioned = 0, matched = 0;
+	uchar dnsip[IPaddrlen];
+	Sender *snd;
+	Ndbtuple *nt, *next, *first;
+
+	/* internal mail is exempt from this checking */
+	if (strcmp(nci->root, "/net") == 0)
+		return 1;
+	rdsenders();
+	for (snd = sendlist; snd != nil; snd = snd->next) {
+		if (strcmp(rcpt, snd->rcpt) != 0)
+			continue;
+		/*
+		 * see if this domain's ips match nci->rsys.
+		 * if not, perhaps a later entry's domain will.
+		 */
+		mentioned = 1;
+		if (parseip(dnsip, snd->domain) != -1 &&
+		    memcmp(rsysip, dnsip, IPaddrlen) == 0)
+			return 1;
+		/*
+		 * NB: nt->line links form a circular list(!).
+		 * we need to make one complete pass over it to free it all.
+		 */
+		first = nt = dnsquery(nci->root, snd->domain, "ip");
+		if (first == nil)
+			continue;
+		do {
+			if (strcmp(nt->attr, "ip") == 0 &&
+			    parseip(dnsip, nt->val) != -1 &&
+			    memcmp(rsysip, dnsip, IPaddrlen) == 0)
+				matched = 1;
+			next = nt->line;
+			free(nt);
+			nt = next;
+		} while (nt != first);
+	}
+	if (matched)
+		return 1;
+	else
+		return !mentioned;
+}
+
 void
 receiver(String *path)
 {
-	char *sender;
+	char *sender, *rcpt;
 
 	if(rejectcheck())
 		return;
@@ -359,11 +478,19 @@ receiver(String *path)
 
 	if(!recipok(s_to_c(path))){
 		rejectcount++;
-		syslog(0, "smtpd", "Disallowed %s (%s/%s) to %s",
+		syslog(0, "smtpd", "Disallowed %s (%s/%s) to blocked name %s",
 				sender, him, nci->rsys, s_to_c(path));
 		reply("550 %s ... user unknown\r\n", s_to_c(path));
 		return;
 	}
+	rcpt = s_to_c(path);
+	if (!senderok(rcpt)) {
+		rejectcount++;
+		syslog(0, "smtpd", "Disallowed sending IP of %s (%s/%s) to %s",
+				sender, him, nci->rsys, rcpt);
+		reply("550 %s ... sending system not allowed\r\n", rcpt);
+		return;
+	}
 
 	logged = 0;
 		/* forwarding() can modify 'path' on loopback request */
@@ -804,7 +931,7 @@ pipemsg(int *byteswritten)
 		nbytes += forgedheaderwarnings();
 
 	/*
-	 *  add  an orginator and/or destination if either is missing
+	 *  add an orginator and/or destination if either is missing
 	 */
 	if(originator == 0){
 		if(senders.last == nil)
@@ -879,6 +1006,20 @@ pipemsg(int *byteswritten)
 	return status;
 }
 
+char*
+firstline(char *x)
+{
+	static char buf[128];
+	char *p;
+
+	strncpy(buf, x, sizeof(buf));
+	buf[sizeof(buf)-1] = 0;
+	p = strchr(buf, '\n');
+	if(p)
+		*p = 0;
+	return buf;
+}
+
 void
 data(void)
 {
@@ -940,10 +1081,12 @@ data(void)
 		int code;
 
 		if(strstr(s_to_c(err), "mail refused")){
-			syslog(0, "smtpd", "++[%s/%s] %s refused %d", him, nci->rsys, s_to_c(cmd), status);
+			syslog(0, "smtpd", "++[%s/%s] %s %s refused: %s", him, nci->rsys,
+				s_to_c(senders.first->p), s_to_c(cmd), firstline(s_to_c(err)));
 			code = 554;
 		} else {
-			syslog(0, "smtpd", "++[%s/%s] %s returned %d", him, nci->rsys, s_to_c(cmd), status);
+			syslog(0, "smtpd", "++[%s/%s] %s %s returned %s", him, nci->rsys,
+				s_to_c(senders.first->p), s_to_c(cmd), firstline(s_to_c(err)));
 			code = 450;
 		}
 		for(cp = s_to_c(err); ep = strchr(cp, '\n'); cp = ep){
@@ -1058,8 +1201,12 @@ starttls(void)
 	if (fd < 0) {
 		free(cert);
 		free(conn);
-if(debug)fprint(2, "tlsServer failed: %r\n");
-		return;	/*  XXX  We should really force the client to hang up here.  */
+		syslog(0, "smtpd", "TLS start-up failed with %s", him);
+
+		/* force the client to hang up */
+		close(Bfildes(&bin));		/* probably fd 0 */
+		close(1);
+		exits("tls failed");
 	}
 	Bterm(&bin);
 	Binit(&bin, fd, OREAD);

+ 39 - 3
sys/src/cmd/upas/vf/vf.c

@@ -28,6 +28,7 @@ static Part*	problemchild(Part *p);
 static void	readheader(Part *p);
 static Hline*	readhl(void);
 static void	readmtypes(void);
+static void	save(Part *p);
 static void	setfilename(Part *p, char *name);
 static char*	skiptosemi(char *p);
 static char*	skipwhite(char *p);
@@ -108,6 +109,7 @@ struct Mtype {
 Mtype *mtypes;
 
 int justreject;
+char *savefile;
 
 /*
  *  this is a filter that changes mime types and names of
@@ -121,6 +123,11 @@ main(int argc, char **argv)
 	case 'r':
 		justreject = 1;
 		break;
+	case 's':
+		savefile = ARGF();
+		if(savefile == nil)
+			exits("usage");
+		break;
 	}ARGEND;
 
 	Binit(&in, 0, OREAD);
@@ -188,12 +195,14 @@ part(Part *pp)
 			 */
 			if(p->badtype || p->badfile){
 				if(p->badfile == 2){
+					if(savefile != nil)
+						save(p);
 					syslog(0, "vf", "vf rejected %s %s", p->type?s_to_c(p->type):"?",
 						p->filename?s_to_c(p->filename):"?");
-					fprint(2, "The mail contained an attachment which was a DOS/Windows\n");
-					fprint(2, "executable file.  We refuse all mail containing such.\n");
+					fprint(2, "The mail contained an executable attachment.\n");
+					fprint(2, "We refuse all mail containing such.\n");
 					postnote(PNGROUP, getpid(), "mail refused: we don't accept executable attachments");
-					exits("we don't accept executable attachments");
+					exits("mail refused: we don't accept executable attachments");
 				}
 				return problemchild(p);
 			} else {
@@ -313,6 +322,33 @@ passbody(Part *p, int dobound)
 	return nil;
 }
 
+/*
+ *  save the message somewhere
+ */
+static void
+save(Part *p)
+{
+	int fd;
+	char *cp;
+
+	Bterm(&out);
+	memset(&out, 0, sizeof(out));
+
+	fd = open(savefile, OWRITE);
+	if(fd < 0)
+		return;
+	seek(fd, 0, 2);
+	Binit(&out, fd, OWRITE);
+	cp = ctime(time(0));
+	cp[20] = 0;
+	Bprint(&out, "From virusfilter %s\n", cp);
+	writeheader(p);
+	passbody(p, 1);
+	Bprint(&out, "\n");
+	Bterm(&out);
+	close(fd);
+}
+
 /*
  *  emit a multipart Part that explains the problem
  */