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 5.47 (Berkeley) 12/16/92"; 11 #endif /* not lint */ 12 13 # include <sys/ioctl.h> 14 # include <sys/param.h> 15 # include <pwd.h> 16 # include "sendmail.h" 17 # include "pathnames.h" 18 19 /* 20 ** CONF.C -- Sendmail Configuration Tables. 21 ** 22 ** Defines the configuration of this installation. 23 ** 24 ** Configuration Variables: 25 ** HdrInfo -- a table describing well-known header fields. 26 ** Each entry has the field name and some flags, 27 ** which are described in sendmail.h. 28 ** 29 ** Notes: 30 ** I have tried to put almost all the reasonable 31 ** configuration information into the configuration 32 ** file read at runtime. My intent is that anything 33 ** here is a function of the version of UNIX you 34 ** are running, or is really static -- for example 35 ** the headers are a superset of widely used 36 ** protocols. If you find yourself playing with 37 ** this file too much, you may be making a mistake! 38 */ 39 40 41 42 43 /* 44 ** Header info table 45 ** Final (null) entry contains the flags used for any other field. 46 ** 47 ** Not all of these are actually handled specially by sendmail 48 ** at this time. They are included as placeholders, to let 49 ** you know that "someday" I intend to have sendmail do 50 ** something with them. 51 */ 52 53 struct hdrinfo HdrInfo[] = 54 { 55 /* originator fields, most to least significant */ 56 "resent-sender", H_FROM|H_RESENT, 57 "resent-from", H_FROM|H_RESENT, 58 "resent-reply-to", H_FROM|H_RESENT, 59 "sender", H_FROM, 60 "from", H_FROM, 61 "reply-to", H_FROM, 62 "full-name", H_ACHECK, 63 "return-receipt-to", H_FROM, 64 "errors-to", H_FROM, 65 /* destination fields */ 66 "to", H_RCPT, 67 "resent-to", H_RCPT|H_RESENT, 68 "cc", H_RCPT, 69 "resent-cc", H_RCPT|H_RESENT, 70 "bcc", H_RCPT|H_ACHECK, 71 "resent-bcc", H_RCPT|H_ACHECK|H_RESENT, 72 "apparently-to", H_RCPT, 73 /* message identification and control */ 74 "message-id", 0, 75 "resent-message-id", H_RESENT, 76 "message", H_EOH, 77 "text", H_EOH, 78 /* date fields */ 79 "date", 0, 80 "resent-date", H_RESENT, 81 /* trace fields */ 82 "received", H_TRACE|H_FORCE, 83 "via", H_TRACE|H_FORCE, 84 "mail-from", H_TRACE|H_FORCE, 85 86 NULL, 0, 87 }; 88 89 90 /* 91 ** ARPANET error message numbers. 92 */ 93 94 char Arpa_Info[] = "050"; /* arbitrary info */ 95 char Arpa_TSyserr[] = "451"; /* some (transient) system error */ 96 char Arpa_PSyserr[] = "554"; /* some (permanent) system error */ 97 char Arpa_Usrerr[] = "554"; /* some (fatal) user error */ 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 108 109 110 /* 111 ** Miscellaneous stuff. 112 */ 113 114 int DtableSize = 50; /* max open files; reset in 4.2bsd */ 115 /* 116 ** SETDEFAULTS -- set default values 117 ** 118 ** Because of the way freezing is done, these must be initialized 119 ** using direct code. 120 ** 121 ** Parameters: 122 ** none. 123 ** 124 ** Returns: 125 ** none. 126 ** 127 ** Side Effects: 128 ** Initializes a bunch of global variables to their 129 ** default values. 130 */ 131 132 setdefaults() 133 { 134 QueueLA = 8; 135 QueueFactor = 10000; 136 RefuseLA = 12; 137 SpaceSub = ' '; 138 WkRecipFact = 1000; 139 WkClassFact = 1800; 140 WkTimeFact = 9000; 141 FileMode = (getuid() != geteuid()) ? 0644 : 0600; 142 DefUid = 1; 143 DefGid = 1; 144 CheckpointInterval = 10; 145 MaxHopCount = 17; 146 SendMode = SM_FORK; 147 ErrorMode = EM_PRINT; 148 EightBit = FALSE; 149 MaxMciCache = 1; 150 MciCacheTimeout = 300; 151 setdefuser(); 152 setupmaps(); 153 } 154 155 156 /* 157 ** SETDEFUSER -- set/reset DefUser using DefUid (for initgroups()) 158 */ 159 160 setdefuser() 161 { 162 struct passwd *defpwent; 163 164 if (DefUser != NULL) 165 free(DefUser); 166 if ((defpwent = getpwuid(DefUid)) != NULL) 167 DefUser = newstr(defpwent->pw_name); 168 else 169 DefUser = newstr("nobody"); 170 } 171 /* 172 ** SETUPMAPS -- set up map classes 173 ** 174 ** Since these are compiled in, they cannot be in the config file. 175 ** 176 */ 177 178 setupmaps() 179 { 180 register STAB *s; 181 extern bool host_map_init(); 182 extern char *maphostname(); 183 184 /* set up host name lookup map */ 185 s = stab("host", ST_MAPCLASS, ST_ENTER); 186 s->s_mapclass.map_init = host_map_init; 187 s->s_mapclass.map_lookup = maphostname; 188 189 /* 190 ** Set up other map classes. 191 */ 192 193 # ifdef DBM_MAP 194 /* dbm file access */ 195 { 196 extern bool dbm_map_init(); 197 extern char *dbm_map_lookup(); 198 199 s = stab("dbm", ST_MAPCLASS, ST_ENTER); 200 s->s_mapclass.map_init = dbm_map_init; 201 s->s_mapclass.map_lookup = dbm_map_lookup; 202 } 203 # endif 204 205 # ifdef BTREE_MAP 206 /* new database file access -- btree files */ 207 { 208 extern bool bt_map_init(); 209 extern char *db_map_lookup(); 210 211 s = stab("btree", ST_MAPCLASS, ST_ENTER); 212 s->s_mapclass.map_init = bt_map_init; 213 s->s_mapclass.map_lookup = db_map_lookup; 214 } 215 # endif 216 217 # ifdef HASH_MAP 218 /* new database file access -- hash files */ 219 { 220 extern bool hash_map_init(); 221 extern char *db_map_lookup(); 222 223 s = stab("hash", ST_MAPCLASS, ST_ENTER); 224 s->s_mapclass.map_init = hash_map_init; 225 s->s_mapclass.map_lookup = db_map_lookup; 226 } 227 # endif 228 229 # ifdef USERDB_MAP 230 /* user database */ 231 { 232 extern bool udb_map_init(); 233 extern char *udb_map_lookup(); 234 235 s = stab("udb", ST_MAPCLASS, ST_ENTER); 236 s->s_mapclass.map_init = udb_map_init; 237 s->s_mapclass.map_lookup = udb_map_lookup; 238 } 239 # endif 240 } 241 /* 242 ** HOST_MAP_INIT -- initialize host class structures 243 */ 244 245 bool 246 host_map_init(map, mapname, args) 247 MAP *map; 248 char *mapname; 249 char *args; 250 { 251 register char *p = args; 252 253 for (;;) 254 { 255 while (isspace(*p)) 256 p++; 257 if (*p != '-') 258 break; 259 switch (*++p) 260 { 261 case 'a': 262 map->map_app = ++p; 263 break; 264 } 265 while (*p != '\0' && !isspace(*p)) 266 p++; 267 if (*p != '\0') 268 *p++ = '\0'; 269 } 270 if (map->map_app != NULL) 271 map->map_app = newstr(map->map_app); 272 return TRUE; 273 } 274 275 /* 276 ** GETRUID -- get real user id (V7) 277 */ 278 279 getruid() 280 { 281 if (OpMode == MD_DAEMON) 282 return (RealUid); 283 else 284 return (getuid()); 285 } 286 287 288 /* 289 ** GETRGID -- get real group id (V7). 290 */ 291 292 getrgid() 293 { 294 if (OpMode == MD_DAEMON) 295 return (RealGid); 296 else 297 return (getgid()); 298 } 299 /* 300 ** USERNAME -- return the user id of the logged in user. 301 ** 302 ** Parameters: 303 ** none. 304 ** 305 ** Returns: 306 ** The login name of the logged in user. 307 ** 308 ** Side Effects: 309 ** none. 310 ** 311 ** Notes: 312 ** The return value is statically allocated. 313 */ 314 315 char * 316 username() 317 { 318 static char *myname = NULL; 319 extern char *getlogin(); 320 register struct passwd *pw; 321 322 /* cache the result */ 323 if (myname == NULL) 324 { 325 myname = getlogin(); 326 if (myname == NULL || myname[0] == '\0') 327 { 328 329 pw = getpwuid(getruid()); 330 if (pw != NULL) 331 myname = newstr(pw->pw_name); 332 } 333 else 334 { 335 336 myname = newstr(myname); 337 if ((pw = getpwnam(myname)) == NULL || 338 getuid() != pw->pw_uid) 339 { 340 pw = getpwuid(getuid()); 341 if (pw != NULL) 342 myname = newstr(pw->pw_name); 343 } 344 } 345 if (myname == NULL || myname[0] == '\0') 346 { 347 syserr("Who are you?"); 348 myname = "postmaster"; 349 } 350 } 351 352 return (myname); 353 } 354 /* 355 ** TTYPATH -- Get the path of the user's tty 356 ** 357 ** Returns the pathname of the user's tty. Returns NULL if 358 ** the user is not logged in or if s/he has write permission 359 ** denied. 360 ** 361 ** Parameters: 362 ** none 363 ** 364 ** Returns: 365 ** pathname of the user's tty. 366 ** NULL if not logged in or write permission denied. 367 ** 368 ** Side Effects: 369 ** none. 370 ** 371 ** WARNING: 372 ** Return value is in a local buffer. 373 ** 374 ** Called By: 375 ** savemail 376 */ 377 378 # include <sys/stat.h> 379 380 char * 381 ttypath() 382 { 383 struct stat stbuf; 384 register char *pathn; 385 extern char *ttyname(); 386 extern char *getlogin(); 387 388 /* compute the pathname of the controlling tty */ 389 if ((pathn = ttyname(2)) == NULL && (pathn = ttyname(1)) == NULL && 390 (pathn = ttyname(0)) == NULL) 391 { 392 errno = 0; 393 return (NULL); 394 } 395 396 /* see if we have write permission */ 397 if (stat(pathn, &stbuf) < 0 || !bitset(02, stbuf.st_mode)) 398 { 399 errno = 0; 400 return (NULL); 401 } 402 403 /* see if the user is logged in */ 404 if (getlogin() == NULL) 405 return (NULL); 406 407 /* looks good */ 408 return (pathn); 409 } 410 /* 411 ** CHECKCOMPAT -- check for From and To person compatible. 412 ** 413 ** This routine can be supplied on a per-installation basis 414 ** to determine whether a person is allowed to send a message. 415 ** This allows restriction of certain types of internet 416 ** forwarding or registration of users. 417 ** 418 ** If the hosts are found to be incompatible, an error 419 ** message should be given using "usrerr" and FALSE should 420 ** be returned. 421 ** 422 ** 'NoReturn' can be set to suppress the return-to-sender 423 ** function; this should be done on huge messages. 424 ** 425 ** Parameters: 426 ** to -- the person being sent to. 427 ** 428 ** Returns: 429 ** TRUE -- ok to send. 430 ** FALSE -- not ok. 431 ** 432 ** Side Effects: 433 ** none (unless you include the usrerr stuff) 434 */ 435 436 bool 437 checkcompat(to, e) 438 register ADDRESS *to; 439 register ENVELOPE *e; 440 { 441 # ifdef lint 442 if (to == NULL) 443 to++; 444 # endif lint 445 # ifdef EXAMPLE_CODE 446 /* this code is intended as an example only */ 447 register STAB *s; 448 449 s = stab("arpa", ST_MAILER, ST_FIND); 450 if (s != NULL && e->e_from.q_mailer != LocalMailer && 451 to->q_mailer == s->s_mailer) 452 { 453 usrerr("No ARPA mail through this machine: see your system administration"); 454 /* NoReturn = TRUE; to supress return copy */ 455 return (FALSE); 456 } 457 # endif /* EXAMPLE_CODE */ 458 return (TRUE); 459 } 460 /* 461 ** HOLDSIGS -- arrange to hold all signals 462 ** 463 ** Parameters: 464 ** none. 465 ** 466 ** Returns: 467 ** none. 468 ** 469 ** Side Effects: 470 ** Arranges that signals are held. 471 */ 472 473 holdsigs() 474 { 475 } 476 /* 477 ** RLSESIGS -- arrange to release all signals 478 ** 479 ** This undoes the effect of holdsigs. 480 ** 481 ** Parameters: 482 ** none. 483 ** 484 ** Returns: 485 ** none. 486 ** 487 ** Side Effects: 488 ** Arranges that signals are released. 489 */ 490 491 rlsesigs() 492 { 493 } 494 /* 495 ** GETLA -- get the current load average 496 ** 497 ** This code stolen from la.c. 498 ** 499 ** Parameters: 500 ** none. 501 ** 502 ** Returns: 503 ** The current load average as an integer. 504 ** 505 ** Side Effects: 506 ** none. 507 */ 508 509 /* try to guess what style of load average we have */ 510 #define LA_ZERO 1 /* always return load average as zero */ 511 #define LA_INT 2 /* read kmem for avenrun; interpret as int */ 512 #define LA_FLOAT 3 /* read kmem for avenrun; interpret as float */ 513 #define LA_SUBR 4 /* call getloadavg */ 514 515 #ifndef LA_TYPE 516 # if defined(sun) 517 # define LA_TYPE LA_INT 518 # endif 519 # if defined(mips) 520 /* Ultrix or RISC/os */ 521 # define LA_TYPE LA_INT 522 # define LA_AVENRUN "avenrun" 523 # endif 524 # if defined(hpux) 525 # define LA_TYPE LA_FLOAT 526 # endif 527 # if defined(BSD) 528 # define LA_TYPE LA_SUBR 529 # endif 530 531 # ifndef LA_TYPE 532 # define LA_TYPE LA_ZERO 533 # endif 534 #endif 535 536 #if (LA_TYPE == LA_INT) || (LA_TYPE == LA_FLOAT) 537 538 #include <nlist.h> 539 #include <fcntl.h> 540 541 #ifndef LA_AVENRUN 542 #define LA_AVENRUN "_avenrun" 543 #endif 544 545 /* _PATH_UNIX should be defined in <paths.h> */ 546 #ifndef _PATH_UNIX 547 # if defined(hpux) 548 # define _PATH_UNIX "/hp-ux" 549 # endif 550 # if defined(mips) && !defined(ultrix) 551 /* powerful RISC/os */ 552 # define _PATH_UNIX "/unix" 553 # endif 554 # ifndef _PATH_UNIX 555 # define _PATH_UNIX "/vmunix" 556 # endif 557 #endif 558 559 struct nlist Nl[] = 560 { 561 { LA_AVENRUN }, 562 #define X_AVENRUN 0 563 { 0 }, 564 }; 565 566 #if (LA_TYPE == LA_INT) && !defined(FSHIFT) 567 # define FSHIFT 8 568 # define FSCALE (1 << FSHIFT) 569 #endif 570 571 getla() 572 { 573 static int kmem = -1; 574 #if LA_TYPE == LA_INT 575 long avenrun[3]; 576 #else 577 double avenrun[3]; 578 #endif 579 extern off_t lseek(); 580 581 if (kmem < 0) 582 { 583 kmem = open("/dev/kmem", 0, 0); 584 if (kmem < 0) 585 return (-1); 586 (void) fcntl(kmem, F_SETFD, 1); 587 nlist(_PATH_UNIX, Nl); 588 if (Nl[0].n_type == 0) 589 return (-1); 590 } 591 if (lseek(kmem, (off_t) Nl[X_AVENRUN].n_value, 0) == -1 || 592 read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun)) 593 { 594 /* thank you Ian */ 595 return (-1); 596 } 597 #if LA_TYPE == LA_INT 598 return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT); 599 #else 600 return ((int) (avenrun[0] + 0.5)); 601 #endif 602 } 603 604 #else 605 #if LA_TYPE == LA_SUBR 606 607 getla() 608 { 609 double avenrun[3]; 610 611 if (getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])) < 0) 612 return (-1); 613 return ((int) (avenrun[0] + 0.5)); 614 } 615 616 #else 617 618 getla() 619 { 620 return (0); 621 } 622 623 #endif 624 #endif 625 /* 626 ** SHOULDQUEUE -- should this message be queued or sent? 627 ** 628 ** Compares the message cost to the load average to decide. 629 ** 630 ** Parameters: 631 ** pri -- the priority of the message in question. 632 ** 633 ** Returns: 634 ** TRUE -- if this message should be queued up for the 635 ** time being. 636 ** FALSE -- if the load is low enough to send this message. 637 ** 638 ** Side Effects: 639 ** none. 640 */ 641 642 bool 643 shouldqueue(pri) 644 long pri; 645 { 646 if (CurrentLA < QueueLA) 647 return (FALSE); 648 return (pri > (QueueFactor / (CurrentLA - QueueLA + 1))); 649 } 650 /* 651 ** REFUSECONNECTIONS -- decide if connections should be refused 652 ** 653 ** Parameters: 654 ** none. 655 ** 656 ** Returns: 657 ** TRUE if incoming SMTP connections should be refused 658 ** (for now). 659 ** FALSE if we should accept new work. 660 ** 661 ** Side Effects: 662 ** none. 663 */ 664 665 bool 666 refuseconnections() 667 { 668 /* this is probably too simplistic */ 669 return (CurrentLA > RefuseLA); 670 } 671 /* 672 ** SETPROCTITLE -- set process title for ps 673 ** 674 ** Parameters: 675 ** fmt -- a printf style format string. 676 ** a, b, c -- possible parameters to fmt. 677 ** 678 ** Returns: 679 ** none. 680 ** 681 ** Side Effects: 682 ** Clobbers argv of our main procedure so ps(1) will 683 ** display the title. 684 */ 685 686 /*VARARGS1*/ 687 setproctitle(fmt VA_ARG_FORMAL) 688 char *fmt; 689 VA_ARG_DECL 690 { 691 # ifdef SETPROCTITLE 692 register char *p; 693 register int i; 694 char buf[MAXLINE]; 695 VA_LOCAL_DECL 696 extern char **Argv; 697 extern char *LastArgv; 698 699 p = buf; 700 701 /* print sendmail: heading for grep */ 702 (void) strcpy(p, "sendmail: "); 703 p += strlen(p); 704 705 /* print the argument string */ 706 VA_START(fmt); 707 (void) vsprintf(p, fmt, ap); 708 VA_END; 709 710 i = strlen(buf); 711 if (i > LastArgv - Argv[0] - 2) 712 { 713 i = LastArgv - Argv[0] - 2; 714 buf[i] = '\0'; 715 } 716 (void) strcpy(Argv[0], buf); 717 p = &Argv[0][i]; 718 while (p < LastArgv) 719 *p++ = ' '; 720 # endif /* SETPROCTITLE */ 721 } 722 /* 723 ** REAPCHILD -- pick up the body of my child, lest it become a zombie 724 ** 725 ** Parameters: 726 ** none. 727 ** 728 ** Returns: 729 ** none. 730 ** 731 ** Side Effects: 732 ** Picks up extant zombies. 733 */ 734 735 # include <sys/wait.h> 736 737 void 738 reapchild() 739 { 740 # ifdef WNOHANG 741 union wait status; 742 743 while (wait3((int *)&status, WNOHANG, (struct rusage *) NULL) > 0) 744 continue; 745 # else /* WNOHANG */ 746 auto int status; 747 748 while (wait((int *)&status) > 0) 749 continue; 750 # endif /* WNOHANG */ 751 } 752 /* 753 ** UNSETENV -- remove a variable from the environment 754 ** 755 ** Not needed on newer systems. 756 ** 757 ** Parameters: 758 ** name -- the string name of the environment variable to be 759 ** deleted from the current environment. 760 ** 761 ** Returns: 762 ** none. 763 ** 764 ** Globals: 765 ** environ -- a pointer to the current environment. 766 ** 767 ** Side Effects: 768 ** Modifies environ. 769 */ 770 771 #ifdef UNSETENV 772 773 void 774 unsetenv(name) 775 char *name; 776 { 777 extern char **environ; 778 register char **pp; 779 int len = strlen(name); 780 781 for (pp = environ; *pp != NULL; pp++) 782 { 783 if (strncmp(name, *pp, len) == 0 && 784 ((*pp)[len] == '=' || (*pp)[len] == '\0')) 785 break; 786 } 787 788 for (; *pp != NULL; pp++) 789 *pp = pp[1]; 790 } 791 792 #endif /* UNSETENV */ 793 /* 794 ** GETDTABLESIZE -- return number of file descriptors 795 ** 796 ** Only on non-BSD systems 797 ** 798 ** Parameters: 799 ** none 800 ** 801 ** Returns: 802 ** size of file descriptor table 803 ** 804 ** Side Effects: 805 ** none 806 */ 807 808 #ifdef SYSTEM5 809 810 int 811 getdtablesize() 812 { 813 return NOFILE; 814 } 815 816 #endif 817