xref: /netbsd-src/libexec/ftpd/popen.c (revision cee9ac24adef232e929b37419e1b51dc8c800dce)
1*cee9ac24Schristos /*	$NetBSD: popen.c,v 1.16 1999/08/25 20:07:33 christos Exp $	*/
26a991762Scgd 
361f28255Scgd /*
4d6743f02Sderaadt  * Copyright (c) 1988, 1993, 1994
5d6743f02Sderaadt  *	The Regents of the University of California.  All rights reserved.
661f28255Scgd  *
761f28255Scgd  * This code is derived from software written by Ken Arnold and
861f28255Scgd  * published in UNIX Review, Vol. 6, No. 8.
961f28255Scgd  *
1061f28255Scgd  * Redistribution and use in source and binary forms, with or without
1161f28255Scgd  * modification, are permitted provided that the following conditions
1261f28255Scgd  * are met:
1361f28255Scgd  * 1. Redistributions of source code must retain the above copyright
1461f28255Scgd  *    notice, this list of conditions and the following disclaimer.
1561f28255Scgd  * 2. Redistributions in binary form must reproduce the above copyright
1661f28255Scgd  *    notice, this list of conditions and the following disclaimer in the
1761f28255Scgd  *    documentation and/or other materials provided with the distribution.
1861f28255Scgd  * 3. All advertising materials mentioning features or use of this software
1961f28255Scgd  *    must display the following acknowledgement:
2061f28255Scgd  *	This product includes software developed by the University of
2161f28255Scgd  *	California, Berkeley and its contributors.
2261f28255Scgd  * 4. Neither the name of the University nor the names of its contributors
2361f28255Scgd  *    may be used to endorse or promote products derived from this software
2461f28255Scgd  *    without specific prior written permission.
2561f28255Scgd  *
2661f28255Scgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2761f28255Scgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2861f28255Scgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2961f28255Scgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
3061f28255Scgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3161f28255Scgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3261f28255Scgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3361f28255Scgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3461f28255Scgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3561f28255Scgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3661f28255Scgd  * SUCH DAMAGE.
3761f28255Scgd  *
3861f28255Scgd  */
3961f28255Scgd 
402424c4f9Schristos #include <sys/cdefs.h>
4161f28255Scgd #ifndef lint
426a991762Scgd #if 0
43d6743f02Sderaadt static char sccsid[] = "@(#)popen.c	8.3 (Berkeley) 4/6/94";
446a991762Scgd #else
45*cee9ac24Schristos __RCSID("$NetBSD: popen.c,v 1.16 1999/08/25 20:07:33 christos Exp $");
466a991762Scgd #endif
4761f28255Scgd #endif /* not lint */
4861f28255Scgd 
4961f28255Scgd #include <sys/types.h>
5061f28255Scgd #include <sys/wait.h>
51d6743f02Sderaadt 
52d6743f02Sderaadt #include <errno.h>
53d6743f02Sderaadt #include <glob.h>
5461f28255Scgd #include <signal.h>
5561f28255Scgd #include <stdio.h>
5661f28255Scgd #include <stdlib.h>
5761f28255Scgd #include <string.h>
5825cf35a4Slukem #include <syslog.h>
59d6743f02Sderaadt #include <unistd.h>
60d6743f02Sderaadt 
61b2f939acSexplorer #ifdef KERBEROS5
62*cee9ac24Schristos #include <krb5/krb5.h>
63b2f939acSexplorer #endif
64b2f939acSexplorer 
65d6743f02Sderaadt #include "extern.h"
6661f28255Scgd 
672424c4f9Schristos #define INCR	100
6861f28255Scgd /*
699c9d43e6Slukem  * Special version of popen which avoids call to shell.  This ensures no-one
7061f28255Scgd  * may create a pipe to a hidden program as a side effect of a list or dir
7161f28255Scgd  * command.
729c9d43e6Slukem  * If stderrfd != -1, then send stderr of a read command there,
739c9d43e6Slukem  * otherwise close stderr.
7461f28255Scgd  */
7561f28255Scgd static int *pids;
7661f28255Scgd static int fds;
7761f28255Scgd 
7825cf35a4Slukem extern int ls_main __P((int, char *[]));
7925cf35a4Slukem 
8061f28255Scgd FILE *
819c9d43e6Slukem ftpd_popen(program, type, stderrfd)
8261f28255Scgd 	char *program, *type;
839c9d43e6Slukem 	int stderrfd;
8461f28255Scgd {
85d6743f02Sderaadt 	char *cp;
862424c4f9Schristos 	FILE *iop = NULL;
8725cf35a4Slukem 	int argc, gargc, pdes[2], pid, isls;
882424c4f9Schristos 	char **pop, **np;
892424c4f9Schristos 	char **argv = NULL, **gargv = NULL;
902424c4f9Schristos 	size_t nargc = 100, ngargc = 100;
912424c4f9Schristos #ifdef __GNUC__
922424c4f9Schristos 	(void) &iop;
932424c4f9Schristos 	(void) &gargc;
942424c4f9Schristos 	(void) &gargv;
952424c4f9Schristos 	(void) &argv;
962424c4f9Schristos #endif
9725cf35a4Slukem 	isls = 0;
9861f28255Scgd 
9966783f1fSlukem 	if ((*type != 'r' && *type != 'w') || type[1])
10061f28255Scgd 		return (NULL);
10161f28255Scgd 
10261f28255Scgd 	if (!pids) {
10361f28255Scgd 		if ((fds = getdtablesize()) <= 0)
10461f28255Scgd 			return (NULL);
10561f28255Scgd 		if ((pids = (int *)malloc((u_int)(fds * sizeof(int)))) == NULL)
10661f28255Scgd 			return (NULL);
107d6743f02Sderaadt 		memset(pids, 0, fds * sizeof(int));
10861f28255Scgd 	}
10961f28255Scgd 	if (pipe(pdes) < 0)
11061f28255Scgd 		return (NULL);
11161f28255Scgd 
1122424c4f9Schristos 	if ((argv = malloc(nargc * sizeof(char *))) == NULL)
1132424c4f9Schristos 		return NULL;
1142424c4f9Schristos 
1152424c4f9Schristos #define CHECKMORE(c, v, n) \
1162424c4f9Schristos 	if (c >= n + 2) { \
1172424c4f9Schristos 		n += INCR; \
1182424c4f9Schristos 		if ((np = realloc(v, n * sizeof(char *))) == NULL) \
1192424c4f9Schristos 			goto pfree; \
1202424c4f9Schristos 		else \
1212424c4f9Schristos 			v = np; \
1222424c4f9Schristos 	}
1232424c4f9Schristos 
12461f28255Scgd 	/* break up string into pieces */
1252424c4f9Schristos 	for (argc = 0, cp = program;; cp = NULL) {
1262424c4f9Schristos 		CHECKMORE(argc, argv, nargc)
12761f28255Scgd 		if (!(argv[argc++] = strtok(cp, " \t\n")))
12861f28255Scgd 			break;
1292424c4f9Schristos 	}
1302424c4f9Schristos 
1312424c4f9Schristos 	if ((gargv = malloc(ngargc * sizeof(char *))) == NULL)
1322424c4f9Schristos 		goto pfree;
13361f28255Scgd 
13461f28255Scgd 	/* glob each piece */
13561f28255Scgd 	gargv[0] = argv[0];
13661f28255Scgd 	for (gargc = argc = 1; argv[argc]; argc++) {
137d6743f02Sderaadt 		glob_t gl;
138fc5d36f8Skleink 		int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE;
139d6743f02Sderaadt 
140d6743f02Sderaadt 		memset(&gl, 0, sizeof(gl));
1412424c4f9Schristos 		if (glob(argv[argc], flags, NULL, &gl)) {
1422424c4f9Schristos 			CHECKMORE(gargc, gargv, ngargc)
1432424c4f9Schristos 			if ((gargv[gargc++] = strdup(argv[argc])) == NULL)
1442424c4f9Schristos 				goto pfree;
1452424c4f9Schristos 		}
146d6743f02Sderaadt 		else
1472424c4f9Schristos 			for (pop = gl.gl_pathv; *pop; pop++) {
1482424c4f9Schristos 				CHECKMORE(gargc, gargv, ngargc)
1492424c4f9Schristos 				if ((gargv[gargc++] = strdup(*pop)) == NULL)
1502424c4f9Schristos 					goto pfree;
1512424c4f9Schristos 			}
152d6743f02Sderaadt 		globfree(&gl);
15361f28255Scgd 	}
15461f28255Scgd 	gargv[gargc] = NULL;
15561f28255Scgd 
1564b2b2847Slukem 	isls = (strcmp(gargv[0], INTERNAL_LS) == 0);
15725cf35a4Slukem 
15825cf35a4Slukem 	pid = isls ? fork() : vfork();
15925cf35a4Slukem 	switch (pid) {
16061f28255Scgd 	case -1:			/* error */
16161f28255Scgd 		(void)close(pdes[0]);
16261f28255Scgd 		(void)close(pdes[1]);
16361f28255Scgd 		goto pfree;
16461f28255Scgd 		/* NOTREACHED */
16561f28255Scgd 	case 0:				/* child */
16661f28255Scgd 		if (*type == 'r') {
167d6743f02Sderaadt 			if (pdes[1] != STDOUT_FILENO) {
168d6743f02Sderaadt 				dup2(pdes[1], STDOUT_FILENO);
16961f28255Scgd 				(void)close(pdes[1]);
17061f28255Scgd 			}
1719c9d43e6Slukem 			if (stderrfd == -1)
17231547ec6Slukem 				(void)close(STDERR_FILENO);
1739c9d43e6Slukem 			else
1749c9d43e6Slukem 				dup2(stderrfd, STDERR_FILENO);
17561f28255Scgd 			(void)close(pdes[0]);
17661f28255Scgd 		} else {
177d6743f02Sderaadt 			if (pdes[0] != STDIN_FILENO) {
178d6743f02Sderaadt 				dup2(pdes[0], STDIN_FILENO);
17961f28255Scgd 				(void)close(pdes[0]);
18061f28255Scgd 			}
18161f28255Scgd 			(void)close(pdes[1]);
18261f28255Scgd 		}
18325cf35a4Slukem 		if (isls) {	/* use internal ls */
18425cf35a4Slukem 			optreset = optind = optopt = 1;
18525cf35a4Slukem 			closelog();
18625cf35a4Slukem 			exit(ls_main(gargc, gargv));
18725cf35a4Slukem 		}
18861f28255Scgd 		execv(gargv[0], gargv);
18961f28255Scgd 		_exit(1);
19061f28255Scgd 	}
19161f28255Scgd 	/* parent; assume fdopen can't fail...  */
19261f28255Scgd 	if (*type == 'r') {
19361f28255Scgd 		iop = fdopen(pdes[0], type);
19461f28255Scgd 		(void)close(pdes[1]);
19561f28255Scgd 	} else {
19661f28255Scgd 		iop = fdopen(pdes[1], type);
19761f28255Scgd 		(void)close(pdes[0]);
19861f28255Scgd 	}
19961f28255Scgd 	pids[fileno(iop)] = pid;
20061f28255Scgd 
2012424c4f9Schristos pfree:	if (gargv) {
2022424c4f9Schristos 		for (argc = 1; argc < gargc; argc++)
203d6743f02Sderaadt 			free(gargv[argc]);
2042424c4f9Schristos 		free(gargv);
2052424c4f9Schristos 	}
2062424c4f9Schristos 	if (argv)
2072424c4f9Schristos 		free(argv);
208d6743f02Sderaadt 
20961f28255Scgd 	return (iop);
21061f28255Scgd }
21161f28255Scgd 
212d6743f02Sderaadt int
21361f28255Scgd ftpd_pclose(iop)
21461f28255Scgd 	FILE *iop;
21561f28255Scgd {
21666783f1fSlukem 	int fdes, status;
217d6743f02Sderaadt 	pid_t pid;
218ebeae88dSmycroft 	sigset_t sigset, osigset;
21961f28255Scgd 
22061f28255Scgd 	/*
22161f28255Scgd 	 * pclose returns -1 if stream is not associated with a
22261f28255Scgd 	 * `popened' command, or, if already `pclosed'.
22361f28255Scgd 	 */
22461f28255Scgd 	if (pids == 0 || pids[fdes = fileno(iop)] == 0)
22561f28255Scgd 		return (-1);
22661f28255Scgd 	(void)fclose(iop);
227ebeae88dSmycroft 	sigemptyset(&sigset);
228ebeae88dSmycroft 	sigaddset(&sigset, SIGINT);
229ebeae88dSmycroft 	sigaddset(&sigset, SIGQUIT);
230ebeae88dSmycroft 	sigaddset(&sigset, SIGHUP);
231ebeae88dSmycroft 	sigprocmask(SIG_BLOCK, &sigset, &osigset);
232d6743f02Sderaadt 	while ((pid = waitpid(pids[fdes], &status, 0)) < 0 && errno == EINTR)
233d6743f02Sderaadt 		continue;
234ebeae88dSmycroft 	sigprocmask(SIG_SETMASK, &osigset, NULL);
23561f28255Scgd 	pids[fdes] = 0;
236d6743f02Sderaadt 	if (pid < 0)
237d6743f02Sderaadt 		return (pid);
238d6743f02Sderaadt 	if (WIFEXITED(status))
239d6743f02Sderaadt 		return (WEXITSTATUS(status));
240d6743f02Sderaadt 	return (1);
24161f28255Scgd }
242