home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.sbin / sendmail / src / main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-20  |  23.0 KB  |  1,100 lines

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