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