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