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