util.c revision 43730
138032Speter/*
238032Speter * Copyright (c) 1998 Sendmail, Inc.  All rights reserved.
338032Speter * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
438032Speter * Copyright (c) 1988, 1993
538032Speter *	The Regents of the University of California.  All rights reserved.
638032Speter *
738032Speter * By using this file, you agree to the terms and conditions set
838032Speter * forth in the LICENSE file which can be found at the top level of
938032Speter * the sendmail distribution.
1038032Speter *
1138032Speter */
1238032Speter
1338032Speter#ifndef lint
1443730Speterstatic char sccsid[] = "@(#)util.c	8.168 (Berkeley) 1/21/1999";
1538032Speter#endif /* not lint */
1638032Speter
1738032Speter# include "sendmail.h"
1838032Speter# include <sysexits.h>
1938032Speter/*
2038032Speter**  STRIPQUOTES -- Strip quotes & quote bits from a string.
2138032Speter**
2238032Speter**	Runs through a string and strips off unquoted quote
2338032Speter**	characters and quote bits.  This is done in place.
2438032Speter**
2538032Speter**	Parameters:
2638032Speter**		s -- the string to strip.
2738032Speter**
2838032Speter**	Returns:
2938032Speter**		none.
3038032Speter**
3138032Speter**	Side Effects:
3238032Speter**		none.
3338032Speter**
3438032Speter**	Called By:
3538032Speter**		deliver
3638032Speter*/
3738032Speter
3838032Spetervoid
3938032Speterstripquotes(s)
4038032Speter	char *s;
4138032Speter{
4238032Speter	register char *p;
4338032Speter	register char *q;
4438032Speter	register char c;
4538032Speter
4638032Speter	if (s == NULL)
4738032Speter		return;
4838032Speter
4938032Speter	p = q = s;
5038032Speter	do
5138032Speter	{
5238032Speter		c = *p++;
5338032Speter		if (c == '\\')
5438032Speter			c = *p++;
5538032Speter		else if (c == '"')
5638032Speter			continue;
5738032Speter		*q++ = c;
5838032Speter	} while (c != '\0');
5938032Speter}
6038032Speter/*
6138032Speter**  ADDQUOTES -- Adds quotes & quote bits to a string.
6238032Speter**
6338032Speter**	Runs through a string and adds characters and quote bits.
6438032Speter**
6538032Speter**	Parameters:
6638032Speter**		s -- the string to modify.
6738032Speter**
6838032Speter**	Returns:
6938032Speter**		pointer to quoted string.
7038032Speter**
7138032Speter**	Side Effects:
7238032Speter**		none.
7338032Speter**
7438032Speter*/
7538032Speter
7638032Speterchar *
7738032Speteraddquotes(s)
7838032Speter	char *s;
7938032Speter{
8038032Speter	int len = 0;
8138032Speter	char c;
8238032Speter	char *p = s, *q, *r;
8338032Speter
8438032Speter	if (s == NULL)
8538032Speter		return NULL;
8638032Speter
8738032Speter	/* Find length of quoted string */
8838032Speter	while ((c = *p++) != '\0')
8938032Speter	{
9038032Speter		len++;
9138032Speter		if (c == '\\' || c == '"')
9238032Speter			len++;
9338032Speter	}
9438032Speter
9538032Speter	q = r = xalloc(len + 3);
9638032Speter	p = s;
9738032Speter
9838032Speter	/* add leading quote */
9938032Speter	*q++ = '"';
10038032Speter	while ((c = *p++) != '\0')
10138032Speter	{
10238032Speter		/* quote \ or " */
10338032Speter		if (c == '\\' || c == '"')
10438032Speter			*q++ = '\\';
10538032Speter		*q++ = c;
10638032Speter	}
10738032Speter	*q++ = '"';
10838032Speter	*q = '\0';
10938032Speter	return r;
11038032Speter}
11138032Speter/*
11238032Speter**  RFC822_STRING -- Checks string for proper RFC822 string quoting.
11338032Speter**
11438032Speter**	Runs through a string and verifies RFC822 special characters
11538032Speter**	are only found inside comments, quoted strings, or backslash
11638032Speter**	escaped.  Also verified balanced quotes and parenthesis.
11738032Speter**
11838032Speter**	Parameters:
11938032Speter**		s -- the string to modify.
12038032Speter**
12138032Speter**	Returns:
12238032Speter**		TRUE -- if the string is RFC822 compliant.
12338032Speter**		FALSE -- if the string is not RFC822 compliant.
12438032Speter**
12538032Speter**	Side Effects:
12638032Speter**		none.
12738032Speter**
12838032Speter*/
12938032Speter
13038032Speterbool
13138032Speterrfc822_string(s)
13238032Speter	char *s;
13338032Speter{
13438032Speter	bool quoted = FALSE;
13538032Speter	int commentlev = 0;
13638032Speter	char *c = s;
13738032Speter
13838032Speter	if (s == NULL)
13938032Speter		return FALSE;
14038032Speter
14138032Speter	while (*c != '\0')
14238032Speter	{
14338032Speter		/* escaped character */
14438032Speter		if (*c == '\\')
14538032Speter		{
14638032Speter			c++;
14738032Speter			if (*c == '\0')
14838032Speter				return FALSE;
14938032Speter		}
15038032Speter		else if (commentlev == 0 && *c == '"')
15138032Speter			quoted = !quoted;
15238032Speter		else if (!quoted)
15338032Speter		{
15438032Speter			if (*c == ')')
15538032Speter			{
15638032Speter				/* unbalanced ')' */
15738032Speter				if (commentlev == 0)
15838032Speter					return FALSE;
15938032Speter				else
16038032Speter					commentlev--;
16138032Speter			}
16238032Speter			else if (*c == '(')
16338032Speter				commentlev++;
16438032Speter			else if (commentlev == 0 &&
16538032Speter				 strchr(MustQuoteChars, *c) != NULL)
16638032Speter				return FALSE;
16738032Speter		}
16838032Speter		c++;
16938032Speter	}
17038032Speter	/* unbalanced '"' or '(' */
17138032Speter	if (quoted || commentlev != 0)
17238032Speter		return FALSE;
17338032Speter	else
17438032Speter		return TRUE;
17538032Speter}
17638032Speter/*
17742575Speter**  SHORTEN_RFC822_STRING -- Truncate and rebalance an RFC822 string
17842575Speter**
17942575Speter**	Arbitratily shorten (in place) an RFC822 string and rebalance
18042575Speter**	comments and quotes.
18142575Speter**
18242575Speter**	Parameters:
18342575Speter**		string -- the string to shorten
18442575Speter**		length -- the maximum size, 0 if no maximum
18542575Speter**
18642575Speter**	Returns:
18742575Speter**		TRUE if string is changed, FALSE otherwise
18842575Speter**
18942575Speter**	Side Effects:
19042575Speter**		Changes string in place, possibly resulting
19142575Speter**		in a shorter string.
19242575Speter*/
19342575Speter
19442575Speterbool
19542575Spetershorten_rfc822_string(string, length)
19642575Speter	char *string;
19742575Speter	size_t length;
19842575Speter{
19942575Speter	bool backslash = FALSE;
20042575Speter	bool modified = FALSE;
20142575Speter	bool quoted = FALSE;
20242575Speter	size_t slen;
20342575Speter	int parencount = 0;
20442575Speter	char *ptr = string;
20542575Speter
20642575Speter	/*
20742575Speter	**  If have to rebalance an already short enough string,
20842575Speter	**  need to do it within allocated space.
20942575Speter	*/
21042575Speter	slen = strlen(string);
21142575Speter	if (length == 0 || slen < length)
21242575Speter		length = slen;
21342575Speter
21442575Speter	while (*ptr != '\0')
21542575Speter	{
21642575Speter		if (backslash)
21742575Speter		{
21842575Speter			backslash = FALSE;
21942575Speter			goto increment;
22042575Speter		}
22142575Speter
22242575Speter		if (*ptr == '\\')
22342575Speter			backslash = TRUE;
22442575Speter		else if (*ptr == '(')
22542575Speter		{
22642575Speter			if (!quoted)
22742575Speter				parencount++;
22842575Speter		}
22942575Speter		else if (*ptr == ')')
23042575Speter		{
23142575Speter			if (--parencount < 0)
23242575Speter				parencount = 0;
23342575Speter		}
23442575Speter
23542575Speter		/* Inside a comment, quotes don't matter */
23642575Speter		if (parencount <= 0 && *ptr == '"')
23742575Speter			quoted = !quoted;
23842575Speter
23942575Speterincrement:
24042575Speter		/* Check for sufficient space for next character */
24142575Speter		if (length - (ptr - string) <= ((backslash ? 1 : 0) +
24242575Speter						parencount +
24342575Speter						(quoted ? 1 : 0)))
24442575Speter		{
24542575Speter			/* Not enough, backtrack */
24642575Speter			if (*ptr == '\\')
24742575Speter				backslash = FALSE;
24842575Speter			else if (*ptr == '(' && !quoted)
24942575Speter				parencount--;
25042575Speter			else if (*ptr == '"' && parencount == 0)
25142575Speter				quoted = FALSE;
25242575Speter			break;
25342575Speter		}
25442575Speter		ptr++;
25542575Speter	}
25642575Speter
25742575Speter	/* Rebalance */
25842575Speter	while (parencount-- > 0)
25942575Speter	{
26042575Speter		if (*ptr != ')')
26142575Speter		{
26242575Speter			modified = TRUE;
26342575Speter			*ptr = ')';
26442575Speter		}
26542575Speter		ptr++;
26642575Speter	}
26742575Speter	if (quoted)
26842575Speter	{
26942575Speter		if (*ptr != '"')
27042575Speter		{
27142575Speter			modified = TRUE;
27242575Speter			*ptr = '"';
27342575Speter		}
27442575Speter		ptr++;
27542575Speter	}
27642575Speter	if (*ptr != '\0')
27742575Speter	{
27842575Speter		modified = TRUE;
27942575Speter		*ptr = '\0';
28042575Speter	}
28142575Speter	return modified;
28242575Speter}
28342575Speter/*
28442575Speter**  FIND_CHARACTER -- find an unquoted character in an RFC822 string
28542575Speter**
28642575Speter**	Find an unquoted, non-commented character in an RFC822
28742575Speter**	string and return a pointer to its location in the
28842575Speter**	string.
28942575Speter**
29042575Speter**	Parameters:
29142575Speter**		string -- the string to search
29242575Speter**		character -- the character to find
29342575Speter**
29442575Speter**	Returns:
29542575Speter**		pointer to the character, or
29642575Speter**		a pointer to the end of the line if character is not found
29742575Speter*/
29842575Speter
29942575Speterchar *
30042575Speterfind_character(string, character)
30142575Speter	char *string;
30242575Speter	char character;
30342575Speter{
30442575Speter	bool backslash = FALSE;
30542575Speter	bool quoted = FALSE;
30642575Speter	int parencount = 0;
30742575Speter
30842575Speter	while (string != NULL && *string != '\0')
30942575Speter	{
31042575Speter		if (backslash)
31142575Speter		{
31242575Speter			backslash = FALSE;
31342575Speter			if (!quoted && character == '\\' && *string == '\\')
31442575Speter				break;
31542575Speter			string++;
31642575Speter			continue;
31742575Speter		}
31842575Speter		switch (*string)
31942575Speter		{
32042575Speter		  case '\\':
32142575Speter			backslash = TRUE;
32242575Speter			break;
32342575Speter
32442575Speter		  case '(':
32542575Speter			if (!quoted)
32642575Speter				parencount++;
32742575Speter			break;
32842575Speter
32942575Speter		  case ')':
33042575Speter			if (--parencount < 0)
33142575Speter				parencount = 0;
33242575Speter			break;
33342575Speter		}
33442575Speter
33542575Speter		/* Inside a comment, nothing matters */
33642575Speter		if (parencount > 0)
33742575Speter		{
33842575Speter			string++;
33942575Speter			continue;
34042575Speter		}
34142575Speter
34242575Speter		if (*string == '"')
34342575Speter			quoted = !quoted;
34442575Speter		else if (*string == character && !quoted)
34542575Speter			break;
34642575Speter		string++;
34742575Speter	}
34842575Speter
34942575Speter	/* Return pointer to the character */
35042575Speter	return string;
35142575Speter}
35242575Speter/*
35338032Speter**  XALLOC -- Allocate memory and bitch wildly on failure.
35438032Speter**
35538032Speter**	THIS IS A CLUDGE.  This should be made to give a proper
35638032Speter**	error -- but after all, what can we do?
35738032Speter**
35838032Speter**	Parameters:
35938032Speter**		sz -- size of area to allocate.
36038032Speter**
36138032Speter**	Returns:
36238032Speter**		pointer to data region.
36338032Speter**
36438032Speter**	Side Effects:
36538032Speter**		Memory is allocated.
36638032Speter*/
36738032Speter
36838032Speterchar *
36938032Speterxalloc(sz)
37038032Speter	register int sz;
37138032Speter{
37238032Speter	register char *p;
37338032Speter
37438032Speter	/* some systems can't handle size zero mallocs */
37538032Speter	if (sz <= 0)
37638032Speter		sz = 1;
37738032Speter
37838032Speter	p = malloc((unsigned) sz);
37938032Speter	if (p == NULL)
38038032Speter	{
38138032Speter		syserr("!Out of memory!!");
38238032Speter		/* exit(EX_UNAVAILABLE); */
38338032Speter	}
38438032Speter	return (p);
38538032Speter}
38638032Speter/*
38738032Speter**  COPYPLIST -- copy list of pointers.
38838032Speter**
38938032Speter**	This routine is the equivalent of newstr for lists of
39038032Speter**	pointers.
39138032Speter**
39238032Speter**	Parameters:
39338032Speter**		list -- list of pointers to copy.
39438032Speter**			Must be NULL terminated.
39538032Speter**		copycont -- if TRUE, copy the contents of the vector
39638032Speter**			(which must be a string) also.
39738032Speter**
39838032Speter**	Returns:
39938032Speter**		a copy of 'list'.
40038032Speter**
40138032Speter**	Side Effects:
40238032Speter**		none.
40338032Speter*/
40438032Speter
40538032Speterchar **
40638032Spetercopyplist(list, copycont)
40738032Speter	char **list;
40838032Speter	bool copycont;
40938032Speter{
41038032Speter	register char **vp;
41138032Speter	register char **newvp;
41238032Speter
41338032Speter	for (vp = list; *vp != NULL; vp++)
41438032Speter		continue;
41538032Speter
41638032Speter	vp++;
41738032Speter
41838032Speter	newvp = (char **) xalloc((int) (vp - list) * sizeof *vp);
41938032Speter	bcopy((char *) list, (char *) newvp, (int) (vp - list) * sizeof *vp);
42038032Speter
42138032Speter	if (copycont)
42238032Speter	{
42338032Speter		for (vp = newvp; *vp != NULL; vp++)
42438032Speter			*vp = newstr(*vp);
42538032Speter	}
42638032Speter
42738032Speter	return (newvp);
42838032Speter}
42938032Speter/*
43038032Speter**  COPYQUEUE -- copy address queue.
43138032Speter**
43238032Speter**	This routine is the equivalent of newstr for address queues
43338032Speter**	addresses marked with QDONTSEND aren't copied
43438032Speter**
43538032Speter**	Parameters:
43638032Speter**		addr -- list of address structures to copy.
43738032Speter**
43838032Speter**	Returns:
43938032Speter**		a copy of 'addr'.
44038032Speter**
44138032Speter**	Side Effects:
44238032Speter**		none.
44338032Speter*/
44438032Speter
44538032SpeterADDRESS *
44638032Spetercopyqueue(addr)
44738032Speter	ADDRESS *addr;
44838032Speter{
44938032Speter	register ADDRESS *newaddr;
45038032Speter	ADDRESS *ret;
45138032Speter	register ADDRESS **tail = &ret;
45238032Speter
45338032Speter	while (addr != NULL)
45438032Speter	{
45538032Speter		if (!bitset(QDONTSEND, addr->q_flags))
45638032Speter		{
45738032Speter			newaddr = (ADDRESS *) xalloc(sizeof(ADDRESS));
45838032Speter			STRUCTCOPY(*addr, *newaddr);
45938032Speter			*tail = newaddr;
46038032Speter			tail = &newaddr->q_next;
46138032Speter		}
46238032Speter		addr = addr->q_next;
46338032Speter	}
46438032Speter	*tail = NULL;
46538032Speter
46638032Speter	return ret;
46738032Speter}
46838032Speter/*
46938032Speter**  PRINTAV -- print argument vector.
47038032Speter**
47138032Speter**	Parameters:
47238032Speter**		av -- argument vector.
47338032Speter**
47438032Speter**	Returns:
47538032Speter**		none.
47638032Speter**
47738032Speter**	Side Effects:
47838032Speter**		prints av.
47938032Speter*/
48038032Speter
48138032Spetervoid
48238032Speterprintav(av)
48338032Speter	register char **av;
48438032Speter{
48538032Speter	while (*av != NULL)
48638032Speter	{
48738032Speter		if (tTd(0, 44))
48838032Speter			printf("\n\t%08lx=", (u_long) *av);
48938032Speter		else
49038032Speter			(void) putchar(' ');
49138032Speter		xputs(*av++);
49238032Speter	}
49338032Speter	(void) putchar('\n');
49438032Speter}
49538032Speter/*
49638032Speter**  LOWER -- turn letter into lower case.
49738032Speter**
49838032Speter**	Parameters:
49938032Speter**		c -- character to turn into lower case.
50038032Speter**
50138032Speter**	Returns:
50238032Speter**		c, in lower case.
50338032Speter**
50438032Speter**	Side Effects:
50538032Speter**		none.
50638032Speter*/
50738032Speter
50838032Speterchar
50938032Speterlower(c)
51038032Speter	register char c;
51138032Speter{
51238032Speter	return((isascii(c) && isupper(c)) ? tolower(c) : c);
51338032Speter}
51438032Speter/*
51538032Speter**  XPUTS -- put string doing control escapes.
51638032Speter**
51738032Speter**	Parameters:
51838032Speter**		s -- string to put.
51938032Speter**
52038032Speter**	Returns:
52138032Speter**		none.
52238032Speter**
52338032Speter**	Side Effects:
52438032Speter**		output to stdout
52538032Speter*/
52638032Speter
52738032Spetervoid
52838032Speterxputs(s)
52938032Speter	register const char *s;
53038032Speter{
53138032Speter	register int c;
53238032Speter	register struct metamac *mp;
53338032Speter	bool shiftout = FALSE;
53438032Speter	extern struct metamac MetaMacros[];
53538032Speter
53638032Speter	if (s == NULL)
53738032Speter	{
53838032Speter		printf("%s<null>%s", TermEscape.te_rv_on, TermEscape.te_rv_off);
53938032Speter		return;
54038032Speter	}
54138032Speter	while ((c = (*s++ & 0377)) != '\0')
54238032Speter	{
54338032Speter		if (shiftout)
54438032Speter		{
54538032Speter			printf("%s", TermEscape.te_rv_off);
54638032Speter			shiftout = FALSE;
54738032Speter		}
54838032Speter		if (!isascii(c))
54938032Speter		{
55038032Speter			if (c == MATCHREPL)
55138032Speter			{
55238032Speter				printf("%s$", TermEscape.te_rv_on);
55338032Speter				shiftout = TRUE;
55438032Speter				if (*s == '\0')
55538032Speter					continue;
55638032Speter				c = *s++ & 0377;
55738032Speter				goto printchar;
55838032Speter			}
55938032Speter			if (c == MACROEXPAND || c == MACRODEXPAND)
56038032Speter			{
56138032Speter				printf("%s$", TermEscape.te_rv_on);
56238032Speter				if (c == MACRODEXPAND)
56338032Speter					putchar('&');
56438032Speter				shiftout = TRUE;
56538032Speter				if (*s == '\0')
56638032Speter					continue;
56738032Speter				if (strchr("=~&?", *s) != NULL)
56838032Speter					putchar(*s++);
56938032Speter				if (bitset(0200, *s))
57038032Speter					printf("{%s}", macname(*s++ & 0377));
57138032Speter				else
57238032Speter					printf("%c", *s++);
57338032Speter				continue;
57438032Speter			}
57538032Speter			for (mp = MetaMacros; mp->metaname != '\0'; mp++)
57638032Speter			{
57738032Speter				if ((mp->metaval & 0377) == c)
57838032Speter				{
57938032Speter					printf("%s$%c",
58038032Speter						TermEscape.te_rv_on,
58138032Speter						mp->metaname);
58238032Speter					shiftout = TRUE;
58338032Speter					break;
58438032Speter				}
58538032Speter			}
58638032Speter			if (c == MATCHCLASS || c == MATCHNCLASS)
58738032Speter			{
58838032Speter				if (bitset(0200, *s))
58938032Speter					printf("{%s}", macname(*s++ & 0377));
59038032Speter				else if (*s != '\0')
59138032Speter					printf("%c", *s++);
59238032Speter			}
59338032Speter			if (mp->metaname != '\0')
59438032Speter				continue;
59538032Speter
59638032Speter			/* unrecognized meta character */
59738032Speter			printf("%sM-", TermEscape.te_rv_on);
59838032Speter			shiftout = TRUE;
59938032Speter			c &= 0177;
60038032Speter		}
60138032Speter  printchar:
60238032Speter		if (isprint(c))
60338032Speter		{
60438032Speter			putchar(c);
60538032Speter			continue;
60638032Speter		}
60738032Speter
60838032Speter		/* wasn't a meta-macro -- find another way to print it */
60938032Speter		switch (c)
61038032Speter		{
61138032Speter		  case '\n':
61238032Speter			c = 'n';
61338032Speter			break;
61438032Speter
61538032Speter		  case '\r':
61638032Speter			c = 'r';
61738032Speter			break;
61838032Speter
61938032Speter		  case '\t':
62038032Speter			c = 't';
62138032Speter			break;
62238032Speter		}
62338032Speter		if (!shiftout)
62438032Speter		{
62538032Speter			printf("%s", TermEscape.te_rv_on);
62638032Speter			shiftout = TRUE;
62738032Speter		}
62838032Speter		if (isprint(c))
62938032Speter		{
63038032Speter			(void) putchar('\\');
63138032Speter			(void) putchar(c);
63238032Speter		}
63338032Speter		else
63438032Speter		{
63538032Speter			(void) putchar('^');
63638032Speter			(void) putchar(c ^ 0100);
63738032Speter		}
63838032Speter	}
63938032Speter	if (shiftout)
64038032Speter		printf("%s", TermEscape.te_rv_off);
64138032Speter	(void) fflush(stdout);
64238032Speter}
64338032Speter/*
64438032Speter**  MAKELOWER -- Translate a line into lower case
64538032Speter**
64638032Speter**	Parameters:
64738032Speter**		p -- the string to translate.  If NULL, return is
64838032Speter**			immediate.
64938032Speter**
65038032Speter**	Returns:
65138032Speter**		none.
65238032Speter**
65338032Speter**	Side Effects:
65438032Speter**		String pointed to by p is translated to lower case.
65538032Speter**
65638032Speter**	Called By:
65738032Speter**		parse
65838032Speter*/
65938032Speter
66038032Spetervoid
66138032Spetermakelower(p)
66238032Speter	register char *p;
66338032Speter{
66438032Speter	register char c;
66538032Speter
66638032Speter	if (p == NULL)
66738032Speter		return;
66838032Speter	for (; (c = *p) != '\0'; p++)
66938032Speter		if (isascii(c) && isupper(c))
67038032Speter			*p = tolower(c);
67138032Speter}
67238032Speter/*
67338032Speter**  BUILDFNAME -- build full name from gecos style entry.
67438032Speter**
67538032Speter**	This routine interprets the strange entry that would appear
67638032Speter**	in the GECOS field of the password file.
67738032Speter**
67838032Speter**	Parameters:
67938032Speter**		p -- name to build.
68038032Speter**		login -- the login name of this user (for &).
68138032Speter**		buf -- place to put the result.
68238032Speter**		buflen -- length of buf.
68338032Speter**
68438032Speter**	Returns:
68538032Speter**		none.
68638032Speter**
68738032Speter**	Side Effects:
68838032Speter**		none.
68938032Speter*/
69038032Speter
69138032Spetervoid
69238032Speterbuildfname(gecos, login, buf, buflen)
69338032Speter	register char *gecos;
69438032Speter	char *login;
69538032Speter	char *buf;
69638032Speter	int buflen;
69738032Speter{
69838032Speter	register char *p;
69938032Speter	register char *bp = buf;
70038032Speter
70138032Speter	if (*gecos == '*')
70238032Speter		gecos++;
70338032Speter
70438032Speter	/* copy gecos, interpolating & to be full name */
70538032Speter	for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++)
70638032Speter	{
70738032Speter		if (bp >= &buf[buflen - 1])
70838032Speter		{
70938032Speter			/* buffer overflow -- just use login name */
71038032Speter			snprintf(buf, buflen, "%s", login);
71138032Speter			return;
71238032Speter		}
71338032Speter		if (*p == '&')
71438032Speter		{
71538032Speter			/* interpolate full name */
71638032Speter			snprintf(bp, buflen - (bp - buf), "%s", login);
71738032Speter			*bp = toupper(*bp);
71838032Speter			bp += strlen(bp);
71938032Speter		}
72038032Speter		else
72138032Speter			*bp++ = *p;
72238032Speter	}
72338032Speter	*bp = '\0';
72438032Speter}
72538032Speter/*
72638032Speter**  FIXCRLF -- fix <CR><LF> in line.
72738032Speter**
72838032Speter**	Looks for the <CR><LF> combination and turns it into the
72938032Speter**	UNIX canonical <NL> character.  It only takes one line,
73038032Speter**	i.e., it is assumed that the first <NL> found is the end
73138032Speter**	of the line.
73238032Speter**
73338032Speter**	Parameters:
73438032Speter**		line -- the line to fix.
73538032Speter**		stripnl -- if true, strip the newline also.
73638032Speter**
73738032Speter**	Returns:
73838032Speter**		none.
73938032Speter**
74038032Speter**	Side Effects:
74138032Speter**		line is changed in place.
74238032Speter*/
74338032Speter
74438032Spetervoid
74538032Speterfixcrlf(line, stripnl)
74638032Speter	char *line;
74738032Speter	bool stripnl;
74838032Speter{
74938032Speter	register char *p;
75038032Speter
75138032Speter	p = strchr(line, '\n');
75238032Speter	if (p == NULL)
75338032Speter		return;
75438032Speter	if (p > line && p[-1] == '\r')
75538032Speter		p--;
75638032Speter	if (!stripnl)
75738032Speter		*p++ = '\n';
75838032Speter	*p = '\0';
75938032Speter}
76038032Speter/*
76138032Speter**  PUTLINE -- put a line like fputs obeying SMTP conventions
76238032Speter**
76338032Speter**	This routine always guarantees outputing a newline (or CRLF,
76438032Speter**	as appropriate) at the end of the string.
76538032Speter**
76638032Speter**	Parameters:
76738032Speter**		l -- line to put.
76838032Speter**		mci -- the mailer connection information.
76938032Speter**
77038032Speter**	Returns:
77138032Speter**		none
77238032Speter**
77338032Speter**	Side Effects:
77438032Speter**		output of l to fp.
77538032Speter*/
77638032Speter
77738032Spetervoid
77838032Speterputline(l, mci)
77938032Speter	register char *l;
78038032Speter	register MCI *mci;
78138032Speter{
78238032Speter	putxline(l, strlen(l), mci, PXLF_MAPFROM);
78338032Speter}
78438032Speter/*
78538032Speter**  PUTXLINE -- putline with flags bits.
78638032Speter**
78738032Speter**	This routine always guarantees outputing a newline (or CRLF,
78838032Speter**	as appropriate) at the end of the string.
78938032Speter**
79038032Speter**	Parameters:
79138032Speter**		l -- line to put.
79238032Speter**		len -- the length of the line.
79338032Speter**		mci -- the mailer connection information.
79438032Speter**		pxflags -- flag bits:
79538032Speter**		    PXLF_MAPFROM -- map From_ to >From_.
79638032Speter**		    PXLF_STRIP8BIT -- strip 8th bit.
79738032Speter**		    PXLF_HEADER -- map bare newline in header to newline space.
79838032Speter**
79938032Speter**	Returns:
80038032Speter**		none
80138032Speter**
80238032Speter**	Side Effects:
80338032Speter**		output of l to fp.
80438032Speter*/
80538032Speter
80638032Spetervoid
80738032Speterputxline(l, len, mci, pxflags)
80838032Speter	register char *l;
80938032Speter	size_t len;
81038032Speter	register MCI *mci;
81138032Speter	int pxflags;
81238032Speter{
81338032Speter	register char *p, *end;
81438032Speter	int slop = 0;
81538032Speter	size_t eol_len = strlen(mci->mci_mailer->m_eol);
81638032Speter
81738032Speter	/* strip out 0200 bits -- these can look like TELNET protocol */
81838032Speter	if (bitset(MCIF_7BIT, mci->mci_flags) ||
81938032Speter	    bitset(PXLF_STRIP8BIT, pxflags))
82038032Speter	{
82138032Speter		register char svchar;
82238032Speter
82338032Speter		for (p = l; (svchar = *p) != '\0'; ++p)
82438032Speter			if (bitset(0200, svchar))
82538032Speter				*p = svchar &~ 0200;
82638032Speter	}
82738032Speter
82838032Speter	end = l + len;
82938032Speter	do
83038032Speter	{
83138032Speter		/* find the end of the line */
83238032Speter		p = memchr(l, '\n', end - l);
83338032Speter		if (p == NULL)
83438032Speter			p = end;
83538032Speter
83638032Speter		if (TrafficLogFile != NULL)
83738032Speter			fprintf(TrafficLogFile, "%05d >>> ", (int) getpid());
83838032Speter
83938032Speter		/* check for line overflow */
84038032Speter		while (mci->mci_mailer->m_linelimit > 0 &&
84138032Speter		       (p - l + slop) > mci->mci_mailer->m_linelimit)
84238032Speter		{
84338032Speter			char *l_base = l;
84438032Speter			register char *q = &l[mci->mci_mailer->m_linelimit - slop - 1];
84538032Speter
84638032Speter			if (l[0] == '.' && slop == 0 &&
84738032Speter			    bitnset(M_XDOT, mci->mci_mailer->m_flags))
84838032Speter			{
84938032Speter				(void) putc('.', mci->mci_out);
85038032Speter				if (!bitset(MCIF_INHEADER, mci->mci_flags))
85138032Speter					mci->mci_contentlen++;
85238032Speter				if (TrafficLogFile != NULL)
85338032Speter					(void) putc('.', TrafficLogFile);
85438032Speter			}
85538032Speter			else if (l[0] == 'F' && slop == 0 &&
85638032Speter				 bitset(PXLF_MAPFROM, pxflags) &&
85738032Speter				 strncmp(l, "From ", 5) == 0 &&
85838032Speter				 bitnset(M_ESCFROM, mci->mci_mailer->m_flags))
85938032Speter			{
86038032Speter				(void) putc('>', mci->mci_out);
86138032Speter				if (!bitset(MCIF_INHEADER, mci->mci_flags))
86238032Speter					mci->mci_contentlen++;
86338032Speter				if (TrafficLogFile != NULL)
86438032Speter					(void) putc('>', TrafficLogFile);
86538032Speter			}
86638032Speter			while (l < q)
86738032Speter			{
86838032Speter				(void) putc(*l++, mci->mci_out);
86938032Speter				if (!bitset(MCIF_INHEADER, mci->mci_flags))
87038032Speter					mci->mci_contentlen++;
87138032Speter			}
87238032Speter			(void) putc('!', mci->mci_out);
87338032Speter			if (!bitset(MCIF_INHEADER, mci->mci_flags))
87438032Speter				mci->mci_contentlen++;
87538032Speter			fputs(mci->mci_mailer->m_eol, mci->mci_out);
87638032Speter			if (!bitset(MCIF_INHEADER, mci->mci_flags))
87738032Speter				mci->mci_contentlen += eol_len;
87838032Speter			(void) putc(' ', mci->mci_out);
87938032Speter			if (!bitset(MCIF_INHEADER, mci->mci_flags))
88038032Speter				mci->mci_contentlen++;
88138032Speter			if (TrafficLogFile != NULL)
88238032Speter			{
88338032Speter				for (l = l_base; l < q; l++)
88438032Speter					(void) putc(*l, TrafficLogFile);
88538032Speter				fprintf(TrafficLogFile, "!\n%05d >>>  ",
88638032Speter					(int) getpid());
88738032Speter			}
88838032Speter			slop = 1;
88938032Speter		}
89038032Speter
89138032Speter		/* output last part */
89238032Speter		if (l[0] == '.' && slop == 0 &&
89338032Speter		    bitnset(M_XDOT, mci->mci_mailer->m_flags))
89438032Speter		{
89538032Speter			(void) putc('.', mci->mci_out);
89638032Speter			if (!bitset(MCIF_INHEADER, mci->mci_flags))
89738032Speter				mci->mci_contentlen++;
89838032Speter			if (TrafficLogFile != NULL)
89938032Speter				(void) putc('.', TrafficLogFile);
90038032Speter		}
90138032Speter		else if (l[0] == 'F' && slop == 0 &&
90238032Speter			 bitset(PXLF_MAPFROM, pxflags) &&
90338032Speter			 strncmp(l, "From ", 5) == 0 &&
90438032Speter			 bitnset(M_ESCFROM, mci->mci_mailer->m_flags))
90538032Speter		{
90638032Speter			(void) putc('>', mci->mci_out);
90738032Speter			if (!bitset(MCIF_INHEADER, mci->mci_flags))
90838032Speter				mci->mci_contentlen++;
90938032Speter			if (TrafficLogFile != NULL)
91038032Speter				(void) putc('>', TrafficLogFile);
91138032Speter		}
91238032Speter		for ( ; l < p; ++l)
91338032Speter		{
91438032Speter			if (TrafficLogFile != NULL)
91538032Speter				(void) putc(*l, TrafficLogFile);
91638032Speter			(void) putc(*l, mci->mci_out);
91738032Speter			if (!bitset(MCIF_INHEADER, mci->mci_flags))
91838032Speter				mci->mci_contentlen++;
91938032Speter		}
92038032Speter		if (TrafficLogFile != NULL)
92138032Speter			(void) putc('\n', TrafficLogFile);
92238032Speter		fputs(mci->mci_mailer->m_eol, mci->mci_out);
92338032Speter		if (!bitset(MCIF_INHEADER, mci->mci_flags))
92438032Speter			mci->mci_contentlen += eol_len;
92538032Speter		if (l < end && *l == '\n')
92638032Speter		{
92738032Speter			if (*++l != ' ' && *l != '\t' && *l != '\0' &&
92838032Speter			    bitset(PXLF_HEADER, pxflags))
92938032Speter			{
93038032Speter				(void) putc(' ', mci->mci_out);
93138032Speter				if (!bitset(MCIF_INHEADER, mci->mci_flags))
93238032Speter					mci->mci_contentlen++;
93338032Speter				if (TrafficLogFile != NULL)
93438032Speter					(void) putc(' ', TrafficLogFile);
93538032Speter			}
93638032Speter		}
93738032Speter	} while (l < end);
93838032Speter}
93938032Speter/*
94038032Speter**  XUNLINK -- unlink a file, doing logging as appropriate.
94138032Speter**
94238032Speter**	Parameters:
94338032Speter**		f -- name of file to unlink.
94438032Speter**
94538032Speter**	Returns:
94638032Speter**		none.
94738032Speter**
94838032Speter**	Side Effects:
94938032Speter**		f is unlinked.
95038032Speter*/
95138032Speter
95238032Spetervoid
95338032Speterxunlink(f)
95438032Speter	char *f;
95538032Speter{
95638032Speter	register int i;
95738032Speter
95838032Speter	if (LogLevel > 98)
95938032Speter		sm_syslog(LOG_DEBUG, CurEnv->e_id,
96038032Speter			"unlink %s",
96138032Speter			f);
96238032Speter
96338032Speter	i = unlink(f);
96438032Speter	if (i < 0 && LogLevel > 97)
96538032Speter		sm_syslog(LOG_DEBUG, CurEnv->e_id,
96638032Speter			"%s: unlink-fail %d",
96738032Speter			f, errno);
96838032Speter}
96938032Speter/*
97038032Speter**  XFCLOSE -- close a file, doing logging as appropriate.
97138032Speter**
97238032Speter**	Parameters:
97338032Speter**		fp -- file pointer for the file to close
97438032Speter**		a, b -- miscellaneous crud to print for debugging
97538032Speter**
97638032Speter**	Returns:
97738032Speter**		none.
97838032Speter**
97938032Speter**	Side Effects:
98038032Speter**		fp is closed.
98138032Speter*/
98238032Speter
98338032Spetervoid
98438032Speterxfclose(fp, a, b)
98538032Speter	FILE *fp;
98638032Speter	char *a, *b;
98738032Speter{
98838032Speter	if (tTd(53, 99))
98938032Speter		printf("xfclose(%lx) %s %s\n", (u_long) fp, a, b);
99038032Speter#if XDEBUG
99138032Speter	if (fileno(fp) == 1)
99238032Speter		syserr("xfclose(%s %s): fd = 1", a, b);
99338032Speter#endif
99438032Speter	if (fclose(fp) < 0 && tTd(53, 99))
99538032Speter		printf("xfclose FAILURE: %s\n", errstring(errno));
99638032Speter}
99738032Speter/*
99838032Speter**  SFGETS -- "safe" fgets -- times out and ignores random interrupts.
99938032Speter**
100038032Speter**	Parameters:
100138032Speter**		buf -- place to put the input line.
100238032Speter**		siz -- size of buf.
100338032Speter**		fp -- file to read from.
100438032Speter**		timeout -- the timeout before error occurs.
100538032Speter**		during -- what we are trying to read (for error messages).
100638032Speter**
100738032Speter**	Returns:
100838032Speter**		NULL on error (including timeout).  This will also leave
100938032Speter**			buf containing a null string.
101038032Speter**		buf otherwise.
101138032Speter**
101238032Speter**	Side Effects:
101338032Speter**		none.
101438032Speter*/
101538032Speter
101638032Speterstatic jmp_buf	CtxReadTimeout;
101738032Speterstatic void	readtimeout __P((time_t));
101838032Speter
101938032Speterchar *
102038032Spetersfgets(buf, siz, fp, timeout, during)
102138032Speter	char *buf;
102238032Speter	int siz;
102338032Speter	FILE *fp;
102438032Speter	time_t timeout;
102538032Speter	char *during;
102638032Speter{
102738032Speter	register EVENT *ev = NULL;
102838032Speter	register char *p;
102943730Speter	int save_errno;
103038032Speter
103138032Speter	if (fp == NULL)
103238032Speter	{
103338032Speter		buf[0] = '\0';
103438032Speter		return NULL;
103538032Speter	}
103638032Speter
103738032Speter	/* set the timeout */
103838032Speter	if (timeout != 0)
103938032Speter	{
104038032Speter		if (setjmp(CtxReadTimeout) != 0)
104138032Speter		{
104238032Speter			if (LogLevel > 1)
104338032Speter				sm_syslog(LOG_NOTICE, CurEnv->e_id,
104438032Speter				       "timeout waiting for input from %.100s during %s",
104538032Speter				       CurHostName ? CurHostName : "local",
104638032Speter				       during);
104738032Speter			buf[0] = '\0';
104838032Speter#if XDEBUG
104938032Speter			checkfd012(during);
105038032Speter#endif
105138032Speter			if (TrafficLogFile != NULL)
105238032Speter				fprintf(TrafficLogFile, "%05d <<< [TIMEOUT]\n",
105338032Speter					(int) getpid());
105443730Speter			errno = 0;
105538032Speter			return (NULL);
105638032Speter		}
105738032Speter		ev = setevent(timeout, readtimeout, 0);
105838032Speter	}
105938032Speter
106038032Speter	/* try to read */
106138032Speter	p = NULL;
106243730Speter	errno = 0;
106338032Speter	while (!feof(fp) && !ferror(fp))
106438032Speter	{
106538032Speter		errno = 0;
106638032Speter		p = fgets(buf, siz, fp);
106738032Speter		if (p != NULL || errno != EINTR)
106838032Speter			break;
106938032Speter		clearerr(fp);
107038032Speter	}
107143730Speter	save_errno = errno;
107238032Speter
107338032Speter	/* clear the event if it has not sprung */
107438032Speter	clrevent(ev);
107538032Speter
107638032Speter	/* clean up the books and exit */
107738032Speter	LineNumber++;
107838032Speter	if (p == NULL)
107938032Speter	{
108038032Speter		buf[0] = '\0';
108138032Speter		if (TrafficLogFile != NULL)
108238032Speter			fprintf(TrafficLogFile, "%05d <<< [EOF]\n", (int) getpid());
108343730Speter		errno = save_errno;
108438032Speter		return (NULL);
108538032Speter	}
108638032Speter	if (TrafficLogFile != NULL)
108738032Speter		fprintf(TrafficLogFile, "%05d <<< %s", (int) getpid(), buf);
108838032Speter	if (SevenBitInput)
108938032Speter	{
109038032Speter		for (p = buf; *p != '\0'; p++)
109138032Speter			*p &= ~0200;
109238032Speter	}
109338032Speter	else if (!HasEightBits)
109438032Speter	{
109538032Speter		for (p = buf; *p != '\0'; p++)
109638032Speter		{
109738032Speter			if (bitset(0200, *p))
109838032Speter			{
109938032Speter				HasEightBits = TRUE;
110038032Speter				break;
110138032Speter			}
110238032Speter		}
110338032Speter	}
110438032Speter	return (buf);
110538032Speter}
110638032Speter
110738032Speter/* ARGSUSED */
110838032Speterstatic void
110938032Speterreadtimeout(timeout)
111038032Speter	time_t timeout;
111138032Speter{
111238032Speter	longjmp(CtxReadTimeout, 1);
111338032Speter}
111438032Speter/*
111538032Speter**  FGETFOLDED -- like fgets, but know about folded lines.
111638032Speter**
111738032Speter**	Parameters:
111838032Speter**		buf -- place to put result.
111938032Speter**		n -- bytes available.
112038032Speter**		f -- file to read from.
112138032Speter**
112238032Speter**	Returns:
112338032Speter**		input line(s) on success, NULL on error or EOF.
112438032Speter**		This will normally be buf -- unless the line is too
112538032Speter**			long, when it will be xalloc()ed.
112638032Speter**
112738032Speter**	Side Effects:
112838032Speter**		buf gets lines from f, with continuation lines (lines
112938032Speter**		with leading white space) appended.  CRLF's are mapped
113038032Speter**		into single newlines.  Any trailing NL is stripped.
113138032Speter*/
113238032Speter
113338032Speterchar *
113438032Speterfgetfolded(buf, n, f)
113538032Speter	char *buf;
113638032Speter	register int n;
113738032Speter	FILE *f;
113838032Speter{
113938032Speter	register char *p = buf;
114038032Speter	char *bp = buf;
114138032Speter	register int i;
114238032Speter
114338032Speter	n--;
114438032Speter	while ((i = getc(f)) != EOF)
114538032Speter	{
114638032Speter		if (i == '\r')
114738032Speter		{
114838032Speter			i = getc(f);
114938032Speter			if (i != '\n')
115038032Speter			{
115138032Speter				if (i != EOF)
115238032Speter					(void) ungetc(i, f);
115338032Speter				i = '\r';
115438032Speter			}
115538032Speter		}
115638032Speter		if (--n <= 0)
115738032Speter		{
115838032Speter			/* allocate new space */
115938032Speter			char *nbp;
116038032Speter			int nn;
116138032Speter
116238032Speter			nn = (p - bp);
116338032Speter			if (nn < MEMCHUNKSIZE)
116438032Speter				nn *= 2;
116538032Speter			else
116638032Speter				nn += MEMCHUNKSIZE;
116738032Speter			nbp = xalloc(nn);
116838032Speter			bcopy(bp, nbp, p - bp);
116938032Speter			p = &nbp[p - bp];
117038032Speter			if (bp != buf)
117138032Speter				free(bp);
117238032Speter			bp = nbp;
117338032Speter			n = nn - (p - bp);
117438032Speter		}
117538032Speter		*p++ = i;
117638032Speter		if (i == '\n')
117738032Speter		{
117838032Speter			LineNumber++;
117938032Speter			i = getc(f);
118038032Speter			if (i != EOF)
118138032Speter				(void) ungetc(i, f);
118238032Speter			if (i != ' ' && i != '\t')
118338032Speter				break;
118438032Speter		}
118538032Speter	}
118638032Speter	if (p == bp)
118738032Speter		return (NULL);
118838032Speter	if (p[-1] == '\n')
118938032Speter		p--;
119038032Speter	*p = '\0';
119138032Speter	return (bp);
119238032Speter}
119338032Speter/*
119438032Speter**  CURTIME -- return current time.
119538032Speter**
119638032Speter**	Parameters:
119738032Speter**		none.
119838032Speter**
119938032Speter**	Returns:
120038032Speter**		the current time.
120138032Speter**
120238032Speter**	Side Effects:
120338032Speter**		none.
120438032Speter*/
120538032Speter
120638032Spetertime_t
120738032Spetercurtime()
120838032Speter{
120938032Speter	auto time_t t;
121038032Speter
121138032Speter	(void) time(&t);
121238032Speter	return (t);
121338032Speter}
121438032Speter/*
121538032Speter**  ATOBOOL -- convert a string representation to boolean.
121638032Speter**
121738032Speter**	Defaults to "TRUE"
121838032Speter**
121938032Speter**	Parameters:
122038032Speter**		s -- string to convert.  Takes "tTyY" as true,
122138032Speter**			others as false.
122238032Speter**
122338032Speter**	Returns:
122438032Speter**		A boolean representation of the string.
122538032Speter**
122638032Speter**	Side Effects:
122738032Speter**		none.
122838032Speter*/
122938032Speter
123038032Speterbool
123138032Speteratobool(s)
123238032Speter	register char *s;
123338032Speter{
123438032Speter	if (s == NULL || *s == '\0' || strchr("tTyY", *s) != NULL)
123538032Speter		return (TRUE);
123638032Speter	return (FALSE);
123738032Speter}
123838032Speter/*
123938032Speter**  ATOOCT -- convert a string representation to octal.
124038032Speter**
124138032Speter**	Parameters:
124238032Speter**		s -- string to convert.
124338032Speter**
124438032Speter**	Returns:
124538032Speter**		An integer representing the string interpreted as an
124638032Speter**		octal number.
124738032Speter**
124838032Speter**	Side Effects:
124938032Speter**		none.
125038032Speter*/
125138032Speter
125238032Speterint
125338032Speteratooct(s)
125438032Speter	register char *s;
125538032Speter{
125638032Speter	register int i = 0;
125738032Speter
125838032Speter	while (*s >= '0' && *s <= '7')
125938032Speter		i = (i << 3) | (*s++ - '0');
126038032Speter	return (i);
126138032Speter}
126238032Speter/*
126338032Speter**  BITINTERSECT -- tell if two bitmaps intersect
126438032Speter**
126538032Speter**	Parameters:
126638032Speter**		a, b -- the bitmaps in question
126738032Speter**
126838032Speter**	Returns:
126938032Speter**		TRUE if they have a non-null intersection
127038032Speter**		FALSE otherwise
127138032Speter**
127238032Speter**	Side Effects:
127338032Speter**		none.
127438032Speter*/
127538032Speter
127638032Speterbool
127738032Speterbitintersect(a, b)
127838032Speter	BITMAP a;
127938032Speter	BITMAP b;
128038032Speter{
128138032Speter	int i;
128238032Speter
128338032Speter	for (i = BITMAPBYTES / sizeof (int); --i >= 0; )
128438032Speter		if ((a[i] & b[i]) != 0)
128538032Speter			return (TRUE);
128638032Speter	return (FALSE);
128738032Speter}
128838032Speter/*
128938032Speter**  BITZEROP -- tell if a bitmap is all zero
129038032Speter**
129138032Speter**	Parameters:
129238032Speter**		map -- the bit map to check
129338032Speter**
129438032Speter**	Returns:
129538032Speter**		TRUE if map is all zero.
129638032Speter**		FALSE if there are any bits set in map.
129738032Speter**
129838032Speter**	Side Effects:
129938032Speter**		none.
130038032Speter*/
130138032Speter
130238032Speterbool
130338032Speterbitzerop(map)
130438032Speter	BITMAP map;
130538032Speter{
130638032Speter	int i;
130738032Speter
130838032Speter	for (i = BITMAPBYTES / sizeof (int); --i >= 0; )
130938032Speter		if (map[i] != 0)
131038032Speter			return (FALSE);
131138032Speter	return (TRUE);
131238032Speter}
131338032Speter/*
131438032Speter**  STRCONTAINEDIN -- tell if one string is contained in another
131538032Speter**
131638032Speter**	Parameters:
131738032Speter**		a -- possible substring.
131838032Speter**		b -- possible superstring.
131938032Speter**
132038032Speter**	Returns:
132138032Speter**		TRUE if a is contained in b.
132238032Speter**		FALSE otherwise.
132338032Speter*/
132438032Speter
132538032Speterbool
132638032Speterstrcontainedin(a, b)
132738032Speter	register char *a;
132838032Speter	register char *b;
132938032Speter{
133038032Speter	int la;
133138032Speter	int lb;
133238032Speter	int c;
133338032Speter
133438032Speter	la = strlen(a);
133538032Speter	lb = strlen(b);
133638032Speter	c = *a;
133738032Speter	if (isascii(c) && isupper(c))
133838032Speter		c = tolower(c);
133938032Speter	for (; lb-- >= la; b++)
134038032Speter	{
134138032Speter		if (*b != c && isascii(*b) && isupper(*b) && tolower(*b) != c)
134238032Speter			continue;
134338032Speter		if (strncasecmp(a, b, la) == 0)
134438032Speter			return TRUE;
134538032Speter	}
134638032Speter	return FALSE;
134738032Speter}
134838032Speter/*
134938032Speter**  CHECKFD012 -- check low numbered file descriptors
135038032Speter**
135138032Speter**	File descriptors 0, 1, and 2 should be open at all times.
135238032Speter**	This routine verifies that, and fixes it if not true.
135338032Speter**
135438032Speter**	Parameters:
135538032Speter**		where -- a tag printed if the assertion failed
135638032Speter**
135738032Speter**	Returns:
135838032Speter**		none
135938032Speter*/
136038032Speter
136138032Spetervoid
136238032Spetercheckfd012(where)
136338032Speter	char *where;
136438032Speter{
136538032Speter#if XDEBUG
136638032Speter	register int i;
136738032Speter
136838032Speter	for (i = 0; i < 3; i++)
136938032Speter		fill_fd(i, where);
137038032Speter#endif /* XDEBUG */
137138032Speter}
137238032Speter/*
137338032Speter**  CHECKFDOPEN -- make sure file descriptor is open -- for extended debugging
137438032Speter**
137538032Speter**	Parameters:
137638032Speter**		fd -- file descriptor to check.
137738032Speter**		where -- tag to print on failure.
137838032Speter**
137938032Speter**	Returns:
138038032Speter**		none.
138138032Speter*/
138238032Speter
138338032Spetervoid
138438032Spetercheckfdopen(fd, where)
138538032Speter	int fd;
138638032Speter	char *where;
138738032Speter{
138838032Speter#if XDEBUG
138938032Speter	struct stat st;
139038032Speter
139138032Speter	if (fstat(fd, &st) < 0 && errno == EBADF)
139238032Speter	{
139338032Speter		syserr("checkfdopen(%d): %s not open as expected!", fd, where);
139438032Speter		printopenfds(TRUE);
139538032Speter	}
139638032Speter#endif
139738032Speter}
139838032Speter/*
139938032Speter**  CHECKFDS -- check for new or missing file descriptors
140038032Speter**
140138032Speter**	Parameters:
140238032Speter**		where -- tag for printing.  If null, take a base line.
140338032Speter**
140438032Speter**	Returns:
140538032Speter**		none
140638032Speter**
140738032Speter**	Side Effects:
140838032Speter**		If where is set, shows changes since the last call.
140938032Speter*/
141038032Speter
141138032Spetervoid
141238032Spetercheckfds(where)
141338032Speter	char *where;
141438032Speter{
141538032Speter	int maxfd;
141638032Speter	register int fd;
141738032Speter	bool printhdr = TRUE;
141838032Speter	int save_errno = errno;
141938032Speter	static BITMAP baseline;
142038032Speter	extern int DtableSize;
142138032Speter
142238032Speter	if (DtableSize > 256)
142338032Speter		maxfd = 256;
142438032Speter	else
142538032Speter		maxfd = DtableSize;
142638032Speter	if (where == NULL)
142738032Speter		clrbitmap(baseline);
142838032Speter
142938032Speter	for (fd = 0; fd < maxfd; fd++)
143038032Speter	{
143138032Speter		struct stat stbuf;
143238032Speter
143338032Speter		if (fstat(fd, &stbuf) < 0 && errno != EOPNOTSUPP)
143438032Speter		{
143538032Speter			if (!bitnset(fd, baseline))
143638032Speter				continue;
143738032Speter			clrbitn(fd, baseline);
143838032Speter		}
143938032Speter		else if (!bitnset(fd, baseline))
144038032Speter			setbitn(fd, baseline);
144138032Speter		else
144238032Speter			continue;
144338032Speter
144438032Speter		/* file state has changed */
144538032Speter		if (where == NULL)
144638032Speter			continue;
144738032Speter		if (printhdr)
144838032Speter		{
144938032Speter			sm_syslog(LOG_DEBUG, CurEnv->e_id,
145038032Speter				"%s: changed fds:",
145138032Speter				where);
145238032Speter			printhdr = FALSE;
145338032Speter		}
145438032Speter		dumpfd(fd, TRUE, TRUE);
145538032Speter	}
145638032Speter	errno = save_errno;
145738032Speter}
145838032Speter/*
145938032Speter**  PRINTOPENFDS -- print the open file descriptors (for debugging)
146038032Speter**
146138032Speter**	Parameters:
146238032Speter**		logit -- if set, send output to syslog; otherwise
146338032Speter**			print for debugging.
146438032Speter**
146538032Speter**	Returns:
146638032Speter**		none.
146738032Speter*/
146838032Speter
146938032Speter#include <arpa/inet.h>
147038032Speter
147138032Spetervoid
147238032Speterprintopenfds(logit)
147338032Speter	bool logit;
147438032Speter{
147538032Speter	register int fd;
147638032Speter	extern int DtableSize;
147738032Speter
147838032Speter	for (fd = 0; fd < DtableSize; fd++)
147938032Speter		dumpfd(fd, FALSE, logit);
148038032Speter}
148138032Speter/*
148238032Speter**  DUMPFD -- dump a file descriptor
148338032Speter**
148438032Speter**	Parameters:
148538032Speter**		fd -- the file descriptor to dump.
148638032Speter**		printclosed -- if set, print a notification even if
148738032Speter**			it is closed; otherwise print nothing.
148838032Speter**		logit -- if set, send output to syslog instead of stdout.
148938032Speter*/
149038032Speter
149138032Spetervoid
149238032Speterdumpfd(fd, printclosed, logit)
149338032Speter	int fd;
149438032Speter	bool printclosed;
149538032Speter	bool logit;
149638032Speter{
149738032Speter	register char *p;
149838032Speter	char *hp;
149938032Speter#ifdef S_IFSOCK
150038032Speter	SOCKADDR sa;
150138032Speter#endif
150238032Speter	auto SOCKADDR_LEN_T slen;
150338032Speter	int i;
150438032Speter#if STAT64 > 0
150538032Speter	struct stat64 st;
150638032Speter#else
150738032Speter	struct stat st;
150838032Speter#endif
150938032Speter	char buf[200];
151038032Speter
151138032Speter	p = buf;
151238032Speter	snprintf(p, SPACELEFT(buf, p), "%3d: ", fd);
151338032Speter	p += strlen(p);
151438032Speter
151538032Speter	if (
151638032Speter#if STAT64 > 0
151738032Speter	    fstat64(fd, &st)
151838032Speter#else
151938032Speter	    fstat(fd, &st)
152038032Speter#endif
152138032Speter	    < 0)
152238032Speter	{
152338032Speter		if (errno != EBADF)
152438032Speter		{
152538032Speter			snprintf(p, SPACELEFT(buf, p), "CANNOT STAT (%s)",
152638032Speter				errstring(errno));
152738032Speter			goto printit;
152838032Speter		}
152938032Speter		else if (printclosed)
153038032Speter		{
153138032Speter			snprintf(p, SPACELEFT(buf, p), "CLOSED");
153238032Speter			goto printit;
153338032Speter		}
153438032Speter		return;
153538032Speter	}
153638032Speter
153738032Speter	i = fcntl(fd, F_GETFL, NULL);
153838032Speter	if (i != -1)
153938032Speter	{
154038032Speter		snprintf(p, SPACELEFT(buf, p), "fl=0x%x, ", i);
154138032Speter		p += strlen(p);
154238032Speter	}
154338032Speter
154438032Speter	snprintf(p, SPACELEFT(buf, p), "mode=%o: ", st.st_mode);
154538032Speter	p += strlen(p);
154638032Speter	switch (st.st_mode & S_IFMT)
154738032Speter	{
154838032Speter#ifdef S_IFSOCK
154938032Speter	  case S_IFSOCK:
155038032Speter		snprintf(p, SPACELEFT(buf, p), "SOCK ");
155138032Speter		p += strlen(p);
155238032Speter		slen = sizeof sa;
155338032Speter		if (getsockname(fd, &sa.sa, &slen) < 0)
155438032Speter			snprintf(p, SPACELEFT(buf, p), "(%s)", errstring(errno));
155538032Speter		else
155638032Speter		{
155738032Speter			hp = hostnamebyanyaddr(&sa);
155838032Speter			if (sa.sa.sa_family == AF_INET)
155938032Speter				snprintf(p, SPACELEFT(buf, p), "%s/%d",
156038032Speter					hp, ntohs(sa.sin.sin_port));
156138032Speter			else
156238032Speter				snprintf(p, SPACELEFT(buf, p), "%s", hp);
156338032Speter		}
156438032Speter		p += strlen(p);
156538032Speter		snprintf(p, SPACELEFT(buf, p), "->");
156638032Speter		p += strlen(p);
156738032Speter		slen = sizeof sa;
156838032Speter		if (getpeername(fd, &sa.sa, &slen) < 0)
156938032Speter			snprintf(p, SPACELEFT(buf, p), "(%s)", errstring(errno));
157038032Speter		else
157138032Speter		{
157238032Speter			hp = hostnamebyanyaddr(&sa);
157338032Speter			if (sa.sa.sa_family == AF_INET)
157438032Speter				snprintf(p, SPACELEFT(buf, p), "%s/%d",
157538032Speter					hp, ntohs(sa.sin.sin_port));
157638032Speter			else
157738032Speter				snprintf(p, SPACELEFT(buf, p), "%s", hp);
157838032Speter		}
157938032Speter		break;
158038032Speter#endif
158138032Speter
158238032Speter	  case S_IFCHR:
158338032Speter		snprintf(p, SPACELEFT(buf, p), "CHR: ");
158438032Speter		p += strlen(p);
158538032Speter		goto defprint;
158638032Speter
158738032Speter	  case S_IFBLK:
158838032Speter		snprintf(p, SPACELEFT(buf, p), "BLK: ");
158938032Speter		p += strlen(p);
159038032Speter		goto defprint;
159138032Speter
159238032Speter#if defined(S_IFIFO) && (!defined(S_IFSOCK) || S_IFIFO != S_IFSOCK)
159338032Speter	  case S_IFIFO:
159438032Speter		snprintf(p, SPACELEFT(buf, p), "FIFO: ");
159538032Speter		p += strlen(p);
159638032Speter		goto defprint;
159738032Speter#endif
159838032Speter
159938032Speter#ifdef S_IFDIR
160038032Speter	  case S_IFDIR:
160138032Speter		snprintf(p, SPACELEFT(buf, p), "DIR: ");
160238032Speter		p += strlen(p);
160338032Speter		goto defprint;
160438032Speter#endif
160538032Speter
160638032Speter#ifdef S_IFLNK
160738032Speter	  case S_IFLNK:
160838032Speter		snprintf(p, SPACELEFT(buf, p), "LNK: ");
160938032Speter		p += strlen(p);
161038032Speter		goto defprint;
161138032Speter#endif
161238032Speter
161338032Speter	  default:
161438032Speterdefprint:
161538032Speter		if (sizeof st.st_ino > sizeof (long))
161638032Speter			snprintf(p, SPACELEFT(buf, p),
161738032Speter				 "dev=%d/%d, ino=%s, nlink=%d, u/gid=%d/%d, ",
161838032Speter				 major(st.st_dev), minor(st.st_dev),
161938032Speter				 quad_to_string(st.st_ino),
162038032Speter				 st.st_nlink, st.st_uid, st.st_gid);
162138032Speter		else
162238032Speter			snprintf(p, SPACELEFT(buf, p),
162338032Speter				"dev=%d/%d, ino=%lu, nlink=%d, u/gid=%d/%d, ",
162438032Speter				major(st.st_dev), minor(st.st_dev),
162538032Speter				(unsigned long) st.st_ino,
162638032Speter				st.st_nlink, st.st_uid, st.st_gid);
162738032Speter		if (sizeof st.st_size > sizeof (long))
162838032Speter			snprintf(p, SPACELEFT(buf, p), "size=%s",
162938032Speter				 quad_to_string(st.st_size));
163038032Speter		else
163138032Speter			snprintf(p, SPACELEFT(buf, p), "size=%lu",
163238032Speter				 (unsigned long) st.st_size);
163338032Speter		break;
163438032Speter	}
163538032Speter
163638032Speterprintit:
163738032Speter	if (logit)
163838032Speter		sm_syslog(LOG_DEBUG, CurEnv ? CurEnv->e_id : NULL,
163938032Speter			"%.800s", buf);
164038032Speter	else
164138032Speter		printf("%s\n", buf);
164238032Speter}
164338032Speter/*
164438032Speter**  SHORTEN_HOSTNAME -- strip local domain information off of hostname.
164538032Speter**
164638032Speter**	Parameters:
164738032Speter**		host -- the host to shorten (stripped in place).
164838032Speter**
164938032Speter**	Returns:
165038032Speter**		none.
165138032Speter*/
165238032Speter
165338032Spetervoid
165438032Spetershorten_hostname(host)
165538032Speter	char host[];
165638032Speter{
165738032Speter	register char *p;
165838032Speter	char *mydom;
165938032Speter	int i;
166038032Speter	bool canon = FALSE;
166138032Speter
166238032Speter	/* strip off final dot */
166338032Speter	p = &host[strlen(host) - 1];
166438032Speter	if (*p == '.')
166538032Speter	{
166638032Speter		*p = '\0';
166738032Speter		canon = TRUE;
166838032Speter	}
166938032Speter
167038032Speter	/* see if there is any domain at all -- if not, we are done */
167138032Speter	p = strchr(host, '.');
167238032Speter	if (p == NULL)
167338032Speter		return;
167438032Speter
167538032Speter	/* yes, we have a domain -- see if it looks like us */
167638032Speter	mydom = macvalue('m', CurEnv);
167738032Speter	if (mydom == NULL)
167838032Speter		mydom = "";
167938032Speter	i = strlen(++p);
168038032Speter	if ((canon ? strcasecmp(p, mydom) : strncasecmp(p, mydom, i)) == 0 &&
168138032Speter	    (mydom[i] == '.' || mydom[i] == '\0'))
168238032Speter		*--p = '\0';
168338032Speter}
168438032Speter/*
168538032Speter**  PROG_OPEN -- open a program for reading
168638032Speter**
168738032Speter**	Parameters:
168838032Speter**		argv -- the argument list.
168938032Speter**		pfd -- pointer to a place to store the file descriptor.
169038032Speter**		e -- the current envelope.
169138032Speter**
169238032Speter**	Returns:
169338032Speter**		pid of the process -- -1 if it failed.
169438032Speter*/
169538032Speter
169638032Speterint
169738032Speterprog_open(argv, pfd, e)
169838032Speter	char **argv;
169938032Speter	int *pfd;
170038032Speter	ENVELOPE *e;
170138032Speter{
170238032Speter	int pid;
170338032Speter	int i;
170438032Speter	int saveerrno;
170538032Speter	int fdv[2];
170638032Speter	char *p, *q;
170738032Speter	char buf[MAXLINE + 1];
170838032Speter	extern int DtableSize;
170938032Speter
171038032Speter	if (pipe(fdv) < 0)
171138032Speter	{
171238032Speter		syserr("%s: cannot create pipe for stdout", argv[0]);
171338032Speter		return -1;
171438032Speter	}
171538032Speter	pid = fork();
171638032Speter	if (pid < 0)
171738032Speter	{
171838032Speter		syserr("%s: cannot fork", argv[0]);
171938032Speter		close(fdv[0]);
172038032Speter		close(fdv[1]);
172138032Speter		return -1;
172238032Speter	}
172338032Speter	if (pid > 0)
172438032Speter	{
172538032Speter		/* parent */
172638032Speter		close(fdv[1]);
172738032Speter		*pfd = fdv[0];
172838032Speter		return pid;
172938032Speter	}
173038032Speter
173138032Speter	/* child -- close stdin */
173238032Speter	close(0);
173338032Speter
173438032Speter	/* stdout goes back to parent */
173538032Speter	close(fdv[0]);
173638032Speter	if (dup2(fdv[1], 1) < 0)
173738032Speter	{
173838032Speter		syserr("%s: cannot dup2 for stdout", argv[0]);
173938032Speter		_exit(EX_OSERR);
174038032Speter	}
174138032Speter	close(fdv[1]);
174238032Speter
174338032Speter	/* stderr goes to transcript if available */
174438032Speter	if (e->e_xfp != NULL)
174538032Speter	{
174638032Speter		if (dup2(fileno(e->e_xfp), 2) < 0)
174738032Speter		{
174838032Speter			syserr("%s: cannot dup2 for stderr", argv[0]);
174938032Speter			_exit(EX_OSERR);
175038032Speter		}
175138032Speter	}
175238032Speter
175338032Speter	/* this process has no right to the queue file */
175438032Speter	if (e->e_lockfp != NULL)
175538032Speter		close(fileno(e->e_lockfp));
175638032Speter
175738032Speter	/* run as default user */
175838032Speter	endpwent();
175938032Speter	if (setgid(DefGid) < 0 && geteuid() == 0)
176038032Speter		syserr("prog_open: setgid(%ld) failed", (long) DefGid);
176138032Speter	if (setuid(DefUid) < 0 && geteuid() == 0)
176238032Speter		syserr("prog_open: setuid(%ld) failed", (long) DefUid);
176338032Speter
176438032Speter	/* run in some directory */
176538032Speter	if (ProgMailer != NULL)
176638032Speter		p = ProgMailer->m_execdir;
176738032Speter	else
176838032Speter		p = NULL;
176938032Speter	for (; p != NULL; p = q)
177038032Speter	{
177138032Speter		q = strchr(p, ':');
177238032Speter		if (q != NULL)
177338032Speter			*q = '\0';
177438032Speter		expand(p, buf, sizeof buf, e);
177538032Speter		if (q != NULL)
177638032Speter			*q++ = ':';
177738032Speter		if (buf[0] != '\0' && chdir(buf) >= 0)
177838032Speter			break;
177938032Speter	}
178038032Speter	if (p == NULL)
178138032Speter	{
178238032Speter		/* backup directories */
178338032Speter		if (chdir("/tmp") < 0)
178438032Speter			(void) chdir("/");
178538032Speter	}
178638032Speter
178738032Speter	/* arrange for all the files to be closed */
178838032Speter	for (i = 3; i < DtableSize; i++)
178938032Speter	{
179038032Speter		register int j;
179138032Speter
179238032Speter		if ((j = fcntl(i, F_GETFD, 0)) != -1)
179338032Speter			(void) fcntl(i, F_SETFD, j | 1);
179438032Speter	}
179538032Speter
179638032Speter	/* now exec the process */
179738032Speter	execve(argv[0], (ARGV_T) argv, (ARGV_T) UserEnviron);
179838032Speter
179938032Speter	/* woops!  failed */
180038032Speter	saveerrno = errno;
180138032Speter	syserr("%s: cannot exec", argv[0]);
180238032Speter	if (transienterror(saveerrno))
180338032Speter		_exit(EX_OSERR);
180438032Speter	_exit(EX_CONFIG);
180538032Speter	return -1;	/* avoid compiler warning on IRIX */
180638032Speter}
180738032Speter/*
180838032Speter**  GET_COLUMN  -- look up a Column in a line buffer
180938032Speter**
181038032Speter**	Parameters:
181138032Speter**		line -- the raw text line to search.
181238032Speter**		col -- the column number to fetch.
181338032Speter**		delim -- the delimiter between columns.  If null,
181438032Speter**			use white space.
181538032Speter**		buf -- the output buffer.
181638032Speter**		buflen -- the length of buf.
181738032Speter**
181838032Speter**	Returns:
181938032Speter**		buf if successful.
182038032Speter**		NULL otherwise.
182138032Speter*/
182238032Speter
182338032Speterchar *
182438032Speterget_column(line, col, delim, buf, buflen)
182538032Speter	char line[];
182638032Speter	int col;
182738032Speter	char delim;
182838032Speter	char buf[];
182938032Speter	int buflen;
183038032Speter{
183138032Speter	char *p;
183238032Speter	char *begin, *end;
183338032Speter	int i;
183438032Speter	char delimbuf[4];
183538032Speter
183638032Speter	if (delim == '\0')
183738032Speter		strcpy(delimbuf, "\n\t ");
183838032Speter	else
183938032Speter	{
184038032Speter		delimbuf[0] = delim;
184138032Speter		delimbuf[1] = '\0';
184238032Speter	}
184338032Speter
184438032Speter	p = line;
184538032Speter	if (*p == '\0')
184638032Speter		return NULL;			/* line empty */
184738032Speter	if (*p == delim && col == 0)
184838032Speter		return NULL;			/* first column empty */
184938032Speter
185038032Speter	begin = line;
185138032Speter
185238032Speter	if (col == 0 && delim == '\0')
185338032Speter	{
185438032Speter		while (*begin != '\0' && isascii(*begin) && isspace(*begin))
185538032Speter			begin++;
185638032Speter	}
185738032Speter
185838032Speter	for (i = 0; i < col; i++)
185938032Speter	{
186038032Speter		if ((begin = strpbrk(begin, delimbuf)) == NULL)
186138032Speter			return NULL;		/* no such column */
186238032Speter		begin++;
186338032Speter		if (delim == '\0')
186438032Speter		{
186538032Speter			while (*begin != '\0' && isascii(*begin) && isspace(*begin))
186638032Speter				begin++;
186738032Speter		}
186838032Speter	}
186938032Speter
187038032Speter	end = strpbrk(begin, delimbuf);
187138032Speter	if (end == NULL)
187238032Speter		i = strlen(begin);
187338032Speter	else
187438032Speter		i = end - begin;
187538032Speter	if (i >= buflen)
187638032Speter		i = buflen - 1;
187738032Speter	strncpy(buf, begin, i);
187838032Speter	buf[i] = '\0';
187938032Speter	return buf;
188038032Speter}
188138032Speter/*
188238032Speter**  CLEANSTRCPY -- copy string keeping out bogus characters
188338032Speter**
188438032Speter**	Parameters:
188538032Speter**		t -- "to" string.
188638032Speter**		f -- "from" string.
188738032Speter**		l -- length of space available in "to" string.
188838032Speter**
188938032Speter**	Returns:
189038032Speter**		none.
189138032Speter*/
189238032Speter
189338032Spetervoid
189438032Spetercleanstrcpy(t, f, l)
189538032Speter	register char *t;
189638032Speter	register char *f;
189738032Speter	int l;
189838032Speter{
189938032Speter	/* check for newlines and log if necessary */
190038032Speter	(void) denlstring(f, TRUE, TRUE);
190138032Speter
190238032Speter	l--;
190338032Speter	while (l > 0 && *f != '\0')
190438032Speter	{
190538032Speter		if (isascii(*f) &&
190638032Speter		    (isalnum(*f) || strchr("!#$%&'*+-./^_`{|}~", *f) != NULL))
190738032Speter		{
190838032Speter			l--;
190938032Speter			*t++ = *f;
191038032Speter		}
191138032Speter		f++;
191238032Speter	}
191338032Speter	*t = '\0';
191438032Speter}
191538032Speter/*
191638032Speter**  DENLSTRING -- convert newlines in a string to spaces
191738032Speter**
191838032Speter**	Parameters:
191938032Speter**		s -- the input string
192038032Speter**		strict -- if set, don't permit continuation lines.
192138032Speter**		logattacks -- if set, log attempted attacks.
192238032Speter**
192338032Speter**	Returns:
192438032Speter**		A pointer to a version of the string with newlines
192538032Speter**		mapped to spaces.  This should be copied.
192638032Speter*/
192738032Speter
192838032Speterchar *
192938032Speterdenlstring(s, strict, logattacks)
193038032Speter	char *s;
193138032Speter	bool strict;
193238032Speter	bool logattacks;
193338032Speter{
193438032Speter	register char *p;
193538032Speter	int l;
193638032Speter	static char *bp = NULL;
193738032Speter	static int bl = 0;
193838032Speter
193938032Speter	p = s;
194038032Speter	while ((p = strchr(p, '\n')) != NULL)
194138032Speter		if (strict || (*++p != ' ' && *p != '\t'))
194238032Speter			break;
194338032Speter	if (p == NULL)
194438032Speter		return s;
194538032Speter
194638032Speter	l = strlen(s) + 1;
194738032Speter	if (bl < l)
194838032Speter	{
194938032Speter		/* allocate more space */
195038032Speter		if (bp != NULL)
195138032Speter			free(bp);
195238032Speter		bp = xalloc(l);
195338032Speter		bl = l;
195438032Speter	}
195538032Speter	strcpy(bp, s);
195638032Speter	for (p = bp; (p = strchr(p, '\n')) != NULL; )
195738032Speter		*p++ = ' ';
195838032Speter
195938032Speter	if (logattacks)
196038032Speter	{
196138032Speter		sm_syslog(LOG_NOTICE, CurEnv->e_id,
196238032Speter			"POSSIBLE ATTACK from %.100s: newline in string \"%s\"",
196338032Speter			RealHostName == NULL ? "[UNKNOWN]" : RealHostName,
196438032Speter			shortenstring(bp, MAXSHORTSTR));
196538032Speter	}
196638032Speter
196738032Speter	return bp;
196838032Speter}
196938032Speter/*
197038032Speter**  PATH_IS_DIR -- check to see if file exists and is a directory.
197138032Speter**
197238032Speter**	There are some additional checks for security violations in
197338032Speter**	here.  This routine is intended to be used for the host status
197438032Speter**	support.
197538032Speter**
197638032Speter**	Parameters:
197738032Speter**		pathname -- pathname to check for directory-ness.
197838032Speter**		createflag -- if set, create directory if needed.
197938032Speter**
198038032Speter**	Returns:
198138032Speter**		TRUE -- if the indicated pathname is a directory
198238032Speter**		FALSE -- otherwise
198338032Speter*/
198438032Speter
198538032Speterint
198638032Speterpath_is_dir(pathname, createflag)
198738032Speter	char *pathname;
198838032Speter	bool createflag;
198938032Speter{
199038032Speter	struct stat statbuf;
199138032Speter
199238032Speter#if HASLSTAT
199338032Speter	if (lstat(pathname, &statbuf) < 0)
199438032Speter#else
199538032Speter	if (stat(pathname, &statbuf) < 0)
199638032Speter#endif
199738032Speter	{
199838032Speter		if (errno != ENOENT || !createflag)
199938032Speter			return FALSE;
200038032Speter		if (mkdir(pathname, 0755) < 0)
200138032Speter			return FALSE;
200238032Speter		return TRUE;
200338032Speter	}
200438032Speter	if (!S_ISDIR(statbuf.st_mode))
200538032Speter	{
200638032Speter		errno = ENOTDIR;
200738032Speter		return FALSE;
200838032Speter	}
200938032Speter
201038032Speter	/* security: don't allow writable directories */
201138032Speter	if (bitset(S_IWGRP|S_IWOTH, statbuf.st_mode))
201238032Speter	{
201338032Speter		errno = EACCES;
201438032Speter		return FALSE;
201538032Speter	}
201638032Speter
201738032Speter	return TRUE;
201838032Speter}
201938032Speter/*
202038032Speter**  PROC_LIST_ADD -- add process id to list of our children
202138032Speter**
202238032Speter**	Parameters:
202338032Speter**		pid -- pid to add to list.
202438032Speter**
202538032Speter**	Returns:
202638032Speter**		none
202738032Speter*/
202838032Speter
202942575Speterstruct procs
203042575Speter{
203142575Speter	pid_t	proc_pid;
203242575Speter	char 	*proc_task;
203342575Speter};
203442575Speter
203542575Speterstatic struct procs	*ProcListVec	= NULL;
203638032Speterstatic int	ProcListSize	= 0;
203738032Speter
203838032Speter#define NO_PID		((pid_t) 0)
203938032Speter#ifndef PROC_LIST_SEG
204038032Speter# define PROC_LIST_SEG	32		/* number of pids to alloc at a time */
204138032Speter#endif
204238032Speter
204338032Spetervoid
204442575Speterproc_list_add(pid, task)
204538032Speter	pid_t pid;
204642575Speter	char *task;
204738032Speter{
204838032Speter	int i;
204938032Speter
205038032Speter	for (i = 0; i < ProcListSize; i++)
205138032Speter	{
205242575Speter		if (ProcListVec[i].proc_pid == NO_PID)
205338032Speter			break;
205438032Speter	}
205538032Speter	if (i >= ProcListSize)
205638032Speter	{
205738032Speter		/* probe the existing vector to avoid growing infinitely */
205838032Speter		proc_list_probe();
205938032Speter
206038032Speter		/* now scan again */
206138032Speter		for (i = 0; i < ProcListSize; i++)
206238032Speter		{
206342575Speter			if (ProcListVec[i].proc_pid == NO_PID)
206438032Speter				break;
206538032Speter		}
206638032Speter	}
206738032Speter	if (i >= ProcListSize)
206838032Speter	{
206938032Speter		/* grow process list */
207042575Speter		struct procs *npv;
207138032Speter
207242575Speter		npv = (struct procs *) xalloc(sizeof (struct procs) * (ProcListSize + PROC_LIST_SEG));
207338032Speter		if (ProcListSize > 0)
207438032Speter		{
207542575Speter			bcopy(ProcListVec, npv, ProcListSize *
207642575Speter						sizeof (struct procs));
207738032Speter			free(ProcListVec);
207838032Speter		}
207938032Speter		for (i = ProcListSize; i < ProcListSize + PROC_LIST_SEG; i++)
208042575Speter		{
208142575Speter			npv[i].proc_pid = NO_PID;
208242575Speter			npv[i].proc_task = NULL;
208342575Speter		}
208438032Speter		i = ProcListSize;
208538032Speter		ProcListSize += PROC_LIST_SEG;
208638032Speter		ProcListVec = npv;
208738032Speter	}
208842575Speter	ProcListVec[i].proc_pid = pid;
208942575Speter	ProcListVec[i].proc_task = newstr(task);
209042575Speter
209142575Speter	/* if process adding itself, it's not a child */
209242575Speter	if (pid != getpid())
209342575Speter		CurChildren++;
209438032Speter}
209538032Speter/*
209642575Speter**  PROC_LIST_SET -- set pid task in process list
209742575Speter**
209842575Speter**	Parameters:
209942575Speter**		pid -- pid to set
210042575Speter**		task -- task of pid
210142575Speter**
210242575Speter**	Returns:
210342575Speter**		none.
210442575Speter*/
210542575Speter
210642575Spetervoid
210742575Speterproc_list_set(pid, task)
210842575Speter	pid_t pid;
210942575Speter	char *task;
211042575Speter{
211142575Speter	int i;
211242575Speter
211342575Speter	for (i = 0; i < ProcListSize; i++)
211442575Speter	{
211542575Speter		if (ProcListVec[i].proc_pid == pid)
211642575Speter		{
211742575Speter			if (ProcListVec[i].proc_task != NULL)
211842575Speter				free(ProcListVec[i].proc_task);
211942575Speter			ProcListVec[i].proc_task = newstr(task);
212042575Speter			break;
212142575Speter		}
212242575Speter	}
212342575Speter}
212442575Speter/*
212538032Speter**  PROC_LIST_DROP -- drop pid from process list
212638032Speter**
212738032Speter**	Parameters:
212838032Speter**		pid -- pid to drop
212938032Speter**
213038032Speter**	Returns:
213138032Speter**		none.
213238032Speter*/
213338032Speter
213438032Spetervoid
213538032Speterproc_list_drop(pid)
213638032Speter	pid_t pid;
213738032Speter{
213838032Speter	int i;
213938032Speter
214038032Speter	for (i = 0; i < ProcListSize; i++)
214138032Speter	{
214242575Speter		if (ProcListVec[i].proc_pid == pid)
214338032Speter		{
214442575Speter			ProcListVec[i].proc_pid = NO_PID;
214542575Speter			if (ProcListVec[i].proc_task != NULL)
214642575Speter			{
214742575Speter				free(ProcListVec[i].proc_task);
214842575Speter				ProcListVec[i].proc_task = NULL;
214942575Speter			}
215038032Speter			break;
215138032Speter		}
215238032Speter	}
215338032Speter	if (CurChildren > 0)
215438032Speter		CurChildren--;
215538032Speter}
215638032Speter/*
215738032Speter**  PROC_LIST_CLEAR -- clear the process list
215838032Speter**
215938032Speter**	Parameters:
216038032Speter**		none.
216138032Speter**
216238032Speter**	Returns:
216338032Speter**		none.
216438032Speter*/
216538032Speter
216638032Spetervoid
216738032Speterproc_list_clear()
216838032Speter{
216938032Speter	int i;
217038032Speter
217142575Speter	/* start from 1 since 0 is the daemon itself */
217242575Speter	for (i = 1; i < ProcListSize; i++)
217342575Speter	{
217442575Speter		ProcListVec[i].proc_pid = NO_PID;
217542575Speter		if (ProcListVec[i].proc_task != NULL)
217642575Speter		{
217742575Speter			free(ProcListVec[i].proc_task);
217842575Speter			ProcListVec[i].proc_task = NULL;
217942575Speter		}
218042575Speter	}
218138032Speter	CurChildren = 0;
218238032Speter}
218338032Speter/*
218438032Speter**  PROC_LIST_PROBE -- probe processes in the list to see if they still exist
218538032Speter**
218638032Speter**	Parameters:
218738032Speter**		none
218838032Speter**
218938032Speter**	Returns:
219038032Speter**		none
219138032Speter*/
219238032Speter
219338032Spetervoid
219438032Speterproc_list_probe()
219538032Speter{
219638032Speter	int i;
219738032Speter
219842575Speter	/* start from 1 since 0 is the daemon itself */
219942575Speter	for (i = 1; i < ProcListSize; i++)
220038032Speter	{
220142575Speter		if (ProcListVec[i].proc_pid == NO_PID)
220238032Speter			continue;
220342575Speter		if (kill(ProcListVec[i].proc_pid, 0) < 0)
220438032Speter		{
220538032Speter			if (LogLevel > 3)
220638032Speter				sm_syslog(LOG_DEBUG, CurEnv->e_id,
220738032Speter					"proc_list_probe: lost pid %d",
220842575Speter					(int) ProcListVec[i].proc_pid);
220942575Speter			ProcListVec[i].proc_pid = NO_PID;
221042575Speter			if (ProcListVec[i].proc_task != NULL)
221142575Speter			{
221242575Speter				free(ProcListVec[i].proc_task);
221342575Speter				ProcListVec[i].proc_task = NULL;
221442575Speter			}
221538032Speter			CurChildren--;
221638032Speter		}
221738032Speter	}
221838032Speter	if (CurChildren < 0)
221938032Speter		CurChildren = 0;
222038032Speter}
222138032Speter/*
222242575Speter**  PROC_LIST_DISPLAY -- display the process list
222342575Speter**
222442575Speter**	Parameters:
222542575Speter**		out -- output file pointer
222642575Speter**
222742575Speter**	Returns:
222842575Speter**		none.
222942575Speter*/
223042575Speter
223142575Spetervoid
223242575Speterproc_list_display(out)
223342575Speter	FILE *out;
223442575Speter{
223542575Speter	int i;
223642575Speter
223742575Speter	for (i = 0; i < ProcListSize; i++)
223842575Speter	{
223942575Speter		if (ProcListVec[i].proc_pid == NO_PID)
224042575Speter			continue;
224142575Speter
224242575Speter		fprintf(out, "%d %s%s\n", (int) ProcListVec[i].proc_pid,
224342575Speter			ProcListVec[i].proc_task != NULL ?
224442575Speter			ProcListVec[i].proc_task : "(unknown)",
224542575Speter			(OpMode == MD_SMTP ||
224642575Speter			 OpMode == MD_DAEMON ||
224742575Speter			 OpMode == MD_ARPAFTP) ? "\r" : "");
224842575Speter	}
224942575Speter}
225042575Speter/*
225138032Speter**  SM_STRCASECMP -- 8-bit clean version of strcasecmp
225238032Speter**
225338032Speter**	Thank you, vendors, for making this all necessary.
225438032Speter*/
225538032Speter
225638032Speter/*
225738032Speter * Copyright (c) 1987, 1993
225838032Speter *	The Regents of the University of California.  All rights reserved.
225938032Speter *
226038032Speter * Redistribution and use in source and binary forms, with or without
226138032Speter * modification, are permitted provided that the following conditions
226238032Speter * are met:
226338032Speter * 1. Redistributions of source code must retain the above copyright
226438032Speter *    notice, this list of conditions and the following disclaimer.
226538032Speter * 2. Redistributions in binary form must reproduce the above copyright
226638032Speter *    notice, this list of conditions and the following disclaimer in the
226738032Speter *    documentation and/or other materials provided with the distribution.
226838032Speter * 3. All advertising materials mentioning features or use of this software
226938032Speter *    must display the following acknowledgement:
227038032Speter *	This product includes software developed by the University of
227138032Speter *	California, Berkeley and its contributors.
227238032Speter * 4. Neither the name of the University nor the names of its contributors
227338032Speter *    may be used to endorse or promote products derived from this software
227438032Speter *    without specific prior written permission.
227538032Speter *
227638032Speter * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
227738032Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
227838032Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
227938032Speter * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
228038032Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
228138032Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
228238032Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
228338032Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
228438032Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
228538032Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
228638032Speter * SUCH DAMAGE.
228738032Speter */
228838032Speter
228938032Speter#if defined(LIBC_SCCS) && !defined(lint)
229038032Speterstatic char sccsid[] = "@(#)strcasecmp.c	8.1 (Berkeley) 6/4/93";
229138032Speter#endif /* LIBC_SCCS and not lint */
229238032Speter
229338032Speter/*
229438032Speter * This array is designed for mapping upper and lower case letter
229538032Speter * together for a case independent comparison.  The mappings are
229638032Speter * based upon ascii character sequences.
229738032Speter */
229838032Speterstatic const u_char charmap[] = {
229938032Speter	0000, 0001, 0002, 0003, 0004, 0005, 0006, 0007,
230038032Speter	0010, 0011, 0012, 0013, 0014, 0015, 0016, 0017,
230138032Speter	0020, 0021, 0022, 0023, 0024, 0025, 0026, 0027,
230238032Speter	0030, 0031, 0032, 0033, 0034, 0035, 0036, 0037,
230338032Speter	0040, 0041, 0042, 0043, 0044, 0045, 0046, 0047,
230438032Speter	0050, 0051, 0052, 0053, 0054, 0055, 0056, 0057,
230538032Speter	0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067,
230638032Speter	0070, 0071, 0072, 0073, 0074, 0075, 0076, 0077,
230738032Speter	0100, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
230838032Speter	0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157,
230938032Speter	0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167,
231038032Speter	0170, 0171, 0172, 0133, 0134, 0135, 0136, 0137,
231138032Speter	0140, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
231238032Speter	0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157,
231338032Speter	0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167,
231438032Speter	0170, 0171, 0172, 0173, 0174, 0175, 0176, 0177,
231538032Speter	0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207,
231638032Speter	0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217,
231738032Speter	0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227,
231838032Speter	0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237,
231938032Speter	0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247,
232038032Speter	0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
232138032Speter	0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,
232238032Speter	0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277,
232338032Speter	0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307,
232438032Speter	0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317,
232538032Speter	0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327,
232638032Speter	0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
232738032Speter	0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
232838032Speter	0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357,
232938032Speter	0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,
233038032Speter	0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377,
233138032Speter};
233238032Speter
233338032Speterint
233438032Spetersm_strcasecmp(s1, s2)
233538032Speter	const char *s1, *s2;
233638032Speter{
233738032Speter	register const u_char *cm = charmap,
233838032Speter			*us1 = (const u_char *)s1,
233938032Speter			*us2 = (const u_char *)s2;
234038032Speter
234138032Speter	while (cm[*us1] == cm[*us2++])
234238032Speter		if (*us1++ == '\0')
234338032Speter			return (0);
234438032Speter	return (cm[*us1] - cm[*--us2]);
234538032Speter}
234638032Speter
234738032Speterint
234838032Spetersm_strncasecmp(s1, s2, n)
234938032Speter	const char *s1, *s2;
235038032Speter	register size_t n;
235138032Speter{
235238032Speter	if (n != 0) {
235338032Speter		register const u_char *cm = charmap,
235438032Speter				*us1 = (const u_char *)s1,
235538032Speter				*us2 = (const u_char *)s2;
235638032Speter
235738032Speter		do {
235838032Speter			if (cm[*us1] != cm[*us2++])
235938032Speter				return (cm[*us1] - cm[*--us2]);
236038032Speter			if (*us1++ == '\0')
236138032Speter				break;
236238032Speter		} while (--n != 0);
236338032Speter	}
236438032Speter	return (0);
236538032Speter}
2366