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