1 /* 2 * Copyright (c) 1983 Eric P. Allman 3 * Copyright (c) 1988, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * %sccs.include.redist.c% 7 */ 8 9 #ifndef lint 10 static char sccsid[] = "@(#)util.c 8.17.1.1 (Berkeley) 11/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 ** TRUE -- if the resulting message should be a MIME format. 333 ** FALSE -- if MIME is not necessary. 334 ** 335 ** Side Effects: 336 ** none. 337 */ 338 339 /* values for should_quote */ 340 #define NO_QUOTE 0 341 #define SHOULD_QUOTE 1 342 #define SHOULD_MIME 2 343 344 int 345 buildfname(gecos, login, buf) 346 register unsigned char *gecos; 347 const unsigned char *login; 348 unsigned char *buf; 349 { 350 register unsigned char *bp = buf; 351 unsigned char *p; 352 int should_quote = NO_QUOTE; 353 354 /* make sure specials, SPACE and CTLs are quoted within " " */ 355 for (p = gecos; *p && *p != ',' && *p != ';' && *p != '%'; p++) 356 { 357 if (*p >= 0200) 358 { 359 should_quote = SHOULD_MIME; 360 break; 361 } 362 switch (*p) 363 { 364 case '(': 365 case ')': 366 case '<': 367 case '>': 368 case '@': 369 case ':': 370 case '\\': 371 case '"': 372 case '.': 373 case '[': 374 case ']': 375 should_quote = SHOULD_QUOTE; 376 break; 377 } 378 } 379 if (should_quote == SHOULD_MIME) 380 { 381 strcpy (bp, "=?iso-8859-1?Q?"); 382 bp += 15; 383 for (p = gecos; *p && *p != ',' && *p != ';' && *p != '%'; p++) 384 { 385 if (*p == ' ') 386 *bp++ = '_'; 387 else if (*p == '&') 388 { 389 (void) strcpy(bp, login); 390 *bp = toupper(*bp); 391 bp += strlen (bp); 392 } 393 else if (*p < 040 || *p >= 200 || 394 strchr("_?()<>@:\\\".[]", *p) != NULL) 395 { 396 *bp++ = '='; 397 *bp++ = "0123456789ABCDEF"[(*p >> 4) & 0xf]; 398 *bp++ = "0123456789ABCDEF"[*p & 0xf]; 399 } 400 else 401 *bp++ = *p; 402 } 403 strcpy (bp, "?= "); 404 bp += 3; 405 } 406 else 407 { 408 if (should_quote) 409 *bp++ = '"'; 410 for (p = gecos; *p && *p != ',' && *p != ';' && *p != '%'; p++) 411 { 412 if (*p == '&') 413 { 414 (void) strcpy(bp, login); 415 *bp = toupper(*bp); 416 while (*bp != '\0') 417 bp++; 418 } 419 else 420 { 421 if (*p == '"') 422 *bp++ = '\\'; 423 *bp++ = *p; 424 } 425 } 426 if (bp[-1] == '\\') 427 *bp++ = '\\'; 428 if (should_quote) 429 *bp++ = '"'; 430 } 431 432 *bp = '\0'; 433 return should_quote == SHOULD_MIME; 434 } 435 /* 436 ** SAFEFILE -- return true if a file exists and is safe for a user. 437 ** 438 ** Parameters: 439 ** fn -- filename to check. 440 ** uid -- user id to compare against. 441 ** gid -- group id to compare against. 442 ** uname -- user name to compare against (used for group 443 ** sets). 444 ** flags -- modifiers: 445 ** SF_MUSTOWN -- "uid" must own this file. 446 ** SF_NOSLINK -- file cannot be a symbolic link. 447 ** mode -- mode bits that must match. 448 ** 449 ** Returns: 450 ** 0 if fn exists, is owned by uid, and matches mode. 451 ** An errno otherwise. The actual errno is cleared. 452 ** 453 ** Side Effects: 454 ** none. 455 */ 456 457 #include <grp.h> 458 459 #ifndef S_IXOTH 460 # define S_IXOTH (S_IEXEC >> 6) 461 #endif 462 463 #ifndef S_IXGRP 464 # define S_IXGRP (S_IEXEC >> 3) 465 #endif 466 467 #ifndef S_IXUSR 468 # define S_IXUSR (S_IEXEC) 469 #endif 470 471 int 472 safefile(fn, uid, gid, uname, flags, mode) 473 char *fn; 474 uid_t uid; 475 gid_t gid; 476 char *uname; 477 int flags; 478 int mode; 479 { 480 register char *p; 481 register struct group *gr = NULL; 482 struct stat stbuf; 483 484 if (tTd(54, 4)) 485 printf("safefile(%s, uid=%d, gid=%d, flags=%x, mode=%o):\n", 486 fn, uid, gid, flags, mode); 487 errno = 0; 488 489 for (p = fn; (p = strchr(++p, '/')) != NULL; *p = '/') 490 { 491 *p = '\0'; 492 if (stat(fn, &stbuf) < 0) 493 break; 494 if (stbuf.st_uid == uid && bitset(S_IXUSR, stbuf.st_mode)) 495 continue; 496 if (stbuf.st_gid == gid && bitset(S_IXGRP, stbuf.st_mode)) 497 continue; 498 #ifndef NO_GROUP_SET 499 if (uname != NULL && 500 ((gr != NULL && gr->gr_gid == stbuf.st_gid) || 501 (gr = getgrgid(stbuf.st_gid)) != NULL)) 502 { 503 register char **gp; 504 505 for (gp = gr->gr_mem; *gp != NULL; gp++) 506 if (strcmp(*gp, uname) == 0) 507 break; 508 if (*gp != NULL && bitset(S_IXGRP, stbuf.st_mode)) 509 continue; 510 } 511 #endif 512 if (!bitset(S_IXOTH, stbuf.st_mode)) 513 break; 514 } 515 if (p != NULL) 516 { 517 int ret = errno; 518 519 if (ret == 0) 520 ret = EACCES; 521 if (tTd(54, 4)) 522 printf("\t[dir %s] %s\n", fn, errstring(ret)); 523 *p = '/'; 524 return ret; 525 } 526 527 #ifdef HASLSTAT 528 if ((bitset(SF_NOSLINK, flags) ? lstat(fn, &stbuf) 529 : stat(fn, &stbuf)) < 0) 530 #else 531 if (stat(fn, &stbuf) < 0) 532 #endif 533 { 534 int ret = errno; 535 536 if (tTd(54, 4)) 537 printf("\t%s\n", errstring(ret)); 538 539 errno = 0; 540 return ret; 541 } 542 543 #ifdef S_ISLNK 544 if (bitset(SF_NOSLINK, flags) && S_ISLNK(stbuf.st_mode)) 545 { 546 if (tTd(54, 4)) 547 printf("\t[mode %o]\tEPERM\n"); 548 return EPERM; 549 } 550 #endif 551 552 if (uid == 0) 553 mode >>= 6; 554 else if (stbuf.st_uid != uid) 555 { 556 mode >>= 3; 557 if (stbuf.st_gid == gid) 558 ; 559 #ifndef NO_GROUP_SET 560 else if (uname != NULL && 561 ((gr != NULL && gr->gr_gid == stbuf.st_gid) || 562 (gr = getgrgid(stbuf.st_gid)) != NULL)) 563 { 564 register char **gp; 565 566 for (gp = gr->gr_mem; *gp != NULL; gp++) 567 if (strcmp(*gp, uname) == 0) 568 break; 569 if (*gp == NULL) 570 mode >>= 3; 571 } 572 #endif 573 else 574 mode >>= 3; 575 } 576 if (tTd(54, 4)) 577 printf("\t[uid %d, stat %o, mode %o] ", 578 stbuf.st_uid, stbuf.st_mode, mode); 579 if ((stbuf.st_uid == uid || stbuf.st_uid == 0 || 580 !bitset(SF_MUSTOWN, flags)) && 581 (stbuf.st_mode & mode) == mode) 582 { 583 if (tTd(54, 4)) 584 printf("\tOK\n"); 585 return 0; 586 } 587 if (tTd(54, 4)) 588 printf("\tEACCES\n"); 589 return EACCES; 590 } 591 /* 592 ** FIXCRLF -- fix <CR><LF> in line. 593 ** 594 ** Looks for the <CR><LF> combination and turns it into the 595 ** UNIX canonical <NL> character. It only takes one line, 596 ** i.e., it is assumed that the first <NL> found is the end 597 ** of the line. 598 ** 599 ** Parameters: 600 ** line -- the line to fix. 601 ** stripnl -- if true, strip the newline also. 602 ** 603 ** Returns: 604 ** none. 605 ** 606 ** Side Effects: 607 ** line is changed in place. 608 */ 609 610 fixcrlf(line, stripnl) 611 char *line; 612 bool stripnl; 613 { 614 register char *p; 615 616 p = strchr(line, '\n'); 617 if (p == NULL) 618 return; 619 if (p > line && p[-1] == '\r') 620 p--; 621 if (!stripnl) 622 *p++ = '\n'; 623 *p = '\0'; 624 } 625 /* 626 ** DFOPEN -- determined file open 627 ** 628 ** This routine has the semantics of fopen, except that it will 629 ** keep trying a few times to make this happen. The idea is that 630 ** on very loaded systems, we may run out of resources (inodes, 631 ** whatever), so this tries to get around it. 632 */ 633 634 #ifndef O_ACCMODE 635 # define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR) 636 #endif 637 638 struct omodes 639 { 640 int mask; 641 int mode; 642 char *farg; 643 } OpenModes[] = 644 { 645 O_ACCMODE, O_RDONLY, "r", 646 O_ACCMODE|O_APPEND, O_WRONLY, "w", 647 O_ACCMODE|O_APPEND, O_WRONLY|O_APPEND, "a", 648 O_TRUNC, 0, "w+", 649 O_APPEND, O_APPEND, "a+", 650 0, 0, "r+", 651 }; 652 653 FILE * 654 dfopen(filename, omode, cmode) 655 char *filename; 656 int omode; 657 int cmode; 658 { 659 register int tries; 660 int fd; 661 register struct omodes *om; 662 struct stat st; 663 664 for (om = OpenModes; om->mask != 0; om++) 665 if ((omode & om->mask) == om->mode) 666 break; 667 668 for (tries = 0; tries < 10; tries++) 669 { 670 sleep((unsigned) (10 * tries)); 671 errno = 0; 672 fd = open(filename, omode, cmode); 673 if (fd >= 0) 674 break; 675 if (errno != ENFILE && errno != EINTR) 676 break; 677 } 678 if (fd >= 0 && fstat(fd, &st) >= 0 && S_ISREG(st.st_mode)) 679 { 680 int locktype; 681 682 /* lock the file to avoid accidental conflicts */ 683 if ((omode & O_ACCMODE) != O_RDONLY) 684 locktype = LOCK_EX; 685 else 686 locktype = LOCK_SH; 687 (void) lockfile(fd, filename, NULL, locktype); 688 errno = 0; 689 } 690 if (fd < 0) 691 return NULL; 692 else 693 return fdopen(fd, om->farg); 694 } 695 /* 696 ** PUTLINE -- put a line like fputs obeying SMTP conventions 697 ** 698 ** This routine always guarantees outputing a newline (or CRLF, 699 ** as appropriate) at the end of the string. 700 ** 701 ** Parameters: 702 ** l -- line to put. 703 ** fp -- file to put it onto. 704 ** m -- the mailer used to control output. 705 ** 706 ** Returns: 707 ** none 708 ** 709 ** Side Effects: 710 ** output of l to fp. 711 */ 712 713 putline(l, fp, m) 714 register char *l; 715 FILE *fp; 716 MAILER *m; 717 { 718 register char *p; 719 register char svchar; 720 721 /* strip out 0200 bits -- these can look like TELNET protocol */ 722 if (bitnset(M_7BITS, m->m_flags)) 723 { 724 for (p = l; (svchar = *p) != '\0'; ++p) 725 if (bitset(0200, svchar)) 726 *p = svchar &~ 0200; 727 } 728 729 do 730 { 731 /* find the end of the line */ 732 p = strchr(l, '\n'); 733 if (p == NULL) 734 p = &l[strlen(l)]; 735 736 if (TrafficLogFile != NULL) 737 fprintf(TrafficLogFile, "%05d >>> ", getpid()); 738 739 /* check for line overflow */ 740 while (m->m_linelimit > 0 && (p - l) > m->m_linelimit) 741 { 742 register char *q = &l[m->m_linelimit - 1]; 743 744 svchar = *q; 745 *q = '\0'; 746 if (l[0] == '.' && bitnset(M_XDOT, m->m_flags)) 747 { 748 (void) putc('.', fp); 749 if (TrafficLogFile != NULL) 750 (void) putc('.', TrafficLogFile); 751 } 752 fputs(l, fp); 753 (void) putc('!', fp); 754 fputs(m->m_eol, fp); 755 if (TrafficLogFile != NULL) 756 fprintf(TrafficLogFile, "%s!\n%05d >>> ", 757 l, getpid()); 758 *q = svchar; 759 l = q; 760 } 761 762 /* output last part */ 763 if (l[0] == '.' && bitnset(M_XDOT, m->m_flags)) 764 { 765 (void) putc('.', fp); 766 if (TrafficLogFile != NULL) 767 (void) putc('.', TrafficLogFile); 768 } 769 if (TrafficLogFile != NULL) 770 fprintf(TrafficLogFile, "%.*s\n", p - l, l); 771 for ( ; l < p; ++l) 772 (void) putc(*l, fp); 773 fputs(m->m_eol, fp); 774 if (*l == '\n') 775 ++l; 776 } while (l[0] != '\0'); 777 } 778 /* 779 ** XUNLINK -- unlink a file, doing logging as appropriate. 780 ** 781 ** Parameters: 782 ** f -- name of file to unlink. 783 ** 784 ** Returns: 785 ** none. 786 ** 787 ** Side Effects: 788 ** f is unlinked. 789 */ 790 791 xunlink(f) 792 char *f; 793 { 794 register int i; 795 796 # ifdef LOG 797 if (LogLevel > 98) 798 syslog(LOG_DEBUG, "%s: unlink %s", CurEnv->e_id, f); 799 # endif /* LOG */ 800 801 i = unlink(f); 802 # ifdef LOG 803 if (i < 0 && LogLevel > 97) 804 syslog(LOG_DEBUG, "%s: unlink-fail %d", f, errno); 805 # endif /* LOG */ 806 } 807 /* 808 ** XFCLOSE -- close a file, doing logging as appropriate. 809 ** 810 ** Parameters: 811 ** fp -- file pointer for the file to close 812 ** a, b -- miscellaneous crud to print for debugging 813 ** 814 ** Returns: 815 ** none. 816 ** 817 ** Side Effects: 818 ** fp is closed. 819 */ 820 821 xfclose(fp, a, b) 822 FILE *fp; 823 char *a, *b; 824 { 825 if (tTd(53, 99)) 826 printf("xfclose(%x) %s %s\n", fp, a, b); 827 #ifdef XDEBUG 828 if (fileno(fp) == 1) 829 syserr("xfclose(%s %s): fd = 1", a, b); 830 #endif 831 if (fclose(fp) < 0 && tTd(53, 99)) 832 printf("xfclose FAILURE: %s\n", errstring(errno)); 833 } 834 /* 835 ** SFGETS -- "safe" fgets -- times out and ignores random interrupts. 836 ** 837 ** Parameters: 838 ** buf -- place to put the input line. 839 ** siz -- size of buf. 840 ** fp -- file to read from. 841 ** timeout -- the timeout before error occurs. 842 ** during -- what we are trying to read (for error messages). 843 ** 844 ** Returns: 845 ** NULL on error (including timeout). This will also leave 846 ** buf containing a null string. 847 ** buf otherwise. 848 ** 849 ** Side Effects: 850 ** none. 851 */ 852 853 static jmp_buf CtxReadTimeout; 854 static int readtimeout(); 855 856 char * 857 sfgets(buf, siz, fp, timeout, during) 858 char *buf; 859 int siz; 860 FILE *fp; 861 time_t timeout; 862 char *during; 863 { 864 register EVENT *ev = NULL; 865 register char *p; 866 867 /* set the timeout */ 868 if (timeout != 0) 869 { 870 if (setjmp(CtxReadTimeout) != 0) 871 { 872 # ifdef LOG 873 syslog(LOG_NOTICE, 874 "timeout waiting for input from %s during %s\n", 875 CurHostName? CurHostName: "local", during); 876 # endif 877 errno = 0; 878 usrerr("451 timeout waiting for input during %s", 879 during); 880 buf[0] = '\0'; 881 #ifdef XDEBUG 882 checkfd012(during); 883 #endif 884 return (NULL); 885 } 886 ev = setevent(timeout, readtimeout, 0); 887 } 888 889 /* try to read */ 890 p = NULL; 891 while (p == NULL && !feof(fp) && !ferror(fp)) 892 { 893 errno = 0; 894 p = fgets(buf, siz, fp); 895 if (errno == EINTR) 896 clearerr(fp); 897 } 898 899 /* clear the event if it has not sprung */ 900 clrevent(ev); 901 902 /* clean up the books and exit */ 903 LineNumber++; 904 if (p == NULL) 905 { 906 buf[0] = '\0'; 907 if (TrafficLogFile != NULL) 908 fprintf(TrafficLogFile, "%05d <<< [EOF]\n", getpid()); 909 return (NULL); 910 } 911 if (TrafficLogFile != NULL) 912 fprintf(TrafficLogFile, "%05d <<< %s", getpid(), buf); 913 if (SevenBit) 914 for (p = buf; *p != '\0'; p++) 915 *p &= ~0200; 916 return (buf); 917 } 918 919 static 920 readtimeout() 921 { 922 longjmp(CtxReadTimeout, 1); 923 } 924 /* 925 ** FGETFOLDED -- like fgets, but know about folded lines. 926 ** 927 ** Parameters: 928 ** buf -- place to put result. 929 ** n -- bytes available. 930 ** f -- file to read from. 931 ** 932 ** Returns: 933 ** input line(s) on success, NULL on error or EOF. 934 ** This will normally be buf -- unless the line is too 935 ** long, when it will be xalloc()ed. 936 ** 937 ** Side Effects: 938 ** buf gets lines from f, with continuation lines (lines 939 ** with leading white space) appended. CRLF's are mapped 940 ** into single newlines. Any trailing NL is stripped. 941 */ 942 943 char * 944 fgetfolded(buf, n, f) 945 char *buf; 946 register int n; 947 FILE *f; 948 { 949 register char *p = buf; 950 char *bp = buf; 951 register int i; 952 953 n--; 954 while ((i = getc(f)) != EOF) 955 { 956 if (i == '\r') 957 { 958 i = getc(f); 959 if (i != '\n') 960 { 961 if (i != EOF) 962 (void) ungetc(i, f); 963 i = '\r'; 964 } 965 } 966 if (--n <= 0) 967 { 968 /* allocate new space */ 969 char *nbp; 970 int nn; 971 972 nn = (p - bp); 973 if (nn < MEMCHUNKSIZE) 974 nn *= 2; 975 else 976 nn += MEMCHUNKSIZE; 977 nbp = xalloc(nn); 978 bcopy(bp, nbp, p - bp); 979 p = &nbp[p - bp]; 980 if (bp != buf) 981 free(bp); 982 bp = nbp; 983 n = nn - (p - bp); 984 } 985 *p++ = i; 986 if (i == '\n') 987 { 988 LineNumber++; 989 i = getc(f); 990 if (i != EOF) 991 (void) ungetc(i, f); 992 if (i != ' ' && i != '\t') 993 break; 994 } 995 } 996 if (p == bp) 997 return (NULL); 998 *--p = '\0'; 999 return (bp); 1000 } 1001 /* 1002 ** CURTIME -- return current time. 1003 ** 1004 ** Parameters: 1005 ** none. 1006 ** 1007 ** Returns: 1008 ** the current time. 1009 ** 1010 ** Side Effects: 1011 ** none. 1012 */ 1013 1014 time_t 1015 curtime() 1016 { 1017 auto time_t t; 1018 1019 (void) time(&t); 1020 return (t); 1021 } 1022 /* 1023 ** ATOBOOL -- convert a string representation to boolean. 1024 ** 1025 ** Defaults to "TRUE" 1026 ** 1027 ** Parameters: 1028 ** s -- string to convert. Takes "tTyY" as true, 1029 ** others as false. 1030 ** 1031 ** Returns: 1032 ** A boolean representation of the string. 1033 ** 1034 ** Side Effects: 1035 ** none. 1036 */ 1037 1038 bool 1039 atobool(s) 1040 register char *s; 1041 { 1042 if (s == NULL || *s == '\0' || strchr("tTyY", *s) != NULL) 1043 return (TRUE); 1044 return (FALSE); 1045 } 1046 /* 1047 ** ATOOCT -- convert a string representation to octal. 1048 ** 1049 ** Parameters: 1050 ** s -- string to convert. 1051 ** 1052 ** Returns: 1053 ** An integer representing the string interpreted as an 1054 ** octal number. 1055 ** 1056 ** Side Effects: 1057 ** none. 1058 */ 1059 1060 atooct(s) 1061 register char *s; 1062 { 1063 register int i = 0; 1064 1065 while (*s >= '0' && *s <= '7') 1066 i = (i << 3) | (*s++ - '0'); 1067 return (i); 1068 } 1069 /* 1070 ** WAITFOR -- wait for a particular process id. 1071 ** 1072 ** Parameters: 1073 ** pid -- process id to wait for. 1074 ** 1075 ** Returns: 1076 ** status of pid. 1077 ** -1 if pid never shows up. 1078 ** 1079 ** Side Effects: 1080 ** none. 1081 */ 1082 1083 int 1084 waitfor(pid) 1085 int pid; 1086 { 1087 #ifdef WAITUNION 1088 union wait st; 1089 #else 1090 auto int st; 1091 #endif 1092 int i; 1093 1094 do 1095 { 1096 errno = 0; 1097 i = wait(&st); 1098 } while ((i >= 0 || errno == EINTR) && i != pid); 1099 if (i < 0) 1100 return -1; 1101 #ifdef WAITUNION 1102 return st.w_status; 1103 #else 1104 return st; 1105 #endif 1106 } 1107 /* 1108 ** BITINTERSECT -- tell if two bitmaps intersect 1109 ** 1110 ** Parameters: 1111 ** a, b -- the bitmaps in question 1112 ** 1113 ** Returns: 1114 ** TRUE if they have a non-null intersection 1115 ** FALSE otherwise 1116 ** 1117 ** Side Effects: 1118 ** none. 1119 */ 1120 1121 bool 1122 bitintersect(a, b) 1123 BITMAP a; 1124 BITMAP b; 1125 { 1126 int i; 1127 1128 for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) 1129 if ((a[i] & b[i]) != 0) 1130 return (TRUE); 1131 return (FALSE); 1132 } 1133 /* 1134 ** BITZEROP -- tell if a bitmap is all zero 1135 ** 1136 ** Parameters: 1137 ** map -- the bit map to check 1138 ** 1139 ** Returns: 1140 ** TRUE if map is all zero. 1141 ** FALSE if there are any bits set in map. 1142 ** 1143 ** Side Effects: 1144 ** none. 1145 */ 1146 1147 bool 1148 bitzerop(map) 1149 BITMAP map; 1150 { 1151 int i; 1152 1153 for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) 1154 if (map[i] != 0) 1155 return (FALSE); 1156 return (TRUE); 1157 } 1158 /* 1159 ** STRCONTAINEDIN -- tell if one string is contained in another 1160 ** 1161 ** Parameters: 1162 ** a -- possible substring. 1163 ** b -- possible superstring. 1164 ** 1165 ** Returns: 1166 ** TRUE if a is contained in b. 1167 ** FALSE otherwise. 1168 */ 1169 1170 bool 1171 strcontainedin(a, b) 1172 register char *a; 1173 register char *b; 1174 { 1175 int l; 1176 1177 l = strlen(a); 1178 for (;;) 1179 { 1180 b = strchr(b, a[0]); 1181 if (b == NULL) 1182 return FALSE; 1183 if (strncmp(a, b, l) == 0) 1184 return TRUE; 1185 b++; 1186 } 1187 } 1188 /* 1189 ** CHECKFD012 -- check low numbered file descriptors 1190 ** 1191 ** File descriptors 0, 1, and 2 should be open at all times. 1192 ** This routine verifies that, and fixes it if not true. 1193 ** 1194 ** Parameters: 1195 ** where -- a tag printed if the assertion failed 1196 ** 1197 ** Returns: 1198 ** none 1199 */ 1200 1201 checkfd012(where) 1202 char *where; 1203 { 1204 #ifdef XDEBUG 1205 register int i; 1206 struct stat stbuf; 1207 1208 for (i = 0; i < 3; i++) 1209 { 1210 if (fstat(i, &stbuf) < 0 && errno != EOPNOTSUPP) 1211 { 1212 /* oops.... */ 1213 int fd; 1214 1215 syserr("%s: fd %d not open", where, i); 1216 fd = open("/dev/null", i == 0 ? O_RDONLY : O_WRONLY, 0666); 1217 if (fd != i) 1218 { 1219 (void) dup2(fd, i); 1220 (void) close(fd); 1221 } 1222 } 1223 } 1224 #endif /* XDEBUG */ 1225 } 1226 /* 1227 ** PRINTOPENFDS -- print the open file descriptors (for debugging) 1228 ** 1229 ** Parameters: 1230 ** logit -- if set, send output to syslog; otherwise 1231 ** print for debugging. 1232 ** 1233 ** Returns: 1234 ** none. 1235 */ 1236 1237 #include <netdb.h> 1238 #include <arpa/inet.h> 1239 1240 printopenfds(logit) 1241 bool logit; 1242 { 1243 register int fd; 1244 extern int DtableSize; 1245 1246 for (fd = 0; fd < DtableSize; fd++) 1247 dumpfd(fd, FALSE, logit); 1248 } 1249 /* 1250 ** DUMPFD -- dump a file descriptor 1251 ** 1252 ** Parameters: 1253 ** fd -- the file descriptor to dump. 1254 ** printclosed -- if set, print a notification even if 1255 ** it is closed; otherwise print nothing. 1256 ** logit -- if set, send output to syslog instead of stdout. 1257 */ 1258 1259 dumpfd(fd, printclosed, logit) 1260 int fd; 1261 bool printclosed; 1262 bool logit; 1263 { 1264 register struct hostent *hp; 1265 register char *p; 1266 struct sockaddr_in sin; 1267 auto int slen; 1268 struct stat st; 1269 char buf[200]; 1270 1271 p = buf; 1272 sprintf(p, "%3d: ", fd); 1273 p += strlen(p); 1274 1275 if (fstat(fd, &st) < 0) 1276 { 1277 if (printclosed || errno != EBADF) 1278 { 1279 sprintf(p, "CANNOT STAT (%s)", errstring(errno)); 1280 goto printit; 1281 } 1282 return; 1283 } 1284 1285 slen = fcntl(fd, F_GETFL, NULL); 1286 if (slen != -1) 1287 { 1288 sprintf(p, "fl=0x%x, ", slen); 1289 p += strlen(p); 1290 } 1291 1292 sprintf(p, "mode=%o: ", st.st_mode); 1293 p += strlen(p); 1294 switch (st.st_mode & S_IFMT) 1295 { 1296 #ifdef S_IFSOCK 1297 case S_IFSOCK: 1298 sprintf(p, "SOCK "); 1299 p += strlen(p); 1300 slen = sizeof sin; 1301 if (getsockname(fd, (struct sockaddr *) &sin, &slen) < 0) 1302 sprintf(p, "(badsock)"); 1303 else 1304 { 1305 hp = gethostbyaddr((char *) &sin.sin_addr, slen, AF_INET); 1306 sprintf(p, "%s/%d", hp == NULL ? inet_ntoa(sin.sin_addr) 1307 : hp->h_name, ntohs(sin.sin_port)); 1308 } 1309 p += strlen(p); 1310 sprintf(p, "->"); 1311 p += strlen(p); 1312 slen = sizeof sin; 1313 if (getpeername(fd, (struct sockaddr *) &sin, &slen) < 0) 1314 sprintf(p, "(badsock)"); 1315 else 1316 { 1317 hp = gethostbyaddr((char *) &sin.sin_addr, slen, AF_INET); 1318 sprintf(p, "%s/%d", hp == NULL ? inet_ntoa(sin.sin_addr) 1319 : hp->h_name, ntohs(sin.sin_port)); 1320 } 1321 break; 1322 #endif 1323 1324 case S_IFCHR: 1325 sprintf(p, "CHR: "); 1326 p += strlen(p); 1327 goto defprint; 1328 1329 case S_IFBLK: 1330 sprintf(p, "BLK: "); 1331 p += strlen(p); 1332 goto defprint; 1333 1334 default: 1335 defprint: 1336 sprintf(p, "dev=%d/%d, ino=%d, nlink=%d, u/gid=%d/%d, size=%ld", 1337 major(st.st_dev), minor(st.st_dev), st.st_ino, 1338 st.st_nlink, st.st_uid, st.st_gid, st.st_size); 1339 break; 1340 } 1341 1342 printit: 1343 if (logit) 1344 syslog(LOG_INFO, "%s", buf); 1345 else 1346 printf("%s\n", buf); 1347 } 1348