138032Speter/*
2261370Sgshapiro * Copyright (c) 1998-2007, 2009 Proofpoint, 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
1464562Sgshapiro#include <sendmail.h>
1564562Sgshapiro
16266711SgshapiroSM_RCSID("@(#)$Id: util.c,v 8.427 2013-11-22 20:51:57 ca Exp $")
1764562Sgshapiro
18168515Sgshapiro#include <sm/sendmail.h>
1990792Sgshapiro#include <sysexits.h>
2090792Sgshapiro#include <sm/xtrap.h>
2164562Sgshapiro
2290792Sgshapiro/*
23132943Sgshapiro**  NEWSTR -- Create a copy of a C string
24132943Sgshapiro**
25132943Sgshapiro**	Parameters:
26132943Sgshapiro**		s -- the string to copy.
27132943Sgshapiro**
28132943Sgshapiro**	Returns:
29132943Sgshapiro**		pointer to newly allocated string.
30132943Sgshapiro*/
31132943Sgshapiro
32132943Sgshapirochar *
33132943Sgshapironewstr(s)
34132943Sgshapiro	const char *s;
35132943Sgshapiro{
36132943Sgshapiro	size_t l;
37132943Sgshapiro	char *n;
38132943Sgshapiro
39132943Sgshapiro	l = strlen(s);
40132943Sgshapiro	SM_ASSERT(l + 1 > l);
41132943Sgshapiro	n = xalloc(l + 1);
42132943Sgshapiro	sm_strlcpy(n, s, l + 1);
43132943Sgshapiro	return n;
44132943Sgshapiro}
45132943Sgshapiro
46132943Sgshapiro/*
4738032Speter**  ADDQUOTES -- Adds quotes & quote bits to a string.
4838032Speter**
4990792Sgshapiro**	Runs through a string and adds backslashes and quote bits.
5038032Speter**
5138032Speter**	Parameters:
5238032Speter**		s -- the string to modify.
5390792Sgshapiro**		rpool -- resource pool from which to allocate result
5438032Speter**
5538032Speter**	Returns:
5638032Speter**		pointer to quoted string.
5738032Speter*/
5838032Speter
5938032Speterchar *
6090792Sgshapiroaddquotes(s, rpool)
6138032Speter	char *s;
6290792Sgshapiro	SM_RPOOL_T *rpool;
6338032Speter{
6438032Speter	int len = 0;
6538032Speter	char c;
6638032Speter	char *p = s, *q, *r;
6738032Speter
6838032Speter	if (s == NULL)
6938032Speter		return NULL;
7038032Speter
7138032Speter	/* Find length of quoted string */
7238032Speter	while ((c = *p++) != '\0')
7338032Speter	{
7438032Speter		len++;
7538032Speter		if (c == '\\' || c == '"')
7638032Speter			len++;
7738032Speter	}
7864562Sgshapiro
7990792Sgshapiro	q = r = sm_rpool_malloc_x(rpool, len + 3);
8038032Speter	p = s;
8138032Speter
8238032Speter	/* add leading quote */
8338032Speter	*q++ = '"';
8438032Speter	while ((c = *p++) != '\0')
8538032Speter	{
8638032Speter		/* quote \ or " */
8738032Speter		if (c == '\\' || c == '"')
8838032Speter			*q++ = '\\';
8938032Speter		*q++ = c;
9038032Speter	}
9138032Speter	*q++ = '"';
9238032Speter	*q = '\0';
9338032Speter	return r;
9438032Speter}
95110560Sgshapiro
9690792Sgshapiro/*
97141858Sgshapiro**  STRIPBACKSLASH -- Strip all leading backslashes from a string, provided
98141858Sgshapiro**	the following character is alpha-numerical.
99110560Sgshapiro**
100110560Sgshapiro**	This is done in place.
101110560Sgshapiro**
102110560Sgshapiro**	Parameters:
103110560Sgshapiro**		s -- the string to strip.
104110560Sgshapiro**
105110560Sgshapiro**	Returns:
106110560Sgshapiro**		none.
107110560Sgshapiro*/
108110560Sgshapiro
109110560Sgshapirovoid
110110560Sgshapirostripbackslash(s)
111110560Sgshapiro	char *s;
112110560Sgshapiro{
113110560Sgshapiro	char *p, *q, c;
114110560Sgshapiro
115110560Sgshapiro	if (s == NULL || *s == '\0')
116110560Sgshapiro		return;
117110560Sgshapiro	p = q = s;
118110560Sgshapiro	while (*p == '\\' && (p[1] == '\\' || (isascii(p[1]) && isalnum(p[1]))))
119110560Sgshapiro		p++;
120110560Sgshapiro	do
121110560Sgshapiro	{
122110560Sgshapiro		c = *q++ = *p++;
123110560Sgshapiro	} while (c != '\0');
124110560Sgshapiro}
125110560Sgshapiro
126110560Sgshapiro/*
12738032Speter**  RFC822_STRING -- Checks string for proper RFC822 string quoting.
12838032Speter**
12938032Speter**	Runs through a string and verifies RFC822 special characters
13038032Speter**	are only found inside comments, quoted strings, or backslash
13138032Speter**	escaped.  Also verified balanced quotes and parenthesis.
13238032Speter**
13338032Speter**	Parameters:
13438032Speter**		s -- the string to modify.
13538032Speter**
13638032Speter**	Returns:
13790792Sgshapiro**		true iff the string is RFC822 compliant, false otherwise.
13838032Speter*/
13938032Speter
14038032Speterbool
14138032Speterrfc822_string(s)
14238032Speter	char *s;
14338032Speter{
14490792Sgshapiro	bool quoted = false;
14538032Speter	int commentlev = 0;
14638032Speter	char *c = s;
14738032Speter
14838032Speter	if (s == NULL)
14990792Sgshapiro		return false;
15038032Speter
15138032Speter	while (*c != '\0')
15238032Speter	{
15338032Speter		/* escaped character */
15438032Speter		if (*c == '\\')
15538032Speter		{
15638032Speter			c++;
15738032Speter			if (*c == '\0')
15890792Sgshapiro				return false;
15938032Speter		}
16038032Speter		else if (commentlev == 0 && *c == '"')
16138032Speter			quoted = !quoted;
16238032Speter		else if (!quoted)
16338032Speter		{
16438032Speter			if (*c == ')')
16538032Speter			{
16638032Speter				/* unbalanced ')' */
16738032Speter				if (commentlev == 0)
16890792Sgshapiro					return false;
16938032Speter				else
17038032Speter					commentlev--;
17138032Speter			}
17238032Speter			else if (*c == '(')
17338032Speter				commentlev++;
17438032Speter			else if (commentlev == 0 &&
17538032Speter				 strchr(MustQuoteChars, *c) != NULL)
17690792Sgshapiro				return false;
17738032Speter		}
17838032Speter		c++;
17938032Speter	}
18090792Sgshapiro
18138032Speter	/* unbalanced '"' or '(' */
18290792Sgshapiro	return !quoted && commentlev == 0;
18338032Speter}
184168515Sgshapiro
18590792Sgshapiro/*
18642575Speter**  SHORTEN_RFC822_STRING -- Truncate and rebalance an RFC822 string
18742575Speter**
18864562Sgshapiro**	Arbitrarily shorten (in place) an RFC822 string and rebalance
18942575Speter**	comments and quotes.
19042575Speter**
19142575Speter**	Parameters:
19242575Speter**		string -- the string to shorten
19342575Speter**		length -- the maximum size, 0 if no maximum
19442575Speter**
19542575Speter**	Returns:
19690792Sgshapiro**		true if string is changed, false otherwise
19742575Speter**
19842575Speter**	Side Effects:
19942575Speter**		Changes string in place, possibly resulting
20042575Speter**		in a shorter string.
20142575Speter*/
20242575Speter
20342575Speterbool
20442575Spetershorten_rfc822_string(string, length)
20542575Speter	char *string;
20642575Speter	size_t length;
20742575Speter{
20890792Sgshapiro	bool backslash = false;
20990792Sgshapiro	bool modified = false;
21090792Sgshapiro	bool quoted = false;
21142575Speter	size_t slen;
21242575Speter	int parencount = 0;
21342575Speter	char *ptr = string;
21464562Sgshapiro
21542575Speter	/*
21642575Speter	**  If have to rebalance an already short enough string,
21742575Speter	**  need to do it within allocated space.
21842575Speter	*/
21971345Sgshapiro
22042575Speter	slen = strlen(string);
22142575Speter	if (length == 0 || slen < length)
22242575Speter		length = slen;
22342575Speter
22442575Speter	while (*ptr != '\0')
22542575Speter	{
22642575Speter		if (backslash)
22742575Speter		{
22890792Sgshapiro			backslash = false;
22942575Speter			goto increment;
23042575Speter		}
23142575Speter
23242575Speter		if (*ptr == '\\')
23390792Sgshapiro			backslash = true;
23442575Speter		else if (*ptr == '(')
23542575Speter		{
23642575Speter			if (!quoted)
23742575Speter				parencount++;
23842575Speter		}
23942575Speter		else if (*ptr == ')')
24042575Speter		{
24142575Speter			if (--parencount < 0)
24242575Speter				parencount = 0;
24342575Speter		}
24464562Sgshapiro
24542575Speter		/* Inside a comment, quotes don't matter */
24642575Speter		if (parencount <= 0 && *ptr == '"')
24742575Speter			quoted = !quoted;
24842575Speter
24942575Speterincrement:
25042575Speter		/* Check for sufficient space for next character */
25164562Sgshapiro		if (length - (ptr - string) <= (size_t) ((backslash ? 1 : 0) +
25242575Speter						parencount +
25342575Speter						(quoted ? 1 : 0)))
25442575Speter		{
25542575Speter			/* Not enough, backtrack */
25642575Speter			if (*ptr == '\\')
25790792Sgshapiro				backslash = false;
25842575Speter			else if (*ptr == '(' && !quoted)
25942575Speter				parencount--;
26042575Speter			else if (*ptr == '"' && parencount == 0)
26190792Sgshapiro				quoted = false;
26242575Speter			break;
26342575Speter		}
26442575Speter		ptr++;
26542575Speter	}
26642575Speter
26742575Speter	/* Rebalance */
26842575Speter	while (parencount-- > 0)
26942575Speter	{
27042575Speter		if (*ptr != ')')
27142575Speter		{
27290792Sgshapiro			modified = true;
27342575Speter			*ptr = ')';
27442575Speter		}
27542575Speter		ptr++;
27642575Speter	}
27742575Speter	if (quoted)
27842575Speter	{
27942575Speter		if (*ptr != '"')
28042575Speter		{
28190792Sgshapiro			modified = true;
28242575Speter			*ptr = '"';
28342575Speter		}
28442575Speter		ptr++;
28542575Speter	}
28642575Speter	if (*ptr != '\0')
28742575Speter	{
28890792Sgshapiro		modified = true;
28942575Speter		*ptr = '\0';
29042575Speter	}
29142575Speter	return modified;
29242575Speter}
293168515Sgshapiro
29490792Sgshapiro/*
29542575Speter**  FIND_CHARACTER -- find an unquoted character in an RFC822 string
29642575Speter**
29742575Speter**	Find an unquoted, non-commented character in an RFC822
29842575Speter**	string and return a pointer to its location in the
29942575Speter**	string.
30042575Speter**
30142575Speter**	Parameters:
30242575Speter**		string -- the string to search
30342575Speter**		character -- the character to find
30442575Speter**
30542575Speter**	Returns:
30642575Speter**		pointer to the character, or
30742575Speter**		a pointer to the end of the line if character is not found
30842575Speter*/
30942575Speter
31042575Speterchar *
31142575Speterfind_character(string, character)
31242575Speter	char *string;
31364562Sgshapiro	int character;
31442575Speter{
31590792Sgshapiro	bool backslash = false;
31690792Sgshapiro	bool quoted = false;
31742575Speter	int parencount = 0;
31864562Sgshapiro
31942575Speter	while (string != NULL && *string != '\0')
32042575Speter	{
32142575Speter		if (backslash)
32242575Speter		{
32390792Sgshapiro			backslash = false;
32442575Speter			if (!quoted && character == '\\' && *string == '\\')
32542575Speter				break;
32642575Speter			string++;
32742575Speter			continue;
32842575Speter		}
32942575Speter		switch (*string)
33042575Speter		{
33142575Speter		  case '\\':
33290792Sgshapiro			backslash = true;
33342575Speter			break;
33464562Sgshapiro
33542575Speter		  case '(':
33642575Speter			if (!quoted)
33742575Speter				parencount++;
33842575Speter			break;
33964562Sgshapiro
34042575Speter		  case ')':
34142575Speter			if (--parencount < 0)
34242575Speter				parencount = 0;
34342575Speter			break;
34442575Speter		}
34564562Sgshapiro
34642575Speter		/* Inside a comment, nothing matters */
34742575Speter		if (parencount > 0)
34842575Speter		{
34942575Speter			string++;
35042575Speter			continue;
35142575Speter		}
35264562Sgshapiro
35342575Speter		if (*string == '"')
35442575Speter			quoted = !quoted;
35542575Speter		else if (*string == character && !quoted)
35642575Speter			break;
35742575Speter		string++;
35842575Speter	}
35942575Speter
36042575Speter	/* Return pointer to the character */
36142575Speter	return string;
36242575Speter}
36390792Sgshapiro
36490792Sgshapiro/*
36590792Sgshapiro**  CHECK_BODYTYPE -- check bodytype parameter
36638032Speter**
36738032Speter**	Parameters:
36890792Sgshapiro**		bodytype -- bodytype parameter
36938032Speter**
37038032Speter**	Returns:
37190792Sgshapiro**		BODYTYPE_* according to parameter
37238032Speter**
37338032Speter*/
37438032Speter
37590792Sgshapiroint
37690792Sgshapirocheck_bodytype(bodytype)
37790792Sgshapiro	char *bodytype;
37838032Speter{
37990792Sgshapiro	/* check body type for legality */
38090792Sgshapiro	if (bodytype == NULL)
38190792Sgshapiro		return BODYTYPE_NONE;
38290792Sgshapiro	if (sm_strcasecmp(bodytype, "7BIT") == 0)
38390792Sgshapiro		return BODYTYPE_7BIT;
38490792Sgshapiro	if (sm_strcasecmp(bodytype, "8BITMIME") == 0)
38590792Sgshapiro		return BODYTYPE_8BITMIME;
38690792Sgshapiro	return BODYTYPE_ILLEGAL;
38790792Sgshapiro}
38838032Speter
38990792Sgshapiro/*
39090792Sgshapiro**  TRUNCATE_AT_DELIM -- truncate string at a delimiter and append "..."
39177349Sgshapiro**
39277349Sgshapiro**	Parameters:
39390792Sgshapiro**		str -- string to truncate
39490792Sgshapiro**		len -- maximum length (including '\0') (0 for unlimited)
39590792Sgshapiro**		delim -- delimiter character
39677349Sgshapiro**
39777349Sgshapiro**	Returns:
39890792Sgshapiro**		None.
39977349Sgshapiro*/
40077349Sgshapiro
40190792Sgshapirovoid
40290792Sgshapirotruncate_at_delim(str, len, delim)
40390792Sgshapiro	char *str;
40490792Sgshapiro	size_t len;
40590792Sgshapiro	int delim;
40677349Sgshapiro{
40790792Sgshapiro	char *p;
40877349Sgshapiro
40990792Sgshapiro	if (str == NULL || len == 0 || strlen(str) < len)
41090792Sgshapiro		return;
41177349Sgshapiro
41290792Sgshapiro	*(str + len - 1) = '\0';
41390792Sgshapiro	while ((p = strrchr(str, delim)) != NULL)
41477349Sgshapiro	{
41590792Sgshapiro		*p = '\0';
41690792Sgshapiro		if (p - str + 4 < len)
41790792Sgshapiro		{
418120256Sgshapiro			*p++ = (char) delim;
41990792Sgshapiro			*p = '\0';
42090792Sgshapiro			(void) sm_strlcat(str, "...", len);
42190792Sgshapiro			return;
42290792Sgshapiro		}
42390792Sgshapiro	}
42477349Sgshapiro
42590792Sgshapiro	/* Couldn't find a place to append "..." */
42690792Sgshapiro	if (len > 3)
42790792Sgshapiro		(void) sm_strlcpy(str, "...", len);
42890792Sgshapiro	else
42990792Sgshapiro		str[0] = '\0';
43077349Sgshapiro}
431168515Sgshapiro
43290792Sgshapiro/*
43390792Sgshapiro**  XALLOC -- Allocate memory, raise an exception on error
43477349Sgshapiro**
43577349Sgshapiro**	Parameters:
43690792Sgshapiro**		sz -- size of area to allocate.
43777349Sgshapiro**
43877349Sgshapiro**	Returns:
43977349Sgshapiro**		pointer to data region.
44077349Sgshapiro**
44190792Sgshapiro**	Exceptions:
44290792Sgshapiro**		SmHeapOutOfMemory (F:sm.heap) -- cannot allocate memory
44390792Sgshapiro**
44477349Sgshapiro**	Side Effects:
44577349Sgshapiro**		Memory is allocated.
44677349Sgshapiro*/
44777349Sgshapiro
44877349Sgshapirochar *
44990792Sgshapiro#if SM_HEAP_CHECK
45090792Sgshapiroxalloc_tagged(sz, file, line)
45190792Sgshapiro	register int sz;
45290792Sgshapiro	char *file;
45390792Sgshapiro	int line;
45490792Sgshapiro#else /* SM_HEAP_CHECK */
45590792Sgshapiroxalloc(sz)
45690792Sgshapiro	register int sz;
45790792Sgshapiro#endif /* SM_HEAP_CHECK */
45877349Sgshapiro{
45977349Sgshapiro	register char *p;
46077349Sgshapiro
461157001Sgshapiro	SM_REQUIRE(sz >= 0);
462157001Sgshapiro
46377349Sgshapiro	/* some systems can't handle size zero mallocs */
46477349Sgshapiro	if (sz <= 0)
46577349Sgshapiro		sz = 1;
46677349Sgshapiro
46790792Sgshapiro	/* scaffolding for testing error handling code */
46890792Sgshapiro	sm_xtrap_raise_x(&SmHeapOutOfMemory);
46990792Sgshapiro
47090792Sgshapiro	p = sm_malloc_tagged((unsigned) sz, file, line, sm_heap_group());
47177349Sgshapiro	if (p == NULL)
47277349Sgshapiro	{
47390792Sgshapiro		sm_exc_raise_x(&SmHeapOutOfMemory);
47477349Sgshapiro	}
47577349Sgshapiro	return p;
47677349Sgshapiro}
477168515Sgshapiro
47890792Sgshapiro/*
47938032Speter**  COPYPLIST -- copy list of pointers.
48038032Speter**
48190792Sgshapiro**	This routine is the equivalent of strdup for lists of
48238032Speter**	pointers.
48338032Speter**
48438032Speter**	Parameters:
48538032Speter**		list -- list of pointers to copy.
48638032Speter**			Must be NULL terminated.
48790792Sgshapiro**		copycont -- if true, copy the contents of the vector
48838032Speter**			(which must be a string) also.
48990792Sgshapiro**		rpool -- resource pool from which to allocate storage,
49090792Sgshapiro**			or NULL
49138032Speter**
49238032Speter**	Returns:
49338032Speter**		a copy of 'list'.
49438032Speter*/
49538032Speter
49638032Speterchar **
49790792Sgshapirocopyplist(list, copycont, rpool)
49838032Speter	char **list;
49938032Speter	bool copycont;
50090792Sgshapiro	SM_RPOOL_T *rpool;
50138032Speter{
50238032Speter	register char **vp;
50338032Speter	register char **newvp;
50438032Speter
50538032Speter	for (vp = list; *vp != NULL; vp++)
50638032Speter		continue;
50738032Speter
50838032Speter	vp++;
50938032Speter
510168515Sgshapiro	newvp = (char **) sm_rpool_malloc_x(rpool, (vp - list) * sizeof(*vp));
511168515Sgshapiro	memmove((char *) newvp, (char *) list, (int) (vp - list) * sizeof(*vp));
51238032Speter
51338032Speter	if (copycont)
51438032Speter	{
51538032Speter		for (vp = newvp; *vp != NULL; vp++)
51690792Sgshapiro			*vp = sm_rpool_strdup_x(rpool, *vp);
51738032Speter	}
51838032Speter
51964562Sgshapiro	return newvp;
52038032Speter}
521168515Sgshapiro
52290792Sgshapiro/*
52338032Speter**  COPYQUEUE -- copy address queue.
52438032Speter**
52590792Sgshapiro**	This routine is the equivalent of strdup for address queues;
52664562Sgshapiro**	addresses marked as QS_IS_DEAD() aren't copied
52738032Speter**
52838032Speter**	Parameters:
52938032Speter**		addr -- list of address structures to copy.
53090792Sgshapiro**		rpool -- resource pool from which to allocate storage
53138032Speter**
53238032Speter**	Returns:
53338032Speter**		a copy of 'addr'.
53438032Speter*/
53538032Speter
53638032SpeterADDRESS *
53790792Sgshapirocopyqueue(addr, rpool)
53838032Speter	ADDRESS *addr;
53990792Sgshapiro	SM_RPOOL_T *rpool;
54038032Speter{
54138032Speter	register ADDRESS *newaddr;
54238032Speter	ADDRESS *ret;
54338032Speter	register ADDRESS **tail = &ret;
54438032Speter
54538032Speter	while (addr != NULL)
54638032Speter	{
54764562Sgshapiro		if (!QS_IS_DEAD(addr->q_state))
54838032Speter		{
54990792Sgshapiro			newaddr = (ADDRESS *) sm_rpool_malloc_x(rpool,
550168515Sgshapiro							sizeof(*newaddr));
55138032Speter			STRUCTCOPY(*addr, *newaddr);
55238032Speter			*tail = newaddr;
55338032Speter			tail = &newaddr->q_next;
55438032Speter		}
55538032Speter		addr = addr->q_next;
55638032Speter	}
55738032Speter	*tail = NULL;
55864562Sgshapiro
55938032Speter	return ret;
56038032Speter}
561168515Sgshapiro
56290792Sgshapiro/*
56364562Sgshapiro**  LOG_SENDMAIL_PID -- record sendmail pid and command line.
56464562Sgshapiro**
56564562Sgshapiro**	Parameters:
56664562Sgshapiro**		e -- the current envelope.
56764562Sgshapiro**
56864562Sgshapiro**	Returns:
56964562Sgshapiro**		none.
57064562Sgshapiro**
57164562Sgshapiro**	Side Effects:
57290792Sgshapiro**		writes pidfile, logs command line.
573132943Sgshapiro**		keeps file open and locked to prevent overwrite of active file
57464562Sgshapiro*/
57564562Sgshapiro
576132943Sgshapirostatic SM_FILE_T	*Pidf = NULL;
577132943Sgshapiro
57864562Sgshapirovoid
57964562Sgshapirolog_sendmail_pid(e)
58064562Sgshapiro	ENVELOPE *e;
58164562Sgshapiro{
58264562Sgshapiro	long sff;
58398121Sgshapiro	char pidpath[MAXPATHLEN];
58490792Sgshapiro	extern char *CommandLineArgs;
58564562Sgshapiro
58664562Sgshapiro	/* write the pid to the log file for posterity */
587132943Sgshapiro	sff = SFF_NOLINK|SFF_ROOTOK|SFF_REGONLY|SFF_CREAT|SFF_NBLOCK;
58864562Sgshapiro	if (TrustedUid != 0 && RealUid == TrustedUid)
58964562Sgshapiro		sff |= SFF_OPENASROOT;
590168515Sgshapiro	expand(PidFile, pidpath, sizeof(pidpath), e);
591132943Sgshapiro	Pidf = safefopen(pidpath, O_WRONLY|O_TRUNC, FileMode, sff);
592132943Sgshapiro	if (Pidf == NULL)
59364562Sgshapiro	{
594132943Sgshapiro		if (errno == EWOULDBLOCK)
595132943Sgshapiro			sm_syslog(LOG_ERR, NOQID,
596132943Sgshapiro				  "unable to write pid to %s: file in use by another process",
597132943Sgshapiro				  pidpath);
598132943Sgshapiro		else
599132943Sgshapiro			sm_syslog(LOG_ERR, NOQID,
600132943Sgshapiro				  "unable to write pid to %s: %s",
601132943Sgshapiro				  pidpath, sm_errstring(errno));
60264562Sgshapiro	}
60364562Sgshapiro	else
60464562Sgshapiro	{
605132943Sgshapiro		PidFilePid = getpid();
60664562Sgshapiro
60764562Sgshapiro		/* write the process id on line 1 */
608132943Sgshapiro		(void) sm_io_fprintf(Pidf, SM_TIME_DEFAULT, "%ld\n",
609132943Sgshapiro				     (long) PidFilePid);
61064562Sgshapiro
61164562Sgshapiro		/* line 2 contains all command line flags */
612132943Sgshapiro		(void) sm_io_fprintf(Pidf, SM_TIME_DEFAULT, "%s\n",
61390792Sgshapiro				     CommandLineArgs);
61464562Sgshapiro
615132943Sgshapiro		/* flush */
616132943Sgshapiro		(void) sm_io_flush(Pidf, SM_TIME_DEFAULT);
617132943Sgshapiro
618132943Sgshapiro		/*
619132943Sgshapiro		**  Leave pid file open until process ends
620132943Sgshapiro		**  so it's not overwritten by another
621132943Sgshapiro		**  process.
622132943Sgshapiro		*/
62364562Sgshapiro	}
62490792Sgshapiro	if (LogLevel > 9)
62590792Sgshapiro		sm_syslog(LOG_INFO, NOQID, "started as: %s", CommandLineArgs);
62664562Sgshapiro}
627132943Sgshapiro
62890792Sgshapiro/*
629132943Sgshapiro**  CLOSE_SENDMAIL_PID -- close sendmail pid file
630132943Sgshapiro**
631132943Sgshapiro**	Parameters:
632132943Sgshapiro**		none.
633132943Sgshapiro**
634132943Sgshapiro**	Returns:
635132943Sgshapiro**		none.
636132943Sgshapiro*/
637132943Sgshapiro
638132943Sgshapirovoid
639132943Sgshapiroclose_sendmail_pid()
640132943Sgshapiro{
641132943Sgshapiro	if (Pidf == NULL)
642132943Sgshapiro		return;
643132943Sgshapiro
644132943Sgshapiro	(void) sm_io_close(Pidf, SM_TIME_DEFAULT);
645132943Sgshapiro	Pidf = NULL;
646132943Sgshapiro}
647132943Sgshapiro
648132943Sgshapiro/*
64964562Sgshapiro**  SET_DELIVERY_MODE -- set and record the delivery mode
65064562Sgshapiro**
65164562Sgshapiro**	Parameters:
65264562Sgshapiro**		mode -- delivery mode
65364562Sgshapiro**		e -- the current envelope.
65464562Sgshapiro**
65564562Sgshapiro**	Returns:
65664562Sgshapiro**		none.
65764562Sgshapiro**
65864562Sgshapiro**	Side Effects:
65990792Sgshapiro**		sets {deliveryMode} macro
66064562Sgshapiro*/
66164562Sgshapiro
66264562Sgshapirovoid
66364562Sgshapiroset_delivery_mode(mode, e)
66464562Sgshapiro	int mode;
66564562Sgshapiro	ENVELOPE *e;
66664562Sgshapiro{
66764562Sgshapiro	char buf[2];
66864562Sgshapiro
66990792Sgshapiro	e->e_sendmode = (char) mode;
67090792Sgshapiro	buf[0] = (char) mode;
67164562Sgshapiro	buf[1] = '\0';
67290792Sgshapiro	macdefine(&e->e_macro, A_TEMP, macid("{deliveryMode}"), buf);
67364562Sgshapiro}
674168515Sgshapiro
67590792Sgshapiro/*
67690792Sgshapiro**  SET_OP_MODE -- set and record the op mode
67790792Sgshapiro**
67890792Sgshapiro**	Parameters:
67990792Sgshapiro**		mode -- op mode
68090792Sgshapiro**		e -- the current envelope.
68190792Sgshapiro**
68290792Sgshapiro**	Returns:
68390792Sgshapiro**		none.
68490792Sgshapiro**
68590792Sgshapiro**	Side Effects:
68690792Sgshapiro**		sets {opMode} macro
68790792Sgshapiro*/
68890792Sgshapiro
68990792Sgshapirovoid
69090792Sgshapiroset_op_mode(mode)
69190792Sgshapiro	int mode;
69290792Sgshapiro{
69390792Sgshapiro	char buf[2];
69490792Sgshapiro	extern ENVELOPE BlankEnvelope;
69590792Sgshapiro
69690792Sgshapiro	OpMode = (char) mode;
69790792Sgshapiro	buf[0] = (char) mode;
69890792Sgshapiro	buf[1] = '\0';
69990792Sgshapiro	macdefine(&BlankEnvelope.e_macro, A_TEMP, MID_OPMODE, buf);
70090792Sgshapiro}
701168515Sgshapiro
70290792Sgshapiro/*
70338032Speter**  PRINTAV -- print argument vector.
70438032Speter**
70538032Speter**	Parameters:
706132943Sgshapiro**		fp -- output file pointer.
70738032Speter**		av -- argument vector.
70838032Speter**
70938032Speter**	Returns:
71038032Speter**		none.
71138032Speter**
71238032Speter**	Side Effects:
71338032Speter**		prints av.
71438032Speter*/
71538032Speter
71638032Spetervoid
717132943Sgshapiroprintav(fp, av)
718132943Sgshapiro	SM_FILE_T *fp;
719168515Sgshapiro	char **av;
72038032Speter{
72138032Speter	while (*av != NULL)
72238032Speter	{
72338032Speter		if (tTd(0, 44))
72490792Sgshapiro			sm_dprintf("\n\t%08lx=", (unsigned long) *av);
72538032Speter		else
726132943Sgshapiro			(void) sm_io_putc(fp, SM_TIME_DEFAULT, ' ');
727168515Sgshapiro		if (tTd(0, 99))
728168515Sgshapiro			sm_dprintf("%s", str2prt(*av++));
729168515Sgshapiro		else
730168515Sgshapiro			xputs(fp, *av++);
73138032Speter	}
732132943Sgshapiro	(void) sm_io_putc(fp, SM_TIME_DEFAULT, '\n');
73338032Speter}
734168515Sgshapiro
73590792Sgshapiro/*
73638032Speter**  XPUTS -- put string doing control escapes.
73738032Speter**
73838032Speter**	Parameters:
739132943Sgshapiro**		fp -- output file pointer.
74038032Speter**		s -- string to put.
74138032Speter**
74238032Speter**	Returns:
74338032Speter**		none.
74438032Speter**
74538032Speter**	Side Effects:
74638032Speter**		output to stdout
74738032Speter*/
74838032Speter
74938032Spetervoid
750132943Sgshapiroxputs(fp, s)
751132943Sgshapiro	SM_FILE_T *fp;
752168515Sgshapiro	const char *s;
75338032Speter{
754168515Sgshapiro	int c;
755168515Sgshapiro	struct metamac *mp;
75690792Sgshapiro	bool shiftout = false;
75738032Speter	extern struct metamac MetaMacros[];
75890792Sgshapiro	static SM_DEBUG_T DebugANSI = SM_DEBUG_INITIALIZER("ANSI",
75990792Sgshapiro		"@(#)$Debug: ANSI - enable reverse video in debug output $");
76038032Speter
76190792Sgshapiro	/*
76290792Sgshapiro	**  TermEscape is set here, rather than in main(),
76390792Sgshapiro	**  because ANSI mode can be turned on or off at any time
76490792Sgshapiro	**  if we are in -bt rule testing mode.
76590792Sgshapiro	*/
76690792Sgshapiro
76790792Sgshapiro	if (sm_debug_unknown(&DebugANSI))
76890792Sgshapiro	{
76990792Sgshapiro		if (sm_debug_active(&DebugANSI, 1))
77090792Sgshapiro		{
77190792Sgshapiro			TermEscape.te_rv_on = "\033[7m";
772168515Sgshapiro			TermEscape.te_normal = "\033[0m";
77390792Sgshapiro		}
77490792Sgshapiro		else
77590792Sgshapiro		{
77690792Sgshapiro			TermEscape.te_rv_on = "";
777168515Sgshapiro			TermEscape.te_normal = "";
77890792Sgshapiro		}
77990792Sgshapiro	}
78090792Sgshapiro
78138032Speter	if (s == NULL)
78238032Speter	{
783132943Sgshapiro		(void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s<null>%s",
784168515Sgshapiro				     TermEscape.te_rv_on, TermEscape.te_normal);
78538032Speter		return;
78638032Speter	}
78738032Speter	while ((c = (*s++ & 0377)) != '\0')
78838032Speter	{
78938032Speter		if (shiftout)
79038032Speter		{
791132943Sgshapiro			(void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s",
792168515Sgshapiro					     TermEscape.te_normal);
79390792Sgshapiro			shiftout = false;
79438032Speter		}
795168515Sgshapiro		if (!isascii(c) && !tTd(84, 1))
79638032Speter		{
79738032Speter			if (c == MATCHREPL)
79838032Speter			{
799132943Sgshapiro				(void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
80090792Sgshapiro						     "%s$",
80190792Sgshapiro						     TermEscape.te_rv_on);
80290792Sgshapiro				shiftout = true;
80338032Speter				if (*s == '\0')
80438032Speter					continue;
80538032Speter				c = *s++ & 0377;
80638032Speter				goto printchar;
80738032Speter			}
80838032Speter			if (c == MACROEXPAND || c == MACRODEXPAND)
80938032Speter			{
810132943Sgshapiro				(void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
81190792Sgshapiro						     "%s$",
81290792Sgshapiro						     TermEscape.te_rv_on);
81338032Speter				if (c == MACRODEXPAND)
814132943Sgshapiro					(void) sm_io_putc(fp,
81590792Sgshapiro							  SM_TIME_DEFAULT, '&');
81690792Sgshapiro				shiftout = true;
81738032Speter				if (*s == '\0')
81838032Speter					continue;
81938032Speter				if (strchr("=~&?", *s) != NULL)
820132943Sgshapiro					(void) sm_io_putc(fp,
82190792Sgshapiro							  SM_TIME_DEFAULT,
82290792Sgshapiro							  *s++);
82338032Speter				if (bitset(0200, *s))
824132943Sgshapiro					(void) sm_io_fprintf(fp,
82590792Sgshapiro							     SM_TIME_DEFAULT,
82690792Sgshapiro							     "{%s}",
82790792Sgshapiro							     macname(bitidx(*s++)));
82838032Speter				else
829132943Sgshapiro					(void) sm_io_fprintf(fp,
83090792Sgshapiro							     SM_TIME_DEFAULT,
83190792Sgshapiro							     "%c",
83290792Sgshapiro							     *s++);
83338032Speter				continue;
83438032Speter			}
83538032Speter			for (mp = MetaMacros; mp->metaname != '\0'; mp++)
83638032Speter			{
83790792Sgshapiro				if (bitidx(mp->metaval) == c)
83838032Speter				{
839132943Sgshapiro					(void) sm_io_fprintf(fp,
84090792Sgshapiro							     SM_TIME_DEFAULT,
84190792Sgshapiro							     "%s$%c",
84290792Sgshapiro							     TermEscape.te_rv_on,
84390792Sgshapiro							     mp->metaname);
84490792Sgshapiro					shiftout = true;
84538032Speter					break;
84638032Speter				}
84738032Speter			}
84838032Speter			if (c == MATCHCLASS || c == MATCHNCLASS)
84938032Speter			{
85038032Speter				if (bitset(0200, *s))
851132943Sgshapiro					(void) sm_io_fprintf(fp,
85290792Sgshapiro							     SM_TIME_DEFAULT,
85390792Sgshapiro							     "{%s}",
85490792Sgshapiro							     macname(bitidx(*s++)));
85538032Speter				else if (*s != '\0')
856132943Sgshapiro					(void) sm_io_fprintf(fp,
85790792Sgshapiro							     SM_TIME_DEFAULT,
85890792Sgshapiro							     "%c",
85990792Sgshapiro							     *s++);
86038032Speter			}
86138032Speter			if (mp->metaname != '\0')
86238032Speter				continue;
86338032Speter
86438032Speter			/* unrecognized meta character */
865132943Sgshapiro			(void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%sM-",
86690792Sgshapiro					     TermEscape.te_rv_on);
86790792Sgshapiro			shiftout = true;
86838032Speter			c &= 0177;
86938032Speter		}
87038032Speter  printchar:
871203004Sgshapiro		if (isascii(c) && isprint(c))
87238032Speter		{
873132943Sgshapiro			(void) sm_io_putc(fp, SM_TIME_DEFAULT, c);
87438032Speter			continue;
87538032Speter		}
87638032Speter
87738032Speter		/* wasn't a meta-macro -- find another way to print it */
87838032Speter		switch (c)
87938032Speter		{
88038032Speter		  case '\n':
88138032Speter			c = 'n';
88238032Speter			break;
88338032Speter
88438032Speter		  case '\r':
88538032Speter			c = 'r';
88638032Speter			break;
88738032Speter
88838032Speter		  case '\t':
88938032Speter			c = 't';
89038032Speter			break;
89138032Speter		}
89238032Speter		if (!shiftout)
89338032Speter		{
894132943Sgshapiro			(void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s",
89590792Sgshapiro					     TermEscape.te_rv_on);
89690792Sgshapiro			shiftout = true;
89738032Speter		}
898203004Sgshapiro		if (isascii(c) && isprint(c))
89938032Speter		{
900132943Sgshapiro			(void) sm_io_putc(fp, SM_TIME_DEFAULT, '\\');
901132943Sgshapiro			(void) sm_io_putc(fp, SM_TIME_DEFAULT, c);
90238032Speter		}
903168515Sgshapiro		else if (tTd(84, 2))
904168515Sgshapiro			(void) sm_io_fprintf(fp, SM_TIME_DEFAULT, " %o ", c);
905168515Sgshapiro		else if (tTd(84, 1))
906168515Sgshapiro			(void) sm_io_fprintf(fp, SM_TIME_DEFAULT, " %#x ", c);
907168515Sgshapiro		else if (!isascii(c) && !tTd(84, 1))
90838032Speter		{
909132943Sgshapiro			(void) sm_io_putc(fp, SM_TIME_DEFAULT, '^');
910132943Sgshapiro			(void) sm_io_putc(fp, SM_TIME_DEFAULT, c ^ 0100);
91138032Speter		}
91238032Speter	}
91338032Speter	if (shiftout)
914132943Sgshapiro		(void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s",
915168515Sgshapiro				     TermEscape.te_normal);
916132943Sgshapiro	(void) sm_io_flush(fp, SM_TIME_DEFAULT);
91738032Speter}
918168515Sgshapiro
91990792Sgshapiro/*
92038032Speter**  MAKELOWER -- Translate a line into lower case
92138032Speter**
92238032Speter**	Parameters:
92338032Speter**		p -- the string to translate.  If NULL, return is
92438032Speter**			immediate.
92538032Speter**
92638032Speter**	Returns:
92738032Speter**		none.
92838032Speter**
92938032Speter**	Side Effects:
93038032Speter**		String pointed to by p is translated to lower case.
93138032Speter*/
93238032Speter
93338032Spetervoid
93438032Spetermakelower(p)
93538032Speter	register char *p;
93638032Speter{
93738032Speter	register char c;
93838032Speter
93938032Speter	if (p == NULL)
94038032Speter		return;
94138032Speter	for (; (c = *p) != '\0'; p++)
94238032Speter		if (isascii(c) && isupper(c))
94338032Speter			*p = tolower(c);
94438032Speter}
945168515Sgshapiro
94690792Sgshapiro/*
94738032Speter**  FIXCRLF -- fix <CR><LF> in line.
94838032Speter**
94938032Speter**	Looks for the <CR><LF> combination and turns it into the
95038032Speter**	UNIX canonical <NL> character.  It only takes one line,
95138032Speter**	i.e., it is assumed that the first <NL> found is the end
95238032Speter**	of the line.
95338032Speter**
95438032Speter**	Parameters:
95538032Speter**		line -- the line to fix.
95638032Speter**		stripnl -- if true, strip the newline also.
95738032Speter**
95838032Speter**	Returns:
95938032Speter**		none.
96038032Speter**
96138032Speter**	Side Effects:
96238032Speter**		line is changed in place.
96338032Speter*/
96438032Speter
96538032Spetervoid
96638032Speterfixcrlf(line, stripnl)
96738032Speter	char *line;
96838032Speter	bool stripnl;
96938032Speter{
97038032Speter	register char *p;
97138032Speter
97238032Speter	p = strchr(line, '\n');
97338032Speter	if (p == NULL)
97438032Speter		return;
97538032Speter	if (p > line && p[-1] == '\r')
97638032Speter		p--;
97738032Speter	if (!stripnl)
97838032Speter		*p++ = '\n';
97938032Speter	*p = '\0';
98038032Speter}
981168515Sgshapiro
98290792Sgshapiro/*
98338032Speter**  PUTLINE -- put a line like fputs obeying SMTP conventions
98438032Speter**
98538032Speter**	This routine always guarantees outputing a newline (or CRLF,
98638032Speter**	as appropriate) at the end of the string.
98738032Speter**
98838032Speter**	Parameters:
98938032Speter**		l -- line to put.
99038032Speter**		mci -- the mailer connection information.
99138032Speter**
99238032Speter**	Returns:
993157001Sgshapiro**		true iff line was written successfully
99438032Speter**
99538032Speter**	Side Effects:
99690792Sgshapiro**		output of l to mci->mci_out.
99738032Speter*/
99838032Speter
999157001Sgshapirobool
100038032Speterputline(l, mci)
100138032Speter	register char *l;
100238032Speter	register MCI *mci;
100338032Speter{
1004157001Sgshapiro	return putxline(l, strlen(l), mci, PXLF_MAPFROM);
100538032Speter}
1006168515Sgshapiro
100790792Sgshapiro/*
100838032Speter**  PUTXLINE -- putline with flags bits.
100938032Speter**
101038032Speter**	This routine always guarantees outputing a newline (or CRLF,
101138032Speter**	as appropriate) at the end of the string.
101238032Speter**
101338032Speter**	Parameters:
101438032Speter**		l -- line to put.
101538032Speter**		len -- the length of the line.
101638032Speter**		mci -- the mailer connection information.
101738032Speter**		pxflags -- flag bits:
101838032Speter**		    PXLF_MAPFROM -- map From_ to >From_.
101938032Speter**		    PXLF_STRIP8BIT -- strip 8th bit.
102038032Speter**		    PXLF_HEADER -- map bare newline in header to newline space.
102194334Sgshapiro**		    PXLF_NOADDEOL -- don't add an EOL if one wasn't present.
1022168515Sgshapiro**		    PXLF_STRIPMQUOTE -- strip METAQUOTE bytes.
102338032Speter**
102438032Speter**	Returns:
1025157001Sgshapiro**		true iff line was written successfully
102638032Speter**
102738032Speter**	Side Effects:
102890792Sgshapiro**		output of l to mci->mci_out.
102938032Speter*/
103038032Speter
1031168515Sgshapiro
1032168515Sgshapiro#define PUTX(limit)							\
1033168515Sgshapiro	do								\
1034168515Sgshapiro	{								\
1035168515Sgshapiro		quotenext = false;					\
1036168515Sgshapiro		while (l < limit)					\
1037168515Sgshapiro		{							\
1038168515Sgshapiro			unsigned char c = (unsigned char) *l++;		\
1039168515Sgshapiro									\
1040168515Sgshapiro			if (bitset(PXLF_STRIPMQUOTE, pxflags) &&	\
1041168515Sgshapiro			    !quotenext && c == METAQUOTE)		\
1042168515Sgshapiro			{						\
1043168515Sgshapiro				quotenext = true;			\
1044168515Sgshapiro				continue;				\
1045168515Sgshapiro			}						\
1046168515Sgshapiro			quotenext = false;				\
1047168515Sgshapiro			if (strip8bit)					\
1048168515Sgshapiro				c &= 0177;				\
1049168515Sgshapiro			if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT,	\
1050168515Sgshapiro				       c) == SM_IO_EOF)			\
1051168515Sgshapiro			{						\
1052168515Sgshapiro				dead = true;				\
1053168515Sgshapiro				break;					\
1054168515Sgshapiro			}						\
1055168515Sgshapiro			if (TrafficLogFile != NULL)			\
1056168515Sgshapiro				(void) sm_io_putc(TrafficLogFile,	\
1057168515Sgshapiro						  SM_TIME_DEFAULT,	\
1058168515Sgshapiro						  c);			\
1059168515Sgshapiro		}							\
1060168515Sgshapiro	} while (0)
1061168515Sgshapiro
1062157001Sgshapirobool
106338032Speterputxline(l, len, mci, pxflags)
106438032Speter	register char *l;
106538032Speter	size_t len;
106638032Speter	register MCI *mci;
106738032Speter	int pxflags;
106838032Speter{
106938032Speter	register char *p, *end;
1070168515Sgshapiro	int slop;
1071168515Sgshapiro	bool dead, quotenext, strip8bit;
107238032Speter
107338032Speter	/* strip out 0200 bits -- these can look like TELNET protocol */
1074168515Sgshapiro	strip8bit = bitset(MCIF_7BIT, mci->mci_flags) ||
1075168515Sgshapiro		    bitset(PXLF_STRIP8BIT, pxflags);
1076168515Sgshapiro	dead = false;
1077168515Sgshapiro	slop = 0;
107838032Speter
107938032Speter	end = l + len;
108038032Speter	do
108138032Speter	{
108294334Sgshapiro		bool noeol = false;
108394334Sgshapiro
108438032Speter		/* find the end of the line */
108538032Speter		p = memchr(l, '\n', end - l);
108638032Speter		if (p == NULL)
108794334Sgshapiro		{
108838032Speter			p = end;
108994334Sgshapiro			noeol = true;
109094334Sgshapiro		}
109138032Speter
109238032Speter		if (TrafficLogFile != NULL)
109390792Sgshapiro			(void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT,
109490792Sgshapiro					     "%05d >>> ", (int) CurrentPid);
109538032Speter
109638032Speter		/* check for line overflow */
109738032Speter		while (mci->mci_mailer->m_linelimit > 0 &&
109838032Speter		       (p - l + slop) > mci->mci_mailer->m_linelimit)
109938032Speter		{
110038032Speter			register char *q = &l[mci->mci_mailer->m_linelimit - slop - 1];
110138032Speter
110238032Speter			if (l[0] == '.' && slop == 0 &&
110338032Speter			    bitnset(M_XDOT, mci->mci_mailer->m_flags))
110438032Speter			{
110590792Sgshapiro				if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT,
110690792Sgshapiro					       '.') == SM_IO_EOF)
110790792Sgshapiro					dead = true;
110838032Speter				if (TrafficLogFile != NULL)
110990792Sgshapiro					(void) sm_io_putc(TrafficLogFile,
111090792Sgshapiro							  SM_TIME_DEFAULT, '.');
111138032Speter			}
111238032Speter			else if (l[0] == 'F' && slop == 0 &&
111338032Speter				 bitset(PXLF_MAPFROM, pxflags) &&
111438032Speter				 strncmp(l, "From ", 5) == 0 &&
111538032Speter				 bitnset(M_ESCFROM, mci->mci_mailer->m_flags))
111638032Speter			{
111790792Sgshapiro				if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT,
111890792Sgshapiro					       '>') == SM_IO_EOF)
111990792Sgshapiro					dead = true;
112038032Speter				if (TrafficLogFile != NULL)
112190792Sgshapiro					(void) sm_io_putc(TrafficLogFile,
112290792Sgshapiro							  SM_TIME_DEFAULT,
112390792Sgshapiro							  '>');
112438032Speter			}
112564562Sgshapiro			if (dead)
112664562Sgshapiro				break;
112764562Sgshapiro
1128168515Sgshapiro			PUTX(q);
112964562Sgshapiro			if (dead)
113064562Sgshapiro				break;
113164562Sgshapiro
1132168515Sgshapiro			if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT,
1133168515Sgshapiro					'!') == SM_IO_EOF ||
113490792Sgshapiro			    sm_io_fputs(mci->mci_out, SM_TIME_DEFAULT,
1135168515Sgshapiro					mci->mci_mailer->m_eol) == SM_IO_EOF ||
1136168515Sgshapiro			    sm_io_putc(mci->mci_out, SM_TIME_DEFAULT,
1137168515Sgshapiro					' ') == SM_IO_EOF)
113864562Sgshapiro			{
113990792Sgshapiro				dead = true;
114064562Sgshapiro				break;
114164562Sgshapiro			}
114238032Speter			if (TrafficLogFile != NULL)
114338032Speter			{
114490792Sgshapiro				(void) sm_io_fprintf(TrafficLogFile,
114590792Sgshapiro						     SM_TIME_DEFAULT,
114690792Sgshapiro						     "!\n%05d >>>  ",
114790792Sgshapiro						     (int) CurrentPid);
114838032Speter			}
114938032Speter			slop = 1;
115038032Speter		}
115138032Speter
115264562Sgshapiro		if (dead)
115364562Sgshapiro			break;
115464562Sgshapiro
115538032Speter		/* output last part */
115638032Speter		if (l[0] == '.' && slop == 0 &&
1157173340Sgshapiro		    bitnset(M_XDOT, mci->mci_mailer->m_flags) &&
1158173340Sgshapiro		    !bitset(MCIF_INLONGLINE, mci->mci_flags))
115938032Speter		{
116090792Sgshapiro			if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT, '.') ==
116190792Sgshapiro			    SM_IO_EOF)
1162157001Sgshapiro			{
1163157001Sgshapiro				dead = true;
116464562Sgshapiro				break;
116571345Sgshapiro			}
116638032Speter			if (TrafficLogFile != NULL)
116790792Sgshapiro				(void) sm_io_putc(TrafficLogFile,
116890792Sgshapiro						  SM_TIME_DEFAULT, '.');
116938032Speter		}
117038032Speter		else if (l[0] == 'F' && slop == 0 &&
117138032Speter			 bitset(PXLF_MAPFROM, pxflags) &&
117238032Speter			 strncmp(l, "From ", 5) == 0 &&
1173173340Sgshapiro			 bitnset(M_ESCFROM, mci->mci_mailer->m_flags) &&
1174173340Sgshapiro			 !bitset(MCIF_INLONGLINE, mci->mci_flags))
117538032Speter		{
117690792Sgshapiro			if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT, '>') ==
117790792Sgshapiro			    SM_IO_EOF)
1178157001Sgshapiro			{
1179157001Sgshapiro				dead = true;
118064562Sgshapiro				break;
118171345Sgshapiro			}
118238032Speter			if (TrafficLogFile != NULL)
118390792Sgshapiro				(void) sm_io_putc(TrafficLogFile,
118490792Sgshapiro						  SM_TIME_DEFAULT, '>');
118538032Speter		}
1186168515Sgshapiro		PUTX(p);
118764562Sgshapiro		if (dead)
118864562Sgshapiro			break;
118964562Sgshapiro
119038032Speter		if (TrafficLogFile != NULL)
119190792Sgshapiro			(void) sm_io_putc(TrafficLogFile, SM_TIME_DEFAULT,
119290792Sgshapiro					  '\n');
1193173340Sgshapiro		if ((!bitset(PXLF_NOADDEOL, pxflags) || !noeol))
1194157001Sgshapiro		{
1195173340Sgshapiro			mci->mci_flags &= ~MCIF_INLONGLINE;
1196173340Sgshapiro			if (sm_io_fputs(mci->mci_out, SM_TIME_DEFAULT,
1197173340Sgshapiro					mci->mci_mailer->m_eol) == SM_IO_EOF)
1198173340Sgshapiro			{
1199173340Sgshapiro				dead = true;
1200173340Sgshapiro				break;
1201173340Sgshapiro			}
120271345Sgshapiro		}
1203173340Sgshapiro		else
1204173340Sgshapiro			mci->mci_flags |= MCIF_INLONGLINE;
1205173340Sgshapiro
120638032Speter		if (l < end && *l == '\n')
120738032Speter		{
120838032Speter			if (*++l != ' ' && *l != '\t' && *l != '\0' &&
120938032Speter			    bitset(PXLF_HEADER, pxflags))
121038032Speter			{
121190792Sgshapiro				if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT,
121290792Sgshapiro					       ' ') == SM_IO_EOF)
1213157001Sgshapiro				{
1214157001Sgshapiro					dead = true;
121564562Sgshapiro					break;
121671345Sgshapiro				}
121790792Sgshapiro
121838032Speter				if (TrafficLogFile != NULL)
121990792Sgshapiro					(void) sm_io_putc(TrafficLogFile,
122090792Sgshapiro							  SM_TIME_DEFAULT, ' ');
122138032Speter			}
122238032Speter		}
122390792Sgshapiro
122438032Speter	} while (l < end);
1225157001Sgshapiro	return !dead;
122638032Speter}
1227157001Sgshapiro
122890792Sgshapiro/*
122938032Speter**  XUNLINK -- unlink a file, doing logging as appropriate.
123038032Speter**
123138032Speter**	Parameters:
123238032Speter**		f -- name of file to unlink.
123338032Speter**
123438032Speter**	Returns:
123590792Sgshapiro**		return value of unlink()
123638032Speter**
123738032Speter**	Side Effects:
123838032Speter**		f is unlinked.
123938032Speter*/
124038032Speter
124190792Sgshapiroint
124238032Speterxunlink(f)
124338032Speter	char *f;
124438032Speter{
124538032Speter	register int i;
124690792Sgshapiro	int save_errno;
124738032Speter
124838032Speter	if (LogLevel > 98)
124990792Sgshapiro		sm_syslog(LOG_DEBUG, CurEnv->e_id, "unlink %s", f);
125038032Speter
125138032Speter	i = unlink(f);
125290792Sgshapiro	save_errno = errno;
125338032Speter	if (i < 0 && LogLevel > 97)
125490792Sgshapiro		sm_syslog(LOG_DEBUG, CurEnv->e_id, "%s: unlink-fail %d",
125564562Sgshapiro			  f, errno);
125690792Sgshapiro	if (i >= 0)
125790792Sgshapiro		SYNC_DIR(f, false);
125890792Sgshapiro	errno = save_errno;
125990792Sgshapiro	return i;
126038032Speter}
1261168515Sgshapiro
126290792Sgshapiro/*
126338032Speter**  SFGETS -- "safe" fgets -- times out and ignores random interrupts.
126438032Speter**
126538032Speter**	Parameters:
126638032Speter**		buf -- place to put the input line.
126738032Speter**		siz -- size of buf.
126838032Speter**		fp -- file to read from.
126938032Speter**		timeout -- the timeout before error occurs.
127038032Speter**		during -- what we are trying to read (for error messages).
127138032Speter**
127238032Speter**	Returns:
127390792Sgshapiro**		NULL on error (including timeout).  This may also leave
127438032Speter**			buf containing a null string.
127538032Speter**		buf otherwise.
127638032Speter*/
127738032Speter
127864562Sgshapiro
127938032Speterchar *
128038032Spetersfgets(buf, siz, fp, timeout, during)
128138032Speter	char *buf;
128238032Speter	int siz;
128390792Sgshapiro	SM_FILE_T *fp;
128438032Speter	time_t timeout;
128538032Speter	char *during;
128638032Speter{
128738032Speter	register char *p;
1288249865Sgshapiro	int save_errno, io_timeout, l;
128938032Speter
129090792Sgshapiro	SM_REQUIRE(siz > 0);
129190792Sgshapiro	SM_REQUIRE(buf != NULL);
129290792Sgshapiro
129338032Speter	if (fp == NULL)
129438032Speter	{
129538032Speter		buf[0] = '\0';
129690792Sgshapiro		errno = EBADF;
129738032Speter		return NULL;
129838032Speter	}
129938032Speter
130090792Sgshapiro	/* try to read */
1301249865Sgshapiro	l = -1;
130290792Sgshapiro	errno = 0;
130390792Sgshapiro
130490792Sgshapiro	/* convert the timeout to sm_io notation */
130590792Sgshapiro	io_timeout = (timeout <= 0) ? SM_TIME_DEFAULT : timeout * 1000;
130690792Sgshapiro	while (!sm_io_eof(fp) && !sm_io_error(fp))
130738032Speter	{
130890792Sgshapiro		errno = 0;
1309249865Sgshapiro		l = sm_io_fgets(fp, io_timeout, buf, siz);
1310249865Sgshapiro		if (l < 0 && errno == EAGAIN)
131138032Speter		{
131290792Sgshapiro			/* The sm_io_fgets() call timedout */
131338032Speter			if (LogLevel > 1)
131438032Speter				sm_syslog(LOG_NOTICE, CurEnv->e_id,
131564562Sgshapiro					  "timeout waiting for input from %.100s during %s",
131690792Sgshapiro					  CURHOSTNAME,
131764562Sgshapiro					  during);
131838032Speter			buf[0] = '\0';
131938032Speter#if XDEBUG
132038032Speter			checkfd012(during);
132164562Sgshapiro#endif /* XDEBUG */
132238032Speter			if (TrafficLogFile != NULL)
132390792Sgshapiro				(void) sm_io_fprintf(TrafficLogFile,
132490792Sgshapiro						     SM_TIME_DEFAULT,
132590792Sgshapiro						     "%05d <<< [TIMEOUT]\n",
132690792Sgshapiro						     (int) CurrentPid);
132790792Sgshapiro			errno = ETIMEDOUT;
132864562Sgshapiro			return NULL;
132938032Speter		}
1330249865Sgshapiro		if (l >= 0 || errno != EINTR)
133138032Speter			break;
133290792Sgshapiro		(void) sm_io_clearerr(fp);
133338032Speter	}
133443730Speter	save_errno = errno;
133538032Speter
133638032Speter	/* clean up the books and exit */
133738032Speter	LineNumber++;
1338249865Sgshapiro	if (l < 0)
133938032Speter	{
134038032Speter		buf[0] = '\0';
134138032Speter		if (TrafficLogFile != NULL)
134290792Sgshapiro			(void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT,
134390792Sgshapiro					     "%05d <<< [EOF]\n",
134490792Sgshapiro					     (int) CurrentPid);
134543730Speter		errno = save_errno;
134664562Sgshapiro		return NULL;
134738032Speter	}
134838032Speter	if (TrafficLogFile != NULL)
134990792Sgshapiro		(void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT,
135090792Sgshapiro				     "%05d <<< %s", (int) CurrentPid, buf);
135138032Speter	if (SevenBitInput)
135238032Speter	{
135338032Speter		for (p = buf; *p != '\0'; p++)
135438032Speter			*p &= ~0200;
135538032Speter	}
135638032Speter	else if (!HasEightBits)
135738032Speter	{
135838032Speter		for (p = buf; *p != '\0'; p++)
135938032Speter		{
136038032Speter			if (bitset(0200, *p))
136138032Speter			{
136290792Sgshapiro				HasEightBits = true;
136338032Speter				break;
136438032Speter			}
136538032Speter		}
136638032Speter	}
136764562Sgshapiro	return buf;
136838032Speter}
1369168515Sgshapiro
137090792Sgshapiro/*
137190792Sgshapiro**  FGETFOLDED -- like fgets, but knows about folded lines.
137238032Speter**
137338032Speter**	Parameters:
137438032Speter**		buf -- place to put result.
1375168515Sgshapiro**		np -- pointer to bytes available; will be updated with
1376168515Sgshapiro**			the actual buffer size (not number of bytes filled)
1377168515Sgshapiro**			on return.
137838032Speter**		f -- file to read from.
137938032Speter**
138038032Speter**	Returns:
138190792Sgshapiro**		input line(s) on success, NULL on error or SM_IO_EOF.
138238032Speter**		This will normally be buf -- unless the line is too
138390792Sgshapiro**			long, when it will be sm_malloc_x()ed.
138438032Speter**
138538032Speter**	Side Effects:
138638032Speter**		buf gets lines from f, with continuation lines (lines
138738032Speter**		with leading white space) appended.  CRLF's are mapped
138838032Speter**		into single newlines.  Any trailing NL is stripped.
138938032Speter*/
139038032Speter
139138032Speterchar *
1392168515Sgshapirofgetfolded(buf, np, f)
139338032Speter	char *buf;
1394168515Sgshapiro	int *np;
139590792Sgshapiro	SM_FILE_T *f;
139638032Speter{
139738032Speter	register char *p = buf;
139838032Speter	char *bp = buf;
139938032Speter	register int i;
1400168515Sgshapiro	int n;
140138032Speter
1402168515Sgshapiro	SM_REQUIRE(np != NULL);
1403168515Sgshapiro	n = *np;
140490792Sgshapiro	SM_REQUIRE(n > 0);
140590792Sgshapiro	SM_REQUIRE(buf != NULL);
140690792Sgshapiro	if (f == NULL)
140790792Sgshapiro	{
140890792Sgshapiro		buf[0] = '\0';
140990792Sgshapiro		errno = EBADF;
141090792Sgshapiro		return NULL;
141190792Sgshapiro	}
141290792Sgshapiro
141338032Speter	n--;
141490792Sgshapiro	while ((i = sm_io_getc(f, SM_TIME_DEFAULT)) != SM_IO_EOF)
141538032Speter	{
141638032Speter		if (i == '\r')
141738032Speter		{
141890792Sgshapiro			i = sm_io_getc(f, SM_TIME_DEFAULT);
141938032Speter			if (i != '\n')
142038032Speter			{
142190792Sgshapiro				if (i != SM_IO_EOF)
142290792Sgshapiro					(void) sm_io_ungetc(f, SM_TIME_DEFAULT,
142390792Sgshapiro							    i);
142438032Speter				i = '\r';
142538032Speter			}
142638032Speter		}
142738032Speter		if (--n <= 0)
142838032Speter		{
142938032Speter			/* allocate new space */
143038032Speter			char *nbp;
143138032Speter			int nn;
143238032Speter
143338032Speter			nn = (p - bp);
143438032Speter			if (nn < MEMCHUNKSIZE)
143538032Speter				nn *= 2;
143638032Speter			else
143738032Speter				nn += MEMCHUNKSIZE;
143890792Sgshapiro			nbp = sm_malloc_x(nn);
143964562Sgshapiro			memmove(nbp, bp, p - bp);
144038032Speter			p = &nbp[p - bp];
144138032Speter			if (bp != buf)
144277349Sgshapiro				sm_free(bp);
144338032Speter			bp = nbp;
144438032Speter			n = nn - (p - bp);
1445168515Sgshapiro			*np = nn;
144638032Speter		}
144738032Speter		*p++ = i;
144838032Speter		if (i == '\n')
144938032Speter		{
145038032Speter			LineNumber++;
145190792Sgshapiro			i = sm_io_getc(f, SM_TIME_DEFAULT);
145290792Sgshapiro			if (i != SM_IO_EOF)
145390792Sgshapiro				(void) sm_io_ungetc(f, SM_TIME_DEFAULT, i);
145438032Speter			if (i != ' ' && i != '\t')
145538032Speter				break;
145638032Speter		}
145738032Speter	}
145838032Speter	if (p == bp)
145964562Sgshapiro		return NULL;
146038032Speter	if (p[-1] == '\n')
146138032Speter		p--;
146238032Speter	*p = '\0';
146364562Sgshapiro	return bp;
146438032Speter}
1465168515Sgshapiro
146690792Sgshapiro/*
146738032Speter**  CURTIME -- return current time.
146838032Speter**
146938032Speter**	Parameters:
147038032Speter**		none.
147138032Speter**
147238032Speter**	Returns:
147338032Speter**		the current time.
147438032Speter*/
147538032Speter
147638032Spetertime_t
147738032Spetercurtime()
147838032Speter{
147938032Speter	auto time_t t;
148038032Speter
148138032Speter	(void) time(&t);
148264562Sgshapiro	return t;
148338032Speter}
1484168515Sgshapiro
148590792Sgshapiro/*
148638032Speter**  ATOBOOL -- convert a string representation to boolean.
148738032Speter**
148890792Sgshapiro**	Defaults to false
148938032Speter**
149038032Speter**	Parameters:
149190792Sgshapiro**		s -- string to convert.  Takes "tTyY", empty, and NULL as true,
149238032Speter**			others as false.
149338032Speter**
149438032Speter**	Returns:
149538032Speter**		A boolean representation of the string.
149638032Speter*/
149738032Speter
149838032Speterbool
149938032Speteratobool(s)
150038032Speter	register char *s;
150138032Speter{
150238032Speter	if (s == NULL || *s == '\0' || strchr("tTyY", *s) != NULL)
150390792Sgshapiro		return true;
150490792Sgshapiro	return false;
150538032Speter}
1506168515Sgshapiro
150790792Sgshapiro/*
150838032Speter**  ATOOCT -- convert a string representation to octal.
150938032Speter**
151038032Speter**	Parameters:
151138032Speter**		s -- string to convert.
151238032Speter**
151338032Speter**	Returns:
151438032Speter**		An integer representing the string interpreted as an
151538032Speter**		octal number.
151638032Speter*/
151738032Speter
151838032Speterint
151938032Speteratooct(s)
152038032Speter	register char *s;
152138032Speter{
152238032Speter	register int i = 0;
152338032Speter
152438032Speter	while (*s >= '0' && *s <= '7')
152538032Speter		i = (i << 3) | (*s++ - '0');
152664562Sgshapiro	return i;
152738032Speter}
1528168515Sgshapiro
152990792Sgshapiro/*
153038032Speter**  BITINTERSECT -- tell if two bitmaps intersect
153138032Speter**
153238032Speter**	Parameters:
153338032Speter**		a, b -- the bitmaps in question
153438032Speter**
153538032Speter**	Returns:
153690792Sgshapiro**		true if they have a non-null intersection
153790792Sgshapiro**		false otherwise
153838032Speter*/
153938032Speter
154038032Speterbool
154138032Speterbitintersect(a, b)
154264562Sgshapiro	BITMAP256 a;
154364562Sgshapiro	BITMAP256 b;
154438032Speter{
154538032Speter	int i;
154638032Speter
1547168515Sgshapiro	for (i = BITMAPBYTES / sizeof(int); --i >= 0; )
154871345Sgshapiro	{
154938032Speter		if ((a[i] & b[i]) != 0)
155090792Sgshapiro			return true;
155171345Sgshapiro	}
155290792Sgshapiro	return false;
155338032Speter}
1554168515Sgshapiro
155590792Sgshapiro/*
155638032Speter**  BITZEROP -- tell if a bitmap is all zero
155738032Speter**
155838032Speter**	Parameters:
155938032Speter**		map -- the bit map to check
156038032Speter**
156138032Speter**	Returns:
156290792Sgshapiro**		true if map is all zero.
156390792Sgshapiro**		false if there are any bits set in map.
156438032Speter*/
156538032Speter
156638032Speterbool
156738032Speterbitzerop(map)
156864562Sgshapiro	BITMAP256 map;
156938032Speter{
157038032Speter	int i;
157138032Speter
1572168515Sgshapiro	for (i = BITMAPBYTES / sizeof(int); --i >= 0; )
157371345Sgshapiro	{
157438032Speter		if (map[i] != 0)
157590792Sgshapiro			return false;
157671345Sgshapiro	}
157790792Sgshapiro	return true;
157838032Speter}
1579168515Sgshapiro
158090792Sgshapiro/*
158138032Speter**  STRCONTAINEDIN -- tell if one string is contained in another
158238032Speter**
158338032Speter**	Parameters:
158490792Sgshapiro**		icase -- ignore case?
158538032Speter**		a -- possible substring.
158638032Speter**		b -- possible superstring.
158738032Speter**
158838032Speter**	Returns:
158990792Sgshapiro**		true if a is contained in b (case insensitive).
159090792Sgshapiro**		false otherwise.
159138032Speter*/
159238032Speter
159338032Speterbool
159490792Sgshapirostrcontainedin(icase, a, b)
159590792Sgshapiro	bool icase;
159638032Speter	register char *a;
159738032Speter	register char *b;
159838032Speter{
159938032Speter	int la;
160038032Speter	int lb;
160138032Speter	int c;
160238032Speter
160338032Speter	la = strlen(a);
160438032Speter	lb = strlen(b);
160538032Speter	c = *a;
160690792Sgshapiro	if (icase && isascii(c) && isupper(c))
160738032Speter		c = tolower(c);
160838032Speter	for (; lb-- >= la; b++)
160938032Speter	{
161090792Sgshapiro		if (icase)
161190792Sgshapiro		{
161290792Sgshapiro			if (*b != c &&
161390792Sgshapiro			    isascii(*b) && isupper(*b) && tolower(*b) != c)
161490792Sgshapiro				continue;
161590792Sgshapiro			if (sm_strncasecmp(a, b, la) == 0)
161690792Sgshapiro				return true;
161790792Sgshapiro		}
161890792Sgshapiro		else
161990792Sgshapiro		{
162090792Sgshapiro			if (*b != c)
162190792Sgshapiro				continue;
162290792Sgshapiro			if (strncmp(a, b, la) == 0)
162390792Sgshapiro				return true;
162490792Sgshapiro		}
162538032Speter	}
162690792Sgshapiro	return false;
162738032Speter}
1628168515Sgshapiro
162990792Sgshapiro/*
163038032Speter**  CHECKFD012 -- check low numbered file descriptors
163138032Speter**
163238032Speter**	File descriptors 0, 1, and 2 should be open at all times.
163338032Speter**	This routine verifies that, and fixes it if not true.
163438032Speter**
163538032Speter**	Parameters:
163638032Speter**		where -- a tag printed if the assertion failed
163738032Speter**
163838032Speter**	Returns:
163938032Speter**		none
164038032Speter*/
164138032Speter
164238032Spetervoid
164338032Spetercheckfd012(where)
164438032Speter	char *where;
164538032Speter{
164638032Speter#if XDEBUG
164738032Speter	register int i;
164838032Speter
164938032Speter	for (i = 0; i < 3; i++)
165038032Speter		fill_fd(i, where);
165138032Speter#endif /* XDEBUG */
165238032Speter}
1653168515Sgshapiro
165490792Sgshapiro/*
165538032Speter**  CHECKFDOPEN -- make sure file descriptor is open -- for extended debugging
165638032Speter**
165738032Speter**	Parameters:
165838032Speter**		fd -- file descriptor to check.
165938032Speter**		where -- tag to print on failure.
166038032Speter**
166138032Speter**	Returns:
166238032Speter**		none.
166338032Speter*/
166438032Speter
166538032Spetervoid
166638032Spetercheckfdopen(fd, where)
166738032Speter	int fd;
166838032Speter	char *where;
166938032Speter{
167038032Speter#if XDEBUG
167138032Speter	struct stat st;
167238032Speter
167338032Speter	if (fstat(fd, &st) < 0 && errno == EBADF)
167438032Speter	{
167538032Speter		syserr("checkfdopen(%d): %s not open as expected!", fd, where);
167690792Sgshapiro		printopenfds(true);
167738032Speter	}
167864562Sgshapiro#endif /* XDEBUG */
167938032Speter}
1680168515Sgshapiro
168190792Sgshapiro/*
168238032Speter**  CHECKFDS -- check for new or missing file descriptors
168338032Speter**
168438032Speter**	Parameters:
168538032Speter**		where -- tag for printing.  If null, take a base line.
168638032Speter**
168738032Speter**	Returns:
168838032Speter**		none
168938032Speter**
169038032Speter**	Side Effects:
169138032Speter**		If where is set, shows changes since the last call.
169238032Speter*/
169338032Speter
169438032Spetervoid
169538032Spetercheckfds(where)
169638032Speter	char *where;
169738032Speter{
169838032Speter	int maxfd;
169938032Speter	register int fd;
170090792Sgshapiro	bool printhdr = true;
170138032Speter	int save_errno = errno;
170264562Sgshapiro	static BITMAP256 baseline;
170338032Speter	extern int DtableSize;
170438032Speter
170571345Sgshapiro	if (DtableSize > BITMAPBITS)
170671345Sgshapiro		maxfd = BITMAPBITS;
170738032Speter	else
170838032Speter		maxfd = DtableSize;
170938032Speter	if (where == NULL)
171038032Speter		clrbitmap(baseline);
171138032Speter
171238032Speter	for (fd = 0; fd < maxfd; fd++)
171338032Speter	{
171438032Speter		struct stat stbuf;
171538032Speter
171638032Speter		if (fstat(fd, &stbuf) < 0 && errno != EOPNOTSUPP)
171738032Speter		{
171838032Speter			if (!bitnset(fd, baseline))
171938032Speter				continue;
172038032Speter			clrbitn(fd, baseline);
172138032Speter		}
172238032Speter		else if (!bitnset(fd, baseline))
172338032Speter			setbitn(fd, baseline);
172438032Speter		else
172538032Speter			continue;
172638032Speter
172738032Speter		/* file state has changed */
172838032Speter		if (where == NULL)
172938032Speter			continue;
173038032Speter		if (printhdr)
173138032Speter		{
173238032Speter			sm_syslog(LOG_DEBUG, CurEnv->e_id,
173364562Sgshapiro				  "%s: changed fds:",
173464562Sgshapiro				  where);
173590792Sgshapiro			printhdr = false;
173638032Speter		}
173790792Sgshapiro		dumpfd(fd, true, true);
173838032Speter	}
173938032Speter	errno = save_errno;
174038032Speter}
1741168515Sgshapiro
174290792Sgshapiro/*
174338032Speter**  PRINTOPENFDS -- print the open file descriptors (for debugging)
174438032Speter**
174538032Speter**	Parameters:
174638032Speter**		logit -- if set, send output to syslog; otherwise
174738032Speter**			print for debugging.
174838032Speter**
174938032Speter**	Returns:
175038032Speter**		none.
175138032Speter*/
175238032Speter
175364562Sgshapiro#if NETINET || NETINET6
175464562Sgshapiro# include <arpa/inet.h>
175564562Sgshapiro#endif /* NETINET || NETINET6 */
175638032Speter
175738032Spetervoid
175838032Speterprintopenfds(logit)
175938032Speter	bool logit;
176038032Speter{
176138032Speter	register int fd;
176238032Speter	extern int DtableSize;
176338032Speter
176438032Speter	for (fd = 0; fd < DtableSize; fd++)
176590792Sgshapiro		dumpfd(fd, false, logit);
176638032Speter}
1767168515Sgshapiro
176890792Sgshapiro/*
176938032Speter**  DUMPFD -- dump a file descriptor
177038032Speter**
177138032Speter**	Parameters:
177238032Speter**		fd -- the file descriptor to dump.
177338032Speter**		printclosed -- if set, print a notification even if
177438032Speter**			it is closed; otherwise print nothing.
1775132943Sgshapiro**		logit -- if set, use sm_syslog instead of sm_dprintf()
177690792Sgshapiro**
177790792Sgshapiro**	Returns:
177890792Sgshapiro**		none.
177938032Speter*/
178038032Speter
178138032Spetervoid
178238032Speterdumpfd(fd, printclosed, logit)
178338032Speter	int fd;
178438032Speter	bool printclosed;
178538032Speter	bool logit;
178638032Speter{
178738032Speter	register char *p;
178838032Speter	char *hp;
178938032Speter#ifdef S_IFSOCK
179038032Speter	SOCKADDR sa;
179164562Sgshapiro#endif /* S_IFSOCK */
179238032Speter	auto SOCKADDR_LEN_T slen;
179338032Speter	int i;
179438032Speter#if STAT64 > 0
179538032Speter	struct stat64 st;
179664562Sgshapiro#else /* STAT64 > 0 */
179738032Speter	struct stat st;
179864562Sgshapiro#endif /* STAT64 > 0 */
179938032Speter	char buf[200];
180038032Speter
180138032Speter	p = buf;
180290792Sgshapiro	(void) sm_snprintf(p, SPACELEFT(buf, p), "%3d: ", fd);
180338032Speter	p += strlen(p);
180438032Speter
180538032Speter	if (
180638032Speter#if STAT64 > 0
180738032Speter	    fstat64(fd, &st)
180864562Sgshapiro#else /* STAT64 > 0 */
180938032Speter	    fstat(fd, &st)
181064562Sgshapiro#endif /* STAT64 > 0 */
181138032Speter	    < 0)
181238032Speter	{
181338032Speter		if (errno != EBADF)
181438032Speter		{
181590792Sgshapiro			(void) sm_snprintf(p, SPACELEFT(buf, p),
181690792Sgshapiro				"CANNOT STAT (%s)",
181790792Sgshapiro				sm_errstring(errno));
181838032Speter			goto printit;
181938032Speter		}
182038032Speter		else if (printclosed)
182138032Speter		{
182290792Sgshapiro			(void) sm_snprintf(p, SPACELEFT(buf, p), "CLOSED");
182338032Speter			goto printit;
182438032Speter		}
182538032Speter		return;
182638032Speter	}
182738032Speter
182894334Sgshapiro	i = fcntl(fd, F_GETFL, 0);
182938032Speter	if (i != -1)
183038032Speter	{
183190792Sgshapiro		(void) sm_snprintf(p, SPACELEFT(buf, p), "fl=0x%x, ", i);
183238032Speter		p += strlen(p);
183338032Speter	}
183438032Speter
183590792Sgshapiro	(void) sm_snprintf(p, SPACELEFT(buf, p), "mode=%o: ",
183690792Sgshapiro			(int) st.st_mode);
183738032Speter	p += strlen(p);
183838032Speter	switch (st.st_mode & S_IFMT)
183938032Speter	{
184038032Speter#ifdef S_IFSOCK
184138032Speter	  case S_IFSOCK:
184290792Sgshapiro		(void) sm_snprintf(p, SPACELEFT(buf, p), "SOCK ");
184338032Speter		p += strlen(p);
1844168515Sgshapiro		memset(&sa, '\0', sizeof(sa));
1845168515Sgshapiro		slen = sizeof(sa);
184638032Speter		if (getsockname(fd, &sa.sa, &slen) < 0)
184790792Sgshapiro			(void) sm_snprintf(p, SPACELEFT(buf, p), "(%s)",
184890792Sgshapiro				 sm_errstring(errno));
184938032Speter		else
185038032Speter		{
185138032Speter			hp = hostnamebyanyaddr(&sa);
185264562Sgshapiro			if (hp == NULL)
185364562Sgshapiro			{
185464562Sgshapiro				/* EMPTY */
185564562Sgshapiro				/* do nothing */
185664562Sgshapiro			}
185764562Sgshapiro# if NETINET
185864562Sgshapiro			else if (sa.sa.sa_family == AF_INET)
185990792Sgshapiro				(void) sm_snprintf(p, SPACELEFT(buf, p),
186090792Sgshapiro					"%s/%d", hp, ntohs(sa.sin.sin_port));
186164562Sgshapiro# endif /* NETINET */
186264562Sgshapiro# if NETINET6
186364562Sgshapiro			else if (sa.sa.sa_family == AF_INET6)
186490792Sgshapiro				(void) sm_snprintf(p, SPACELEFT(buf, p),
186590792Sgshapiro					"%s/%d", hp, ntohs(sa.sin6.sin6_port));
186664562Sgshapiro# endif /* NETINET6 */
186738032Speter			else
186890792Sgshapiro				(void) sm_snprintf(p, SPACELEFT(buf, p),
186990792Sgshapiro					"%s", hp);
187038032Speter		}
187138032Speter		p += strlen(p);
187290792Sgshapiro		(void) sm_snprintf(p, SPACELEFT(buf, p), "->");
187338032Speter		p += strlen(p);
1874168515Sgshapiro		slen = sizeof(sa);
187538032Speter		if (getpeername(fd, &sa.sa, &slen) < 0)
187690792Sgshapiro			(void) sm_snprintf(p, SPACELEFT(buf, p), "(%s)",
187790792Sgshapiro					sm_errstring(errno));
187838032Speter		else
187938032Speter		{
188038032Speter			hp = hostnamebyanyaddr(&sa);
188164562Sgshapiro			if (hp == NULL)
188264562Sgshapiro			{
188364562Sgshapiro				/* EMPTY */
188464562Sgshapiro				/* do nothing */
188564562Sgshapiro			}
188664562Sgshapiro# if NETINET
188764562Sgshapiro			else if (sa.sa.sa_family == AF_INET)
188890792Sgshapiro				(void) sm_snprintf(p, SPACELEFT(buf, p),
188990792Sgshapiro					"%s/%d", hp, ntohs(sa.sin.sin_port));
189064562Sgshapiro# endif /* NETINET */
189164562Sgshapiro# if NETINET6
189264562Sgshapiro			else if (sa.sa.sa_family == AF_INET6)
189390792Sgshapiro				(void) sm_snprintf(p, SPACELEFT(buf, p),
189490792Sgshapiro					"%s/%d", hp, ntohs(sa.sin6.sin6_port));
189564562Sgshapiro# endif /* NETINET6 */
189638032Speter			else
189790792Sgshapiro				(void) sm_snprintf(p, SPACELEFT(buf, p),
189890792Sgshapiro					"%s", hp);
189938032Speter		}
190038032Speter		break;
190164562Sgshapiro#endif /* S_IFSOCK */
190238032Speter
190338032Speter	  case S_IFCHR:
190490792Sgshapiro		(void) sm_snprintf(p, SPACELEFT(buf, p), "CHR: ");
190538032Speter		p += strlen(p);
190638032Speter		goto defprint;
190738032Speter
190890792Sgshapiro#ifdef S_IFBLK
190938032Speter	  case S_IFBLK:
191090792Sgshapiro		(void) sm_snprintf(p, SPACELEFT(buf, p), "BLK: ");
191138032Speter		p += strlen(p);
191238032Speter		goto defprint;
191390792Sgshapiro#endif /* S_IFBLK */
191438032Speter
191538032Speter#if defined(S_IFIFO) && (!defined(S_IFSOCK) || S_IFIFO != S_IFSOCK)
191638032Speter	  case S_IFIFO:
191790792Sgshapiro		(void) sm_snprintf(p, SPACELEFT(buf, p), "FIFO: ");
191838032Speter		p += strlen(p);
191938032Speter		goto defprint;
192064562Sgshapiro#endif /* defined(S_IFIFO) && (!defined(S_IFSOCK) || S_IFIFO != S_IFSOCK) */
192138032Speter
192238032Speter#ifdef S_IFDIR
192338032Speter	  case S_IFDIR:
192490792Sgshapiro		(void) sm_snprintf(p, SPACELEFT(buf, p), "DIR: ");
192538032Speter		p += strlen(p);
192638032Speter		goto defprint;
192764562Sgshapiro#endif /* S_IFDIR */
192838032Speter
192938032Speter#ifdef S_IFLNK
193038032Speter	  case S_IFLNK:
193190792Sgshapiro		(void) sm_snprintf(p, SPACELEFT(buf, p), "LNK: ");
193238032Speter		p += strlen(p);
193338032Speter		goto defprint;
193464562Sgshapiro#endif /* S_IFLNK */
193538032Speter
193638032Speter	  default:
193738032Speterdefprint:
193890792Sgshapiro		(void) sm_snprintf(p, SPACELEFT(buf, p),
193990792Sgshapiro			 "dev=%d/%d, ino=%llu, nlink=%d, u/gid=%d/%d, ",
194090792Sgshapiro			 major(st.st_dev), minor(st.st_dev),
194190792Sgshapiro			 (ULONGLONG_T) st.st_ino,
194290792Sgshapiro			 (int) st.st_nlink, (int) st.st_uid,
194390792Sgshapiro			 (int) st.st_gid);
194490792Sgshapiro		p += strlen(p);
194590792Sgshapiro		(void) sm_snprintf(p, SPACELEFT(buf, p), "size=%llu",
194690792Sgshapiro			 (ULONGLONG_T) st.st_size);
194738032Speter		break;
194838032Speter	}
194938032Speter
195038032Speterprintit:
195138032Speter	if (logit)
195238032Speter		sm_syslog(LOG_DEBUG, CurEnv ? CurEnv->e_id : NULL,
195364562Sgshapiro			  "%.800s", buf);
195438032Speter	else
1955132943Sgshapiro		sm_dprintf("%s\n", buf);
195638032Speter}
1957168515Sgshapiro
195890792Sgshapiro/*
195938032Speter**  SHORTEN_HOSTNAME -- strip local domain information off of hostname.
196038032Speter**
196138032Speter**	Parameters:
196238032Speter**		host -- the host to shorten (stripped in place).
196338032Speter**
196438032Speter**	Returns:
196590792Sgshapiro**		place where string was truncated, NULL if not truncated.
196638032Speter*/
196738032Speter
196873188Sgshapirochar *
196938032Spetershorten_hostname(host)
197038032Speter	char host[];
197138032Speter{
197238032Speter	register char *p;
197338032Speter	char *mydom;
197438032Speter	int i;
197590792Sgshapiro	bool canon = false;
197638032Speter
197738032Speter	/* strip off final dot */
197890792Sgshapiro	i = strlen(host);
197990792Sgshapiro	p = &host[(i == 0) ? 0 : i - 1];
198038032Speter	if (*p == '.')
198138032Speter	{
198238032Speter		*p = '\0';
198390792Sgshapiro		canon = true;
198438032Speter	}
198538032Speter
198638032Speter	/* see if there is any domain at all -- if not, we are done */
198738032Speter	p = strchr(host, '.');
198838032Speter	if (p == NULL)
198973188Sgshapiro		return NULL;
199038032Speter
199138032Speter	/* yes, we have a domain -- see if it looks like us */
199238032Speter	mydom = macvalue('m', CurEnv);
199338032Speter	if (mydom == NULL)
199438032Speter		mydom = "";
199538032Speter	i = strlen(++p);
199690792Sgshapiro	if ((canon ? sm_strcasecmp(p, mydom)
199790792Sgshapiro		   : sm_strncasecmp(p, mydom, i)) == 0 &&
199890792Sgshapiro			(mydom[i] == '.' || mydom[i] == '\0'))
199973188Sgshapiro	{
200038032Speter		*--p = '\0';
200173188Sgshapiro		return p;
200273188Sgshapiro	}
200373188Sgshapiro	return NULL;
200438032Speter}
2005168515Sgshapiro
200690792Sgshapiro/*
200738032Speter**  PROG_OPEN -- open a program for reading
200838032Speter**
200938032Speter**	Parameters:
201038032Speter**		argv -- the argument list.
201138032Speter**		pfd -- pointer to a place to store the file descriptor.
201238032Speter**		e -- the current envelope.
201338032Speter**
201438032Speter**	Returns:
201538032Speter**		pid of the process -- -1 if it failed.
201638032Speter*/
201738032Speter
201877349Sgshapiropid_t
201938032Speterprog_open(argv, pfd, e)
202038032Speter	char **argv;
202138032Speter	int *pfd;
202238032Speter	ENVELOPE *e;
202338032Speter{
202477349Sgshapiro	pid_t pid;
202564562Sgshapiro	int save_errno;
202690792Sgshapiro	int sff;
202790792Sgshapiro	int ret;
202838032Speter	int fdv[2];
202938032Speter	char *p, *q;
203098121Sgshapiro	char buf[MAXPATHLEN];
203138032Speter	extern int DtableSize;
203238032Speter
203338032Speter	if (pipe(fdv) < 0)
203438032Speter	{
203538032Speter		syserr("%s: cannot create pipe for stdout", argv[0]);
203638032Speter		return -1;
203738032Speter	}
203838032Speter	pid = fork();
203938032Speter	if (pid < 0)
204038032Speter	{
204138032Speter		syserr("%s: cannot fork", argv[0]);
204264562Sgshapiro		(void) close(fdv[0]);
204364562Sgshapiro		(void) close(fdv[1]);
204438032Speter		return -1;
204538032Speter	}
204638032Speter	if (pid > 0)
204738032Speter	{
204838032Speter		/* parent */
204964562Sgshapiro		(void) close(fdv[1]);
205038032Speter		*pfd = fdv[0];
205138032Speter		return pid;
205238032Speter	}
205338032Speter
205477349Sgshapiro	/* Reset global flags */
205577349Sgshapiro	RestartRequest = NULL;
205690792Sgshapiro	RestartWorkGroup = false;
205777349Sgshapiro	ShutdownRequest = NULL;
205877349Sgshapiro	PendingSignal = 0;
205990792Sgshapiro	CurrentPid = getpid();
206077349Sgshapiro
206190792Sgshapiro	/*
206290792Sgshapiro	**  Initialize exception stack and default exception
206390792Sgshapiro	**  handler for child process.
206490792Sgshapiro	*/
206590792Sgshapiro
206690792Sgshapiro	sm_exc_newthread(fatal_error);
206790792Sgshapiro
206890792Sgshapiro	/* child -- close stdin */
206990792Sgshapiro	(void) close(0);
207090792Sgshapiro
207138032Speter	/* stdout goes back to parent */
207264562Sgshapiro	(void) close(fdv[0]);
207338032Speter	if (dup2(fdv[1], 1) < 0)
207438032Speter	{
207538032Speter		syserr("%s: cannot dup2 for stdout", argv[0]);
207638032Speter		_exit(EX_OSERR);
207738032Speter	}
207864562Sgshapiro	(void) close(fdv[1]);
207938032Speter
208038032Speter	/* stderr goes to transcript if available */
208138032Speter	if (e->e_xfp != NULL)
208238032Speter	{
208364562Sgshapiro		int xfd;
208464562Sgshapiro
208590792Sgshapiro		xfd = sm_io_getinfo(e->e_xfp, SM_IO_WHAT_FD, NULL);
208664562Sgshapiro		if (xfd >= 0 && dup2(xfd, 2) < 0)
208738032Speter		{
208838032Speter			syserr("%s: cannot dup2 for stderr", argv[0]);
208938032Speter			_exit(EX_OSERR);
209038032Speter		}
209138032Speter	}
209238032Speter
209338032Speter	/* this process has no right to the queue file */
209438032Speter	if (e->e_lockfp != NULL)
2095159609Sgshapiro	{
2096159609Sgshapiro		int fd;
209738032Speter
2098159609Sgshapiro		fd = sm_io_getinfo(e->e_lockfp, SM_IO_WHAT_FD, NULL);
2099159609Sgshapiro		if (fd >= 0)
2100159609Sgshapiro			(void) close(fd);
2101159609Sgshapiro		else
2102159609Sgshapiro			syserr("%s: lockfp does not have a fd", argv[0]);
2103159609Sgshapiro	}
2104159609Sgshapiro
210564562Sgshapiro	/* chroot to the program mailer directory, if defined */
210664562Sgshapiro	if (ProgMailer != NULL && ProgMailer->m_rootdir != NULL)
210764562Sgshapiro	{
2108168515Sgshapiro		expand(ProgMailer->m_rootdir, buf, sizeof(buf), e);
210964562Sgshapiro		if (chroot(buf) < 0)
211064562Sgshapiro		{
211164562Sgshapiro			syserr("prog_open: cannot chroot(%s)", buf);
211264562Sgshapiro			exit(EX_TEMPFAIL);
211364562Sgshapiro		}
211464562Sgshapiro		if (chdir("/") < 0)
211564562Sgshapiro		{
211664562Sgshapiro			syserr("prog_open: cannot chdir(/)");
211764562Sgshapiro			exit(EX_TEMPFAIL);
211864562Sgshapiro		}
211964562Sgshapiro	}
212064562Sgshapiro
212138032Speter	/* run as default user */
212238032Speter	endpwent();
212390792Sgshapiro	sm_mbdb_terminate();
2124157001Sgshapiro#if _FFR_MEMSTAT
2125157001Sgshapiro	(void) sm_memstat_close();
2126157001Sgshapiro#endif /* _FFR_MEMSTAT */
212738032Speter	if (setgid(DefGid) < 0 && geteuid() == 0)
212864562Sgshapiro	{
212938032Speter		syserr("prog_open: setgid(%ld) failed", (long) DefGid);
213064562Sgshapiro		exit(EX_TEMPFAIL);
213164562Sgshapiro	}
213238032Speter	if (setuid(DefUid) < 0 && geteuid() == 0)
213364562Sgshapiro	{
213438032Speter		syserr("prog_open: setuid(%ld) failed", (long) DefUid);
213564562Sgshapiro		exit(EX_TEMPFAIL);
213664562Sgshapiro	}
213738032Speter
213838032Speter	/* run in some directory */
213938032Speter	if (ProgMailer != NULL)
214038032Speter		p = ProgMailer->m_execdir;
214138032Speter	else
214238032Speter		p = NULL;
214338032Speter	for (; p != NULL; p = q)
214438032Speter	{
214538032Speter		q = strchr(p, ':');
214638032Speter		if (q != NULL)
214738032Speter			*q = '\0';
2148168515Sgshapiro		expand(p, buf, sizeof(buf), e);
214938032Speter		if (q != NULL)
215038032Speter			*q++ = ':';
215138032Speter		if (buf[0] != '\0' && chdir(buf) >= 0)
215238032Speter			break;
215338032Speter	}
215438032Speter	if (p == NULL)
215538032Speter	{
215638032Speter		/* backup directories */
215738032Speter		if (chdir("/tmp") < 0)
215838032Speter			(void) chdir("/");
215938032Speter	}
216038032Speter
216190792Sgshapiro	/* Check safety of program to be run */
216290792Sgshapiro	sff = SFF_ROOTOK|SFF_EXECOK;
216390792Sgshapiro	if (!bitnset(DBS_RUNWRITABLEPROGRAM, DontBlameSendmail))
216490792Sgshapiro		sff |= SFF_NOGWFILES|SFF_NOWWFILES;
216590792Sgshapiro	if (bitnset(DBS_RUNPROGRAMINUNSAFEDIRPATH, DontBlameSendmail))
216690792Sgshapiro		sff |= SFF_NOPATHCHECK;
216790792Sgshapiro	else
216890792Sgshapiro		sff |= SFF_SAFEDIRPATH;
216990792Sgshapiro	ret = safefile(argv[0], DefUid, DefGid, DefUser, sff, 0, NULL);
217090792Sgshapiro	if (ret != 0)
217190792Sgshapiro		sm_syslog(LOG_INFO, e->e_id,
217290792Sgshapiro			  "Warning: prog_open: program %s unsafe: %s",
217390792Sgshapiro			  argv[0], sm_errstring(ret));
217490792Sgshapiro
217538032Speter	/* arrange for all the files to be closed */
2176132943Sgshapiro	sm_close_on_exec(STDERR_FILENO + 1, DtableSize);
217738032Speter
217838032Speter	/* now exec the process */
217964562Sgshapiro	(void) execve(argv[0], (ARGV_T) argv, (ARGV_T) UserEnviron);
218038032Speter
218138032Speter	/* woops!  failed */
218264562Sgshapiro	save_errno = errno;
218338032Speter	syserr("%s: cannot exec", argv[0]);
218464562Sgshapiro	if (transienterror(save_errno))
218538032Speter		_exit(EX_OSERR);
218638032Speter	_exit(EX_CONFIG);
218738032Speter	return -1;	/* avoid compiler warning on IRIX */
218838032Speter}
2189168515Sgshapiro
219090792Sgshapiro/*
219164562Sgshapiro**  GET_COLUMN -- look up a Column in a line buffer
219238032Speter**
219338032Speter**	Parameters:
219438032Speter**		line -- the raw text line to search.
219538032Speter**		col -- the column number to fetch.
219638032Speter**		delim -- the delimiter between columns.  If null,
219738032Speter**			use white space.
219838032Speter**		buf -- the output buffer.
219938032Speter**		buflen -- the length of buf.
220038032Speter**
220138032Speter**	Returns:
220238032Speter**		buf if successful.
220338032Speter**		NULL otherwise.
220438032Speter*/
220538032Speter
220638032Speterchar *
220738032Speterget_column(line, col, delim, buf, buflen)
220838032Speter	char line[];
220938032Speter	int col;
221064562Sgshapiro	int delim;
221138032Speter	char buf[];
221238032Speter	int buflen;
221338032Speter{
221438032Speter	char *p;
221538032Speter	char *begin, *end;
221638032Speter	int i;
221738032Speter	char delimbuf[4];
221864562Sgshapiro
221990792Sgshapiro	if ((char) delim == '\0')
2220168515Sgshapiro		(void) sm_strlcpy(delimbuf, "\n\t ", sizeof(delimbuf));
222138032Speter	else
222238032Speter	{
222390792Sgshapiro		delimbuf[0] = (char) delim;
222438032Speter		delimbuf[1] = '\0';
222538032Speter	}
222638032Speter
222738032Speter	p = line;
222838032Speter	if (*p == '\0')
222938032Speter		return NULL;			/* line empty */
223090792Sgshapiro	if (*p == (char) delim && col == 0)
223138032Speter		return NULL;			/* first column empty */
223238032Speter
223338032Speter	begin = line;
223438032Speter
223590792Sgshapiro	if (col == 0 && (char) delim == '\0')
223638032Speter	{
223738032Speter		while (*begin != '\0' && isascii(*begin) && isspace(*begin))
223838032Speter			begin++;
223938032Speter	}
224038032Speter
224138032Speter	for (i = 0; i < col; i++)
224238032Speter	{
224338032Speter		if ((begin = strpbrk(begin, delimbuf)) == NULL)
224438032Speter			return NULL;		/* no such column */
224538032Speter		begin++;
224690792Sgshapiro		if ((char) delim == '\0')
224738032Speter		{
224838032Speter			while (*begin != '\0' && isascii(*begin) && isspace(*begin))
224938032Speter				begin++;
225038032Speter		}
225138032Speter	}
225264562Sgshapiro
225338032Speter	end = strpbrk(begin, delimbuf);
225438032Speter	if (end == NULL)
225538032Speter		i = strlen(begin);
225638032Speter	else
225738032Speter		i = end - begin;
225838032Speter	if (i >= buflen)
225938032Speter		i = buflen - 1;
226090792Sgshapiro	(void) sm_strlcpy(buf, begin, i + 1);
226138032Speter	return buf;
226238032Speter}
2263168515Sgshapiro
226490792Sgshapiro/*
226538032Speter**  CLEANSTRCPY -- copy string keeping out bogus characters
226638032Speter**
226738032Speter**	Parameters:
226838032Speter**		t -- "to" string.
226938032Speter**		f -- "from" string.
227038032Speter**		l -- length of space available in "to" string.
227138032Speter**
227238032Speter**	Returns:
227338032Speter**		none.
227438032Speter*/
227538032Speter
227638032Spetervoid
227738032Spetercleanstrcpy(t, f, l)
227838032Speter	register char *t;
227938032Speter	register char *f;
228038032Speter	int l;
228138032Speter{
228238032Speter	/* check for newlines and log if necessary */
228390792Sgshapiro	(void) denlstring(f, true, true);
228438032Speter
228564562Sgshapiro	if (l <= 0)
228664562Sgshapiro		syserr("!cleanstrcpy: length == 0");
228764562Sgshapiro
228838032Speter	l--;
228938032Speter	while (l > 0 && *f != '\0')
229038032Speter	{
229138032Speter		if (isascii(*f) &&
229238032Speter		    (isalnum(*f) || strchr("!#$%&'*+-./^_`{|}~", *f) != NULL))
229338032Speter		{
229438032Speter			l--;
229538032Speter			*t++ = *f;
229638032Speter		}
229738032Speter		f++;
229838032Speter	}
229938032Speter	*t = '\0';
230038032Speter}
2301168515Sgshapiro
230290792Sgshapiro/*
230338032Speter**  DENLSTRING -- convert newlines in a string to spaces
230438032Speter**
230538032Speter**	Parameters:
230638032Speter**		s -- the input string
230738032Speter**		strict -- if set, don't permit continuation lines.
230838032Speter**		logattacks -- if set, log attempted attacks.
230938032Speter**
231038032Speter**	Returns:
231138032Speter**		A pointer to a version of the string with newlines
231238032Speter**		mapped to spaces.  This should be copied.
231338032Speter*/
231438032Speter
231538032Speterchar *
231638032Speterdenlstring(s, strict, logattacks)
231738032Speter	char *s;
231838032Speter	bool strict;
231938032Speter	bool logattacks;
232038032Speter{
232138032Speter	register char *p;
232238032Speter	int l;
232338032Speter	static char *bp = NULL;
232438032Speter	static int bl = 0;
232538032Speter
232638032Speter	p = s;
232738032Speter	while ((p = strchr(p, '\n')) != NULL)
232838032Speter		if (strict || (*++p != ' ' && *p != '\t'))
232938032Speter			break;
233038032Speter	if (p == NULL)
233138032Speter		return s;
233238032Speter
233338032Speter	l = strlen(s) + 1;
233438032Speter	if (bl < l)
233538032Speter	{
233638032Speter		/* allocate more space */
233790792Sgshapiro		char *nbp = sm_pmalloc_x(l);
233890792Sgshapiro
233938032Speter		if (bp != NULL)
234077349Sgshapiro			sm_free(bp);
234190792Sgshapiro		bp = nbp;
234238032Speter		bl = l;
234338032Speter	}
234490792Sgshapiro	(void) sm_strlcpy(bp, s, l);
234538032Speter	for (p = bp; (p = strchr(p, '\n')) != NULL; )
234638032Speter		*p++ = ' ';
234738032Speter
234838032Speter	if (logattacks)
234938032Speter	{
2350168515Sgshapiro		sm_syslog(LOG_NOTICE, CurEnv ? CurEnv->e_id : NULL,
235164562Sgshapiro			  "POSSIBLE ATTACK from %.100s: newline in string \"%s\"",
235264562Sgshapiro			  RealHostName == NULL ? "[UNKNOWN]" : RealHostName,
235364562Sgshapiro			  shortenstring(bp, MAXSHORTSTR));
235438032Speter	}
235538032Speter
235638032Speter	return bp;
235738032Speter}
235898841Sgshapiro
235990792Sgshapiro/*
236098841Sgshapiro**  STRREPLNONPRT -- replace "unprintable" characters in a string with subst
236198841Sgshapiro**
236298841Sgshapiro**	Parameters:
236398841Sgshapiro**		s -- string to manipulate (in place)
236498841Sgshapiro**		subst -- character to use as replacement
236598841Sgshapiro**
236698841Sgshapiro**	Returns:
236798841Sgshapiro**		true iff string did not contain "unprintable" characters
236898841Sgshapiro*/
236998841Sgshapiro
237098841Sgshapirobool
237198841Sgshapirostrreplnonprt(s, c)
237298841Sgshapiro	char *s;
237398841Sgshapiro	int c;
237498841Sgshapiro{
237598841Sgshapiro	bool ok;
237698841Sgshapiro
237798841Sgshapiro	ok = true;
237898841Sgshapiro	if (s == NULL)
237998841Sgshapiro		return ok;
238098841Sgshapiro	while (*s != '\0')
238198841Sgshapiro	{
238298841Sgshapiro		if (!(isascii(*s) && isprint(*s)))
238398841Sgshapiro		{
238498841Sgshapiro			*s = c;
238598841Sgshapiro			ok = false;
238698841Sgshapiro		}
238798841Sgshapiro		++s;
238898841Sgshapiro	}
238998841Sgshapiro	return ok;
239098841Sgshapiro}
239198841Sgshapiro
239298841Sgshapiro/*
239338032Speter**  PATH_IS_DIR -- check to see if file exists and is a directory.
239438032Speter**
239538032Speter**	There are some additional checks for security violations in
239638032Speter**	here.  This routine is intended to be used for the host status
239738032Speter**	support.
239838032Speter**
239938032Speter**	Parameters:
240038032Speter**		pathname -- pathname to check for directory-ness.
240138032Speter**		createflag -- if set, create directory if needed.
240238032Speter**
240338032Speter**	Returns:
240490792Sgshapiro**		true -- if the indicated pathname is a directory
240590792Sgshapiro**		false -- otherwise
240638032Speter*/
240738032Speter
2408120256Sgshapirobool
240938032Speterpath_is_dir(pathname, createflag)
241038032Speter	char *pathname;
241138032Speter	bool createflag;
241238032Speter{
241338032Speter	struct stat statbuf;
241438032Speter
241538032Speter#if HASLSTAT
241638032Speter	if (lstat(pathname, &statbuf) < 0)
241764562Sgshapiro#else /* HASLSTAT */
241838032Speter	if (stat(pathname, &statbuf) < 0)
241964562Sgshapiro#endif /* HASLSTAT */
242038032Speter	{
242138032Speter		if (errno != ENOENT || !createflag)
242290792Sgshapiro			return false;
242338032Speter		if (mkdir(pathname, 0755) < 0)
242490792Sgshapiro			return false;
242590792Sgshapiro		return true;
242638032Speter	}
242738032Speter	if (!S_ISDIR(statbuf.st_mode))
242838032Speter	{
242938032Speter		errno = ENOTDIR;
243090792Sgshapiro		return false;
243138032Speter	}
243238032Speter
243338032Speter	/* security: don't allow writable directories */
243438032Speter	if (bitset(S_IWGRP|S_IWOTH, statbuf.st_mode))
243538032Speter	{
243638032Speter		errno = EACCES;
243790792Sgshapiro		return false;
243838032Speter	}
243990792Sgshapiro	return true;
244038032Speter}
2441168515Sgshapiro
244290792Sgshapiro/*
244338032Speter**  PROC_LIST_ADD -- add process id to list of our children
244438032Speter**
244538032Speter**	Parameters:
244638032Speter**		pid -- pid to add to list.
244764562Sgshapiro**		task -- task of pid.
244864562Sgshapiro**		type -- type of process.
244990792Sgshapiro**		count -- number of processes.
245090792Sgshapiro**		other -- other information for this type.
245138032Speter**
245238032Speter**	Returns:
245338032Speter**		none
245490792Sgshapiro**
245590792Sgshapiro**	Side Effects:
245690792Sgshapiro**		May increase CurChildren. May grow ProcList.
245738032Speter*/
245838032Speter
245990792Sgshapirotypedef struct procs	PROCS_T;
246042575Speter
246190792Sgshapirostruct procs
246290792Sgshapiro{
2463132943Sgshapiro	pid_t		proc_pid;
2464132943Sgshapiro	char		*proc_task;
2465132943Sgshapiro	int		proc_type;
2466132943Sgshapiro	int		proc_count;
2467132943Sgshapiro	int		proc_other;
2468132943Sgshapiro	SOCKADDR	proc_hostaddr;
246990792Sgshapiro};
247090792Sgshapiro
247190792Sgshapirostatic PROCS_T	*volatile ProcListVec = NULL;
247290792Sgshapirostatic int	ProcListSize = 0;
247390792Sgshapiro
247438032Spetervoid
2475132943Sgshapiroproc_list_add(pid, task, type, count, other, hostaddr)
247638032Speter	pid_t pid;
247742575Speter	char *task;
247864562Sgshapiro	int type;
247990792Sgshapiro	int count;
248090792Sgshapiro	int other;
2481132943Sgshapiro	SOCKADDR *hostaddr;
248238032Speter{
248338032Speter	int i;
248438032Speter
248538032Speter	for (i = 0; i < ProcListSize; i++)
248638032Speter	{
248742575Speter		if (ProcListVec[i].proc_pid == NO_PID)
248838032Speter			break;
248938032Speter	}
249038032Speter	if (i >= ProcListSize)
249138032Speter	{
249238032Speter		/* probe the existing vector to avoid growing infinitely */
249338032Speter		proc_list_probe();
249438032Speter
249538032Speter		/* now scan again */
249638032Speter		for (i = 0; i < ProcListSize; i++)
249738032Speter		{
249842575Speter			if (ProcListVec[i].proc_pid == NO_PID)
249938032Speter				break;
250038032Speter		}
250138032Speter	}
250238032Speter	if (i >= ProcListSize)
250338032Speter	{
250438032Speter		/* grow process list */
2505168515Sgshapiro		int chldwasblocked;
250690792Sgshapiro		PROCS_T *npv;
250738032Speter
250890792Sgshapiro		SM_ASSERT(ProcListSize < INT_MAX - PROC_LIST_SEG);
2509168515Sgshapiro		npv = (PROCS_T *) sm_pmalloc_x((sizeof(*npv)) *
251090792Sgshapiro					       (ProcListSize + PROC_LIST_SEG));
2511168515Sgshapiro
2512168515Sgshapiro		/* Block SIGCHLD so reapchild() doesn't mess with us */
2513168515Sgshapiro		chldwasblocked = sm_blocksignal(SIGCHLD);
251438032Speter		if (ProcListSize > 0)
251538032Speter		{
251664562Sgshapiro			memmove(npv, ProcListVec,
2517168515Sgshapiro				ProcListSize * sizeof(PROCS_T));
251877349Sgshapiro			sm_free(ProcListVec);
251938032Speter		}
252090792Sgshapiro
252190792Sgshapiro		/* XXX just use memset() to initialize this part? */
252238032Speter		for (i = ProcListSize; i < ProcListSize + PROC_LIST_SEG; i++)
252342575Speter		{
252442575Speter			npv[i].proc_pid = NO_PID;
252542575Speter			npv[i].proc_task = NULL;
252664562Sgshapiro			npv[i].proc_type = PROC_NONE;
252742575Speter		}
252838032Speter		i = ProcListSize;
252938032Speter		ProcListSize += PROC_LIST_SEG;
253038032Speter		ProcListVec = npv;
2531168515Sgshapiro		if (chldwasblocked == 0)
2532168515Sgshapiro			(void) sm_releasesignal(SIGCHLD);
253338032Speter	}
253442575Speter	ProcListVec[i].proc_pid = pid;
253590792Sgshapiro	PSTRSET(ProcListVec[i].proc_task, task);
253664562Sgshapiro	ProcListVec[i].proc_type = type;
253790792Sgshapiro	ProcListVec[i].proc_count = count;
253890792Sgshapiro	ProcListVec[i].proc_other = other;
2539132943Sgshapiro	if (hostaddr != NULL)
2540132943Sgshapiro		ProcListVec[i].proc_hostaddr = *hostaddr;
2541132943Sgshapiro	else
2542132943Sgshapiro		memset(&ProcListVec[i].proc_hostaddr, 0,
2543132943Sgshapiro			sizeof(ProcListVec[i].proc_hostaddr));
254442575Speter
254542575Speter	/* if process adding itself, it's not a child */
254690792Sgshapiro	if (pid != CurrentPid)
254790792Sgshapiro	{
254890792Sgshapiro		SM_ASSERT(CurChildren < INT_MAX);
254942575Speter		CurChildren++;
255090792Sgshapiro	}
255138032Speter}
2552168515Sgshapiro
255390792Sgshapiro/*
255442575Speter**  PROC_LIST_SET -- set pid task in process list
255542575Speter**
255642575Speter**	Parameters:
255742575Speter**		pid -- pid to set
255842575Speter**		task -- task of pid
255942575Speter**
256042575Speter**	Returns:
256142575Speter**		none.
256242575Speter*/
256342575Speter
256442575Spetervoid
256542575Speterproc_list_set(pid, task)
256642575Speter	pid_t pid;
256742575Speter	char *task;
256842575Speter{
256942575Speter	int i;
257042575Speter
257142575Speter	for (i = 0; i < ProcListSize; i++)
257242575Speter	{
257342575Speter		if (ProcListVec[i].proc_pid == pid)
257442575Speter		{
257590792Sgshapiro			PSTRSET(ProcListVec[i].proc_task, task);
257642575Speter			break;
257742575Speter		}
257842575Speter	}
257942575Speter}
2580168515Sgshapiro
258190792Sgshapiro/*
258238032Speter**  PROC_LIST_DROP -- drop pid from process list
258338032Speter**
258438032Speter**	Parameters:
258538032Speter**		pid -- pid to drop
258690792Sgshapiro**		st -- process status
258790792Sgshapiro**		other -- storage for proc_other (return).
258838032Speter**
258938032Speter**	Returns:
259090792Sgshapiro**		none.
259177349Sgshapiro**
259290792Sgshapiro**	Side Effects:
259390792Sgshapiro**		May decrease CurChildren, CurRunners, or
259490792Sgshapiro**		set RestartRequest or ShutdownRequest.
259590792Sgshapiro**
259677349Sgshapiro**	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
259777349Sgshapiro**		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
259877349Sgshapiro**		DOING.
259938032Speter*/
260038032Speter
260190792Sgshapirovoid
260290792Sgshapiroproc_list_drop(pid, st, other)
260338032Speter	pid_t pid;
260490792Sgshapiro	int st;
260590792Sgshapiro	int *other;
260638032Speter{
260738032Speter	int i;
260864562Sgshapiro	int type = PROC_NONE;
260938032Speter
261038032Speter	for (i = 0; i < ProcListSize; i++)
261138032Speter	{
261242575Speter		if (ProcListVec[i].proc_pid == pid)
261338032Speter		{
261442575Speter			ProcListVec[i].proc_pid = NO_PID;
261564562Sgshapiro			type = ProcListVec[i].proc_type;
261690792Sgshapiro			if (other != NULL)
261790792Sgshapiro				*other = ProcListVec[i].proc_other;
2618157001Sgshapiro			if (CurChildren > 0)
2619157001Sgshapiro				CurChildren--;
262038032Speter			break;
262138032Speter		}
262238032Speter	}
262364562Sgshapiro
262464562Sgshapiro
262590792Sgshapiro	if (type == PROC_CONTROL && WIFEXITED(st))
262690792Sgshapiro	{
262790792Sgshapiro		/* if so, see if we need to restart or shutdown */
262890792Sgshapiro		if (WEXITSTATUS(st) == EX_RESTART)
262990792Sgshapiro			RestartRequest = "control socket";
263090792Sgshapiro		else if (WEXITSTATUS(st) == EX_SHUTDOWN)
263190792Sgshapiro			ShutdownRequest = "control socket";
263290792Sgshapiro	}
263390792Sgshapiro	else if (type == PROC_QUEUE_CHILD && !WIFSTOPPED(st) &&
263490792Sgshapiro		 ProcListVec[i].proc_other > -1)
263590792Sgshapiro	{
263690792Sgshapiro		/* restart this persistent runner */
263790792Sgshapiro		mark_work_group_restart(ProcListVec[i].proc_other, st);
263890792Sgshapiro	}
263990792Sgshapiro	else if (type == PROC_QUEUE)
2640244928Sgshapiro	{
264190792Sgshapiro		CurRunners -= ProcListVec[i].proc_count;
2642244928Sgshapiro
2643244928Sgshapiro		/* CHK_CUR_RUNNERS() can't be used here: uses syslog() */
2644244928Sgshapiro		if (CurRunners < 0)
2645244928Sgshapiro			CurRunners = 0;
2646244928Sgshapiro	}
264738032Speter}
2648168515Sgshapiro
264990792Sgshapiro/*
265038032Speter**  PROC_LIST_CLEAR -- clear the process list
265138032Speter**
265238032Speter**	Parameters:
265338032Speter**		none.
265438032Speter**
265538032Speter**	Returns:
265638032Speter**		none.
265790792Sgshapiro**
265890792Sgshapiro**	Side Effects:
265990792Sgshapiro**		Sets CurChildren to zero.
266038032Speter*/
266138032Speter
266238032Spetervoid
266338032Speterproc_list_clear()
266438032Speter{
266538032Speter	int i;
266638032Speter
266742575Speter	/* start from 1 since 0 is the daemon itself */
266842575Speter	for (i = 1; i < ProcListSize; i++)
266942575Speter		ProcListVec[i].proc_pid = NO_PID;
267038032Speter	CurChildren = 0;
267138032Speter}
2672168515Sgshapiro
267390792Sgshapiro/*
267438032Speter**  PROC_LIST_PROBE -- probe processes in the list to see if they still exist
267538032Speter**
267638032Speter**	Parameters:
267738032Speter**		none
267838032Speter**
267938032Speter**	Returns:
268038032Speter**		none
268190792Sgshapiro**
268290792Sgshapiro**	Side Effects:
268390792Sgshapiro**		May decrease CurChildren.
268438032Speter*/
268538032Speter
268638032Spetervoid
268738032Speterproc_list_probe()
268838032Speter{
2689157001Sgshapiro	int i, children;
2690157001Sgshapiro	int chldwasblocked;
2691157001Sgshapiro	pid_t pid;
269238032Speter
2693157001Sgshapiro	children = 0;
2694157001Sgshapiro	chldwasblocked = sm_blocksignal(SIGCHLD);
2695157001Sgshapiro
269642575Speter	/* start from 1 since 0 is the daemon itself */
269742575Speter	for (i = 1; i < ProcListSize; i++)
269838032Speter	{
2699157001Sgshapiro		pid = ProcListVec[i].proc_pid;
2700157001Sgshapiro		if (pid == NO_PID || pid == CurrentPid)
270138032Speter			continue;
2702157001Sgshapiro		if (kill(pid, 0) < 0)
270338032Speter		{
270438032Speter			if (LogLevel > 3)
270538032Speter				sm_syslog(LOG_DEBUG, CurEnv->e_id,
270664562Sgshapiro					  "proc_list_probe: lost pid %d",
270764562Sgshapiro					  (int) ProcListVec[i].proc_pid);
270842575Speter			ProcListVec[i].proc_pid = NO_PID;
270990792Sgshapiro			SM_FREE_CLR(ProcListVec[i].proc_task);
2710244928Sgshapiro
2711244928Sgshapiro			if (ProcListVec[i].proc_type == PROC_QUEUE)
2712244928Sgshapiro			{
2713244928Sgshapiro				CurRunners -= ProcListVec[i].proc_count;
2714244928Sgshapiro				CHK_CUR_RUNNERS("proc_list_probe", i,
2715244928Sgshapiro						ProcListVec[i].proc_count);
2716244928Sgshapiro			}
2717244928Sgshapiro
271838032Speter			CurChildren--;
271938032Speter		}
2720157001Sgshapiro		else
2721157001Sgshapiro		{
2722157001Sgshapiro			++children;
2723157001Sgshapiro		}
272438032Speter	}
272538032Speter	if (CurChildren < 0)
272638032Speter		CurChildren = 0;
2727157001Sgshapiro	if (chldwasblocked == 0)
2728157001Sgshapiro		(void) sm_releasesignal(SIGCHLD);
2729159609Sgshapiro	if (LogLevel > 10 && children != CurChildren && CurrentPid == DaemonPid)
2730157001Sgshapiro	{
2731157001Sgshapiro		sm_syslog(LOG_ERR, NOQID,
2732157001Sgshapiro			  "proc_list_probe: found %d children, expected %d",
2733157001Sgshapiro			  children, CurChildren);
2734157001Sgshapiro	}
273538032Speter}
273690792Sgshapiro
273790792Sgshapiro/*
273842575Speter**  PROC_LIST_DISPLAY -- display the process list
273942575Speter**
274042575Speter**	Parameters:
274142575Speter**		out -- output file pointer
274290792Sgshapiro**		prefix -- string to output in front of each line.
274342575Speter**
274442575Speter**	Returns:
274542575Speter**		none.
274642575Speter*/
274742575Speter
274842575Spetervoid
274990792Sgshapiroproc_list_display(out, prefix)
275090792Sgshapiro	SM_FILE_T *out;
275190792Sgshapiro	char *prefix;
275242575Speter{
275342575Speter	int i;
275442575Speter
275542575Speter	for (i = 0; i < ProcListSize; i++)
275642575Speter	{
275742575Speter		if (ProcListVec[i].proc_pid == NO_PID)
275842575Speter			continue;
275942575Speter
276090792Sgshapiro		(void) sm_io_fprintf(out, SM_TIME_DEFAULT, "%s%d %s%s\n",
276190792Sgshapiro				     prefix,
276290792Sgshapiro				     (int) ProcListVec[i].proc_pid,
276390792Sgshapiro				     ProcListVec[i].proc_task != NULL ?
276490792Sgshapiro				     ProcListVec[i].proc_task : "(unknown)",
276590792Sgshapiro				     (OpMode == MD_SMTP ||
276690792Sgshapiro				      OpMode == MD_DAEMON ||
276790792Sgshapiro				      OpMode == MD_ARPAFTP) ? "\r" : "");
276842575Speter	}
276942575Speter}
277090792Sgshapiro
277190792Sgshapiro/*
277290792Sgshapiro**  PROC_LIST_SIGNAL -- send a signal to a type of process in the list
277380785Sgshapiro**
277480785Sgshapiro**	Parameters:
277590792Sgshapiro**		type -- type of process to signal
277690792Sgshapiro**		signal -- the type of signal to send
277780785Sgshapiro**
277890792Sgshapiro**	Results:
277990792Sgshapiro**		none.
278090792Sgshapiro**
278190792Sgshapiro**	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
278290792Sgshapiro**		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
278390792Sgshapiro**		DOING.
278480785Sgshapiro*/
278580785Sgshapiro
278690792Sgshapirovoid
278790792Sgshapiroproc_list_signal(type, signal)
278890792Sgshapiro	int type;
278990792Sgshapiro	int signal;
279080785Sgshapiro{
279190792Sgshapiro	int chldwasblocked;
279290792Sgshapiro	int alrmwasblocked;
279390792Sgshapiro	int i;
279490792Sgshapiro	pid_t mypid = getpid();
279580785Sgshapiro
279690792Sgshapiro	/* block these signals so that we may signal cleanly */
279790792Sgshapiro	chldwasblocked = sm_blocksignal(SIGCHLD);
279890792Sgshapiro	alrmwasblocked = sm_blocksignal(SIGALRM);
279980785Sgshapiro
280090792Sgshapiro	/* Find all processes of type and send signal */
280190792Sgshapiro	for (i = 0; i < ProcListSize; i++)
280280785Sgshapiro	{
280390792Sgshapiro		if (ProcListVec[i].proc_pid == NO_PID ||
280490792Sgshapiro		    ProcListVec[i].proc_pid == mypid)
280590792Sgshapiro			continue;
280690792Sgshapiro		if (ProcListVec[i].proc_type != type)
280790792Sgshapiro			continue;
280890792Sgshapiro		(void) kill(ProcListVec[i].proc_pid, signal);
280980785Sgshapiro	}
281080785Sgshapiro
281190792Sgshapiro	/* restore the signals */
281290792Sgshapiro	if (alrmwasblocked == 0)
281390792Sgshapiro		(void) sm_releasesignal(SIGALRM);
281490792Sgshapiro	if (chldwasblocked == 0)
281590792Sgshapiro		(void) sm_releasesignal(SIGCHLD);
281680785Sgshapiro}
2817132943Sgshapiro
2818132943Sgshapiro/*
2819132943Sgshapiro**  COUNT_OPEN_CONNECTIONS
2820132943Sgshapiro**
2821132943Sgshapiro**	Parameters:
2822132943Sgshapiro**		hostaddr - ClientAddress
2823132943Sgshapiro**
2824132943Sgshapiro**	Returns:
2825132943Sgshapiro**		the number of open connections for this client
2826132943Sgshapiro**
2827132943Sgshapiro*/
2828132943Sgshapiro
2829132943Sgshapiroint
2830132943Sgshapirocount_open_connections(hostaddr)
2831132943Sgshapiro	SOCKADDR *hostaddr;
2832132943Sgshapiro{
2833132943Sgshapiro	int i, n;
2834132943Sgshapiro
2835132943Sgshapiro	if (hostaddr == NULL)
2836132943Sgshapiro		return 0;
2837173340Sgshapiro
2838173340Sgshapiro	/*
2839182352Sgshapiro	**  This code gets called before proc_list_add() gets called,
2840182352Sgshapiro	**  so we (the daemon child for this connection) have not yet
2841182352Sgshapiro	**  counted ourselves.  Hence initialize the counter to 1
2842182352Sgshapiro	**  instead of 0 to compensate.
2843173340Sgshapiro	*/
2844173340Sgshapiro
2845173340Sgshapiro	n = 1;
2846132943Sgshapiro	for (i = 0; i < ProcListSize; i++)
2847132943Sgshapiro	{
2848132943Sgshapiro		if (ProcListVec[i].proc_pid == NO_PID)
2849132943Sgshapiro			continue;
2850132943Sgshapiro		if (hostaddr->sa.sa_family !=
2851132943Sgshapiro		    ProcListVec[i].proc_hostaddr.sa.sa_family)
2852132943Sgshapiro			continue;
2853132943Sgshapiro#if NETINET
2854132943Sgshapiro		if (hostaddr->sa.sa_family == AF_INET &&
2855132943Sgshapiro		    (hostaddr->sin.sin_addr.s_addr ==
2856132943Sgshapiro		     ProcListVec[i].proc_hostaddr.sin.sin_addr.s_addr))
2857132943Sgshapiro			n++;
2858132943Sgshapiro#endif /* NETINET */
2859132943Sgshapiro#if NETINET6
2860132943Sgshapiro		if (hostaddr->sa.sa_family == AF_INET6 &&
2861132943Sgshapiro		    IN6_ARE_ADDR_EQUAL(&(hostaddr->sin6.sin6_addr),
2862132943Sgshapiro				       &(ProcListVec[i].proc_hostaddr.sin6.sin6_addr)))
2863132943Sgshapiro			n++;
2864132943Sgshapiro#endif /* NETINET6 */
2865132943Sgshapiro	}
2866132943Sgshapiro	return n;
2867132943Sgshapiro}
2868244928Sgshapiro
2869