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

unix.superglobalmegacorp.com

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