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