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