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