1b528cefcSMark Murray /* 2b528cefcSMark Murray * Copyright (c) 1988, 1993, 1994 3b528cefcSMark Murray * The Regents of the University of California. All rights reserved. 4b528cefcSMark Murray * 5b528cefcSMark Murray * This code is derived from software written by Ken Arnold and 6b528cefcSMark Murray * published in UNIX Review, Vol. 6, No. 8. 7b528cefcSMark Murray * 8b528cefcSMark Murray * Redistribution and use in source and binary forms, with or without 9b528cefcSMark Murray * modification, are permitted provided that the following conditions 10b528cefcSMark Murray * are met: 11b528cefcSMark Murray * 1. Redistributions of source code must retain the above copyright 12b528cefcSMark Murray * notice, this list of conditions and the following disclaimer. 13b528cefcSMark Murray * 2. Redistributions in binary form must reproduce the above copyright 14b528cefcSMark Murray * notice, this list of conditions and the following disclaimer in the 15b528cefcSMark Murray * documentation and/or other materials provided with the distribution. 16b528cefcSMark Murray * 3. All advertising materials mentioning features or use of this software 17b528cefcSMark Murray * must display the following acknowledgement: 18b528cefcSMark Murray * This product includes software developed by the University of 19b528cefcSMark Murray * California, Berkeley and its contributors. 20b528cefcSMark Murray * 4. Neither the name of the University nor the names of its contributors 21b528cefcSMark Murray * may be used to endorse or promote products derived from this software 22b528cefcSMark Murray * without specific prior written permission. 23b528cefcSMark Murray * 24b528cefcSMark Murray * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25b528cefcSMark Murray * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26b528cefcSMark Murray * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27b528cefcSMark Murray * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28b528cefcSMark Murray * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29b528cefcSMark Murray * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30b528cefcSMark Murray * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31b528cefcSMark Murray * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32b528cefcSMark Murray * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33b528cefcSMark Murray * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34b528cefcSMark Murray * SUCH DAMAGE. 35b528cefcSMark Murray * 36b528cefcSMark Murray */ 37b528cefcSMark Murray 38b528cefcSMark Murray #ifdef HAVE_CONFIG_H 39b528cefcSMark Murray #include <config.h> 405e9cd1aeSAssar Westerlund RCSID("$Id: popen.c,v 1.22 2001/02/05 07:51:51 assar Exp $"); 41b528cefcSMark Murray #endif 42b528cefcSMark Murray 43b528cefcSMark Murray #include <sys/types.h> 44b528cefcSMark Murray #ifdef TIME_WITH_SYS_TIME 45b528cefcSMark Murray #include <sys/time.h> 46b528cefcSMark Murray #include <time.h> 47b528cefcSMark Murray #elif defined(HAVE_SYS_TIME_H) 48b528cefcSMark Murray #include <sys/time.h> 49b528cefcSMark Murray #else 50b528cefcSMark Murray #include <time.h> 51b528cefcSMark Murray #endif 52b528cefcSMark Murray #ifdef HAVE_SYS_RESOURCE_H 53b528cefcSMark Murray #include <sys/resource.h> 54b528cefcSMark Murray #endif 55b528cefcSMark Murray #include <sys/wait.h> 56b528cefcSMark Murray 57b528cefcSMark Murray #include <errno.h> 58b528cefcSMark Murray #include <glob.h> 59b528cefcSMark Murray #include <signal.h> 60b528cefcSMark Murray #include <stdio.h> 61b528cefcSMark Murray #include <stdlib.h> 62b528cefcSMark Murray #include <string.h> 63b528cefcSMark Murray #include <unistd.h> 645e9cd1aeSAssar Westerlund #include <roken.h> 65b528cefcSMark Murray #include "extern.h" 66b528cefcSMark Murray 67b528cefcSMark Murray 68b528cefcSMark Murray /* 69b528cefcSMark Murray * Special version of popen which avoids call to shell. This ensures 70b528cefcSMark Murray * no one may create a pipe to a hidden program as a side effect of a 71b528cefcSMark Murray * list or dir command. 72b528cefcSMark Murray */ 73b528cefcSMark Murray static int *pids; 74b528cefcSMark Murray static int fds; 75b528cefcSMark Murray 76b528cefcSMark Murray extern int dochroot; 77b528cefcSMark Murray 78b528cefcSMark Murray /* return path prepended with ~ftp if that file exists, otherwise 79b528cefcSMark Murray * return path unchanged 80b528cefcSMark Murray */ 81b528cefcSMark Murray 82b528cefcSMark Murray const char * 83b528cefcSMark Murray ftp_rooted(const char *path) 84b528cefcSMark Murray { 85b528cefcSMark Murray static char home[MaxPathLen] = ""; 86b528cefcSMark Murray static char newpath[MaxPathLen]; 87b528cefcSMark Murray struct passwd *pwd; 88b528cefcSMark Murray 89b528cefcSMark Murray if(!home[0]) 90b528cefcSMark Murray if((pwd = k_getpwnam("ftp"))) 91b528cefcSMark Murray strlcpy(home, pwd->pw_dir, sizeof(home)); 92b528cefcSMark Murray snprintf(newpath, sizeof(newpath), "%s/%s", home, path); 93b528cefcSMark Murray if(access(newpath, X_OK)) 94b528cefcSMark Murray strlcpy(newpath, path, sizeof(newpath)); 95b528cefcSMark Murray return newpath; 96b528cefcSMark Murray } 97b528cefcSMark Murray 98b528cefcSMark Murray 995e9cd1aeSAssar Westerlund #define MAXARGS 100 1005e9cd1aeSAssar Westerlund #define MAXGLOBS 1000 1015e9cd1aeSAssar Westerlund 102b528cefcSMark Murray FILE * 103b528cefcSMark Murray ftpd_popen(char *program, char *type, int do_stderr, int no_glob) 104b528cefcSMark Murray { 105b528cefcSMark Murray char *cp; 106b528cefcSMark Murray FILE *iop; 107b528cefcSMark Murray int argc, gargc, pdes[2], pid; 1085e9cd1aeSAssar Westerlund char **pop, *argv[MAXARGS], *gargv[MAXGLOBS]; 109b528cefcSMark Murray char *foo; 110b528cefcSMark Murray 111b528cefcSMark Murray if (strcmp(type, "r") && strcmp(type, "w")) 112b528cefcSMark Murray return (NULL); 113b528cefcSMark Murray 114b528cefcSMark Murray if (!pids) { 115b528cefcSMark Murray 116b528cefcSMark Murray /* This function is ugly and should be rewritten, in 117b528cefcSMark Murray * modern unices there is no such thing as a maximum 118b528cefcSMark Murray * filedescriptor. 119b528cefcSMark Murray */ 120b528cefcSMark Murray 121b528cefcSMark Murray fds = getdtablesize(); 122b528cefcSMark Murray pids = (int*)calloc(fds, sizeof(int)); 123b528cefcSMark Murray if(!pids) 124b528cefcSMark Murray return NULL; 125b528cefcSMark Murray } 126b528cefcSMark Murray if (pipe(pdes) < 0) 127b528cefcSMark Murray return (NULL); 128b528cefcSMark Murray 129b528cefcSMark Murray /* break up string into pieces */ 130b528cefcSMark Murray foo = NULL; 1315e9cd1aeSAssar Westerlund for (argc = 0, cp = program; argc < MAXARGS - 1; cp = NULL) { 132b528cefcSMark Murray if (!(argv[argc++] = strtok_r(cp, " \t\n", &foo))) 133b528cefcSMark Murray break; 134b528cefcSMark Murray } 1355e9cd1aeSAssar Westerlund argv[MAXARGS - 1] = NULL; 136b528cefcSMark Murray 137b528cefcSMark Murray gargv[0] = (char*)ftp_rooted(argv[0]); 138b528cefcSMark Murray /* glob each piece */ 1395e9cd1aeSAssar Westerlund for (gargc = argc = 1; argv[argc] && gargc < MAXGLOBS - 1; argc++) { 140b528cefcSMark Murray glob_t gl; 141b528cefcSMark Murray int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE; 142b528cefcSMark Murray 143b528cefcSMark Murray memset(&gl, 0, sizeof(gl)); 144b528cefcSMark Murray if (no_glob || glob(argv[argc], flags, NULL, &gl)) 145b528cefcSMark Murray gargv[gargc++] = strdup(argv[argc]); 146b528cefcSMark Murray else 1475e9cd1aeSAssar Westerlund for (pop = gl.gl_pathv; 1485e9cd1aeSAssar Westerlund *pop && gargc < MAXGLOBS - 1; 1495e9cd1aeSAssar Westerlund pop++) 150b528cefcSMark Murray gargv[gargc++] = strdup(*pop); 151b528cefcSMark Murray globfree(&gl); 152b528cefcSMark Murray } 153b528cefcSMark Murray gargv[gargc] = NULL; 154b528cefcSMark Murray 155b528cefcSMark Murray iop = NULL; 156b528cefcSMark Murray switch(pid = fork()) { 157b528cefcSMark Murray case -1: /* error */ 158b528cefcSMark Murray close(pdes[0]); 159b528cefcSMark Murray close(pdes[1]); 160b528cefcSMark Murray goto pfree; 161b528cefcSMark Murray /* NOTREACHED */ 162b528cefcSMark Murray case 0: /* child */ 163b528cefcSMark Murray if (*type == 'r') { 164b528cefcSMark Murray if (pdes[1] != STDOUT_FILENO) { 165b528cefcSMark Murray dup2(pdes[1], STDOUT_FILENO); 166b528cefcSMark Murray close(pdes[1]); 167b528cefcSMark Murray } 168b528cefcSMark Murray if(do_stderr) 169b528cefcSMark Murray dup2(STDOUT_FILENO, STDERR_FILENO); 170b528cefcSMark Murray close(pdes[0]); 171b528cefcSMark Murray } else { 172b528cefcSMark Murray if (pdes[0] != STDIN_FILENO) { 173b528cefcSMark Murray dup2(pdes[0], STDIN_FILENO); 174b528cefcSMark Murray close(pdes[0]); 175b528cefcSMark Murray } 176b528cefcSMark Murray close(pdes[1]); 177b528cefcSMark Murray } 178b528cefcSMark Murray execv(gargv[0], gargv); 179b528cefcSMark Murray gargv[0] = argv[0]; 180b528cefcSMark Murray execv(gargv[0], gargv); 181b528cefcSMark Murray _exit(1); 182b528cefcSMark Murray } 183b528cefcSMark Murray /* parent; assume fdopen can't fail... */ 184b528cefcSMark Murray if (*type == 'r') { 185b528cefcSMark Murray iop = fdopen(pdes[0], type); 186b528cefcSMark Murray close(pdes[1]); 187b528cefcSMark Murray } else { 188b528cefcSMark Murray iop = fdopen(pdes[1], type); 189b528cefcSMark Murray close(pdes[0]); 190b528cefcSMark Murray } 191b528cefcSMark Murray pids[fileno(iop)] = pid; 192b528cefcSMark Murray 193b528cefcSMark Murray pfree: 194b528cefcSMark Murray for (argc = 1; gargv[argc] != NULL; argc++) 195b528cefcSMark Murray free(gargv[argc]); 196b528cefcSMark Murray 197b528cefcSMark Murray 198b528cefcSMark Murray return (iop); 199b528cefcSMark Murray } 200b528cefcSMark Murray 201b528cefcSMark Murray int 202b528cefcSMark Murray ftpd_pclose(FILE *iop) 203b528cefcSMark Murray { 204b528cefcSMark Murray int fdes, status; 205b528cefcSMark Murray pid_t pid; 206b528cefcSMark Murray sigset_t sigset, osigset; 207b528cefcSMark Murray 208b528cefcSMark Murray /* 209b528cefcSMark Murray * pclose returns -1 if stream is not associated with a 210b528cefcSMark Murray * `popened' command, or, if already `pclosed'. 211b528cefcSMark Murray */ 212b528cefcSMark Murray if (pids == 0 || pids[fdes = fileno(iop)] == 0) 213b528cefcSMark Murray return (-1); 214b528cefcSMark Murray fclose(iop); 215b528cefcSMark Murray sigemptyset(&sigset); 216b528cefcSMark Murray sigaddset(&sigset, SIGINT); 217b528cefcSMark Murray sigaddset(&sigset, SIGQUIT); 218b528cefcSMark Murray sigaddset(&sigset, SIGHUP); 219b528cefcSMark Murray sigprocmask(SIG_BLOCK, &sigset, &osigset); 220b528cefcSMark Murray while ((pid = waitpid(pids[fdes], &status, 0)) < 0 && errno == EINTR) 221b528cefcSMark Murray continue; 222b528cefcSMark Murray sigprocmask(SIG_SETMASK, &osigset, NULL); 223b528cefcSMark Murray pids[fdes] = 0; 224b528cefcSMark Murray if (pid < 0) 225b528cefcSMark Murray return (pid); 226b528cefcSMark Murray if (WIFEXITED(status)) 227b528cefcSMark Murray return (WEXITSTATUS(status)); 228b528cefcSMark Murray return (1); 229b528cefcSMark Murray } 230