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.76 (Berkeley) 02/14/94"; 11 #endif /* not lint */ 12 13 # include "sendmail.h" 14 # include "pathnames.h" 15 # include <sys/ioctl.h> 16 # include <sys/param.h> 17 # include <netdb.h> 18 # include <pwd.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 *PidFile = _PATH_SENDMAILPID; /* stores daemon proc id */ 106 107 108 109 /* 110 ** Privacy values 111 */ 112 113 struct prival PrivacyValues[] = 114 { 115 "public", PRIV_PUBLIC, 116 "needmailhelo", PRIV_NEEDMAILHELO, 117 "needexpnhelo", PRIV_NEEDEXPNHELO, 118 "needvrfyhelo", PRIV_NEEDVRFYHELO, 119 "noexpn", PRIV_NOEXPN, 120 "novrfy", PRIV_NOVRFY, 121 "restrictmailq", PRIV_RESTRICTMAILQ, 122 "restrictqrun", PRIV_RESTRICTQRUN, 123 "authwarnings", PRIV_AUTHWARNINGS, 124 "goaway", PRIV_GOAWAY, 125 NULL, 0, 126 }; 127 128 129 130 /* 131 ** Miscellaneous stuff. 132 */ 133 134 int DtableSize = 50; /* max open files; reset in 4.2bsd */ 135 136 137 /* 138 ** Following should be config parameters (and probably will be in 139 ** future releases). In the meantime, setting these is considered 140 ** unsupported, and is intentionally undocumented. 141 */ 142 143 #ifdef BROKENSMTPPEERS 144 bool BrokenSmtpPeers = TRUE; /* set if you have broken SMTP peers */ 145 #else 146 bool BrokenSmtpPeers = FALSE; /* set if you have broken SMTP peers */ 147 #endif 148 #ifdef NOLOOPBACKCHECK 149 bool CheckLoopBack = FALSE; /* set to check HELO loopback */ 150 #else 151 bool CheckLoopBack = TRUE; /* set to check HELO loopback */ 152 #endif 153 154 /* 155 ** SETDEFAULTS -- set default values 156 ** 157 ** Because of the way freezing is done, these must be initialized 158 ** using direct code. 159 ** 160 ** Parameters: 161 ** e -- the default envelope. 162 ** 163 ** Returns: 164 ** none. 165 ** 166 ** Side Effects: 167 ** Initializes a bunch of global variables to their 168 ** default values. 169 */ 170 171 #define DAYS * 24 * 60 * 60 172 173 setdefaults(e) 174 register ENVELOPE *e; 175 { 176 SpaceSub = ' '; /* option B */ 177 QueueLA = 8; /* option x */ 178 RefuseLA = 12; /* option X */ 179 WkRecipFact = 30000L; /* option y */ 180 WkClassFact = 1800L; /* option z */ 181 WkTimeFact = 90000L; /* option Z */ 182 QueueFactor = WkRecipFact * 20; /* option q */ 183 FileMode = (RealUid != geteuid()) ? 0644 : 0600; 184 /* option F */ 185 DefUid = 1; /* option u */ 186 DefGid = 1; /* option g */ 187 CheckpointInterval = 10; /* option C */ 188 MaxHopCount = 25; /* option h */ 189 e->e_sendmode = SM_FORK; /* option d */ 190 e->e_errormode = EM_PRINT; /* option e */ 191 SevenBit = FALSE; /* option 7 */ 192 MaxMciCache = 1; /* option k */ 193 MciCacheTimeout = 300; /* option K */ 194 LogLevel = 9; /* option L */ 195 settimeouts(NULL); /* option r */ 196 TimeOuts.to_q_return = 5 DAYS; /* option T */ 197 TimeOuts.to_q_warning = 0; /* option T */ 198 PrivacyFlags = 0; /* option p */ 199 setdefuser(); 200 setupmaps(); 201 setupmailers(); 202 } 203 204 205 /* 206 ** SETDEFUSER -- set/reset DefUser using DefUid (for initgroups()) 207 */ 208 209 setdefuser() 210 { 211 struct passwd *defpwent; 212 static char defuserbuf[40]; 213 214 DefUser = defuserbuf; 215 if ((defpwent = getpwuid(DefUid)) != NULL) 216 strcpy(defuserbuf, defpwent->pw_name); 217 else 218 strcpy(defuserbuf, "nobody"); 219 } 220 /* 221 ** HOST_MAP_INIT -- initialize host class structures 222 */ 223 224 bool 225 host_map_init(map, args) 226 MAP *map; 227 char *args; 228 { 229 register char *p = args; 230 231 for (;;) 232 { 233 while (isascii(*p) && isspace(*p)) 234 p++; 235 if (*p != '-') 236 break; 237 switch (*++p) 238 { 239 case 'a': 240 map->map_app = ++p; 241 break; 242 } 243 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 244 p++; 245 if (*p != '\0') 246 *p++ = '\0'; 247 } 248 if (map->map_app != NULL) 249 map->map_app = newstr(map->map_app); 250 return TRUE; 251 } 252 /* 253 ** SETUPMAILERS -- initialize default mailers 254 */ 255 256 setupmailers() 257 { 258 char buf[100]; 259 260 strcpy(buf, "prog, P=/bin/sh, F=lsD, A=sh -c $u"); 261 makemailer(buf); 262 263 strcpy(buf, "*file*, P=/dev/null, F=lsDFMPEu, A=FILE"); 264 makemailer(buf); 265 266 strcpy(buf, "*include*, P=/dev/null, F=su, A=INCLUDE"); 267 makemailer(buf); 268 } 269 /* 270 ** SETUPMAPS -- set up map classes 271 */ 272 273 #define MAPDEF(name, ext, flags, parse, open, close, lookup, store) \ 274 { \ 275 extern bool parse __P((MAP *, char *)); \ 276 extern bool open __P((MAP *, int)); \ 277 extern void close __P((MAP *)); \ 278 extern char *lookup __P((MAP *, char *, char **, int *)); \ 279 extern void store __P((MAP *, char *, char *)); \ 280 s = stab(name, ST_MAPCLASS, ST_ENTER); \ 281 s->s_mapclass.map_cname = name; \ 282 s->s_mapclass.map_ext = ext; \ 283 s->s_mapclass.map_cflags = flags; \ 284 s->s_mapclass.map_parse = parse; \ 285 s->s_mapclass.map_open = open; \ 286 s->s_mapclass.map_close = close; \ 287 s->s_mapclass.map_lookup = lookup; \ 288 s->s_mapclass.map_store = store; \ 289 } 290 291 setupmaps() 292 { 293 register STAB *s; 294 295 #ifdef NEWDB 296 MAPDEF("hash", ".db", MCF_ALIASOK|MCF_REBUILDABLE, 297 map_parseargs, hash_map_open, db_map_close, 298 db_map_lookup, db_map_store); 299 MAPDEF("btree", ".db", MCF_ALIASOK|MCF_REBUILDABLE, 300 map_parseargs, bt_map_open, db_map_close, 301 db_map_lookup, db_map_store); 302 #endif 303 304 #ifdef NDBM 305 MAPDEF("dbm", ".dir", MCF_ALIASOK|MCF_REBUILDABLE, 306 map_parseargs, ndbm_map_open, ndbm_map_close, 307 ndbm_map_lookup, ndbm_map_store); 308 #endif 309 310 #ifdef NIS 311 MAPDEF("nis", NULL, MCF_ALIASOK, 312 map_parseargs, nis_map_open, nis_map_close, 313 nis_map_lookup, nis_map_store); 314 #endif 315 316 MAPDEF("stab", NULL, MCF_ALIASOK|MCF_ALIASONLY, 317 map_parseargs, stab_map_open, stab_map_close, 318 stab_map_lookup, stab_map_store); 319 320 MAPDEF("implicit", NULL, MCF_ALIASOK|MCF_ALIASONLY|MCF_REBUILDABLE, 321 map_parseargs, impl_map_open, impl_map_close, 322 impl_map_lookup, impl_map_store); 323 324 /* host DNS lookup */ 325 MAPDEF("host", NULL, 0, 326 host_map_init, null_map_open, null_map_close, 327 host_map_lookup, null_map_store); 328 329 /* dequote map */ 330 MAPDEF("dequote", NULL, 0, 331 dequote_init, null_map_open, null_map_close, 332 dequote_map, null_map_store); 333 334 #if 0 335 # ifdef USERDB 336 /* user database */ 337 MAPDEF("udb", ".db", 0, 338 udb_map_parse, null_map_open, null_map_close, 339 udb_map_lookup, null_map_store); 340 # endif 341 #endif 342 } 343 344 #undef MAPDEF 345 /* 346 ** USERNAME -- return the user id of the logged in user. 347 ** 348 ** Parameters: 349 ** none. 350 ** 351 ** Returns: 352 ** The login name of the logged in user. 353 ** 354 ** Side Effects: 355 ** none. 356 ** 357 ** Notes: 358 ** The return value is statically allocated. 359 */ 360 361 char * 362 username() 363 { 364 static char *myname = NULL; 365 extern char *getlogin(); 366 register struct passwd *pw; 367 368 /* cache the result */ 369 if (myname == NULL) 370 { 371 myname = getlogin(); 372 if (myname == NULL || myname[0] == '\0') 373 { 374 pw = getpwuid(RealUid); 375 if (pw != NULL) 376 myname = newstr(pw->pw_name); 377 } 378 else 379 { 380 uid_t uid = RealUid; 381 382 myname = newstr(myname); 383 if ((pw = getpwnam(myname)) == NULL || 384 (uid != 0 && uid != pw->pw_uid)) 385 { 386 pw = getpwuid(uid); 387 if (pw != NULL) 388 myname = newstr(pw->pw_name); 389 } 390 } 391 if (myname == NULL || myname[0] == '\0') 392 { 393 syserr("554 Who are you?"); 394 myname = "postmaster"; 395 } 396 } 397 398 return (myname); 399 } 400 /* 401 ** TTYPATH -- Get the path of the user's tty 402 ** 403 ** Returns the pathname of the user's tty. Returns NULL if 404 ** the user is not logged in or if s/he has write permission 405 ** denied. 406 ** 407 ** Parameters: 408 ** none 409 ** 410 ** Returns: 411 ** pathname of the user's tty. 412 ** NULL if not logged in or write permission denied. 413 ** 414 ** Side Effects: 415 ** none. 416 ** 417 ** WARNING: 418 ** Return value is in a local buffer. 419 ** 420 ** Called By: 421 ** savemail 422 */ 423 424 char * 425 ttypath() 426 { 427 struct stat stbuf; 428 register char *pathn; 429 extern char *ttyname(); 430 extern char *getlogin(); 431 432 /* compute the pathname of the controlling tty */ 433 if ((pathn = ttyname(2)) == NULL && (pathn = ttyname(1)) == NULL && 434 (pathn = ttyname(0)) == NULL) 435 { 436 errno = 0; 437 return (NULL); 438 } 439 440 /* see if we have write permission */ 441 if (stat(pathn, &stbuf) < 0 || !bitset(02, stbuf.st_mode)) 442 { 443 errno = 0; 444 return (NULL); 445 } 446 447 /* see if the user is logged in */ 448 if (getlogin() == NULL) 449 return (NULL); 450 451 /* looks good */ 452 return (pathn); 453 } 454 /* 455 ** CHECKCOMPAT -- check for From and To person compatible. 456 ** 457 ** This routine can be supplied on a per-installation basis 458 ** to determine whether a person is allowed to send a message. 459 ** This allows restriction of certain types of internet 460 ** forwarding or registration of users. 461 ** 462 ** If the hosts are found to be incompatible, an error 463 ** message should be given using "usrerr" and 0 should 464 ** be returned. 465 ** 466 ** 'NoReturn' can be set to suppress the return-to-sender 467 ** function; this should be done on huge messages. 468 ** 469 ** Parameters: 470 ** to -- the person being sent to. 471 ** 472 ** Returns: 473 ** an exit status 474 ** 475 ** Side Effects: 476 ** none (unless you include the usrerr stuff) 477 */ 478 479 checkcompat(to, e) 480 register ADDRESS *to; 481 register ENVELOPE *e; 482 { 483 # ifdef lint 484 if (to == NULL) 485 to++; 486 # endif /* lint */ 487 488 if (tTd(49, 1)) 489 printf("checkcompat(to=%s, from=%s)\n", 490 to->q_paddr, e->e_from.q_paddr); 491 492 # ifdef EXAMPLE_CODE 493 /* this code is intended as an example only */ 494 register STAB *s; 495 496 s = stab("arpa", ST_MAILER, ST_FIND); 497 if (s != NULL && e->e_from.q_mailer != LocalMailer && 498 to->q_mailer == s->s_mailer) 499 { 500 usrerr("553 No ARPA mail through this machine: see your system administration"); 501 /* NoReturn = TRUE; to supress return copy */ 502 return (EX_UNAVAILABLE); 503 } 504 # endif /* EXAMPLE_CODE */ 505 return (EX_OK); 506 } 507 /* 508 ** SETSIGNAL -- set a signal handler 509 ** 510 ** This is essentially old BSD "signal(3)". 511 */ 512 513 sigfunc_t 514 setsignal(sig, handler) 515 int sig; 516 sigfunc_t handler; 517 { 518 #if defined(SYS5SIGNALS) || defined(BSD4_3) || defined(_AUX_SOURCE) 519 return signal(sig, handler); 520 #else 521 struct sigaction n, o; 522 523 bzero(&n, sizeof n); 524 n.sa_handler = handler; 525 if (sigaction(sig, &n, &o) < 0) 526 return SIG_ERR; 527 return o.sa_handler; 528 #endif 529 } 530 /* 531 ** HOLDSIGS -- arrange to hold all signals 532 ** 533 ** Parameters: 534 ** none. 535 ** 536 ** Returns: 537 ** none. 538 ** 539 ** Side Effects: 540 ** Arranges that signals are held. 541 */ 542 543 holdsigs() 544 { 545 } 546 /* 547 ** RLSESIGS -- arrange to release all signals 548 ** 549 ** This undoes the effect of holdsigs. 550 ** 551 ** Parameters: 552 ** none. 553 ** 554 ** Returns: 555 ** none. 556 ** 557 ** Side Effects: 558 ** Arranges that signals are released. 559 */ 560 561 rlsesigs() 562 { 563 } 564 /* 565 ** INIT_MD -- do machine dependent initializations 566 ** 567 ** Systems that have global modes that should be set should do 568 ** them here rather than in main. 569 */ 570 571 #ifdef _AUX_SOURCE 572 # include <compat.h> 573 #endif 574 575 init_md(argc, argv) 576 int argc; 577 char **argv; 578 { 579 #ifdef _AUX_SOURCE 580 setcompat(getcompat() | COMPAT_BSDPROT); 581 #endif 582 } 583 /* 584 ** GETLA -- get the current load average 585 ** 586 ** This code stolen from la.c. 587 ** 588 ** Parameters: 589 ** none. 590 ** 591 ** Returns: 592 ** The current load average as an integer. 593 ** 594 ** Side Effects: 595 ** none. 596 */ 597 598 /* try to guess what style of load average we have */ 599 #define LA_ZERO 1 /* always return load average as zero */ 600 #define LA_INT 2 /* read kmem for avenrun; interpret as long */ 601 #define LA_FLOAT 3 /* read kmem for avenrun; interpret as float */ 602 #define LA_SUBR 4 /* call getloadavg */ 603 #define LA_MACH 5 /* MACH load averages (as on NeXT boxes) */ 604 #define LA_SHORT 6 /* read kmem for avenrun; interpret as short */ 605 606 /* do guesses based on general OS type */ 607 #ifndef LA_TYPE 608 # define LA_TYPE LA_ZERO 609 #endif 610 611 #if (LA_TYPE == LA_INT) || (LA_TYPE == LA_FLOAT) || (LA_TYPE == LA_SHORT) 612 613 #include <nlist.h> 614 615 #ifndef LA_AVENRUN 616 # ifdef SYSTEM5 617 # define LA_AVENRUN "avenrun" 618 # else 619 # define LA_AVENRUN "_avenrun" 620 # endif 621 #endif 622 623 /* _PATH_UNIX should be defined in <paths.h> */ 624 #ifndef _PATH_UNIX 625 # if defined(SYSTEM5) 626 # define _PATH_UNIX "/unix" 627 # else 628 # define _PATH_UNIX "/vmunix" 629 # endif 630 #endif 631 632 struct nlist Nl[] = 633 { 634 { LA_AVENRUN }, 635 #define X_AVENRUN 0 636 { 0 }, 637 }; 638 639 #ifndef FSHIFT 640 # if defined(unixpc) 641 # define FSHIFT 5 642 # endif 643 644 # if defined(__alpha) 645 # define FSHIFT 10 646 # endif 647 648 # if (LA_TYPE == LA_INT) || (LA_TYPE == LA_SHORT) 649 # define FSHIFT 8 650 # endif 651 #endif 652 653 #if ((LA_TYPE == LA_INT) || (LA_TYPE == LA_SHORT)) && !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 # if LA_TYPE == LA_SHORT 664 short avenrun[3]; 665 # else 666 double avenrun[3]; 667 # endif 668 #endif 669 extern off_t lseek(); 670 extern int errno; 671 672 if (kmem < 0) 673 { 674 kmem = open("/dev/kmem", 0, 0); 675 if (kmem < 0) 676 { 677 if (tTd(3, 1)) 678 printf("getla: open(/dev/kmem): %s\n", 679 errstring(errno)); 680 return (-1); 681 } 682 (void) fcntl(kmem, F_SETFD, 1); 683 if (nlist(_PATH_UNIX, Nl) < 0) 684 { 685 if (tTd(3, 1)) 686 printf("getla: nlist(%s): %s\n", _PATH_UNIX, 687 errstring(errno)); 688 return (-1); 689 } 690 if (Nl[X_AVENRUN].n_value == 0) 691 { 692 if (tTd(3, 1)) 693 printf("getla: nlist(%s, %s) ==> 0\n", 694 _PATH_UNIX, LA_AVENRUN); 695 return (-1); 696 } 697 } 698 if (tTd(3, 20)) 699 printf("getla: symbol address = %#x\n", Nl[X_AVENRUN].n_value); 700 if (lseek(kmem, (off_t) Nl[X_AVENRUN].n_value, 0) == -1 || 701 read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun)) 702 { 703 /* thank you Ian */ 704 if (tTd(3, 1)) 705 printf("getla: lseek or read: %s\n", errstring(errno)); 706 return (-1); 707 } 708 #if (LA_TYPE == LA_INT) || (LA_TYPE == LA_SHORT) 709 if (tTd(3, 5)) 710 { 711 printf("getla: avenrun = %d", avenrun[0]); 712 if (tTd(3, 15)) 713 printf(", %d, %d", avenrun[1], avenrun[2]); 714 printf("\n"); 715 } 716 if (tTd(3, 1)) 717 printf("getla: %d\n", (int) (avenrun[0] + FSCALE/2) >> FSHIFT); 718 return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT); 719 #else 720 if (tTd(3, 5)) 721 { 722 printf("getla: avenrun = %g", avenrun[0]); 723 if (tTd(3, 15)) 724 printf(", %g, %g", avenrun[1], avenrun[2]); 725 printf("\n"); 726 } 727 if (tTd(3, 1)) 728 printf("getla: %d\n", (int) (avenrun[0] +0.5)); 729 return ((int) (avenrun[0] + 0.5)); 730 #endif 731 } 732 733 #else 734 #if LA_TYPE == LA_SUBR 735 736 #ifdef DGUX 737 738 #include <sys/dg_sys_info.h> 739 740 int getla() 741 { 742 struct dg_sys_info_load_info load_info; 743 744 dg_sys_info((long *)&load_info, 745 DG_SYS_INFO_LOAD_INFO_TYPE, DG_SYS_INFO_LOAD_VERSION_0); 746 747 return((int) (load_info.one_minute + 0.5)); 748 } 749 750 #else 751 752 getla() 753 { 754 double avenrun[3]; 755 756 if (getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])) < 0) 757 { 758 if (tTd(3, 1)) 759 perror("getla: getloadavg failed:"); 760 return (-1); 761 } 762 if (tTd(3, 1)) 763 printf("getla: %d\n", (int) (avenrun[0] +0.5)); 764 return ((int) (avenrun[0] + 0.5)); 765 } 766 767 #endif /* DGUX */ 768 #else 769 #if LA_TYPE == LA_MACH 770 771 /* 772 ** This has been tested on NEXTSTEP release 2.1/3.X. 773 */ 774 775 #if defined(NX_CURRENT_COMPILER_RELEASE) && NX_CURRENT_COMPILER_RELEASE > NX_COMPILER_RELEASE_3_0 776 # include <mach/mach.h> 777 #else 778 # include <mach.h> 779 #endif 780 781 getla() 782 { 783 processor_set_t default_set; 784 kern_return_t error; 785 unsigned int info_count; 786 struct processor_set_basic_info info; 787 host_t host; 788 789 error = processor_set_default(host_self(), &default_set); 790 if (error != KERN_SUCCESS) 791 return -1; 792 info_count = PROCESSOR_SET_BASIC_INFO_COUNT; 793 if (processor_set_info(default_set, PROCESSOR_SET_BASIC_INFO, 794 &host, (processor_set_info_t)&info, 795 &info_count) != KERN_SUCCESS) 796 { 797 return -1; 798 } 799 return (int) (info.load_average + (LOAD_SCALE / 2)) / LOAD_SCALE; 800 } 801 802 803 #else 804 805 getla() 806 { 807 if (tTd(3, 1)) 808 printf("getla: ZERO\n"); 809 return (0); 810 } 811 812 #endif 813 #endif 814 #endif 815 816 817 /* 818 * Copyright 1989 Massachusetts Institute of Technology 819 * 820 * Permission to use, copy, modify, distribute, and sell this software and its 821 * documentation for any purpose is hereby granted without fee, provided that 822 * the above copyright notice appear in all copies and that both that 823 * copyright notice and this permission notice appear in supporting 824 * documentation, and that the name of M.I.T. not be used in advertising or 825 * publicity pertaining to distribution of the software without specific, 826 * written prior permission. M.I.T. makes no representations about the 827 * suitability of this software for any purpose. It is provided "as is" 828 * without express or implied warranty. 829 * 830 * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL 831 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T. 832 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 833 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 834 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 835 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 836 * 837 * Authors: Many and varied... 838 */ 839 840 /* Non Apollo stuff removed by Don Lewis 11/15/93 */ 841 #ifndef lint 842 static char rcsid[] = "@(#)$Id: getloadavg.c,v 1.16 1991/06/21 12:51:15 paul Exp $"; 843 #endif /* !lint */ 844 845 # ifdef apollo 846 # undef volatile 847 # include <apollo/base.h> 848 # include <apollo/time.h> 849 # include <sys/types.h> 850 851 /* ARGSUSED */ 852 int getloadavg( call_data ) 853 caddr_t call_data; /* pointer to (double) return value */ 854 { 855 double *avenrun = (double *) call_data; 856 int i; 857 status_$t st; 858 long loadav[3]; 859 proc1_$get_loadav(loadav, &st); 860 *avenrun = loadav[0] / (double) (1 << 16); 861 return(0); 862 } 863 # endif /* apollo */ 864 /* 865 ** SHOULDQUEUE -- should this message be queued or sent? 866 ** 867 ** Compares the message cost to the load average to decide. 868 ** 869 ** Parameters: 870 ** pri -- the priority of the message in question. 871 ** ctime -- the message creation time. 872 ** 873 ** Returns: 874 ** TRUE -- if this message should be queued up for the 875 ** time being. 876 ** FALSE -- if the load is low enough to send this message. 877 ** 878 ** Side Effects: 879 ** none. 880 */ 881 882 bool 883 shouldqueue(pri, ctime) 884 long pri; 885 time_t ctime; 886 { 887 if (CurrentLA < QueueLA) 888 return (FALSE); 889 if (CurrentLA >= RefuseLA) 890 return (TRUE); 891 return (pri > (QueueFactor / (CurrentLA - QueueLA + 1))); 892 } 893 /* 894 ** REFUSECONNECTIONS -- decide if connections should be refused 895 ** 896 ** Parameters: 897 ** none. 898 ** 899 ** Returns: 900 ** TRUE if incoming SMTP connections should be refused 901 ** (for now). 902 ** FALSE if we should accept new work. 903 ** 904 ** Side Effects: 905 ** none. 906 */ 907 908 bool 909 refuseconnections() 910 { 911 #ifdef XLA 912 if (!xla_smtp_ok()) 913 return TRUE; 914 #endif 915 916 /* this is probably too simplistic */ 917 return (CurrentLA >= RefuseLA); 918 } 919 /* 920 ** SETPROCTITLE -- set process title for ps 921 ** 922 ** Parameters: 923 ** fmt -- a printf style format string. 924 ** a, b, c -- possible parameters to fmt. 925 ** 926 ** Returns: 927 ** none. 928 ** 929 ** Side Effects: 930 ** Clobbers argv of our main procedure so ps(1) will 931 ** display the title. 932 */ 933 934 #ifdef SETPROCTITLE 935 # ifdef HASSETPROCTITLE 936 *** ERROR *** Cannot have both SETPROCTITLE and HASSETPROCTITLE defined 937 # endif 938 # ifdef __hpux 939 # include <sys/pstat.h> 940 # endif 941 # ifdef BSD4_4 942 # include <machine/vmparam.h> 943 # include <sys/exec.h> 944 # ifdef __bsdi__ 945 # undef PS_STRINGS /* BSDI 1.0 doesn't do PS_STRINGS as we expect */ 946 # define PROCTITLEPAD '\0' 947 # endif 948 # ifdef PS_STRINGS 949 # define SETPROC_STATIC static 950 # endif 951 # endif 952 # ifndef SETPROC_STATIC 953 # define SETPROC_STATIC 954 # endif 955 #endif 956 957 #ifndef PROCTITLEPAD 958 # define PROCTITLEPAD ' ' 959 #endif 960 961 #ifndef HASSETPROCTITLE 962 963 /*VARARGS1*/ 964 #ifdef __STDC__ 965 setproctitle(char *fmt, ...) 966 #else 967 setproctitle(fmt, va_alist) 968 char *fmt; 969 va_dcl 970 #endif 971 { 972 # ifdef SETPROCTITLE 973 register char *p; 974 register int i; 975 SETPROC_STATIC char buf[MAXLINE]; 976 VA_LOCAL_DECL 977 # ifdef __hpux 978 union pstun pst; 979 # endif 980 extern char **Argv; 981 extern char *LastArgv; 982 983 p = buf; 984 985 /* print sendmail: heading for grep */ 986 (void) strcpy(p, "sendmail: "); 987 p += strlen(p); 988 989 /* print the argument string */ 990 VA_START(fmt); 991 (void) vsprintf(p, fmt, ap); 992 VA_END; 993 994 i = strlen(buf); 995 996 # ifdef __hpux 997 pst.pst_command = buf; 998 pstat(PSTAT_SETCMD, pst, i, 0, 0); 999 # else 1000 # ifdef PS_STRINGS 1001 PS_STRINGS->ps_nargvstr = 1; 1002 PS_STRINGS->ps_argvstr = buf; 1003 # else 1004 if (i > LastArgv - Argv[0] - 2) 1005 { 1006 i = LastArgv - Argv[0] - 2; 1007 buf[i] = '\0'; 1008 } 1009 (void) strcpy(Argv[0], buf); 1010 p = &Argv[0][i]; 1011 while (p < LastArgv) 1012 *p++ = PROCTITLEPAD; 1013 # endif 1014 # endif 1015 # endif /* SETPROCTITLE */ 1016 } 1017 1018 #endif 1019 /* 1020 ** REAPCHILD -- pick up the body of my child, lest it become a zombie 1021 ** 1022 ** Parameters: 1023 ** none. 1024 ** 1025 ** Returns: 1026 ** none. 1027 ** 1028 ** Side Effects: 1029 ** Picks up extant zombies. 1030 */ 1031 1032 void 1033 reapchild() 1034 { 1035 int olderrno = errno; 1036 # ifdef HASWAITPID 1037 auto int status; 1038 int count; 1039 int pid; 1040 1041 count = 0; 1042 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) 1043 { 1044 if (count++ > 1000) 1045 { 1046 syslog(LOG_ALERT, "reapchild: waitpid loop: pid=%d, status=%x", 1047 pid, status); 1048 break; 1049 } 1050 } 1051 # else 1052 # ifdef WNOHANG 1053 union wait status; 1054 1055 while (wait3(&status, WNOHANG, (struct rusage *) NULL) > 0) 1056 continue; 1057 # else /* WNOHANG */ 1058 auto int status; 1059 1060 while (wait(&status) > 0) 1061 continue; 1062 # endif /* WNOHANG */ 1063 # endif 1064 # ifdef SYS5SIGNALS 1065 (void) setsignal(SIGCHLD, reapchild); 1066 # endif 1067 errno = olderrno; 1068 } 1069 /* 1070 ** UNSETENV -- remove a variable from the environment 1071 ** 1072 ** Not needed on newer systems. 1073 ** 1074 ** Parameters: 1075 ** name -- the string name of the environment variable to be 1076 ** deleted from the current environment. 1077 ** 1078 ** Returns: 1079 ** none. 1080 ** 1081 ** Globals: 1082 ** environ -- a pointer to the current environment. 1083 ** 1084 ** Side Effects: 1085 ** Modifies environ. 1086 */ 1087 1088 #ifndef HASUNSETENV 1089 1090 void 1091 unsetenv(name) 1092 char *name; 1093 { 1094 extern char **environ; 1095 register char **pp; 1096 int len = strlen(name); 1097 1098 for (pp = environ; *pp != NULL; pp++) 1099 { 1100 if (strncmp(name, *pp, len) == 0 && 1101 ((*pp)[len] == '=' || (*pp)[len] == '\0')) 1102 break; 1103 } 1104 1105 for (; *pp != NULL; pp++) 1106 *pp = pp[1]; 1107 } 1108 1109 #endif 1110 /* 1111 ** GETDTABLESIZE -- return number of file descriptors 1112 ** 1113 ** Only on non-BSD systems 1114 ** 1115 ** Parameters: 1116 ** none 1117 ** 1118 ** Returns: 1119 ** size of file descriptor table 1120 ** 1121 ** Side Effects: 1122 ** none 1123 */ 1124 1125 #ifdef SOLARIS 1126 # include <sys/resource.h> 1127 #endif 1128 1129 int 1130 getdtsize() 1131 { 1132 #ifdef RLIMIT_NOFILE 1133 struct rlimit rl; 1134 1135 if (getrlimit(RLIMIT_NOFILE, &rl) >= 0) 1136 return rl.rlim_cur; 1137 #endif 1138 1139 # ifdef HASGETDTABLESIZE 1140 return getdtablesize(); 1141 # else 1142 # ifdef _SC_OPEN_MAX 1143 return sysconf(_SC_OPEN_MAX); 1144 # else 1145 return NOFILE; 1146 # endif 1147 # endif 1148 } 1149 /* 1150 ** UNAME -- get the UUCP name of this system. 1151 */ 1152 1153 #ifndef HASUNAME 1154 1155 int 1156 uname(name) 1157 struct utsname *name; 1158 { 1159 FILE *file; 1160 char *n; 1161 1162 name->nodename[0] = '\0'; 1163 1164 /* try /etc/whoami -- one line with the node name */ 1165 if ((file = fopen("/etc/whoami", "r")) != NULL) 1166 { 1167 (void) fgets(name->nodename, NODE_LENGTH + 1, file); 1168 (void) fclose(file); 1169 n = strchr(name->nodename, '\n'); 1170 if (n != NULL) 1171 *n = '\0'; 1172 if (name->nodename[0] != '\0') 1173 return (0); 1174 } 1175 1176 /* try /usr/include/whoami.h -- has a #define somewhere */ 1177 if ((file = fopen("/usr/include/whoami.h", "r")) != NULL) 1178 { 1179 char buf[MAXLINE]; 1180 1181 while (fgets(buf, MAXLINE, file) != NULL) 1182 if (sscanf(buf, "#define sysname \"%*[^\"]\"", 1183 NODE_LENGTH, name->nodename) > 0) 1184 break; 1185 (void) fclose(file); 1186 if (name->nodename[0] != '\0') 1187 return (0); 1188 } 1189 1190 #ifdef TRUST_POPEN 1191 /* 1192 ** Popen is known to have security holes. 1193 */ 1194 1195 /* try uuname -l to return local name */ 1196 if ((file = popen("uuname -l", "r")) != NULL) 1197 { 1198 (void) fgets(name, NODE_LENGTH + 1, file); 1199 (void) pclose(file); 1200 n = strchr(name, '\n'); 1201 if (n != NULL) 1202 *n = '\0'; 1203 if (name->nodename[0] != '\0') 1204 return (0); 1205 } 1206 #endif 1207 1208 return (-1); 1209 } 1210 #endif /* HASUNAME */ 1211 /* 1212 ** INITGROUPS -- initialize groups 1213 ** 1214 ** Stub implementation for System V style systems 1215 */ 1216 1217 #ifndef HASINITGROUPS 1218 1219 initgroups(name, basegid) 1220 char *name; 1221 int basegid; 1222 { 1223 return 0; 1224 } 1225 1226 #endif 1227 /* 1228 ** SETSID -- set session id (for non-POSIX systems) 1229 */ 1230 1231 #ifndef HASSETSID 1232 1233 pid_t 1234 setsid __P ((void)) 1235 { 1236 #ifdef TIOCNOTTY 1237 int fd; 1238 1239 fd = open("/dev/tty", 2); 1240 if (fd >= 0) 1241 { 1242 (void) ioctl(fd, (int) TIOCNOTTY, (char *) 0); 1243 (void) close(fd); 1244 } 1245 #endif /* TIOCNOTTY */ 1246 # ifdef SYS5SETPGRP 1247 return setpgrp(); 1248 # else 1249 return setpgid(0, getpid()); 1250 # endif 1251 } 1252 1253 #endif 1254 /* 1255 ** DGUX_INET_ADDR -- inet_addr for DG/UX 1256 ** 1257 ** Data General DG/UX version of inet_addr returns a struct in_addr 1258 ** instead of a long. This patches things. 1259 */ 1260 1261 #ifdef DGUX 1262 1263 #undef inet_addr 1264 1265 long 1266 dgux_inet_addr(host) 1267 char *host; 1268 { 1269 struct in_addr haddr; 1270 1271 haddr = inet_addr(host); 1272 return haddr.s_addr; 1273 } 1274 1275 #endif 1276 /* 1277 ** GETOPT -- for old systems or systems with bogus implementations 1278 */ 1279 1280 #ifdef NEEDGETOPT 1281 1282 /* 1283 * Copyright (c) 1985 Regents of the University of California. 1284 * All rights reserved. The Berkeley software License Agreement 1285 * specifies the terms and conditions for redistribution. 1286 */ 1287 1288 1289 /* 1290 ** this version hacked to add `atend' flag to allow state machine 1291 ** to reset if invoked by the program to scan args for a 2nd time 1292 */ 1293 1294 #if defined(LIBC_SCCS) && !defined(lint) 1295 static char sccsid[] = "@(#)getopt.c 4.3 (Berkeley) 3/9/86"; 1296 #endif /* LIBC_SCCS and not lint */ 1297 1298 #include <stdio.h> 1299 1300 /* 1301 * get option letter from argument vector 1302 */ 1303 #ifdef _CONVEX_SOURCE 1304 extern int optind, opterr; 1305 #else 1306 int opterr = 1; /* if error message should be printed */ 1307 int optind = 1; /* index into parent argv vector */ 1308 #endif 1309 int optopt; /* character checked for validity */ 1310 char *optarg; /* argument associated with option */ 1311 1312 #define BADCH (int)'?' 1313 #define EMSG "" 1314 #define tell(s) if (opterr) {fputs(*nargv,stderr);fputs(s,stderr); \ 1315 fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);} 1316 1317 getopt(nargc,nargv,ostr) 1318 int nargc; 1319 char *const *nargv; 1320 const char *ostr; 1321 { 1322 static char *place = EMSG; /* option letter processing */ 1323 static char atend = 0; 1324 register char *oli; /* option letter list index */ 1325 1326 if (atend) { 1327 atend = 0; 1328 place = EMSG; 1329 } 1330 if(!*place) { /* update scanning pointer */ 1331 if (optind >= nargc || *(place = nargv[optind]) != '-' || !*++place) { 1332 atend++; 1333 return(EOF); 1334 } 1335 if (*place == '-') { /* found "--" */ 1336 ++optind; 1337 atend++; 1338 return(EOF); 1339 } 1340 } /* option letter okay? */ 1341 if ((optopt = (int)*place++) == (int)':' || !(oli = strchr(ostr,optopt))) { 1342 if (!*place) ++optind; 1343 tell(": illegal option -- "); 1344 } 1345 if (*++oli != ':') { /* don't need argument */ 1346 optarg = NULL; 1347 if (!*place) ++optind; 1348 } 1349 else { /* need an argument */ 1350 if (*place) optarg = place; /* no white space */ 1351 else if (nargc <= ++optind) { /* no arg */ 1352 place = EMSG; 1353 tell(": option requires an argument -- "); 1354 } 1355 else optarg = nargv[optind]; /* white space */ 1356 place = EMSG; 1357 ++optind; 1358 } 1359 return(optopt); /* dump back option letter */ 1360 } 1361 1362 #endif 1363 /* 1364 ** VFPRINTF, VSPRINTF -- for old 4.3 BSD systems missing a real version 1365 */ 1366 1367 #ifdef NEEDVPRINTF 1368 1369 #define MAXARG 16 1370 1371 vfprintf(fp, fmt, ap) 1372 FILE * fp; 1373 char * fmt; 1374 char ** ap; 1375 { 1376 char * bp[MAXARG]; 1377 int i = 0; 1378 1379 while (*ap && i < MAXARG) 1380 bp[i++] = *ap++; 1381 fprintf(fp, fmt, bp[0], bp[1], bp[2], bp[3], 1382 bp[4], bp[5], bp[6], bp[7], 1383 bp[8], bp[9], bp[10], bp[11], 1384 bp[12], bp[13], bp[14], bp[15]); 1385 } 1386 1387 vsprintf(s, fmt, ap) 1388 char * s; 1389 char * fmt; 1390 char ** ap; 1391 { 1392 char * bp[MAXARG]; 1393 int i = 0; 1394 1395 while (*ap && i < MAXARG) 1396 bp[i++] = *ap++; 1397 sprintf(s, fmt, bp[0], bp[1], bp[2], bp[3], 1398 bp[4], bp[5], bp[6], bp[7], 1399 bp[8], bp[9], bp[10], bp[11], 1400 bp[12], bp[13], bp[14], bp[15]); 1401 } 1402 1403 #endif 1404 /* 1405 ** USERSHELLOK -- tell if a user's shell is ok for unrestricted use 1406 ** 1407 ** Parameters: 1408 ** shell -- the user's shell from /etc/passwd 1409 ** 1410 ** Returns: 1411 ** TRUE -- if it is ok to use this for unrestricted access. 1412 ** FALSE -- if the shell is restricted. 1413 */ 1414 1415 #if !HASGETUSERSHELL 1416 1417 # ifndef _PATH_SHELLS 1418 # define _PATH_SHELLS "/etc/shells" 1419 # endif 1420 1421 char *DefaultUserShells[] = 1422 { 1423 "/bin/sh", 1424 "/usr/bin/sh", 1425 "/bin/csh", 1426 "/usr/bin/csh", 1427 #ifdef __hpux 1428 "/bin/rsh", 1429 "/bin/ksh", 1430 "/bin/rksh", 1431 "/bin/pam", 1432 "/usr/bin/keysh", 1433 "/bin/posix/sh", 1434 #endif 1435 NULL 1436 }; 1437 1438 #endif 1439 1440 #define WILDCARD_SHELL "/SENDMAIL/ANY/SHELL/" 1441 1442 bool 1443 usershellok(shell) 1444 char *shell; 1445 { 1446 #if HASGETUSERSHELL 1447 register char *p; 1448 extern char *getusershell(); 1449 1450 setusershell(); 1451 while ((p = getusershell()) != NULL) 1452 if (strcmp(p, shell) == 0 || strcmp(p, WILDCARD_SHELL) == 0) 1453 break; 1454 endusershell(); 1455 return p != NULL; 1456 #else 1457 register FILE *shellf; 1458 char buf[MAXLINE]; 1459 1460 shellf = fopen(_PATH_SHELLS, "r"); 1461 if (shellf == NULL) 1462 { 1463 /* no /etc/shells; see if it is one of the std shells */ 1464 char **d; 1465 1466 for (d = DefaultUserShells; *d != NULL; d++) 1467 { 1468 if (strcmp(shell, *d) == 0) 1469 return TRUE; 1470 } 1471 return FALSE; 1472 } 1473 1474 while (fgets(buf, sizeof buf, shellf) != NULL) 1475 { 1476 register char *p, *q; 1477 1478 p = buf; 1479 while (*p != '\0' && *p != '#' && *p != '/') 1480 p++; 1481 if (*p == '#' || *p == '\0') 1482 continue; 1483 q = p; 1484 while (*p != '\0' && *p != '#' && !isspace(*p)) 1485 p++; 1486 *p = '\0'; 1487 if (strcmp(shell, q) == 0 || strcmp(WILDCARD_SHELL, q) == 0) 1488 { 1489 fclose(shellf); 1490 return TRUE; 1491 } 1492 } 1493 fclose(shellf); 1494 return FALSE; 1495 #endif 1496 } 1497 /* 1498 ** FREESPACE -- see how much free space is on the queue filesystem 1499 ** 1500 ** Only implemented if you have statfs. 1501 ** 1502 ** Parameters: 1503 ** dir -- the directory in question. 1504 ** bsize -- a variable into which the filesystem 1505 ** block size is stored. 1506 ** 1507 ** Returns: 1508 ** The number of bytes free on the queue filesystem. 1509 ** -1 if the statfs call fails. 1510 ** 1511 ** Side effects: 1512 ** Puts the filesystem block size into bsize. 1513 */ 1514 1515 /* statfs types */ 1516 #define SFS_NONE 0 /* no statfs implementation */ 1517 #define SFS_USTAT 1 /* use ustat */ 1518 #define SFS_4ARGS 2 /* use four-argument statfs call */ 1519 #define SFS_VFS 3 /* use <sys/vfs.h> implementation */ 1520 #define SFS_MOUNT 4 /* use <sys/mount.h> implementation */ 1521 #define SFS_STATFS 5 /* use <sys/statfs.h> implementation */ 1522 1523 #ifndef SFS_TYPE 1524 # define SFS_TYPE SFS_NONE 1525 #endif 1526 1527 #if SFS_TYPE == SFS_USTAT 1528 # include <ustat.h> 1529 #endif 1530 #if SFS_TYPE == SFS_4ARGS || SFS_TYPE == SFS_STATFS 1531 # include <sys/statfs.h> 1532 #endif 1533 #if SFS_TYPE == SFS_VFS 1534 # include <sys/vfs.h> 1535 #endif 1536 #if SFS_TYPE == SFS_MOUNT 1537 # include <sys/mount.h> 1538 #endif 1539 1540 long 1541 freespace(dir, bsize) 1542 char *dir; 1543 long *bsize; 1544 { 1545 #if SFS_TYPE != SFS_NONE 1546 # if SFS_TYPE == SFS_USTAT 1547 struct ustat fs; 1548 struct stat statbuf; 1549 # define FSBLOCKSIZE DEV_BSIZE 1550 # define f_bavail f_tfree 1551 # else 1552 # if defined(ultrix) 1553 struct fs_data fs; 1554 # define f_bavail fd_bfreen 1555 # define FSBLOCKSIZE fs.fd_bsize 1556 # else 1557 struct statfs fs; 1558 # define FSBLOCKSIZE fs.f_bsize 1559 # if defined(_SCO_unix_) || defined(IRIX) || defined(apollo) 1560 # define f_bavail f_bfree 1561 # endif 1562 # endif 1563 # endif 1564 extern int errno; 1565 1566 # if SFS_TYPE == SFS_USTAT 1567 if (stat(dir, &statbuf) == 0 && ustat(statbuf.st_dev, &fs) == 0) 1568 # else 1569 # if SFS_TYPE == SFS_4ARGS 1570 if (statfs(dir, &fs, sizeof fs, 0) == 0) 1571 # else 1572 # if defined(ultrix) 1573 if (statfs(dir, &fs) > 0) 1574 # else 1575 if (statfs(dir, &fs) == 0) 1576 # endif 1577 # endif 1578 # endif 1579 { 1580 if (bsize != NULL) 1581 *bsize = FSBLOCKSIZE; 1582 return (fs.f_bavail); 1583 } 1584 #endif 1585 return (-1); 1586 } 1587 /* 1588 ** ENOUGHSPACE -- check to see if there is enough free space on the queue fs 1589 ** 1590 ** Only implemented if you have statfs. 1591 ** 1592 ** Parameters: 1593 ** msize -- the size to check against. If zero, we don't yet 1594 ** know how big the message will be, so just check for 1595 ** a "reasonable" amount. 1596 ** 1597 ** Returns: 1598 ** TRUE if there is enough space. 1599 ** FALSE otherwise. 1600 */ 1601 1602 bool 1603 enoughspace(msize) 1604 long msize; 1605 { 1606 long bfree, bsize; 1607 1608 if (MinBlocksFree <= 0 && msize <= 0) 1609 { 1610 if (tTd(4, 80)) 1611 printf("enoughspace: no threshold\n"); 1612 return TRUE; 1613 } 1614 1615 if ((bfree = freespace(QueueDir, &bsize)) >= 0) 1616 { 1617 if (tTd(4, 80)) 1618 printf("enoughspace: bavail=%ld, need=%ld\n", 1619 bfree, msize); 1620 1621 /* convert msize to block count */ 1622 msize = msize / bsize + 1; 1623 if (MinBlocksFree >= 0) 1624 msize += MinBlocksFree; 1625 1626 if (bfree < msize) 1627 { 1628 #ifdef LOG 1629 if (LogLevel > 0) 1630 syslog(LOG_ALERT, 1631 "%s: low on space (have %ld, %s needs %ld in %s)", 1632 CurEnv->e_id, bfree, 1633 CurHostName, msize, QueueDir); 1634 #endif 1635 return FALSE; 1636 } 1637 } 1638 else if (tTd(4, 80)) 1639 printf("enoughspace failure: min=%ld, need=%ld: %s\n", 1640 MinBlocksFree, msize, errstring(errno)); 1641 return TRUE; 1642 } 1643 /* 1644 ** TRANSIENTERROR -- tell if an error code indicates a transient failure 1645 ** 1646 ** This looks at an errno value and tells if this is likely to 1647 ** go away if retried later. 1648 ** 1649 ** Parameters: 1650 ** err -- the errno code to classify. 1651 ** 1652 ** Returns: 1653 ** TRUE if this is probably transient. 1654 ** FALSE otherwise. 1655 */ 1656 1657 bool 1658 transienterror(err) 1659 int err; 1660 { 1661 switch (err) 1662 { 1663 case EIO: /* I/O error */ 1664 case ENXIO: /* Device not configured */ 1665 case EAGAIN: /* Resource temporarily unavailable */ 1666 case ENOMEM: /* Cannot allocate memory */ 1667 case ENODEV: /* Operation not supported by device */ 1668 case ENFILE: /* Too many open files in system */ 1669 case EMFILE: /* Too many open files */ 1670 case ENOSPC: /* No space left on device */ 1671 #ifdef ETIMEDOUT 1672 case ETIMEDOUT: /* Connection timed out */ 1673 #endif 1674 #ifdef ESTALE 1675 case ESTALE: /* Stale NFS file handle */ 1676 #endif 1677 #ifdef ENETDOWN 1678 case ENETDOWN: /* Network is down */ 1679 #endif 1680 #ifdef ENETUNREACH 1681 case ENETUNREACH: /* Network is unreachable */ 1682 #endif 1683 #ifdef ENETRESET 1684 case ENETRESET: /* Network dropped connection on reset */ 1685 #endif 1686 #ifdef ECONNABORTED 1687 case ECONNABORTED: /* Software caused connection abort */ 1688 #endif 1689 #ifdef ECONNRESET 1690 case ECONNRESET: /* Connection reset by peer */ 1691 #endif 1692 #ifdef ENOBUFS 1693 case ENOBUFS: /* No buffer space available */ 1694 #endif 1695 #ifdef ESHUTDOWN 1696 case ESHUTDOWN: /* Can't send after socket shutdown */ 1697 #endif 1698 #ifdef ECONNREFUSED 1699 case ECONNREFUSED: /* Connection refused */ 1700 #endif 1701 #ifdef EHOSTDOWN 1702 case EHOSTDOWN: /* Host is down */ 1703 #endif 1704 #ifdef EHOSTUNREACH 1705 case EHOSTUNREACH: /* No route to host */ 1706 #endif 1707 #ifdef EDQUOT 1708 case EDQUOT: /* Disc quota exceeded */ 1709 #endif 1710 #ifdef EPROCLIM 1711 case EPROCLIM: /* Too many processes */ 1712 #endif 1713 #ifdef EUSERS 1714 case EUSERS: /* Too many users */ 1715 #endif 1716 #ifdef EDEADLK 1717 case EDEADLK: /* Resource deadlock avoided */ 1718 #endif 1719 #ifdef EISCONN 1720 case EISCONN: /* Socket already connected */ 1721 #endif 1722 #ifdef EINPROGRESS 1723 case EINPROGRESS: /* Operation now in progress */ 1724 #endif 1725 #ifdef EALREADY 1726 case EALREADY: /* Operation already in progress */ 1727 #endif 1728 #ifdef EADDRINUSE 1729 case EADDRINUSE: /* Address already in use */ 1730 #endif 1731 #ifdef EADDRNOTAVAIL 1732 case EADDRNOTAVAIL: /* Can't assign requested address */ 1733 #endif 1734 #ifdef ETXTBSY 1735 case ETXTBSY: /* (Apollo) file locked */ 1736 #endif 1737 #if defined(ENOSR) && (!defined(ENOBUFS) || (ENOBUFS != ENOSR)) 1738 case ENOSR: /* Out of streams resources */ 1739 #endif 1740 return TRUE; 1741 } 1742 1743 /* nope, must be permanent */ 1744 return FALSE; 1745 } 1746 /* 1747 ** LOCKFILE -- lock a file using flock or (shudder) fcntl locking 1748 ** 1749 ** Parameters: 1750 ** fd -- the file descriptor of the file. 1751 ** filename -- the file name (for error messages). 1752 ** ext -- the filename extension. 1753 ** type -- type of the lock. Bits can be: 1754 ** LOCK_EX -- exclusive lock. 1755 ** LOCK_NB -- non-blocking. 1756 ** 1757 ** Returns: 1758 ** TRUE if the lock was acquired. 1759 ** FALSE otherwise. 1760 */ 1761 1762 bool 1763 lockfile(fd, filename, ext, type) 1764 int fd; 1765 char *filename; 1766 char *ext; 1767 int type; 1768 { 1769 # if !HASFLOCK 1770 int action; 1771 struct flock lfd; 1772 1773 if (ext == NULL) 1774 ext = ""; 1775 1776 bzero(&lfd, sizeof lfd); 1777 if (bitset(LOCK_UN, type)) 1778 lfd.l_type = F_UNLCK; 1779 else if (bitset(LOCK_EX, type)) 1780 lfd.l_type = F_WRLCK; 1781 else 1782 lfd.l_type = F_RDLCK; 1783 1784 if (bitset(LOCK_NB, type)) 1785 action = F_SETLK; 1786 else 1787 action = F_SETLKW; 1788 1789 if (tTd(55, 60)) 1790 printf("lockfile(%s%s, action=%d, type=%d): ", 1791 filename, ext, action, lfd.l_type); 1792 1793 if (fcntl(fd, action, &lfd) >= 0) 1794 { 1795 if (tTd(55, 60)) 1796 printf("SUCCESS\n"); 1797 return TRUE; 1798 } 1799 1800 if (tTd(55, 60)) 1801 printf("(%s) ", errstring(errno)); 1802 1803 /* 1804 ** On SunOS, if you are testing using -oQ/tmp/mqueue or 1805 ** -oA/tmp/aliases or anything like that, and /tmp is mounted 1806 ** as type "tmp" (that is, served from swap space), the 1807 ** previous fcntl will fail with "Invalid argument" errors. 1808 ** Since this is fairly common during testing, we will assume 1809 ** that this indicates that the lock is successfully grabbed. 1810 */ 1811 1812 if (errno == EINVAL) 1813 { 1814 if (tTd(55, 60)) 1815 printf("SUCCESS\n"); 1816 return TRUE; 1817 } 1818 1819 if (!bitset(LOCK_NB, type) || (errno != EACCES && errno != EAGAIN)) 1820 { 1821 int omode = -1; 1822 # ifdef F_GETFL 1823 int oerrno = errno; 1824 1825 (void) fcntl(fd, F_GETFL, &omode); 1826 errno = oerrno; 1827 # endif 1828 syserr("cannot lockf(%s%s, fd=%d, type=%o, omode=%o, euid=%d)", 1829 filename, ext, fd, type, omode, geteuid()); 1830 } 1831 # else 1832 if (ext == NULL) 1833 ext = ""; 1834 1835 if (tTd(55, 60)) 1836 printf("lockfile(%s%s, type=%o): ", filename, ext, type); 1837 1838 if (flock(fd, type) >= 0) 1839 { 1840 if (tTd(55, 60)) 1841 printf("SUCCESS\n"); 1842 return TRUE; 1843 } 1844 1845 if (tTd(55, 60)) 1846 printf("(%s) ", errstring(errno)); 1847 1848 if (!bitset(LOCK_NB, type) || errno != EWOULDBLOCK) 1849 { 1850 int omode = -1; 1851 # ifdef F_GETFL 1852 int oerrno = errno; 1853 1854 (void) fcntl(fd, F_GETFL, &omode); 1855 errno = oerrno; 1856 # endif 1857 syserr("cannot flock(%s%s, fd=%d, type=%o, omode=%o, euid=%d)", 1858 filename, ext, fd, type, omode, geteuid()); 1859 } 1860 # endif 1861 if (tTd(55, 60)) 1862 printf("FAIL\n"); 1863 return FALSE; 1864 } 1865 /* 1866 ** CHOWNSAFE -- tell if chown is "safe" (executable only by root) 1867 ** 1868 ** Parameters: 1869 ** fd -- the file descriptor to check. 1870 ** 1871 ** Returns: 1872 ** TRUE -- if only root can chown the file to an arbitrary 1873 ** user. 1874 ** FALSE -- if an arbitrary user can give away a file. 1875 */ 1876 1877 bool 1878 chownsafe(fd) 1879 int fd; 1880 { 1881 #ifdef __hpux 1882 char *s; 1883 int tfd; 1884 uid_t o_uid, o_euid; 1885 gid_t o_gid, o_egid; 1886 bool rval; 1887 struct stat stbuf; 1888 1889 o_uid = getuid(); 1890 o_euid = geteuid(); 1891 o_gid = getgid(); 1892 o_egid = getegid(); 1893 fstat(fd, &stbuf); 1894 setresuid(stbuf.st_uid, stbuf.st_uid, -1); 1895 setresgid(stbuf.st_gid, stbuf.st_gid, -1); 1896 s = tmpnam(NULL); 1897 tfd = open(s, O_RDONLY|O_CREAT, 0600); 1898 rval = fchown(tfd, DefUid, DefGid) != 0; 1899 close(tfd); 1900 unlink(s); 1901 setreuid(o_uid, o_euid); 1902 setresgid(o_gid, o_egid, -1); 1903 return rval; 1904 #else 1905 # ifdef _POSIX_CHOWN_RESTRICTED 1906 # if _POSIX_CHOWN_RESTRICTED == -1 1907 return FALSE; 1908 # else 1909 return TRUE; 1910 # endif 1911 # else 1912 # ifdef _PC_CHOWN_RESTRICTED 1913 return fpathconf(fd, _PC_CHOWN_RESTRICTED) > 0; 1914 # else 1915 # ifdef BSD 1916 return TRUE; 1917 # else 1918 return FALSE; 1919 # endif 1920 # endif 1921 # endif 1922 #endif 1923 } 1924 /* 1925 ** GETCFNAME -- return the name of the .cf file. 1926 ** 1927 ** Some systems (e.g., NeXT) determine this dynamically. 1928 */ 1929 1930 char * 1931 getcfname() 1932 { 1933 if (ConfFile != NULL) 1934 return ConfFile; 1935 #ifdef NETINFO 1936 { 1937 extern char *ni_propval(); 1938 char *cflocation; 1939 1940 cflocation = ni_propval("/locations/sendmail", "sendmail.cf"); 1941 if (cflocation != NULL) 1942 return cflocation; 1943 } 1944 #endif 1945 return _PATH_SENDMAILCF; 1946 } 1947 /* 1948 ** SETVENDOR -- process vendor code from V configuration line 1949 ** 1950 ** Parameters: 1951 ** vendor -- string representation of vendor. 1952 ** 1953 ** Returns: 1954 ** TRUE -- if ok. 1955 ** FALSE -- if vendor code could not be processed. 1956 ** 1957 ** Side Effects: 1958 ** It is reasonable to set mode flags here to tweak 1959 ** processing in other parts of the code if necessary. 1960 ** For example, if you are a vendor that uses $%y to 1961 ** indicate YP lookups, you could enable that here. 1962 */ 1963 1964 bool 1965 setvendor(vendor) 1966 char *vendor; 1967 { 1968 if (strcasecmp(vendor, "Berkeley") == 0) 1969 return TRUE; 1970 1971 /* add vendor extensions here */ 1972 1973 return FALSE; 1974 } 1975 /* 1976 ** STRTOL -- convert string to long integer 1977 ** 1978 ** For systems that don't have it in the C library. 1979 */ 1980 1981 #ifdef NEEDSTRTOL 1982 1983 long 1984 strtol(p, ep, b) 1985 char *p; 1986 char **ep; 1987 int b; 1988 { 1989 long l = 0; 1990 char c; 1991 char maxd; 1992 int neg = 1; 1993 1994 maxd = (b > 10) ? '9' : b + '0'; 1995 1996 if (p && *p == '-') { 1997 neg = -1; 1998 p++; 1999 } 2000 while (p && (c = *p)) { 2001 if (c >= '0' && c <= maxd) { 2002 l = l*b + *p++ - '0'; 2003 continue; 2004 } 2005 if (c >= 'A' && c <= 'Z') 2006 c -= 'A' + 'a'; 2007 c = c - 'a' + 10; 2008 if (b > c) { 2009 l = l*b + c; 2010 p++; 2011 continue; 2012 } 2013 break; 2014 } 2015 l *= neg; 2016 if (ep) 2017 *ep = p; 2018 return l; 2019 } 2020 2021 #endif 2022 /* 2023 ** SOLARIS_GETHOSTBY{NAME,ADDR} -- compatibility routines for gethostbyXXX 2024 ** 2025 ** Solaris versions prior through 2.3 don't properly deliver a 2026 ** canonical h_name field. This tries to work around it. 2027 */ 2028 2029 #ifdef SOLARIS 2030 2031 struct hostent * 2032 solaris_gethostbyname(name) 2033 const char *name; 2034 { 2035 # ifdef SOLARIS_2_3 2036 static struct hostent hp; 2037 static char buf[1000]; 2038 extern struct hostent *_switch_gethostbyname_r(); 2039 2040 return _switch_gethostbyname_r(name, &hp, buf, sizeof(buf), &h_errno); 2041 # else 2042 extern struct hostent *__switch_gethostbyname(); 2043 2044 return __switch_gethostbyname(name); 2045 # endif 2046 } 2047 2048 struct hostent * 2049 solaris_gethostbyaddr(addr, len, type) 2050 const char *addr; 2051 int len; 2052 int type; 2053 { 2054 # ifdef SOLARIS_2_3 2055 static struct hostent hp; 2056 static char buf[1000]; 2057 extern struct hostent *_switch_gethostbyaddr_r(); 2058 2059 return _switch_gethostbyaddr_r(addr, len, type, &hp, buf, sizeof(buf), &h_errno); 2060 # else 2061 extern struct hostent *__switch_gethostbyaddr(); 2062 2063 return __switch_gethostbyaddr(addr, len, type); 2064 # endif 2065 } 2066 2067 #endif 2068 /* 2069 ** NI_PROPVAL -- netinfo property value lookup routine 2070 ** 2071 ** Parameters: 2072 ** directory -- the Netinfo directory name. 2073 ** propname -- the Netinfo property name. 2074 ** 2075 ** Returns: 2076 ** NULL -- if: 2077 ** 1. the directory is not found 2078 ** 2. the property name is not found 2079 ** 3. the property contains multiple values 2080 ** 4. some error occured 2081 ** else -- the location of the config file. 2082 ** 2083 ** Notes: 2084 ** Caller should free the return value of ni_proval 2085 */ 2086 2087 #ifdef NETINFO 2088 2089 # include <netinfo/ni.h> 2090 2091 # define LOCAL_NETINFO_DOMAIN "." 2092 # define PARENT_NETINFO_DOMAIN ".." 2093 # define MAX_NI_LEVELS 256 2094 2095 char * 2096 ni_propval(directory, propname) 2097 char *directory; 2098 char *propname; 2099 { 2100 char *propval = NULL; 2101 int i; 2102 void *ni = NULL; 2103 void *lastni = NULL; 2104 ni_status nis; 2105 ni_id nid; 2106 ni_namelist ninl; 2107 2108 /* 2109 ** If the passed directory and property name are found 2110 ** in one of netinfo domains we need to search (starting 2111 ** from the local domain moving all the way back to the 2112 ** root domain) set propval to the property's value 2113 ** and return it. 2114 */ 2115 2116 for (i = 0; i < MAX_NI_LEVELS; ++i) 2117 { 2118 if (i == 0) 2119 { 2120 nis = ni_open(NULL, LOCAL_NETINFO_DOMAIN, &ni); 2121 } 2122 else 2123 { 2124 if (lastni != NULL) 2125 ni_free(lastni); 2126 lastni = ni; 2127 nis = ni_open(lastni, PARENT_NETINFO_DOMAIN, &ni); 2128 } 2129 2130 /* 2131 ** Don't bother if we didn't get a handle on a 2132 ** proper domain. This is not necessarily an error. 2133 ** We would get a positive ni_status if, for instance 2134 ** we never found the directory or property and tried 2135 ** to open the parent of the root domain! 2136 */ 2137 2138 if (nis != 0) 2139 break; 2140 2141 /* 2142 ** Find the path to the server information. 2143 */ 2144 2145 if (ni_pathsearch(ni, &nid, directory) != 0) 2146 continue; 2147 2148 /* 2149 ** Find "host" information. 2150 */ 2151 2152 if (ni_lookupprop(ni, &nid, propname, &ninl) != 0) 2153 continue; 2154 2155 /* 2156 ** If there's only one name in 2157 ** the list, assume we've got 2158 ** what we want. 2159 */ 2160 2161 if (ninl.ni_namelist_len == 1) 2162 { 2163 propval = ni_name_dup(ninl.ni_namelist_val[0]); 2164 break; 2165 } 2166 } 2167 2168 /* 2169 ** Clean up. 2170 */ 2171 2172 if (ni != NULL) 2173 ni_free(ni); 2174 if (lastni != NULL && ni != lastni) 2175 ni_free(lastni); 2176 2177 return propval; 2178 } 2179 2180 #endif /* NETINFO */ 2181 /* 2182 ** HARD_SYSLOG -- call syslog repeatedly until it works 2183 ** 2184 ** Needed on HP-UX, which apparently doesn't guarantee that 2185 ** syslog succeeds during interrupt handlers. 2186 */ 2187 2188 #ifdef __hpux 2189 2190 # define MAXSYSLOGTRIES 100 2191 # undef syslog 2192 2193 # ifdef __STDC__ 2194 hard_syslog(int pri, char *msg, ...) 2195 # else 2196 hard_syslog(pri, msg, va_alist) 2197 int pri; 2198 char *msg; 2199 va_dcl 2200 # endif 2201 { 2202 int i; 2203 char buf[SYSLOG_BUFSIZE * 2]; 2204 VA_LOCAL_DECL; 2205 2206 VA_START(msg); 2207 vsprintf(buf, msg, ap); 2208 VA_END; 2209 2210 for (i = MAXSYSLOGTRIES; --i >= 0 && syslog(pri, "%s", buf) < 0; ) 2211 continue; 2212 } 2213 2214 #endif 2215