155682Smarkm/* 255682Smarkm * Copyright (c) 1988, 1993, 1994 355682Smarkm * The Regents of the University of California. All rights reserved. 455682Smarkm * 555682Smarkm * This code is derived from software written by Ken Arnold and 655682Smarkm * published in UNIX Review, Vol. 6, No. 8. 755682Smarkm * 855682Smarkm * Redistribution and use in source and binary forms, with or without 955682Smarkm * modification, are permitted provided that the following conditions 1055682Smarkm * are met: 1155682Smarkm * 1. Redistributions of source code must retain the above copyright 1255682Smarkm * notice, this list of conditions and the following disclaimer. 1355682Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1455682Smarkm * notice, this list of conditions and the following disclaimer in the 1555682Smarkm * documentation and/or other materials provided with the distribution. 1655682Smarkm * 3. All advertising materials mentioning features or use of this software 1755682Smarkm * must display the following acknowledgement: 1855682Smarkm * This product includes software developed by the University of 1955682Smarkm * California, Berkeley and its contributors. 2055682Smarkm * 4. Neither the name of the University nor the names of its contributors 2155682Smarkm * may be used to endorse or promote products derived from this software 2255682Smarkm * without specific prior written permission. 2355682Smarkm * 2455682Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2555682Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2655682Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2755682Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2855682Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2955682Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3055682Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3155682Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3255682Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3355682Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3455682Smarkm * SUCH DAMAGE. 3555682Smarkm * 3655682Smarkm */ 3755682Smarkm 3855682Smarkm#ifdef HAVE_CONFIG_H 3955682Smarkm#include <config.h> 40233294SstasRCSID("$Id$"); 4155682Smarkm#endif 4255682Smarkm 4355682Smarkm#include <sys/types.h> 4455682Smarkm#ifdef TIME_WITH_SYS_TIME 4555682Smarkm#include <sys/time.h> 4655682Smarkm#include <time.h> 4755682Smarkm#elif defined(HAVE_SYS_TIME_H) 4855682Smarkm#include <sys/time.h> 4955682Smarkm#else 5055682Smarkm#include <time.h> 5155682Smarkm#endif 5255682Smarkm#ifdef HAVE_SYS_RESOURCE_H 5355682Smarkm#include <sys/resource.h> 5455682Smarkm#endif 5555682Smarkm#include <sys/wait.h> 5655682Smarkm 5755682Smarkm#include <errno.h> 5855682Smarkm#include <glob.h> 5955682Smarkm#include <signal.h> 6055682Smarkm#include <stdio.h> 6155682Smarkm#include <stdlib.h> 6255682Smarkm#include <string.h> 6355682Smarkm#include <unistd.h> 6472445Sassar#include <roken.h> 6555682Smarkm#include "extern.h" 6655682Smarkm 6755682Smarkm 68233294Sstas/* 6955682Smarkm * Special version of popen which avoids call to shell. This ensures 7055682Smarkm * no one may create a pipe to a hidden program as a side effect of a 7155682Smarkm * list or dir command. 7255682Smarkm */ 7355682Smarkmstatic int *pids; 7455682Smarkmstatic int fds; 7555682Smarkm 7655682Smarkm/* return path prepended with ~ftp if that file exists, otherwise 7755682Smarkm * return path unchanged 7855682Smarkm */ 7955682Smarkm 8055682Smarkmconst char * 8155682Smarkmftp_rooted(const char *path) 8255682Smarkm{ 8355682Smarkm static char home[MaxPathLen] = ""; 8455682Smarkm static char newpath[MaxPathLen]; 8555682Smarkm struct passwd *pwd; 8655682Smarkm 8755682Smarkm if(!home[0]) 8855682Smarkm if((pwd = k_getpwnam("ftp"))) 8955682Smarkm strlcpy(home, pwd->pw_dir, sizeof(home)); 9055682Smarkm snprintf(newpath, sizeof(newpath), "%s/%s", home, path); 9155682Smarkm if(access(newpath, X_OK)) 9255682Smarkm strlcpy(newpath, path, sizeof(newpath)); 9355682Smarkm return newpath; 9455682Smarkm} 9555682Smarkm 9655682Smarkm 9772445Sassar#define MAXARGS 100 9872445Sassar#define MAXGLOBS 1000 9972445Sassar 10055682SmarkmFILE * 10155682Smarkmftpd_popen(char *program, char *type, int do_stderr, int no_glob) 10255682Smarkm{ 10355682Smarkm char *cp; 10455682Smarkm FILE *iop; 10555682Smarkm int argc, gargc, pdes[2], pid; 10672445Sassar char **pop, *argv[MAXARGS], *gargv[MAXGLOBS]; 10755682Smarkm char *foo; 10855682Smarkm 10955682Smarkm if (strcmp(type, "r") && strcmp(type, "w")) 11055682Smarkm return (NULL); 11155682Smarkm 11255682Smarkm if (!pids) { 11355682Smarkm 11455682Smarkm /* This function is ugly and should be rewritten, in 11555682Smarkm * modern unices there is no such thing as a maximum 11655682Smarkm * filedescriptor. 11755682Smarkm */ 11855682Smarkm 11955682Smarkm fds = getdtablesize(); 12055682Smarkm pids = (int*)calloc(fds, sizeof(int)); 12155682Smarkm if(!pids) 12255682Smarkm return NULL; 12355682Smarkm } 12455682Smarkm if (pipe(pdes) < 0) 12555682Smarkm return (NULL); 12655682Smarkm 12755682Smarkm /* break up string into pieces */ 12855682Smarkm foo = NULL; 12972445Sassar for (argc = 0, cp = program; argc < MAXARGS - 1; cp = NULL) { 13055682Smarkm if (!(argv[argc++] = strtok_r(cp, " \t\n", &foo))) 13155682Smarkm break; 13255682Smarkm } 13372445Sassar argv[MAXARGS - 1] = NULL; 13455682Smarkm 13555682Smarkm gargv[0] = (char*)ftp_rooted(argv[0]); 13655682Smarkm /* glob each piece */ 13772445Sassar for (gargc = argc = 1; argv[argc] && gargc < MAXGLOBS - 1; argc++) { 13855682Smarkm glob_t gl; 13978527Sassar int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE 14090926Snectar | 14190926Snectar#ifdef GLOB_MAXPATH 14290926Snectar GLOB_MAXPATH 14390926Snectar#else 14490926Snectar GLOB_LIMIT 14590926Snectar#endif 14690926Snectar ; 14755682Smarkm 14855682Smarkm memset(&gl, 0, sizeof(gl)); 149233294Sstas if (no_glob || 150233294Sstas glob(argv[argc], flags, NULL, &gl) || 151102644Snectar gl.gl_pathc == 0) 15255682Smarkm gargv[gargc++] = strdup(argv[argc]); 15355682Smarkm else 15472445Sassar for (pop = gl.gl_pathv; 15572445Sassar *pop && gargc < MAXGLOBS - 1; 15672445Sassar pop++) 15755682Smarkm gargv[gargc++] = strdup(*pop); 15855682Smarkm globfree(&gl); 15955682Smarkm } 16055682Smarkm gargv[gargc] = NULL; 16155682Smarkm 16255682Smarkm iop = NULL; 16355682Smarkm switch(pid = fork()) { 16455682Smarkm case -1: /* error */ 16555682Smarkm close(pdes[0]); 16655682Smarkm close(pdes[1]); 16755682Smarkm goto pfree; 16855682Smarkm /* NOTREACHED */ 16955682Smarkm case 0: /* child */ 17055682Smarkm if (*type == 'r') { 17155682Smarkm if (pdes[1] != STDOUT_FILENO) { 17255682Smarkm dup2(pdes[1], STDOUT_FILENO); 17355682Smarkm close(pdes[1]); 17455682Smarkm } 17555682Smarkm if(do_stderr) 17655682Smarkm dup2(STDOUT_FILENO, STDERR_FILENO); 17755682Smarkm close(pdes[0]); 17855682Smarkm } else { 17955682Smarkm if (pdes[0] != STDIN_FILENO) { 18055682Smarkm dup2(pdes[0], STDIN_FILENO); 18155682Smarkm close(pdes[0]); 18255682Smarkm } 18355682Smarkm close(pdes[1]); 18455682Smarkm } 18555682Smarkm execv(gargv[0], gargv); 18655682Smarkm gargv[0] = argv[0]; 18755682Smarkm execv(gargv[0], gargv); 18855682Smarkm _exit(1); 18955682Smarkm } 19055682Smarkm /* parent; assume fdopen can't fail... */ 19155682Smarkm if (*type == 'r') { 19255682Smarkm iop = fdopen(pdes[0], type); 19355682Smarkm close(pdes[1]); 19455682Smarkm } else { 19555682Smarkm iop = fdopen(pdes[1], type); 19655682Smarkm close(pdes[0]); 19755682Smarkm } 19855682Smarkm pids[fileno(iop)] = pid; 199233294Sstas 200233294Sstaspfree: 20155682Smarkm for (argc = 1; gargv[argc] != NULL; argc++) 20255682Smarkm free(gargv[argc]); 20355682Smarkm 20455682Smarkm 20555682Smarkm return (iop); 20655682Smarkm} 20755682Smarkm 20855682Smarkmint 20955682Smarkmftpd_pclose(FILE *iop) 21055682Smarkm{ 21155682Smarkm int fdes, status; 21255682Smarkm pid_t pid; 21355682Smarkm sigset_t sigset, osigset; 21455682Smarkm 21555682Smarkm /* 21655682Smarkm * pclose returns -1 if stream is not associated with a 21755682Smarkm * `popened' command, or, if already `pclosed'. 21855682Smarkm */ 21955682Smarkm if (pids == 0 || pids[fdes = fileno(iop)] == 0) 22055682Smarkm return (-1); 22155682Smarkm fclose(iop); 22255682Smarkm sigemptyset(&sigset); 22355682Smarkm sigaddset(&sigset, SIGINT); 22455682Smarkm sigaddset(&sigset, SIGQUIT); 22555682Smarkm sigaddset(&sigset, SIGHUP); 22655682Smarkm sigprocmask(SIG_BLOCK, &sigset, &osigset); 22755682Smarkm while ((pid = waitpid(pids[fdes], &status, 0)) < 0 && errno == EINTR) 22855682Smarkm continue; 22955682Smarkm sigprocmask(SIG_SETMASK, &osigset, NULL); 23055682Smarkm pids[fdes] = 0; 23155682Smarkm if (pid < 0) 23255682Smarkm return (pid); 23355682Smarkm if (WIFEXITED(status)) 23455682Smarkm return (WEXITSTATUS(status)); 23555682Smarkm return (1); 23655682Smarkm} 237