xref: /csrg-svn/usr.sbin/sendmail/src/util.c (revision 46928)
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.19 (Berkeley) 03/02/91";
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 
261 	if (s == NULL)
262 	{
263 		printf("<null>");
264 		return;
265 	}
266 	(void) putchar('"');
267 	while ((c = *s++) != '\0')
268 	{
269 		if (!isascii(c))
270 		{
271 			(void) putchar('\\');
272 			c &= 0177;
273 		}
274 		if (c < 040 || c >= 0177)
275 		{
276 			(void) putchar('^');
277 			c ^= 0100;
278 		}
279 		(void) putchar(c);
280 	}
281 	(void) putchar('"');
282 	(void) fflush(stdout);
283 }
284 /*
285 **  MAKELOWER -- Translate a line into lower case
286 **
287 **	Parameters:
288 **		p -- the string to translate.  If NULL, return is
289 **			immediate.
290 **
291 **	Returns:
292 **		none.
293 **
294 **	Side Effects:
295 **		String pointed to by p is translated to lower case.
296 **
297 **	Called By:
298 **		parse
299 */
300 
301 makelower(p)
302 	register char *p;
303 {
304 	register char c;
305 
306 	if (p == NULL)
307 		return;
308 	for (; (c = *p) != '\0'; p++)
309 		if (isascii(c) && isupper(c))
310 			*p = tolower(c);
311 }
312 /*
313 **  BUILDFNAME -- build full name from gecos style entry.
314 **
315 **	This routine interprets the strange entry that would appear
316 **	in the GECOS field of the password file.
317 **
318 **	Parameters:
319 **		p -- name to build.
320 **		login -- the login name of this user (for &).
321 **		buf -- place to put the result.
322 **
323 **	Returns:
324 **		none.
325 **
326 **	Side Effects:
327 **		none.
328 */
329 
330 buildfname(p, login, buf)
331 	register char *p;
332 	char *login;
333 	char *buf;
334 {
335 	register char *bp = buf;
336 
337 	if (*p == '*')
338 		p++;
339 	while (*p != '\0' && *p != ',' && *p != ';' && *p != '%')
340 	{
341 		if (*p == '&')
342 		{
343 			(void) strcpy(bp, login);
344 			*bp = toupper(*bp);
345 			while (*bp != '\0')
346 				bp++;
347 			p++;
348 		}
349 		else
350 			*bp++ = *p++;
351 	}
352 	*bp = '\0';
353 }
354 /*
355 **  SAFEFILE -- return true if a file exists and is safe for a user.
356 **
357 **	Parameters:
358 **		fn -- filename to check.
359 **		uid -- uid to compare against.
360 **		mode -- mode bits that must match.
361 **
362 **	Returns:
363 **		TRUE if fn exists, is owned by uid, and matches mode.
364 **		FALSE otherwise.
365 **
366 **	Side Effects:
367 **		none.
368 */
369 
370 bool
371 safefile(fn, uid, mode)
372 	char *fn;
373 	int uid;
374 	int mode;
375 {
376 	struct stat stbuf;
377 
378 	if (stat(fn, &stbuf) >= 0 && stbuf.st_uid == uid &&
379 	    (stbuf.st_mode & mode) == mode)
380 		return (TRUE);
381 	errno = 0;
382 	return (FALSE);
383 }
384 /*
385 **  FIXCRLF -- fix <CR><LF> in line.
386 **
387 **	Looks for the <CR><LF> combination and turns it into the
388 **	UNIX canonical <NL> character.  It only takes one line,
389 **	i.e., it is assumed that the first <NL> found is the end
390 **	of the line.
391 **
392 **	Parameters:
393 **		line -- the line to fix.
394 **		stripnl -- if true, strip the newline also.
395 **
396 **	Returns:
397 **		none.
398 **
399 **	Side Effects:
400 **		line is changed in place.
401 */
402 
403 fixcrlf(line, stripnl)
404 	char *line;
405 	bool stripnl;
406 {
407 	register char *p;
408 
409 	p = index(line, '\n');
410 	if (p == NULL)
411 		return;
412 	if (p > line && p[-1] == '\r')
413 		p--;
414 	if (!stripnl)
415 		*p++ = '\n';
416 	*p = '\0';
417 }
418 /*
419 **  DFOPEN -- determined file open
420 **
421 **	This routine has the semantics of fopen, except that it will
422 **	keep trying a few times to make this happen.  The idea is that
423 **	on very loaded systems, we may run out of resources (inodes,
424 **	whatever), so this tries to get around it.
425 */
426 
427 FILE *
428 dfopen(filename, mode)
429 	char *filename;
430 	char *mode;
431 {
432 	register int tries;
433 	register FILE *fp;
434 
435 	for (tries = 0; tries < 10; tries++)
436 	{
437 		sleep((unsigned) (10 * tries));
438 		errno = 0;
439 		fp = fopen(filename, mode);
440 		if (fp != NULL)
441 			break;
442 		if (errno != ENFILE && errno != EINTR)
443 			break;
444 	}
445 	errno = 0;
446 	return (fp);
447 }
448 /*
449 **  PUTLINE -- put a line like fputs obeying SMTP conventions
450 **
451 **	This routine always guarantees outputing a newline (or CRLF,
452 **	as appropriate) at the end of the string.
453 **
454 **	Parameters:
455 **		l -- line to put.
456 **		fp -- file to put it onto.
457 **		m -- the mailer used to control output.
458 **
459 **	Returns:
460 **		none
461 **
462 **	Side Effects:
463 **		output of l to fp.
464 */
465 
466 # define SMTPLINELIM	990	/* maximum line length */
467 
468 putline(l, fp, m)
469 	register char *l;
470 	FILE *fp;
471 	MAILER *m;
472 {
473 	register char *p;
474 	char svchar;
475 
476 	/* strip out 0200 bits -- these can look like TELNET protocol */
477 	if (bitnset(M_LIMITS, m->m_flags))
478 	{
479 		p = l;
480 		while ((*p++ &= ~0200) != 0)
481 			continue;
482 	}
483 
484 	do
485 	{
486 		/* find the end of the line */
487 		p = index(l, '\n');
488 		if (p == NULL)
489 			p = &l[strlen(l)];
490 
491 		/* check for line overflow */
492 		while ((p - l) > SMTPLINELIM && bitnset(M_LIMITS, m->m_flags))
493 		{
494 			register char *q = &l[SMTPLINELIM - 1];
495 
496 			svchar = *q;
497 			*q = '\0';
498 			if (l[0] == '.' && bitnset(M_XDOT, m->m_flags))
499 				(void) putc('.', fp);
500 			fputs(l, fp);
501 			(void) putc('!', fp);
502 			fputs(m->m_eol, fp);
503 			*q = svchar;
504 			l = q;
505 		}
506 
507 		/* output last part */
508 		svchar = *p;
509 		*p = '\0';
510 		if (l[0] == '.' && bitnset(M_XDOT, m->m_flags))
511 			(void) putc('.', fp);
512 		fputs(l, fp);
513 		fputs(m->m_eol, fp);
514 		*p = svchar;
515 		l = p;
516 		if (*l == '\n')
517 			l++;
518 	} while (l[0] != '\0');
519 }
520 /*
521 **  XUNLINK -- unlink a file, doing logging as appropriate.
522 **
523 **	Parameters:
524 **		f -- name of file to unlink.
525 **
526 **	Returns:
527 **		none.
528 **
529 **	Side Effects:
530 **		f is unlinked.
531 */
532 
533 xunlink(f)
534 	char *f;
535 {
536 	register int i;
537 
538 # ifdef LOG
539 	if (LogLevel > 20)
540 		syslog(LOG_DEBUG, "%s: unlink %s\n", CurEnv->e_id, f);
541 # endif LOG
542 
543 	i = unlink(f);
544 # ifdef LOG
545 	if (i < 0 && LogLevel > 21)
546 		syslog(LOG_DEBUG, "%s: unlink-fail %d", f, errno);
547 # endif LOG
548 }
549 /*
550 **  SFGETS -- "safe" fgets -- times out and ignores random interrupts.
551 **
552 **	Parameters:
553 **		buf -- place to put the input line.
554 **		siz -- size of buf.
555 **		fp -- file to read from.
556 **
557 **	Returns:
558 **		NULL on error (including timeout).  This will also leave
559 **			buf containing a null string.
560 **		buf otherwise.
561 **
562 **	Side Effects:
563 **		none.
564 */
565 
566 static jmp_buf	CtxReadTimeout;
567 
568 char *
569 sfgets(buf, siz, fp)
570 	char *buf;
571 	int siz;
572 	FILE *fp;
573 {
574 	register EVENT *ev = NULL;
575 	register char *p;
576 	static int readtimeout();
577 
578 	/* set the timeout */
579 	if (ReadTimeout != 0)
580 	{
581 		if (setjmp(CtxReadTimeout) != 0)
582 		{
583 # ifdef LOG
584 			syslog(LOG_NOTICE,
585 			    "timeout waiting for input from %s\n",
586 			    RealHostName? RealHostName: "local");
587 # endif
588 			errno = 0;
589 			usrerr("451 timeout waiting for input");
590 			buf[0] = '\0';
591 			return (NULL);
592 		}
593 		ev = setevent((time_t) ReadTimeout, readtimeout, 0);
594 	}
595 
596 	/* try to read */
597 	p = NULL;
598 	while (p == NULL && !feof(fp) && !ferror(fp))
599 	{
600 		errno = 0;
601 		p = fgets(buf, siz, fp);
602 		if (errno == EINTR)
603 			clearerr(fp);
604 	}
605 
606 	/* clear the event if it has not sprung */
607 	clrevent(ev);
608 
609 	/* clean up the books and exit */
610 	LineNumber++;
611 	if (p == NULL)
612 	{
613 		buf[0] = '\0';
614 		return (NULL);
615 	}
616 	for (p = buf; *p != '\0'; p++)
617 		*p &= ~0200;
618 	return (buf);
619 }
620 
621 static
622 readtimeout()
623 {
624 	longjmp(CtxReadTimeout, 1);
625 }
626 /*
627 **  FGETFOLDED -- like fgets, but know about folded lines.
628 **
629 **	Parameters:
630 **		buf -- place to put result.
631 **		n -- bytes available.
632 **		f -- file to read from.
633 **
634 **	Returns:
635 **		buf on success, NULL on error or EOF.
636 **
637 **	Side Effects:
638 **		buf gets lines from f, with continuation lines (lines
639 **		with leading white space) appended.  CRLF's are mapped
640 **		into single newlines.  Any trailing NL is stripped.
641 */
642 
643 char *
644 fgetfolded(buf, n, f)
645 	char *buf;
646 	register int n;
647 	FILE *f;
648 {
649 	register char *p = buf;
650 	register int i;
651 
652 	n--;
653 	while ((i = getc(f)) != EOF)
654 	{
655 		if (i == '\r')
656 		{
657 			i = getc(f);
658 			if (i != '\n')
659 			{
660 				if (i != EOF)
661 					(void) ungetc(i, f);
662 				i = '\r';
663 			}
664 		}
665 		if (--n > 0)
666 			*p++ = i;
667 		if (i == '\n')
668 		{
669 			LineNumber++;
670 			i = getc(f);
671 			if (i != EOF)
672 				(void) ungetc(i, f);
673 			if (i != ' ' && i != '\t')
674 			{
675 				*--p = '\0';
676 				return (buf);
677 			}
678 		}
679 	}
680 	return (NULL);
681 }
682 /*
683 **  CURTIME -- return current time.
684 **
685 **	Parameters:
686 **		none.
687 **
688 **	Returns:
689 **		the current time.
690 **
691 **	Side Effects:
692 **		none.
693 */
694 
695 time_t
696 curtime()
697 {
698 	auto time_t t;
699 
700 	(void) time(&t);
701 	return (t);
702 }
703 /*
704 **  ATOBOOL -- convert a string representation to boolean.
705 **
706 **	Defaults to "TRUE"
707 **
708 **	Parameters:
709 **		s -- string to convert.  Takes "tTyY" as true,
710 **			others as false.
711 **
712 **	Returns:
713 **		A boolean representation of the string.
714 **
715 **	Side Effects:
716 **		none.
717 */
718 
719 bool
720 atobool(s)
721 	register char *s;
722 {
723 	if (*s == '\0' || index("tTyY", *s) != NULL)
724 		return (TRUE);
725 	return (FALSE);
726 }
727 /*
728 **  ATOOCT -- convert a string representation to octal.
729 **
730 **	Parameters:
731 **		s -- string to convert.
732 **
733 **	Returns:
734 **		An integer representing the string interpreted as an
735 **		octal number.
736 **
737 **	Side Effects:
738 **		none.
739 */
740 
741 atooct(s)
742 	register char *s;
743 {
744 	register int i = 0;
745 
746 	while (*s >= '0' && *s <= '7')
747 		i = (i << 3) | (*s++ - '0');
748 	return (i);
749 }
750 /*
751 **  WAITFOR -- wait for a particular process id.
752 **
753 **	Parameters:
754 **		pid -- process id to wait for.
755 **
756 **	Returns:
757 **		status of pid.
758 **		-1 if pid never shows up.
759 **
760 **	Side Effects:
761 **		none.
762 */
763 
764 waitfor(pid)
765 	int pid;
766 {
767 	auto int st;
768 	int i;
769 
770 	do
771 	{
772 		errno = 0;
773 		i = wait(&st);
774 	} while ((i >= 0 || errno == EINTR) && i != pid);
775 	if (i < 0)
776 		st = -1;
777 	return (st);
778 }
779 /*
780 **  BITINTERSECT -- tell if two bitmaps intersect
781 **
782 **	Parameters:
783 **		a, b -- the bitmaps in question
784 **
785 **	Returns:
786 **		TRUE if they have a non-null intersection
787 **		FALSE otherwise
788 **
789 **	Side Effects:
790 **		none.
791 */
792 
793 bool
794 bitintersect(a, b)
795 	BITMAP a;
796 	BITMAP b;
797 {
798 	int i;
799 
800 	for (i = BITMAPBYTES / sizeof (int); --i >= 0; )
801 		if ((a[i] & b[i]) != 0)
802 			return (TRUE);
803 	return (FALSE);
804 }
805 /*
806 **  BITZEROP -- tell if a bitmap is all zero
807 **
808 **	Parameters:
809 **		map -- the bit map to check
810 **
811 **	Returns:
812 **		TRUE if map is all zero.
813 **		FALSE if there are any bits set in map.
814 **
815 **	Side Effects:
816 **		none.
817 */
818 
819 bool
820 bitzerop(map)
821 	BITMAP map;
822 {
823 	int i;
824 
825 	for (i = BITMAPBYTES / sizeof (int); --i >= 0; )
826 		if (map[i] != 0)
827 			return (FALSE);
828 	return (TRUE);
829 }
830