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

📄 vf.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  this is a filter that changes mime types and names of *  suspect executable attachments. */#include "common.h"#include <ctype.h>Biobuf in;Biobuf out;typedef struct Mtype Mtype;typedef struct Hdef Hdef;typedef struct Hline Hline;typedef struct Part Part;static int	badfile(char *name);static int	badtype(char *type);static void	ctype(Part*, Hdef*, char*);static void	cencoding(Part*, Hdef*, char*);static void	cdisposition(Part*, Hdef*, char*);static int	decquoted(char *out, char *in, char *e);static char*	getstring(char *p, String *s, int dolower);static void	init_hdefs(void);static int	isattribute(char **pp, char *attr);static int	latin1toutf(char *out, char *in, char *e);static String*	mkboundary(void);static Part*	part(Part *pp);static Part*	passbody(Part *p, int dobound);static void	passnotheader(void);static void	passunixheader(void);static Part*	problemchild(Part *p);static void	readheader(Part *p);static Hline*	readhl(void);static void	readmtypes(void);static int	save(Part *p, char *file);static void	setfilename(Part *p, char *name);static char*	skiptosemi(char *p);static char*	skipwhite(char *p);static String*	tokenconvert(String *t);static void	writeheader(Part *p, int);enum{	// encodings	Enone=	0,	Ebase64,	Equoted,	// disposition possibilities	Dnone=	0,	Dinline,	Dfile,	Dignore,	PAD64=	'=',};/* *  a message part; either the whole message or a subpart */struct Part{	Part	*pp;		/* parent part */	Hline	*hl;		/* linked list of header lines */	int	disposition;	int	encoding;	int	badfile;	int	badtype;	String	*boundary;	/* boundary for multiparts */	int	blen;	String	*charset;	/* character set */	String	*type;		/* content type */	String	*filename;	/* file name */	Biobuf	*tmpbuf;		/* diversion input buffer */};/* *  a (multi)line header */struct Hline{	Hline	*next;	String		*s;};/* *  header definitions for parsing */struct Hdef{	char *type;	void (*f)(Part*, Hdef*, char*);	int len;};Hdef hdefs[] ={	{ "content-type:", ctype, },	{ "content-transfer-encoding:", cencoding, },	{ "content-disposition:", cdisposition, },	{ 0, },};/* *  acceptable content types and their extensions */struct Mtype {	Mtype	*next;	char 	*ext;		/* extension */	char	*gtype;		/* generic content type */	char	*stype;		/* specific content type */	char	class;};Mtype *mtypes;int justreject;char *savefile;voidusage(void){	fprint(2, "usage: upas/vf [-r] [-s savefile]\n");	exits("usage");}voidmain(int argc, char **argv){	ARGBEGIN{	case 'r':		justreject = 1;		break;	case 's':		savefile = EARGF(usage());		break;	default:		usage();	}ARGEND	if(argc)		usage();	Binit(&in, 0, OREAD);	Binit(&out, 1, OWRITE);	init_hdefs();	readmtypes();	/* pass through our standard 'From ' line */	passunixheader();	/* parse with the top level part */	part(nil);	exits(0);}voidrefuse(void){	postnote(PNGROUP, getpid(), "mail refused: we don't accept executable attachments");	exits("mail refused: we don't accept executable attachments");}/* *  parse a part; returns the ancestor whose boundary terminated *  this part or nil on EOF. */static Part*part(Part *pp){	Part *p, *np;	p = mallocz(sizeof *p, 1);	p->pp = pp;	readheader(p);	if(p->boundary != nil){		/* the format of a multipart part is always:		 *   header		 *   null or ignored body		 *   boundary		 *   header		 *   body		 *   boundary		 *   ...		 */		writeheader(p, 1);		np = passbody(p, 1);		if(np != p)			return np;		for(;;){			np = part(p);			if(np != p)				return np;		}	} else {		/* no boundary */		/* may still be multipart if this is a forwarded message */		if(p->type && cistrcmp(s_to_c(p->type), "message/rfc822") == 0){			/* the format of forwarded message is:			 *   header			 *   header			 *   body			 */			writeheader(p, 1);			passnotheader();			return part(p);		} else {			/* 			 * This is the meat.  This may be an executable.			 * if so, wrap it and change its type			 */			if(p->badtype || p->badfile){				if(p->badfile == 2){					if(savefile != nil)						save(p, savefile);					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 executable attachment.\n");					fprint(2, "We refuse all mail containing such.\n");					refuse();				}				np = problemchild(p);				if(np != p)					return np;				/* if problemchild returns p, it turns out p is okay: fall thru */			}			writeheader(p, 1);			return passbody(p, 1);		}	}}/* *  read and parse a complete header */static voidreadheader(Part *p){	Hline *hl, **l;	Hdef *hd;	l = &p->hl;	for(;;){		hl = readhl();		if(hl == nil)			break;		*l = hl;		l = &hl->next;		for(hd = hdefs; hd->type != nil; hd++){			if(cistrncmp(s_to_c(hl->s), hd->type, hd->len) == 0){				(*hd->f)(p, hd, s_to_c(hl->s));				break;			}		}	}}/* *  read a possibly multiline header line */static Hline*readhl(void){	Hline *hl;	String *s;	char *p;	int n;	p = Brdline(&in, '\n');	if(p == nil)		return nil;	n = Blinelen(&in);	if(memchr(p, ':', n) == nil){		Bseek(&in, -n, 1);		return nil;	}	s = s_nappend(s_new(), p, n);	for(;;){		p = Brdline(&in, '\n');		if(p == nil)			break;		n = Blinelen(&in);		if(*p != ' ' && *p != '\t'){			Bseek(&in, -n, 1);			break;		}		s = s_nappend(s, p, n);	}	hl = malloc(sizeof *hl);	hl->s = s;	hl->next = nil;	return hl;}/* *  write out a complete header */static voidwriteheader(Part *p, int xfree){	Hline *hl, *next;	for(hl = p->hl; hl != nil; hl = next){		Bprint(&out, "%s", s_to_c(hl->s));		if(xfree)			s_free(hl->s);		next = hl->next;		if(xfree)			free(hl);	}	if(xfree)		p->hl = nil;}/* *  pass a body through.  return if we hit one of our ancestors' *  boundaries or EOF.  if we hit a boundary, return a pointer to *  that ancestor.  if we hit EOF, return nil. */static Part*passbody(Part *p, int dobound){	Part *pp;	Biobuf *b;	char *cp;	for(;;){		if(p->tmpbuf){			b = p->tmpbuf;			cp = Brdline(b, '\n');			if(cp == nil){				Bterm(b);				p->tmpbuf = nil;				goto Stdin;			}		}else{		Stdin:			b = &in;			cp = Brdline(b, '\n');		}		if(cp == nil)			return nil;		for(pp = p; pp != nil; pp = pp->pp)			if(pp->boundary != nil			&& strncmp(cp, s_to_c(pp->boundary), pp->blen) == 0){				if(dobound)					Bwrite(&out, cp, Blinelen(b));				else					Bseek(b, -Blinelen(b), 1);				return pp;			}		Bwrite(&out, cp, Blinelen(b));	}}/* *  save the message somewhere */static vlong bodyoff;	/* clumsy hack */static intsave(Part *p, char *file){	int fd;	char *cp;	Bterm(&out);	memset(&out, 0, sizeof(out));	fd = open(file, OWRITE);	if(fd < 0)		return -1;	seek(fd, 0, 2);	Binit(&out, fd, OWRITE);	cp = ctime(time(0));	cp[28] = 0;	Bprint(&out, "From virusfilter %s\n", cp);	writeheader(p, 0);	bodyoff = Boffset(&out);	passbody(p, 1);	Bprint(&out, "\n");	Bterm(&out);	close(fd);		memset(&out, 0, sizeof out);	Binit(&out, 1, OWRITE);	return 0;}/* * write to a file but save the fd for passbody. */static char*savetmp(Part *p){	char buf[40], *name;	int fd;		strcpy(buf, "/tmp/vf.XXXXXXXXXXX");	name = mktemp(buf);	if((fd = create(name, OWRITE|OEXCL, 0666)) < 0){		fprint(2, "error creating temporary file: %r\n");		refuse();	}	close(fd);	if(save(p, name) < 0){		fprint(2, "error saving temporary file: %r\n");		refuse();	}	if(p->tmpbuf){		fprint(2, "error in savetmp: already have tmp file!\n");		refuse();	}	p->tmpbuf = Bopen(name, OREAD|ORCLOSE);	if(p->tmpbuf == nil){		fprint(2, "error reading tempoary file: %r\n");		refuse();	}	Bseek(p->tmpbuf, bodyoff, 0);	return strdup(name);}/* * Run the external checker to do content-based checks. */static intrunchecker(Part *p){	int pid;	char *name;	Waitmsg *w;		if(access("/mail/lib/validateattachment", AEXEC) < 0)		return 0;		name = savetmp(p);	fprint(2, "run checker %s\n", name);	switch(pid = fork()){	case -1:		sysfatal("fork: %r");	case 0:		dup(2, 1);		execl("/mail/lib/validateattachment", "validateattachment", name, nil);		_exits("exec failed");	}	/*	 * Okay to return on error - will let mail through but wrapped.	 */	w = wait();	if(w == nil){		syslog(0, "mail", "vf wait failed: %r");		return 0;	}	if(w->pid != pid){		syslog(0, "mail", "vf wrong pid %d != %d", w->pid, pid);		return 0;	}	if(p->filename)		name = s_to_c(p->filename);	if(strstr(w->msg, "discard")){		syslog(0, "mail", "vf validateattachment rejected %s", name);		refuse();	}	if(strstr(w->msg, "accept")){		syslog(0, "mail", "vf validateattachment accepted %s", name);		return 1;	}	free(w);	return 0;}/* *  emit a multipart Part that explains the problem */static Part*problemchild(Part *p){	Part *np;	Hline *hl;	String *boundary;	char *cp;	/*	 * We don't know whether the attachment is okay.	 * If there's an external checker, let it have a crack at it.	 */	if(runchecker(p) > 0)		return p;	if(justreject)		return p;fprint(2, "x\n");	syslog(0, "mail", "vf wrapped %s %s", p->type?s_to_c(p->type):"?",		p->filename?s_to_c(p->filename):"?");fprint(2, "x\n");	boundary = mkboundary();fprint(2, "x\n");	/* print out non-mime headers */	for(hl = p->hl; hl != nil; hl = hl->next)		if(cistrncmp(s_to_c(hl->s), "content-", 8) != 0)			Bprint(&out, "%s", s_to_c(hl->s));fprint(2, "x\n");	/* add in our own multipart headers and message */	Bprint(&out, "Content-Type: multipart/mixed;\n");	Bprint(&out, "\tboundary=\"%s\"\n", s_to_c(boundary));	Bprint(&out, "Content-Disposition: inline\n");	Bprint(&out, "\n");	Bprint(&out, "This is a multi-part message in MIME format.\n");	Bprint(&out, "--%s\n", s_to_c(boundary));	Bprint(&out, "Content-Disposition: inline\n");	Bprint(&out, "Content-Type: text/plain; charset=\"US-ASCII\"\n");	Bprint(&out, "Content-Transfer-Encoding: 7bit\n");	Bprint(&out, "\n");	Bprint(&out, "from postmaster@%s:\n", sysname());	Bprint(&out, "The following attachment had content that we can't\n");	Bprint(&out, "prove to be harmless.  To avoid possible automatic\n");	Bprint(&out, "execution, we changed the content headers.\n");	Bprint(&out, "The original header was:\n\n");	/* print out original header lines */	for(hl = p->hl; hl != nil; hl = hl->next)		if(cistrncmp(s_to_c(hl->s), "content-", 8) == 0)			Bprint(&out, "\t%s", s_to_c(hl->s));	Bprint(&out, "--%s\n", s_to_c(boundary));	/* change file name */	if(p->filename)		s_append(p->filename, ".suspect");	else		p->filename = s_copy("file.suspect");	/* print out new header */	Bprint(&out, "Content-Type: application/octet-stream\n");	Bprint(&out, "Content-Disposition: attachment; filename=\"%s\"\n", s_to_c(p->filename));	switch(p->encoding){	case Enone:		break;	case Ebase64:		Bprint(&out, "Content-Transfer-Encoding: base64\n");		break;	case Equoted:		Bprint(&out, "Content-Transfer-Encoding: quoted-printable\n");		break;	}fprint(2, "z\n");	/* pass the body */	np = passbody(p, 0);fprint(2, "w\n");	/* add the new boundary and the original terminator */	Bprint(&out, "--%s--\n", s_to_c(boundary));

⌨️ 快捷键说明

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