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