Beispiel #1
0
/* parse a mailbox style header */
int
parse_header(char *line, String *sender, String *date)
{
	if (!IS_HEADER(line))
		return -1;
	line += sizeof("From ") - 1;
	s_restart(sender);
	while(*line==' '||*line=='\t')
		line++;
	if(*line == '"'){
		s_putc(sender, *line++);
		while(*line && *line != '"')
			s_putc(sender, *line++);
		s_putc(sender, *line++);
	} else {
		while(*line && *line != ' ' && *line != '\t')
			s_putc(sender, *line++);
	}
	s_terminate(sender);
	s_restart(date);
	while(*line==' '||*line=='\t')
		line++;
	while(*line)
		s_putc(date, *line++);
	s_terminate(date);
	return 0;
}
Beispiel #2
0
/* Append an input line to a String.
 *
 * Returns a pointer to the character string (or 0).
 * Leading whitespace and newlines are removed.
 * Lines starting with #include cause us to descend into the new file.
 * Empty lines and other lines starting with '#' are ignored.
 */ 
extern char *
s_rdinstack(Sinstack *sp, String *to)
{
	char *p;
	Biobuf *fp, *nfp;

	s_terminate(to);
	fp = sp->fp[sp->depth];

	for(;;){
		p = rdline(fp, to);
		if(p == nil){
			if(sp->depth == 0)
				break;
			Bterm(fp);
			sp->depth--;
			return s_rdinstack(sp, to);
		}

		if(strncmp(p, "#include", 8) == 0 && (p[8] == ' ' || p[8] == '\t')){
			to->ptr = p;
			p += 8;

			/* sanity (and looping) */
			if(sp->depth >= nelem(sp->fp))
				sysfatal("s_recgetline: includes too deep");

			/* skip white */
			while(*p == ' ' || *p == '\t')
				p++;

			nfp = Bopen(p, OREAD);
			if(nfp == nil)
				continue;
			sp->depth++;
			sp->fp[sp->depth] = nfp;
			return s_rdinstack(sp, to);
		}

		/* got milk? */
		if(*p != '#')
			break;

		/* take care of comments */
		to->ptr = p;
		s_terminate(to);
	}
	return p;
}
Beispiel #3
0
/*
 *  Get the next token from `line'.  The symbol `\l' is replaced by
 *  the name of the local system.
 */
extern String *
rule_parse(String *line, char *system, int *backl)
{
	String *token;
	String *expanded;
	char *cp;

	token = s_parse(line, 0);
	if(token == 0)
		return(token);
	if(strchr(s_to_c(token), '\\')==0)
		return(token);
	expanded = s_new();
	for(cp = s_to_c(token); *cp; cp++) {
		if(*cp == '\\') switch(*++cp) {
		case 'l':
			s_append(expanded, system);
			*backl = 1;
			break;
		case '\\':
			s_putc(expanded, '\\');
			break;
		default:
			s_putc(expanded, '\\');
			s_putc(expanded, *cp);
			break;
		} else
			s_putc(expanded, *cp);
	}
	s_free(token);
	s_terminate(expanded);
	return(expanded);
}
Beispiel #4
0
/* Get the next field from a String.  The field is delimited by white space,
 * single or double quotes.
 */
String *
s_parse(String *from, String *to)
{
	if (*from->ptr == '\0')
		return 0;
	if (to == 0)
		to = s_new();
	if (*from->ptr == '\'') {
		from->ptr++;
		for (;*from->ptr != '\'' && *from->ptr != '\0'; from->ptr++)
			s_putc(to, *from->ptr);
		if (*from->ptr == '\'')	
			from->ptr++;
	} else if (*from->ptr == '"') {
		from->ptr++;
		for (;*from->ptr != '"' && *from->ptr != '\0'; from->ptr++)
			s_putc(to, *from->ptr);
		if (*from->ptr == '"')	
			from->ptr++;
	} else {
		for (;!isspace(*from->ptr) && *from->ptr != '\0'; from->ptr++)
			s_putc(to, *from->ptr);
	}
	s_terminate(to);

	/* crunch trailing white */
	while(isspace(*from->ptr))
		from->ptr++;

	return to;
}
Beispiel #5
0
/* append a char array to a String */
String *
s_append(String *to, char *from)
{
	if (to == 0)
		to = s_new();
	if (from == 0)
		return to;
	for(; *from; from++)
		s_putc(to, *from);
	s_terminate(to);
	return to;
}
Beispiel #6
0
/*
 *  Get a line including a crnl into a string.  Convert crnl into nl.
 */
char *
getcrnl(String *s)
{
	int c;
	int count;

	count = 0;
	for(;;){
		c = Bgetc(&bin);
		if(debug)
			Bputc(&berr, c);
		switch(c){
		case -1:
			s_append(s, "connection closed unexpectedly by remote system");
			s_terminate(s);
			return 0;
		case '\r':
			c = Bgetc(&bin);
			if(c == '\n'){
		case '\n':
				s_putc(s, c);
				if(debug)
					Bputc(&berr, c);
				count++;
				s_terminate(s);
				return s->ptr - count;
			}
			Bungetc(&bin);
			s_putc(s, '\r');
			if(debug)
				Bputc(&berr, '\r');
			count++;
			break;
		default:
			s_putc(s, c);
			count++;
			break;
		}
	}
}
Beispiel #7
0
/*
 *  simplify an address, reduce to a domain
 */
static String*
simplify(char *addr)
{
	int dots, dotlim;
	char *p, *at;
	String *s;

	mklower(addr);
	at = strchr(addr, '@');
	if(at == nil){
		/* local address, make it an exact match */
		s = s_copy("=");
		s_append(s, addr);
		return s;
	}

	/* copy up to, and including, the '@' sign */
	at++;
	s = s_copy("~");
	for(p = addr; p < at; p++){
		if(strchr(".*+?(|)\\[]^$", *p))
			s_putc(s, '\\');
		s_putc(s, *p);
	}

	/*
	 * just any address matching the two most significant domain elements,
	 * except for .uk, which needs three.
	 */
	s_append(s, "(.*\\.)?");
	p = addr+strlen(addr);			/* point at NUL */
	if (p[-1] == '.')
		*--p = '\0';
	if (p - addr > 3 && strcmp(".uk", p - 3) == 0)
		dotlim = 3;
	else
		dotlim = 2;
	dots = 0;
	while(--p > at)
		if(*p == '.' && ++dots >= dotlim){
			p++;
			break;
		}
	for(; *p; p++){
		if(strchr(".*+?(|)\\[]^$", *p) != nil)
			s_putc(s, '\\');
		s_putc(s, *p);
	}
	s_terminate(s);

	return s;
}
Beispiel #8
0
/* create a new `short' String */
extern String *
s_new(void)
{
	String *sp;

	sp = _s_alloc();
	if(sp == nil)
		sysfatal("s_new: %r");
	sp->base = sp->ptr = malloc(STRLEN);
	if (sp->base == nil)
		sysfatal("s_new: %r");
	sp->end = sp->base + STRLEN;
	s_terminate(sp);
	return sp;
}
Beispiel #9
0
/*
 *  simplify an address, reduce to a domain
 */
static String*
simplify(char *addr)
{
	int dots;
	char *p, *at;
	String *s;

	mklower(addr);
	at = strchr(addr, '@');
	if(at == nil){
		/* local address, make it an exact match */
		s = s_copy("=");
		s_append(s, addr);
		return s;
	}

	/* copy up to the '@' sign */
	at++;
	s = s_copy("~");
	for(p = addr; p < at; p++){
		if(strchr(".*+?(|)\\[]^$", *p))
			s_putc(s, '\\');
		s_putc(s, *p);
	}

	/* just any address matching the two most significant domain elements */
	s_append(s, "(.*\\.)?");
	p = addr+strlen(addr);
	dots = 0;
	for(; p > at; p--){
		if(*p != '.')
			continue;
		if(dots++ > 0){
			p++;
			break;
		}
	}
	for(; *p; p++){
		if(strchr(".*+?(|)\\[]^$", *p) != 0)
			s_putc(s, '\\');
		s_putc(s, *p);
	}
	s_terminate(s);

	return s;
}
Beispiel #10
0
/*  Append an input line to a String.
 *
 *  Empty lines and leading whitespace are removed.
 */
static char *
rdline(Biobuf *fp, String *to)
{
	int c;
	int len = 0;

	c = Bgetc(fp);

	/* eat leading white */
	while(c==' ' || c=='\t' || c=='\n' || c=='\r')
		c = Bgetc(fp);

	if(c < 0)
		return 0;

	for(;;){
		switch(c) {
		case -1:
			goto out;
		case '\\':
			c = Bgetc(fp);
			if (c != '\n') {
				s_putc(to, '\\');
				s_putc(to, c);
				len += 2;
			}
			break;
		case '\r':
			break;
		case '\n':
			if(len != 0)
				goto out;
			break;
		default:
			s_putc(to, c);
			len++;
			break;
		}
		c = Bgetc(fp);
	}
out:
	s_terminate(to);
	return to->ptr - len;
}
Beispiel #11
0
/*
 *  get a line that ends in crnl or cr, turn terminating crnl into a nl
 *
 *  return 0 on EOF
 */
static int
getcrnl(String *s, Biobuf *fp)
{
	int c;

	for(;;){
		c = Bgetc(fp);
		if(debug) {
			seek(2, 0, 2);
			fprint(2, "%c", c);
		}
		switch(c){
		case 0:
			break;
		case -1:
			goto out;
		case '\r':
			c = Bgetc(fp);
			if(c == '\n'){
				if(debug) {
					seek(2, 0, 2);
					fprint(2, "%c", c);
					stamp();
				}
				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);
}
Beispiel #12
0
/* create a new `short' String */
extern String *
s_newalloc(int len)
{
	String *sp;

	sp = _s_alloc();
	if(sp == nil)
		sysfatal("s_newalloc: %r");
	setmalloctag(sp, getcallerpc(&len));
	if(len < STRLEN)
		len = STRLEN;
	sp->base = sp->ptr = malloc(len);
	if (sp->base == nil)
		sysfatal("s_newalloc: %r");
	setmalloctag(sp->base, getcallerpc(&len));

	sp->end = sp->base + len;
	s_terminate(sp);
	return sp;
}
Beispiel #13
0
Datei: lex.c Projekt: lufia/wf
static int
rreadstr(char *delim, char *s)	/* if s != 0, skip this chars before reading */
{
	int c;

	s_reset(sbuf);
	if(s)
		skip(s);
	while((c=GETC()) >= 0){
		if(strchr(delim, c)){
			UNGETC(c);
			s_terminate(sbuf);
			return Tstring;
		}
		s_putc(sbuf, c);
	}
	if(c == Beof)
		yyerror("eof in string");
	return Terror;
}
Beispiel #14
0
/* get the text of a header line minus the field name */
static String*
getstring(Node *p)
{
	String *s;

	s = s_new();
	if(p == nil)
		return s;

	for(p = p->next; p; p = p->next){
		if(p->s){
			s_append(s, s_to_c(p->s));
		}else{
			s_putc(s, p->c);
			s_terminate(s);
		}
		if(p->white)
			s_append(s, s_to_c(p->white));
	}
	return s;
}
Beispiel #15
0
Datei: lex.c Projekt: lufia/wf
static int
readname(char *s)
{
	int c;

	s_reset(sbuf);
	if(s)
		skip(s);
	while((c=GETC()) >= 0 && (isalnum(c) || c == '-'))
		s_putc(sbuf, c);
	if(c == Beof){
		yyerror("eof in id/class");
		return Terror;
	}
	UNGETC(c);
	if(s_len(sbuf) == 0){
		yyerror("empty name");
		return Terror;
	}
	s_terminate(sbuf);
	return Tstring;
}
Beispiel #16
0
String *
s_dec64(String *sin)
{
	int lin, lout;
	String *sout;

	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;
}
Beispiel #17
0
Datei: lex.c Projekt: lufia/wf
int
yylex(void)
{
	int c, r;
	char c1;
	Sym *s;

genblock:
	if(block != nblock){
		if(block > nblock){
			if(debug)
				fprint(2, "%s %d -> %d\n", ty(Tend), block, nblock);
			block--;
			return Tend;
		}else{
			if(debug)
				fprint(2, "%s %d -> %d\n", ty(Tbegin), block, nblock);
			block++;
			return Tbegin;
		}
	}

	c = GETC();
	if(c == Beof){
		nblock = 0;
		if(block != nblock)
			goto genblock;
		return 0;
	}
	UNGETC(c);

	switch(state){
	case Head0:			/* [%type] string */
		c = GETC();
		if(c != '%'){
			UNGETC(c);
			setstate(Body0);
			goto genblock;
		}
		r = readname(" \t");
		if(r == Terror)
			return fail(Head2);

		s = lookup(s_to_c(sbuf));
		yylval.sym = s;
		if(debug)
			fprint(2, "Sym[%s] %s\n", ty(s->type), s->name);
		setstate(Head1);
		return s->type;

	case Head1:			/* %type [string] */
		r = readstr("\n", " \t", 0);
		if(r == Terror)
			return fail(Head2);
		yylval.s = estrdup(s_to_c(sbuf));
		if(debug)
			fprint(2, "%s %q\n", ty(Tstring), yylval.s);
		setstate(Head2);
		return Tstring;

	case Head2:
		skip(" \t");
		c = GETC();
		assert(c == '\n' || c == Beof);
		setstate(Head0);
		return ';';

	case Body0:			/* [indent] cmd inline */
		c = GETC();
		if(c == '%'){
			UNGETC(c);
			setstate(Head0);
			goto genblock;
		}
		UNGETC(c);

		r = skip(" \t");
		c = GETC();
		if(c == '\n'){
			if(debug)
				fprint(2, "%s\n", ty(Tbreak));
			return Tbreak;
		}
		UNGETC(c);

		nblock = r;
		setstate(Body1);
		goto genblock;

	case Body1:			/* indent [cmd] inline */
		switch(c = GETC()){
		case Beof:
			yyerror("eof in body");
			if(debug)
				fprint(2, "%s\n", ty(Terror));
			return fail(Body3);
		case '=':
		case '\\':
		case '+':
		case '*':
		case ':':
		case '-':
		case '>':
			if(debug)
				fprint(2, "%c\n", c);
			setstate(Body2);
			return c;
		case '!':
			if(debug)
				fprint(2, "%c\n", c);
			setstate(Code);
			return c;
		case '{':
		case '}':
			if(debug)
				fprint(2, "%c\n", c);
			setstate(Body3);
			return c;
		case '#':
			if(debug)
				fprint(2, "%c\n", c);
			setstate(ID);
			return c;
		case '.':
			if(debug)
				fprint(2, "%c\n", c);
			setstate(Class);
			return c;
		case '|':
			if(debug)
				fprint(2, "%c\n", c);
			setstate(Table);
			return c;
		default:
			UNGETC(c);
			if(debug)
				fprint(2, "\\\n");
			setstate(Body2);
			return '\\';
		}

	case Body2:			/* indent cmd [inline] */
	case Table:
		r = skip(" \t");
		if(state == Table && r > 0)
			return ',';

		switch(c = getcc(&c1, "*[]|<>")){
		case Beof:
			yyerror("eof in body");
			if(debug)
				fprint(2, "%s\n", ty(Terror));
			return fail(Body3);
		case '\n':
			UNGETC(c);
			setstate(Body3);
			break;
		case '*':
		case '[':
		case ']':
		case '|':
		case '<':
		case '>':
			if(c == '[' || c == '|' || c == '<')
				skip(" \t\n");
			if(debug)
				fprint(2, "%c\n", c);
			return c;
		default:
			s_reset(sbuf);
			s_putc(sbuf, c1);
			while((c=getcc(&c1, "*[]|<>")) == 0){
				if(state == Table && c1 == '\t'){
					UNGETC(c);
					break;
				}
				s_putc(sbuf, c1);
			}
			s_terminate(sbuf);
			if(c > 0)
				UNGETC(c);
			yylval.s = estrdup(s_to_c(sbuf));
			if(debug)
				fprint(2, "%s %q\n", ty(Tstring), yylval.s);
			return Tstring;
		}

	case Body3:
		skip(" \t");
		c = GETC();
		if(c != '\n')
			return fail(Body3);
		setstate(Body0);
		return ';';

	case Code:
		r = readstr("\n", "", 1);
		if(r == Terror){
			if(debug)
				fprint(2, "%s\n", ty(Terror));
			return fail(Body3);
		}
		setstate(Body3);
		yylval.s = estrdup(s_to_c(sbuf));
		if(debug)
			fprint(2, "%s %q\n", ty(Tstring), yylval.s);
		return Tstring;

	case ID:
	case Class:
		r = readname(" \t");
		if(r == Terror){
			if(debug)
				fprint(2, "%s\n", ty(Terror));
			return fail(Body3);
		}
		setstate(Body3);
		yylval.s = estrdup(s_to_c(sbuf));
		if(debug)
			fprint(2, "%s %q\n", ty(Tstring), yylval.s);
		return Tstring;

	default:
		assert(0);
		return Terror;
	}
}
Beispiel #18
0
void
sender(String *path)
{
	String *s;
	static char *lastsender;

	if(rejectcheck())
		return;
	if (authenticate && !authenticated) {
		rejectcount++;
		reply("530 5.7.0 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("501 5.1.3 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 5.1.8 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
	 */
	logged = 0;
	filterstate = blocked(path);
	/*
	 * permanently reject what we can before trying smtp ping, which
	 * often leads to merely temporary rejections.
	 */
	switch (filterstate){
	case DENIED:
		syslog(0, "smtpd", "Denied %s (%s/%s)",
			s_to_c(path), him, nci->rsys);
		rejectcount++;
		logged++;
		reply("554-5.7.1 We don't accept mail from %s.\r\n",
			s_to_c(path));
		reply("554 5.7.1 Contact postmaster@%s for more information.\r\n",
			dom);
		return;
	case REFUSED:
		syslog(0, "smtpd", "Refused %s (%s/%s)",
			s_to_c(path), him, nci->rsys);
		rejectcount++;
		logged++;
		reply("554 5.7.1 Sender domain must exist: %s\r\n",
			s_to_c(path));
		return;
	}

	listadd(&senders, path);
	reply("250 2.0.0 sender is %s\r\n", s_to_c(path));
}
Beispiel #19
0
static String *
substitute(String *source, Resub *subexp, message *mp)
{
	int i;
	char *s;
	char *sp;
	String *stp;
	
	if(source == 0)
		return 0;
	sp = s_to_c(source);

	/* someplace to put it */
	stp = s_new();

	/* do the substitution */
	while (*sp != '\0') {
		if(*sp == '\\') {
			switch (*++sp) {
			case '0': case '1': case '2': case '3': case '4':
			case '5': case '6': case '7': case '8': case '9':
				i = *sp-'0';
				if(subexp[i].s.sp != 0)
					for (s = subexp[i].s.sp;
					     s < subexp[i].e.ep;
					     s++)
						s_putc(stp, *s);
				break;
			case '\\':
				s_putc(stp, '\\');
				break;
			case '\0':
				sp--;
				break;
			case 's':
				for(s = s_to_c(mp->replyaddr); *s; s++)
					s_putc(stp, *s);
				break;
			case 'p':
				if(mp->bulk)
					s = "bulk";
				else
					s = "normal";
				for(;*s; s++)
					s_putc(stp, *s);
				break;
			default:
				s_putc(stp, *sp);
				break;
			}
		} else if(*sp == '&') {			
			if(subexp[0].s.sp != 0)
				for (s = subexp[0].s.sp;
				     s < subexp[0].e.ep; s++)
					s_putc(stp, *s);
		} else if(*sp == '$') {
			sp = getrcvar(sp+1, &s);
			s_append(stp, s);
			free(s);
			sp--;	/* counter sp++ below */
		} else
			s_putc(stp, *sp);
		sp++;
	}
	s_terminate(stp);

	return s_restart(stp);
}
Beispiel #20
0
/* fix 822 addresses */
static void
rfc822cruft(message *mp)
{
	Field *f;
	Node *p;
	String *body, *s;
	char *cp;

	/*
	 *  parse headers in in-core part
	 */
	yyinit(s_to_c(mp->body), s_len(mp->body));
	mp->rfc822headers = 0;
	yyparse();
	mp->rfc822headers = 1;
	mp->received = received;

	/*
	 *  remove equivalent systems in all addresses
	 */
	body = s_new();
	cp = s_to_c(mp->body);
	for(f = firstfield; f; f = f->next){
		if(f->node->c == MIMEVERSION)
			mp->havemime = 1;
		if(f->node->c == FROM)
			mp->havefrom = getaddr(f->node);
		if(f->node->c == SENDER)
			mp->havesender = getaddr(f->node);
		if(f->node->c == REPLY_TO)
			mp->havereplyto = getaddr(f->node);
		if(f->node->c == TO)
			mp->haveto = 1;
		if(f->node->c == DATE)
			mp->havedate = 1;
		if(f->node->c == SUBJECT)
			mp->havesubject = getstring(f->node);
		if(f->node->c == PRECEDENCE && f->node->next && f->node->next->next){
			s = f->node->next->next->s;
			if(s && (strcmp(s_to_c(s), "bulk") == 0
				|| strcmp(s_to_c(s), "Bulk") == 0))
					mp->bulk = 1;
		}
		for(p = f->node; p; p = p->next){
			if(p->s){
				if(p->addr){
					cp = skipequiv(s_to_c(p->s));
					s_append(body, cp);
				} else 
					s_append(body, s_to_c(p->s));
			}else{
				s_putc(body, p->c);
				s_terminate(body);
			}
			if(p->white)
				s_append(body, s_to_c(p->white));
			cp = p->end+1;
		}
		s_append(body, "\n");
	}

	if(*s_to_c(body) == 0){
		s_free(body);
		return;
	}

	if(*cp != '\n')
		s_append(body, "\n");
	s_memappend(body, cp, s_len(mp->body) - (cp - s_to_c(mp->body)));
	s_terminate(body);

	firstfield = 0;
	mp->size += s_len(body) - s_len(mp->body);
	s_free(mp->body);
	mp->body = body;
}