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