1 #define MFDEBUG /* temporarily */
3 static char Id[] = "@(#)$Id: rmail.c,v 1.2 1993/08/25 17:32:49 jromine Exp $";
16 * Developed from the Berkeley mail program of the same name
17 * by Mike Obrien at RAND to run with the MMDF mail system.
18 * Rewritten by Doug Kingston, US Army Ballistics Research Laboratory
19 * Hacked a lot by Steve Bellovin (smb@unc)
21 * This program runs SETUID to root so that it can set effective and
22 * real [ug]ids to mmdflogin.
24 * 27-Oct-82 Marshall T. Rose <mrose%uci@rand-relay>
25 * Support proper munging by using the UCI mail filtering
26 * routines (enabled by #ifdef MF)
27 * Also use ll_log() package (enabled by #ifdef LOG)
29 * 17-Oct-83 Marshall T. Rose <mrose%uci@rand-relay>
30 * New interfacing. Remove the #ifdef:s
34 #define NAMESZ 64 /* Limit on component name size */
42 char *Fromtmp = "/tmp/rml.f.XXXXXX";
43 char *Msgtmp = "/tmp/rml.m.XXXXXX";
44 char *Errtmp = "/tmp/rml.e.XXXXXX";
45 char *Okhosts = "/usr/mmdf/table/rmail.ok";
46 char *Okdests = "/usr/mmdf/table/rmail.okdests";
48 extern char cmddfldir[];
49 extern char logdfldir[];
50 extern char mmdflogin[];
51 extern char pathsubmit[];
52 extern char sitesignature[];
53 extern char supportaddr[];
54 extern struct ll_struct chanlog;
56 char *dupfpath (), *index(), *rindex();
57 struct passwd *getpwnam(), *getpwuid();
62 struct ll_struct *logptr = &chanlog;
64 FILE *fromf; /* temporary out for colon-less UUCP "From" lines */
65 FILE *msgf; /* temporary out for message text */
66 FILE *mmdf; /* filtered mail file */
67 FILE *pipef; /* output to "submit" or "uux" */
68 char date[LINESIZE]; /* date of origination from uucp header */
69 char from[LINESIZE]; /* accumulated path of sender */
70 char origsys[NAMESZ]; /* originating system */
71 char origpath[LINESIZE];/* path from us to originating system */
72 char usrfrm[LINESIZE];
73 char Mailsys[LINESIZE];
74 int pbroke; /* broken-pipe flag */
75 int rtnflag; /* note was sent back */
84 char fromwhom[NAMESZ]; /* user on remote system */
86 char linebuf[LINESIZE]; /* scratchpad */
87 char sys[NAMESZ]; /* an element in the uucp path */
94 fprintf(stderr, "Usage: rmail user [user ...]\n");
99 ll_hdinit (logptr, "RM");
100 logptr -> ll_file = dupfpath (logptr -> ll_file, logdfldir);
102 if ((pw = getpwnam (mmdflogin)) == NULL) {
103 fprintf (stderr, "Cannot find mmdflogin\n");
109 sprintf (Mailsys, "%s <%s@%s>",
110 sitesignature, mmdflogin, LocalName ());
114 { /* BE VERY SURE... */
117 for (i = fileno (stdout); i <= HIGHFD; i++)
121 /* create file to hold stderr output. We first open some */
122 /* null file to make sure stdout is taken. If stdin isn't */
123 /* open either, we've got so much trouble it isn't even worth */
124 /* worrying about a little more */
125 open("/dev/null", 0);
127 if (freopen(Errtmp, "w", stderr) == NULL) {
128 fprintf(stderr, "Can't create %s\n", Errtmp);
129 ll_log (logptr, LLOGFAT, "Unable to create '%s'",
133 dup2 (fileno (stderr), fileno (stdout));
135 /* Create temp file for rest of message */
137 if ((msgf=fdopen(creat(Msgtmp, Tmpmode), "w")) == NULL) {
138 fprintf(stderr, "Can't create %s\n", Msgtmp);
139 ll_log (logptr, LLOGFAT, "Unable to create '%s'",
144 /* create temp file for colon-less UUCP "From" lines */
146 if ((fromf=fdopen(creat(Fromtmp, Tmpmode), "w")) == NULL) {
147 fprintf(stderr, "Can't create %s\n", Fromtmp);
148 ll_log (logptr, LLOGFAT, "Unable to create '%s'",
156 if( fgets(linebuf, sizeof linebuf, stdin) == NULL )
158 if( strncmp(linebuf, "From ", 5)
159 && strncmp(linebuf, ">From ", 6) )
162 if (linebuf[0] != '>')
164 fputs(linebuf, fromf); /* Save, we may forward via UUCP */
165 cp = index (linebuf, ' '); /* start of name */
167 cp = index (cp, ' '); /* cp at end of name */
168 *cp++ = 0; /* term. name, cp at date */
169 strcpy (fromwhom, fromptr);
170 strncpy (date, cp, 24); /* Mon Nov 10 23:12:09 1981 */
173 cp = index(cp+1, 'r');
175 cp = rindex(fromwhom, '!');
179 p = rindex(fromwhom, '!');
180 if (p != NULL) strcpy(origsys, p+1);
181 else strcpy(origsys, fromwhom);
182 strcat(from, fromwhom);
184 strcpy(fromwhom, cp+1);
187 strcpy (sys, SystemName ());
189 strcpy (origsys, sys);
193 if (strncmp(cp, "remote from ", 12) == 0)
197 sscanf(cp, "remote from %s", sys);
199 strcpy(origsys, sys); /* Save for quick ref. */
203 if( fromwhom[0] == '\0' ) /* No from line, illegal */
208 strcpy (origpath, from);
209 strcat (from, fromwhom);
210 mf_get_addr (from, usrfrm);
211 if ((cp = rindex (usrfrm, '<')) != NULL) {
212 strcpy (usrfrm, ++cp);/* sigh */
213 if ((cp = rindex (usrfrm, '>')) != NULL)
216 if (usrfrm[0] == NULL)
217 sprintf (usrfrm, "%s!%s%%%s@%s",
218 SystemName (), from, UucpChan (), LocalName ());
219 ll_log (logptr, LLOGGEN, "Rmail from '%s' (%s)", from, usrfrm);
220 fputs (linebuf, msgf);
221 if (rp_isbad (txtcpy (stdin, msgf)))
222 fputs ("\n *** Problem during receipt from UUCP ***\n", msgf);
224 freopen (Msgtmp, "r", msgf);
225 freopen (Fromtmp, "r", fromf);
231 for (argv++; --argc > 0; ) {
238 signal(SIGPIPE, brpipe);
239 if (rp_isbad(deliver(*argv++)) && !rtnflag)
243 /* Send back a copy if something nasty happened. For now, we use */
244 /* a real kludge -- we see if we noted some error, or if we find */
245 /* anything written to stderr.... */
249 if (cpyback) {rcpy();zcpy();}
259 * deliver() -- Handle all deliveries be they returns, automatic
260 * copies, or the real thing. Based on the address
261 * the letter is accepted or returned with a copy
262 * to the system administrators
264 * main() has set up the "from" string and the
268 " --------------- End of Returned Mail ---------------\n";
275 char linebuf[LINESIZE];
276 char tmpbuf[LINESIZE];
278 switch (adrcheck (to)) {
280 ll_log (logptr, LLOGGEN, "Rmail to '%s' via MMDF", to);
281 if (rp_isbad (replyval =
282 xsubmit (NULL, usrfrm, NULL, NULL, to)))
285 if (mf_get_msg () == NOTOK)
287 replyval = txtcpy (mmdf, pipef);
289 i = (pclose(pipef) >> 8 ) & 0xff;
290 if (rp_isgood(replyval)) replyval = i;
295 ll_log (logptr, LLOGGEN, "Rmail to '%s' via UUCP", to);
296 if (rp_isbad (replyval = xuucp(from, to)))
298 replyval = txtcpy(msgf, pipef);
300 i = (pclose(pipef) >> 8 ) & 0xff;
301 if (rp_isgood(replyval)) replyval = (i == 0 ? RP_OK : RP_LIO);
309 ll_log (logptr, LLOGGEN, "Illegal Rmail to '%s'", to);
310 switch (adrcheck (from)) {
313 replyval = xsubmit (dtimenow (), Mailsys,
314 from, supportaddr, from);
316 txtcpy(fromf, pipef);
318 fputs (rtnend, pipef);
320 i = (pclose(pipef) >> 8 ) & 0xff;
321 if (rp_isgood(replyval)) replyval = i;
326 replyval = xuucp (mmdflogin, from);
327 if (rp_isbad (replyval))
329 fprintf (pipef, "To: %s\n", from);
330 fprintf (pipef, "Cc: %s\n", supportaddr);
332 txtcpy(fromf, pipef);
334 fputs (rtnend, pipef);
336 i = (pclose(pipef) >> 8 ) & 0xff;
337 if (rp_isgood(replyval))
338 replyval = (i == 0 ? RP_OK : RP_LIO);
343 /* And now for the mail overseer's copy */
345 ll_log (logptr, LLOGGEN, "Notifying %s", supportaddr);
349 replyval = xsubmit (dtimenow (), Mailsys,
350 usrfrm, supportaddr, supportaddr);
351 if (rp_isbad (replyval))
354 txtcpy (fromf, pipef);
355 txtcpy (msgf, pipef);
356 fputs (rtnend, pipef);
358 i = (pclose(pipef) >> 8 ) & 0xff;
359 if (rp_isgood(replyval)) replyval = i;
368 adrcheck (adr) /* Gateway to Arpanet? */
377 if ((adrxp = seekadrx (adr)) == NULL)
379 strcpy (err, adrxp -> err ? adrxp -> err : "");
380 strcpy (host, adrxp -> host ? adrxp -> host : "");
381 strcpy (mbox, adrxp -> mbox ? adrxp -> mbox : "");
382 while (seekadrx (NULL))
385 if (err[0] || mbox[0] == NULL)
387 if (index (mbox, '!') || host[0] == NULL)
389 if (rp_isgood (lookup (origsys, Okhosts)))
391 if (index (host, '@') || rp_isbad (okhost (host)))
398 okhost(host) /* Host permitted to use mail facilities? */
401 if (rp_isgood (lookup (origsys, Okhosts)))
402 return (RP_OK); /* Fully privledged originator */
403 if (rp_isgood (lookup (host, Okhosts)))
404 return (RP_OK); /* Fully privledged dest */
405 if (rp_isgood (lookup (host, Okdests)))
406 return (RP_OK); /* Unrestricted Dest. Host, OK */
407 return(RP_NO); /* Not permitted; must be bad */
413 * lookup() -- This lookup function looks for strings which
414 * must be the first string on a line. Sorry Dave (dhc)
415 * but the MMDF channel functions are too specific
416 * to be easily used here without much kludging.
419 /*****************************************
420 **** Can this be a call to a MMDF function??
421 **** Remember I have the RHOSTs table and the OKHOSTS table.
422 ******************************************/
428 char entry[LINESIZE];
431 if ((lookf = fopen (where, "r")) == NULL)
432 return (RP_NO); /* Unknown problem */
433 while (fgets (entry, sizeof entry, lookf) != NULL) {
435 while (*cp != '\n' && *cp != ' ' && *cp != '\t')
438 if (lexequ (what, entry)) {
450 char *rtnmessage[] = {
451 " Your message has been intercepted trying to access\n",
452 "a restricted access host (e.g. an ARPANET host). A copy\n",
453 "of your message has been sent to the system administrators.\n",
454 "The text of your message follows.\n\n",
455 " --------------- Returned Mail Follows --------------\n",
464 fprintf (pipef, "Subject: Illegal Address (%s)\n\n", badadr);
465 for (cpp = rtnmessage; *cpp; cpp++)
475 while (!pbroke && (nread = fread (buffer, sizeof (*buffer), BUFSIZ, frm)) > 0)
476 fwrite (buffer, sizeof (*buffer), nread, to);
477 return (ferror (frm) ? RP_LIO : RP_OK );
482 xsubmit (date, from, to, cc, realto)
483 char *date, *from, *to, *cc, *realto;
485 char cmdstr[LINESIZE],
488 getfpath (pathsubmit, cmddfldir, submit);
489 sprintf (cmdstr, "%s '-mlti%s*'", submit, UucpChan ());
492 if ((pipef = popen (cmdstr, "w")) == NULL)
496 printf ("%s\n", cmdstr);
499 fprintf (pipef, "%s\n%s\n!\n", from, realto);
502 fprintf (pipef, "Date: %s\n", date);
503 fprintf (pipef, "From: %s\n", from);
506 fprintf (pipef, "To: %s", to);
508 fputc ('\n', pipef);/* Explicit host specified */
510 fprintf (pipef, "@%s\n", LocalName ());
513 fprintf (pipef, "Cc: %s\n", cc);
524 char cmdstr[LINESIZE];
526 sprintf (cmdstr, "/etc/delivermail -r%s -ep -m -s -i %s", from, to);
529 if ((pipef = popen (cmdstr, "w")) == NULL)
533 printf ("%s\n", cmdstr);
541 brpipe() /* catch broken-pipe signals */
543 signal(SIGPIPE, SIG_IGN);
547 char *oopsmessage[] = {
548 "\n\n\tThe system administrators (%s) have been informed of the\n",
549 "problem, but have not been given a copy of your message.\n",
561 ll_log (logptr, LLOGGEN, "Advising %s of failure as %s...", from, usrfrm);
563 sprintf (buffer, "Problems sending mail:\n\n");
564 if (ml_1adr (NO, NO, sitesignature, "Problems sending mail", usrfrm)
569 if ((fp = fopen (Errtmp, "r")) != NULL) {
571 if (ftell (fp) == 0L)
572 fprintf (pipef, "\tunknown problem\n");
576 ml_txt ("\tunknown problem\n");
578 for (i = 0; oopsmessage[i]; i++) {
579 sprintf (message, oopsmessage[i], supportaddr);
582 fprintf (pipef, "\n\nReturned message follows:\n\n---------------\n\n");
588 if (ml_end (OK) != OK) {
592 if (cp = index (buffer, '\n'))
594 ll_log (logptr, LLOGFAT, "Unable to post failure notice");
595 ll_log (logptr, LLOGFAT, "info: %s", buffer);
605 ll_log (logptr, LLOGGEN, "Advising %s of failure...", supportaddr);
607 sprintf (buffer, "Problems sending mail for %s (aka %s):\n\n",
609 if (ml_1adr (NO, NO, sitesignature, "Problems sending mail", supportaddr)
614 if ((fp = fopen (Errtmp, "r")) != NULL) {
616 if (ftell (fp) == 0L)
617 fprintf (pipef, "\tunknown problem\n");
621 ml_txt ("\tunable to open error file\n");
623 if (ml_end (OK) != OK) {
627 if (cp = index (buffer, '\n'))
629 ll_log (logptr, LLOGFAT, "Unable to post failure notice");
630 ll_log (logptr, LLOGFAT, "info: %s", buffer);
649 strcpy (tmpfil, "/tmp/rmailXXXXXX");
650 unlink (mktemp (tmpfil));
651 if ((fd = creat (tmpfil, Tmpmode)) == NOTOK)
654 if ((fd = open (tmpfil, 2)) == NOTOK)
656 if ((out = fdopen (fd, "w")) == NULL) {
660 if ((td = dup (fd)) == NOTOK) {
665 fprintf (out, "From %s %s\n", from, date);
666 if (rp_isbad (txtcpy (msgf, out))) {
672 lseek (td, (off_t)0, 0);
674 strcpy (mmdfil, "/tmp/mmdfXXXXXX");
675 unlink (mktemp (mmdfil));
676 if ((fd = creat (mmdfil, Tmpmode)) == NOTOK) {
681 if ((fd = open (mmdfil, 2)) == NOTOK) {
686 if ((md = dup (fd)) == NOTOK) {
695 switch (i = uucp_to_mmdf (td, fd, TRUE)) {
697 lseek (md, (off_t)0, 0);
698 if ((mmdf = fdopen (md, "r")) != NULL)
704 sprintf (buffer, "rmail(%d) filtering failed(%d)\n",
706 if (ml_1adr (NO, NO, sitesignature, "MF Failure", supportaddr)
711 lseek (td, (off_t)0, 0);
712 if ((md = dup (td)) == NOTOK)
713 ml_txt ("unable to dup() descriptor for message copy\n");
715 if ((fp = fdopen (md, "r")) == NULL) {
716 ml_txt ("unable to fdopen() descriptor for message copy\n");
720 ml_txt ("\n --Message Follows--\n");
725 if (ml_end (OK) != OK) {
729 if (cp = index (buffer, '\n'))
731 ll_log (logptr, LLOGFAT, "Unable to post failure notice");
732 ll_log (logptr, LLOGFAT, "info: %s", buffer);
748 mf_get_addr (from, to)
756 if ((adrxp = seekadrx (from)) == NULL)
758 addr_convert (adrxp, to, TRUE);
759 while (seekadrx (NULL))