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.14 (Berkeley) 1/10/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 = 9000; 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: }