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