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