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