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> 408373020dSJacques Vidrine RCSID("$Id: popen.c,v 1.26 2002/04/02 11:57:39 joda 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; 141adb0ddaeSAssar Westerlund int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE 1424137ff4cSJacques Vidrine | 1434137ff4cSJacques Vidrine #ifdef GLOB_MAXPATH 1444137ff4cSJacques Vidrine GLOB_MAXPATH 1454137ff4cSJacques Vidrine #else 1464137ff4cSJacques Vidrine GLOB_LIMIT 1474137ff4cSJacques Vidrine #endif 1484137ff4cSJacques Vidrine ; 149b528cefcSMark Murray 150b528cefcSMark Murray memset(&gl, 0, sizeof(gl)); 1518373020dSJacques Vidrine if (no_glob || 1528373020dSJacques Vidrine glob(argv[argc], flags, NULL, &gl) || 1538373020dSJacques Vidrine gl.gl_pathc == 0) 154b528cefcSMark Murray gargv[gargc++] = strdup(argv[argc]); 155b528cefcSMark Murray else 1565e9cd1aeSAssar Westerlund for (pop = gl.gl_pathv; 1575e9cd1aeSAssar Westerlund *pop && gargc < MAXGLOBS - 1; 1585e9cd1aeSAssar Westerlund pop++) 159b528cefcSMark Murray gargv[gargc++] = strdup(*pop); 160b528cefcSMark Murray globfree(&gl); 161b528cefcSMark Murray } 162b528cefcSMark Murray gargv[gargc] = NULL; 163b528cefcSMark Murray 164b528cefcSMark Murray iop = NULL; 165b528cefcSMark Murray switch(pid = fork()) { 166b528cefcSMark Murray case -1: /* error */ 167b528cefcSMark Murray close(pdes[0]); 168b528cefcSMark Murray close(pdes[1]); 169b528cefcSMark Murray goto pfree; 170b528cefcSMark Murray /* NOTREACHED */ 171b528cefcSMark Murray case 0: /* child */ 172b528cefcSMark Murray if (*type == 'r') { 173b528cefcSMark Murray if (pdes[1] != STDOUT_FILENO) { 174b528cefcSMark Murray dup2(pdes[1], STDOUT_FILENO); 175b528cefcSMark Murray close(pdes[1]); 176b528cefcSMark Murray } 177b528cefcSMark Murray if(do_stderr) 178b528cefcSMark Murray dup2(STDOUT_FILENO, STDERR_FILENO); 179b528cefcSMark Murray close(pdes[0]); 180b528cefcSMark Murray } else { 181b528cefcSMark Murray if (pdes[0] != STDIN_FILENO) { 182b528cefcSMark Murray dup2(pdes[0], STDIN_FILENO); 183b528cefcSMark Murray close(pdes[0]); 184b528cefcSMark Murray } 185b528cefcSMark Murray close(pdes[1]); 186b528cefcSMark Murray } 187b528cefcSMark Murray execv(gargv[0], gargv); 188b528cefcSMark Murray gargv[0] = argv[0]; 189b528cefcSMark Murray execv(gargv[0], gargv); 190b528cefcSMark Murray _exit(1); 191b528cefcSMark Murray } 192b528cefcSMark Murray /* parent; assume fdopen can't fail... */ 193b528cefcSMark Murray if (*type == 'r') { 194b528cefcSMark Murray iop = fdopen(pdes[0], type); 195b528cefcSMark Murray close(pdes[1]); 196b528cefcSMark Murray } else { 197b528cefcSMark Murray iop = fdopen(pdes[1], type); 198b528cefcSMark Murray close(pdes[0]); 199b528cefcSMark Murray } 200b528cefcSMark Murray pids[fileno(iop)] = pid; 201b528cefcSMark Murray 202b528cefcSMark Murray pfree: 203b528cefcSMark Murray for (argc = 1; gargv[argc] != NULL; argc++) 204b528cefcSMark Murray free(gargv[argc]); 205b528cefcSMark Murray 206b528cefcSMark Murray 207b528cefcSMark Murray return (iop); 208b528cefcSMark Murray } 209b528cefcSMark Murray 210b528cefcSMark Murray int 211b528cefcSMark Murray ftpd_pclose(FILE *iop) 212b528cefcSMark Murray { 213b528cefcSMark Murray int fdes, status; 214b528cefcSMark Murray pid_t pid; 215b528cefcSMark Murray sigset_t sigset, osigset; 216b528cefcSMark Murray 217b528cefcSMark Murray /* 218b528cefcSMark Murray * pclose returns -1 if stream is not associated with a 219b528cefcSMark Murray * `popened' command, or, if already `pclosed'. 220b528cefcSMark Murray */ 221b528cefcSMark Murray if (pids == 0 || pids[fdes = fileno(iop)] == 0) 222b528cefcSMark Murray return (-1); 223b528cefcSMark Murray fclose(iop); 224b528cefcSMark Murray sigemptyset(&sigset); 225b528cefcSMark Murray sigaddset(&sigset, SIGINT); 226b528cefcSMark Murray sigaddset(&sigset, SIGQUIT); 227b528cefcSMark Murray sigaddset(&sigset, SIGHUP); 228b528cefcSMark Murray sigprocmask(SIG_BLOCK, &sigset, &osigset); 229b528cefcSMark Murray while ((pid = waitpid(pids[fdes], &status, 0)) < 0 && errno == EINTR) 230b528cefcSMark Murray continue; 231b528cefcSMark Murray sigprocmask(SIG_SETMASK, &osigset, NULL); 232b528cefcSMark Murray pids[fdes] = 0; 233b528cefcSMark Murray if (pid < 0) 234b528cefcSMark Murray return (pid); 235b528cefcSMark Murray if (WIFEXITED(status)) 236b528cefcSMark Murray return (WEXITSTATUS(status)); 237b528cefcSMark Murray return (1); 238b528cefcSMark Murray } 239