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