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