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 3.42 02/02/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 return (FALSE); 427 } 428 /* 429 ** FIXCRLF -- fix <CR><LF> in line. 430 ** 431 ** Looks for the <CR><LF> combination and turns it into the 432 ** UNIX canonical <NL> character. It only takes one line, 433 ** i.e., it is assumed that the first <NL> found is the end 434 ** of the line. 435 ** 436 ** Parameters: 437 ** line -- the line to fix. 438 ** stripnl -- if true, strip the newline also. 439 ** 440 ** Returns: 441 ** none. 442 ** 443 ** Side Effects: 444 ** line is changed in place. 445 */ 446 447 fixcrlf(line, stripnl) 448 char *line; 449 bool stripnl; 450 { 451 register char *p; 452 453 p = index(line, '\n'); 454 if (p == NULL) 455 return; 456 if (p[-1] == '\r') 457 p--; 458 if (!stripnl) 459 *p++ = '\n'; 460 *p = '\0'; 461 } 462 /* 463 ** SYSLOG -- fake entry to fool lint 464 */ 465 466 # ifdef LOG 467 # ifdef lint 468 469 /*VARARGS2*/ 470 syslog(pri, fmt, args) 471 int pri; 472 char *fmt; 473 { 474 pri = *fmt; 475 args = pri; 476 pri = args; 477 } 478 479 # endif lint 480 # endif LOG 481 /* 482 ** DFOPEN -- determined file open 483 ** 484 ** This routine has the semantics of fopen, except that it will 485 ** keep trying a few times to make this happen. The idea is that 486 ** on very loaded systems, we may run out of resources (inodes, 487 ** whatever), so this tries to get around it. 488 */ 489 490 FILE * 491 dfopen(filename, mode) 492 char *filename; 493 char *mode; 494 { 495 register int tries; 496 register FILE *fp; 497 498 for (tries = 0; tries < 10; tries++) 499 { 500 sleep(10 * tries); 501 errno = 0; 502 fp = fopen(filename, mode); 503 if (fp != NULL) 504 break; 505 if (errno != ENFILE && errno != EINTR) 506 break; 507 } 508 return (fp); 509 } 510 /* 511 ** PUTLINE -- put a line like fputs obeying SMTP conventions 512 ** 513 ** This routine always guarantees outputing a newline (or CRLF, 514 ** as appropriate) at the end of the string. 515 ** 516 ** Parameters: 517 ** l -- line to put. 518 ** fp -- file to put it onto. 519 ** m -- the mailer used to control output. 520 ** 521 ** Returns: 522 ** none 523 ** 524 ** Side Effects: 525 ** output of l to fp. 526 */ 527 528 # define SMTPLINELIM 990 /* maximum line length */ 529 530 putline(l, fp, m) 531 register char *l; 532 FILE *fp; 533 MAILER *m; 534 { 535 register char *p; 536 char svchar; 537 538 do 539 { 540 /* find the end of the line */ 541 p = index(l, '\n'); 542 if (p == NULL) 543 p = &l[strlen(l)]; 544 545 /* check for line overflow */ 546 while (bitnset(M_LIMITS, m->m_flags) && (p - l) > SMTPLINELIM) 547 { 548 register char *q = &l[SMTPLINELIM - 1]; 549 550 svchar = *q; 551 *q = '\0'; 552 if (l[0] == '.' && bitnset(M_XDOT, m->m_flags)) 553 fputc('.', fp); 554 fputs(l, fp); 555 fputc('!', fp); 556 fputs(m->m_eol, fp); 557 *q = svchar; 558 l = q; 559 } 560 561 /* output last part */ 562 svchar = *p; 563 *p = '\0'; 564 if (l[0] == '.' && bitnset(M_XDOT, m->m_flags)) 565 fputc('.', fp); 566 fputs(l, fp); 567 fputs(m->m_eol, fp); 568 *p = svchar; 569 l = p; 570 if (*l == '\n') 571 l++; 572 } while (l[0] != '\0'); 573 } 574 /* 575 ** XUNLINK -- unlink a file, doing logging as appropriate. 576 ** 577 ** Parameters: 578 ** f -- name of file to unlink. 579 ** 580 ** Returns: 581 ** none. 582 ** 583 ** Side Effects: 584 ** f is unlinked. 585 */ 586 587 xunlink(f) 588 char *f; 589 { 590 register int i; 591 592 # ifdef LOG 593 if (LogLevel > 20) 594 syslog(LOG_DEBUG, "%s: unlink %s\n", CurEnv->e_id, f); 595 # endif LOG 596 597 i = unlink(f); 598 # ifdef LOG 599 if (i < 0 && LogLevel > 21) 600 syslog(LOG_DEBUG, "%s: unlink-fail %d", f, errno); 601 # endif LOG 602 } 603 /* 604 ** SFGETS -- "safe" fgets -- times out. 605 ** 606 ** Parameters: 607 ** buf -- place to put the input line. 608 ** siz -- size of buf. 609 ** fp -- file to read from. 610 ** 611 ** Returns: 612 ** NULL on error (including timeout). 613 ** buf otherwise. 614 ** 615 ** Side Effects: 616 ** none. 617 */ 618 619 static bool TimeoutFlag; 620 621 char * 622 sfgets(buf, siz, fp) 623 char *buf; 624 int siz; 625 FILE *fp; 626 { 627 register EVENT *ev = NULL; 628 register char *p; 629 extern readtimeout(); 630 631 if (ReadTimeout != 0) 632 ev = setevent(ReadTimeout, readtimeout, 0); 633 TimeoutFlag = FALSE; 634 do 635 { 636 errno = 0; 637 p = fgets(buf, siz, fp); 638 } while (!(p != NULL || TimeoutFlag || errno != EINTR)); 639 clrevent(ev); 640 LineNumber++; 641 if (TimeoutFlag) 642 syserr("sfgets: timeout on read (mailer may be hung)"); 643 return (p); 644 } 645 646 static 647 readtimeout() 648 { 649 TimeoutFlag = TRUE; 650 } 651 /* 652 ** FGETFOLDED -- like fgets, but know about folded lines. 653 ** 654 ** Parameters: 655 ** buf -- place to put result. 656 ** n -- bytes available. 657 ** f -- file to read from. 658 ** 659 ** Returns: 660 ** buf on success, NULL on error or EOF. 661 ** 662 ** Side Effects: 663 ** buf gets lines from f, with continuation lines (lines 664 ** with leading white space) appended. CRLF's are mapped 665 ** into single newlines. Any trailing NL is stripped. 666 */ 667 668 char * 669 fgetfolded(buf, n, f) 670 char *buf; 671 register int n; 672 FILE *f; 673 { 674 register char *p = buf; 675 register int i; 676 677 n--; 678 while (fgets(p, n, f) != NULL) 679 { 680 LineNumber++; 681 fixcrlf(p, TRUE); 682 i = fgetc(f); 683 if (i != EOF) 684 ungetc(i, f); 685 if (i != ' ' && i != '\t') 686 return (buf); 687 i = strlen(p); 688 p += i; 689 *p++ = '\n'; 690 n -= i + 1; 691 } 692 return (NULL); 693 } 694 /* 695 ** CURTIME -- return current time. 696 ** 697 ** Parameters: 698 ** none. 699 ** 700 ** Returns: 701 ** the current time. 702 ** 703 ** Side Effects: 704 ** none. 705 */ 706 707 time_t 708 curtime() 709 { 710 auto time_t t; 711 712 (void) time(&t); 713 return (t); 714 } 715 /* 716 ** ATOBOOL -- convert a string representation to boolean. 717 ** 718 ** Defaults to "TRUE" 719 ** 720 ** Parameters: 721 ** s -- string to convert. Takes "tTyY" as true, 722 ** others as false. 723 ** 724 ** Returns: 725 ** A boolean representation of the string. 726 ** 727 ** Side Effects: 728 ** none. 729 */ 730 731 bool 732 atobool(s) 733 register char *s; 734 { 735 if (*s == '\0' || index("tTyY", *s) != NULL) 736 return (TRUE); 737 return (FALSE); 738 } 739 /* 740 ** ATOOCT -- convert a string representation to octal. 741 ** 742 ** Parameters: 743 ** s -- string to convert. 744 ** 745 ** Returns: 746 ** An integer representing the string interpreted as an 747 ** octal number. 748 ** 749 ** Side Effects: 750 ** none. 751 */ 752 753 atooct(s) 754 register char *s; 755 { 756 register int i = 0; 757 758 while (*s >= '0' && *s <= '7') 759 i = (i << 3) | (*s++ - '0'); 760 return (i); 761 } 762 /* 763 ** WAITFOR -- wait for a particular process id. 764 ** 765 ** Parameters: 766 ** pid -- process id to wait for. 767 ** 768 ** Returns: 769 ** status of pid. 770 ** -1 if pid never shows up. 771 ** 772 ** Side Effects: 773 ** none. 774 */ 775 776 waitfor(pid) 777 int pid; 778 { 779 auto int st; 780 int i; 781 782 do 783 { 784 errno = 0; 785 i = wait(&st); 786 } while ((i >= 0 || errno == EINTR) && i != pid); 787 if (i < 0) 788 st = -1; 789 return (st); 790 } 791 /* 792 ** CLOSEALL -- close all extraneous file descriptors 793 ** 794 ** Parameters: 795 ** none. 796 ** 797 ** Returns: 798 ** none. 799 ** 800 ** Side Effects: 801 ** Closes all file descriptors except zero, one, and two. 802 */ 803 804 closeall() 805 { 806 int i; 807 808 for (i = 3; i < 50; i++) 809 (void) close(i); 810 } 811 /* 812 ** BITINTERSECT -- tell if two bitmaps intersect 813 ** 814 ** Parameters: 815 ** a, b -- the bitmaps in question 816 ** 817 ** Returns: 818 ** TRUE if they have a non-null intersection 819 ** FALSE otherwise 820 ** 821 ** Side Effects: 822 ** none. 823 */ 824 825 bool 826 bitintersect(a, b) 827 BITMAP a; 828 BITMAP b; 829 { 830 int i; 831 832 for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) 833 if ((a[i] & b[i]) != 0) 834 return (TRUE); 835 return (FALSE); 836 } 837 /* 838 ** BITZEROP -- tell if a bitmap is all zero 839 ** 840 ** Parameters: 841 ** map -- the bit map to check 842 ** 843 ** Returns: 844 ** TRUE if map is all zero. 845 ** FALSE if there are any bits set in map. 846 ** 847 ** Side Effects: 848 ** none. 849 */ 850 851 bool 852 bitzerop(map) 853 BITMAP map; 854 { 855 int i; 856 857 for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) 858 if (map[i] != 0) 859 return (FALSE); 860 return (TRUE); 861 } 862