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