popen.c revision 78527
1155228Smjacob/* 2155228Smjacob * Copyright (c) 1988, 1993, 1994 3196008Smjacob * The Regents of the University of California. All rights reserved. 4167403Smjacob * 5167403Smjacob * This code is derived from software written by Ken Arnold and 6167403Smjacob * published in UNIX Review, Vol. 6, No. 8. 7167403Smjacob * 8167403Smjacob * Redistribution and use in source and binary forms, with or without 9167403Smjacob * modification, are permitted provided that the following conditions 10167403Smjacob * are met: 11167403Smjacob * 1. Redistributions of source code must retain the above copyright 12167403Smjacob * notice, this list of conditions and the following disclaimer. 13167403Smjacob * 2. Redistributions in binary form must reproduce the above copyright 14167403Smjacob * notice, this list of conditions and the following disclaimer in the 15167403Smjacob * documentation and/or other materials provided with the distribution. 16167403Smjacob * 3. All advertising materials mentioning features or use of this software 17167403Smjacob * must display the following acknowledgement: 18167403Smjacob * This product includes software developed by the University of 19167403Smjacob * California, Berkeley and its contributors. 20167403Smjacob * 4. Neither the name of the University nor the names of its contributors 21167403Smjacob * may be used to endorse or promote products derived from this software 22167403Smjacob * without specific prior written permission. 23167403Smjacob * 24167403Smjacob * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25167403Smjacob * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26167403Smjacob * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27196008Smjacob * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28155228Smjacob * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29196008Smjacob * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30196008Smjacob * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31155228Smjacob * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32196008Smjacob * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33196008Smjacob * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34196008Smjacob * SUCH DAMAGE. 35196008Smjacob * 36196008Smjacob */ 37196008Smjacob 38196008Smjacob#ifdef HAVE_CONFIG_H 39238869Smjacob#include <config.h> 40155228SmjacobRCSID("$Id: popen.c,v 1.24 2001/03/26 11:41:02 assar Exp $"); 41196008Smjacob#endif 42196008Smjacob 43196008Smjacob#include <sys/types.h> 44196008Smjacob#ifdef TIME_WITH_SYS_TIME 45196008Smjacob#include <sys/time.h> 46203444Smjacob#include <time.h> 47196008Smjacob#elif defined(HAVE_SYS_TIME_H) 48196008Smjacob#include <sys/time.h> 49203444Smjacob#else 50196008Smjacob#include <time.h> 51168240Smjacob#endif 52196008Smjacob#ifdef HAVE_SYS_RESOURCE_H 53196008Smjacob#include <sys/resource.h> 54196008Smjacob#endif 55196008Smjacob#include <sys/wait.h> 56196008Smjacob 57196008Smjacob#include <errno.h> 58196008Smjacob#include <glob.h> 59196008Smjacob#include <signal.h> 60196008Smjacob#include <stdio.h> 61196008Smjacob#include <stdlib.h> 62196008Smjacob#include <string.h> 63196008Smjacob#include <unistd.h> 64196008Smjacob#include <roken.h> 65196008Smjacob#include "extern.h" 66196008Smjacob 67196008Smjacob 68196008Smjacob/* 69238869Smjacob * Special version of popen which avoids call to shell. This ensures 70196008Smjacob * no one may create a pipe to a hidden program as a side effect of a 71196008Smjacob * list or dir command. 72196008Smjacob */ 73196008Smjacobstatic int *pids; 74196008Smjacobstatic int fds; 75196008Smjacob 76196008Smjacobextern int dochroot; 77196008Smjacob 78196008Smjacob/* return path prepended with ~ftp if that file exists, otherwise 79196008Smjacob * return path unchanged 80196008Smjacob */ 81196008Smjacob 82196008Smjacobconst char * 83196008Smjacobftp_rooted(const char *path) 84196008Smjacob{ 85196008Smjacob static char home[MaxPathLen] = ""; 86196008Smjacob static char newpath[MaxPathLen]; 87196008Smjacob struct passwd *pwd; 88196008Smjacob 89196008Smjacob if(!home[0]) 90196008Smjacob if((pwd = k_getpwnam("ftp"))) 91196008Smjacob strlcpy(home, pwd->pw_dir, sizeof(home)); 92196008Smjacob snprintf(newpath, sizeof(newpath), "%s/%s", home, path); 93196008Smjacob if(access(newpath, X_OK)) 94196008Smjacob strlcpy(newpath, path, sizeof(newpath)); 95196008Smjacob return newpath; 96196008Smjacob} 97196008Smjacob 98196008Smjacob 99196008Smjacob#define MAXARGS 100 100196008Smjacob#define MAXGLOBS 1000 101196008Smjacob 102196008SmjacobFILE * 103196008Smjacobftpd_popen(char *program, char *type, int do_stderr, int no_glob) 104196008Smjacob{ 105196008Smjacob char *cp; 106196008Smjacob FILE *iop; 107196008Smjacob int argc, gargc, pdes[2], pid; 108196008Smjacob char **pop, *argv[MAXARGS], *gargv[MAXGLOBS]; 109196008Smjacob char *foo; 110238869Smjacob 111196008Smjacob if (strcmp(type, "r") && strcmp(type, "w")) 112196008Smjacob return (NULL); 113204397Smjacob 114196008Smjacob if (!pids) { 115196008Smjacob 116196008Smjacob /* This function is ugly and should be rewritten, in 117196008Smjacob * modern unices there is no such thing as a maximum 118196008Smjacob * filedescriptor. 119196008Smjacob */ 120196008Smjacob 121196008Smjacob fds = getdtablesize(); 122196008Smjacob pids = (int*)calloc(fds, sizeof(int)); 123196008Smjacob if(!pids) 124196008Smjacob return NULL; 125196008Smjacob } 126290104Smav if (pipe(pdes) < 0) 127290104Smav return (NULL); 128290104Smav 129290104Smav /* break up string into pieces */ 130196008Smjacob foo = NULL; 131196008Smjacob for (argc = 0, cp = program; argc < MAXARGS - 1; cp = NULL) { 132196008Smjacob if (!(argv[argc++] = strtok_r(cp, " \t\n", &foo))) 133196008Smjacob break; 134196008Smjacob } 135196008Smjacob argv[MAXARGS - 1] = NULL; 136196008Smjacob 137196008Smjacob gargv[0] = (char*)ftp_rooted(argv[0]); 138196008Smjacob /* glob each piece */ 139196008Smjacob for (gargc = argc = 1; argv[argc] && gargc < MAXGLOBS - 1; argc++) { 140196008Smjacob glob_t gl; 141196008Smjacob int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE 142196008Smjacob | GLOB_LIMIT; 143196008Smjacob 144196008Smjacob memset(&gl, 0, sizeof(gl)); 145196008Smjacob if (no_glob || glob(argv[argc], flags, NULL, &gl)) 146196008Smjacob gargv[gargc++] = strdup(argv[argc]); 147196008Smjacob else 148238869Smjacob for (pop = gl.gl_pathv; 149196008Smjacob *pop && gargc < MAXGLOBS - 1; 150196008Smjacob pop++) 151291000Smav gargv[gargc++] = strdup(*pop); 152196008Smjacob globfree(&gl); 153196008Smjacob } 154238869Smjacob gargv[gargc] = NULL; 155196008Smjacob 156196008Smjacob iop = NULL; 157196008Smjacob switch(pid = fork()) { 158196008Smjacob case -1: /* error */ 159196008Smjacob close(pdes[0]); 160155704Smjacob close(pdes[1]); 161196008Smjacob goto pfree; 162155228Smjacob /* NOTREACHED */ 163155704Smjacob case 0: /* child */ 164155704Smjacob if (*type == 'r') { 165155704Smjacob if (pdes[1] != STDOUT_FILENO) { 166155228Smjacob dup2(pdes[1], STDOUT_FILENO); 167196008Smjacob close(pdes[1]); 168155228Smjacob } 169203444Smjacob if(do_stderr) 170196008Smjacob dup2(STDOUT_FILENO, STDERR_FILENO); 171196008Smjacob close(pdes[0]); 172196008Smjacob } else { 173285459Smav if (pdes[0] != STDIN_FILENO) { 174291080Smav dup2(pdes[0], STDIN_FILENO); 175291080Smav close(pdes[0]); 176291080Smav } 177291080Smav close(pdes[1]); 178285459Smav } 179196008Smjacob execv(gargv[0], gargv); 180289838Smav gargv[0] = argv[0]; 181196008Smjacob execv(gargv[0], gargv); 182196008Smjacob _exit(1); 183196008Smjacob } 184196008Smjacob /* parent; assume fdopen can't fail... */ 185196008Smjacob if (*type == 'r') { 186196008Smjacob iop = fdopen(pdes[0], type); 187196008Smjacob close(pdes[1]); 188196008Smjacob } else { 189196008Smjacob iop = fdopen(pdes[1], type); 190196008Smjacob close(pdes[0]); 191196008Smjacob } 192196008Smjacob pids[fileno(iop)] = pid; 193196008Smjacob 194196008Smjacobpfree: 195196008Smjacob for (argc = 1; gargv[argc] != NULL; argc++) 196196008Smjacob free(gargv[argc]); 197196008Smjacob 198196008Smjacob 199196008Smjacob return (iop); 200196008Smjacob} 201196008Smjacob 202196008Smjacobint 203196008Smjacobftpd_pclose(FILE *iop) 204196008Smjacob{ 205196008Smjacob int fdes, status; 206196008Smjacob pid_t pid; 207196008Smjacob sigset_t sigset, osigset; 208196008Smjacob 209196008Smjacob /* 210196008Smjacob * pclose returns -1 if stream is not associated with a 211196008Smjacob * `popened' command, or, if already `pclosed'. 212196008Smjacob */ 213196008Smjacob if (pids == 0 || pids[fdes = fileno(iop)] == 0) 214196008Smjacob return (-1); 215196008Smjacob fclose(iop); 216196008Smjacob sigemptyset(&sigset); 217196008Smjacob sigaddset(&sigset, SIGINT); 218196008Smjacob sigaddset(&sigset, SIGQUIT); 219196008Smjacob sigaddset(&sigset, SIGHUP); 220196008Smjacob sigprocmask(SIG_BLOCK, &sigset, &osigset); 221196008Smjacob while ((pid = waitpid(pids[fdes], &status, 0)) < 0 && errno == EINTR) 222196008Smjacob continue; 223196008Smjacob sigprocmask(SIG_SETMASK, &osigset, NULL); 224 pids[fdes] = 0; 225 if (pid < 0) 226 return (pid); 227 if (WIFEXITED(status)) 228 return (WEXITSTATUS(status)); 229 return (1); 230} 231