aboutsummaryrefslogtreecommitdiff
path: root/networking
diff options
context:
space:
mode:
Diffstat (limited to 'networking')
-rw-r--r--networking/ftpd.c79
1 files changed, 57 insertions, 22 deletions
diff --git a/networking/ftpd.c b/networking/ftpd.c
index b295ddf4f..0a4b185a1 100644
--- a/networking/ftpd.c
+++ b/networking/ftpd.c
@@ -87,7 +87,9 @@ enum {
struct globals {
int pasv_listen_fd;
- int proc_self_fd;
+#if !BB_MMU
+ int root_fd;
+#endif
int local_file_fd;
unsigned end_time;
unsigned timeout;
@@ -615,7 +617,13 @@ static int
popen_ls(const char *opt)
{
char *cwd;
- const char *argv[5] = { "ftpd", opt, NULL, G.ftp_arg, NULL };
+ const char *argv[] = {
+ "ftpd",
+ opt,
+ BB_MMU ? "--" : NULL,
+ G.ftp_arg,
+ NULL
+ };
struct fd_pair outfd;
pid_t pid;
@@ -623,25 +631,40 @@ popen_ls(const char *opt)
xpiped_pair(outfd);
/*fflush(NULL); - so far we dont use stdio on output */
- pid = vfork();
- switch (pid) {
- case -1: /* failure */
- bb_perror_msg_and_die("vfork");
- case 0: /* child */
- /* NB: close _first_, then move fds! */
+ pid = BB_MMU ? fork() : vfork();
+ if (pid < 0)
+ bb_perror_msg_and_die(BB_MMU ? "fork" : "vfork");
+
+ if (pid == 0) {
+ /* child */
+#if !BB_MMU
+ if (fchdir(G.root_fd) != 0)
+ _exit(127);
+ close(G.root_fd);
+#endif
+ /* NB: close _first_, then move fd! */
close(outfd.rd);
xmove_fd(outfd.wr, STDOUT_FILENO);
+ /* Opening /dev/null in chroot is hard.
+ * Just making sure STDIN_FILENO is opened
+ * to something harmless. Paranoia,
+ * ls won't read it anyway */
close(STDIN_FILENO);
- /* xopen("/dev/null", O_RDONLY); - chroot may lack it! */
- if (fchdir(G.proc_self_fd) == 0) {
- close(G.proc_self_fd);
- argv[2] = cwd;
- /* ftpd ls helper chdirs to argv[2],
- * preventing peer from seeing /proc/self
- */
- execv("exe", (char**) argv);
- }
+ dup(STDOUT_FILENO); /* copy will become STDIN_FILENO */
+#if !BB_MMU
+ /* ftpd ls helper chdirs to argv[2],
+ * preventing peer from seeing real root we are in now
+ */
+ argv[2] = cwd;
+ /* + 1: we must use relative path here if in chroot.
+ * For example, execv("/proc/self/exe") will fail, since
+ * it looks for "/proc/self/exe" _relative to chroot!_ */
+ execv(CONFIG_BUSYBOX_EXEC_PATH + 1, (char**) argv);
_exit(127);
+#else
+ memset(&G, 0, sizeof(G));
+ exit(ls_main(ARRAY_SIZE(argv) - 1, (char**) argv));
+#endif
}
/* parent */
@@ -1006,15 +1029,21 @@ enum {
const_TYPE = mk_const4('T', 'Y', 'P', 'E'),
const_USER = mk_const4('U', 'S', 'E', 'R'),
+#if !BB_MMU
OPT_l = (1 << 0),
OPT_1 = (1 << 1),
- OPT_v = (1 << 2),
- OPT_S = (1 << 3),
- OPT_w = (1 << 4),
+#endif
+ OPT_v = (1 << ((!BB_MMU) * 2 + 0)),
+ OPT_S = (1 << ((!BB_MMU) * 2 + 1)),
+ OPT_w = (1 << ((!BB_MMU) * 2 + 2)) * ENABLE_FEATURE_FTP_WRITE,
};
int ftpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+#if !BB_MMU
int ftpd_main(int argc, char **argv)
+#else
+int ftpd_main(int argc UNUSED_PARAM, char **argv)
+#endif
{
unsigned abs_timeout;
smallint opts;
@@ -1024,16 +1053,20 @@ int ftpd_main(int argc, char **argv)
abs_timeout = 1 * 60 * 60;
G.timeout = 2 * 60;
opt_complementary = "t+:T+:vv";
+#if BB_MMU
+ opts = getopt32(argv, "vS" USE_FEATURE_FTP_WRITE("w") "t:T:", &G.timeout, &abs_timeout, &G.verbose);
+#else
opts = getopt32(argv, "l1vS" USE_FEATURE_FTP_WRITE("w") "t:T:", &G.timeout, &abs_timeout, &G.verbose);
if (opts & (OPT_l|OPT_1)) {
/* Our secret backdoor to ls */
- memset(&G, 0, sizeof(G));
/* TODO: pass -n too? */
/* --group-directories-first would be nice, but ls don't do that yet */
xchdir(argv[2]);
argv[2] = (char*)"--";
+ memset(&G, 0, sizeof(G));
return ls_main(argc, argv);
}
+#endif
if (abs_timeout | G.timeout) {
if (abs_timeout == 0)
abs_timeout = INT_MAX;
@@ -1065,7 +1098,9 @@ int ftpd_main(int argc, char **argv)
if (logmode)
applet_name = xasprintf("%s[%u]", applet_name, (int)getpid());
- G.proc_self_fd = xopen("/proc/self", O_RDONLY | O_DIRECTORY);
+#if !BB_MMU
+ G.root_fd = xopen("/", O_RDONLY | O_DIRECTORY);
+#endif
if (argv[optind]) {
xchdir(argv[optind]);