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.40 01/09/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 exit(EX_UNAVAILABLE); 140 } 141 return (p); 142 } 143 /* 144 ** COPYPLIST -- copy list of pointers. 145 ** 146 ** This routine is the equivalent of newstr for lists of 147 ** pointers. 148 ** 149 ** Parameters: 150 ** list -- list of pointers to copy. 151 ** Must be NULL terminated. 152 ** copycont -- if TRUE, copy the contents of the vector 153 ** (which must be a string) also. 154 ** 155 ** Returns: 156 ** a copy of 'list'. 157 ** 158 ** Side Effects: 159 ** none. 160 */ 161 162 char ** 163 copyplist(list, copycont) 164 char **list; 165 bool copycont; 166 { 167 register char **vp; 168 register char **newvp; 169 170 for (vp = list; *vp != NULL; vp++) 171 continue; 172 173 vp++; 174 175 newvp = (char **) xalloc((vp - list) * sizeof *vp); 176 bmove((char *) list, (char *) newvp, (vp - list) * sizeof *vp); 177 178 if (copycont) 179 { 180 for (vp = newvp; *vp != NULL; vp++) 181 *vp = newstr(*vp); 182 } 183 184 return (newvp); 185 } 186 /* 187 ** PRINTAV -- print argument vector. 188 ** 189 ** Parameters: 190 ** av -- argument vector. 191 ** 192 ** Returns: 193 ** none. 194 ** 195 ** Side Effects: 196 ** prints av. 197 */ 198 199 # ifdef DEBUG 200 printav(av) 201 register char **av; 202 { 203 while (*av != NULL) 204 { 205 if (tTd(0, 44)) 206 printf("\n\t%08x=", *av); 207 else 208 putchar(' '); 209 xputs(*av++); 210 } 211 putchar('\n'); 212 } 213 # endif DEBUG 214 /* 215 ** LOWER -- turn letter into lower case. 216 ** 217 ** Parameters: 218 ** c -- character to turn into lower case. 219 ** 220 ** Returns: 221 ** c, in lower case. 222 ** 223 ** Side Effects: 224 ** none. 225 */ 226 227 char 228 lower(c) 229 register char c; 230 { 231 if (isascii(c) && isupper(c)) 232 c = c - 'A' + 'a'; 233 return (c); 234 } 235 /* 236 ** XPUTS -- put string doing control escapes. 237 ** 238 ** Parameters: 239 ** s -- string to put. 240 ** 241 ** Returns: 242 ** none. 243 ** 244 ** Side Effects: 245 ** output to stdout 246 */ 247 248 # ifdef DEBUG 249 xputs(s) 250 register char *s; 251 { 252 register char c; 253 254 if (s == NULL) 255 { 256 printf("<null>"); 257 return; 258 } 259 putchar('"'); 260 while ((c = *s++) != '\0') 261 { 262 if (!isascii(c)) 263 { 264 putchar('\\'); 265 c &= 0177; 266 } 267 if (iscntrl(c)) 268 { 269 putchar('^'); 270 c |= 0100; 271 } 272 putchar(c); 273 } 274 putchar('"'); 275 (void) fflush(stdout); 276 } 277 # endif DEBUG 278 /* 279 ** MAKELOWER -- Translate a line into lower case 280 ** 281 ** Parameters: 282 ** p -- the string to translate. If NULL, return is 283 ** immediate. 284 ** 285 ** Returns: 286 ** none. 287 ** 288 ** Side Effects: 289 ** String pointed to by p is translated to lower case. 290 ** 291 ** Called By: 292 ** parse 293 */ 294 295 makelower(p) 296 register char *p; 297 { 298 register char c; 299 300 if (p == NULL) 301 return; 302 for (; (c = *p) != '\0'; p++) 303 if (isascii(c) && isupper(c)) 304 *p = c - 'A' + 'a'; 305 } 306 /* 307 ** SAMEWORD -- return TRUE if the words are the same 308 ** 309 ** Ignores case. 310 ** 311 ** Parameters: 312 ** a, b -- the words to compare. 313 ** 314 ** Returns: 315 ** TRUE if a & b match exactly (modulo case) 316 ** FALSE otherwise. 317 ** 318 ** Side Effects: 319 ** none. 320 */ 321 322 bool 323 sameword(a, b) 324 register char *a, *b; 325 { 326 while (lower(*a) == lower(*b)) 327 { 328 if (*a == '\0') 329 return (TRUE); 330 a++; 331 b++; 332 } 333 return (FALSE); 334 } 335 /* 336 ** CLEAR -- clear a block of memory 337 ** 338 ** Parameters: 339 ** p -- location to clear. 340 ** l -- number of bytes to clear. 341 ** 342 ** Returns: 343 ** none. 344 ** 345 ** Side Effects: 346 ** none. 347 */ 348 349 clear(p, l) 350 register char *p; 351 register int l; 352 { 353 while (l-- > 0) 354 *p++ = 0; 355 } 356 /* 357 ** BUILDFNAME -- build full name from gecos style entry. 358 ** 359 ** This routine interprets the strange entry that would appear 360 ** in the GECOS field of the password file. 361 ** 362 ** Parameters: 363 ** p -- name to build. 364 ** login -- the login name of this user (for &). 365 ** buf -- place to put the result. 366 ** 367 ** Returns: 368 ** none. 369 ** 370 ** Side Effects: 371 ** none. 372 */ 373 374 buildfname(p, login, buf) 375 register char *p; 376 char *login; 377 char *buf; 378 { 379 register char *bp = buf; 380 381 if (*p == '*') 382 p++; 383 while (*p != '\0' && *p != ',' && *p != ';' && *p != '%') 384 { 385 if (*p == '&') 386 { 387 (void) strcpy(bp, login); 388 *bp = toupper(*bp); 389 while (*bp != '\0') 390 bp++; 391 p++; 392 } 393 else 394 *bp++ = *p++; 395 } 396 *bp = '\0'; 397 } 398 /* 399 ** SAFEFILE -- return true if a file exists and is safe for a user. 400 ** 401 ** Parameters: 402 ** fn -- filename to check. 403 ** uid -- uid to compare against. 404 ** mode -- mode bits that must match. 405 ** 406 ** Returns: 407 ** TRUE if fn exists, is owned by uid, and matches mode. 408 ** FALSE otherwise. 409 ** 410 ** Side Effects: 411 ** none. 412 */ 413 414 bool 415 safefile(fn, uid, mode) 416 char *fn; 417 int uid; 418 int mode; 419 { 420 struct stat stbuf; 421 422 if (stat(fn, &stbuf) >= 0 && stbuf.st_uid == uid && 423 (stbuf.st_mode & mode) == mode) 424 return (TRUE); 425 return (FALSE); 426 } 427 /* 428 ** FIXCRLF -- fix <CR><LF> in line. 429 ** 430 ** Looks for the <CR><LF> combination and turns it into the 431 ** UNIX canonical <NL> character. It only takes one line, 432 ** i.e., it is assumed that the first <NL> found is the end 433 ** of the line. 434 ** 435 ** Parameters: 436 ** line -- the line to fix. 437 ** stripnl -- if true, strip the newline also. 438 ** 439 ** Returns: 440 ** none. 441 ** 442 ** Side Effects: 443 ** line is changed in place. 444 */ 445 446 fixcrlf(line, stripnl) 447 char *line; 448 bool stripnl; 449 { 450 register char *p; 451 452 p = index(line, '\n'); 453 if (p == NULL) 454 return; 455 if (p[-1] == '\r') 456 p--; 457 if (!stripnl) 458 *p++ = '\n'; 459 *p = '\0'; 460 } 461 /* 462 ** SYSLOG -- fake entry to fool lint 463 */ 464 465 # ifdef LOG 466 # ifdef lint 467 468 /*VARARGS2*/ 469 syslog(pri, fmt, args) 470 int pri; 471 char *fmt; 472 { 473 pri = *fmt; 474 args = pri; 475 pri = args; 476 } 477 478 # endif lint 479 # endif LOG 480 /* 481 ** DFOPEN -- determined file open 482 ** 483 ** This routine has the semantics of fopen, except that it will 484 ** keep trying a few times to make this happen. The idea is that 485 ** on very loaded systems, we may run out of resources (inodes, 486 ** whatever), so this tries to get around it. 487 */ 488 489 FILE * 490 dfopen(filename, mode) 491 char *filename; 492 char *mode; 493 { 494 register int tries; 495 register FILE *fp; 496 497 for (tries = 0; tries < 10; tries++) 498 { 499 sleep(10 * tries); 500 errno = 0; 501 fp = fopen(filename, mode); 502 if (fp != NULL) 503 break; 504 if (errno != ENFILE && errno != EINTR) 505 break; 506 } 507 return (fp); 508 } 509 /* 510 ** PUTLINE -- put a line like fputs obeying SMTP conventions 511 ** 512 ** This routine always guarantees outputing a newline (or CRLF, 513 ** as appropriate) at the end of the string. 514 ** 515 ** Parameters: 516 ** l -- line to put. 517 ** fp -- file to put it onto. 518 ** m -- the mailer used to control output. 519 ** 520 ** Returns: 521 ** none 522 ** 523 ** Side Effects: 524 ** output of l to fp. 525 */ 526 527 # define SMTPLINELIM 990 /* maximum line length */ 528 529 putline(l, fp, m) 530 register char *l; 531 FILE *fp; 532 MAILER *m; 533 { 534 register char *p; 535 char svchar; 536 537 do 538 { 539 /* find the end of the line */ 540 p = index(l, '\n'); 541 if (p == NULL) 542 p = &l[strlen(l)]; 543 544 /* check for line overflow */ 545 while (bitset(M_LIMITS, m->m_flags) && (p - l) > SMTPLINELIM) 546 { 547 register char *q = &l[SMTPLINELIM - 1]; 548 549 svchar = *q; 550 *q = '\0'; 551 if (l[0] == '.' && bitset(M_XDOT, m->m_flags)) 552 fputc('.', fp); 553 fputs(l, fp); 554 fputc('!', fp); 555 fputs(crlf(m), fp); 556 *q = svchar; 557 l = q; 558 } 559 560 /* output last part */ 561 svchar = *p; 562 *p = '\0'; 563 if (l[0] == '.' && bitset(M_XDOT, m->m_flags)) 564 fputc('.', fp); 565 fputs(l, fp); 566 fputs(crlf(m), fp); 567 *p = svchar; 568 l = p; 569 if (*l == '\n') 570 l++; 571 } while (l[0] != '\0'); 572 } 573 /* 574 ** XUNLINK -- unlink a file, doing logging as appropriate. 575 ** 576 ** Parameters: 577 ** f -- name of file to unlink. 578 ** 579 ** Returns: 580 ** none. 581 ** 582 ** Side Effects: 583 ** f is unlinked. 584 */ 585 586 xunlink(f) 587 char *f; 588 { 589 register int i; 590 591 # ifdef LOG 592 if (LogLevel > 20) 593 syslog(LOG_DEBUG, "%s: unlink %s\n", CurEnv->e_id, f); 594 # endif LOG 595 596 i = unlink(f); 597 # ifdef LOG 598 if (i < 0 && LogLevel > 21) 599 syslog(LOG_DEBUG, "%s: unlink-fail %d", f, errno); 600 # endif LOG 601 } 602 /* 603 ** SFGETS -- "safe" fgets -- times out. 604 ** 605 ** Parameters: 606 ** buf -- place to put the input line. 607 ** siz -- size of buf. 608 ** fp -- file to read from. 609 ** 610 ** Returns: 611 ** NULL on error (including timeout). 612 ** buf otherwise. 613 ** 614 ** Side Effects: 615 ** none. 616 */ 617 618 static bool TimeoutFlag; 619 620 char * 621 sfgets(buf, siz, fp) 622 char *buf; 623 int siz; 624 FILE *fp; 625 { 626 register EVENT *ev = NULL; 627 register char *p; 628 extern readtimeout(); 629 630 if (ReadTimeout != 0) 631 ev = setevent(ReadTimeout, readtimeout, 0); 632 TimeoutFlag = FALSE; 633 do 634 { 635 errno = 0; 636 p = fgets(buf, siz, fp); 637 } while (!(p != NULL || TimeoutFlag || errno != EINTR)); 638 clrevent(ev); 639 LineNumber++; 640 if (TimeoutFlag) 641 syserr("sfgets: timeout on read (mailer may be hung)"); 642 return (p); 643 } 644 645 static 646 readtimeout() 647 { 648 TimeoutFlag = TRUE; 649 } 650 /* 651 ** FGETFOLDED -- like fgets, but know about folded lines. 652 ** 653 ** Parameters: 654 ** buf -- place to put result. 655 ** n -- bytes available. 656 ** f -- file to read from. 657 ** 658 ** Returns: 659 ** buf on success, NULL on error or EOF. 660 ** 661 ** Side Effects: 662 ** buf gets lines from f, with continuation lines (lines 663 ** with leading white space) appended. CRLF's are mapped 664 ** into single newlines. Any trailing NL is stripped. 665 */ 666 667 char * 668 fgetfolded(buf, n, f) 669 char *buf; 670 register int n; 671 FILE *f; 672 { 673 register char *p = buf; 674 register int i; 675 676 n--; 677 while (fgets(p, n, f) != NULL) 678 { 679 LineNumber++; 680 fixcrlf(p, TRUE); 681 i = fgetc(f); 682 if (i != EOF) 683 ungetc(i, f); 684 if (i != ' ' && i != '\t') 685 return (buf); 686 i = strlen(p); 687 p += i; 688 *p++ = '\n'; 689 n -= i + 1; 690 } 691 return (NULL); 692 } 693 /* 694 ** CURTIME -- return current time. 695 ** 696 ** Parameters: 697 ** none. 698 ** 699 ** Returns: 700 ** the current time. 701 ** 702 ** Side Effects: 703 ** none. 704 */ 705 706 time_t 707 curtime() 708 { 709 auto time_t t; 710 711 (void) time(&t); 712 return (t); 713 } 714 /* 715 ** ATOBOOL -- convert a string representation to boolean. 716 ** 717 ** Defaults to "TRUE" 718 ** 719 ** Parameters: 720 ** s -- string to convert. Takes "tTyY" as true, 721 ** others as false. 722 ** 723 ** Returns: 724 ** A boolean representation of the string. 725 ** 726 ** Side Effects: 727 ** none. 728 */ 729 730 bool 731 atobool(s) 732 register char *s; 733 { 734 if (*s == '\0' || index("tTyY", *s) != NULL) 735 return (TRUE); 736 return (FALSE); 737 } 738 /* 739 ** ATOOCT -- convert a string representation to octal. 740 ** 741 ** Parameters: 742 ** s -- string to convert. 743 ** 744 ** Returns: 745 ** An integer representing the string interpreted as an 746 ** octal number. 747 ** 748 ** Side Effects: 749 ** none. 750 */ 751 752 atooct(s) 753 register char *s; 754 { 755 register int i = 0; 756 757 while (*s >= '0' && *s <= '7') 758 i = (i << 3) | (*s++ - '0'); 759 return (i); 760 } 761 /* 762 ** WAITFOR -- wait for a particular process id. 763 ** 764 ** Parameters: 765 ** pid -- process id to wait for. 766 ** 767 ** Returns: 768 ** status of pid. 769 ** -1 if pid never shows up. 770 ** 771 ** Side Effects: 772 ** none. 773 */ 774 775 waitfor(pid) 776 int pid; 777 { 778 auto int st; 779 int i; 780 781 do 782 { 783 errno = 0; 784 i = wait(&st); 785 } while ((i >= 0 || errno == EINTR) && i != pid); 786 if (i < 0) 787 st = -1; 788 return (st); 789 } 790 /* 791 ** CLOSEALL -- close all extraneous file descriptors 792 ** 793 ** Parameters: 794 ** none. 795 ** 796 ** Returns: 797 ** none. 798 ** 799 ** Side Effects: 800 ** Closes all file descriptors except zero, one, and two. 801 */ 802 803 closeall() 804 { 805 int i; 806 807 for (i = 3; i < 50; i++) 808 (void) close(i); 809 } 810