sulogin: use bb_error_msg instead of bb_info_msg; better message
[oweals/busybox.git] / networking / ftpd.c
index 9fcc3e9637c71165418f2ee80a5970376e6e7d02..8345ae67c112ad3c4eb874d2e0af8541a73dc6e0 100644 (file)
@@ -377,7 +377,7 @@ ftpdataio_get_pasv_fd(void)
                return remote_fd;
        }
 
-       setsockopt(remote_fd, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1));
+       setsockopt_keepalive(remote_fd);
        return remote_fd;
 }
 
@@ -622,7 +622,7 @@ popen_ls(const char *opt)
        pid_t pid;
 
        argv[0] = "ftpd";
-       argv[1] = opt; /* "-l" or "-1" */
+       argv[1] = opt; /* "-lA" or "-1A" */
        argv[2] = "--";
        argv[3] = G.ftp_arg;
        argv[4] = NULL;
@@ -699,7 +699,7 @@ handle_dir_common(int opts)
        if (!(opts & USE_CTRL_CONN) && !port_or_pasv_was_seen())
                return; /* port_or_pasv_was_seen emitted error response */
 
-       ls_fd = popen_ls((opts & LONG_LISTING) ? "-l" : "-1");
+       ls_fd = popen_ls((opts & LONG_LISTING) ? "-lA" : "-1A");
        ls_fp = xfdopen_for_read(ls_fd);
 /* FIXME: filenames with embedded newlines are mishandled */
 
@@ -1102,10 +1102,11 @@ enum {
 #if !BB_MMU
        OPT_l = (1 << 0),
        OPT_1 = (1 << 1),
+       OPT_A = (1 << 2),
 #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,
+       OPT_v = (1 << ((!BB_MMU) * 3 + 0)),
+       OPT_S = (1 << ((!BB_MMU) * 3 + 1)),
+       OPT_w = (1 << ((!BB_MMU) * 3 + 2)) * ENABLE_FEATURE_FTP_WRITE,
 };
 
 int ftpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
@@ -1115,6 +1116,9 @@ int ftpd_main(int argc, char **argv)
 int ftpd_main(int argc UNUSED_PARAM, char **argv)
 #endif
 {
+#if ENABLE_FEATURE_FTP_AUTHENTICATION
+       struct passwd *pw = NULL;
+#endif
        unsigned abs_timeout;
        unsigned verbose_S;
        smallint opts;
@@ -1126,12 +1130,11 @@ int ftpd_main(int argc UNUSED_PARAM, char **argv)
        G.timeout = 2 * 60;
        opt_complementary = "t+:T+:vv:SS";
 #if BB_MMU
-       opts = getopt32(argv,   "vS" IF_FEATURE_FTP_WRITE("w") "t:T:", &G.timeout, &abs_timeout, &G.verbose, &verbose_S);
+       opts = getopt32(argv,    "vS" IF_FEATURE_FTP_WRITE("w") "t:T:", &G.timeout, &abs_timeout, &G.verbose, &verbose_S);
 #else
-       opts = getopt32(argv, "l1vS" IF_FEATURE_FTP_WRITE("w") "t:T:", &G.timeout, &abs_timeout, &G.verbose, &verbose_S);
+       opts = getopt32(argv, "l1AvS" IF_FEATURE_FTP_WRITE("w") "t:T:", &G.timeout, &abs_timeout, &G.verbose, &verbose_S);
        if (opts & (OPT_l|OPT_1)) {
                /* Our secret backdoor to ls */
-/* TODO: pass -A? It shows dot files */
 /* TODO: pass --group-directories-first? would be nice, but ls doesn't do that yet */
                if (fchdir(3) != 0)
                        _exit(127);
@@ -1174,43 +1177,42 @@ int ftpd_main(int argc UNUSED_PARAM, char **argv)
 
        //umask(077); - admin can set umask before starting us
 
-       /* Signals. We'll always take -EPIPE rather than a rude signal, thanks */
-       signal(SIGPIPE, SIG_IGN);
+       /* Signals */
+       bb_signals(0
+               /* We'll always take EPIPE rather than a rude signal, thanks */
+               + (1 << SIGPIPE)
+               /* LIST command spawns chilren. Prevent zombies */
+               + (1 << SIGCHLD)
+               , SIG_IGN);
 
        /* Set up options on the command socket (do we need these all? why?) */
-       setsockopt(STDIN_FILENO, IPPROTO_TCP, TCP_NODELAY, &const_int_1, sizeof(const_int_1));
-       setsockopt(STDIN_FILENO, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1));
+       setsockopt_1(STDIN_FILENO, IPPROTO_TCP, TCP_NODELAY);
+       setsockopt_keepalive(STDIN_FILENO);
        /* Telnet protocol over command link may send "urgent" data,
         * we prefer it to be received in the "normal" data stream: */
-       setsockopt(STDIN_FILENO, SOL_SOCKET, SO_OOBINLINE, &const_int_1, sizeof(const_int_1));
+       setsockopt_1(STDIN_FILENO, SOL_SOCKET, SO_OOBINLINE);
 
        WRITE_OK(FTP_GREET);
        signal(SIGALRM, timeout_handler);
 
 #if ENABLE_FEATURE_FTP_AUTHENTICATION
-       {
-               struct passwd *pw = NULL;
-
-               while (1) {
-                       uint32_t cmdval = cmdio_get_cmd_and_arg();
-
+       while (1) {
+               uint32_t cmdval = cmdio_get_cmd_and_arg();
                        if (cmdval == const_USER) {
-                               pw = getpwnam(G.ftp_arg);
-                               cmdio_write_raw(STR(FTP_GIVEPWORD)" Please specify password\r\n");
-                       } else if (cmdval == const_PASS) {
-                               if (check_password(pw, G.ftp_arg) > 0) {
-                                       break;  /* login success */
-                               }
-                               cmdio_write_raw(STR(FTP_LOGINERR)" Login failed\r\n");
-                               pw = NULL;
-                       } else if (cmdval == const_QUIT) {
-                               WRITE_OK(FTP_GOODBYE);
-                               return 0;
-                       } else {
-                               cmdio_write_raw(STR(FTP_LOGINERR)" Login with USER and PASS\r\n");
+                       pw = getpwnam(G.ftp_arg);
+                       cmdio_write_raw(STR(FTP_GIVEPWORD)" Please specify password\r\n");
+               } else if (cmdval == const_PASS) {
+                       if (check_password(pw, G.ftp_arg) > 0) {
+                               break;  /* login success */
                        }
+                       cmdio_write_raw(STR(FTP_LOGINERR)" Login failed\r\n");
+                       pw = NULL;
+               } else if (cmdval == const_QUIT) {
+                       WRITE_OK(FTP_GOODBYE);
+                       return 0;
+               } else {
+                       cmdio_write_raw(STR(FTP_LOGINERR)" Login with USER and PASS\r\n");
                }
-               change_identity(pw);
        }
        WRITE_OK(FTP_LOGINOK);
 #endif
@@ -1221,13 +1223,32 @@ int ftpd_main(int argc UNUSED_PARAM, char **argv)
 #endif
        argv += optind;
        if (argv[0]) {
+               const char *basedir = argv[0];
 #if !BB_MMU
                G.root_fd = xopen("/", O_RDONLY | O_DIRECTORY);
                close_on_exec_on(G.root_fd);
 #endif
-               xchroot(argv[0]);
+               if (chroot(basedir) == 0)
+                       basedir = "/";
+#if !BB_MMU
+               else {
+                       close(G.root_fd);
+                       G.root_fd = -1;
+               }
+#endif
+               /*
+                * If chroot failed, assume that we aren't root,
+                * and at least chdir to the specified DIR
+                * (older versions were dying with error message).
+                * If chroot worked, move current dir to new "/":
+                */
+               xchdir(basedir);
        }
 
+#if ENABLE_FEATURE_FTP_AUTHENTICATION
+       change_identity(pw);
+#endif
+
        /* RFC-959 Section 5.1
         * The following commands and options MUST be supported by every
         * server-FTP and user-FTP, except in cases where the underlying