1*cee9ac24Schristos /* $NetBSD: popen.c,v 1.16 1999/08/25 20:07:33 christos Exp $ */ 26a991762Scgd 361f28255Scgd /* 4d6743f02Sderaadt * Copyright (c) 1988, 1993, 1994 5d6743f02Sderaadt * The Regents of the University of California. All rights reserved. 661f28255Scgd * 761f28255Scgd * This code is derived from software written by Ken Arnold and 861f28255Scgd * published in UNIX Review, Vol. 6, No. 8. 961f28255Scgd * 1061f28255Scgd * Redistribution and use in source and binary forms, with or without 1161f28255Scgd * modification, are permitted provided that the following conditions 1261f28255Scgd * are met: 1361f28255Scgd * 1. Redistributions of source code must retain the above copyright 1461f28255Scgd * notice, this list of conditions and the following disclaimer. 1561f28255Scgd * 2. Redistributions in binary form must reproduce the above copyright 1661f28255Scgd * notice, this list of conditions and the following disclaimer in the 1761f28255Scgd * documentation and/or other materials provided with the distribution. 1861f28255Scgd * 3. All advertising materials mentioning features or use of this software 1961f28255Scgd * must display the following acknowledgement: 2061f28255Scgd * This product includes software developed by the University of 2161f28255Scgd * California, Berkeley and its contributors. 2261f28255Scgd * 4. Neither the name of the University nor the names of its contributors 2361f28255Scgd * may be used to endorse or promote products derived from this software 2461f28255Scgd * without specific prior written permission. 2561f28255Scgd * 2661f28255Scgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2761f28255Scgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2861f28255Scgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2961f28255Scgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 3061f28255Scgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3161f28255Scgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3261f28255Scgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3361f28255Scgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3461f28255Scgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3561f28255Scgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3661f28255Scgd * SUCH DAMAGE. 3761f28255Scgd * 3861f28255Scgd */ 3961f28255Scgd 402424c4f9Schristos #include <sys/cdefs.h> 4161f28255Scgd #ifndef lint 426a991762Scgd #if 0 43d6743f02Sderaadt static char sccsid[] = "@(#)popen.c 8.3 (Berkeley) 4/6/94"; 446a991762Scgd #else 45*cee9ac24Schristos __RCSID("$NetBSD: popen.c,v 1.16 1999/08/25 20:07:33 christos Exp $"); 466a991762Scgd #endif 4761f28255Scgd #endif /* not lint */ 4861f28255Scgd 4961f28255Scgd #include <sys/types.h> 5061f28255Scgd #include <sys/wait.h> 51d6743f02Sderaadt 52d6743f02Sderaadt #include <errno.h> 53d6743f02Sderaadt #include <glob.h> 5461f28255Scgd #include <signal.h> 5561f28255Scgd #include <stdio.h> 5661f28255Scgd #include <stdlib.h> 5761f28255Scgd #include <string.h> 5825cf35a4Slukem #include <syslog.h> 59d6743f02Sderaadt #include <unistd.h> 60d6743f02Sderaadt 61b2f939acSexplorer #ifdef KERBEROS5 62*cee9ac24Schristos #include <krb5/krb5.h> 63b2f939acSexplorer #endif 64b2f939acSexplorer 65d6743f02Sderaadt #include "extern.h" 6661f28255Scgd 672424c4f9Schristos #define INCR 100 6861f28255Scgd /* 699c9d43e6Slukem * Special version of popen which avoids call to shell. This ensures no-one 7061f28255Scgd * may create a pipe to a hidden program as a side effect of a list or dir 7161f28255Scgd * command. 729c9d43e6Slukem * If stderrfd != -1, then send stderr of a read command there, 739c9d43e6Slukem * otherwise close stderr. 7461f28255Scgd */ 7561f28255Scgd static int *pids; 7661f28255Scgd static int fds; 7761f28255Scgd 7825cf35a4Slukem extern int ls_main __P((int, char *[])); 7925cf35a4Slukem 8061f28255Scgd FILE * 819c9d43e6Slukem ftpd_popen(program, type, stderrfd) 8261f28255Scgd char *program, *type; 839c9d43e6Slukem int stderrfd; 8461f28255Scgd { 85d6743f02Sderaadt char *cp; 862424c4f9Schristos FILE *iop = NULL; 8725cf35a4Slukem int argc, gargc, pdes[2], pid, isls; 882424c4f9Schristos char **pop, **np; 892424c4f9Schristos char **argv = NULL, **gargv = NULL; 902424c4f9Schristos size_t nargc = 100, ngargc = 100; 912424c4f9Schristos #ifdef __GNUC__ 922424c4f9Schristos (void) &iop; 932424c4f9Schristos (void) &gargc; 942424c4f9Schristos (void) &gargv; 952424c4f9Schristos (void) &argv; 962424c4f9Schristos #endif 9725cf35a4Slukem isls = 0; 9861f28255Scgd 9966783f1fSlukem if ((*type != 'r' && *type != 'w') || type[1]) 10061f28255Scgd return (NULL); 10161f28255Scgd 10261f28255Scgd if (!pids) { 10361f28255Scgd if ((fds = getdtablesize()) <= 0) 10461f28255Scgd return (NULL); 10561f28255Scgd if ((pids = (int *)malloc((u_int)(fds * sizeof(int)))) == NULL) 10661f28255Scgd return (NULL); 107d6743f02Sderaadt memset(pids, 0, fds * sizeof(int)); 10861f28255Scgd } 10961f28255Scgd if (pipe(pdes) < 0) 11061f28255Scgd return (NULL); 11161f28255Scgd 1122424c4f9Schristos if ((argv = malloc(nargc * sizeof(char *))) == NULL) 1132424c4f9Schristos return NULL; 1142424c4f9Schristos 1152424c4f9Schristos #define CHECKMORE(c, v, n) \ 1162424c4f9Schristos if (c >= n + 2) { \ 1172424c4f9Schristos n += INCR; \ 1182424c4f9Schristos if ((np = realloc(v, n * sizeof(char *))) == NULL) \ 1192424c4f9Schristos goto pfree; \ 1202424c4f9Schristos else \ 1212424c4f9Schristos v = np; \ 1222424c4f9Schristos } 1232424c4f9Schristos 12461f28255Scgd /* break up string into pieces */ 1252424c4f9Schristos for (argc = 0, cp = program;; cp = NULL) { 1262424c4f9Schristos CHECKMORE(argc, argv, nargc) 12761f28255Scgd if (!(argv[argc++] = strtok(cp, " \t\n"))) 12861f28255Scgd break; 1292424c4f9Schristos } 1302424c4f9Schristos 1312424c4f9Schristos if ((gargv = malloc(ngargc * sizeof(char *))) == NULL) 1322424c4f9Schristos goto pfree; 13361f28255Scgd 13461f28255Scgd /* glob each piece */ 13561f28255Scgd gargv[0] = argv[0]; 13661f28255Scgd for (gargc = argc = 1; argv[argc]; argc++) { 137d6743f02Sderaadt glob_t gl; 138fc5d36f8Skleink int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE; 139d6743f02Sderaadt 140d6743f02Sderaadt memset(&gl, 0, sizeof(gl)); 1412424c4f9Schristos if (glob(argv[argc], flags, NULL, &gl)) { 1422424c4f9Schristos CHECKMORE(gargc, gargv, ngargc) 1432424c4f9Schristos if ((gargv[gargc++] = strdup(argv[argc])) == NULL) 1442424c4f9Schristos goto pfree; 1452424c4f9Schristos } 146d6743f02Sderaadt else 1472424c4f9Schristos for (pop = gl.gl_pathv; *pop; pop++) { 1482424c4f9Schristos CHECKMORE(gargc, gargv, ngargc) 1492424c4f9Schristos if ((gargv[gargc++] = strdup(*pop)) == NULL) 1502424c4f9Schristos goto pfree; 1512424c4f9Schristos } 152d6743f02Sderaadt globfree(&gl); 15361f28255Scgd } 15461f28255Scgd gargv[gargc] = NULL; 15561f28255Scgd 1564b2b2847Slukem isls = (strcmp(gargv[0], INTERNAL_LS) == 0); 15725cf35a4Slukem 15825cf35a4Slukem pid = isls ? fork() : vfork(); 15925cf35a4Slukem switch (pid) { 16061f28255Scgd case -1: /* error */ 16161f28255Scgd (void)close(pdes[0]); 16261f28255Scgd (void)close(pdes[1]); 16361f28255Scgd goto pfree; 16461f28255Scgd /* NOTREACHED */ 16561f28255Scgd case 0: /* child */ 16661f28255Scgd if (*type == 'r') { 167d6743f02Sderaadt if (pdes[1] != STDOUT_FILENO) { 168d6743f02Sderaadt dup2(pdes[1], STDOUT_FILENO); 16961f28255Scgd (void)close(pdes[1]); 17061f28255Scgd } 1719c9d43e6Slukem if (stderrfd == -1) 17231547ec6Slukem (void)close(STDERR_FILENO); 1739c9d43e6Slukem else 1749c9d43e6Slukem dup2(stderrfd, STDERR_FILENO); 17561f28255Scgd (void)close(pdes[0]); 17661f28255Scgd } else { 177d6743f02Sderaadt if (pdes[0] != STDIN_FILENO) { 178d6743f02Sderaadt dup2(pdes[0], STDIN_FILENO); 17961f28255Scgd (void)close(pdes[0]); 18061f28255Scgd } 18161f28255Scgd (void)close(pdes[1]); 18261f28255Scgd } 18325cf35a4Slukem if (isls) { /* use internal ls */ 18425cf35a4Slukem optreset = optind = optopt = 1; 18525cf35a4Slukem closelog(); 18625cf35a4Slukem exit(ls_main(gargc, gargv)); 18725cf35a4Slukem } 18861f28255Scgd execv(gargv[0], gargv); 18961f28255Scgd _exit(1); 19061f28255Scgd } 19161f28255Scgd /* parent; assume fdopen can't fail... */ 19261f28255Scgd if (*type == 'r') { 19361f28255Scgd iop = fdopen(pdes[0], type); 19461f28255Scgd (void)close(pdes[1]); 19561f28255Scgd } else { 19661f28255Scgd iop = fdopen(pdes[1], type); 19761f28255Scgd (void)close(pdes[0]); 19861f28255Scgd } 19961f28255Scgd pids[fileno(iop)] = pid; 20061f28255Scgd 2012424c4f9Schristos pfree: if (gargv) { 2022424c4f9Schristos for (argc = 1; argc < gargc; argc++) 203d6743f02Sderaadt free(gargv[argc]); 2042424c4f9Schristos free(gargv); 2052424c4f9Schristos } 2062424c4f9Schristos if (argv) 2072424c4f9Schristos free(argv); 208d6743f02Sderaadt 20961f28255Scgd return (iop); 21061f28255Scgd } 21161f28255Scgd 212d6743f02Sderaadt int 21361f28255Scgd ftpd_pclose(iop) 21461f28255Scgd FILE *iop; 21561f28255Scgd { 21666783f1fSlukem int fdes, status; 217d6743f02Sderaadt pid_t pid; 218ebeae88dSmycroft sigset_t sigset, osigset; 21961f28255Scgd 22061f28255Scgd /* 22161f28255Scgd * pclose returns -1 if stream is not associated with a 22261f28255Scgd * `popened' command, or, if already `pclosed'. 22361f28255Scgd */ 22461f28255Scgd if (pids == 0 || pids[fdes = fileno(iop)] == 0) 22561f28255Scgd return (-1); 22661f28255Scgd (void)fclose(iop); 227ebeae88dSmycroft sigemptyset(&sigset); 228ebeae88dSmycroft sigaddset(&sigset, SIGINT); 229ebeae88dSmycroft sigaddset(&sigset, SIGQUIT); 230ebeae88dSmycroft sigaddset(&sigset, SIGHUP); 231ebeae88dSmycroft sigprocmask(SIG_BLOCK, &sigset, &osigset); 232d6743f02Sderaadt while ((pid = waitpid(pids[fdes], &status, 0)) < 0 && errno == EINTR) 233d6743f02Sderaadt continue; 234ebeae88dSmycroft sigprocmask(SIG_SETMASK, &osigset, NULL); 23561f28255Scgd pids[fdes] = 0; 236d6743f02Sderaadt if (pid < 0) 237d6743f02Sderaadt return (pid); 238d6743f02Sderaadt if (WIFEXITED(status)) 239d6743f02Sderaadt return (WEXITSTATUS(status)); 240d6743f02Sderaadt return (1); 24161f28255Scgd } 242