1 /* 2 * Copyright (c) 1983 Eric P. Allman 3 * Copyright (c) 1988 Regents of the University of California. 4 * All rights reserved. 5 * 6 * %sccs.include.redist.c% 7 */ 8 9 #ifndef lint 10 static char sccsid[] = "@(#)util.c 5.30 (Berkeley) 09/22/92"; 11 #endif /* not lint */ 12 13 # include <stdio.h> 14 # include <sys/types.h> 15 # include <sys/stat.h> 16 # include <sysexits.h> 17 # include <errno.h> 18 # include "sendmail.h" 19 20 /* 21 ** STRIPQUOTES -- Strip quotes & quote bits from a string. 22 ** 23 ** Runs through a string and strips off unquoted quote 24 ** characters and quote bits. This is done in place. 25 ** 26 ** Parameters: 27 ** s -- the string to strip. 28 ** 29 ** Returns: 30 ** none. 31 ** 32 ** Side Effects: 33 ** none. 34 ** 35 ** Called By: 36 ** deliver 37 */ 38 39 stripquotes(s) 40 char *s; 41 { 42 register char *p; 43 register char *q; 44 register char c; 45 46 if (s == NULL) 47 return; 48 49 p = q = s; 50 do 51 { 52 c = *p++; 53 if (c == '\\') 54 c = *p++; 55 else if (c == '"') 56 continue; 57 *q++ = c; 58 } while (c != '\0'); 59 } 60 /* 61 ** CAPITALIZE -- return a copy of a string, properly capitalized. 62 ** 63 ** Parameters: 64 ** s -- the string to capitalize. 65 ** 66 ** Returns: 67 ** a pointer to a properly capitalized string. 68 ** 69 ** Side Effects: 70 ** none. 71 */ 72 73 char * 74 capitalize(s) 75 register char *s; 76 { 77 static char buf[50]; 78 register char *p; 79 80 p = buf; 81 82 for (;;) 83 { 84 while (!isalpha(*s) && *s != '\0') 85 *p++ = *s++; 86 if (*s == '\0') 87 break; 88 *p++ = toupper(*s); 89 s++; 90 while (isalpha(*s)) 91 *p++ = *s++; 92 } 93 94 *p = '\0'; 95 return (buf); 96 } 97 /* 98 ** XALLOC -- Allocate memory and bitch wildly on failure. 99 ** 100 ** THIS IS A CLUDGE. This should be made to give a proper 101 ** error -- but after all, what can we do? 102 ** 103 ** Parameters: 104 ** sz -- size of area to allocate. 105 ** 106 ** Returns: 107 ** pointer to data region. 108 ** 109 ** Side Effects: 110 ** Memory is allocated. 111 */ 112 113 char * 114 xalloc(sz) 115 register int sz; 116 { 117 register char *p; 118 extern char *malloc(); 119 120 p = malloc((unsigned) sz); 121 if (p == NULL) 122 { 123 syserr("Out of memory!!"); 124 abort(); 125 /* exit(EX_UNAVAILABLE); */ 126 } 127 return (p); 128 } 129 /* 130 ** COPYPLIST -- copy list of pointers. 131 ** 132 ** This routine is the equivalent of newstr for lists of 133 ** pointers. 134 ** 135 ** Parameters: 136 ** list -- list of pointers to copy. 137 ** Must be NULL terminated. 138 ** copycont -- if TRUE, copy the contents of the vector 139 ** (which must be a string) also. 140 ** 141 ** Returns: 142 ** a copy of 'list'. 143 ** 144 ** Side Effects: 145 ** none. 146 */ 147 148 char ** 149 copyplist(list, copycont) 150 char **list; 151 bool copycont; 152 { 153 register char **vp; 154 register char **newvp; 155 156 for (vp = list; *vp != NULL; vp++) 157 continue; 158 159 vp++; 160 161 newvp = (char **) xalloc((int) (vp - list) * sizeof *vp); 162 bcopy((char *) list, (char *) newvp, (int) (vp - list) * sizeof *vp); 163 164 if (copycont) 165 { 166 for (vp = newvp; *vp != NULL; vp++) 167 *vp = newstr(*vp); 168 } 169 170 return (newvp); 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 char c; 234 register struct metamac *mp; 235 extern struct metamac MetaMacros[]; 236 237 if (s == NULL) 238 { 239 printf("<null>"); 240 return; 241 } 242 c = *s; 243 if (c == MATCHREPL && isdigit(s[1]) && s[2] == '\0') 244 { 245 printf("$%c", s[1]); 246 return; 247 } 248 for (mp = MetaMacros; mp->metaname != NULL; mp++) 249 { 250 if (mp->metaval == c) 251 { 252 printf("$%c%s", mp->metaname, ++s); 253 return; 254 } 255 } 256 (void) putchar('"'); 257 while ((c = *s++) != '\0') 258 { 259 if (!isascii(c)) 260 { 261 (void) putchar('\\'); 262 c &= 0177; 263 } 264 if (c < 040 || c >= 0177) 265 { 266 switch (c) 267 { 268 case '\n': 269 c = 'n'; 270 break; 271 272 case '\r': 273 c = 'r'; 274 break; 275 276 case '\t': 277 c = 't'; 278 break; 279 280 case '\001': 281 (void) putchar('$'); 282 continue; 283 284 default: 285 (void) putchar('^'); 286 (void) putchar(c ^ 0100); 287 continue; 288 } 289 (void) putchar('\\'); 290 } 291 (void) putchar(c); 292 } 293 (void) putchar('"'); 294 (void) fflush(stdout); 295 } 296 /* 297 ** MAKELOWER -- Translate a line into lower case 298 ** 299 ** Parameters: 300 ** p -- the string to translate. If NULL, return is 301 ** immediate. 302 ** 303 ** Returns: 304 ** none. 305 ** 306 ** Side Effects: 307 ** String pointed to by p is translated to lower case. 308 ** 309 ** Called By: 310 ** parse 311 */ 312 313 makelower(p) 314 register char *p; 315 { 316 register char c; 317 318 if (p == NULL) 319 return; 320 for (; (c = *p) != '\0'; p++) 321 if (isascii(c) && isupper(c)) 322 *p = tolower(c); 323 } 324 /* 325 ** BUILDFNAME -- build full name from gecos style entry. 326 ** 327 ** This routine interprets the strange entry that would appear 328 ** in the GECOS field of the password file. 329 ** 330 ** Parameters: 331 ** p -- name to build. 332 ** login -- the login name of this user (for &). 333 ** buf -- place to put the result. 334 ** 335 ** Returns: 336 ** none. 337 ** 338 ** Side Effects: 339 ** none. 340 */ 341 342 buildfname(gecos, login, buf) 343 register char *gecos; 344 char *login; 345 char *buf; 346 { 347 register char *p; 348 register char *bp = buf; 349 int l; 350 bool quoteit; 351 352 if (*gecos == '*') 353 gecos++; 354 355 /* see if the full name needs to be quoted */ 356 l = 0; 357 quoteit = FALSE; 358 for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++) 359 { 360 if (index("<>()'.", *p) != NULL) 361 quoteit = TRUE; 362 if (*p == '&') 363 l += strlen(login); 364 else 365 l++; 366 } 367 if (quoteit) 368 l += 2; 369 370 /* now fill in buf */ 371 if (quoteit) 372 *bp++ = '"'; 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 if (quoteit) 386 *bp++ = '"'; 387 *bp = '\0'; 388 } 389 /* 390 ** SAFEFILE -- return true if a file exists and is safe for a user. 391 ** 392 ** Parameters: 393 ** fn -- filename to check. 394 ** uid -- uid to compare against. 395 ** mode -- mode bits that must match. 396 ** 397 ** Returns: 398 ** TRUE if fn exists, is owned by uid, and matches mode. 399 ** FALSE otherwise. 400 ** 401 ** Side Effects: 402 ** none. 403 */ 404 405 bool 406 safefile(fn, uid, mode) 407 char *fn; 408 uid_t uid; 409 int mode; 410 { 411 struct stat stbuf; 412 413 if (stat(fn, &stbuf) >= 0 && stbuf.st_uid == uid && 414 (stbuf.st_mode & mode) == mode) 415 return (TRUE); 416 errno = 0; 417 return (FALSE); 418 } 419 /* 420 ** FIXCRLF -- fix <CR><LF> in line. 421 ** 422 ** Looks for the <CR><LF> combination and turns it into the 423 ** UNIX canonical <NL> character. It only takes one line, 424 ** i.e., it is assumed that the first <NL> found is the end 425 ** of the line. 426 ** 427 ** Parameters: 428 ** line -- the line to fix. 429 ** stripnl -- if true, strip the newline also. 430 ** 431 ** Returns: 432 ** none. 433 ** 434 ** Side Effects: 435 ** line is changed in place. 436 */ 437 438 fixcrlf(line, stripnl) 439 char *line; 440 bool stripnl; 441 { 442 register char *p; 443 444 p = index(line, '\n'); 445 if (p == NULL) 446 return; 447 if (p > line && p[-1] == '\r') 448 p--; 449 if (!stripnl) 450 *p++ = '\n'; 451 *p = '\0'; 452 } 453 /* 454 ** DFOPEN -- determined file open 455 ** 456 ** This routine has the semantics of fopen, except that it will 457 ** keep trying a few times to make this happen. The idea is that 458 ** on very loaded systems, we may run out of resources (inodes, 459 ** whatever), so this tries to get around it. 460 */ 461 462 FILE * 463 dfopen(filename, mode) 464 char *filename; 465 char *mode; 466 { 467 register int tries; 468 register FILE *fp; 469 470 for (tries = 0; tries < 10; tries++) 471 { 472 sleep((unsigned) (10 * tries)); 473 errno = 0; 474 fp = fopen(filename, mode); 475 if (fp != NULL) 476 break; 477 if (errno != ENFILE && errno != EINTR) 478 break; 479 } 480 if (fp != NULL) 481 { 482 #ifdef FLOCK 483 int locktype; 484 485 /* lock the file to avoid accidental conflicts */ 486 if (*mode == 'w' || *mode == 'a') 487 locktype = LOCK_EX; 488 else 489 locktype = LOCK_SH; 490 (void) flock(fileno(fp), locktype); 491 #endif 492 errno = 0; 493 } 494 return (fp); 495 } 496 /* 497 ** PUTLINE -- put a line like fputs obeying SMTP conventions 498 ** 499 ** This routine always guarantees outputing a newline (or CRLF, 500 ** as appropriate) at the end of the string. 501 ** 502 ** Parameters: 503 ** l -- line to put. 504 ** fp -- file to put it onto. 505 ** m -- the mailer used to control output. 506 ** 507 ** Returns: 508 ** none 509 ** 510 ** Side Effects: 511 ** output of l to fp. 512 */ 513 514 putline(l, fp, m) 515 register char *l; 516 FILE *fp; 517 MAILER *m; 518 { 519 register char *p; 520 register char svchar; 521 522 /* strip out 0200 bits -- these can look like TELNET protocol */ 523 if (bitnset(M_7BITS, m->m_flags)) 524 { 525 for (p = l; svchar = *p; ++p) 526 if (svchar & 0200) 527 *p = svchar &~ 0200; 528 } 529 530 do 531 { 532 /* find the end of the line */ 533 p = index(l, '\n'); 534 if (p == NULL) 535 p = &l[strlen(l)]; 536 537 /* check for line overflow */ 538 while (m->m_linelimit > 0 && (p - l) > m->m_linelimit) 539 { 540 register char *q = &l[m->m_linelimit - 1]; 541 542 svchar = *q; 543 *q = '\0'; 544 if (l[0] == '.' && bitnset(M_XDOT, m->m_flags)) 545 (void) putc('.', fp); 546 fputs(l, fp); 547 (void) putc('!', fp); 548 fputs(m->m_eol, fp); 549 *q = svchar; 550 l = q; 551 } 552 553 /* output last part */ 554 if (l[0] == '.' && bitnset(M_XDOT, m->m_flags)) 555 (void) putc('.', fp); 556 for ( ; l < p; ++l) 557 (void) putc(*l, fp); 558 fputs(m->m_eol, fp); 559 if (*l == '\n') 560 ++l; 561 } while (l[0] != '\0'); 562 } 563 /* 564 ** XUNLINK -- unlink a file, doing logging as appropriate. 565 ** 566 ** Parameters: 567 ** f -- name of file to unlink. 568 ** 569 ** Returns: 570 ** none. 571 ** 572 ** Side Effects: 573 ** f is unlinked. 574 */ 575 576 xunlink(f) 577 char *f; 578 { 579 register int i; 580 581 # ifdef LOG 582 if (LogLevel > 20) 583 syslog(LOG_DEBUG, "%s: unlink %s\n", CurEnv->e_id, f); 584 # endif LOG 585 586 i = unlink(f); 587 # ifdef LOG 588 if (i < 0 && LogLevel > 21) 589 syslog(LOG_DEBUG, "%s: unlink-fail %d", f, errno); 590 # endif LOG 591 } 592 /* 593 ** SFGETS -- "safe" fgets -- times out and ignores random interrupts. 594 ** 595 ** Parameters: 596 ** buf -- place to put the input line. 597 ** siz -- size of buf. 598 ** fp -- file to read from. 599 ** 600 ** Returns: 601 ** NULL on error (including timeout). This will also leave 602 ** buf containing a null string. 603 ** buf otherwise. 604 ** 605 ** Side Effects: 606 ** none. 607 */ 608 609 static jmp_buf CtxReadTimeout; 610 611 char * 612 sfgets(buf, siz, fp) 613 char *buf; 614 int siz; 615 FILE *fp; 616 { 617 register EVENT *ev = NULL; 618 register char *p; 619 static int readtimeout(); 620 621 /* set the timeout */ 622 if (ReadTimeout != 0) 623 { 624 if (setjmp(CtxReadTimeout) != 0) 625 { 626 # ifdef LOG 627 syslog(LOG_NOTICE, 628 "timeout waiting for input from %s\n", 629 RealHostName? RealHostName: "local"); 630 # endif 631 errno = 0; 632 usrerr("451 timeout waiting for input"); 633 buf[0] = '\0'; 634 return (NULL); 635 } 636 ev = setevent((time_t) ReadTimeout, readtimeout, 0); 637 } 638 639 /* try to read */ 640 p = NULL; 641 while (p == NULL && !feof(fp) && !ferror(fp)) 642 { 643 errno = 0; 644 p = fgets(buf, siz, fp); 645 if (errno == EINTR) 646 clearerr(fp); 647 } 648 649 /* clear the event if it has not sprung */ 650 clrevent(ev); 651 652 /* clean up the books and exit */ 653 LineNumber++; 654 if (p == NULL) 655 { 656 buf[0] = '\0'; 657 return (NULL); 658 } 659 if (!EightBit) 660 for (p = buf; *p != '\0'; p++) 661 *p &= ~0200; 662 return (buf); 663 } 664 665 static 666 readtimeout() 667 { 668 longjmp(CtxReadTimeout, 1); 669 } 670 /* 671 ** FGETFOLDED -- like fgets, but know about folded lines. 672 ** 673 ** Parameters: 674 ** buf -- place to put result. 675 ** n -- bytes available. 676 ** f -- file to read from. 677 ** 678 ** Returns: 679 ** buf on success, NULL on error or EOF. 680 ** 681 ** Side Effects: 682 ** buf gets lines from f, with continuation lines (lines 683 ** with leading white space) appended. CRLF's are mapped 684 ** into single newlines. Any trailing NL is stripped. 685 */ 686 687 char * 688 fgetfolded(buf, n, f) 689 char *buf; 690 register int n; 691 FILE *f; 692 { 693 register char *p = buf; 694 register int i; 695 696 n--; 697 while ((i = getc(f)) != EOF) 698 { 699 if (i == '\r') 700 { 701 i = getc(f); 702 if (i != '\n') 703 { 704 if (i != EOF) 705 (void) ungetc(i, f); 706 i = '\r'; 707 } 708 } 709 if (--n > 0) 710 *p++ = i; 711 else if (n == 0) 712 nmessage(Arpa_Info, "warning: line truncated"); 713 if (i == '\n') 714 { 715 LineNumber++; 716 i = getc(f); 717 if (i != EOF) 718 (void) ungetc(i, f); 719 if (i != ' ' && i != '\t') 720 break; 721 } 722 } 723 if (p == buf) 724 return (NULL); 725 *--p = '\0'; 726 return (buf); 727 } 728 /* 729 ** CURTIME -- return current time. 730 ** 731 ** Parameters: 732 ** none. 733 ** 734 ** Returns: 735 ** the current time. 736 ** 737 ** Side Effects: 738 ** none. 739 */ 740 741 time_t 742 curtime() 743 { 744 auto time_t t; 745 746 (void) time(&t); 747 return (t); 748 } 749 /* 750 ** ATOBOOL -- convert a string representation to boolean. 751 ** 752 ** Defaults to "TRUE" 753 ** 754 ** Parameters: 755 ** s -- string to convert. Takes "tTyY" as true, 756 ** others as false. 757 ** 758 ** Returns: 759 ** A boolean representation of the string. 760 ** 761 ** Side Effects: 762 ** none. 763 */ 764 765 bool 766 atobool(s) 767 register char *s; 768 { 769 if (*s == '\0' || index("tTyY", *s) != NULL) 770 return (TRUE); 771 return (FALSE); 772 } 773 /* 774 ** ATOOCT -- convert a string representation to octal. 775 ** 776 ** Parameters: 777 ** s -- string to convert. 778 ** 779 ** Returns: 780 ** An integer representing the string interpreted as an 781 ** octal number. 782 ** 783 ** Side Effects: 784 ** none. 785 */ 786 787 atooct(s) 788 register char *s; 789 { 790 register int i = 0; 791 792 while (*s >= '0' && *s <= '7') 793 i = (i << 3) | (*s++ - '0'); 794 return (i); 795 } 796 /* 797 ** WAITFOR -- wait for a particular process id. 798 ** 799 ** Parameters: 800 ** pid -- process id to wait for. 801 ** 802 ** Returns: 803 ** status of pid. 804 ** -1 if pid never shows up. 805 ** 806 ** Side Effects: 807 ** none. 808 */ 809 810 waitfor(pid) 811 int pid; 812 { 813 auto int st; 814 int i; 815 816 do 817 { 818 errno = 0; 819 i = wait(&st); 820 } while ((i >= 0 || errno == EINTR) && i != pid); 821 if (i < 0) 822 st = -1; 823 return (st); 824 } 825 /* 826 ** BITINTERSECT -- tell if two bitmaps intersect 827 ** 828 ** Parameters: 829 ** a, b -- the bitmaps in question 830 ** 831 ** Returns: 832 ** TRUE if they have a non-null intersection 833 ** FALSE otherwise 834 ** 835 ** Side Effects: 836 ** none. 837 */ 838 839 bool 840 bitintersect(a, b) 841 BITMAP a; 842 BITMAP b; 843 { 844 int i; 845 846 for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) 847 if ((a[i] & b[i]) != 0) 848 return (TRUE); 849 return (FALSE); 850 } 851 /* 852 ** BITZEROP -- tell if a bitmap is all zero 853 ** 854 ** Parameters: 855 ** map -- the bit map to check 856 ** 857 ** Returns: 858 ** TRUE if map is all zero. 859 ** FALSE if there are any bits set in map. 860 ** 861 ** Side Effects: 862 ** none. 863 */ 864 865 bool 866 bitzerop(map) 867 BITMAP map; 868 { 869 int i; 870 871 for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) 872 if (map[i] != 0) 873 return (FALSE); 874 return (TRUE); 875 } 876