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

📄 smtpd.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 3 页
字号:
		rejectcount++;		reply("503 Start by saying HELO, please\r\n");		return;	}	if(senders.last)		sender = s_to_c(senders.last->p);	else		sender = "<unknown>";	if(!recipok(s_to_c(path))){		rejectcount++;		syslog(0, "smtpd",		 "Disallowed %s (%s/%s) to blocked, unknown or invalid 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 */	if(filterstate == ACCEPT && (fflag && !authenticated) && forwarding(path)) {		syslog(0, "smtpd", "Bad Forward %s (%s/%s) (%s)",			s_to_c(senders.last->p), him, nci->rsys, s_to_c(path));		rejectcount++;		reply("550 we don't relay.  send to your-path@[] for loopback.\r\n");		return;	}	listadd(&rcvers, path);	reply("250 receiver is %s\r\n", s_to_c(path));}voidquit(void){	reply("221 Successful termination\r\n");	close(0);	exits(0);}voidturn(void){	if(rejectcheck())		return;	reply("502 TURN unimplemented\r\n");}voidnoop(void){	if(rejectcheck())		return;	reply("250 Stop wasting my time!\r\n");}voidhelp(String *cmd){	if(rejectcheck())		return;	if(cmd)		s_free(cmd);	reply("250 Read rfc821 and stop wasting my time\r\n");}voidverify(String *path){	char *p, *q;	char *av[4];	if(rejectcheck())		return;	if(shellchars(s_to_c(path))){		reply("503 Bad character in address %s.\r\n", s_to_c(path));		return;	}	av[0] = s_to_c(mailer);	av[1] = "-x";	av[2] = s_to_c(path);	av[3] = 0;	pp = noshell_proc_start(av, (stream *)0, outstream(),  (stream *)0, 1, 0);	if (pp == 0) {		reply("450 We're busy right now, try later\r\n");		return;	}	p = Brdline(pp->std[1]->fp, '\n');	if(p == 0){		reply("550 String does not match anything.\r\n");	} else {		p[Blinelen(pp->std[1]->fp)-1] = 0;		if(strchr(p, ':'))			reply("550 String does not match anything.\r\n");		else{			q = strrchr(p, '!');			if(q)				p = q+1;			reply("250 %s <%s@%s>\r\n", s_to_c(path), p, dom);		}	}	proc_wait(pp);	proc_free(pp);	pp = 0;}/* *  get a line that ends in crnl or cr, turn terminating crnl into a nl * *  return 0 on EOF */static intgetcrnl(String *s, Biobuf *fp){	int c;	for(;;){		c = Bgetc(fp);		if(debug) {			seek(2, 0, 2);			fprint(2, "%c", c);		}		switch(c){		case -1:			goto out;		case '\r':			c = Bgetc(fp);			if(c == '\n'){				if(debug) {					seek(2, 0, 2);					fprint(2, "%c", c);				}				s_putc(s, '\n');				goto out;			}			Bungetc(fp);			s_putc(s, '\r');			break;		case '\n':			s_putc(s, c);			goto out;		default:			s_putc(s, c);			break;		}	}out:	s_terminate(s);	return s_len(s);}voidlogcall(int nbytes){	Link *l;	String *to, *from;	to = s_new();	from = s_new();	for(l = senders.first; l; l = l->next){		if(l != senders.first)			s_append(from, ", ");		s_append(from, s_to_c(l->p));	}	for(l = rcvers.first; l; l = l->next){		if(l != rcvers.first)			s_append(to, ", ");		s_append(to, s_to_c(l->p));	}	syslog(0, "smtpd", "[%s/%s] %s sent %d bytes to %s", him, nci->rsys,		s_to_c(from), nbytes, s_to_c(to));	s_free(to);	s_free(from);}static voidlogmsg(char *action){	Link *l;	if(logged)		return;	logged = 1;	for(l = rcvers.first; l; l = l->next)		syslog(0, "smtpd", "%s %s (%s/%s) (%s)", action,			s_to_c(senders.last->p), him, nci->rsys, s_to_c(l->p));}static intoptoutall(int filterstate){	Link *l;	switch(filterstate){	case ACCEPT:	case TRUSTED:		return filterstate;	}	for(l = rcvers.first; l; l = l->next)		if(!optoutofspamfilter(s_to_c(l->p)))			return filterstate;	return ACCEPT;}String*startcmd(void){	int n;	Link *l;	char **av;	String *cmd;	char *filename;	/*	 *  ignore the filterstate if the all the receivers prefer it.	 */	filterstate = optoutall(filterstate);	switch (filterstate){	case BLOCKED:	case DELAY:		rejectcount++;		logmsg("Blocked");		filename = dumpfile(s_to_c(senders.last->p));		cmd = s_new();		s_append(cmd, "cat > ");		s_append(cmd, filename);		pp = proc_start(s_to_c(cmd), instream(), 0, outstream(), 0, 0);		break;	case DIALUP:		logmsg("Dialup");		rejectcount++;		reply("554 We don't accept mail from dial-up ports.\r\n");		/*		 * we could exit here, because we're never going to accept mail from this		 * ip address, but it's unclear that RFC821 allows that.  Instead we set		 * the hardreject flag and go stupid.		 */		hardreject = 1;		return 0;	case DENIED:		logmsg("Denied");		rejectcount++;		reply("554-We don't accept mail from %s.\r\n", s_to_c(senders.last->p));		reply("554 Contact postmaster@%s for more information.\r\n", dom);		return 0;	case REFUSED:		logmsg("Refused");		rejectcount++;		reply("554 Sender domain must exist: %s\r\n", s_to_c(senders.last->p));		return 0;	default:	case NONE:		logmsg("Confused");		rejectcount++;		reply("554-We have had an internal mailer error classifying your message.\r\n");		reply("554-Filterstate is %d\r\n", filterstate);		reply("554 Contact postmaster@%s for more information.\r\n", dom);		return 0;	case ACCEPT:	case TRUSTED:		/*		 * now that all other filters have been passed,		 * do grey-list processing.		 */		if(gflag)			vfysenderhostok();		/*		 *  set up mail command		 */		cmd = s_clone(mailer);		n = 3;		for(l = rcvers.first; l; l = l->next)			n++;		av = malloc(n*sizeof(char*));		if(av == nil){			reply("450 We're busy right now, try later\n");			s_free(cmd);			return 0;		}			n = 0;		av[n++] = s_to_c(cmd);		av[n++] = "-r";		for(l = rcvers.first; l; l = l->next)			av[n++] = s_to_c(l->p);		av[n] = 0;		/*		 *  start mail process		 */		pp = noshell_proc_start(av, instream(), outstream(), outstream(), 0, 0);		free(av);		break;	}	if(pp == 0) {		reply("450 We're busy right now, try later\n");		s_free(cmd);		return 0;	}	return cmd;}/* *  print out a header line, expanding any domainless addresses into *  address@him */char*bprintnode(Biobuf *b, Node *p){	if(p->s){		if(p->addr && strchr(s_to_c(p->s), '@') == nil){			if(Bprint(b, "%s@%s", s_to_c(p->s), him) < 0)				return nil;		} else {			if(Bwrite(b, s_to_c(p->s), s_len(p->s)) < 0)				return nil;		}	}else{		if(Bputc(b, p->c) < 0)			return nil;	}	if(p->white)		if(Bwrite(b, s_to_c(p->white), s_len(p->white)) < 0)			return nil;	return p->end+1;}static String*getaddr(Node *p){	for(; p; p = p->next)		if(p->s && p->addr)			return p->s;	return nil;}/* *  add waring headers of the form *	X-warning: <reason> *  for any headers that looked like they might be forged. * *  return byte count of new headers */static intforgedheaderwarnings(void){	int nbytes;	Field *f;	nbytes = 0;	/* warn about envelope sender */	if(strcmp(s_to_c(senders.last->p), "/dev/null") != 0 && masquerade(senders.last->p, nil))		nbytes += Bprint(pp->std[0]->fp, "X-warning: suspect envelope domain\n");	/*	 *  check Sender: field.  If it's OK, ignore the others because this is an	 *  exploded mailing list.	 */	for(f = firstfield; f; f = f->next){		if(f->node->c == SENDER){			if(masquerade(getaddr(f->node), him))				nbytes += Bprint(pp->std[0]->fp, "X-warning: suspect Sender: domain\n");			else				return nbytes;		}	}	/* check From: */	for(f = firstfield; f; f = f->next){		if(f->node->c == FROM && masquerade(getaddr(f->node), him))			nbytes += Bprint(pp->std[0]->fp, "X-warning: suspect From: domain\n");	}	return nbytes;}/* *  pipe message to mailer with the following transformations: *	- change \r\n into \n. *	- add sender's domain to any addrs with no domain *	- add a From: if none of From:, Sender:, or Replyto: exists *	- add a Received: line */intpipemsg(int *byteswritten){	int status;	char *cp;	String *line;	String *hdr;	int n, nbytes;	int sawdot;	Field *f;	Node *p;	Link *l;	pipesig(&status);	/* set status to 1 on write to closed pipe */	sawdot = 0;	status = 0;	/*	 *  add a 'From ' line as envelope	 */	nbytes = 0;	nbytes += Bprint(pp->std[0]->fp, "From %s %s remote from \n",			s_to_c(senders.first->p), thedate());	/*	 *  add our own Received: stamp	 */	nbytes += Bprint(pp->std[0]->fp, "Received: from %s ", him);	if(nci->rsys)		nbytes += Bprint(pp->std[0]->fp, "([%s]) ", nci->rsys);	nbytes += Bprint(pp->std[0]->fp, "by %s; %s\n", me, thedate());	/*	 *  read first 16k obeying '.' escape.  we're assuming	 *  the header will all be there.	 */	line = s_new();	hdr = s_new();	while(sawdot == 0 && s_len(hdr) < 16*1024){		n = getcrnl(s_reset(line), &bin);		/* eof or error ends the message */		if(n <= 0)			break;		/* a line with only a '.' ends the message */		cp = s_to_c(line);		if(n == 2 && *cp == '.' && *(cp+1) == '\n'){			sawdot = 1;			break;		}		s_append(hdr, *cp == '.' ? cp+1 : cp);	}	/* 	 *  parse header	 */	yyinit(s_to_c(hdr), s_len(hdr));	yyparse();	/* 	 *  Look for masquerades.  Let Sender: trump From: to allow mailing list	 *  forwarded messages.	 */	if(fflag)		nbytes += forgedheaderwarnings();	/*	 *  add an orginator and/or destination if either is missing	 */	if(originator == 0){		if(senders.last == nil)			Bprint(pp->std[0]->fp, "From: /dev/null@%s\n", him);		else			Bprint(pp->std[0]->fp, "From: %s\n", s_to_c(senders.last->p));	}	if(destination == 0){		Bprint(pp->std[0]->fp, "To: ");		for(l = rcvers.first; l; l = l->next){			if(l != rcvers.first)				Bprint(pp->std[0]->fp, ", ");			Bprint(pp->std[0]->fp, "%s", s_to_c(l->p));		}		Bprint(pp->std[0]->fp, "\n");	}	/*	 *  add sender's domain to any domainless addresses	 *  (to avoid forging local addresses)	 */	cp = s_to_c(hdr);	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){			piperror = "write error";			status = 1;		}	}	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){		piperror = "write error 2";		status = 1;	}	s_free(hdr);	/*

⌨️ 快捷键说明

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