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:             errno = ETIMEDOUT;
 647:             syserr("sfgets: timeout on read (mailer may be hung)");
 648:             return (NULL);
 649:         }
 650:         ev = setevent((time_t) ReadTimeout, readtimeout, 0);
 651:     }
 652: 
 653:     /* try to read */
 654:     do
 655:     {
 656:         errno = 0;
 657:         p = fgets(buf, siz, fp);
 658:     } while (p == NULL && errno == EINTR);
 659: 
 660:     /* clear the event if it has not sprung */
 661:     clrevent(ev);
 662: 
 663:     /* clean up the books and exit */
 664:     LineNumber++;
 665:     return (p);
 666: }
 667: 
 668: static
 669: readtimeout()
 670: {
 671:     longjmp(CtxReadTimeout, 1);
 672: }
 673: /*
 674: **  FGETFOLDED -- like fgets, but know about folded lines.
 675: **
 676: **	Parameters:
 677: **		buf -- place to put result.
 678: **		n -- bytes available.
 679: **		f -- file to read from.
 680: **
 681: **	Returns:
 682: **		buf on success, NULL on error or EOF.
 683: **
 684: **	Side Effects:
 685: **		buf gets lines from f, with continuation lines (lines
 686: **		with leading white space) appended.  CRLF's are mapped
 687: **		into single newlines.  Any trailing NL is stripped.
 688: */
 689: 
 690: char *
 691: fgetfolded(buf, n, f)
 692:     char *buf;
 693:     register int n;
 694:     FILE *f;
 695: {
 696:     register char *p = buf;
 697:     register int i;
 698: 
 699:     n--;
 700:     while (fgets(p, n, f) != NULL)
 701:     {
 702:         LineNumber++;
 703:         fixcrlf(p, TRUE);
 704:         i = fgetc(f);
 705:         if (i != EOF)
 706:             ungetc(i, f);
 707:         if (i != ' ' && i != '\t')
 708:             return (buf);
 709:         i = strlen(p);
 710:         p += i;
 711:         *p++ = '\n';
 712:         n -= i + 1;
 713:     }
 714:     return (NULL);
 715: }
 716: /*
 717: **  CURTIME -- return current time.
 718: **
 719: **	Parameters:
 720: **		none.
 721: **
 722: **	Returns:
 723: **		the current time.
 724: **
 725: **	Side Effects:
 726: **		none.
 727: */
 728: 
 729: time_t
 730: curtime()
 731: {
 732:     auto time_t t;
 733: 
 734:     (void) time(&t);
 735:     return (t);
 736: }
 737: /*
 738: **  ATOBOOL -- convert a string representation to boolean.
 739: **
 740: **	Defaults to "TRUE"
 741: **
 742: **	Parameters:
 743: **		s -- string to convert.  Takes "tTyY" as true,
 744: **			others as false.
 745: **
 746: **	Returns:
 747: **		A boolean representation of the string.
 748: **
 749: **	Side Effects:
 750: **		none.
 751: */
 752: 
 753: bool
 754: atobool(s)
 755:     register char *s;
 756: {
 757:     if (*s == '\0' || index("tTyY", *s) != NULL)
 758:         return (TRUE);
 759:     return (FALSE);
 760: }
 761: /*
 762: **  ATOOCT -- convert a string representation to octal.
 763: **
 764: **	Parameters:
 765: **		s -- string to convert.
 766: **
 767: **	Returns:
 768: **		An integer representing the string interpreted as an
 769: **		octal number.
 770: **
 771: **	Side Effects:
 772: **		none.
 773: */
 774: 
 775: atooct(s)
 776:     register char *s;
 777: {
 778:     register int i = 0;
 779: 
 780:     while (*s >= '0' && *s <= '7')
 781:         i = (i << 3) | (*s++ - '0');
 782:     return (i);
 783: }
 784: /*
 785: **  WAITFOR -- wait for a particular process id.
 786: **
 787: **	Parameters:
 788: **		pid -- process id to wait for.
 789: **
 790: **	Returns:
 791: **		status of pid.
 792: **		-1 if pid never shows up.
 793: **
 794: **	Side Effects:
 795: **		none.
 796: */
 797: 
 798: waitfor(pid)
 799:     int pid;
 800: {
 801:     auto int st;
 802:     int i;
 803: 
 804:     do
 805:     {
 806:         errno = 0;
 807:         i = wait(&st);
 808:     } while ((i >= 0 || errno == EINTR) && i != pid);
 809:     if (i < 0)
 810:         st = -1;
 811:     return (st);
 812: }
 813: /*
 814: **  CLOSEALL -- close all extraneous file descriptors
 815: **
 816: **	Parameters:
 817: **		none.
 818: **
 819: **	Returns:
 820: **		none.
 821: **
 822: **	Side Effects:
 823: **		Closes all file descriptors except zero, one, and two.
 824: */
 825: 
 826: closeall()
 827: {
 828:     int i;
 829: 
 830:     for (i = 3; i < 50; i++)
 831:         (void) close(i);
 832: }
 833: /*
 834: **  BITINTERSECT -- tell if two bitmaps intersect
 835: **
 836: **	Parameters:
 837: **		a, b -- the bitmaps in question
 838: **
 839: **	Returns:
 840: **		TRUE if they have a non-null intersection
 841: **		FALSE otherwise
 842: **
 843: **	Side Effects:
 844: **		none.
 845: */
 846: 
 847: bool
 848: bitintersect(a, b)
 849:     BITMAP a;
 850:     BITMAP b;
 851: {
 852:     int i;
 853: 
 854:     for (i = BITMAPBYTES / sizeof (int); --i >= 0; )
 855:         if ((a[i] & b[i]) != 0)
 856:             return (TRUE);
 857:     return (FALSE);
 858: }
 859: /*
 860: **  BITZEROP -- tell if a bitmap is all zero
 861: **
 862: **	Parameters:
 863: **		map -- the bit map to check
 864: **
 865: **	Returns:
 866: **		TRUE if map is all zero.
 867: **		FALSE if there are any bits set in map.
 868: **
 869: **	Side Effects:
 870: **		none.
 871: */
 872: 
 873: bool
 874: bitzerop(map)
 875:     BITMAP map;
 876: {
 877:     int i;
 878: 
 879:     for (i = BITMAPBYTES / sizeof (int); --i >= 0; )
 880:         if (map[i] != 0)
 881:             return (FALSE);
 882:     return (TRUE);
 883: }

Defined functions

atobool defined in line 753; used 10 times
atooct defined in line 775; used 1 times
bitintersect defined in line 847; never used
bitzerop defined in line 873; used 2 times
buildfname defined in line 375; never used
capitalize defined in line 90; used 5 times
closeall defined in line 826; never used
lower defined in line 228; used 7 times
qstrlen defined in line 63; used 2 times
readtimeout defined in line 668; used 2 times
xunlink defined in line 597; used 4 times

Defined variables

CtxReadTimeout defined in line 629; used 2 times
bool defined in line 753; used 7 times

Defined macros

SMTPLINELIM defined in line 530; used 2 times
Last modified: 1984-03-20
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1741
Valid CSS Valid XHTML 1.0 Strict