1 /* 2 * Copyright (c) 1983 Eric P. Allman 3 * Copyright (c) 1988 Regents of the University of California. 4 * All rights reserved. 5 * 6 * %sccs.include.redist.c% 7 */ 8 9 #ifndef lint 10 static char sccsid[] = "@(#)conf.c 6.54 (Berkeley) 05/11/93"; 11 #endif /* not lint */ 12 13 # include <sys/ioctl.h> 14 # include <sys/param.h> 15 # include <signal.h> 16 # include <pwd.h> 17 # include "sendmail.h" 18 # include "pathnames.h" 19 20 /* 21 ** CONF.C -- Sendmail Configuration Tables. 22 ** 23 ** Defines the configuration of this installation. 24 ** 25 ** Configuration Variables: 26 ** HdrInfo -- a table describing well-known header fields. 27 ** Each entry has the field name and some flags, 28 ** which are described in sendmail.h. 29 ** 30 ** Notes: 31 ** I have tried to put almost all the reasonable 32 ** configuration information into the configuration 33 ** file read at runtime. My intent is that anything 34 ** here is a function of the version of UNIX you 35 ** are running, or is really static -- for example 36 ** the headers are a superset of widely used 37 ** protocols. If you find yourself playing with 38 ** this file too much, you may be making a mistake! 39 */ 40 41 42 43 44 /* 45 ** Header info table 46 ** Final (null) entry contains the flags used for any other field. 47 ** 48 ** Not all of these are actually handled specially by sendmail 49 ** at this time. They are included as placeholders, to let 50 ** you know that "someday" I intend to have sendmail do 51 ** something with them. 52 */ 53 54 struct hdrinfo HdrInfo[] = 55 { 56 /* originator fields, most to least significant */ 57 "resent-sender", H_FROM|H_RESENT, 58 "resent-from", H_FROM|H_RESENT, 59 "resent-reply-to", H_FROM|H_RESENT, 60 "sender", H_FROM, 61 "from", H_FROM, 62 "reply-to", H_FROM, 63 "full-name", H_ACHECK, 64 "return-receipt-to", H_FROM /* |H_RECEIPTTO */, 65 "errors-to", H_FROM|H_ERRORSTO, 66 67 /* destination fields */ 68 "to", H_RCPT, 69 "resent-to", H_RCPT|H_RESENT, 70 "cc", H_RCPT, 71 "resent-cc", H_RCPT|H_RESENT, 72 "bcc", H_RCPT|H_ACHECK, 73 "resent-bcc", H_RCPT|H_ACHECK|H_RESENT, 74 "apparently-to", H_RCPT, 75 76 /* message identification and control */ 77 "message-id", 0, 78 "resent-message-id", H_RESENT, 79 "message", H_EOH, 80 "text", H_EOH, 81 82 /* date fields */ 83 "date", 0, 84 "resent-date", H_RESENT, 85 86 /* trace fields */ 87 "received", H_TRACE|H_FORCE, 88 "x400-received", H_TRACE|H_FORCE, 89 "via", H_TRACE|H_FORCE, 90 "mail-from", H_TRACE|H_FORCE, 91 92 /* miscellaneous fields */ 93 "comments", H_FORCE, 94 "return-path", H_ACHECK, 95 96 NULL, 0, 97 }; 98 99 100 101 /* 102 ** Location of system files/databases/etc. 103 */ 104 105 char *ConfFile = _PATH_SENDMAILCF; /* runtime configuration */ 106 char *FreezeFile = _PATH_SENDMAILFC; /* frozen version of above */ 107 char *PidFile = _PATH_SENDMAILPID; /* stores daemon proc id */ 108 109 110 111 /* 112 ** Privacy values 113 */ 114 115 struct prival PrivacyValues[] = 116 { 117 "public", PRIV_PUBLIC, 118 "needmailhelo", PRIV_NEEDMAILHELO, 119 "needexpnhelo", PRIV_NEEDEXPNHELO, 120 "needvrfyhelo", PRIV_NEEDVRFYHELO, 121 "noexpn", PRIV_NOEXPN, 122 "novrfy", PRIV_NOVRFY, 123 "restrictmailq", PRIV_RESTRMAILQ, 124 "authwarnings", PRIV_AUTHWARNINGS, 125 "goaway", PRIV_GOAWAY, 126 NULL, 0, 127 }; 128 129 130 131 /* 132 ** Miscellaneous stuff. 133 */ 134 135 int DtableSize = 50; /* max open files; reset in 4.2bsd */ 136 /* 137 ** SETDEFAULTS -- set default values 138 ** 139 ** Because of the way freezing is done, these must be initialized 140 ** using direct code. 141 ** 142 ** Parameters: 143 ** e -- the default envelope. 144 ** 145 ** Returns: 146 ** none. 147 ** 148 ** Side Effects: 149 ** Initializes a bunch of global variables to their 150 ** default values. 151 */ 152 153 #define DAYS * 24 * 60 * 60 154 155 setdefaults(e) 156 register ENVELOPE *e; 157 { 158 SpaceSub = ' '; /* option B */ 159 QueueLA = 8; /* option x */ 160 RefuseLA = 12; /* option X */ 161 WkRecipFact = 30000L; /* option y */ 162 WkClassFact = 1800L; /* option z */ 163 WkTimeFact = 90000L; /* option Z */ 164 QueueFactor = WkRecipFact * 20; /* option q */ 165 FileMode = (getuid() != geteuid()) ? 0644 : 0600; 166 /* option F */ 167 DefUid = 1; /* option u */ 168 DefGid = 1; /* option g */ 169 CheckpointInterval = 10; /* option C */ 170 MaxHopCount = 25; /* option h */ 171 e->e_sendmode = SM_FORK; /* option d */ 172 e->e_errormode = EM_PRINT; /* option e */ 173 SevenBit = FALSE; /* option 7 */ 174 MaxMciCache = 1; /* option k */ 175 MciCacheTimeout = 300; /* option K */ 176 LogLevel = 9; /* option L */ 177 settimeouts(NULL); /* option r */ 178 TimeOuts.to_q_return = 5 DAYS; /* option T */ 179 TimeOuts.to_q_warning = 0; /* option T */ 180 PrivacyFlags = 0; /* option p */ 181 setdefuser(); 182 setupaliases(); 183 setupmaps(); 184 setupmailers(); 185 } 186 187 188 /* 189 ** SETDEFUSER -- set/reset DefUser using DefUid (for initgroups()) 190 */ 191 192 setdefuser() 193 { 194 struct passwd *defpwent; 195 static char defuserbuf[40]; 196 197 DefUser = defuserbuf; 198 if ((defpwent = getpwuid(DefUid)) != NULL) 199 strcpy(defuserbuf, defpwent->pw_name); 200 else 201 strcpy(defuserbuf, "nobody"); 202 } 203 /* 204 ** SETUPMAPS -- set up map classes 205 ** 206 ** Since these are compiled in, they cannot be in the config file. 207 ** 208 */ 209 210 setupmaps() 211 { 212 register STAB *s; 213 214 /* host name lookup map */ 215 { 216 extern bool host_map_init(); 217 extern char *maphostname(); 218 219 s = stab("host", ST_MAPCLASS, ST_ENTER); 220 s->s_mapclass.map_init = host_map_init; 221 s->s_mapclass.map_lookup = maphostname; 222 } 223 224 /* dequote map */ 225 { 226 extern bool dequote_init(); 227 extern char *dequote_map(); 228 229 s = stab("dequote", ST_MAPCLASS, ST_ENTER); 230 s->s_mapclass.map_init = dequote_init; 231 s->s_mapclass.map_lookup = dequote_map; 232 } 233 234 # ifdef DBM_MAP 235 /* dbm file access */ 236 { 237 extern bool dbm_map_init(); 238 extern char *dbm_map_lookup(); 239 240 s = stab("dbm", ST_MAPCLASS, ST_ENTER); 241 s->s_mapclass.map_init = dbm_map_init; 242 s->s_mapclass.map_lookup = dbm_map_lookup; 243 } 244 # endif 245 246 # ifdef BTREE_MAP 247 /* new database file access -- btree files */ 248 { 249 extern bool bt_map_init(); 250 extern char *db_map_lookup(); 251 252 s = stab("btree", ST_MAPCLASS, ST_ENTER); 253 s->s_mapclass.map_init = bt_map_init; 254 s->s_mapclass.map_lookup = db_map_lookup; 255 } 256 # endif 257 258 # ifdef HASH_MAP 259 /* new database file access -- hash files */ 260 { 261 extern bool hash_map_init(); 262 extern char *db_map_lookup(); 263 264 s = stab("hash", ST_MAPCLASS, ST_ENTER); 265 s->s_mapclass.map_init = hash_map_init; 266 s->s_mapclass.map_lookup = db_map_lookup; 267 } 268 # endif 269 270 # ifdef NIS_MAP 271 /* NIS map access */ 272 { 273 extern bool nis_map_init(); 274 extern char *nis_map_lookup(); 275 276 s = stab("nis", ST_MAPCLASS, ST_ENTER); 277 s->s_mapclass.map_init = nis_map_init; 278 s->s_mapclass.map_lookup = nis_map_lookup; 279 } 280 # endif 281 282 # ifdef USERDB_MAP 283 /* user database */ 284 { 285 extern bool udb_map_init(); 286 extern char *udb_map_lookup(); 287 288 s = stab("udb", ST_MAPCLASS, ST_ENTER); 289 s->s_mapclass.map_init = udb_map_init; 290 s->s_mapclass.map_lookup = udb_map_lookup; 291 } 292 # endif 293 } 294 /* 295 ** HOST_MAP_INIT -- initialize host class structures 296 */ 297 298 bool 299 host_map_init(map, mapname, args) 300 MAP *map; 301 char *mapname; 302 char *args; 303 { 304 register char *p = args; 305 306 for (;;) 307 { 308 while (isascii(*p) && isspace(*p)) 309 p++; 310 if (*p != '-') 311 break; 312 switch (*++p) 313 { 314 case 'a': 315 map->map_app = ++p; 316 break; 317 } 318 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 319 p++; 320 if (*p != '\0') 321 *p++ = '\0'; 322 } 323 if (map->map_app != NULL) 324 map->map_app = newstr(map->map_app); 325 return TRUE; 326 } 327 /* 328 ** SETUPMAILERS -- initialize default mailers 329 */ 330 331 setupmailers() 332 { 333 char buf[100]; 334 335 strcpy(buf, "prog, P=/bin/sh, F=lsD, A=sh -c $u"); 336 makemailer(buf); 337 338 strcpy(buf, "*file*, P=/dev/null, F=lsDFMPEu, A=FILE"); 339 makemailer(buf); 340 341 strcpy(buf, "*include*, P=/dev/null, F=su, A=INCLUDE"); 342 makemailer(buf); 343 } 344 /* 345 ** GETRUID -- get real user id (V7) 346 */ 347 348 getruid() 349 { 350 if (OpMode == MD_DAEMON) 351 return (RealUid); 352 else 353 return (getuid()); 354 } 355 356 357 /* 358 ** GETRGID -- get real group id (V7). 359 */ 360 361 getrgid() 362 { 363 if (OpMode == MD_DAEMON) 364 return (RealGid); 365 else 366 return (getgid()); 367 } 368 /* 369 ** USERNAME -- return the user id of the logged in user. 370 ** 371 ** Parameters: 372 ** none. 373 ** 374 ** Returns: 375 ** The login name of the logged in user. 376 ** 377 ** Side Effects: 378 ** none. 379 ** 380 ** Notes: 381 ** The return value is statically allocated. 382 */ 383 384 char * 385 username() 386 { 387 static char *myname = NULL; 388 extern char *getlogin(); 389 register struct passwd *pw; 390 391 /* cache the result */ 392 if (myname == NULL) 393 { 394 myname = getlogin(); 395 if (myname == NULL || myname[0] == '\0') 396 { 397 pw = getpwuid(getruid()); 398 if (pw != NULL) 399 myname = newstr(pw->pw_name); 400 } 401 else 402 { 403 uid_t uid = getuid(); 404 405 myname = newstr(myname); 406 if ((pw = getpwnam(myname)) == NULL || 407 (uid != 0 && uid != pw->pw_uid)) 408 { 409 pw = getpwuid(uid); 410 if (pw != NULL) 411 myname = newstr(pw->pw_name); 412 } 413 } 414 if (myname == NULL || myname[0] == '\0') 415 { 416 syserr("554 Who are you?"); 417 myname = "postmaster"; 418 } 419 } 420 421 return (myname); 422 } 423 /* 424 ** TTYPATH -- Get the path of the user's tty 425 ** 426 ** Returns the pathname of the user's tty. Returns NULL if 427 ** the user is not logged in or if s/he has write permission 428 ** denied. 429 ** 430 ** Parameters: 431 ** none 432 ** 433 ** Returns: 434 ** pathname of the user's tty. 435 ** NULL if not logged in or write permission denied. 436 ** 437 ** Side Effects: 438 ** none. 439 ** 440 ** WARNING: 441 ** Return value is in a local buffer. 442 ** 443 ** Called By: 444 ** savemail 445 */ 446 447 char * 448 ttypath() 449 { 450 struct stat stbuf; 451 register char *pathn; 452 extern char *ttyname(); 453 extern char *getlogin(); 454 455 /* compute the pathname of the controlling tty */ 456 if ((pathn = ttyname(2)) == NULL && (pathn = ttyname(1)) == NULL && 457 (pathn = ttyname(0)) == NULL) 458 { 459 errno = 0; 460 return (NULL); 461 } 462 463 /* see if we have write permission */ 464 if (stat(pathn, &stbuf) < 0 || !bitset(02, stbuf.st_mode)) 465 { 466 errno = 0; 467 return (NULL); 468 } 469 470 /* see if the user is logged in */ 471 if (getlogin() == NULL) 472 return (NULL); 473 474 /* looks good */ 475 return (pathn); 476 } 477 /* 478 ** CHECKCOMPAT -- check for From and To person compatible. 479 ** 480 ** This routine can be supplied on a per-installation basis 481 ** to determine whether a person is allowed to send a message. 482 ** This allows restriction of certain types of internet 483 ** forwarding or registration of users. 484 ** 485 ** If the hosts are found to be incompatible, an error 486 ** message should be given using "usrerr" and 0 should 487 ** be returned. 488 ** 489 ** 'NoReturn' can be set to suppress the return-to-sender 490 ** function; this should be done on huge messages. 491 ** 492 ** Parameters: 493 ** to -- the person being sent to. 494 ** 495 ** Returns: 496 ** an exit status 497 ** 498 ** Side Effects: 499 ** none (unless you include the usrerr stuff) 500 */ 501 502 checkcompat(to, e) 503 register ADDRESS *to; 504 register ENVELOPE *e; 505 { 506 # ifdef lint 507 if (to == NULL) 508 to++; 509 # endif lint 510 # ifdef EXAMPLE_CODE 511 /* this code is intended as an example only */ 512 register STAB *s; 513 514 s = stab("arpa", ST_MAILER, ST_FIND); 515 if (s != NULL && e->e_from.q_mailer != LocalMailer && 516 to->q_mailer == s->s_mailer) 517 { 518 usrerr("553 No ARPA mail through this machine: see your system administration"); 519 /* NoReturn = TRUE; to supress return copy */ 520 return (EX_UNAVAILABLE); 521 } 522 # endif /* EXAMPLE_CODE */ 523 return (EX_OK); 524 } 525 /* 526 ** HOLDSIGS -- arrange to hold all signals 527 ** 528 ** Parameters: 529 ** none. 530 ** 531 ** Returns: 532 ** none. 533 ** 534 ** Side Effects: 535 ** Arranges that signals are held. 536 */ 537 538 holdsigs() 539 { 540 } 541 /* 542 ** RLSESIGS -- arrange to release all signals 543 ** 544 ** This undoes the effect of holdsigs. 545 ** 546 ** Parameters: 547 ** none. 548 ** 549 ** Returns: 550 ** none. 551 ** 552 ** Side Effects: 553 ** Arranges that signals are released. 554 */ 555 556 rlsesigs() 557 { 558 } 559 /* 560 ** GETLA -- get the current load average 561 ** 562 ** This code stolen from la.c. 563 ** 564 ** Parameters: 565 ** none. 566 ** 567 ** Returns: 568 ** The current load average as an integer. 569 ** 570 ** Side Effects: 571 ** none. 572 */ 573 574 /* try to guess what style of load average we have */ 575 #define LA_ZERO 1 /* always return load average as zero */ 576 #define LA_INT 2 /* read kmem for avenrun; interpret as int */ 577 #define LA_FLOAT 3 /* read kmem for avenrun; interpret as float */ 578 #define LA_SUBR 4 /* call getloadavg */ 579 580 #ifndef LA_TYPE 581 # if defined(sun) 582 # define LA_TYPE LA_INT 583 # endif 584 # if defined(mips) || defined(__alpha) 585 /* Ultrix or OSF/1 or RISC/os */ 586 # define LA_TYPE LA_INT 587 # define LA_AVENRUN "avenrun" 588 # endif 589 # if defined(__hpux) 590 # define LA_TYPE LA_FLOAT 591 # define LA_AVENRUN "avenrun" 592 # endif 593 594 # ifndef LA_TYPE 595 # if defined(SYSTEM5) 596 # define LA_TYPE LA_INT 597 # define LA_AVENRUN "avenrun" 598 # else 599 # if defined(BSD) 600 # define LA_TYPE LA_SUBR 601 # else 602 # define LA_TYPE LA_ZERO 603 # endif 604 # endif 605 # endif 606 #endif 607 608 #if (LA_TYPE == LA_INT) || (LA_TYPE == LA_FLOAT) 609 610 #include <nlist.h> 611 612 #ifndef LA_AVENRUN 613 #define LA_AVENRUN "_avenrun" 614 #endif 615 616 /* _PATH_UNIX should be defined in <paths.h> */ 617 #ifndef _PATH_UNIX 618 # if defined(__hpux) 619 # define _PATH_UNIX "/hp-ux" 620 # endif 621 # if defined(mips) && !defined(ultrix) 622 /* powerful RISC/os */ 623 # define _PATH_UNIX "/unix" 624 # endif 625 # if defined(SYSTEM5) 626 # ifndef _PATH_UNIX 627 # define _PATH_UNIX "/unix" 628 # endif 629 # endif 630 # ifndef _PATH_UNIX 631 # define _PATH_UNIX "/vmunix" 632 # endif 633 #endif 634 635 struct nlist Nl[] = 636 { 637 { LA_AVENRUN }, 638 #define X_AVENRUN 0 639 { 0 }, 640 }; 641 642 #if defined(unixpc) 643 # define FSHIFT 5 644 #endif 645 646 #if defined(__alpha) 647 # define FSHIFT 10 648 #endif 649 650 #if (LA_TYPE == LA_INT) && !defined(FSHIFT) 651 # define FSHIFT 8 652 #endif 653 #if (LA_TYPE == LA_INT) && !defined(FSCALE) 654 # define FSCALE (1 << FSHIFT) 655 #endif 656 657 getla() 658 { 659 static int kmem = -1; 660 #if LA_TYPE == LA_INT 661 long avenrun[3]; 662 #else 663 double avenrun[3]; 664 #endif 665 extern off_t lseek(); 666 extern char *errstring(); 667 extern int errno; 668 669 if (kmem < 0) 670 { 671 kmem = open("/dev/kmem", 0, 0); 672 if (kmem < 0) 673 { 674 if (tTd(3, 1)) 675 printf("getla: open(/dev/kmem): %s\n", 676 errstring(errno)); 677 return (-1); 678 } 679 (void) fcntl(kmem, F_SETFD, 1); 680 if (nlist(_PATH_UNIX, Nl) < 0) 681 { 682 if (tTd(3, 1)) 683 printf("getla: nlist(%s): %s\n", _PATH_UNIX, 684 errstring(errno)); 685 return (-1); 686 } 687 if (Nl[X_AVENRUN].n_value == 0) 688 { 689 if (tTd(3, 1)) 690 printf("getla: nlist(%s, %s) ==> 0\n", 691 _PATH_UNIX, LA_AVENRUN); 692 return (-1); 693 } 694 } 695 if (tTd(3, 20)) 696 printf("getla: symbol address = %#x\n", Nl[X_AVENRUN].n_value); 697 if (lseek(kmem, (off_t) Nl[X_AVENRUN].n_value, 0) == -1 || 698 read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun)) 699 { 700 /* thank you Ian */ 701 if (tTd(3, 1)) 702 printf("getla: lseek or read: %s\n", errstring(errno)); 703 return (-1); 704 } 705 #if LA_TYPE == LA_INT 706 if (tTd(3, 5)) 707 { 708 printf("getla: avenrun = %d", avenrun[0]); 709 if (tTd(3, 15)) 710 printf(", %d, %d", avenrun[1], avenrun[2]); 711 printf("\n"); 712 } 713 if (tTd(3, 1)) 714 printf("getla: %d\n", (int) (avenrun[0] + FSCALE/2) >> FSHIFT); 715 return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT); 716 #else 717 if (tTd(3, 5)) 718 { 719 printf("getla: avenrun = %g", avenrun[0]); 720 if (tTd(3, 15)) 721 printf(", %g, %g", avenrun[1], avenrun[2]); 722 printf("\n"); 723 } 724 if (tTd(3, 1)) 725 printf("getla: %d\n", (int) (avenrun[0] +0.5)); 726 return ((int) (avenrun[0] + 0.5)); 727 #endif 728 } 729 730 #else 731 #if LA_TYPE == LA_SUBR 732 733 getla() 734 { 735 double avenrun[3]; 736 737 if (getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])) < 0) 738 { 739 if (tTd(3, 1)) 740 perror("getla: getloadavg failed:"); 741 return (-1); 742 } 743 if (tTd(3, 1)) 744 printf("getla: %d\n", (int) (avenrun[0] +0.5)); 745 return ((int) (avenrun[0] + 0.5)); 746 } 747 748 #else 749 750 getla() 751 { 752 if (tTd(3, 1)) 753 printf("getla: ZERO\n"); 754 return (0); 755 } 756 757 #endif 758 #endif 759 /* 760 ** SHOULDQUEUE -- should this message be queued or sent? 761 ** 762 ** Compares the message cost to the load average to decide. 763 ** 764 ** Parameters: 765 ** pri -- the priority of the message in question. 766 ** ctime -- the message creation time. 767 ** 768 ** Returns: 769 ** TRUE -- if this message should be queued up for the 770 ** time being. 771 ** FALSE -- if the load is low enough to send this message. 772 ** 773 ** Side Effects: 774 ** none. 775 */ 776 777 bool 778 shouldqueue(pri, ctime) 779 long pri; 780 time_t ctime; 781 { 782 if (CurrentLA < QueueLA) 783 return (FALSE); 784 if (CurrentLA >= RefuseLA) 785 return (TRUE); 786 return (pri > (QueueFactor / (CurrentLA - QueueLA + 1))); 787 } 788 /* 789 ** REFUSECONNECTIONS -- decide if connections should be refused 790 ** 791 ** Parameters: 792 ** none. 793 ** 794 ** Returns: 795 ** TRUE if incoming SMTP connections should be refused 796 ** (for now). 797 ** FALSE if we should accept new work. 798 ** 799 ** Side Effects: 800 ** none. 801 */ 802 803 bool 804 refuseconnections() 805 { 806 #ifdef XLA 807 if (!xla_smtp_ok()) 808 return TRUE; 809 #endif 810 811 /* this is probably too simplistic */ 812 return (CurrentLA >= RefuseLA); 813 } 814 /* 815 ** SETPROCTITLE -- set process title for ps 816 ** 817 ** Parameters: 818 ** fmt -- a printf style format string. 819 ** a, b, c -- possible parameters to fmt. 820 ** 821 ** Returns: 822 ** none. 823 ** 824 ** Side Effects: 825 ** Clobbers argv of our main procedure so ps(1) will 826 ** display the title. 827 */ 828 829 #ifdef SETPROCTITLE 830 # ifdef __hpux 831 # include <sys/pstat.h> 832 # endif 833 # ifdef BSD4_4 834 # include <machine/vmparam.h> 835 # include <sys/exec.h> 836 # define SETPROC_STATIC static 837 # endif 838 # ifndef SETPROC_STATIC 839 # define SETPROC_STATIC 840 # endif 841 #endif 842 843 /*VARARGS1*/ 844 #ifdef __STDC__ 845 setproctitle(char *fmt, ...) 846 #else 847 setproctitle(fmt, va_alist) 848 char *fmt; 849 va_dcl 850 #endif 851 { 852 # ifdef SETPROCTITLE 853 register char *p; 854 register int i; 855 SETPROC_STATIC char buf[MAXLINE]; 856 VA_LOCAL_DECL 857 # ifdef __hpux 858 union pstun pst; 859 # endif 860 extern char **Argv; 861 extern char *LastArgv; 862 863 p = buf; 864 865 /* print sendmail: heading for grep */ 866 (void) strcpy(p, "sendmail: "); 867 p += strlen(p); 868 869 /* print the argument string */ 870 VA_START(fmt); 871 (void) vsprintf(p, fmt, ap); 872 VA_END; 873 874 i = strlen(buf); 875 876 # ifdef __hpux 877 pst.pst_command = buf; 878 pstat(PSTAT_SETCMD, pst, i, 0, 0); 879 # else 880 # ifdef BSD4_4 881 PS_STRINGS->ps_nargvstr = 1; 882 PS_STRINGS->ps_argvstr = buf; 883 # else 884 if (i > LastArgv - Argv[0] - 2) 885 { 886 i = LastArgv - Argv[0] - 2; 887 buf[i] = '\0'; 888 } 889 (void) strcpy(Argv[0], buf); 890 p = &Argv[0][i]; 891 while (p < LastArgv) 892 *p++ = ' '; 893 # endif 894 # endif 895 # endif /* SETPROCTITLE */ 896 } 897 /* 898 ** REAPCHILD -- pick up the body of my child, lest it become a zombie 899 ** 900 ** Parameters: 901 ** none. 902 ** 903 ** Returns: 904 ** none. 905 ** 906 ** Side Effects: 907 ** Picks up extant zombies. 908 */ 909 910 # include <sys/wait.h> 911 912 void 913 reapchild() 914 { 915 # ifdef WNOHANG 916 union wait status; 917 918 while (wait3((int *)&status, WNOHANG, (struct rusage *) NULL) > 0) 919 continue; 920 # else /* WNOHANG */ 921 auto int status; 922 923 while (wait((int *)&status) > 0) 924 continue; 925 # endif /* WNOHANG */ 926 # ifdef SYSTEM5 927 (void) signal(SIGCHLD, reapchild); 928 # endif 929 } 930 /* 931 ** UNSETENV -- remove a variable from the environment 932 ** 933 ** Not needed on newer systems. 934 ** 935 ** Parameters: 936 ** name -- the string name of the environment variable to be 937 ** deleted from the current environment. 938 ** 939 ** Returns: 940 ** none. 941 ** 942 ** Globals: 943 ** environ -- a pointer to the current environment. 944 ** 945 ** Side Effects: 946 ** Modifies environ. 947 */ 948 949 #ifdef UNSETENV 950 951 void 952 unsetenv(name) 953 char *name; 954 { 955 extern char **environ; 956 register char **pp; 957 int len = strlen(name); 958 959 for (pp = environ; *pp != NULL; pp++) 960 { 961 if (strncmp(name, *pp, len) == 0 && 962 ((*pp)[len] == '=' || (*pp)[len] == '\0')) 963 break; 964 } 965 966 for (; *pp != NULL; pp++) 967 *pp = pp[1]; 968 } 969 970 #endif /* UNSETENV */ 971 /* 972 ** GETDTABLESIZE -- return number of file descriptors 973 ** 974 ** Only on non-BSD systems 975 ** 976 ** Parameters: 977 ** none 978 ** 979 ** Returns: 980 ** size of file descriptor table 981 ** 982 ** Side Effects: 983 ** none 984 */ 985 986 #ifdef SYSTEM5 987 988 int 989 getdtablesize() 990 { 991 # ifdef _SC_OPEN_MAX 992 return sysconf(_SC_OPEN_MAX); 993 # else 994 return NOFILE; 995 # endif 996 } 997 998 #endif 999 /* 1000 ** UNAME -- get the UUCP name of this system. 1001 */ 1002 1003 #ifndef HASUNAME 1004 1005 int 1006 uname(name) 1007 struct utsname *name; 1008 { 1009 FILE *file; 1010 char *n; 1011 1012 name->nodename[0] = '\0'; 1013 1014 /* try /etc/whoami -- one line with the node name */ 1015 if ((file = fopen("/etc/whoami", "r")) != NULL) 1016 { 1017 (void) fgets(name->nodename, NODE_LENGTH + 1, file); 1018 (void) fclose(file); 1019 n = strchr(name->nodename, '\n'); 1020 if (n != NULL) 1021 *n = '\0'; 1022 if (name->nodename[0] != '\0') 1023 return (0); 1024 } 1025 1026 /* try /usr/include/whoami.h -- has a #define somewhere */ 1027 if ((file = fopen("/usr/include/whoami.h", "r")) != NULL) 1028 { 1029 char buf[MAXLINE]; 1030 1031 while (fgets(buf, MAXLINE, file) != NULL) 1032 if (sscanf(buf, "#define sysname \"%*[^\"]\"", 1033 NODE_LENGTH, name->nodename) > 0) 1034 break; 1035 (void) fclose(file); 1036 if (name->nodename[0] != '\0') 1037 return (0); 1038 } 1039 1040 #ifdef TRUST_POPEN 1041 /* 1042 ** Popen is known to have security holes. 1043 */ 1044 1045 /* try uuname -l to return local name */ 1046 if ((file = popen("uuname -l", "r")) != NULL) 1047 { 1048 (void) fgets(name, NODE_LENGTH + 1, file); 1049 (void) pclose(file); 1050 n = strchr(name, '\n'); 1051 if (n != NULL) 1052 *n = '\0'; 1053 if (name->nodename[0] != '\0') 1054 return (0); 1055 } 1056 #endif 1057 1058 return (-1); 1059 } 1060 #endif /* HASUNAME */ 1061 /* 1062 ** INITGROUPS -- initialize groups 1063 ** 1064 ** Stub implementation for System V style systems 1065 */ 1066 1067 #ifndef HASINITGROUPS 1068 # if !defined(SYSTEM5) || defined(__hpux) 1069 # define HASINITGROUPS 1070 # endif 1071 #endif 1072 1073 #ifndef HASINITGROUPS 1074 1075 initgroups(name, basegid) 1076 char *name; 1077 int basegid; 1078 { 1079 return 0; 1080 } 1081 1082 #endif 1083 /* 1084 ** SETSID -- set session id (for non-POSIX systems) 1085 */ 1086 1087 #ifndef HASSETSID 1088 1089 setsid() 1090 { 1091 # ifdef SYSTEM5 1092 setpgrp(); 1093 # endif 1094 } 1095 1096 #endif 1097 /* 1098 ** ENOUGHSPACE -- check to see if there is enough free space on the queue fs 1099 ** 1100 ** Only implemented if you have statfs. 1101 ** 1102 ** Parameters: 1103 ** msize -- the size to check against. If zero, we don't yet 1104 ** know how big the message will be, so just check for 1105 ** a "reasonable" amount. 1106 ** 1107 ** Returns: 1108 ** TRUE if there is enough space. 1109 ** FALSE otherwise. 1110 */ 1111 1112 #ifndef HASSTATFS 1113 # if defined(BSD4_4) || defined(__osf__) 1114 # define HASSTATFS 1115 # endif 1116 #endif 1117 1118 #ifdef HASSTATFS 1119 # undef HASUSTAT 1120 #endif 1121 1122 #if defined(HASUSTAT) 1123 # include <ustat.h> 1124 #endif 1125 1126 #ifdef HASSTATFS 1127 # if defined(sgi) || defined(apollo) 1128 # include <sys/statfs.h> 1129 # else 1130 # if defined(sun) || defined(__hpux) 1131 # include <sys/vfs.h> 1132 # else 1133 # include <sys/mount.h> 1134 # endif 1135 # endif 1136 #endif 1137 1138 bool 1139 enoughspace(msize) 1140 long msize; 1141 { 1142 #if defined(HASSTATFS) || defined(HASUSTAT) 1143 # if defined(HASUSTAT) 1144 struct ustat fs; 1145 struct stat statbuf; 1146 # define FSBLOCKSIZE DEV_BSIZE 1147 # define f_bavail f_tfree 1148 # else 1149 # if defined(ultrix) 1150 struct fs_data fs; 1151 # define f_bavail fd_bfreen 1152 # define FSBLOCKSIZE fs.fd_bsize 1153 # else 1154 struct statfs fs; 1155 # define FSBLOCKSIZE fs.f_bsize 1156 # endif 1157 # endif 1158 long blocksneeded; 1159 extern int errno; 1160 extern char *errstring(); 1161 1162 if (MinBlocksFree <= 0 && msize <= 0) 1163 { 1164 if (tTd(4, 80)) 1165 printf("enoughspace: no threshold\n"); 1166 return TRUE; 1167 } 1168 1169 # if defined(HASUSTAT) 1170 if (stat(QueueDir, &statbuf) == 0 && ustat(statbuf.st_dev, &fs) == 0) 1171 # else 1172 # if defined(sgi) || defined(apollo) 1173 if (statfs(QueueDir, &fs, sizeof fs, 0) == 0) 1174 # else 1175 # if defined(ultrix) 1176 if (statfs(QueueDir, &fs) > 0) 1177 # else 1178 if (statfs(QueueDir, &fs) == 0) 1179 # endif 1180 # endif 1181 # endif 1182 { 1183 if (tTd(4, 80)) 1184 printf("enoughspace: bavail=%ld, need=%ld\n", 1185 fs.f_bavail, msize); 1186 1187 /* convert msize to block count */ 1188 msize = msize / FSBLOCKSIZE + 1; 1189 if (MinBlocksFree >= 0) 1190 msize += MinBlocksFree; 1191 1192 if (fs.f_bavail < msize) 1193 { 1194 #ifdef LOG 1195 if (LogLevel > 0) 1196 syslog(LOG_ALERT, "%s: low on space (have %ld, need %ld)", 1197 QueueDir, fs.f_bavail, msize); 1198 #endif 1199 return FALSE; 1200 } 1201 } 1202 else if (tTd(4, 80)) 1203 printf("enoughspace failure: min=%ld, need=%ld: %s\n", 1204 MinBlocksFree, msize, errstring(errno)); 1205 #endif 1206 return TRUE; 1207 } 1208 /* 1209 ** TRANSIENTERROR -- tell if an error code indicates a transient failure 1210 ** 1211 ** This looks at an errno value and tells if this is likely to 1212 ** go away if retried later. 1213 ** 1214 ** Parameters: 1215 ** err -- the errno code to classify. 1216 ** 1217 ** Returns: 1218 ** TRUE if this is probably transient. 1219 ** FALSE otherwise. 1220 */ 1221 1222 bool 1223 transienterror(err) 1224 int err; 1225 { 1226 switch (err) 1227 { 1228 case EIO: /* I/O error */ 1229 case ENXIO: /* Device not configured */ 1230 case EAGAIN: /* Resource temporarily unavailable */ 1231 case ENOMEM: /* Cannot allocate memory */ 1232 case ENODEV: /* Operation not supported by device */ 1233 case ENFILE: /* Too many open files in system */ 1234 case EMFILE: /* Too many open files */ 1235 case ENOSPC: /* No space left on device */ 1236 #ifdef ETIMEDOUT 1237 case ETIMEDOUT: /* Connection timed out */ 1238 #endif 1239 #ifdef ESTALE 1240 case ESTALE: /* Stale NFS file handle */ 1241 #endif 1242 #ifdef ENETDOWN 1243 case ENETDOWN: /* Network is down */ 1244 #endif 1245 #ifdef ENETUNREACH 1246 case ENETUNREACH: /* Network is unreachable */ 1247 #endif 1248 #ifdef ENETRESET 1249 case ENETRESET: /* Network dropped connection on reset */ 1250 #endif 1251 #ifdef ECONNABORTED 1252 case ECONNABORTED: /* Software caused connection abort */ 1253 #endif 1254 #ifdef ECONNRESET 1255 case ECONNRESET: /* Connection reset by peer */ 1256 #endif 1257 #ifdef ENOBUFS 1258 case ENOBUFS: /* No buffer space available */ 1259 #endif 1260 #ifdef ESHUTDOWN 1261 case ESHUTDOWN: /* Can't send after socket shutdown */ 1262 #endif 1263 #ifdef ECONNREFUSED 1264 case ECONNREFUSED: /* Connection refused */ 1265 #endif 1266 #ifdef EHOSTDOWN 1267 case EHOSTDOWN: /* Host is down */ 1268 #endif 1269 #ifdef EHOSTUNREACH 1270 case EHOSTUNREACH: /* No route to host */ 1271 #endif 1272 #ifdef EDQUOT 1273 case EDQUOT: /* Disc quota exceeded */ 1274 #endif 1275 #ifdef EPROCLIM 1276 case EPROCLIM: /* Too many processes */ 1277 #endif 1278 #ifdef EUSERS 1279 case EUSERS: /* Too many users */ 1280 #endif 1281 #ifdef EDEADLK 1282 case EDEADLK: /* Resource deadlock avoided */ 1283 #endif 1284 #ifdef EISCONN 1285 case EISCONN: /* Socket already connected */ 1286 #endif 1287 #ifdef EINPROGRESS 1288 case EINPROGRESS: /* Operation now in progress */ 1289 #endif 1290 #ifdef EALREADY 1291 case EALREADY: /* Operation already in progress */ 1292 #endif 1293 #ifdef EADDRINUSE 1294 case EADDRINUSE: /* Address already in use */ 1295 #endif 1296 #ifdef EADDRNOTAVAIL 1297 case EADDRNOTAVAIL: /* Can't assign requested address */ 1298 #endif 1299 #ifdef ENOSR 1300 case ENOSR: /* Out of streams resources */ 1301 #endif 1302 return TRUE; 1303 } 1304 1305 /* nope, must be permanent */ 1306 return FALSE; 1307 } 1308 /* 1309 ** LOCKFILE -- lock a file using flock or (shudder) lockf 1310 ** 1311 ** Parameters: 1312 ** fd -- the file descriptor of the file. 1313 ** filename -- the file name (for error messages). 1314 ** type -- type of the lock. Bits can be: 1315 ** LOCK_EX -- exclusive lock. 1316 ** LOCK_NB -- non-blocking. 1317 ** 1318 ** Returns: 1319 ** TRUE if the lock was acquired. 1320 ** FALSE otherwise. 1321 */ 1322 1323 bool 1324 lockfile(fd, filename, type) 1325 int fd; 1326 char *filename; 1327 int type; 1328 { 1329 # ifdef LOCKF 1330 int action; 1331 struct flock lfd; 1332 1333 if (bitset(LOCK_UN, type)) 1334 lfd.l_type = F_UNLCK; 1335 else if (bitset(LOCK_EX, type)) 1336 lfd.l_type = F_WRLCK; 1337 else 1338 lfd.l_type = F_RDLCK; 1339 1340 if (bitset(LOCK_NB, type)) 1341 action = F_SETLK; 1342 else 1343 action = F_SETLKW; 1344 1345 lfd.l_whence = lfd.l_start = lfd.l_len = 0; 1346 1347 if (fcntl(fd, action, &lfd) >= 0) 1348 return TRUE; 1349 1350 if (!bitset(LOCK_NB, type) || (errno != EACCES && errno != EAGAIN)) 1351 syserr("cannot lockf(%s, %o)", filename, type); 1352 # else 1353 if (flock(fd, type) >= 0) 1354 return TRUE; 1355 1356 if (!bitset(LOCK_NB, type) || errno != EWOULDBLOCK) 1357 syserr("cannot flock(%s, %o)", filename, type); 1358 # endif 1359 return FALSE; 1360 } 1361