1: # include <stdio.h>
   2: # include <signal.h>
   3: # include <ctype.h>
   4: # include "dlvrmail.h"
   5: # ifdef LOG
   6: # include <log.h>
   7: # endif LOG
   8: 
   9: static char SccsId[] = "@(#)main.c	2.3	1/10/81";
  10: 
  11: /*
  12: **  DELIVERMAIL -- Deliver mail to a set of destinations
  13: **
  14: **	This is the basic mail router.  All user mail programs should
  15: **	call this routine to actually deliver mail.  Delivermail in
  16: **	turn calls a bunch of mail servers that do the real work of
  17: **	delivering the mail.
  18: **
  19: **	Delivermail is driven by tables defined in config.c.  This
  20: **	file will be different from system to system, but the rest
  21: **	of the code will be the same.  This table could be read in,
  22: **	but it seemed nicer to have it compiled in, since deliver-
  23: **	mail will potentially be exercised a lot.
  24: **
  25: **	Usage:
  26: **		/etc/delivermail [-f name] [-a] [-q] [-v] [-n] [-m] addr ...
  27: **
  28: **	Positional Parameters:
  29: **		addr -- the address to deliver the mail to.  There
  30: **			can be several.
  31: **
  32: **	Flags:
  33: **		-f name		The mail is from "name" -- used for
  34: **				the header in local mail, and to
  35: **				deliver reports of failures to.
  36: **		-r name		Same as -f; however, this flag is
  37: **				reserved to indicate special processing
  38: **				for remote mail delivery as needed
  39: **				in the future.  So, network servers
  40: **				should use -r.
  41: **		-a		This mail should be in ARPANET std
  42: **				format (not used).
  43: **		-n		Don't do aliasing.  This might be used
  44: **				when delivering responses, for
  45: **				instance.
  46: **		-d		Run in debug mode.
  47: **		-em		Mail back a response if there was an
  48: **				error in processing.  This should be
  49: **				used when the origin of this message
  50: **				is another machine.
  51: **		-ew		Write back a response if the user is
  52: **				still logged in, otherwise, act like
  53: **				-em.
  54: **		-eq		Don't print any error message (just
  55: **				return exit status).
  56: **		-ep		(default)  Print error messages
  57: **				normally.
  58: **		-ee		Send BerkNet style errors.  This
  59: **				is equivalent to MailBack except
  60: **				that it has gives zero return code
  61: **				(unless there were errors during
  62: **				returning).  This used to be
  63: **				"EchoBack", but you know how the old
  64: **				software bounces.
  65: **		-m		In group expansion, send to the
  66: **				sender also (stands for the Mail metoo
  67: **				option.
  68: **		-i		Do not terminate mail on a line
  69: **				containing just dot.
  70: **		-s		Save UNIX-like "From" lines on the
  71: **				front of messages.
  72: **
  73: **	Return Codes:
  74: **		As defined in <sysexits.h>.
  75: **
  76: **		These codes are actually returned from the auxiliary
  77: **		mailers; it is their responsibility to make them
  78: **		correct.
  79: **
  80: **	Compilation Flags:
  81: **		LOG -- if set, everything is logged.
  82: **
  83: **	Compilation Instructions:
  84: **		cc -c -O main.c config.c deliver.c parse.c
  85: **		cc -n -s *.o -lS
  86: **		chown root a.out
  87: **		chmod 755 a.out
  88: **		mv a.out delivermail
  89: **
  90: **	Deficiencies:
  91: **		It ought to collect together messages that are
  92: **			destined for a single host and send these
  93: **			to the auxiliary mail server together.
  94: **		It should take "user at host" as three separate
  95: **			parameters and combine them into one address.
  96: **
  97: **	Author:
  98: **		Eric Allman, UCB/INGRES
  99: */
 100: 
 101: 
 102: 
 103: 
 104: 
 105: bool    ArpaFmt;    /* mail is expected to be in ARPANET format */
 106: bool    FromFlag;   /* from person is explicitly specified */
 107: bool    Debug;      /* run in debug mode */
 108: bool    MailBack;   /* mail back response on error */
 109: bool    BerkNet;    /* called from BerkNet */
 110: bool    WriteBack;  /* write back response on error */
 111: bool    HasXscrpt;  /* if set, the transcript file exists */
 112: bool    NoAlias;    /* don't do aliasing */
 113: bool    ForceMail;  /* mail even if already sent a copy */
 114: bool    MeToo;      /* send to the sender also if in a group expansion */
 115: bool    SaveFrom;   /* save From lines on the front of messages */
 116: bool    IgnrDot;    /* if set, ignore dot when collecting mail */
 117: bool    SuprErrs;   /* supress errors if set */
 118: int Errors;     /* count of errors */
 119: char    InFileName[] = "/tmp/mailtXXXXXX";
 120: char    Transcript[] = "/tmp/mailxXXXXXX";
 121: addrq   From;       /* the from person */
 122: char    *To;        /* the target person */
 123: int HopCount;   /* hop count */
 124: int ExitStat;   /* the exit status byte */
 125: addrq   SendQ;      /* queue of people to send to */
 126: addrq   AliasQ;     /* queue of people who turned out to be aliases */
 127: 
 128: 
 129: 
 130: 
 131: 
 132: 
 133: main(argc, argv)
 134:     int argc;
 135:     char **argv;
 136: {
 137:     register char *p;
 138:     extern char *maketemp();
 139:     extern char *getname();
 140:     extern int finis();
 141:     extern addrq *parse();
 142:     register addrq *q;
 143:     extern char Version[];
 144:     extern int errno;
 145:     char *from;
 146:     register int i;
 147:     typedef int (*fnptr)();
 148:     char nbuf[MAXLINE];
 149: 
 150:     if (signal(SIGINT, SIG_IGN) != SIG_IGN)
 151:         signal(SIGINT, finis);
 152:     signal(SIGTERM, finis);
 153:     setbuf(stdout, (char *) NULL);
 154: # ifdef LOG
 155:     openlog("delivermail", 0);
 156: # endif LOG
 157: # ifdef DEBUG
 158: # ifdef DEBUGFILE
 159:     if ((i = open(DEBUGFILE, 1)) > 0)
 160:     {
 161:         lseek(i, 0L, 2);
 162:         close(1);
 163:         dup(i);
 164:         close(i);
 165:         Debug++;
 166:     }
 167: # endif DEBUGFILE
 168: # endif
 169:     errno = 0;
 170:     from = NULL;
 171: 
 172:     /*
 173: 	** Crack argv.
 174: 	*/
 175: 
 176:     while (--argc > 0 && (p = *++argv)[0] == '-')
 177:     {
 178:         switch (p[1])
 179:         {
 180:           case 'r': /* obsolete -f flag */
 181:           case 'f': /* from address */
 182:             p += 2;
 183:             if (*p == '\0')
 184:             {
 185:                 p = *++argv;
 186:                 if (--argc <= 0 || *p == '-')
 187:                 {
 188:                     syserr("No \"from\" person");
 189:                     argc++;
 190:                     argv--;
 191:                     break;
 192:                 }
 193:             }
 194:             if (from != NULL)
 195:             {
 196:                 syserr("More than one \"from\" person");
 197:                 break;
 198:             }
 199:             from = p;
 200:             break;
 201: 
 202:           case 'h': /* hop count */
 203:             p += 2;
 204:             if (*p == '\0')
 205:             {
 206:                 p = *++argv;
 207:                 if (--argc <= 0 || *p < '0' || *p > '9')
 208:                 {
 209:                     syserr("Bad hop count (%s)", p);
 210:                     argc++;
 211:                     argv--;
 212:                     break;
 213:                 }
 214:             }
 215:             HopCount = atoi(p);
 216:             break;
 217: 
 218:           case 'e': /* error message disposition */
 219:             switch (p[2])
 220:             {
 221:               case 'p': /* print errors normally */
 222:                 break;  /* (default) */
 223: 
 224:               case 'q': /* be silent about it */
 225:                 freopen("/dev/null", "w", stdout);
 226:                 break;
 227: 
 228:               case 'm': /* mail back */
 229:                 MailBack++;
 230:                 openxscrpt();
 231:                 break;
 232: 
 233:               case 'e': /* do berknet error processing */
 234:                 BerkNet++;
 235:                 openxscrpt();
 236:                 break;
 237: 
 238:               case 'w': /* write back (or mail) */
 239:                 WriteBack++;
 240:                 openxscrpt();
 241:                 break;
 242:             }
 243:             break;
 244: 
 245: # ifdef DEBUG
 246:           case 'd': /* debug */
 247:             Debug++;
 248:             printf("%s\n", Version);
 249:             break;
 250: # endif DEBUG
 251: 
 252:           case 'n': /* don't alias */
 253:             NoAlias++;
 254:             break;
 255: 
 256:           case 'm': /* send to me too */
 257:             MeToo++;
 258:             break;
 259: 
 260:           case 'i': /* don't let dot stop me */
 261:             IgnrDot++;
 262:             break;
 263: 
 264:           case 'a': /* arpanet format */
 265:             ArpaFmt++;
 266:             break;
 267: 
 268:           case 's': /* save From lines in headers */
 269:             SaveFrom++;
 270:             break;
 271: 
 272:           default:
 273:             /* at Eric Schmidt's suggestion, this will not be an error....
 274: 			syserr("Unknown flag %s", p);
 275: 			... seems that upward compatibility will be easier. */
 276:             break;
 277:         }
 278:     }
 279: 
 280:     if (from != NULL && ArpaFmt)
 281:         syserr("-f and -a are mutually exclusive");
 282: 
 283:     /*
 284: 	** Get a temp file.
 285: 	*/
 286: 
 287:     p = maketemp();
 288:     if (from == NULL)
 289:         from = p;
 290: # ifdef DEBUG
 291:     if (Debug)
 292:         printf("Message-Id: <%s>\n", MsgId);
 293: # endif DEBUG
 294: 
 295:     /*
 296: 	**  Figure out who it's coming from.
 297: 	**	Under certain circumstances allow the user to say who
 298: 	**	s/he is (using -f or -r).  These are:
 299: 	**	1.  The user's uid is zero (root).
 300: 	**	2.  The user's login name is "network" (mail from
 301: 	**	    a network server).
 302: 	**	3.  The user's login name is "uucp" (mail from the
 303: 	**	    uucp network).
 304: 	**	4.  The address the user is trying to claim has a
 305: 	**	    "!" character in it (since #3 doesn't do it for
 306: 	**	    us if we are dialing out).
 307: 	**	A better check to replace #3 & #4 would be if the
 308: 	**	effective uid is "UUCP" -- this would require me
 309: 	**	to rewrite getpwent to "grab" uucp as it went by,
 310: 	**	make getname more nasty, do another passwd file
 311: 	**	scan, or compile the UID of "UUCP" into the code,
 312: 	**	all of which are reprehensible.
 313: 	**
 314: 	**	Assuming all of these fail, we figure out something
 315: 	**	ourselves.
 316: 	*/
 317: 
 318:     errno = 0;
 319:     p = getname();
 320:     if (p == NULL || p[0] == '\0')
 321:     {
 322:         syserr("Who are you? (uid=%d)", getuid());
 323:         finis();
 324:     }
 325:     errno = 0;
 326:     if (from != NULL)
 327:     {
 328:         if (strcmp(p, "network") != 0 && strcmp(p, "uucp") != 0 &&
 329:             index(from, '!') == NULL && getuid() != 0)
 330:         {
 331:             /* network sends -r regardless (why why why?) */
 332:             /* syserr("%s, you cannot use the -f flag", p); */
 333:             from = NULL;
 334:         }
 335:     }
 336:     if (from == NULL || from[0] == '\0')
 337:         from = p;
 338:     else
 339:         FromFlag++;
 340:     SuprErrs = TRUE;
 341:     if (parse(from, &From, 0) == NULL)
 342:     {
 343:         /* too many arpanet hosts generate garbage From addresses ....
 344: 		syserr("Bad from address `%s'", from);
 345: 		.... so we will just ignore this address */
 346:         from = p;
 347:         FromFlag = FALSE;
 348:     }
 349:     SuprErrs = FALSE;
 350: 
 351: # ifdef DEBUG
 352:     if (Debug)
 353:         printf("From person = \"%s\"\n", From.q_paddr);
 354: # endif DEBUG
 355: 
 356:     if (argc <= 0)
 357:         usrerr("Usage: /etc/delivermail [flags] addr...");
 358: 
 359:     /*
 360: 	**  Process Hop count.
 361: 	**	The Hop count tells us how many times this message has
 362: 	**	been processed by delivermail.  If it exceeds some
 363: 	**	fairly large threshold, then we assume that we have
 364: 	**	an infinite forwarding loop and die.
 365: 	*/
 366: 
 367:     if (++HopCount > MAXHOP)
 368:         syserr("Infinite forwarding loop (%s->%s)", From.q_paddr, *argv);
 369: 
 370:     /*
 371: 	** Scan argv and deliver the message to everyone.
 372: 	*/
 373: 
 374:     for (; argc-- > 0; argv++)
 375:     {
 376:         p = argv[1];
 377:         if (argc >= 2 && p[2] == '\0' &&
 378:             (p[0] == 'a' || p[0] == 'A') &&
 379:             (p[1] == 't' || p[1] == 'T'))
 380:         {
 381:             if (strlen(argv[0]) + strlen(argv[2]) + 2 > sizeof nbuf)
 382:             {
 383:                 usrerr("address overflow");
 384:                 p = argv[0];
 385:             }
 386:             else
 387:             {
 388:                 strcpy(nbuf, argv[0]);
 389:                 strcat(nbuf, "@");
 390:                 strcat(nbuf, argv[2]);
 391:                 p = nbuf;
 392:                 argv += 2;
 393:                 argc -= 2;
 394:             }
 395:         }
 396:         else
 397:             p = argv[0];
 398:         sendto(p, 0);
 399:     }
 400: 
 401:     /* if we have had errors sofar, drop out now */
 402:     if (Errors > 0 && ExitStat == EX_OK)
 403:         ExitStat = EX_USAGE;
 404:     if (ExitStat != EX_OK)
 405:         finis();
 406: 
 407:     /*
 408: 	**  See if we have anyone to send to at all.
 409: 	*/
 410: 
 411:     if (nxtinq(&SendQ) == NULL && ExitStat == EX_OK)
 412:     {
 413:         syserr("Noone to send to!");
 414:         ExitStat = EX_USAGE;
 415:         finis();
 416:     }
 417: 
 418:     /*
 419: 	**  Do aliasing.
 420: 	**	First arrange that the person who is sending the mail
 421: 	**	will not be expanded (unless explicitly requested).
 422: 	*/
 423: 
 424:     if (!MeToo)
 425:         recipient(&From, &AliasQ);
 426:     To = NULL;
 427:     alias();
 428:     if (nxtinq(&SendQ) == NULL && ExitStat == EX_OK)
 429:     {
 430: /*
 431: 		syserr("Vacant send queue; probably aliasing loop");
 432: 		ExitStat = EX_SOFTWARE;
 433: 		finis();
 434: */
 435:         recipient(&From, &SendQ);
 436:     }
 437: 
 438:     /*
 439: 	**  Actually send everything.
 440: 	*/
 441: 
 442:     for (q = &SendQ; (q = nxtinq(q)) != NULL; )
 443:         deliver(q, (fnptr) NULL);
 444: 
 445:     /*
 446: 	** All done.
 447: 	*/
 448: 
 449:     finis();
 450: }
 451: /*
 452: **  FINIS -- Clean up and exit.
 453: **
 454: **	Parameters:
 455: **		none
 456: **
 457: **	Returns:
 458: **		never
 459: **
 460: **	Side Effects:
 461: **		exits delivermail
 462: **
 463: **	Called By:
 464: **		main
 465: **		via signal on interrupt.
 466: **
 467: **	Deficiencies:
 468: **		It may be that it should only remove the input
 469: **			file if there have been no errors.
 470: */
 471: 
 472: finis()
 473: {
 474:     /* mail back the transcript on errors */
 475:     if (ExitStat != EX_OK)
 476:         savemail();
 477: 
 478:     if (HasXscrpt)
 479:         unlink(Transcript);
 480:     unlink(InFileName);
 481:     exit(ExitStat);
 482: }
 483: /*
 484: **  OPENXSCRPT -- Open transcript file
 485: **
 486: **	Creates a transcript file for possible eventual mailing or
 487: **	sending back.
 488: **
 489: **	Parameters:
 490: **		none
 491: **
 492: **	Returns:
 493: **		none
 494: **
 495: **	Side Effects:
 496: **		Turns the standard output into a special file
 497: **			somewhere.
 498: **
 499: **	Called By:
 500: **		main
 501: */
 502: 
 503: openxscrpt()
 504: {
 505:     mktemp(Transcript);
 506:     HasXscrpt++;
 507:     if (freopen(Transcript, "w", stdout) == NULL)
 508:         syserr("Can't create %s", Transcript);
 509:     chmod(Transcript, 0600);
 510:     setbuf(stdout, (char *) NULL);
 511: }

Defined functions

finis defined in line 472; used 7 times
main defined in line 133; never used
openxscrpt defined in line 503; used 3 times

Defined variables

AliasQ defined in line 126; used 2 times
Errors defined in line 118; used 1 times
ExitStat defined in line 124; used 8 times
From defined in line 121; used 5 times
HopCount defined in line 123; used 4 times
InFileName defined in line 119; used 10 times
SccsId defined in line 9; never used
SendQ defined in line 125; used 8 times
To defined in line 122; used 1 times
Transcript defined in line 120; used 14 times
Last modified: 1981-02-06
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1294
Valid CSS Valid XHTML 1.0 Strict