home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume3 / sm-smtp / smtpd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-02-03  |  5.2 KB  |  261 lines

  1. #ifndef lint
  2. static char *sccsid = "@(#)smtpd.c    1.7 87/07/31";
  3. #endif lint
  4. /*
  5.  * smtpd - SMTP listener: receives SMTP mail & invokes cmail.
  6.  *    SMTP is either Simple Mail Transfer Protocol or
  7.  *    Sado-Masochistic Torture Procedure.
  8.  */
  9.  
  10. #include "smtp.h"
  11. #include <signal.h>
  12. #include <netdb.h>
  13. #include <sys/uio.h>
  14. #include <sys/socket.h>
  15. #ifdef BSD
  16. #include <sgtty.h>
  17. #include <sys/wait.h>
  18. #endif
  19. #include <sys/resource.h>    /* for wait3(2) */
  20. #include <netinet/in.h>
  21.  
  22. /* forward declarations */
  23. FILE    *popen();
  24.  
  25. #ifdef INETD
  26. #ifdef BSD
  27. int    reapchild();
  28. #endif
  29. #endif
  30.  
  31. extern    char **environ;
  32. extern    int errno, sys_nerr;
  33. extern    char *sys_errlist[];
  34.  
  35. #ifndef SERVNAME
  36. #define SERVNAME "smtp"
  37. #endif                /* SERVNAME */
  38. struct sockaddr_in sin = { AF_INET };
  39. struct sockaddr_in from;
  40.  
  41. int debug;
  42. char *progname;
  43. char logm[MAXSTR];
  44.  
  45. /*
  46.  * main - parse arguments and handle options
  47.  */
  48.  
  49. main(argc, argv)
  50. int argc;
  51. char *argv[];
  52. {
  53.     int c;
  54.     int errflg = 0;
  55.     extern int optind;
  56.     extern char *optarg;
  57.  
  58.     progname = argv[0];
  59.     getmynames ();
  60.  
  61.     while ((c = getopt(argc, argv, "d")) != EOF)
  62.         switch (c) {
  63.         case 'd':
  64.             ++debug;
  65.             break;
  66.         case '?':
  67.         default:
  68.             errflg++;
  69.             break;
  70.         }
  71.     if (errflg) {
  72.         logit(LOG_CRIT, "Usage: %s [-d]\n", progname);
  73.         exit(2);
  74.     }
  75.  
  76.     if (optind >= argc)
  77.         process();
  78. #ifdef INETD
  79.     else if (optind == argc - 1) {        /* one argument */
  80.         if (sscanf(argv[optind], "%lx.%hd", &from.sin_addr.s_addr,
  81.             &from.sin_port) != 2) {
  82.             logit(LOG_CRIT,
  83.                 "in.smtpd: bad arg from inetd: %s\n",
  84.                 argv[optind]);
  85.             exit(2);
  86.         }
  87.         from.sin_family = AF_INET;
  88.         from.sin_addr.s_addr = htonl(from.sin_addr.s_addr);
  89.         from.sin_port = htons(from.sin_port);
  90.         process();
  91.     }
  92. #endif                /* INETD */
  93.     else {
  94.         logit(LOG_CRIT, "%s: too many args\n", progname);
  95.         exit(2);
  96.     }
  97.  
  98.     return 0;
  99. }
  100.  
  101. /*
  102.  * process - process input file
  103.  */
  104. process()
  105. {
  106. #ifndef INETD
  107.     int s, pid;
  108. #endif        /* INETD */
  109.     struct servent *sp;
  110.  
  111.     sp = getservbyname(SERVNAME, "tcp");
  112.     if (sp == 0) {
  113.         logit(LOG_CRIT, "tcp/%s: unknown service\n", SERVNAME);
  114.         exit(1);
  115.     }
  116.     sin.sin_port = sp->s_port;
  117.  
  118. #ifdef INETD
  119.     /* connection on fd 0 from inetd */
  120.     doit(0, &from);
  121.     /* NOTREACHED */
  122.     exit(0);
  123. #else                    /* INETD */
  124. #ifndef DEBUG
  125.     if (fork())            /* run in the background */
  126.         exit(0);
  127.     for (s = 0; s < 10; s++)    /* close most file descriptors */
  128.         (void) close(s);
  129.     (void) open("/dev/null", 0);    /* reopen them on harmless streams */
  130.     (void) dup2(0, 1);
  131.     (void) dup2(0, 2);
  132.     { int tt = open("/dev/tty", 2);    /* leave current process group */
  133.       if (tt > 0) {
  134. #ifdef TIOCNOTTY
  135.         (void) ioctl(tt, TIOCNOTTY, (char *)0);
  136. #endif
  137.         (void) close(tt);
  138.       }
  139.     }
  140. #endif                    /* DEBUG */
  141.     /* create internet socket s; retry 5 times at 5 s. intervals if no luck */
  142.     while ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
  143.         static int nlog = 0;
  144.  
  145.         if (nlog++ <= 5)
  146.             logit(LOG_CRIT, "socket", "");
  147.         sleep(5);
  148.     }
  149.     /* set socket options, notably keepalive */
  150.     if (debug) {
  151.         int debugval = 1;
  152.  
  153.         if (setsockopt(s, SOL_SOCKET, SO_DEBUG,
  154.             (char *)&debugval, sizeof(int)) < 0)
  155.             logit(LOG_CRIT, "setsockopt (SO_DEBUG)", "");
  156.     }
  157.     if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *)0, 0) < 0)
  158.         logit(LOG_CRIT, "setsockopt (SO_KEEPALIVE)", "");
  159.     /* bind socket to SERVNAME (SMTP) port; retry as above on failure */
  160.     while (bind(s, (struct sockaddr *)&sin, sizeof sin) < 0) {
  161.         static int nlog = 0;
  162.  
  163.         if (nlog++ <= 5)
  164.             logit(LOG_CRIT, "bind", "");
  165.         sleep(5);
  166.     }
  167.  
  168. #ifdef BSD
  169.     (void) signal(SIGCHLD, TYPESIG reapchild);
  170. #else
  171.     (void) signal(SIGCHLD, SIG_IGN);    /* SystemV takes care ... */
  172. #endif
  173.  
  174.     /* listen with 10 input buffers on socket (?) */
  175.     if (listen(s, 10) == -1)
  176.         logit(LOG_CRIT, "listen", "");
  177.     for (;;) {
  178.         int conn, fromlen = sizeof from;
  179.  
  180.         /* get a connection on fd conn; stores src host addr in from */
  181.         conn = accept(s, (struct sockaddr *)&from, &fromlen);
  182.         if (conn < 0) {
  183.             static int nlog = 0;
  184.  
  185.             if (errno == EINTR)
  186.                 continue;
  187.             if (++nlog <= 5)
  188.                 logit(LOG_CRIT, "accept", "");
  189.             sleep(1);
  190.             continue;
  191.         }
  192.         /* fork a child for this connection */
  193.         if ((pid = fork()) < 0)
  194.             logit(LOG_CRIT, "can't fork!!", "");
  195.         else if (pid == 0) {
  196.             (void) signal(SIGCHLD, SIG_DFL);
  197.             doit(conn, &from);    /* listen to SMTP dialogue */
  198.             /* NOTREACHED */
  199.             exit(0);
  200.         }
  201.         (void) close(conn);
  202.     }
  203.     /*NOTREACHED*/
  204. #endif            /* INETD */
  205. }
  206.  
  207. #ifndef INETD
  208. #ifdef BSD
  209. reapchild()
  210. {
  211.     union wait status;
  212.  
  213.     /* gross hack! */
  214.     while (wait3(&status, WNOHANG, (struct rusage *)0) > 0);
  215.  
  216. }
  217. #endif                /* BSD */
  218. #endif            /* INETD */
  219.  
  220. /*
  221.  * handle some input.  never returns.
  222.  */
  223. doit(f, fromaddr)
  224. int f;
  225. struct sockaddr_in *fromaddr;        /* internet addr of sending host */
  226. {
  227.     FILE *fi, *fo;
  228.  
  229.     if ((fi = fdopen(f, "r")) == NULL)
  230.         logit(LOG_CRIT, "fdopen of socket for input", "");
  231.     if ((fo = fdopen(f, "w")) == NULL)
  232.         logit(LOG_CRIT, "fdopen of socket for output", "");
  233.  
  234.     converse(fi, fo, fromaddr);
  235.     /* NOTREACHED */
  236.     return 0;
  237. }
  238.  
  239. #ifndef NOBOMB
  240. bomb(err)
  241. int err;
  242. {
  243.     death(err);
  244. }
  245. #endif
  246.  
  247. logit (sev, fmt, str)
  248. int sev;
  249. char *fmt, *str;
  250. {
  251. #ifdef SYSLOG
  252.     (void) sprintf(logm, "%s: %s", progname, fmt);
  253.     (void) syslog(sev, logm, (str == "" && errno <= sys_nerr)?
  254.         sys_errlist[errno]: str);
  255. #else
  256.     (void) sprintf(logm, "%s: %s", progname, fmt);
  257.     (void) fprintf(stderr, logm, (str == "" && errno <= sys_nerr)?
  258.         sys_errlist[errno]: str);
  259. #endif
  260. }
  261.