xref: /csrg-svn/usr.sbin/sendmail/src/util.c (revision 33731)
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.11 (Berkeley) 03/13/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[-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 #ifndef ETIMEDOUT
576 #define ETIMEDOUT	EINTR
577 #endif
578 
579 char *
580 sfgets(buf, siz, fp)
581 	char *buf;
582 	int siz;
583 	FILE *fp;
584 {
585 	register EVENT *ev = NULL;
586 	register char *p;
587 	extern readtimeout();
588 
589 	/* set the timeout */
590 	if (ReadTimeout != 0)
591 	{
592 		if (setjmp(CtxReadTimeout) != 0)
593 		{
594 			errno = ETIMEDOUT;
595 			syserr("net timeout");
596 			buf[0] = '\0';
597 			return (NULL);
598 		}
599 		ev = setevent((time_t) ReadTimeout, readtimeout, 0);
600 	}
601 
602 	/* try to read */
603 	p = NULL;
604 	while (p == NULL && !feof(fp) && !ferror(fp))
605 	{
606 		errno = 0;
607 		p = fgets(buf, siz, fp);
608 		if (errno == EINTR)
609 			clearerr(fp);
610 	}
611 
612 	/* clear the event if it has not sprung */
613 	clrevent(ev);
614 
615 	/* clean up the books and exit */
616 	LineNumber++;
617 	if (p == NULL)
618 	{
619 		buf[0] = '\0';
620 		return (NULL);
621 	}
622 	for (p = buf; *p != '\0'; p++)
623 		*p &= ~0200;
624 	return (buf);
625 }
626 
627 static
628 readtimeout()
629 {
630 	longjmp(CtxReadTimeout, 1);
631 }
632 /*
633 **  FGETFOLDED -- like fgets, but know about folded lines.
634 **
635 **	Parameters:
636 **		buf -- place to put result.
637 **		n -- bytes available.
638 **		f -- file to read from.
639 **
640 **	Returns:
641 **		buf on success, NULL on error or EOF.
642 **
643 **	Side Effects:
644 **		buf gets lines from f, with continuation lines (lines
645 **		with leading white space) appended.  CRLF's are mapped
646 **		into single newlines.  Any trailing NL is stripped.
647 */
648 
649 char *
650 fgetfolded(buf, n, f)
651 	char *buf;
652 	register int n;
653 	FILE *f;
654 {
655 	register char *p = buf;
656 	register int i;
657 
658 	n--;
659 	while ((i = getc(f)) != EOF)
660 	{
661 		if (i == '\r')
662 		{
663 			i = getc(f);
664 			if (i != '\n')
665 			{
666 				if (i != EOF)
667 					(void) ungetc(i, f);
668 				i = '\r';
669 			}
670 		}
671 		if (--n > 0)
672 			*p++ = i;
673 		if (i == '\n')
674 		{
675 			LineNumber++;
676 			i = getc(f);
677 			if (i != EOF)
678 				(void) ungetc(i, f);
679 			if (i != ' ' && i != '\t')
680 			{
681 				*--p = '\0';
682 				return (buf);
683 			}
684 		}
685 	}
686 	return (NULL);
687 }
688 /*
689 **  CURTIME -- return current time.
690 **
691 **	Parameters:
692 **		none.
693 **
694 **	Returns:
695 **		the current time.
696 **
697 **	Side Effects:
698 **		none.
699 */
700 
701 time_t
702 curtime()
703 {
704 	auto time_t t;
705 
706 	(void) time(&t);
707 	return (t);
708 }
709 /*
710 **  ATOBOOL -- convert a string representation to boolean.
711 **
712 **	Defaults to "TRUE"
713 **
714 **	Parameters:
715 **		s -- string to convert.  Takes "tTyY" as true,
716 **			others as false.
717 **
718 **	Returns:
719 **		A boolean representation of the string.
720 **
721 **	Side Effects:
722 **		none.
723 */
724 
725 bool
726 atobool(s)
727 	register char *s;
728 {
729 	if (*s == '\0' || index("tTyY", *s) != NULL)
730 		return (TRUE);
731 	return (FALSE);
732 }
733 /*
734 **  ATOOCT -- convert a string representation to octal.
735 **
736 **	Parameters:
737 **		s -- string to convert.
738 **
739 **	Returns:
740 **		An integer representing the string interpreted as an
741 **		octal number.
742 **
743 **	Side Effects:
744 **		none.
745 */
746 
747 atooct(s)
748 	register char *s;
749 {
750 	register int i = 0;
751 
752 	while (*s >= '0' && *s <= '7')
753 		i = (i << 3) | (*s++ - '0');
754 	return (i);
755 }
756 /*
757 **  WAITFOR -- wait for a particular process id.
758 **
759 **	Parameters:
760 **		pid -- process id to wait for.
761 **
762 **	Returns:
763 **		status of pid.
764 **		-1 if pid never shows up.
765 **
766 **	Side Effects:
767 **		none.
768 */
769 
770 waitfor(pid)
771 	int pid;
772 {
773 	auto int st;
774 	int i;
775 
776 	do
777 	{
778 		errno = 0;
779 		i = wait(&st);
780 	} while ((i >= 0 || errno == EINTR) && i != pid);
781 	if (i < 0)
782 		st = -1;
783 	return (st);
784 }
785 /*
786 **  BITINTERSECT -- tell if two bitmaps intersect
787 **
788 **	Parameters:
789 **		a, b -- the bitmaps in question
790 **
791 **	Returns:
792 **		TRUE if they have a non-null intersection
793 **		FALSE otherwise
794 **
795 **	Side Effects:
796 **		none.
797 */
798 
799 bool
800 bitintersect(a, b)
801 	BITMAP a;
802 	BITMAP b;
803 {
804 	int i;
805 
806 	for (i = BITMAPBYTES / sizeof (int); --i >= 0; )
807 		if ((a[i] & b[i]) != 0)
808 			return (TRUE);
809 	return (FALSE);
810 }
811 /*
812 **  BITZEROP -- tell if a bitmap is all zero
813 **
814 **	Parameters:
815 **		map -- the bit map to check
816 **
817 **	Returns:
818 **		TRUE if map is all zero.
819 **		FALSE if there are any bits set in map.
820 **
821 **	Side Effects:
822 **		none.
823 */
824 
825 bool
826 bitzerop(map)
827 	BITMAP map;
828 {
829 	int i;
830 
831 	for (i = BITMAPBYTES / sizeof (int); --i >= 0; )
832 		if (map[i] != 0)
833 			return (FALSE);
834 	return (TRUE);
835 }
836