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