Annotation of 41BSD/cmd/delivermail/main.c, revision 1.1.1.1

1.1       root        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  1.11    10/18/80";
                     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: 
                    149:        if (signal(SIGINT, SIG_IGN) != SIG_IGN)
                    150:                signal(SIGINT, finis);
                    151:        signal(SIGTERM, finis);
                    152:        setbuf(stdout, (char *) NULL);
                    153: # ifdef LOG
                    154:        initlog("delivermail", 0, LOG_INDEP);
                    155: # endif LOG
                    156: # ifdef DEBUG
                    157: # ifdef DEBUGFILE
                    158:        if ((i = open(DEBUGFILE, 1)) > 0)
                    159:        {
                    160:                lseek(i, 0L, 2);
                    161:                close(1);
                    162:                dup(i);
                    163:                close(i);
                    164:                Debug++;
                    165:        }
                    166: # endif DEBUGFILE
                    167: # endif
                    168:        errno = 0;
                    169:        from = NULL;
                    170: 
                    171:        /*
                    172:        ** Crack argv.
                    173:        */
                    174: 
                    175:        while (--argc > 0 && (p = *++argv)[0] == '-')
                    176:        {
                    177:                switch (p[1])
                    178:                {
                    179:                  case 'r':     /* obsolete -f flag */
                    180:                  case 'f':     /* from address */
                    181:                        p += 2;
                    182:                        if (*p == '\0')
                    183:                        {
                    184:                                p = *++argv;
                    185:                                if (--argc <= 0 || *p == '-')
                    186:                                {
                    187:                                        syserr("No \"from\" person");
                    188:                                        argc++;
                    189:                                        argv--;
                    190:                                        break;
                    191:                                }
                    192:                        }
                    193:                        if (from != NULL)
                    194:                        {
                    195:                                syserr("More than one \"from\" person");
                    196:                                break;
                    197:                        }
                    198:                        from = p;
                    199:                        break;
                    200: 
                    201:                  case 'h':     /* hop count */
                    202:                        p += 2;
                    203:                        if (*p == '\0')
                    204:                        {
                    205:                                p = *++argv;
                    206:                                if (--argc <= 0 || *p < '0' || *p > '9')
                    207:                                {
                    208:                                        syserr("Bad hop count (%s)", p);
                    209:                                        argc++;
                    210:                                        argv--;
                    211:                                        break;
                    212:                                }
                    213:                        }
                    214:                        HopCount = atoi(p);
                    215:                        break;
                    216: 
                    217:                  case 'e':     /* error message disposition */
                    218:                        switch (p[2])
                    219:                        {
                    220:                          case 'p':     /* print errors normally */
                    221:                                break;  /* (default) */
                    222: 
                    223:                          case 'q':     /* be silent about it */
                    224:                                freopen("/dev/null", "w", stdout);
                    225:                                break;
                    226: 
                    227:                          case 'm':     /* mail back */
                    228:                                MailBack++;
                    229:                                openxscrpt();
                    230:                                break;
                    231: 
                    232:                          case 'e':     /* do berknet error processing */
                    233:                                BerkNet++;
                    234:                                openxscrpt();
                    235:                                break;
                    236: 
                    237:                          case 'w':     /* write back (or mail) */
                    238:                                WriteBack++;
                    239:                                openxscrpt();
                    240:                                break;
                    241:                        }
                    242:                        break;
                    243: 
                    244: # ifdef DEBUG
                    245:                  case 'd':     /* debug */
                    246:                        Debug++;
                    247:                        printf("%s\n", Version);
                    248:                        break;
                    249: # endif DEBUG
                    250:                
                    251:                  case 'n':     /* don't alias */
                    252:                        NoAlias++;
                    253:                        break;
                    254: 
                    255:                  case 'm':     /* send to me too */
                    256:                        MeToo++;
                    257:                        break;
                    258: 
                    259:                  case 'i':     /* don't let dot stop me */
                    260:                        IgnrDot++;
                    261:                        break;
                    262: 
                    263:                  case 'a':     /* arpanet format */
                    264:                        ArpaFmt++;
                    265:                        break;
                    266:                
                    267:                  case 's':     /* save From lines in headers */
                    268:                        SaveFrom++;
                    269:                        break;
                    270: 
                    271:                  default:
                    272:                        /* at Eric Schmidt's suggestion, this will not be an error....
                    273:                        syserr("Unknown flag %s", p);
                    274:                        ... seems that upward compatibility will be easier. */
                    275:                        break;
                    276:                }
                    277:        }
                    278: 
                    279:        if (from != NULL && ArpaFmt)
                    280:                syserr("-f and -a are mutually exclusive");
                    281: 
                    282:        /*
                    283:        ** Get a temp file.
                    284:        */
                    285: 
                    286:        p = maketemp();
                    287:        if (from == NULL)
                    288:                from = p;
                    289: # ifdef DEBUG
                    290:        if (Debug)
                    291:                printf("Message-Id: <%s>\n", MsgId);
                    292: # endif DEBUG
                    293: 
                    294:        /*
                    295:        **  Figure out who it's coming from.
                    296:        **      Under certain circumstances allow the user to say who
                    297:        **      s/he is (using -f or -r).  These are:
                    298:        **      1.  The user's uid is zero (root).
                    299:        **      2.  The user's login name is "network" (mail from
                    300:        **          a network server).
                    301:        **      3.  The user's login name is "uucp" (mail from the
                    302:        **          uucp network).
                    303:        **      4.  The address the user is trying to claim has a
                    304:        **          "!" character in it (since #3 doesn't do it for
                    305:        **          us if we are dialing out).
                    306:        **      A better check to replace #3 & #4 would be if the
                    307:        **      effective uid is "UUCP" -- this would require me
                    308:        **      to rewrite getpwent to "grab" uucp as it went by,
                    309:        **      make getname more nasty, do another passwd file
                    310:        **      scan, or compile the UID of "UUCP" into the code,
                    311:        **      all of which are reprehensible.
                    312:        **
                    313:        **      Assuming all of these fail, we figure out something
                    314:        **      ourselves.
                    315:        */
                    316: 
                    317:        errno = 0;
                    318:        p = getname();
                    319:        if (p == NULL || p[0] == '\0')
                    320:        {
                    321:                syserr("Who are you? (uid=%d)", getuid());
                    322:                finis();
                    323:        }
                    324:        errno = 0;
                    325:        if (from != NULL)
                    326:        {
                    327:                if (strcmp(p, "network") != 0 && strcmp(p, "uucp") != 0 &&
                    328:                    index(from, '!') == NULL && getuid() != 0)
                    329:                {
                    330:                        /* network sends -r regardless (why why why?) */
                    331:                        /* syserr("%s, you cannot use the -f flag", p); */
                    332:                        from = NULL;
                    333:                }
                    334:        }
                    335:        if (from == NULL || from[0] == '\0')
                    336:                from = p;
                    337:        else
                    338:                FromFlag++;
                    339:        SuprErrs = TRUE;
                    340:        if (parse(from, &From, 0) == NULL)
                    341:        {
                    342:                /* too many arpanet hosts generate garbage From addresses ....
                    343:                syserr("Bad from address `%s'", from);
                    344:                .... so we will just ignore this address */
                    345:                from = p;
                    346:                FromFlag = FALSE;
                    347:        }
                    348:        SuprErrs = FALSE;
                    349: 
                    350: # ifdef DEBUG
                    351:        if (Debug)
                    352:                printf("From person = \"%s\"\n", From.q_paddr);
                    353: # endif DEBUG
                    354: 
                    355:        if (argc <= 0)
                    356:                usrerr("Usage: /etc/delivermail [flags] addr...");
                    357: 
                    358:        /*
                    359:        **  Process Hop count.
                    360:        **      The Hop count tells us how many times this message has
                    361:        **      been processed by delivermail.  If it exceeds some
                    362:        **      fairly large threshold, then we assume that we have
                    363:        **      an infinite forwarding loop and die.
                    364:        */
                    365: 
                    366:        if (++HopCount > MAXHOP)
                    367:                syserr("Infinite forwarding loop (%s->%s)", From.q_paddr, *argv);
                    368: 
                    369:        /*
                    370:        ** Scan argv and deliver the message to everyone.
                    371:        */
                    372: 
                    373:        for (; argc-- > 0; argv++)
                    374:        {
                    375:                sendto(*argv, 0);
                    376:        }
                    377: 
                    378:        /* if we have had errors sofar, drop out now */
                    379:        if (Errors > 0 && ExitStat == EX_OK)
                    380:                ExitStat = EX_USAGE;
                    381:        if (ExitStat != EX_OK)
                    382:                finis();
                    383: 
                    384:        /*
                    385:        **  See if we have anyone to send to at all.
                    386:        */
                    387: 
                    388:        if (nxtinq(&SendQ) == NULL && ExitStat == EX_OK)
                    389:        {
                    390:                syserr("Noone to send to!");
                    391:                ExitStat = EX_USAGE;
                    392:                finis();
                    393:        }
                    394: 
                    395:        /*
                    396:        **  Do aliasing.
                    397:        **      First arrange that the person who is sending the mail
                    398:        **      will not be expanded (unless explicitly requested).
                    399:        */
                    400: 
                    401:        if (!MeToo)
                    402:                recipient(&From, &AliasQ);
                    403:        To = NULL;
                    404:        alias();
                    405:        if (nxtinq(&SendQ) == NULL && ExitStat == EX_OK)
                    406:        {
                    407: /*
                    408:                syserr("Vacant send queue; probably aliasing loop");
                    409:                ExitStat = EX_SOFTWARE;
                    410:                finis();
                    411: */
                    412:                recipient(&From, &SendQ);
                    413:        }
                    414: 
                    415:        /*
                    416:        **  Actually send everything.
                    417:        */
                    418: 
                    419:        for (q = &SendQ; (q = nxtinq(q)) != NULL; )
                    420:                deliver(q, (fnptr) NULL);
                    421: 
                    422:        /*
                    423:        ** All done.
                    424:        */
                    425: 
                    426:        finis();
                    427: }
                    428: /*
                    429: **  FINIS -- Clean up and exit.
                    430: **
                    431: **     Parameters:
                    432: **             none
                    433: **
                    434: **     Returns:
                    435: **             never
                    436: **
                    437: **     Side Effects:
                    438: **             exits delivermail
                    439: **
                    440: **     Called By:
                    441: **             main
                    442: **             via signal on interrupt.
                    443: **
                    444: **     Deficiencies:
                    445: **             It may be that it should only remove the input
                    446: **                     file if there have been no errors.
                    447: */
                    448: 
                    449: finis()
                    450: {
                    451:        /* mail back the transcript on errors */
                    452:        if (ExitStat != EX_OK)
                    453:                savemail();
                    454: 
                    455:        if (HasXscrpt)
                    456:                unlink(Transcript);
                    457:        unlink(InFileName);
                    458:        exit(ExitStat);
                    459: }
                    460: /*
                    461: **  OPENXSCRPT -- Open transcript file
                    462: **
                    463: **     Creates a transcript file for possible eventual mailing or
                    464: **     sending back.
                    465: **
                    466: **     Parameters:
                    467: **             none
                    468: **
                    469: **     Returns:
                    470: **             none
                    471: **
                    472: **     Side Effects:
                    473: **             Turns the standard output into a special file
                    474: **                     somewhere.
                    475: **
                    476: **     Called By:
                    477: **             main
                    478: */
                    479: 
                    480: openxscrpt()
                    481: {
                    482:        mktemp(Transcript);
                    483:        HasXscrpt++;
                    484:        if (freopen(Transcript, "w", stdout) == NULL)
                    485:                syserr("Can't create %s", Transcript);
                    486:        chmod(Transcript, 0600);
                    487:        setbuf(stdout, (char *) NULL);
                    488: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.