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