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.9 11/13/84); 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((int) (vp - list) * sizeof *vp); 177 bcopy((char *) list, (char *) newvp, (int) (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 char ca, cb; 328 329 do 330 { 331 ca = *a++; 332 cb = *b++; 333 if (isascii(ca) && isupper(ca)) 334 ca = ca - 'A' + 'a'; 335 if (isascii(cb) && isupper(cb)) 336 cb = cb - 'A' + 'a'; 337 } while (ca != '\0' && ca == cb); 338 return (ca == cb); 339 } 340 /* 341 ** BUILDFNAME -- build full name from gecos style entry. 342 ** 343 ** This routine interprets the strange entry that would appear 344 ** in the GECOS field of the password file. 345 ** 346 ** Parameters: 347 ** p -- name to build. 348 ** login -- the login name of this user (for &). 349 ** buf -- place to put the result. 350 ** 351 ** Returns: 352 ** none. 353 ** 354 ** Side Effects: 355 ** none. 356 */ 357 358 buildfname(p, login, buf) 359 register char *p; 360 char *login; 361 char *buf; 362 { 363 register char *bp = buf; 364 365 if (*p == '*') 366 p++; 367 while (*p != '\0' && *p != ',' && *p != ';' && *p != '%') 368 { 369 if (*p == '&') 370 { 371 (void) strcpy(bp, login); 372 *bp = toupper(*bp); 373 while (*bp != '\0') 374 bp++; 375 p++; 376 } 377 else 378 *bp++ = *p++; 379 } 380 *bp = '\0'; 381 } 382 /* 383 ** SAFEFILE -- return true if a file exists and is safe for a user. 384 ** 385 ** Parameters: 386 ** fn -- filename to check. 387 ** uid -- uid to compare against. 388 ** mode -- mode bits that must match. 389 ** 390 ** Returns: 391 ** TRUE if fn exists, is owned by uid, and matches mode. 392 ** FALSE otherwise. 393 ** 394 ** Side Effects: 395 ** none. 396 */ 397 398 bool 399 safefile(fn, uid, mode) 400 char *fn; 401 int uid; 402 int mode; 403 { 404 struct stat stbuf; 405 406 if (stat(fn, &stbuf) >= 0 && stbuf.st_uid == uid && 407 (stbuf.st_mode & mode) == mode) 408 return (TRUE); 409 errno = 0; 410 return (FALSE); 411 } 412 /* 413 ** FIXCRLF -- fix <CR><LF> in line. 414 ** 415 ** Looks for the <CR><LF> combination and turns it into the 416 ** UNIX canonical <NL> character. It only takes one line, 417 ** i.e., it is assumed that the first <NL> found is the end 418 ** of the line. 419 ** 420 ** Parameters: 421 ** line -- the line to fix. 422 ** stripnl -- if true, strip the newline also. 423 ** 424 ** Returns: 425 ** none. 426 ** 427 ** Side Effects: 428 ** line is changed in place. 429 */ 430 431 fixcrlf(line, stripnl) 432 char *line; 433 bool stripnl; 434 { 435 register char *p; 436 437 p = index(line, '\n'); 438 if (p == NULL) 439 return; 440 if (p[-1] == '\r') 441 p--; 442 if (!stripnl) 443 *p++ = '\n'; 444 *p = '\0'; 445 } 446 /* 447 ** SYSLOG -- fake entry to fool lint 448 */ 449 450 # ifdef LOG 451 # ifdef lint 452 453 /*VARARGS2*/ 454 syslog(pri, fmt, args) 455 int pri; 456 char *fmt; 457 { 458 pri = *fmt; 459 args = pri; 460 pri = args; 461 } 462 463 # endif lint 464 # endif LOG 465 /* 466 ** DFOPEN -- determined file open 467 ** 468 ** This routine has the semantics of fopen, except that it will 469 ** keep trying a few times to make this happen. The idea is that 470 ** on very loaded systems, we may run out of resources (inodes, 471 ** whatever), so this tries to get around it. 472 */ 473 474 FILE * 475 dfopen(filename, mode) 476 char *filename; 477 char *mode; 478 { 479 register int tries; 480 register FILE *fp; 481 482 for (tries = 0; tries < 10; tries++) 483 { 484 sleep(10 * tries); 485 errno = 0; 486 fp = fopen(filename, mode); 487 if (fp != NULL) 488 break; 489 if (errno != ENFILE && errno != EINTR) 490 break; 491 } 492 errno = 0; 493 return (fp); 494 } 495 /* 496 ** PUTLINE -- put a line like fputs obeying SMTP conventions 497 ** 498 ** This routine always guarantees outputing a newline (or CRLF, 499 ** as appropriate) at the end of the string. 500 ** 501 ** Parameters: 502 ** l -- line to put. 503 ** fp -- file to put it onto. 504 ** m -- the mailer used to control output. 505 ** 506 ** Returns: 507 ** none 508 ** 509 ** Side Effects: 510 ** output of l to fp. 511 */ 512 513 # define SMTPLINELIM 990 /* maximum line length */ 514 515 putline(l, fp, m) 516 register char *l; 517 FILE *fp; 518 MAILER *m; 519 { 520 register char *p; 521 char svchar; 522 523 /* strip out 0200 bits -- these can look like TELNET protocol */ 524 if (bitnset(M_LIMITS, m->m_flags)) 525 { 526 p = l; 527 while ((*p++ &= ~0200) != 0) 528 continue; 529 } 530 531 do 532 { 533 /* find the end of the line */ 534 p = index(l, '\n'); 535 if (p == NULL) 536 p = &l[strlen(l)]; 537 538 /* check for line overflow */ 539 while ((p - l) > SMTPLINELIM && bitnset(M_LIMITS, m->m_flags)) 540 { 541 register char *q = &l[SMTPLINELIM - 1]; 542 543 svchar = *q; 544 *q = '\0'; 545 if (l[0] == '.' && bitnset(M_XDOT, m->m_flags)) 546 fputc('.', fp); 547 fputs(l, fp); 548 fputc('!', fp); 549 fputs(m->m_eol, fp); 550 *q = svchar; 551 l = q; 552 } 553 554 /* output last part */ 555 svchar = *p; 556 *p = '\0'; 557 if (l[0] == '.' && bitnset(M_XDOT, m->m_flags)) 558 fputc('.', fp); 559 fputs(l, fp); 560 fputs(m->m_eol, fp); 561 *p = svchar; 562 l = p; 563 if (*l == '\n') 564 l++; 565 } while (l[0] != '\0'); 566 } 567 /* 568 ** XUNLINK -- unlink a file, doing logging as appropriate. 569 ** 570 ** Parameters: 571 ** f -- name of file to unlink. 572 ** 573 ** Returns: 574 ** none. 575 ** 576 ** Side Effects: 577 ** f is unlinked. 578 */ 579 580 xunlink(f) 581 char *f; 582 { 583 register int i; 584 585 # ifdef LOG 586 if (LogLevel > 20) 587 syslog(LOG_DEBUG, "%s: unlink %s\n", CurEnv->e_id, f); 588 # endif LOG 589 590 i = unlink(f); 591 # ifdef LOG 592 if (i < 0 && LogLevel > 21) 593 syslog(LOG_DEBUG, "%s: unlink-fail %d", f, errno); 594 # endif LOG 595 } 596 /* 597 ** SFGETS -- "safe" fgets -- times out and ignores random interrupts. 598 ** 599 ** Parameters: 600 ** buf -- place to put the input line. 601 ** siz -- size of buf. 602 ** fp -- file to read from. 603 ** 604 ** Returns: 605 ** NULL on error (including timeout). This will also leave 606 ** buf containing a null string. 607 ** buf otherwise. 608 ** 609 ** Side Effects: 610 ** none. 611 */ 612 613 static jmp_buf CtxReadTimeout; 614 615 #ifndef ETIMEDOUT 616 #define ETIMEDOUT EINTR 617 #endif 618 619 char * 620 sfgets(buf, siz, fp) 621 char *buf; 622 int siz; 623 FILE *fp; 624 { 625 register EVENT *ev = NULL; 626 register char *p; 627 extern readtimeout(); 628 629 /* set the timeout */ 630 if (ReadTimeout != 0) 631 { 632 if (setjmp(CtxReadTimeout) != 0) 633 { 634 errno = ETIMEDOUT; 635 syserr("sfgets: timeout on read (mailer may be hung)"); 636 return (NULL); 637 } 638 ev = setevent((time_t) ReadTimeout, readtimeout, 0); 639 } 640 641 /* try to read */ 642 p = NULL; 643 while (p == NULL && !feof(fp) && !ferror(fp)) 644 { 645 errno = 0; 646 p = fgets(buf, siz, fp); 647 if (errno == EINTR) 648 clearerr(fp); 649 } 650 651 /* clear the event if it has not sprung */ 652 clrevent(ev); 653 654 /* clean up the books and exit */ 655 LineNumber++; 656 if (p == NULL) 657 { 658 buf[0] = '\0'; 659 return (NULL); 660 } 661 for (p = buf; *p != '\0'; p++) 662 *p &= ~0200; 663 return (buf); 664 } 665 666 static 667 readtimeout() 668 { 669 longjmp(CtxReadTimeout, 1); 670 } 671 /* 672 ** FGETFOLDED -- like fgets, but know about folded lines. 673 ** 674 ** Parameters: 675 ** buf -- place to put result. 676 ** n -- bytes available. 677 ** f -- file to read from. 678 ** 679 ** Returns: 680 ** buf on success, NULL on error or EOF. 681 ** 682 ** Side Effects: 683 ** buf gets lines from f, with continuation lines (lines 684 ** with leading white space) appended. CRLF's are mapped 685 ** into single newlines. Any trailing NL is stripped. 686 */ 687 688 char * 689 fgetfolded(buf, n, f) 690 char *buf; 691 register int n; 692 FILE *f; 693 { 694 register char *p = buf; 695 register int i; 696 697 n--; 698 while ((i = getc(f)) != EOF) 699 { 700 if (i == '\r') 701 { 702 i = getc(f); 703 if (i != '\n') 704 { 705 if (i != EOF) 706 ungetc(i, f); 707 i = '\r'; 708 } 709 } 710 if (--n > 0) 711 *p++ = i; 712 if (i == '\n') 713 { 714 LineNumber++; 715 i = getc(f); 716 if (i != EOF) 717 ungetc(i, f); 718 if (i != ' ' && i != '\t') 719 { 720 *--p = '\0'; 721 return (buf); 722 } 723 } 724 } 725 return (NULL); 726 } 727 /* 728 ** CURTIME -- return current time. 729 ** 730 ** Parameters: 731 ** none. 732 ** 733 ** Returns: 734 ** the current time. 735 ** 736 ** Side Effects: 737 ** none. 738 */ 739 740 time_t 741 curtime() 742 { 743 auto time_t t; 744 745 (void) time(&t); 746 return (t); 747 } 748 /* 749 ** ATOBOOL -- convert a string representation to boolean. 750 ** 751 ** Defaults to "TRUE" 752 ** 753 ** Parameters: 754 ** s -- string to convert. Takes "tTyY" as true, 755 ** others as false. 756 ** 757 ** Returns: 758 ** A boolean representation of the string. 759 ** 760 ** Side Effects: 761 ** none. 762 */ 763 764 bool 765 atobool(s) 766 register char *s; 767 { 768 if (*s == '\0' || index("tTyY", *s) != NULL) 769 return (TRUE); 770 return (FALSE); 771 } 772 /* 773 ** ATOOCT -- convert a string representation to octal. 774 ** 775 ** Parameters: 776 ** s -- string to convert. 777 ** 778 ** Returns: 779 ** An integer representing the string interpreted as an 780 ** octal number. 781 ** 782 ** Side Effects: 783 ** none. 784 */ 785 786 atooct(s) 787 register char *s; 788 { 789 register int i = 0; 790 791 while (*s >= '0' && *s <= '7') 792 i = (i << 3) | (*s++ - '0'); 793 return (i); 794 } 795 /* 796 ** WAITFOR -- wait for a particular process id. 797 ** 798 ** Parameters: 799 ** pid -- process id to wait for. 800 ** 801 ** Returns: 802 ** status of pid. 803 ** -1 if pid never shows up. 804 ** 805 ** Side Effects: 806 ** none. 807 */ 808 809 waitfor(pid) 810 int pid; 811 { 812 auto int st; 813 int i; 814 815 do 816 { 817 errno = 0; 818 i = wait(&st); 819 } while ((i >= 0 || errno == EINTR) && i != pid); 820 if (i < 0) 821 st = -1; 822 return (st); 823 } 824 /* 825 ** BITINTERSECT -- tell if two bitmaps intersect 826 ** 827 ** Parameters: 828 ** a, b -- the bitmaps in question 829 ** 830 ** Returns: 831 ** TRUE if they have a non-null intersection 832 ** FALSE otherwise 833 ** 834 ** Side Effects: 835 ** none. 836 */ 837 838 bool 839 bitintersect(a, b) 840 BITMAP a; 841 BITMAP b; 842 { 843 int i; 844 845 for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) 846 if ((a[i] & b[i]) != 0) 847 return (TRUE); 848 return (FALSE); 849 } 850 /* 851 ** BITZEROP -- tell if a bitmap is all zero 852 ** 853 ** Parameters: 854 ** map -- the bit map to check 855 ** 856 ** Returns: 857 ** TRUE if map is all zero. 858 ** FALSE if there are any bits set in map. 859 ** 860 ** Side Effects: 861 ** none. 862 */ 863 864 bool 865 bitzerop(map) 866 BITMAP map; 867 { 868 int i; 869 870 for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) 871 if (map[i] != 0) 872 return (FALSE); 873 return (TRUE); 874 } 875