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