1 /* 2 ** Sendmail 3 ** Copyright (c) 1983 Eric P. Allman 4 ** Berkeley, California 5 ** 6 ** Copyright (c) 1983 Regents of the University of California. 7 ** All rights reserved. The Berkeley software License Agreement 8 ** specifies the terms and conditions for redistribution. 9 */ 10 11 #ifndef lint 12 static char SccsId[] = "@(#)conf.c 5.13 (Berkeley) 01/05/86"; 13 #endif not lint 14 15 # include <pwd.h> 16 # include <sys/ioctl.h> 17 # ifdef sun 18 # include <sys/param.h> 19 # endif sun 20 # include "sendmail.h" 21 22 /* 23 ** CONF.C -- Sendmail Configuration Tables. 24 ** 25 ** Defines the configuration of this installation. 26 ** 27 ** Compilation Flags: 28 ** V6 -- running on a version 6 system. This determines 29 ** whether to define certain routines between 30 ** the two systems. If you are running a funny 31 ** system, e.g., V6 with long tty names, this 32 ** should be checked carefully. 33 ** VMUNIX -- running on a Berkeley UNIX system. 34 ** 35 ** Configuration Variables: 36 ** HdrInfo -- a table describing well-known header fields. 37 ** Each entry has the field name and some flags, 38 ** which are described in sendmail.h. 39 ** 40 ** Notes: 41 ** I have tried to put almost all the reasonable 42 ** configuration information into the configuration 43 ** file read at runtime. My intent is that anything 44 ** here is a function of the version of UNIX you 45 ** are running, or is really static -- for example 46 ** the headers are a superset of widely used 47 ** protocols. If you find yourself playing with 48 ** this file too much, you may be making a mistake! 49 */ 50 51 52 53 54 /* 55 ** Header info table 56 ** Final (null) entry contains the flags used for any other field. 57 ** 58 ** Not all of these are actually handled specially by sendmail 59 ** at this time. They are included as placeholders, to let 60 ** you know that "someday" I intend to have sendmail do 61 ** something with them. 62 */ 63 64 struct hdrinfo HdrInfo[] = 65 { 66 /* originator fields, most to least significant */ 67 "resent-sender", H_FROM|H_RESENT, 68 "resent-from", H_FROM|H_RESENT, 69 "resent-reply-to", H_FROM|H_RESENT, 70 "sender", H_FROM, 71 "from", H_FROM, 72 "reply-to", H_FROM, 73 "full-name", H_ACHECK, 74 "return-receipt-to", H_FROM, 75 "errors-to", H_FROM, 76 /* destination fields */ 77 "to", H_RCPT, 78 "resent-to", H_RCPT|H_RESENT, 79 "cc", H_RCPT, 80 "resent-cc", H_RCPT|H_RESENT, 81 "bcc", H_RCPT|H_ACHECK, 82 "resent-bcc", H_RCPT|H_ACHECK|H_RESENT, 83 /* message identification and control */ 84 "message-id", 0, 85 "resent-message-id", H_RESENT, 86 "message", H_EOH, 87 "text", H_EOH, 88 /* date fields */ 89 "date", 0, 90 "resent-date", H_RESENT, 91 /* trace fields */ 92 "received", H_TRACE|H_FORCE, 93 "via", H_TRACE|H_FORCE, 94 "mail-from", H_TRACE|H_FORCE, 95 96 NULL, 0, 97 }; 98 99 100 /* 101 ** ARPANET error message numbers. 102 */ 103 104 char Arpa_Info[] = "050"; /* arbitrary info */ 105 char Arpa_TSyserr[] = "451"; /* some (transient) system error */ 106 char Arpa_PSyserr[] = "554"; /* some (permanent) system error */ 107 char Arpa_Usrerr[] = "554"; /* some (fatal) user error */ 108 109 110 111 /* 112 ** Location of system files/databases/etc. 113 */ 114 115 char *ConfFile = "/usr/lib/sendmail.cf"; /* runtime configuration */ 116 char *FreezeFile = "/usr/lib/sendmail.fc"; /* frozen version of above */ 117 118 119 120 /* 121 ** Miscellaneous stuff. 122 */ 123 124 int DtableSize = 50; /* max open files; reset in 4.2bsd */ 125 /* 126 ** SETDEFAULTS -- set default values 127 ** 128 ** Because of the way freezing is done, these must be initialized 129 ** using direct code. 130 ** 131 ** Parameters: 132 ** none. 133 ** 134 ** Returns: 135 ** none. 136 ** 137 ** Side Effects: 138 ** Initializes a bunch of global variables to their 139 ** default values. 140 */ 141 142 setdefaults() 143 { 144 QueueLA = 8; 145 QueueFactor = 10000; 146 RefuseLA = 12; 147 SpaceSub = ' '; 148 WkRecipFact = 1000; 149 WkClassFact = 1800; 150 WkTimeFact = 600; 151 FileMode = 0644; 152 DefUid = 1; 153 DefGid = 1; 154 } 155 156 # ifdef V6 157 /* 158 ** TTYNAME -- return name of terminal. 159 ** 160 ** Parameters: 161 ** fd -- file descriptor to check. 162 ** 163 ** Returns: 164 ** pointer to full path of tty. 165 ** NULL if no tty. 166 ** 167 ** Side Effects: 168 ** none. 169 */ 170 171 char * 172 ttyname(fd) 173 int fd; 174 { 175 register char tn; 176 static char pathn[] = "/dev/ttyx"; 177 178 /* compute the pathname of the controlling tty */ 179 if ((tn = ttyn(fd)) == NULL) 180 { 181 errno = 0; 182 return (NULL); 183 } 184 pathn[8] = tn; 185 return (pathn); 186 } 187 /* 188 ** FDOPEN -- Open a stdio file given an open file descriptor. 189 ** 190 ** This is included here because it is standard in v7, but we 191 ** need it in v6. 192 ** 193 ** Algorithm: 194 ** Open /dev/null to create a descriptor. 195 ** Close that descriptor. 196 ** Copy the existing fd into the descriptor. 197 ** 198 ** Parameters: 199 ** fd -- the open file descriptor. 200 ** type -- "r", "w", or whatever. 201 ** 202 ** Returns: 203 ** The file descriptor it creates. 204 ** 205 ** Side Effects: 206 ** none 207 ** 208 ** Called By: 209 ** deliver 210 ** 211 ** Notes: 212 ** The mode of fd must match "type". 213 */ 214 215 FILE * 216 fdopen(fd, type) 217 int fd; 218 char *type; 219 { 220 register FILE *f; 221 222 f = fopen("/dev/null", type); 223 (void) close(fileno(f)); 224 fileno(f) = fd; 225 return (f); 226 } 227 /* 228 ** INDEX -- Return pointer to character in string 229 ** 230 ** For V7 compatibility. 231 ** 232 ** Parameters: 233 ** s -- a string to scan. 234 ** c -- a character to look for. 235 ** 236 ** Returns: 237 ** If c is in s, returns the address of the first 238 ** instance of c in s. 239 ** NULL if c is not in s. 240 ** 241 ** Side Effects: 242 ** none. 243 */ 244 245 char * 246 index(s, c) 247 register char *s; 248 register char c; 249 { 250 while (*s != '\0') 251 { 252 if (*s++ == c) 253 return (--s); 254 } 255 return (NULL); 256 } 257 /* 258 ** UMASK -- fake the umask system call. 259 ** 260 ** Since V6 always acts like the umask is zero, we will just 261 ** assume the same thing. 262 */ 263 264 /*ARGSUSED*/ 265 umask(nmask) 266 { 267 return (0); 268 } 269 270 271 /* 272 ** GETRUID -- get real user id. 273 */ 274 275 getruid() 276 { 277 return (getuid() & 0377); 278 } 279 280 281 /* 282 ** GETRGID -- get real group id. 283 */ 284 285 getrgid() 286 { 287 return (getgid() & 0377); 288 } 289 290 291 /* 292 ** GETEUID -- get effective user id. 293 */ 294 295 geteuid() 296 { 297 return ((getuid() >> 8) & 0377); 298 } 299 300 301 /* 302 ** GETEGID -- get effective group id. 303 */ 304 305 getegid() 306 { 307 return ((getgid() >> 8) & 0377); 308 } 309 310 # endif V6 311 312 # ifndef V6 313 314 /* 315 ** GETRUID -- get real user id (V7) 316 */ 317 318 getruid() 319 { 320 if (OpMode == MD_DAEMON) 321 return (RealUid); 322 else 323 return (getuid()); 324 } 325 326 327 /* 328 ** GETRGID -- get real group id (V7). 329 */ 330 331 getrgid() 332 { 333 if (OpMode == MD_DAEMON) 334 return (RealGid); 335 else 336 return (getgid()); 337 } 338 339 # endif V6 340 /* 341 ** USERNAME -- return the user id of the logged in user. 342 ** 343 ** Parameters: 344 ** none. 345 ** 346 ** Returns: 347 ** The login name of the logged in user. 348 ** 349 ** Side Effects: 350 ** none. 351 ** 352 ** Notes: 353 ** The return value is statically allocated. 354 */ 355 356 char * 357 username() 358 { 359 static char *myname = NULL; 360 extern char *getlogin(); 361 register struct passwd *pw; 362 extern struct passwd *getpwuid(); 363 364 /* cache the result */ 365 if (myname == NULL) 366 { 367 myname = getlogin(); 368 if (myname == NULL || myname[0] == '\0') 369 { 370 371 pw = getpwuid(getruid()); 372 if (pw != NULL) 373 myname = pw->pw_name; 374 } 375 else 376 { 377 378 pw = getpwnam(myname); 379 if(getuid() != pw->pw_uid) 380 { 381 pw = getpwuid(getuid()); 382 if (pw != NULL) 383 myname = pw->pw_name; 384 } 385 } 386 if (myname == NULL || myname[0] == '\0') 387 { 388 syserr("Who are you?"); 389 myname = "postmaster"; 390 } 391 } 392 393 return (myname); 394 } 395 /* 396 ** TTYPATH -- Get the path of the user's tty 397 ** 398 ** Returns the pathname of the user's tty. Returns NULL if 399 ** the user is not logged in or if s/he has write permission 400 ** denied. 401 ** 402 ** Parameters: 403 ** none 404 ** 405 ** Returns: 406 ** pathname of the user's tty. 407 ** NULL if not logged in or write permission denied. 408 ** 409 ** Side Effects: 410 ** none. 411 ** 412 ** WARNING: 413 ** Return value is in a local buffer. 414 ** 415 ** Called By: 416 ** savemail 417 */ 418 419 # include <sys/stat.h> 420 421 char * 422 ttypath() 423 { 424 struct stat stbuf; 425 register char *pathn; 426 extern char *ttyname(); 427 extern char *getlogin(); 428 429 /* compute the pathname of the controlling tty */ 430 if ((pathn = ttyname(2)) == NULL && (pathn = ttyname(1)) == NULL && 431 (pathn = ttyname(0)) == NULL) 432 { 433 errno = 0; 434 return (NULL); 435 } 436 437 /* see if we have write permission */ 438 if (stat(pathn, &stbuf) < 0 || !bitset(02, stbuf.st_mode)) 439 { 440 errno = 0; 441 return (NULL); 442 } 443 444 /* see if the user is logged in */ 445 if (getlogin() == NULL) 446 return (NULL); 447 448 /* looks good */ 449 return (pathn); 450 } 451 /* 452 ** CHECKCOMPAT -- check for From and To person compatible. 453 ** 454 ** This routine can be supplied on a per-installation basis 455 ** to determine whether a person is allowed to send a message. 456 ** This allows restriction of certain types of internet 457 ** forwarding or registration of users. 458 ** 459 ** If the hosts are found to be incompatible, an error 460 ** message should be given using "usrerr" and FALSE should 461 ** be returned. 462 ** 463 ** 'NoReturn' can be set to suppress the return-to-sender 464 ** function; this should be done on huge messages. 465 ** 466 ** Parameters: 467 ** to -- the person being sent to. 468 ** 469 ** Returns: 470 ** TRUE -- ok to send. 471 ** FALSE -- not ok. 472 ** 473 ** Side Effects: 474 ** none (unless you include the usrerr stuff) 475 */ 476 477 bool 478 checkcompat(to) 479 register ADDRESS *to; 480 { 481 # ifdef lint 482 if (to == NULL) 483 to++; 484 # endif lint 485 # ifdef EXAMPLE_CODE 486 /* this code is intended as an example only */ 487 register STAB *s; 488 489 s = stab("arpa", ST_MAILER, ST_FIND); 490 if (s != NULL && CurEnv->e_from.q_mailer != LocalMailer && 491 to->q_mailer == s->s_mailer) 492 { 493 usrerr("No ARPA mail through this machine: see your system administration"); 494 /* NoReturn = TRUE; to supress return copy */ 495 return (FALSE); 496 } 497 # endif EXAMPLE_CODE 498 return (TRUE); 499 } 500 /* 501 ** HOLDSIGS -- arrange to hold all signals 502 ** 503 ** Parameters: 504 ** none. 505 ** 506 ** Returns: 507 ** none. 508 ** 509 ** Side Effects: 510 ** Arranges that signals are held. 511 */ 512 513 holdsigs() 514 { 515 } 516 /* 517 ** RLSESIGS -- arrange to release all signals 518 ** 519 ** This undoes the effect of holdsigs. 520 ** 521 ** Parameters: 522 ** none. 523 ** 524 ** Returns: 525 ** none. 526 ** 527 ** Side Effects: 528 ** Arranges that signals are released. 529 */ 530 531 rlsesigs() 532 { 533 } 534 /* 535 ** GETLA -- get the current load average 536 ** 537 ** This code stolen from la.c. 538 ** 539 ** Parameters: 540 ** none. 541 ** 542 ** Returns: 543 ** The current load average as an integer. 544 ** 545 ** Side Effects: 546 ** none. 547 */ 548 549 #ifdef VMUNIX 550 551 #include <nlist.h> 552 553 struct nlist Nl[] = 554 { 555 { "_avenrun" }, 556 #define X_AVENRUN 0 557 { 0 }, 558 }; 559 560 getla() 561 { 562 static int kmem = -1; 563 # ifdef sun 564 long avenrun[3]; 565 # else 566 double avenrun[3]; 567 # endif 568 extern off_t lseek(); 569 570 if (kmem < 0) 571 { 572 kmem = open("/dev/kmem", 0, 0); 573 if (kmem < 0) 574 return (-1); 575 (void) ioctl(kmem, (int) FIOCLEX, (char *) 0); 576 nlist("/vmunix", Nl); 577 if (Nl[0].n_type == 0) 578 return (-1); 579 } 580 if (lseek(kmem, (off_t) Nl[X_AVENRUN].n_value, 0) == -1 || 581 read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun)) 582 { 583 /* thank you Ian */ 584 return (-1); 585 } 586 # ifdef sun 587 return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT); 588 # else 589 return ((int) (avenrun[0] + 0.5)); 590 # endif 591 } 592 593 #else VMUNIX 594 595 getla() 596 { 597 return (0); 598 } 599 600 #endif VMUNIX 601 /* 602 ** SHOULDQUEUE -- should this message be queued or sent? 603 ** 604 ** Compares the message cost to the load average to decide. 605 ** 606 ** Parameters: 607 ** pri -- the priority of the message in question. 608 ** 609 ** Returns: 610 ** TRUE -- if this message should be queued up for the 611 ** time being. 612 ** FALSE -- if the load is low enough to send this message. 613 ** 614 ** Side Effects: 615 ** none. 616 */ 617 618 bool 619 shouldqueue(pri) 620 long pri; 621 { 622 int la; 623 624 la = getla(); 625 if (la < QueueLA) 626 return (FALSE); 627 return (pri > (QueueFactor / (la - QueueLA + 1))); 628 } 629 /* 630 ** SETPROCTITLE -- set process title for ps 631 ** 632 ** Parameters: 633 ** fmt -- a printf style format string. 634 ** a, b, c -- possible parameters to fmt. 635 ** 636 ** Returns: 637 ** none. 638 ** 639 ** Side Effects: 640 ** Clobbers argv of our main procedure so ps(1) will 641 ** display the title. 642 */ 643 644 /*VARARGS1*/ 645 setproctitle(fmt, a, b, c) 646 char *fmt; 647 { 648 # ifdef SETPROCTITLE 649 register char *p; 650 register int i; 651 extern char **Argv; 652 extern char *LastArgv; 653 char buf[MAXLINE]; 654 655 (void) sprintf(buf, fmt, a, b, c); 656 657 /* make ps print "(sendmail)" */ 658 p = Argv[0]; 659 *p++ = '-'; 660 661 i = strlen(buf); 662 if (i > LastArgv - p - 2) 663 { 664 i = LastArgv - p - 2; 665 buf[i] = '\0'; 666 } 667 (void) strcpy(p, buf); 668 p += i; 669 while (p < LastArgv) 670 *p++ = ' '; 671 # endif SETPROCTITLE 672 } 673 /* 674 ** REAPCHILD -- pick up the body of my child, lest it become a zombie 675 ** 676 ** Parameters: 677 ** none. 678 ** 679 ** Returns: 680 ** none. 681 ** 682 ** Side Effects: 683 ** Picks up extant zombies. 684 */ 685 686 # ifdef VMUNIX 687 # include <sys/wait.h> 688 # endif VMUNIX 689 690 reapchild() 691 { 692 # ifdef WNOHANG 693 union wait status; 694 695 while (wait3(&status, WNOHANG, (struct rusage *) NULL) > 0) 696 continue; 697 # else WNOHANG 698 auto int status; 699 700 while (wait(&status) > 0) 701 continue; 702 # endif WNOHANG 703 } 704