1 /* 2 * Copyright (c) 1998 Sendmail, Inc. All rights reserved. 3 * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 4 * Copyright (c) 1988, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * By using this file, you agree to the terms and conditions set 8 * forth in the LICENSE file which can be found at the top level of 9 * the sendmail distribution. 10 * 11 */ 12 13 #ifndef lint 14 static char sccsid[] = "@(#)util.c 8.159 (Berkeley) 7/1/98"; 15 #endif /* not lint */ 16 17 # include "sendmail.h" 18 # include <sysexits.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 void 39 stripquotes(s) 40 char *s; 41 { 42 register char *p; 43 register char *q; 44 register char c; 45 46 if (s == NULL) 47 return; 48 49 p = q = s; 50 do 51 { 52 c = *p++; 53 if (c == '\\') 54 c = *p++; 55 else if (c == '"') 56 continue; 57 *q++ = c; 58 } while (c != '\0'); 59 } 60 /* 61 ** ADDQUOTES -- Adds quotes & quote bits to a string. 62 ** 63 ** Runs through a string and adds characters and quote bits. 64 ** 65 ** Parameters: 66 ** s -- the string to modify. 67 ** 68 ** Returns: 69 ** pointer to quoted string. 70 ** 71 ** Side Effects: 72 ** none. 73 ** 74 */ 75 76 char * 77 addquotes(s) 78 char *s; 79 { 80 int len = 0; 81 char c; 82 char *p = s, *q, *r; 83 84 if (s == NULL) 85 return NULL; 86 87 /* Find length of quoted string */ 88 while ((c = *p++) != '\0') 89 { 90 len++; 91 if (c == '\\' || c == '"') 92 len++; 93 } 94 95 q = r = xalloc(len + 3); 96 p = s; 97 98 /* add leading quote */ 99 *q++ = '"'; 100 while ((c = *p++) != '\0') 101 { 102 /* quote \ or " */ 103 if (c == '\\' || c == '"') 104 *q++ = '\\'; 105 *q++ = c; 106 } 107 *q++ = '"'; 108 *q = '\0'; 109 return r; 110 } 111 /* 112 ** RFC822_STRING -- Checks string for proper RFC822 string quoting. 113 ** 114 ** Runs through a string and verifies RFC822 special characters 115 ** are only found inside comments, quoted strings, or backslash 116 ** escaped. Also verified balanced quotes and parenthesis. 117 ** 118 ** Parameters: 119 ** s -- the string to modify. 120 ** 121 ** Returns: 122 ** TRUE -- if the string is RFC822 compliant. 123 ** FALSE -- if the string is not RFC822 compliant. 124 ** 125 ** Side Effects: 126 ** none. 127 ** 128 */ 129 130 bool 131 rfc822_string(s) 132 char *s; 133 { 134 bool quoted = FALSE; 135 int commentlev = 0; 136 char *c = s; 137 138 if (s == NULL) 139 return FALSE; 140 141 while (*c != '\0') 142 { 143 /* escaped character */ 144 if (*c == '\\') 145 { 146 c++; 147 if (*c == '\0') 148 return FALSE; 149 } 150 else if (commentlev == 0 && *c == '"') 151 quoted = !quoted; 152 else if (!quoted) 153 { 154 if (*c == ')') 155 { 156 /* unbalanced ')' */ 157 if (commentlev == 0) 158 return FALSE; 159 else 160 commentlev--; 161 } 162 else if (*c == '(') 163 commentlev++; 164 else if (commentlev == 0 && 165 strchr(MustQuoteChars, *c) != NULL) 166 return FALSE; 167 } 168 c++; 169 } 170 /* unbalanced '"' or '(' */ 171 if (quoted || commentlev != 0) 172 return FALSE; 173 else 174 return TRUE; 175 } 176 /* 177 ** XALLOC -- Allocate memory and bitch wildly on failure. 178 ** 179 ** THIS IS A CLUDGE. This should be made to give a proper 180 ** error -- but after all, what can we do? 181 ** 182 ** Parameters: 183 ** sz -- size of area to allocate. 184 ** 185 ** Returns: 186 ** pointer to data region. 187 ** 188 ** Side Effects: 189 ** Memory is allocated. 190 */ 191 192 char * 193 xalloc(sz) 194 register int sz; 195 { 196 register char *p; 197 198 /* some systems can't handle size zero mallocs */ 199 if (sz <= 0) 200 sz = 1; 201 202 p = malloc((unsigned) sz); 203 if (p == NULL) 204 { 205 syserr("!Out of memory!!"); 206 /* exit(EX_UNAVAILABLE); */ 207 } 208 return (p); 209 } 210 /* 211 ** COPYPLIST -- copy list of pointers. 212 ** 213 ** This routine is the equivalent of newstr for lists of 214 ** pointers. 215 ** 216 ** Parameters: 217 ** list -- list of pointers to copy. 218 ** Must be NULL terminated. 219 ** copycont -- if TRUE, copy the contents of the vector 220 ** (which must be a string) also. 221 ** 222 ** Returns: 223 ** a copy of 'list'. 224 ** 225 ** Side Effects: 226 ** none. 227 */ 228 229 char ** 230 copyplist(list, copycont) 231 char **list; 232 bool copycont; 233 { 234 register char **vp; 235 register char **newvp; 236 237 for (vp = list; *vp != NULL; vp++) 238 continue; 239 240 vp++; 241 242 newvp = (char **) xalloc((int) (vp - list) * sizeof *vp); 243 bcopy((char *) list, (char *) newvp, (int) (vp - list) * sizeof *vp); 244 245 if (copycont) 246 { 247 for (vp = newvp; *vp != NULL; vp++) 248 *vp = newstr(*vp); 249 } 250 251 return (newvp); 252 } 253 /* 254 ** COPYQUEUE -- copy address queue. 255 ** 256 ** This routine is the equivalent of newstr for address queues 257 ** addresses marked with QDONTSEND aren't copied 258 ** 259 ** Parameters: 260 ** addr -- list of address structures to copy. 261 ** 262 ** Returns: 263 ** a copy of 'addr'. 264 ** 265 ** Side Effects: 266 ** none. 267 */ 268 269 ADDRESS * 270 copyqueue(addr) 271 ADDRESS *addr; 272 { 273 register ADDRESS *newaddr; 274 ADDRESS *ret; 275 register ADDRESS **tail = &ret; 276 277 while (addr != NULL) 278 { 279 if (!bitset(QDONTSEND, addr->q_flags)) 280 { 281 newaddr = (ADDRESS *) xalloc(sizeof(ADDRESS)); 282 STRUCTCOPY(*addr, *newaddr); 283 *tail = newaddr; 284 tail = &newaddr->q_next; 285 } 286 addr = addr->q_next; 287 } 288 *tail = NULL; 289 290 return ret; 291 } 292 /* 293 ** PRINTAV -- print argument vector. 294 ** 295 ** Parameters: 296 ** av -- argument vector. 297 ** 298 ** Returns: 299 ** none. 300 ** 301 ** Side Effects: 302 ** prints av. 303 */ 304 305 void 306 printav(av) 307 register char **av; 308 { 309 while (*av != NULL) 310 { 311 if (tTd(0, 44)) 312 printf("\n\t%08lx=", (u_long) *av); 313 else 314 (void) putchar(' '); 315 xputs(*av++); 316 } 317 (void) putchar('\n'); 318 } 319 /* 320 ** LOWER -- turn letter into lower case. 321 ** 322 ** Parameters: 323 ** c -- character to turn into lower case. 324 ** 325 ** Returns: 326 ** c, in lower case. 327 ** 328 ** Side Effects: 329 ** none. 330 */ 331 332 char 333 lower(c) 334 register char c; 335 { 336 return((isascii(c) && isupper(c)) ? tolower(c) : c); 337 } 338 /* 339 ** XPUTS -- put string doing control escapes. 340 ** 341 ** Parameters: 342 ** s -- string to put. 343 ** 344 ** Returns: 345 ** none. 346 ** 347 ** Side Effects: 348 ** output to stdout 349 */ 350 351 void 352 xputs(s) 353 register const char *s; 354 { 355 register int c; 356 register struct metamac *mp; 357 bool shiftout = FALSE; 358 extern struct metamac MetaMacros[]; 359 360 if (s == NULL) 361 { 362 printf("%s<null>%s", TermEscape.te_rv_on, TermEscape.te_rv_off); 363 return; 364 } 365 while ((c = (*s++ & 0377)) != '\0') 366 { 367 if (shiftout) 368 { 369 printf("%s", TermEscape.te_rv_off); 370 shiftout = FALSE; 371 } 372 if (!isascii(c)) 373 { 374 if (c == MATCHREPL) 375 { 376 printf("%s$", TermEscape.te_rv_on); 377 shiftout = TRUE; 378 if (*s == '\0') 379 continue; 380 c = *s++ & 0377; 381 goto printchar; 382 } 383 if (c == MACROEXPAND || c == MACRODEXPAND) 384 { 385 printf("%s$", TermEscape.te_rv_on); 386 if (c == MACRODEXPAND) 387 putchar('&'); 388 shiftout = TRUE; 389 if (*s == '\0') 390 continue; 391 if (strchr("=~&?", *s) != NULL) 392 putchar(*s++); 393 if (bitset(0200, *s)) 394 printf("{%s}", macname(*s++ & 0377)); 395 else 396 printf("%c", *s++); 397 continue; 398 } 399 for (mp = MetaMacros; mp->metaname != '\0'; mp++) 400 { 401 if ((mp->metaval & 0377) == c) 402 { 403 printf("%s$%c", 404 TermEscape.te_rv_on, 405 mp->metaname); 406 shiftout = TRUE; 407 break; 408 } 409 } 410 if (c == MATCHCLASS || c == MATCHNCLASS) 411 { 412 if (bitset(0200, *s)) 413 printf("{%s}", macname(*s++ & 0377)); 414 else if (*s != '\0') 415 printf("%c", *s++); 416 } 417 if (mp->metaname != '\0') 418 continue; 419 420 /* unrecognized meta character */ 421 printf("%sM-", TermEscape.te_rv_on); 422 shiftout = TRUE; 423 c &= 0177; 424 } 425 printchar: 426 if (isprint(c)) 427 { 428 putchar(c); 429 continue; 430 } 431 432 /* wasn't a meta-macro -- find another way to print it */ 433 switch (c) 434 { 435 case '\n': 436 c = 'n'; 437 break; 438 439 case '\r': 440 c = 'r'; 441 break; 442 443 case '\t': 444 c = 't'; 445 break; 446 } 447 if (!shiftout) 448 { 449 printf("%s", TermEscape.te_rv_on); 450 shiftout = TRUE; 451 } 452 if (isprint(c)) 453 { 454 (void) putchar('\\'); 455 (void) putchar(c); 456 } 457 else 458 { 459 (void) putchar('^'); 460 (void) putchar(c ^ 0100); 461 } 462 } 463 if (shiftout) 464 printf("%s", TermEscape.te_rv_off); 465 (void) fflush(stdout); 466 } 467 /* 468 ** MAKELOWER -- Translate a line into lower case 469 ** 470 ** Parameters: 471 ** p -- the string to translate. If NULL, return is 472 ** immediate. 473 ** 474 ** Returns: 475 ** none. 476 ** 477 ** Side Effects: 478 ** String pointed to by p is translated to lower case. 479 ** 480 ** Called By: 481 ** parse 482 */ 483 484 void 485 makelower(p) 486 register char *p; 487 { 488 register char c; 489 490 if (p == NULL) 491 return; 492 for (; (c = *p) != '\0'; p++) 493 if (isascii(c) && isupper(c)) 494 *p = tolower(c); 495 } 496 /* 497 ** BUILDFNAME -- build full name from gecos style entry. 498 ** 499 ** This routine interprets the strange entry that would appear 500 ** in the GECOS field of the password file. 501 ** 502 ** Parameters: 503 ** p -- name to build. 504 ** login -- the login name of this user (for &). 505 ** buf -- place to put the result. 506 ** buflen -- length of buf. 507 ** 508 ** Returns: 509 ** none. 510 ** 511 ** Side Effects: 512 ** none. 513 */ 514 515 void 516 buildfname(gecos, login, buf, buflen) 517 register char *gecos; 518 char *login; 519 char *buf; 520 int buflen; 521 { 522 register char *p; 523 register char *bp = buf; 524 525 if (*gecos == '*') 526 gecos++; 527 528 /* copy gecos, interpolating & to be full name */ 529 for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++) 530 { 531 if (bp >= &buf[buflen - 1]) 532 { 533 /* buffer overflow -- just use login name */ 534 snprintf(buf, buflen, "%s", login); 535 return; 536 } 537 if (*p == '&') 538 { 539 /* interpolate full name */ 540 snprintf(bp, buflen - (bp - buf), "%s", login); 541 *bp = toupper(*bp); 542 bp += strlen(bp); 543 } 544 else 545 *bp++ = *p; 546 } 547 *bp = '\0'; 548 } 549 /* 550 ** FIXCRLF -- fix <CR><LF> in line. 551 ** 552 ** Looks for the <CR><LF> combination and turns it into the 553 ** UNIX canonical <NL> character. It only takes one line, 554 ** i.e., it is assumed that the first <NL> found is the end 555 ** of the line. 556 ** 557 ** Parameters: 558 ** line -- the line to fix. 559 ** stripnl -- if true, strip the newline also. 560 ** 561 ** Returns: 562 ** none. 563 ** 564 ** Side Effects: 565 ** line is changed in place. 566 */ 567 568 void 569 fixcrlf(line, stripnl) 570 char *line; 571 bool stripnl; 572 { 573 register char *p; 574 575 p = strchr(line, '\n'); 576 if (p == NULL) 577 return; 578 if (p > line && p[-1] == '\r') 579 p--; 580 if (!stripnl) 581 *p++ = '\n'; 582 *p = '\0'; 583 } 584 /* 585 ** PUTLINE -- put a line like fputs obeying SMTP conventions 586 ** 587 ** This routine always guarantees outputing a newline (or CRLF, 588 ** as appropriate) at the end of the string. 589 ** 590 ** Parameters: 591 ** l -- line to put. 592 ** mci -- the mailer connection information. 593 ** 594 ** Returns: 595 ** none 596 ** 597 ** Side Effects: 598 ** output of l to fp. 599 */ 600 601 void 602 putline(l, mci) 603 register char *l; 604 register MCI *mci; 605 { 606 putxline(l, strlen(l), mci, PXLF_MAPFROM); 607 } 608 /* 609 ** PUTXLINE -- putline with flags bits. 610 ** 611 ** This routine always guarantees outputing a newline (or CRLF, 612 ** as appropriate) at the end of the string. 613 ** 614 ** Parameters: 615 ** l -- line to put. 616 ** len -- the length of the line. 617 ** mci -- the mailer connection information. 618 ** pxflags -- flag bits: 619 ** PXLF_MAPFROM -- map From_ to >From_. 620 ** PXLF_STRIP8BIT -- strip 8th bit. 621 ** PXLF_HEADER -- map bare newline in header to newline space. 622 ** 623 ** Returns: 624 ** none 625 ** 626 ** Side Effects: 627 ** output of l to fp. 628 */ 629 630 void 631 putxline(l, len, mci, pxflags) 632 register char *l; 633 size_t len; 634 register MCI *mci; 635 int pxflags; 636 { 637 register char *p, *end; 638 int slop = 0; 639 size_t eol_len = strlen(mci->mci_mailer->m_eol); 640 641 /* strip out 0200 bits -- these can look like TELNET protocol */ 642 if (bitset(MCIF_7BIT, mci->mci_flags) || 643 bitset(PXLF_STRIP8BIT, pxflags)) 644 { 645 register char svchar; 646 647 for (p = l; (svchar = *p) != '\0'; ++p) 648 if (bitset(0200, svchar)) 649 *p = svchar &~ 0200; 650 } 651 652 end = l + len; 653 do 654 { 655 /* find the end of the line */ 656 p = memchr(l, '\n', end - l); 657 if (p == NULL) 658 p = end; 659 660 if (TrafficLogFile != NULL) 661 fprintf(TrafficLogFile, "%05d >>> ", (int) getpid()); 662 663 /* check for line overflow */ 664 while (mci->mci_mailer->m_linelimit > 0 && 665 (p - l + slop) > mci->mci_mailer->m_linelimit) 666 { 667 char *l_base = l; 668 register char *q = &l[mci->mci_mailer->m_linelimit - slop - 1]; 669 670 if (l[0] == '.' && slop == 0 && 671 bitnset(M_XDOT, mci->mci_mailer->m_flags)) 672 { 673 (void) putc('.', mci->mci_out); 674 if (!bitset(MCIF_INHEADER, mci->mci_flags)) 675 mci->mci_contentlen++; 676 if (TrafficLogFile != NULL) 677 (void) putc('.', TrafficLogFile); 678 } 679 else if (l[0] == 'F' && slop == 0 && 680 bitset(PXLF_MAPFROM, pxflags) && 681 strncmp(l, "From ", 5) == 0 && 682 bitnset(M_ESCFROM, mci->mci_mailer->m_flags)) 683 { 684 (void) putc('>', mci->mci_out); 685 if (!bitset(MCIF_INHEADER, mci->mci_flags)) 686 mci->mci_contentlen++; 687 if (TrafficLogFile != NULL) 688 (void) putc('>', TrafficLogFile); 689 } 690 while (l < q) 691 { 692 (void) putc(*l++, mci->mci_out); 693 if (!bitset(MCIF_INHEADER, mci->mci_flags)) 694 mci->mci_contentlen++; 695 } 696 (void) putc('!', mci->mci_out); 697 if (!bitset(MCIF_INHEADER, mci->mci_flags)) 698 mci->mci_contentlen++; 699 fputs(mci->mci_mailer->m_eol, mci->mci_out); 700 if (!bitset(MCIF_INHEADER, mci->mci_flags)) 701 mci->mci_contentlen += eol_len; 702 (void) putc(' ', mci->mci_out); 703 if (!bitset(MCIF_INHEADER, mci->mci_flags)) 704 mci->mci_contentlen++; 705 if (TrafficLogFile != NULL) 706 { 707 for (l = l_base; l < q; l++) 708 (void) putc(*l, TrafficLogFile); 709 fprintf(TrafficLogFile, "!\n%05d >>> ", 710 (int) getpid()); 711 } 712 slop = 1; 713 } 714 715 /* output last part */ 716 if (l[0] == '.' && slop == 0 && 717 bitnset(M_XDOT, mci->mci_mailer->m_flags)) 718 { 719 (void) putc('.', mci->mci_out); 720 if (!bitset(MCIF_INHEADER, mci->mci_flags)) 721 mci->mci_contentlen++; 722 if (TrafficLogFile != NULL) 723 (void) putc('.', TrafficLogFile); 724 } 725 else if (l[0] == 'F' && slop == 0 && 726 bitset(PXLF_MAPFROM, pxflags) && 727 strncmp(l, "From ", 5) == 0 && 728 bitnset(M_ESCFROM, mci->mci_mailer->m_flags)) 729 { 730 (void) putc('>', mci->mci_out); 731 if (!bitset(MCIF_INHEADER, mci->mci_flags)) 732 mci->mci_contentlen++; 733 if (TrafficLogFile != NULL) 734 (void) putc('>', TrafficLogFile); 735 } 736 for ( ; l < p; ++l) 737 { 738 if (TrafficLogFile != NULL) 739 (void) putc(*l, TrafficLogFile); 740 (void) putc(*l, mci->mci_out); 741 if (!bitset(MCIF_INHEADER, mci->mci_flags)) 742 mci->mci_contentlen++; 743 } 744 if (TrafficLogFile != NULL) 745 (void) putc('\n', TrafficLogFile); 746 fputs(mci->mci_mailer->m_eol, mci->mci_out); 747 if (!bitset(MCIF_INHEADER, mci->mci_flags)) 748 mci->mci_contentlen += eol_len; 749 if (l < end && *l == '\n') 750 { 751 if (*++l != ' ' && *l != '\t' && *l != '\0' && 752 bitset(PXLF_HEADER, pxflags)) 753 { 754 (void) putc(' ', mci->mci_out); 755 if (!bitset(MCIF_INHEADER, mci->mci_flags)) 756 mci->mci_contentlen++; 757 if (TrafficLogFile != NULL) 758 (void) putc(' ', TrafficLogFile); 759 } 760 } 761 } while (l < end); 762 } 763 /* 764 ** XUNLINK -- unlink a file, doing logging as appropriate. 765 ** 766 ** Parameters: 767 ** f -- name of file to unlink. 768 ** 769 ** Returns: 770 ** none. 771 ** 772 ** Side Effects: 773 ** f is unlinked. 774 */ 775 776 void 777 xunlink(f) 778 char *f; 779 { 780 register int i; 781 782 if (LogLevel > 98) 783 sm_syslog(LOG_DEBUG, CurEnv->e_id, 784 "unlink %s", 785 f); 786 787 i = unlink(f); 788 if (i < 0 && LogLevel > 97) 789 sm_syslog(LOG_DEBUG, CurEnv->e_id, 790 "%s: unlink-fail %d", 791 f, errno); 792 } 793 /* 794 ** XFCLOSE -- close a file, doing logging as appropriate. 795 ** 796 ** Parameters: 797 ** fp -- file pointer for the file to close 798 ** a, b -- miscellaneous crud to print for debugging 799 ** 800 ** Returns: 801 ** none. 802 ** 803 ** Side Effects: 804 ** fp is closed. 805 */ 806 807 void 808 xfclose(fp, a, b) 809 FILE *fp; 810 char *a, *b; 811 { 812 if (tTd(53, 99)) 813 printf("xfclose(%lx) %s %s\n", (u_long) fp, a, b); 814 #if XDEBUG 815 if (fileno(fp) == 1) 816 syserr("xfclose(%s %s): fd = 1", a, b); 817 #endif 818 if (fclose(fp) < 0 && tTd(53, 99)) 819 printf("xfclose FAILURE: %s\n", errstring(errno)); 820 } 821 /* 822 ** SFGETS -- "safe" fgets -- times out and ignores random interrupts. 823 ** 824 ** Parameters: 825 ** buf -- place to put the input line. 826 ** siz -- size of buf. 827 ** fp -- file to read from. 828 ** timeout -- the timeout before error occurs. 829 ** during -- what we are trying to read (for error messages). 830 ** 831 ** Returns: 832 ** NULL on error (including timeout). This will also leave 833 ** buf containing a null string. 834 ** buf otherwise. 835 ** 836 ** Side Effects: 837 ** none. 838 */ 839 840 static jmp_buf CtxReadTimeout; 841 static void readtimeout __P((time_t)); 842 843 char * 844 sfgets(buf, siz, fp, timeout, during) 845 char *buf; 846 int siz; 847 FILE *fp; 848 time_t timeout; 849 char *during; 850 { 851 register EVENT *ev = NULL; 852 register char *p; 853 854 if (fp == NULL) 855 { 856 buf[0] = '\0'; 857 return NULL; 858 } 859 860 /* set the timeout */ 861 if (timeout != 0) 862 { 863 if (setjmp(CtxReadTimeout) != 0) 864 { 865 if (LogLevel > 1) 866 sm_syslog(LOG_NOTICE, CurEnv->e_id, 867 "timeout waiting for input from %.100s during %s", 868 CurHostName ? CurHostName : "local", 869 during); 870 errno = 0; 871 buf[0] = '\0'; 872 #if XDEBUG 873 checkfd012(during); 874 #endif 875 if (TrafficLogFile != NULL) 876 fprintf(TrafficLogFile, "%05d <<< [TIMEOUT]\n", 877 (int) getpid()); 878 return (NULL); 879 } 880 ev = setevent(timeout, readtimeout, 0); 881 } 882 883 /* try to read */ 884 p = NULL; 885 while (!feof(fp) && !ferror(fp)) 886 { 887 errno = 0; 888 p = fgets(buf, siz, fp); 889 if (p != NULL || errno != EINTR) 890 break; 891 clearerr(fp); 892 } 893 894 /* clear the event if it has not sprung */ 895 clrevent(ev); 896 897 /* clean up the books and exit */ 898 LineNumber++; 899 if (p == NULL) 900 { 901 buf[0] = '\0'; 902 if (TrafficLogFile != NULL) 903 fprintf(TrafficLogFile, "%05d <<< [EOF]\n", (int) getpid()); 904 return (NULL); 905 } 906 if (TrafficLogFile != NULL) 907 fprintf(TrafficLogFile, "%05d <<< %s", (int) getpid(), buf); 908 if (SevenBitInput) 909 { 910 for (p = buf; *p != '\0'; p++) 911 *p &= ~0200; 912 } 913 else if (!HasEightBits) 914 { 915 for (p = buf; *p != '\0'; p++) 916 { 917 if (bitset(0200, *p)) 918 { 919 HasEightBits = TRUE; 920 break; 921 } 922 } 923 } 924 return (buf); 925 } 926 927 /* ARGSUSED */ 928 static void 929 readtimeout(timeout) 930 time_t timeout; 931 { 932 longjmp(CtxReadTimeout, 1); 933 } 934 /* 935 ** FGETFOLDED -- like fgets, but know about folded lines. 936 ** 937 ** Parameters: 938 ** buf -- place to put result. 939 ** n -- bytes available. 940 ** f -- file to read from. 941 ** 942 ** Returns: 943 ** input line(s) on success, NULL on error or EOF. 944 ** This will normally be buf -- unless the line is too 945 ** long, when it will be xalloc()ed. 946 ** 947 ** Side Effects: 948 ** buf gets lines from f, with continuation lines (lines 949 ** with leading white space) appended. CRLF's are mapped 950 ** into single newlines. Any trailing NL is stripped. 951 */ 952 953 char * 954 fgetfolded(buf, n, f) 955 char *buf; 956 register int n; 957 FILE *f; 958 { 959 register char *p = buf; 960 char *bp = buf; 961 register int i; 962 963 n--; 964 while ((i = getc(f)) != EOF) 965 { 966 if (i == '\r') 967 { 968 i = getc(f); 969 if (i != '\n') 970 { 971 if (i != EOF) 972 (void) ungetc(i, f); 973 i = '\r'; 974 } 975 } 976 if (--n <= 0) 977 { 978 /* allocate new space */ 979 char *nbp; 980 int nn; 981 982 nn = (p - bp); 983 if (nn < MEMCHUNKSIZE) 984 nn *= 2; 985 else 986 nn += MEMCHUNKSIZE; 987 nbp = xalloc(nn); 988 bcopy(bp, nbp, p - bp); 989 p = &nbp[p - bp]; 990 if (bp != buf) 991 free(bp); 992 bp = nbp; 993 n = nn - (p - bp); 994 } 995 *p++ = i; 996 if (i == '\n') 997 { 998 LineNumber++; 999 i = getc(f); 1000 if (i != EOF) 1001 (void) ungetc(i, f); 1002 if (i != ' ' && i != '\t') 1003 break; 1004 } 1005 } 1006 if (p == bp) 1007 return (NULL); 1008 if (p[-1] == '\n') 1009 p--; 1010 *p = '\0'; 1011 return (bp); 1012 } 1013 /* 1014 ** CURTIME -- return current time. 1015 ** 1016 ** Parameters: 1017 ** none. 1018 ** 1019 ** Returns: 1020 ** the current time. 1021 ** 1022 ** Side Effects: 1023 ** none. 1024 */ 1025 1026 time_t 1027 curtime() 1028 { 1029 auto time_t t; 1030 1031 (void) time(&t); 1032 return (t); 1033 } 1034 /* 1035 ** ATOBOOL -- convert a string representation to boolean. 1036 ** 1037 ** Defaults to "TRUE" 1038 ** 1039 ** Parameters: 1040 ** s -- string to convert. Takes "tTyY" as true, 1041 ** others as false. 1042 ** 1043 ** Returns: 1044 ** A boolean representation of the string. 1045 ** 1046 ** Side Effects: 1047 ** none. 1048 */ 1049 1050 bool 1051 atobool(s) 1052 register char *s; 1053 { 1054 if (s == NULL || *s == '\0' || strchr("tTyY", *s) != NULL) 1055 return (TRUE); 1056 return (FALSE); 1057 } 1058 /* 1059 ** ATOOCT -- convert a string representation to octal. 1060 ** 1061 ** Parameters: 1062 ** s -- string to convert. 1063 ** 1064 ** Returns: 1065 ** An integer representing the string interpreted as an 1066 ** octal number. 1067 ** 1068 ** Side Effects: 1069 ** none. 1070 */ 1071 1072 int 1073 atooct(s) 1074 register char *s; 1075 { 1076 register int i = 0; 1077 1078 while (*s >= '0' && *s <= '7') 1079 i = (i << 3) | (*s++ - '0'); 1080 return (i); 1081 } 1082 /* 1083 ** BITINTERSECT -- tell if two bitmaps intersect 1084 ** 1085 ** Parameters: 1086 ** a, b -- the bitmaps in question 1087 ** 1088 ** Returns: 1089 ** TRUE if they have a non-null intersection 1090 ** FALSE otherwise 1091 ** 1092 ** Side Effects: 1093 ** none. 1094 */ 1095 1096 bool 1097 bitintersect(a, b) 1098 BITMAP a; 1099 BITMAP b; 1100 { 1101 int i; 1102 1103 for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) 1104 if ((a[i] & b[i]) != 0) 1105 return (TRUE); 1106 return (FALSE); 1107 } 1108 /* 1109 ** BITZEROP -- tell if a bitmap is all zero 1110 ** 1111 ** Parameters: 1112 ** map -- the bit map to check 1113 ** 1114 ** Returns: 1115 ** TRUE if map is all zero. 1116 ** FALSE if there are any bits set in map. 1117 ** 1118 ** Side Effects: 1119 ** none. 1120 */ 1121 1122 bool 1123 bitzerop(map) 1124 BITMAP map; 1125 { 1126 int i; 1127 1128 for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) 1129 if (map[i] != 0) 1130 return (FALSE); 1131 return (TRUE); 1132 } 1133 /* 1134 ** STRCONTAINEDIN -- tell if one string is contained in another 1135 ** 1136 ** Parameters: 1137 ** a -- possible substring. 1138 ** b -- possible superstring. 1139 ** 1140 ** Returns: 1141 ** TRUE if a is contained in b. 1142 ** FALSE otherwise. 1143 */ 1144 1145 bool 1146 strcontainedin(a, b) 1147 register char *a; 1148 register char *b; 1149 { 1150 int la; 1151 int lb; 1152 int c; 1153 1154 la = strlen(a); 1155 lb = strlen(b); 1156 c = *a; 1157 if (isascii(c) && isupper(c)) 1158 c = tolower(c); 1159 for (; lb-- >= la; b++) 1160 { 1161 if (*b != c && isascii(*b) && isupper(*b) && tolower(*b) != c) 1162 continue; 1163 if (strncasecmp(a, b, la) == 0) 1164 return TRUE; 1165 } 1166 return FALSE; 1167 } 1168 /* 1169 ** CHECKFD012 -- check low numbered file descriptors 1170 ** 1171 ** File descriptors 0, 1, and 2 should be open at all times. 1172 ** This routine verifies that, and fixes it if not true. 1173 ** 1174 ** Parameters: 1175 ** where -- a tag printed if the assertion failed 1176 ** 1177 ** Returns: 1178 ** none 1179 */ 1180 1181 void 1182 checkfd012(where) 1183 char *where; 1184 { 1185 #if XDEBUG 1186 register int i; 1187 1188 for (i = 0; i < 3; i++) 1189 fill_fd(i, where); 1190 #endif /* XDEBUG */ 1191 } 1192 /* 1193 ** CHECKFDOPEN -- make sure file descriptor is open -- for extended debugging 1194 ** 1195 ** Parameters: 1196 ** fd -- file descriptor to check. 1197 ** where -- tag to print on failure. 1198 ** 1199 ** Returns: 1200 ** none. 1201 */ 1202 1203 void 1204 checkfdopen(fd, where) 1205 int fd; 1206 char *where; 1207 { 1208 #if XDEBUG 1209 struct stat st; 1210 1211 if (fstat(fd, &st) < 0 && errno == EBADF) 1212 { 1213 syserr("checkfdopen(%d): %s not open as expected!", fd, where); 1214 printopenfds(TRUE); 1215 } 1216 #endif 1217 } 1218 /* 1219 ** CHECKFDS -- check for new or missing file descriptors 1220 ** 1221 ** Parameters: 1222 ** where -- tag for printing. If null, take a base line. 1223 ** 1224 ** Returns: 1225 ** none 1226 ** 1227 ** Side Effects: 1228 ** If where is set, shows changes since the last call. 1229 */ 1230 1231 void 1232 checkfds(where) 1233 char *where; 1234 { 1235 int maxfd; 1236 register int fd; 1237 bool printhdr = TRUE; 1238 int save_errno = errno; 1239 static BITMAP baseline; 1240 extern int DtableSize; 1241 1242 if (DtableSize > 256) 1243 maxfd = 256; 1244 else 1245 maxfd = DtableSize; 1246 if (where == NULL) 1247 clrbitmap(baseline); 1248 1249 for (fd = 0; fd < maxfd; fd++) 1250 { 1251 struct stat stbuf; 1252 1253 if (fstat(fd, &stbuf) < 0 && errno != EOPNOTSUPP) 1254 { 1255 if (!bitnset(fd, baseline)) 1256 continue; 1257 clrbitn(fd, baseline); 1258 } 1259 else if (!bitnset(fd, baseline)) 1260 setbitn(fd, baseline); 1261 else 1262 continue; 1263 1264 /* file state has changed */ 1265 if (where == NULL) 1266 continue; 1267 if (printhdr) 1268 { 1269 sm_syslog(LOG_DEBUG, CurEnv->e_id, 1270 "%s: changed fds:", 1271 where); 1272 printhdr = FALSE; 1273 } 1274 dumpfd(fd, TRUE, TRUE); 1275 } 1276 errno = save_errno; 1277 } 1278 /* 1279 ** PRINTOPENFDS -- print the open file descriptors (for debugging) 1280 ** 1281 ** Parameters: 1282 ** logit -- if set, send output to syslog; otherwise 1283 ** print for debugging. 1284 ** 1285 ** Returns: 1286 ** none. 1287 */ 1288 1289 #include <arpa/inet.h> 1290 1291 void 1292 printopenfds(logit) 1293 bool logit; 1294 { 1295 register int fd; 1296 extern int DtableSize; 1297 1298 for (fd = 0; fd < DtableSize; fd++) 1299 dumpfd(fd, FALSE, logit); 1300 } 1301 /* 1302 ** DUMPFD -- dump a file descriptor 1303 ** 1304 ** Parameters: 1305 ** fd -- the file descriptor to dump. 1306 ** printclosed -- if set, print a notification even if 1307 ** it is closed; otherwise print nothing. 1308 ** logit -- if set, send output to syslog instead of stdout. 1309 */ 1310 1311 void 1312 dumpfd(fd, printclosed, logit) 1313 int fd; 1314 bool printclosed; 1315 bool logit; 1316 { 1317 register char *p; 1318 char *hp; 1319 #ifdef S_IFSOCK 1320 SOCKADDR sa; 1321 #endif 1322 auto SOCKADDR_LEN_T slen; 1323 int i; 1324 #if STAT64 > 0 1325 struct stat64 st; 1326 #else 1327 struct stat st; 1328 #endif 1329 char buf[200]; 1330 1331 p = buf; 1332 snprintf(p, SPACELEFT(buf, p), "%3d: ", fd); 1333 p += strlen(p); 1334 1335 if ( 1336 #if STAT64 > 0 1337 fstat64(fd, &st) 1338 #else 1339 fstat(fd, &st) 1340 #endif 1341 < 0) 1342 { 1343 if (errno != EBADF) 1344 { 1345 snprintf(p, SPACELEFT(buf, p), "CANNOT STAT (%s)", 1346 errstring(errno)); 1347 goto printit; 1348 } 1349 else if (printclosed) 1350 { 1351 snprintf(p, SPACELEFT(buf, p), "CLOSED"); 1352 goto printit; 1353 } 1354 return; 1355 } 1356 1357 i = fcntl(fd, F_GETFL, NULL); 1358 if (i != -1) 1359 { 1360 snprintf(p, SPACELEFT(buf, p), "fl=0x%x, ", i); 1361 p += strlen(p); 1362 } 1363 1364 snprintf(p, SPACELEFT(buf, p), "mode=%o: ", st.st_mode); 1365 p += strlen(p); 1366 switch (st.st_mode & S_IFMT) 1367 { 1368 #ifdef S_IFSOCK 1369 case S_IFSOCK: 1370 snprintf(p, SPACELEFT(buf, p), "SOCK "); 1371 p += strlen(p); 1372 slen = sizeof sa; 1373 if (getsockname(fd, &sa.sa, &slen) < 0) 1374 snprintf(p, SPACELEFT(buf, p), "(%s)", errstring(errno)); 1375 else 1376 { 1377 hp = hostnamebyanyaddr(&sa); 1378 if (sa.sa.sa_family == AF_INET) 1379 snprintf(p, SPACELEFT(buf, p), "%s/%d", 1380 hp, ntohs(sa.sin.sin_port)); 1381 else 1382 snprintf(p, SPACELEFT(buf, p), "%s", hp); 1383 } 1384 p += strlen(p); 1385 snprintf(p, SPACELEFT(buf, p), "->"); 1386 p += strlen(p); 1387 slen = sizeof sa; 1388 if (getpeername(fd, &sa.sa, &slen) < 0) 1389 snprintf(p, SPACELEFT(buf, p), "(%s)", errstring(errno)); 1390 else 1391 { 1392 hp = hostnamebyanyaddr(&sa); 1393 if (sa.sa.sa_family == AF_INET) 1394 snprintf(p, SPACELEFT(buf, p), "%s/%d", 1395 hp, ntohs(sa.sin.sin_port)); 1396 else 1397 snprintf(p, SPACELEFT(buf, p), "%s", hp); 1398 } 1399 break; 1400 #endif 1401 1402 case S_IFCHR: 1403 snprintf(p, SPACELEFT(buf, p), "CHR: "); 1404 p += strlen(p); 1405 goto defprint; 1406 1407 case S_IFBLK: 1408 snprintf(p, SPACELEFT(buf, p), "BLK: "); 1409 p += strlen(p); 1410 goto defprint; 1411 1412 #if defined(S_IFIFO) && (!defined(S_IFSOCK) || S_IFIFO != S_IFSOCK) 1413 case S_IFIFO: 1414 snprintf(p, SPACELEFT(buf, p), "FIFO: "); 1415 p += strlen(p); 1416 goto defprint; 1417 #endif 1418 1419 #ifdef S_IFDIR 1420 case S_IFDIR: 1421 snprintf(p, SPACELEFT(buf, p), "DIR: "); 1422 p += strlen(p); 1423 goto defprint; 1424 #endif 1425 1426 #ifdef S_IFLNK 1427 case S_IFLNK: 1428 snprintf(p, SPACELEFT(buf, p), "LNK: "); 1429 p += strlen(p); 1430 goto defprint; 1431 #endif 1432 1433 default: 1434 defprint: 1435 if (sizeof st.st_ino > sizeof (long)) 1436 snprintf(p, SPACELEFT(buf, p), 1437 "dev=%d/%d, ino=%s, nlink=%d, u/gid=%d/%d, ", 1438 major(st.st_dev), minor(st.st_dev), 1439 quad_to_string(st.st_ino), 1440 st.st_nlink, st.st_uid, st.st_gid); 1441 else 1442 snprintf(p, SPACELEFT(buf, p), 1443 "dev=%d/%d, ino=%lu, nlink=%d, u/gid=%d/%d, ", 1444 major(st.st_dev), minor(st.st_dev), 1445 (unsigned long) st.st_ino, 1446 st.st_nlink, st.st_uid, st.st_gid); 1447 if (sizeof st.st_size > sizeof (long)) 1448 snprintf(p, SPACELEFT(buf, p), "size=%s", 1449 quad_to_string(st.st_size)); 1450 else 1451 snprintf(p, SPACELEFT(buf, p), "size=%lu", 1452 (unsigned long) st.st_size); 1453 break; 1454 } 1455 1456 printit: 1457 if (logit) 1458 sm_syslog(LOG_DEBUG, CurEnv ? CurEnv->e_id : NULL, 1459 "%.800s", buf); 1460 else 1461 printf("%s\n", buf); 1462 } 1463 /* 1464 ** SHORTEN_HOSTNAME -- strip local domain information off of hostname. 1465 ** 1466 ** Parameters: 1467 ** host -- the host to shorten (stripped in place). 1468 ** 1469 ** Returns: 1470 ** none. 1471 */ 1472 1473 void 1474 shorten_hostname(host) 1475 char host[]; 1476 { 1477 register char *p; 1478 char *mydom; 1479 int i; 1480 bool canon = FALSE; 1481 1482 /* strip off final dot */ 1483 p = &host[strlen(host) - 1]; 1484 if (*p == '.') 1485 { 1486 *p = '\0'; 1487 canon = TRUE; 1488 } 1489 1490 /* see if there is any domain at all -- if not, we are done */ 1491 p = strchr(host, '.'); 1492 if (p == NULL) 1493 return; 1494 1495 /* yes, we have a domain -- see if it looks like us */ 1496 mydom = macvalue('m', CurEnv); 1497 if (mydom == NULL) 1498 mydom = ""; 1499 i = strlen(++p); 1500 if ((canon ? strcasecmp(p, mydom) : strncasecmp(p, mydom, i)) == 0 && 1501 (mydom[i] == '.' || mydom[i] == '\0')) 1502 *--p = '\0'; 1503 } 1504 /* 1505 ** PROG_OPEN -- open a program for reading 1506 ** 1507 ** Parameters: 1508 ** argv -- the argument list. 1509 ** pfd -- pointer to a place to store the file descriptor. 1510 ** e -- the current envelope. 1511 ** 1512 ** Returns: 1513 ** pid of the process -- -1 if it failed. 1514 */ 1515 1516 int 1517 prog_open(argv, pfd, e) 1518 char **argv; 1519 int *pfd; 1520 ENVELOPE *e; 1521 { 1522 int pid; 1523 int i; 1524 int saveerrno; 1525 int fdv[2]; 1526 char *p, *q; 1527 char buf[MAXLINE + 1]; 1528 extern int DtableSize; 1529 1530 if (pipe(fdv) < 0) 1531 { 1532 syserr("%s: cannot create pipe for stdout", argv[0]); 1533 return -1; 1534 } 1535 pid = fork(); 1536 if (pid < 0) 1537 { 1538 syserr("%s: cannot fork", argv[0]); 1539 close(fdv[0]); 1540 close(fdv[1]); 1541 return -1; 1542 } 1543 if (pid > 0) 1544 { 1545 /* parent */ 1546 close(fdv[1]); 1547 *pfd = fdv[0]; 1548 return pid; 1549 } 1550 1551 /* child -- close stdin */ 1552 close(0); 1553 1554 /* stdout goes back to parent */ 1555 close(fdv[0]); 1556 if (dup2(fdv[1], 1) < 0) 1557 { 1558 syserr("%s: cannot dup2 for stdout", argv[0]); 1559 _exit(EX_OSERR); 1560 } 1561 close(fdv[1]); 1562 1563 /* stderr goes to transcript if available */ 1564 if (e->e_xfp != NULL) 1565 { 1566 if (dup2(fileno(e->e_xfp), 2) < 0) 1567 { 1568 syserr("%s: cannot dup2 for stderr", argv[0]); 1569 _exit(EX_OSERR); 1570 } 1571 } 1572 1573 /* this process has no right to the queue file */ 1574 if (e->e_lockfp != NULL) 1575 close(fileno(e->e_lockfp)); 1576 1577 /* run as default user */ 1578 endpwent(); 1579 if (setgid(DefGid) < 0 && geteuid() == 0) 1580 syserr("prog_open: setgid(%ld) failed", (long) DefGid); 1581 if (setuid(DefUid) < 0 && geteuid() == 0) 1582 syserr("prog_open: setuid(%ld) failed", (long) DefUid); 1583 1584 /* run in some directory */ 1585 if (ProgMailer != NULL) 1586 p = ProgMailer->m_execdir; 1587 else 1588 p = NULL; 1589 for (; p != NULL; p = q) 1590 { 1591 q = strchr(p, ':'); 1592 if (q != NULL) 1593 *q = '\0'; 1594 expand(p, buf, sizeof buf, e); 1595 if (q != NULL) 1596 *q++ = ':'; 1597 if (buf[0] != '\0' && chdir(buf) >= 0) 1598 break; 1599 } 1600 if (p == NULL) 1601 { 1602 /* backup directories */ 1603 if (chdir("/tmp") < 0) 1604 (void) chdir("/"); 1605 } 1606 1607 /* arrange for all the files to be closed */ 1608 for (i = 3; i < DtableSize; i++) 1609 { 1610 register int j; 1611 1612 if ((j = fcntl(i, F_GETFD, 0)) != -1) 1613 (void) fcntl(i, F_SETFD, j | 1); 1614 } 1615 1616 /* now exec the process */ 1617 execve(argv[0], (ARGV_T) argv, (ARGV_T) UserEnviron); 1618 1619 /* woops! failed */ 1620 saveerrno = errno; 1621 syserr("%s: cannot exec", argv[0]); 1622 if (transienterror(saveerrno)) 1623 _exit(EX_OSERR); 1624 _exit(EX_CONFIG); 1625 return -1; /* avoid compiler warning on IRIX */ 1626 } 1627 /* 1628 ** GET_COLUMN -- look up a Column in a line buffer 1629 ** 1630 ** Parameters: 1631 ** line -- the raw text line to search. 1632 ** col -- the column number to fetch. 1633 ** delim -- the delimiter between columns. If null, 1634 ** use white space. 1635 ** buf -- the output buffer. 1636 ** buflen -- the length of buf. 1637 ** 1638 ** Returns: 1639 ** buf if successful. 1640 ** NULL otherwise. 1641 */ 1642 1643 char * 1644 get_column(line, col, delim, buf, buflen) 1645 char line[]; 1646 int col; 1647 char delim; 1648 char buf[]; 1649 int buflen; 1650 { 1651 char *p; 1652 char *begin, *end; 1653 int i; 1654 char delimbuf[4]; 1655 1656 if (delim == '\0') 1657 strcpy(delimbuf, "\n\t "); 1658 else 1659 { 1660 delimbuf[0] = delim; 1661 delimbuf[1] = '\0'; 1662 } 1663 1664 p = line; 1665 if (*p == '\0') 1666 return NULL; /* line empty */ 1667 if (*p == delim && col == 0) 1668 return NULL; /* first column empty */ 1669 1670 begin = line; 1671 1672 if (col == 0 && delim == '\0') 1673 { 1674 while (*begin != '\0' && isascii(*begin) && isspace(*begin)) 1675 begin++; 1676 } 1677 1678 for (i = 0; i < col; i++) 1679 { 1680 if ((begin = strpbrk(begin, delimbuf)) == NULL) 1681 return NULL; /* no such column */ 1682 begin++; 1683 if (delim == '\0') 1684 { 1685 while (*begin != '\0' && isascii(*begin) && isspace(*begin)) 1686 begin++; 1687 } 1688 } 1689 1690 end = strpbrk(begin, delimbuf); 1691 if (end == NULL) 1692 i = strlen(begin); 1693 else 1694 i = end - begin; 1695 if (i >= buflen) 1696 i = buflen - 1; 1697 strncpy(buf, begin, i); 1698 buf[i] = '\0'; 1699 return buf; 1700 } 1701 /* 1702 ** CLEANSTRCPY -- copy string keeping out bogus characters 1703 ** 1704 ** Parameters: 1705 ** t -- "to" string. 1706 ** f -- "from" string. 1707 ** l -- length of space available in "to" string. 1708 ** 1709 ** Returns: 1710 ** none. 1711 */ 1712 1713 void 1714 cleanstrcpy(t, f, l) 1715 register char *t; 1716 register char *f; 1717 int l; 1718 { 1719 /* check for newlines and log if necessary */ 1720 (void) denlstring(f, TRUE, TRUE); 1721 1722 l--; 1723 while (l > 0 && *f != '\0') 1724 { 1725 if (isascii(*f) && 1726 (isalnum(*f) || strchr("!#$%&'*+-./^_`{|}~", *f) != NULL)) 1727 { 1728 l--; 1729 *t++ = *f; 1730 } 1731 f++; 1732 } 1733 *t = '\0'; 1734 } 1735 /* 1736 ** DENLSTRING -- convert newlines in a string to spaces 1737 ** 1738 ** Parameters: 1739 ** s -- the input string 1740 ** strict -- if set, don't permit continuation lines. 1741 ** logattacks -- if set, log attempted attacks. 1742 ** 1743 ** Returns: 1744 ** A pointer to a version of the string with newlines 1745 ** mapped to spaces. This should be copied. 1746 */ 1747 1748 char * 1749 denlstring(s, strict, logattacks) 1750 char *s; 1751 bool strict; 1752 bool logattacks; 1753 { 1754 register char *p; 1755 int l; 1756 static char *bp = NULL; 1757 static int bl = 0; 1758 1759 p = s; 1760 while ((p = strchr(p, '\n')) != NULL) 1761 if (strict || (*++p != ' ' && *p != '\t')) 1762 break; 1763 if (p == NULL) 1764 return s; 1765 1766 l = strlen(s) + 1; 1767 if (bl < l) 1768 { 1769 /* allocate more space */ 1770 if (bp != NULL) 1771 free(bp); 1772 bp = xalloc(l); 1773 bl = l; 1774 } 1775 strcpy(bp, s); 1776 for (p = bp; (p = strchr(p, '\n')) != NULL; ) 1777 *p++ = ' '; 1778 1779 if (logattacks) 1780 { 1781 sm_syslog(LOG_NOTICE, CurEnv->e_id, 1782 "POSSIBLE ATTACK from %.100s: newline in string \"%s\"", 1783 RealHostName == NULL ? "[UNKNOWN]" : RealHostName, 1784 shortenstring(bp, MAXSHORTSTR)); 1785 } 1786 1787 return bp; 1788 } 1789 /* 1790 ** PATH_IS_DIR -- check to see if file exists and is a directory. 1791 ** 1792 ** There are some additional checks for security violations in 1793 ** here. This routine is intended to be used for the host status 1794 ** support. 1795 ** 1796 ** Parameters: 1797 ** pathname -- pathname to check for directory-ness. 1798 ** createflag -- if set, create directory if needed. 1799 ** 1800 ** Returns: 1801 ** TRUE -- if the indicated pathname is a directory 1802 ** FALSE -- otherwise 1803 */ 1804 1805 int 1806 path_is_dir(pathname, createflag) 1807 char *pathname; 1808 bool createflag; 1809 { 1810 struct stat statbuf; 1811 1812 #if HASLSTAT 1813 if (lstat(pathname, &statbuf) < 0) 1814 #else 1815 if (stat(pathname, &statbuf) < 0) 1816 #endif 1817 { 1818 if (errno != ENOENT || !createflag) 1819 return FALSE; 1820 if (mkdir(pathname, 0755) < 0) 1821 return FALSE; 1822 return TRUE; 1823 } 1824 if (!S_ISDIR(statbuf.st_mode)) 1825 { 1826 errno = ENOTDIR; 1827 return FALSE; 1828 } 1829 1830 /* security: don't allow writable directories */ 1831 if (bitset(S_IWGRP|S_IWOTH, statbuf.st_mode)) 1832 { 1833 errno = EACCES; 1834 return FALSE; 1835 } 1836 1837 return TRUE; 1838 } 1839 /* 1840 ** PROC_LIST_ADD -- add process id to list of our children 1841 ** 1842 ** Parameters: 1843 ** pid -- pid to add to list. 1844 ** 1845 ** Returns: 1846 ** none 1847 */ 1848 1849 static pid_t *ProcListVec = NULL; 1850 static int ProcListSize = 0; 1851 1852 #define NO_PID ((pid_t) 0) 1853 #ifndef PROC_LIST_SEG 1854 # define PROC_LIST_SEG 32 /* number of pids to alloc at a time */ 1855 #endif 1856 1857 void 1858 proc_list_add(pid) 1859 pid_t pid; 1860 { 1861 int i; 1862 extern void proc_list_probe __P((void)); 1863 1864 for (i = 0; i < ProcListSize; i++) 1865 { 1866 if (ProcListVec[i] == NO_PID) 1867 break; 1868 } 1869 if (i >= ProcListSize) 1870 { 1871 /* probe the existing vector to avoid growing infinitely */ 1872 proc_list_probe(); 1873 1874 /* now scan again */ 1875 for (i = 0; i < ProcListSize; i++) 1876 { 1877 if (ProcListVec[i] == NO_PID) 1878 break; 1879 } 1880 } 1881 if (i >= ProcListSize) 1882 { 1883 /* grow process list */ 1884 pid_t *npv; 1885 1886 npv = (pid_t *) xalloc(sizeof (pid_t) * (ProcListSize + PROC_LIST_SEG)); 1887 if (ProcListSize > 0) 1888 { 1889 bcopy(ProcListVec, npv, ProcListSize * sizeof (pid_t)); 1890 free(ProcListVec); 1891 } 1892 for (i = ProcListSize; i < ProcListSize + PROC_LIST_SEG; i++) 1893 npv[i] = NO_PID; 1894 i = ProcListSize; 1895 ProcListSize += PROC_LIST_SEG; 1896 ProcListVec = npv; 1897 } 1898 ProcListVec[i] = pid; 1899 CurChildren++; 1900 } 1901 /* 1902 ** PROC_LIST_DROP -- drop pid from process list 1903 ** 1904 ** Parameters: 1905 ** pid -- pid to drop 1906 ** 1907 ** Returns: 1908 ** none. 1909 */ 1910 1911 void 1912 proc_list_drop(pid) 1913 pid_t pid; 1914 { 1915 int i; 1916 1917 for (i = 0; i < ProcListSize; i++) 1918 { 1919 if (ProcListVec[i] == pid) 1920 { 1921 ProcListVec[i] = NO_PID; 1922 break; 1923 } 1924 } 1925 if (CurChildren > 0) 1926 CurChildren--; 1927 } 1928 /* 1929 ** PROC_LIST_CLEAR -- clear the process list 1930 ** 1931 ** Parameters: 1932 ** none. 1933 ** 1934 ** Returns: 1935 ** none. 1936 */ 1937 1938 void 1939 proc_list_clear() 1940 { 1941 int i; 1942 1943 for (i = 0; i < ProcListSize; i++) 1944 ProcListVec[i] = NO_PID; 1945 CurChildren = 0; 1946 } 1947 /* 1948 ** PROC_LIST_PROBE -- probe processes in the list to see if they still exist 1949 ** 1950 ** Parameters: 1951 ** none 1952 ** 1953 ** Returns: 1954 ** none 1955 */ 1956 1957 void 1958 proc_list_probe() 1959 { 1960 int i; 1961 1962 for (i = 0; i < ProcListSize; i++) 1963 { 1964 if (ProcListVec[i] == NO_PID) 1965 continue; 1966 if (kill(ProcListVec[i], 0) < 0) 1967 { 1968 if (LogLevel > 3) 1969 sm_syslog(LOG_DEBUG, CurEnv->e_id, 1970 "proc_list_probe: lost pid %d", 1971 ProcListVec[i]); 1972 ProcListVec[i] = NO_PID; 1973 CurChildren--; 1974 } 1975 } 1976 if (CurChildren < 0) 1977 CurChildren = 0; 1978 } 1979 /* 1980 ** SM_STRCASECMP -- 8-bit clean version of strcasecmp 1981 ** 1982 ** Thank you, vendors, for making this all necessary. 1983 */ 1984 1985 /* 1986 * Copyright (c) 1987, 1993 1987 * The Regents of the University of California. All rights reserved. 1988 * 1989 * Redistribution and use in source and binary forms, with or without 1990 * modification, are permitted provided that the following conditions 1991 * are met: 1992 * 1. Redistributions of source code must retain the above copyright 1993 * notice, this list of conditions and the following disclaimer. 1994 * 2. Redistributions in binary form must reproduce the above copyright 1995 * notice, this list of conditions and the following disclaimer in the 1996 * documentation and/or other materials provided with the distribution. 1997 * 3. All advertising materials mentioning features or use of this software 1998 * must display the following acknowledgement: 1999 * This product includes software developed by the University of 2000 * California, Berkeley and its contributors. 2001 * 4. Neither the name of the University nor the names of its contributors 2002 * may be used to endorse or promote products derived from this software 2003 * without specific prior written permission. 2004 * 2005 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2006 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2007 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2008 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2009 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2010 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2011 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2012 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2013 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2014 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2015 * SUCH DAMAGE. 2016 */ 2017 2018 #if defined(LIBC_SCCS) && !defined(lint) 2019 static char sccsid[] = "@(#)strcasecmp.c 8.1 (Berkeley) 6/4/93"; 2020 #endif /* LIBC_SCCS and not lint */ 2021 2022 /* 2023 * This array is designed for mapping upper and lower case letter 2024 * together for a case independent comparison. The mappings are 2025 * based upon ascii character sequences. 2026 */ 2027 static const u_char charmap[] = { 2028 0000, 0001, 0002, 0003, 0004, 0005, 0006, 0007, 2029 0010, 0011, 0012, 0013, 0014, 0015, 0016, 0017, 2030 0020, 0021, 0022, 0023, 0024, 0025, 0026, 0027, 2031 0030, 0031, 0032, 0033, 0034, 0035, 0036, 0037, 2032 0040, 0041, 0042, 0043, 0044, 0045, 0046, 0047, 2033 0050, 0051, 0052, 0053, 0054, 0055, 0056, 0057, 2034 0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067, 2035 0070, 0071, 0072, 0073, 0074, 0075, 0076, 0077, 2036 0100, 0141, 0142, 0143, 0144, 0145, 0146, 0147, 2037 0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157, 2038 0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167, 2039 0170, 0171, 0172, 0133, 0134, 0135, 0136, 0137, 2040 0140, 0141, 0142, 0143, 0144, 0145, 0146, 0147, 2041 0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157, 2042 0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167, 2043 0170, 0171, 0172, 0173, 0174, 0175, 0176, 0177, 2044 0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207, 2045 0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217, 2046 0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227, 2047 0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237, 2048 0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247, 2049 0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257, 2050 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267, 2051 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277, 2052 0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307, 2053 0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317, 2054 0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327, 2055 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337, 2056 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347, 2057 0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357, 2058 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367, 2059 0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377, 2060 }; 2061 2062 int 2063 sm_strcasecmp(s1, s2) 2064 const char *s1, *s2; 2065 { 2066 register const u_char *cm = charmap, 2067 *us1 = (const u_char *)s1, 2068 *us2 = (const u_char *)s2; 2069 2070 while (cm[*us1] == cm[*us2++]) 2071 if (*us1++ == '\0') 2072 return (0); 2073 return (cm[*us1] - cm[*--us2]); 2074 } 2075 2076 int 2077 sm_strncasecmp(s1, s2, n) 2078 const char *s1, *s2; 2079 register size_t n; 2080 { 2081 if (n != 0) { 2082 register const u_char *cm = charmap, 2083 *us1 = (const u_char *)s1, 2084 *us2 = (const u_char *)s2; 2085 2086 do { 2087 if (cm[*us1] != cm[*us2++]) 2088 return (cm[*us1] - cm[*--us2]); 2089 if (*us1++ == '\0') 2090 break; 2091 } while (--n != 0); 2092 } 2093 return (0); 2094 } 2095