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

📄 smtpd.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 3 页
字号:
	 *  pass rest of message to mailer.  take care of '.'	 *  escapes.	 */	while(sawdot == 0){		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;		}		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 */		snprint(pipbuf, sizeof pipbuf, "network eof: %r");		piperror = pipbuf;		syskillpg(pp->pid);		status = 1;	}	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;}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;}intsendermxcheck(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;}voiddata(void){	String *cmd;	String *err;	int status, nbytes;	char *cp, *ep;	char errx[ERRMAX];	Link *l;	if(rejectcheck())		return;	if(senders.last == 0){		reply("503 Data without MAIL FROM:\r\n");		rejectcount++;		return;	}	if(rcvers.last == 0){		reply("503 Data without RCPT TO:\r\n");		rejectcount++;		return;	}	if(!trusted && 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)		return;	reply("354 Input message; end with <CRLF>.<CRLF>\r\n");	/*	 *  allow 145 more minutes to move the data	 */	alarm(145*60*1000);	status = pipemsg(&nbytes);	/*	 *  read any error messages	 */	err = s_new();	while(s_read_line(pp->std[2]->fp, err))		;	alarm(0);	atnotify(catchalarm, 0);	status |= proc_wait(pp);	if(debug){		seek(2, 0, 2);		fprint(2, "%d status %ux\n", getpid(), status);		if(*s_to_c(err))			fprint(2, "%d error %s\n", getpid(), s_to_c(err));	}	/*	 *  if process terminated abnormally, send back error message	 */	if(status){		int code;		if(strstr(s_to_c(err), "mail refused")){			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 %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){			*ep++ = 0;			reply("%d-%s\r\n", code, cp);		}		reply("%d mail process terminated abnormally\r\n", code);	} else {		/*		 * if a message appeared on stderr, despite good status,		 * log it.  this can happen if rewrite.in contains a bad		 * r.e., for example.		 */		if(*s_to_c(err))			syslog(0, "smtpd",				"%s returned good status, but said: %s",				s_to_c(mailer), s_to_c(err));		if(filterstate == BLOCKED)			reply("554 we believe this is spam.  we don't accept it.\r\n");		else		if(filterstate == DELAY)			reply("554 There will be a delay in delivery of this message.\r\n");		else {			reply("250 sent\r\n");			logcall(nbytes);		}	}	proc_free(pp);	pp = 0;	s_free(cmd);	s_free(err);	listfree(&senders);	listfree(&rcvers);}/* * when we have blocked a transaction based on IP address, there is nothing * that the sender can do to convince us to take the message.  after the * first rejection, some spammers continually RSET and give a new MAIL FROM: * filling our logs with rejections.  rejectcheck() limits the retries and * swiftly rejects all further commands after the first 500-series message * is issued. */intrejectcheck(void){	if(rejectcount > MAXREJECTS){		syslog(0, "smtpd", "Rejected (%s/%s)", him, nci->rsys);		reply("554 too many errors.  transaction failed.\r\n");		exits("errcount");	}	if(hardreject){		rejectcount++;		reply("554 We don't accept mail from dial-up ports.\r\n");	}	return hardreject;}/* *  create abs path of the mailer */String*mailerpath(char *p){	String *s;	if(p == nil)		return nil;	if(*p == '/')		return s_copy(p);	s = s_new();	s_append(s, UPASBIN);	s_append(s, "/");	s_append(s, p);	return s;}String *s_dec64(String *sin){	String *sout;	int lin, lout;	lin = s_len(sin);	/*	 * if the string is coming from smtpd.y, it will have no nl.	 * if it is coming from getcrnl below, it will have an nl.	 */	if (*(s_to_c(sin)+lin-1) == '\n')		lin--;	sout = s_newalloc(lin+1);	lout = dec64((uchar *)s_to_c(sout), lin, s_to_c(sin), lin);	if (lout < 0) {		s_free(sout);		return nil;	}	sout->ptr = sout->base + lout;	s_terminate(sout);	return sout;}voidstarttls(void){	uchar *cert;	int certlen, fd;	TLSconn *conn;	if (tlscert == nil) {		reply("454 TLS not available\r\n");		return;	}	conn = mallocz(sizeof *conn, 1);	cert = readcert(tlscert, &certlen);	if (conn == nil || cert == nil) {		if (conn != nil)			free(conn);		reply("454 TLS not available\r\n");		return;	}	reply("220 Go ahead make my day\r\n");	conn->cert = cert;	conn->certlen = certlen;	fd = tlsServer(Bfildes(&bin), conn);	if (fd < 0) {		free(cert);		free(conn);		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);	if (dup(fd, 1) < 0)		fprint(2, "dup of %d failed: %r\n", fd);	passwordinclear = 1;	syslog(0, "smtpd", "started TLS with %s", him);}voidauth(String *mech, String *resp){	Chalstate *chs = nil;	AuthInfo *ai = nil;	String *s_resp1_64 = nil;	String *s_resp2_64 = nil;	String *s_resp1 = nil;	String *s_resp2 = nil;	char *scratch = nil;	char *user, *pass;	if (rejectcheck())		goto bomb_out; 	syslog(0, "smtpd", "auth(%s, %s) from %s", s_to_c(mech),		"(protected)", him);	if (authenticated) {	bad_sequence:		rejectcount++;		reply("503 Bad sequence of commands\r\n");		goto bomb_out;	}	if (cistrcmp(s_to_c(mech), "plain") == 0) {		if (!passwordinclear) {			rejectcount++;			reply("538 Encryption required for requested authentication mechanism\r\n");			goto bomb_out;		}		s_resp1_64 = resp;		if (s_resp1_64 == nil) {			reply("334 \r\n");			s_resp1_64 = s_new();			if (getcrnl(s_resp1_64, &bin) <= 0) {				goto bad_sequence;			}		}		s_resp1 = s_dec64(s_resp1_64);		if (s_resp1 == nil) {			rejectcount++;			reply("501 Cannot decode base64\r\n");			goto bomb_out;		}		memset(s_to_c(s_resp1_64), 'X', s_len(s_resp1_64));		user = (s_to_c(s_resp1) + strlen(s_to_c(s_resp1)) + 1);		pass = user + (strlen(user) + 1);		ai = auth_userpasswd(user, pass);		authenticated = ai != nil;		memset(pass, 'X', strlen(pass));		goto windup;	}	else if (cistrcmp(s_to_c(mech), "login") == 0) {		if (!passwordinclear) {			rejectcount++;			reply("538 Encryption required for requested authentication mechanism\r\n");			goto bomb_out;		}		if (resp == nil) {			reply("334 VXNlcm5hbWU6\r\n");			s_resp1_64 = s_new();			if (getcrnl(s_resp1_64, &bin) <= 0)				goto bad_sequence;		}		reply("334 UGFzc3dvcmQ6\r\n");		s_resp2_64 = s_new();		if (getcrnl(s_resp2_64, &bin) <= 0)			goto bad_sequence;		s_resp1 = s_dec64(s_resp1_64);		s_resp2 = s_dec64(s_resp2_64);		memset(s_to_c(s_resp2_64), 'X', s_len(s_resp2_64));		if (s_resp1 == nil || s_resp2 == nil) {			rejectcount++;			reply("501 Cannot decode base64\r\n");			goto bomb_out;		}		ai = auth_userpasswd(s_to_c(s_resp1), s_to_c(s_resp2));		authenticated = ai != nil;		memset(s_to_c(s_resp2), 'X', s_len(s_resp2));	windup:		if (authenticated)			reply("235 Authentication successful\r\n");		else {			rejectcount++;			reply("535 Authentication failed\r\n");		}		goto bomb_out;	}	else if (cistrcmp(s_to_c(mech), "cram-md5") == 0) {		char *resp;		int chal64n;		char *t;		chs = auth_challenge("proto=cram role=server");		if (chs == nil) {			rejectcount++;			reply("501 Couldn't get CRAM-MD5 challenge\r\n");			goto bomb_out;		}		scratch = malloc(chs->nchal * 2 + 1);		chal64n = enc64(scratch, chs->nchal * 2, (uchar *)chs->chal, chs->nchal);		scratch[chal64n] = 0;		reply("334 %s\r\n", scratch);		s_resp1_64 = s_new();		if (getcrnl(s_resp1_64, &bin) <= 0)			goto bad_sequence;		s_resp1 = s_dec64(s_resp1_64);		if (s_resp1 == nil) {			rejectcount++;			reply("501 Cannot decode base64\r\n");			goto bomb_out;		}		/* should be of form <user><space><response> */		resp = s_to_c(s_resp1);		t = strchr(resp, ' ');		if (t == nil) {			rejectcount++;			reply("501 Poorly formed CRAM-MD5 response\r\n");			goto bomb_out;		}		*t++ = 0;		chs->user = resp;		chs->resp = t;		chs->nresp = strlen(t);		ai = auth_response(chs);		authenticated = ai != nil;		goto windup;	}	rejectcount++;	reply("501 Unrecognised authentication type %s\r\n", s_to_c(mech));bomb_out:	if (ai)		auth_freeAI(ai);	if (chs)		auth_freechal(chs);	if (scratch)		free(scratch);	if (s_resp1)		s_free(s_resp1);	if (s_resp2)		s_free(s_resp2);	if (s_resp1_64)		s_free(s_resp1_64);	if (s_resp2_64)		s_free(s_resp2_64);}

⌨️ 快捷键说明

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