1235267Sgabor/* 2330449Seadler * Copyright (c) 1988, 1993, 1994 3330449Seadler * The Regents of the University of California. All rights reserved. 4235267Sgabor * 5251245Sgabor * This code is derived from software written by Ken Arnold and 6235267Sgabor * published in UNIX Review, Vol. 6, No. 8. 7235267Sgabor * 8235267Sgabor * Redistribution and use in source and binary forms, with or without 9235267Sgabor * modification, are permitted provided that the following conditions 10235267Sgabor * are met: 11235267Sgabor * 1. Redistributions of source code must retain the above copyright 12235267Sgabor * notice, this list of conditions and the following disclaimer. 13235267Sgabor * 2. Redistributions in binary form must reproduce the above copyright 14235267Sgabor * notice, this list of conditions and the following disclaimer in the 15235267Sgabor * documentation and/or other materials provided with the distribution. 16235267Sgabor * 3. All advertising materials mentioning features or use of this software 17235267Sgabor * must display the following acknowledgement: 18235267Sgabor * This product includes software developed by the University of 19235267Sgabor * California, Berkeley and its contributors. 20235267Sgabor * 4. Neither the name of the University nor the names of its contributors 21235267Sgabor * may be used to endorse or promote products derived from this software 22235267Sgabor * without specific prior written permission. 23235267Sgabor * 24235267Sgabor * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25235267Sgabor * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26235267Sgabor * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27235267Sgabor * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28235267Sgabor * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29235267Sgabor * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30235267Sgabor * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31235267Sgabor * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32235267Sgabor * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33235267Sgabor * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34235267Sgabor * SUCH DAMAGE. 35235267Sgabor */ 36235267Sgabor 37235267Sgabor#ifndef lint 38235267Sgabor#if 0 39235267Sgaborstatic char sccsid[] = "@(#)popen.c 8.3 (Berkeley) 4/6/94"; 40235267Sgabor#endif 41235267Sgabor#endif /* not lint */ 42235267Sgabor 43235267Sgabor#include <sys/cdefs.h> 44235267Sgabor__FBSDID("$FreeBSD: src/libexec/ftpd/popen.c,v 1.26 2004/11/18 13:46:29 yar Exp $"); 45235267Sgabor 46235267Sgabor#include <sys/types.h> 47235267Sgabor#include <sys/wait.h> 48235267Sgabor#include <netinet/in.h> 49235435Sgabor 50235267Sgabor#include <errno.h> 51235267Sgabor#include <glob.h> 52242430Sgabor#include <signal.h> 53235267Sgabor#include <stdio.h> 54242430Sgabor#include <stdlib.h> 55242430Sgabor#include <string.h> 56242430Sgabor#include <unistd.h> 57235267Sgabor 58235267Sgabor#include "extern.h" 59235267Sgabor#include "pathnames.h" 60235267Sgabor#include <syslog.h> 61235267Sgabor#include <time.h> 62235267Sgabor 63235267Sgabor#define MAXUSRARGS 100 64235267Sgabor#define MAXGLOBARGS 1000 65235267Sgabor 66235267Sgabor/* 67235267Sgabor * Special version of popen which avoids call to shell. This ensures noone 68235267Sgabor * may create a pipe to a hidden program as a side effect of a list or dir 69235267Sgabor * command. 70235267Sgabor */ 71235267Sgaborstatic int *pids; 72235267Sgaborstatic int fds; 73235267Sgabor 74235267SgaborFILE * 75235267Sgaborftpd_popen(char *program, char *type) 76235267Sgabor{ 77235267Sgabor char *cp; 78235267Sgabor FILE *iop; 79235267Sgabor int argc, gargc, pdes[2], pid; 80235267Sgabor char **pop, *argv[MAXUSRARGS], *gargv[MAXGLOBARGS]; 81235267Sgabor 82235267Sgabor if (((*type != 'r') && (*type != 'w')) || type[1]) 83281123Spfg return (NULL); 84235267Sgabor 85235267Sgabor if (!pids) { 86235267Sgabor if ((fds = getdtablesize()) <= 0) 87235267Sgabor return (NULL); 88235267Sgabor if ((pids = calloc(fds, sizeof(int))) == NULL) 89235267Sgabor return (NULL); 90235267Sgabor } 91235267Sgabor if (pipe(pdes) < 0) 92235267Sgabor return (NULL); 93235267Sgabor 94235267Sgabor /* break up string into pieces */ 95235267Sgabor for (argc = 0, cp = program; argc < MAXUSRARGS; cp = NULL) { 96235267Sgabor if (!(argv[argc++] = strtok(cp, " \t\n"))) 97235267Sgabor break; 98281132Spfg } 99235267Sgabor argv[argc - 1] = NULL; 100235267Sgabor 101235267Sgabor /* glob each piece */ 102235267Sgabor gargv[0] = argv[0]; 103235267Sgabor for (gargc = argc = 1; argv[argc] && gargc < (MAXGLOBARGS-1); argc++) { 104235267Sgabor glob_t gl; 105235267Sgabor int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE; 106235267Sgabor 107235267Sgabor memset(&gl, 0, sizeof(gl)); 108281132Spfg gl.gl_matchc = MAXGLOBARGS; 109235267Sgabor flags |= GLOB_LIMIT; 110318153Smarius if (glob(argv[argc], flags, NULL, &gl)) 111318153Smarius gargv[gargc++] = strdup(argv[argc]); 112318153Smarius else if (gl.gl_pathc > 0) { 113318153Smarius for (pop = gl.gl_pathv; *pop && gargc < (MAXGLOBARGS-1); 114318153Smarius pop++) 115318153Smarius gargv[gargc++] = strdup(*pop); 116318153Smarius } 117235267Sgabor globfree(&gl); 118235267Sgabor } 119235267Sgabor gargv[gargc] = NULL; 120235267Sgabor 121235267Sgabor iop = NULL; 122318153Smarius fflush(NULL); 123318153Smarius#ifdef BUILTIN_LS 124318153Smarius pid = (strcmp(gargv[0], _PATH_LS) == 0) ? fork() : vfork(); 125318153Smarius#else 126318153Smarius pid = fork(); 127318153Smarius#endif 128318153Smarius switch(pid) { 129318153Smarius case -1: /* error */ 130318153Smarius (void)close(pdes[0]); 131318153Smarius (void)close(pdes[1]); 132318153Smarius goto pfree; 133235267Sgabor /* NOTREACHED */ 134235267Sgabor case 0: /* child */ 135235267Sgabor if (*type == 'r') { 136235267Sgabor if (pdes[1] != STDOUT_FILENO) { 137235267Sgabor dup2(pdes[1], STDOUT_FILENO); 138281132Spfg (void)close(pdes[1]); 139235267Sgabor } 140235267Sgabor dup2(STDOUT_FILENO, STDERR_FILENO); /* stderr too! */ 141235267Sgabor (void)close(pdes[0]); 142318153Smarius } else { 143235267Sgabor if (pdes[0] != STDIN_FILENO) { 144235267Sgabor dup2(pdes[0], STDIN_FILENO); 145235267Sgabor (void)close(pdes[0]); 146235267Sgabor } 147235267Sgabor (void)close(pdes[1]); 148235267Sgabor } 149235267Sgabor#ifdef BUILTIN_LS 150235267Sgabor if (strcmp(gargv[0], _PATH_LS) == 0) { 151235267Sgabor /* Reset getopt for ls_main() */ 152235267Sgabor optreset = optind = optopt = 1; 153235267Sgabor /* Close syslogging to remove pwd.db missing msgs */ 154235267Sgabor closelog(); 155235267Sgabor /* Trigger to sense new /etc/localtime after chroot */ 156235267Sgabor if (getenv("TZ") == NULL) { 157235267Sgabor setenv("TZ", "", 0); 158235267Sgabor tzset(); 159235267Sgabor unsetenv("TZ"); 160235267Sgabor tzset(); 161235267Sgabor } 162235267Sgabor exit(ls_main(gargc, gargv)); 163235267Sgabor } 164235267Sgabor#endif 165235267Sgabor execv(gargv[0], gargv); 166235267Sgabor _exit(1); 167235267Sgabor } 168235267Sgabor /* parent; assume fdopen can't fail... */ 169235267Sgabor if (*type == 'r') { 170235267Sgabor iop = fdopen(pdes[0], type); 171235267Sgabor (void)close(pdes[1]); 172235267Sgabor } else { 173235267Sgabor iop = fdopen(pdes[1], type); 174235267Sgabor (void)close(pdes[0]); 175235267Sgabor } 176318153Smarius pids[fileno(iop)] = pid; 177235267Sgabor 178318153Smariuspfree: for (argc = 1; gargv[argc] != NULL; argc++) 179235267Sgabor free(gargv[argc]); 180235267Sgabor 181235267Sgabor return (iop); 182235267Sgabor} 183235267Sgabor 184235267Sgaborint 185235267Sgaborftpd_pclose(FILE *iop) 186235267Sgabor{ 187235267Sgabor int fdes, omask, status; 188235267Sgabor pid_t pid; 189235267Sgabor 190235267Sgabor /* 191235267Sgabor * pclose returns -1 if stream is not associated with a 192235267Sgabor * `popened' command, or, if already `pclosed'. 193281132Spfg */ 194235267Sgabor if (pids == NULL || pids[fdes = fileno(iop)] == 0) 195235267Sgabor return (-1); 196235267Sgabor (void)fclose(iop); 197235267Sgabor omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP)); 198235267Sgabor while ((pid = waitpid(pids[fdes], &status, 0)) < 0 && errno == EINTR) 199235267Sgabor continue; 200235267Sgabor (void)sigsetmask(omask); 201235267Sgabor pids[fdes] = 0; 202235267Sgabor if (pid < 0) 203235267Sgabor return (pid); 204281132Spfg if (WIFEXITED(status)) 205235267Sgabor return (WEXITSTATUS(status)); 206235267Sgabor return (1); 207235267Sgabor} 208235267Sgabor