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