xref: /csrg-svn/usr.sbin/sendmail/src/util.c (revision 7685)
13151Seric # include <stdio.h>
24538Seric # include <sys/types.h>
34538Seric # include <sys/stat.h>
4298Seric # include <sysexits.h>
56890Seric # include <errno.h>
62900Seric # include <ctype.h>
76890Seric # include "sendmail.h"
8298Seric 
9*7685Seric SCCSID(@(#)util.c	3.22		08/08/82);
10409Seric 
11298Seric /*
12298Seric **  STRIPQUOTES -- Strip quotes & quote bits from a string.
13298Seric **
14298Seric **	Runs through a string and strips off unquoted quote
15298Seric **	characters and quote bits.  This is done in place.
16298Seric **
17298Seric **	Parameters:
18298Seric **		s -- the string to strip.
194101Seric **		qf -- if set, remove actual `` " '' characters
204101Seric **			as well as the quote bits.
21298Seric **
22298Seric **	Returns:
23298Seric **		none.
24298Seric **
25298Seric **	Side Effects:
26298Seric **		none.
27298Seric **
28298Seric **	Called By:
29298Seric **		deliver
30298Seric */
31298Seric 
324101Seric stripquotes(s, qf)
33298Seric 	char *s;
344101Seric 	bool qf;
35298Seric {
36298Seric 	register char *p;
37298Seric 	register char *q;
38298Seric 	register char c;
39298Seric 
404101Seric 	if (s == NULL)
414101Seric 		return;
424101Seric 
43298Seric 	for (p = q = s; (c = *p++) != '\0'; )
44298Seric 	{
454101Seric 		if (c != '"' || !qf)
46298Seric 			*q++ = c & 0177;
47298Seric 	}
48298Seric 	*q = '\0';
49298Seric }
50298Seric /*
512900Seric **  CAPITALIZE -- return a copy of a string, properly capitalized.
522900Seric **
532900Seric **	Parameters:
542900Seric **		s -- the string to capitalize.
552900Seric **
562900Seric **	Returns:
572900Seric **		a pointer to a properly capitalized string.
582900Seric **
592900Seric **	Side Effects:
602900Seric **		none.
612900Seric */
622900Seric 
632900Seric char *
642900Seric capitalize(s)
652900Seric 	register char *s;
662900Seric {
672900Seric 	static char buf[50];
682900Seric 	register char *p;
692900Seric 
702900Seric 	p = buf;
712900Seric 
722900Seric 	for (;;)
732900Seric 	{
742900Seric 		while (!isalpha(*s) && *s != '\0')
752900Seric 			*p++ = *s++;
762900Seric 		if (*s == '\0')
772900Seric 			break;
782900Seric 		*p++ = toupper(*s++);
792900Seric 		while (isalpha(*s))
802900Seric 			*p++ = *s++;
812900Seric 	}
822900Seric 
832900Seric 	*p = '\0';
842900Seric 	return (buf);
852900Seric }
862900Seric /*
87298Seric **  XALLOC -- Allocate memory and bitch wildly on failure.
88298Seric **
89298Seric **	THIS IS A CLUDGE.  This should be made to give a proper
90298Seric **	error -- but after all, what can we do?
91298Seric **
92298Seric **	Parameters:
93298Seric **		sz -- size of area to allocate.
94298Seric **
95298Seric **	Returns:
96298Seric **		pointer to data region.
97298Seric **
98298Seric **	Side Effects:
99298Seric **		Memory is allocated.
100298Seric */
101298Seric 
102298Seric char *
103298Seric xalloc(sz)
1047007Seric 	register int sz;
105298Seric {
106298Seric 	register char *p;
107298Seric 
108298Seric 	p = malloc(sz);
109298Seric 	if (p == NULL)
110298Seric 	{
111298Seric 		syserr("Out of memory!!");
1121598Seric 		exit(EX_UNAVAILABLE);
113298Seric 	}
114298Seric 	return (p);
115298Seric }
116298Seric /*
1172900Seric **  NEWSTR -- make copy of string.
1182900Seric **
1192900Seric **	Space is allocated for it using xalloc.
1202900Seric **
1212900Seric **	Parameters:
1222900Seric **		string to copy.
1232900Seric **
1242900Seric **	Returns:
1252900Seric **		pointer to new string.
1262900Seric **
1272900Seric **	Side Effects:
1282900Seric **		none.
1292900Seric */
1302900Seric 
1312900Seric char *
1322900Seric newstr(s)
1332900Seric 	register char *s;
1342900Seric {
1352900Seric 	register char *p;
1362900Seric 
1377007Seric 	p = xalloc(strlen(s) + 1);
1387007Seric 	(void) strcpy(p, s);
1392900Seric 	return (p);
1402900Seric }
1413151Seric /*
1423151Seric **  COPYPLIST -- copy list of pointers.
1433151Seric **
1443151Seric **	This routine is the equivalent of newstr for lists of
1453151Seric **	pointers.
1463151Seric **
1473151Seric **	Parameters:
1483151Seric **		list -- list of pointers to copy.
1493151Seric **			Must be NULL terminated.
1503151Seric **		copycont -- if TRUE, copy the contents of the vector
1513151Seric **			(which must be a string) also.
1523151Seric **
1533151Seric **	Returns:
1543151Seric **		a copy of 'list'.
1553151Seric **
1563151Seric **	Side Effects:
1573151Seric **		none.
1583151Seric */
1593151Seric 
1603151Seric char **
1613151Seric copyplist(list, copycont)
1623151Seric 	char **list;
1633151Seric 	bool copycont;
1643151Seric {
1653151Seric 	register char **vp;
1663151Seric 	register char **newvp;
1673151Seric 
1683151Seric 	for (vp = list; *vp != NULL; vp++)
1693151Seric 		continue;
1703151Seric 
1713151Seric 	vp++;
1723151Seric 
1737007Seric 	newvp = (char **) xalloc((vp - list) * sizeof *vp);
1744086Seric 	bmove((char *) list, (char *) newvp, (vp - list) * sizeof *vp);
1753151Seric 
1763151Seric 	if (copycont)
1773151Seric 	{
1783151Seric 		for (vp = newvp; *vp != NULL; vp++)
1793151Seric 			*vp = newstr(*vp);
1803151Seric 	}
1813151Seric 
1823151Seric 	return (newvp);
1833151Seric }
1843151Seric /*
1853151Seric **  PRINTAV -- print argument vector.
1863151Seric **
1873151Seric **	Parameters:
1883151Seric **		av -- argument vector.
1893151Seric **
1903151Seric **	Returns:
1913151Seric **		none.
1923151Seric **
1933151Seric **	Side Effects:
1943151Seric **		prints av.
1953151Seric */
1963151Seric 
1973151Seric # ifdef DEBUG
1983151Seric printav(av)
1993151Seric 	register char **av;
2003151Seric {
2013151Seric 	while (*av != NULL)
2023151Seric 	{
2033151Seric 		printf("\t%08x=", *av);
2043151Seric 		xputs(*av++);
2053151Seric 		putchar('\n');
2063151Seric 	}
2073151Seric }
2083151Seric # endif DEBUG
2093151Seric /*
2103151Seric **  LOWER -- turn letter into lower case.
2113151Seric **
2123151Seric **	Parameters:
2133151Seric **		c -- character to turn into lower case.
2143151Seric **
2153151Seric **	Returns:
2163151Seric **		c, in lower case.
2173151Seric **
2183151Seric **	Side Effects:
2193151Seric **		none.
2203151Seric */
2213151Seric 
2223151Seric char
2233151Seric lower(c)
2243151Seric 	register char c;
2253151Seric {
2263151Seric 	if (isascii(c) && isupper(c))
2273151Seric 		c = c - 'A' + 'a';
2283151Seric 	return (c);
2293151Seric }
2303151Seric /*
2313151Seric **  XPUTS -- put string doing control escapes.
2323151Seric **
2333151Seric **	Parameters:
2343151Seric **		s -- string to put.
2353151Seric **
2363151Seric **	Returns:
2373151Seric **		none.
2383151Seric **
2393151Seric **	Side Effects:
2403151Seric **		output to stdout
2413151Seric */
2423151Seric 
2433151Seric # ifdef DEBUG
2443151Seric xputs(s)
2453151Seric 	register char *s;
2463151Seric {
2473151Seric 	register char c;
2483151Seric 
2493151Seric 	while ((c = *s++) != '\0')
2503151Seric 	{
2513151Seric 		if (!isascii(c))
2523151Seric 		{
2533151Seric 			putchar('\\');
2543151Seric 			c &= 0177;
2553151Seric 		}
2563151Seric 		if (iscntrl(c))
2573151Seric 		{
2583151Seric 			putchar('^');
2593151Seric 			c |= 0100;
2603151Seric 		}
2613151Seric 		putchar(c);
2623151Seric 	}
2634086Seric 	(void) fflush(stdout);
2643151Seric }
2653151Seric # endif DEBUG
2663151Seric /*
2673151Seric **  MAKELOWER -- Translate a line into lower case
2683151Seric **
2693151Seric **	Parameters:
2703151Seric **		p -- the string to translate.  If NULL, return is
2713151Seric **			immediate.
2723151Seric **
2733151Seric **	Returns:
2743151Seric **		none.
2753151Seric **
2763151Seric **	Side Effects:
2773151Seric **		String pointed to by p is translated to lower case.
2783151Seric **
2793151Seric **	Called By:
2803151Seric **		parse
2813151Seric */
2823151Seric 
2833151Seric makelower(p)
2843151Seric 	register char *p;
2853151Seric {
2863151Seric 	register char c;
2873151Seric 
2883151Seric 	if (p == NULL)
2893151Seric 		return;
2903151Seric 	for (; (c = *p) != '\0'; p++)
2913151Seric 		if (isascii(c) && isupper(c))
2923151Seric 			*p = c - 'A' + 'a';
2933151Seric }
2944059Seric /*
2954059Seric **  SAMEWORD -- return TRUE if the words are the same
2964059Seric **
2974059Seric **	Ignores case.
2984059Seric **
2994059Seric **	Parameters:
3004059Seric **		a, b -- the words to compare.
3014059Seric **
3024059Seric **	Returns:
3034059Seric **		TRUE if a & b match exactly (modulo case)
3044059Seric **		FALSE otherwise.
3054059Seric **
3064059Seric **	Side Effects:
3074059Seric **		none.
3084059Seric */
3094059Seric 
3104059Seric bool
3114059Seric sameword(a, b)
3124059Seric 	register char *a, *b;
3134059Seric {
3144059Seric 	while (lower(*a) == lower(*b))
3154059Seric 	{
3164059Seric 		if (*a == '\0')
3174059Seric 			return (TRUE);
3184059Seric 		a++;
3194059Seric 		b++;
3204059Seric 	}
3214059Seric 	return (FALSE);
3224059Seric }
3234086Seric /*
3244101Seric **  CLEAR -- clear a block of memory
3254101Seric **
3264101Seric **	Parameters:
3274101Seric **		p -- location to clear.
3284101Seric **		l -- number of bytes to clear.
3294101Seric **
3304101Seric **	Returns:
3314101Seric **		none.
3324101Seric **
3334101Seric **	Side Effects:
3344101Seric **		none.
3354101Seric */
3364101Seric 
3374101Seric clear(p, l)
3384101Seric 	register char *p;
3394101Seric 	register int l;
3404101Seric {
3414101Seric 	while (l-- > 0)
3424101Seric 		*p++ = 0;
3434101Seric }
3444101Seric /*
3455196Seric **  BUILDFNAME -- build full name from gecos style entry.
3464375Seric **
3475196Seric **	This routine interprets the strange entry that would appear
3485196Seric **	in the GECOS field of the password file.
3495196Seric **
3504375Seric **	Parameters:
3515196Seric **		p -- name to build.
3525196Seric **		login -- the login name of this user (for &).
3535196Seric **		buf -- place to put the result.
3544375Seric **
3554375Seric **	Returns:
3564375Seric **		none.
3574375Seric **
3584375Seric **	Side Effects:
3594375Seric **		none.
3604375Seric */
3614375Seric 
3625196Seric buildfname(p, login, buf)
3635196Seric 	register char *p;
3645196Seric 	char *login;
3654375Seric 	char *buf;
3664375Seric {
3674375Seric 	register char *bp = buf;
3684375Seric 
3694438Seric 	if (*p == '*')
3704438Seric 		p++;
3716278Seric 	while (*p != '\0' && *p != ',' && *p != ';' && *p != '%')
3724375Seric 	{
3734375Seric 		if (*p == '&')
3744375Seric 		{
3755196Seric 			(void) strcpy(bp, login);
3764375Seric 			*bp = toupper(*bp);
3774375Seric 			while (*bp != '\0')
3784375Seric 				bp++;
3794375Seric 			p++;
3804375Seric 		}
3814375Seric 		else
3824375Seric 			*bp++ = *p++;
3834375Seric 	}
3844375Seric 	*bp = '\0';
3854375Seric }
3864375Seric /*
3874538Seric **  SAFEFILE -- return true if a file exists and is safe for a user.
3884538Seric **
3894538Seric **	Parameters:
3904538Seric **		fn -- filename to check.
3914538Seric **		uid -- uid to compare against.
3924538Seric **		mode -- mode bits that must match.
3934538Seric **
3944538Seric **	Returns:
3954538Seric **		TRUE if fn exists, is owned by uid, and matches mode.
3964538Seric **		FALSE otherwise.
3974538Seric **
3984538Seric **	Side Effects:
3994538Seric **		none.
4004538Seric */
4014538Seric 
4024538Seric bool
4034538Seric safefile(fn, uid, mode)
4044538Seric 	char *fn;
4054538Seric 	int uid;
4064538Seric 	int mode;
4074538Seric {
4084538Seric 	struct stat stbuf;
4094538Seric 
4104538Seric 	if (stat(fn, &stbuf) >= 0 && stbuf.st_uid == uid &&
4114538Seric 	    (stbuf.st_mode & mode) == mode)
4124538Seric 		return (TRUE);
4134538Seric 	return (FALSE);
4144538Seric }
4154538Seric /*
4164557Seric **  FIXCRLF -- fix <CR><LF> in line.
4174557Seric **
4184557Seric **	Looks for the <CR><LF> combination and turns it into the
4194557Seric **	UNIX canonical <NL> character.  It only takes one line,
4204557Seric **	i.e., it is assumed that the first <NL> found is the end
4214557Seric **	of the line.
4224557Seric **
4234557Seric **	Parameters:
4244557Seric **		line -- the line to fix.
4254557Seric **		stripnl -- if true, strip the newline also.
4264557Seric **
4274557Seric **	Returns:
4284557Seric **		none.
4294557Seric **
4304557Seric **	Side Effects:
4314557Seric **		line is changed in place.
4324557Seric */
4334557Seric 
4344557Seric fixcrlf(line, stripnl)
4354557Seric 	char *line;
4364557Seric 	bool stripnl;
4374557Seric {
4384557Seric 	register char *p;
4394557Seric 
4404557Seric 	p = index(line, '\n');
4414557Seric 	if (p == NULL)
4424557Seric 		return;
4434794Seric 	if (p[-1] == '\r')
4444557Seric 		p--;
4454557Seric 	if (!stripnl)
4464557Seric 		*p++ = '\n';
4474557Seric 	*p = '\0';
4484557Seric }
4494557Seric /*
4504086Seric **  SYSLOG -- fake entry to fool lint
4514086Seric */
4524086Seric 
4534086Seric # ifdef LOG
4544086Seric # ifdef lint
4554086Seric 
4564086Seric /*VARARGS2*/
4574086Seric syslog(pri, fmt, args)
4584086Seric 	int pri;
4594086Seric 	char *fmt;
4604086Seric {
4614086Seric 	pri = *fmt;
4624086Seric 	args = pri;
4634086Seric 	pri = args;
4644086Seric }
4654086Seric 
4664086Seric # endif lint
4674086Seric # endif LOG
4686890Seric /*
4696890Seric **  DFOPEN -- determined file open
4706890Seric **
4716890Seric **	This routine has the semantics of fopen, except that it will
4726890Seric **	keep trying a few times to make this happen.  The idea is that
4736890Seric **	on very loaded systems, we may run out of resources (inodes,
4746890Seric **	whatever), so this tries to get around it.
4756890Seric */
4766890Seric 
4776890Seric FILE *
4786890Seric dfopen(filename, mode)
4796890Seric 	char *filename;
4806890Seric 	char *mode;
4816890Seric {
4826890Seric 	register int tries;
4836890Seric 	register FILE *fp;
4846890Seric 	extern int errno;
4856890Seric 
4866890Seric 	for (tries = 0; tries < 10; tries++)
4876890Seric 	{
4886890Seric 		sleep(10 * tries);
4896890Seric 		errno = 0;
4906890Seric 		fp = fopen(filename, mode);
4916890Seric 		if (fp != NULL || errno != ENFILE)
4926890Seric 			break;
4936890Seric 	}
4946890Seric 	return (fp);
4956890Seric }
4967124Seric /*
4977124Seric **  PUTLINE -- put a line like fputs obeying SMTP conventions
4987124Seric **
4997124Seric **	Parameters:
5007124Seric **		l -- line to put.
5017124Seric **		fp -- file to put it onto.
5027124Seric **		fullsmtp -- if set, obey strictest SMTP conventions.
5037124Seric **
5047124Seric **	Returns:
5057124Seric **		none
5067124Seric **
5077124Seric **	Side Effects:
5087124Seric **		output of l to fp.
5097124Seric */
5107124Seric 
5117124Seric # define SMTPLINELIM	120	/* maximum line length */
5127124Seric 
5137124Seric putline(l, fp, fullsmtp)
5147124Seric 	char *l;
5157124Seric 	FILE *fp;
5167124Seric 	bool fullsmtp;
5177124Seric {
5187124Seric 	register char *p;
5197124Seric 
5207124Seric 	if (!fullsmtp)
5217124Seric 	{
5227124Seric 		fputs(l, fp);
5237124Seric 		return;
5247124Seric 	}
5257124Seric 
5267124Seric 	/* find the end of the line */
5277286Seric 	p = index(l, '\n');
5287124Seric 	if (p == NULL)
5297124Seric 		p = &l[strlen(l)];
5307124Seric 
5317124Seric 	/* check for line overflow */
5327124Seric 	while (p - l > SMTPLINELIM)
5337124Seric 	{
5347124Seric 		register char *q = &l[SMTPLINELIM - 1];
5357124Seric 		char svchar = *q;
5367124Seric 
5377124Seric 		*q = '\0';
5387124Seric 		fputs(l, fp);
5397124Seric 		fputs("!\r\n", fp);
5407124Seric 		*q = svchar;
5417124Seric 		l = q;
5427124Seric 	}
5437124Seric 
5447124Seric 	/* output last part */
5457124Seric 	*p = '\0';
5467124Seric 	fputs(l, fp);
5477124Seric 	fputs("\r\n", fp);
5487124Seric 	*p = '\n';
5497124Seric }
5507676Seric /*
5517676Seric **  XUNLINK -- unlink a file, doing logging as appropriate.
5527676Seric **
5537676Seric **	Parameters:
5547676Seric **		f -- name of file to unlink.
5557676Seric **
5567676Seric **	Returns:
5577676Seric **		none.
5587676Seric **
5597676Seric **	Side Effects:
5607676Seric **		f is unlinked.
5617676Seric */
5627676Seric 
5637676Seric xunlink(f)
5647676Seric 	char *f;
5657676Seric {
5667676Seric 	register int i;
5677676Seric 
5687676Seric # ifdef LOG
5697676Seric 	if (LogLevel > 20)
5707676Seric 		syslog(LOG_DEBUG, "%s: unlink %s\n", MsgId, f);
5717676Seric # endif LOG
5727676Seric 
5737676Seric 	i = unlink(f);
5747676Seric # ifdef LOG
5757676Seric 	if (i < 0 && LogLevel > 21)
5767676Seric 		syslog(LOG_DEBUG, "%s: unlink-fail %e");
5777676Seric # endif LOG
5787676Seric }
579*7685Seric /*
580*7685Seric **  SFGETS -- "safe" fgets -- times out.
581*7685Seric **
582*7685Seric **	Parameters:
583*7685Seric **		buf -- place to put the input line.
584*7685Seric **		siz -- size of buf.
585*7685Seric **		fp -- file to read from.
586*7685Seric **
587*7685Seric **	Returns:
588*7685Seric **		NULL on error (including timeout).
589*7685Seric **		buf otherwise.
590*7685Seric **
591*7685Seric **	Side Effects:
592*7685Seric **		none.
593*7685Seric */
594*7685Seric 
595*7685Seric jmp_buf	TimeoFrame;
596*7685Seric 
597*7685Seric char *
598*7685Seric sfgets(buf, siz, fp)
599*7685Seric 	char *buf;
600*7685Seric 	int siz;
601*7685Seric 	FILE *fp;
602*7685Seric {
603*7685Seric 	register EVENT *ev;
604*7685Seric 	register char *p;
605*7685Seric 	extern readtimeout();
606*7685Seric 
607*7685Seric 	ev = setevent(ReadTimeout, readtimeout, 0);
608*7685Seric 	if (setjmp(TimeoFrame) != 0)
609*7685Seric 		return (NULL);
610*7685Seric 	p = fgets(buf, siz, fp);
611*7685Seric 	clrevent(ev);
612*7685Seric 	return (p);
613*7685Seric }
614*7685Seric 
615*7685Seric static
616*7685Seric readtimeout()
617*7685Seric {
618*7685Seric 	longjmp(TimeoFrame, 1);
619*7685Seric }
620