1/*	$NetBSD: popen.c,v 1.31 2006/02/01 14:20:14 christos Exp $	*/
2
3/*-
4 * Copyright (c) 1999-2004 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Luke Mewburn.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 *    must display the following acknowledgement:
20 *        This product includes software developed by the NetBSD
21 *        Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 *    contributors may be used to endorse or promote products derived
24 *    from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39/*
40 * Copyright (c) 1988, 1993, 1994
41 *	The Regents of the University of California.  All rights reserved.
42 *
43 * This code is derived from software written by Ken Arnold and
44 * published in UNIX Review, Vol. 6, No. 8.
45 *
46 * Redistribution and use in source and binary forms, with or without
47 * modification, are permitted provided that the following conditions
48 * are met:
49 * 1. Redistributions of source code must retain the above copyright
50 *    notice, this list of conditions and the following disclaimer.
51 * 2. Redistributions in binary form must reproduce the above copyright
52 *    notice, this list of conditions and the following disclaimer in the
53 *    documentation and/or other materials provided with the distribution.
54 * 3. Neither the name of the University nor the names of its contributors
55 *    may be used to endorse or promote products derived from this software
56 *    without specific prior written permission.
57 *
58 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
61 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
68 * SUCH DAMAGE.
69 *
70 */
71
72#include <sys/cdefs.h>
73#ifndef lint
74#if 0
75static char sccsid[] = "@(#)popen.c	8.3 (Berkeley) 4/6/94";
76#else
77__RCSID("$NetBSD: popen.c,v 1.31 2006/02/01 14:20:14 christos Exp $");
78#endif
79#endif /* not lint */
80
81#include <sys/types.h>
82#include <sys/param.h>
83#include <sys/wait.h>
84
85#include <errno.h>
86#include <glob.h>
87#include <signal.h>
88#include <stdio.h>
89#include <stdlib.h>
90#include <string.h>
91#include <stringlist.h>
92#include <syslog.h>
93#include <unistd.h>
94
95#ifdef KERBEROS5
96#include <krb5/krb5.h>
97#endif
98
99#include "extern.h"
100
101#define INCR	100
102/*
103 * Special version of popen which avoids call to shell.  This ensures no-one
104 * may create a pipe to a hidden program as a side effect of a list or dir
105 * command.
106 * If stderrfd != -1, then send stderr of a read command there,
107 * otherwise close stderr.
108 */
109static int *pids;
110static int fds;
111
112extern int ls_main(int, char *[]);
113
114FILE *
115ftpd_popen(char *argv[], const char *ptype, int stderrfd)
116{
117	FILE *iop;
118	int argc, pdes[2], pid, isls;
119	char **pop;
120	StringList *sl;
121
122	iop = NULL;
123	isls = 0;
124	if ((*ptype != 'r' && *ptype != 'w') || ptype[1])
125		return (NULL);
126
127	if (!pids) {
128		if ((fds = getdtablesize()) <= 0)
129			return (NULL);
130		if ((pids = (int *)malloc((u_int)(fds * sizeof(int)))) == NULL)
131			return (NULL);
132		memset(pids, 0, fds * sizeof(int));
133	}
134	if (pipe(pdes) < 0)
135		return (NULL);
136
137	if ((sl = sl_init()) == NULL)
138		goto pfree;
139
140					/* glob each piece */
141	if (sl_add(sl, ftpd_strdup(argv[0])) == -1)
142		goto pfree;
143	for (argc = 1; argv[argc]; argc++) {
144		glob_t gl;
145		int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE|GLOB_LIMIT;
146
147		memset(&gl, 0, sizeof(gl));
148		if (glob(argv[argc], flags, NULL, &gl)) {
149			if (sl_add(sl, ftpd_strdup(argv[argc])) == -1) {
150				globfree(&gl);
151				goto pfree;
152			}
153		} else {
154			for (pop = gl.gl_pathv; *pop; pop++) {
155				if (sl_add(sl, ftpd_strdup(*pop)) == -1) {
156					globfree(&gl);
157					goto pfree;
158				}
159			}
160		}
161		globfree(&gl);
162	}
163	if (sl_add(sl, NULL) == -1)
164		goto pfree;
165
166#ifndef NO_INTERNAL_LS
167	isls = (strcmp(sl->sl_str[0], INTERNAL_LS) == 0);
168#endif
169
170	pid = isls ? fork() : vfork();
171	switch (pid) {
172	case -1:			/* error */
173		(void)close(pdes[0]);
174		(void)close(pdes[1]);
175		goto pfree;
176		/* NOTREACHED */
177	case 0:				/* child */
178		if (*ptype == 'r') {
179			if (pdes[1] != STDOUT_FILENO) {
180				dup2(pdes[1], STDOUT_FILENO);
181				(void)close(pdes[1]);
182			}
183			if (stderrfd == -1)
184				(void)close(STDERR_FILENO);
185			else
186				dup2(stderrfd, STDERR_FILENO);
187			(void)close(pdes[0]);
188		} else {
189			if (pdes[0] != STDIN_FILENO) {
190				dup2(pdes[0], STDIN_FILENO);
191				(void)close(pdes[0]);
192			}
193			(void)close(pdes[1]);
194		}
195#ifndef NO_INTERNAL_LS
196		if (isls) {	/* use internal ls */
197			optreset = optind = optopt = 1;
198			closelog();
199			exit(ls_main(sl->sl_cur - 1, sl->sl_str));
200		}
201#endif
202
203		execv(sl->sl_str[0], sl->sl_str);
204		_exit(1);
205	}
206	/* parent; assume fdopen can't fail...  */
207	if (*ptype == 'r') {
208		iop = fdopen(pdes[0], ptype);
209		(void)close(pdes[1]);
210	} else {
211		iop = fdopen(pdes[1], ptype);
212		(void)close(pdes[0]);
213	}
214	pids[fileno(iop)] = pid;
215
216 pfree:
217	if (sl)
218		sl_free(sl, 1);
219	return (iop);
220}
221
222int
223ftpd_pclose(FILE *iop)
224{
225	int fdes, status;
226	pid_t pid;
227	sigset_t nsigset, osigset;
228
229	/*
230	 * pclose returns -1 if stream is not associated with a
231	 * `popened' command, or, if already `pclosed'.
232	 */
233	if (pids == 0 || pids[fdes = fileno(iop)] == 0)
234		return (-1);
235	(void)fclose(iop);
236	sigemptyset(&nsigset);
237	sigaddset(&nsigset, SIGINT);
238	sigaddset(&nsigset, SIGQUIT);
239	sigaddset(&nsigset, SIGHUP);
240	sigprocmask(SIG_BLOCK, &nsigset, &osigset);
241	while ((pid = waitpid(pids[fdes], &status, 0)) < 0 && errno == EINTR)
242		continue;
243	sigprocmask(SIG_SETMASK, &osigset, NULL);
244	pids[fdes] = 0;
245	if (pid < 0)
246		return (pid);
247	if (WIFEXITED(status))
248		return (WEXITSTATUS(status));
249	return (1);
250}
251