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