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.22 (Berkeley) 12/10/93"; 11 #endif /* not lint */ 12 13 # include "sendmail.h" 14 # include <sysexits.h> 15 /* 16 ** STRIPQUOTES -- Strip quotes & quote bits from a string. 17 ** 18 ** Runs through a string and strips off unquoted quote 19 ** characters and quote bits. This is done in place. 20 ** 21 ** Parameters: 22 ** s -- the string to strip. 23 ** 24 ** Returns: 25 ** none. 26 ** 27 ** Side Effects: 28 ** none. 29 ** 30 ** Called By: 31 ** deliver 32 */ 33 34 stripquotes(s) 35 char *s; 36 { 37 register char *p; 38 register char *q; 39 register char c; 40 41 if (s == NULL) 42 return; 43 44 p = q = s; 45 do 46 { 47 c = *p++; 48 if (c == '\\') 49 c = *p++; 50 else if (c == '"') 51 continue; 52 *q++ = c; 53 } while (c != '\0'); 54 } 55 /* 56 ** XALLOC -- Allocate memory and bitch wildly on failure. 57 ** 58 ** THIS IS A CLUDGE. This should be made to give a proper 59 ** error -- but after all, what can we do? 60 ** 61 ** Parameters: 62 ** sz -- size of area to allocate. 63 ** 64 ** Returns: 65 ** pointer to data region. 66 ** 67 ** Side Effects: 68 ** Memory is allocated. 69 */ 70 71 char * 72 xalloc(sz) 73 register int sz; 74 { 75 register char *p; 76 77 p = malloc((unsigned) sz); 78 if (p == NULL) 79 { 80 syserr("Out of memory!!"); 81 abort(); 82 /* exit(EX_UNAVAILABLE); */ 83 } 84 return (p); 85 } 86 /* 87 ** COPYPLIST -- copy list of pointers. 88 ** 89 ** This routine is the equivalent of newstr for lists of 90 ** pointers. 91 ** 92 ** Parameters: 93 ** list -- list of pointers to copy. 94 ** Must be NULL terminated. 95 ** copycont -- if TRUE, copy the contents of the vector 96 ** (which must be a string) also. 97 ** 98 ** Returns: 99 ** a copy of 'list'. 100 ** 101 ** Side Effects: 102 ** none. 103 */ 104 105 char ** 106 copyplist(list, copycont) 107 char **list; 108 bool copycont; 109 { 110 register char **vp; 111 register char **newvp; 112 113 for (vp = list; *vp != NULL; vp++) 114 continue; 115 116 vp++; 117 118 newvp = (char **) xalloc((int) (vp - list) * sizeof *vp); 119 bcopy((char *) list, (char *) newvp, (int) (vp - list) * sizeof *vp); 120 121 if (copycont) 122 { 123 for (vp = newvp; *vp != NULL; vp++) 124 *vp = newstr(*vp); 125 } 126 127 return (newvp); 128 } 129 /* 130 ** COPYQUEUE -- copy address queue. 131 ** 132 ** This routine is the equivalent of newstr for address queues 133 ** addresses marked with QDONTSEND aren't copied 134 ** 135 ** Parameters: 136 ** addr -- list of address structures to copy. 137 ** 138 ** Returns: 139 ** a copy of 'addr'. 140 ** 141 ** Side Effects: 142 ** none. 143 */ 144 145 ADDRESS * 146 copyqueue(addr) 147 ADDRESS *addr; 148 { 149 register ADDRESS *newaddr; 150 ADDRESS *ret; 151 register ADDRESS **tail = &ret; 152 153 while (addr != NULL) 154 { 155 if (!bitset(QDONTSEND, addr->q_flags)) 156 { 157 newaddr = (ADDRESS *) xalloc(sizeof(ADDRESS)); 158 STRUCTCOPY(*addr, *newaddr); 159 *tail = newaddr; 160 tail = &newaddr->q_next; 161 } 162 addr = addr->q_next; 163 } 164 *tail = NULL; 165 166 return ret; 167 } 168 /* 169 ** PRINTAV -- print argument vector. 170 ** 171 ** Parameters: 172 ** av -- argument vector. 173 ** 174 ** Returns: 175 ** none. 176 ** 177 ** Side Effects: 178 ** prints av. 179 */ 180 181 printav(av) 182 register char **av; 183 { 184 while (*av != NULL) 185 { 186 if (tTd(0, 44)) 187 printf("\n\t%08x=", *av); 188 else 189 (void) putchar(' '); 190 xputs(*av++); 191 } 192 (void) putchar('\n'); 193 } 194 /* 195 ** LOWER -- turn letter into lower case. 196 ** 197 ** Parameters: 198 ** c -- character to turn into lower case. 199 ** 200 ** Returns: 201 ** c, in lower case. 202 ** 203 ** Side Effects: 204 ** none. 205 */ 206 207 char 208 lower(c) 209 register char c; 210 { 211 return((isascii(c) && isupper(c)) ? tolower(c) : c); 212 } 213 /* 214 ** XPUTS -- put string doing control escapes. 215 ** 216 ** Parameters: 217 ** s -- string to put. 218 ** 219 ** Returns: 220 ** none. 221 ** 222 ** Side Effects: 223 ** output to stdout 224 */ 225 226 xputs(s) 227 register char *s; 228 { 229 register int c; 230 register struct metamac *mp; 231 extern struct metamac MetaMacros[]; 232 233 if (s == NULL) 234 { 235 printf("<null>"); 236 return; 237 } 238 while ((c = (*s++ & 0377)) != '\0') 239 { 240 if (!isascii(c)) 241 { 242 if (c == MATCHREPL || c == MACROEXPAND) 243 { 244 putchar('$'); 245 continue; 246 } 247 for (mp = MetaMacros; mp->metaname != '\0'; mp++) 248 { 249 if ((mp->metaval & 0377) == c) 250 { 251 printf("$%c", mp->metaname); 252 break; 253 } 254 } 255 if (mp->metaname != '\0') 256 continue; 257 (void) putchar('\\'); 258 c &= 0177; 259 } 260 if (isprint(c)) 261 { 262 putchar(c); 263 continue; 264 } 265 266 /* wasn't a meta-macro -- find another way to print it */ 267 switch (c) 268 { 269 case '\0': 270 continue; 271 272 case '\n': 273 c = 'n'; 274 break; 275 276 case '\r': 277 c = 'r'; 278 break; 279 280 case '\t': 281 c = 't'; 282 break; 283 284 default: 285 (void) putchar('^'); 286 (void) putchar(c ^ 0100); 287 continue; 288 } 289 } 290 (void) fflush(stdout); 291 } 292 /* 293 ** MAKELOWER -- Translate a line into lower case 294 ** 295 ** Parameters: 296 ** p -- the string to translate. If NULL, return is 297 ** immediate. 298 ** 299 ** Returns: 300 ** none. 301 ** 302 ** Side Effects: 303 ** String pointed to by p is translated to lower case. 304 ** 305 ** Called By: 306 ** parse 307 */ 308 309 makelower(p) 310 register char *p; 311 { 312 register char c; 313 314 if (p == NULL) 315 return; 316 for (; (c = *p) != '\0'; p++) 317 if (isascii(c) && isupper(c)) 318 *p = tolower(c); 319 } 320 /* 321 ** BUILDFNAME -- build full name from gecos style entry. 322 ** 323 ** This routine interprets the strange entry that would appear 324 ** in the GECOS field of the password file. 325 ** 326 ** Parameters: 327 ** p -- name to build. 328 ** login -- the login name of this user (for &). 329 ** buf -- place to put the result. 330 ** 331 ** Returns: 332 ** none. 333 ** 334 ** Side Effects: 335 ** none. 336 */ 337 338 buildfname(gecos, login, buf) 339 register char *gecos; 340 char *login; 341 char *buf; 342 { 343 register char *p; 344 register char *bp = buf; 345 int l; 346 347 if (*gecos == '*') 348 gecos++; 349 350 /* find length of final string */ 351 l = 0; 352 for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++) 353 { 354 if (*p == '&') 355 l += strlen(login); 356 else 357 l++; 358 } 359 360 /* now fill in buf */ 361 for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++) 362 { 363 if (*p == '&') 364 { 365 (void) strcpy(bp, login); 366 *bp = toupper(*bp); 367 while (*bp != '\0') 368 bp++; 369 } 370 else 371 *bp++ = *p; 372 } 373 *bp = '\0'; 374 } 375 /* 376 ** SAFEFILE -- return true if a file exists and is safe for a user. 377 ** 378 ** Parameters: 379 ** fn -- filename to check. 380 ** uid -- user id to compare against. 381 ** gid -- group id to compare against. 382 ** uname -- user name to compare against (used for group 383 ** sets). 384 ** flags -- modifiers: 385 ** SFF_MUSTOWN -- "uid" must own this file. 386 ** SFF_NOSLINK -- file cannot be a symbolic link. 387 ** mode -- mode bits that must match. 388 ** 389 ** Returns: 390 ** 0 if fn exists, is owned by uid, and matches mode. 391 ** An errno otherwise. The actual errno is cleared. 392 ** 393 ** Side Effects: 394 ** none. 395 */ 396 397 #include <grp.h> 398 399 #ifndef S_IXOTH 400 # define S_IXOTH (S_IEXEC >> 6) 401 #endif 402 403 #ifndef S_IXGRP 404 # define S_IXGRP (S_IEXEC >> 3) 405 #endif 406 407 #ifndef S_IXUSR 408 # define S_IXUSR (S_IEXEC) 409 #endif 410 411 int 412 safefile(fn, uid, gid, uname, flags, mode) 413 char *fn; 414 uid_t uid; 415 gid_t gid; 416 char *uname; 417 int flags; 418 int mode; 419 { 420 register char *p; 421 register struct group *gr = NULL; 422 struct stat stbuf; 423 424 if (tTd(54, 4)) 425 printf("safefile(%s, uid=%d, gid=%d, flags=%x, mode=%o):\n", 426 fn, uid, gid, flags, mode); 427 errno = 0; 428 429 for (p = fn; (p = strchr(++p, '/')) != NULL; *p = '/') 430 { 431 *p = '\0'; 432 if (stat(fn, &stbuf) < 0) 433 break; 434 if (stbuf.st_uid == uid && bitset(S_IXUSR, stbuf.st_mode)) 435 continue; 436 if (stbuf.st_gid == gid && bitset(S_IXGRP, stbuf.st_mode)) 437 continue; 438 #ifndef NO_GROUP_SET 439 if (uname != NULL && 440 ((gr != NULL && gr->gr_gid == stbuf.st_gid) || 441 (gr = getgrgid(stbuf.st_gid)) != NULL)) 442 { 443 register char **gp; 444 445 for (gp = gr->gr_mem; *gp != NULL; gp++) 446 if (strcmp(*gp, uname) == 0) 447 break; 448 if (*gp != NULL && bitset(S_IXGRP, stbuf.st_mode)) 449 continue; 450 } 451 #endif 452 if (!bitset(S_IXOTH, stbuf.st_mode)) 453 break; 454 } 455 if (p != NULL) 456 { 457 int ret = errno; 458 459 if (ret == 0) 460 ret = EACCES; 461 if (tTd(54, 4)) 462 printf("\t[dir %s] %s\n", fn, errstring(ret)); 463 *p = '/'; 464 return ret; 465 } 466 467 #ifdef HASLSTAT 468 if ((bitset(SFF_NOSLINK, flags) ? lstat(fn, &stbuf) 469 : stat(fn, &stbuf)) < 0) 470 #else 471 if (stat(fn, &stbuf) < 0) 472 #endif 473 { 474 int ret = errno; 475 476 if (tTd(54, 4)) 477 printf("\t%s\n", errstring(ret)); 478 479 errno = 0; 480 return ret; 481 } 482 483 #ifdef S_ISLNK 484 if (bitset(SFF_NOSLINK, flags) && S_ISLNK(stbuf.st_mode)) 485 { 486 if (tTd(54, 4)) 487 printf("\t[mode %o]\tEPERM\n"); 488 return EPERM; 489 } 490 #endif 491 492 if (uid == 0) 493 mode >>= 6; 494 else if (stbuf.st_uid != uid) 495 { 496 mode >>= 3; 497 if (stbuf.st_gid == gid) 498 ; 499 #ifndef NO_GROUP_SET 500 else if (uname != NULL && 501 ((gr != NULL && gr->gr_gid == stbuf.st_gid) || 502 (gr = getgrgid(stbuf.st_gid)) != NULL)) 503 { 504 register char **gp; 505 506 for (gp = gr->gr_mem; *gp != NULL; gp++) 507 if (strcmp(*gp, uname) == 0) 508 break; 509 if (*gp == NULL) 510 mode >>= 3; 511 } 512 #endif 513 else 514 mode >>= 3; 515 } 516 if (tTd(54, 4)) 517 printf("\t[uid %d, stat %o, mode %o] ", 518 stbuf.st_uid, stbuf.st_mode, mode); 519 if ((stbuf.st_uid == uid || stbuf.st_uid == 0 || 520 !bitset(SFF_MUSTOWN, flags)) && 521 (stbuf.st_mode & mode) == mode) 522 { 523 if (tTd(54, 4)) 524 printf("\tOK\n"); 525 return 0; 526 } 527 if (tTd(54, 4)) 528 printf("\tEACCES\n"); 529 return EACCES; 530 } 531 /* 532 ** FIXCRLF -- fix <CR><LF> in line. 533 ** 534 ** Looks for the <CR><LF> combination and turns it into the 535 ** UNIX canonical <NL> character. It only takes one line, 536 ** i.e., it is assumed that the first <NL> found is the end 537 ** of the line. 538 ** 539 ** Parameters: 540 ** line -- the line to fix. 541 ** stripnl -- if true, strip the newline also. 542 ** 543 ** Returns: 544 ** none. 545 ** 546 ** Side Effects: 547 ** line is changed in place. 548 */ 549 550 fixcrlf(line, stripnl) 551 char *line; 552 bool stripnl; 553 { 554 register char *p; 555 556 p = strchr(line, '\n'); 557 if (p == NULL) 558 return; 559 if (p > line && p[-1] == '\r') 560 p--; 561 if (!stripnl) 562 *p++ = '\n'; 563 *p = '\0'; 564 } 565 /* 566 ** DFOPEN -- determined file open 567 ** 568 ** This routine has the semantics of fopen, except that it will 569 ** keep trying a few times to make this happen. The idea is that 570 ** on very loaded systems, we may run out of resources (inodes, 571 ** whatever), so this tries to get around it. 572 */ 573 574 #ifndef O_ACCMODE 575 # define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR) 576 #endif 577 578 struct omodes 579 { 580 int mask; 581 int mode; 582 char *farg; 583 } OpenModes[] = 584 { 585 O_ACCMODE, O_RDONLY, "r", 586 O_ACCMODE|O_APPEND, O_WRONLY, "w", 587 O_ACCMODE|O_APPEND, O_WRONLY|O_APPEND, "a", 588 O_TRUNC, 0, "w+", 589 O_APPEND, O_APPEND, "a+", 590 0, 0, "r+", 591 }; 592 593 FILE * 594 dfopen(filename, omode, cmode) 595 char *filename; 596 int omode; 597 int cmode; 598 { 599 register int tries; 600 int fd; 601 register struct omodes *om; 602 struct stat st; 603 604 for (om = OpenModes; om->mask != 0; om++) 605 if ((omode & om->mask) == om->mode) 606 break; 607 608 for (tries = 0; tries < 10; tries++) 609 { 610 sleep((unsigned) (10 * tries)); 611 errno = 0; 612 fd = open(filename, omode, cmode); 613 if (fd >= 0) 614 break; 615 if (errno != ENFILE && errno != EINTR) 616 break; 617 } 618 if (fd >= 0 && fstat(fd, &st) >= 0 && S_ISREG(st.st_mode)) 619 { 620 int locktype; 621 622 /* lock the file to avoid accidental conflicts */ 623 if ((omode & O_ACCMODE) != O_RDONLY) 624 locktype = LOCK_EX; 625 else 626 locktype = LOCK_SH; 627 (void) lockfile(fd, filename, NULL, locktype); 628 errno = 0; 629 } 630 if (fd < 0) 631 return NULL; 632 else 633 return fdopen(fd, om->farg); 634 } 635 /* 636 ** PUTLINE -- put a line like fputs obeying SMTP conventions 637 ** 638 ** This routine always guarantees outputing a newline (or CRLF, 639 ** as appropriate) at the end of the string. 640 ** 641 ** Parameters: 642 ** l -- line to put. 643 ** fp -- file to put it onto. 644 ** m -- the mailer used to control output. 645 ** 646 ** Returns: 647 ** none 648 ** 649 ** Side Effects: 650 ** output of l to fp. 651 */ 652 653 putline(l, fp, m) 654 register char *l; 655 FILE *fp; 656 MAILER *m; 657 { 658 register char *p; 659 register char svchar; 660 661 /* strip out 0200 bits -- these can look like TELNET protocol */ 662 if (bitnset(M_7BITS, m->m_flags)) 663 { 664 for (p = l; (svchar = *p) != '\0'; ++p) 665 if (bitset(0200, svchar)) 666 *p = svchar &~ 0200; 667 } 668 669 do 670 { 671 /* find the end of the line */ 672 p = strchr(l, '\n'); 673 if (p == NULL) 674 p = &l[strlen(l)]; 675 676 if (TrafficLogFile != NULL) 677 fprintf(TrafficLogFile, "%05d >>> ", getpid()); 678 679 /* check for line overflow */ 680 while (m->m_linelimit > 0 && (p - l) > m->m_linelimit) 681 { 682 register char *q = &l[m->m_linelimit - 1]; 683 684 svchar = *q; 685 *q = '\0'; 686 if (l[0] == '.' && bitnset(M_XDOT, m->m_flags)) 687 { 688 (void) putc('.', fp); 689 if (TrafficLogFile != NULL) 690 (void) putc('.', TrafficLogFile); 691 } 692 fputs(l, fp); 693 (void) putc('!', fp); 694 fputs(m->m_eol, fp); 695 if (TrafficLogFile != NULL) 696 fprintf(TrafficLogFile, "%s!\n%05d >>> ", 697 l, getpid()); 698 *q = svchar; 699 l = q; 700 } 701 702 /* output last part */ 703 if (l[0] == '.' && bitnset(M_XDOT, m->m_flags)) 704 { 705 (void) putc('.', fp); 706 if (TrafficLogFile != NULL) 707 (void) putc('.', TrafficLogFile); 708 } 709 if (TrafficLogFile != NULL) 710 fprintf(TrafficLogFile, "%.*s\n", p - l, l); 711 for ( ; l < p; ++l) 712 (void) putc(*l, fp); 713 fputs(m->m_eol, fp); 714 if (*l == '\n') 715 ++l; 716 } while (l[0] != '\0'); 717 } 718 /* 719 ** XUNLINK -- unlink a file, doing logging as appropriate. 720 ** 721 ** Parameters: 722 ** f -- name of file to unlink. 723 ** 724 ** Returns: 725 ** none. 726 ** 727 ** Side Effects: 728 ** f is unlinked. 729 */ 730 731 xunlink(f) 732 char *f; 733 { 734 register int i; 735 736 # ifdef LOG 737 if (LogLevel > 98) 738 syslog(LOG_DEBUG, "%s: unlink %s", CurEnv->e_id, f); 739 # endif /* LOG */ 740 741 i = unlink(f); 742 # ifdef LOG 743 if (i < 0 && LogLevel > 97) 744 syslog(LOG_DEBUG, "%s: unlink-fail %d", f, errno); 745 # endif /* LOG */ 746 } 747 /* 748 ** XFCLOSE -- close a file, doing logging as appropriate. 749 ** 750 ** Parameters: 751 ** fp -- file pointer for the file to close 752 ** a, b -- miscellaneous crud to print for debugging 753 ** 754 ** Returns: 755 ** none. 756 ** 757 ** Side Effects: 758 ** fp is closed. 759 */ 760 761 xfclose(fp, a, b) 762 FILE *fp; 763 char *a, *b; 764 { 765 if (tTd(53, 99)) 766 printf("xfclose(%x) %s %s\n", fp, a, b); 767 #ifdef XDEBUG 768 if (fileno(fp) == 1) 769 syserr("xfclose(%s %s): fd = 1", a, b); 770 #endif 771 if (fclose(fp) < 0 && tTd(53, 99)) 772 printf("xfclose FAILURE: %s\n", errstring(errno)); 773 } 774 /* 775 ** SFGETS -- "safe" fgets -- times out and ignores random interrupts. 776 ** 777 ** Parameters: 778 ** buf -- place to put the input line. 779 ** siz -- size of buf. 780 ** fp -- file to read from. 781 ** timeout -- the timeout before error occurs. 782 ** during -- what we are trying to read (for error messages). 783 ** 784 ** Returns: 785 ** NULL on error (including timeout). This will also leave 786 ** buf containing a null string. 787 ** buf otherwise. 788 ** 789 ** Side Effects: 790 ** none. 791 */ 792 793 static jmp_buf CtxReadTimeout; 794 static int readtimeout(); 795 796 char * 797 sfgets(buf, siz, fp, timeout, during) 798 char *buf; 799 int siz; 800 FILE *fp; 801 time_t timeout; 802 char *during; 803 { 804 register EVENT *ev = NULL; 805 register char *p; 806 807 /* set the timeout */ 808 if (timeout != 0) 809 { 810 if (setjmp(CtxReadTimeout) != 0) 811 { 812 # ifdef LOG 813 syslog(LOG_NOTICE, 814 "timeout waiting for input from %s during %s\n", 815 CurHostName? CurHostName: "local", during); 816 # endif 817 errno = 0; 818 usrerr("451 timeout waiting for input during %s", 819 during); 820 buf[0] = '\0'; 821 #ifdef XDEBUG 822 checkfd012(during); 823 #endif 824 return (NULL); 825 } 826 ev = setevent(timeout, readtimeout, 0); 827 } 828 829 /* try to read */ 830 p = NULL; 831 while (p == NULL && !feof(fp) && !ferror(fp)) 832 { 833 errno = 0; 834 p = fgets(buf, siz, fp); 835 if (errno == EINTR) 836 clearerr(fp); 837 } 838 839 /* clear the event if it has not sprung */ 840 clrevent(ev); 841 842 /* clean up the books and exit */ 843 LineNumber++; 844 if (p == NULL) 845 { 846 buf[0] = '\0'; 847 if (TrafficLogFile != NULL) 848 fprintf(TrafficLogFile, "%05d <<< [EOF]\n", getpid()); 849 return (NULL); 850 } 851 if (TrafficLogFile != NULL) 852 fprintf(TrafficLogFile, "%05d <<< %s", getpid(), buf); 853 if (SevenBit) 854 for (p = buf; *p != '\0'; p++) 855 *p &= ~0200; 856 return (buf); 857 } 858 859 static 860 readtimeout() 861 { 862 longjmp(CtxReadTimeout, 1); 863 } 864 /* 865 ** FGETFOLDED -- like fgets, but know about folded lines. 866 ** 867 ** Parameters: 868 ** buf -- place to put result. 869 ** n -- bytes available. 870 ** f -- file to read from. 871 ** 872 ** Returns: 873 ** input line(s) on success, NULL on error or EOF. 874 ** This will normally be buf -- unless the line is too 875 ** long, when it will be xalloc()ed. 876 ** 877 ** Side Effects: 878 ** buf gets lines from f, with continuation lines (lines 879 ** with leading white space) appended. CRLF's are mapped 880 ** into single newlines. Any trailing NL is stripped. 881 */ 882 883 char * 884 fgetfolded(buf, n, f) 885 char *buf; 886 register int n; 887 FILE *f; 888 { 889 register char *p = buf; 890 char *bp = buf; 891 register int i; 892 893 n--; 894 while ((i = getc(f)) != EOF) 895 { 896 if (i == '\r') 897 { 898 i = getc(f); 899 if (i != '\n') 900 { 901 if (i != EOF) 902 (void) ungetc(i, f); 903 i = '\r'; 904 } 905 } 906 if (--n <= 0) 907 { 908 /* allocate new space */ 909 char *nbp; 910 int nn; 911 912 nn = (p - bp); 913 if (nn < MEMCHUNKSIZE) 914 nn *= 2; 915 else 916 nn += MEMCHUNKSIZE; 917 nbp = xalloc(nn); 918 bcopy(bp, nbp, p - bp); 919 p = &nbp[p - bp]; 920 if (bp != buf) 921 free(bp); 922 bp = nbp; 923 n = nn - (p - bp); 924 } 925 *p++ = i; 926 if (i == '\n') 927 { 928 LineNumber++; 929 i = getc(f); 930 if (i != EOF) 931 (void) ungetc(i, f); 932 if (i != ' ' && i != '\t') 933 break; 934 } 935 } 936 if (p == bp) 937 return (NULL); 938 *--p = '\0'; 939 return (bp); 940 } 941 /* 942 ** CURTIME -- return current time. 943 ** 944 ** Parameters: 945 ** none. 946 ** 947 ** Returns: 948 ** the current time. 949 ** 950 ** Side Effects: 951 ** none. 952 */ 953 954 time_t 955 curtime() 956 { 957 auto time_t t; 958 959 (void) time(&t); 960 return (t); 961 } 962 /* 963 ** ATOBOOL -- convert a string representation to boolean. 964 ** 965 ** Defaults to "TRUE" 966 ** 967 ** Parameters: 968 ** s -- string to convert. Takes "tTyY" as true, 969 ** others as false. 970 ** 971 ** Returns: 972 ** A boolean representation of the string. 973 ** 974 ** Side Effects: 975 ** none. 976 */ 977 978 bool 979 atobool(s) 980 register char *s; 981 { 982 if (s == NULL || *s == '\0' || strchr("tTyY", *s) != NULL) 983 return (TRUE); 984 return (FALSE); 985 } 986 /* 987 ** ATOOCT -- convert a string representation to octal. 988 ** 989 ** Parameters: 990 ** s -- string to convert. 991 ** 992 ** Returns: 993 ** An integer representing the string interpreted as an 994 ** octal number. 995 ** 996 ** Side Effects: 997 ** none. 998 */ 999 1000 atooct(s) 1001 register char *s; 1002 { 1003 register int i = 0; 1004 1005 while (*s >= '0' && *s <= '7') 1006 i = (i << 3) | (*s++ - '0'); 1007 return (i); 1008 } 1009 /* 1010 ** WAITFOR -- wait for a particular process id. 1011 ** 1012 ** Parameters: 1013 ** pid -- process id to wait for. 1014 ** 1015 ** Returns: 1016 ** status of pid. 1017 ** -1 if pid never shows up. 1018 ** 1019 ** Side Effects: 1020 ** none. 1021 */ 1022 1023 int 1024 waitfor(pid) 1025 int pid; 1026 { 1027 #ifdef WAITUNION 1028 union wait st; 1029 #else 1030 auto int st; 1031 #endif 1032 int i; 1033 1034 do 1035 { 1036 errno = 0; 1037 i = wait(&st); 1038 } while ((i >= 0 || errno == EINTR) && i != pid); 1039 if (i < 0) 1040 return -1; 1041 #ifdef WAITUNION 1042 return st.w_status; 1043 #else 1044 return st; 1045 #endif 1046 } 1047 /* 1048 ** BITINTERSECT -- tell if two bitmaps intersect 1049 ** 1050 ** Parameters: 1051 ** a, b -- the bitmaps in question 1052 ** 1053 ** Returns: 1054 ** TRUE if they have a non-null intersection 1055 ** FALSE otherwise 1056 ** 1057 ** Side Effects: 1058 ** none. 1059 */ 1060 1061 bool 1062 bitintersect(a, b) 1063 BITMAP a; 1064 BITMAP b; 1065 { 1066 int i; 1067 1068 for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) 1069 if ((a[i] & b[i]) != 0) 1070 return (TRUE); 1071 return (FALSE); 1072 } 1073 /* 1074 ** BITZEROP -- tell if a bitmap is all zero 1075 ** 1076 ** Parameters: 1077 ** map -- the bit map to check 1078 ** 1079 ** Returns: 1080 ** TRUE if map is all zero. 1081 ** FALSE if there are any bits set in map. 1082 ** 1083 ** Side Effects: 1084 ** none. 1085 */ 1086 1087 bool 1088 bitzerop(map) 1089 BITMAP map; 1090 { 1091 int i; 1092 1093 for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) 1094 if (map[i] != 0) 1095 return (FALSE); 1096 return (TRUE); 1097 } 1098 /* 1099 ** STRCONTAINEDIN -- tell if one string is contained in another 1100 ** 1101 ** Parameters: 1102 ** a -- possible substring. 1103 ** b -- possible superstring. 1104 ** 1105 ** Returns: 1106 ** TRUE if a is contained in b. 1107 ** FALSE otherwise. 1108 */ 1109 1110 bool 1111 strcontainedin(a, b) 1112 register char *a; 1113 register char *b; 1114 { 1115 int la; 1116 int lb; 1117 int c; 1118 1119 la = strlen(a); 1120 lb = strlen(b); 1121 c = *a; 1122 if (isascii(c) && isupper(c)) 1123 c = tolower(c); 1124 for (; lb-- >= la; b++) 1125 { 1126 if (*b != c && isascii(*b) && isupper(*b) && tolower(*b) != c) 1127 continue; 1128 if (strncasecmp(a, b, la) == 0) 1129 return TRUE; 1130 } 1131 return FALSE; 1132 } 1133 /* 1134 ** CHECKFD012 -- check low numbered file descriptors 1135 ** 1136 ** File descriptors 0, 1, and 2 should be open at all times. 1137 ** This routine verifies that, and fixes it if not true. 1138 ** 1139 ** Parameters: 1140 ** where -- a tag printed if the assertion failed 1141 ** 1142 ** Returns: 1143 ** none 1144 */ 1145 1146 checkfd012(where) 1147 char *where; 1148 { 1149 #ifdef XDEBUG 1150 register int i; 1151 struct stat stbuf; 1152 1153 for (i = 0; i < 3; i++) 1154 { 1155 if (fstat(i, &stbuf) < 0 && errno != EOPNOTSUPP) 1156 { 1157 /* oops.... */ 1158 int fd; 1159 1160 syserr("%s: fd %d not open", where, i); 1161 fd = open("/dev/null", i == 0 ? O_RDONLY : O_WRONLY, 0666); 1162 if (fd != i) 1163 { 1164 (void) dup2(fd, i); 1165 (void) close(fd); 1166 } 1167 } 1168 } 1169 #endif /* XDEBUG */ 1170 } 1171 /* 1172 ** PRINTOPENFDS -- print the open file descriptors (for debugging) 1173 ** 1174 ** Parameters: 1175 ** logit -- if set, send output to syslog; otherwise 1176 ** print for debugging. 1177 ** 1178 ** Returns: 1179 ** none. 1180 */ 1181 1182 #include <netdb.h> 1183 #include <arpa/inet.h> 1184 1185 printopenfds(logit) 1186 bool logit; 1187 { 1188 register int fd; 1189 extern int DtableSize; 1190 1191 for (fd = 0; fd < DtableSize; fd++) 1192 dumpfd(fd, FALSE, logit); 1193 } 1194 /* 1195 ** DUMPFD -- dump a file descriptor 1196 ** 1197 ** Parameters: 1198 ** fd -- the file descriptor to dump. 1199 ** printclosed -- if set, print a notification even if 1200 ** it is closed; otherwise print nothing. 1201 ** logit -- if set, send output to syslog instead of stdout. 1202 */ 1203 1204 dumpfd(fd, printclosed, logit) 1205 int fd; 1206 bool printclosed; 1207 bool logit; 1208 { 1209 register struct hostent *hp; 1210 register char *p; 1211 struct sockaddr_in sin; 1212 auto int slen; 1213 struct stat st; 1214 char buf[200]; 1215 1216 p = buf; 1217 sprintf(p, "%3d: ", fd); 1218 p += strlen(p); 1219 1220 if (fstat(fd, &st) < 0) 1221 { 1222 if (printclosed || errno != EBADF) 1223 { 1224 sprintf(p, "CANNOT STAT (%s)", errstring(errno)); 1225 goto printit; 1226 } 1227 return; 1228 } 1229 1230 slen = fcntl(fd, F_GETFL, NULL); 1231 if (slen != -1) 1232 { 1233 sprintf(p, "fl=0x%x, ", slen); 1234 p += strlen(p); 1235 } 1236 1237 sprintf(p, "mode=%o: ", st.st_mode); 1238 p += strlen(p); 1239 switch (st.st_mode & S_IFMT) 1240 { 1241 #ifdef S_IFSOCK 1242 case S_IFSOCK: 1243 sprintf(p, "SOCK "); 1244 p += strlen(p); 1245 slen = sizeof sin; 1246 if (getsockname(fd, (struct sockaddr *) &sin, &slen) < 0) 1247 sprintf(p, "(badsock)"); 1248 else 1249 { 1250 hp = gethostbyaddr((char *) &sin.sin_addr, slen, AF_INET); 1251 sprintf(p, "%s/%d", hp == NULL ? inet_ntoa(sin.sin_addr) 1252 : hp->h_name, ntohs(sin.sin_port)); 1253 } 1254 p += strlen(p); 1255 sprintf(p, "->"); 1256 p += strlen(p); 1257 slen = sizeof sin; 1258 if (getpeername(fd, (struct sockaddr *) &sin, &slen) < 0) 1259 sprintf(p, "(badsock)"); 1260 else 1261 { 1262 hp = gethostbyaddr((char *) &sin.sin_addr, slen, AF_INET); 1263 sprintf(p, "%s/%d", hp == NULL ? inet_ntoa(sin.sin_addr) 1264 : hp->h_name, ntohs(sin.sin_port)); 1265 } 1266 break; 1267 #endif 1268 1269 case S_IFCHR: 1270 sprintf(p, "CHR: "); 1271 p += strlen(p); 1272 goto defprint; 1273 1274 case S_IFBLK: 1275 sprintf(p, "BLK: "); 1276 p += strlen(p); 1277 goto defprint; 1278 1279 default: 1280 defprint: 1281 sprintf(p, "dev=%d/%d, ino=%d, nlink=%d, u/gid=%d/%d, size=%ld", 1282 major(st.st_dev), minor(st.st_dev), st.st_ino, 1283 st.st_nlink, st.st_uid, st.st_gid, st.st_size); 1284 break; 1285 } 1286 1287 printit: 1288 if (logit) 1289 syslog(LOG_DEBUG, "%s", buf); 1290 else 1291 printf("%s\n", buf); 1292 } 1293 /* 1294 ** SHORTENSTRING -- return short version of a string 1295 ** 1296 ** If the string is already short, just return it. If it is too 1297 ** long, return the head and tail of the string. 1298 ** 1299 ** Parameters: 1300 ** s -- the string to shorten. 1301 ** m -- the max length of the string. 1302 ** 1303 ** Returns: 1304 ** Either s or a short version of s. 1305 */ 1306 1307 #ifndef MAXSHORTSTR 1308 # define MAXSHORTSTR 203 1309 #endif 1310 1311 char * 1312 shortenstring(s, m) 1313 register char *s; 1314 int m; 1315 { 1316 int l; 1317 static char buf[MAXSHORTSTR + 1]; 1318 1319 l = strlen(s); 1320 if (l < m) 1321 return s; 1322 if (m > MAXSHORTSTR) 1323 m = MAXSHORTSTR; 1324 else if (m < 10) 1325 { 1326 if (m < 5) 1327 { 1328 strncpy(buf, s, m); 1329 buf[m] = '\0'; 1330 return buf; 1331 } 1332 strncpy(buf, s, m - 3); 1333 strcpy(buf + m - 3, "..."); 1334 return buf; 1335 } 1336 m = (m - 3) / 2; 1337 strncpy(buf, s, m); 1338 strcpy(buf + m, "..."); 1339 strcpy(buf + m + 3, s + l - m); 1340 return buf; 1341 } 1342