xref: /csrg-svn/usr.sbin/sendmail/src/util.c (revision 66004)
122717Sdist /*
242833Sbostic  * Copyright (c) 1983 Eric P. Allman
363589Sbostic  * Copyright (c) 1988, 1993
463589Sbostic  *	The Regents of the University of California.  All rights reserved.
533731Sbostic  *
642833Sbostic  * %sccs.include.redist.c%
733731Sbostic  */
822717Sdist 
922717Sdist #ifndef lint
10*66004Seric static char sccsid[] = "@(#)util.c	8.30 (Berkeley) 02/05/94";
1133731Sbostic #endif /* not lint */
1222717Sdist 
1358332Seric # include "sendmail.h"
14298Seric # include <sysexits.h>
1557135Seric /*
16298Seric **  STRIPQUOTES -- Strip quotes & quote bits from a string.
17298Seric **
18298Seric **	Runs through a string and strips off unquoted quote
19298Seric **	characters and quote bits.  This is done in place.
20298Seric **
21298Seric **	Parameters:
22298Seric **		s -- the string to strip.
23298Seric **
24298Seric **	Returns:
25298Seric **		none.
26298Seric **
27298Seric **	Side Effects:
28298Seric **		none.
29298Seric **
30298Seric **	Called By:
31298Seric **		deliver
32298Seric */
33298Seric 
3454983Seric stripquotes(s)
35298Seric 	char *s;
36298Seric {
37298Seric 	register char *p;
38298Seric 	register char *q;
39298Seric 	register char c;
40298Seric 
414101Seric 	if (s == NULL)
424101Seric 		return;
434101Seric 
4454983Seric 	p = q = s;
4554983Seric 	do
46298Seric 	{
4754983Seric 		c = *p++;
4854983Seric 		if (c == '\\')
4954983Seric 			c = *p++;
5054983Seric 		else if (c == '"')
5154983Seric 			continue;
5254983Seric 		*q++ = c;
5354983Seric 	} while (c != '\0');
54298Seric }
55298Seric /*
56298Seric **  XALLOC -- Allocate memory and bitch wildly on failure.
57298Seric **
58298Seric **	THIS IS A CLUDGE.  This should be made to give a proper
59298Seric **	error -- but after all, what can we do?
60298Seric **
61298Seric **	Parameters:
62298Seric **		sz -- size of area to allocate.
63298Seric **
64298Seric **	Returns:
65298Seric **		pointer to data region.
66298Seric **
67298Seric **	Side Effects:
68298Seric **		Memory is allocated.
69298Seric */
70298Seric 
71298Seric char *
72298Seric xalloc(sz)
737007Seric 	register int sz;
74298Seric {
75298Seric 	register char *p;
76298Seric 
7723121Seric 	p = malloc((unsigned) sz);
78298Seric 	if (p == NULL)
79298Seric 	{
80298Seric 		syserr("Out of memory!!");
8110685Seric 		abort();
8210685Seric 		/* exit(EX_UNAVAILABLE); */
83298Seric 	}
84298Seric 	return (p);
85298Seric }
86298Seric /*
873151Seric **  COPYPLIST -- copy list of pointers.
883151Seric **
893151Seric **	This routine is the equivalent of newstr for lists of
903151Seric **	pointers.
913151Seric **
923151Seric **	Parameters:
933151Seric **		list -- list of pointers to copy.
943151Seric **			Must be NULL terminated.
953151Seric **		copycont -- if TRUE, copy the contents of the vector
963151Seric **			(which must be a string) also.
973151Seric **
983151Seric **	Returns:
993151Seric **		a copy of 'list'.
1003151Seric **
1013151Seric **	Side Effects:
1023151Seric **		none.
1033151Seric */
1043151Seric 
1053151Seric char **
1063151Seric copyplist(list, copycont)
1073151Seric 	char **list;
1083151Seric 	bool copycont;
1093151Seric {
1103151Seric 	register char **vp;
1113151Seric 	register char **newvp;
1123151Seric 
1133151Seric 	for (vp = list; *vp != NULL; vp++)
1143151Seric 		continue;
1153151Seric 
1163151Seric 	vp++;
1173151Seric 
11816897Seric 	newvp = (char **) xalloc((int) (vp - list) * sizeof *vp);
11916897Seric 	bcopy((char *) list, (char *) newvp, (int) (vp - list) * sizeof *vp);
1203151Seric 
1213151Seric 	if (copycont)
1223151Seric 	{
1233151Seric 		for (vp = newvp; *vp != NULL; vp++)
1243151Seric 			*vp = newstr(*vp);
1253151Seric 	}
1263151Seric 
1273151Seric 	return (newvp);
1283151Seric }
1293151Seric /*
13058170Seric **  COPYQUEUE -- copy address queue.
13158170Seric **
13258170Seric **	This routine is the equivalent of newstr for address queues
13358170Seric **	addresses marked with QDONTSEND aren't copied
13458170Seric **
13558170Seric **	Parameters:
13658170Seric **		addr -- list of address structures to copy.
13758170Seric **
13858170Seric **	Returns:
13958170Seric **		a copy of 'addr'.
14058170Seric **
14158170Seric **	Side Effects:
14258170Seric **		none.
14358170Seric */
14458170Seric 
14558170Seric ADDRESS *
14658170Seric copyqueue(addr)
14758170Seric 	ADDRESS *addr;
14858170Seric {
14958170Seric 	register ADDRESS *newaddr;
15058170Seric 	ADDRESS *ret;
15158170Seric 	register ADDRESS **tail = &ret;
15258170Seric 
15358170Seric 	while (addr != NULL)
15458170Seric 	{
15558170Seric 		if (!bitset(QDONTSEND, addr->q_flags))
15658170Seric 		{
15758170Seric 			newaddr = (ADDRESS *) xalloc(sizeof(ADDRESS));
15858170Seric 			STRUCTCOPY(*addr, *newaddr);
15958170Seric 			*tail = newaddr;
16058170Seric 			tail = &newaddr->q_next;
16158170Seric 		}
16258170Seric 		addr = addr->q_next;
16358170Seric 	}
16458170Seric 	*tail = NULL;
16558170Seric 
16658170Seric 	return ret;
16758170Seric }
16858170Seric /*
1693151Seric **  PRINTAV -- print argument vector.
1703151Seric **
1713151Seric **	Parameters:
1723151Seric **		av -- argument vector.
1733151Seric **
1743151Seric **	Returns:
1753151Seric **		none.
1763151Seric **
1773151Seric **	Side Effects:
1783151Seric **		prints av.
1793151Seric */
1803151Seric 
1813151Seric printav(av)
1823151Seric 	register char **av;
1833151Seric {
1843151Seric 	while (*av != NULL)
1853151Seric 	{
1868063Seric 		if (tTd(0, 44))
1878063Seric 			printf("\n\t%08x=", *av);
1888063Seric 		else
18923105Seric 			(void) putchar(' ');
1903151Seric 		xputs(*av++);
1913151Seric 	}
19223105Seric 	(void) putchar('\n');
1933151Seric }
1943151Seric /*
1953151Seric **  LOWER -- turn letter into lower case.
1963151Seric **
1973151Seric **	Parameters:
1983151Seric **		c -- character to turn into lower case.
1993151Seric **
2003151Seric **	Returns:
2013151Seric **		c, in lower case.
2023151Seric **
2033151Seric **	Side Effects:
2043151Seric **		none.
2053151Seric */
2063151Seric 
2073151Seric char
2083151Seric lower(c)
2093151Seric 	register char c;
2103151Seric {
21158050Seric 	return((isascii(c) && isupper(c)) ? tolower(c) : c);
2123151Seric }
2133151Seric /*
2143151Seric **  XPUTS -- put string doing control escapes.
2153151Seric **
2163151Seric **	Parameters:
2173151Seric **		s -- string to put.
2183151Seric **
2193151Seric **	Returns:
2203151Seric **		none.
2213151Seric **
2223151Seric **	Side Effects:
2233151Seric **		output to stdout
2243151Seric */
2253151Seric 
2263151Seric xputs(s)
2273151Seric 	register char *s;
2283151Seric {
22958050Seric 	register int c;
23051781Seric 	register struct metamac *mp;
23151781Seric 	extern struct metamac MetaMacros[];
2323151Seric 
2338055Seric 	if (s == NULL)
2348055Seric 	{
2358055Seric 		printf("<null>");
2368055Seric 		return;
2378055Seric 	}
23858050Seric 	while ((c = (*s++ & 0377)) != '\0')
2393151Seric 	{
2403151Seric 		if (!isascii(c))
2413151Seric 		{
24258050Seric 			if (c == MATCHREPL || c == MACROEXPAND)
24358050Seric 			{
24458050Seric 				putchar('$');
24558050Seric 				continue;
24658050Seric 			}
24758050Seric 			for (mp = MetaMacros; mp->metaname != '\0'; mp++)
24858050Seric 			{
24958050Seric 				if ((mp->metaval & 0377) == c)
25058050Seric 				{
25158050Seric 					printf("$%c", mp->metaname);
25258050Seric 					break;
25358050Seric 				}
25458050Seric 			}
25558050Seric 			if (mp->metaname != '\0')
25658050Seric 				continue;
25723105Seric 			(void) putchar('\\');
2583151Seric 			c &= 0177;
2593151Seric 		}
26057589Seric 		if (isprint(c))
2613151Seric 		{
26257589Seric 			putchar(c);
26357589Seric 			continue;
26457589Seric 		}
26552050Seric 
26657589Seric 		/* wasn't a meta-macro -- find another way to print it */
26757589Seric 		switch (c)
26857589Seric 		{
26957589Seric 		  case '\0':
27057589Seric 			continue;
27152050Seric 
27257589Seric 		  case '\n':
27357589Seric 			c = 'n';
27457589Seric 			break;
27552050Seric 
27657589Seric 		  case '\r':
27757589Seric 			c = 'r';
27857589Seric 			break;
27952637Seric 
28057589Seric 		  case '\t':
28157589Seric 			c = 't';
28257589Seric 			break;
28357589Seric 
28457589Seric 		  default:
28557589Seric 			(void) putchar('^');
28657589Seric 			(void) putchar(c ^ 0100);
28757589Seric 			continue;
2883151Seric 		}
2893151Seric 	}
2904086Seric 	(void) fflush(stdout);
2913151Seric }
2923151Seric /*
2933151Seric **  MAKELOWER -- Translate a line into lower case
2943151Seric **
2953151Seric **	Parameters:
2963151Seric **		p -- the string to translate.  If NULL, return is
2973151Seric **			immediate.
2983151Seric **
2993151Seric **	Returns:
3003151Seric **		none.
3013151Seric **
3023151Seric **	Side Effects:
3033151Seric **		String pointed to by p is translated to lower case.
3043151Seric **
3053151Seric **	Called By:
3063151Seric **		parse
3073151Seric */
3083151Seric 
3093151Seric makelower(p)
3103151Seric 	register char *p;
3113151Seric {
3123151Seric 	register char c;
3133151Seric 
3143151Seric 	if (p == NULL)
3153151Seric 		return;
3163151Seric 	for (; (c = *p) != '\0'; p++)
3173151Seric 		if (isascii(c) && isupper(c))
31833724Sbostic 			*p = tolower(c);
3193151Seric }
3204059Seric /*
3215196Seric **  BUILDFNAME -- build full name from gecos style entry.
3224375Seric **
3235196Seric **	This routine interprets the strange entry that would appear
3245196Seric **	in the GECOS field of the password file.
3255196Seric **
3264375Seric **	Parameters:
3275196Seric **		p -- name to build.
3285196Seric **		login -- the login name of this user (for &).
3295196Seric **		buf -- place to put the result.
3304375Seric **
3314375Seric **	Returns:
33265006Seric **		none.
3334375Seric **
3344375Seric **	Side Effects:
3354375Seric **		none.
3364375Seric */
3374375Seric 
33854984Seric buildfname(gecos, login, buf)
33965006Seric 	register char *gecos;
34065006Seric 	char *login;
34165006Seric 	char *buf;
3424375Seric {
34365006Seric 	register char *p;
34465006Seric 	register char *bp = buf;
34565006Seric 	int l;
3464375Seric 
34765006Seric 	if (*gecos == '*')
34865006Seric 		gecos++;
34965006Seric 
35065006Seric 	/* find length of final string */
35165006Seric 	l = 0;
35265006Seric 	for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++)
35354984Seric 	{
35465006Seric 		if (*p == '&')
35565006Seric 			l += strlen(login);
35665006Seric 		else
35765006Seric 			l++;
35854984Seric 	}
35965006Seric 
36065006Seric 	/* now fill in buf */
36165006Seric 	for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++)
3624375Seric 	{
36365006Seric 		if (*p == '&')
3644375Seric 		{
36565006Seric 			(void) strcpy(bp, login);
36665006Seric 			*bp = toupper(*bp);
36765006Seric 			while (*bp != '\0')
36865006Seric 				bp++;
3694375Seric 		}
37065006Seric 		else
37165006Seric 			*bp++ = *p;
3724375Seric 	}
3734375Seric 	*bp = '\0';
3744375Seric }
3754375Seric /*
3764538Seric **  SAFEFILE -- return true if a file exists and is safe for a user.
3774538Seric **
3784538Seric **	Parameters:
3794538Seric **		fn -- filename to check.
38064083Seric **		uid -- user id to compare against.
38164083Seric **		gid -- group id to compare against.
38264083Seric **		uname -- user name to compare against (used for group
38364083Seric **			sets).
38464944Seric **		flags -- modifiers:
38565064Seric **			SFF_MUSTOWN -- "uid" must own this file.
38665064Seric **			SFF_NOSLINK -- file cannot be a symbolic link.
3874538Seric **		mode -- mode bits that must match.
3884538Seric **
3894538Seric **	Returns:
39058247Seric **		0 if fn exists, is owned by uid, and matches mode.
39158247Seric **		An errno otherwise.  The actual errno is cleared.
3924538Seric **
3934538Seric **	Side Effects:
3944538Seric **		none.
3954538Seric */
3964538Seric 
39764083Seric #include <grp.h>
39864083Seric 
39963581Seric #ifndef S_IXOTH
40063581Seric # define S_IXOTH	(S_IEXEC >> 6)
40163581Seric #endif
40263581Seric 
40364083Seric #ifndef S_IXGRP
40464083Seric # define S_IXGRP	(S_IEXEC >> 3)
40564083Seric #endif
40664083Seric 
40763753Seric #ifndef S_IXUSR
40863753Seric # define S_IXUSR	(S_IEXEC)
40963753Seric #endif
41063753Seric 
41158247Seric int
41264944Seric safefile(fn, uid, gid, uname, flags, mode)
4134538Seric 	char *fn;
41455372Seric 	uid_t uid;
41564083Seric 	gid_t gid;
41664083Seric 	char *uname;
41764944Seric 	int flags;
4184538Seric 	int mode;
4194538Seric {
42063581Seric 	register char *p;
42164083Seric 	register struct group *gr = NULL;
4224538Seric 	struct stat stbuf;
4234538Seric 
42463581Seric 	if (tTd(54, 4))
42564944Seric 		printf("safefile(%s, uid=%d, gid=%d, flags=%x, mode=%o):\n",
42664944Seric 			fn, uid, gid, flags, mode);
42763581Seric 	errno = 0;
42863581Seric 
42963581Seric 	for (p = fn; (p = strchr(++p, '/')) != NULL; *p = '/')
43063581Seric 	{
43163581Seric 		*p = '\0';
43264083Seric 		if (stat(fn, &stbuf) < 0)
43364083Seric 			break;
43465225Seric 		if (uid == 0 && !bitset(SFF_ROOTOK, flags))
43565225Seric 		{
43665225Seric 			if (bitset(S_IXOTH, stbuf.st_mode))
43765225Seric 				continue;
43865225Seric 			break;
43965225Seric 		}
44064362Seric 		if (stbuf.st_uid == uid && bitset(S_IXUSR, stbuf.st_mode))
44164362Seric 			continue;
44264083Seric 		if (stbuf.st_gid == gid && bitset(S_IXGRP, stbuf.st_mode))
44364083Seric 			continue;
44464084Seric #ifndef NO_GROUP_SET
44564083Seric 		if (uname != NULL &&
44664083Seric 		    ((gr != NULL && gr->gr_gid == stbuf.st_gid) ||
44764083Seric 		     (gr = getgrgid(stbuf.st_gid)) != NULL))
44863581Seric 		{
44964083Seric 			register char **gp;
45063581Seric 
45164083Seric 			for (gp = gr->gr_mem; *gp != NULL; gp++)
45264083Seric 				if (strcmp(*gp, uname) == 0)
45364083Seric 					break;
45464362Seric 			if (*gp != NULL && bitset(S_IXGRP, stbuf.st_mode))
45564362Seric 				continue;
45663581Seric 		}
45764084Seric #endif
45864083Seric 		if (!bitset(S_IXOTH, stbuf.st_mode))
45964083Seric 			break;
46063581Seric 	}
46164083Seric 	if (p != NULL)
46264083Seric 	{
46364083Seric 		int ret = errno;
46463581Seric 
46564083Seric 		if (ret == 0)
46664083Seric 			ret = EACCES;
46764083Seric 		if (tTd(54, 4))
46864083Seric 			printf("\t[dir %s] %s\n", fn, errstring(ret));
46964083Seric 		*p = '/';
47064083Seric 		return ret;
47164083Seric 	}
47264083Seric 
47364944Seric #ifdef HASLSTAT
47465064Seric 	if ((bitset(SFF_NOSLINK, flags) ? lstat(fn, &stbuf)
47565064Seric 					: stat(fn, &stbuf)) < 0)
47664944Seric #else
47758247Seric 	if (stat(fn, &stbuf) < 0)
47864944Seric #endif
47958247Seric 	{
48058247Seric 		int ret = errno;
48158247Seric 
48263581Seric 		if (tTd(54, 4))
48364083Seric 			printf("\t%s\n", errstring(ret));
48463581Seric 
48558247Seric 		errno = 0;
48658247Seric 		return ret;
48758247Seric 	}
48864944Seric 
48964944Seric #ifdef S_ISLNK
49065064Seric 	if (bitset(SFF_NOSLINK, flags) && S_ISLNK(stbuf.st_mode))
49164944Seric 	{
49264944Seric 		if (tTd(54, 4))
49365123Seric 			printf("\t[slink mode %o]\tEPERM\n", stbuf.st_mode);
49464944Seric 		return EPERM;
49564944Seric 	}
49664944Seric #endif
49764944Seric 
49865139Seric 	if (uid == 0 && !bitset(SFF_ROOTOK, flags))
49963581Seric 		mode >>= 6;
50064084Seric 	else if (stbuf.st_uid != uid)
50164084Seric 	{
50264084Seric 		mode >>= 3;
50364084Seric 		if (stbuf.st_gid == gid)
50464084Seric 			;
50564084Seric #ifndef NO_GROUP_SET
50664084Seric 		else if (uname != NULL &&
50764084Seric 			 ((gr != NULL && gr->gr_gid == stbuf.st_gid) ||
50864084Seric 			  (gr = getgrgid(stbuf.st_gid)) != NULL))
50964084Seric 		{
51064084Seric 			register char **gp;
51164084Seric 
51264084Seric 			for (gp = gr->gr_mem; *gp != NULL; gp++)
51364084Seric 				if (strcmp(*gp, uname) == 0)
51464084Seric 					break;
51564084Seric 			if (*gp == NULL)
51664084Seric 				mode >>= 3;
51764084Seric 		}
51864084Seric #endif
51964084Seric 		else
52064084Seric 			mode >>= 3;
52164084Seric 	}
52263581Seric 	if (tTd(54, 4))
52364084Seric 		printf("\t[uid %d, stat %o, mode %o] ",
52464084Seric 			stbuf.st_uid, stbuf.st_mode, mode);
52564944Seric 	if ((stbuf.st_uid == uid || stbuf.st_uid == 0 ||
52665064Seric 	     !bitset(SFF_MUSTOWN, flags)) &&
52763581Seric 	    (stbuf.st_mode & mode) == mode)
52863581Seric 	{
52963581Seric 		if (tTd(54, 4))
53064083Seric 			printf("\tOK\n");
53158247Seric 		return 0;
53263581Seric 	}
53363581Seric 	if (tTd(54, 4))
53464083Seric 		printf("\tEACCES\n");
53563581Seric 	return EACCES;
5364538Seric }
5374538Seric /*
5384557Seric **  FIXCRLF -- fix <CR><LF> in line.
5394557Seric **
5404557Seric **	Looks for the <CR><LF> combination and turns it into the
5414557Seric **	UNIX canonical <NL> character.  It only takes one line,
5424557Seric **	i.e., it is assumed that the first <NL> found is the end
5434557Seric **	of the line.
5444557Seric **
5454557Seric **	Parameters:
5464557Seric **		line -- the line to fix.
5474557Seric **		stripnl -- if true, strip the newline also.
5484557Seric **
5494557Seric **	Returns:
5504557Seric **		none.
5514557Seric **
5524557Seric **	Side Effects:
5534557Seric **		line is changed in place.
5544557Seric */
5554557Seric 
5564557Seric fixcrlf(line, stripnl)
5574557Seric 	char *line;
5584557Seric 	bool stripnl;
5594557Seric {
5604557Seric 	register char *p;
5614557Seric 
56256795Seric 	p = strchr(line, '\n');
5634557Seric 	if (p == NULL)
5644557Seric 		return;
56536291Sbostic 	if (p > line && p[-1] == '\r')
5664557Seric 		p--;
5674557Seric 	if (!stripnl)
5684557Seric 		*p++ = '\n';
5694557Seric 	*p = '\0';
5704557Seric }
5714557Seric /*
5726890Seric **  DFOPEN -- determined file open
5736890Seric **
5746890Seric **	This routine has the semantics of fopen, except that it will
5756890Seric **	keep trying a few times to make this happen.  The idea is that
5766890Seric **	on very loaded systems, we may run out of resources (inodes,
5776890Seric **	whatever), so this tries to get around it.
5786890Seric */
5796890Seric 
58063753Seric #ifndef O_ACCMODE
58163753Seric # define O_ACCMODE	(O_RDONLY|O_WRONLY|O_RDWR)
58263753Seric #endif
58363753Seric 
58459745Seric struct omodes
58559745Seric {
58659745Seric 	int	mask;
58759745Seric 	int	mode;
58859745Seric 	char	*farg;
58959745Seric } OpenModes[] =
59059745Seric {
59159745Seric 	O_ACCMODE,		O_RDONLY,		"r",
59259745Seric 	O_ACCMODE|O_APPEND,	O_WRONLY,		"w",
59359745Seric 	O_ACCMODE|O_APPEND,	O_WRONLY|O_APPEND,	"a",
59459745Seric 	O_TRUNC,		0,			"w+",
59559745Seric 	O_APPEND,		O_APPEND,		"a+",
59659745Seric 	0,			0,			"r+",
59759745Seric };
59859745Seric 
5996890Seric FILE *
60059745Seric dfopen(filename, omode, cmode)
6016890Seric 	char *filename;
60259745Seric 	int omode;
60359745Seric 	int cmode;
6046890Seric {
6056890Seric 	register int tries;
60659745Seric 	int fd;
60759745Seric 	register struct omodes *om;
60859431Seric 	struct stat st;
6096890Seric 
61059745Seric 	for (om = OpenModes; om->mask != 0; om++)
61159745Seric 		if ((omode & om->mask) == om->mode)
61259745Seric 			break;
61359745Seric 
6146890Seric 	for (tries = 0; tries < 10; tries++)
6156890Seric 	{
61625618Seric 		sleep((unsigned) (10 * tries));
6176890Seric 		errno = 0;
61859745Seric 		fd = open(filename, omode, cmode);
61959745Seric 		if (fd >= 0)
6206890Seric 			break;
6219376Seric 		if (errno != ENFILE && errno != EINTR)
6229376Seric 			break;
6236890Seric 	}
62459745Seric 	if (fd >= 0 && fstat(fd, &st) >= 0 && S_ISREG(st.st_mode))
62556328Seric 	{
62656328Seric 		int locktype;
62756328Seric 
62856328Seric 		/* lock the file to avoid accidental conflicts */
62959745Seric 		if ((omode & O_ACCMODE) != O_RDONLY)
63056328Seric 			locktype = LOCK_EX;
63156328Seric 		else
63256328Seric 			locktype = LOCK_SH;
63364335Seric 		(void) lockfile(fd, filename, NULL, locktype);
63456328Seric 		errno = 0;
63556328Seric 	}
63663787Seric 	if (fd < 0)
63763787Seric 		return NULL;
63863787Seric 	else
63963787Seric 		return fdopen(fd, om->farg);
6406890Seric }
6417124Seric /*
6427124Seric **  PUTLINE -- put a line like fputs obeying SMTP conventions
6437124Seric **
6447753Seric **	This routine always guarantees outputing a newline (or CRLF,
6457753Seric **	as appropriate) at the end of the string.
6467753Seric **
6477124Seric **	Parameters:
6487124Seric **		l -- line to put.
64965870Seric **		mci -- the mailer connection information.
6507124Seric **
6517124Seric **	Returns:
6527124Seric **		none
6537124Seric **
6547124Seric **	Side Effects:
6557124Seric **		output of l to fp.
6567124Seric */
6577124Seric 
65865870Seric putline(l, mci)
6597753Seric 	register char *l;
66065870Seric 	register MCI *mci;
6617124Seric {
6627124Seric 	register char *p;
66347157Sbostic 	register char svchar;
664*66004Seric 	int slop = 0;
6657124Seric 
66611275Seric 	/* strip out 0200 bits -- these can look like TELNET protocol */
66765870Seric 	if (bitset(MCIF_7BIT, mci->mci_flags))
66811275Seric 	{
66961707Seric 		for (p = l; (svchar = *p) != '\0'; ++p)
67061707Seric 			if (bitset(0200, svchar))
67147157Sbostic 				*p = svchar &~ 0200;
67211275Seric 	}
67311275Seric 
6747753Seric 	do
6757124Seric 	{
6767753Seric 		/* find the end of the line */
67756795Seric 		p = strchr(l, '\n');
6787753Seric 		if (p == NULL)
6797753Seric 			p = &l[strlen(l)];
6807124Seric 
68163753Seric 		if (TrafficLogFile != NULL)
68263753Seric 			fprintf(TrafficLogFile, "%05d >>> ", getpid());
68363753Seric 
6847753Seric 		/* check for line overflow */
68565870Seric 		while (mci->mci_mailer->m_linelimit > 0 &&
686*66004Seric 		       (p - l + slop) > mci->mci_mailer->m_linelimit)
6877753Seric 		{
688*66004Seric 			register char *q = &l[mci->mci_mailer->m_linelimit - slop - 1];
6897124Seric 
6907753Seric 			svchar = *q;
6917753Seric 			*q = '\0';
692*66004Seric 			if (l[0] == '.' && slop == 0 &&
693*66004Seric 			    bitnset(M_XDOT, mci->mci_mailer->m_flags))
69463753Seric 			{
69565870Seric 				(void) putc('.', mci->mci_out);
69663753Seric 				if (TrafficLogFile != NULL)
69763753Seric 					(void) putc('.', TrafficLogFile);
69863753Seric 			}
69965870Seric 			fputs(l, mci->mci_out);
70065870Seric 			(void) putc('!', mci->mci_out);
70165870Seric 			fputs(mci->mci_mailer->m_eol, mci->mci_out);
702*66004Seric 			(void) putc(' ', mci->mci_out);
70363753Seric 			if (TrafficLogFile != NULL)
704*66004Seric 				fprintf(TrafficLogFile, "%s!\n%05d >>>  ",
70563753Seric 					l, getpid());
7067753Seric 			*q = svchar;
7077753Seric 			l = q;
708*66004Seric 			slop = 1;
7097753Seric 		}
7107124Seric 
7117753Seric 		/* output last part */
712*66004Seric 		if (l[0] == '.' && slop == 0 &&
713*66004Seric 		    bitnset(M_XDOT, mci->mci_mailer->m_flags))
71463753Seric 		{
71565870Seric 			(void) putc('.', mci->mci_out);
71663753Seric 			if (TrafficLogFile != NULL)
71763753Seric 				(void) putc('.', TrafficLogFile);
71863753Seric 		}
71963753Seric 		if (TrafficLogFile != NULL)
72063753Seric 			fprintf(TrafficLogFile, "%.*s\n", p - l, l);
72147157Sbostic 		for ( ; l < p; ++l)
72265870Seric 			(void) putc(*l, mci->mci_out);
72365870Seric 		fputs(mci->mci_mailer->m_eol, mci->mci_out);
7247753Seric 		if (*l == '\n')
72547157Sbostic 			++l;
7267753Seric 	} while (l[0] != '\0');
7277124Seric }
7287676Seric /*
7297676Seric **  XUNLINK -- unlink a file, doing logging as appropriate.
7307676Seric **
7317676Seric **	Parameters:
7327676Seric **		f -- name of file to unlink.
7337676Seric **
7347676Seric **	Returns:
7357676Seric **		none.
7367676Seric **
7377676Seric **	Side Effects:
7387676Seric **		f is unlinked.
7397676Seric */
7407676Seric 
7417676Seric xunlink(f)
7427676Seric 	char *f;
7437676Seric {
7447676Seric 	register int i;
7457676Seric 
7467676Seric # ifdef LOG
74758020Seric 	if (LogLevel > 98)
74858020Seric 		syslog(LOG_DEBUG, "%s: unlink %s", CurEnv->e_id, f);
74956795Seric # endif /* LOG */
7507676Seric 
7517676Seric 	i = unlink(f);
7527676Seric # ifdef LOG
75358020Seric 	if (i < 0 && LogLevel > 97)
7547942Seric 		syslog(LOG_DEBUG, "%s: unlink-fail %d", f, errno);
75556795Seric # endif /* LOG */
7567676Seric }
7577685Seric /*
75858680Seric **  XFCLOSE -- close a file, doing logging as appropriate.
75958680Seric **
76058680Seric **	Parameters:
76158680Seric **		fp -- file pointer for the file to close
76258680Seric **		a, b -- miscellaneous crud to print for debugging
76358680Seric **
76458680Seric **	Returns:
76558680Seric **		none.
76658680Seric **
76758680Seric **	Side Effects:
76858680Seric **		fp is closed.
76958680Seric */
77058680Seric 
77158680Seric xfclose(fp, a, b)
77258680Seric 	FILE *fp;
77358680Seric 	char *a, *b;
77458680Seric {
77558796Seric 	if (tTd(53, 99))
77658680Seric 		printf("xfclose(%x) %s %s\n", fp, a, b);
77764401Seric #ifdef XDEBUG
77864401Seric 	if (fileno(fp) == 1)
77964401Seric 		syserr("xfclose(%s %s): fd = 1", a, b);
78064401Seric #endif
78158796Seric 	if (fclose(fp) < 0 && tTd(53, 99))
78258680Seric 		printf("xfclose FAILURE: %s\n", errstring(errno));
78358680Seric }
78458680Seric /*
78514885Seric **  SFGETS -- "safe" fgets -- times out and ignores random interrupts.
7867685Seric **
7877685Seric **	Parameters:
7887685Seric **		buf -- place to put the input line.
7897685Seric **		siz -- size of buf.
7907685Seric **		fp -- file to read from.
79157384Seric **		timeout -- the timeout before error occurs.
79261093Seric **		during -- what we are trying to read (for error messages).
7937685Seric **
7947685Seric **	Returns:
79515533Seric **		NULL on error (including timeout).  This will also leave
79615533Seric **			buf containing a null string.
7977685Seric **		buf otherwise.
7987685Seric **
7997685Seric **	Side Effects:
8007685Seric **		none.
8017685Seric */
8027685Seric 
80314885Seric static jmp_buf	CtxReadTimeout;
80463937Seric static int	readtimeout();
8057685Seric 
8067685Seric char *
80761093Seric sfgets(buf, siz, fp, timeout, during)
8087685Seric 	char *buf;
8097685Seric 	int siz;
8107685Seric 	FILE *fp;
81157384Seric 	time_t timeout;
81261093Seric 	char *during;
8137685Seric {
8147942Seric 	register EVENT *ev = NULL;
8157685Seric 	register char *p;
8167685Seric 
81714885Seric 	/* set the timeout */
81857384Seric 	if (timeout != 0)
81914885Seric 	{
82014885Seric 		if (setjmp(CtxReadTimeout) != 0)
82114885Seric 		{
82236233Skarels # ifdef LOG
82336230Skarels 			syslog(LOG_NOTICE,
82461093Seric 			    "timeout waiting for input from %s during %s\n",
82561093Seric 			    CurHostName? CurHostName: "local", during);
82636233Skarels # endif
82736230Skarels 			errno = 0;
82861093Seric 			usrerr("451 timeout waiting for input during %s",
82961093Seric 				during);
83019037Seric 			buf[0] = '\0';
83163753Seric #ifdef XDEBUG
83263753Seric 			checkfd012(during);
83363753Seric #endif
83414885Seric 			return (NULL);
83514885Seric 		}
83657384Seric 		ev = setevent(timeout, readtimeout, 0);
83714885Seric 	}
83814885Seric 
83914885Seric 	/* try to read */
84015533Seric 	p = NULL;
84165190Seric 	while (!feof(fp) && !ferror(fp))
8427942Seric 	{
8437942Seric 		errno = 0;
8447942Seric 		p = fgets(buf, siz, fp);
84565190Seric 		if (p != NULL || errno != EINTR)
84665186Seric 			break;
84765190Seric 		clearerr(fp);
84815533Seric 	}
84914885Seric 
85014885Seric 	/* clear the event if it has not sprung */
8517685Seric 	clrevent(ev);
85214885Seric 
85314885Seric 	/* clean up the books and exit */
8548055Seric 	LineNumber++;
85515533Seric 	if (p == NULL)
85616880Seric 	{
85715533Seric 		buf[0] = '\0';
85863753Seric 		if (TrafficLogFile != NULL)
85963753Seric 			fprintf(TrafficLogFile, "%05d <<< [EOF]\n", getpid());
86016880Seric 		return (NULL);
86116880Seric 	}
86263753Seric 	if (TrafficLogFile != NULL)
86363753Seric 		fprintf(TrafficLogFile, "%05d <<< %s", getpid(), buf);
86459709Seric 	if (SevenBit)
86552106Seric 		for (p = buf; *p != '\0'; p++)
86652106Seric 			*p &= ~0200;
86716880Seric 	return (buf);
8687685Seric }
8697685Seric 
8707685Seric static
8717685Seric readtimeout()
8727685Seric {
87314885Seric 	longjmp(CtxReadTimeout, 1);
8747685Seric }
8757786Seric /*
8767786Seric **  FGETFOLDED -- like fgets, but know about folded lines.
8777786Seric **
8787786Seric **	Parameters:
8797786Seric **		buf -- place to put result.
8807786Seric **		n -- bytes available.
8817786Seric **		f -- file to read from.
8827786Seric **
8837786Seric **	Returns:
88457135Seric **		input line(s) on success, NULL on error or EOF.
88557135Seric **		This will normally be buf -- unless the line is too
88657135Seric **			long, when it will be xalloc()ed.
8877786Seric **
8887786Seric **	Side Effects:
8897786Seric **		buf gets lines from f, with continuation lines (lines
8907786Seric **		with leading white space) appended.  CRLF's are mapped
8917786Seric **		into single newlines.  Any trailing NL is stripped.
8927786Seric */
8937786Seric 
8947786Seric char *
8957786Seric fgetfolded(buf, n, f)
8967786Seric 	char *buf;
8977786Seric 	register int n;
8987786Seric 	FILE *f;
8997786Seric {
9007786Seric 	register char *p = buf;
90157135Seric 	char *bp = buf;
9027786Seric 	register int i;
9037786Seric 
9047786Seric 	n--;
90517350Seric 	while ((i = getc(f)) != EOF)
9067786Seric 	{
90717350Seric 		if (i == '\r')
90817350Seric 		{
90917350Seric 			i = getc(f);
91017350Seric 			if (i != '\n')
91117350Seric 			{
91217350Seric 				if (i != EOF)
91323105Seric 					(void) ungetc(i, f);
91417350Seric 				i = '\r';
91517350Seric 			}
91617350Seric 		}
91757135Seric 		if (--n <= 0)
91857135Seric 		{
91957135Seric 			/* allocate new space */
92057135Seric 			char *nbp;
92157135Seric 			int nn;
92257135Seric 
92357135Seric 			nn = (p - bp);
92457232Seric 			if (nn < MEMCHUNKSIZE)
92557135Seric 				nn *= 2;
92657135Seric 			else
92757232Seric 				nn += MEMCHUNKSIZE;
92857135Seric 			nbp = xalloc(nn);
92957135Seric 			bcopy(bp, nbp, p - bp);
93057135Seric 			p = &nbp[p - bp];
93157135Seric 			if (bp != buf)
93257135Seric 				free(bp);
93357135Seric 			bp = nbp;
93457135Seric 			n = nn - (p - bp);
93557135Seric 		}
93657135Seric 		*p++ = i;
93717350Seric 		if (i == '\n')
93817350Seric 		{
93917350Seric 			LineNumber++;
94017350Seric 			i = getc(f);
94117350Seric 			if (i != EOF)
94223105Seric 				(void) ungetc(i, f);
94317350Seric 			if (i != ' ' && i != '\t')
94452647Seric 				break;
94517350Seric 		}
9467786Seric 	}
94757135Seric 	if (p == bp)
94852647Seric 		return (NULL);
94952647Seric 	*--p = '\0';
95057135Seric 	return (bp);
9517786Seric }
9527860Seric /*
9537886Seric **  CURTIME -- return current time.
9547886Seric **
9557886Seric **	Parameters:
9567886Seric **		none.
9577886Seric **
9587886Seric **	Returns:
9597886Seric **		the current time.
9607886Seric **
9617886Seric **	Side Effects:
9627886Seric **		none.
9637886Seric */
9647886Seric 
9657886Seric time_t
9667886Seric curtime()
9677886Seric {
9687886Seric 	auto time_t t;
9697886Seric 
9707886Seric 	(void) time(&t);
9717886Seric 	return (t);
9727886Seric }
9738264Seric /*
9748264Seric **  ATOBOOL -- convert a string representation to boolean.
9758264Seric **
9768264Seric **	Defaults to "TRUE"
9778264Seric **
9788264Seric **	Parameters:
9798264Seric **		s -- string to convert.  Takes "tTyY" as true,
9808264Seric **			others as false.
9818264Seric **
9828264Seric **	Returns:
9838264Seric **		A boolean representation of the string.
9848264Seric **
9858264Seric **	Side Effects:
9868264Seric **		none.
9878264Seric */
9888264Seric 
9898264Seric bool
9908264Seric atobool(s)
9918264Seric 	register char *s;
9928264Seric {
99363833Seric 	if (s == NULL || *s == '\0' || strchr("tTyY", *s) != NULL)
9948264Seric 		return (TRUE);
9958264Seric 	return (FALSE);
9968264Seric }
9979048Seric /*
9989048Seric **  ATOOCT -- convert a string representation to octal.
9999048Seric **
10009048Seric **	Parameters:
10019048Seric **		s -- string to convert.
10029048Seric **
10039048Seric **	Returns:
10049048Seric **		An integer representing the string interpreted as an
10059048Seric **		octal number.
10069048Seric **
10079048Seric **	Side Effects:
10089048Seric **		none.
10099048Seric */
10109048Seric 
10119048Seric atooct(s)
10129048Seric 	register char *s;
10139048Seric {
10149048Seric 	register int i = 0;
10159048Seric 
10169048Seric 	while (*s >= '0' && *s <= '7')
10179048Seric 		i = (i << 3) | (*s++ - '0');
10189048Seric 	return (i);
10199048Seric }
10209376Seric /*
10219376Seric **  WAITFOR -- wait for a particular process id.
10229376Seric **
10239376Seric **	Parameters:
10249376Seric **		pid -- process id to wait for.
10259376Seric **
10269376Seric **	Returns:
10279376Seric **		status of pid.
10289376Seric **		-1 if pid never shows up.
10299376Seric **
10309376Seric **	Side Effects:
10319376Seric **		none.
10329376Seric */
10339376Seric 
103464562Seric int
10359376Seric waitfor(pid)
10369376Seric 	int pid;
10379376Seric {
103864562Seric #ifdef WAITUNION
103964562Seric 	union wait st;
104064562Seric #else
10419376Seric 	auto int st;
104264562Seric #endif
10439376Seric 	int i;
10449376Seric 
10459376Seric 	do
10469376Seric 	{
10479376Seric 		errno = 0;
10489376Seric 		i = wait(&st);
10499376Seric 	} while ((i >= 0 || errno == EINTR) && i != pid);
10509376Seric 	if (i < 0)
105164562Seric 		return -1;
105264562Seric #ifdef WAITUNION
105364562Seric 	return st.w_status;
105464562Seric #else
105564562Seric 	return st;
105664562Seric #endif
10579376Seric }
10589376Seric /*
105910685Seric **  BITINTERSECT -- tell if two bitmaps intersect
106010685Seric **
106110685Seric **	Parameters:
106210685Seric **		a, b -- the bitmaps in question
106310685Seric **
106410685Seric **	Returns:
106510685Seric **		TRUE if they have a non-null intersection
106610685Seric **		FALSE otherwise
106710685Seric **
106810685Seric **	Side Effects:
106910685Seric **		none.
107010685Seric */
107110685Seric 
107210685Seric bool
107310685Seric bitintersect(a, b)
107410685Seric 	BITMAP a;
107510685Seric 	BITMAP b;
107610685Seric {
107710685Seric 	int i;
107810685Seric 
107910685Seric 	for (i = BITMAPBYTES / sizeof (int); --i >= 0; )
108010685Seric 		if ((a[i] & b[i]) != 0)
108110685Seric 			return (TRUE);
108210685Seric 	return (FALSE);
108310685Seric }
108410685Seric /*
108510685Seric **  BITZEROP -- tell if a bitmap is all zero
108610685Seric **
108710685Seric **	Parameters:
108810685Seric **		map -- the bit map to check
108910685Seric **
109010685Seric **	Returns:
109110685Seric **		TRUE if map is all zero.
109210685Seric **		FALSE if there are any bits set in map.
109310685Seric **
109410685Seric **	Side Effects:
109510685Seric **		none.
109610685Seric */
109710685Seric 
109810685Seric bool
109910685Seric bitzerop(map)
110010685Seric 	BITMAP map;
110110685Seric {
110210685Seric 	int i;
110310685Seric 
110410685Seric 	for (i = BITMAPBYTES / sizeof (int); --i >= 0; )
110510685Seric 		if (map[i] != 0)
110610685Seric 			return (FALSE);
110710685Seric 	return (TRUE);
110810685Seric }
110958247Seric /*
111058318Seric **  STRCONTAINEDIN -- tell if one string is contained in another
111158318Seric **
111258318Seric **	Parameters:
111358318Seric **		a -- possible substring.
111458318Seric **		b -- possible superstring.
111558318Seric **
111658318Seric **	Returns:
111758318Seric **		TRUE if a is contained in b.
111858318Seric **		FALSE otherwise.
111958318Seric */
112058318Seric 
112158318Seric bool
112258318Seric strcontainedin(a, b)
112358318Seric 	register char *a;
112458318Seric 	register char *b;
112558318Seric {
112665012Seric 	int la;
112765012Seric 	int lb;
112865012Seric 	int c;
112958318Seric 
113065012Seric 	la = strlen(a);
113165012Seric 	lb = strlen(b);
113265012Seric 	c = *a;
113365012Seric 	if (isascii(c) && isupper(c))
113465012Seric 		c = tolower(c);
113565012Seric 	for (; lb-- >= la; b++)
113658318Seric 	{
113765012Seric 		if (*b != c && isascii(*b) && isupper(*b) && tolower(*b) != c)
113865012Seric 			continue;
113965012Seric 		if (strncasecmp(a, b, la) == 0)
114058318Seric 			return TRUE;
114158318Seric 	}
114265012Seric 	return FALSE;
114358318Seric }
114463753Seric /*
114563753Seric **  CHECKFD012 -- check low numbered file descriptors
114663753Seric **
114763753Seric **	File descriptors 0, 1, and 2 should be open at all times.
114863753Seric **	This routine verifies that, and fixes it if not true.
114963753Seric **
115063753Seric **	Parameters:
115163753Seric **		where -- a tag printed if the assertion failed
115263753Seric **
115363753Seric **	Returns:
115463753Seric **		none
115563753Seric */
115663753Seric 
115763753Seric checkfd012(where)
115863753Seric 	char *where;
115963753Seric {
116063753Seric #ifdef XDEBUG
116163753Seric 	register int i;
116263753Seric 	struct stat stbuf;
116363753Seric 
116463753Seric 	for (i = 0; i < 3; i++)
116563753Seric 	{
116664735Seric 		if (fstat(i, &stbuf) < 0 && errno != EOPNOTSUPP)
116763753Seric 		{
116863753Seric 			/* oops.... */
116963753Seric 			int fd;
117063753Seric 
117163753Seric 			syserr("%s: fd %d not open", where, i);
117263753Seric 			fd = open("/dev/null", i == 0 ? O_RDONLY : O_WRONLY, 0666);
117363753Seric 			if (fd != i)
117463753Seric 			{
117563753Seric 				(void) dup2(fd, i);
117663753Seric 				(void) close(fd);
117763753Seric 			}
117863753Seric 		}
117963753Seric 	}
118063937Seric #endif /* XDEBUG */
118163753Seric }
118264725Seric /*
118364725Seric **  PRINTOPENFDS -- print the open file descriptors (for debugging)
118464725Seric **
118564725Seric **	Parameters:
118664725Seric **		logit -- if set, send output to syslog; otherwise
118764725Seric **			print for debugging.
118864725Seric **
118964725Seric **	Returns:
119064725Seric **		none.
119164725Seric */
119264725Seric 
119364725Seric #include <netdb.h>
119464725Seric #include <arpa/inet.h>
119564725Seric 
119664725Seric printopenfds(logit)
119764725Seric 	bool logit;
119864725Seric {
119964725Seric 	register int fd;
120064743Seric 	extern int DtableSize;
120164743Seric 
120264743Seric 	for (fd = 0; fd < DtableSize; fd++)
120364743Seric 		dumpfd(fd, FALSE, logit);
120464743Seric }
120564743Seric /*
120664743Seric **  DUMPFD -- dump a file descriptor
120764743Seric **
120864743Seric **	Parameters:
120964743Seric **		fd -- the file descriptor to dump.
121064743Seric **		printclosed -- if set, print a notification even if
121164743Seric **			it is closed; otherwise print nothing.
121264743Seric **		logit -- if set, send output to syslog instead of stdout.
121364743Seric */
121464743Seric 
121564743Seric dumpfd(fd, printclosed, logit)
121664743Seric 	int fd;
121764743Seric 	bool printclosed;
121864743Seric 	bool logit;
121964743Seric {
122064725Seric 	register struct hostent *hp;
122164725Seric 	register char *p;
122264743Seric 	struct sockaddr_in sin;
122364743Seric 	auto int slen;
122464743Seric 	struct stat st;
122564725Seric 	char buf[200];
122664725Seric 
122764743Seric 	p = buf;
122864743Seric 	sprintf(p, "%3d: ", fd);
122964743Seric 	p += strlen(p);
123064743Seric 
123164743Seric 	if (fstat(fd, &st) < 0)
123264725Seric 	{
123364743Seric 		if (printclosed || errno != EBADF)
123464743Seric 		{
123564743Seric 			sprintf(p, "CANNOT STAT (%s)", errstring(errno));
123664743Seric 			goto printit;
123764743Seric 		}
123864743Seric 		return;
123964743Seric 	}
124064725Seric 
124164743Seric 	slen = fcntl(fd, F_GETFL, NULL);
124264743Seric 	if (slen != -1)
124364743Seric 	{
124464743Seric 		sprintf(p, "fl=0x%x, ", slen);
124564743Seric 		p += strlen(p);
124664743Seric 	}
124764725Seric 
124864743Seric 	sprintf(p, "mode=%o: ", st.st_mode);
124964743Seric 	p += strlen(p);
125064743Seric 	switch (st.st_mode & S_IFMT)
125164743Seric 	{
125264807Seric #ifdef S_IFSOCK
125364743Seric 	  case S_IFSOCK:
125464743Seric 		sprintf(p, "SOCK ");
125564725Seric 		p += strlen(p);
125664743Seric 		slen = sizeof sin;
125764743Seric 		if (getsockname(fd, (struct sockaddr *) &sin, &slen) < 0)
125864743Seric 			sprintf(p, "(badsock)");
125964743Seric 		else
126064725Seric 		{
126164743Seric 			hp = gethostbyaddr((char *) &sin.sin_addr, slen, AF_INET);
126264743Seric 			sprintf(p, "%s/%d", hp == NULL ? inet_ntoa(sin.sin_addr)
126364743Seric 						   : hp->h_name, ntohs(sin.sin_port));
126464743Seric 		}
126564743Seric 		p += strlen(p);
126664743Seric 		sprintf(p, "->");
126764743Seric 		p += strlen(p);
126864743Seric 		slen = sizeof sin;
126964743Seric 		if (getpeername(fd, (struct sockaddr *) &sin, &slen) < 0)
127064743Seric 			sprintf(p, "(badsock)");
127164743Seric 		else
127264743Seric 		{
127364743Seric 			hp = gethostbyaddr((char *) &sin.sin_addr, slen, AF_INET);
127464743Seric 			sprintf(p, "%s/%d", hp == NULL ? inet_ntoa(sin.sin_addr)
127564743Seric 						   : hp->h_name, ntohs(sin.sin_port));
127664743Seric 		}
127764743Seric 		break;
127864807Seric #endif
127964725Seric 
128064743Seric 	  case S_IFCHR:
128164743Seric 		sprintf(p, "CHR: ");
128264743Seric 		p += strlen(p);
128364743Seric 		goto defprint;
128464725Seric 
128564743Seric 	  case S_IFBLK:
128664743Seric 		sprintf(p, "BLK: ");
128764743Seric 		p += strlen(p);
128864743Seric 		goto defprint;
128964725Seric 
129065378Seric #ifdef S_IFIFO
129165378Seric 	  case S_IFIFO:
129265378Seric 		sprintf(p, "FIFO: ");
129365378Seric 		p += strlen(p);
129465378Seric 		goto defprint;
129565378Seric #endif
129665378Seric 
129765378Seric #ifdef S_IFDIR
129865378Seric 	  case S_IFDIR:
129965378Seric 		sprintf(p, "DIR: ");
130065378Seric 		p += strlen(p);
130165378Seric 		goto defprint;
130265378Seric #endif
130365378Seric 
130465378Seric #ifdef S_IFLNK
130565378Seric 	  case S_IFLNK:
130665378Seric 		sprintf(p, "LNK: ");
130765378Seric 		p += strlen(p);
130865378Seric 		goto defprint;
130965378Seric #endif
131065378Seric 
131164743Seric 	  default:
131264725Seric defprint:
131364743Seric 		sprintf(p, "dev=%d/%d, ino=%d, nlink=%d, u/gid=%d/%d, size=%ld",
131464743Seric 			major(st.st_dev), minor(st.st_dev), st.st_ino,
131564743Seric 			st.st_nlink, st.st_uid, st.st_gid, st.st_size);
131664743Seric 		break;
131764743Seric 	}
131864725Seric 
131964743Seric printit:
132064743Seric 	if (logit)
132165006Seric 		syslog(LOG_DEBUG, "%s", buf);
132264743Seric 	else
132364743Seric 		printf("%s\n", buf);
132464725Seric }
132565015Seric /*
132665015Seric **  SHORTENSTRING -- return short version of a string
132765015Seric **
132865015Seric **	If the string is already short, just return it.  If it is too
132965015Seric **	long, return the head and tail of the string.
133065015Seric **
133165015Seric **	Parameters:
133265015Seric **		s -- the string to shorten.
133365015Seric **		m -- the max length of the string.
133465015Seric **
133565015Seric **	Returns:
133665015Seric **		Either s or a short version of s.
133765015Seric */
133865015Seric 
133965015Seric #ifndef MAXSHORTSTR
134065055Seric # define MAXSHORTSTR	203
134165015Seric #endif
134265015Seric 
134365015Seric char *
134465015Seric shortenstring(s, m)
134565015Seric 	register char *s;
134665015Seric 	int m;
134765015Seric {
134865015Seric 	int l;
134965015Seric 	static char buf[MAXSHORTSTR + 1];
135065015Seric 
135165015Seric 	l = strlen(s);
135265015Seric 	if (l < m)
135365015Seric 		return s;
135465015Seric 	if (m > MAXSHORTSTR)
135565015Seric 		m = MAXSHORTSTR;
135665015Seric 	else if (m < 10)
135765015Seric 	{
135865015Seric 		if (m < 5)
135965015Seric 		{
136065015Seric 			strncpy(buf, s, m);
136165015Seric 			buf[m] = '\0';
136265015Seric 			return buf;
136365015Seric 		}
136465015Seric 		strncpy(buf, s, m - 3);
136565015Seric 		strcpy(buf + m - 3, "...");
136665015Seric 		return buf;
136765015Seric 	}
136865015Seric 	m = (m - 3) / 2;
136965015Seric 	strncpy(buf, s, m);
137065015Seric 	strcpy(buf + m, "...");
137165015Seric 	strcpy(buf + m + 3, s + l - m);
137265015Seric 	return buf;
137365015Seric }
1374