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