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.35 (Berkeley) 03/14/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 /* destination fields */ 67 "to", H_RCPT, 68 "resent-to", H_RCPT|H_RESENT, 69 "cc", H_RCPT, 70 "resent-cc", H_RCPT|H_RESENT, 71 "bcc", H_RCPT|H_ACHECK, 72 "resent-bcc", H_RCPT|H_ACHECK|H_RESENT, 73 "apparently-to", H_RCPT, 74 /* message identification and control */ 75 "message-id", 0, 76 "resent-message-id", H_RESENT, 77 "message", H_EOH, 78 "text", H_EOH, 79 /* date fields */ 80 "date", 0, 81 "resent-date", H_RESENT, 82 /* trace fields */ 83 "received", H_TRACE|H_FORCE, 84 "via", H_TRACE|H_FORCE, 85 "mail-from", H_TRACE|H_FORCE, 86 87 NULL, 0, 88 }; 89 90 91 92 /* 93 ** Location of system files/databases/etc. 94 */ 95 96 char *ConfFile = _PATH_SENDMAILCF; /* runtime configuration */ 97 char *FreezeFile = _PATH_SENDMAILFC; /* frozen version of above */ 98 char *PidFile = _PATH_SENDMAILPID; /* stores daemon proc id */ 99 100 101 102 /* 103 ** Privacy values 104 */ 105 106 struct prival PrivacyValues[] = 107 { 108 "public", PRIV_PUBLIC, 109 "needmailhelo", PRIV_NEEDMAILHELO, 110 "needexpnhelo", PRIV_NEEDEXPNHELO, 111 "needvrfyhelo", PRIV_NEEDVRFYHELO, 112 "noexpn", PRIV_NOEXPN, 113 "novrfy", PRIV_NOVRFY, 114 "restrictmailq", PRIV_RESTRMAILQ, 115 "goaway", PRIV_GOAWAY, 116 NULL, PRIV_PUBLIC, 117 }; 118 119 120 121 /* 122 ** Miscellaneous stuff. 123 */ 124 125 int DtableSize = 50; /* max open files; reset in 4.2bsd */ 126 /* 127 ** SETDEFAULTS -- set default values 128 ** 129 ** Because of the way freezing is done, these must be initialized 130 ** using direct code. 131 ** 132 ** Parameters: 133 ** none. 134 ** 135 ** Returns: 136 ** none. 137 ** 138 ** Side Effects: 139 ** Initializes a bunch of global variables to their 140 ** default values. 141 */ 142 143 setdefaults() 144 { 145 SpaceSub = ' '; /* option B */ 146 QueueLA = 8; /* option x */ 147 RefuseLA = 12; /* option X */ 148 WkRecipFact = 30000L; /* option y */ 149 WkClassFact = 1800L; /* option z */ 150 WkTimeFact = 90000L; /* option Z */ 151 QueueFactor = WkRecipFact * 20; /* option q */ 152 FileMode = (getuid() != geteuid()) ? 0644 : 0600; 153 /* option F */ 154 DefUid = 1; /* option u */ 155 DefGid = 1; /* option g */ 156 CheckpointInterval = 10; /* option C */ 157 MaxHopCount = 25; /* option h */ 158 SendMode = SM_FORK; /* option d */ 159 ErrorMode = EM_PRINT; /* option e */ 160 EightBit = FALSE; /* option 8 */ 161 MaxMciCache = 1; /* option k */ 162 MciCacheTimeout = 300; /* option K */ 163 LogLevel = 9; /* option L */ 164 settimeouts(NULL); /* option r */ 165 TimeOut = 5 * 24 * 60 * 60; /* option T */ 166 setdefuser(); 167 setupmaps(); 168 setupmailers(); 169 } 170 171 172 /* 173 ** SETDEFUSER -- set/reset DefUser using DefUid (for initgroups()) 174 */ 175 176 setdefuser() 177 { 178 struct passwd *defpwent; 179 static char defuserbuf[40]; 180 181 DefUser = defuserbuf; 182 if ((defpwent = getpwuid(DefUid)) != NULL) 183 strcpy(defuserbuf, defpwent->pw_name); 184 else 185 strcpy(defuserbuf, "nobody"); 186 } 187 /* 188 ** SETUPMAPS -- set up map classes 189 ** 190 ** Since these are compiled in, they cannot be in the config file. 191 ** 192 */ 193 194 setupmaps() 195 { 196 register STAB *s; 197 extern bool host_map_init(); 198 extern char *maphostname(); 199 200 /* set up host name lookup map */ 201 s = stab("host", ST_MAPCLASS, ST_ENTER); 202 s->s_mapclass.map_init = host_map_init; 203 s->s_mapclass.map_lookup = maphostname; 204 205 /* 206 ** Set up other map classes. 207 */ 208 209 # ifdef DBM_MAP 210 /* dbm file access */ 211 { 212 extern bool dbm_map_init(); 213 extern char *dbm_map_lookup(); 214 215 s = stab("dbm", ST_MAPCLASS, ST_ENTER); 216 s->s_mapclass.map_init = dbm_map_init; 217 s->s_mapclass.map_lookup = dbm_map_lookup; 218 } 219 # endif 220 221 # ifdef BTREE_MAP 222 /* new database file access -- btree files */ 223 { 224 extern bool bt_map_init(); 225 extern char *db_map_lookup(); 226 227 s = stab("btree", ST_MAPCLASS, ST_ENTER); 228 s->s_mapclass.map_init = bt_map_init; 229 s->s_mapclass.map_lookup = db_map_lookup; 230 } 231 # endif 232 233 # ifdef HASH_MAP 234 /* new database file access -- hash files */ 235 { 236 extern bool hash_map_init(); 237 extern char *db_map_lookup(); 238 239 s = stab("hash", ST_MAPCLASS, ST_ENTER); 240 s->s_mapclass.map_init = hash_map_init; 241 s->s_mapclass.map_lookup = db_map_lookup; 242 } 243 # endif 244 245 # ifdef NIS_MAP 246 /* NIS map access */ 247 { 248 extern bool nis_map_init(); 249 extern char *nis_map_lookup(); 250 251 s = stab("nis", ST_MAPCLASS, ST_ENTER); 252 s->s_mapclass.map_init = nis_map_init; 253 s->s_mapclass.map_lookup = nis_map_lookup; 254 } 255 # endif 256 257 # ifdef USERDB_MAP 258 /* user database */ 259 { 260 extern bool udb_map_init(); 261 extern char *udb_map_lookup(); 262 263 s = stab("udb", ST_MAPCLASS, ST_ENTER); 264 s->s_mapclass.map_init = udb_map_init; 265 s->s_mapclass.map_lookup = udb_map_lookup; 266 } 267 # endif 268 } 269 /* 270 ** HOST_MAP_INIT -- initialize host class structures 271 */ 272 273 bool 274 host_map_init(map, mapname, args) 275 MAP *map; 276 char *mapname; 277 char *args; 278 { 279 register char *p = args; 280 281 for (;;) 282 { 283 while (isascii(*p) && isspace(*p)) 284 p++; 285 if (*p != '-') 286 break; 287 switch (*++p) 288 { 289 case 'a': 290 map->map_app = ++p; 291 break; 292 } 293 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 294 p++; 295 if (*p != '\0') 296 *p++ = '\0'; 297 } 298 if (map->map_app != NULL) 299 map->map_app = newstr(map->map_app); 300 return TRUE; 301 } 302 /* 303 ** SETUPMAILERS -- initialize default mailers 304 */ 305 306 setupmailers() 307 { 308 char buf[100]; 309 310 strcpy(buf, "prog, P=/bin/sh, F=lsD, A=sh -c $u"); 311 makemailer(buf); 312 313 strcpy(buf, "*file*, P=/dev/null, F=lsDEu, A=FILE"); 314 makemailer(buf); 315 316 strcpy(buf, "*include*, P=/dev/null, F=su, A=INCLUDE"); 317 makemailer(buf); 318 } 319 /* 320 ** GETRUID -- get real user id (V7) 321 */ 322 323 getruid() 324 { 325 if (OpMode == MD_DAEMON) 326 return (RealUid); 327 else 328 return (getuid()); 329 } 330 331 332 /* 333 ** GETRGID -- get real group id (V7). 334 */ 335 336 getrgid() 337 { 338 if (OpMode == MD_DAEMON) 339 return (RealGid); 340 else 341 return (getgid()); 342 } 343 /* 344 ** USERNAME -- return the user id of the logged in user. 345 ** 346 ** Parameters: 347 ** none. 348 ** 349 ** Returns: 350 ** The login name of the logged in user. 351 ** 352 ** Side Effects: 353 ** none. 354 ** 355 ** Notes: 356 ** The return value is statically allocated. 357 */ 358 359 char * 360 username() 361 { 362 static char *myname = NULL; 363 extern char *getlogin(); 364 register struct passwd *pw; 365 366 /* cache the result */ 367 if (myname == NULL) 368 { 369 myname = getlogin(); 370 if (myname == NULL || myname[0] == '\0') 371 { 372 373 pw = getpwuid(getruid()); 374 if (pw != NULL) 375 myname = newstr(pw->pw_name); 376 } 377 else 378 { 379 380 myname = newstr(myname); 381 if ((pw = getpwnam(myname)) == NULL || 382 getuid() != pw->pw_uid) 383 { 384 pw = getpwuid(getuid()); 385 if (pw != NULL) 386 myname = newstr(pw->pw_name); 387 } 388 } 389 if (myname == NULL || myname[0] == '\0') 390 { 391 syserr("554 Who are you?"); 392 myname = "postmaster"; 393 } 394 } 395 396 return (myname); 397 } 398 /* 399 ** TTYPATH -- Get the path of the user's tty 400 ** 401 ** Returns the pathname of the user's tty. Returns NULL if 402 ** the user is not logged in or if s/he has write permission 403 ** denied. 404 ** 405 ** Parameters: 406 ** none 407 ** 408 ** Returns: 409 ** pathname of the user's tty. 410 ** NULL if not logged in or write permission denied. 411 ** 412 ** Side Effects: 413 ** none. 414 ** 415 ** WARNING: 416 ** Return value is in a local buffer. 417 ** 418 ** Called By: 419 ** savemail 420 */ 421 422 # include <sys/stat.h> 423 424 char * 425 ttypath() 426 { 427 struct stat stbuf; 428 register char *pathn; 429 extern char *ttyname(); 430 extern char *getlogin(); 431 432 /* compute the pathname of the controlling tty */ 433 if ((pathn = ttyname(2)) == NULL && (pathn = ttyname(1)) == NULL && 434 (pathn = ttyname(0)) == NULL) 435 { 436 errno = 0; 437 return (NULL); 438 } 439 440 /* see if we have write permission */ 441 if (stat(pathn, &stbuf) < 0 || !bitset(02, stbuf.st_mode)) 442 { 443 errno = 0; 444 return (NULL); 445 } 446 447 /* see if the user is logged in */ 448 if (getlogin() == NULL) 449 return (NULL); 450 451 /* looks good */ 452 return (pathn); 453 } 454 /* 455 ** CHECKCOMPAT -- check for From and To person compatible. 456 ** 457 ** This routine can be supplied on a per-installation basis 458 ** to determine whether a person is allowed to send a message. 459 ** This allows restriction of certain types of internet 460 ** forwarding or registration of users. 461 ** 462 ** If the hosts are found to be incompatible, an error 463 ** message should be given using "usrerr" and 0 should 464 ** be returned. 465 ** 466 ** 'NoReturn' can be set to suppress the return-to-sender 467 ** function; this should be done on huge messages. 468 ** 469 ** Parameters: 470 ** to -- the person being sent to. 471 ** 472 ** Returns: 473 ** an exit status 474 ** 475 ** Side Effects: 476 ** none (unless you include the usrerr stuff) 477 */ 478 479 checkcompat(to, e) 480 register ADDRESS *to; 481 register ENVELOPE *e; 482 { 483 # ifdef lint 484 if (to == NULL) 485 to++; 486 # endif lint 487 # ifdef EXAMPLE_CODE 488 /* this code is intended as an example only */ 489 register STAB *s; 490 491 s = stab("arpa", ST_MAILER, ST_FIND); 492 if (s != NULL && e->e_from.q_mailer != LocalMailer && 493 to->q_mailer == s->s_mailer) 494 { 495 usrerr("553 No ARPA mail through this machine: see your system administration"); 496 /* NoReturn = TRUE; to supress return copy */ 497 return (EX_UNAVAILABLE); 498 } 499 # endif /* EXAMPLE_CODE */ 500 return (EX_OK); 501 } 502 /* 503 ** HOLDSIGS -- arrange to hold all signals 504 ** 505 ** Parameters: 506 ** none. 507 ** 508 ** Returns: 509 ** none. 510 ** 511 ** Side Effects: 512 ** Arranges that signals are held. 513 */ 514 515 holdsigs() 516 { 517 } 518 /* 519 ** RLSESIGS -- arrange to release all signals 520 ** 521 ** This undoes the effect of holdsigs. 522 ** 523 ** Parameters: 524 ** none. 525 ** 526 ** Returns: 527 ** none. 528 ** 529 ** Side Effects: 530 ** Arranges that signals are released. 531 */ 532 533 rlsesigs() 534 { 535 } 536 /* 537 ** GETLA -- get the current load average 538 ** 539 ** This code stolen from la.c. 540 ** 541 ** Parameters: 542 ** none. 543 ** 544 ** Returns: 545 ** The current load average as an integer. 546 ** 547 ** Side Effects: 548 ** none. 549 */ 550 551 /* try to guess what style of load average we have */ 552 #define LA_ZERO 1 /* always return load average as zero */ 553 #define LA_INT 2 /* read kmem for avenrun; interpret as int */ 554 #define LA_FLOAT 3 /* read kmem for avenrun; interpret as float */ 555 #define LA_SUBR 4 /* call getloadavg */ 556 557 #ifndef LA_TYPE 558 # if defined(sun) 559 # define LA_TYPE LA_INT 560 # endif 561 # if defined(mips) || defined(__alpha) 562 /* Ultrix or OSF/1 or RISC/os */ 563 # define LA_TYPE LA_INT 564 # define LA_AVENRUN "avenrun" 565 # endif 566 # if defined(hpux) 567 # define LA_TYPE LA_FLOAT 568 # endif 569 570 # ifndef LA_TYPE 571 # if defined(SYSTEM5) 572 # define LA_TYPE LA_INT 573 # define LA_AVENRUN "avenrun" 574 # else 575 # if defined(BSD) 576 # define LA_TYPE LA_SUBR 577 # else 578 # define LA_TYPE LA_ZERO 579 # endif 580 # endif 581 # endif 582 #endif 583 584 #if (LA_TYPE == LA_INT) || (LA_TYPE == LA_FLOAT) 585 586 #include <nlist.h> 587 #include <fcntl.h> 588 589 #ifndef LA_AVENRUN 590 #define LA_AVENRUN "_avenrun" 591 #endif 592 593 /* _PATH_UNIX should be defined in <paths.h> */ 594 #ifndef _PATH_UNIX 595 # if defined(hpux) 596 # define _PATH_UNIX "/hp-ux" 597 # endif 598 # if defined(mips) && !defined(ultrix) 599 /* powerful RISC/os */ 600 # define _PATH_UNIX "/unix" 601 # endif 602 # if defined(SYSTEM5) 603 # ifndef _PATH_UNIX 604 # define _PATH_UNIX "/unix" 605 # endif 606 # endif 607 # ifndef _PATH_UNIX 608 # define _PATH_UNIX "/vmunix" 609 # endif 610 #endif 611 612 struct nlist Nl[] = 613 { 614 { LA_AVENRUN }, 615 #define X_AVENRUN 0 616 { 0 }, 617 }; 618 619 #if defined(unixpc) 620 # define FSHIFT 5 621 #endif 622 623 #if defined(__alpha) 624 # define FSHIFT 10 625 #endif 626 627 #if (LA_TYPE == LA_INT) && !defined(FSHIFT) 628 # define FSHIFT 8 629 #endif 630 #if (LA_TYPE == LA_INT) && !defined(FSCALE) 631 # define FSCALE (1 << FSHIFT) 632 #endif 633 634 getla() 635 { 636 static int kmem = -1; 637 #if LA_TYPE == LA_INT 638 long avenrun[3]; 639 #else 640 double avenrun[3]; 641 #endif 642 extern off_t lseek(); 643 extern char *errstring(); 644 extern int errno; 645 646 if (kmem < 0) 647 { 648 kmem = open("/dev/kmem", 0, 0); 649 if (kmem < 0) 650 { 651 if (tTd(3, 1)) 652 printf("getla: open(/dev/kmem): %s\n", 653 errstring(errno)); 654 return (-1); 655 } 656 (void) fcntl(kmem, F_SETFD, 1); 657 if (nlist(_PATH_UNIX, Nl) < 0) 658 { 659 if (tTd(3, 1)) 660 printf("getla: nlist(%s): %s\n", _PATH_UNIX, 661 errstring(errno)); 662 return (-1); 663 } 664 } 665 if (tTd(3, 20)) 666 printf("getla: symbol address = %#x\n", Nl[X_AVENRUN].n_value); 667 if (lseek(kmem, (off_t) Nl[X_AVENRUN].n_value, 0) == -1 || 668 read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun)) 669 { 670 /* thank you Ian */ 671 if (tTd(3, 1)) 672 printf("getla: lseek or read: %s\n", errstring(errno)); 673 return (-1); 674 } 675 #if LA_TYPE == LA_INT 676 if (tTd(3, 5)) 677 { 678 printf("getla: avenrun = %d", avenrun[0]); 679 if (tTd(3, 15)) 680 printf(", %d, %d", avenrun[1], avenrun[2]); 681 printf("\n"); 682 } 683 if (tTd(3, 1)) 684 printf("getla: %d\n", (int) (avenrun[0] + FSCALE/2) >> FSHIFT); 685 return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT); 686 #else 687 if (tTd(3, 5)) 688 { 689 printf("getla: avenrun = %g", avenrun[0]); 690 if (tTd(3, 15)) 691 printf(", %g, %g", avenrun[1], avenrun[2]); 692 printf("\n"); 693 } 694 if (tTd(3, 1)) 695 printf("getla: %d\n", (int) (avenrun[0] +0.5)); 696 return ((int) (avenrun[0] + 0.5)); 697 #endif 698 } 699 700 #else 701 #if LA_TYPE == LA_SUBR 702 703 getla() 704 { 705 double avenrun[3]; 706 707 if (getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])) < 0) 708 { 709 if (tTd(3, 1)) 710 perror("getla: getloadavg failed:"); 711 return (-1); 712 } 713 if (tTd(3, 1)) 714 printf("getla: %d\n", (int) (avenrun[0] +0.5)); 715 return ((int) (avenrun[0] + 0.5)); 716 } 717 718 #else 719 720 getla() 721 { 722 if (tTd(3, 1)) 723 printf("getla: ZERO\n"); 724 return (0); 725 } 726 727 #endif 728 #endif 729 /* 730 ** SHOULDQUEUE -- should this message be queued or sent? 731 ** 732 ** Compares the message cost to the load average to decide. 733 ** 734 ** Parameters: 735 ** pri -- the priority of the message in question. 736 ** ctime -- the message creation time. 737 ** 738 ** Returns: 739 ** TRUE -- if this message should be queued up for the 740 ** time being. 741 ** FALSE -- if the load is low enough to send this message. 742 ** 743 ** Side Effects: 744 ** none. 745 */ 746 747 bool 748 shouldqueue(pri, ctime) 749 long pri; 750 time_t ctime; 751 { 752 if (CurrentLA < QueueLA) 753 return (FALSE); 754 if (CurrentLA >= RefuseLA) 755 return (TRUE); 756 return (pri > (QueueFactor / (CurrentLA - QueueLA + 1))); 757 } 758 /* 759 ** REFUSECONNECTIONS -- decide if connections should be refused 760 ** 761 ** Parameters: 762 ** none. 763 ** 764 ** Returns: 765 ** TRUE if incoming SMTP connections should be refused 766 ** (for now). 767 ** FALSE if we should accept new work. 768 ** 769 ** Side Effects: 770 ** none. 771 */ 772 773 bool 774 refuseconnections() 775 { 776 /* this is probably too simplistic */ 777 return (CurrentLA >= RefuseLA); 778 } 779 /* 780 ** SETPROCTITLE -- set process title for ps 781 ** 782 ** Parameters: 783 ** fmt -- a printf style format string. 784 ** a, b, c -- possible parameters to fmt. 785 ** 786 ** Returns: 787 ** none. 788 ** 789 ** Side Effects: 790 ** Clobbers argv of our main procedure so ps(1) will 791 ** display the title. 792 */ 793 794 /*VARARGS1*/ 795 #ifdef __STDC__ 796 setproctitle(char *fmt, ...) 797 #else 798 setproctitle(fmt, va_alist) 799 char *fmt; 800 va_dcl 801 #endif 802 { 803 # ifdef SETPROCTITLE 804 register char *p; 805 register int i; 806 char buf[MAXLINE]; 807 VA_LOCAL_DECL 808 extern char **Argv; 809 extern char *LastArgv; 810 811 p = buf; 812 813 /* print sendmail: heading for grep */ 814 (void) strcpy(p, "sendmail: "); 815 p += strlen(p); 816 817 /* print the argument string */ 818 VA_START(fmt); 819 (void) vsprintf(p, fmt, ap); 820 VA_END; 821 822 i = strlen(buf); 823 if (i > LastArgv - Argv[0] - 2) 824 { 825 i = LastArgv - Argv[0] - 2; 826 buf[i] = '\0'; 827 } 828 (void) strcpy(Argv[0], buf); 829 p = &Argv[0][i]; 830 while (p < LastArgv) 831 *p++ = ' '; 832 # endif /* SETPROCTITLE */ 833 } 834 /* 835 ** REAPCHILD -- pick up the body of my child, lest it become a zombie 836 ** 837 ** Parameters: 838 ** none. 839 ** 840 ** Returns: 841 ** none. 842 ** 843 ** Side Effects: 844 ** Picks up extant zombies. 845 */ 846 847 # include <sys/wait.h> 848 849 void 850 reapchild() 851 { 852 # ifdef WNOHANG 853 union wait status; 854 855 while (wait3((int *)&status, WNOHANG, (struct rusage *) NULL) > 0) 856 continue; 857 # else /* WNOHANG */ 858 auto int status; 859 860 while (wait((int *)&status) > 0) 861 continue; 862 # endif /* WNOHANG */ 863 # ifdef SYSTEM5 864 (void) signal(SIGCHLD, reapchild); 865 # endif 866 } 867 /* 868 ** UNSETENV -- remove a variable from the environment 869 ** 870 ** Not needed on newer systems. 871 ** 872 ** Parameters: 873 ** name -- the string name of the environment variable to be 874 ** deleted from the current environment. 875 ** 876 ** Returns: 877 ** none. 878 ** 879 ** Globals: 880 ** environ -- a pointer to the current environment. 881 ** 882 ** Side Effects: 883 ** Modifies environ. 884 */ 885 886 #ifdef UNSETENV 887 888 void 889 unsetenv(name) 890 char *name; 891 { 892 extern char **environ; 893 register char **pp; 894 int len = strlen(name); 895 896 for (pp = environ; *pp != NULL; pp++) 897 { 898 if (strncmp(name, *pp, len) == 0 && 899 ((*pp)[len] == '=' || (*pp)[len] == '\0')) 900 break; 901 } 902 903 for (; *pp != NULL; pp++) 904 *pp = pp[1]; 905 } 906 907 #endif /* UNSETENV */ 908 /* 909 ** GETDTABLESIZE -- return number of file descriptors 910 ** 911 ** Only on non-BSD systems 912 ** 913 ** Parameters: 914 ** none 915 ** 916 ** Returns: 917 ** size of file descriptor table 918 ** 919 ** Side Effects: 920 ** none 921 */ 922 923 #ifdef SYSTEM5 924 925 int 926 getdtablesize() 927 { 928 return NOFILE; 929 } 930 931 #endif 932 /* 933 ** UNAME -- get the UUCP name of this system. 934 */ 935 936 #ifndef HASUNAME 937 938 int 939 uname(name) 940 struct utsname *name; 941 { 942 FILE *file; 943 char *n; 944 945 name->nodename[0] = '\0'; 946 947 /* try /etc/whoami -- one line with the node name */ 948 if ((file = fopen("/etc/whoami", "r")) != NULL) 949 { 950 (void) fgets(name->nodename, NODE_LENGTH + 1, file); 951 (void) fclose(file); 952 n = strchr(name->nodename, '\n'); 953 if (n != NULL) 954 *n = '\0'; 955 if (name->nodename[0] != '\0') 956 return (0); 957 } 958 959 /* try /usr/include/whoami.h -- has a #define somewhere */ 960 if ((file = fopen("/usr/include/whoami.h", "r")) != NULL) 961 { 962 char buf[MAXLINE]; 963 964 while (fgets(buf, MAXLINE, file) != NULL) 965 if (sscanf(buf, "#define sysname \"%*[^\"]\"", 966 NODE_LENGTH, name->nodename) > 0) 967 break; 968 (void) fclose(file); 969 if (name->nodename[0] != '\0') 970 return (0); 971 } 972 973 #ifdef TRUST_POPEN 974 /* 975 ** Popen is known to have security holes. 976 */ 977 978 /* try uuname -l to return local name */ 979 if ((file = popen("uuname -l", "r")) != NULL) 980 { 981 (void) fgets(name, NODE_LENGTH + 1, file); 982 (void) pclose(file); 983 n = strchr(name, '\n'); 984 if (n != NULL) 985 *n = '\0'; 986 if (name->nodename[0] != '\0') 987 return (0); 988 } 989 #endif 990 991 return (-1); 992 } 993 #endif /* HASUNAME */ 994 /* 995 ** INITGROUPS -- initialize groups 996 ** 997 ** Stub implementation for System V style systems 998 */ 999 1000 #ifndef HASINITGROUPS 1001 # if !defined(SYSTEM5) || defined(hpux) 1002 # define HASINITGROUPS 1003 # endif 1004 #endif 1005 1006 #ifndef HASINITGROUPS 1007 1008 initgroups(name, basegid) 1009 char *name; 1010 int basegid; 1011 { 1012 return 0; 1013 } 1014 1015 #endif 1016 /* 1017 ** ENOUGHSPACE -- check to see if there is enough free space on the queue fs 1018 ** 1019 ** Only implemented if you have statfs. 1020 ** 1021 ** Parameters: 1022 ** msize -- the size to check against. If zero, we don't yet 1023 ** know how big the message will be, so just check for 1024 ** a "reasonable" amount. 1025 ** 1026 ** Returns: 1027 ** TRUE if there is enough space. 1028 ** FALSE otherwise. 1029 */ 1030 1031 #ifndef HASSTATFS 1032 # if defined(BSD4_4) || defined(__osf__) 1033 # define HASSTATFS 1034 # endif 1035 #endif 1036 1037 #ifdef HASSTATFS 1038 # undef HASUSTAT 1039 #endif 1040 1041 #if defined(HASUSTAT) 1042 # include <sys/stat.h> 1043 # include <ustat.h> 1044 #endif 1045 1046 #ifdef HASSTATFS 1047 # if defined(sgi) || defined(apollo) 1048 # include <sys/statfs.h> 1049 # else 1050 # if defined(sun) || defined(hpux) 1051 # include <sys/vfs.h> 1052 # else 1053 # include <sys/mount.h> 1054 # endif 1055 # endif 1056 #endif 1057 1058 bool 1059 enoughspace(msize) 1060 long msize; 1061 { 1062 #if defined(HASSTATFS) || defined(HASUSTAT) 1063 # if defined(HASUSTAT) 1064 struct ustat fs; 1065 struct stat statbuf; 1066 # define FSBLOCKSIZE DEV_BSIZE 1067 # define f_bavail f_tfree 1068 # else 1069 # if defined(ultrix) 1070 struct fs_data fs; 1071 # define f_bavail fd_bfreen 1072 # define FSBLOCKSIZE fs.fd_bsize 1073 # else 1074 struct statfs fs; 1075 # define FSBLOCKSIZE fs.f_bsize 1076 # endif 1077 # endif 1078 long blocksneeded; 1079 extern int errno; 1080 extern char *errstring(); 1081 1082 if (MinBlocksFree <= 0 && msize <= 0) 1083 { 1084 if (tTd(4, 80)) 1085 printf("enoughspace: no threshold\n"); 1086 return TRUE; 1087 } 1088 1089 # if defined(HASUSTAT) 1090 if (stat(QueueDir, &statbuf) == 0 && ustat(statbuf.st_dev, &fs) == 0) 1091 # else 1092 # if defined(sgi) || defined(apollo) 1093 if (statfs(QueueDir, &fs, sizeof fs, 0) == 0) 1094 # else 1095 # if defined(ultrix) 1096 if (statfs(QueueDir, &fs) > 0) 1097 # else 1098 if (statfs(QueueDir, &fs) == 0) 1099 # endif 1100 # endif 1101 # endif 1102 { 1103 if (tTd(4, 80)) 1104 printf("enoughspace: bavail=%ld, need=%ld\n", 1105 fs.f_bavail, msize); 1106 1107 /* convert msize to block count */ 1108 msize = msize / FSBLOCKSIZE + 1; 1109 if (MinBlocksFree >= 0) 1110 msize += MinBlocksFree; 1111 1112 if (fs.f_bavail < msize) 1113 { 1114 #ifdef LOG 1115 if (LogLevel > 0) 1116 syslog(LOG_ALERT, "%s: low on space (have %ld, need %ld)", 1117 QueueDir, fs.f_bavail, msize); 1118 #endif 1119 return FALSE; 1120 } 1121 } 1122 else if (tTd(4, 80)) 1123 printf("enoughspace failure: min=%ld, need=%ld: %s\n", 1124 MinBlocksFree, msize, errstring(errno)); 1125 #endif 1126 return TRUE; 1127 } 1128 /* 1129 ** TRANSIENTERROR -- tell if an error code indicates a transient failure 1130 ** 1131 ** This looks at an errno value and tells if this is likely to 1132 ** go away if retried later. 1133 ** 1134 ** Parameters: 1135 ** err -- the errno code to classify. 1136 ** 1137 ** Returns: 1138 ** TRUE if this is probably transient. 1139 ** FALSE otherwise. 1140 */ 1141 1142 bool 1143 transienterror(err) 1144 int err; 1145 { 1146 switch (err) 1147 { 1148 case EIO: /* I/O error */ 1149 case ENXIO: /* Device not configured */ 1150 case EAGAIN: /* Resource temporarily unavailable */ 1151 case ENOMEM: /* Cannot allocate memory */ 1152 case ENODEV: /* Operation not supported by device */ 1153 case ENFILE: /* Too many open files in system */ 1154 case EMFILE: /* Too many open files */ 1155 case ENOSPC: /* No space left on device */ 1156 #ifdef ETIMEDOUT 1157 case ETIMEDOUT: /* Connection timed out */ 1158 #endif 1159 #ifdef ESTALE 1160 case ESTALE: /* Stale NFS file handle */ 1161 #endif 1162 #ifdef ENETDOWN 1163 case ENETDOWN: /* Network is down */ 1164 #endif 1165 #ifdef ENETUNREACH 1166 case ENETUNREACH: /* Network is unreachable */ 1167 #endif 1168 #ifdef ENETRESET 1169 case ENETRESET: /* Network dropped connection on reset */ 1170 #endif 1171 #ifdef ECONNABORTED 1172 case ECONNABORTED: /* Software caused connection abort */ 1173 #endif 1174 #ifdef ECONNRESET 1175 case ECONNRESET: /* Connection reset by peer */ 1176 #endif 1177 #ifdef ENOBUFS 1178 case ENOBUFS: /* No buffer space available */ 1179 #endif 1180 #ifdef ESHUTDOWN 1181 case ESHUTDOWN: /* Can't send after socket shutdown */ 1182 #endif 1183 #ifdef ECONNREFUSED 1184 case ECONNREFUSED: /* Connection refused */ 1185 #endif 1186 #ifdef EHOSTDOWN 1187 case EHOSTDOWN: /* Host is down */ 1188 #endif 1189 #ifdef EHOSTUNREACH 1190 case EHOSTUNREACH: /* No route to host */ 1191 #endif 1192 #ifdef EDQUOT 1193 case EDQUOT: /* Disc quota exceeded */ 1194 #endif 1195 #ifdef EPROCLIM 1196 case EPROCLIM: /* Too many processes */ 1197 #endif 1198 #ifdef EUSERS 1199 case EUSERS: /* Too many users */ 1200 #endif 1201 #ifdef EDEADLK 1202 case EDEADLK: /* Resource deadlock avoided */ 1203 #endif 1204 #ifdef EISCONN 1205 case EISCONN: /* Socket already connected */ 1206 #endif 1207 #ifdef EINPROGRESS 1208 case EINPROGRESS: /* Operation now in progress */ 1209 #endif 1210 #ifdef EALREADY 1211 case EALREADY: /* Operation already in progress */ 1212 #endif 1213 #ifdef EADDRINUSE 1214 case EADDRINUSE: /* Address already in use */ 1215 #endif 1216 #ifdef EADDRNOTAVAIL 1217 case EADDRNOTAVAIL: /* Can't assign requested address */ 1218 #endif 1219 #ifdef ENOSR 1220 case ENOSR: /* Out of streams resources */ 1221 #endif 1222 return TRUE; 1223 } 1224 1225 /* nope, must be permanent */ 1226 return FALSE; 1227 } 1228