home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / N / TCPIP / NNTP-1.000 / NNTP-1 / nntp.1.5.11t / server / spawn.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-17  |  7.0 KB  |  344 lines

  1. #ifndef lint
  2. static    char    *sccsid = "@(#)$Header: spawn.c,v 1.21 91/01/12 11:25:33 sob Exp $";
  3. #endif
  4.  
  5. #include "common.h"
  6.  
  7. #include <signal.h>
  8. #ifdef sparc
  9. #include <vfork.h>
  10. #endif
  11. #ifdef XFER_TIMEOUT
  12. static int    xfer_lines;
  13. static int    old_xfer_lines;
  14. #endif
  15.  
  16. static char    tempfile[256];
  17. #ifndef CNEWS
  18. static char    badfile[256];
  19. #endif
  20.  
  21. /*
  22.  * spawn -- create a child process with the input from the client
  23.  * as stdin.
  24.  *
  25.  *    Parameters:    "path" is the path of the program to invoke.
  26.  *            "name" is the name to call the program.
  27.  *            "flag" is a single flag to be passed to the program.
  28.  *            "cont_code" is the response code to transmit
  29.  *            on successful startup.
  30.  *            "err_code" is the response code to transmit when
  31.  *            something goes wrong.
  32.  *
  33.  *    Returns:    -1 on non-zero return from child,
  34.  *            0 on error before fork/exec,
  35.  *            1 otherwise.
  36.  *
  37.  *    Side effects:    Creates and removes temporary file;
  38.  *            accepts input from client; forks and execs.
  39.  *            Can time out if XFER_TIMEOUT is defined.
  40.  */
  41.  
  42. spawn(path, name, flag, cont_code, err_code, errbuf, msg_id)
  43.     char        *path;
  44.     char        *name;
  45.     char        *flag;
  46.     int        cont_code;
  47.     int        err_code;
  48.     char        *errbuf;
  49.     char        *msg_id;
  50. {
  51.     char        line[NNTP_STRLEN];
  52.     register char    *cp;
  53.     int        i, fd;
  54.     int        fds[2];
  55.     int        pid, npid;
  56.     int        exit_status;
  57. #ifdef POSTER
  58.     char *envp[4], user[sizeof(POSTER) + 5], logname[sizeof(POSTER) + 8];
  59.     char *home;
  60. #else
  61.     char *envp[1];
  62. #endif
  63. #ifdef XFER_TIMEOUT
  64.     int        xfer_timeout();
  65. #endif
  66. #ifdef USG
  67.     int        status;
  68. #else not USG
  69.     union wait    status;
  70. #endif not USG
  71.     register FILE    *fp;
  72.  
  73. #ifdef CNEWS
  74.     (void) strcpy(tempfile, "/usr/tmp/rpostXXXXXX");
  75. #else
  76.     sprintf(tempfile, "%s/.tmp/rpostXXXXXX",SPOOLDIR);
  77. #endif
  78.     (void) mktemp(tempfile);
  79.  
  80.     fp = fopen(tempfile, "w");
  81.     if (fp == NULL) {
  82.         printf("%d Cannot create temporary file.\r\n", err_code);
  83.         (void) fflush(stdout);
  84.         return (0);
  85.     }
  86.  
  87. #ifdef AUTH
  88.     /*
  89.     * If this is a posting, rather than an XFER, leave a trail of
  90.     * breadcrumbs by stuffing where it came from into the header
  91.     */
  92.     if (cont_code == CONT_POST)
  93.         fprintf(fp, "Nntp-Posting-Host: %s\n", hostname);
  94. #endif AUTH
  95.  
  96.     printf("%d Ok\r\n", cont_code);
  97.     (void) fflush(stdout);
  98.  
  99. #ifdef XFER_TIMEOUT
  100.     xfer_lines = old_xfer_lines = 0;
  101.     signal(SIGALRM, xfer_timeout);
  102.     (void) alarm(XFER_TIMEOUT);
  103. #endif
  104.  
  105.     while (fgets(line, sizeof(line), stdin) != NULL) {
  106. #ifdef XFER_TIMEOUT
  107.         xfer_lines++;
  108. #endif
  109.         if ((cp = index(line, '\r')) != NULL)
  110.             *cp = '\0';
  111.         else if ((cp = index(line, '\n')) != NULL)
  112.             *cp = '\0';
  113.  
  114.         if (line[0] == '.' && line[1] == '\0')
  115.             break;
  116.  
  117.         if (line[0] == '.')
  118.             fputs(line+1, fp);
  119.         else
  120.             fputs(line, fp);
  121.         putc('\n', fp);
  122.     }
  123.     (void) fclose(fp);
  124.  
  125. #ifdef XFER_TIMEOUT
  126.     (void) alarm(0);
  127.     (void) signal(SIGALRM, SIG_DFL);
  128. #endif
  129.  
  130.     /* See if the connection got closed somehow... */
  131.  
  132.     if (line[0] != '.' && line[1] != '\0') {
  133.         (void) unlink(tempfile);
  134. #ifdef SYSLOG
  135. # ifdef LOG
  136.         syslog(LOG_ERR,
  137.             "%s spawn: EOF before period on line by itself %s",
  138.             hostname, msg_id);
  139. # else
  140.         syslog(LOG_ERR,
  141.             "spawn: EOF before period on line by itself %s", msg_id);
  142. # endif
  143. #endif
  144.         return (0);
  145.     }
  146.         
  147. #ifdef POSTER
  148.     if (tempfile[0])
  149.         (void) chown(tempfile, uid_poster, gid_poster);
  150. #endif
  151.  
  152.     /* Set up a pipe so we can see errors from rnews */
  153.  
  154.     if (pipe(fds) < 0) {
  155. #ifdef SYSLOG
  156.         syslog(LOG_ERR, "spawn: pipe: %m");
  157. #endif
  158.         (void) unlink(tempfile);
  159.         return (-1);
  160.     }
  161.  
  162.     /*
  163.      * Ok, now we have the article in "tempfile".  We
  164.      * should be able to fork off, close fd's 0 to 31 (or
  165.      * whatever), open "tempfile" for input, thus making
  166.      * it stdin, and then execle the inews.  We think.
  167.      */
  168. #ifdef SYSLOG
  169.     /*
  170.      * Close in such a way that syslog() will know to reopen.
  171.      * We must do this before the vfork() otherwise the parent
  172.      * will think the syslog fd is closed and open a new one,
  173.      * eventually using up all the available file descriptors.
  174.      */
  175.     closelog();
  176. #endif
  177.  
  178.     pid = vfork();
  179.     if (pid == 0) {        /* We're in child */
  180. #ifdef POSTER
  181. #ifndef USG
  182.         if (getuid() == 0) initgroups(POSTER,gid_poster);
  183. #endif
  184.         (void) setgid(gid_poster);
  185.         (void) setuid(uid_poster);
  186. #endif
  187.  
  188.         /* Set up stdout and stderr for child */
  189.  
  190.         if (fds[1] != 1) {
  191.             (void) dup2(fds[1], 1);
  192.             (void) close(fds[1]);
  193.         }
  194.         (void) dup2(1, 2);
  195.  
  196.         for (i = 3; i < 10; ++i) /* XXX but getdtablesize is too big */
  197.             (void) close(i);
  198.  
  199.         fd = open(tempfile, O_RDONLY);
  200.         if (fd != 0) {
  201.             (void) dup2(fd, 0);
  202.             (void) close(fd);
  203.         }
  204.  
  205.         /* Empty environment keeps cnews inews from telling lies */
  206. #ifdef POSTER
  207.         sprintf(user, "USER=%s", POSTER);
  208.         sprintf(logname, "LOGNAME=%s", POSTER);
  209.         if ((home = (char *)malloc(strlen(home_poster)+5)) != NULL)
  210.             sprintf(home, "HOME=%s", home_poster);
  211.         envp[0] = user;
  212.         envp[1] = logname;
  213.         envp[2] = home;
  214.         envp[3] = 0;
  215. #else
  216.         envp[0] = 0;
  217. #endif
  218.  
  219. #ifdef USG
  220.          /* execle() fails if name is a shell procedure */
  221.          execle("/bin/sh", "sh", path, flag, (char *)NULL, envp);
  222. #else
  223.         execle(path, name, flag, (char *) NULL, envp);
  224. #endif
  225.         fprintf(stderr, "spawn: execle(%s)", path);
  226.         perror(path);
  227. #ifdef SYSLOG
  228.         syslog(LOG_ERR, "spawn: execle(%s): %m", path);
  229. #endif
  230.         _exit(-1);    /* Error */
  231.         /*NOTREACHED*/
  232.     } else {    /* We're in parent. */
  233.         if (pid == -1) {
  234.             /* fork failed! */
  235.             printf("%d Cannot fork %s\r\n", err_code, path);
  236.             (void) fflush(stdout);
  237. #ifdef SYSLOG
  238.             syslog(LOG_ERR, "spawn: fork: %m");
  239. #endif
  240.             (void) unlink(tempfile);
  241.             return (0);
  242.         }
  243.         (void) close(fds[1]);
  244.         fp = fdopen(fds[0], "r");
  245.         if (fp == NULL) {
  246.             printf("%d Cannot fdopen %s pipe\r\n", err_code, path);
  247.             (void) fflush(stdout);
  248. #ifdef SYSLOG
  249.             syslog(LOG_ERR, "spawn: pipe: %m");
  250. #endif
  251.             (void) unlink(tempfile);
  252.             return (0);
  253.         }
  254.  
  255.         if (errbuf)
  256.             *errbuf = '\0';
  257.  
  258.         while (fgets(line, sizeof (line), fp) != NULL) {
  259.             if (line[0] != '\n') {
  260.                 if (errbuf) {
  261.                     if (cp = index(line, '\n'))
  262.                         *cp = '\0';
  263.                     (void) strcat(errbuf, line);
  264.                 }
  265. #ifdef SYSLOG
  266.                 syslog(LOG_INFO, "%s: %s", path, line);
  267. #endif
  268.             }
  269.         }
  270.  
  271.         while ((npid = wait(&status)) > 0)
  272.             if (npid == pid) {
  273. #ifdef USG
  274.                 exit_status = (status >> 8) & 0xff;
  275. #else /* not USG */
  276.                 exit_status = status.w_T.w_Retcode;
  277. #endif /*not USG */
  278.                 break;
  279.             }
  280.  
  281.         (void) fclose(fp);
  282.         (void) fflush(stdout);
  283.         if (npid < 0) {
  284. #ifdef SYSLOG
  285.             syslog(LOG_ERR, "spawn: wait pid %d: %m", pid);
  286. #endif
  287.             return (-1);
  288.         }
  289.  
  290. #ifdef notdef
  291.         /* Make ctags happy */
  292.         {
  293. #endif
  294.         if (exit_status != 0) {
  295. #ifdef SYSLOG
  296.             syslog(LOG_ERR, "spawn: %s exit status %d",
  297.                 path, exit_status);
  298. #endif
  299.             /*
  300.              * Save the tempfile away in .bad.
  301.              */
  302. #ifdef CNEWS
  303.             }
  304.         (void) unlink(tempfile);
  305. #else
  306.             sprintf(badfile, "%s/.bad/nntpXXXXXX",SPOOLDIR);
  307.             (void) mktemp(badfile);
  308.             (void) rename(tempfile, badfile);
  309.         } else {
  310.             (void) unlink(tempfile);
  311.         }
  312. #endif            
  313.         return (exit_status ? -1 : 1);
  314.     }
  315. }
  316.  
  317. #ifdef XFER_TIMEOUT
  318.  
  319. xfer_timeout()
  320. {
  321.     if (old_xfer_lines < xfer_lines) {
  322.         old_xfer_lines = xfer_lines;
  323.         (void) alarm(XFER_TIMEOUT);
  324.         return;
  325.     }
  326.  
  327.     /* Timed out. */
  328.  
  329.     printf("%d timeout after %d seconds, closing connection.\r\n",
  330.         ERR_FAULT, XFER_TIMEOUT);
  331.     fflush(stdout);
  332.  
  333. #ifdef LOG
  334.     syslog(LOG_ERR, "%s transfer_timeout", hostname);
  335. #endif LOG
  336.  
  337.     (void) unlink(tempfile);
  338.  
  339.     exit(1);
  340. }
  341.  
  342. #endif XFER_TIMEOUT
  343.  
  344.