1*04819365SAxel Dörfler /* 2*04819365SAxel Dörfler * Copyright (c) 1988, 1993, 1994 3*04819365SAxel Dörfler * The Regents of the University of California. All rights reserved. 4*04819365SAxel Dörfler * 5*04819365SAxel Dörfler * This code is derived from software written by Ken Arnold and 6*04819365SAxel Dörfler * published in UNIX Review, Vol. 6, No. 8. 7*04819365SAxel Dörfler * 8*04819365SAxel Dörfler * Redistribution and use in source and binary forms, with or without 9*04819365SAxel Dörfler * modification, are permitted provided that the following conditions 10*04819365SAxel Dörfler * are met: 11*04819365SAxel Dörfler * 1. Redistributions of source code must retain the above copyright 12*04819365SAxel Dörfler * notice, this list of conditions and the following disclaimer. 13*04819365SAxel Dörfler * 2. Redistributions in binary form must reproduce the above copyright 14*04819365SAxel Dörfler * notice, this list of conditions and the following disclaimer in the 15*04819365SAxel Dörfler * documentation and/or other materials provided with the distribution. 16*04819365SAxel Dörfler * 3. All advertising materials mentioning features or use of this software 17*04819365SAxel Dörfler * must display the following acknowledgement: 18*04819365SAxel Dörfler * This product includes software developed by the University of 19*04819365SAxel Dörfler * California, Berkeley and its contributors. 20*04819365SAxel Dörfler * 4. Neither the name of the University nor the names of its contributors 21*04819365SAxel Dörfler * may be used to endorse or promote products derived from this software 22*04819365SAxel Dörfler * without specific prior written permission. 23*04819365SAxel Dörfler * 24*04819365SAxel Dörfler * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25*04819365SAxel Dörfler * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26*04819365SAxel Dörfler * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27*04819365SAxel Dörfler * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28*04819365SAxel Dörfler * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29*04819365SAxel Dörfler * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30*04819365SAxel Dörfler * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31*04819365SAxel Dörfler * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32*04819365SAxel Dörfler * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33*04819365SAxel Dörfler * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34*04819365SAxel Dörfler * SUCH DAMAGE. 35*04819365SAxel Dörfler */ 36*04819365SAxel Dörfler 37*04819365SAxel Dörfler #ifndef lint 38*04819365SAxel Dörfler #if 0 39*04819365SAxel Dörfler static char sccsid[] = "@(#)popen.c 8.3 (Berkeley) 4/6/94"; 40*04819365SAxel Dörfler #endif 41*04819365SAxel Dörfler #endif /* not lint */ 42*04819365SAxel Dörfler 43*04819365SAxel Dörfler #include <sys/cdefs.h> 44*04819365SAxel Dörfler __FBSDID("$FreeBSD: src/libexec/ftpd/popen.c,v 1.26 2004/11/18 13:46:29 yar Exp $"); 45*04819365SAxel Dörfler 46*04819365SAxel Dörfler #include <sys/types.h> 47*04819365SAxel Dörfler #include <sys/wait.h> 48*04819365SAxel Dörfler #include <netinet/in.h> 49*04819365SAxel Dörfler 50*04819365SAxel Dörfler #include <errno.h> 51*04819365SAxel Dörfler #include <glob.h> 52*04819365SAxel Dörfler #include <signal.h> 53*04819365SAxel Dörfler #include <stdio.h> 54*04819365SAxel Dörfler #include <stdlib.h> 55*04819365SAxel Dörfler #include <string.h> 56*04819365SAxel Dörfler #include <unistd.h> 57*04819365SAxel Dörfler 58*04819365SAxel Dörfler #include "extern.h" 59*04819365SAxel Dörfler #include "pathnames.h" 60*04819365SAxel Dörfler #include <syslog.h> 61*04819365SAxel Dörfler #include <time.h> 62*04819365SAxel Dörfler 63*04819365SAxel Dörfler #define MAXUSRARGS 100 64*04819365SAxel Dörfler #define MAXGLOBARGS 1000 65*04819365SAxel Dörfler 66*04819365SAxel Dörfler /* 67*04819365SAxel Dörfler * Special version of popen which avoids call to shell. This ensures noone 68*04819365SAxel Dörfler * may create a pipe to a hidden program as a side effect of a list or dir 69*04819365SAxel Dörfler * command. 70*04819365SAxel Dörfler */ 71*04819365SAxel Dörfler static int *pids; 72*04819365SAxel Dörfler static int fds; 73*04819365SAxel Dörfler 74*04819365SAxel Dörfler FILE * 75*04819365SAxel Dörfler ftpd_popen(char *program, char *type) 76*04819365SAxel Dörfler { 77*04819365SAxel Dörfler char *cp; 78*04819365SAxel Dörfler FILE *iop; 79*04819365SAxel Dörfler int argc, gargc, pdes[2], pid; 80*04819365SAxel Dörfler char **pop, *argv[MAXUSRARGS], *gargv[MAXGLOBARGS]; 81*04819365SAxel Dörfler 82*04819365SAxel Dörfler if (((*type != 'r') && (*type != 'w')) || type[1]) 83*04819365SAxel Dörfler return (NULL); 84*04819365SAxel Dörfler 85*04819365SAxel Dörfler if (!pids) { 86*04819365SAxel Dörfler if ((fds = getdtablesize()) <= 0) 87*04819365SAxel Dörfler return (NULL); 88*04819365SAxel Dörfler if ((pids = malloc(fds * sizeof(int))) == NULL) 89*04819365SAxel Dörfler return (NULL); 90*04819365SAxel Dörfler memset(pids, 0, fds * sizeof(int)); 91*04819365SAxel Dörfler } 92*04819365SAxel Dörfler if (pipe(pdes) < 0) 93*04819365SAxel Dörfler return (NULL); 94*04819365SAxel Dörfler 95*04819365SAxel Dörfler /* break up string into pieces */ 96*04819365SAxel Dörfler for (argc = 0, cp = program; argc < MAXUSRARGS; cp = NULL) { 97*04819365SAxel Dörfler if (!(argv[argc++] = strtok(cp, " \t\n"))) 98*04819365SAxel Dörfler break; 99*04819365SAxel Dörfler } 100*04819365SAxel Dörfler argv[argc - 1] = NULL; 101*04819365SAxel Dörfler 102*04819365SAxel Dörfler /* glob each piece */ 103*04819365SAxel Dörfler gargv[0] = argv[0]; 104*04819365SAxel Dörfler for (gargc = argc = 1; argv[argc] && gargc < (MAXGLOBARGS-1); argc++) { 105*04819365SAxel Dörfler glob_t gl; 106*04819365SAxel Dörfler int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE; 107*04819365SAxel Dörfler 108*04819365SAxel Dörfler memset(&gl, 0, sizeof(gl)); 109*04819365SAxel Dörfler gl.gl_matchc = MAXGLOBARGS; 110*04819365SAxel Dörfler flags |= GLOB_LIMIT; 111*04819365SAxel Dörfler if (glob(argv[argc], flags, NULL, &gl)) 112*04819365SAxel Dörfler gargv[gargc++] = strdup(argv[argc]); 113*04819365SAxel Dörfler else 114*04819365SAxel Dörfler for (pop = gl.gl_pathv; *pop && gargc < (MAXGLOBARGS-1); 115*04819365SAxel Dörfler pop++) 116*04819365SAxel Dörfler gargv[gargc++] = strdup(*pop); 117*04819365SAxel Dörfler globfree(&gl); 118*04819365SAxel Dörfler } 119*04819365SAxel Dörfler gargv[gargc] = NULL; 120*04819365SAxel Dörfler 121*04819365SAxel Dörfler iop = NULL; 122*04819365SAxel Dörfler fflush(NULL); 123*04819365SAxel Dörfler #ifdef BUILTIN_LS 124*04819365SAxel Dörfler pid = (strcmp(gargv[0], _PATH_LS) == 0) ? fork() : vfork(); 125*04819365SAxel Dörfler #else 126*04819365SAxel Dörfler pid = fork(); 127*04819365SAxel Dörfler #endif 128*04819365SAxel Dörfler switch(pid) { 129*04819365SAxel Dörfler case -1: /* error */ 130*04819365SAxel Dörfler (void)close(pdes[0]); 131*04819365SAxel Dörfler (void)close(pdes[1]); 132*04819365SAxel Dörfler goto pfree; 133*04819365SAxel Dörfler /* NOTREACHED */ 134*04819365SAxel Dörfler case 0: /* child */ 135*04819365SAxel Dörfler if (*type == 'r') { 136*04819365SAxel Dörfler if (pdes[1] != STDOUT_FILENO) { 137*04819365SAxel Dörfler dup2(pdes[1], STDOUT_FILENO); 138*04819365SAxel Dörfler (void)close(pdes[1]); 139*04819365SAxel Dörfler } 140*04819365SAxel Dörfler dup2(STDOUT_FILENO, STDERR_FILENO); /* stderr too! */ 141*04819365SAxel Dörfler (void)close(pdes[0]); 142*04819365SAxel Dörfler } else { 143*04819365SAxel Dörfler if (pdes[0] != STDIN_FILENO) { 144*04819365SAxel Dörfler dup2(pdes[0], STDIN_FILENO); 145*04819365SAxel Dörfler (void)close(pdes[0]); 146*04819365SAxel Dörfler } 147*04819365SAxel Dörfler (void)close(pdes[1]); 148*04819365SAxel Dörfler } 149*04819365SAxel Dörfler #ifdef BUILTIN_LS 150*04819365SAxel Dörfler if (strcmp(gargv[0], _PATH_LS) == 0) { 151*04819365SAxel Dörfler /* Reset getopt for ls_main() */ 152*04819365SAxel Dörfler optreset = optind = optopt = 1; 153*04819365SAxel Dörfler /* Close syslogging to remove pwd.db missing msgs */ 154*04819365SAxel Dörfler closelog(); 155*04819365SAxel Dörfler /* Trigger to sense new /etc/localtime after chroot */ 156*04819365SAxel Dörfler if (getenv("TZ") == NULL) { 157*04819365SAxel Dörfler setenv("TZ", "", 0); 158*04819365SAxel Dörfler tzset(); 159*04819365SAxel Dörfler unsetenv("TZ"); 160*04819365SAxel Dörfler tzset(); 161*04819365SAxel Dörfler } 162*04819365SAxel Dörfler exit(ls_main(gargc, gargv)); 163*04819365SAxel Dörfler } 164*04819365SAxel Dörfler #endif 165*04819365SAxel Dörfler execv(gargv[0], gargv); 166*04819365SAxel Dörfler _exit(1); 167*04819365SAxel Dörfler } 168*04819365SAxel Dörfler /* parent; assume fdopen can't fail... */ 169*04819365SAxel Dörfler if (*type == 'r') { 170*04819365SAxel Dörfler iop = fdopen(pdes[0], type); 171*04819365SAxel Dörfler (void)close(pdes[1]); 172*04819365SAxel Dörfler } else { 173*04819365SAxel Dörfler iop = fdopen(pdes[1], type); 174*04819365SAxel Dörfler (void)close(pdes[0]); 175*04819365SAxel Dörfler } 176*04819365SAxel Dörfler pids[fileno(iop)] = pid; 177*04819365SAxel Dörfler 178*04819365SAxel Dörfler pfree: for (argc = 1; gargv[argc] != NULL; argc++) 179*04819365SAxel Dörfler free(gargv[argc]); 180*04819365SAxel Dörfler 181*04819365SAxel Dörfler return (iop); 182*04819365SAxel Dörfler } 183*04819365SAxel Dörfler 184*04819365SAxel Dörfler int 185*04819365SAxel Dörfler ftpd_pclose(FILE *iop) 186*04819365SAxel Dörfler { 187*04819365SAxel Dörfler int fdes, omask, status; 188*04819365SAxel Dörfler pid_t pid; 189*04819365SAxel Dörfler 190*04819365SAxel Dörfler /* 191*04819365SAxel Dörfler * pclose returns -1 if stream is not associated with a 192*04819365SAxel Dörfler * `popened' command, or, if already `pclosed'. 193*04819365SAxel Dörfler */ 194*04819365SAxel Dörfler if (pids == 0 || pids[fdes = fileno(iop)] == 0) 195*04819365SAxel Dörfler return (-1); 196*04819365SAxel Dörfler (void)fclose(iop); 197*04819365SAxel Dörfler omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP)); 198*04819365SAxel Dörfler while ((pid = waitpid(pids[fdes], &status, 0)) < 0 && errno == EINTR) 199*04819365SAxel Dörfler continue; 200*04819365SAxel Dörfler (void)sigsetmask(omask); 201*04819365SAxel Dörfler pids[fdes] = 0; 202*04819365SAxel Dörfler if (pid < 0) 203*04819365SAxel Dörfler return (pid); 204*04819365SAxel Dörfler if (WIFEXITED(status)) 205*04819365SAxel Dörfler return (WEXITSTATUS(status)); 206*04819365SAxel Dörfler return (1); 207*04819365SAxel Dörfler } 208