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