Browse Source

Plan 9 from Bell Labs 2004-10-27

David du Colombier 19 years ago
parent
commit
762e8a7d44

+ 14 - 8
dist/replica/_plan9.db

@@ -2841,6 +2841,8 @@ mail/lib/smtpd.conf - 664 upas upas 961114164 536
 mail/lib/smtpd.conf.ext - 664 upas upas 1089299188 1032
 mail/lib/spam.rc - 775 upas upas 1063950954 400
 mail/lib/unspam.rc - 775 upas upas 1063950954 400
+mail/lib/validateaddress - 775 upas upas 1098803974 48
+mail/lib/validatesender - 775 upas upas 1098803974 1081
 mail/lib/white.starter - 664 upas upas 1067739606 326
 mail/queue - 20000000777 upas upas 953302652 0
 mail/tmp - 20000000777 upas upas 953302655 0
@@ -10801,8 +10803,8 @@ sys/src/cmd/upas/bayes/classify.re - 664 sys sys 1063951008 73671
 sys/src/cmd/upas/bayes/dfa.c - 664 sys sys 1063951008 14687
 sys/src/cmd/upas/bayes/dfa.h - 664 sys sys 1063951008 457
 sys/src/cmd/upas/bayes/dump.c - 664 sys sys 1063951008 1227
-sys/src/cmd/upas/bayes/hash.c - 664 sys sys 1089299190 4208
-sys/src/cmd/upas/bayes/hash.h - 664 sys sys 1063951009 459
+sys/src/cmd/upas/bayes/hash.c - 664 sys sys 1098803887 4562
+sys/src/cmd/upas/bayes/hash.h - 664 sys sys 1098803887 470
 sys/src/cmd/upas/bayes/mkfile - 664 sys sys 1063951009 466
 sys/src/cmd/upas/bayes/msgclass.c - 664 sys sys 1089299190 4776
 sys/src/cmd/upas/bayes/msgdb.c - 664 sys sys 1063951010 902
@@ -10815,13 +10817,13 @@ sys/src/cmd/upas/common - 20000000775 sys sys 1015088626 0
 sys/src/cmd/upas/common/appendfiletombox.c - 664 sys sys 1075064534 2154
 sys/src/cmd/upas/common/aux.c - 664 sys sys 1019498851 2300
 sys/src/cmd/upas/common/become.c - 664 sys sys 1015009623 430
-sys/src/cmd/upas/common/common.h - 664 sys sys 1075069143 2021
+sys/src/cmd/upas/common/common.h - 664 sys sys 1098803897 2040
 sys/src/cmd/upas/common/config.c - 664 sys sys 944961316 254
 sys/src/cmd/upas/common/libsys.c - 664 sys sys 1078840017 14437
 sys/src/cmd/upas/common/mail.c - 664 sys sys 944961315 1346
 sys/src/cmd/upas/common/makefile - 664 sys sys 944961315 366
 sys/src/cmd/upas/common/mkfile - 664 sys sys 1075069142 273
-sys/src/cmd/upas/common/process.c - 664 sys sys 1015009624 2984
+sys/src/cmd/upas/common/process.c - 664 sys sys 1098803900 3012
 sys/src/cmd/upas/common/sys.h - 664 sys sys 1055699577 2223
 sys/src/cmd/upas/filterkit - 20000000775 sys sys 1018549521 0
 sys/src/cmd/upas/filterkit/dat.h - 664 sys sys 1018549520 107
@@ -10877,7 +10879,7 @@ sys/src/cmd/upas/pop3/pop3.c - 664 sys sys 1076176207 14301
 sys/src/cmd/upas/q - 20000000775 sys sys 988250019 0
 sys/src/cmd/upas/q/mkfile - 664 sys sys 1064589601 262
 sys/src/cmd/upas/q/qer.c - 664 sys sys 1014926528 3179
-sys/src/cmd/upas/q/runq.c - 664 sys sys 1071335819 11904
+sys/src/cmd/upas/q/runq.c - 664 sys sys 1098803913 12465
 sys/src/cmd/upas/scanmail - 20000000775 sys sys 988250021 0
 sys/src/cmd/upas/scanmail/common.c - 664 sys sys 1015013177 12385
 sys/src/cmd/upas/scanmail/mkfile - 664 sys sys 1064589604 334
@@ -10908,15 +10910,15 @@ sys/src/cmd/upas/send/tryit - 664 sys sys 944961322 584
 sys/src/cmd/upas/smtp - 20000000775 sys sys 988250017 0
 sys/src/cmd/upas/smtp/greylist.c - 664 sys sys 1091126808 6470
 sys/src/cmd/upas/smtp/mkfile - 664 sys sys 1067722781 746
-sys/src/cmd/upas/smtp/mxdial.c - 664 sys sys 1055703150 4887
+sys/src/cmd/upas/smtp/mxdial.c - 664 sys sys 1098803923 5150
 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 1097901337 19565
 sys/src/cmd/upas/smtp/smtp.h - 664 sys sys 1064589597 1084
-sys/src/cmd/upas/smtp/smtpd.c - 664 sys sys 1087421671 27665
+sys/src/cmd/upas/smtp/smtpd.c - 664 sys sys 1098803934 30216
 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
+sys/src/cmd/upas/smtp/spam.c - 664 sys sys 1098803961 10231
 sys/src/cmd/upas/unesc - 20000000775 sys sys 1075080255 0
 sys/src/cmd/upas/unesc/mkfile - 664 sys sys 1075080255 164
 sys/src/cmd/upas/unesc/unesc.c - 664 sys sys 1075080255 789
@@ -12388,3 +12390,7 @@ usr/glenda/lib/profile - 664 glenda glenda 1021580005 847
 usr/glenda/readme.acme - 664 glenda glenda 1019860628 4753
 usr/glenda/readme.rio - 664 glenda glenda 1019860628 6370
 usr/glenda/tmp - 20000000775 glenda glenda 1018802620 0
+386/bin/upas/runq - 775 sys sys 1098846467 111047
+386/bin/upas/send - 775 sys sys 1098846467 189497
+386/bin/upas/smtp - 775 sys sys 1098846467 270306
+386/bin/upas/smtpd - 775 sys sys 1098846468 326493

+ 14 - 12
dist/replica/plan9.db

@@ -446,11 +446,11 @@
 386/bin/upas/pop3 - 775 sys sys 1085077114 259808
 386/bin/upas/qer - 775 sys sys 1085077114 97840
 386/bin/upas/ratfs - 775 sys sys 1089257539 109406
-386/bin/upas/runq - 775 sys sys 1085077115 110358
+386/bin/upas/runq - 775 sys sys 1098846467 111047
 386/bin/upas/scanmail - 775 sys sys 1085077115 126758
-386/bin/upas/send - 775 sys sys 1085077116 189534
-386/bin/upas/smtp - 775 sys sys 1098158515 270192
-386/bin/upas/smtpd - 775 sys sys 1091156988 324025
+386/bin/upas/send - 775 sys sys 1098846467 189497
+386/bin/upas/smtp - 775 sys sys 1098846467 270306
+386/bin/upas/smtpd - 775 sys sys 1098846468 326493
 386/bin/upas/spam - 775 sys sys 1064598366 36
 386/bin/upas/testscan - 775 sys sys 1085077117 81626
 386/bin/upas/token - 775 sys sys 1085077117 75518
@@ -2841,6 +2841,8 @@ mail/lib/smtpd.conf - 664 upas upas 961114164 536
 mail/lib/smtpd.conf.ext - 664 upas upas 1089299188 1032
 mail/lib/spam.rc - 775 upas upas 1063950954 400
 mail/lib/unspam.rc - 775 upas upas 1063950954 400
+mail/lib/validateaddress - 775 upas upas 1098803974 48
+mail/lib/validatesender - 775 upas upas 1098803974 1081
 mail/lib/white.starter - 664 upas upas 1067739606 326
 mail/queue - 20000000777 upas upas 953302652 0
 mail/tmp - 20000000777 upas upas 953302655 0
@@ -10801,8 +10803,8 @@ sys/src/cmd/upas/bayes/classify.re - 664 sys sys 1063951008 73671
 sys/src/cmd/upas/bayes/dfa.c - 664 sys sys 1063951008 14687
 sys/src/cmd/upas/bayes/dfa.h - 664 sys sys 1063951008 457
 sys/src/cmd/upas/bayes/dump.c - 664 sys sys 1063951008 1227
-sys/src/cmd/upas/bayes/hash.c - 664 sys sys 1089299190 4208
-sys/src/cmd/upas/bayes/hash.h - 664 sys sys 1063951009 459
+sys/src/cmd/upas/bayes/hash.c - 664 sys sys 1098803887 4562
+sys/src/cmd/upas/bayes/hash.h - 664 sys sys 1098803887 470
 sys/src/cmd/upas/bayes/mkfile - 664 sys sys 1063951009 466
 sys/src/cmd/upas/bayes/msgclass.c - 664 sys sys 1089299190 4776
 sys/src/cmd/upas/bayes/msgdb.c - 664 sys sys 1063951010 902
@@ -10815,13 +10817,13 @@ sys/src/cmd/upas/common - 20000000775 sys sys 1015088626 0
 sys/src/cmd/upas/common/appendfiletombox.c - 664 sys sys 1075064534 2154
 sys/src/cmd/upas/common/aux.c - 664 sys sys 1019498851 2300
 sys/src/cmd/upas/common/become.c - 664 sys sys 1015009623 430
-sys/src/cmd/upas/common/common.h - 664 sys sys 1075069143 2021
+sys/src/cmd/upas/common/common.h - 664 sys sys 1098803897 2040
 sys/src/cmd/upas/common/config.c - 664 sys sys 944961316 254
 sys/src/cmd/upas/common/libsys.c - 664 sys sys 1078840017 14437
 sys/src/cmd/upas/common/mail.c - 664 sys sys 944961315 1346
 sys/src/cmd/upas/common/makefile - 664 sys sys 944961315 366
 sys/src/cmd/upas/common/mkfile - 664 sys sys 1075069142 273
-sys/src/cmd/upas/common/process.c - 664 sys sys 1015009624 2984
+sys/src/cmd/upas/common/process.c - 664 sys sys 1098803900 3012
 sys/src/cmd/upas/common/sys.h - 664 sys sys 1055699577 2223
 sys/src/cmd/upas/filterkit - 20000000775 sys sys 1018549521 0
 sys/src/cmd/upas/filterkit/dat.h - 664 sys sys 1018549520 107
@@ -10877,7 +10879,7 @@ sys/src/cmd/upas/pop3/pop3.c - 664 sys sys 1076176207 14301
 sys/src/cmd/upas/q - 20000000775 sys sys 988250019 0
 sys/src/cmd/upas/q/mkfile - 664 sys sys 1064589601 262
 sys/src/cmd/upas/q/qer.c - 664 sys sys 1014926528 3179
-sys/src/cmd/upas/q/runq.c - 664 sys sys 1071335819 11904
+sys/src/cmd/upas/q/runq.c - 664 sys sys 1098803913 12465
 sys/src/cmd/upas/scanmail - 20000000775 sys sys 988250021 0
 sys/src/cmd/upas/scanmail/common.c - 664 sys sys 1015013177 12385
 sys/src/cmd/upas/scanmail/mkfile - 664 sys sys 1064589604 334
@@ -10908,15 +10910,15 @@ sys/src/cmd/upas/send/tryit - 664 sys sys 944961322 584
 sys/src/cmd/upas/smtp - 20000000775 sys sys 988250017 0
 sys/src/cmd/upas/smtp/greylist.c - 664 sys sys 1091126808 6470
 sys/src/cmd/upas/smtp/mkfile - 664 sys sys 1067722781 746
-sys/src/cmd/upas/smtp/mxdial.c - 664 sys sys 1055703150 4887
+sys/src/cmd/upas/smtp/mxdial.c - 664 sys sys 1098803923 5150
 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 1097901337 19565
 sys/src/cmd/upas/smtp/smtp.h - 664 sys sys 1064589597 1084
-sys/src/cmd/upas/smtp/smtpd.c - 664 sys sys 1087421671 27665
+sys/src/cmd/upas/smtp/smtpd.c - 664 sys sys 1098803934 30216
 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
+sys/src/cmd/upas/smtp/spam.c - 664 sys sys 1098803961 10231
 sys/src/cmd/upas/unesc - 20000000775 sys sys 1075080255 0
 sys/src/cmd/upas/unesc/mkfile - 664 sys sys 1075080255 164
 sys/src/cmd/upas/unesc/unesc.c - 664 sys sys 1075080255 789

+ 14 - 0
dist/replica/plan9.log

@@ -16918,3 +16918,17 @@
 1098541861 0 c sys/games/lib/fortunes - 664 sys sys 1098540092 250651
 1098547262 0 c sys/src/9/port/sd.h - 664 sys sys 1098546338 2348
 1098588670 0 c 386/9pcdisk - 775 sys sys 1098587542 2019954
+1098804712 0 a mail/lib/validateaddress - 775 upas upas 1098803974 48
+1098804712 1 a mail/lib/validatesender - 775 upas upas 1098803974 1081
+1098804712 2 c sys/src/cmd/upas/bayes/hash.c - 664 sys sys 1098803887 4562
+1098804712 3 c sys/src/cmd/upas/bayes/hash.h - 664 sys sys 1098803887 470
+1098804712 4 c sys/src/cmd/upas/common/common.h - 664 sys sys 1098803897 2040
+1098804712 5 c sys/src/cmd/upas/common/process.c - 664 sys sys 1098803900 3012
+1098804712 6 c sys/src/cmd/upas/q/runq.c - 664 sys sys 1098803913 12465
+1098804712 7 c sys/src/cmd/upas/smtp/mxdial.c - 664 sys sys 1098803923 5150
+1098804712 8 c sys/src/cmd/upas/smtp/smtpd.c - 664 sys sys 1098803934 30216
+1098804712 9 c sys/src/cmd/upas/smtp/spam.c - 664 sys sys 1098803961 10231
+1098847920 0 c 386/bin/upas/runq - 775 sys sys 1098846467 111047
+1098847920 1 c 386/bin/upas/send - 775 sys sys 1098846467 189497
+1098847920 2 c 386/bin/upas/smtp - 775 sys sys 1098846467 270306
+1098847920 3 c 386/bin/upas/smtpd - 775 sys sys 1098846468 326493

+ 2 - 0
mail/lib/validateaddress

@@ -0,0 +1,2 @@
+#!/bin/rc
+mail -x $1 | grep -vs '^unknown user'

+ 51 - 0
mail/lib/validatesender

@@ -0,0 +1,51 @@
+#!/bin/rc
+
+rfork en
+fn usage{
+	echo 'usage: validatesender [-n /net] plan9.bell-labs.com glenda' >[1=2]
+	exit usage
+}
+
+echo $sysname $pid '$' validatesender $* >>/sys/log/smtpd.mx
+
+netroot=/net
+if(~ $1 -n){
+	shift
+	netroot=$1
+	shift
+}
+if(! ~ $#* 2)
+	usage
+
+dom=$1
+addr=$2
+
+# Cause some problems
+if(~ $dom swtch.com && ~ $addr glenda && ! ~ $sysname olive)
+	exit 'deferred: always defer this one'
+
+# Lucent only - use external network when mail from external domains
+# is delivered to us internally.  Assume that local domains are fine.
+netroot=/net
+if(~ $dom *.lucent.com lucent.com *.bell-labs.com bell-labs.com)
+	exit ''
+if(! ~ $sysname ethel)
+	exit ''
+if(~ $sysname ethel){
+	if(! test -d /net.alt/tcp)
+		import outside /net.alt
+	if(test -d /net.alt/tcp)
+		netroot=/net.alt
+}
+
+if(x=`{upas/smtp -p $netroot/tcp!$dom postmaster $addr >[2=1] | 
+		tee >{sed 's/^/'$sysname' '$pid' /' >> /sys/log/smtpd.mx} |
+		tail -1})
+	exit ''
+
+smtpstatus=$status
+if(~ $#x 0)
+	x=$smtpstatus
+if(~ $smtpstatus *'Permanent Failure'*)
+	exit 'rejected: smtp ping: '^$"x
+exit 'deferred: smtp ping: '^$"x

+ 1 - 0
sys/src/9/pc/ether82557.c

@@ -931,6 +931,7 @@ i82557pci(void)
 		case 0x1209:		/* Intel 82559ER */
 		case 0x1229:		/* Intel 8255[789] */
 		case 0x1030:		/* Intel 82559 InBusiness 10/100  */
+		case 0x1039:		/* Intel 82801BD PRO/100 VE */
 			break;
 		}
 

+ 1 - 0
sys/src/boot/pc/ether82557.c

@@ -555,6 +555,7 @@ i82557pci(void)
 		case 0x1229:		/* Intel 8255[789] */
 		case 0x1031:		/* Intel 82562EM */
 		case 0x2449:		/* Intel 82562ET */
+		case 0x1039:		/* Intel 82801BD PRO/100 VE */
 			break;
 		}
 

+ 24 - 4
sys/src/cmd/upas/bayes/hash.c

@@ -121,6 +121,7 @@ findstab(Hash *hh, char *str, int n, int create)
 	hh->all = tab;
 	tab->n = n;
 	tab->count = 0;
+	tab->date = 0;
 	hh->stab[h] = tab;
 
 	hh->ntab++;
@@ -217,14 +218,21 @@ int
 Bwritehash(Biobuf *b, Hash *hh)
 {
 	Stringtab *s;
+	int now;
 
+	now = time(0);
 	s = sortstab(hh);
 	Bprint(b, "# hash table\n");
 	for(; s; s=s->link){
 		if(s->count <= 0)
 			continue;
+		/*
+		 * Entries that haven't been updated in thirty days get tossed.
+		 */
+		if(s->date+30*86400 < now)
+			continue;
 		Bwrite(b, s->str, s->n);
-		Bprint(b, "\t%d\n", s->count);
+		Bprint(b, "\t%d %d\n", s->count, s->date);
 	}
 	if(Bflush(b) == Beof)
 		return -1;
@@ -237,6 +245,8 @@ Breadhash(Biobuf *b, Hash *hh, int scale)
 	char *s;
 	char *t;
 	int n;
+	int date;
+	Stringtab *st;
 
 	s = Brdstr(b, '\n', 1);
 	if(s == nil)
@@ -253,9 +263,19 @@ Breadhash(Biobuf *b, Hash *hh, int scale)
 		if(*t < '0' || *t > '9')
 			sysfatal("bad hash table format");
 		n = strtol(t, &t, 10);
-		if(*t != 0)
-			sysfatal("bad hash table format");
-		findstab(hh, s, strlen(s), 1)->count += n*scale;
+		date = time(0);
+		if(*t != 0){
+			if(*t == ' '){
+				t++;
+				date = strtol(t, &t, 10);
+			}
+			if(*t != 0)
+				sysfatal("bad hash table format");
+		}
+		st = findstab(hh, s, strlen(s), 1);
+		if(date > st->date)
+			st->date = date;
+		st->count += n*scale;
 	}
 }
 

+ 1 - 0
sys/src/cmd/upas/bayes/hash.h

@@ -5,6 +5,7 @@ struct Stringtab {
 	char *str;
 	int n;
 	int count;
+	int date;
 };
 
 typedef struct Hash Hash;

+ 1 - 0
sys/src/cmd/upas/common/common.h

@@ -63,6 +63,7 @@ typedef struct process{
 	stream	*std[3];	/* standard fd's*/
 	int	pid;		/* process identifier*/
 	int	status;		/* exit status*/
+	Waitmsg	*waitmsg;
 } process;
 
 extern stream	*instream(void);

+ 2 - 1
sys/src/cmd/upas/common/process.c

@@ -143,7 +143,7 @@ proc_wait(process *pp)
 		pp->status = -1;
 	else
 		pp->status = status->msg[0];
-	free(status);
+	pp->waitmsg = status;
 	return pp->status;
 }
 
@@ -160,6 +160,7 @@ proc_free(process *pp)
 			stream_free(pp->std[i]);
 	if (pp->pid >= 0)
 		proc_wait(pp);
+	free(pp->waitmsg);
 	free((char *)pp);
 	return 0;
 }

+ 25 - 8
sys/src/cmd/upas/q/runq.c

@@ -445,10 +445,14 @@ dofile(Dir *dp)
 		close(dfd);
 		close(2);
 		efd = open(file(dp->name, 'E'), OWRITE);
-		if(efd < 0)
-			efd = create(file(dp->name, 'E'), OWRITE, 0664);
-		if(efd < 0)
-			exits("");
+		if(efd < 0){
+			if(debug) syslog(0, "runq", "open %s as %s: %r", file(dp->name,'E'), getuser());
+			efd = create(file(dp->name, 'E'), OWRITE, 0666);
+			if(efd < 0){
+				if(debug) syslog(0, "runq", "create %s as %s: %r", file(dp->name, 'E'), getuser());
+				exits("could not open error file - Retry");
+			}
+		}
 		seek(efd, 0, 2);
 		exec(cmd, av);
 		error("can't exec %s", cmd);
@@ -462,13 +466,15 @@ dofile(Dir *dp)
 				break;
 			free(wm);
 		}
+		if(debug)
+			fprint(2, "wm->pid %d wm->msg == %s\n", wm->pid, wm->msg);
 
 		if(wm->msg[0]){
 			if(debug)
 				fprint(2, "[%d] wm->msg == %s\n", getpid(), wm->msg);
 			if(!Rflag && strstr(wm->msg, "Retry")==0){
 				/* return the message and remove it */
-				if(returnmail(av, dp->name, wm->msg) == 0)
+				if(returnmail(av, dp->name, wm->msg) != 0)
 					logit("returnmail failed", dp->name, av);
 				remmatch(dp->name);
 			} else {
@@ -538,11 +544,14 @@ returnmail(char **av, char *name, char *msg)
 		return 0;
 	}
 
-	if(pipe(pfd) < 0)
+	if(pipe(pfd) < 0){
+		logit("runq - pipe failed", name, av);
 		return -1;
+	}
 
 	switch(rfork(RFFDG|RFPROC|RFENVG)){
 	case -1:
+		logit("runq - fork failed", name, av);
 		return -1;
 	case 0:
 		logit("returning", name, av);
@@ -584,9 +593,17 @@ returnmail(char **av, char *name, char *msg)
 	close(pfd[1]);
 out:
 	wm = wait();
-	if(wm == nil)
+	if(wm == nil){
+		syslog(0, "runq", "wait: %r");
+		logit("wait failed", name, av);
 		return -1;
-	i = wm->msg[0] ? -1 : 0;
+	}
+	i = 0;
+	if(wm->msg[0]){
+		i = -1;
+		syslog(0, "runq", "returnmail child: %s", wm->msg);
+		logit("returnmail child failed", name, av);
+	}
 	free(wm);
 	return i;
 }

+ 52 - 47
sys/src/cmd/upas/smtp/mxdial.c

@@ -11,6 +11,7 @@ typedef struct Mx	Mx;
 struct Mx
 {
 	char host[256];
+	char ip[24];
 	int pref;
 };
 static Mx mx[Nmx];
@@ -78,6 +79,16 @@ callmx(DS *ds, char *dest, char *domain)
 		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){
+			if(debug)
+				fprint(2, "mxlookup returns loopback\n");
+			werrstr("illegal: domain lists 127.0.0.1 as mail server");
+			return -1;
+		}
+	}
+
 	/* sort by preference */
 	if(nmx > 1)
 		qsort(mx, nmx, sizeof(Mx), compar);
@@ -129,8 +140,7 @@ mxlookup1(DS *ds, char *domain)
 	char buf[1024];
 	char dnsname[Maxstring];
 	char *fields[4];
-	int n, fd, nmx;
-	char **mynames;
+	int i, n, fd, nmx;
 
 	snprint(dnsname, sizeof dnsname, "%s/dns", ds->netdir);
 
@@ -145,6 +155,8 @@ mxlookup1(DS *ds, char *domain)
 	n = write(fd, buf, strlen(buf));
 	if(n < 0){
 		rerrstr(buf, sizeof buf);
+		if(debug)
+			fprint(2, "dns: %s\n", buf);
 		if(strstr(buf, "dns failure")){
 			/* if dns fails for the mx lookup, we have to stop */
 			close(fd);
@@ -157,6 +169,8 @@ mxlookup1(DS *ds, char *domain)
 		seek(fd, 0, 0);
 		while(nmx < Nmx && (n = read(fd, buf, sizeof(buf)-1)) > 0){
 			buf[n] = 0;
+			if(debug)
+				fprint(2, "dns mx: %s\n", buf);
 			n = getfields(buf, fields, 4, 1, " \t");
 			if(n < 4)
 				continue;
@@ -168,58 +182,49 @@ mxlookup1(DS *ds, char *domain)
 			mx[nmx].pref = atoi(fields[2]);
 			nmx++;
 		}
-	}
-	close(fd);
-
-	if(nmx){
-		/* ignore the mx if we are one of the systems */
-		mynames = sysnames_read();
-		if(mynames == 0)
-			return nmx;
-		for(; nmx && *mynames; mynames++)
-			for(n = 0; n < nmx; n++)
-				if(cistrcmp(*mynames, mx[n].host) == 0)
-					nmx = 0;
-		if(nmx)
-			return nmx;
+		if(debug)
+			fprint(2, "dns mx; got %d entries\n", nmx);
 	}
 
+	/*
+	 * no mx record? try name itself.
+	 */
+	/*
+	 * BUG? If domain has no dots, then we used to look up ds->host
+	 * but return domain instead of ds->host in the list.  Now we return
+	 * ds->host.  What will this break?
+	 */
+	if(nmx == 0){
+		mx[0].pref = 1;
+		strncpy(mx[0].host, ds->host, sizeof(mx[0].host));
+		nmx++;
+	}
 
 	/*
-	 *  no mx, look to see if it has an ip address
+	 * look up all ip addresses
 	 */
-	fd = open(dnsname, ORDWR);
-	if(fd < 0)
-		return 0;
-	snprint(buf, sizeof(buf), "%s ip", ds->host);
-	if(debug)
-		fprint(2, "sending %s '%s'\n", dnsname, buf);
-	n = write(fd, buf, strlen(buf));
-	if(n < 0){
-		rerrstr(buf, sizeof buf);
-		if(strstr(buf, "dns failure")){
-			close(fd);
-			return -1;
-		}
-	} else {
+	for(i = 0; i < nmx; i++){
 		seek(fd, 0, 0);
-	
-		if((n = read(fd, buf, sizeof(buf)-1)) > 0){
-			buf[n] = 0;
-			n = getfields(buf, fields, 4, 1, " \t");
-			if(n >= 3){
-				if(strchr(domain, '.') == 0)
-					strcpy(domain, fields[0]);
-	
-				strncpy(mx[nmx].host, fields[0], sizeof(mx[n].host)-1);
-				mx[nmx].pref = 1;
-				nmx++;
-			}
-		}
+		snprint(buf, sizeof buf, "%s ip", mx[i].host);
+		mx[i].ip[0] = 0;
+		if(write(fd, buf, strlen(buf)) < 0)
+			goto no;
+		seek(fd, 0, 0);
+		if((n = read(fd, buf, sizeof buf-1)) < 0)
+			goto no;
+		buf[n] = 0;
+		if(getfields(buf, fields, 4, 1, " \t") < 3)
+			goto no;
+		strncpy(mx[i].ip, fields[2], sizeof(mx[i].ip)-1);
+		continue;
+
+	no:
+		/* remove mx[i] and go around again */
+		nmx--;
+		mx[i] = mx[nmx];
+		i--;
 	}
-	close(fd);
-
-	return nmx;
+	return nmx;		
 }
 
 static int

+ 143 - 25
sys/src/cmd/upas/smtp/smtpd.c

@@ -9,6 +9,8 @@
 #include <auth.h>
 #include "../smtp/y.tab.h"
 
+#define DBGMX 1
+
 char	*me;
 char	*him="";
 char	*dom;
@@ -38,6 +40,7 @@ char	*tlscert;
 List	senders;
 List	rcvers;
 
+char	*piperror;
 int	pipemsg(int*);
 String*	startcmd(void);
 int	rejectcheck(void);
@@ -53,10 +56,10 @@ catchalarm(void *a, char *msg)
 	/* log alarms but continue */
 	if(strstr(msg, "alarm")){
 		if(senders.first && rcvers.first)
-			syslog(0, "smtpd", "note: %s->%s: %s\n", s_to_c(senders.first->p),
+			syslog(0, "smtpd", "note: %s->%s: %s", s_to_c(senders.first->p),
 				s_to_c(rcvers.first->p), msg);
 		else
-			syslog(0, "smtpd", "note: %s\n", msg);
+			syslog(0, "smtpd", "note: %s", msg);
 		rv = 0;
 	}
 
@@ -90,6 +93,7 @@ main(int argc, char **argv)
 	char *netdir;
 
 	netdir = nil;
+	quotefmtinstall();
 	ARGBEGIN{
 	case 'D':
 		Dflag++;
@@ -250,9 +254,32 @@ sayhi(void)
 void
 hello(String *himp, int extended)
 {
+	char **mynames;
+
 	if(rejectcheck())
 		return;
 	him = s_to_c(himp);
+
+	if(strchr(him, '.') && nci && !trusted && fflag && strcmp(nci->rsys, nci->lsys) != 0){
+		/*
+		 * We don't care if he lies about who he is, but it is
+		 * not okay to pretend to be us.  Many viruses do this,
+		 * just parroting back what we say in the greeting.
+		 */
+		if(strcmp(him, dom) == 0)
+			goto Liarliar;
+		for(mynames=sysnames_read(); mynames && *mynames; mynames++){
+			if(cistrcmp(*mynames, him) == 0){
+			Liarliar:
+				syslog(0, "smtpd", "Hung up on %s; claimed to be %s",
+					nci->rsys, him);
+				reply("554 Liar!\r\n");
+				exits("client pretended to be us");
+				return;
+			}
+		}
+	}
+		
 	if(strchr(him, '.') == 0 && nci != nil && strchr(nci->rsys, '.') != nil)
 		him = nci->rsys;
 
@@ -273,7 +300,6 @@ void
 sender(String *path)
 {
 	String *s;
-	char *cp;
 	static char *lastsender;
 
 	if(rejectcheck())
@@ -325,18 +351,6 @@ sender(String *path)
 	 */
 	filterstate = blocked(path);
 
-	/*
-	 * perform DNS lookup to see if sending domain exists
-	 */
-	if(filterstate == ACCEPT && rflag && returnable(s_to_c(path))){
-		if(rmtdns(nci->root, s_to_c(path)) < 0){
-			filterstate = REFUSED;
-			lastsender = strdup(s_to_c(path));
-			cp = strrchr(lastsender, '!');
-			if(cp)
-				*cp = 0;
-		}
-	}
 	logged = 0;
 	listadd(&senders, path);
 	reply("250 sender is %s\r\n", s_to_c(path));
@@ -921,7 +935,7 @@ pipemsg(int *byteswritten)
 	yyparse();
 
 	/*
- 	 *  Llook for masquerades.  Let Sender: trump From: to allow mailing list
+ 	 *  Look for masquerades.  Let Sender: trump From: to allow mailing list
 	 *  forwarded messages.
 	 */
 	if(fflag)
@@ -954,15 +968,21 @@ pipemsg(int *byteswritten)
 	for(f = firstfield; cp != nil && f; f = f->next){
 		for(p = f->node; cp != 0 && p; p = p->next)
 			cp = bprintnode(pp->std[0]->fp, p);
-		if(status == 0 && Bprint(pp->std[0]->fp, "\n") < 0)
+		if(status == 0 && Bprint(pp->std[0]->fp, "\n") < 0){
+			piperror = "write error";
 			status = 1;
+		}
 	}
-	if(cp == nil)
+	if(cp == nil){
+		piperror = "sender domain";
 		status = 1;
+	}
 
 	/* write anything we read following the header */
-	if(status == 0 && Bwrite(pp->std[0]->fp, cp, s_to_c(hdr) + s_len(hdr) - cp) < 0)
+	if(status == 0 && Bwrite(pp->std[0]->fp, cp, s_to_c(hdr) + s_len(hdr) - cp) < 0){
+		piperror = "write error 2";
 		status = 1;
+	}
 	s_free(hdr);
 
 	/*
@@ -984,22 +1004,28 @@ pipemsg(int *byteswritten)
 		}
 		nbytes += n;
 		if(status == 0 && Bwrite(pp->std[0]->fp, *cp == '.' ? cp+1 : cp, n) < 0){
+			piperror = "write error 3";
 			status = 1;
 		}
 	}
 	s_free(line);
 	if(sawdot == 0){
 		/* message did not terminate normally */
+		piperror = "unexpected eof";
 		syskillpg(pp->pid);
 		status = 1;
 	}
 
-	if(status == 0 && Bflush(pp->std[0]->fp) < 0)
+	if(status == 0 && Bflush(pp->std[0]->fp) < 0){
+		piperror = "write error 4";
 		status = 1;
+	}
 	stream_free(pp->std[0]);
 	pp->std[0] = 0;
 	*byteswritten = nbytes;
 	pipesigoff();
+	if(status && !piperror)
+		piperror = "write on closed pipe";
 	return status;
 }
 
@@ -1017,6 +1043,79 @@ firstline(char *x)
 	return buf;
 }
 
+int
+sendermxcheck(void)
+{
+	char *cp, *senddom, *user;
+	char *who;
+	int pid;
+	Waitmsg *w;
+
+	who = s_to_c(senders.first->p);
+	if(strcmp(who, "/dev/null") == 0){
+		/* /dev/null can only send to one rcpt at a time */
+		if(rcvers.first != rcvers.last){
+			werrstr("rejected: /dev/null sending to multiple recipients");
+			return -1;
+		}
+		return 0;
+	}
+
+	if(access("/mail/lib/validatesender", AEXEC) < 0)
+		return 0;
+
+	senddom = strdup(who);
+	if((cp = strchr(senddom, '!')) == nil){
+		werrstr("rejected: domainless sender %s", who);
+		free(senddom);
+		return -1;
+	}
+	*cp++ = 0;
+	user = cp;
+
+	switch(pid = fork()){
+	case -1:
+		werrstr("deferred: fork: %r");
+		return -1;
+	case 0:
+		/*
+		 * Could add an option with the remote IP address
+		 * to allow validatesender to implement SPF eventually.
+		 */
+		execl("/mail/lib/validatesender", "validatesender", 
+			"-n", nci->root, senddom, user, nil);
+		_exits("exec validatesender: %r");
+	default:
+		break;
+	}
+
+	free(senddom);
+	w = wait();
+	if(w == nil){
+		werrstr("deferred: wait failed: %r");
+		return -1;
+	}
+	if(w->pid != pid){
+		werrstr("deferred: wait returned wrong pid %d != %d", w->pid, pid);
+		free(w);
+		return -1;
+	}
+	if(w->msg[0] == 0){
+		free(w);
+		return 0;
+	}
+	/*
+	 * skip over validatesender 143123132: prefix from rc.
+	 */
+	cp = strchr(w->msg, ':');
+	if(cp && *(cp+1) == ' ')
+		werrstr("%s", cp+2);
+	else
+		werrstr("%s", w->msg);
+	free(w);
+	return -1;
+}
+
 void
 data(void)
 {
@@ -1024,6 +1123,8 @@ data(void)
 	String *err;
 	int status, nbytes;
 	char *cp, *ep;
+	char errx[ERRMAX];
+	Link *l;
 
 	if(rejectcheck())
 		return;
@@ -1037,6 +1138,19 @@ data(void)
 		rejectcount++;
 		return;
 	}
+	if(sendermxcheck()){
+		rerrstr(errx, sizeof errx);
+		if(strncmp(errx, "rejected:", 9) == 0)
+			reply("554 %s\r\n", errx);
+		else
+			reply("450 %s\r\n", errx);
+		for(l=rcvers.first; l; l=l->next)
+			syslog(0, "smtpd", "[%s/%s] %s -> %s sendercheck: %s",
+					him, nci->rsys, s_to_c(senders.first->p), 
+					s_to_c(l->p), errx);
+		rejectcount++;
+		return;
+	}
 
 	cmd = startcmd();
 	if(cmd == 0)
@@ -1068,8 +1182,6 @@ data(void)
 		if(*s_to_c(err))
 			fprint(2, "%d error %s\n", getpid(), s_to_c(err));
 	}
-	proc_free(pp);
-	pp = 0;
 
 	/*
 	 *  if process terminated abnormally, send back error message
@@ -1082,8 +1194,12 @@ data(void)
 				s_to_c(senders.first->p), s_to_c(cmd), firstline(s_to_c(err)));
 			code = 554;
 		} else {
-			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)));
+			syslog(0, "smtpd", "++[%s/%s] %s %s %s%s%sreturned %#q %s", him, nci->rsys,
+				s_to_c(senders.first->p), s_to_c(cmd), 
+				piperror ? "error during pipemsg: " : "",
+				piperror ? piperror : "",
+				piperror ? "; " : "",
+				pp->waitmsg->msg, firstline(s_to_c(err)));
 			code = 450;
 		}
 		for(cp = s_to_c(err); ep = strchr(cp, '\n'); cp = ep){
@@ -1102,6 +1218,8 @@ data(void)
 			logcall(nbytes);
 		}
 	}
+	proc_free(pp);
+	pp = 0;
 	s_free(cmd);
 	s_free(err);
 
@@ -1228,7 +1346,7 @@ auth(String *mech, String *resp)
 	if (rejectcheck())
 		goto bomb_out;
 
- 	syslog(0, "smtpd", "auth(%s, %s) from %s\n", s_to_c(mech),
+ 	syslog(0, "smtpd", "auth(%s, %s) from %s", s_to_c(mech),
 		resp==nil?"nil":s_to_c(resp), him);
 
 	if (authenticated) {

+ 31 - 0
sys/src/cmd/upas/smtp/spam.c

@@ -493,6 +493,8 @@ dumpfile(char *sender)
 	return "/dev/null";
 }
 
+char *validator = "/mail/lib/validateaddress";
+
 int
 recipok(char *user)
 {
@@ -500,6 +502,34 @@ recipok(char *user)
 	char buf[512];
 	int n;
 	Biobuf *bp;
+	int pid;
+	Waitmsg *w;
+
+	if(shellchars(user)){
+		syslog(0, "smtpd", "shellchars in user name");
+		return 0;
+	}
+
+	if(access(validator, AEXEC) == 0)
+	switch(pid = fork()) {
+	case -1:
+		break;
+	case 0:
+		execl(validator, "validateaddress", user, nil);
+		exits(0);
+	default:
+		while(w = wait()) {
+			if(w->pid != pid)
+				continue;
+			if(w->msg[0] != 0){
+				/*
+				syslog(0, "smtpd", "validateaddress %s: %s", user, w->msg);
+				*/
+				return 0;
+			}
+			break;
+		}
+	}
 
 	snprint(buf, sizeof(buf), "%s/names.blocked", UPASLIB);
 	bp = sysopen(buf, "r", 0);
@@ -523,6 +553,7 @@ recipok(char *user)
 		if(p > cp){
 			*p = 0;
 			if(cistrcmp(user, cp) == 0){
+				syslog(0, "smtpd", "names.blocked blocks %s", user);
 				Bterm(bp);
 				return 0;
 			}