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