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