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