xref: /original-bsd/usr.sbin/sendmail/src/util.c (revision ed5ac44c)
1 /*
2  * Copyright (c) 1983 Eric P. Allman
3  * Copyright (c) 1988 Regents of the University of California.
4  * All rights reserved.
5  *
6  * %sccs.include.redist.c%
7  */
8 
9 #ifndef lint
10 static char sccsid[] = "@(#)util.c	5.23 (Berkeley) 01/04/92";
11 #endif /* not lint */
12 
13 # include <stdio.h>
14 # include <sys/types.h>
15 # include <sys/stat.h>
16 # include <sysexits.h>
17 # include <errno.h>
18 # include "sendmail.h"
19 
20 /*
21 **  STRIPQUOTES -- Strip quotes & quote bits from a string.
22 **
23 **	Runs through a string and strips off unquoted quote
24 **	characters and quote bits.  This is done in place.
25 **
26 **	Parameters:
27 **		s -- the string to strip.
28 **		qf -- if set, remove actual `` " '' characters
29 **			as well as the quote bits.
30 **
31 **	Returns:
32 **		none.
33 **
34 **	Side Effects:
35 **		none.
36 **
37 **	Called By:
38 **		deliver
39 */
40 
41 stripquotes(s, qf)
42 	char *s;
43 	bool qf;
44 {
45 	register char *p;
46 	register char *q;
47 	register char c;
48 
49 	if (s == NULL)
50 		return;
51 
52 	for (p = q = s; (c = *p++) != '\0'; )
53 	{
54 		if (c != '"' || !qf)
55 			*q++ = c & 0177;
56 	}
57 	*q = '\0';
58 }
59 /*
60 **  QSTRLEN -- give me the string length assuming 0200 bits add a char
61 **
62 **	Parameters:
63 **		s -- the string to measure.
64 **
65 **	Reurns:
66 **		The length of s, including space for backslash escapes.
67 **
68 **	Side Effects:
69 **		none.
70 */
71 
72 qstrlen(s)
73 	register char *s;
74 {
75 	register int l = 0;
76 	register char c;
77 
78 	while ((c = *s++) != '\0')
79 	{
80 		if (bitset(0200, c))
81 			l++;
82 		l++;
83 	}
84 	return (l);
85 }
86 /*
87 **  CAPITALIZE -- return a copy of a string, properly capitalized.
88 **
89 **	Parameters:
90 **		s -- the string to capitalize.
91 **
92 **	Returns:
93 **		a pointer to a properly capitalized string.
94 **
95 **	Side Effects:
96 **		none.
97 */
98 
99 char *
100 capitalize(s)
101 	register char *s;
102 {
103 	static char buf[50];
104 	register char *p;
105 
106 	p = buf;
107 
108 	for (;;)
109 	{
110 		while (!isalpha(*s) && *s != '\0')
111 			*p++ = *s++;
112 		if (*s == '\0')
113 			break;
114 		*p++ = toupper(*s);
115 		s++;
116 		while (isalpha(*s))
117 			*p++ = *s++;
118 	}
119 
120 	*p = '\0';
121 	return (buf);
122 }
123 /*
124 **  XALLOC -- Allocate memory and bitch wildly on failure.
125 **
126 **	THIS IS A CLUDGE.  This should be made to give a proper
127 **	error -- but after all, what can we do?
128 **
129 **	Parameters:
130 **		sz -- size of area to allocate.
131 **
132 **	Returns:
133 **		pointer to data region.
134 **
135 **	Side Effects:
136 **		Memory is allocated.
137 */
138 
139 char *
140 xalloc(sz)
141 	register int sz;
142 {
143 	register char *p;
144 	extern char *malloc();
145 
146 	p = malloc((unsigned) sz);
147 	if (p == NULL)
148 	{
149 		syserr("Out of memory!!");
150 		abort();
151 		/* exit(EX_UNAVAILABLE); */
152 	}
153 	return (p);
154 }
155 /*
156 **  COPYPLIST -- copy list of pointers.
157 **
158 **	This routine is the equivalent of newstr for lists of
159 **	pointers.
160 **
161 **	Parameters:
162 **		list -- list of pointers to copy.
163 **			Must be NULL terminated.
164 **		copycont -- if TRUE, copy the contents of the vector
165 **			(which must be a string) also.
166 **
167 **	Returns:
168 **		a copy of 'list'.
169 **
170 **	Side Effects:
171 **		none.
172 */
173 
174 char **
175 copyplist(list, copycont)
176 	char **list;
177 	bool copycont;
178 {
179 	register char **vp;
180 	register char **newvp;
181 
182 	for (vp = list; *vp != NULL; vp++)
183 		continue;
184 
185 	vp++;
186 
187 	newvp = (char **) xalloc((int) (vp - list) * sizeof *vp);
188 	bcopy((char *) list, (char *) newvp, (int) (vp - list) * sizeof *vp);
189 
190 	if (copycont)
191 	{
192 		for (vp = newvp; *vp != NULL; vp++)
193 			*vp = newstr(*vp);
194 	}
195 
196 	return (newvp);
197 }
198 /*
199 **  PRINTAV -- print argument vector.
200 **
201 **	Parameters:
202 **		av -- argument vector.
203 **
204 **	Returns:
205 **		none.
206 **
207 **	Side Effects:
208 **		prints av.
209 */
210 
211 printav(av)
212 	register char **av;
213 {
214 	while (*av != NULL)
215 	{
216 		if (tTd(0, 44))
217 			printf("\n\t%08x=", *av);
218 		else
219 			(void) putchar(' ');
220 		xputs(*av++);
221 	}
222 	(void) putchar('\n');
223 }
224 /*
225 **  LOWER -- turn letter into lower case.
226 **
227 **	Parameters:
228 **		c -- character to turn into lower case.
229 **
230 **	Returns:
231 **		c, in lower case.
232 **
233 **	Side Effects:
234 **		none.
235 */
236 
237 char
238 lower(c)
239 	register char c;
240 {
241 	return(isascii(c) && isupper(c) ? tolower(c) : c);
242 }
243 /*
244 **  XPUTS -- put string doing control escapes.
245 **
246 **	Parameters:
247 **		s -- string to put.
248 **
249 **	Returns:
250 **		none.
251 **
252 **	Side Effects:
253 **		output to stdout
254 */
255 
256 xputs(s)
257 	register char *s;
258 {
259 	register char c;
260 	register struct metamac *mp;
261 	extern struct metamac MetaMacros[];
262 
263 	if (s == NULL)
264 	{
265 		printf("<null>");
266 		return;
267 	}
268 	c = *s;
269 	if (c == MATCHREPL && isdigit(s[1]) && s[2] == '\0')
270 	{
271 		printf("$%c", s[1]);
272 		return;
273 	}
274 	for (mp = MetaMacros; mp->metaname != NULL; mp++)
275 	{
276 		if (mp->metaval == c)
277 		{
278 			printf("$%c%s", mp->metaname, ++s);
279 			return;
280 		}
281 	}
282 	(void) putchar('"');
283 	while ((c = *s++) != '\0')
284 	{
285 		if (!isascii(c))
286 		{
287 			(void) putchar('\\');
288 			c &= 0177;
289 		}
290 		if (c < 040 || c >= 0177)
291 		{
292 			switch (c)
293 			{
294 			  case '\n':
295 				c = 'n';
296 				break;
297 
298 			  case '\r':
299 				c = 'r';
300 				break;
301 
302 			  case '\t':
303 				c = 't';
304 				break;
305 
306 			  default:
307 				(void) putchar('^');
308 				(void) putchar(c ^ 0100);
309 				continue;
310 			}
311 			(void) putchar('\\');
312 		}
313 		(void) putchar(c);
314 	}
315 	(void) putchar('"');
316 	(void) fflush(stdout);
317 }
318 /*
319 **  MAKELOWER -- Translate a line into lower case
320 **
321 **	Parameters:
322 **		p -- the string to translate.  If NULL, return is
323 **			immediate.
324 **
325 **	Returns:
326 **		none.
327 **
328 **	Side Effects:
329 **		String pointed to by p is translated to lower case.
330 **
331 **	Called By:
332 **		parse
333 */
334 
335 makelower(p)
336 	register char *p;
337 {
338 	register char c;
339 
340 	if (p == NULL)
341 		return;
342 	for (; (c = *p) != '\0'; p++)
343 		if (isascii(c) && isupper(c))
344 			*p = tolower(c);
345 }
346 /*
347 **  BUILDFNAME -- build full name from gecos style entry.
348 **
349 **	This routine interprets the strange entry that would appear
350 **	in the GECOS field of the password file.
351 **
352 **	Parameters:
353 **		p -- name to build.
354 **		login -- the login name of this user (for &).
355 **		buf -- place to put the result.
356 **
357 **	Returns:
358 **		none.
359 **
360 **	Side Effects:
361 **		none.
362 */
363 
364 buildfname(p, login, buf)
365 	register char *p;
366 	char *login;
367 	char *buf;
368 {
369 	register char *bp = buf;
370 
371 	if (*p == '*')
372 		p++;
373 	while (*p != '\0' && *p != ',' && *p != ';' && *p != '%')
374 	{
375 		if (*p == '&')
376 		{
377 			(void) strcpy(bp, login);
378 			*bp = toupper(*bp);
379 			while (*bp != '\0')
380 				bp++;
381 			p++;
382 		}
383 		else
384 			*bp++ = *p++;
385 	}
386 	*bp = '\0';
387 }
388 /*
389 **  SAFEFILE -- return true if a file exists and is safe for a user.
390 **
391 **	Parameters:
392 **		fn -- filename to check.
393 **		uid -- uid to compare against.
394 **		mode -- mode bits that must match.
395 **
396 **	Returns:
397 **		TRUE if fn exists, is owned by uid, and matches mode.
398 **		FALSE otherwise.
399 **
400 **	Side Effects:
401 **		none.
402 */
403 
404 bool
405 safefile(fn, uid, mode)
406 	char *fn;
407 	int uid;
408 	int mode;
409 {
410 	struct stat stbuf;
411 
412 	if (stat(fn, &stbuf) >= 0 && stbuf.st_uid == uid &&
413 	    (stbuf.st_mode & mode) == mode)
414 		return (TRUE);
415 	errno = 0;
416 	return (FALSE);
417 }
418 /*
419 **  FIXCRLF -- fix <CR><LF> in line.
420 **
421 **	Looks for the <CR><LF> combination and turns it into the
422 **	UNIX canonical <NL> character.  It only takes one line,
423 **	i.e., it is assumed that the first <NL> found is the end
424 **	of the line.
425 **
426 **	Parameters:
427 **		line -- the line to fix.
428 **		stripnl -- if true, strip the newline also.
429 **
430 **	Returns:
431 **		none.
432 **
433 **	Side Effects:
434 **		line is changed in place.
435 */
436 
437 fixcrlf(line, stripnl)
438 	char *line;
439 	bool stripnl;
440 {
441 	register char *p;
442 
443 	p = index(line, '\n');
444 	if (p == NULL)
445 		return;
446 	if (p > line && p[-1] == '\r')
447 		p--;
448 	if (!stripnl)
449 		*p++ = '\n';
450 	*p = '\0';
451 }
452 /*
453 **  DFOPEN -- determined file open
454 **
455 **	This routine has the semantics of fopen, except that it will
456 **	keep trying a few times to make this happen.  The idea is that
457 **	on very loaded systems, we may run out of resources (inodes,
458 **	whatever), so this tries to get around it.
459 */
460 
461 FILE *
462 dfopen(filename, mode)
463 	char *filename;
464 	char *mode;
465 {
466 	register int tries;
467 	register FILE *fp;
468 
469 	for (tries = 0; tries < 10; tries++)
470 	{
471 		sleep((unsigned) (10 * tries));
472 		errno = 0;
473 		fp = fopen(filename, mode);
474 		if (fp != NULL)
475 			break;
476 		if (errno != ENFILE && errno != EINTR)
477 			break;
478 	}
479 	errno = 0;
480 	return (fp);
481 }
482 /*
483 **  PUTLINE -- put a line like fputs obeying SMTP conventions
484 **
485 **	This routine always guarantees outputing a newline (or CRLF,
486 **	as appropriate) at the end of the string.
487 **
488 **	Parameters:
489 **		l -- line to put.
490 **		fp -- file to put it onto.
491 **		m -- the mailer used to control output.
492 **
493 **	Returns:
494 **		none
495 **
496 **	Side Effects:
497 **		output of l to fp.
498 */
499 
500 putline(l, fp, m)
501 	register char *l;
502 	FILE *fp;
503 	MAILER *m;
504 {
505 	register char *p;
506 	register char svchar;
507 
508 	/* strip out 0200 bits -- these can look like TELNET protocol */
509 	if (bitnset(M_7BITS, m->m_flags))
510 	{
511 		for (p = l; svchar = *p; ++p)
512 			if (svchar & 0200)
513 				*p = svchar &~ 0200;
514 	}
515 
516 	do
517 	{
518 		/* find the end of the line */
519 		p = index(l, '\n');
520 		if (p == NULL)
521 			p = &l[strlen(l)];
522 
523 		/* check for line overflow */
524 		while (m->m_linelimit > 0 && (p - l) > m->m_linelimit)
525 		{
526 			register char *q = &l[m->m_linelimit - 1];
527 
528 			svchar = *q;
529 			*q = '\0';
530 			if (l[0] == '.' && bitnset(M_XDOT, m->m_flags))
531 				(void) putc('.', fp);
532 			fputs(l, fp);
533 			(void) putc('!', fp);
534 			fputs(m->m_eol, fp);
535 			*q = svchar;
536 			l = q;
537 		}
538 
539 		/* output last part */
540 		if (l[0] == '.' && bitnset(M_XDOT, m->m_flags))
541 			(void) putc('.', fp);
542 		for ( ; l < p; ++l)
543 			(void) putc(*l, fp);
544 		fputs(m->m_eol, fp);
545 		if (*l == '\n')
546 			++l;
547 	} while (l[0] != '\0');
548 }
549 /*
550 **  XUNLINK -- unlink a file, doing logging as appropriate.
551 **
552 **	Parameters:
553 **		f -- name of file to unlink.
554 **
555 **	Returns:
556 **		none.
557 **
558 **	Side Effects:
559 **		f is unlinked.
560 */
561 
562 xunlink(f)
563 	char *f;
564 {
565 	register int i;
566 
567 # ifdef LOG
568 	if (LogLevel > 20)
569 		syslog(LOG_DEBUG, "%s: unlink %s\n", CurEnv->e_id, f);
570 # endif LOG
571 
572 	i = unlink(f);
573 # ifdef LOG
574 	if (i < 0 && LogLevel > 21)
575 		syslog(LOG_DEBUG, "%s: unlink-fail %d", f, errno);
576 # endif LOG
577 }
578 /*
579 **  SFGETS -- "safe" fgets -- times out and ignores random interrupts.
580 **
581 **	Parameters:
582 **		buf -- place to put the input line.
583 **		siz -- size of buf.
584 **		fp -- file to read from.
585 **
586 **	Returns:
587 **		NULL on error (including timeout).  This will also leave
588 **			buf containing a null string.
589 **		buf otherwise.
590 **
591 **	Side Effects:
592 **		none.
593 */
594 
595 static jmp_buf	CtxReadTimeout;
596 
597 char *
598 sfgets(buf, siz, fp)
599 	char *buf;
600 	int siz;
601 	FILE *fp;
602 {
603 	register EVENT *ev = NULL;
604 	register char *p;
605 	static int readtimeout();
606 
607 	/* set the timeout */
608 	if (ReadTimeout != 0)
609 	{
610 		if (setjmp(CtxReadTimeout) != 0)
611 		{
612 # ifdef LOG
613 			syslog(LOG_NOTICE,
614 			    "timeout waiting for input from %s\n",
615 			    RealHostName? RealHostName: "local");
616 # endif
617 			errno = 0;
618 			usrerr("451 timeout waiting for input");
619 			buf[0] = '\0';
620 			return (NULL);
621 		}
622 		ev = setevent((time_t) ReadTimeout, readtimeout, 0);
623 	}
624 
625 	/* try to read */
626 	p = NULL;
627 	while (p == NULL && !feof(fp) && !ferror(fp))
628 	{
629 		errno = 0;
630 		p = fgets(buf, siz, fp);
631 		if (errno == EINTR)
632 			clearerr(fp);
633 	}
634 
635 	/* clear the event if it has not sprung */
636 	clrevent(ev);
637 
638 	/* clean up the books and exit */
639 	LineNumber++;
640 	if (p == NULL)
641 	{
642 		buf[0] = '\0';
643 		return (NULL);
644 	}
645 	if (!EightBit)
646 		for (p = buf; *p != '\0'; p++)
647 			*p &= ~0200;
648 	return (buf);
649 }
650 
651 static
652 readtimeout()
653 {
654 	longjmp(CtxReadTimeout, 1);
655 }
656 /*
657 **  FGETFOLDED -- like fgets, but know about folded lines.
658 **
659 **	Parameters:
660 **		buf -- place to put result.
661 **		n -- bytes available.
662 **		f -- file to read from.
663 **
664 **	Returns:
665 **		buf on success, NULL on error or EOF.
666 **
667 **	Side Effects:
668 **		buf gets lines from f, with continuation lines (lines
669 **		with leading white space) appended.  CRLF's are mapped
670 **		into single newlines.  Any trailing NL is stripped.
671 */
672 
673 char *
674 fgetfolded(buf, n, f)
675 	char *buf;
676 	register int n;
677 	FILE *f;
678 {
679 	register char *p = buf;
680 	register int i;
681 
682 	n--;
683 	while ((i = getc(f)) != EOF)
684 	{
685 		if (i == '\r')
686 		{
687 			i = getc(f);
688 			if (i != '\n')
689 			{
690 				if (i != EOF)
691 					(void) ungetc(i, f);
692 				i = '\r';
693 			}
694 		}
695 		if (--n > 0)
696 			*p++ = i;
697 		if (i == '\n')
698 		{
699 			LineNumber++;
700 			i = getc(f);
701 			if (i != EOF)
702 				(void) ungetc(i, f);
703 			if (i != ' ' && i != '\t')
704 			{
705 				*--p = '\0';
706 				if (!EightBit)
707 				{
708 					/* headers always have to be 7-bit */
709 					for (p = buf; (i = *p) != '\0'; *p++)
710 						if (bitset(0200, i))
711 							*p = i & ~0200;
712 				}
713 				return (buf);
714 			}
715 		}
716 	}
717 	return (NULL);
718 }
719 /*
720 **  CURTIME -- return current time.
721 **
722 **	Parameters:
723 **		none.
724 **
725 **	Returns:
726 **		the current time.
727 **
728 **	Side Effects:
729 **		none.
730 */
731 
732 time_t
733 curtime()
734 {
735 	auto time_t t;
736 
737 	(void) time(&t);
738 	return (t);
739 }
740 /*
741 **  ATOBOOL -- convert a string representation to boolean.
742 **
743 **	Defaults to "TRUE"
744 **
745 **	Parameters:
746 **		s -- string to convert.  Takes "tTyY" as true,
747 **			others as false.
748 **
749 **	Returns:
750 **		A boolean representation of the string.
751 **
752 **	Side Effects:
753 **		none.
754 */
755 
756 bool
757 atobool(s)
758 	register char *s;
759 {
760 	if (*s == '\0' || index("tTyY", *s) != NULL)
761 		return (TRUE);
762 	return (FALSE);
763 }
764 /*
765 **  ATOOCT -- convert a string representation to octal.
766 **
767 **	Parameters:
768 **		s -- string to convert.
769 **
770 **	Returns:
771 **		An integer representing the string interpreted as an
772 **		octal number.
773 **
774 **	Side Effects:
775 **		none.
776 */
777 
778 atooct(s)
779 	register char *s;
780 {
781 	register int i = 0;
782 
783 	while (*s >= '0' && *s <= '7')
784 		i = (i << 3) | (*s++ - '0');
785 	return (i);
786 }
787 /*
788 **  WAITFOR -- wait for a particular process id.
789 **
790 **	Parameters:
791 **		pid -- process id to wait for.
792 **
793 **	Returns:
794 **		status of pid.
795 **		-1 if pid never shows up.
796 **
797 **	Side Effects:
798 **		none.
799 */
800 
801 waitfor(pid)
802 	int pid;
803 {
804 	auto int st;
805 	int i;
806 
807 	do
808 	{
809 		errno = 0;
810 		i = wait(&st);
811 	} while ((i >= 0 || errno == EINTR) && i != pid);
812 	if (i < 0)
813 		st = -1;
814 	return (st);
815 }
816 /*
817 **  BITINTERSECT -- tell if two bitmaps intersect
818 **
819 **	Parameters:
820 **		a, b -- the bitmaps in question
821 **
822 **	Returns:
823 **		TRUE if they have a non-null intersection
824 **		FALSE otherwise
825 **
826 **	Side Effects:
827 **		none.
828 */
829 
830 bool
831 bitintersect(a, b)
832 	BITMAP a;
833 	BITMAP b;
834 {
835 	int i;
836 
837 	for (i = BITMAPBYTES / sizeof (int); --i >= 0; )
838 		if ((a[i] & b[i]) != 0)
839 			return (TRUE);
840 	return (FALSE);
841 }
842 /*
843 **  BITZEROP -- tell if a bitmap is all zero
844 **
845 **	Parameters:
846 **		map -- the bit map to check
847 **
848 **	Returns:
849 **		TRUE if map is all zero.
850 **		FALSE if there are any bits set in map.
851 **
852 **	Side Effects:
853 **		none.
854 */
855 
856 bool
857 bitzerop(map)
858 	BITMAP map;
859 {
860 	int i;
861 
862 	for (i = BITMAPBYTES / sizeof (int); --i >= 0; )
863 		if (map[i] != 0)
864 			return (FALSE);
865 	return (TRUE);
866 }
867