Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/libexec/ftpd/popen.c
34822 views
1
/*-
2
* SPDX-License-Identifier: BSD-3-Clause
3
*
4
* Copyright (c) 1988, 1993, 1994
5
* The Regents of the University of California. All rights reserved.
6
*
7
* This code is derived from software written by Ken Arnold and
8
* published in UNIX Review, Vol. 6, No. 8.
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. Neither the name of the University nor the names of its contributors
19
* may be used to endorse or promote products derived from this software
20
* without specific prior written permission.
21
*
22
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32
* SUCH DAMAGE.
33
*/
34
35
#include <sys/types.h>
36
#include <sys/wait.h>
37
#include <netinet/in.h>
38
39
#include <errno.h>
40
#include <glob.h>
41
#include <signal.h>
42
#include <stdio.h>
43
#include <stdlib.h>
44
#include <string.h>
45
#include <unistd.h>
46
47
#include "extern.h"
48
#include "pathnames.h"
49
#include <syslog.h>
50
#include <time.h>
51
52
#define MAXUSRARGS 100
53
#define MAXGLOBARGS 1000
54
55
/*
56
* Special version of popen which avoids call to shell. This ensures no one
57
* may create a pipe to a hidden program as a side effect of a list or dir
58
* command.
59
*/
60
static int *pids;
61
static int fds;
62
63
FILE *
64
ftpd_popen(char *program, char *type)
65
{
66
char *cp;
67
FILE *iop;
68
int argc, gargc, pdes[2], pid;
69
char **pop, *argv[MAXUSRARGS], *gargv[MAXGLOBARGS];
70
71
if (((*type != 'r') && (*type != 'w')) || type[1])
72
return (NULL);
73
74
if (!pids) {
75
if ((fds = getdtablesize()) <= 0)
76
return (NULL);
77
if ((pids = calloc(fds, sizeof(int))) == NULL)
78
return (NULL);
79
}
80
if (pipe(pdes) < 0)
81
return (NULL);
82
83
/* break up string into pieces */
84
for (argc = 0, cp = program; argc < MAXUSRARGS; cp = NULL) {
85
if (!(argv[argc++] = strtok(cp, " \t\n")))
86
break;
87
}
88
argv[argc - 1] = NULL;
89
90
/* glob each piece */
91
gargv[0] = argv[0];
92
for (gargc = argc = 1; argv[argc] && gargc < (MAXGLOBARGS-1); argc++) {
93
glob_t gl;
94
int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE;
95
96
memset(&gl, 0, sizeof(gl));
97
gl.gl_matchc = MAXGLOBARGS;
98
flags |= GLOB_LIMIT;
99
if (glob(argv[argc], flags, NULL, &gl))
100
gargv[gargc++] = strdup(argv[argc]);
101
else if (gl.gl_pathc > 0) {
102
for (pop = gl.gl_pathv; *pop && gargc < (MAXGLOBARGS-1);
103
pop++)
104
gargv[gargc++] = strdup(*pop);
105
}
106
globfree(&gl);
107
}
108
gargv[gargc] = NULL;
109
110
iop = NULL;
111
fflush(NULL);
112
pid = (strcmp(gargv[0], _PATH_LS) == 0) ? fork() : vfork();
113
switch(pid) {
114
case -1: /* error */
115
(void)close(pdes[0]);
116
(void)close(pdes[1]);
117
goto pfree;
118
/* NOTREACHED */
119
case 0: /* child */
120
if (*type == 'r') {
121
if (pdes[1] != STDOUT_FILENO) {
122
dup2(pdes[1], STDOUT_FILENO);
123
(void)close(pdes[1]);
124
}
125
dup2(STDOUT_FILENO, STDERR_FILENO); /* stderr too! */
126
(void)close(pdes[0]);
127
} else {
128
if (pdes[0] != STDIN_FILENO) {
129
dup2(pdes[0], STDIN_FILENO);
130
(void)close(pdes[0]);
131
}
132
(void)close(pdes[1]);
133
}
134
/* Drop privileges before proceeding */
135
if (getuid() != geteuid() && setuid(geteuid()) < 0)
136
_exit(1);
137
if (strcmp(gargv[0], _PATH_LS) == 0) {
138
/* Reset getopt for ls_main() */
139
optreset = optind = optopt = 1;
140
/* Close syslogging to remove pwd.db missing msgs */
141
closelog();
142
/* Trigger to sense new /etc/localtime after chroot */
143
if (getenv("TZ") == NULL) {
144
setenv("TZ", "", 0);
145
tzset();
146
unsetenv("TZ");
147
tzset();
148
}
149
exit(ls_main(gargc, gargv));
150
}
151
execv(gargv[0], gargv);
152
_exit(1);
153
}
154
/* parent; assume fdopen can't fail... */
155
if (*type == 'r') {
156
iop = fdopen(pdes[0], type);
157
(void)close(pdes[1]);
158
} else {
159
iop = fdopen(pdes[1], type);
160
(void)close(pdes[0]);
161
}
162
pids[fileno(iop)] = pid;
163
164
pfree: for (argc = 1; gargv[argc] != NULL; argc++)
165
free(gargv[argc]);
166
167
return (iop);
168
}
169
170
int
171
ftpd_pclose(FILE *iop)
172
{
173
int fdes, omask, status;
174
pid_t pid;
175
176
/*
177
* pclose returns -1 if stream is not associated with a
178
* `popened' command, or, if already `pclosed'.
179
*/
180
if (pids == NULL || pids[fdes = fileno(iop)] == 0)
181
return (-1);
182
(void)fclose(iop);
183
omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
184
while ((pid = waitpid(pids[fdes], &status, 0)) < 0 && errno == EINTR)
185
continue;
186
(void)sigsetmask(omask);
187
pids[fdes] = 0;
188
if (pid < 0)
189
return (pid);
190
if (WIFEXITED(status))
191
return (WEXITSTATUS(status));
192
return (1);
193
}
194
195