util.c revision 38032
1/*
2 * Copyright (c) 1998 Sendmail, Inc.  All rights reserved.
3 * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
4 * Copyright (c) 1988, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * By using this file, you agree to the terms and conditions set
8 * forth in the LICENSE file which can be found at the top level of
9 * the sendmail distribution.
10 *
11 */
12
13#ifndef lint
14static char sccsid[] = "@(#)util.c	8.159 (Berkeley) 7/1/98";
15#endif /* not lint */
16
17# include "sendmail.h"
18# include <sysexits.h>
19/*
20**  STRIPQUOTES -- Strip quotes & quote bits from a string.
21**
22**	Runs through a string and strips off unquoted quote
23**	characters and quote bits.  This is done in place.
24**
25**	Parameters:
26**		s -- the string to strip.
27**
28**	Returns:
29**		none.
30**
31**	Side Effects:
32**		none.
33**
34**	Called By:
35**		deliver
36*/
37
38void
39stripquotes(s)
40	char *s;
41{
42	register char *p;
43	register char *q;
44	register char c;
45
46	if (s == NULL)
47		return;
48
49	p = q = s;
50	do
51	{
52		c = *p++;
53		if (c == '\\')
54			c = *p++;
55		else if (c == '"')
56			continue;
57		*q++ = c;
58	} while (c != '\0');
59}
60/*
61**  ADDQUOTES -- Adds quotes & quote bits to a string.
62**
63**	Runs through a string and adds characters and quote bits.
64**
65**	Parameters:
66**		s -- the string to modify.
67**
68**	Returns:
69**		pointer to quoted string.
70**
71**	Side Effects:
72**		none.
73**
74*/
75
76char *
77addquotes(s)
78	char *s;
79{
80	int len = 0;
81	char c;
82	char *p = s, *q, *r;
83
84	if (s == NULL)
85		return NULL;
86
87	/* Find length of quoted string */
88	while ((c = *p++) != '\0')
89	{
90		len++;
91		if (c == '\\' || c == '"')
92			len++;
93	}
94
95	q = r = xalloc(len + 3);
96	p = s;
97
98	/* add leading quote */
99	*q++ = '"';
100	while ((c = *p++) != '\0')
101	{
102		/* quote \ or " */
103		if (c == '\\' || c == '"')
104			*q++ = '\\';
105		*q++ = c;
106	}
107	*q++ = '"';
108	*q = '\0';
109	return r;
110}
111/*
112**  RFC822_STRING -- Checks string for proper RFC822 string quoting.
113**
114**	Runs through a string and verifies RFC822 special characters
115**	are only found inside comments, quoted strings, or backslash
116**	escaped.  Also verified balanced quotes and parenthesis.
117**
118**	Parameters:
119**		s -- the string to modify.
120**
121**	Returns:
122**		TRUE -- if the string is RFC822 compliant.
123**		FALSE -- if the string is not RFC822 compliant.
124**
125**	Side Effects:
126**		none.
127**
128*/
129
130bool
131rfc822_string(s)
132	char *s;
133{
134	bool quoted = FALSE;
135	int commentlev = 0;
136	char *c = s;
137
138	if (s == NULL)
139		return FALSE;
140
141	while (*c != '\0')
142	{
143		/* escaped character */
144		if (*c == '\\')
145		{
146			c++;
147			if (*c == '\0')
148				return FALSE;
149		}
150		else if (commentlev == 0 && *c == '"')
151			quoted = !quoted;
152		else if (!quoted)
153		{
154			if (*c == ')')
155			{
156				/* unbalanced ')' */
157				if (commentlev == 0)
158					return FALSE;
159				else
160					commentlev--;
161			}
162			else if (*c == '(')
163				commentlev++;
164			else if (commentlev == 0 &&
165				 strchr(MustQuoteChars, *c) != NULL)
166				return FALSE;
167		}
168		c++;
169	}
170	/* unbalanced '"' or '(' */
171	if (quoted || commentlev != 0)
172		return FALSE;
173	else
174		return TRUE;
175}
176/*
177**  XALLOC -- Allocate memory and bitch wildly on failure.
178**
179**	THIS IS A CLUDGE.  This should be made to give a proper
180**	error -- but after all, what can we do?
181**
182**	Parameters:
183**		sz -- size of area to allocate.
184**
185**	Returns:
186**		pointer to data region.
187**
188**	Side Effects:
189**		Memory is allocated.
190*/
191
192char *
193xalloc(sz)
194	register int sz;
195{
196	register char *p;
197
198	/* some systems can't handle size zero mallocs */
199	if (sz <= 0)
200		sz = 1;
201
202	p = malloc((unsigned) sz);
203	if (p == NULL)
204	{
205		syserr("!Out of memory!!");
206		/* exit(EX_UNAVAILABLE); */
207	}
208	return (p);
209}
210/*
211**  COPYPLIST -- copy list of pointers.
212**
213**	This routine is the equivalent of newstr for lists of
214**	pointers.
215**
216**	Parameters:
217**		list -- list of pointers to copy.
218**			Must be NULL terminated.
219**		copycont -- if TRUE, copy the contents of the vector
220**			(which must be a string) also.
221**
222**	Returns:
223**		a copy of 'list'.
224**
225**	Side Effects:
226**		none.
227*/
228
229char **
230copyplist(list, copycont)
231	char **list;
232	bool copycont;
233{
234	register char **vp;
235	register char **newvp;
236
237	for (vp = list; *vp != NULL; vp++)
238		continue;
239
240	vp++;
241
242	newvp = (char **) xalloc((int) (vp - list) * sizeof *vp);
243	bcopy((char *) list, (char *) newvp, (int) (vp - list) * sizeof *vp);
244
245	if (copycont)
246	{
247		for (vp = newvp; *vp != NULL; vp++)
248			*vp = newstr(*vp);
249	}
250
251	return (newvp);
252}
253/*
254**  COPYQUEUE -- copy address queue.
255**
256**	This routine is the equivalent of newstr for address queues
257**	addresses marked with QDONTSEND aren't copied
258**
259**	Parameters:
260**		addr -- list of address structures to copy.
261**
262**	Returns:
263**		a copy of 'addr'.
264**
265**	Side Effects:
266**		none.
267*/
268
269ADDRESS *
270copyqueue(addr)
271	ADDRESS *addr;
272{
273	register ADDRESS *newaddr;
274	ADDRESS *ret;
275	register ADDRESS **tail = &ret;
276
277	while (addr != NULL)
278	{
279		if (!bitset(QDONTSEND, addr->q_flags))
280		{
281			newaddr = (ADDRESS *) xalloc(sizeof(ADDRESS));
282			STRUCTCOPY(*addr, *newaddr);
283			*tail = newaddr;
284			tail = &newaddr->q_next;
285		}
286		addr = addr->q_next;
287	}
288	*tail = NULL;
289
290	return ret;
291}
292/*
293**  PRINTAV -- print argument vector.
294**
295**	Parameters:
296**		av -- argument vector.
297**
298**	Returns:
299**		none.
300**
301**	Side Effects:
302**		prints av.
303*/
304
305void
306printav(av)
307	register char **av;
308{
309	while (*av != NULL)
310	{
311		if (tTd(0, 44))
312			printf("\n\t%08lx=", (u_long) *av);
313		else
314			(void) putchar(' ');
315		xputs(*av++);
316	}
317	(void) putchar('\n');
318}
319/*
320**  LOWER -- turn letter into lower case.
321**
322**	Parameters:
323**		c -- character to turn into lower case.
324**
325**	Returns:
326**		c, in lower case.
327**
328**	Side Effects:
329**		none.
330*/
331
332char
333lower(c)
334	register char c;
335{
336	return((isascii(c) && isupper(c)) ? tolower(c) : c);
337}
338/*
339**  XPUTS -- put string doing control escapes.
340**
341**	Parameters:
342**		s -- string to put.
343**
344**	Returns:
345**		none.
346**
347**	Side Effects:
348**		output to stdout
349*/
350
351void
352xputs(s)
353	register const char *s;
354{
355	register int c;
356	register struct metamac *mp;
357	bool shiftout = FALSE;
358	extern struct metamac MetaMacros[];
359
360	if (s == NULL)
361	{
362		printf("%s<null>%s", TermEscape.te_rv_on, TermEscape.te_rv_off);
363		return;
364	}
365	while ((c = (*s++ & 0377)) != '\0')
366	{
367		if (shiftout)
368		{
369			printf("%s", TermEscape.te_rv_off);
370			shiftout = FALSE;
371		}
372		if (!isascii(c))
373		{
374			if (c == MATCHREPL)
375			{
376				printf("%s$", TermEscape.te_rv_on);
377				shiftout = TRUE;
378				if (*s == '\0')
379					continue;
380				c = *s++ & 0377;
381				goto printchar;
382			}
383			if (c == MACROEXPAND || c == MACRODEXPAND)
384			{
385				printf("%s$", TermEscape.te_rv_on);
386				if (c == MACRODEXPAND)
387					putchar('&');
388				shiftout = TRUE;
389				if (*s == '\0')
390					continue;
391				if (strchr("=~&?", *s) != NULL)
392					putchar(*s++);
393				if (bitset(0200, *s))
394					printf("{%s}", macname(*s++ & 0377));
395				else
396					printf("%c", *s++);
397				continue;
398			}
399			for (mp = MetaMacros; mp->metaname != '\0'; mp++)
400			{
401				if ((mp->metaval & 0377) == c)
402				{
403					printf("%s$%c",
404						TermEscape.te_rv_on,
405						mp->metaname);
406					shiftout = TRUE;
407					break;
408				}
409			}
410			if (c == MATCHCLASS || c == MATCHNCLASS)
411			{
412				if (bitset(0200, *s))
413					printf("{%s}", macname(*s++ & 0377));
414				else if (*s != '\0')
415					printf("%c", *s++);
416			}
417			if (mp->metaname != '\0')
418				continue;
419
420			/* unrecognized meta character */
421			printf("%sM-", TermEscape.te_rv_on);
422			shiftout = TRUE;
423			c &= 0177;
424		}
425  printchar:
426		if (isprint(c))
427		{
428			putchar(c);
429			continue;
430		}
431
432		/* wasn't a meta-macro -- find another way to print it */
433		switch (c)
434		{
435		  case '\n':
436			c = 'n';
437			break;
438
439		  case '\r':
440			c = 'r';
441			break;
442
443		  case '\t':
444			c = 't';
445			break;
446		}
447		if (!shiftout)
448		{
449			printf("%s", TermEscape.te_rv_on);
450			shiftout = TRUE;
451		}
452		if (isprint(c))
453		{
454			(void) putchar('\\');
455			(void) putchar(c);
456		}
457		else
458		{
459			(void) putchar('^');
460			(void) putchar(c ^ 0100);
461		}
462	}
463	if (shiftout)
464		printf("%s", TermEscape.te_rv_off);
465	(void) fflush(stdout);
466}
467/*
468**  MAKELOWER -- Translate a line into lower case
469**
470**	Parameters:
471**		p -- the string to translate.  If NULL, return is
472**			immediate.
473**
474**	Returns:
475**		none.
476**
477**	Side Effects:
478**		String pointed to by p is translated to lower case.
479**
480**	Called By:
481**		parse
482*/
483
484void
485makelower(p)
486	register char *p;
487{
488	register char c;
489
490	if (p == NULL)
491		return;
492	for (; (c = *p) != '\0'; p++)
493		if (isascii(c) && isupper(c))
494			*p = tolower(c);
495}
496/*
497**  BUILDFNAME -- build full name from gecos style entry.
498**
499**	This routine interprets the strange entry that would appear
500**	in the GECOS field of the password file.
501**
502**	Parameters:
503**		p -- name to build.
504**		login -- the login name of this user (for &).
505**		buf -- place to put the result.
506**		buflen -- length of buf.
507**
508**	Returns:
509**		none.
510**
511**	Side Effects:
512**		none.
513*/
514
515void
516buildfname(gecos, login, buf, buflen)
517	register char *gecos;
518	char *login;
519	char *buf;
520	int buflen;
521{
522	register char *p;
523	register char *bp = buf;
524
525	if (*gecos == '*')
526		gecos++;
527
528	/* copy gecos, interpolating & to be full name */
529	for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++)
530	{
531		if (bp >= &buf[buflen - 1])
532		{
533			/* buffer overflow -- just use login name */
534			snprintf(buf, buflen, "%s", login);
535			return;
536		}
537		if (*p == '&')
538		{
539			/* interpolate full name */
540			snprintf(bp, buflen - (bp - buf), "%s", login);
541			*bp = toupper(*bp);
542			bp += strlen(bp);
543		}
544		else
545			*bp++ = *p;
546	}
547	*bp = '\0';
548}
549/*
550**  FIXCRLF -- fix <CR><LF> in line.
551**
552**	Looks for the <CR><LF> combination and turns it into the
553**	UNIX canonical <NL> character.  It only takes one line,
554**	i.e., it is assumed that the first <NL> found is the end
555**	of the line.
556**
557**	Parameters:
558**		line -- the line to fix.
559**		stripnl -- if true, strip the newline also.
560**
561**	Returns:
562**		none.
563**
564**	Side Effects:
565**		line is changed in place.
566*/
567
568void
569fixcrlf(line, stripnl)
570	char *line;
571	bool stripnl;
572{
573	register char *p;
574
575	p = strchr(line, '\n');
576	if (p == NULL)
577		return;
578	if (p > line && p[-1] == '\r')
579		p--;
580	if (!stripnl)
581		*p++ = '\n';
582	*p = '\0';
583}
584/*
585**  PUTLINE -- put a line like fputs obeying SMTP conventions
586**
587**	This routine always guarantees outputing a newline (or CRLF,
588**	as appropriate) at the end of the string.
589**
590**	Parameters:
591**		l -- line to put.
592**		mci -- the mailer connection information.
593**
594**	Returns:
595**		none
596**
597**	Side Effects:
598**		output of l to fp.
599*/
600
601void
602putline(l, mci)
603	register char *l;
604	register MCI *mci;
605{
606	putxline(l, strlen(l), mci, PXLF_MAPFROM);
607}
608/*
609**  PUTXLINE -- putline with flags bits.
610**
611**	This routine always guarantees outputing a newline (or CRLF,
612**	as appropriate) at the end of the string.
613**
614**	Parameters:
615**		l -- line to put.
616**		len -- the length of the line.
617**		mci -- the mailer connection information.
618**		pxflags -- flag bits:
619**		    PXLF_MAPFROM -- map From_ to >From_.
620**		    PXLF_STRIP8BIT -- strip 8th bit.
621**		    PXLF_HEADER -- map bare newline in header to newline space.
622**
623**	Returns:
624**		none
625**
626**	Side Effects:
627**		output of l to fp.
628*/
629
630void
631putxline(l, len, mci, pxflags)
632	register char *l;
633	size_t len;
634	register MCI *mci;
635	int pxflags;
636{
637	register char *p, *end;
638	int slop = 0;
639	size_t eol_len = strlen(mci->mci_mailer->m_eol);
640
641	/* strip out 0200 bits -- these can look like TELNET protocol */
642	if (bitset(MCIF_7BIT, mci->mci_flags) ||
643	    bitset(PXLF_STRIP8BIT, pxflags))
644	{
645		register char svchar;
646
647		for (p = l; (svchar = *p) != '\0'; ++p)
648			if (bitset(0200, svchar))
649				*p = svchar &~ 0200;
650	}
651
652	end = l + len;
653	do
654	{
655		/* find the end of the line */
656		p = memchr(l, '\n', end - l);
657		if (p == NULL)
658			p = end;
659
660		if (TrafficLogFile != NULL)
661			fprintf(TrafficLogFile, "%05d >>> ", (int) getpid());
662
663		/* check for line overflow */
664		while (mci->mci_mailer->m_linelimit > 0 &&
665		       (p - l + slop) > mci->mci_mailer->m_linelimit)
666		{
667			char *l_base = l;
668			register char *q = &l[mci->mci_mailer->m_linelimit - slop - 1];
669
670			if (l[0] == '.' && slop == 0 &&
671			    bitnset(M_XDOT, mci->mci_mailer->m_flags))
672			{
673				(void) putc('.', mci->mci_out);
674				if (!bitset(MCIF_INHEADER, mci->mci_flags))
675					mci->mci_contentlen++;
676				if (TrafficLogFile != NULL)
677					(void) putc('.', TrafficLogFile);
678			}
679			else if (l[0] == 'F' && slop == 0 &&
680				 bitset(PXLF_MAPFROM, pxflags) &&
681				 strncmp(l, "From ", 5) == 0 &&
682				 bitnset(M_ESCFROM, mci->mci_mailer->m_flags))
683			{
684				(void) putc('>', mci->mci_out);
685				if (!bitset(MCIF_INHEADER, mci->mci_flags))
686					mci->mci_contentlen++;
687				if (TrafficLogFile != NULL)
688					(void) putc('>', TrafficLogFile);
689			}
690			while (l < q)
691			{
692				(void) putc(*l++, mci->mci_out);
693				if (!bitset(MCIF_INHEADER, mci->mci_flags))
694					mci->mci_contentlen++;
695			}
696			(void) putc('!', mci->mci_out);
697			if (!bitset(MCIF_INHEADER, mci->mci_flags))
698				mci->mci_contentlen++;
699			fputs(mci->mci_mailer->m_eol, mci->mci_out);
700			if (!bitset(MCIF_INHEADER, mci->mci_flags))
701				mci->mci_contentlen += eol_len;
702			(void) putc(' ', mci->mci_out);
703			if (!bitset(MCIF_INHEADER, mci->mci_flags))
704				mci->mci_contentlen++;
705			if (TrafficLogFile != NULL)
706			{
707				for (l = l_base; l < q; l++)
708					(void) putc(*l, TrafficLogFile);
709				fprintf(TrafficLogFile, "!\n%05d >>>  ",
710					(int) getpid());
711			}
712			slop = 1;
713		}
714
715		/* output last part */
716		if (l[0] == '.' && slop == 0 &&
717		    bitnset(M_XDOT, mci->mci_mailer->m_flags))
718		{
719			(void) putc('.', mci->mci_out);
720			if (!bitset(MCIF_INHEADER, mci->mci_flags))
721				mci->mci_contentlen++;
722			if (TrafficLogFile != NULL)
723				(void) putc('.', TrafficLogFile);
724		}
725		else if (l[0] == 'F' && slop == 0 &&
726			 bitset(PXLF_MAPFROM, pxflags) &&
727			 strncmp(l, "From ", 5) == 0 &&
728			 bitnset(M_ESCFROM, mci->mci_mailer->m_flags))
729		{
730			(void) putc('>', mci->mci_out);
731			if (!bitset(MCIF_INHEADER, mci->mci_flags))
732				mci->mci_contentlen++;
733			if (TrafficLogFile != NULL)
734				(void) putc('>', TrafficLogFile);
735		}
736		for ( ; l < p; ++l)
737		{
738			if (TrafficLogFile != NULL)
739				(void) putc(*l, TrafficLogFile);
740			(void) putc(*l, mci->mci_out);
741			if (!bitset(MCIF_INHEADER, mci->mci_flags))
742				mci->mci_contentlen++;
743		}
744		if (TrafficLogFile != NULL)
745			(void) putc('\n', TrafficLogFile);
746		fputs(mci->mci_mailer->m_eol, mci->mci_out);
747		if (!bitset(MCIF_INHEADER, mci->mci_flags))
748			mci->mci_contentlen += eol_len;
749		if (l < end && *l == '\n')
750		{
751			if (*++l != ' ' && *l != '\t' && *l != '\0' &&
752			    bitset(PXLF_HEADER, pxflags))
753			{
754				(void) putc(' ', mci->mci_out);
755				if (!bitset(MCIF_INHEADER, mci->mci_flags))
756					mci->mci_contentlen++;
757				if (TrafficLogFile != NULL)
758					(void) putc(' ', TrafficLogFile);
759			}
760		}
761	} while (l < end);
762}
763/*
764**  XUNLINK -- unlink a file, doing logging as appropriate.
765**
766**	Parameters:
767**		f -- name of file to unlink.
768**
769**	Returns:
770**		none.
771**
772**	Side Effects:
773**		f is unlinked.
774*/
775
776void
777xunlink(f)
778	char *f;
779{
780	register int i;
781
782	if (LogLevel > 98)
783		sm_syslog(LOG_DEBUG, CurEnv->e_id,
784			"unlink %s",
785			f);
786
787	i = unlink(f);
788	if (i < 0 && LogLevel > 97)
789		sm_syslog(LOG_DEBUG, CurEnv->e_id,
790			"%s: unlink-fail %d",
791			f, errno);
792}
793/*
794**  XFCLOSE -- close a file, doing logging as appropriate.
795**
796**	Parameters:
797**		fp -- file pointer for the file to close
798**		a, b -- miscellaneous crud to print for debugging
799**
800**	Returns:
801**		none.
802**
803**	Side Effects:
804**		fp is closed.
805*/
806
807void
808xfclose(fp, a, b)
809	FILE *fp;
810	char *a, *b;
811{
812	if (tTd(53, 99))
813		printf("xfclose(%lx) %s %s\n", (u_long) fp, a, b);
814#if XDEBUG
815	if (fileno(fp) == 1)
816		syserr("xfclose(%s %s): fd = 1", a, b);
817#endif
818	if (fclose(fp) < 0 && tTd(53, 99))
819		printf("xfclose FAILURE: %s\n", errstring(errno));
820}
821/*
822**  SFGETS -- "safe" fgets -- times out and ignores random interrupts.
823**
824**	Parameters:
825**		buf -- place to put the input line.
826**		siz -- size of buf.
827**		fp -- file to read from.
828**		timeout -- the timeout before error occurs.
829**		during -- what we are trying to read (for error messages).
830**
831**	Returns:
832**		NULL on error (including timeout).  This will also leave
833**			buf containing a null string.
834**		buf otherwise.
835**
836**	Side Effects:
837**		none.
838*/
839
840static jmp_buf	CtxReadTimeout;
841static void	readtimeout __P((time_t));
842
843char *
844sfgets(buf, siz, fp, timeout, during)
845	char *buf;
846	int siz;
847	FILE *fp;
848	time_t timeout;
849	char *during;
850{
851	register EVENT *ev = NULL;
852	register char *p;
853
854	if (fp == NULL)
855	{
856		buf[0] = '\0';
857		return NULL;
858	}
859
860	/* set the timeout */
861	if (timeout != 0)
862	{
863		if (setjmp(CtxReadTimeout) != 0)
864		{
865			if (LogLevel > 1)
866				sm_syslog(LOG_NOTICE, CurEnv->e_id,
867				       "timeout waiting for input from %.100s during %s",
868				       CurHostName ? CurHostName : "local",
869				       during);
870			errno = 0;
871			buf[0] = '\0';
872#if XDEBUG
873			checkfd012(during);
874#endif
875			if (TrafficLogFile != NULL)
876				fprintf(TrafficLogFile, "%05d <<< [TIMEOUT]\n",
877					(int) getpid());
878			return (NULL);
879		}
880		ev = setevent(timeout, readtimeout, 0);
881	}
882
883	/* try to read */
884	p = NULL;
885	while (!feof(fp) && !ferror(fp))
886	{
887		errno = 0;
888		p = fgets(buf, siz, fp);
889		if (p != NULL || errno != EINTR)
890			break;
891		clearerr(fp);
892	}
893
894	/* clear the event if it has not sprung */
895	clrevent(ev);
896
897	/* clean up the books and exit */
898	LineNumber++;
899	if (p == NULL)
900	{
901		buf[0] = '\0';
902		if (TrafficLogFile != NULL)
903			fprintf(TrafficLogFile, "%05d <<< [EOF]\n", (int) getpid());
904		return (NULL);
905	}
906	if (TrafficLogFile != NULL)
907		fprintf(TrafficLogFile, "%05d <<< %s", (int) getpid(), buf);
908	if (SevenBitInput)
909	{
910		for (p = buf; *p != '\0'; p++)
911			*p &= ~0200;
912	}
913	else if (!HasEightBits)
914	{
915		for (p = buf; *p != '\0'; p++)
916		{
917			if (bitset(0200, *p))
918			{
919				HasEightBits = TRUE;
920				break;
921			}
922		}
923	}
924	return (buf);
925}
926
927/* ARGSUSED */
928static void
929readtimeout(timeout)
930	time_t timeout;
931{
932	longjmp(CtxReadTimeout, 1);
933}
934/*
935**  FGETFOLDED -- like fgets, but know about folded lines.
936**
937**	Parameters:
938**		buf -- place to put result.
939**		n -- bytes available.
940**		f -- file to read from.
941**
942**	Returns:
943**		input line(s) on success, NULL on error or EOF.
944**		This will normally be buf -- unless the line is too
945**			long, when it will be xalloc()ed.
946**
947**	Side Effects:
948**		buf gets lines from f, with continuation lines (lines
949**		with leading white space) appended.  CRLF's are mapped
950**		into single newlines.  Any trailing NL is stripped.
951*/
952
953char *
954fgetfolded(buf, n, f)
955	char *buf;
956	register int n;
957	FILE *f;
958{
959	register char *p = buf;
960	char *bp = buf;
961	register int i;
962
963	n--;
964	while ((i = getc(f)) != EOF)
965	{
966		if (i == '\r')
967		{
968			i = getc(f);
969			if (i != '\n')
970			{
971				if (i != EOF)
972					(void) ungetc(i, f);
973				i = '\r';
974			}
975		}
976		if (--n <= 0)
977		{
978			/* allocate new space */
979			char *nbp;
980			int nn;
981
982			nn = (p - bp);
983			if (nn < MEMCHUNKSIZE)
984				nn *= 2;
985			else
986				nn += MEMCHUNKSIZE;
987			nbp = xalloc(nn);
988			bcopy(bp, nbp, p - bp);
989			p = &nbp[p - bp];
990			if (bp != buf)
991				free(bp);
992			bp = nbp;
993			n = nn - (p - bp);
994		}
995		*p++ = i;
996		if (i == '\n')
997		{
998			LineNumber++;
999			i = getc(f);
1000			if (i != EOF)
1001				(void) ungetc(i, f);
1002			if (i != ' ' && i != '\t')
1003				break;
1004		}
1005	}
1006	if (p == bp)
1007		return (NULL);
1008	if (p[-1] == '\n')
1009		p--;
1010	*p = '\0';
1011	return (bp);
1012}
1013/*
1014**  CURTIME -- return current time.
1015**
1016**	Parameters:
1017**		none.
1018**
1019**	Returns:
1020**		the current time.
1021**
1022**	Side Effects:
1023**		none.
1024*/
1025
1026time_t
1027curtime()
1028{
1029	auto time_t t;
1030
1031	(void) time(&t);
1032	return (t);
1033}
1034/*
1035**  ATOBOOL -- convert a string representation to boolean.
1036**
1037**	Defaults to "TRUE"
1038**
1039**	Parameters:
1040**		s -- string to convert.  Takes "tTyY" as true,
1041**			others as false.
1042**
1043**	Returns:
1044**		A boolean representation of the string.
1045**
1046**	Side Effects:
1047**		none.
1048*/
1049
1050bool
1051atobool(s)
1052	register char *s;
1053{
1054	if (s == NULL || *s == '\0' || strchr("tTyY", *s) != NULL)
1055		return (TRUE);
1056	return (FALSE);
1057}
1058/*
1059**  ATOOCT -- convert a string representation to octal.
1060**
1061**	Parameters:
1062**		s -- string to convert.
1063**
1064**	Returns:
1065**		An integer representing the string interpreted as an
1066**		octal number.
1067**
1068**	Side Effects:
1069**		none.
1070*/
1071
1072int
1073atooct(s)
1074	register char *s;
1075{
1076	register int i = 0;
1077
1078	while (*s >= '0' && *s <= '7')
1079		i = (i << 3) | (*s++ - '0');
1080	return (i);
1081}
1082/*
1083**  BITINTERSECT -- tell if two bitmaps intersect
1084**
1085**	Parameters:
1086**		a, b -- the bitmaps in question
1087**
1088**	Returns:
1089**		TRUE if they have a non-null intersection
1090**		FALSE otherwise
1091**
1092**	Side Effects:
1093**		none.
1094*/
1095
1096bool
1097bitintersect(a, b)
1098	BITMAP a;
1099	BITMAP b;
1100{
1101	int i;
1102
1103	for (i = BITMAPBYTES / sizeof (int); --i >= 0; )
1104		if ((a[i] & b[i]) != 0)
1105			return (TRUE);
1106	return (FALSE);
1107}
1108/*
1109**  BITZEROP -- tell if a bitmap is all zero
1110**
1111**	Parameters:
1112**		map -- the bit map to check
1113**
1114**	Returns:
1115**		TRUE if map is all zero.
1116**		FALSE if there are any bits set in map.
1117**
1118**	Side Effects:
1119**		none.
1120*/
1121
1122bool
1123bitzerop(map)
1124	BITMAP map;
1125{
1126	int i;
1127
1128	for (i = BITMAPBYTES / sizeof (int); --i >= 0; )
1129		if (map[i] != 0)
1130			return (FALSE);
1131	return (TRUE);
1132}
1133/*
1134**  STRCONTAINEDIN -- tell if one string is contained in another
1135**
1136**	Parameters:
1137**		a -- possible substring.
1138**		b -- possible superstring.
1139**
1140**	Returns:
1141**		TRUE if a is contained in b.
1142**		FALSE otherwise.
1143*/
1144
1145bool
1146strcontainedin(a, b)
1147	register char *a;
1148	register char *b;
1149{
1150	int la;
1151	int lb;
1152	int c;
1153
1154	la = strlen(a);
1155	lb = strlen(b);
1156	c = *a;
1157	if (isascii(c) && isupper(c))
1158		c = tolower(c);
1159	for (; lb-- >= la; b++)
1160	{
1161		if (*b != c && isascii(*b) && isupper(*b) && tolower(*b) != c)
1162			continue;
1163		if (strncasecmp(a, b, la) == 0)
1164			return TRUE;
1165	}
1166	return FALSE;
1167}
1168/*
1169**  CHECKFD012 -- check low numbered file descriptors
1170**
1171**	File descriptors 0, 1, and 2 should be open at all times.
1172**	This routine verifies that, and fixes it if not true.
1173**
1174**	Parameters:
1175**		where -- a tag printed if the assertion failed
1176**
1177**	Returns:
1178**		none
1179*/
1180
1181void
1182checkfd012(where)
1183	char *where;
1184{
1185#if XDEBUG
1186	register int i;
1187
1188	for (i = 0; i < 3; i++)
1189		fill_fd(i, where);
1190#endif /* XDEBUG */
1191}
1192/*
1193**  CHECKFDOPEN -- make sure file descriptor is open -- for extended debugging
1194**
1195**	Parameters:
1196**		fd -- file descriptor to check.
1197**		where -- tag to print on failure.
1198**
1199**	Returns:
1200**		none.
1201*/
1202
1203void
1204checkfdopen(fd, where)
1205	int fd;
1206	char *where;
1207{
1208#if XDEBUG
1209	struct stat st;
1210
1211	if (fstat(fd, &st) < 0 && errno == EBADF)
1212	{
1213		syserr("checkfdopen(%d): %s not open as expected!", fd, where);
1214		printopenfds(TRUE);
1215	}
1216#endif
1217}
1218/*
1219**  CHECKFDS -- check for new or missing file descriptors
1220**
1221**	Parameters:
1222**		where -- tag for printing.  If null, take a base line.
1223**
1224**	Returns:
1225**		none
1226**
1227**	Side Effects:
1228**		If where is set, shows changes since the last call.
1229*/
1230
1231void
1232checkfds(where)
1233	char *where;
1234{
1235	int maxfd;
1236	register int fd;
1237	bool printhdr = TRUE;
1238	int save_errno = errno;
1239	static BITMAP baseline;
1240	extern int DtableSize;
1241
1242	if (DtableSize > 256)
1243		maxfd = 256;
1244	else
1245		maxfd = DtableSize;
1246	if (where == NULL)
1247		clrbitmap(baseline);
1248
1249	for (fd = 0; fd < maxfd; fd++)
1250	{
1251		struct stat stbuf;
1252
1253		if (fstat(fd, &stbuf) < 0 && errno != EOPNOTSUPP)
1254		{
1255			if (!bitnset(fd, baseline))
1256				continue;
1257			clrbitn(fd, baseline);
1258		}
1259		else if (!bitnset(fd, baseline))
1260			setbitn(fd, baseline);
1261		else
1262			continue;
1263
1264		/* file state has changed */
1265		if (where == NULL)
1266			continue;
1267		if (printhdr)
1268		{
1269			sm_syslog(LOG_DEBUG, CurEnv->e_id,
1270				"%s: changed fds:",
1271				where);
1272			printhdr = FALSE;
1273		}
1274		dumpfd(fd, TRUE, TRUE);
1275	}
1276	errno = save_errno;
1277}
1278/*
1279**  PRINTOPENFDS -- print the open file descriptors (for debugging)
1280**
1281**	Parameters:
1282**		logit -- if set, send output to syslog; otherwise
1283**			print for debugging.
1284**
1285**	Returns:
1286**		none.
1287*/
1288
1289#include <arpa/inet.h>
1290
1291void
1292printopenfds(logit)
1293	bool logit;
1294{
1295	register int fd;
1296	extern int DtableSize;
1297
1298	for (fd = 0; fd < DtableSize; fd++)
1299		dumpfd(fd, FALSE, logit);
1300}
1301/*
1302**  DUMPFD -- dump a file descriptor
1303**
1304**	Parameters:
1305**		fd -- the file descriptor to dump.
1306**		printclosed -- if set, print a notification even if
1307**			it is closed; otherwise print nothing.
1308**		logit -- if set, send output to syslog instead of stdout.
1309*/
1310
1311void
1312dumpfd(fd, printclosed, logit)
1313	int fd;
1314	bool printclosed;
1315	bool logit;
1316{
1317	register char *p;
1318	char *hp;
1319#ifdef S_IFSOCK
1320	SOCKADDR sa;
1321#endif
1322	auto SOCKADDR_LEN_T slen;
1323	int i;
1324#if STAT64 > 0
1325	struct stat64 st;
1326#else
1327	struct stat st;
1328#endif
1329	char buf[200];
1330
1331	p = buf;
1332	snprintf(p, SPACELEFT(buf, p), "%3d: ", fd);
1333	p += strlen(p);
1334
1335	if (
1336#if STAT64 > 0
1337	    fstat64(fd, &st)
1338#else
1339	    fstat(fd, &st)
1340#endif
1341	    < 0)
1342	{
1343		if (errno != EBADF)
1344		{
1345			snprintf(p, SPACELEFT(buf, p), "CANNOT STAT (%s)",
1346				errstring(errno));
1347			goto printit;
1348		}
1349		else if (printclosed)
1350		{
1351			snprintf(p, SPACELEFT(buf, p), "CLOSED");
1352			goto printit;
1353		}
1354		return;
1355	}
1356
1357	i = fcntl(fd, F_GETFL, NULL);
1358	if (i != -1)
1359	{
1360		snprintf(p, SPACELEFT(buf, p), "fl=0x%x, ", i);
1361		p += strlen(p);
1362	}
1363
1364	snprintf(p, SPACELEFT(buf, p), "mode=%o: ", st.st_mode);
1365	p += strlen(p);
1366	switch (st.st_mode & S_IFMT)
1367	{
1368#ifdef S_IFSOCK
1369	  case S_IFSOCK:
1370		snprintf(p, SPACELEFT(buf, p), "SOCK ");
1371		p += strlen(p);
1372		slen = sizeof sa;
1373		if (getsockname(fd, &sa.sa, &slen) < 0)
1374			snprintf(p, SPACELEFT(buf, p), "(%s)", errstring(errno));
1375		else
1376		{
1377			hp = hostnamebyanyaddr(&sa);
1378			if (sa.sa.sa_family == AF_INET)
1379				snprintf(p, SPACELEFT(buf, p), "%s/%d",
1380					hp, ntohs(sa.sin.sin_port));
1381			else
1382				snprintf(p, SPACELEFT(buf, p), "%s", hp);
1383		}
1384		p += strlen(p);
1385		snprintf(p, SPACELEFT(buf, p), "->");
1386		p += strlen(p);
1387		slen = sizeof sa;
1388		if (getpeername(fd, &sa.sa, &slen) < 0)
1389			snprintf(p, SPACELEFT(buf, p), "(%s)", errstring(errno));
1390		else
1391		{
1392			hp = hostnamebyanyaddr(&sa);
1393			if (sa.sa.sa_family == AF_INET)
1394				snprintf(p, SPACELEFT(buf, p), "%s/%d",
1395					hp, ntohs(sa.sin.sin_port));
1396			else
1397				snprintf(p, SPACELEFT(buf, p), "%s", hp);
1398		}
1399		break;
1400#endif
1401
1402	  case S_IFCHR:
1403		snprintf(p, SPACELEFT(buf, p), "CHR: ");
1404		p += strlen(p);
1405		goto defprint;
1406
1407	  case S_IFBLK:
1408		snprintf(p, SPACELEFT(buf, p), "BLK: ");
1409		p += strlen(p);
1410		goto defprint;
1411
1412#if defined(S_IFIFO) && (!defined(S_IFSOCK) || S_IFIFO != S_IFSOCK)
1413	  case S_IFIFO:
1414		snprintf(p, SPACELEFT(buf, p), "FIFO: ");
1415		p += strlen(p);
1416		goto defprint;
1417#endif
1418
1419#ifdef S_IFDIR
1420	  case S_IFDIR:
1421		snprintf(p, SPACELEFT(buf, p), "DIR: ");
1422		p += strlen(p);
1423		goto defprint;
1424#endif
1425
1426#ifdef S_IFLNK
1427	  case S_IFLNK:
1428		snprintf(p, SPACELEFT(buf, p), "LNK: ");
1429		p += strlen(p);
1430		goto defprint;
1431#endif
1432
1433	  default:
1434defprint:
1435		if (sizeof st.st_ino > sizeof (long))
1436			snprintf(p, SPACELEFT(buf, p),
1437				 "dev=%d/%d, ino=%s, nlink=%d, u/gid=%d/%d, ",
1438				 major(st.st_dev), minor(st.st_dev),
1439				 quad_to_string(st.st_ino),
1440				 st.st_nlink, st.st_uid, st.st_gid);
1441		else
1442			snprintf(p, SPACELEFT(buf, p),
1443				"dev=%d/%d, ino=%lu, nlink=%d, u/gid=%d/%d, ",
1444				major(st.st_dev), minor(st.st_dev),
1445				(unsigned long) st.st_ino,
1446				st.st_nlink, st.st_uid, st.st_gid);
1447		if (sizeof st.st_size > sizeof (long))
1448			snprintf(p, SPACELEFT(buf, p), "size=%s",
1449				 quad_to_string(st.st_size));
1450		else
1451			snprintf(p, SPACELEFT(buf, p), "size=%lu",
1452				 (unsigned long) st.st_size);
1453		break;
1454	}
1455
1456printit:
1457	if (logit)
1458		sm_syslog(LOG_DEBUG, CurEnv ? CurEnv->e_id : NULL,
1459			"%.800s", buf);
1460	else
1461		printf("%s\n", buf);
1462}
1463/*
1464**  SHORTEN_HOSTNAME -- strip local domain information off of hostname.
1465**
1466**	Parameters:
1467**		host -- the host to shorten (stripped in place).
1468**
1469**	Returns:
1470**		none.
1471*/
1472
1473void
1474shorten_hostname(host)
1475	char host[];
1476{
1477	register char *p;
1478	char *mydom;
1479	int i;
1480	bool canon = FALSE;
1481
1482	/* strip off final dot */
1483	p = &host[strlen(host) - 1];
1484	if (*p == '.')
1485	{
1486		*p = '\0';
1487		canon = TRUE;
1488	}
1489
1490	/* see if there is any domain at all -- if not, we are done */
1491	p = strchr(host, '.');
1492	if (p == NULL)
1493		return;
1494
1495	/* yes, we have a domain -- see if it looks like us */
1496	mydom = macvalue('m', CurEnv);
1497	if (mydom == NULL)
1498		mydom = "";
1499	i = strlen(++p);
1500	if ((canon ? strcasecmp(p, mydom) : strncasecmp(p, mydom, i)) == 0 &&
1501	    (mydom[i] == '.' || mydom[i] == '\0'))
1502		*--p = '\0';
1503}
1504/*
1505**  PROG_OPEN -- open a program for reading
1506**
1507**	Parameters:
1508**		argv -- the argument list.
1509**		pfd -- pointer to a place to store the file descriptor.
1510**		e -- the current envelope.
1511**
1512**	Returns:
1513**		pid of the process -- -1 if it failed.
1514*/
1515
1516int
1517prog_open(argv, pfd, e)
1518	char **argv;
1519	int *pfd;
1520	ENVELOPE *e;
1521{
1522	int pid;
1523	int i;
1524	int saveerrno;
1525	int fdv[2];
1526	char *p, *q;
1527	char buf[MAXLINE + 1];
1528	extern int DtableSize;
1529
1530	if (pipe(fdv) < 0)
1531	{
1532		syserr("%s: cannot create pipe for stdout", argv[0]);
1533		return -1;
1534	}
1535	pid = fork();
1536	if (pid < 0)
1537	{
1538		syserr("%s: cannot fork", argv[0]);
1539		close(fdv[0]);
1540		close(fdv[1]);
1541		return -1;
1542	}
1543	if (pid > 0)
1544	{
1545		/* parent */
1546		close(fdv[1]);
1547		*pfd = fdv[0];
1548		return pid;
1549	}
1550
1551	/* child -- close stdin */
1552	close(0);
1553
1554	/* stdout goes back to parent */
1555	close(fdv[0]);
1556	if (dup2(fdv[1], 1) < 0)
1557	{
1558		syserr("%s: cannot dup2 for stdout", argv[0]);
1559		_exit(EX_OSERR);
1560	}
1561	close(fdv[1]);
1562
1563	/* stderr goes to transcript if available */
1564	if (e->e_xfp != NULL)
1565	{
1566		if (dup2(fileno(e->e_xfp), 2) < 0)
1567		{
1568			syserr("%s: cannot dup2 for stderr", argv[0]);
1569			_exit(EX_OSERR);
1570		}
1571	}
1572
1573	/* this process has no right to the queue file */
1574	if (e->e_lockfp != NULL)
1575		close(fileno(e->e_lockfp));
1576
1577	/* run as default user */
1578	endpwent();
1579	if (setgid(DefGid) < 0 && geteuid() == 0)
1580		syserr("prog_open: setgid(%ld) failed", (long) DefGid);
1581	if (setuid(DefUid) < 0 && geteuid() == 0)
1582		syserr("prog_open: setuid(%ld) failed", (long) DefUid);
1583
1584	/* run in some directory */
1585	if (ProgMailer != NULL)
1586		p = ProgMailer->m_execdir;
1587	else
1588		p = NULL;
1589	for (; p != NULL; p = q)
1590	{
1591		q = strchr(p, ':');
1592		if (q != NULL)
1593			*q = '\0';
1594		expand(p, buf, sizeof buf, e);
1595		if (q != NULL)
1596			*q++ = ':';
1597		if (buf[0] != '\0' && chdir(buf) >= 0)
1598			break;
1599	}
1600	if (p == NULL)
1601	{
1602		/* backup directories */
1603		if (chdir("/tmp") < 0)
1604			(void) chdir("/");
1605	}
1606
1607	/* arrange for all the files to be closed */
1608	for (i = 3; i < DtableSize; i++)
1609	{
1610		register int j;
1611
1612		if ((j = fcntl(i, F_GETFD, 0)) != -1)
1613			(void) fcntl(i, F_SETFD, j | 1);
1614	}
1615
1616	/* now exec the process */
1617	execve(argv[0], (ARGV_T) argv, (ARGV_T) UserEnviron);
1618
1619	/* woops!  failed */
1620	saveerrno = errno;
1621	syserr("%s: cannot exec", argv[0]);
1622	if (transienterror(saveerrno))
1623		_exit(EX_OSERR);
1624	_exit(EX_CONFIG);
1625	return -1;	/* avoid compiler warning on IRIX */
1626}
1627/*
1628**  GET_COLUMN  -- look up a Column in a line buffer
1629**
1630**	Parameters:
1631**		line -- the raw text line to search.
1632**		col -- the column number to fetch.
1633**		delim -- the delimiter between columns.  If null,
1634**			use white space.
1635**		buf -- the output buffer.
1636**		buflen -- the length of buf.
1637**
1638**	Returns:
1639**		buf if successful.
1640**		NULL otherwise.
1641*/
1642
1643char *
1644get_column(line, col, delim, buf, buflen)
1645	char line[];
1646	int col;
1647	char delim;
1648	char buf[];
1649	int buflen;
1650{
1651	char *p;
1652	char *begin, *end;
1653	int i;
1654	char delimbuf[4];
1655
1656	if (delim == '\0')
1657		strcpy(delimbuf, "\n\t ");
1658	else
1659	{
1660		delimbuf[0] = delim;
1661		delimbuf[1] = '\0';
1662	}
1663
1664	p = line;
1665	if (*p == '\0')
1666		return NULL;			/* line empty */
1667	if (*p == delim && col == 0)
1668		return NULL;			/* first column empty */
1669
1670	begin = line;
1671
1672	if (col == 0 && delim == '\0')
1673	{
1674		while (*begin != '\0' && isascii(*begin) && isspace(*begin))
1675			begin++;
1676	}
1677
1678	for (i = 0; i < col; i++)
1679	{
1680		if ((begin = strpbrk(begin, delimbuf)) == NULL)
1681			return NULL;		/* no such column */
1682		begin++;
1683		if (delim == '\0')
1684		{
1685			while (*begin != '\0' && isascii(*begin) && isspace(*begin))
1686				begin++;
1687		}
1688	}
1689
1690	end = strpbrk(begin, delimbuf);
1691	if (end == NULL)
1692		i = strlen(begin);
1693	else
1694		i = end - begin;
1695	if (i >= buflen)
1696		i = buflen - 1;
1697	strncpy(buf, begin, i);
1698	buf[i] = '\0';
1699	return buf;
1700}
1701/*
1702**  CLEANSTRCPY -- copy string keeping out bogus characters
1703**
1704**	Parameters:
1705**		t -- "to" string.
1706**		f -- "from" string.
1707**		l -- length of space available in "to" string.
1708**
1709**	Returns:
1710**		none.
1711*/
1712
1713void
1714cleanstrcpy(t, f, l)
1715	register char *t;
1716	register char *f;
1717	int l;
1718{
1719	/* check for newlines and log if necessary */
1720	(void) denlstring(f, TRUE, TRUE);
1721
1722	l--;
1723	while (l > 0 && *f != '\0')
1724	{
1725		if (isascii(*f) &&
1726		    (isalnum(*f) || strchr("!#$%&'*+-./^_`{|}~", *f) != NULL))
1727		{
1728			l--;
1729			*t++ = *f;
1730		}
1731		f++;
1732	}
1733	*t = '\0';
1734}
1735/*
1736**  DENLSTRING -- convert newlines in a string to spaces
1737**
1738**	Parameters:
1739**		s -- the input string
1740**		strict -- if set, don't permit continuation lines.
1741**		logattacks -- if set, log attempted attacks.
1742**
1743**	Returns:
1744**		A pointer to a version of the string with newlines
1745**		mapped to spaces.  This should be copied.
1746*/
1747
1748char *
1749denlstring(s, strict, logattacks)
1750	char *s;
1751	bool strict;
1752	bool logattacks;
1753{
1754	register char *p;
1755	int l;
1756	static char *bp = NULL;
1757	static int bl = 0;
1758
1759	p = s;
1760	while ((p = strchr(p, '\n')) != NULL)
1761		if (strict || (*++p != ' ' && *p != '\t'))
1762			break;
1763	if (p == NULL)
1764		return s;
1765
1766	l = strlen(s) + 1;
1767	if (bl < l)
1768	{
1769		/* allocate more space */
1770		if (bp != NULL)
1771			free(bp);
1772		bp = xalloc(l);
1773		bl = l;
1774	}
1775	strcpy(bp, s);
1776	for (p = bp; (p = strchr(p, '\n')) != NULL; )
1777		*p++ = ' ';
1778
1779	if (logattacks)
1780	{
1781		sm_syslog(LOG_NOTICE, CurEnv->e_id,
1782			"POSSIBLE ATTACK from %.100s: newline in string \"%s\"",
1783			RealHostName == NULL ? "[UNKNOWN]" : RealHostName,
1784			shortenstring(bp, MAXSHORTSTR));
1785	}
1786
1787	return bp;
1788}
1789/*
1790**  PATH_IS_DIR -- check to see if file exists and is a directory.
1791**
1792**	There are some additional checks for security violations in
1793**	here.  This routine is intended to be used for the host status
1794**	support.
1795**
1796**	Parameters:
1797**		pathname -- pathname to check for directory-ness.
1798**		createflag -- if set, create directory if needed.
1799**
1800**	Returns:
1801**		TRUE -- if the indicated pathname is a directory
1802**		FALSE -- otherwise
1803*/
1804
1805int
1806path_is_dir(pathname, createflag)
1807	char *pathname;
1808	bool createflag;
1809{
1810	struct stat statbuf;
1811
1812#if HASLSTAT
1813	if (lstat(pathname, &statbuf) < 0)
1814#else
1815	if (stat(pathname, &statbuf) < 0)
1816#endif
1817	{
1818		if (errno != ENOENT || !createflag)
1819			return FALSE;
1820		if (mkdir(pathname, 0755) < 0)
1821			return FALSE;
1822		return TRUE;
1823	}
1824	if (!S_ISDIR(statbuf.st_mode))
1825	{
1826		errno = ENOTDIR;
1827		return FALSE;
1828	}
1829
1830	/* security: don't allow writable directories */
1831	if (bitset(S_IWGRP|S_IWOTH, statbuf.st_mode))
1832	{
1833		errno = EACCES;
1834		return FALSE;
1835	}
1836
1837	return TRUE;
1838}
1839/*
1840**  PROC_LIST_ADD -- add process id to list of our children
1841**
1842**	Parameters:
1843**		pid -- pid to add to list.
1844**
1845**	Returns:
1846**		none
1847*/
1848
1849static pid_t	*ProcListVec	= NULL;
1850static int	ProcListSize	= 0;
1851
1852#define NO_PID		((pid_t) 0)
1853#ifndef PROC_LIST_SEG
1854# define PROC_LIST_SEG	32		/* number of pids to alloc at a time */
1855#endif
1856
1857void
1858proc_list_add(pid)
1859	pid_t pid;
1860{
1861	int i;
1862	extern void proc_list_probe __P((void));
1863
1864	for (i = 0; i < ProcListSize; i++)
1865	{
1866		if (ProcListVec[i] == NO_PID)
1867			break;
1868	}
1869	if (i >= ProcListSize)
1870	{
1871		/* probe the existing vector to avoid growing infinitely */
1872		proc_list_probe();
1873
1874		/* now scan again */
1875		for (i = 0; i < ProcListSize; i++)
1876		{
1877			if (ProcListVec[i] == NO_PID)
1878				break;
1879		}
1880	}
1881	if (i >= ProcListSize)
1882	{
1883		/* grow process list */
1884		pid_t *npv;
1885
1886		npv = (pid_t *) xalloc(sizeof (pid_t) * (ProcListSize + PROC_LIST_SEG));
1887		if (ProcListSize > 0)
1888		{
1889			bcopy(ProcListVec, npv, ProcListSize * sizeof (pid_t));
1890			free(ProcListVec);
1891		}
1892		for (i = ProcListSize; i < ProcListSize + PROC_LIST_SEG; i++)
1893			npv[i] = NO_PID;
1894		i = ProcListSize;
1895		ProcListSize += PROC_LIST_SEG;
1896		ProcListVec = npv;
1897	}
1898	ProcListVec[i] = pid;
1899	CurChildren++;
1900}
1901/*
1902**  PROC_LIST_DROP -- drop pid from process list
1903**
1904**	Parameters:
1905**		pid -- pid to drop
1906**
1907**	Returns:
1908**		none.
1909*/
1910
1911void
1912proc_list_drop(pid)
1913	pid_t pid;
1914{
1915	int i;
1916
1917	for (i = 0; i < ProcListSize; i++)
1918	{
1919		if (ProcListVec[i] == pid)
1920		{
1921			ProcListVec[i] = NO_PID;
1922			break;
1923		}
1924	}
1925	if (CurChildren > 0)
1926		CurChildren--;
1927}
1928/*
1929**  PROC_LIST_CLEAR -- clear the process list
1930**
1931**	Parameters:
1932**		none.
1933**
1934**	Returns:
1935**		none.
1936*/
1937
1938void
1939proc_list_clear()
1940{
1941	int i;
1942
1943	for (i = 0; i < ProcListSize; i++)
1944		ProcListVec[i] = NO_PID;
1945	CurChildren = 0;
1946}
1947/*
1948**  PROC_LIST_PROBE -- probe processes in the list to see if they still exist
1949**
1950**	Parameters:
1951**		none
1952**
1953**	Returns:
1954**		none
1955*/
1956
1957void
1958proc_list_probe()
1959{
1960	int i;
1961
1962	for (i = 0; i < ProcListSize; i++)
1963	{
1964		if (ProcListVec[i] == NO_PID)
1965			continue;
1966		if (kill(ProcListVec[i], 0) < 0)
1967		{
1968			if (LogLevel > 3)
1969				sm_syslog(LOG_DEBUG, CurEnv->e_id,
1970					"proc_list_probe: lost pid %d",
1971					ProcListVec[i]);
1972			ProcListVec[i] = NO_PID;
1973			CurChildren--;
1974		}
1975	}
1976	if (CurChildren < 0)
1977		CurChildren = 0;
1978}
1979/*
1980**  SM_STRCASECMP -- 8-bit clean version of strcasecmp
1981**
1982**	Thank you, vendors, for making this all necessary.
1983*/
1984
1985/*
1986 * Copyright (c) 1987, 1993
1987 *	The Regents of the University of California.  All rights reserved.
1988 *
1989 * Redistribution and use in source and binary forms, with or without
1990 * modification, are permitted provided that the following conditions
1991 * are met:
1992 * 1. Redistributions of source code must retain the above copyright
1993 *    notice, this list of conditions and the following disclaimer.
1994 * 2. Redistributions in binary form must reproduce the above copyright
1995 *    notice, this list of conditions and the following disclaimer in the
1996 *    documentation and/or other materials provided with the distribution.
1997 * 3. All advertising materials mentioning features or use of this software
1998 *    must display the following acknowledgement:
1999 *	This product includes software developed by the University of
2000 *	California, Berkeley and its contributors.
2001 * 4. Neither the name of the University nor the names of its contributors
2002 *    may be used to endorse or promote products derived from this software
2003 *    without specific prior written permission.
2004 *
2005 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2006 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2007 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2008 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2009 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2010 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2011 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2012 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2013 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2014 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2015 * SUCH DAMAGE.
2016 */
2017
2018#if defined(LIBC_SCCS) && !defined(lint)
2019static char sccsid[] = "@(#)strcasecmp.c	8.1 (Berkeley) 6/4/93";
2020#endif /* LIBC_SCCS and not lint */
2021
2022/*
2023 * This array is designed for mapping upper and lower case letter
2024 * together for a case independent comparison.  The mappings are
2025 * based upon ascii character sequences.
2026 */
2027static const u_char charmap[] = {
2028	0000, 0001, 0002, 0003, 0004, 0005, 0006, 0007,
2029	0010, 0011, 0012, 0013, 0014, 0015, 0016, 0017,
2030	0020, 0021, 0022, 0023, 0024, 0025, 0026, 0027,
2031	0030, 0031, 0032, 0033, 0034, 0035, 0036, 0037,
2032	0040, 0041, 0042, 0043, 0044, 0045, 0046, 0047,
2033	0050, 0051, 0052, 0053, 0054, 0055, 0056, 0057,
2034	0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067,
2035	0070, 0071, 0072, 0073, 0074, 0075, 0076, 0077,
2036	0100, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
2037	0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157,
2038	0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167,
2039	0170, 0171, 0172, 0133, 0134, 0135, 0136, 0137,
2040	0140, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
2041	0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157,
2042	0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167,
2043	0170, 0171, 0172, 0173, 0174, 0175, 0176, 0177,
2044	0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207,
2045	0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217,
2046	0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227,
2047	0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237,
2048	0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247,
2049	0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
2050	0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,
2051	0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277,
2052	0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307,
2053	0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317,
2054	0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327,
2055	0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
2056	0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
2057	0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357,
2058	0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,
2059	0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377,
2060};
2061
2062int
2063sm_strcasecmp(s1, s2)
2064	const char *s1, *s2;
2065{
2066	register const u_char *cm = charmap,
2067			*us1 = (const u_char *)s1,
2068			*us2 = (const u_char *)s2;
2069
2070	while (cm[*us1] == cm[*us2++])
2071		if (*us1++ == '\0')
2072			return (0);
2073	return (cm[*us1] - cm[*--us2]);
2074}
2075
2076int
2077sm_strncasecmp(s1, s2, n)
2078	const char *s1, *s2;
2079	register size_t n;
2080{
2081	if (n != 0) {
2082		register const u_char *cm = charmap,
2083				*us1 = (const u_char *)s1,
2084				*us2 = (const u_char *)s2;
2085
2086		do {
2087			if (cm[*us1] != cm[*us2++])
2088				return (cm[*us1] - cm[*--us2]);
2089			if (*us1++ == '\0')
2090				break;
2091		} while (--n != 0);
2092	}
2093	return (0);
2094}
2095