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