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