SRI-NOSC/mmdf/submit.c
#
/*
* MULTI-CHANNEL MEMO DISTRIBUTION FACILITY (MMDF)
*
* Copyright (C) 1979 University of Delaware
*
* This program and its listings may be copied freely by United States
* federal, state, and local government agencies and by not-for-profit
* institutions, after sending written notification to:
*
* Professor David J. Farber
* Department of Electrical Engineering
* University of Delaware
* Newark, Delaware 19711
*
* Telephone: (302) 738-2405
*
* Notification should include the name of the acquiring organization,
* name and contact information for the person responsible for maintaining
* the operating system, and license information if MMDF will be run on a
* Western Electric Unix(TM) operating system.
*
* Others may obtain copies by arrangement.
*
* The system was originally implemented by David H. Crocker, and the
* effort was supported in part by the University of Delaware and in part
* by contracts from the United States Department of the Army Readiness
* and Materiel Command and the General Systems Division of International
* Business Machines. The system was built upon software initially
* developed by The Rand Corporation, under the sponsorship of the
* Information Processing Techniques Office of the Defense Advanced
* Research Projects Agency, and was developed with their cooperation.
*
* The above statements must be retained with all copies of this program
* and may not be removed without the consent of the University of
* Delaware.
**/
/* Fall, 78: David H. Crocker: Completed initial coding */
/* 15 Dec 78: dhc: Try to stop auto-inclusion of aliases */
/* 20 Dec 78: dhc: Sender verification policy change: only local login */
#define VERBOSE 1
#include "mailer.h"
#include "ffio.h"
#define FFAKE 0 /* ff_read does no buffer stuffing */
#define MAXNUM 077777
struct adrstruct snoopadr;
#ifdef LOCDLVR
struct netstruct net_loc;
#endif
#ifdef ARPANET
struct netstruct net_arpa;
#endif
#ifdef POBOX
struct netstruct net_pobox;
#endif
#ifdef DIALSND
struct netstruct net_dialsnd;
#endif
int
userid,
ownerid,
lochostnum, /* local host number */
/* snoopnum, ** host number of snoopbox */
/* sentprotect, /* protection on files in mail */
/* directories */
highfd; /* # of fd's per process */
extern int
fout; /* for printf */
#define NUMFFBUFS 5
char ffbufs[NUMFFBUFS][FF_BUF];
char
chrcnv[], /* character conversion table */
locname[], /* local host name */
lhostr[], /* string version of lochostnum */
nammailer[], /* name of mailer process */
prgmailer[], /* program name of mailer proc. */
homeque[], /* directory containing mail */
/* queue directories */
*thefile, /* filename part of pathname */
aquedir[], /* name of directory where que- */
/* ued mail addresses are put */
tquedir[], /* temporary directory for */
/* aquedir file */
mquedir[], /* name of directory where que- */
/* ued mail text is put */
snoopfile[], /* if exists, do snooping */
*logindir, /* path to initial work dir */
/* Following are for gcread... */
nltrm[] "\n\377",
colntrm[] ":\377",
lsttrm[] ",\n\377",
lwsptrm[] " \t\r\n\377",
lstnultrm[] ",\n\000\377",
nultrm[] "\000\377";
struct iobuf tfilfd,
mfilfd,
cntlifd,
logbuf;
struct adrstruct adrstrt;
int retloc, /* address for envret () */
*echofd, /* handle on file for echochar */
passfd, /* handle on passwd file */
i,
numacmpt, /* number of adrcmpt entries */
numadrs, /* current number of addresses */
msgflgs, /* in first line of taquedir */
#define FLGFROM 1
#define OKFROM 2
passfrom; /* whether to authenticate from */
char earlyret, /* return from submit asap */
msgstat, /* status of proc'ing this msg */
msgend, /* null or eof encountered */
eofhit, /* to terminate program */
dbgmode, /* more verbosity */
domsg,
snoopcnt, /* only needed at Rand */
rtn2sndr, /* return addr = submitter */
*sourcetxt, /* add txt to source-info */
useprot
{
TRUE
} , /* protocol vs. parm control */
/* */ snoopall, /* always snoop messages */
delv DELMAIL, /* which ftp command to use */
domailer, /* fork mailer for send? */
takadrs, /* will be given (partial) list */
bldadrs, /* extract addrs from message */
watchit, /* user watch immediate sends? */
trustflg, /* trust the submitter? */
*vianet, /* coming from net x */
vrfyflg, /* signal each addr acceptance */
username[10], /* from passwd file */
*moreline, /* for cmpntin to pass back */
testline[LINESIZE], /* for authentication */
*tfilnam, /* file name in tquedir */
*afilnam, /* file name in aquedir */
*mfilnam, /* file name in mquedir */
*adrcmpt[5], /* components containing adrs */
sndloc 'q', /* whether to wait for local or */
sndnet 'q', /* network messages */
haveloc, /* actually have local addrs */
havenet, /* actually have net addrs. */
*filpref; /* text to precede file refs */
struct adrstruct *adrfree ();
/****************** ADDRLST INPUT ROUTINES ***************** */
primeadrs (adrbuf) /* used by doaddrs */
char *adrbuf;
{ /* we are being given these */
register int tmp;
register char *strptr;
if (((tmp = cntlin (strptr = adrbuf, lstnultrm)) <= 0) ||
(*strptr == '!' && strptr[1] == '\n') ||
/* terminate the list */
msgend) /* this shouldn't happen */
return (NOTOK); /* eof */
return (tmp);
}
struct iobuf *infilfd; /* initialized by addrfil */
filin (adrbuf)
char *adrbuf;
{ /* we are being given these */
register int tmp;
register char *strptr;
if ((tmp = gcread (infilfd, strptr = adrbuf, LINESIZE, lstnultrm)) <= 0)
return (NOTOK); /* eof */
return (tmp);
}
cmpntin (adrbuf)
char *adrbuf;
{ /* adrs extracted from message */
static morcmpnt;
register int tmp;
register char *strptr;
if (((tmp = cntlin (strptr = adrbuf,
(morcmpnt) ? ":,\n\000\377" : lstnultrm)) <= 0)
|| msgend)
return (NOTOK); /* eof */
if (*strptr == '\0')
return (NOTOK); /* end of headers */
fwrite (&mfilfd, adrbuf, tmp);
if (morcmpnt)
{ /* potential continuation line */
if (*strptr != ' ' && *strptr != '\t')
{ /* no such luck */
morcmpnt = FALSE;
strptr[tmp] = '\0';
moreline = strdup (strptr);
return (NOTOK);
}
for (; lwsp (*strptr); strptr++);
if (strptr > adrbuf)
strcpy (strptr, adrbuf);
}
if (adrbuf[tmp - 1] == '\n')
morcmpnt = TRUE;
return (strlen (adrbuf));
}
/* MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN */
main (argc, argv)
int argc;
char *argv[];
{
char *argcptr;
dbgmode = TRUE;
dbglog ("Submit says hello.");
pgminit (argc, argv); /* parse args, alloc buffers. */
userinit (); /* Get user's system name */
dirinit (); /* chdir into homeque */
for (envsave (&retloc); !eofhit;)
{
loopinit ();
if (useprot && switchinit () < OK)
break; /* no commands from user */
queueinit (); /* set-up the files */
if (takadrs || !bldadrs) /* if list being given, */
adrlst (&primeadrs, TRUE);
/* acquire, canonicalize, store */
if (msgend)
sysabrt (RPLSYN, "Input ended prior to processing text");
stormsg (); /* queue & authenticage */
fflush (&mfilfd);
close (mfilfd.fildes); /* done with message text file */
storadrs (); /* put adr list into file */
fflush (&tfilfd);
close (tfilfd.fildes);
dbglog ("msg done");
if (link (tfilnam, afilnam) == NOTOK)
sysabrt (RPLLOC, "unable to move file to mail queue");
if (unlink (tfilnam) == NOTOK)
/* move to regular directory */
sysabrt (RPLLOC, "unable to move file to mail queue");
tfilfd.fildes = 0;
mfilfd.fildes = 0;
dbglog ("doing mailer?");
send (); /* give the message a mailer */
if (!earlyret)
rplok ("Done");
if (!eofhit)
alstfree ();
}
if (!eofhit)
suckup ();
dbglog ("normal exit");
flush ();
exit (msgstat / 10);
}
/* *********************** UTILITIES *********************** */
char echochar ()
{
register char c;
if ((c = getc (&cntlifd)) > '\0')
{
if (putc (c, echofd) < 0)
sysabrt (RPLLOC, "output error");
}
else
{
msgend = TRUE;
if (c == NOTOK)
eofhit = TRUE;
}
return (c);
}
cntlin (buffer, brkset)
char *buffer;
char *brkset;
{
register int tmp;
register char *strptr;
#ifdef VERBOSE
dbglog ("cntlin ()");
#endif
switch (tmp = gcread (&cntlifd, strptr = buffer, LINESIZE - 1, brkset))
{
case -1:
sysabrt (RPLLOC, "Error reading data from control stream");
case 0:
dbglog ("\t EOF");
msgend = eofhit = TRUE;
break;
default:
if (strptr[tmp - 1] == '\0')
msgend = TRUE;
else
strptr[tmp] = '\0';
}
#ifdef VERBOSE
dbglog ("\treturning: \"%s\"", strptr);
#endif
return (tmp);
}
char *stralloc (numbytes)
int numbytes;
{
register char *tmp;
if ((tmp = alloc (numbytes)) == NOTOK)
sysabrt ("No more storage available");
return (tmp);
}
/* ******************** INITIALIZATIONS *********************** */
pgminit (argc, argv)
int argc;
char *argv[];
{
int tmp;
for (tmp = 0; tmp < NUMFFBUFS; tmp++)
ff_use (ffbufs[tmp]);
for (tmp = 1; tmp < argc; tmp++)
{
if (*argv[tmp] == '-')
{
useprot = FALSE;
parminit (&argv[tmp][1]);
}
#ifdef ARPANET
else
if (strequ (argv[tmp], "snoop"))
snoopcnt = snoopall = TRUE;
#endif /* for use by FTP */
}
fout = dup (1); /* force buffered output */
close (1);
/* add directory part of pathname */
tfilnam = stralloc (strlen (&tquedir) + 15);
afilnam = stralloc (strlen (&aquedir) + 15);
mfilnam = stralloc (strlen (&mquedir) + 15);
strcpy (&tquedir, tfilnam);
thefile = tfilnam + strlen (&tquedir);
/* thefile = just file name */
strcpy (&mquedir, mfilnam);
strcpy (&aquedir, afilnam);
}
userinit ()
{ /* who is running me? */
int tmp;
char uidstr[6];
register char c,
*charptr;
if ((passfd = ff_open ("/etc/passwd", 0)) == NOTOK)
sysabrt (RPLLOC, "Cannot open password file");
for (userid = getuid (), ownerid = (userid >> 8) & 0377, userid =& 0377;
(tmp = ff_read (passfd, &username, sizeof username, colntrm)) > 0;
ff_read (passfd, FFAKE, MAXNUM, nltrm))
/* do our own getpw, in order */
{ /* to use the ff_ routines */
if (tmp < 0)
sysabrt (RPLLOC, "Error reading password file");
username[tmp - 1] = '\0';
ff_read (passfd, FFAKE, MAXNUM, colntrm);
/* skip encrypted password */
uidstr[ff_read (passfd, &uidstr, sizeof uidstr, colntrm) - 1]
= '\0'; /* get user number so */
/* we know who you are... */
ff_read (passfd, FFAKE, MAXNUM, colntrm);
ff_read (passfd, FFAKE, MAXNUM, colntrm);
/* skip group & GCOS info */
/* get the initial working directory */
testline[ff_read (passfd, &testline, LINESIZE, colntrm) - 1] = '\0';
logindir = strdup (testline);
if (userid == atoi (&uidstr))
return (TRUE);
}
sysabrt (RPLLOC, "Your user id isn't in password file!");
}
dirinit ()
{
filpref = gwdir (); /* save original working dir name */
if (chdir (homeque) == NOTOK) /* change wdir into mail queues */
sysabrt (RPLLOC, "Unable to change directory.");
setuid (getuid () & 0377); /* so we have the user's privileges */
/* to access address files */
}
loopinit ()
{
earlyret =
haveloc =
havenet =
msgend = FALSE;
msgstat = OK;
snoopcnt = snoopall; /* if FTP always include snoop */
echofd = &mfilfd;
}
switchinit ()
{
register **strptr;
if (vianet)
free (vianet);
for (strptr = adrcmpt; *strptr; free (*strptr));
numadrs =
numacmpt =
sourcetxt =
msgflgs = 0;
passfrom =
takadrs =
bldadrs =
rtn2sndr =
watchit =
vrfyflg =
vianet =
domailer = FALSE;
delv = DELMAIL; /* default to MAIL command */
/* return full message */
sndloc = /* default is not to wait for */
sndnet = 'q'; /* any deliveries */
switch (cntlin (&testline, nltrm))
{
case NOTOK:
msgabrt ("RPLPARM, Error reading switches");
case 0:
return (NOTOK);
}
parminit (&testline);
}
parminit (str)
char *str;
{
if (!parmset (str))
msgabrt (RPLPARM, "Invalid parameter specification");
if (!useprot)
{
domsg = TRUE;
if (vrfyflg)
sysabrt (RPLPARM, "Verification only allowed in protocol mode");
}
if (trustflg)
passfrom = (userid == 0 || userid == ownerid || vianet)
? OKFROM : FLGFROM;
if (watchit)
{
if (sndloc == 's')
sndloc = 'w';
if (sndnet == 's')
sndnet = 'w';
}
if (!domailer) /* queueing is de facto */
sndloc = sndnet = 's';
}
parmset (parmlst)
char *parmlst;
{
char *strtptr;
char tchar;
register int ind;
register char *ptr;
for (ptr = parmlst;;)
switch (*ptr++) /* read until end of list */
{
case '\n':
case '\0': /* end (shouldn't happen) */
return (TRUE);
case ' ':
case '\t':
continue;
case 'a':
delv = DELTTY; /* alert, thru xsem command */
break;
case 'c':
msgflgs =| RETCITE;
/* only cite return mail, don't */
break; /* send full copy */
case 'd':
dbgmode = TRUE;
break;
case 'f':
switch (*(ptr = getparm (strtptr = ptr, &sourcetxt)))
{
case ',':
case '*':
ptr++;
}
break; /* added to Source-Info field */
case 'g': /* 'x' [name *(',' name)] '*' */
takadrs = TRUE; /* extract addrs from cmpnts */
case 'i': /* indirection "via" network */
switch (*(ptr = getparm (strtptr = ptr, &vianet)))
{case ',':
case '*':
ptr++;
}
break;
case 'l':
sndloc = 's'; /* for local mail, */
domailer = TRUE; /* fork a mailer */
break;
case 'm':
delv = DELMAIL; /* use ftp mail command */
break;
case 'n':
sndnet = 's'; /* for "net" mail, */
domailer = TRUE; /* fork a mailer */
break;
case 'r':
rtn2sndr = TRUE; /* don't read it from input */
break;
case 's':
delv = DELBOTH; /* use ftp xsen command */
break;
case 't': /* trust me; assumed authentic */
/* must be root */
trustflg = TRUE;
break;
case 'u': /* no verify, no trust */
passfrom = FLGFROM; /* include disclaimer */
break;
case 'v':
vrfyflg = TRUE; /* Certify each address */
break;
case 'w':
watchit = TRUE; /* user wants to watch delivery */
break;
case 'x': /* 'x' [name *(',' name)] '*' */
bldadrs = TRUE; /* extract addrs from cmpnts */
while (numacmpt < 10)
{ /* get component name */
switch (*(ptr = getparm (strtptr = ptr,
&(adrcmpt[numacmpt++]))))
{
case ',':
ptr++;
continue;
case '*':
ptr++;
default:
break;
}
break;
}
adrcmpt[numacmpt] = 0;
break;
}
return (FALSE);
}
getparm (pstrtadr, strptr)
char *pstrtadr;
char **strptr; /* where to put dup'd str */
{
int retval;
register char tchar;
register char *strtadr;
for (strtadr = pstrtadr;; strtadr++)
switch (*strtadr)
{
case '*':
case ',':
case '\0':
case '\n':
tchar = *strtadr;
*strtadr = '\0';
*strptr = strdup (pstrtadr);
*strtadr = tchar;
return (strtadr); /* c'est tout */
}
}
queueinit ()
{
long int ltmp;
int tmp;
char longstr[11]; /* for creation time */
crname (thefile); /* filename part into afilnam */
strcpy (thefile, &(mfilnam[strlen (&mquedir)]));
strcpy (thefile, &(afilnam[strlen (&aquedir)]));
/* dbglog ("tname = \"%s\"", tfilnam); */
/* create file in temp directory */
flush ();
if (fcreat (tfilnam, &tfilfd) < 0)
sysabrt (RPLLOC, "Can't create address file to be queued.");
/* strictly sequential output */
time (<mp); /* Initialize contents */
litoa (ltmp, &longstr); /* 1. Full creation time string */
fwrite (&tfilfd, &longstr, strlen (&longstr));
putc ('/', &tfilfd); /* 2. Delivery status */
itoa (msgflgs, &longstr);
fwrite (&tfilfd, &longstr, strlen (&longstr));
/* 3. Flags: only retcite, now */
putc ('\n', &tfilfd); /* 4. New line... */
if (rtn2sndr) /* 5. return address */
{
fwrite (&tfilfd, username, strlen (username));
putc ('\n', &tfilfd);
}
else
for (echofd = &tfilfd; echochar () != '\n';);
echofd = &mfilfd;
}
/* ************ ADDRESS LINKED-LIST PRIMITIVES *************** */
addadr (padr)
struct adrstruct *padr;
{
char *mbox;
register struct adrstruct *adr,
*curadr,
*lastptr;
/* dbglog ("addadr ()"); */
for (adr = padr, curadr = adrstrt.nxtadr, lastptr = &adrstrt;
curadr != 0; lastptr = curadr, curadr = curadr -> nxtadr)
{
switch (adrcmpr (adr, curadr))
{
case 1:
continue;
case 0: /* duplicate entry */
return;
}
break; /* => adrcmpr returned NOTOK */
}
numadrs++;
lastptr -> nxtadr = adr;
adr -> nxtadr = curadr;
}
storadrs ()
{
char *snooptr,
*tmpadr;
register struct adrstruct *curadr;
register int tmp;
dbglog ("storadrs: %d addrs...", numadrs);
#ifdef SNOOP
if (snoopcnt && (snoopadr.dlv_code != '\0') && !access (snoopfile, 0))
{
for (tmpadr = stralloc (tmp = sizeof *curadr),
snooptr = &snoopadr; tmp >= 0; tmp--)
tmpadr[tmp] = snooptr[tmp];
addadr (tmpadr);
}
#endif
for (curadr = adrstrt.nxtadr; curadr != 0; curadr = curadr -> nxtadr)
adrstor (curadr);
}
alstfree ()
{
register struct adrstruct *curadr;
for (curadr = adrstrt.nxtadr; curadr != 0; curadr = adrfree (curadr));
adrstrt.nxtadr = 0;
numadrs = 0;
}
struct adrstruct
*adrfree (padr)
struct adrstruct *padr;
{
register struct adrstruct *curadr,
*nxtadr;
if ((curadr = padr) == 0)
return (0);
if (curadr -> smbox != 0)
free (curadr -> smbox);
if (curadr -> shostr != 0)
free (curadr -> shostr);
nxtadr = curadr -> nxtadr;
free (curadr);
return (nxtadr);
}
/* **************** ADDRESS PARSING ROUTINES **************** */
adrlst (inproc, errabrt)
int (*inproc) (), /* process to acquire adr strs; */
/* it decides when to end stream */
errabrt; /* abort on error? */
{ /* process stream of addresses */
struct adrstruct *tstadr;
int adrlen;
char adrline[LINESIZE],
*strtptr;
register char *strptr;
/* dbglog ("adrlst ()"); */
for EVER
{
zero (adrline, LINESIZE);
if ((adrlen = ((*inproc) (strptr = &adrline))) <= 0)
break;
strptr[adrlen - 1] = '\0';
if (!rmcmnt (strptr, strptr) && errabrt)
if (vrfyflg)
procerr (RPLUSR, "Bad comment \"%s\"", strptr);
else
msgabrt (RPLUSR, "Bad comment \"%s\"", strptr);
compress (strptr, strptr);/* strip lead, trail & extra space */
switch (*strptr)
{
case '\0': /* ignore blank lines */
continue;
case '<': /* indirect through a file */
for (strptr++; lwsp (*strptr); strptr++);
/* skip leading white space */
addrfil (strptr, errabrt);
continue;
}
if (!chkadr (strtptr = strptr) && errabrt)
{
strptr = &adrline[LINESIZE - 1];
*strptr = '\0';
while (strptr >= &adrline && *strptr-- == '\0');
for (; strptr >= &adrline; strptr--)
if (*strptr == '\0')
*strptr = ' ';
if (vrfyflg)
procerr (RPLUSR, "Unknown address \"%s\"", strtptr);
else
msgabrt (RPLUSR, "Unknown address \"%s\"", strtptr);
}
else
if (vrfyflg && errabrt)
rplok (strtptr);
}
}
addrfil (strptr, errabrt)
char *strptr;
int errabrt;
{
char filename[LINESIZE];
dbglog ("addrfil ()");
strcpy (strptr, strcpy ((*strptr == '/') ? "" : filpref, filename));
infilfd = stralloc (sizeof *infilfd);
zero (infilfd, sizeof *infilfd);
if (fopen (filename, infilfd) < OK)
msgabrt (RPLUSR, "Can't get addresses from file %s", filename);
adrlst (&filin, errabrt); /* file inherits abort-ability */
close (infilfd -> fildes);
free (infilfd);
return (OK);
}
chkadr (tstline)
char *tstline;
{
register struct adrstruct *tstadr;
register char *ptr;
int mboxlen;
char netcode,
hostr[LINESIZE],
adrstr[LINESIZE];
#ifdef VERBOSE
dbglog ("chkadr (%s)", tstline);
#endif
/* DBG HANDLE NETWORK NAME */
for (ptr = tstline; lwsp (*ptr); ptr++);
if (ptr > tstline) /* delete leading lwspaces */
strcpy (ptr, tstline);
/* netcode = NOTOK;*/
if ((ptr = ghostpart (tstline, mboxlen = strlen (tstline), hostr))
== NOTOK)
netcode = LOCDLVR;
else /* net was explicitly referenced */
{
if ((netcode = net2code (hostr)) >= OK)
ptr = ghostpart (tstline, ptr - tstline, hostr);
while (ptr > tstline && lwsp (*ptr))
ptr--;
mboxlen = ptr - tstline + 1; /* length of mbox str */
}
switch (netcode)
{
default: /* no net reference */
#ifdef ARPANET
case ARPANET: /* At least it THINKS it's a hostname */
if (host2first (&net_arpa, TRUE, hostr, adrstr) ||
digit (adrstr[0]))
{ /* A "remote" host */
if (!strequ (locname, adrstr))
{
strcpy (adrstr, hostr);
netcode = ARPANET;
havenet = TRUE;
break;
}
netcode = LOCDLVR;
}
#endif
#ifdef POBOX
case POBOX:
if (netcode==NOTOK)
if (host2adr (&net_pobox, TRUE, hostr, adrstr)) {
if (!strequ( locname, adrstr))
{ /* A "remote" host */
netcode = POBOX;
havenet = TRUE;
strcpy (adrstr, hostr);
break;
}
netcode = LOCDLVR;
}
#endif
#ifdef DIALSND
case DIALSND:
if (netcode==NOTOK)
if (host2adr (&net_dialsnd, TRUE, hostr, adrstr)) {
if (!strequ( locname, adrstr))
{ /* A "remote" host */
netcode = DIALSND;
havenet = TRUE;
strcpy (adrstr, hostr);
break;
}
netcode = LOCDLVR;
}
#endif
#ifdef LOCDLVR
case LOCDLVR:
if (netcode == LOCDLVR)
{ /* no hostname => lochost */
blt (tstline, adrstr, mboxlen);
adrstr[mboxlen] = '\0';
if (aliasrch (adrstr))
{ /* local host -> local mbox */
dbglog ("alias = %s", tstline);
return (TRUE);/* if ok, it's been added */
}
if (passrch (adrstr))
{
hostr[0] = '\0';
netcode = LOCDLVR;
haveloc = TRUE;
break;
}
netcode = NOTOK;
break;
}
#endif
}
if (netcode == NOTOK)
return (FALSE);
tstadr = stralloc (sizeof *tstadr);
tstadr -> dlv_code = netcode;
tstadr -> shostr = (netcode == LOCDLVR) ? 0 : strdup (hostr);
tstadr -> smbox = ptr = stralloc (mboxlen + 1);
blt (tstline, ptr, mboxlen);
ptr[mboxlen] = '\0';
addadr (tstadr); /* ok, by this point */
#ifdef SNOOP
chksnoop (tstadr);
#endif
return (TRUE);
}
ghostpart (adrline, adrlen, destr)
char *adrline;
int adrlen;
char *destr; /* put "hostname" into here */
{
register char *strptr;
int tmp;
char *hostptr;
char *endptr;
/* dbglog ("ghostpart ()"); */
for (strptr = &(adrline[adrlen - 1]); lwsp(*strptr); strptr--);
for (endptr = strptr; ; hostptr = strptr--)
{
if (strptr <= adrline)
return (NOTOK);
switch (*strptr)
{
default:
continue;
case '@':
case '%':
break;
case ' ':
case '\t':
for (strptr--; (strptr > adrline) && lwsp (*strptr);
strptr--);
switch (*strptr) /* got one now */
{
case '@':
case '%':
break;
default: /* " at "?? */
if (equal (&strptr[-1], "AT", 2))
strptr--;
else /* tsk tsk */
return (NOTOK);
}
break;
}
break;
}
if (destr)
{
blt (hostptr, destr, tmp = (endptr - hostptr + 1));
destr[tmp] = '\0';
compress (destr, destr);
}
return (&strptr[-1]);
}
rmcmnt( from, to) /* remove comments from an address string */
register char *from, *to;
{ int inlit, incom;
inlit = FALSE;
incom = 0;
for (;;from++)
{ switch (*from)
{
case '\0': /* end of the string */
*to = *from;
return( inlit || (incom != 0) ? FALSE : TRUE );
case QUOTE: /* next char is quoted */
if (incom > 0) /* in a comment */
{ from++; continue;}
else /* to string must get both chars */
{ *to++ = *from++; break;}
case '"':
inlit = (inlit ? FALSE : TRUE);
break;
case LCMNTDLIM: /* left comment delimiter */
if (!inlit)
{
incom++;
continue;
}
else break;
case RCMNTDLIM: /* right comment delimiter */
if (!inlit)
if (incom > 0)
{ incom--;
if (incom == 0) *to++ = ' ';
continue;
}
else
{ for (; (*to++ = *from) != '\0'; *from++) ; /* copy rest of string */
return(FALSE); /* bad comment nesting */
}
}
if ( incom == 0) *to++ = *from;
}
}
net2code (str)
char *str;
{
extern struct netstruct *nets[];
register struct netstruct **netptr;
for (netptr = nets; *netptr != 0; netptr++)
if (strequ (str, (*netptr) -> net_spec))
return ((*netptr) -> net_code);
return (NOTOK);
}
code2net (code)
char code;
{
extern struct netstruct *nets[];
register struct netstruct **netptr;
for (netptr = nets; *netptr != 0; netptr++)
if (code == (*netptr) -> net_code)
return (*netptr); /* handle on entire entry */
return (NOTOK);
}
#ifdef SNOOP
chksnoop (tstadr)
struct adrstruct *tstadr;
{ /* Policy for snooping */
if ((tstadr -> shnum ^ lochostnum) & 077)
/* Same IMP as us? */
snoopcnt = TRUE; /* if not, big brother is watching */
}
#endif
struct aliastruct /* previous aposinfo's are stored */
{ /* on aliasrch's stack when aliasrch */
char *abufpos; /* curr pos in aliasbuf */
char aliasbuf[LINESIZE]; /* adr-part of alias entry */
} *curalias;
aliasin (buf)
char *buf; /* output buffer */
{
register char *toptr,
*fromptr;
if (*(fromptr = (curalias -> abufpos)) == '\0')
return (NOTOK); /* end of list */
for (toptr = buf;; fromptr++, toptr++)
switch (*toptr = *fromptr)
{
case ',':
case '\n':
case '\0':
*toptr = '\0';
curalias -> abufpos = fromptr;
return (toptr - buf + 1);
}
}
aliasrch (mbox)
char *mbox;
{
struct aliastruct *oldalias,
newalias;
long int oldpos;
int retval;
oldpos = (curalias == 0) ? 0 : ff_pos (net_loc.net_tabfd);
if (host2adr (&net_loc, FALSE, mbox,
newalias.abufpos = &newalias.aliasbuf))
{ /* recurse, using rest of alias line */
oldalias = curalias;
curalias = &newalias;
adrlst (&aliasin, FALSE);
curalias = oldalias;
retval = TRUE;
}
else
retval = FALSE;
ff_seek (net_loc.net_tabfd, oldpos);
return (retval);
}
passrch (pname)
char *pname;
{
int tmp;
char user[20];
register char *name;
ff_seek (passfd, 0, 0);
name = pname;
while ((tmp = ff_read (passfd, &user, sizeof user, colntrm)) > 0)
{
user[tmp - 1] = '\0';
if (strequ (name, user)) /* does name match? */
return (TRUE); /* then return success */
else /* skip rest of line */
if ((tmp = ff_read (passfd, FFAKE, MAXNUM, nltrm)) < 0)
break; /* shouldn't happen... */
}
if (tmp < 0)
sysabrt (RPLLOC, "Error reading during search of password file");
return (FALSE); /* return failure */
}
adrcmpr (padr1, padr2)
struct adrstruct *padr1,
*padr2;
{
register int tmp;
register struct adrstruct *adr1,
*adr2;
if ((tmp = ((adr1 = padr1) -> dlv_code - (adr2 = padr2) -> dlv_code))
< 0)
return (NOTOK);
if (tmp > 0)
return (1);
#ifdef NVRCOMPIL
if ((tmp = adr1 -> shnum) > 0)
{ /* host ref is numeric */
if ((tmp = (tmp - adr2 -> shnum)) < 0)
return (NOTOK);
if (tmp > 0)
return (1);
}
else /* have to do char compare */
#endif
switch (lexrel (adr1 -> shostr, adr2 -> shostr))
{
case 1:
return (1);
case NOTOK:
return (NOTOK);
}
return (lexrel (adr1 -> smbox, adr2 -> smbox));
}
adrstor (padr)
struct adrstruct *padr;
{
register struct adrstruct *curadr;
char anum[7];
curadr = padr;
/* dbglog ("%c %8s/%s",
curadr -> dlv_code, curadr -> shostr, curadr -> smbox); */
putc (curadr -> dlv_code, &tfilfd);
putc ((curadr -> dlv_code == LOCDLVR)
? sndloc : sndnet, &tfilfd);
putc (delv, &tfilfd);
if (curadr -> dlv_code != LOCDLVR)
{
#ifdef NVRCOMPIL
if (curadr -> shnum <= 0)
#endif
fwrite (&tfilfd, curadr -> shostr, strlen (curadr -> shostr));
#ifdef NVRCOMPIL
else
{ /* nope... */
itoa (curadr -> shnum, &anum);
fwrite (&tfilfd, &anum, strlen (&anum));
}
#endif
putc (' ', &tfilfd); /* separate host ref & mailbox */
}
fwrite (&tfilfd, curadr -> smbox, strlen (curadr -> smbox));
putc ('\n', &tfilfd);
}
/* ****************** MESSAGE TRANSFER ROUTINES ********************* */
stormsg ()
{
int tmp;
char gotsender,
gotfrom,
authorok;
register char *tstptr;
gotsender =
gotfrom =
authorok = FALSE;
dbglog ("stormsg ()");
if (fcreat (mfilnam, &mfilfd) < 0)
sysabrt (RPLLOC, "Can't create text file to be queued.");
if (passfrom)
authorok = gotfrom = gotsender = TRUE;
if (passfrom == FLGFROM || sourcetxt != 0)
dosrcinfo ();
if (vianet)
switch (vianet[0])
{
#ifdef ARPANET
case ARPANET:
dobody (); /* treat whole message as body */
return;
#endif
#ifdef POBOX
case POBOX:
dovia ();
#endif
}
while (!msgend && (tmp = cntlin (&testline, ":\n\000\377")) > 0
&& testline[0] != '\0')
{
#ifdef VERBOSE
dbglog ("\tdid cmpnt name input");
#endif
if (testline[tmp - 1] == '\0')
tmp--;
fwrite (&mfilfd, &testline, tmp);
tstfld:
switch (testline[0])
{
case ':':
msgabrt (RPLSYN, "Component without a name");
case '\n': /* "empty" component => end of headers */
dobody (gotsender, gotfrom, authorok);
return;
case ' ': /* continuation line */
case '\t':
cntline2mfil (tmp);
continue;
}
if (testline[tmp - 1] != ':')
msgabrt (RPLSYN, "No component name terminator");
testline[tmp - 1] = '\0';
compress (testline, testline);
/* remove extra lwsp */
if (strequ ("Sender", &testline) && !passfrom)
{ if (gotsender++ > 0)
msgabrt (RPLSYN, "Only one Sender component allowed");
if (!(authorok = chksndr ()))
msgabrt (RPLSYN, "Invalid specification in Sender component");
continue;
}
if (strequ ("From", &testline))
{ dbglog ("doing From");
tmp = chksndr ();
gotfrom++;
if (!gotsender)
authorok = tmp;
if (vianet)
doviareply ();
continue;
}
if (bldadrs && numacmpt > 0 && isadrcmpt (&testline))
{ adrlst (&cmpntin, TRUE);
if (moreline != 0)
{ strcpy (moreline, testline);
tmp = strlen (&testline);
free (moreline);
moreline = 0;
goto tstfld; /* "stuff" the input queue */
}
break;
}
cntline2mfil (0);
}
dbglog ("doing Body");
if (gotsender > 0 && gotfrom == 0)
msgabrt (RPLSYN,
"A From component must be present when a Sender one is used");
if (!authorok)
msgabrt (RPLSYN, "No valid author specification present");
if (!msgend) /* process the body */
dobody ();
}
dosrcinfo ()
{
puts ("Source-Info: ", &mfilfd);
if (passfrom == FLGFROM)
{
strcpy ("From (and/or Sender) name not authenticated.\n",
testline);
fwrite (&mfilfd, testline, strlen (testline));
if (sourcetxt != 0) /* pad for second line of text */
puts (" ", &mfilfd);
}
if (sourcetxt != 0)
{
fwrite (&mfilfd, sourcetxt, strlen (sourcetxt));
if (sourcetxt[strlen (sourcetxt) - 1] != '\n')
putc ('\n', &mfilfd);
}
}
dovia ()
{
struct netstruct *netptr;
char srchost[LINESIZE];
netptr = code2net (vianet[0]);
host2first (netptr, TRUE, &vianet[1], srchost);
/* Via: sourcehost to local-host use sourcehost%originating-net */
/* Via: <UDel-EE to Rand-Unix use UDel-EE%POBox> */
puts ("Via: <", &mfilfd);
puts (srchost, &mfilfd);
puts (" to ", &mfilfd);
puts (locname, &mfilfd);
puts (" use ", &mfilfd);
puts (srchost, &mfilfd);
putc ('%', &mfilfd);
puts (netptr -> net_spec, &mfilfd);
putc ('>', &mfilfd);
putc ('\n', &mfilfd);
}
cntline2mfil (curlast)
int curlast;
{
register int tmp;
for (tmp = curlast; !msgend && testline[tmp - 1] != '\n';
fwrite (&mfilfd, &testline, tmp))
{
#ifdef VERBOSE
dbglog ("rest of line:");
#endif
tmp = cntlin (&testline, nltrm);
}
}
doviareply ()
{
register char *ptr;
dbglog ("Doing Reply-to");
puts ("Reply-to: ", &mfilfd);
for (ptr = testline; lwsp(*ptr); ptr++);
for EVER
{ switch (*ptr)
{ case '\0':
case ' ':
case '\t':
case '@':
break;
default:
putc (*ptr, &mfilfd);
ptr++ ;
continue;
}
break;
}
/* puts (testline, &mfilfd); */
/* if (gtsrcname (vianet, testline)) */
/* { */
/* putc ('%', &mfilfd); */
/* puts (testline, &mfilfd); */
/* } */
puts (" at ", &mfilfd);
puts (locname, &mfilfd);
putc ('\n', &mfilfd);
}
dobody (gotsender, gotfrom, authorok)
char gotsender,
gotfrom,
authorok;
{
register int bodlen;
register char c;
for (; !msgend && (bodlen = cntlin (&testline, nultrm)) > 0;
fwrite (&mfilfd, &testline, bodlen))
{
if ((c = testline[bodlen - 1]) == '\0' && bodlen > 1)
c = testline[--bodlen - 1];
}
if (c != '\n') /* msgs must end with newline */
putc ('\n', &mfilfd);
}
isadrcmpt (name)
char *name;
{
register int entry;
for (entry = 0; entry < numacmpt && adrcmpt[entry]; entry++)
if (strequ (name, adrcmpt[entry]))
return (TRUE);
return (FALSE);
}
gtsrcname (pvianet, obuf)
char *pvianet,
*obuf;
{
struct netstruct *netptr;
char *ptr;
netptr = code2net (*pvianet); /* get net info */
host2first (netptr, TRUE, &pvianet[1], obuf);
for (ptr = obuf; *ptr; ptr++);
*ptr++ = '%';
strcpy (netptr -> net_spec, ptr);
/* Net name */
return (TRUE);
}
/* ******************* AUTHENTICATE SENDER ************************ */
chksndr ()
{
char hostr[LINESIZE];
char mbox[LINESIZE];
char *ptr;
register struct adrstruct *tstadr;
register int tmp;
dbglog ("chksndr: ");
if ((tmp = cntlin (&testline, nltrm)) <= 0)
return (FALSE);
fwrite (&mfilfd, &testline, tmp);
testline[--tmp] = '\0';
if ((ptr = ghostpart (&testline, tmp, hostr)) == NOTOK)
return (NOTOK);
blt (testline, mbox, ptr - testline);
mbox[ptr -testline] = '\0';
compress (mbox, mbox);
if (!strequ (hostr, locname) || !passrch (&mbox))
return (FALSE); /* bad nost or unknown user name */
return (TRUE);
}
/* ************************ FORK MAILER *************************** */
#define FRKEXEC 1
#define SPNEXEC 2
#define FRKWAIT 1
#define FRKPIGO 2
#define FRKCIGO 4
#define EXECR 8 /* Use execr, instead of execv */
send ()
{
register char c,
*q;
register int host; /* destination host, for snoop */
int proctyp,
dowait,
retval;
extern int regfdary[];
proctyp =
dowait = 0;
if (watchit) /* wait for fork */
{
proctyp = FRKEXEC;
dowait = FRKWAIT | FRKPIGO;
}
else /* otherwise let it run by */
{
rplok ("Submited");
regfdary[1] = NOTOK; /* won't be outputting to caller */
earlyret = TRUE; /* as soon as possible */
if (sndloc == 's' || sndnet == 's')
proctyp = SPNEXEC;
else
return; /* no forking at all */
}
if (!domailer ||
((!haveloc || sndloc == 'q') && (!havenet || sndnet == 'q')))
return;
regfdary[1] = fout;
retval = newpgml (proctyp, dowait | FRKCIGO, ®fdary,
&prgmailer, &nammailer, thefile, "-d", (watchit) ? "-w" : 0, 0);
/* if ((dowait & FRKWAIT) && (retval >> 8 == NOTOK)) */
/* procerr ("?unable to invoke mailer; retval = %o", retval); */
}
/* ********************** UTILITY ROUTINES ************************* */
suckup ()
{
if (!msgend)
while (gcread (&cntlifd, FFAKE, MAXNUM, nultrm) > 0);
}
/* Print the error indicated in the cerror cell */
int errno,
sys_nerr;
char *sys_errlist[];
inexit (errchar) /* exit if input from */
char errchar; /* communications pipe error */
{
int errcode;
sysabrt (RPLXFER, "input error: code = %d", errcode = errchar);
}
scram (c)
char c;
{
/* unlink (tfilnam); DBG */
inexit (c);
}
clrfiles ()
{
if (tfilfd.fildes > 0)
{
close (tfilfd.fildes);
unlink (tfilnam);
unlink (afilnam);
}
if (mfilfd.fildes > 0)
{
close (mfilfd.fildes);
unlink (mfilnam);
}
flush ();
/* if (useprot || vrfyflg) */
/* write (fout, "/\n", 2); ** signal error completion */
}
rplok (str)
char *str;
{
if (!(useprot || vrfyflg))
return;
putchar ('0');
/* printf ("%3d", RPLOK); */
if (str != 0)
printf (" %s", str);
putchar ('\n');
flush ();
}
sysabrt (code, a, b, c, d, e, f)
int code;
char *a,
*b,
*c,
*d,
*e,
*f;
{
if (envsave (&retloc)) /* have msgabrt return to here. */
msgabrt (code, a, b, c, d, e, f);
exit (code / 10);
}
msgabrt (code, a, b, c, d, e, f)
int code;
char *a,
*b,
*c,
*d,
*e,
*f;
{
msgstat = code;
procerr (code, a, b, c, d); /* includes "nack" flag */
suckup ();
clrfiles ();
if (useprot)
envrest (&retloc);
exit (code / 10);
}
procerr (code, a, b, c, d, e, f)
int code;
char *a,
*b,
*c,
*d,
*e,
*f;
{
char doerrno;
doerrno = FALSE;
log ("*** Submit error:");
log (a, b, c, d, e, f);
if (errno > 0 && errno < sys_nerr)
{
doerrno = TRUE;
log ("\t[ %s ]", sys_errlist[errno]);
}
if (earlyret)
return;
if (useprot)
putchar ('/'); /* DGB keep same interface, switch to code */
/* printf ("%3d ", code); when other pgms converted */
else
printf ("Submit: ");
printf (a, b, c, d, e, f);
if (doerrno)
printf (" [ %s ]", sys_errlist[errno]);
putchar ('\n');
flush ();
}