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