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.84 (Berkeley) 04/12/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 #define LA_PROCSTR 7 /* read string ("1.17") from /proc/loadavg */ 606 607 /* do guesses based on general OS type */ 608 #ifndef LA_TYPE 609 # define LA_TYPE LA_ZERO 610 #endif 611 612 #if (LA_TYPE == LA_INT) || (LA_TYPE == LA_FLOAT) || (LA_TYPE == LA_SHORT) 613 614 #include <nlist.h> 615 616 #ifndef LA_AVENRUN 617 # ifdef SYSTEM5 618 # define LA_AVENRUN "avenrun" 619 # else 620 # define LA_AVENRUN "_avenrun" 621 # endif 622 #endif 623 624 /* _PATH_UNIX should be defined in <paths.h> */ 625 #ifndef _PATH_UNIX 626 # if defined(SYSTEM5) 627 # define _PATH_UNIX "/unix" 628 # else 629 # define _PATH_UNIX "/vmunix" 630 # endif 631 #endif 632 633 struct nlist Nl[] = 634 { 635 { LA_AVENRUN }, 636 #define X_AVENRUN 0 637 { 0 }, 638 }; 639 640 #ifndef FSHIFT 641 # if defined(unixpc) 642 # define FSHIFT 5 643 # endif 644 645 # if defined(__alpha) 646 # define FSHIFT 10 647 # endif 648 649 # if (LA_TYPE == LA_INT) || (LA_TYPE == LA_SHORT) 650 # define FSHIFT 8 651 # endif 652 #endif 653 654 #if ((LA_TYPE == LA_INT) || (LA_TYPE == LA_SHORT)) && !defined(FSCALE) 655 # define FSCALE (1 << FSHIFT) 656 #endif 657 658 getla() 659 { 660 static int kmem = -1; 661 #if LA_TYPE == LA_INT 662 long avenrun[3]; 663 #else 664 # if LA_TYPE == LA_SHORT 665 short avenrun[3]; 666 # else 667 double avenrun[3]; 668 # endif 669 #endif 670 extern off_t lseek(); 671 extern int errno; 672 673 if (kmem < 0) 674 { 675 kmem = open("/dev/kmem", 0, 0); 676 if (kmem < 0) 677 { 678 if (tTd(3, 1)) 679 printf("getla: open(/dev/kmem): %s\n", 680 errstring(errno)); 681 return (-1); 682 } 683 (void) fcntl(kmem, F_SETFD, 1); 684 if (nlist(_PATH_UNIX, Nl) < 0) 685 { 686 if (tTd(3, 1)) 687 printf("getla: nlist(%s): %s\n", _PATH_UNIX, 688 errstring(errno)); 689 return (-1); 690 } 691 if (Nl[X_AVENRUN].n_value == 0) 692 { 693 if (tTd(3, 1)) 694 printf("getla: nlist(%s, %s) ==> 0\n", 695 _PATH_UNIX, LA_AVENRUN); 696 return (-1); 697 } 698 } 699 if (tTd(3, 20)) 700 printf("getla: symbol address = %#x\n", Nl[X_AVENRUN].n_value); 701 if (lseek(kmem, (off_t) Nl[X_AVENRUN].n_value, 0) == -1 || 702 read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun)) 703 { 704 /* thank you Ian */ 705 if (tTd(3, 1)) 706 printf("getla: lseek or read: %s\n", errstring(errno)); 707 return (-1); 708 } 709 #if (LA_TYPE == LA_INT) || (LA_TYPE == LA_SHORT) 710 if (tTd(3, 5)) 711 { 712 printf("getla: avenrun = %d", avenrun[0]); 713 if (tTd(3, 15)) 714 printf(", %d, %d", avenrun[1], avenrun[2]); 715 printf("\n"); 716 } 717 if (tTd(3, 1)) 718 printf("getla: %d\n", (int) (avenrun[0] + FSCALE/2) >> FSHIFT); 719 return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT); 720 #else 721 if (tTd(3, 5)) 722 { 723 printf("getla: avenrun = %g", avenrun[0]); 724 if (tTd(3, 15)) 725 printf(", %g, %g", avenrun[1], avenrun[2]); 726 printf("\n"); 727 } 728 if (tTd(3, 1)) 729 printf("getla: %d\n", (int) (avenrun[0] +0.5)); 730 return ((int) (avenrun[0] + 0.5)); 731 #endif 732 } 733 734 #else 735 #if LA_TYPE == LA_SUBR 736 737 #ifdef DGUX 738 739 #include <sys/dg_sys_info.h> 740 741 int getla() 742 { 743 struct dg_sys_info_load_info load_info; 744 745 dg_sys_info((long *)&load_info, 746 DG_SYS_INFO_LOAD_INFO_TYPE, DG_SYS_INFO_LOAD_VERSION_0); 747 748 return((int) (load_info.one_minute + 0.5)); 749 } 750 751 #else 752 753 getla() 754 { 755 double avenrun[3]; 756 757 if (getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])) < 0) 758 { 759 if (tTd(3, 1)) 760 perror("getla: getloadavg failed:"); 761 return (-1); 762 } 763 if (tTd(3, 1)) 764 printf("getla: %d\n", (int) (avenrun[0] +0.5)); 765 return ((int) (avenrun[0] + 0.5)); 766 } 767 768 #endif /* DGUX */ 769 #else 770 #if LA_TYPE == LA_MACH 771 772 /* 773 ** This has been tested on NEXTSTEP release 2.1/3.X. 774 */ 775 776 #if defined(NX_CURRENT_COMPILER_RELEASE) && NX_CURRENT_COMPILER_RELEASE > NX_COMPILER_RELEASE_3_0 777 # include <mach/mach.h> 778 #else 779 # include <mach.h> 780 #endif 781 782 getla() 783 { 784 processor_set_t default_set; 785 kern_return_t error; 786 unsigned int info_count; 787 struct processor_set_basic_info info; 788 host_t host; 789 790 error = processor_set_default(host_self(), &default_set); 791 if (error != KERN_SUCCESS) 792 return -1; 793 info_count = PROCESSOR_SET_BASIC_INFO_COUNT; 794 if (processor_set_info(default_set, PROCESSOR_SET_BASIC_INFO, 795 &host, (processor_set_info_t)&info, 796 &info_count) != KERN_SUCCESS) 797 { 798 return -1; 799 } 800 return (int) (info.load_average + (LOAD_SCALE / 2)) / LOAD_SCALE; 801 } 802 803 804 #else 805 #if LA_TYPE == LA_PROCSTR 806 807 /* 808 ** Read /proc/loadavg for the load average. This is assumed to be 809 ** in a format like "0.15 0.12 0.06". 810 ** 811 ** Initially intended for Linux. This has been in the kernel 812 ** since at least 0.99.15. 813 */ 814 815 # ifndef _PATH_LOADAVG 816 # define _PATH_LOADAVG "/proc/loadavg" 817 # endif 818 819 int 820 getla() 821 { 822 double avenrun; 823 register int result; 824 FILE *fp; 825 826 fp = fopen(_PATH_LOADAVG, "r"); 827 if (fp == NULL) 828 { 829 if (tTd(3, 1)) 830 printf("getla: fopen(%s): %s\n", 831 _PATH_LOADAVG, errstring(errno)); 832 return -1; 833 } 834 result = fscanf(fp, "%lf", &avenrun); 835 fclose(fp); 836 if (result != 1) 837 { 838 if (tTd(3, 1)) 839 printf("getla: fscanf() = %d: %s\n", 840 result, errstring(errno)); 841 return -1; 842 } 843 844 if (tTd(3, 1)) 845 printf("getla(): %.2f\n", avenrun); 846 847 return ((int) (avenrun + 0.5)); 848 } 849 850 #else 851 852 getla() 853 { 854 if (tTd(3, 1)) 855 printf("getla: ZERO\n"); 856 return (0); 857 } 858 859 #endif 860 #endif 861 #endif 862 #endif 863 864 865 /* 866 * Copyright 1989 Massachusetts Institute of Technology 867 * 868 * Permission to use, copy, modify, distribute, and sell this software and its 869 * documentation for any purpose is hereby granted without fee, provided that 870 * the above copyright notice appear in all copies and that both that 871 * copyright notice and this permission notice appear in supporting 872 * documentation, and that the name of M.I.T. not be used in advertising or 873 * publicity pertaining to distribution of the software without specific, 874 * written prior permission. M.I.T. makes no representations about the 875 * suitability of this software for any purpose. It is provided "as is" 876 * without express or implied warranty. 877 * 878 * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL 879 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T. 880 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 881 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 882 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 883 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 884 * 885 * Authors: Many and varied... 886 */ 887 888 /* Non Apollo stuff removed by Don Lewis 11/15/93 */ 889 #ifndef lint 890 static char rcsid[] = "@(#)$Id: getloadavg.c,v 1.16 1991/06/21 12:51:15 paul Exp $"; 891 #endif /* !lint */ 892 893 #ifdef apollo 894 # undef volatile 895 # include <apollo/base.h> 896 897 /* ARGSUSED */ 898 int getloadavg( call_data ) 899 caddr_t call_data; /* pointer to (double) return value */ 900 { 901 double *avenrun = (double *) call_data; 902 int i; 903 status_$t st; 904 long loadav[3]; 905 proc1_$get_loadav(loadav, &st); 906 *avenrun = loadav[0] / (double) (1 << 16); 907 return(0); 908 } 909 # endif /* apollo */ 910 /* 911 ** SHOULDQUEUE -- should this message be queued or sent? 912 ** 913 ** Compares the message cost to the load average to decide. 914 ** 915 ** Parameters: 916 ** pri -- the priority of the message in question. 917 ** ctime -- the message creation time. 918 ** 919 ** Returns: 920 ** TRUE -- if this message should be queued up for the 921 ** time being. 922 ** FALSE -- if the load is low enough to send this message. 923 ** 924 ** Side Effects: 925 ** none. 926 */ 927 928 bool 929 shouldqueue(pri, ctime) 930 long pri; 931 time_t ctime; 932 { 933 if (CurrentLA < QueueLA) 934 return (FALSE); 935 if (CurrentLA >= RefuseLA) 936 return (TRUE); 937 return (pri > (QueueFactor / (CurrentLA - QueueLA + 1))); 938 } 939 /* 940 ** REFUSECONNECTIONS -- decide if connections should be refused 941 ** 942 ** Parameters: 943 ** none. 944 ** 945 ** Returns: 946 ** TRUE if incoming SMTP connections should be refused 947 ** (for now). 948 ** FALSE if we should accept new work. 949 ** 950 ** Side Effects: 951 ** none. 952 */ 953 954 bool 955 refuseconnections() 956 { 957 #ifdef XLA 958 if (!xla_smtp_ok()) 959 return TRUE; 960 #endif 961 962 /* this is probably too simplistic */ 963 return (CurrentLA >= RefuseLA); 964 } 965 /* 966 ** SETPROCTITLE -- set process title for ps 967 ** 968 ** Parameters: 969 ** fmt -- a printf style format string. 970 ** a, b, c -- possible parameters to fmt. 971 ** 972 ** Returns: 973 ** none. 974 ** 975 ** Side Effects: 976 ** Clobbers argv of our main procedure so ps(1) will 977 ** display the title. 978 */ 979 980 #ifdef SETPROCTITLE 981 # ifdef HASSETPROCTITLE 982 *** ERROR *** Cannot have both SETPROCTITLE and HASSETPROCTITLE defined 983 # endif 984 # ifdef __hpux 985 # include <sys/pstat.h> 986 # endif 987 # ifdef BSD4_4 988 # include <machine/vmparam.h> 989 # include <sys/exec.h> 990 # ifdef __bsdi__ 991 # undef PS_STRINGS /* BSDI 1.0 doesn't do PS_STRINGS as we expect */ 992 # define PROCTITLEPAD '\0' 993 # endif 994 # ifdef PS_STRINGS 995 # define SETPROC_STATIC static 996 # endif 997 # endif 998 # ifndef SETPROC_STATIC 999 # define SETPROC_STATIC 1000 # endif 1001 #endif 1002 1003 #ifndef PROCTITLEPAD 1004 # define PROCTITLEPAD ' ' 1005 #endif 1006 1007 #ifndef HASSETPROCTITLE 1008 1009 /*VARARGS1*/ 1010 #ifdef __STDC__ 1011 setproctitle(char *fmt, ...) 1012 #else 1013 setproctitle(fmt, va_alist) 1014 char *fmt; 1015 va_dcl 1016 #endif 1017 { 1018 # ifdef SETPROCTITLE 1019 register char *p; 1020 register int i; 1021 SETPROC_STATIC char buf[MAXLINE]; 1022 VA_LOCAL_DECL 1023 # ifdef __hpux 1024 union pstun pst; 1025 # endif 1026 extern char **Argv; 1027 extern char *LastArgv; 1028 1029 p = buf; 1030 1031 /* print sendmail: heading for grep */ 1032 (void) strcpy(p, "sendmail: "); 1033 p += strlen(p); 1034 1035 /* print the argument string */ 1036 VA_START(fmt); 1037 (void) vsprintf(p, fmt, ap); 1038 VA_END; 1039 1040 i = strlen(buf); 1041 1042 # ifdef __hpux 1043 pst.pst_command = buf; 1044 pstat(PSTAT_SETCMD, pst, i, 0, 0); 1045 # else 1046 # ifdef PS_STRINGS 1047 PS_STRINGS->ps_nargvstr = 1; 1048 PS_STRINGS->ps_argvstr = buf; 1049 # else 1050 if (i > LastArgv - Argv[0] - 2) 1051 { 1052 i = LastArgv - Argv[0] - 2; 1053 buf[i] = '\0'; 1054 } 1055 (void) strcpy(Argv[0], buf); 1056 p = &Argv[0][i]; 1057 while (p < LastArgv) 1058 *p++ = PROCTITLEPAD; 1059 # endif 1060 # endif 1061 # endif /* SETPROCTITLE */ 1062 } 1063 1064 #endif 1065 /* 1066 ** REAPCHILD -- pick up the body of my child, lest it become a zombie 1067 ** 1068 ** Parameters: 1069 ** none. 1070 ** 1071 ** Returns: 1072 ** none. 1073 ** 1074 ** Side Effects: 1075 ** Picks up extant zombies. 1076 */ 1077 1078 void 1079 reapchild() 1080 { 1081 int olderrno = errno; 1082 # ifdef HASWAITPID 1083 auto int status; 1084 int count; 1085 int pid; 1086 1087 count = 0; 1088 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) 1089 { 1090 if (count++ > 1000) 1091 { 1092 #ifdef LOG 1093 syslog(LOG_ALERT, "reapchild: waitpid loop: pid=%d, status=%x", 1094 pid, status); 1095 #endif 1096 break; 1097 } 1098 } 1099 # else 1100 # ifdef WNOHANG 1101 union wait status; 1102 1103 while (wait3(&status, WNOHANG, (struct rusage *) NULL) > 0) 1104 continue; 1105 # else /* WNOHANG */ 1106 auto int status; 1107 1108 while (wait(&status) > 0) 1109 continue; 1110 # endif /* WNOHANG */ 1111 # endif 1112 # ifdef SYS5SIGNALS 1113 (void) setsignal(SIGCHLD, reapchild); 1114 # endif 1115 errno = olderrno; 1116 } 1117 /* 1118 ** UNSETENV -- remove a variable from the environment 1119 ** 1120 ** Not needed on newer systems. 1121 ** 1122 ** Parameters: 1123 ** name -- the string name of the environment variable to be 1124 ** deleted from the current environment. 1125 ** 1126 ** Returns: 1127 ** none. 1128 ** 1129 ** Globals: 1130 ** environ -- a pointer to the current environment. 1131 ** 1132 ** Side Effects: 1133 ** Modifies environ. 1134 */ 1135 1136 #ifndef HASUNSETENV 1137 1138 void 1139 unsetenv(name) 1140 char *name; 1141 { 1142 extern char **environ; 1143 register char **pp; 1144 int len = strlen(name); 1145 1146 for (pp = environ; *pp != NULL; pp++) 1147 { 1148 if (strncmp(name, *pp, len) == 0 && 1149 ((*pp)[len] == '=' || (*pp)[len] == '\0')) 1150 break; 1151 } 1152 1153 for (; *pp != NULL; pp++) 1154 *pp = pp[1]; 1155 } 1156 1157 #endif 1158 /* 1159 ** GETDTABLESIZE -- return number of file descriptors 1160 ** 1161 ** Only on non-BSD systems 1162 ** 1163 ** Parameters: 1164 ** none 1165 ** 1166 ** Returns: 1167 ** size of file descriptor table 1168 ** 1169 ** Side Effects: 1170 ** none 1171 */ 1172 1173 #ifdef SOLARIS 1174 # include <sys/resource.h> 1175 #endif 1176 1177 int 1178 getdtsize() 1179 { 1180 #ifdef RLIMIT_NOFILE 1181 struct rlimit rl; 1182 1183 if (getrlimit(RLIMIT_NOFILE, &rl) >= 0) 1184 return rl.rlim_cur; 1185 #endif 1186 1187 # ifdef HASGETDTABLESIZE 1188 return getdtablesize(); 1189 # else 1190 # ifdef _SC_OPEN_MAX 1191 return sysconf(_SC_OPEN_MAX); 1192 # else 1193 return NOFILE; 1194 # endif 1195 # endif 1196 } 1197 /* 1198 ** UNAME -- get the UUCP name of this system. 1199 */ 1200 1201 #ifndef HASUNAME 1202 1203 int 1204 uname(name) 1205 struct utsname *name; 1206 { 1207 FILE *file; 1208 char *n; 1209 1210 name->nodename[0] = '\0'; 1211 1212 /* try /etc/whoami -- one line with the node name */ 1213 if ((file = fopen("/etc/whoami", "r")) != NULL) 1214 { 1215 (void) fgets(name->nodename, NODE_LENGTH + 1, file); 1216 (void) fclose(file); 1217 n = strchr(name->nodename, '\n'); 1218 if (n != NULL) 1219 *n = '\0'; 1220 if (name->nodename[0] != '\0') 1221 return (0); 1222 } 1223 1224 /* try /usr/include/whoami.h -- has a #define somewhere */ 1225 if ((file = fopen("/usr/include/whoami.h", "r")) != NULL) 1226 { 1227 char buf[MAXLINE]; 1228 1229 while (fgets(buf, MAXLINE, file) != NULL) 1230 if (sscanf(buf, "#define sysname \"%*[^\"]\"", 1231 NODE_LENGTH, name->nodename) > 0) 1232 break; 1233 (void) fclose(file); 1234 if (name->nodename[0] != '\0') 1235 return (0); 1236 } 1237 1238 #ifdef TRUST_POPEN 1239 /* 1240 ** Popen is known to have security holes. 1241 */ 1242 1243 /* try uuname -l to return local name */ 1244 if ((file = popen("uuname -l", "r")) != NULL) 1245 { 1246 (void) fgets(name, NODE_LENGTH + 1, file); 1247 (void) pclose(file); 1248 n = strchr(name, '\n'); 1249 if (n != NULL) 1250 *n = '\0'; 1251 if (name->nodename[0] != '\0') 1252 return (0); 1253 } 1254 #endif 1255 1256 return (-1); 1257 } 1258 #endif /* HASUNAME */ 1259 /* 1260 ** INITGROUPS -- initialize groups 1261 ** 1262 ** Stub implementation for System V style systems 1263 */ 1264 1265 #ifndef HASINITGROUPS 1266 1267 initgroups(name, basegid) 1268 char *name; 1269 int basegid; 1270 { 1271 return 0; 1272 } 1273 1274 #endif 1275 /* 1276 ** SETSID -- set session id (for non-POSIX systems) 1277 */ 1278 1279 #ifndef HASSETSID 1280 1281 pid_t 1282 setsid __P ((void)) 1283 { 1284 #ifdef TIOCNOTTY 1285 int fd; 1286 1287 fd = open("/dev/tty", O_RDWR, 0); 1288 if (fd >= 0) 1289 { 1290 (void) ioctl(fd, (int) TIOCNOTTY, (char *) 0); 1291 (void) close(fd); 1292 } 1293 #endif /* TIOCNOTTY */ 1294 # ifdef SYS5SETPGRP 1295 return setpgrp(); 1296 # else 1297 return setpgid(0, getpid()); 1298 # endif 1299 } 1300 1301 #endif 1302 /* 1303 ** FSYNC -- dummy fsync 1304 */ 1305 1306 #ifdef NEEDFSYNC 1307 1308 fsync(fd) 1309 int fd; 1310 { 1311 # ifdef O_SYNC 1312 return fcntl(fd, F_SETFL, O_SYNC); 1313 # else 1314 /* nothing we can do */ 1315 return 0; 1316 # endif 1317 } 1318 1319 #endif 1320 /* 1321 ** DGUX_INET_ADDR -- inet_addr for DG/UX 1322 ** 1323 ** Data General DG/UX version of inet_addr returns a struct in_addr 1324 ** instead of a long. This patches things. 1325 */ 1326 1327 #ifdef DGUX 1328 1329 #undef inet_addr 1330 1331 long 1332 dgux_inet_addr(host) 1333 char *host; 1334 { 1335 struct in_addr haddr; 1336 1337 haddr = inet_addr(host); 1338 return haddr.s_addr; 1339 } 1340 1341 #endif 1342 /* 1343 ** GETOPT -- for old systems or systems with bogus implementations 1344 */ 1345 1346 #ifdef NEEDGETOPT 1347 1348 /* 1349 * Copyright (c) 1985 Regents of the University of California. 1350 * All rights reserved. The Berkeley software License Agreement 1351 * specifies the terms and conditions for redistribution. 1352 */ 1353 1354 1355 /* 1356 ** this version hacked to add `atend' flag to allow state machine 1357 ** to reset if invoked by the program to scan args for a 2nd time 1358 */ 1359 1360 #if defined(LIBC_SCCS) && !defined(lint) 1361 static char sccsid[] = "@(#)getopt.c 4.3 (Berkeley) 3/9/86"; 1362 #endif /* LIBC_SCCS and not lint */ 1363 1364 #include <stdio.h> 1365 1366 /* 1367 * get option letter from argument vector 1368 */ 1369 #ifdef _CONVEX_SOURCE 1370 extern int optind, opterr; 1371 #else 1372 int opterr = 1; /* if error message should be printed */ 1373 int optind = 1; /* index into parent argv vector */ 1374 #endif 1375 int optopt; /* character checked for validity */ 1376 char *optarg; /* argument associated with option */ 1377 1378 #define BADCH (int)'?' 1379 #define EMSG "" 1380 #define tell(s) if (opterr) {fputs(*nargv,stderr);fputs(s,stderr); \ 1381 fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);} 1382 1383 getopt(nargc,nargv,ostr) 1384 int nargc; 1385 char *const *nargv; 1386 const char *ostr; 1387 { 1388 static char *place = EMSG; /* option letter processing */ 1389 static char atend = 0; 1390 register char *oli; /* option letter list index */ 1391 1392 if (atend) { 1393 atend = 0; 1394 place = EMSG; 1395 } 1396 if(!*place) { /* update scanning pointer */ 1397 if (optind >= nargc || *(place = nargv[optind]) != '-' || !*++place) { 1398 atend++; 1399 return(EOF); 1400 } 1401 if (*place == '-') { /* found "--" */ 1402 ++optind; 1403 atend++; 1404 return(EOF); 1405 } 1406 } /* option letter okay? */ 1407 if ((optopt = (int)*place++) == (int)':' || !(oli = strchr(ostr,optopt))) { 1408 if (!*place) ++optind; 1409 tell(": illegal option -- "); 1410 } 1411 if (*++oli != ':') { /* don't need argument */ 1412 optarg = NULL; 1413 if (!*place) ++optind; 1414 } 1415 else { /* need an argument */ 1416 if (*place) optarg = place; /* no white space */ 1417 else if (nargc <= ++optind) { /* no arg */ 1418 place = EMSG; 1419 tell(": option requires an argument -- "); 1420 } 1421 else optarg = nargv[optind]; /* white space */ 1422 place = EMSG; 1423 ++optind; 1424 } 1425 return(optopt); /* dump back option letter */ 1426 } 1427 1428 #endif 1429 /* 1430 ** VFPRINTF, VSPRINTF -- for old 4.3 BSD systems missing a real version 1431 */ 1432 1433 #ifdef NEEDVPRINTF 1434 1435 #define MAXARG 16 1436 1437 vfprintf(fp, fmt, ap) 1438 FILE * fp; 1439 char * fmt; 1440 char ** ap; 1441 { 1442 char * bp[MAXARG]; 1443 int i = 0; 1444 1445 while (*ap && i < MAXARG) 1446 bp[i++] = *ap++; 1447 fprintf(fp, fmt, bp[0], bp[1], bp[2], bp[3], 1448 bp[4], bp[5], bp[6], bp[7], 1449 bp[8], bp[9], bp[10], bp[11], 1450 bp[12], bp[13], bp[14], bp[15]); 1451 } 1452 1453 vsprintf(s, fmt, ap) 1454 char * s; 1455 char * fmt; 1456 char ** ap; 1457 { 1458 char * bp[MAXARG]; 1459 int i = 0; 1460 1461 while (*ap && i < MAXARG) 1462 bp[i++] = *ap++; 1463 sprintf(s, fmt, bp[0], bp[1], bp[2], bp[3], 1464 bp[4], bp[5], bp[6], bp[7], 1465 bp[8], bp[9], bp[10], bp[11], 1466 bp[12], bp[13], bp[14], bp[15]); 1467 } 1468 1469 #endif 1470 /* 1471 ** USERSHELLOK -- tell if a user's shell is ok for unrestricted use 1472 ** 1473 ** Parameters: 1474 ** shell -- the user's shell from /etc/passwd 1475 ** 1476 ** Returns: 1477 ** TRUE -- if it is ok to use this for unrestricted access. 1478 ** FALSE -- if the shell is restricted. 1479 */ 1480 1481 #if !HASGETUSERSHELL 1482 1483 # ifndef _PATH_SHELLS 1484 # define _PATH_SHELLS "/etc/shells" 1485 # endif 1486 1487 char *DefaultUserShells[] = 1488 { 1489 "/bin/sh", 1490 "/usr/bin/sh", 1491 "/bin/csh", 1492 "/usr/bin/csh", 1493 #ifdef __hpux 1494 "/bin/rsh", 1495 "/bin/ksh", 1496 "/bin/rksh", 1497 "/bin/pam", 1498 "/usr/bin/keysh", 1499 "/bin/posix/sh", 1500 #endif 1501 NULL 1502 }; 1503 1504 #endif 1505 1506 #define WILDCARD_SHELL "/SENDMAIL/ANY/SHELL/" 1507 1508 bool 1509 usershellok(shell) 1510 char *shell; 1511 { 1512 #if HASGETUSERSHELL 1513 register char *p; 1514 extern char *getusershell(); 1515 1516 setusershell(); 1517 while ((p = getusershell()) != NULL) 1518 if (strcmp(p, shell) == 0 || strcmp(p, WILDCARD_SHELL) == 0) 1519 break; 1520 endusershell(); 1521 return p != NULL; 1522 #else 1523 register FILE *shellf; 1524 char buf[MAXLINE]; 1525 1526 shellf = fopen(_PATH_SHELLS, "r"); 1527 if (shellf == NULL) 1528 { 1529 /* no /etc/shells; see if it is one of the std shells */ 1530 char **d; 1531 1532 for (d = DefaultUserShells; *d != NULL; d++) 1533 { 1534 if (strcmp(shell, *d) == 0) 1535 return TRUE; 1536 } 1537 return FALSE; 1538 } 1539 1540 while (fgets(buf, sizeof buf, shellf) != NULL) 1541 { 1542 register char *p, *q; 1543 1544 p = buf; 1545 while (*p != '\0' && *p != '#' && *p != '/') 1546 p++; 1547 if (*p == '#' || *p == '\0') 1548 continue; 1549 q = p; 1550 while (*p != '\0' && *p != '#' && !isspace(*p)) 1551 p++; 1552 *p = '\0'; 1553 if (strcmp(shell, q) == 0 || strcmp(WILDCARD_SHELL, q) == 0) 1554 { 1555 fclose(shellf); 1556 return TRUE; 1557 } 1558 } 1559 fclose(shellf); 1560 return FALSE; 1561 #endif 1562 } 1563 /* 1564 ** FREESPACE -- see how much free space is on the queue filesystem 1565 ** 1566 ** Only implemented if you have statfs. 1567 ** 1568 ** Parameters: 1569 ** dir -- the directory in question. 1570 ** bsize -- a variable into which the filesystem 1571 ** block size is stored. 1572 ** 1573 ** Returns: 1574 ** The number of bytes free on the queue filesystem. 1575 ** -1 if the statfs call fails. 1576 ** 1577 ** Side effects: 1578 ** Puts the filesystem block size into bsize. 1579 */ 1580 1581 /* statfs types */ 1582 #define SFS_NONE 0 /* no statfs implementation */ 1583 #define SFS_USTAT 1 /* use ustat */ 1584 #define SFS_4ARGS 2 /* use four-argument statfs call */ 1585 #define SFS_VFS 3 /* use <sys/vfs.h> implementation */ 1586 #define SFS_MOUNT 4 /* use <sys/mount.h> implementation */ 1587 #define SFS_STATFS 5 /* use <sys/statfs.h> implementation */ 1588 1589 #ifndef SFS_TYPE 1590 # define SFS_TYPE SFS_NONE 1591 #endif 1592 1593 #if SFS_TYPE == SFS_USTAT 1594 # include <ustat.h> 1595 #endif 1596 #if SFS_TYPE == SFS_4ARGS || SFS_TYPE == SFS_STATFS 1597 # include <sys/statfs.h> 1598 #endif 1599 #if SFS_TYPE == SFS_VFS 1600 # include <sys/vfs.h> 1601 #endif 1602 #if SFS_TYPE == SFS_MOUNT 1603 # include <sys/mount.h> 1604 #endif 1605 1606 long 1607 freespace(dir, bsize) 1608 char *dir; 1609 long *bsize; 1610 { 1611 #if SFS_TYPE != SFS_NONE 1612 # if SFS_TYPE == SFS_USTAT 1613 struct ustat fs; 1614 struct stat statbuf; 1615 # define FSBLOCKSIZE DEV_BSIZE 1616 # define f_bavail f_tfree 1617 # else 1618 # if defined(ultrix) 1619 struct fs_data fs; 1620 # define f_bavail fd_bfreen 1621 # define FSBLOCKSIZE fs.fd_bsize 1622 # else 1623 struct statfs fs; 1624 # define FSBLOCKSIZE fs.f_bsize 1625 # if defined(_SCO_unix_) || defined(IRIX) || defined(apollo) 1626 # define f_bavail f_bfree 1627 # endif 1628 # endif 1629 # endif 1630 extern int errno; 1631 1632 # if SFS_TYPE == SFS_USTAT 1633 if (stat(dir, &statbuf) == 0 && ustat(statbuf.st_dev, &fs) == 0) 1634 # else 1635 # if SFS_TYPE == SFS_4ARGS 1636 if (statfs(dir, &fs, sizeof fs, 0) == 0) 1637 # else 1638 # if defined(ultrix) 1639 if (statfs(dir, &fs) > 0) 1640 # else 1641 if (statfs(dir, &fs) == 0) 1642 # endif 1643 # endif 1644 # endif 1645 { 1646 if (bsize != NULL) 1647 *bsize = FSBLOCKSIZE; 1648 return (fs.f_bavail); 1649 } 1650 #endif 1651 return (-1); 1652 } 1653 /* 1654 ** ENOUGHSPACE -- check to see if there is enough free space on the queue fs 1655 ** 1656 ** Only implemented if you have statfs. 1657 ** 1658 ** Parameters: 1659 ** msize -- the size to check against. If zero, we don't yet 1660 ** know how big the message will be, so just check for 1661 ** a "reasonable" amount. 1662 ** 1663 ** Returns: 1664 ** TRUE if there is enough space. 1665 ** FALSE otherwise. 1666 */ 1667 1668 bool 1669 enoughspace(msize) 1670 long msize; 1671 { 1672 long bfree, bsize; 1673 1674 if (MinBlocksFree <= 0 && msize <= 0) 1675 { 1676 if (tTd(4, 80)) 1677 printf("enoughspace: no threshold\n"); 1678 return TRUE; 1679 } 1680 1681 if ((bfree = freespace(QueueDir, &bsize)) >= 0) 1682 { 1683 if (tTd(4, 80)) 1684 printf("enoughspace: bavail=%ld, need=%ld\n", 1685 bfree, msize); 1686 1687 /* convert msize to block count */ 1688 msize = msize / bsize + 1; 1689 if (MinBlocksFree >= 0) 1690 msize += MinBlocksFree; 1691 1692 if (bfree < msize) 1693 { 1694 #ifdef LOG 1695 if (LogLevel > 0) 1696 syslog(LOG_ALERT, 1697 "%s: low on space (have %ld, %s needs %ld in %s)", 1698 CurEnv->e_id, bfree, 1699 CurHostName, msize, QueueDir); 1700 #endif 1701 return FALSE; 1702 } 1703 } 1704 else if (tTd(4, 80)) 1705 printf("enoughspace failure: min=%ld, need=%ld: %s\n", 1706 MinBlocksFree, msize, errstring(errno)); 1707 return TRUE; 1708 } 1709 /* 1710 ** TRANSIENTERROR -- tell if an error code indicates a transient failure 1711 ** 1712 ** This looks at an errno value and tells if this is likely to 1713 ** go away if retried later. 1714 ** 1715 ** Parameters: 1716 ** err -- the errno code to classify. 1717 ** 1718 ** Returns: 1719 ** TRUE if this is probably transient. 1720 ** FALSE otherwise. 1721 */ 1722 1723 bool 1724 transienterror(err) 1725 int err; 1726 { 1727 switch (err) 1728 { 1729 case EIO: /* I/O error */ 1730 case ENXIO: /* Device not configured */ 1731 case EAGAIN: /* Resource temporarily unavailable */ 1732 case ENOMEM: /* Cannot allocate memory */ 1733 case ENODEV: /* Operation not supported by device */ 1734 case ENFILE: /* Too many open files in system */ 1735 case EMFILE: /* Too many open files */ 1736 case ENOSPC: /* No space left on device */ 1737 #ifdef ETIMEDOUT 1738 case ETIMEDOUT: /* Connection timed out */ 1739 #endif 1740 #ifdef ESTALE 1741 case ESTALE: /* Stale NFS file handle */ 1742 #endif 1743 #ifdef ENETDOWN 1744 case ENETDOWN: /* Network is down */ 1745 #endif 1746 #ifdef ENETUNREACH 1747 case ENETUNREACH: /* Network is unreachable */ 1748 #endif 1749 #ifdef ENETRESET 1750 case ENETRESET: /* Network dropped connection on reset */ 1751 #endif 1752 #ifdef ECONNABORTED 1753 case ECONNABORTED: /* Software caused connection abort */ 1754 #endif 1755 #ifdef ECONNRESET 1756 case ECONNRESET: /* Connection reset by peer */ 1757 #endif 1758 #ifdef ENOBUFS 1759 case ENOBUFS: /* No buffer space available */ 1760 #endif 1761 #ifdef ESHUTDOWN 1762 case ESHUTDOWN: /* Can't send after socket shutdown */ 1763 #endif 1764 #ifdef ECONNREFUSED 1765 case ECONNREFUSED: /* Connection refused */ 1766 #endif 1767 #ifdef EHOSTDOWN 1768 case EHOSTDOWN: /* Host is down */ 1769 #endif 1770 #ifdef EHOSTUNREACH 1771 case EHOSTUNREACH: /* No route to host */ 1772 #endif 1773 #ifdef EDQUOT 1774 case EDQUOT: /* Disc quota exceeded */ 1775 #endif 1776 #ifdef EPROCLIM 1777 case EPROCLIM: /* Too many processes */ 1778 #endif 1779 #ifdef EUSERS 1780 case EUSERS: /* Too many users */ 1781 #endif 1782 #ifdef EDEADLK 1783 case EDEADLK: /* Resource deadlock avoided */ 1784 #endif 1785 #ifdef EISCONN 1786 case EISCONN: /* Socket already connected */ 1787 #endif 1788 #ifdef EINPROGRESS 1789 case EINPROGRESS: /* Operation now in progress */ 1790 #endif 1791 #ifdef EALREADY 1792 case EALREADY: /* Operation already in progress */ 1793 #endif 1794 #ifdef EADDRINUSE 1795 case EADDRINUSE: /* Address already in use */ 1796 #endif 1797 #ifdef EADDRNOTAVAIL 1798 case EADDRNOTAVAIL: /* Can't assign requested address */ 1799 #endif 1800 #ifdef ETXTBSY 1801 case ETXTBSY: /* (Apollo) file locked */ 1802 #endif 1803 #if defined(ENOSR) && (!defined(ENOBUFS) || (ENOBUFS != ENOSR)) 1804 case ENOSR: /* Out of streams resources */ 1805 #endif 1806 return TRUE; 1807 } 1808 1809 /* nope, must be permanent */ 1810 return FALSE; 1811 } 1812 /* 1813 ** LOCKFILE -- lock a file using flock or (shudder) fcntl locking 1814 ** 1815 ** Parameters: 1816 ** fd -- the file descriptor of the file. 1817 ** filename -- the file name (for error messages). 1818 ** ext -- the filename extension. 1819 ** type -- type of the lock. Bits can be: 1820 ** LOCK_EX -- exclusive lock. 1821 ** LOCK_NB -- non-blocking. 1822 ** 1823 ** Returns: 1824 ** TRUE if the lock was acquired. 1825 ** FALSE otherwise. 1826 */ 1827 1828 bool 1829 lockfile(fd, filename, ext, type) 1830 int fd; 1831 char *filename; 1832 char *ext; 1833 int type; 1834 { 1835 # if !HASFLOCK 1836 int action; 1837 struct flock lfd; 1838 1839 if (ext == NULL) 1840 ext = ""; 1841 1842 bzero(&lfd, sizeof lfd); 1843 if (bitset(LOCK_UN, type)) 1844 lfd.l_type = F_UNLCK; 1845 else if (bitset(LOCK_EX, type)) 1846 lfd.l_type = F_WRLCK; 1847 else 1848 lfd.l_type = F_RDLCK; 1849 1850 if (bitset(LOCK_NB, type)) 1851 action = F_SETLK; 1852 else 1853 action = F_SETLKW; 1854 1855 if (tTd(55, 60)) 1856 printf("lockfile(%s%s, action=%d, type=%d): ", 1857 filename, ext, action, lfd.l_type); 1858 1859 if (fcntl(fd, action, &lfd) >= 0) 1860 { 1861 if (tTd(55, 60)) 1862 printf("SUCCESS\n"); 1863 return TRUE; 1864 } 1865 1866 if (tTd(55, 60)) 1867 printf("(%s) ", errstring(errno)); 1868 1869 /* 1870 ** On SunOS, if you are testing using -oQ/tmp/mqueue or 1871 ** -oA/tmp/aliases or anything like that, and /tmp is mounted 1872 ** as type "tmp" (that is, served from swap space), the 1873 ** previous fcntl will fail with "Invalid argument" errors. 1874 ** Since this is fairly common during testing, we will assume 1875 ** that this indicates that the lock is successfully grabbed. 1876 */ 1877 1878 if (errno == EINVAL) 1879 { 1880 if (tTd(55, 60)) 1881 printf("SUCCESS\n"); 1882 return TRUE; 1883 } 1884 1885 if (!bitset(LOCK_NB, type) || (errno != EACCES && errno != EAGAIN)) 1886 { 1887 int omode = -1; 1888 # ifdef F_GETFL 1889 int oerrno = errno; 1890 1891 (void) fcntl(fd, F_GETFL, &omode); 1892 errno = oerrno; 1893 # endif 1894 syserr("cannot lockf(%s%s, fd=%d, type=%o, omode=%o, euid=%d)", 1895 filename, ext, fd, type, omode, geteuid()); 1896 } 1897 # else 1898 if (ext == NULL) 1899 ext = ""; 1900 1901 if (tTd(55, 60)) 1902 printf("lockfile(%s%s, type=%o): ", filename, ext, type); 1903 1904 if (flock(fd, type) >= 0) 1905 { 1906 if (tTd(55, 60)) 1907 printf("SUCCESS\n"); 1908 return TRUE; 1909 } 1910 1911 if (tTd(55, 60)) 1912 printf("(%s) ", errstring(errno)); 1913 1914 if (!bitset(LOCK_NB, type) || errno != EWOULDBLOCK) 1915 { 1916 int omode = -1; 1917 # ifdef F_GETFL 1918 int oerrno = errno; 1919 1920 (void) fcntl(fd, F_GETFL, &omode); 1921 errno = oerrno; 1922 # endif 1923 syserr("cannot flock(%s%s, fd=%d, type=%o, omode=%o, euid=%d)", 1924 filename, ext, fd, type, omode, geteuid()); 1925 } 1926 # endif 1927 if (tTd(55, 60)) 1928 printf("FAIL\n"); 1929 return FALSE; 1930 } 1931 /* 1932 ** CHOWNSAFE -- tell if chown is "safe" (executable only by root) 1933 ** 1934 ** Parameters: 1935 ** fd -- the file descriptor to check. 1936 ** 1937 ** Returns: 1938 ** TRUE -- if only root can chown the file to an arbitrary 1939 ** user. 1940 ** FALSE -- if an arbitrary user can give away a file. 1941 */ 1942 1943 bool 1944 chownsafe(fd) 1945 int fd; 1946 { 1947 #ifdef __hpux 1948 char *s; 1949 int tfd; 1950 uid_t o_uid, o_euid; 1951 gid_t o_gid, o_egid; 1952 bool rval; 1953 struct stat stbuf; 1954 1955 o_uid = getuid(); 1956 o_euid = geteuid(); 1957 o_gid = getgid(); 1958 o_egid = getegid(); 1959 fstat(fd, &stbuf); 1960 setresuid(stbuf.st_uid, stbuf.st_uid, -1); 1961 setresgid(stbuf.st_gid, stbuf.st_gid, -1); 1962 s = tmpnam(NULL); 1963 tfd = open(s, O_RDONLY|O_CREAT, 0600); 1964 rval = fchown(tfd, DefUid, DefGid) != 0; 1965 close(tfd); 1966 unlink(s); 1967 setreuid(o_uid, o_euid); 1968 setresgid(o_gid, o_egid, -1); 1969 return rval; 1970 #else 1971 # ifdef _POSIX_CHOWN_RESTRICTED 1972 # if _POSIX_CHOWN_RESTRICTED == -1 1973 return FALSE; 1974 # else 1975 return TRUE; 1976 # endif 1977 # else 1978 # ifdef _PC_CHOWN_RESTRICTED 1979 return fpathconf(fd, _PC_CHOWN_RESTRICTED) > 0; 1980 # else 1981 # ifdef BSD 1982 return TRUE; 1983 # else 1984 return FALSE; 1985 # endif 1986 # endif 1987 # endif 1988 #endif 1989 } 1990 /* 1991 ** GETCFNAME -- return the name of the .cf file. 1992 ** 1993 ** Some systems (e.g., NeXT) determine this dynamically. 1994 */ 1995 1996 char * 1997 getcfname() 1998 { 1999 if (ConfFile != NULL) 2000 return ConfFile; 2001 #ifdef NETINFO 2002 { 2003 extern char *ni_propval(); 2004 char *cflocation; 2005 2006 cflocation = ni_propval("/locations/sendmail", "sendmail.cf"); 2007 if (cflocation != NULL) 2008 return cflocation; 2009 } 2010 #endif 2011 return _PATH_SENDMAILCF; 2012 } 2013 /* 2014 ** SETVENDOR -- process vendor code from V configuration line 2015 ** 2016 ** Parameters: 2017 ** vendor -- string representation of vendor. 2018 ** 2019 ** Returns: 2020 ** TRUE -- if ok. 2021 ** FALSE -- if vendor code could not be processed. 2022 ** 2023 ** Side Effects: 2024 ** It is reasonable to set mode flags here to tweak 2025 ** processing in other parts of the code if necessary. 2026 ** For example, if you are a vendor that uses $%y to 2027 ** indicate YP lookups, you could enable that here. 2028 */ 2029 2030 bool 2031 setvendor(vendor) 2032 char *vendor; 2033 { 2034 if (strcasecmp(vendor, "Berkeley") == 0) 2035 return TRUE; 2036 2037 /* add vendor extensions here */ 2038 2039 return FALSE; 2040 } 2041 /* 2042 ** STRTOL -- convert string to long integer 2043 ** 2044 ** For systems that don't have it in the C library. 2045 ** 2046 ** This is taken verbatim from the 4.4-Lite C library. 2047 */ 2048 2049 #ifdef NEEDSTRTOL 2050 2051 #if defined(LIBC_SCCS) && !defined(lint) 2052 static char sccsid[] = "@(#)strtol.c 8.1 (Berkeley) 6/4/93"; 2053 #endif /* LIBC_SCCS and not lint */ 2054 2055 #include <limits.h> 2056 2057 /* 2058 * Convert a string to a long integer. 2059 * 2060 * Ignores `locale' stuff. Assumes that the upper and lower case 2061 * alphabets and digits are each contiguous. 2062 */ 2063 2064 long 2065 strtol(nptr, endptr, base) 2066 const char *nptr; 2067 char **endptr; 2068 register int base; 2069 { 2070 register const char *s = nptr; 2071 register unsigned long acc; 2072 register int c; 2073 register unsigned long cutoff; 2074 register int neg = 0, any, cutlim; 2075 2076 /* 2077 * Skip white space and pick up leading +/- sign if any. 2078 * If base is 0, allow 0x for hex and 0 for octal, else 2079 * assume decimal; if base is already 16, allow 0x. 2080 */ 2081 do { 2082 c = *s++; 2083 } while (isspace(c)); 2084 if (c == '-') { 2085 neg = 1; 2086 c = *s++; 2087 } else if (c == '+') 2088 c = *s++; 2089 if ((base == 0 || base == 16) && 2090 c == '0' && (*s == 'x' || *s == 'X')) { 2091 c = s[1]; 2092 s += 2; 2093 base = 16; 2094 } 2095 if (base == 0) 2096 base = c == '0' ? 8 : 10; 2097 2098 /* 2099 * Compute the cutoff value between legal numbers and illegal 2100 * numbers. That is the largest legal value, divided by the 2101 * base. An input number that is greater than this value, if 2102 * followed by a legal input character, is too big. One that 2103 * is equal to this value may be valid or not; the limit 2104 * between valid and invalid numbers is then based on the last 2105 * digit. For instance, if the range for longs is 2106 * [-2147483648..2147483647] and the input base is 10, 2107 * cutoff will be set to 214748364 and cutlim to either 2108 * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated 2109 * a value > 214748364, or equal but the next digit is > 7 (or 8), 2110 * the number is too big, and we will return a range error. 2111 * 2112 * Set any if any `digits' consumed; make it negative to indicate 2113 * overflow. 2114 */ 2115 cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX; 2116 cutlim = cutoff % (unsigned long)base; 2117 cutoff /= (unsigned long)base; 2118 for (acc = 0, any = 0;; c = *s++) { 2119 if (isdigit(c)) 2120 c -= '0'; 2121 else if (isalpha(c)) 2122 c -= isupper(c) ? 'A' - 10 : 'a' - 10; 2123 else 2124 break; 2125 if (c >= base) 2126 break; 2127 if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim) 2128 any = -1; 2129 else { 2130 any = 1; 2131 acc *= base; 2132 acc += c; 2133 } 2134 } 2135 if (any < 0) { 2136 acc = neg ? LONG_MIN : LONG_MAX; 2137 errno = ERANGE; 2138 } else if (neg) 2139 acc = -acc; 2140 if (endptr != 0) 2141 *endptr = (char *)(any ? s - 1 : nptr); 2142 return (acc); 2143 } 2144 2145 #endif 2146 /* 2147 ** SOLARIS_GETHOSTBY{NAME,ADDR} -- compatibility routines for gethostbyXXX 2148 ** 2149 ** Solaris versions prior through 2.3 don't properly deliver a 2150 ** canonical h_name field. This tries to work around it. 2151 */ 2152 2153 #ifdef SOLARIS 2154 2155 struct hostent * 2156 solaris_gethostbyname(name) 2157 const char *name; 2158 { 2159 # ifdef SOLARIS_2_3 2160 static struct hostent hp; 2161 static char buf[1000]; 2162 extern struct hostent *_switch_gethostbyname_r(); 2163 2164 return _switch_gethostbyname_r(name, &hp, buf, sizeof(buf), &h_errno); 2165 # else 2166 extern struct hostent *__switch_gethostbyname(); 2167 2168 return __switch_gethostbyname(name); 2169 # endif 2170 } 2171 2172 struct hostent * 2173 solaris_gethostbyaddr(addr, len, type) 2174 const char *addr; 2175 int len; 2176 int type; 2177 { 2178 # ifdef SOLARIS_2_3 2179 static struct hostent hp; 2180 static char buf[1000]; 2181 extern struct hostent *_switch_gethostbyaddr_r(); 2182 2183 return _switch_gethostbyaddr_r(addr, len, type, &hp, buf, sizeof(buf), &h_errno); 2184 # else 2185 extern struct hostent *__switch_gethostbyaddr(); 2186 2187 return __switch_gethostbyaddr(addr, len, type); 2188 # endif 2189 } 2190 2191 #endif 2192 /* 2193 ** NI_PROPVAL -- netinfo property value lookup routine 2194 ** 2195 ** Parameters: 2196 ** directory -- the Netinfo directory name. 2197 ** propname -- the Netinfo property name. 2198 ** 2199 ** Returns: 2200 ** NULL -- if: 2201 ** 1. the directory is not found 2202 ** 2. the property name is not found 2203 ** 3. the property contains multiple values 2204 ** 4. some error occured 2205 ** else -- the location of the config file. 2206 ** 2207 ** Notes: 2208 ** Caller should free the return value of ni_proval 2209 */ 2210 2211 #ifdef NETINFO 2212 2213 # include <netinfo/ni.h> 2214 2215 # define LOCAL_NETINFO_DOMAIN "." 2216 # define PARENT_NETINFO_DOMAIN ".." 2217 # define MAX_NI_LEVELS 256 2218 2219 char * 2220 ni_propval(directory, propname) 2221 char *directory; 2222 char *propname; 2223 { 2224 char *propval = NULL; 2225 int i; 2226 void *ni = NULL; 2227 void *lastni = NULL; 2228 ni_status nis; 2229 ni_id nid; 2230 ni_namelist ninl; 2231 2232 /* 2233 ** If the passed directory and property name are found 2234 ** in one of netinfo domains we need to search (starting 2235 ** from the local domain moving all the way back to the 2236 ** root domain) set propval to the property's value 2237 ** and return it. 2238 */ 2239 2240 for (i = 0; i < MAX_NI_LEVELS; ++i) 2241 { 2242 if (i == 0) 2243 { 2244 nis = ni_open(NULL, LOCAL_NETINFO_DOMAIN, &ni); 2245 } 2246 else 2247 { 2248 if (lastni != NULL) 2249 ni_free(lastni); 2250 lastni = ni; 2251 nis = ni_open(lastni, PARENT_NETINFO_DOMAIN, &ni); 2252 } 2253 2254 /* 2255 ** Don't bother if we didn't get a handle on a 2256 ** proper domain. This is not necessarily an error. 2257 ** We would get a positive ni_status if, for instance 2258 ** we never found the directory or property and tried 2259 ** to open the parent of the root domain! 2260 */ 2261 2262 if (nis != 0) 2263 break; 2264 2265 /* 2266 ** Find the path to the server information. 2267 */ 2268 2269 if (ni_pathsearch(ni, &nid, directory) != 0) 2270 continue; 2271 2272 /* 2273 ** Find "host" information. 2274 */ 2275 2276 if (ni_lookupprop(ni, &nid, propname, &ninl) != 0) 2277 continue; 2278 2279 /* 2280 ** If there's only one name in 2281 ** the list, assume we've got 2282 ** what we want. 2283 */ 2284 2285 if (ninl.ni_namelist_len == 1) 2286 { 2287 propval = ni_name_dup(ninl.ni_namelist_val[0]); 2288 break; 2289 } 2290 } 2291 2292 /* 2293 ** Clean up. 2294 */ 2295 2296 if (ni != NULL) 2297 ni_free(ni); 2298 if (lastni != NULL && ni != lastni) 2299 ni_free(lastni); 2300 2301 return propval; 2302 } 2303 2304 #endif /* NETINFO */ 2305 /* 2306 ** HARD_SYSLOG -- call syslog repeatedly until it works 2307 ** 2308 ** Needed on HP-UX, which apparently doesn't guarantee that 2309 ** syslog succeeds during interrupt handlers. 2310 */ 2311 2312 #ifdef __hpux 2313 2314 # define MAXSYSLOGTRIES 100 2315 # undef syslog 2316 2317 # ifdef __STDC__ 2318 hard_syslog(int pri, char *msg, ...) 2319 # else 2320 hard_syslog(pri, msg, va_alist) 2321 int pri; 2322 char *msg; 2323 va_dcl 2324 # endif 2325 { 2326 int i; 2327 char buf[SYSLOG_BUFSIZE * 2]; 2328 VA_LOCAL_DECL; 2329 2330 VA_START(msg); 2331 vsprintf(buf, msg, ap); 2332 VA_END; 2333 2334 for (i = MAXSYSLOGTRIES; --i >= 0 && syslog(pri, "%s", buf) < 0; ) 2335 continue; 2336 } 2337 2338 #endif 2339