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