Annotation of 43BSDTahoe/usr.lib/sendmail/src/main.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1983 Eric P. Allman
                      3:  * Copyright (c) 1988 Regents of the University of California.
                      4:  * All rights reserved.
                      5:  *
                      6:  * Redistribution and use in source and binary forms are permitted
                      7:  * provided that the above copyright notice and this paragraph are
                      8:  * duplicated in all such forms and that any documentation,
                      9:  * advertising materials, and other materials related to such
                     10:  * distribution and use acknowledge that the software was developed
                     11:  * by the University of California, Berkeley.  The name of the
                     12:  * University may not be used to endorse or promote products derived
                     13:  * from this software without specific prior written permission.
                     14:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
                     15:  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
                     16:  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
                     17:  */
                     18: 
                     19: #ifndef lint
                     20: char copyright[] =
                     21: "@(#) Copyright (c) 1988 Regents of the University of California.\n\
                     22:  All rights reserved.\n";
                     23: #endif /* not lint */
                     24: 
                     25: #ifndef lint
                     26: static char sccsid[] = "@(#)main.c     5.18 (Berkeley) 6/30/88";
                     27: #endif /* not lint */
                     28: 
                     29: #define        _DEFINE
                     30: 
                     31: #include <signal.h>
                     32: #include <sgtty.h>
                     33: #include "sendmail.h"
                     34: #include <arpa/nameser.h>
                     35: #include <resolv.h>
                     36: 
                     37: # ifdef lint
                     38: char   edata, end;
                     39: # endif lint
                     40: 
                     41: /*
                     42: **  SENDMAIL -- Post mail to a set of destinations.
                     43: **
                     44: **     This is the basic mail router.  All user mail programs should
                     45: **     call this routine to actually deliver mail.  Sendmail in
                     46: **     turn calls a bunch of mail servers that do the real work of
                     47: **     delivering the mail.
                     48: **
                     49: **     Sendmail is driven by tables read in from /usr/lib/sendmail.cf
                     50: **     (read by readcf.c).  Some more static configuration info,
                     51: **     including some code that you may want to tailor for your
                     52: **     installation, is in conf.c.  You may also want to touch
                     53: **     daemon.c (if you have some other IPC mechanism), acct.c
                     54: **     (to change your accounting), names.c (to adjust the name
                     55: **     server mechanism).
                     56: **
                     57: **     Usage:
                     58: **             /usr/lib/sendmail [flags] addr ...
                     59: **
                     60: **             See the associated documentation for details.
                     61: **
                     62: **     Author:
                     63: **             Eric Allman, UCB/INGRES (until 10/81)
                     64: **                          Britton-Lee, Inc., purveyors of fine
                     65: **                             database computers (from 11/81)
                     66: **             The support of the INGRES Project and Britton-Lee is
                     67: **                     gratefully acknowledged.  Britton-Lee in
                     68: **                     particular had absolutely nothing to gain from
                     69: **                     my involvement in this project.
                     70: */
                     71: 
                     72: 
                     73: int            NextMailer;     /* "free" index into Mailer struct */
                     74: char           *FullName;      /* sender's full name */
                     75: ENVELOPE       BlankEnvelope;  /* a "blank" envelope */
                     76: ENVELOPE       MainEnvelope;   /* the envelope around the basic letter */
                     77: ADDRESS                NullAddress =   /* a null address */
                     78:                { "", "", "" };
                     79: 
                     80: /*
                     81: **  Pointers for setproctitle.
                     82: **     This allows "ps" listings to give more useful information.
                     83: **     These must be kept out of BSS for frozen configuration files
                     84: **             to work.
                     85: */
                     86: 
                     87: # ifdef SETPROCTITLE
                     88: char           **Argv = NULL;          /* pointer to argument vector */
                     89: char           *LastArgv = NULL;       /* end of argv */
                     90: # endif SETPROCTITLE
                     91: 
                     92: #ifdef DAEMON
                     93: #ifndef SMTP
                     94: ERROR %%%%   Cannot have daemon mode without SMTP   %%%% ERROR
                     95: #endif SMTP
                     96: #endif DAEMON
                     97: 
                     98: main(argc, argv, envp)
                     99:        int argc;
                    100:        char **argv;
                    101:        char **envp;
                    102: {
                    103:        register char *p;
                    104:        char **av;
                    105:        extern int finis();
                    106:        extern char Version[];
                    107:        char *from;
                    108:        typedef int (*fnptr)();
                    109:        STAB *st;
                    110:        register int i;
                    111:        bool readconfig = TRUE;
                    112:        bool queuemode = FALSE;         /* process queue requests */
                    113:        bool nothaw;
                    114:        static bool reenter = FALSE;
                    115:        char jbuf[30];                  /* holds MyHostName */
                    116:        extern bool safefile();
                    117:        extern time_t convtime();
                    118:        extern putheader(), putbody();
                    119:        extern ENVELOPE *newenvelope();
                    120:        extern intsig();
                    121:        extern char **myhostname();
                    122:        extern char *arpadate();
                    123:        extern char **environ;
                    124: 
                    125:        /*
                    126:        **  Check to see if we reentered.
                    127:        **      This would normally happen if e_putheader or e_putbody
                    128:        **      were NULL when invoked.
                    129:        */
                    130: 
                    131:        if (reenter)
                    132:        {
                    133:                syserr("main: reentered!");
                    134:                abort();
                    135:        }
                    136:        reenter = TRUE;
                    137: 
                    138:        /* Enforce use of local time */
                    139:        unsetenv("TZ");
                    140: 
                    141:        /*
                    142:        **  Be sure we have enough file descriptors.
                    143:        **      But also be sure that 0, 1, & 2 are open.
                    144:        */
                    145: 
                    146:        i = open("/dev/null", 2);
                    147:        while (i >= 0 && i < 2)
                    148:                i = dup(i);
                    149:        for (i = 3; i < 50; i++)
                    150:                (void) close(i);
                    151:        errno = 0;
                    152: 
                    153:        /*
                    154:        **  Set default values for variables.
                    155:        **      These cannot be in initialized data space.
                    156:        */
                    157: 
                    158:        setdefaults();
                    159: 
                    160:        /* set up the blank envelope */
                    161:        BlankEnvelope.e_puthdr = putheader;
                    162:        BlankEnvelope.e_putbody = putbody;
                    163:        BlankEnvelope.e_xfp = NULL;
                    164:        STRUCTCOPY(NullAddress, BlankEnvelope.e_from);
                    165:        CurEnv = &BlankEnvelope;
                    166:        STRUCTCOPY(NullAddress, MainEnvelope.e_from);
                    167: 
                    168:        /*
                    169:        **  Do a quick prescan of the argument list.
                    170:        **      We do this to find out if we can potentially thaw the
                    171:        **      configuration file.  If not, we do the thaw now so that
                    172:        **      the argument processing applies to this run rather than
                    173:        **      to the run that froze the configuration.
                    174:        */
                    175: 
                    176:        argv[argc] = NULL;
                    177:        av = argv;
                    178:        nothaw = FALSE;
                    179:        while ((p = *++av) != NULL)
                    180:        {
                    181:                if (strncmp(p, "-C", 2) == 0)
                    182:                {
                    183:                        ConfFile = &p[2];
                    184:                        if (ConfFile[0] == '\0')
                    185:                                ConfFile = "sendmail.cf";
                    186:                        (void) setgid(getrgid());
                    187:                        (void) setuid(getruid());
                    188:                        nothaw = TRUE;
                    189:                }
                    190:                else if (strncmp(p, "-bz", 3) == 0)
                    191:                        nothaw = TRUE;
                    192: # ifdef DEBUG
                    193:                else if (strncmp(p, "-d", 2) == 0)
                    194:                {
                    195:                        tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
                    196:                        tTflag(&p[2]);
                    197:                        setbuf(stdout, (char *) NULL);
                    198:                        printf("Version %s\n", Version);
                    199:                }
                    200: # endif DEBUG
                    201:        }
                    202:        if (!nothaw)
                    203:                readconfig = !thaw(FreezeFile);
                    204: 
                    205:        /* reset the environment after the thaw */
                    206:        for (i = 0; i < MAXUSERENVIRON && envp[i] != NULL; i++)
                    207:                UserEnviron[i] = newstr(envp[i]);
                    208:        UserEnviron[i] = NULL;
                    209:        environ = UserEnviron;
                    210: 
                    211: # ifdef SETPROCTITLE
                    212:        /*
                    213:        **  Save start and extent of argv for setproctitle.
                    214:        */
                    215: 
                    216:        Argv = argv;
                    217:        if (i > 0)
                    218:                LastArgv = envp[i - 1] + strlen(envp[i - 1]);
                    219:        else
                    220:                LastArgv = argv[argc - 1] + strlen(argv[argc - 1]);
                    221: # endif SETPROCTITLE
                    222: 
                    223:        /*
                    224:        **  Now do basic initialization
                    225:        */
                    226: 
                    227:        InChannel = stdin;
                    228:        OutChannel = stdout;
                    229:        if (signal(SIGINT, SIG_IGN) != SIG_IGN)
                    230:                (void) signal(SIGINT, intsig);
                    231:        if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
                    232:                (void) signal(SIGHUP, intsig);
                    233:        (void) signal(SIGTERM, intsig);
                    234:        (void) signal(SIGPIPE, SIG_IGN);
                    235:        OldUmask = umask(0);
                    236:        OpMode = MD_DELIVER;
                    237:        MotherPid = getpid();
                    238:        FullName = getenv("NAME");
                    239: 
                    240: # ifdef LOG
                    241:        openlog("sendmail", LOG_PID, LOG_MAIL);
                    242: # endif LOG
                    243:        errno = 0;
                    244:        from = NULL;
                    245: 
                    246:        if (readconfig)
                    247:        {
                    248:                /* initialize some macros, etc. */
                    249:                initmacros();
                    250: 
                    251:                /* hostname */
                    252:                av = myhostname(jbuf, sizeof jbuf);
                    253:                if (jbuf[0] != '\0')
                    254:                {
                    255: #ifdef DEBUG
                    256:                        if (tTd(0, 4))
                    257:                                printf("canonical name: %s\n", jbuf);
                    258: #endif DEBUG
                    259:                        p = newstr(jbuf);
                    260:                        define('w', p, CurEnv);
                    261:                        setclass('w', p);
                    262:                }
                    263:                while (av != NULL && *av != NULL)
                    264:                {
                    265: #ifdef DEBUG
                    266:                        if (tTd(0, 4))
                    267:                                printf("\ta.k.a.: %s\n", *av);
                    268: #endif DEBUG
                    269:                        setclass('w', *av++);
                    270:                }
                    271: 
                    272:                /* version */
                    273:                define('v', Version, CurEnv);
                    274:        }
                    275: 
                    276:        /* current time */
                    277:        define('b', arpadate((char *) NULL), CurEnv);
                    278: 
                    279:        /*
                    280:        ** Crack argv.
                    281:        */
                    282: 
                    283:        av = argv;
                    284:        p = rindex(*av, '/');
                    285:        if (p++ == NULL)
                    286:                p = *av;
                    287:        if (strcmp(p, "newaliases") == 0)
                    288:                OpMode = MD_INITALIAS;
                    289:        else if (strcmp(p, "mailq") == 0)
                    290:                OpMode = MD_PRINT;
                    291:        else if (strcmp(p, "smtpd") == 0)
                    292:                OpMode = MD_DAEMON;
                    293:        while ((p = *++av) != NULL && p[0] == '-')
                    294:        {
                    295:                switch (p[1])
                    296:                {
                    297:                  case 'b':     /* operations mode */
                    298:                        switch (p[2])
                    299:                        {
                    300:                          case MD_DAEMON:
                    301: # ifndef DAEMON
                    302:                                syserr("Daemon mode not implemented");
                    303:                                break;
                    304: # endif DAEMON
                    305:                          case MD_SMTP:
                    306: # ifndef SMTP
                    307:                                syserr("I don't speak SMTP");
                    308:                                break;
                    309: # endif SMTP
                    310:                          case MD_ARPAFTP:
                    311:                          case MD_DELIVER:
                    312:                          case MD_VERIFY:
                    313:                          case MD_TEST:
                    314:                          case MD_INITALIAS:
                    315:                          case MD_PRINT:
                    316:                          case MD_FREEZE:
                    317:                                OpMode = p[2];
                    318:                                break;
                    319: 
                    320:                          default:
                    321:                                syserr("Invalid operation mode %c", p[2]);
                    322:                                break;
                    323:                        }
                    324:                        break;
                    325: 
                    326:                  case 'C':     /* select configuration file (already done) */
                    327:                        break;
                    328: 
                    329: #ifdef DEBUG
                    330:                  case 'd':     /* debugging -- redo in case frozen */
                    331:                        tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
                    332:                        tTflag(&p[2]);
                    333:                        setbuf(stdout, (char *) NULL);
                    334:                        _res.options |= RES_DEBUG;
                    335:                        break;
                    336: #endif
                    337: 
                    338:                  case 'f':     /* from address */
                    339:                  case 'r':     /* obsolete -f flag */
                    340:                        p += 2;
                    341:                        if (*p == '\0' && ((p = *++av) == NULL || *p == '-'))
                    342:                        {
                    343:                                p = *++av;
                    344:                                if (p == NULL || *p == '-')
                    345:                                {
                    346:                                        syserr("No \"from\" person");
                    347:                                        av--;
                    348:                                        break;
                    349:                                }
                    350:                        }
                    351:                        if (from != NULL)
                    352:                        {
                    353:                                syserr("More than one \"from\" person");
                    354:                                break;
                    355:                        }
                    356:                        from = newstr(p);
                    357:                        break;
                    358: 
                    359:                  case 'F':     /* set full name */
                    360:                        p += 2;
                    361:                        if (*p == '\0' && ((p = *++av) == NULL || *p == '-'))
                    362:                        {
                    363:                                syserr("Bad -F flag");
                    364:                                av--;
                    365:                                break;
                    366:                        }
                    367:                        FullName = newstr(p);
                    368:                        break;
                    369: 
                    370:                  case 'h':     /* hop count */
                    371:                        p += 2;
                    372:                        if (*p == '\0' && ((p = *++av) == NULL || !isdigit(*p)))
                    373:                        {
                    374:                                syserr("Bad hop count (%s)", p);
                    375:                                av--;
                    376:                                break;
                    377:                        }
                    378:                        CurEnv->e_hopcount = atoi(p);
                    379:                        break;
                    380:                
                    381:                  case 'n':     /* don't alias */
                    382:                        NoAlias = TRUE;
                    383:                        break;
                    384: 
                    385:                  case 'o':     /* set option */
                    386:                        setoption(p[2], &p[3], FALSE, TRUE);
                    387:                        break;
                    388: 
                    389:                  case 'q':     /* run queue files at intervals */
                    390: # ifdef QUEUE
                    391:                        queuemode = TRUE;
                    392:                        QueueIntvl = convtime(&p[2]);
                    393: # else QUEUE
                    394:                        syserr("I don't know about queues");
                    395: # endif QUEUE
                    396:                        break;
                    397: 
                    398:                  case 't':     /* read recipients from message */
                    399:                        GrabTo = TRUE;
                    400:                        break;
                    401: 
                    402:                        /* compatibility flags */
                    403:                  case 'c':     /* connect to non-local mailers */
                    404:                  case 'e':     /* error message disposition */
                    405:                  case 'i':     /* don't let dot stop me */
                    406:                  case 'm':     /* send to me too */
                    407:                  case 'T':     /* set timeout interval */
                    408:                  case 'v':     /* give blow-by-blow description */
                    409:                        setoption(p[1], &p[2], FALSE, TRUE);
                    410:                        break;
                    411: 
                    412:                  case 's':     /* save From lines in headers */
                    413:                        setoption('f', &p[2], FALSE, TRUE);
                    414:                        break;
                    415: 
                    416: # ifdef DBM
                    417:                  case 'I':     /* initialize alias DBM file */
                    418:                        OpMode = MD_INITALIAS;
                    419:                        break;
                    420: # endif DBM
                    421:                }
                    422:        }
                    423: 
                    424:        /*
                    425:        **  Do basic initialization.
                    426:        **      Read system control file.
                    427:        **      Extract special fields for local use.
                    428:        */
                    429: 
                    430:        if (OpMode == MD_FREEZE || readconfig)
                    431:                readcf(ConfFile);
                    432: 
                    433:        switch (OpMode)
                    434:        {
                    435:          case MD_FREEZE:
                    436:                /* this is critical to avoid forgeries of the frozen config */
                    437:                (void) setgid(getgid());
                    438:                (void) setuid(getuid());
                    439: 
                    440:                /* freeze the configuration */
                    441:                freeze(FreezeFile);
                    442:                exit(EX_OK);
                    443: 
                    444:          case MD_INITALIAS:
                    445:                Verbose = TRUE;
                    446:                break;
                    447:        }
                    448: 
                    449:        /* do heuristic mode adjustment */
                    450:        if (Verbose)
                    451:        {
                    452:                /* turn off noconnect option */
                    453:                setoption('c', "F", TRUE, FALSE);
                    454: 
                    455:                /* turn on interactive delivery */
                    456:                setoption('d', "", TRUE, FALSE);
                    457:        }
                    458: 
                    459:        /* our name for SMTP codes */
                    460:        expand("\001j", jbuf, &jbuf[sizeof jbuf - 1], CurEnv);
                    461:        MyHostName = jbuf;
                    462: 
                    463:        /* the indices of local and program mailers */
                    464:        st = stab("local", ST_MAILER, ST_FIND);
                    465:        if (st == NULL)
                    466:                syserr("No local mailer defined");
                    467:        else
                    468:                LocalMailer = st->s_mailer;
                    469:        st = stab("prog", ST_MAILER, ST_FIND);
                    470:        if (st == NULL)
                    471:                syserr("No prog mailer defined");
                    472:        else
                    473:                ProgMailer = st->s_mailer;
                    474: 
                    475:        /* operate in queue directory */
                    476:        if (chdir(QueueDir) < 0)
                    477:        {
                    478:                syserr("cannot chdir(%s)", QueueDir);
                    479:                exit(EX_SOFTWARE);
                    480:        }
                    481: 
                    482:        /*
                    483:        **  Do operation-mode-dependent initialization.
                    484:        */
                    485: 
                    486:        switch (OpMode)
                    487:        {
                    488:          case MD_PRINT:
                    489:                /* print the queue */
                    490: #ifdef QUEUE
                    491:                dropenvelope(CurEnv);
                    492:                printqueue();
                    493:                exit(EX_OK);
                    494: #else QUEUE
                    495:                usrerr("No queue to print");
                    496:                finis();
                    497: #endif QUEUE
                    498: 
                    499:          case MD_INITALIAS:
                    500:                /* initialize alias database */
                    501:                initaliases(AliasFile, TRUE);
                    502:                exit(EX_OK);
                    503: 
                    504:          case MD_DAEMON:
                    505:                /* don't open alias database -- done in srvrsmtp */
                    506:                break;
                    507: 
                    508:          default:
                    509:                /* open the alias database */
                    510:                initaliases(AliasFile, FALSE);
                    511:                break;
                    512:        }
                    513: 
                    514: # ifdef DEBUG
                    515:        if (tTd(0, 15))
                    516:        {
                    517:                /* print configuration table (or at least part of it) */
                    518:                printrules();
                    519:                for (i = 0; i < MAXMAILERS; i++)
                    520:                {
                    521:                        register struct mailer *m = Mailer[i];
                    522:                        int j;
                    523: 
                    524:                        if (m == NULL)
                    525:                                continue;
                    526:                        printf("mailer %d (%s): P=%s S=%d R=%d M=%ld F=", i, m->m_name,
                    527:                                m->m_mailer, m->m_s_rwset, m->m_r_rwset,
                    528:                                m->m_maxsize);
                    529:                        for (j = '\0'; j <= '\177'; j++)
                    530:                                if (bitnset(j, m->m_flags))
                    531:                                        (void) putchar(j);
                    532:                        printf(" E=");
                    533:                        xputs(m->m_eol);
                    534:                        printf("\n");
                    535:                }
                    536:        }
                    537: # endif DEBUG
                    538: 
                    539:        /*
                    540:        **  Switch to the main envelope.
                    541:        */
                    542: 
                    543:        CurEnv = newenvelope(&MainEnvelope);
                    544:        MainEnvelope.e_flags = BlankEnvelope.e_flags;
                    545: 
                    546:        /*
                    547:        **  If test mode, read addresses from stdin and process.
                    548:        */
                    549: 
                    550:        if (OpMode == MD_TEST)
                    551:        {
                    552:                char buf[MAXLINE];
                    553: 
                    554:                printf("ADDRESS TEST MODE\nEnter <ruleset> <address>\n");
                    555:                for (;;)
                    556:                {
                    557:                        register char **pvp;
                    558:                        char *q;
                    559:                        extern char *DelimChar;
                    560: 
                    561:                        printf("> ");
                    562:                        (void) fflush(stdout);
                    563:                        if (fgets(buf, sizeof buf, stdin) == NULL)
                    564:                                finis();
                    565:                        for (p = buf; isspace(*p); *p++)
                    566:                                continue;
                    567:                        q = p;
                    568:                        while (*p != '\0' && !isspace(*p))
                    569:                                p++;
                    570:                        if (*p == '\0')
                    571:                                continue;
                    572:                        *p = '\0';
                    573:                        do
                    574:                        {
                    575:                                extern char **prescan();
                    576:                                char pvpbuf[PSBUFSIZE];
                    577: 
                    578:                                pvp = prescan(++p, ',', pvpbuf);
                    579:                                if (pvp == NULL)
                    580:                                        continue;
                    581:                                rewrite(pvp, 3);
                    582:                                p = q;
                    583:                                while (*p != '\0')
                    584:                                {
                    585:                                        rewrite(pvp, atoi(p));
                    586:                                        while (*p != '\0' && *p++ != ',')
                    587:                                                continue;
                    588:                                }
                    589:                        } while (*(p = DelimChar) != '\0');
                    590:                }
                    591:        }
                    592: 
                    593: # ifdef QUEUE
                    594:        /*
                    595:        **  If collecting stuff from the queue, go start doing that.
                    596:        */
                    597: 
                    598:        if (queuemode && OpMode != MD_DAEMON && QueueIntvl == 0)
                    599:        {
                    600:                runqueue(FALSE);
                    601:                finis();
                    602:        }
                    603: # endif QUEUE
                    604: 
                    605:        /*
                    606:        **  If a daemon, wait for a request.
                    607:        **      getrequests will always return in a child.
                    608:        **      If we should also be processing the queue, start
                    609:        **              doing it in background.
                    610:        **      We check for any errors that might have happened
                    611:        **              during startup.
                    612:        */
                    613: 
                    614:        if (OpMode == MD_DAEMON || QueueIntvl != 0)
                    615:        {
                    616:                if (!tTd(0, 1))
                    617:                {
                    618:                        /* put us in background */
                    619:                        i = fork();
                    620:                        if (i < 0)
                    621:                                syserr("daemon: cannot fork");
                    622:                        if (i != 0)
                    623:                                exit(0);
                    624: 
                    625:                        /* get our pid right */
                    626:                        MotherPid = getpid();
                    627: 
                    628:                        /* disconnect from our controlling tty */
                    629:                        disconnect(TRUE);
                    630:                }
                    631: 
                    632: # ifdef QUEUE
                    633:                if (queuemode)
                    634:                {
                    635:                        runqueue(TRUE);
                    636:                        if (OpMode != MD_DAEMON)
                    637:                                for (;;)
                    638:                                        pause();
                    639:                }
                    640: # endif QUEUE
                    641:                dropenvelope(CurEnv);
                    642: 
                    643: #ifdef DAEMON
                    644:                getrequests();
                    645: 
                    646:                /* at this point we are in a child: reset state */
                    647:                OpMode = MD_SMTP;
                    648:                (void) newenvelope(CurEnv);
                    649:                openxscript(CurEnv);
                    650: #endif DAEMON
                    651:        }
                    652:        
                    653: # ifdef SMTP
                    654:        /*
                    655:        **  If running SMTP protocol, start collecting and executing
                    656:        **  commands.  This will never return.
                    657:        */
                    658: 
                    659:        if (OpMode == MD_SMTP)
                    660:                smtp();
                    661: # endif SMTP
                    662: 
                    663:        /*
                    664:        **  Do basic system initialization and set the sender
                    665:        */
                    666: 
                    667:        initsys();
                    668:        setsender(from);
                    669: 
                    670:        if (OpMode != MD_ARPAFTP && *av == NULL && !GrabTo)
                    671:        {
                    672:                usrerr("Recipient names must be specified");
                    673: 
                    674:                /* collect body for UUCP return */
                    675:                if (OpMode != MD_VERIFY)
                    676:                        collect(FALSE);
                    677:                finis();
                    678:        }
                    679:        if (OpMode == MD_VERIFY)
                    680:                SendMode = SM_VERIFY;
                    681: 
                    682:        /*
                    683:        **  Scan argv and deliver the message to everyone.
                    684:        */
                    685: 
                    686:        sendtoargv(av);
                    687: 
                    688:        /* if we have had errors sofar, arrange a meaningful exit stat */
                    689:        if (Errors > 0 && ExitStat == EX_OK)
                    690:                ExitStat = EX_USAGE;
                    691: 
                    692:        /*
                    693:        **  Read the input mail.
                    694:        */
                    695: 
                    696:        CurEnv->e_to = NULL;
                    697:        if (OpMode != MD_VERIFY || GrabTo)
                    698:                collect(FALSE);
                    699:        errno = 0;
                    700: 
                    701:        /* collect statistics */
                    702:        if (OpMode != MD_VERIFY)
                    703:                markstats(CurEnv, (ADDRESS *) NULL);
                    704: 
                    705: # ifdef DEBUG
                    706:        if (tTd(1, 1))
                    707:                printf("From person = \"%s\"\n", CurEnv->e_from.q_paddr);
                    708: # endif DEBUG
                    709: 
                    710:        /*
                    711:        **  Actually send everything.
                    712:        **      If verifying, just ack.
                    713:        */
                    714: 
                    715:        CurEnv->e_from.q_flags |= QDONTSEND;
                    716:        CurEnv->e_to = NULL;
                    717:        sendall(CurEnv, SM_DEFAULT);
                    718: 
                    719:        /*
                    720:        ** All done.
                    721:        */
                    722: 
                    723:        finis();
                    724: }
                    725: /*
                    726: **  FINIS -- Clean up and exit.
                    727: **
                    728: **     Parameters:
                    729: **             none
                    730: **
                    731: **     Returns:
                    732: **             never
                    733: **
                    734: **     Side Effects:
                    735: **             exits sendmail
                    736: */
                    737: 
                    738: finis()
                    739: {
                    740: # ifdef DEBUG
                    741:        if (tTd(2, 1))
                    742:                printf("\n====finis: stat %d e_flags %o\n", ExitStat, CurEnv->e_flags);
                    743: # endif DEBUG
                    744: 
                    745:        /* clean up temp files */
                    746:        CurEnv->e_to = NULL;
                    747:        dropenvelope(CurEnv);
                    748: 
                    749:        /* post statistics */
                    750:        poststats(StatFile);
                    751: 
                    752:        /* and exit */
                    753: # ifdef LOG
                    754:        if (LogLevel > 11)
                    755:                syslog(LOG_DEBUG, "finis, pid=%d", getpid());
                    756: # endif LOG
                    757:        if (ExitStat == EX_TEMPFAIL)
                    758:                ExitStat = EX_OK;
                    759:        exit(ExitStat);
                    760: }
                    761: /*
                    762: **  INTSIG -- clean up on interrupt
                    763: **
                    764: **     This just arranges to exit.  It pessimises in that it
                    765: **     may resend a message.
                    766: **
                    767: **     Parameters:
                    768: **             none.
                    769: **
                    770: **     Returns:
                    771: **             none.
                    772: **
                    773: **     Side Effects:
                    774: **             Unlocks the current job.
                    775: */
                    776: 
                    777: intsig()
                    778: {
                    779:        FileName = NULL;
                    780:        unlockqueue(CurEnv);
                    781:        exit(EX_OK);
                    782: }
                    783: /*
                    784: **  INITMACROS -- initialize the macro system
                    785: **
                    786: **     This just involves defining some macros that are actually
                    787: **     used internally as metasymbols to be themselves.
                    788: **
                    789: **     Parameters:
                    790: **             none.
                    791: **
                    792: **     Returns:
                    793: **             none.
                    794: **
                    795: **     Side Effects:
                    796: **             initializes several macros to be themselves.
                    797: */
                    798: 
                    799: struct metamac
                    800: {
                    801:        char    metaname;
                    802:        char    metaval;
                    803: };
                    804: 
                    805: struct metamac MetaMacros[] =
                    806: {
                    807:        /* LHS pattern matching characters */
                    808:        '*', MATCHZANY, '+', MATCHANY,  '-', MATCHONE,  '=', MATCHCLASS,
                    809:        '~', MATCHNCLASS,
                    810: 
                    811:        /* these are RHS metasymbols */
                    812:        '#', CANONNET,  '@', CANONHOST, ':', CANONUSER, '>', CALLSUBR,
                    813: 
                    814:        /* the conditional operations */
                    815:        '?', CONDIF,    '|', CONDELSE,  '.', CONDFI,
                    816: 
                    817:        /* and finally the hostname lookup characters */
                    818:        '[', HOSTBEGIN, ']', HOSTEND,
                    819: 
                    820:        '\0'
                    821: };
                    822: 
                    823: initmacros()
                    824: {
                    825:        register struct metamac *m;
                    826:        char buf[5];
                    827:        register int c;
                    828: 
                    829:        for (m = MetaMacros; m->metaname != '\0'; m++)
                    830:        {
                    831:                buf[0] = m->metaval;
                    832:                buf[1] = '\0';
                    833:                define(m->metaname, newstr(buf), CurEnv);
                    834:        }
                    835:        buf[0] = MATCHREPL;
                    836:        buf[2] = '\0';
                    837:        for (c = '0'; c <= '9'; c++)
                    838:        {
                    839:                buf[1] = c;
                    840:                define(c, newstr(buf), CurEnv);
                    841:        }
                    842: }
                    843: /*
                    844: **  FREEZE -- freeze BSS & allocated memory
                    845: **
                    846: **     This will be used to efficiently load the configuration file.
                    847: **
                    848: **     Parameters:
                    849: **             freezefile -- the name of the file to freeze to.
                    850: **
                    851: **     Returns:
                    852: **             none.
                    853: **
                    854: **     Side Effects:
                    855: **             Writes BSS and malloc'ed memory to freezefile
                    856: */
                    857: 
                    858: union frz
                    859: {
                    860:        char            frzpad[BUFSIZ]; /* insure we are on a BUFSIZ boundary */
                    861:        struct
                    862:        {
                    863:                time_t  frzstamp;       /* timestamp on this freeze */
                    864:                char    *frzbrk;        /* the current break */
                    865:                char    *frzedata;      /* address of edata */
                    866:                char    *frzend;        /* address of end */
                    867:                char    frzver[252];    /* sendmail version */
                    868:        } frzinfo;
                    869: };
                    870: 
                    871: freeze(freezefile)
                    872:        char *freezefile;
                    873: {
                    874:        int f;
                    875:        union frz fhdr;
                    876:        extern char edata, end;
                    877:        extern char *sbrk();
                    878:        extern char Version[];
                    879: 
                    880:        if (freezefile == NULL)
                    881:                return;
                    882: 
                    883:        /* try to open the freeze file */
                    884:        f = creat(freezefile, FileMode);
                    885:        if (f < 0)
                    886:        {
                    887:                syserr("Cannot freeze");
                    888:                errno = 0;
                    889:                return;
                    890:        }
                    891: 
                    892:        /* build the freeze header */
                    893:        fhdr.frzinfo.frzstamp = curtime();
                    894:        fhdr.frzinfo.frzbrk = sbrk(0);
                    895:        fhdr.frzinfo.frzedata = &edata;
                    896:        fhdr.frzinfo.frzend = &end;
                    897:        (void) strcpy(fhdr.frzinfo.frzver, Version);
                    898: 
                    899:        /* write out the freeze header */
                    900:        if (write(f, (char *) &fhdr, sizeof fhdr) != sizeof fhdr ||
                    901:            write(f, (char *) &edata, (int) (fhdr.frzinfo.frzbrk - &edata)) !=
                    902:                                        (int) (fhdr.frzinfo.frzbrk - &edata))
                    903:        {
                    904:                syserr("Cannot freeze");
                    905:        }
                    906: 
                    907:        /* fine, clean up */
                    908:        (void) close(f);
                    909: }
                    910: /*
                    911: **  THAW -- read in the frozen configuration file.
                    912: **
                    913: **     Parameters:
                    914: **             freezefile -- the name of the file to thaw from.
                    915: **
                    916: **     Returns:
                    917: **             TRUE if it successfully read the freeze file.
                    918: **             FALSE otherwise.
                    919: **
                    920: **     Side Effects:
                    921: **             reads freezefile in to BSS area.
                    922: */
                    923: 
                    924: thaw(freezefile)
                    925:        char *freezefile;
                    926: {
                    927:        int f;
                    928:        union frz fhdr;
                    929:        extern char edata, end;
                    930:        extern char Version[];
                    931:        extern caddr_t brk();
                    932: 
                    933:        if (freezefile == NULL)
                    934:                return (FALSE);
                    935: 
                    936:        /* open the freeze file */
                    937:        f = open(freezefile, 0);
                    938:        if (f < 0)
                    939:        {
                    940:                errno = 0;
                    941:                return (FALSE);
                    942:        }
                    943: 
                    944:        /* read in the header */
                    945:        if (read(f, (char *) &fhdr, sizeof fhdr) < sizeof fhdr ||
                    946:            fhdr.frzinfo.frzedata != &edata ||
                    947:            fhdr.frzinfo.frzend != &end ||
                    948:            strcmp(fhdr.frzinfo.frzver, Version) != 0)
                    949:        {
                    950:                (void) close(f);
                    951:                return (FALSE);
                    952:        }
                    953: 
                    954:        /* arrange to have enough space */
                    955:        if (brk(fhdr.frzinfo.frzbrk) == (caddr_t) -1)
                    956:        {
                    957:                syserr("Cannot break to %x", fhdr.frzinfo.frzbrk);
                    958:                (void) close(f);
                    959:                return (FALSE);
                    960:        }
                    961: 
                    962:        /* now read in the freeze file */
                    963:        if (read(f, (char *) &edata, (int) (fhdr.frzinfo.frzbrk - &edata)) !=
                    964:                                        (int) (fhdr.frzinfo.frzbrk - &edata))
                    965:        {
                    966:                /* oops!  we have trashed memory..... */
                    967:                (void) write(2, "Cannot read freeze file\n", 24);
                    968:                _exit(EX_SOFTWARE);
                    969:        }
                    970: 
                    971:        (void) close(f);
                    972:        return (TRUE);
                    973: }
                    974: /*
                    975: **  DISCONNECT -- remove our connection with any foreground process
                    976: **
                    977: **     Parameters:
                    978: **             fulldrop -- if set, we should also drop the controlling
                    979: **                     TTY if possible -- this should only be done when
                    980: **                     setting up the daemon since otherwise UUCP can
                    981: **                     leave us trying to open a dialin, and we will
                    982: **                     wait for the carrier.
                    983: **
                    984: **     Returns:
                    985: **             none
                    986: **
                    987: **     Side Effects:
                    988: **             Trys to insure that we are immune to vagaries of
                    989: **             the controlling tty.
                    990: */
                    991: 
                    992: disconnect(fulldrop)
                    993:        bool fulldrop;
                    994: {
                    995:        int fd;
                    996: 
                    997: #ifdef DEBUG
                    998:        if (tTd(52, 1))
                    999:                printf("disconnect: In %d Out %d\n", fileno(InChannel),
                   1000:                                                fileno(OutChannel));
                   1001:        if (tTd(52, 5))
                   1002:        {
                   1003:                printf("don't\n");
                   1004:                return;
                   1005:        }
                   1006: #endif DEBUG
                   1007: 
                   1008:        /* be sure we don't get nasty signals */
                   1009:        (void) signal(SIGHUP, SIG_IGN);
                   1010:        (void) signal(SIGINT, SIG_IGN);
                   1011:        (void) signal(SIGQUIT, SIG_IGN);
                   1012: 
                   1013:        /* we can't communicate with our caller, so.... */
                   1014:        HoldErrs = TRUE;
                   1015:        ErrorMode = EM_MAIL;
                   1016:        Verbose = FALSE;
                   1017: 
                   1018:        /* all input from /dev/null */
                   1019:        if (InChannel != stdin)
                   1020:        {
                   1021:                (void) fclose(InChannel);
                   1022:                InChannel = stdin;
                   1023:        }
                   1024:        (void) freopen("/dev/null", "r", stdin);
                   1025: 
                   1026:        /* output to the transcript */
                   1027:        if (OutChannel != stdout)
                   1028:        {
                   1029:                (void) fclose(OutChannel);
                   1030:                OutChannel = stdout;
                   1031:        }
                   1032:        if (CurEnv->e_xfp == NULL)
                   1033:                CurEnv->e_xfp = fopen("/dev/null", "w");
                   1034:        (void) fflush(stdout);
                   1035:        (void) close(1);
                   1036:        (void) close(2);
                   1037:        while ((fd = dup(fileno(CurEnv->e_xfp))) < 2 && fd > 0)
                   1038:                continue;
                   1039: 
                   1040: #ifdef TIOCNOTTY
                   1041:        /* drop our controlling TTY completely if possible */
                   1042:        if (fulldrop)
                   1043:        {
                   1044:                fd = open("/dev/tty", 2);
                   1045:                if (fd >= 0)
                   1046:                {
                   1047:                        (void) ioctl(fd, (int) TIOCNOTTY, (char *) 0);
                   1048:                        (void) close(fd);
                   1049:                }
                   1050:                (void) setpgrp(0, 0);
                   1051:                errno = 0;
                   1052:        }
                   1053: #endif TIOCNOTTY
                   1054: 
                   1055: # ifdef LOG
                   1056:        if (LogLevel > 11)
                   1057:                syslog(LOG_DEBUG, "in background, pid=%d", getpid());
                   1058: # endif LOG
                   1059: 
                   1060:        errno = 0;
                   1061: }

unix.superglobalmegacorp.com

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