⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 smtpd.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 3 页
字号:
#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>#include "../smtp/y.tab.h"#define DBGMX 1char	*me;char	*him="";char	*dom;process	*pp;String	*mailer;NetConnInfo *nci;int	filterstate = ACCEPT;int	trusted;int	logged;int	rejectcount;int	hardreject;Biobuf	bin;int	debug;int	Dflag;int	fflag;int	gflag;int	rflag;int	sflag;int	authenticate;int	authenticated;int	passwordinclear;char	*tlscert;List	senders;List	rcvers;char pipbuf[ERRMAX];char	*piperror;int	pipemsg(int*);String*	startcmd(void);int	rejectcheck(void);String*	mailerpath(char*);static intcatchalarm(void *a, char *msg){	int rv = 1;	USED(a);	/* log alarms but continue */	if(strstr(msg, "alarm")){		if(senders.first && rcvers.first)			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", msg);		rv = 0;	}	/* kill the children if there are any */	if(pp)		syskillpg(pp->pid);	return rv;}	/* override string error functions to do something reasonable */voids_error(char *f, char *status){	char errbuf[Errlen];	errbuf[0] = 0;	rerrstr(errbuf, sizeof(errbuf));	if(f && *f)		reply("452 out of memory %s: %s\r\n", f, errbuf);	else		reply("452 out of memory %s\r\n", errbuf);	syslog(0, "smtpd", "++Malloc failure %s [%s]", him, nci->rsys);	exits(status);}voidmain(int argc, char **argv){	char *p, buf[1024];	char *netdir;	netdir = nil;	quotefmtinstall();	ARGBEGIN{	case 'D':		Dflag++;		break;	case 'd':		debug++;		break;	case 'n':				/* log peer ip address */		netdir = ARGF();		break;	case 'f':				/* disallow relaying */		fflag = 1;		break;	case 'g':		gflag = 1;		break;	case 'h':				/* default domain name */		dom = ARGF();		break;	case 'k':				/* prohibited ip address */		p = ARGF();		if (p)			addbadguy(p);		break;	case 'm':				/* set mail command */		p = ARGF();		if(p)			mailer = mailerpath(p);		break;	case 'r':		rflag = 1;			/* verify sender's domain */		break;	case 's':				/* save blocked messages */		sflag = 1;		break;	case 'a':		authenticate = 1;		break;	case 'p':		passwordinclear = 1;		break;	case 'c':		tlscert = ARGF();		break;	case 't':		fprint(2, "%s: the -t option is no longer supported, see -c\n", argv0);		tlscert = "/sys/lib/ssl/smtpd-cert.pem";		break;	default:		fprint(2, "usage: smtpd [-dfhrs] [-n net] [-c cert]\n");		exits("usage");	}ARGEND;	nci = getnetconninfo(netdir, 0);	if(nci == nil)		sysfatal("can't get remote system's address");	if(mailer == nil)		mailer = mailerpath("send");	if(debug){		close(2);		snprint(buf, sizeof(buf), "%s/smtpd.db", UPASLOG);		if (open(buf, OWRITE) >= 0) {			seek(2, 0, 2);			fprint(2, "%d smtpd %s\n", getpid(), thedate());		} else			debug = 0;	}	getconf();	Binit(&bin, 0, OREAD);	chdir(UPASLOG);	me = sysname_read();	if(dom == 0 || dom[0] == 0)		dom = domainname_read();	if(dom == 0 || dom[0] == 0)		dom = me;	sayhi();	parseinit();		/* allow 45 minutes to parse the header */	atnotify(catchalarm, 1);	alarm(45*60*1000);	zzparse();	exits(0);}voidlistfree(List *l){	Link *lp;	Link *next;	for(lp = l->first; lp; lp = next){		next = lp->next;		s_free(lp->p);		free(lp);	}	l->first = l->last = 0;}voidlistadd(List *l, String *path){	Link *lp;	lp = (Link *)malloc(sizeof(Link));	lp->p = path;	lp->next = 0;	if(l->last)		l->last->next = lp;	else		l->first = lp;	l->last = lp;}#define	SIZE	4096intreply(char *fmt, ...){	char buf[SIZE], *out;	va_list arg;	int n;	va_start(arg, fmt);	out = vseprint(buf, buf+SIZE, fmt, arg);	va_end(arg);	n = (long)(out-buf);	if(debug) {		seek(2, 0, 2);		write(2, buf, n);	}	write(1, buf, n);	return n;}voidreset(void){	if(rejectcheck())		return;	listfree(&rcvers);	listfree(&senders);	if(filterstate != DIALUP){		logged = 0;		filterstate = ACCEPT;	}	reply("250 ok\r\n");}voidsayhi(void){	reply("220 %s SMTP\r\n", dom);}voidhello(String *himp, int extended){	char **mynames;	him = s_to_c(himp);	syslog(0, "smtpd", "%s from %s as %s", extended ? "ehlo" : "helo", nci->rsys, him);	if(rejectcheck())		return;	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;			}		}	}	/*	 * it is never acceptable to claim to be "localhost",	 * "localhost.localdomain" or "localhost.example.com"; only spammers	 * do this.  it is also unacceptable to claim any string that doesn't	 * look like a domain name (e.g., has at least one dot in it), but	 * Microsoft mail client software gets this wrong, so let trusted	 * (local) clients get it wrong.	 */	if (!trusted && strchr(him, '.') == nil ||	    strcmp(him, "localhost.localdomain") == 0 ||	    strcmp(him, "localhost.example.com") == 0)		goto Liarliar;	/*	 * similarly, if the claimed domain is not an address-literal,	 * require at least one letter, which there will be in	 * at least the last component (e.g., .com, .net) if it's real.	 * this rejects non-address-literal IP addresses,	 * among other bogosities.	 */	if (!trusted && him[0] != '[') {		char *p;		for (p = him; *p != '\0'; p++)			if (isascii(*p) && isalpha(*p))				break;		if (*p == '\0')			goto Liarliar;	}	if(strchr(him, '.') == 0 && nci != nil && strchr(nci->rsys, '.') != nil)		him = nci->rsys;	if(Dflag)		sleep(15*1000);	reply("250%c%s you are %s\r\n", extended ? '-' : ' ', dom, him);	if (extended) {		if(tlscert != nil)			reply("250-STARTTLS\r\n");		if (passwordinclear)					reply("250 AUTH CRAM-MD5 PLAIN LOGIN\r\n");		else			reply("250 AUTH CRAM-MD5\r\n");	}}voidsender(String *path){	String *s;	static char *lastsender;	if(rejectcheck())		return;	if (authenticate && !authenticated) {		rejectcount++;		reply("530 Authentication required\r\n");		return;	}	if(him == 0 || *him == 0){		rejectcount++;		reply("503 Start by saying HELO, please.\r\n", s_to_c(path));		return;	}	/* don't add the domain onto black holes or we will loop */	if(strchr(s_to_c(path), '!') == 0 && strcmp(s_to_c(path), "/dev/null") != 0){		s = s_new();		s_append(s, him);		s_append(s, "!");		s_append(s, s_to_c(path));		s_terminate(s);		s_free(path);		path = s;	}	if(shellchars(s_to_c(path))){		rejectcount++;		reply("503 Bad character in sender address %s.\r\n", s_to_c(path));		return;	}	/*	 * if the last sender address resulted in a rejection because the sending	 * domain didn't exist and this sender has the same domain, reject immediately.	 */	if(lastsender){		if (strncmp(lastsender, s_to_c(path), strlen(lastsender)) == 0){			filterstate = REFUSED;			rejectcount++;			reply("554 Sender domain must exist: %s\r\n", s_to_c(path));			return;		}		free(lastsender);	/* different sender domain */		lastsender = 0;	}	/*	 * see if this ip address, domain name, user name or account is blocked	 */	filterstate = blocked(path);	logged = 0;	listadd(&senders, 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 intrdsenders(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 intsenderok(char *rcpt){	int mentioned = 0, matched = 0;	uchar dnsip[IPaddrlen];	Sender *snd;	Ndbtuple *nt, *next, *first;	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;}voidreceiver(String *path){	char *sender, *rcpt;	if(rejectcheck())		return;	if(him == 0 || *him == 0){

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -