retry data connection (SO_REUSEADDR isn't enough); show directories
[unix-history] / usr / src / libexec / ftpd / popen.c
index 5fd5fa7..408b23f 100644 (file)
  * from this software without specific prior written permission.
  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  * from this software without specific prior written permission.
  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  *
  *
- * static char sccsid[] = "@(#)popen.c 5.7 (Berkeley) 9/1/88";
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)popen.c    5.1 (Berkeley) %G%";
+static char sccsid[] = "@(#)popen.c    5.7 (Berkeley) %G%";
 #endif /* not lint */
 
 #endif /* not lint */
 
-#include <sys/param.h>
+#include <sys/types.h>
 #include <sys/signal.h>
 #include <sys/wait.h>
 #include <stdio.h>
 
 #include <sys/signal.h>
 #include <sys/wait.h>
 #include <stdio.h>
 
-static uid_t *pids;
+/*
+ * Special version of popen which avoids call to shell.  This insures noone
+ * may create a pipe to a hidden program as a side effect of a list or dir
+ * command.
+ */
+static int *pids;
 static int fds;
 
 FILE *
 static int fds;
 
 FILE *
-popen(program, type)
+ftpd_popen(program, type)
        char *program, *type;
 {
        char *program, *type;
 {
+       register char *cp;
        FILE *iop;
        FILE *iop;
-       int pdes[2], pid;
-       char *malloc();
+       int argc, gargc, pdes[2], pid;
+       char **pop, *argv[100], *gargv[1000], *vv[2];
+       extern char **glob(), **copyblk(), *strtok(), *malloc();
 
        if (*type != 'r' && *type != 'w' || type[1])
                return(NULL);
 
        if (*type != 'r' && *type != 'w' || type[1])
                return(NULL);
@@ -46,23 +52,44 @@ popen(program, type)
        if (!pids) {
                if ((fds = getdtablesize()) <= 0)
                        return(NULL);
        if (!pids) {
                if ((fds = getdtablesize()) <= 0)
                        return(NULL);
-               if (!(pids =
-                   (uid_t *)malloc((u_int)(fds * sizeof(uid_t)))))
+               if ((pids = (int *)malloc((u_int)(fds * sizeof(int)))) == NULL)
                        return(NULL);
                        return(NULL);
-               bzero(pids, fds * sizeof(uid_t));
+               bzero((char *)pids, fds * sizeof(int));
        }
        if (pipe(pdes) < 0)
                return(NULL);
        }
        if (pipe(pdes) < 0)
                return(NULL);
+
+       /* break up string into pieces */
+       for (argc = 0, cp = program;; cp = NULL)
+               if (!(argv[argc++] = strtok(cp, " \t\n")))
+                       break;
+
+       /* glob each piece */
+       gargv[0] = argv[0];
+       for (gargc = argc = 1; argv[argc]; argc++) {
+               if (!(pop = glob(argv[argc]))) {        /* globbing failed */
+                       vv[0] = argv[argc];
+                       vv[1] = NULL;
+                       pop = copyblk(vv);
+               }
+               argv[argc] = (char *)pop;               /* save to free later */
+               while (*pop && gargc < 1000)
+                       gargv[gargc++] = *pop++;
+       }
+       gargv[gargc] = NULL;
+
+       iop = NULL;
        switch(pid = vfork()) {
        case -1:                        /* error */
                (void)close(pdes[0]);
                (void)close(pdes[1]);
        switch(pid = vfork()) {
        case -1:                        /* error */
                (void)close(pdes[0]);
                (void)close(pdes[1]);
-               return(NULL);
+               goto pfree;
                /* NOTREACHED */
        case 0:                         /* child */
                if (*type == 'r') {
                        if (pdes[1] != 1) {
                                dup2(pdes[1], 1);
                /* NOTREACHED */
        case 0:                         /* child */
                if (*type == 'r') {
                        if (pdes[1] != 1) {
                                dup2(pdes[1], 1);
+                               dup2(pdes[1], 2);       /* stderr, too! */
                                (void)close(pdes[1]);
                        }
                        (void)close(pdes[0]);
                                (void)close(pdes[1]);
                        }
                        (void)close(pdes[0]);
@@ -73,9 +100,8 @@ popen(program, type)
                        }
                        (void)close(pdes[1]);
                }
                        }
                        (void)close(pdes[1]);
                }
-               execl("/bin/sh", "sh", "-c", program, NULL);
-               _exit(127);
-               /* NOTREACHED */
+               execv(gargv[0], gargv);
+               _exit(1);
        }
        /* parent; assume fdopen can't fail...  */
        if (*type == 'r') {
        }
        /* parent; assume fdopen can't fail...  */
        if (*type == 'r') {
@@ -86,28 +112,32 @@ popen(program, type)
                (void)close(pdes[0]);
        }
        pids[fileno(iop)] = pid;
                (void)close(pdes[0]);
        }
        pids[fileno(iop)] = pid;
+
+pfree: for (argc = 1; argv[argc] != NULL; argc++) {
+               blkfree((char **)argv[argc]);
+               free((char *)argv[argc]);
+       }
        return(iop);
 }
 
        return(iop);
 }
 
-pclose(iop)
+ftpd_pclose(iop)
        FILE *iop;
 {
        register int fdes;
        FILE *iop;
 {
        register int fdes;
-       long omask;
-       int stat_loc;
-       pid_t waitpid();
+       int omask;
+       union wait stat_loc;
+       int pid;
 
        /*
         * pclose returns -1 if stream is not associated with a
         * `popened' command, or, if already `pclosed'.
         */
 
        /*
         * pclose returns -1 if stream is not associated with a
         * `popened' command, or, if already `pclosed'.
         */
-       if (pids[fdes = fileno(iop)] == 0)
+       if (pids == 0 || pids[fdes = fileno(iop)] == 0)
                return(-1);
        (void)fclose(iop);
        omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
                return(-1);
        (void)fclose(iop);
        omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
-       stat_loc = waitpid(pids[fdes], &stat_loc, 0) == -1 ?
-           -1 : WEXITSTATUS(stat_loc);
+       while ((pid = wait(&stat_loc)) != pids[fdes] && pid != -1);
        (void)sigsetmask(omask);
        pids[fdes] = 0;
        (void)sigsetmask(omask);
        pids[fdes] = 0;
-       return(stat_loc);
+       return(pid == -1 ? -1 : stat_loc.w_status);
 }
 }