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: }

Defined functions

atobool defined in line 755; used 11 times
atooct defined in line 777; used 1 times
bitintersect defined in line 829; used 2 times
bitzerop defined in line 855; used 2 times
capitalize defined in line 102; used 5 times
qstrlen defined in line 75; used 2 times
readtimeout defined in line 657; used 2 times

Defined variables

CtxReadTimeout defined in line 603; used 2 times
SccsId defined in line 12; never used

Defined macros

ETIMEDOUT defined in line 606; used 2 times
SMTPLINELIM defined in line 503; used 2 times
Last modified: 1985-12-20
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2144
Valid CSS Valid XHTML 1.0 Strict