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