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