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.56 (Berkeley) 03/07/95"; 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 /* some systems can't handle size zero mallocs */ 78 if (sz <= 0) 79 sz = 1; 80 81 p = malloc((unsigned) sz); 82 if (p == NULL) 83 { 84 syserr("Out of memory!!"); 85 abort(); 86 /* exit(EX_UNAVAILABLE); */ 87 } 88 return (p); 89 } 90 /* 91 ** COPYPLIST -- copy list of pointers. 92 ** 93 ** This routine is the equivalent of newstr for lists of 94 ** pointers. 95 ** 96 ** Parameters: 97 ** list -- list of pointers to copy. 98 ** Must be NULL terminated. 99 ** copycont -- if TRUE, copy the contents of the vector 100 ** (which must be a string) also. 101 ** 102 ** Returns: 103 ** a copy of 'list'. 104 ** 105 ** Side Effects: 106 ** none. 107 */ 108 109 char ** 110 copyplist(list, copycont) 111 char **list; 112 bool copycont; 113 { 114 register char **vp; 115 register char **newvp; 116 117 for (vp = list; *vp != NULL; vp++) 118 continue; 119 120 vp++; 121 122 newvp = (char **) xalloc((int) (vp - list) * sizeof *vp); 123 bcopy((char *) list, (char *) newvp, (int) (vp - list) * sizeof *vp); 124 125 if (copycont) 126 { 127 for (vp = newvp; *vp != NULL; vp++) 128 *vp = newstr(*vp); 129 } 130 131 return (newvp); 132 } 133 /* 134 ** COPYQUEUE -- copy address queue. 135 ** 136 ** This routine is the equivalent of newstr for address queues 137 ** addresses marked with QDONTSEND aren't copied 138 ** 139 ** Parameters: 140 ** addr -- list of address structures to copy. 141 ** 142 ** Returns: 143 ** a copy of 'addr'. 144 ** 145 ** Side Effects: 146 ** none. 147 */ 148 149 ADDRESS * 150 copyqueue(addr) 151 ADDRESS *addr; 152 { 153 register ADDRESS *newaddr; 154 ADDRESS *ret; 155 register ADDRESS **tail = &ret; 156 157 while (addr != NULL) 158 { 159 if (!bitset(QDONTSEND, addr->q_flags)) 160 { 161 newaddr = (ADDRESS *) xalloc(sizeof(ADDRESS)); 162 STRUCTCOPY(*addr, *newaddr); 163 *tail = newaddr; 164 tail = &newaddr->q_next; 165 } 166 addr = addr->q_next; 167 } 168 *tail = NULL; 169 170 return ret; 171 } 172 /* 173 ** PRINTAV -- print argument vector. 174 ** 175 ** Parameters: 176 ** av -- argument vector. 177 ** 178 ** Returns: 179 ** none. 180 ** 181 ** Side Effects: 182 ** prints av. 183 */ 184 185 printav(av) 186 register char **av; 187 { 188 while (*av != NULL) 189 { 190 if (tTd(0, 44)) 191 printf("\n\t%08x=", *av); 192 else 193 (void) putchar(' '); 194 xputs(*av++); 195 } 196 (void) putchar('\n'); 197 } 198 /* 199 ** LOWER -- turn letter into lower case. 200 ** 201 ** Parameters: 202 ** c -- character to turn into lower case. 203 ** 204 ** Returns: 205 ** c, in lower case. 206 ** 207 ** Side Effects: 208 ** none. 209 */ 210 211 char 212 lower(c) 213 register char c; 214 { 215 return((isascii(c) && isupper(c)) ? tolower(c) : c); 216 } 217 /* 218 ** XPUTS -- put string doing control escapes. 219 ** 220 ** Parameters: 221 ** s -- string to put. 222 ** 223 ** Returns: 224 ** none. 225 ** 226 ** Side Effects: 227 ** output to stdout 228 */ 229 230 xputs(s) 231 register char *s; 232 { 233 register int c; 234 register struct metamac *mp; 235 extern struct metamac MetaMacros[]; 236 237 if (s == NULL) 238 { 239 printf("<null>"); 240 return; 241 } 242 while ((c = (*s++ & 0377)) != '\0') 243 { 244 if (!isascii(c)) 245 { 246 if (c == MATCHREPL) 247 { 248 putchar('$'); 249 continue; 250 } 251 if (c == MACROEXPAND) 252 { 253 putchar('$'); 254 if (bitset(0200, *s)) 255 printf("{%s}", macname(*s++ & 0377)); 256 continue; 257 } 258 for (mp = MetaMacros; mp->metaname != '\0'; mp++) 259 { 260 if ((mp->metaval & 0377) == c) 261 { 262 printf("$%c", mp->metaname); 263 break; 264 } 265 } 266 if (mp->metaname != '\0') 267 continue; 268 (void) putchar('\\'); 269 c &= 0177; 270 } 271 if (isprint(c)) 272 { 273 putchar(c); 274 continue; 275 } 276 277 /* wasn't a meta-macro -- find another way to print it */ 278 switch (c) 279 { 280 case '\n': 281 c = 'n'; 282 break; 283 284 case '\r': 285 c = 'r'; 286 break; 287 288 case '\t': 289 c = 't'; 290 break; 291 292 default: 293 (void) putchar('^'); 294 (void) putchar(c ^ 0100); 295 continue; 296 } 297 (void) putchar('\\'); 298 (void) putchar(c); 299 } 300 (void) fflush(stdout); 301 } 302 /* 303 ** MAKELOWER -- Translate a line into lower case 304 ** 305 ** Parameters: 306 ** p -- the string to translate. If NULL, return is 307 ** immediate. 308 ** 309 ** Returns: 310 ** none. 311 ** 312 ** Side Effects: 313 ** String pointed to by p is translated to lower case. 314 ** 315 ** Called By: 316 ** parse 317 */ 318 319 void 320 makelower(p) 321 register char *p; 322 { 323 register char c; 324 325 if (p == NULL) 326 return; 327 for (; (c = *p) != '\0'; p++) 328 if (isascii(c) && isupper(c)) 329 *p = tolower(c); 330 } 331 /* 332 ** BUILDFNAME -- build full name from gecos style entry. 333 ** 334 ** This routine interprets the strange entry that would appear 335 ** in the GECOS field of the password file. 336 ** 337 ** Parameters: 338 ** p -- name to build. 339 ** login -- the login name of this user (for &). 340 ** buf -- place to put the result. 341 ** 342 ** Returns: 343 ** none. 344 ** 345 ** Side Effects: 346 ** none. 347 */ 348 349 buildfname(gecos, login, buf) 350 register char *gecos; 351 char *login; 352 char *buf; 353 { 354 register char *p; 355 register char *bp = buf; 356 int l; 357 358 if (*gecos == '*') 359 gecos++; 360 361 /* find length of final string */ 362 l = 0; 363 for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++) 364 { 365 if (*p == '&') 366 l += strlen(login); 367 else 368 l++; 369 } 370 371 /* now fill in buf */ 372 for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++) 373 { 374 if (*p == '&') 375 { 376 (void) strcpy(bp, login); 377 *bp = toupper(*bp); 378 while (*bp != '\0') 379 bp++; 380 } 381 else 382 *bp++ = *p; 383 } 384 *bp = '\0'; 385 } 386 /* 387 ** SAFEFILE -- return true if a file exists and is safe for a user. 388 ** 389 ** Parameters: 390 ** fn -- filename to check. 391 ** uid -- user id to compare against. 392 ** gid -- group id to compare against. 393 ** uname -- user name to compare against (used for group 394 ** sets). 395 ** flags -- modifiers: 396 ** SFF_MUSTOWN -- "uid" must own this file. 397 ** SFF_NOSLINK -- file cannot be a symbolic link. 398 ** mode -- mode bits that must match. 399 ** st -- if set, points to a stat structure that will 400 ** get the stat info for the file. 401 ** 402 ** Returns: 403 ** 0 if fn exists, is owned by uid, and matches mode. 404 ** An errno otherwise. The actual errno is cleared. 405 ** 406 ** Side Effects: 407 ** none. 408 */ 409 410 #include <grp.h> 411 412 #ifndef S_IXOTH 413 # define S_IXOTH (S_IEXEC >> 6) 414 #endif 415 416 #ifndef S_IXGRP 417 # define S_IXGRP (S_IEXEC >> 3) 418 #endif 419 420 #ifndef S_IXUSR 421 # define S_IXUSR (S_IEXEC) 422 #endif 423 424 #define ST_MODE_NOFILE 0171147 /* unlikely to occur */ 425 426 int 427 safefile(fn, uid, gid, uname, flags, mode, st) 428 char *fn; 429 uid_t uid; 430 gid_t gid; 431 char *uname; 432 int flags; 433 int mode; 434 struct stat *st; 435 { 436 register char *p; 437 register struct group *gr = NULL; 438 struct stat stbuf; 439 440 if (tTd(54, 4)) 441 printf("safefile(%s, uid=%d, gid=%d, flags=%x, mode=%o):\n", 442 fn, uid, gid, flags, mode); 443 errno = 0; 444 if (st == NULL) 445 st = &stbuf; 446 447 if (!bitset(SFF_NOPATHCHECK, flags) || 448 (uid == 0 && !bitset(SFF_ROOTOK, flags))) 449 { 450 /* check the path to the file for acceptability */ 451 for (p = fn; (p = strchr(++p, '/')) != NULL; *p = '/') 452 { 453 *p = '\0'; 454 if (stat(fn, &stbuf) < 0) 455 break; 456 if (uid == 0 && !bitset(SFF_ROOTOK, flags)) 457 { 458 if (bitset(S_IXOTH, stbuf.st_mode)) 459 continue; 460 break; 461 } 462 if (stbuf.st_uid == uid && 463 bitset(S_IXUSR, stbuf.st_mode)) 464 continue; 465 if (stbuf.st_gid == gid && 466 bitset(S_IXGRP, stbuf.st_mode)) 467 continue; 468 #ifndef NO_GROUP_SET 469 if (uname != NULL && 470 ((gr != NULL && gr->gr_gid == stbuf.st_gid) || 471 (gr = getgrgid(stbuf.st_gid)) != NULL)) 472 { 473 register char **gp; 474 475 for (gp = gr->gr_mem; gp != NULL && *gp != NULL; gp++) 476 if (strcmp(*gp, uname) == 0) 477 break; 478 if (gp != NULL && *gp != NULL && 479 bitset(S_IXGRP, stbuf.st_mode)) 480 continue; 481 } 482 #endif 483 if (!bitset(S_IXOTH, stbuf.st_mode)) 484 break; 485 } 486 if (p != NULL) 487 { 488 int ret = errno; 489 490 if (ret == 0) 491 ret = EACCES; 492 if (tTd(54, 4)) 493 printf("\t[dir %s] %s\n", fn, errstring(ret)); 494 *p = '/'; 495 return ret; 496 } 497 } 498 499 #ifdef HASLSTAT 500 if ((bitset(SFF_NOSLINK, flags) ? lstat(fn, st) 501 : stat(fn, st)) < 0) 502 #else 503 if (stat(fn, st) < 0) 504 #endif 505 { 506 int ret = errno; 507 508 if (tTd(54, 4)) 509 printf("\t%s\n", errstring(ret)); 510 511 errno = 0; 512 if (!bitset(SFF_CREAT, flags)) 513 return ret; 514 515 /* check to see if legal to create the file */ 516 p = strrchr(fn, '/'); 517 if (p == NULL) 518 return ENOTDIR; 519 *p = '\0'; 520 if (stat(fn, &stbuf) >= 0) 521 { 522 int md = S_IWRITE|S_IEXEC; 523 if (stbuf.st_uid != uid) 524 md >>= 6; 525 if ((stbuf.st_mode & md) != md) 526 errno = EACCES; 527 } 528 ret = errno; 529 if (tTd(54, 4)) 530 printf("\t[final dir %s uid %d mode %o] %s\n", 531 fn, stbuf.st_uid, stbuf.st_mode, 532 errstring(ret)); 533 *p = '/'; 534 st->st_mode = ST_MODE_NOFILE; 535 return ret; 536 } 537 538 #ifdef S_ISLNK 539 if (bitset(SFF_NOSLINK, flags) && S_ISLNK(st->st_mode)) 540 { 541 if (tTd(54, 4)) 542 printf("\t[slink mode %o]\tEPERM\n", st->st_mode); 543 return EPERM; 544 } 545 #endif 546 547 if (bitset(S_IWUSR|S_IWGRP|S_IWOTH, mode) && bitset(0111, st->st_mode)) 548 { 549 if (tTd(29, 5)) 550 printf("failed (mode %o: x bits)\n", st->st_mode); 551 errno = EPERM; 552 return FALSE; 553 } 554 555 if (bitset(SFF_SETUIDOK, flags)) 556 { 557 if (bitset(S_ISUID, st->st_mode) && 558 (st->st_uid != 0 || bitset(SFF_ROOTOK, flags))) 559 { 560 uid = st->st_uid; 561 uname = NULL; 562 } 563 if (bitset(S_ISGID, st->st_mode) && 564 (st->st_gid != 0 || bitset(SFF_ROOTOK, flags))) 565 gid = st->st_gid; 566 } 567 568 if (uid == 0 && !bitset(SFF_ROOTOK, flags)) 569 mode >>= 6; 570 else if (st->st_uid != uid) 571 { 572 mode >>= 3; 573 if (st->st_gid == gid) 574 ; 575 #ifndef NO_GROUP_SET 576 else if (uname != NULL && 577 ((gr != NULL && gr->gr_gid == st->st_gid) || 578 (gr = getgrgid(st->st_gid)) != NULL)) 579 { 580 register char **gp; 581 582 for (gp = gr->gr_mem; *gp != NULL; gp++) 583 if (strcmp(*gp, uname) == 0) 584 break; 585 if (*gp == NULL) 586 mode >>= 3; 587 } 588 #endif 589 else 590 mode >>= 3; 591 } 592 if (tTd(54, 4)) 593 printf("\t[uid %d, stat %o, mode %o] ", 594 st->st_uid, st->st_mode, mode); 595 if ((st->st_uid == uid || st->st_uid == 0 || 596 !bitset(SFF_MUSTOWN, flags)) && 597 (st->st_mode & mode) == mode) 598 { 599 if (tTd(54, 4)) 600 printf("\tOK\n"); 601 return 0; 602 } 603 if (tTd(54, 4)) 604 printf("\tEACCES\n"); 605 return EACCES; 606 } 607 /* 608 ** SAFEFOPEN -- do a file open with extra checking 609 ** 610 ** Parameters: 611 ** fn -- the file name to open. 612 ** omode -- the open-style mode flags. 613 ** cmode -- the create-style mode flags. 614 ** sff -- safefile flags. 615 ** 616 ** Returns: 617 ** Same as fopen. 618 */ 619 620 FILE * 621 safefopen(fn, omode, cmode, sff) 622 char *fn; 623 int omode; 624 int cmode; 625 int sff; 626 { 627 int rval; 628 FILE *fp; 629 int smode; 630 struct stat stb, sta; 631 extern char RealUserName[]; 632 633 if (bitset(O_CREAT, omode)) 634 sff |= SFF_CREAT; 635 smode = 0; 636 switch (omode & O_ACCMODE) 637 { 638 case O_RDONLY: 639 smode = S_IREAD; 640 break; 641 642 case O_WRONLY: 643 smode = S_IWRITE; 644 break; 645 646 case O_RDWR: 647 smode = S_IREAD|S_IWRITE; 648 break; 649 650 default: 651 smode = 0; 652 break; 653 } 654 rval = safefile(fn, RealUid, RealGid, RealUserName, sff, smode, &stb); 655 if (rval != 0) 656 { 657 errno = rval; 658 return NULL; 659 } 660 if (stb.st_mode == ST_MODE_NOFILE) 661 omode |= O_EXCL; 662 663 fp = dfopen(fn, omode, cmode); 664 if (fp == NULL) 665 return NULL; 666 if (bitset(O_EXCL, omode)) 667 return fp; 668 if (fstat(fileno(fp), &sta) < 0 || 669 sta.st_nlink != stb.st_nlink || 670 sta.st_dev != stb.st_dev || 671 sta.st_ino != stb.st_ino || 672 sta.st_uid != stb.st_uid || 673 sta.st_gid != stb.st_gid) 674 { 675 syserr("554 cannot open: file %s changed after open", fn); 676 errno = EPERM; 677 fclose(fp); 678 return NULL; 679 } 680 return fp; 681 } 682 /* 683 ** FIXCRLF -- fix <CR><LF> in line. 684 ** 685 ** Looks for the <CR><LF> combination and turns it into the 686 ** UNIX canonical <NL> character. It only takes one line, 687 ** i.e., it is assumed that the first <NL> found is the end 688 ** of the line. 689 ** 690 ** Parameters: 691 ** line -- the line to fix. 692 ** stripnl -- if true, strip the newline also. 693 ** 694 ** Returns: 695 ** none. 696 ** 697 ** Side Effects: 698 ** line is changed in place. 699 */ 700 701 fixcrlf(line, stripnl) 702 char *line; 703 bool stripnl; 704 { 705 register char *p; 706 707 p = strchr(line, '\n'); 708 if (p == NULL) 709 return; 710 if (p > line && p[-1] == '\r') 711 p--; 712 if (!stripnl) 713 *p++ = '\n'; 714 *p = '\0'; 715 } 716 /* 717 ** DFOPEN -- determined file open 718 ** 719 ** This routine has the semantics of fopen, except that it will 720 ** keep trying a few times to make this happen. The idea is that 721 ** on very loaded systems, we may run out of resources (inodes, 722 ** whatever), so this tries to get around it. 723 */ 724 725 #ifndef O_ACCMODE 726 # define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR) 727 #endif 728 729 struct omodes 730 { 731 int mask; 732 int mode; 733 char *farg; 734 } OpenModes[] = 735 { 736 O_ACCMODE, O_RDONLY, "r", 737 O_ACCMODE|O_APPEND, O_WRONLY, "w", 738 O_ACCMODE|O_APPEND, O_WRONLY|O_APPEND, "a", 739 O_TRUNC, 0, "w+", 740 O_APPEND, O_APPEND, "a+", 741 0, 0, "r+", 742 }; 743 744 FILE * 745 dfopen(filename, omode, cmode) 746 char *filename; 747 int omode; 748 int cmode; 749 { 750 register int tries; 751 int fd; 752 register struct omodes *om; 753 struct stat st; 754 755 for (om = OpenModes; om->mask != 0; om++) 756 if ((omode & om->mask) == om->mode) 757 break; 758 759 for (tries = 0; tries < 10; tries++) 760 { 761 sleep((unsigned) (10 * tries)); 762 errno = 0; 763 fd = open(filename, omode, cmode); 764 if (fd >= 0) 765 break; 766 switch (errno) 767 { 768 case ENFILE: /* system file table full */ 769 case EINTR: /* interrupted syscall */ 770 #ifdef ETXTBSY 771 case ETXTBSY: /* Apollo: net file locked */ 772 #endif 773 continue; 774 } 775 break; 776 } 777 if (fd >= 0 && fstat(fd, &st) >= 0 && S_ISREG(st.st_mode)) 778 { 779 int locktype; 780 781 /* lock the file to avoid accidental conflicts */ 782 if ((omode & O_ACCMODE) != O_RDONLY) 783 locktype = LOCK_EX; 784 else 785 locktype = LOCK_SH; 786 (void) lockfile(fd, filename, NULL, locktype); 787 errno = 0; 788 } 789 if (fd < 0) 790 return NULL; 791 else 792 return fdopen(fd, om->farg); 793 } 794 /* 795 ** PUTLINE -- put a line like fputs obeying SMTP conventions 796 ** 797 ** This routine always guarantees outputing a newline (or CRLF, 798 ** as appropriate) at the end of the string. 799 ** 800 ** Parameters: 801 ** l -- line to put. 802 ** mci -- the mailer connection information. 803 ** 804 ** Returns: 805 ** none 806 ** 807 ** Side Effects: 808 ** output of l to fp. 809 */ 810 811 putline(l, mci) 812 register char *l; 813 register MCI *mci; 814 { 815 register char *p; 816 register char svchar; 817 int slop = 0; 818 819 /* strip out 0200 bits -- these can look like TELNET protocol */ 820 if (bitset(MCIF_7BIT, mci->mci_flags)) 821 { 822 for (p = l; (svchar = *p) != '\0'; ++p) 823 if (bitset(0200, svchar)) 824 *p = svchar &~ 0200; 825 } 826 827 do 828 { 829 /* find the end of the line */ 830 p = strchr(l, '\n'); 831 if (p == NULL) 832 p = &l[strlen(l)]; 833 834 if (TrafficLogFile != NULL) 835 fprintf(TrafficLogFile, "%05d >>> ", getpid()); 836 837 /* check for line overflow */ 838 while (mci->mci_mailer->m_linelimit > 0 && 839 (p - l + slop) > mci->mci_mailer->m_linelimit) 840 { 841 register char *q = &l[mci->mci_mailer->m_linelimit - slop - 1]; 842 843 svchar = *q; 844 *q = '\0'; 845 if (l[0] == '.' && slop == 0 && 846 bitnset(M_XDOT, mci->mci_mailer->m_flags)) 847 { 848 (void) putc('.', mci->mci_out); 849 if (TrafficLogFile != NULL) 850 (void) putc('.', TrafficLogFile); 851 } 852 fputs(l, mci->mci_out); 853 (void) putc('!', mci->mci_out); 854 fputs(mci->mci_mailer->m_eol, mci->mci_out); 855 (void) putc(' ', mci->mci_out); 856 if (TrafficLogFile != NULL) 857 fprintf(TrafficLogFile, "%s!\n%05d >>> ", 858 l, getpid()); 859 *q = svchar; 860 l = q; 861 slop = 1; 862 } 863 864 /* output last part */ 865 if (l[0] == '.' && slop == 0 && 866 bitnset(M_XDOT, mci->mci_mailer->m_flags)) 867 { 868 (void) putc('.', mci->mci_out); 869 if (TrafficLogFile != NULL) 870 (void) putc('.', TrafficLogFile); 871 } 872 if (TrafficLogFile != NULL) 873 fprintf(TrafficLogFile, "%.*s\n", p - l, l); 874 for ( ; l < p; ++l) 875 (void) putc(*l, mci->mci_out); 876 fputs(mci->mci_mailer->m_eol, mci->mci_out); 877 if (*l == '\n') 878 ++l; 879 } while (l[0] != '\0'); 880 } 881 /* 882 ** XUNLINK -- unlink a file, doing logging as appropriate. 883 ** 884 ** Parameters: 885 ** f -- name of file to unlink. 886 ** 887 ** Returns: 888 ** none. 889 ** 890 ** Side Effects: 891 ** f is unlinked. 892 */ 893 894 xunlink(f) 895 char *f; 896 { 897 register int i; 898 899 # ifdef LOG 900 if (LogLevel > 98) 901 syslog(LOG_DEBUG, "%s: unlink %s", CurEnv->e_id, f); 902 # endif /* LOG */ 903 904 i = unlink(f); 905 # ifdef LOG 906 if (i < 0 && LogLevel > 97) 907 syslog(LOG_DEBUG, "%s: unlink-fail %d", f, errno); 908 # endif /* LOG */ 909 } 910 /* 911 ** XFCLOSE -- close a file, doing logging as appropriate. 912 ** 913 ** Parameters: 914 ** fp -- file pointer for the file to close 915 ** a, b -- miscellaneous crud to print for debugging 916 ** 917 ** Returns: 918 ** none. 919 ** 920 ** Side Effects: 921 ** fp is closed. 922 */ 923 924 xfclose(fp, a, b) 925 FILE *fp; 926 char *a, *b; 927 { 928 if (tTd(53, 99)) 929 printf("xfclose(%x) %s %s\n", fp, a, b); 930 #ifdef XDEBUG 931 if (fileno(fp) == 1) 932 syserr("xfclose(%s %s): fd = 1", a, b); 933 #endif 934 if (fclose(fp) < 0 && tTd(53, 99)) 935 printf("xfclose FAILURE: %s\n", errstring(errno)); 936 } 937 /* 938 ** SFGETS -- "safe" fgets -- times out and ignores random interrupts. 939 ** 940 ** Parameters: 941 ** buf -- place to put the input line. 942 ** siz -- size of buf. 943 ** fp -- file to read from. 944 ** timeout -- the timeout before error occurs. 945 ** during -- what we are trying to read (for error messages). 946 ** 947 ** Returns: 948 ** NULL on error (including timeout). This will also leave 949 ** buf containing a null string. 950 ** buf otherwise. 951 ** 952 ** Side Effects: 953 ** none. 954 */ 955 956 static jmp_buf CtxReadTimeout; 957 static void readtimeout(); 958 959 char * 960 sfgets(buf, siz, fp, timeout, during) 961 char *buf; 962 int siz; 963 FILE *fp; 964 time_t timeout; 965 char *during; 966 { 967 register EVENT *ev = NULL; 968 register char *p; 969 970 if (fp == NULL) 971 { 972 buf[0] = '\0'; 973 return NULL; 974 } 975 976 /* set the timeout */ 977 if (timeout != 0) 978 { 979 if (setjmp(CtxReadTimeout) != 0) 980 { 981 # ifdef LOG 982 syslog(LOG_NOTICE, 983 "timeout waiting for input from %s during %s\n", 984 CurHostName? CurHostName: "local", during); 985 # endif 986 errno = 0; 987 usrerr("451 timeout waiting for input during %s", 988 during); 989 buf[0] = '\0'; 990 #ifdef XDEBUG 991 checkfd012(during); 992 #endif 993 return (NULL); 994 } 995 ev = setevent(timeout, readtimeout, 0); 996 } 997 998 /* try to read */ 999 p = NULL; 1000 while (!feof(fp) && !ferror(fp)) 1001 { 1002 errno = 0; 1003 p = fgets(buf, siz, fp); 1004 if (p != NULL || errno != EINTR) 1005 break; 1006 clearerr(fp); 1007 } 1008 1009 /* clear the event if it has not sprung */ 1010 clrevent(ev); 1011 1012 /* clean up the books and exit */ 1013 LineNumber++; 1014 if (p == NULL) 1015 { 1016 buf[0] = '\0'; 1017 if (TrafficLogFile != NULL) 1018 fprintf(TrafficLogFile, "%05d <<< [EOF]\n", getpid()); 1019 return (NULL); 1020 } 1021 if (TrafficLogFile != NULL) 1022 fprintf(TrafficLogFile, "%05d <<< %s", getpid(), buf); 1023 if (SevenBitInput) 1024 { 1025 for (p = buf; *p != '\0'; p++) 1026 *p &= ~0200; 1027 } 1028 else if (!HasEightBits) 1029 { 1030 for (p = buf; *p != '\0'; p++) 1031 { 1032 if (bitset(0200, *p)) 1033 { 1034 HasEightBits = TRUE; 1035 break; 1036 } 1037 } 1038 } 1039 return (buf); 1040 } 1041 1042 static void 1043 readtimeout(timeout) 1044 time_t timeout; 1045 { 1046 longjmp(CtxReadTimeout, 1); 1047 } 1048 /* 1049 ** FGETFOLDED -- like fgets, but know about folded lines. 1050 ** 1051 ** Parameters: 1052 ** buf -- place to put result. 1053 ** n -- bytes available. 1054 ** f -- file to read from. 1055 ** 1056 ** Returns: 1057 ** input line(s) on success, NULL on error or EOF. 1058 ** This will normally be buf -- unless the line is too 1059 ** long, when it will be xalloc()ed. 1060 ** 1061 ** Side Effects: 1062 ** buf gets lines from f, with continuation lines (lines 1063 ** with leading white space) appended. CRLF's are mapped 1064 ** into single newlines. Any trailing NL is stripped. 1065 */ 1066 1067 char * 1068 fgetfolded(buf, n, f) 1069 char *buf; 1070 register int n; 1071 FILE *f; 1072 { 1073 register char *p = buf; 1074 char *bp = buf; 1075 register int i; 1076 1077 n--; 1078 while ((i = getc(f)) != EOF) 1079 { 1080 if (i == '\r') 1081 { 1082 i = getc(f); 1083 if (i != '\n') 1084 { 1085 if (i != EOF) 1086 (void) ungetc(i, f); 1087 i = '\r'; 1088 } 1089 } 1090 if (--n <= 0) 1091 { 1092 /* allocate new space */ 1093 char *nbp; 1094 int nn; 1095 1096 nn = (p - bp); 1097 if (nn < MEMCHUNKSIZE) 1098 nn *= 2; 1099 else 1100 nn += MEMCHUNKSIZE; 1101 nbp = xalloc(nn); 1102 bcopy(bp, nbp, p - bp); 1103 p = &nbp[p - bp]; 1104 if (bp != buf) 1105 free(bp); 1106 bp = nbp; 1107 n = nn - (p - bp); 1108 } 1109 *p++ = i; 1110 if (i == '\n') 1111 { 1112 LineNumber++; 1113 i = getc(f); 1114 if (i != EOF) 1115 (void) ungetc(i, f); 1116 if (i != ' ' && i != '\t') 1117 break; 1118 } 1119 } 1120 if (p == bp) 1121 return (NULL); 1122 *--p = '\0'; 1123 return (bp); 1124 } 1125 /* 1126 ** CURTIME -- return current time. 1127 ** 1128 ** Parameters: 1129 ** none. 1130 ** 1131 ** Returns: 1132 ** the current time. 1133 ** 1134 ** Side Effects: 1135 ** none. 1136 */ 1137 1138 time_t 1139 curtime() 1140 { 1141 auto time_t t; 1142 1143 (void) time(&t); 1144 return (t); 1145 } 1146 /* 1147 ** ATOBOOL -- convert a string representation to boolean. 1148 ** 1149 ** Defaults to "TRUE" 1150 ** 1151 ** Parameters: 1152 ** s -- string to convert. Takes "tTyY" as true, 1153 ** others as false. 1154 ** 1155 ** Returns: 1156 ** A boolean representation of the string. 1157 ** 1158 ** Side Effects: 1159 ** none. 1160 */ 1161 1162 bool 1163 atobool(s) 1164 register char *s; 1165 { 1166 if (s == NULL || *s == '\0' || strchr("tTyY", *s) != NULL) 1167 return (TRUE); 1168 return (FALSE); 1169 } 1170 /* 1171 ** ATOOCT -- convert a string representation to octal. 1172 ** 1173 ** Parameters: 1174 ** s -- string to convert. 1175 ** 1176 ** Returns: 1177 ** An integer representing the string interpreted as an 1178 ** octal number. 1179 ** 1180 ** Side Effects: 1181 ** none. 1182 */ 1183 1184 atooct(s) 1185 register char *s; 1186 { 1187 register int i = 0; 1188 1189 while (*s >= '0' && *s <= '7') 1190 i = (i << 3) | (*s++ - '0'); 1191 return (i); 1192 } 1193 /* 1194 ** WAITFOR -- wait for a particular process id. 1195 ** 1196 ** Parameters: 1197 ** pid -- process id to wait for. 1198 ** 1199 ** Returns: 1200 ** status of pid. 1201 ** -1 if pid never shows up. 1202 ** 1203 ** Side Effects: 1204 ** none. 1205 */ 1206 1207 int 1208 waitfor(pid) 1209 int pid; 1210 { 1211 #ifdef WAITUNION 1212 union wait st; 1213 #else 1214 auto int st; 1215 #endif 1216 int i; 1217 1218 do 1219 { 1220 errno = 0; 1221 i = wait(&st); 1222 } while ((i >= 0 || errno == EINTR) && i != pid); 1223 if (i < 0) 1224 return -1; 1225 #ifdef WAITUNION 1226 return st.w_status; 1227 #else 1228 return st; 1229 #endif 1230 } 1231 /* 1232 ** BITINTERSECT -- tell if two bitmaps intersect 1233 ** 1234 ** Parameters: 1235 ** a, b -- the bitmaps in question 1236 ** 1237 ** Returns: 1238 ** TRUE if they have a non-null intersection 1239 ** FALSE otherwise 1240 ** 1241 ** Side Effects: 1242 ** none. 1243 */ 1244 1245 bool 1246 bitintersect(a, b) 1247 BITMAP a; 1248 BITMAP b; 1249 { 1250 int i; 1251 1252 for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) 1253 if ((a[i] & b[i]) != 0) 1254 return (TRUE); 1255 return (FALSE); 1256 } 1257 /* 1258 ** BITZEROP -- tell if a bitmap is all zero 1259 ** 1260 ** Parameters: 1261 ** map -- the bit map to check 1262 ** 1263 ** Returns: 1264 ** TRUE if map is all zero. 1265 ** FALSE if there are any bits set in map. 1266 ** 1267 ** Side Effects: 1268 ** none. 1269 */ 1270 1271 bool 1272 bitzerop(map) 1273 BITMAP map; 1274 { 1275 int i; 1276 1277 for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) 1278 if (map[i] != 0) 1279 return (FALSE); 1280 return (TRUE); 1281 } 1282 /* 1283 ** STRCONTAINEDIN -- tell if one string is contained in another 1284 ** 1285 ** Parameters: 1286 ** a -- possible substring. 1287 ** b -- possible superstring. 1288 ** 1289 ** Returns: 1290 ** TRUE if a is contained in b. 1291 ** FALSE otherwise. 1292 */ 1293 1294 bool 1295 strcontainedin(a, b) 1296 register char *a; 1297 register char *b; 1298 { 1299 int la; 1300 int lb; 1301 int c; 1302 1303 la = strlen(a); 1304 lb = strlen(b); 1305 c = *a; 1306 if (isascii(c) && isupper(c)) 1307 c = tolower(c); 1308 for (; lb-- >= la; b++) 1309 { 1310 if (*b != c && isascii(*b) && isupper(*b) && tolower(*b) != c) 1311 continue; 1312 if (strncasecmp(a, b, la) == 0) 1313 return TRUE; 1314 } 1315 return FALSE; 1316 } 1317 /* 1318 ** CHECKFD012 -- check low numbered file descriptors 1319 ** 1320 ** File descriptors 0, 1, and 2 should be open at all times. 1321 ** This routine verifies that, and fixes it if not true. 1322 ** 1323 ** Parameters: 1324 ** where -- a tag printed if the assertion failed 1325 ** 1326 ** Returns: 1327 ** none 1328 */ 1329 1330 checkfd012(where) 1331 char *where; 1332 { 1333 #ifdef XDEBUG 1334 register int i; 1335 struct stat stbuf; 1336 1337 for (i = 0; i < 3; i++) 1338 { 1339 if (fstat(i, &stbuf) < 0 && errno != EOPNOTSUPP) 1340 { 1341 /* oops.... */ 1342 int fd; 1343 1344 syserr("%s: fd %d not open", where, i); 1345 fd = open("/dev/null", i == 0 ? O_RDONLY : O_WRONLY, 0666); 1346 if (fd != i) 1347 { 1348 (void) dup2(fd, i); 1349 (void) close(fd); 1350 } 1351 } 1352 } 1353 #endif /* XDEBUG */ 1354 } 1355 /* 1356 ** PRINTOPENFDS -- print the open file descriptors (for debugging) 1357 ** 1358 ** Parameters: 1359 ** logit -- if set, send output to syslog; otherwise 1360 ** print for debugging. 1361 ** 1362 ** Returns: 1363 ** none. 1364 */ 1365 1366 #include <netdb.h> 1367 #include <arpa/inet.h> 1368 1369 printopenfds(logit) 1370 bool logit; 1371 { 1372 register int fd; 1373 extern int DtableSize; 1374 1375 for (fd = 0; fd < DtableSize; fd++) 1376 dumpfd(fd, FALSE, logit); 1377 } 1378 /* 1379 ** DUMPFD -- dump a file descriptor 1380 ** 1381 ** Parameters: 1382 ** fd -- the file descriptor to dump. 1383 ** printclosed -- if set, print a notification even if 1384 ** it is closed; otherwise print nothing. 1385 ** logit -- if set, send output to syslog instead of stdout. 1386 */ 1387 1388 dumpfd(fd, printclosed, logit) 1389 int fd; 1390 bool printclosed; 1391 bool logit; 1392 { 1393 register struct hostent *hp; 1394 register char *p; 1395 char *fmtstr; 1396 struct sockaddr_in sin; 1397 auto int slen; 1398 struct stat st; 1399 char buf[200]; 1400 1401 p = buf; 1402 sprintf(p, "%3d: ", fd); 1403 p += strlen(p); 1404 1405 if (fstat(fd, &st) < 0) 1406 { 1407 if (printclosed || errno != EBADF) 1408 { 1409 sprintf(p, "CANNOT STAT (%s)", errstring(errno)); 1410 goto printit; 1411 } 1412 return; 1413 } 1414 1415 slen = fcntl(fd, F_GETFL, NULL); 1416 if (slen != -1) 1417 { 1418 sprintf(p, "fl=0x%x, ", slen); 1419 p += strlen(p); 1420 } 1421 1422 sprintf(p, "mode=%o: ", st.st_mode); 1423 p += strlen(p); 1424 switch (st.st_mode & S_IFMT) 1425 { 1426 #ifdef S_IFSOCK 1427 case S_IFSOCK: 1428 sprintf(p, "SOCK "); 1429 p += strlen(p); 1430 slen = sizeof sin; 1431 if (getsockname(fd, (struct sockaddr *) &sin, &slen) < 0) 1432 sprintf(p, "(badsock)"); 1433 else 1434 { 1435 hp = gethostbyaddr((char *) &sin.sin_addr, 1436 INADDRSZ, AF_INET); 1437 sprintf(p, "%s/%d", hp == NULL ? inet_ntoa(sin.sin_addr) 1438 : hp->h_name, ntohs(sin.sin_port)); 1439 } 1440 p += strlen(p); 1441 sprintf(p, "->"); 1442 p += strlen(p); 1443 slen = sizeof sin; 1444 if (getpeername(fd, (struct sockaddr *) &sin, &slen) < 0) 1445 sprintf(p, "(badsock)"); 1446 else 1447 { 1448 hp = gethostbyaddr((char *) &sin.sin_addr, 1449 INADDRSZ, AF_INET); 1450 sprintf(p, "%s/%d", hp == NULL ? inet_ntoa(sin.sin_addr) 1451 : hp->h_name, ntohs(sin.sin_port)); 1452 } 1453 break; 1454 #endif 1455 1456 case S_IFCHR: 1457 sprintf(p, "CHR: "); 1458 p += strlen(p); 1459 goto defprint; 1460 1461 case S_IFBLK: 1462 sprintf(p, "BLK: "); 1463 p += strlen(p); 1464 goto defprint; 1465 1466 #if defined(S_IFIFO) && (!defined(S_IFSOCK) || S_IFIFO != S_IFSOCK) 1467 case S_IFIFO: 1468 sprintf(p, "FIFO: "); 1469 p += strlen(p); 1470 goto defprint; 1471 #endif 1472 1473 #ifdef S_IFDIR 1474 case S_IFDIR: 1475 sprintf(p, "DIR: "); 1476 p += strlen(p); 1477 goto defprint; 1478 #endif 1479 1480 #ifdef S_IFLNK 1481 case S_IFLNK: 1482 sprintf(p, "LNK: "); 1483 p += strlen(p); 1484 goto defprint; 1485 #endif 1486 1487 default: 1488 defprint: 1489 if (sizeof st.st_size > sizeof (long)) 1490 fmtstr = "dev=%d/%d, ino=%d, nlink=%d, u/gid=%d/%d, size=%qd"; 1491 else 1492 fmtstr = "dev=%d/%d, ino=%d, nlink=%d, u/gid=%d/%d, size=%ld"; 1493 sprintf(p, fmtstr, 1494 major(st.st_dev), minor(st.st_dev), st.st_ino, 1495 st.st_nlink, st.st_uid, st.st_gid, st.st_size); 1496 break; 1497 } 1498 1499 printit: 1500 #ifdef LOG 1501 if (logit) 1502 syslog(LOG_DEBUG, "%s", buf); 1503 else 1504 #endif 1505 printf("%s\n", buf); 1506 } 1507 /* 1508 ** SHORTENSTRING -- return short version of a string 1509 ** 1510 ** If the string is already short, just return it. If it is too 1511 ** long, return the head and tail of the string. 1512 ** 1513 ** Parameters: 1514 ** s -- the string to shorten. 1515 ** m -- the max length of the string. 1516 ** 1517 ** Returns: 1518 ** Either s or a short version of s. 1519 */ 1520 1521 #ifndef MAXSHORTSTR 1522 # define MAXSHORTSTR 203 1523 #endif 1524 1525 char * 1526 shortenstring(s, m) 1527 register char *s; 1528 int m; 1529 { 1530 int l; 1531 static char buf[MAXSHORTSTR + 1]; 1532 1533 l = strlen(s); 1534 if (l < m) 1535 return s; 1536 if (m > MAXSHORTSTR) 1537 m = MAXSHORTSTR; 1538 else if (m < 10) 1539 { 1540 if (m < 5) 1541 { 1542 strncpy(buf, s, m); 1543 buf[m] = '\0'; 1544 return buf; 1545 } 1546 strncpy(buf, s, m - 3); 1547 strcpy(buf + m - 3, "..."); 1548 return buf; 1549 } 1550 m = (m - 3) / 2; 1551 strncpy(buf, s, m); 1552 strcpy(buf + m, "..."); 1553 strcpy(buf + m + 3, s + l - m); 1554 return buf; 1555 } 1556 /* 1557 ** GET_COLUMN -- look up a Column in a line buffer 1558 ** 1559 ** Parameters: 1560 ** line -- the raw text line to search. 1561 ** col -- the column number to fetch. 1562 ** delim -- the delimiter between columns. If null, 1563 ** use white space. 1564 ** buf -- the output buffer. 1565 ** 1566 ** Returns: 1567 ** buf if successful. 1568 ** NULL otherwise. 1569 */ 1570 1571 char * 1572 get_column(line, col, delim, buf) 1573 char line[]; 1574 int col; 1575 char delim; 1576 char buf[]; 1577 { 1578 char *p; 1579 char *begin, *end; 1580 int i; 1581 char delimbuf[3]; 1582 1583 if (delim == '\0') 1584 strcpy(delimbuf, "\t "); 1585 else 1586 { 1587 delimbuf[0] = delim; 1588 delimbuf[1] = '\0'; 1589 } 1590 1591 p = line; 1592 if (*p == '\0') 1593 return NULL; /* line empty */ 1594 if (*p == delim && col == 0) 1595 return NULL; /* first column empty */ 1596 1597 begin = line; 1598 1599 if (col == 0 && delim == '\0') 1600 { 1601 while (*begin && isspace(*begin)) 1602 begin++; 1603 } 1604 1605 for (i = 0; i < col; i++) 1606 { 1607 if ((begin = strpbrk(begin, delimbuf)) == NULL) 1608 return NULL; /* no such column */ 1609 begin++; 1610 if (delim == '\0') 1611 { 1612 while (*begin && isspace(*begin)) 1613 begin++; 1614 } 1615 } 1616 1617 end = strpbrk(begin, delimbuf); 1618 if (end == NULL) 1619 { 1620 strcpy(buf, begin); 1621 } 1622 else 1623 { 1624 strncpy(buf, begin, end - begin); 1625 buf[end - begin] = '\0'; 1626 } 1627 return buf; 1628 } 1629 /* 1630 ** CLEANSTRCPY -- copy string keeping out bogus characters 1631 ** 1632 ** Parameters: 1633 ** t -- "to" string. 1634 ** f -- "from" string. 1635 ** l -- length of space available in "to" string. 1636 ** 1637 ** Returns: 1638 ** none. 1639 */ 1640 1641 void 1642 cleanstrcpy(t, f, l) 1643 register char *t; 1644 register char *f; 1645 int l; 1646 { 1647 #ifdef LOG 1648 /* check for newlines and log if necessary */ 1649 (void) denlstring(f, TRUE, TRUE); 1650 #endif 1651 1652 l--; 1653 while (l > 0 && *f != '\0') 1654 { 1655 if (isascii(*f) && 1656 (isalnum(*f) || strchr("!#$%&'*+-./^_`{|}~", *f) != NULL)) 1657 { 1658 l--; 1659 *t++ = *f; 1660 } 1661 f++; 1662 } 1663 *t = '\0'; 1664 } 1665 /* 1666 ** DENLSTRING -- convert newlines in a string to spaces 1667 ** 1668 ** Parameters: 1669 ** s -- the input string 1670 ** strict -- if set, don't permit continuation lines. 1671 ** logattacks -- if set, log attempted attacks. 1672 ** 1673 ** Returns: 1674 ** A pointer to a version of the string with newlines 1675 ** mapped to spaces. This should be copied. 1676 */ 1677 1678 char * 1679 denlstring(s, strict, logattacks) 1680 char *s; 1681 int strict; 1682 int logattacks; 1683 { 1684 register char *p; 1685 int l; 1686 static char *bp = NULL; 1687 static int bl = 0; 1688 1689 p = s; 1690 while ((p = strchr(p, '\n')) != NULL) 1691 if (strict || (*++p != ' ' && *p != '\t')) 1692 break; 1693 if (p == NULL) 1694 return s; 1695 1696 l = strlen(s) + 1; 1697 if (bl < l) 1698 { 1699 /* allocate more space */ 1700 if (bp != NULL) 1701 free(bp); 1702 bp = xalloc(l); 1703 bl = l; 1704 } 1705 strcpy(bp, s); 1706 for (p = bp; (p = strchr(p, '\n')) != NULL; ) 1707 *p++ = ' '; 1708 1709 /* 1710 #ifdef LOG 1711 if (logattacks) 1712 { 1713 syslog(LOG_NOTICE, "POSSIBLE ATTACK from %s: newline in string \"%s\"", 1714 RealHostName == NULL ? "[UNKNOWN]" : RealHostName, 1715 shortenstring(bp, 80)); 1716 } 1717 #endif 1718 */ 1719 1720 return bp; 1721 } 1722