1 /* 2 * Copyright (c) 1983 Eric P. Allman 3 * Copyright (c) 1988 Regents of the University of California. 4 * All rights reserved. 5 * 6 * %sccs.include.redist.c% 7 */ 8 9 #ifndef lint 10 static char sccsid[] = "@(#)util.c 6.15 (Berkeley) 04/27/93"; 11 #endif /* not lint */ 12 13 # include "sendmail.h" 14 # include <sysexits.h> 15 /* 16 ** STRIPQUOTES -- Strip quotes & quote bits from a string. 17 ** 18 ** Runs through a string and strips off unquoted quote 19 ** characters and quote bits. This is done in place. 20 ** 21 ** Parameters: 22 ** s -- the string to strip. 23 ** 24 ** Returns: 25 ** none. 26 ** 27 ** Side Effects: 28 ** none. 29 ** 30 ** Called By: 31 ** deliver 32 */ 33 34 stripquotes(s) 35 char *s; 36 { 37 register char *p; 38 register char *q; 39 register char c; 40 41 if (s == NULL) 42 return; 43 44 p = q = s; 45 do 46 { 47 c = *p++; 48 if (c == '\\') 49 c = *p++; 50 else if (c == '"') 51 continue; 52 *q++ = c; 53 } while (c != '\0'); 54 } 55 /* 56 ** CAPITALIZE -- return a copy of a string, properly capitalized. 57 ** 58 ** Parameters: 59 ** s -- the string to capitalize. 60 ** 61 ** Returns: 62 ** a pointer to a properly capitalized string. 63 ** 64 ** Side Effects: 65 ** none. 66 */ 67 68 char * 69 capitalize(s) 70 register char *s; 71 { 72 static char buf[50]; 73 register char *p; 74 75 p = buf; 76 77 for (;;) 78 { 79 while (!(isascii(*s) && isalpha(*s)) && *s != '\0') 80 *p++ = *s++; 81 if (*s == '\0') 82 break; 83 *p++ = toupper(*s); 84 s++; 85 while (isascii(*s) && isalpha(*s)) 86 *p++ = *s++; 87 } 88 89 *p = '\0'; 90 return (buf); 91 } 92 /* 93 ** XALLOC -- Allocate memory and bitch wildly on failure. 94 ** 95 ** THIS IS A CLUDGE. This should be made to give a proper 96 ** error -- but after all, what can we do? 97 ** 98 ** Parameters: 99 ** sz -- size of area to allocate. 100 ** 101 ** Returns: 102 ** pointer to data region. 103 ** 104 ** Side Effects: 105 ** Memory is allocated. 106 */ 107 108 char * 109 xalloc(sz) 110 register int sz; 111 { 112 register char *p; 113 114 p = malloc((unsigned) sz); 115 if (p == NULL) 116 { 117 syserr("Out of memory!!"); 118 abort(); 119 /* exit(EX_UNAVAILABLE); */ 120 } 121 return (p); 122 } 123 /* 124 ** COPYPLIST -- copy list of pointers. 125 ** 126 ** This routine is the equivalent of newstr for lists of 127 ** pointers. 128 ** 129 ** Parameters: 130 ** list -- list of pointers to copy. 131 ** Must be NULL terminated. 132 ** copycont -- if TRUE, copy the contents of the vector 133 ** (which must be a string) also. 134 ** 135 ** Returns: 136 ** a copy of 'list'. 137 ** 138 ** Side Effects: 139 ** none. 140 */ 141 142 char ** 143 copyplist(list, copycont) 144 char **list; 145 bool copycont; 146 { 147 register char **vp; 148 register char **newvp; 149 150 for (vp = list; *vp != NULL; vp++) 151 continue; 152 153 vp++; 154 155 newvp = (char **) xalloc((int) (vp - list) * sizeof *vp); 156 bcopy((char *) list, (char *) newvp, (int) (vp - list) * sizeof *vp); 157 158 if (copycont) 159 { 160 for (vp = newvp; *vp != NULL; vp++) 161 *vp = newstr(*vp); 162 } 163 164 return (newvp); 165 } 166 /* 167 ** COPYQUEUE -- copy address queue. 168 ** 169 ** This routine is the equivalent of newstr for address queues 170 ** addresses marked with QDONTSEND aren't copied 171 ** 172 ** Parameters: 173 ** addr -- list of address structures to copy. 174 ** 175 ** Returns: 176 ** a copy of 'addr'. 177 ** 178 ** Side Effects: 179 ** none. 180 */ 181 182 ADDRESS * 183 copyqueue(addr) 184 ADDRESS *addr; 185 { 186 register ADDRESS *newaddr; 187 ADDRESS *ret; 188 register ADDRESS **tail = &ret; 189 190 while (addr != NULL) 191 { 192 if (!bitset(QDONTSEND, addr->q_flags)) 193 { 194 newaddr = (ADDRESS *) xalloc(sizeof(ADDRESS)); 195 STRUCTCOPY(*addr, *newaddr); 196 *tail = newaddr; 197 tail = &newaddr->q_next; 198 } 199 addr = addr->q_next; 200 } 201 *tail = NULL; 202 203 return ret; 204 } 205 /* 206 ** PRINTAV -- print argument vector. 207 ** 208 ** Parameters: 209 ** av -- argument vector. 210 ** 211 ** Returns: 212 ** none. 213 ** 214 ** Side Effects: 215 ** prints av. 216 */ 217 218 printav(av) 219 register char **av; 220 { 221 while (*av != NULL) 222 { 223 if (tTd(0, 44)) 224 printf("\n\t%08x=", *av); 225 else 226 (void) putchar(' '); 227 xputs(*av++); 228 } 229 (void) putchar('\n'); 230 } 231 /* 232 ** LOWER -- turn letter into lower case. 233 ** 234 ** Parameters: 235 ** c -- character to turn into lower case. 236 ** 237 ** Returns: 238 ** c, in lower case. 239 ** 240 ** Side Effects: 241 ** none. 242 */ 243 244 char 245 lower(c) 246 register char c; 247 { 248 return((isascii(c) && isupper(c)) ? tolower(c) : c); 249 } 250 /* 251 ** XPUTS -- put string doing control escapes. 252 ** 253 ** Parameters: 254 ** s -- string to put. 255 ** 256 ** Returns: 257 ** none. 258 ** 259 ** Side Effects: 260 ** output to stdout 261 */ 262 263 xputs(s) 264 register char *s; 265 { 266 register int c; 267 register struct metamac *mp; 268 extern struct metamac MetaMacros[]; 269 270 if (s == NULL) 271 { 272 printf("<null>"); 273 return; 274 } 275 while ((c = (*s++ & 0377)) != '\0') 276 { 277 if (!isascii(c)) 278 { 279 if (c == MATCHREPL || c == MACROEXPAND) 280 { 281 putchar('$'); 282 continue; 283 } 284 for (mp = MetaMacros; mp->metaname != '\0'; mp++) 285 { 286 if ((mp->metaval & 0377) == c) 287 { 288 printf("$%c", mp->metaname); 289 break; 290 } 291 } 292 if (mp->metaname != '\0') 293 continue; 294 (void) putchar('\\'); 295 c &= 0177; 296 } 297 if (isprint(c)) 298 { 299 putchar(c); 300 continue; 301 } 302 303 /* wasn't a meta-macro -- find another way to print it */ 304 switch (c) 305 { 306 case '\0': 307 continue; 308 309 case '\n': 310 c = 'n'; 311 break; 312 313 case '\r': 314 c = 'r'; 315 break; 316 317 case '\t': 318 c = 't'; 319 break; 320 321 default: 322 (void) putchar('^'); 323 (void) putchar(c ^ 0100); 324 continue; 325 } 326 } 327 (void) fflush(stdout); 328 } 329 /* 330 ** MAKELOWER -- Translate a line into lower case 331 ** 332 ** Parameters: 333 ** p -- the string to translate. If NULL, return is 334 ** immediate. 335 ** 336 ** Returns: 337 ** none. 338 ** 339 ** Side Effects: 340 ** String pointed to by p is translated to lower case. 341 ** 342 ** Called By: 343 ** parse 344 */ 345 346 makelower(p) 347 register char *p; 348 { 349 register char c; 350 351 if (p == NULL) 352 return; 353 for (; (c = *p) != '\0'; p++) 354 if (isascii(c) && isupper(c)) 355 *p = tolower(c); 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(gecos, login, buf) 376 register char *gecos; 377 char *login; 378 char *buf; 379 { 380 register char *p; 381 register char *bp = buf; 382 int l; 383 384 if (*gecos == '*') 385 gecos++; 386 387 /* find length of final string */ 388 l = 0; 389 for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++) 390 { 391 if (*p == '&') 392 l += strlen(login); 393 else 394 l++; 395 } 396 397 /* now fill in buf */ 398 for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++) 399 { 400 if (*p == '&') 401 { 402 (void) strcpy(bp, login); 403 *bp = toupper(*bp); 404 while (*bp != '\0') 405 bp++; 406 } 407 else 408 *bp++ = *p; 409 } 410 *bp = '\0'; 411 } 412 /* 413 ** SAFEFILE -- return true if a file exists and is safe for a user. 414 ** 415 ** Parameters: 416 ** fn -- filename to check. 417 ** uid -- uid to compare against. 418 ** mode -- mode bits that must match. 419 ** 420 ** Returns: 421 ** 0 if fn exists, is owned by uid, and matches mode. 422 ** An errno otherwise. The actual errno is cleared. 423 ** 424 ** Side Effects: 425 ** none. 426 */ 427 428 int 429 safefile(fn, uid, mode) 430 char *fn; 431 uid_t uid; 432 int mode; 433 { 434 struct stat stbuf; 435 436 if (stat(fn, &stbuf) < 0) 437 { 438 int ret = errno; 439 440 errno = 0; 441 return ret; 442 } 443 if (stbuf.st_uid == uid && (stbuf.st_mode & mode) == mode) 444 return 0; 445 return EPERM; 446 } 447 /* 448 ** FIXCRLF -- fix <CR><LF> in line. 449 ** 450 ** Looks for the <CR><LF> combination and turns it into the 451 ** UNIX canonical <NL> character. It only takes one line, 452 ** i.e., it is assumed that the first <NL> found is the end 453 ** of the line. 454 ** 455 ** Parameters: 456 ** line -- the line to fix. 457 ** stripnl -- if true, strip the newline also. 458 ** 459 ** Returns: 460 ** none. 461 ** 462 ** Side Effects: 463 ** line is changed in place. 464 */ 465 466 fixcrlf(line, stripnl) 467 char *line; 468 bool stripnl; 469 { 470 register char *p; 471 472 p = strchr(line, '\n'); 473 if (p == NULL) 474 return; 475 if (p > line && p[-1] == '\r') 476 p--; 477 if (!stripnl) 478 *p++ = '\n'; 479 *p = '\0'; 480 } 481 /* 482 ** DFOPEN -- determined file open 483 ** 484 ** This routine has the semantics of fopen, except that it will 485 ** keep trying a few times to make this happen. The idea is that 486 ** on very loaded systems, we may run out of resources (inodes, 487 ** whatever), so this tries to get around it. 488 */ 489 490 FILE * 491 dfopen(filename, mode) 492 char *filename; 493 char *mode; 494 { 495 register int tries; 496 register FILE *fp; 497 struct stat st; 498 499 for (tries = 0; tries < 10; tries++) 500 { 501 sleep((unsigned) (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 if (fp != NULL && fstat(fileno(fp), &st) >= 0 && S_ISREG(st.st_mode)) 510 { 511 int locktype; 512 extern bool lockfile(); 513 514 /* lock the file to avoid accidental conflicts */ 515 if (*mode == 'w' || *mode == 'a') 516 locktype = LOCK_EX; 517 else 518 locktype = LOCK_SH; 519 (void) lockfile(fileno(fp), filename, locktype); 520 errno = 0; 521 } 522 return (fp); 523 } 524 /* 525 ** PUTLINE -- put a line like fputs obeying SMTP conventions 526 ** 527 ** This routine always guarantees outputing a newline (or CRLF, 528 ** as appropriate) at the end of the string. 529 ** 530 ** Parameters: 531 ** l -- line to put. 532 ** fp -- file to put it onto. 533 ** m -- the mailer used to control output. 534 ** 535 ** Returns: 536 ** none 537 ** 538 ** Side Effects: 539 ** output of l to fp. 540 */ 541 542 putline(l, fp, m) 543 register char *l; 544 FILE *fp; 545 MAILER *m; 546 { 547 register char *p; 548 register char svchar; 549 550 /* strip out 0200 bits -- these can look like TELNET protocol */ 551 if (bitnset(M_7BITS, m->m_flags)) 552 { 553 for (p = l; svchar = *p; ++p) 554 if (svchar & 0200) 555 *p = svchar &~ 0200; 556 } 557 558 do 559 { 560 /* find the end of the line */ 561 p = strchr(l, '\n'); 562 if (p == NULL) 563 p = &l[strlen(l)]; 564 565 /* check for line overflow */ 566 while (m->m_linelimit > 0 && (p - l) > m->m_linelimit) 567 { 568 register char *q = &l[m->m_linelimit - 1]; 569 570 svchar = *q; 571 *q = '\0'; 572 if (l[0] == '.' && bitnset(M_XDOT, m->m_flags)) 573 (void) putc('.', fp); 574 fputs(l, fp); 575 (void) putc('!', fp); 576 fputs(m->m_eol, fp); 577 *q = svchar; 578 l = q; 579 } 580 581 /* output last part */ 582 if (l[0] == '.' && bitnset(M_XDOT, m->m_flags)) 583 (void) putc('.', fp); 584 for ( ; l < p; ++l) 585 (void) putc(*l, fp); 586 fputs(m->m_eol, fp); 587 if (*l == '\n') 588 ++l; 589 } while (l[0] != '\0'); 590 } 591 /* 592 ** XUNLINK -- unlink a file, doing logging as appropriate. 593 ** 594 ** Parameters: 595 ** f -- name of file to unlink. 596 ** 597 ** Returns: 598 ** none. 599 ** 600 ** Side Effects: 601 ** f is unlinked. 602 */ 603 604 xunlink(f) 605 char *f; 606 { 607 register int i; 608 609 # ifdef LOG 610 if (LogLevel > 98) 611 syslog(LOG_DEBUG, "%s: unlink %s", CurEnv->e_id, f); 612 # endif /* LOG */ 613 614 i = unlink(f); 615 # ifdef LOG 616 if (i < 0 && LogLevel > 97) 617 syslog(LOG_DEBUG, "%s: unlink-fail %d", f, errno); 618 # endif /* LOG */ 619 } 620 /* 621 ** XFCLOSE -- close a file, doing logging as appropriate. 622 ** 623 ** Parameters: 624 ** fp -- file pointer for the file to close 625 ** a, b -- miscellaneous crud to print for debugging 626 ** 627 ** Returns: 628 ** none. 629 ** 630 ** Side Effects: 631 ** fp is closed. 632 */ 633 634 xfclose(fp, a, b) 635 FILE *fp; 636 char *a, *b; 637 { 638 if (tTd(53, 99)) 639 printf("xfclose(%x) %s %s\n", fp, a, b); 640 if (fclose(fp) < 0 && tTd(53, 99)) 641 printf("xfclose FAILURE: %s\n", errstring(errno)); 642 } 643 /* 644 ** SFGETS -- "safe" fgets -- times out and ignores random interrupts. 645 ** 646 ** Parameters: 647 ** buf -- place to put the input line. 648 ** siz -- size of buf. 649 ** fp -- file to read from. 650 ** timeout -- the timeout before error occurs. 651 ** 652 ** Returns: 653 ** NULL on error (including timeout). This will also leave 654 ** buf containing a null string. 655 ** buf otherwise. 656 ** 657 ** Side Effects: 658 ** none. 659 */ 660 661 static jmp_buf CtxReadTimeout; 662 663 char * 664 sfgets(buf, siz, fp, timeout) 665 char *buf; 666 int siz; 667 FILE *fp; 668 time_t timeout; 669 { 670 register EVENT *ev = NULL; 671 register char *p; 672 static int readtimeout(); 673 674 /* set the timeout */ 675 if (timeout != 0) 676 { 677 if (setjmp(CtxReadTimeout) != 0) 678 { 679 # ifdef LOG 680 syslog(LOG_NOTICE, 681 "timeout waiting for input from %s\n", 682 CurHostName? CurHostName: "local"); 683 # endif 684 errno = 0; 685 usrerr("451 timeout waiting for input"); 686 buf[0] = '\0'; 687 return (NULL); 688 } 689 ev = setevent(timeout, readtimeout, 0); 690 } 691 692 /* try to read */ 693 p = NULL; 694 while (p == NULL && !feof(fp) && !ferror(fp)) 695 { 696 errno = 0; 697 p = fgets(buf, siz, fp); 698 if (errno == EINTR) 699 clearerr(fp); 700 } 701 702 /* clear the event if it has not sprung */ 703 clrevent(ev); 704 705 /* clean up the books and exit */ 706 LineNumber++; 707 if (p == NULL) 708 { 709 buf[0] = '\0'; 710 return (NULL); 711 } 712 if (!EightBit) 713 for (p = buf; *p != '\0'; p++) 714 *p &= ~0200; 715 return (buf); 716 } 717 718 static 719 readtimeout() 720 { 721 longjmp(CtxReadTimeout, 1); 722 } 723 /* 724 ** FGETFOLDED -- like fgets, but know about folded lines. 725 ** 726 ** Parameters: 727 ** buf -- place to put result. 728 ** n -- bytes available. 729 ** f -- file to read from. 730 ** 731 ** Returns: 732 ** input line(s) on success, NULL on error or EOF. 733 ** This will normally be buf -- unless the line is too 734 ** long, when it will be xalloc()ed. 735 ** 736 ** Side Effects: 737 ** buf gets lines from f, with continuation lines (lines 738 ** with leading white space) appended. CRLF's are mapped 739 ** into single newlines. Any trailing NL is stripped. 740 */ 741 742 char * 743 fgetfolded(buf, n, f) 744 char *buf; 745 register int n; 746 FILE *f; 747 { 748 register char *p = buf; 749 char *bp = buf; 750 register int i; 751 752 n--; 753 while ((i = getc(f)) != EOF) 754 { 755 if (i == '\r') 756 { 757 i = getc(f); 758 if (i != '\n') 759 { 760 if (i != EOF) 761 (void) ungetc(i, f); 762 i = '\r'; 763 } 764 } 765 if (--n <= 0) 766 { 767 /* allocate new space */ 768 char *nbp; 769 int nn; 770 771 nn = (p - bp); 772 if (nn < MEMCHUNKSIZE) 773 nn *= 2; 774 else 775 nn += MEMCHUNKSIZE; 776 nbp = xalloc(nn); 777 bcopy(bp, nbp, p - bp); 778 p = &nbp[p - bp]; 779 if (bp != buf) 780 free(bp); 781 bp = nbp; 782 n = nn - (p - bp); 783 } 784 *p++ = i; 785 if (i == '\n') 786 { 787 LineNumber++; 788 i = getc(f); 789 if (i != EOF) 790 (void) ungetc(i, f); 791 if (i != ' ' && i != '\t') 792 break; 793 } 794 } 795 if (p == bp) 796 return (NULL); 797 *--p = '\0'; 798 return (bp); 799 } 800 /* 801 ** CURTIME -- return current time. 802 ** 803 ** Parameters: 804 ** none. 805 ** 806 ** Returns: 807 ** the current time. 808 ** 809 ** Side Effects: 810 ** none. 811 */ 812 813 time_t 814 curtime() 815 { 816 auto time_t t; 817 818 (void) time(&t); 819 return (t); 820 } 821 /* 822 ** ATOBOOL -- convert a string representation to boolean. 823 ** 824 ** Defaults to "TRUE" 825 ** 826 ** Parameters: 827 ** s -- string to convert. Takes "tTyY" as true, 828 ** others as false. 829 ** 830 ** Returns: 831 ** A boolean representation of the string. 832 ** 833 ** Side Effects: 834 ** none. 835 */ 836 837 bool 838 atobool(s) 839 register char *s; 840 { 841 if (*s == '\0' || strchr("tTyY", *s) != NULL) 842 return (TRUE); 843 return (FALSE); 844 } 845 /* 846 ** ATOOCT -- convert a string representation to octal. 847 ** 848 ** Parameters: 849 ** s -- string to convert. 850 ** 851 ** Returns: 852 ** An integer representing the string interpreted as an 853 ** octal number. 854 ** 855 ** Side Effects: 856 ** none. 857 */ 858 859 atooct(s) 860 register char *s; 861 { 862 register int i = 0; 863 864 while (*s >= '0' && *s <= '7') 865 i = (i << 3) | (*s++ - '0'); 866 return (i); 867 } 868 /* 869 ** WAITFOR -- wait for a particular process id. 870 ** 871 ** Parameters: 872 ** pid -- process id to wait for. 873 ** 874 ** Returns: 875 ** status of pid. 876 ** -1 if pid never shows up. 877 ** 878 ** Side Effects: 879 ** none. 880 */ 881 882 waitfor(pid) 883 int pid; 884 { 885 auto int st; 886 int i; 887 888 do 889 { 890 errno = 0; 891 i = wait(&st); 892 } while ((i >= 0 || errno == EINTR) && i != pid); 893 if (i < 0) 894 st = -1; 895 return (st); 896 } 897 /* 898 ** BITINTERSECT -- tell if two bitmaps intersect 899 ** 900 ** Parameters: 901 ** a, b -- the bitmaps in question 902 ** 903 ** Returns: 904 ** TRUE if they have a non-null intersection 905 ** FALSE otherwise 906 ** 907 ** Side Effects: 908 ** none. 909 */ 910 911 bool 912 bitintersect(a, b) 913 BITMAP a; 914 BITMAP b; 915 { 916 int i; 917 918 for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) 919 if ((a[i] & b[i]) != 0) 920 return (TRUE); 921 return (FALSE); 922 } 923 /* 924 ** BITZEROP -- tell if a bitmap is all zero 925 ** 926 ** Parameters: 927 ** map -- the bit map to check 928 ** 929 ** Returns: 930 ** TRUE if map is all zero. 931 ** FALSE if there are any bits set in map. 932 ** 933 ** Side Effects: 934 ** none. 935 */ 936 937 bool 938 bitzerop(map) 939 BITMAP map; 940 { 941 int i; 942 943 for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) 944 if (map[i] != 0) 945 return (FALSE); 946 return (TRUE); 947 } 948 /* 949 ** STRCONTAINEDIN -- tell if one string is contained in another 950 ** 951 ** Parameters: 952 ** a -- possible substring. 953 ** b -- possible superstring. 954 ** 955 ** Returns: 956 ** TRUE if a is contained in b. 957 ** FALSE otherwise. 958 */ 959 960 bool 961 strcontainedin(a, b) 962 register char *a; 963 register char *b; 964 { 965 int l; 966 967 l = strlen(a); 968 for (;;) 969 { 970 b = strchr(b, a[0]); 971 if (b == NULL) 972 return FALSE; 973 if (strncmp(a, b, l) == 0) 974 return TRUE; 975 b++; 976 } 977 } 978