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