util.c revision 80785
138032Speter/*
273188Sgshapiro * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
364562Sgshapiro *	All rights reserved.
438032Speter * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
538032Speter * Copyright (c) 1988, 1993
638032Speter *	The Regents of the University of California.  All rights reserved.
738032Speter *
838032Speter * By using this file, you agree to the terms and conditions set
938032Speter * forth in the LICENSE file which can be found at the top level of
1038032Speter * the sendmail distribution.
1138032Speter *
1238032Speter */
1338032Speter
1438032Speter#ifndef lint
1580785Sgshapirostatic char id[] = "@(#)$Id: util.c,v 8.225.2.1.2.26 2001/06/01 08:23:25 gshapiro Exp $";
1664562Sgshapiro#endif /* ! lint */
1738032Speter
1864562Sgshapiro#include <sendmail.h>
1964562Sgshapiro#include <sysexits.h>
2064562Sgshapiro
2164562Sgshapiro
2264562Sgshapirostatic void	readtimeout __P((time_t));
2364562Sgshapiro
2438032Speter/*
2538032Speter**  STRIPQUOTES -- Strip quotes & quote bits from a string.
2638032Speter**
2738032Speter**	Runs through a string and strips off unquoted quote
2838032Speter**	characters and quote bits.  This is done in place.
2938032Speter**
3038032Speter**	Parameters:
3138032Speter**		s -- the string to strip.
3238032Speter**
3338032Speter**	Returns:
3438032Speter**		none.
3538032Speter**
3638032Speter**	Side Effects:
3738032Speter**		none.
3838032Speter*/
3938032Speter
4038032Spetervoid
4138032Speterstripquotes(s)
4238032Speter	char *s;
4338032Speter{
4438032Speter	register char *p;
4538032Speter	register char *q;
4638032Speter	register char c;
4738032Speter
4838032Speter	if (s == NULL)
4938032Speter		return;
5038032Speter
5138032Speter	p = q = s;
5238032Speter	do
5338032Speter	{
5438032Speter		c = *p++;
5538032Speter		if (c == '\\')
5638032Speter			c = *p++;
5738032Speter		else if (c == '"')
5838032Speter			continue;
5938032Speter		*q++ = c;
6038032Speter	} while (c != '\0');
6138032Speter}
6238032Speter/*
6338032Speter**  ADDQUOTES -- Adds quotes & quote bits to a string.
6438032Speter**
6538032Speter**	Runs through a string and adds characters and quote bits.
6638032Speter**
6738032Speter**	Parameters:
6838032Speter**		s -- the string to modify.
6938032Speter**
7038032Speter**	Returns:
7138032Speter**		pointer to quoted string.
7238032Speter**
7338032Speter**	Side Effects:
7438032Speter**		none.
7538032Speter**
7638032Speter*/
7738032Speter
7838032Speterchar *
7938032Speteraddquotes(s)
8038032Speter	char *s;
8138032Speter{
8238032Speter	int len = 0;
8338032Speter	char c;
8438032Speter	char *p = s, *q, *r;
8538032Speter
8638032Speter	if (s == NULL)
8738032Speter		return NULL;
8838032Speter
8938032Speter	/* Find length of quoted string */
9038032Speter	while ((c = *p++) != '\0')
9138032Speter	{
9238032Speter		len++;
9338032Speter		if (c == '\\' || c == '"')
9438032Speter			len++;
9538032Speter	}
9664562Sgshapiro
9738032Speter	q = r = xalloc(len + 3);
9838032Speter	p = s;
9938032Speter
10038032Speter	/* add leading quote */
10138032Speter	*q++ = '"';
10238032Speter	while ((c = *p++) != '\0')
10338032Speter	{
10438032Speter		/* quote \ or " */
10538032Speter		if (c == '\\' || c == '"')
10638032Speter			*q++ = '\\';
10738032Speter		*q++ = c;
10838032Speter	}
10938032Speter	*q++ = '"';
11038032Speter	*q = '\0';
11138032Speter	return r;
11238032Speter}
11338032Speter/*
11438032Speter**  RFC822_STRING -- Checks string for proper RFC822 string quoting.
11538032Speter**
11638032Speter**	Runs through a string and verifies RFC822 special characters
11738032Speter**	are only found inside comments, quoted strings, or backslash
11838032Speter**	escaped.  Also verified balanced quotes and parenthesis.
11938032Speter**
12038032Speter**	Parameters:
12138032Speter**		s -- the string to modify.
12238032Speter**
12338032Speter**	Returns:
12438032Speter**		TRUE -- if the string is RFC822 compliant.
12538032Speter**		FALSE -- if the string is not RFC822 compliant.
12638032Speter**
12738032Speter**	Side Effects:
12838032Speter**		none.
12938032Speter**
13038032Speter*/
13138032Speter
13238032Speterbool
13338032Speterrfc822_string(s)
13438032Speter	char *s;
13538032Speter{
13638032Speter	bool quoted = FALSE;
13738032Speter	int commentlev = 0;
13838032Speter	char *c = s;
13938032Speter
14038032Speter	if (s == NULL)
14138032Speter		return FALSE;
14238032Speter
14338032Speter	while (*c != '\0')
14438032Speter	{
14538032Speter		/* escaped character */
14638032Speter		if (*c == '\\')
14738032Speter		{
14838032Speter			c++;
14938032Speter			if (*c == '\0')
15038032Speter				return FALSE;
15138032Speter		}
15238032Speter		else if (commentlev == 0 && *c == '"')
15338032Speter			quoted = !quoted;
15438032Speter		else if (!quoted)
15538032Speter		{
15638032Speter			if (*c == ')')
15738032Speter			{
15838032Speter				/* unbalanced ')' */
15938032Speter				if (commentlev == 0)
16038032Speter					return FALSE;
16138032Speter				else
16238032Speter					commentlev--;
16338032Speter			}
16438032Speter			else if (*c == '(')
16538032Speter				commentlev++;
16638032Speter			else if (commentlev == 0 &&
16738032Speter				 strchr(MustQuoteChars, *c) != NULL)
16838032Speter				return FALSE;
16938032Speter		}
17038032Speter		c++;
17138032Speter	}
17238032Speter	/* unbalanced '"' or '(' */
17338032Speter	if (quoted || commentlev != 0)
17438032Speter		return FALSE;
17538032Speter	else
17638032Speter		return TRUE;
17738032Speter}
17838032Speter/*
17942575Speter**  SHORTEN_RFC822_STRING -- Truncate and rebalance an RFC822 string
18042575Speter**
18164562Sgshapiro**	Arbitrarily shorten (in place) an RFC822 string and rebalance
18242575Speter**	comments and quotes.
18342575Speter**
18442575Speter**	Parameters:
18542575Speter**		string -- the string to shorten
18642575Speter**		length -- the maximum size, 0 if no maximum
18742575Speter**
18842575Speter**	Returns:
18942575Speter**		TRUE if string is changed, FALSE otherwise
19042575Speter**
19142575Speter**	Side Effects:
19242575Speter**		Changes string in place, possibly resulting
19342575Speter**		in a shorter string.
19442575Speter*/
19542575Speter
19642575Speterbool
19742575Spetershorten_rfc822_string(string, length)
19842575Speter	char *string;
19942575Speter	size_t length;
20042575Speter{
20142575Speter	bool backslash = FALSE;
20242575Speter	bool modified = FALSE;
20342575Speter	bool quoted = FALSE;
20442575Speter	size_t slen;
20542575Speter	int parencount = 0;
20642575Speter	char *ptr = string;
20764562Sgshapiro
20842575Speter	/*
20942575Speter	**  If have to rebalance an already short enough string,
21042575Speter	**  need to do it within allocated space.
21142575Speter	*/
21271345Sgshapiro
21342575Speter	slen = strlen(string);
21442575Speter	if (length == 0 || slen < length)
21542575Speter		length = slen;
21642575Speter
21742575Speter	while (*ptr != '\0')
21842575Speter	{
21942575Speter		if (backslash)
22042575Speter		{
22142575Speter			backslash = FALSE;
22242575Speter			goto increment;
22342575Speter		}
22442575Speter
22542575Speter		if (*ptr == '\\')
22642575Speter			backslash = TRUE;
22742575Speter		else if (*ptr == '(')
22842575Speter		{
22942575Speter			if (!quoted)
23042575Speter				parencount++;
23142575Speter		}
23242575Speter		else if (*ptr == ')')
23342575Speter		{
23442575Speter			if (--parencount < 0)
23542575Speter				parencount = 0;
23642575Speter		}
23764562Sgshapiro
23842575Speter		/* Inside a comment, quotes don't matter */
23942575Speter		if (parencount <= 0 && *ptr == '"')
24042575Speter			quoted = !quoted;
24142575Speter
24242575Speterincrement:
24342575Speter		/* Check for sufficient space for next character */
24464562Sgshapiro		if (length - (ptr - string) <= (size_t) ((backslash ? 1 : 0) +
24542575Speter						parencount +
24642575Speter						(quoted ? 1 : 0)))
24742575Speter		{
24842575Speter			/* Not enough, backtrack */
24942575Speter			if (*ptr == '\\')
25042575Speter				backslash = FALSE;
25142575Speter			else if (*ptr == '(' && !quoted)
25242575Speter				parencount--;
25342575Speter			else if (*ptr == '"' && parencount == 0)
25442575Speter				quoted = FALSE;
25542575Speter			break;
25642575Speter		}
25742575Speter		ptr++;
25842575Speter	}
25942575Speter
26042575Speter	/* Rebalance */
26142575Speter	while (parencount-- > 0)
26242575Speter	{
26342575Speter		if (*ptr != ')')
26442575Speter		{
26542575Speter			modified = TRUE;
26642575Speter			*ptr = ')';
26742575Speter		}
26842575Speter		ptr++;
26942575Speter	}
27042575Speter	if (quoted)
27142575Speter	{
27242575Speter		if (*ptr != '"')
27342575Speter		{
27442575Speter			modified = TRUE;
27542575Speter			*ptr = '"';
27642575Speter		}
27742575Speter		ptr++;
27842575Speter	}
27942575Speter	if (*ptr != '\0')
28042575Speter	{
28142575Speter		modified = TRUE;
28242575Speter		*ptr = '\0';
28342575Speter	}
28442575Speter	return modified;
28542575Speter}
28642575Speter/*
28742575Speter**  FIND_CHARACTER -- find an unquoted character in an RFC822 string
28842575Speter**
28942575Speter**	Find an unquoted, non-commented character in an RFC822
29042575Speter**	string and return a pointer to its location in the
29142575Speter**	string.
29242575Speter**
29342575Speter**	Parameters:
29442575Speter**		string -- the string to search
29542575Speter**		character -- the character to find
29642575Speter**
29742575Speter**	Returns:
29842575Speter**		pointer to the character, or
29942575Speter**		a pointer to the end of the line if character is not found
30042575Speter*/
30142575Speter
30242575Speterchar *
30342575Speterfind_character(string, character)
30442575Speter	char *string;
30564562Sgshapiro	int character;
30642575Speter{
30742575Speter	bool backslash = FALSE;
30842575Speter	bool quoted = FALSE;
30942575Speter	int parencount = 0;
31064562Sgshapiro
31142575Speter	while (string != NULL && *string != '\0')
31242575Speter	{
31342575Speter		if (backslash)
31442575Speter		{
31542575Speter			backslash = FALSE;
31642575Speter			if (!quoted && character == '\\' && *string == '\\')
31742575Speter				break;
31842575Speter			string++;
31942575Speter			continue;
32042575Speter		}
32142575Speter		switch (*string)
32242575Speter		{
32342575Speter		  case '\\':
32442575Speter			backslash = TRUE;
32542575Speter			break;
32664562Sgshapiro
32742575Speter		  case '(':
32842575Speter			if (!quoted)
32942575Speter				parencount++;
33042575Speter			break;
33164562Sgshapiro
33242575Speter		  case ')':
33342575Speter			if (--parencount < 0)
33442575Speter				parencount = 0;
33542575Speter			break;
33642575Speter		}
33764562Sgshapiro
33842575Speter		/* Inside a comment, nothing matters */
33942575Speter		if (parencount > 0)
34042575Speter		{
34142575Speter			string++;
34242575Speter			continue;
34342575Speter		}
34464562Sgshapiro
34542575Speter		if (*string == '"')
34642575Speter			quoted = !quoted;
34742575Speter		else if (*string == character && !quoted)
34842575Speter			break;
34942575Speter		string++;
35042575Speter	}
35142575Speter
35242575Speter	/* Return pointer to the character */
35342575Speter	return string;
35442575Speter}
35542575Speter/*
35638032Speter**  XALLOC -- Allocate memory and bitch wildly on failure.
35738032Speter**
35838032Speter**	THIS IS A CLUDGE.  This should be made to give a proper
35938032Speter**	error -- but after all, what can we do?
36038032Speter**
36138032Speter**	Parameters:
36238032Speter**		sz -- size of area to allocate.
36338032Speter**
36438032Speter**	Returns:
36538032Speter**		pointer to data region.
36638032Speter**
36738032Speter**	Side Effects:
36838032Speter**		Memory is allocated.
36938032Speter*/
37038032Speter
37138032Speterchar *
37238032Speterxalloc(sz)
37338032Speter	register int sz;
37438032Speter{
37538032Speter	register char *p;
37638032Speter
37738032Speter	/* some systems can't handle size zero mallocs */
37838032Speter	if (sz <= 0)
37938032Speter		sz = 1;
38038032Speter
38177349Sgshapiro	ENTER_CRITICAL();
38238032Speter	p = malloc((unsigned) sz);
38377349Sgshapiro	LEAVE_CRITICAL();
38438032Speter	if (p == NULL)
38538032Speter	{
38638032Speter		syserr("!Out of memory!!");
38777349Sgshapiro
38877349Sgshapiro		/* NOTREACHED */
38977349Sgshapiro		exit(EX_UNAVAILABLE);
39038032Speter	}
39164562Sgshapiro	return p;
39238032Speter}
39338032Speter/*
39477349Sgshapiro**  XREALLOC -- Reallocate memory and bitch wildly on failure.
39577349Sgshapiro**
39677349Sgshapiro**	THIS IS A CLUDGE.  This should be made to give a proper
39777349Sgshapiro**	error -- but after all, what can we do?
39877349Sgshapiro**
39977349Sgshapiro**	Parameters:
40077349Sgshapiro**		ptr -- original area.
40177349Sgshapiro**		sz -- size of new area to allocate.
40277349Sgshapiro**
40377349Sgshapiro**	Returns:
40477349Sgshapiro**		pointer to data region.
40577349Sgshapiro**
40677349Sgshapiro**	Side Effects:
40777349Sgshapiro**		Memory is allocated.
40877349Sgshapiro*/
40977349Sgshapiro
41077349Sgshapirochar *
41177349Sgshapiroxrealloc(ptr, sz)
41277349Sgshapiro	void *ptr;
41377349Sgshapiro	size_t sz;
41477349Sgshapiro{
41577349Sgshapiro	register char *p;
41677349Sgshapiro
41777349Sgshapiro	/* some systems can't handle size zero mallocs */
41877349Sgshapiro	if (sz <= 0)
41977349Sgshapiro		sz = 1;
42077349Sgshapiro
42177349Sgshapiro	ENTER_CRITICAL();
42277349Sgshapiro	p = realloc(ptr, (unsigned) sz);
42377349Sgshapiro	LEAVE_CRITICAL();
42477349Sgshapiro	if (p == NULL)
42577349Sgshapiro	{
42677349Sgshapiro		syserr("!Out of memory!!");
42777349Sgshapiro
42877349Sgshapiro		/* NOTREACHED */
42977349Sgshapiro		exit(EX_UNAVAILABLE);
43077349Sgshapiro	}
43177349Sgshapiro	return p;
43277349Sgshapiro}
43377349Sgshapiro/*
43477349Sgshapiro**  XCALLOC -- Allocate memory and bitch wildly on failure.
43577349Sgshapiro**
43677349Sgshapiro**	THIS IS A CLUDGE.  This should be made to give a proper
43777349Sgshapiro**	error -- but after all, what can we do?
43877349Sgshapiro**
43977349Sgshapiro**	Parameters:
44077349Sgshapiro**		num -- number of items to allocate
44177349Sgshapiro**		sz -- size of new area to allocate.
44277349Sgshapiro**
44377349Sgshapiro**	Returns:
44477349Sgshapiro**		pointer to data region.
44577349Sgshapiro**
44677349Sgshapiro**	Side Effects:
44777349Sgshapiro**		Memory is allocated.
44877349Sgshapiro*/
44977349Sgshapiro
45077349Sgshapirochar *
45177349Sgshapiroxcalloc(num, sz)
45277349Sgshapiro	size_t num;
45377349Sgshapiro	size_t sz;
45477349Sgshapiro{
45577349Sgshapiro	register char *p;
45677349Sgshapiro
45777349Sgshapiro	/* some systems can't handle size zero mallocs */
45877349Sgshapiro	if (num <= 0)
45977349Sgshapiro		num = 1;
46077349Sgshapiro	if (sz <= 0)
46177349Sgshapiro		sz = 1;
46277349Sgshapiro
46377349Sgshapiro	ENTER_CRITICAL();
46477349Sgshapiro	p = calloc((unsigned) num, (unsigned) sz);
46577349Sgshapiro	LEAVE_CRITICAL();
46677349Sgshapiro	if (p == NULL)
46777349Sgshapiro	{
46877349Sgshapiro		syserr("!Out of memory!!");
46977349Sgshapiro
47077349Sgshapiro		/* NOTREACHED */
47177349Sgshapiro		exit(EX_UNAVAILABLE);
47277349Sgshapiro	}
47377349Sgshapiro	return p;
47477349Sgshapiro}
47577349Sgshapiro/*
47677349Sgshapiro**  SM_FREE -- Free memory safely.
47777349Sgshapiro**
47877349Sgshapiro**	Parameters:
47977349Sgshapiro**		ptr -- area to free
48077349Sgshapiro**
48177349Sgshapiro**	Returns:
48277349Sgshapiro**		none.
48377349Sgshapiro**
48477349Sgshapiro**	Side Effects:
48577349Sgshapiro**		Memory is freed.
48677349Sgshapiro*/
48777349Sgshapiro
48877349Sgshapirovoid
48977349Sgshapirosm_free(ptr)
49077349Sgshapiro	void *ptr;
49177349Sgshapiro{
49277349Sgshapiro	ENTER_CRITICAL();
49377349Sgshapiro	free(ptr);
49477349Sgshapiro	LEAVE_CRITICAL();
49577349Sgshapiro}
49677349Sgshapiro/*
49738032Speter**  COPYPLIST -- copy list of pointers.
49838032Speter**
49938032Speter**	This routine is the equivalent of newstr for lists of
50038032Speter**	pointers.
50138032Speter**
50238032Speter**	Parameters:
50338032Speter**		list -- list of pointers to copy.
50438032Speter**			Must be NULL terminated.
50538032Speter**		copycont -- if TRUE, copy the contents of the vector
50638032Speter**			(which must be a string) also.
50738032Speter**
50838032Speter**	Returns:
50938032Speter**		a copy of 'list'.
51038032Speter**
51138032Speter**	Side Effects:
51238032Speter**		none.
51338032Speter*/
51438032Speter
51538032Speterchar **
51638032Spetercopyplist(list, copycont)
51738032Speter	char **list;
51838032Speter	bool copycont;
51938032Speter{
52038032Speter	register char **vp;
52138032Speter	register char **newvp;
52238032Speter
52338032Speter	for (vp = list; *vp != NULL; vp++)
52438032Speter		continue;
52538032Speter
52638032Speter	vp++;
52738032Speter
52838032Speter	newvp = (char **) xalloc((int) (vp - list) * sizeof *vp);
52964562Sgshapiro	memmove((char *) newvp, (char *) list, (int) (vp - list) * sizeof *vp);
53038032Speter
53138032Speter	if (copycont)
53238032Speter	{
53338032Speter		for (vp = newvp; *vp != NULL; vp++)
53438032Speter			*vp = newstr(*vp);
53538032Speter	}
53638032Speter
53764562Sgshapiro	return newvp;
53838032Speter}
53938032Speter/*
54038032Speter**  COPYQUEUE -- copy address queue.
54138032Speter**
54238032Speter**	This routine is the equivalent of newstr for address queues
54364562Sgshapiro**	addresses marked as QS_IS_DEAD() aren't copied
54438032Speter**
54538032Speter**	Parameters:
54638032Speter**		addr -- list of address structures to copy.
54738032Speter**
54838032Speter**	Returns:
54938032Speter**		a copy of 'addr'.
55038032Speter**
55138032Speter**	Side Effects:
55238032Speter**		none.
55338032Speter*/
55438032Speter
55538032SpeterADDRESS *
55638032Spetercopyqueue(addr)
55738032Speter	ADDRESS *addr;
55838032Speter{
55938032Speter	register ADDRESS *newaddr;
56038032Speter	ADDRESS *ret;
56138032Speter	register ADDRESS **tail = &ret;
56238032Speter
56338032Speter	while (addr != NULL)
56438032Speter	{
56564562Sgshapiro		if (!QS_IS_DEAD(addr->q_state))
56638032Speter		{
56764562Sgshapiro			newaddr = (ADDRESS *) xalloc(sizeof *newaddr);
56838032Speter			STRUCTCOPY(*addr, *newaddr);
56938032Speter			*tail = newaddr;
57038032Speter			tail = &newaddr->q_next;
57138032Speter		}
57238032Speter		addr = addr->q_next;
57338032Speter	}
57438032Speter	*tail = NULL;
57564562Sgshapiro
57638032Speter	return ret;
57738032Speter}
57838032Speter/*
57964562Sgshapiro**  LOG_SENDMAIL_PID -- record sendmail pid and command line.
58064562Sgshapiro**
58164562Sgshapiro**	Parameters:
58264562Sgshapiro**		e -- the current envelope.
58364562Sgshapiro**
58464562Sgshapiro**	Returns:
58564562Sgshapiro**		none.
58664562Sgshapiro**
58764562Sgshapiro**	Side Effects:
58864562Sgshapiro**		writes pidfile.
58964562Sgshapiro*/
59064562Sgshapiro
59164562Sgshapirovoid
59264562Sgshapirolog_sendmail_pid(e)
59364562Sgshapiro	ENVELOPE *e;
59464562Sgshapiro{
59564562Sgshapiro	long sff;
59664562Sgshapiro	FILE *pidf;
59764562Sgshapiro	char pidpath[MAXPATHLEN + 1];
59864562Sgshapiro
59964562Sgshapiro	/* write the pid to the log file for posterity */
60064562Sgshapiro	sff = SFF_NOLINK|SFF_ROOTOK|SFF_REGONLY|SFF_CREAT;
60164562Sgshapiro	if (TrustedUid != 0 && RealUid == TrustedUid)
60264562Sgshapiro		sff |= SFF_OPENASROOT;
60364562Sgshapiro	expand(PidFile, pidpath, sizeof pidpath, e);
60464562Sgshapiro	pidf = safefopen(pidpath, O_WRONLY|O_TRUNC, 0644, sff);
60564562Sgshapiro	if (pidf == NULL)
60664562Sgshapiro	{
60773188Sgshapiro		sm_syslog(LOG_ERR, NOQID, "unable to write %s: %s",
60873188Sgshapiro			  pidpath, errstring(errno));
60964562Sgshapiro	}
61064562Sgshapiro	else
61164562Sgshapiro	{
61277349Sgshapiro		pid_t pid;
61364562Sgshapiro		extern char *CommandLineArgs;
61464562Sgshapiro
61577349Sgshapiro		pid = getpid();
61671345Sgshapiro
61764562Sgshapiro		/* write the process id on line 1 */
61877349Sgshapiro		fprintf(pidf, "%ld\n", (long) pid);
61964562Sgshapiro
62064562Sgshapiro		/* line 2 contains all command line flags */
62164562Sgshapiro		fprintf(pidf, "%s\n", CommandLineArgs);
62264562Sgshapiro
62364562Sgshapiro		/* flush and close */
62464562Sgshapiro		(void) fclose(pidf);
62564562Sgshapiro	}
62664562Sgshapiro}
62764562Sgshapiro/*
62864562Sgshapiro**  SET_DELIVERY_MODE -- set and record the delivery mode
62964562Sgshapiro**
63064562Sgshapiro**	Parameters:
63164562Sgshapiro**		mode -- delivery mode
63264562Sgshapiro**		e -- the current envelope.
63364562Sgshapiro**
63464562Sgshapiro**	Returns:
63564562Sgshapiro**		none.
63664562Sgshapiro**
63764562Sgshapiro**	Side Effects:
63864562Sgshapiro**		sets $&{deliveryMode} macro
63964562Sgshapiro*/
64064562Sgshapiro
64164562Sgshapirovoid
64264562Sgshapiroset_delivery_mode(mode, e)
64364562Sgshapiro	int mode;
64464562Sgshapiro	ENVELOPE *e;
64564562Sgshapiro{
64664562Sgshapiro	char buf[2];
64764562Sgshapiro
64864562Sgshapiro	e->e_sendmode = (char)mode;
64964562Sgshapiro	buf[0] = (char)mode;
65064562Sgshapiro	buf[1] = '\0';
65164562Sgshapiro	define(macid("{deliveryMode}", NULL), newstr(buf), e);
65264562Sgshapiro}
65364562Sgshapiro/*
65438032Speter**  PRINTAV -- print argument vector.
65538032Speter**
65638032Speter**	Parameters:
65738032Speter**		av -- argument vector.
65838032Speter**
65938032Speter**	Returns:
66038032Speter**		none.
66138032Speter**
66238032Speter**	Side Effects:
66338032Speter**		prints av.
66438032Speter*/
66538032Speter
66638032Spetervoid
66738032Speterprintav(av)
66838032Speter	register char **av;
66938032Speter{
67038032Speter	while (*av != NULL)
67138032Speter	{
67238032Speter		if (tTd(0, 44))
67364562Sgshapiro			dprintf("\n\t%08lx=", (u_long) *av);
67438032Speter		else
67538032Speter			(void) putchar(' ');
67638032Speter		xputs(*av++);
67738032Speter	}
67838032Speter	(void) putchar('\n');
67938032Speter}
68038032Speter/*
68138032Speter**  LOWER -- turn letter into lower case.
68238032Speter**
68338032Speter**	Parameters:
68438032Speter**		c -- character to turn into lower case.
68538032Speter**
68638032Speter**	Returns:
68738032Speter**		c, in lower case.
68838032Speter**
68938032Speter**	Side Effects:
69038032Speter**		none.
69138032Speter*/
69238032Speter
69338032Speterchar
69438032Speterlower(c)
69564562Sgshapiro	register int c;
69638032Speter{
69764562Sgshapiro	return ((isascii(c) && isupper(c)) ? tolower(c) : c);
69838032Speter}
69938032Speter/*
70038032Speter**  XPUTS -- put string doing control escapes.
70138032Speter**
70238032Speter**	Parameters:
70338032Speter**		s -- string to put.
70438032Speter**
70538032Speter**	Returns:
70638032Speter**		none.
70738032Speter**
70838032Speter**	Side Effects:
70938032Speter**		output to stdout
71038032Speter*/
71138032Speter
71238032Spetervoid
71338032Speterxputs(s)
71438032Speter	register const char *s;
71538032Speter{
71638032Speter	register int c;
71738032Speter	register struct metamac *mp;
71838032Speter	bool shiftout = FALSE;
71938032Speter	extern struct metamac MetaMacros[];
72038032Speter
72138032Speter	if (s == NULL)
72238032Speter	{
72338032Speter		printf("%s<null>%s", TermEscape.te_rv_on, TermEscape.te_rv_off);
72438032Speter		return;
72538032Speter	}
72638032Speter	while ((c = (*s++ & 0377)) != '\0')
72738032Speter	{
72838032Speter		if (shiftout)
72938032Speter		{
73038032Speter			printf("%s", TermEscape.te_rv_off);
73138032Speter			shiftout = FALSE;
73238032Speter		}
73338032Speter		if (!isascii(c))
73438032Speter		{
73538032Speter			if (c == MATCHREPL)
73638032Speter			{
73738032Speter				printf("%s$", TermEscape.te_rv_on);
73838032Speter				shiftout = TRUE;
73938032Speter				if (*s == '\0')
74038032Speter					continue;
74138032Speter				c = *s++ & 0377;
74238032Speter				goto printchar;
74338032Speter			}
74438032Speter			if (c == MACROEXPAND || c == MACRODEXPAND)
74538032Speter			{
74638032Speter				printf("%s$", TermEscape.te_rv_on);
74738032Speter				if (c == MACRODEXPAND)
74864562Sgshapiro					(void) putchar('&');
74938032Speter				shiftout = TRUE;
75038032Speter				if (*s == '\0')
75138032Speter					continue;
75238032Speter				if (strchr("=~&?", *s) != NULL)
75364562Sgshapiro					(void) putchar(*s++);
75438032Speter				if (bitset(0200, *s))
75571345Sgshapiro					printf("{%s}", macname(bitidx(*s++)));
75638032Speter				else
75738032Speter					printf("%c", *s++);
75838032Speter				continue;
75938032Speter			}
76038032Speter			for (mp = MetaMacros; mp->metaname != '\0'; mp++)
76138032Speter			{
76238032Speter				if ((mp->metaval & 0377) == c)
76338032Speter				{
76438032Speter					printf("%s$%c",
76538032Speter						TermEscape.te_rv_on,
76638032Speter						mp->metaname);
76738032Speter					shiftout = TRUE;
76838032Speter					break;
76938032Speter				}
77038032Speter			}
77138032Speter			if (c == MATCHCLASS || c == MATCHNCLASS)
77238032Speter			{
77338032Speter				if (bitset(0200, *s))
77438032Speter					printf("{%s}", macname(*s++ & 0377));
77538032Speter				else if (*s != '\0')
77638032Speter					printf("%c", *s++);
77738032Speter			}
77838032Speter			if (mp->metaname != '\0')
77938032Speter				continue;
78038032Speter
78138032Speter			/* unrecognized meta character */
78238032Speter			printf("%sM-", TermEscape.te_rv_on);
78338032Speter			shiftout = TRUE;
78438032Speter			c &= 0177;
78538032Speter		}
78638032Speter  printchar:
78738032Speter		if (isprint(c))
78838032Speter		{
78964562Sgshapiro			(void) putchar(c);
79038032Speter			continue;
79138032Speter		}
79238032Speter
79338032Speter		/* wasn't a meta-macro -- find another way to print it */
79438032Speter		switch (c)
79538032Speter		{
79638032Speter		  case '\n':
79738032Speter			c = 'n';
79838032Speter			break;
79938032Speter
80038032Speter		  case '\r':
80138032Speter			c = 'r';
80238032Speter			break;
80338032Speter
80438032Speter		  case '\t':
80538032Speter			c = 't';
80638032Speter			break;
80738032Speter		}
80838032Speter		if (!shiftout)
80938032Speter		{
81038032Speter			printf("%s", TermEscape.te_rv_on);
81138032Speter			shiftout = TRUE;
81238032Speter		}
81338032Speter		if (isprint(c))
81438032Speter		{
81538032Speter			(void) putchar('\\');
81638032Speter			(void) putchar(c);
81738032Speter		}
81838032Speter		else
81938032Speter		{
82038032Speter			(void) putchar('^');
82138032Speter			(void) putchar(c ^ 0100);
82238032Speter		}
82338032Speter	}
82438032Speter	if (shiftout)
82538032Speter		printf("%s", TermEscape.te_rv_off);
82638032Speter	(void) fflush(stdout);
82738032Speter}
82838032Speter/*
82938032Speter**  MAKELOWER -- Translate a line into lower case
83038032Speter**
83138032Speter**	Parameters:
83238032Speter**		p -- the string to translate.  If NULL, return is
83338032Speter**			immediate.
83438032Speter**
83538032Speter**	Returns:
83638032Speter**		none.
83738032Speter**
83838032Speter**	Side Effects:
83938032Speter**		String pointed to by p is translated to lower case.
84038032Speter*/
84138032Speter
84238032Spetervoid
84338032Spetermakelower(p)
84438032Speter	register char *p;
84538032Speter{
84638032Speter	register char c;
84738032Speter
84838032Speter	if (p == NULL)
84938032Speter		return;
85038032Speter	for (; (c = *p) != '\0'; p++)
85138032Speter		if (isascii(c) && isupper(c))
85238032Speter			*p = tolower(c);
85338032Speter}
85438032Speter/*
85538032Speter**  BUILDFNAME -- build full name from gecos style entry.
85638032Speter**
85738032Speter**	This routine interprets the strange entry that would appear
85838032Speter**	in the GECOS field of the password file.
85938032Speter**
86038032Speter**	Parameters:
86138032Speter**		p -- name to build.
86264562Sgshapiro**		user -- the login name of this user (for &).
86338032Speter**		buf -- place to put the result.
86438032Speter**		buflen -- length of buf.
86538032Speter**
86638032Speter**	Returns:
86738032Speter**		none.
86838032Speter**
86938032Speter**	Side Effects:
87038032Speter**		none.
87138032Speter*/
87238032Speter
87338032Spetervoid
87464562Sgshapirobuildfname(gecos, user, buf, buflen)
87538032Speter	register char *gecos;
87664562Sgshapiro	char *user;
87738032Speter	char *buf;
87838032Speter	int buflen;
87938032Speter{
88038032Speter	register char *p;
88138032Speter	register char *bp = buf;
88238032Speter
88338032Speter	if (*gecos == '*')
88438032Speter		gecos++;
88538032Speter
88638032Speter	/* copy gecos, interpolating & to be full name */
88738032Speter	for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++)
88838032Speter	{
88938032Speter		if (bp >= &buf[buflen - 1])
89038032Speter		{
89138032Speter			/* buffer overflow -- just use login name */
89264562Sgshapiro			snprintf(buf, buflen, "%s", user);
89338032Speter			return;
89438032Speter		}
89538032Speter		if (*p == '&')
89638032Speter		{
89738032Speter			/* interpolate full name */
89864562Sgshapiro			snprintf(bp, buflen - (bp - buf), "%s", user);
89938032Speter			*bp = toupper(*bp);
90038032Speter			bp += strlen(bp);
90138032Speter		}
90238032Speter		else
90338032Speter			*bp++ = *p;
90438032Speter	}
90538032Speter	*bp = '\0';
90638032Speter}
90738032Speter/*
90838032Speter**  FIXCRLF -- fix <CR><LF> in line.
90938032Speter**
91038032Speter**	Looks for the <CR><LF> combination and turns it into the
91138032Speter**	UNIX canonical <NL> character.  It only takes one line,
91238032Speter**	i.e., it is assumed that the first <NL> found is the end
91338032Speter**	of the line.
91438032Speter**
91538032Speter**	Parameters:
91638032Speter**		line -- the line to fix.
91738032Speter**		stripnl -- if true, strip the newline also.
91838032Speter**
91938032Speter**	Returns:
92038032Speter**		none.
92138032Speter**
92238032Speter**	Side Effects:
92338032Speter**		line is changed in place.
92438032Speter*/
92538032Speter
92638032Spetervoid
92738032Speterfixcrlf(line, stripnl)
92838032Speter	char *line;
92938032Speter	bool stripnl;
93038032Speter{
93138032Speter	register char *p;
93238032Speter
93338032Speter	p = strchr(line, '\n');
93438032Speter	if (p == NULL)
93538032Speter		return;
93638032Speter	if (p > line && p[-1] == '\r')
93738032Speter		p--;
93838032Speter	if (!stripnl)
93938032Speter		*p++ = '\n';
94038032Speter	*p = '\0';
94138032Speter}
94238032Speter/*
94338032Speter**  PUTLINE -- put a line like fputs obeying SMTP conventions
94438032Speter**
94538032Speter**	This routine always guarantees outputing a newline (or CRLF,
94638032Speter**	as appropriate) at the end of the string.
94738032Speter**
94838032Speter**	Parameters:
94938032Speter**		l -- line to put.
95038032Speter**		mci -- the mailer connection information.
95138032Speter**
95238032Speter**	Returns:
95338032Speter**		none
95438032Speter**
95538032Speter**	Side Effects:
95638032Speter**		output of l to fp.
95738032Speter*/
95838032Speter
95938032Spetervoid
96038032Speterputline(l, mci)
96138032Speter	register char *l;
96238032Speter	register MCI *mci;
96338032Speter{
96438032Speter	putxline(l, strlen(l), mci, PXLF_MAPFROM);
96538032Speter}
96638032Speter/*
96738032Speter**  PUTXLINE -- putline with flags bits.
96838032Speter**
96938032Speter**	This routine always guarantees outputing a newline (or CRLF,
97038032Speter**	as appropriate) at the end of the string.
97138032Speter**
97238032Speter**	Parameters:
97338032Speter**		l -- line to put.
97438032Speter**		len -- the length of the line.
97538032Speter**		mci -- the mailer connection information.
97638032Speter**		pxflags -- flag bits:
97738032Speter**		    PXLF_MAPFROM -- map From_ to >From_.
97838032Speter**		    PXLF_STRIP8BIT -- strip 8th bit.
97938032Speter**		    PXLF_HEADER -- map bare newline in header to newline space.
98038032Speter**
98138032Speter**	Returns:
98238032Speter**		none
98338032Speter**
98438032Speter**	Side Effects:
98538032Speter**		output of l to fp.
98638032Speter*/
98738032Speter
98838032Spetervoid
98938032Speterputxline(l, len, mci, pxflags)
99038032Speter	register char *l;
99138032Speter	size_t len;
99238032Speter	register MCI *mci;
99338032Speter	int pxflags;
99438032Speter{
99564562Sgshapiro	bool dead = FALSE;
99638032Speter	register char *p, *end;
99738032Speter	int slop = 0;
99838032Speter
99938032Speter	/* strip out 0200 bits -- these can look like TELNET protocol */
100038032Speter	if (bitset(MCIF_7BIT, mci->mci_flags) ||
100138032Speter	    bitset(PXLF_STRIP8BIT, pxflags))
100238032Speter	{
100338032Speter		register char svchar;
100438032Speter
100538032Speter		for (p = l; (svchar = *p) != '\0'; ++p)
100638032Speter			if (bitset(0200, svchar))
100738032Speter				*p = svchar &~ 0200;
100838032Speter	}
100938032Speter
101038032Speter	end = l + len;
101138032Speter	do
101238032Speter	{
101338032Speter		/* find the end of the line */
101438032Speter		p = memchr(l, '\n', end - l);
101538032Speter		if (p == NULL)
101638032Speter			p = end;
101738032Speter
101838032Speter		if (TrafficLogFile != NULL)
101938032Speter			fprintf(TrafficLogFile, "%05d >>> ", (int) getpid());
102038032Speter
102138032Speter		/* check for line overflow */
102238032Speter		while (mci->mci_mailer->m_linelimit > 0 &&
102338032Speter		       (p - l + slop) > mci->mci_mailer->m_linelimit)
102438032Speter		{
102538032Speter			char *l_base = l;
102638032Speter			register char *q = &l[mci->mci_mailer->m_linelimit - slop - 1];
102738032Speter
102838032Speter			if (l[0] == '.' && slop == 0 &&
102938032Speter			    bitnset(M_XDOT, mci->mci_mailer->m_flags))
103038032Speter			{
103164562Sgshapiro				if (putc('.', mci->mci_out) == EOF)
103264562Sgshapiro					dead = TRUE;
103371345Sgshapiro				else
103471345Sgshapiro				{
103571345Sgshapiro					/* record progress for DATA timeout */
103671345Sgshapiro					DataProgress = TRUE;
103771345Sgshapiro				}
103838032Speter				if (TrafficLogFile != NULL)
103938032Speter					(void) putc('.', TrafficLogFile);
104038032Speter			}
104138032Speter			else if (l[0] == 'F' && slop == 0 &&
104238032Speter				 bitset(PXLF_MAPFROM, pxflags) &&
104338032Speter				 strncmp(l, "From ", 5) == 0 &&
104438032Speter				 bitnset(M_ESCFROM, mci->mci_mailer->m_flags))
104538032Speter			{
104664562Sgshapiro				if (putc('>', mci->mci_out) == EOF)
104764562Sgshapiro					dead = TRUE;
104871345Sgshapiro				else
104971345Sgshapiro				{
105071345Sgshapiro					/* record progress for DATA timeout */
105171345Sgshapiro					DataProgress = TRUE;
105271345Sgshapiro				}
105338032Speter				if (TrafficLogFile != NULL)
105438032Speter					(void) putc('>', TrafficLogFile);
105538032Speter			}
105664562Sgshapiro			if (dead)
105764562Sgshapiro				break;
105864562Sgshapiro
105938032Speter			while (l < q)
106038032Speter			{
106164562Sgshapiro				if (putc((unsigned char) *l++, mci->mci_out) ==
106264562Sgshapiro				    EOF)
106364562Sgshapiro				{
106464562Sgshapiro					dead = TRUE;
106564562Sgshapiro					break;
106664562Sgshapiro				}
106771345Sgshapiro				else
106871345Sgshapiro				{
106971345Sgshapiro					/* record progress for DATA timeout */
107071345Sgshapiro					DataProgress = TRUE;
107171345Sgshapiro				}
107238032Speter			}
107364562Sgshapiro			if (dead)
107464562Sgshapiro				break;
107564562Sgshapiro
107664562Sgshapiro			if (putc('!', mci->mci_out) == EOF ||
107764562Sgshapiro			    fputs(mci->mci_mailer->m_eol,
107864562Sgshapiro				  mci->mci_out) == EOF ||
107964562Sgshapiro			    putc(' ', mci->mci_out) == EOF)
108064562Sgshapiro			{
108164562Sgshapiro				dead = TRUE;
108264562Sgshapiro				break;
108364562Sgshapiro			}
108471345Sgshapiro			else
108571345Sgshapiro			{
108671345Sgshapiro				/* record progress for DATA timeout */
108771345Sgshapiro				DataProgress = TRUE;
108871345Sgshapiro			}
108938032Speter			if (TrafficLogFile != NULL)
109038032Speter			{
109138032Speter				for (l = l_base; l < q; l++)
109264562Sgshapiro					(void) putc((unsigned char)*l,
109364562Sgshapiro						    TrafficLogFile);
109438032Speter				fprintf(TrafficLogFile, "!\n%05d >>>  ",
109538032Speter					(int) getpid());
109638032Speter			}
109738032Speter			slop = 1;
109838032Speter		}
109938032Speter
110064562Sgshapiro		if (dead)
110164562Sgshapiro			break;
110264562Sgshapiro
110338032Speter		/* output last part */
110438032Speter		if (l[0] == '.' && slop == 0 &&
110538032Speter		    bitnset(M_XDOT, mci->mci_mailer->m_flags))
110638032Speter		{
110764562Sgshapiro			if (putc('.', mci->mci_out) == EOF)
110864562Sgshapiro				break;
110971345Sgshapiro			else
111071345Sgshapiro			{
111171345Sgshapiro				/* record progress for DATA timeout */
111271345Sgshapiro				DataProgress = TRUE;
111371345Sgshapiro			}
111438032Speter			if (TrafficLogFile != NULL)
111538032Speter				(void) putc('.', TrafficLogFile);
111638032Speter		}
111738032Speter		else if (l[0] == 'F' && slop == 0 &&
111838032Speter			 bitset(PXLF_MAPFROM, pxflags) &&
111938032Speter			 strncmp(l, "From ", 5) == 0 &&
112038032Speter			 bitnset(M_ESCFROM, mci->mci_mailer->m_flags))
112138032Speter		{
112264562Sgshapiro			if (putc('>', mci->mci_out) == EOF)
112364562Sgshapiro				break;
112471345Sgshapiro			else
112571345Sgshapiro			{
112671345Sgshapiro				/* record progress for DATA timeout */
112771345Sgshapiro				DataProgress = TRUE;
112871345Sgshapiro			}
112938032Speter			if (TrafficLogFile != NULL)
113038032Speter				(void) putc('>', TrafficLogFile);
113138032Speter		}
113238032Speter		for ( ; l < p; ++l)
113338032Speter		{
113438032Speter			if (TrafficLogFile != NULL)
113564562Sgshapiro				(void) putc((unsigned char)*l, TrafficLogFile);
113664562Sgshapiro			if (putc((unsigned char) *l, mci->mci_out) == EOF)
113764562Sgshapiro			{
113864562Sgshapiro				dead = TRUE;
113964562Sgshapiro				break;
114064562Sgshapiro			}
114171345Sgshapiro			else
114271345Sgshapiro			{
114371345Sgshapiro				/* record progress for DATA timeout */
114471345Sgshapiro				DataProgress = TRUE;
114571345Sgshapiro			}
114638032Speter		}
114764562Sgshapiro		if (dead)
114864562Sgshapiro			break;
114964562Sgshapiro
115038032Speter		if (TrafficLogFile != NULL)
115138032Speter			(void) putc('\n', TrafficLogFile);
115264562Sgshapiro		if (fputs(mci->mci_mailer->m_eol, mci->mci_out) == EOF)
115364562Sgshapiro			break;
115471345Sgshapiro		else
115571345Sgshapiro		{
115671345Sgshapiro			/* record progress for DATA timeout */
115771345Sgshapiro			DataProgress = TRUE;
115871345Sgshapiro		}
115938032Speter		if (l < end && *l == '\n')
116038032Speter		{
116138032Speter			if (*++l != ' ' && *l != '\t' && *l != '\0' &&
116238032Speter			    bitset(PXLF_HEADER, pxflags))
116338032Speter			{
116464562Sgshapiro				if (putc(' ', mci->mci_out) == EOF)
116564562Sgshapiro					break;
116671345Sgshapiro				else
116771345Sgshapiro				{
116871345Sgshapiro					/* record progress for DATA timeout */
116971345Sgshapiro					DataProgress = TRUE;
117071345Sgshapiro				}
117138032Speter				if (TrafficLogFile != NULL)
117238032Speter					(void) putc(' ', TrafficLogFile);
117338032Speter			}
117438032Speter		}
117538032Speter	} while (l < end);
117638032Speter}
117738032Speter/*
117838032Speter**  XUNLINK -- unlink a file, doing logging as appropriate.
117938032Speter**
118038032Speter**	Parameters:
118138032Speter**		f -- name of file to unlink.
118238032Speter**
118338032Speter**	Returns:
118438032Speter**		none.
118538032Speter**
118638032Speter**	Side Effects:
118738032Speter**		f is unlinked.
118838032Speter*/
118938032Speter
119038032Spetervoid
119138032Speterxunlink(f)
119238032Speter	char *f;
119338032Speter{
119438032Speter	register int i;
119538032Speter
119638032Speter	if (LogLevel > 98)
119738032Speter		sm_syslog(LOG_DEBUG, CurEnv->e_id,
119864562Sgshapiro			  "unlink %s",
119964562Sgshapiro			  f);
120038032Speter
120138032Speter	i = unlink(f);
120238032Speter	if (i < 0 && LogLevel > 97)
120338032Speter		sm_syslog(LOG_DEBUG, CurEnv->e_id,
120464562Sgshapiro			  "%s: unlink-fail %d",
120564562Sgshapiro			  f, errno);
120638032Speter}
120738032Speter/*
120838032Speter**  SFGETS -- "safe" fgets -- times out and ignores random interrupts.
120938032Speter**
121038032Speter**	Parameters:
121138032Speter**		buf -- place to put the input line.
121238032Speter**		siz -- size of buf.
121338032Speter**		fp -- file to read from.
121438032Speter**		timeout -- the timeout before error occurs.
121538032Speter**		during -- what we are trying to read (for error messages).
121638032Speter**
121738032Speter**	Returns:
121838032Speter**		NULL on error (including timeout).  This will also leave
121938032Speter**			buf containing a null string.
122038032Speter**		buf otherwise.
122138032Speter**
122238032Speter**	Side Effects:
122338032Speter**		none.
122438032Speter*/
122538032Speter
122664562Sgshapiro
122738032Speterstatic jmp_buf	CtxReadTimeout;
122838032Speter
122938032Speterchar *
123038032Spetersfgets(buf, siz, fp, timeout, during)
123138032Speter	char *buf;
123238032Speter	int siz;
123338032Speter	FILE *fp;
123438032Speter	time_t timeout;
123538032Speter	char *during;
123638032Speter{
123738032Speter	register EVENT *ev = NULL;
123838032Speter	register char *p;
123943730Speter	int save_errno;
124038032Speter
124138032Speter	if (fp == NULL)
124238032Speter	{
124338032Speter		buf[0] = '\0';
124438032Speter		return NULL;
124538032Speter	}
124638032Speter
124738032Speter	/* set the timeout */
124838032Speter	if (timeout != 0)
124938032Speter	{
125038032Speter		if (setjmp(CtxReadTimeout) != 0)
125138032Speter		{
125238032Speter			if (LogLevel > 1)
125338032Speter				sm_syslog(LOG_NOTICE, CurEnv->e_id,
125464562Sgshapiro					  "timeout waiting for input from %.100s during %s",
125564562Sgshapiro					  CurHostName ? CurHostName : "local",
125664562Sgshapiro					  during);
125738032Speter			buf[0] = '\0';
125838032Speter#if XDEBUG
125938032Speter			checkfd012(during);
126064562Sgshapiro#endif /* XDEBUG */
126138032Speter			if (TrafficLogFile != NULL)
126238032Speter				fprintf(TrafficLogFile, "%05d <<< [TIMEOUT]\n",
126338032Speter					(int) getpid());
126443730Speter			errno = 0;
126564562Sgshapiro			return NULL;
126638032Speter		}
126738032Speter		ev = setevent(timeout, readtimeout, 0);
126838032Speter	}
126938032Speter
127038032Speter	/* try to read */
127138032Speter	p = NULL;
127243730Speter	errno = 0;
127338032Speter	while (!feof(fp) && !ferror(fp))
127438032Speter	{
127538032Speter		errno = 0;
127638032Speter		p = fgets(buf, siz, fp);
127738032Speter		if (p != NULL || errno != EINTR)
127838032Speter			break;
127938032Speter		clearerr(fp);
128038032Speter	}
128143730Speter	save_errno = errno;
128238032Speter
128338032Speter	/* clear the event if it has not sprung */
128438032Speter	clrevent(ev);
128538032Speter
128638032Speter	/* clean up the books and exit */
128738032Speter	LineNumber++;
128838032Speter	if (p == NULL)
128938032Speter	{
129038032Speter		buf[0] = '\0';
129138032Speter		if (TrafficLogFile != NULL)
129238032Speter			fprintf(TrafficLogFile, "%05d <<< [EOF]\n", (int) getpid());
129343730Speter		errno = save_errno;
129464562Sgshapiro		return NULL;
129538032Speter	}
129638032Speter	if (TrafficLogFile != NULL)
129738032Speter		fprintf(TrafficLogFile, "%05d <<< %s", (int) getpid(), buf);
129838032Speter	if (SevenBitInput)
129938032Speter	{
130038032Speter		for (p = buf; *p != '\0'; p++)
130138032Speter			*p &= ~0200;
130238032Speter	}
130338032Speter	else if (!HasEightBits)
130438032Speter	{
130538032Speter		for (p = buf; *p != '\0'; p++)
130638032Speter		{
130738032Speter			if (bitset(0200, *p))
130838032Speter			{
130938032Speter				HasEightBits = TRUE;
131038032Speter				break;
131138032Speter			}
131238032Speter		}
131338032Speter	}
131464562Sgshapiro	return buf;
131538032Speter}
131638032Speter
131738032Speter/* ARGSUSED */
131838032Speterstatic void
131938032Speterreadtimeout(timeout)
132038032Speter	time_t timeout;
132138032Speter{
132277349Sgshapiro	/*
132377349Sgshapiro	**  NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
132477349Sgshapiro	**	ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
132577349Sgshapiro	**	DOING.
132677349Sgshapiro	*/
132777349Sgshapiro
132877349Sgshapiro	errno = ETIMEDOUT;
132938032Speter	longjmp(CtxReadTimeout, 1);
133038032Speter}
133138032Speter/*
133238032Speter**  FGETFOLDED -- like fgets, but know about folded lines.
133338032Speter**
133438032Speter**	Parameters:
133538032Speter**		buf -- place to put result.
133638032Speter**		n -- bytes available.
133738032Speter**		f -- file to read from.
133838032Speter**
133938032Speter**	Returns:
134038032Speter**		input line(s) on success, NULL on error or EOF.
134138032Speter**		This will normally be buf -- unless the line is too
134238032Speter**			long, when it will be xalloc()ed.
134338032Speter**
134438032Speter**	Side Effects:
134538032Speter**		buf gets lines from f, with continuation lines (lines
134638032Speter**		with leading white space) appended.  CRLF's are mapped
134738032Speter**		into single newlines.  Any trailing NL is stripped.
134838032Speter*/
134938032Speter
135038032Speterchar *
135138032Speterfgetfolded(buf, n, f)
135238032Speter	char *buf;
135338032Speter	register int n;
135438032Speter	FILE *f;
135538032Speter{
135638032Speter	register char *p = buf;
135738032Speter	char *bp = buf;
135838032Speter	register int i;
135938032Speter
136038032Speter	n--;
136138032Speter	while ((i = getc(f)) != EOF)
136238032Speter	{
136338032Speter		if (i == '\r')
136438032Speter		{
136538032Speter			i = getc(f);
136638032Speter			if (i != '\n')
136738032Speter			{
136838032Speter				if (i != EOF)
136938032Speter					(void) ungetc(i, f);
137038032Speter				i = '\r';
137138032Speter			}
137238032Speter		}
137338032Speter		if (--n <= 0)
137438032Speter		{
137538032Speter			/* allocate new space */
137638032Speter			char *nbp;
137738032Speter			int nn;
137838032Speter
137938032Speter			nn = (p - bp);
138038032Speter			if (nn < MEMCHUNKSIZE)
138138032Speter				nn *= 2;
138238032Speter			else
138338032Speter				nn += MEMCHUNKSIZE;
138438032Speter			nbp = xalloc(nn);
138564562Sgshapiro			memmove(nbp, bp, p - bp);
138638032Speter			p = &nbp[p - bp];
138738032Speter			if (bp != buf)
138877349Sgshapiro				sm_free(bp);
138938032Speter			bp = nbp;
139038032Speter			n = nn - (p - bp);
139138032Speter		}
139238032Speter		*p++ = i;
139338032Speter		if (i == '\n')
139438032Speter		{
139538032Speter			LineNumber++;
139638032Speter			i = getc(f);
139738032Speter			if (i != EOF)
139838032Speter				(void) ungetc(i, f);
139938032Speter			if (i != ' ' && i != '\t')
140038032Speter				break;
140138032Speter		}
140238032Speter	}
140338032Speter	if (p == bp)
140464562Sgshapiro		return NULL;
140538032Speter	if (p[-1] == '\n')
140638032Speter		p--;
140738032Speter	*p = '\0';
140864562Sgshapiro	return bp;
140938032Speter}
141038032Speter/*
141138032Speter**  CURTIME -- return current time.
141238032Speter**
141338032Speter**	Parameters:
141438032Speter**		none.
141538032Speter**
141638032Speter**	Returns:
141738032Speter**		the current time.
141838032Speter**
141938032Speter**	Side Effects:
142038032Speter**		none.
142138032Speter*/
142238032Speter
142338032Spetertime_t
142438032Spetercurtime()
142538032Speter{
142638032Speter	auto time_t t;
142738032Speter
142838032Speter	(void) time(&t);
142964562Sgshapiro	return t;
143038032Speter}
143138032Speter/*
143238032Speter**  ATOBOOL -- convert a string representation to boolean.
143338032Speter**
143438032Speter**	Defaults to "TRUE"
143538032Speter**
143638032Speter**	Parameters:
143738032Speter**		s -- string to convert.  Takes "tTyY" as true,
143838032Speter**			others as false.
143938032Speter**
144038032Speter**	Returns:
144138032Speter**		A boolean representation of the string.
144238032Speter**
144338032Speter**	Side Effects:
144438032Speter**		none.
144538032Speter*/
144638032Speter
144738032Speterbool
144838032Speteratobool(s)
144938032Speter	register char *s;
145038032Speter{
145138032Speter	if (s == NULL || *s == '\0' || strchr("tTyY", *s) != NULL)
145264562Sgshapiro		return TRUE;
145364562Sgshapiro	return FALSE;
145438032Speter}
145538032Speter/*
145638032Speter**  ATOOCT -- convert a string representation to octal.
145738032Speter**
145838032Speter**	Parameters:
145938032Speter**		s -- string to convert.
146038032Speter**
146138032Speter**	Returns:
146238032Speter**		An integer representing the string interpreted as an
146338032Speter**		octal number.
146438032Speter**
146538032Speter**	Side Effects:
146638032Speter**		none.
146738032Speter*/
146838032Speter
146938032Speterint
147038032Speteratooct(s)
147138032Speter	register char *s;
147238032Speter{
147338032Speter	register int i = 0;
147438032Speter
147538032Speter	while (*s >= '0' && *s <= '7')
147638032Speter		i = (i << 3) | (*s++ - '0');
147764562Sgshapiro	return i;
147838032Speter}
147938032Speter/*
148038032Speter**  BITINTERSECT -- tell if two bitmaps intersect
148138032Speter**
148238032Speter**	Parameters:
148338032Speter**		a, b -- the bitmaps in question
148438032Speter**
148538032Speter**	Returns:
148638032Speter**		TRUE if they have a non-null intersection
148738032Speter**		FALSE otherwise
148838032Speter**
148938032Speter**	Side Effects:
149038032Speter**		none.
149138032Speter*/
149238032Speter
149338032Speterbool
149438032Speterbitintersect(a, b)
149564562Sgshapiro	BITMAP256 a;
149664562Sgshapiro	BITMAP256 b;
149738032Speter{
149838032Speter	int i;
149938032Speter
150038032Speter	for (i = BITMAPBYTES / sizeof (int); --i >= 0; )
150171345Sgshapiro	{
150238032Speter		if ((a[i] & b[i]) != 0)
150364562Sgshapiro			return TRUE;
150471345Sgshapiro	}
150564562Sgshapiro	return FALSE;
150638032Speter}
150738032Speter/*
150838032Speter**  BITZEROP -- tell if a bitmap is all zero
150938032Speter**
151038032Speter**	Parameters:
151138032Speter**		map -- the bit map to check
151238032Speter**
151338032Speter**	Returns:
151438032Speter**		TRUE if map is all zero.
151538032Speter**		FALSE if there are any bits set in map.
151638032Speter**
151738032Speter**	Side Effects:
151838032Speter**		none.
151938032Speter*/
152038032Speter
152138032Speterbool
152238032Speterbitzerop(map)
152364562Sgshapiro	BITMAP256 map;
152438032Speter{
152538032Speter	int i;
152638032Speter
152738032Speter	for (i = BITMAPBYTES / sizeof (int); --i >= 0; )
152871345Sgshapiro	{
152938032Speter		if (map[i] != 0)
153064562Sgshapiro			return FALSE;
153171345Sgshapiro	}
153264562Sgshapiro	return TRUE;
153338032Speter}
153438032Speter/*
153538032Speter**  STRCONTAINEDIN -- tell if one string is contained in another
153638032Speter**
153738032Speter**	Parameters:
153838032Speter**		a -- possible substring.
153938032Speter**		b -- possible superstring.
154038032Speter**
154138032Speter**	Returns:
154238032Speter**		TRUE if a is contained in b.
154338032Speter**		FALSE otherwise.
154438032Speter*/
154538032Speter
154638032Speterbool
154738032Speterstrcontainedin(a, b)
154838032Speter	register char *a;
154938032Speter	register char *b;
155038032Speter{
155138032Speter	int la;
155238032Speter	int lb;
155338032Speter	int c;
155438032Speter
155538032Speter	la = strlen(a);
155638032Speter	lb = strlen(b);
155738032Speter	c = *a;
155838032Speter	if (isascii(c) && isupper(c))
155938032Speter		c = tolower(c);
156038032Speter	for (; lb-- >= la; b++)
156138032Speter	{
156238032Speter		if (*b != c && isascii(*b) && isupper(*b) && tolower(*b) != c)
156338032Speter			continue;
156438032Speter		if (strncasecmp(a, b, la) == 0)
156538032Speter			return TRUE;
156638032Speter	}
156738032Speter	return FALSE;
156838032Speter}
156938032Speter/*
157038032Speter**  CHECKFD012 -- check low numbered file descriptors
157138032Speter**
157238032Speter**	File descriptors 0, 1, and 2 should be open at all times.
157338032Speter**	This routine verifies that, and fixes it if not true.
157438032Speter**
157538032Speter**	Parameters:
157638032Speter**		where -- a tag printed if the assertion failed
157738032Speter**
157838032Speter**	Returns:
157938032Speter**		none
158038032Speter*/
158138032Speter
158238032Spetervoid
158338032Spetercheckfd012(where)
158438032Speter	char *where;
158538032Speter{
158638032Speter#if XDEBUG
158738032Speter	register int i;
158838032Speter
158938032Speter	for (i = 0; i < 3; i++)
159038032Speter		fill_fd(i, where);
159138032Speter#endif /* XDEBUG */
159238032Speter}
159338032Speter/*
159438032Speter**  CHECKFDOPEN -- make sure file descriptor is open -- for extended debugging
159538032Speter**
159638032Speter**	Parameters:
159738032Speter**		fd -- file descriptor to check.
159838032Speter**		where -- tag to print on failure.
159938032Speter**
160038032Speter**	Returns:
160138032Speter**		none.
160238032Speter*/
160338032Speter
160438032Spetervoid
160538032Spetercheckfdopen(fd, where)
160638032Speter	int fd;
160738032Speter	char *where;
160838032Speter{
160938032Speter#if XDEBUG
161038032Speter	struct stat st;
161138032Speter
161238032Speter	if (fstat(fd, &st) < 0 && errno == EBADF)
161338032Speter	{
161438032Speter		syserr("checkfdopen(%d): %s not open as expected!", fd, where);
161538032Speter		printopenfds(TRUE);
161638032Speter	}
161764562Sgshapiro#endif /* XDEBUG */
161838032Speter}
161938032Speter/*
162038032Speter**  CHECKFDS -- check for new or missing file descriptors
162138032Speter**
162238032Speter**	Parameters:
162338032Speter**		where -- tag for printing.  If null, take a base line.
162438032Speter**
162538032Speter**	Returns:
162638032Speter**		none
162738032Speter**
162838032Speter**	Side Effects:
162938032Speter**		If where is set, shows changes since the last call.
163038032Speter*/
163138032Speter
163238032Spetervoid
163338032Spetercheckfds(where)
163438032Speter	char *where;
163538032Speter{
163638032Speter	int maxfd;
163738032Speter	register int fd;
163838032Speter	bool printhdr = TRUE;
163938032Speter	int save_errno = errno;
164064562Sgshapiro	static BITMAP256 baseline;
164138032Speter	extern int DtableSize;
164238032Speter
164371345Sgshapiro	if (DtableSize > BITMAPBITS)
164471345Sgshapiro		maxfd = BITMAPBITS;
164538032Speter	else
164638032Speter		maxfd = DtableSize;
164738032Speter	if (where == NULL)
164838032Speter		clrbitmap(baseline);
164938032Speter
165038032Speter	for (fd = 0; fd < maxfd; fd++)
165138032Speter	{
165238032Speter		struct stat stbuf;
165338032Speter
165438032Speter		if (fstat(fd, &stbuf) < 0 && errno != EOPNOTSUPP)
165538032Speter		{
165638032Speter			if (!bitnset(fd, baseline))
165738032Speter				continue;
165838032Speter			clrbitn(fd, baseline);
165938032Speter		}
166038032Speter		else if (!bitnset(fd, baseline))
166138032Speter			setbitn(fd, baseline);
166238032Speter		else
166338032Speter			continue;
166438032Speter
166538032Speter		/* file state has changed */
166638032Speter		if (where == NULL)
166738032Speter			continue;
166838032Speter		if (printhdr)
166938032Speter		{
167038032Speter			sm_syslog(LOG_DEBUG, CurEnv->e_id,
167164562Sgshapiro				  "%s: changed fds:",
167264562Sgshapiro				  where);
167338032Speter			printhdr = FALSE;
167438032Speter		}
167538032Speter		dumpfd(fd, TRUE, TRUE);
167638032Speter	}
167738032Speter	errno = save_errno;
167838032Speter}
167938032Speter/*
168038032Speter**  PRINTOPENFDS -- print the open file descriptors (for debugging)
168138032Speter**
168238032Speter**	Parameters:
168338032Speter**		logit -- if set, send output to syslog; otherwise
168438032Speter**			print for debugging.
168538032Speter**
168638032Speter**	Returns:
168738032Speter**		none.
168838032Speter*/
168938032Speter
169064562Sgshapiro#if NETINET || NETINET6
169164562Sgshapiro# include <arpa/inet.h>
169264562Sgshapiro#endif /* NETINET || NETINET6 */
169338032Speter
169438032Spetervoid
169538032Speterprintopenfds(logit)
169638032Speter	bool logit;
169738032Speter{
169838032Speter	register int fd;
169938032Speter	extern int DtableSize;
170038032Speter
170138032Speter	for (fd = 0; fd < DtableSize; fd++)
170238032Speter		dumpfd(fd, FALSE, logit);
170338032Speter}
170438032Speter/*
170538032Speter**  DUMPFD -- dump a file descriptor
170638032Speter**
170738032Speter**	Parameters:
170838032Speter**		fd -- the file descriptor to dump.
170938032Speter**		printclosed -- if set, print a notification even if
171038032Speter**			it is closed; otherwise print nothing.
171138032Speter**		logit -- if set, send output to syslog instead of stdout.
171238032Speter*/
171338032Speter
171438032Spetervoid
171538032Speterdumpfd(fd, printclosed, logit)
171638032Speter	int fd;
171738032Speter	bool printclosed;
171838032Speter	bool logit;
171938032Speter{
172038032Speter	register char *p;
172138032Speter	char *hp;
172238032Speter#ifdef S_IFSOCK
172338032Speter	SOCKADDR sa;
172464562Sgshapiro#endif /* S_IFSOCK */
172538032Speter	auto SOCKADDR_LEN_T slen;
172638032Speter	int i;
172738032Speter#if STAT64 > 0
172838032Speter	struct stat64 st;
172964562Sgshapiro#else /* STAT64 > 0 */
173038032Speter	struct stat st;
173164562Sgshapiro#endif /* STAT64 > 0 */
173238032Speter	char buf[200];
173338032Speter
173438032Speter	p = buf;
173538032Speter	snprintf(p, SPACELEFT(buf, p), "%3d: ", fd);
173638032Speter	p += strlen(p);
173738032Speter
173838032Speter	if (
173938032Speter#if STAT64 > 0
174038032Speter	    fstat64(fd, &st)
174164562Sgshapiro#else /* STAT64 > 0 */
174238032Speter	    fstat(fd, &st)
174364562Sgshapiro#endif /* STAT64 > 0 */
174438032Speter	    < 0)
174538032Speter	{
174638032Speter		if (errno != EBADF)
174738032Speter		{
174838032Speter			snprintf(p, SPACELEFT(buf, p), "CANNOT STAT (%s)",
174938032Speter				errstring(errno));
175038032Speter			goto printit;
175138032Speter		}
175238032Speter		else if (printclosed)
175338032Speter		{
175438032Speter			snprintf(p, SPACELEFT(buf, p), "CLOSED");
175538032Speter			goto printit;
175638032Speter		}
175738032Speter		return;
175838032Speter	}
175938032Speter
176038032Speter	i = fcntl(fd, F_GETFL, NULL);
176138032Speter	if (i != -1)
176238032Speter	{
176338032Speter		snprintf(p, SPACELEFT(buf, p), "fl=0x%x, ", i);
176438032Speter		p += strlen(p);
176538032Speter	}
176638032Speter
176764562Sgshapiro	snprintf(p, SPACELEFT(buf, p), "mode=%o: ", (int) st.st_mode);
176838032Speter	p += strlen(p);
176938032Speter	switch (st.st_mode & S_IFMT)
177038032Speter	{
177138032Speter#ifdef S_IFSOCK
177238032Speter	  case S_IFSOCK:
177338032Speter		snprintf(p, SPACELEFT(buf, p), "SOCK ");
177438032Speter		p += strlen(p);
177564562Sgshapiro		memset(&sa, '\0', sizeof sa);
177638032Speter		slen = sizeof sa;
177738032Speter		if (getsockname(fd, &sa.sa, &slen) < 0)
177864562Sgshapiro			snprintf(p, SPACELEFT(buf, p), "(%s)",
177964562Sgshapiro				 errstring(errno));
178038032Speter		else
178138032Speter		{
178238032Speter			hp = hostnamebyanyaddr(&sa);
178364562Sgshapiro			if (hp == NULL)
178464562Sgshapiro			{
178564562Sgshapiro				/* EMPTY */
178664562Sgshapiro				/* do nothing */
178764562Sgshapiro			}
178864562Sgshapiro# if NETINET
178964562Sgshapiro			else if (sa.sa.sa_family == AF_INET)
179038032Speter				snprintf(p, SPACELEFT(buf, p), "%s/%d",
179164562Sgshapiro					 hp, ntohs(sa.sin.sin_port));
179264562Sgshapiro# endif /* NETINET */
179364562Sgshapiro# if NETINET6
179464562Sgshapiro			else if (sa.sa.sa_family == AF_INET6)
179564562Sgshapiro				snprintf(p, SPACELEFT(buf, p), "%s/%d",
179664562Sgshapiro					 hp, ntohs(sa.sin6.sin6_port));
179764562Sgshapiro# endif /* NETINET6 */
179838032Speter			else
179938032Speter				snprintf(p, SPACELEFT(buf, p), "%s", hp);
180038032Speter		}
180138032Speter		p += strlen(p);
180238032Speter		snprintf(p, SPACELEFT(buf, p), "->");
180338032Speter		p += strlen(p);
180438032Speter		slen = sizeof sa;
180538032Speter		if (getpeername(fd, &sa.sa, &slen) < 0)
180638032Speter			snprintf(p, SPACELEFT(buf, p), "(%s)", errstring(errno));
180738032Speter		else
180838032Speter		{
180938032Speter			hp = hostnamebyanyaddr(&sa);
181064562Sgshapiro			if (hp == NULL)
181164562Sgshapiro			{
181264562Sgshapiro				/* EMPTY */
181364562Sgshapiro				/* do nothing */
181464562Sgshapiro			}
181564562Sgshapiro# if NETINET
181664562Sgshapiro			else if (sa.sa.sa_family == AF_INET)
181738032Speter				snprintf(p, SPACELEFT(buf, p), "%s/%d",
181864562Sgshapiro					 hp, ntohs(sa.sin.sin_port));
181964562Sgshapiro# endif /* NETINET */
182064562Sgshapiro# if NETINET6
182164562Sgshapiro			else if (sa.sa.sa_family == AF_INET6)
182264562Sgshapiro				snprintf(p, SPACELEFT(buf, p), "%s/%d",
182364562Sgshapiro					 hp, ntohs(sa.sin6.sin6_port));
182464562Sgshapiro# endif /* NETINET6 */
182538032Speter			else
182638032Speter				snprintf(p, SPACELEFT(buf, p), "%s", hp);
182738032Speter		}
182838032Speter		break;
182964562Sgshapiro#endif /* S_IFSOCK */
183038032Speter
183138032Speter	  case S_IFCHR:
183238032Speter		snprintf(p, SPACELEFT(buf, p), "CHR: ");
183338032Speter		p += strlen(p);
183438032Speter		goto defprint;
183538032Speter
183638032Speter	  case S_IFBLK:
183738032Speter		snprintf(p, SPACELEFT(buf, p), "BLK: ");
183838032Speter		p += strlen(p);
183938032Speter		goto defprint;
184038032Speter
184138032Speter#if defined(S_IFIFO) && (!defined(S_IFSOCK) || S_IFIFO != S_IFSOCK)
184238032Speter	  case S_IFIFO:
184338032Speter		snprintf(p, SPACELEFT(buf, p), "FIFO: ");
184438032Speter		p += strlen(p);
184538032Speter		goto defprint;
184664562Sgshapiro#endif /* defined(S_IFIFO) && (!defined(S_IFSOCK) || S_IFIFO != S_IFSOCK) */
184738032Speter
184838032Speter#ifdef S_IFDIR
184938032Speter	  case S_IFDIR:
185038032Speter		snprintf(p, SPACELEFT(buf, p), "DIR: ");
185138032Speter		p += strlen(p);
185238032Speter		goto defprint;
185364562Sgshapiro#endif /* S_IFDIR */
185438032Speter
185538032Speter#ifdef S_IFLNK
185638032Speter	  case S_IFLNK:
185738032Speter		snprintf(p, SPACELEFT(buf, p), "LNK: ");
185838032Speter		p += strlen(p);
185938032Speter		goto defprint;
186064562Sgshapiro#endif /* S_IFLNK */
186138032Speter
186238032Speter	  default:
186338032Speterdefprint:
186464562Sgshapiro		/*CONSTCOND*/
186538032Speter		if (sizeof st.st_ino > sizeof (long))
186638032Speter			snprintf(p, SPACELEFT(buf, p),
186738032Speter				 "dev=%d/%d, ino=%s, nlink=%d, u/gid=%d/%d, ",
186838032Speter				 major(st.st_dev), minor(st.st_dev),
186938032Speter				 quad_to_string(st.st_ino),
187064562Sgshapiro				 (int) st.st_nlink, (int) st.st_uid,
187164562Sgshapiro				 (int) st.st_gid);
187238032Speter		else
187338032Speter			snprintf(p, SPACELEFT(buf, p),
187464562Sgshapiro				 "dev=%d/%d, ino=%lu, nlink=%d, u/gid=%d/%d, ",
187564562Sgshapiro				 major(st.st_dev), minor(st.st_dev),
187664562Sgshapiro				 (unsigned long) st.st_ino,
187764562Sgshapiro				 (int) st.st_nlink, (int) st.st_uid,
187864562Sgshapiro				 (int) st.st_gid);
187964562Sgshapiro		/*CONSTCOND*/
188038032Speter		if (sizeof st.st_size > sizeof (long))
188138032Speter			snprintf(p, SPACELEFT(buf, p), "size=%s",
188238032Speter				 quad_to_string(st.st_size));
188338032Speter		else
188438032Speter			snprintf(p, SPACELEFT(buf, p), "size=%lu",
188538032Speter				 (unsigned long) st.st_size);
188638032Speter		break;
188738032Speter	}
188838032Speter
188938032Speterprintit:
189038032Speter	if (logit)
189138032Speter		sm_syslog(LOG_DEBUG, CurEnv ? CurEnv->e_id : NULL,
189264562Sgshapiro			  "%.800s", buf);
189338032Speter	else
189438032Speter		printf("%s\n", buf);
189538032Speter}
189638032Speter/*
189738032Speter**  SHORTEN_HOSTNAME -- strip local domain information off of hostname.
189838032Speter**
189938032Speter**	Parameters:
190038032Speter**		host -- the host to shorten (stripped in place).
190138032Speter**
190238032Speter**	Returns:
190373188Sgshapiro**		place where string was trunacted, NULL if not truncated.
190438032Speter*/
190538032Speter
190673188Sgshapirochar *
190738032Spetershorten_hostname(host)
190838032Speter	char host[];
190938032Speter{
191038032Speter	register char *p;
191138032Speter	char *mydom;
191238032Speter	int i;
191338032Speter	bool canon = FALSE;
191438032Speter
191538032Speter	/* strip off final dot */
191638032Speter	p = &host[strlen(host) - 1];
191738032Speter	if (*p == '.')
191838032Speter	{
191938032Speter		*p = '\0';
192038032Speter		canon = TRUE;
192138032Speter	}
192238032Speter
192338032Speter	/* see if there is any domain at all -- if not, we are done */
192438032Speter	p = strchr(host, '.');
192538032Speter	if (p == NULL)
192673188Sgshapiro		return NULL;
192738032Speter
192838032Speter	/* yes, we have a domain -- see if it looks like us */
192938032Speter	mydom = macvalue('m', CurEnv);
193038032Speter	if (mydom == NULL)
193138032Speter		mydom = "";
193238032Speter	i = strlen(++p);
193338032Speter	if ((canon ? strcasecmp(p, mydom) : strncasecmp(p, mydom, i)) == 0 &&
193438032Speter	    (mydom[i] == '.' || mydom[i] == '\0'))
193573188Sgshapiro	{
193638032Speter		*--p = '\0';
193773188Sgshapiro		return p;
193873188Sgshapiro	}
193973188Sgshapiro	return NULL;
194038032Speter}
194138032Speter/*
194238032Speter**  PROG_OPEN -- open a program for reading
194338032Speter**
194438032Speter**	Parameters:
194538032Speter**		argv -- the argument list.
194638032Speter**		pfd -- pointer to a place to store the file descriptor.
194738032Speter**		e -- the current envelope.
194838032Speter**
194938032Speter**	Returns:
195038032Speter**		pid of the process -- -1 if it failed.
195138032Speter*/
195238032Speter
195377349Sgshapiropid_t
195438032Speterprog_open(argv, pfd, e)
195538032Speter	char **argv;
195638032Speter	int *pfd;
195738032Speter	ENVELOPE *e;
195838032Speter{
195977349Sgshapiro	pid_t pid;
196038032Speter	int i;
196164562Sgshapiro	int save_errno;
196238032Speter	int fdv[2];
196338032Speter	char *p, *q;
196438032Speter	char buf[MAXLINE + 1];
196538032Speter	extern int DtableSize;
196638032Speter
196738032Speter	if (pipe(fdv) < 0)
196838032Speter	{
196938032Speter		syserr("%s: cannot create pipe for stdout", argv[0]);
197038032Speter		return -1;
197138032Speter	}
197238032Speter	pid = fork();
197338032Speter	if (pid < 0)
197438032Speter	{
197538032Speter		syserr("%s: cannot fork", argv[0]);
197664562Sgshapiro		(void) close(fdv[0]);
197764562Sgshapiro		(void) close(fdv[1]);
197838032Speter		return -1;
197938032Speter	}
198038032Speter	if (pid > 0)
198138032Speter	{
198238032Speter		/* parent */
198364562Sgshapiro		(void) close(fdv[1]);
198438032Speter		*pfd = fdv[0];
198538032Speter		return pid;
198638032Speter	}
198738032Speter
198838032Speter	/* child -- close stdin */
198964562Sgshapiro	(void) close(0);
199038032Speter
199177349Sgshapiro	/* Reset global flags */
199277349Sgshapiro	RestartRequest = NULL;
199377349Sgshapiro	ShutdownRequest = NULL;
199477349Sgshapiro	PendingSignal = 0;
199577349Sgshapiro
199638032Speter	/* stdout goes back to parent */
199764562Sgshapiro	(void) close(fdv[0]);
199838032Speter	if (dup2(fdv[1], 1) < 0)
199938032Speter	{
200038032Speter		syserr("%s: cannot dup2 for stdout", argv[0]);
200138032Speter		_exit(EX_OSERR);
200238032Speter	}
200364562Sgshapiro	(void) close(fdv[1]);
200438032Speter
200538032Speter	/* stderr goes to transcript if available */
200638032Speter	if (e->e_xfp != NULL)
200738032Speter	{
200864562Sgshapiro		int xfd;
200964562Sgshapiro
201064562Sgshapiro		xfd = fileno(e->e_xfp);
201164562Sgshapiro		if (xfd >= 0 && dup2(xfd, 2) < 0)
201238032Speter		{
201338032Speter			syserr("%s: cannot dup2 for stderr", argv[0]);
201438032Speter			_exit(EX_OSERR);
201538032Speter		}
201638032Speter	}
201738032Speter
201838032Speter	/* this process has no right to the queue file */
201938032Speter	if (e->e_lockfp != NULL)
202064562Sgshapiro		(void) close(fileno(e->e_lockfp));
202138032Speter
202264562Sgshapiro	/* chroot to the program mailer directory, if defined */
202364562Sgshapiro	if (ProgMailer != NULL && ProgMailer->m_rootdir != NULL)
202464562Sgshapiro	{
202564562Sgshapiro		expand(ProgMailer->m_rootdir, buf, sizeof buf, e);
202664562Sgshapiro		if (chroot(buf) < 0)
202764562Sgshapiro		{
202864562Sgshapiro			syserr("prog_open: cannot chroot(%s)", buf);
202964562Sgshapiro			exit(EX_TEMPFAIL);
203064562Sgshapiro		}
203164562Sgshapiro		if (chdir("/") < 0)
203264562Sgshapiro		{
203364562Sgshapiro			syserr("prog_open: cannot chdir(/)");
203464562Sgshapiro			exit(EX_TEMPFAIL);
203564562Sgshapiro		}
203664562Sgshapiro	}
203764562Sgshapiro
203838032Speter	/* run as default user */
203938032Speter	endpwent();
204038032Speter	if (setgid(DefGid) < 0 && geteuid() == 0)
204164562Sgshapiro	{
204238032Speter		syserr("prog_open: setgid(%ld) failed", (long) DefGid);
204364562Sgshapiro		exit(EX_TEMPFAIL);
204464562Sgshapiro	}
204538032Speter	if (setuid(DefUid) < 0 && geteuid() == 0)
204664562Sgshapiro	{
204738032Speter		syserr("prog_open: setuid(%ld) failed", (long) DefUid);
204864562Sgshapiro		exit(EX_TEMPFAIL);
204964562Sgshapiro	}
205038032Speter
205138032Speter	/* run in some directory */
205238032Speter	if (ProgMailer != NULL)
205338032Speter		p = ProgMailer->m_execdir;
205438032Speter	else
205538032Speter		p = NULL;
205638032Speter	for (; p != NULL; p = q)
205738032Speter	{
205838032Speter		q = strchr(p, ':');
205938032Speter		if (q != NULL)
206038032Speter			*q = '\0';
206138032Speter		expand(p, buf, sizeof buf, e);
206238032Speter		if (q != NULL)
206338032Speter			*q++ = ':';
206438032Speter		if (buf[0] != '\0' && chdir(buf) >= 0)
206538032Speter			break;
206638032Speter	}
206738032Speter	if (p == NULL)
206838032Speter	{
206938032Speter		/* backup directories */
207038032Speter		if (chdir("/tmp") < 0)
207138032Speter			(void) chdir("/");
207238032Speter	}
207338032Speter
207438032Speter	/* arrange for all the files to be closed */
207538032Speter	for (i = 3; i < DtableSize; i++)
207638032Speter	{
207738032Speter		register int j;
207838032Speter
207938032Speter		if ((j = fcntl(i, F_GETFD, 0)) != -1)
208064562Sgshapiro			(void) fcntl(i, F_SETFD, j | FD_CLOEXEC);
208138032Speter	}
208238032Speter
208338032Speter	/* now exec the process */
208464562Sgshapiro	(void) execve(argv[0], (ARGV_T) argv, (ARGV_T) UserEnviron);
208538032Speter
208638032Speter	/* woops!  failed */
208764562Sgshapiro	save_errno = errno;
208838032Speter	syserr("%s: cannot exec", argv[0]);
208964562Sgshapiro	if (transienterror(save_errno))
209038032Speter		_exit(EX_OSERR);
209138032Speter	_exit(EX_CONFIG);
209238032Speter	return -1;	/* avoid compiler warning on IRIX */
209338032Speter}
209438032Speter/*
209564562Sgshapiro**  GET_COLUMN -- look up a Column in a line buffer
209638032Speter**
209738032Speter**	Parameters:
209838032Speter**		line -- the raw text line to search.
209938032Speter**		col -- the column number to fetch.
210038032Speter**		delim -- the delimiter between columns.  If null,
210138032Speter**			use white space.
210238032Speter**		buf -- the output buffer.
210338032Speter**		buflen -- the length of buf.
210438032Speter**
210538032Speter**	Returns:
210638032Speter**		buf if successful.
210738032Speter**		NULL otherwise.
210838032Speter*/
210938032Speter
211038032Speterchar *
211138032Speterget_column(line, col, delim, buf, buflen)
211238032Speter	char line[];
211338032Speter	int col;
211464562Sgshapiro	int delim;
211538032Speter	char buf[];
211638032Speter	int buflen;
211738032Speter{
211838032Speter	char *p;
211938032Speter	char *begin, *end;
212038032Speter	int i;
212138032Speter	char delimbuf[4];
212264562Sgshapiro
212364562Sgshapiro	if ((char)delim == '\0')
212464562Sgshapiro		(void) strlcpy(delimbuf, "\n\t ", sizeof delimbuf);
212538032Speter	else
212638032Speter	{
212764562Sgshapiro		delimbuf[0] = (char)delim;
212838032Speter		delimbuf[1] = '\0';
212938032Speter	}
213038032Speter
213138032Speter	p = line;
213238032Speter	if (*p == '\0')
213338032Speter		return NULL;			/* line empty */
213464562Sgshapiro	if (*p == (char)delim && col == 0)
213538032Speter		return NULL;			/* first column empty */
213638032Speter
213738032Speter	begin = line;
213838032Speter
213964562Sgshapiro	if (col == 0 && (char)delim == '\0')
214038032Speter	{
214138032Speter		while (*begin != '\0' && isascii(*begin) && isspace(*begin))
214238032Speter			begin++;
214338032Speter	}
214438032Speter
214538032Speter	for (i = 0; i < col; i++)
214638032Speter	{
214738032Speter		if ((begin = strpbrk(begin, delimbuf)) == NULL)
214838032Speter			return NULL;		/* no such column */
214938032Speter		begin++;
215064562Sgshapiro		if ((char)delim == '\0')
215138032Speter		{
215238032Speter			while (*begin != '\0' && isascii(*begin) && isspace(*begin))
215338032Speter				begin++;
215438032Speter		}
215538032Speter	}
215664562Sgshapiro
215738032Speter	end = strpbrk(begin, delimbuf);
215838032Speter	if (end == NULL)
215938032Speter		i = strlen(begin);
216038032Speter	else
216138032Speter		i = end - begin;
216238032Speter	if (i >= buflen)
216338032Speter		i = buflen - 1;
216464562Sgshapiro	(void) strlcpy(buf, begin, i + 1);
216538032Speter	return buf;
216638032Speter}
216738032Speter/*
216838032Speter**  CLEANSTRCPY -- copy string keeping out bogus characters
216938032Speter**
217038032Speter**	Parameters:
217138032Speter**		t -- "to" string.
217238032Speter**		f -- "from" string.
217338032Speter**		l -- length of space available in "to" string.
217438032Speter**
217538032Speter**	Returns:
217638032Speter**		none.
217738032Speter*/
217838032Speter
217938032Spetervoid
218038032Spetercleanstrcpy(t, f, l)
218138032Speter	register char *t;
218238032Speter	register char *f;
218338032Speter	int l;
218438032Speter{
218538032Speter	/* check for newlines and log if necessary */
218638032Speter	(void) denlstring(f, TRUE, TRUE);
218738032Speter
218864562Sgshapiro	if (l <= 0)
218964562Sgshapiro		syserr("!cleanstrcpy: length == 0");
219064562Sgshapiro
219138032Speter	l--;
219238032Speter	while (l > 0 && *f != '\0')
219338032Speter	{
219438032Speter		if (isascii(*f) &&
219538032Speter		    (isalnum(*f) || strchr("!#$%&'*+-./^_`{|}~", *f) != NULL))
219638032Speter		{
219738032Speter			l--;
219838032Speter			*t++ = *f;
219938032Speter		}
220038032Speter		f++;
220138032Speter	}
220238032Speter	*t = '\0';
220338032Speter}
220464562Sgshapiro
220538032Speter/*
220638032Speter**  DENLSTRING -- convert newlines in a string to spaces
220738032Speter**
220838032Speter**	Parameters:
220938032Speter**		s -- the input string
221038032Speter**		strict -- if set, don't permit continuation lines.
221138032Speter**		logattacks -- if set, log attempted attacks.
221238032Speter**
221338032Speter**	Returns:
221438032Speter**		A pointer to a version of the string with newlines
221538032Speter**		mapped to spaces.  This should be copied.
221638032Speter*/
221738032Speter
221838032Speterchar *
221938032Speterdenlstring(s, strict, logattacks)
222038032Speter	char *s;
222138032Speter	bool strict;
222238032Speter	bool logattacks;
222338032Speter{
222438032Speter	register char *p;
222538032Speter	int l;
222638032Speter	static char *bp = NULL;
222738032Speter	static int bl = 0;
222838032Speter
222938032Speter	p = s;
223038032Speter	while ((p = strchr(p, '\n')) != NULL)
223138032Speter		if (strict || (*++p != ' ' && *p != '\t'))
223238032Speter			break;
223338032Speter	if (p == NULL)
223438032Speter		return s;
223538032Speter
223638032Speter	l = strlen(s) + 1;
223738032Speter	if (bl < l)
223838032Speter	{
223938032Speter		/* allocate more space */
224038032Speter		if (bp != NULL)
224177349Sgshapiro			sm_free(bp);
224238032Speter		bp = xalloc(l);
224338032Speter		bl = l;
224438032Speter	}
224564562Sgshapiro	(void) strlcpy(bp, s, l);
224638032Speter	for (p = bp; (p = strchr(p, '\n')) != NULL; )
224738032Speter		*p++ = ' ';
224838032Speter
224938032Speter	if (logattacks)
225038032Speter	{
225138032Speter		sm_syslog(LOG_NOTICE, CurEnv->e_id,
225264562Sgshapiro			  "POSSIBLE ATTACK from %.100s: newline in string \"%s\"",
225364562Sgshapiro			  RealHostName == NULL ? "[UNKNOWN]" : RealHostName,
225464562Sgshapiro			  shortenstring(bp, MAXSHORTSTR));
225538032Speter	}
225638032Speter
225738032Speter	return bp;
225838032Speter}
225938032Speter/*
226038032Speter**  PATH_IS_DIR -- check to see if file exists and is a directory.
226138032Speter**
226238032Speter**	There are some additional checks for security violations in
226338032Speter**	here.  This routine is intended to be used for the host status
226438032Speter**	support.
226538032Speter**
226638032Speter**	Parameters:
226738032Speter**		pathname -- pathname to check for directory-ness.
226838032Speter**		createflag -- if set, create directory if needed.
226938032Speter**
227038032Speter**	Returns:
227138032Speter**		TRUE -- if the indicated pathname is a directory
227238032Speter**		FALSE -- otherwise
227338032Speter*/
227438032Speter
227538032Speterint
227638032Speterpath_is_dir(pathname, createflag)
227738032Speter	char *pathname;
227838032Speter	bool createflag;
227938032Speter{
228038032Speter	struct stat statbuf;
228138032Speter
228238032Speter#if HASLSTAT
228338032Speter	if (lstat(pathname, &statbuf) < 0)
228464562Sgshapiro#else /* HASLSTAT */
228538032Speter	if (stat(pathname, &statbuf) < 0)
228664562Sgshapiro#endif /* HASLSTAT */
228738032Speter	{
228838032Speter		if (errno != ENOENT || !createflag)
228938032Speter			return FALSE;
229038032Speter		if (mkdir(pathname, 0755) < 0)
229138032Speter			return FALSE;
229238032Speter		return TRUE;
229338032Speter	}
229438032Speter	if (!S_ISDIR(statbuf.st_mode))
229538032Speter	{
229638032Speter		errno = ENOTDIR;
229738032Speter		return FALSE;
229838032Speter	}
229938032Speter
230038032Speter	/* security: don't allow writable directories */
230138032Speter	if (bitset(S_IWGRP|S_IWOTH, statbuf.st_mode))
230238032Speter	{
230338032Speter		errno = EACCES;
230438032Speter		return FALSE;
230538032Speter	}
230638032Speter
230738032Speter	return TRUE;
230838032Speter}
230938032Speter/*
231038032Speter**  PROC_LIST_ADD -- add process id to list of our children
231138032Speter**
231238032Speter**	Parameters:
231338032Speter**		pid -- pid to add to list.
231464562Sgshapiro**		task -- task of pid.
231564562Sgshapiro**		type -- type of process.
231638032Speter**
231738032Speter**	Returns:
231838032Speter**		none
231938032Speter*/
232038032Speter
232177349Sgshapirostatic struct procs	*volatile ProcListVec = NULL;
232264562Sgshapirostatic int		ProcListSize = 0;
232342575Speter
232438032Spetervoid
232564562Sgshapiroproc_list_add(pid, task, type)
232638032Speter	pid_t pid;
232742575Speter	char *task;
232864562Sgshapiro	int type;
232938032Speter{
233038032Speter	int i;
233138032Speter
233238032Speter	for (i = 0; i < ProcListSize; i++)
233338032Speter	{
233442575Speter		if (ProcListVec[i].proc_pid == NO_PID)
233538032Speter			break;
233638032Speter	}
233738032Speter	if (i >= ProcListSize)
233838032Speter	{
233938032Speter		/* probe the existing vector to avoid growing infinitely */
234038032Speter		proc_list_probe();
234138032Speter
234238032Speter		/* now scan again */
234338032Speter		for (i = 0; i < ProcListSize; i++)
234438032Speter		{
234542575Speter			if (ProcListVec[i].proc_pid == NO_PID)
234638032Speter				break;
234738032Speter		}
234838032Speter	}
234938032Speter	if (i >= ProcListSize)
235038032Speter	{
235138032Speter		/* grow process list */
235242575Speter		struct procs *npv;
235338032Speter
235464562Sgshapiro		npv = (struct procs *) xalloc((sizeof *npv) *
235564562Sgshapiro					      (ProcListSize + PROC_LIST_SEG));
235638032Speter		if (ProcListSize > 0)
235738032Speter		{
235864562Sgshapiro			memmove(npv, ProcListVec,
235964562Sgshapiro				ProcListSize * sizeof (struct procs));
236077349Sgshapiro			sm_free(ProcListVec);
236138032Speter		}
236238032Speter		for (i = ProcListSize; i < ProcListSize + PROC_LIST_SEG; i++)
236342575Speter		{
236442575Speter			npv[i].proc_pid = NO_PID;
236542575Speter			npv[i].proc_task = NULL;
236664562Sgshapiro			npv[i].proc_type = PROC_NONE;
236742575Speter		}
236838032Speter		i = ProcListSize;
236938032Speter		ProcListSize += PROC_LIST_SEG;
237038032Speter		ProcListVec = npv;
237138032Speter	}
237242575Speter	ProcListVec[i].proc_pid = pid;
237364562Sgshapiro	if (ProcListVec[i].proc_task != NULL)
237477349Sgshapiro		sm_free(ProcListVec[i].proc_task);
237542575Speter	ProcListVec[i].proc_task = newstr(task);
237664562Sgshapiro	ProcListVec[i].proc_type = type;
237742575Speter
237842575Speter	/* if process adding itself, it's not a child */
237942575Speter	if (pid != getpid())
238042575Speter		CurChildren++;
238138032Speter}
238238032Speter/*
238342575Speter**  PROC_LIST_SET -- set pid task in process list
238442575Speter**
238542575Speter**	Parameters:
238642575Speter**		pid -- pid to set
238742575Speter**		task -- task of pid
238842575Speter**
238942575Speter**	Returns:
239042575Speter**		none.
239142575Speter*/
239242575Speter
239342575Spetervoid
239442575Speterproc_list_set(pid, task)
239542575Speter	pid_t pid;
239642575Speter	char *task;
239742575Speter{
239842575Speter	int i;
239942575Speter
240042575Speter	for (i = 0; i < ProcListSize; i++)
240142575Speter	{
240242575Speter		if (ProcListVec[i].proc_pid == pid)
240342575Speter		{
240442575Speter			if (ProcListVec[i].proc_task != NULL)
240577349Sgshapiro				sm_free(ProcListVec[i].proc_task);
240642575Speter			ProcListVec[i].proc_task = newstr(task);
240742575Speter			break;
240842575Speter		}
240942575Speter	}
241042575Speter}
241142575Speter/*
241238032Speter**  PROC_LIST_DROP -- drop pid from process list
241338032Speter**
241438032Speter**	Parameters:
241538032Speter**		pid -- pid to drop
241638032Speter**
241738032Speter**	Returns:
241864562Sgshapiro**		type of process
241977349Sgshapiro**
242077349Sgshapiro**	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
242177349Sgshapiro**		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
242277349Sgshapiro**		DOING.
242338032Speter*/
242438032Speter
242564562Sgshapiroint
242638032Speterproc_list_drop(pid)
242738032Speter	pid_t pid;
242838032Speter{
242938032Speter	int i;
243064562Sgshapiro	int type = PROC_NONE;
243138032Speter
243238032Speter	for (i = 0; i < ProcListSize; i++)
243338032Speter	{
243442575Speter		if (ProcListVec[i].proc_pid == pid)
243538032Speter		{
243642575Speter			ProcListVec[i].proc_pid = NO_PID;
243764562Sgshapiro			type = ProcListVec[i].proc_type;
243838032Speter			break;
243938032Speter		}
244038032Speter	}
244138032Speter	if (CurChildren > 0)
244238032Speter		CurChildren--;
244364562Sgshapiro
244464562Sgshapiro
244564562Sgshapiro	return type;
244638032Speter}
244738032Speter/*
244838032Speter**  PROC_LIST_CLEAR -- clear the process list
244938032Speter**
245038032Speter**	Parameters:
245138032Speter**		none.
245238032Speter**
245338032Speter**	Returns:
245438032Speter**		none.
245538032Speter*/
245638032Speter
245738032Spetervoid
245838032Speterproc_list_clear()
245938032Speter{
246038032Speter	int i;
246138032Speter
246242575Speter	/* start from 1 since 0 is the daemon itself */
246342575Speter	for (i = 1; i < ProcListSize; i++)
246442575Speter	{
246542575Speter		ProcListVec[i].proc_pid = NO_PID;
246642575Speter	}
246738032Speter	CurChildren = 0;
246838032Speter}
246938032Speter/*
247038032Speter**  PROC_LIST_PROBE -- probe processes in the list to see if they still exist
247138032Speter**
247238032Speter**	Parameters:
247338032Speter**		none
247438032Speter**
247538032Speter**	Returns:
247638032Speter**		none
247738032Speter*/
247838032Speter
247938032Spetervoid
248038032Speterproc_list_probe()
248138032Speter{
248238032Speter	int i;
248338032Speter
248442575Speter	/* start from 1 since 0 is the daemon itself */
248542575Speter	for (i = 1; i < ProcListSize; i++)
248638032Speter	{
248742575Speter		if (ProcListVec[i].proc_pid == NO_PID)
248838032Speter			continue;
248942575Speter		if (kill(ProcListVec[i].proc_pid, 0) < 0)
249038032Speter		{
249138032Speter			if (LogLevel > 3)
249238032Speter				sm_syslog(LOG_DEBUG, CurEnv->e_id,
249364562Sgshapiro					  "proc_list_probe: lost pid %d",
249464562Sgshapiro					  (int) ProcListVec[i].proc_pid);
249542575Speter			ProcListVec[i].proc_pid = NO_PID;
249638032Speter			CurChildren--;
249738032Speter		}
249838032Speter	}
249938032Speter	if (CurChildren < 0)
250038032Speter		CurChildren = 0;
250138032Speter}
250238032Speter/*
250342575Speter**  PROC_LIST_DISPLAY -- display the process list
250442575Speter**
250542575Speter**	Parameters:
250642575Speter**		out -- output file pointer
250742575Speter**
250842575Speter**	Returns:
250942575Speter**		none.
251042575Speter*/
251142575Speter
251242575Spetervoid
251342575Speterproc_list_display(out)
251442575Speter	FILE *out;
251542575Speter{
251642575Speter	int i;
251742575Speter
251842575Speter	for (i = 0; i < ProcListSize; i++)
251942575Speter	{
252042575Speter		if (ProcListVec[i].proc_pid == NO_PID)
252142575Speter			continue;
252242575Speter
252342575Speter		fprintf(out, "%d %s%s\n", (int) ProcListVec[i].proc_pid,
252442575Speter			ProcListVec[i].proc_task != NULL ?
252542575Speter			ProcListVec[i].proc_task : "(unknown)",
252642575Speter			(OpMode == MD_SMTP ||
252742575Speter			 OpMode == MD_DAEMON ||
252842575Speter			 OpMode == MD_ARPAFTP) ? "\r" : "");
252942575Speter	}
253042575Speter}
253142575Speter/*
253280785Sgshapiro**  SAFEFOPEN -- do a file open with extra checking
253380785Sgshapiro**
253480785Sgshapiro**	Parameters:
253580785Sgshapiro**		fn -- the file name to open.
253680785Sgshapiro**		omode -- the open-style mode flags.
253780785Sgshapiro**		cmode -- the create-style mode flags.
253880785Sgshapiro**		sff -- safefile flags.
253980785Sgshapiro**
254080785Sgshapiro**	Returns:
254180785Sgshapiro**		Same as fopen.
254280785Sgshapiro*/
254380785Sgshapiro
254480785SgshapiroFILE *
254580785Sgshapirosafefopen(fn, omode, cmode, sff)
254680785Sgshapiro	char *fn;
254780785Sgshapiro	int omode;
254880785Sgshapiro	int cmode;
254980785Sgshapiro	long sff;
255080785Sgshapiro{
255180785Sgshapiro	int fd;
255280785Sgshapiro	int save_errno;
255380785Sgshapiro	FILE *fp;
255480785Sgshapiro	char *fmode;
255580785Sgshapiro
255680785Sgshapiro	switch (omode & O_ACCMODE)
255780785Sgshapiro	{
255880785Sgshapiro	  case O_RDONLY:
255980785Sgshapiro		fmode = "r";
256080785Sgshapiro		break;
256180785Sgshapiro
256280785Sgshapiro	  case O_WRONLY:
256380785Sgshapiro		if (bitset(O_APPEND, omode))
256480785Sgshapiro			fmode = "a";
256580785Sgshapiro		else
256680785Sgshapiro			fmode = "w";
256780785Sgshapiro		break;
256880785Sgshapiro
256980785Sgshapiro	  case O_RDWR:
257080785Sgshapiro		if (bitset(O_TRUNC, omode))
257180785Sgshapiro			fmode = "w+";
257280785Sgshapiro		else if (bitset(O_APPEND, omode))
257380785Sgshapiro			fmode = "a+";
257480785Sgshapiro		else
257580785Sgshapiro			fmode = "r+";
257680785Sgshapiro		break;
257780785Sgshapiro
257880785Sgshapiro	  default:
257980785Sgshapiro		syserr("554 5.3.5 safefopen: unknown omode %o", omode);
258080785Sgshapiro		fmode = "x";
258180785Sgshapiro	}
258280785Sgshapiro	fd = safeopen(fn, omode, cmode, sff);
258380785Sgshapiro	if (fd < 0)
258480785Sgshapiro	{
258580785Sgshapiro		save_errno = errno;
258680785Sgshapiro		if (tTd(44, 10))
258780785Sgshapiro			dprintf("safefopen: safeopen failed: %s\n",
258880785Sgshapiro				errstring(errno));
258980785Sgshapiro		errno = save_errno;
259080785Sgshapiro		return NULL;
259180785Sgshapiro	}
259280785Sgshapiro	fp = fdopen(fd, fmode);
259380785Sgshapiro	if (fp != NULL)
259480785Sgshapiro		return fp;
259580785Sgshapiro
259680785Sgshapiro	save_errno = errno;
259780785Sgshapiro	if (tTd(44, 10))
259880785Sgshapiro	{
259980785Sgshapiro		dprintf("safefopen: fdopen(%s, %s) failed: omode=%x, sff=%lx, err=%s\n",
260080785Sgshapiro			fn, fmode, omode, sff, errstring(errno));
260180785Sgshapiro	}
260280785Sgshapiro	(void) close(fd);
260380785Sgshapiro	errno = save_errno;
260480785Sgshapiro	return NULL;
260580785Sgshapiro}
260680785Sgshapiro/*
260738032Speter**  SM_STRCASECMP -- 8-bit clean version of strcasecmp
260838032Speter**
260938032Speter**	Thank you, vendors, for making this all necessary.
261038032Speter*/
261138032Speter
261238032Speter/*
261338032Speter * Copyright (c) 1987, 1993
261438032Speter *	The Regents of the University of California.  All rights reserved.
261538032Speter *
261638032Speter * Redistribution and use in source and binary forms, with or without
261738032Speter * modification, are permitted provided that the following conditions
261838032Speter * are met:
261938032Speter * 1. Redistributions of source code must retain the above copyright
262038032Speter *    notice, this list of conditions and the following disclaimer.
262138032Speter * 2. Redistributions in binary form must reproduce the above copyright
262238032Speter *    notice, this list of conditions and the following disclaimer in the
262338032Speter *    documentation and/or other materials provided with the distribution.
262438032Speter * 3. All advertising materials mentioning features or use of this software
262538032Speter *    must display the following acknowledgement:
262638032Speter *	This product includes software developed by the University of
262738032Speter *	California, Berkeley and its contributors.
262838032Speter * 4. Neither the name of the University nor the names of its contributors
262938032Speter *    may be used to endorse or promote products derived from this software
263038032Speter *    without specific prior written permission.
263138032Speter *
263238032Speter * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
263338032Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
263438032Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
263538032Speter * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
263638032Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
263738032Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
263838032Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
263938032Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
264038032Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
264138032Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
264238032Speter * SUCH DAMAGE.
264338032Speter */
264438032Speter
264538032Speter#if defined(LIBC_SCCS) && !defined(lint)
264638032Speterstatic char sccsid[] = "@(#)strcasecmp.c	8.1 (Berkeley) 6/4/93";
264764562Sgshapiro#endif /* defined(LIBC_SCCS) && !defined(lint) */
264838032Speter
264938032Speter/*
265038032Speter * This array is designed for mapping upper and lower case letter
265138032Speter * together for a case independent comparison.  The mappings are
265238032Speter * based upon ascii character sequences.
265338032Speter */
265438032Speterstatic const u_char charmap[] = {
265538032Speter	0000, 0001, 0002, 0003, 0004, 0005, 0006, 0007,
265638032Speter	0010, 0011, 0012, 0013, 0014, 0015, 0016, 0017,
265738032Speter	0020, 0021, 0022, 0023, 0024, 0025, 0026, 0027,
265838032Speter	0030, 0031, 0032, 0033, 0034, 0035, 0036, 0037,
265938032Speter	0040, 0041, 0042, 0043, 0044, 0045, 0046, 0047,
266038032Speter	0050, 0051, 0052, 0053, 0054, 0055, 0056, 0057,
266138032Speter	0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067,
266238032Speter	0070, 0071, 0072, 0073, 0074, 0075, 0076, 0077,
266338032Speter	0100, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
266438032Speter	0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157,
266538032Speter	0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167,
266638032Speter	0170, 0171, 0172, 0133, 0134, 0135, 0136, 0137,
266738032Speter	0140, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
266838032Speter	0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157,
266938032Speter	0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167,
267038032Speter	0170, 0171, 0172, 0173, 0174, 0175, 0176, 0177,
267138032Speter	0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207,
267238032Speter	0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217,
267338032Speter	0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227,
267438032Speter	0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237,
267538032Speter	0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247,
267638032Speter	0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
267738032Speter	0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,
267838032Speter	0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277,
267938032Speter	0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307,
268038032Speter	0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317,
268138032Speter	0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327,
268238032Speter	0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
268338032Speter	0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
268438032Speter	0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357,
268538032Speter	0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,
268638032Speter	0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377,
268738032Speter};
268838032Speter
268938032Speterint
269038032Spetersm_strcasecmp(s1, s2)
269138032Speter	const char *s1, *s2;
269238032Speter{
269338032Speter	register const u_char *cm = charmap,
269438032Speter			*us1 = (const u_char *)s1,
269538032Speter			*us2 = (const u_char *)s2;
269638032Speter
269738032Speter	while (cm[*us1] == cm[*us2++])
269838032Speter		if (*us1++ == '\0')
269964562Sgshapiro			return 0;
270038032Speter	return (cm[*us1] - cm[*--us2]);
270138032Speter}
270238032Speter
270338032Speterint
270438032Spetersm_strncasecmp(s1, s2, n)
270538032Speter	const char *s1, *s2;
270638032Speter	register size_t n;
270738032Speter{
270838032Speter	if (n != 0) {
270938032Speter		register const u_char *cm = charmap,
271038032Speter				*us1 = (const u_char *)s1,
271138032Speter				*us2 = (const u_char *)s2;
271238032Speter
271338032Speter		do {
271438032Speter			if (cm[*us1] != cm[*us2++])
271538032Speter				return (cm[*us1] - cm[*--us2]);
271638032Speter			if (*us1++ == '\0')
271738032Speter				break;
271838032Speter		} while (--n != 0);
271938032Speter	}
272064562Sgshapiro	return 0;
272138032Speter}
2722