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