home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.sbin / sendmail / src / daemon.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-20  |  14.1 KB  |  613 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. #include <errno.h>
  36. #include "sendmail.h"
  37.  
  38. #ifndef lint
  39. #ifdef DAEMON
  40. static char sccsid[] = "@(#)daemon.c    5.37 (Berkeley) 3/2/91 (with daemon mode)";
  41. #else
  42. static char sccsid[] = "@(#)daemon.c    5.37 (Berkeley) 3/2/91 (without daemon mode)";
  43. #endif
  44. #endif /* not lint */
  45.  
  46. int la;    /* load average */
  47.  
  48. #ifdef DAEMON
  49.  
  50. # include <netdb.h>
  51. # include <sys/signal.h>
  52. # include <sys/wait.h>
  53. # include <sys/time.h>
  54. # include <sys/resource.h>
  55.  
  56. /*
  57. **  DAEMON.C -- routines to use when running as a daemon.
  58. **
  59. **    This entire file is highly dependent on the 4.2 BSD
  60. **    interprocess communication primitives.  No attempt has
  61. **    been made to make this file portable to Version 7,
  62. **    Version 6, MPX files, etc.  If you should try such a
  63. **    thing yourself, I recommend chucking the entire file
  64. **    and starting from scratch.  Basic semantics are:
  65. **
  66. **    getrequests()
  67. **        Opens a port and initiates a connection.
  68. **        Returns in a child.  Must set InChannel and
  69. **        OutChannel appropriately.
  70. **    clrdaemon()
  71. **        Close any open files associated with getting
  72. **        the connection; this is used when running the queue,
  73. **        etc., to avoid having extra file descriptors during
  74. **        the queue run and to avoid confusing the network
  75. **        code (if it cares).
  76. **    makeconnection(host, port, outfile, infile)
  77. **        Make a connection to the named host on the given
  78. **        port.  Set *outfile and *infile to the files
  79. **        appropriate for communication.  Returns zero on
  80. **        success, else an exit status describing the
  81. **        error.
  82. **    maphostname(hbuf, hbufsize)
  83. **        Convert the entry in hbuf into a canonical form.  It
  84. **        may not be larger than hbufsize.
  85. */
  86. /*
  87. **  GETREQUESTS -- open mail IPC port and get requests.
  88. **
  89. **    Parameters:
  90. **        none.
  91. **
  92. **    Returns:
  93. **        none.
  94. **
  95. **    Side Effects:
  96. **        Waits until some interesting activity occurs.  When
  97. **        it does, a child is created to process it, and the
  98. **        parent waits for completion.  Return from this
  99. **        routine is always in the child.  The file pointers
  100. **        "InChannel" and "OutChannel" should be set to point
  101. **        to the communication channel.
  102. */
  103.  
  104. struct sockaddr_in    SendmailAddress;/* internet address of sendmail */
  105.  
  106. int    DaemonSocket    = -1;        /* fd describing socket */
  107. char    *NetName;            /* name of home (local?) network */
  108.  
  109. getrequests()
  110. {
  111.     int t;
  112.     register struct servent *sp;
  113.     int on = 1;
  114.     extern void reapchild();
  115.  
  116.     /*
  117.     **  Set up the address for the mailer.
  118.     */
  119.  
  120.     sp = getservbyname("smtp", "tcp");
  121.     if (sp == NULL)
  122.     {
  123.         syserr("server \"smtp\" unknown");
  124.         goto severe;
  125.     }
  126.     SendmailAddress.sin_family = AF_INET;
  127.     SendmailAddress.sin_addr.s_addr = INADDR_ANY;
  128.     SendmailAddress.sin_port = sp->s_port;
  129.  
  130.     /*
  131.     **  Try to actually open the connection.
  132.     */
  133.  
  134.     if (tTd(15, 1))
  135.         printf("getrequests: port 0x%x\n", SendmailAddress.sin_port);
  136.  
  137.     /* get a socket for the SMTP connection */
  138.     DaemonSocket = socket(AF_INET, SOCK_STREAM, 0);
  139.     if (DaemonSocket < 0)
  140.     {
  141.         /* probably another daemon already */
  142.         syserr("getrequests: can't create socket");
  143.       severe:
  144. # ifdef LOG
  145.         if (LogLevel > 0)
  146.             syslog(LOG_ALERT, "cannot get connection");
  147. # endif LOG
  148.         finis();
  149.     }
  150.  
  151.     /* turn on network debugging? */
  152.     if (tTd(15, 15))
  153.         (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof on);
  154.  
  155.     (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof on);
  156.     (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, sizeof on);
  157.  
  158.     if (bind(DaemonSocket,
  159.         (struct sockaddr *)&SendmailAddress, sizeof SendmailAddress) < 0)
  160.     {
  161.         syserr("getrequests: cannot bind");
  162.         (void) close(DaemonSocket);
  163.         goto severe;
  164.     }
  165.     if (listen(DaemonSocket, 10) < 0)
  166.     {
  167.         syserr("getrequests: cannot listen");
  168.         (void) close(DaemonSocket);
  169.         goto severe;
  170.     }
  171.  
  172.     (void) signal(SIGCHLD, reapchild);
  173.  
  174.     if (tTd(15, 1))
  175.         printf("getrequests: %d\n", DaemonSocket);
  176.  
  177.     for (;;)
  178.     {
  179.         register int pid;
  180.         auto int lotherend;
  181.         extern int RefuseLA;
  182.  
  183.         /* see if we are rejecting connections */
  184.         while ((la = getla()) > RefuseLA)
  185.         {
  186.             setproctitle("rejecting connections: load average: %.2f", (double)la);
  187.             sleep(5);
  188.         }
  189.  
  190.         /* wait for a connection */
  191.         setproctitle("accepting connections");
  192.         do
  193.         {
  194.             errno = 0;
  195.             lotherend = sizeof RealHostAddr;
  196.             t = accept(DaemonSocket,
  197.                 (struct sockaddr *)&RealHostAddr, &lotherend);
  198.         } while (t < 0 && errno == EINTR);
  199.         if (t < 0)
  200.         {
  201.             syserr("getrequests: accept");
  202.             sleep(5);
  203.             continue;
  204.         }
  205.  
  206.         /*
  207.         **  Create a subprocess to process the mail.
  208.         */
  209.  
  210.         if (tTd(15, 2))
  211.             printf("getrequests: forking (fd = %d)\n", t);
  212.  
  213.         pid = fork();
  214.         if (pid < 0)
  215.         {
  216.             syserr("daemon: cannot fork");
  217.             sleep(10);
  218.             (void) close(t);
  219.             continue;
  220.         }
  221.  
  222.         if (pid == 0)
  223.         {
  224.             extern struct hostent *gethostbyaddr();
  225.             register struct hostent *hp;
  226.             char buf[MAXNAME];
  227.  
  228.             /*
  229.             **  CHILD -- return to caller.
  230.             **    Collect verified idea of sending host.
  231.             **    Verify calling user id if possible here.
  232.             */
  233.  
  234.             (void) signal(SIGCHLD, SIG_DFL);
  235.  
  236.             /* determine host name */
  237.             hp = gethostbyaddr((char *) &RealHostAddr.sin_addr, sizeof RealHostAddr.sin_addr, AF_INET);
  238.             if (hp != NULL)
  239.                 (void) strcpy(buf, hp->h_name);
  240.             else
  241.             {
  242.                 extern char *inet_ntoa();
  243.  
  244.                 /* produce a dotted quad */
  245.                 (void) sprintf(buf, "[%s]",
  246.                     inet_ntoa(RealHostAddr.sin_addr));
  247.             }
  248.  
  249.             /* should we check for illegal connection here? XXX */
  250.  
  251.             RealHostName = newstr(buf);
  252.  
  253.             (void) close(DaemonSocket);
  254.             InChannel = fdopen(t, "r");
  255.             OutChannel = fdopen(dup(t), "w");
  256.             if (tTd(15, 2))
  257.                 printf("getreq: returning\n");
  258. # ifdef LOG
  259.             if (LogLevel > 11)
  260.                 syslog(LOG_DEBUG, "connected, pid=%d", getpid());
  261. # endif LOG
  262.             return;
  263.         }
  264.  
  265.         /* close the port so that others will hang (for a while) */
  266.         (void) close(t);
  267.     }
  268.     /*NOTREACHED*/
  269. }
  270. /*
  271. **  CLRDAEMON -- reset the daemon connection
  272. **
  273. **    Parameters:
  274. **        none.
  275. **
  276. **    Returns:
  277. **        none.
  278. **
  279. **    Side Effects:
  280. **        releases any resources used by the passive daemon.
  281. */
  282.  
  283. clrdaemon()
  284. {
  285.     if (DaemonSocket >= 0)
  286.         (void) close(DaemonSocket);
  287.     DaemonSocket = -1;
  288. }
  289. /*
  290. **  MAKECONNECTION -- make a connection to an SMTP socket on another machine.
  291. **
  292. **    Parameters:
  293. **        host -- the name of the host.
  294. **        port -- the port number to connect to.
  295. **        outfile -- a pointer to a place to put the outfile
  296. **            descriptor.
  297. **        infile -- ditto for infile.
  298. **
  299. **    Returns:
  300. **        An exit code telling whether the connection could be
  301. **            made and if not why not.
  302. **
  303. **    Side Effects:
  304. **        none.
  305. */
  306.  
  307. makeconnection(host, port, outfile, infile)
  308.     char *host;
  309.     u_short port;
  310.     FILE **outfile;
  311.     FILE **infile;
  312. {
  313.     register int i, s;
  314.     register struct hostent *hp = (struct hostent *)NULL;
  315.     extern char *inet_ntoa();
  316.     int sav_errno;
  317. #ifdef NAMED_BIND
  318.     extern int h_errno;
  319. #endif
  320.  
  321.     /*
  322.     **  Set up the address for the mailer.
  323.     **    Accept "[a.b.c.d]" syntax for host name.
  324.     */
  325.  
  326. #ifdef NAMED_BIND
  327.     h_errno = 0;
  328. #endif
  329.     errno = 0;
  330.  
  331.     if (host[0] == '[')
  332.     {
  333.         long hid;
  334.         register char *p = index(host, ']');
  335.  
  336.         if (p != NULL)
  337.         {
  338.             *p = '\0';
  339.             hid = inet_addr(&host[1]);
  340.             *p = ']';
  341.         }
  342.         if (p == NULL || hid == -1)
  343.         {
  344.             usrerr("Invalid numeric domain spec \"%s\"", host);
  345.             return (EX_NOHOST);
  346.         }
  347.         SendmailAddress.sin_addr.s_addr = hid;
  348.     }
  349.     else
  350.     {
  351.         hp = gethostbyname(host);
  352.         if (hp == NULL)
  353.         {
  354. #ifdef NAMED_BIND
  355.             if (errno == ETIMEDOUT || h_errno == TRY_AGAIN)
  356.                 return (EX_TEMPFAIL);
  357.  
  358.             /* if name server is specified, assume temp fail */
  359.             if (errno == ECONNREFUSED && UseNameServer)
  360.                 return (EX_TEMPFAIL);
  361. #endif
  362.  
  363.             /*
  364.             **  XXX Should look for mail forwarder record here
  365.             **  XXX if (h_errno == NO_ADDRESS).
  366.             */
  367.  
  368.             return (EX_NOHOST);
  369.         }
  370.         bcopy(hp->h_addr, (char *) &SendmailAddress.sin_addr, hp->h_length);
  371.         i = 1;
  372.     }
  373.  
  374.     /*
  375.     **  Determine the port number.
  376.     */
  377.  
  378.     if (port != 0)
  379.         SendmailAddress.sin_port = htons(port);
  380.     else
  381.     {
  382.         register struct servent *sp = getservbyname("smtp", "tcp");
  383.  
  384.         if (sp == NULL)
  385.         {
  386.             syserr("makeconnection: server \"smtp\" unknown");
  387.             return (EX_OSFILE);
  388.         }
  389.         SendmailAddress.sin_port = sp->s_port;
  390.     }
  391.  
  392.     /*
  393.     **  Try to actually open the connection.
  394.     */
  395.  
  396. again:
  397.     if (tTd(16, 1))
  398.         printf("makeconnection (%s [%s])\n", host,
  399.             inet_ntoa(SendmailAddress.sin_addr.s_addr));
  400.  
  401.     s = socket(AF_INET, SOCK_STREAM, 0);
  402.     if (s < 0)
  403.     {
  404.         syserr("makeconnection: no socket");
  405.         sav_errno = errno;
  406.         goto failure;
  407.     }
  408.  
  409.     if (tTd(16, 1))
  410.         printf("makeconnection: %d\n", s);
  411.  
  412.     /* turn on network debugging? */
  413.     if (tTd(16, 14))
  414.     {
  415.         int on = 1;
  416.         (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof on);
  417.     }
  418.     if (CurEnv->e_xfp != NULL)
  419.         (void) fflush(CurEnv->e_xfp);        /* for debugging */
  420.     errno = 0;                    /* for debugging */
  421.     SendmailAddress.sin_family = AF_INET;
  422.     if (connect(s,
  423.         (struct sockaddr *)&SendmailAddress, sizeof SendmailAddress) < 0)
  424.     {
  425.         sav_errno = errno;
  426.         (void) close(s);
  427.         if (hp && hp->h_addr_list[i])
  428.         {
  429.             bcopy(hp->h_addr_list[i++],
  430.                 (char *)&SendmailAddress.sin_addr, hp->h_length);
  431.             goto again;
  432.         }
  433.  
  434.         /* failure, decide if temporary or not */
  435.     failure:
  436.         switch (sav_errno)
  437.         {
  438.           case EISCONN:
  439.           case ETIMEDOUT:
  440.           case EINPROGRESS:
  441.           case EALREADY:
  442.           case EADDRINUSE:
  443.           case EHOSTDOWN:
  444.           case ENETDOWN:
  445.           case ENETRESET:
  446.           case ENOBUFS:
  447.           case ECONNREFUSED:
  448.           case ECONNRESET:
  449.           case EHOSTUNREACH:
  450.           case ENETUNREACH:
  451.             /* there are others, I'm sure..... */
  452.             return (EX_TEMPFAIL);
  453.  
  454.           case EPERM:
  455.             /* why is this happening? */
  456.             syserr("makeconnection: funny failure, addr=%lx, port=%x",
  457.                 SendmailAddress.sin_addr.s_addr, SendmailAddress.sin_port);
  458.             return (EX_TEMPFAIL);
  459.  
  460.           default:
  461.             {
  462.                 extern char *errstring();
  463.  
  464.                 message(Arpa_Info, "%s", errstring(sav_errno));
  465.                 return (EX_UNAVAILABLE);
  466.             }
  467.         }
  468.     }
  469.  
  470.     /* connection ok, put it into canonical form */
  471.     *outfile = fdopen(s, "w");
  472.     *infile = fdopen(dup(s), "r");
  473.  
  474.     return (EX_OK);
  475. }
  476. /*
  477. **  MYHOSTNAME -- return the name of this host.
  478. **
  479. **    Parameters:
  480. **        hostbuf -- a place to return the name of this host.
  481. **        size -- the size of hostbuf.
  482. **
  483. **    Returns:
  484. **        A list of aliases for this host.
  485. **
  486. **    Side Effects:
  487. **        none.
  488. */
  489.  
  490. char **
  491. myhostname(hostbuf, size)
  492.     char hostbuf[];
  493.     int size;
  494. {
  495.     extern struct hostent *gethostbyname();
  496.     struct hostent *hp;
  497.  
  498.     if (gethostname(hostbuf, size) < 0)
  499.     {
  500.         (void) strcpy(hostbuf, "localhost");
  501.     }
  502.     hp = gethostbyname(hostbuf);
  503.     if (hp != NULL)
  504.     {
  505.         (void) strcpy(hostbuf, hp->h_name);
  506.         return (hp->h_aliases);
  507.     }
  508.     else
  509.         return (NULL);
  510. }
  511.  
  512. /*
  513.  *  MAPHOSTNAME -- turn a hostname into canonical form
  514.  *
  515.  *    Parameters:
  516.  *        hbuf -- a buffer containing a hostname.
  517.  *        hbsize -- the size of hbuf.
  518.  *
  519.  *    Returns:
  520.  *        none.
  521.  *
  522.  *    Side Effects:
  523.  *        Looks up the host specified in hbuf.  If it is not
  524.  *        the canonical name for that host, replace it with
  525.  *        the canonical name.  If the name is unknown, or it
  526.  *        is already the canonical name, leave it unchanged.
  527.  */
  528. maphostname(hbuf, hbsize)
  529.     char *hbuf;
  530.     int hbsize;
  531. {
  532.     register struct hostent *hp;
  533.     u_long in_addr;
  534.     char ptr[256], *cp;
  535.     struct hostent *gethostbyaddr();
  536.  
  537.     /*
  538.      * If first character is a bracket, then it is an address
  539.      * lookup.  Address is copied into a temporary buffer to
  540.      * strip the brackets and to preserve hbuf if address is
  541.      * unknown.
  542.      */
  543.     if (*hbuf != '[') {
  544.         getcanonname(hbuf, hbsize);
  545.         return;
  546.     }
  547.     if ((cp = index(strcpy(ptr, hbuf), ']')) == NULL)
  548.         return;
  549.     *cp = '\0';
  550.     in_addr = inet_addr(&ptr[1]);
  551.     hp = gethostbyaddr((char *)&in_addr, sizeof(struct in_addr), AF_INET);
  552.     if (hp == NULL)
  553.         return;
  554.     if (strlen(hp->h_name) >= hbsize)
  555.         hp->h_name[hbsize - 1] = '\0';
  556.     (void)strcpy(hbuf, hp->h_name);
  557. }
  558.  
  559. # else DAEMON
  560. /* code for systems without sophisticated networking */
  561.  
  562. /*
  563. **  MYHOSTNAME -- stub version for case of no daemon code.
  564. **
  565. **    Can't convert to upper case here because might be a UUCP name.
  566. **
  567. **    Mark, you can change this to be anything you want......
  568. */
  569.  
  570. char **
  571. myhostname(hostbuf, size)
  572.     char hostbuf[];
  573.     int size;
  574. {
  575.     register FILE *f;
  576.  
  577.     hostbuf[0] = '\0';
  578.     f = fopen("/usr/include/whoami", "r");
  579.     if (f != NULL)
  580.     {
  581.         (void) fgets(hostbuf, size, f);
  582.         fixcrlf(hostbuf, TRUE);
  583.         (void) fclose(f);
  584.     }
  585.     return (NULL);
  586. }
  587. /*
  588. **  MAPHOSTNAME -- turn a hostname into canonical form
  589. **
  590. **    Parameters:
  591. **        hbuf -- a buffer containing a hostname.
  592. **        hbsize -- the size of hbuf.
  593. **
  594. **    Returns:
  595. **        none.
  596. **
  597. **    Side Effects:
  598. **        Looks up the host specified in hbuf.  If it is not
  599. **        the canonical name for that host, replace it with
  600. **        the canonical name.  If the name is unknown, or it
  601. **        is already the canonical name, leave it unchanged.
  602. */
  603.  
  604. /*ARGSUSED*/
  605. maphostname(hbuf, hbsize)
  606.     char *hbuf;
  607.     int hbsize;
  608. {
  609.     return;
  610. }
  611.  
  612. #endif DAEMON
  613.