[net.sources] Easy Internet and uucp aliasing for delivermail users

bstempleton (12/15/82)

At watmath, I, along with Dave Martindale have produced code to allow
people who run delivermail to get uucp aliasing and internet addressing
with minimal changes to the delivermail source.

The following is an explanation of how to add internet mailing and
uucp aliasing simply to your delivermail based mail system.
There is also source to the required mail handler and an explanation
for users.  The source to a "uua" program that lets people query the
database themselves is included.  The code is not complete, but provides
a quick and dirty implementation of the new mailing standard.  It is meant
to serve for the few months before 4.2bsd comes out.

This system is simpler because it doesn not involve changing anything
in delivermail except for the file "conf.c" which you are supposed to
changed.  What follows is the source to a program called "netmail" which
you should compile and place somewhere.  The place we keep it is
/usr/lib/mailers/netmail but it may go wherever you like.  To run this
system you need to have a uucp alias database in DBM format as generated
by Steve Bellovin's alias generating program.  This program is around in
a lot of places and can be found in decvax!~uucp/pathalias.tar among
others.

To install this system you must:
1) Create an alias database and place it somewhere.  The suggested place
is /usr/lib/uucp.  There is a #define in the source to the internet mailer
that gives the location of this database.
To get internet addressing to work, you should put in aliases for various
domain control sites.  For example, to handle the arpa domain you should
have an alias for your nearest arpa gateway.  I have a line of the form:
ucbvax	= arpa
in mine.  You may also wish lines of the form:
udel-relay = csnet
watmath = wat
to define the "csnet" and "wat" domains, the only others I know to exist.

If you connect to only one machine, and it already has a database, it
is wise (to avoid the hassle of maintaining several databases) to just
alias that machine to domain "uucp" and thus any messages for that domain
go there for routing.  If not we assume you have a map for the whole
uucp domain in your own filesystem.

2) Change the appropriate #defines in the netmail.c source and compile it
somewhere.  Also change the "wat" domain listed there to any local domain
you may have.  Don't forget to use -ldbm when compiling.  Also try
-DDEBUG to begin with if you aren't sure your conf.c is right.

3) [The hard part] Go to your delivermail source and change the conf.c
file.  You must make the following changes.  You must be careful that
you change the appropriate entries for your sites as conf.c is full of
ifdefs for all kins of Berkeley sites.  You may want to run cc -E on the
file to see which ones are yours, or follow it through.  If you actually
have an arpanet connection, the process will be somewhat different from what
I describe, which is for the typical isolated uucp site.

	a) Change the entry for the uucp mailer.  Currently this will call
	/bin/mail for you.  After the comment that says:
	"Cheat & use Bell's V7 mail", change the struct entry to:

{
	"/usr/lib/mailers/netmail",
	M_FOPT|M_STRIPQ,	EX_UNAVAILABLE,		UucpLocal,
	{ "...net%mail", "-s", "$h", "-u", "$u", NULL }
},

         	And add another mailer immediately after it with

	/* internet mailer takes user@host.domain syntax */
{
	"/usr/lib/mailers/netmail",
	M_FOPT|M_STRIPQ,	EX_UNAVAILABLE,		UucpLocal,
	{ "...net%mail", "-i", "-s", "$h", "-u", "$u", NULL }
},


===========================================
	You may wish to change the UucpLocal in the second instance to
	something else if you have other names in other domains.

	b) After the line saying "#define M_UUCP	4" add a line with
	"#define M_INTERNET	5"

	c) Change your configure table, after the "# else BERKELEY" probably.

	Since several people and sites will stick the the old "!" syntax,
	you will want to give it highest priority for the time being.
	Thus your table order should be something like:
	"!", "^", '.', "@", "\0"

	You should note that the internet mailing is keyed on "." while
	"@" keys uucp mailing (with aliasing) through a different syntax.
	This is because delivermail will not allow a host name to have a
	dot in it, and thus you can't have user@host.uucp keyed off of the
	at-sign.   Plain old user@host with no dots is assumed to be uucp
	mail now.  You can of course change that to arpanet mail if you
	prefer by a simple alteration to the conf.c.

	Our table looks like this, with #ifdefs to take away the internet
	code:
	
===========================================
	# else BERKELEY
	struct parsetab ParseTab[] =
	{
	
	# ifdef HASUUCP
		'^',	-1,		P_MAP,				"!",
		'!',	M_UUCP,		P_USR_UPPER,			NULL,
	# endif HASUUCP
	#ifdef INTERNET
		'.'	M_INTERNET,	P_HLAST|P_USR_UPPER,		NULL,
		'@'	M_UUCP,		P_HLAST|P_USR_UPPER,		NULL,
	#else INTERNET
	# ifdef HASARPA
		'@',	M_ARPA,		P_HLAST|P_USR_UPPER,		NULL,
	# else HASARPA
		'@',	M_UUCP,		P_HLAST|P_USR_UPPER|P_MOVE,	"decvax!ucbvax",
	# endif HASARPA
	#endif INTERNET
		'\0',	M_LOCAL,	P_MOVE,				"",
	};
	# endif BERKELEY
==================================================


	d)  Compile Delivermail with the new conf.c

	You are now ready to go!
=================================================
Here is a description of the changes for posting as was done at our
site.  You will need to change local refeences.
====================================================
A new version of delivermail(8) has been installed to aid in the
sending of mail to remote computers.  There are several new features:
.sp
An automatic uucp site aliaser allows mail to be sent to other
sites that we are not directly connected to as though we had a
direct connection.  The result of this is that you no longer have
to type long uucp path strings for most sites on the net.  In a
string of the form site!site2!...!user, the new mailer will look
"site1" up in a special database to find the way to mail to it.
Thus "ucbvax!eric" gets mapped to "decvax!ucbvax!eric".
.sp
Longer strings work as well, as "uw-beaver!user" becomes
"decvax!cornell!uw-beaver!user".  The database generally knows the
best way to mail to a certain site.  You can even mail to other
nets.  "sri-unix!knutsen" becomes "decvax!ucbvax!knutsen@sri-unix".
Not all sites and paths are in the database, so if you know of any
special ones you would like put in it, mail to bstempleton with
the connection you know of.  The current database is built from files found
in /usr/lib/uucp/paths.
Currently an ascii version of the database can be found in the file
/usr/pub/uucpaliases, if you wish to query what path is being
used to your site.  In certain cases, where there is a rare direct
connection to a site that the database doesn't know about, you can force
the aliasing to be stopped by using the path "math!yoursite!...". (ie.
stick "math!" in front of your path.  Normally, however, if you wish to
give explicit uucp paths, things should work as they did before.
.sp 2
In addition, the new delivermail crudely supports the new proposed
internet addressing standard.  A description of this standard can be
found the the report in /usr/pub/rfc819.  Addresses of the
from "user@host.domain" are recognized.  We are in the "uucp" domain,
and you are "yourname@watmath.uucp".  You can mail to an arpanet user
fbaggins on arpanet site shire with "fbaggins@shire.arpa"  You can
mail any uucp users with "user@site.uucp".  The uucp is not needed if
you are mailing a message entirely within the uucp domain.  If it goes
outside this domain, for example to the arpa domain, then you must put
the ".uucp" on the end.  Otherwise addresses of the form "mark@cbosgd"
and "peterr@utcsrgv" work fine.  Currently the domains "uucp", "arpa"
and "csnet" are recognized.  The same aliaser  as the one described
above is used.
.sp
The "net mailing" characters have a priority arranged.  That priority is
(high to low) "!", '.' and "@".  This means that if an "!" is found
anywhere in an address it will be sent to the uucp mailer directly without
any internet interpretation.
This means that if you want what the arpanet
sees as "csin!cjh@cca-unix.arpa" you can not type it like this.  The "!"
will be interpreted first and the "cjh@cca-unix.arpa" will be shipped off
to csin by the correct path.  To get such a path, try the address:
"arpa!csin!cjh@cca-unix" for now.
.sp
.ce
IMPORTANT NOTE
.sp
This new aliaser may cause problems with replies from other sites.
The network is slowly moving over to this new syntax, but not all
sites are switched.  Many major sites like "cbosg" and "ucbvax" and friends
are switched, but others may not be.  Due to this, they may have trouble
in using the "r" command to reply to your mail.  There will never be any
problems in the reply to you, just in the replies to additional recipients
of your mail.  At worst, such replies may be routed through our machine.
If you are sending to large lists of people you may wish to worry about
this and use explicit routing.  Also, the "rmail" program that handles
incoming mail has not yet been changed to handle this, so there may be
minor problems with incoming mail from the arpanet.  These problems
will be limited to an inability to reply with the "r" command.  This should
not bother anybody since this never worked before.  If you reply with "r",
it will only work if the arpanet site is in our uucp database.  Most
sites are already in that database, and if you wish to mail to one that
is not, send mail and it will be added.  To properly reply to user@site,
just mail to user@site.arpa and things will be fine.
.sp
If you don't want your replies to other people running this system
to include you, you will need the latest ucb mail and will need to
put a command of the form:
.ce
alternate yourname@yoursite.uucp
in the file.  Another find undocumented command!
=================================================================
Here is the source to the netmail program.
=================================================================
/* 
 * Net mailer that handles all uucp and "internet" mail.
 * With ALIASFILE defined, it tries looking up the destination
 * machine in a path database, expanding the alias if found.
 * There is a special kludge to check for the local GCOS site,
 * which doesn't run uucp but has a special mailer to handle
 * the mail anyway.
 */

#include <stdio.h>
/* outsiders comment out gcos stuff
#define GCOS_SITE	"watbun"
#define GCOS_LEN	sizeof( GCOS_SITE )
#define GCOS_MAILER	"/usr/lib/mailers/hmail"
*/
#define ALIASFILE	"/usr/lib/uucp/alpath"
#define CALL_NAME	"...net%mail"

typedef struct {
	char *dptr;
	int dsize;
} datum;
datum fetch();

char *rindex();
char *sprintf();
char *domains[] = {
	"uucp",
	"wat",
	0
};

main(argc, argv)
int argc;
char **argv;
{
	char *from = NULL;
	char *site = NULL;
	char *user = NULL;
	char *mailargs[10], **argp, *mailer;
	char flag;
	char internet = 0;
	char *recip, *malloc();
	datum newsite;			/* dbm entry with new site */
	datum key;			/* key to look for */
	char **dom, *p, *q;
	int stat, i;

#ifndef DEBUG
	if (strcmp(argv[0], CALL_NAME))
		error("Net mailer not called from delivermail\n");
#endif
	while (--argc > 0) 
		if (**++argv == '-') {
			if (strcmp(*argv, "-i")==0) {
				++internet;
			} else {
				flag = argv[0][1];
				if (--argc <= 0)
					error("Missing arg for -%c\n", flag);
				++argv;
				switch (flag) {
					case 'f':
						from = *argv;
						break;
					case 's':
						site = *argv;
						break;
					case 'u':
						user = *argv;
						break;
					default:
						error("Bad option %c\n", flag);
						break;
				}
			}
		} else
			error("Unflagged string %s\n", *argv);

	if (site == NULL || user == NULL)
		error("Missing site or user\n");
	argp = &mailargs[1];
	if (from != NULL) {
		*argp++ = "-r";
		*argp++ = from;
	}
	if (internet) {
		for (dom = domains; *dom; dom++) 
			if (strcmp(*dom, site)==0) {
				p = rindex(user, '.');
				if ((q=rindex(user, '@')) > p)
					p = q;
				if( p ) {
					*p = 0; /* shorten user */
					site = p+1;
				}
				 else
					/* No @ or dot, we will thus
					leave the site at the examined domain
					and quit */
					break;
			}
	}
		
#ifdef ALIASFILE
	/* now do uucp aliasing */

	dbminit(ALIASFILE);
	key.dptr = site;
	key.dsize = strlen(site) + 1;
	newsite = fetch(key);
	if (newsite.dptr) {
		/* we got an alias */
		recip = malloc(newsite.dsize + strlen(user) + 1);
		sprintf(recip, newsite.dptr, user);
	} else
#endif ALIASFILE
		{
		recip = malloc(strlen(site) + strlen(user) + 2);
		sprintf(recip, "%s!%s", site, user);
	}

	/* At this point it would be nice to add code that checked
	the first character of the recip string to see if it is an
	or bar, and if so, pass the rest of the string on to the shell.
	This allows adding new mailers for individual sites without
	changing any code and gets rid of this GCOS special case
	below.  The problem is that this is a terrible security hole
	so we leave it out for now.
	*/
#ifdef GCOS_SITE
	if( strncmp( recip, GCOS_SITE, GCOS_LEN -1 ) == 0 ) {
		mailer = GCOS_MAILER;
		mailargs[0] = "...gcos%mail";
		*argp++ = recip + GCOS_LEN;
	} else
#endif GCOS_SITE
		{
		mailer = "/bin/mail";
		mailargs[0] = "...uucp%mail";
		*argp++ = "-d";
		*argp++ = recip;
	}
	switch (fork()) {
	case -1:
		error("Could not fork!\n");
	case 0:
		setuid(getuid());
		*argp = NULL;
#ifdef DEBUG
		printf( "%s", mailer );
		{
			int i;
			for( i = 0; mailargs[i]; i++ )
				printf( " %s", mailargs[i] );

		}
		exit(0);
		break;
#else DEBUG
		execv(mailer, mailargs);
		error("execl of %s failed\n", mailer);
#endif DEBUG
	default:
		if (wait(&stat) == -1)
			stat = 1;
		exit((stat>>8)|stat);
	}
}

error(x) 
char *x;
{
	printf("Net Mailer: %r",  &x);
	exit(1);
}
==================================================
Here is an database query program
==================================================
/* uucp datbase checker */
#define ALIASES "/usr/lib/uucp/alpath"

typedef struct {
	char *dptr;
	int dsize;
	} datum;

datum fetch();

main(argc, argv)
int argc;
char **argv;
{
	datum findit, result;
	int i;

	dbminit( ALIASES );
	for( i = 1; i < argc; i++ ) {
		findit.dptr = argv[i];
		findit.dsize = strlen( argv[i] ) + 1;
		result = fetch( findit );
		if( result.dptr ) 
			printf( result.dptr, "User" );
		 else
			printf( "%s : Not found", argv[i] );
		putchar( '\n' );
		}
}
===================================================