Relay-Version: version B 2.10.3 4.3bsd-beta 6/6/85; site seismo.CSS.GOV Posting-Version: version B 2.10.2 9/3/84; site panda.UUCP Path: seismo!harvard!talcott!panda!sources-request From: sources-request@panda.UUCP Newsgroups: mod.sources Subject: GaTech Sendmail (Part 2 of 3) Message-ID: <1001@panda.UUCP> Date: 14 Oct 85 13:21:25 GMT Date-Received: 14 Oct 85 17:05:43 GMT Sender: jpn@panda.UUCP Lines: 782 Approved: jpn@panda.UUCP Mod.sources: Volume 3, Issue 24 Submitted by: Gene Spafford #! /bin/sh # Make a new directory for these sources, cd to it, and run kits 1 thru 3 # through sh. When all 3 kits have been run, read README. echo "This is GaTech Sendmail kit 2 (of 3). If kit 2 is complete, the line" echo '"'"End of kit 2 (of 3)"'" will echo at the end.' echo "" export PATH || (echo "You didn't use sh, you clunch." ; kill $$) echo Extracting overview.ms cat >overview.ms <<'!STUFFY!FUNK!' .TL Mail Handling at Gatech .br Revision II .AU Gene Spafford .AI School of Information and Computer Science Georgia Institute of Technology 23 September 1985 .PP Site "gatech" is running a "smart" version of sendmail. I have hacked at the sendmail configuration files extensively, and although they are not yet doing 100% of what I want, they seem to work pretty well and handle our many (sometimes unusual) mail needs. What follows are brief descriptions of what happens to various bits of mail passing through our site. .PP There have been some changes since the last time I circulated this document. Most of the changes have been inspired (?) by the changes to sendmail done at Rutgers which allow "sendmail" to distinguish the source of incoming mail with mixed syntax addresses (e.g., a!b@c), and which rewrite the names of Internet hosts into the preferred form (as given in the /etc/hosts table, derived from NIC data). .NH 1 Why .PP Site "gatech" is directly on the uucp network (with over 75 contacts and acting as a de facto name server for a "southeast US domain"), the CSNet, and we serve as gateway for our local networks. We also have network traffic with some other major networks, and we might possibly get BITNET and ARPA access in the not-too-distant future, from "gatech" or some other campus machines. We'd like to have as complete and robust a mailing environment as possible. At the same time, we'd like to minimize our current phone bills as they are related to UUCP mail traffic. .NH 1 Routing .NH 2 Known Domains .PP Currently, there is considerable effort going on to identify and establish domains for mailing. Some of these domains are already established, if only in a de facto manner. Our sendmail currently recognizes the following well-known domains: ARPA, CSNET, GOV, EDU, COM, MIL, ORG, NET, UUCP, BITNET, DEC, and MAILNET. The following are also recognized when used as top-level domains: GTNET (local to Georgia Tech), OZ (the Australian network), TEK (recognized internal to Tektronix), and SDC (with sdcrdcf as the gateway). .PP There are a number of other "domains" that are recognized when used in a second-level position within a uucp address. That is, we recognize person@site.ATT.UUCP as something that should be directed to cbosgd via uucp for further resolution. This recognition is done by building psuedo-sites into the uucp routing database based upon the data distributed by the uucp map project. Among domains recognized like this are NCAL, SCAL, ATL, ATT, UK, and so on; the list may change based on updates to the map. (As an aside, at the time of this writing, "gatech" is one of the regional repositories of the current map, and we get automatic updates whenever the "real" map gets changed.) .PP In the following descriptions, any of the above can be used in place of a "DOMAIN" specifier. .NH 2 user@host[.DOMAIN] -and- user%host[.DOMAIN] .PP If mail comes in addressed specifically to one of the known domains, it is routed as described in the next section without any further changes. If the domain is not given, an attempt is made to derive the domain based on available lists of host names and aliases, and then routed as described in the next section. If no host/domain match can be found, the mail is returned with an error stating this. .NH 3 Domain Derivation .PP Host derivation is attempted in the following order: First, the host is checked to see if it is in the GTNET domain. Next, the host is checked to see if it is a host one hop away via UUCP. Next, the host is checked against all CSNET sites. Then it is checked against all Arpa/Internet sites. Next, it is checked against the list of known MAILNET hosts. Then it is checked against the list of all (other) known UUCP sites. Then it is checked against the list of known BITNET hosts. Finally, it is checked against the list of known DEC E-net sites. .PP This kind of checking is not 100% accurate because our lists are not always up-to-date. In particular, the Arpa list is updated infrequently due to the fact that we aren't actually on the Arpanet, and there is no list of DEC net sites available outside of DEC (we make due with gleaning names from posted news articles and exchanges with other sites interested in compiling such a list). .NH 3 Collisions .PP If the same hostname exists in more than one domain, the first match found will be the one used. Qualification of the address with an explicit domain specifier will ensure that the mail goes to the correct host (when routed through gatech). That is, the domain is considered to be the specifer for routing and if one is not explicitly provided (or implicitly, as in the case of "!" notation), then an attempt to made to guess a domain. .NH 2 host1!host2!host3...!hostn!user .PP Starting with "hostn" and working backwards to "host1" our mailer will attempt to find a host listed in our master UUCP path database. This database is generated using pathalias at least weekly based on the latest version of the uucp maps. If a match is found at "hostk", then the address is rewritten to be "!hostk!...hostn!user" and then mailed via UUCP. Such addresses are NEVER routed over any other network, unless "hostn" is recognized to be a GTNET host, in which case our internal transport mechanism is invoked. .PP There is NO way at present to force a path on UUCP mail through "gatech". This is perhaps a "not very good thing" but I can't come up with a good way to work in explicit paths. The map data is generally very good and I have observed very, very few failures since we first started doing this rewriting about 6 months ago. If this presents a major problem for someone, let me know and I'll see what I can work out. .NH 2 host1!host2!host3...!hostn!user@site[.DOMAIN] .br host1!host2!host3...!hostn!user%site[.DOMAIN] .PP This one diverges somewhat from the standard (RFC822 et.al.). The way these addresses get treated is based on the way the mail gets into our "sendmail." If the message originates on any of the local (GTNET) machines, or if it comes in via PMDF from CSNet, then the mail is routed to "site" for eventual delivery to host1!...hostn!user. Mail coming in via a UUCP link with a mixed-mode address like this will have the mail routed via uucp to hostn for eventual delivery to user@site. Thus, if one of our neighbors, such as someone at akgua, were to send mail to us addressed as seismo!person@ucbvax.ARPA, we would send the mail to seismo via uucp and present it to their "rmail" program as "rmail person@ucbvax.ARPA". .PP On the other hand, should someone on gitpyr send mail addressed as seismo!person@ucbvax.ARPA, it would arrive at Gatech via SMTP and then be sent to CSNet-relay via PMDF for delivery to site "ucbvax" with a request to be delivered to "seismo!person" relative to that site. In most cases, depending on the sites involved, this kind of treatment would result in the mail failing. The sendmail configurations I have created for all the local GTNET sites are such that it should not be required to specify such an address. Simply mailing to person@site should see the correct address and network transport mechanism chosen. The Usenet "news" programs on most of these sites have been built to use the Internet-style of address when mailing replies, so there should be few cases of users even seeing mixed mode addresses presented to them (mail passing through any of the mailers gets rewritten to show a consistent format). .NH 2 user%site1%site2%site3 .PP Addresses of this format get turned into user%site1%site2@site3, and an appropriate routing is provided to "site3," if known. .NH 2 Other network characters .PP The ":" delimiter gets turned into "!" symbols in any address presented to our sendmail. The "^" delimiter gets turned into "!" also. Addresses of the form "site=user" get turned into "user@site.BITNET" by convention. .NH 1 Errors .PP I have tried to trap all possible errors and generate return mail with meaningful messages. If you get errors you don't know how to interpret, please contact me. .NH 1 Source .PP I posted an ancestor of my current sendmail files to "mod.sources" a few months ago. If these latest versions appear stable, I will post them to the same place. If you'd like a copy right away, let me know. This includes the sendmail files for all the local GTNET machines, and the source for my "uumail" program which sits between sendmail and uux. !STUFFY!FUNK! echo Extracting uumail.c cat >uumail.c <<'!STUFFY!FUNK!' /* uumail.c --- uucp remailer * EHS 4/2/85 * Added rebuild sentinel and better error handling 10/13/85 * * Compile as: * cc -O -s uumail.c -ldbm -o uumail * * Usage: * usually called from sendmail in the following form: * uumail -f from addr < message * "from" is the address of the sender, and is passed to "uux" * in case of a remote error * "addr" is an address in the following form: * site!site!site!user * and "user" can take on any form not containing a "!" * * If a "-D" is used instead of a "-f", no mail will be sent * and various bits of diagnostic info will be printed to the * standard error output. Messages that would normally be * printed at the console are also printed to stderr, in this * case. The body of the message is also dumped to stderr. * * At least one "!" MUST be present in the address or else it will * be considered an error. * * The address is rewritten for the first applicable site * found in the database. If the path cannot be rewritten, * an error code is returned along with a message indicating * the problem. * * If the special sentinel value of @@@ is not present in the * database, then it is assumed that the database is being * rebuilt and the requesting process is blocked for TIMEOUT * (default = 180) seconds. If, after 5 such blocks, the * sentinel is not present, an error message is logged to * the console, and the error code EX_TEMPFAIL is returned. * The same is true if the dbm files cannot be initialized. * * Note: * The "uux" flags given below are for 4.3 BSD uucp and * may not exist for your version of uucp. Note especially * that the "-L" flag may not be present in earlier versions * (meaning to crank up uucico for a local call, otherwise * just queue it). * * Special defines: * PATHFILE is the basename of the dbm path database. * LOGF if defined is where a log of uucp mail is kept * TIMEOUT is the sleep(2) time, in seconds, to wait * if the database is unavailable or incomplete. * CONSOLE is the pathname of the file to report major errors * MYSITE is the site name to be used in reporting errors * via returned mail; if not defined, the sitename is * derived from a call to gethostname(2) * UUX is a sprintf(3) format string used to remotely execute * the rmail command on the next system. * SENTINEL is the special "sitename" to look for in the * path database to indicate a complete database */ #include #include #include #include #ifndef PATHFILE #define PATHFILE "/usr/lib/mail/uucp.hosts" #endif PATHFILE #ifndef CONSOLE #define CONSOLE "/dev/console" #endif CONSOLE FILE *console; #ifndef TIMEOUT #define TIMEOUT ((unsigned) 180) #endif TIMEOUT #ifndef UUX #define UUX "/usr/bin/uux -p -a%s -L -gM %s!rmail \\(%s\\)\n" #endif UUX #ifndef SENTINEL #define SENTINEL "@@@" #endif SENTINEL extern char *malloc (), *rindex (), *index (); extern char *strcpy (), *strcat (); extern int strlen (); extern FILE *popen (); datum key, result; char workbuf[512]; char *destination, *sender; int debug; #ifdef LOGF FILE *logfile; #endif LOGF main (argc, argv) int argc; char **argv; { register char *stp, *rtp; int indx, retval; extern void die (), checkpath (); destination = argv[3]; /* given destination (and user) */ sender = argv[2]; /* given sender */ if (argc != 4) die ("called with incorrect number of arguments.", EX_USAGE); debug = (argv[1][1] == 'D'); console = fopen (CONSOLE, "a"); if ((console == NULL) || debug) console = stderr; #ifdef LOGF logfile = fopen (LOGF, "a"); if (logfile == NULL) { fprintf (console, "\n*** uumail: Unable to open logfile %s\n", LOGF); logfile = console; } fprintf (logfile, "%s\t%s\t", sender, destination); #endif LOGF for (indx = 0; indx < 5; indx++) { if ((retval = dbminit (PATHFILE)) >= 0) break; if (debug) fprintf (stderr, "Database unavailable. Sleeping.\n"); sleep (TIMEOUT); } if (retval < 0) die ("could not open routing database files.", EX_TEMPFAIL); key.dptr = SENTINEL; key.dsize = strlen (SENTINEL) + 1; for (indx = 0; indx < 5; indx++) { result = fetch (key); if (result.dsize > 0) break; if (debug) fprintf (stderr, "Database incomplete. Sleeping.\n"); sleep (TIMEOUT); } if (result.dsize <= 0) die ("routing database files incomplete or truncated.", EX_TEMPFAIL); /* Now we back up through the address until we find a site we * know how to reach. If we don't find any, it's an error. */ strcpy (workbuf, destination); if (!(rtp = rindex (workbuf, '!'))) die ("address in improper format.", EX_DATAERR); *rtp = '\0'; while (stp = rindex (workbuf, '!')) { checkpath (rtp + 1, stp + 1, (int) (rtp - stp)); *rtp = '!'; rtp = stp; *rtp = '\0'; } checkpath (rtp + 1, workbuf, (int) (rtp - workbuf) + 1); /* If we got to here, we don't have a path */ *rtp = '!'; die ("Unable to find path to any host in pathname.", EX_NOHOST); } /* This routine does all the work. If it finds a path it immediately * will go ahead and do the mailing and exit. */ void checkpath (user, site, len) char *user, *site; int len; { FILE * pipfd; int comlen; char *address, *restol, *command; key.dptr = site; key.dsize = len; result = fetch (key); if (result.dsize <= 0) return; /* result <= 0 implies no match */ /* rewrite here */ comlen = strlen (user) + result.dsize; address = malloc ((unsigned) comlen); if (address == NULL) die ("malloc cannot get memory for new address.\n", EX_SOFTWARE); sprintf (address, result.dptr, user); #ifdef LOGF fprintf (logfile, "%s\n", address); #endif LOGF comlen = strlen (address) + strlen (UUX) + 4; command = malloc ((unsigned) comlen); if (command == NULL) die ("malloc cannot get memory for uux command line.\n", EX_SOFTWARE); if ((restol = index (address, '!')) != NULL) *restol++ = '\0'; sprintf (command, UUX, sender, address, restol); if (debug) { fprintf (stderr, "Command that would be executed: %s\n", command); pipfd = stderr; } else { pipfd = popen (command, "w"); if (pipfd == NULL) die ("cannot open pipe with popen(3).", EX_SOFTWARE); } while (fgets (workbuf, sizeof (workbuf), stdin)) fputs (workbuf, pipfd); comlen = debug == 0 ? pclose (pipfd) : 0; if (comlen) { sprintf (workbuf, "execution of uux returned with error status %d", comlen); die (workbuf, EX_UNAVAILABLE); } exit (EX_OK); } void die (message, errcode) char *message; int errcode; { #ifdef MYSITE char *mysite = MYSITE; #else char mysite[64]; gethostname (mysite, 64); #endif #ifdef LOGF fprintf (logfile, "Error: %s\n", message); #endif LOGF fprintf (console, "\n\07*** Error in uumail!\n"); fprintf (console, " %s\n", message); fprintf (console, " Mail from %s to %s being returned.\n\n", sender, destination); fprintf (stderr, "Mailer at \"%s\": %s\n", mysite, message); exit (errcode); } !STUFFY!FUNK! echo Extracting base.m4 cat >base.m4 <<'!STUFFY!FUNK!' ############################################################ # # General configuration information # # This information is basically just "boiler-plate"; it must be # there, but is essentially constant. # # Information in this file should be independent of location -- # i.e., although there are some policy decisions made, they are # not specific to Gatech per se. # # $Header: base.m4,v 5.1 85/10/13 20:45:34 spaf Release $ # ############################################################ include(version.m4) ########################## ### Special macros ### ########################## # my name DnMAILER-DAEMON # UNIX header format DlFrom $g $d # delimiter (operator) characters Do.:%@!^=/[] # format of a total name Dq$?x$x $.<$g> # SMTP login message De$j Sendmail $v/$V ready at $b ################### ### Options ### ################### # location of alias file OA/usr/lib/aliases # default delivery mode (deliver in background) Odbackground # (don't) connect to "expensive" mailers Oc # temporary file mode OF0600 # default GID Og1 # location of help file OH/usr/lib/sendmail.hf # log level OL2 # default messages to old style Oo # queue directory OQ/usr/spool/mqueue # read timeout -- violates protocols Or2h # status file OS/usr/lib/sendmail.st # queue up everything before starting transmission Os # Queue when we're busy (x) and refuse SMTP when really busy (X) Ox15 OX20 # default timeout interval OT5d # time zone names (V6 only) OtEST,EDT # default UID Ou1 # wizard's password OWa/FjIfuGKXyc2 ############################### ### Message precedences ### ############################### Pfirst-class=0 Pspecial-delivery=100 Pjunk=-100 ######################### ### Trusted users ### ######################### Troot Tdaemon Tuucp Tnetwork ############################# ### Format of headers ### ############################# H?P?Return-Path: <$g> HReceived: $?sfrom $s $.by $j ($v/$V) id $i; $b H?D?Resent-Date: $a H?D?Date: $a H?F?Resent-From: $q H?F?From: $q H?x?Full-Name: $x HSubject: HPosted-Date: $a # H?l?Received-Date: $b # H?M?Resent-Message-Id: <$t.$i@$j> H?M?Message-Id: <$t.$i@$j> ########################### ### Rewriting rules ### ########################### ################################ # Sender Field Pre-rewriting # ################################ S1 ################################### # Recipient Field Pre-rewriting # ################################### S2 ################################# # Final Output Post-rewriting # ################################# S4 R@ $@ handle <> error addr # externalize local domain info R$*<$*LOCAL>$* $1<$2$D>$3 change local info R$*<$+>$* $1$2$3 defocus R$*$=S:$* $1$2!$3 R@$+:$+:$+ $@@$1,$2:$3 canonical # delete duplicate local names -- mostly for arpaproto.mc R$+%$=w@$=w $1@$3 u%UCB@UCB => u@UCB R$+%$=w@$=w.$=D $1@$3.$D u%UCB@UCB => u@UCB # clean up uucp path expressions (some) R$*!$*@$*.UUCP $3!$1!$2 ########################### # Name Canonicalization # ########################### S3 # handle "from:<>" special case R<> $@@ turn into magic token R$*$=S:$=S$* $1$3$4 R$*$=S!$=S$* $1$3$4 # basic textual canonicalization R$*<$+>$* $2 basic RFC821/822 parsing R$+ at $+ $1@$2 "at" -> "@" for RFC 822 R$*<$*>$* $1$2$3 in case recursive # make sure <@a,@b,@c:user@d> syntax is easy to parse -- undone later R@$+,$+ @$1:$2 change all "," to ":" # localize and dispose of domain-based addresses R@$+:$+ $@$>6<@$1>:$2 handle # more miscellaneous cleanup R$+ $:$>8$1 host dependent cleanup R$+:$*;@$+ $@$1:$2;@$3 list syntax # Handle special case of received via uucp R$-!$* $:<$&r>$1!$2 check arriving protocol R$-^$* $:<$&r>$1!$2 both syntaxes R$-!$* $@$>6$2<@$1.UUCP> if via UUCP, resolve R<$*>$* $2 undo kludge R$+@$+ $:$1<@$2> focus on domain R$+<$+@$+> $1$2<@$3> move gaze right R$+<@$+> $@$>6$1<@$2> already canonical # convert old-style addresses to a domain-based address R$+%$+ $:$1<@$2> user%host R$+<@$+%$+> $1%$2<@$3> fix user%host1%host2 R$+<@$+> $@$>6$1<@$2> leave R$-:$+ $@$>6$2<@$1> host:user R$-.$+ $@$>6$2<@$1> host.user R$+^$+ $1!$2 convert ^ to ! R$-!$+ $@$>6$2<@$1.UUCP> resolve uucp names R$-=$+ $@$>6$2<@$1.BITNET> resolve bitnet names !STUFFY!FUNK! echo Extracting MANIFEST cat >MANIFEST <<'!STUFFY!FUNK!' After all the sendmail kits are run you should have the following files: Filename Kit Description -------- --- ----------- Files 1 Description of auxillary files in /usr/lib/mail KEY 3 Describes some of the macros and classes we use. MANIFEST 2 This file: directory of files. Makefile 3 Processes all our files. PATCHES 1 Some source code changes for sendmail and rmail README 1 Description of what files are and what they do. base.m4 2 "basic" information included with all configurations. cirrus.mc 3 Master configuration file for gt-cirrus Clouds machine. csether.m4 3 ICS ethernet definitions. etherm.m4 3 Actual definition of the Ethernet mail "channel". gatech.mc 3 Master configuration file for our main relay machine. gitpyr.mc 3 Master configuration file for ICS/OCS Pyramid. gt-cmmsr.mc 3 Master configuration file for MMR Vax. gtbase.m4 3 Specifics for GT mail. gtqo.mc 3 Master configuration for Physics Sun. gtss.mc 3 Master configuration for Physics Sun. localm.m4 3 Actual definition of the "local" mail channel. nimbus.mc 3 Master configuration for gt-nimbus Clouds machine. overview.ms 2 A description of mail routing and address munging pmdfm.m4 2 Definition of the pmdf mail "channel". short2.m4 3 Short ruleset 0 used by non-ICS sites. short3.m4 3 Short ruleset 0 used by Physics sites (Suns on ethernet). shortzero.m4 3 Short ruleset 0 used in ICS department sites. stratus.mc 3 Master configuration file for gt-stratus Clouds machine. uucpm.m4 3 Definition of the uucp mail "channel". uumail.c 2 Source for the uumail program (read the comments at the top) uumail.m4 3 Definition of the uucp optimizing mailer used on "gatech" version.m4 3 Define the sendmail version. zerobase.m4 3 Machine independent preamble for ruleset 0. !STUFFY!FUNK! echo Extracting pmdfm.m4 cat >pmdfm.m4 <<'!STUFFY!FUNK!' ############################################################ ############################################################ ##### ##### PMDF Phonenet Channel Mailer specification ##### ##### $Header: pmdfm.m4,v 5.1 85/10/13 20:46:01 spaf Release $ ##### ############################################################ ############################################################ Mpmdf, P=/usr/local/lib/pmdf/pmdf-submit, F=mDsFSn, S=17, R=17, M=65535, A=pmdf-submit -f $g $u # # Notice that the PMDF mailer DOES NOT USE the host field. We # set this host field to "CSNET-RELAY" in all instances where # we call the PMDF mailer so as to be able to send one copy # of a letter with a number of recipients. # S17 # pass 's through R<@$+>$* $@<@$1>$2 resolve # map colons to dots everywhere..... R$*:$* $1.$2 map colons to dots # handle the simple case.... R$+<@$+.$=K> $@$>18$1<@$2.$3> user@host.ARPA R$+<@$-.CSNET> $@$1<@$2.CSNET> user@host.CSNET R$+<@LOCAL> $@$1<@$R.CSNET> local names R$+<@$+.LOCAL> $@$1%$2<@$R.CSNET> local notes R$+<@$*$=S> $@$1%$2$3<@$R.CSNET> more local hosts # handle other external cases R$+<@$=X> $@$1<@$2.UUCP> R$+<@$-> $@$1<@$2> R$+<@$+.$-.$=T> $@$1%$2<@$3.$4> approximate something R$+<@[$+]> $@$1<@[$2]> already ok # convert remaining addresses to old format and externalize appropriately # We try to do nifty things to uucp addresses first R$+<@$-.UUCP> $2!$1 R$+!$+!$+ $2!$3 R$+!$+ $@$2@$1.UUCP R$-:$+ $@$1.$2<@$A> convert berk hosts R$+<@$+> $@$1%$2<@$A> pessmize R$+ $:$1<@$R.CSNET> tack on our hostname R$+%$=A<@$A> $1<@$2> strip out unneeded relay S18 R$*<$+>$* $@$1<$%2>$3 !STUFFY!FUNK! echo "" echo "End of kit 2 (of 3)" cat /dev/null >kit2isdone config=true for iskit in 1 2 3; do if test -f kit${iskit}isdone; then echo "You have run kit ${iskit}." else echo "You still need to run kit ${iskit}." config=false fi done case $config in true) echo "You have run all your kits. Please read README." ;; esac : I do not append .signature, but someone might mail this. exit