Changeset 3621 in MondoRescue for branches/3.3/mindi-busybox/networking/ftpd.c


Ignore:
Timestamp:
Dec 20, 2016, 4:07:32 PM (7 years ago)
Author:
Bruno Cornec
Message:

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

Location:
branches/3.3
Files:
1 edited
1 copied

Legend:

Unmodified
Added
Removed
  • branches/3.3/mindi-busybox/networking/ftpd.c

    r3232 r3621  
    3030
    3131#include "libbb.h"
     32#include "common_bufsiz.h"
    3233#include <syslog.h>
    3334#include <netinet/tcp.h>
     
    124125    char msg_err[(sizeof("NNN " MSG_ERR) + 3) & 0xfffc];
    125126} FIX_ALIASING;
    126 #define G (*(struct globals*)&bb_common_bufsiz1)
     127#define G (*(struct globals*)bb_common_bufsiz1)
    127128#define INIT_G() do { \
     129    setup_common_bufsiz(); \
    128130    /* Moved to main */ \
    129131    /*strcpy(G.msg_ok  + 4, MSG_OK );*/ \
     
    378380    }
    379381
    380     setsockopt(remote_fd, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1));
     382    setsockopt_keepalive(remote_fd);
    381383    return remote_fd;
    382384}
     
    623625
    624626    argv[0] = "ftpd";
    625     argv[1] = opt; /* "-l" or "-1" */
    626 #if BB_MMU
     627    argv[1] = opt; /* "-lA" or "-1A" */
    627628    argv[2] = "--";
    628 #else
    629     /* NOMMU ftpd ls helper chdirs to argv[2],
    630      * preventing peer from seeing real root. */
    631     argv[2] = xrealloc_getcwd_or_warn(NULL);
    632 #endif
    633629    argv[3] = G.ftp_arg;
    634630    argv[4] = NULL;
     
    651647    pid = BB_MMU ? xfork() : xvfork();
    652648    if (pid == 0) {
     649#if !BB_MMU
     650        int cur_fd;
     651#endif
    653652        /* child */
    654 #if !BB_MMU
    655         /* On NOMMU, we want to execute a child - copy of ourself.
    656          * In chroot we usually can't do it. Thus we chdir
    657          * out of the chroot back to original root,
    658          * and (see later below) execute bb_busybox_exec_path
    659          * relative to current directory */
    660         if (fchdir(G.root_fd) != 0)
    661             _exit(127);
    662         /*close(G.root_fd); - close_on_exec_on() took care of this */
    663 #endif
    664653        /* NB: close _first_, then move fd! */
    665654        close(outfd.rd);
     
    675664        exit(ls_main(ARRAY_SIZE(argv) - 1, (char**) argv));
    676665#else
    677         /* + 1: we must use relative path here if in chroot.
    678          * For example, execv("/proc/self/exe") will fail, since
    679          * it looks for "/proc/self/exe" _relative to chroot!_ */
    680         execv(bb_busybox_exec_path + 1, (char**) argv);
     666        cur_fd = xopen(".", O_RDONLY | O_DIRECTORY);
     667        /* On NOMMU, we want to execute a child - copy of ourself
     668         * in order to unblock parent after vfork.
     669         * In chroot we usually can't re-exec. Thus we escape
     670         * out of the chroot back to original root.
     671         */
     672        if (G.root_fd >= 0) {
     673            if (fchdir(G.root_fd) != 0 || chroot(".") != 0)
     674                _exit(127);
     675            /*close(G.root_fd); - close_on_exec_on() took care of this */
     676        }
     677        /* Child expects directory to list on fd #3 */
     678        xmove_fd(cur_fd, 3);
     679        execv(bb_busybox_exec_path, (char**) argv);
    681680        _exit(127);
    682681#endif
     
    685684    /* parent */
    686685    close(outfd.wr);
    687 #if !BB_MMU
    688     free((char*)argv[2]);
    689 #endif
    690686    return outfd.rd;
    691687}
     
    706702        return; /* port_or_pasv_was_seen emitted error response */
    707703
    708     /* -n prevents user/groupname display,
    709      * which can be problematic in chroot */
    710     ls_fd = popen_ls((opts & LONG_LISTING) ? "-l" : "-1");
     704    ls_fd = popen_ls((opts & LONG_LISTING) ? "-lA" : "-1A");
    711705    ls_fp = xfdopen_for_read(ls_fd);
     706/* FIXME: filenames with embedded newlines are mishandled */
    712707
    713708    if (opts & USE_CTRL_CONN) {
     
    730725        if (remote_fd >= 0) {
    731726            while (1) {
    732                 line = xmalloc_fgetline(ls_fp);
     727                unsigned len;
     728
     729                line = xmalloc_fgets(ls_fp);
    733730                if (!line)
    734731                    break;
    735732                /* I've seen clients complaining when they
    736733                 * are fed with ls output with bare '\n'.
    737                  * Pity... that would be much simpler.
     734                 * Replace trailing "\n\0" with "\r\n".
    738735                 */
    739 /* TODO: need to s/LF/NUL/g here */
    740                 xwrite_str(remote_fd, line);
    741                 xwrite(remote_fd, "\r\n", 2);
     736                len = strlen(line);
     737                if (len != 0) /* paranoia check */
     738                    line[len - 1] = '\r';
     739                line[len] = '\n';
     740                xwrite(remote_fd, line, len + 1);
    742741                free(line);
    743742            }
     
    10861085    const_PORT = mk_const4('P', 'O', 'R', 'T'),
    10871086    const_PWD  = mk_const3('P', 'W', 'D'),
     1087    /* Same as PWD. Reportedly used by windows ftp client */
     1088    const_XPWD = mk_const4('X', 'P', 'W', 'D'),
    10881089    const_QUIT = mk_const4('Q', 'U', 'I', 'T'),
    10891090    const_REST = mk_const4('R', 'E', 'S', 'T'),
     
    11041105    OPT_l = (1 << 0),
    11051106    OPT_1 = (1 << 1),
    1106 #endif
    1107     OPT_v = (1 << ((!BB_MMU) * 2 + 0)),
    1108     OPT_S = (1 << ((!BB_MMU) * 2 + 1)),
    1109     OPT_w = (1 << ((!BB_MMU) * 2 + 2)) * ENABLE_FEATURE_FTP_WRITE,
     1107    OPT_A = (1 << 2),
     1108#endif
     1109    OPT_v = (1 << ((!BB_MMU) * 3 + 0)),
     1110    OPT_S = (1 << ((!BB_MMU) * 3 + 1)),
     1111    OPT_w = (1 << ((!BB_MMU) * 3 + 2)) * ENABLE_FEATURE_FTP_WRITE,
    11101112};
    11111113
     
    11171119#endif
    11181120{
     1121#if ENABLE_FEATURE_FTP_AUTHENTICATION
     1122    struct passwd *pw = NULL;
     1123#endif
    11191124    unsigned abs_timeout;
    11201125    unsigned verbose_S;
     
    11281133    opt_complementary = "t+:T+:vv:SS";
    11291134#if BB_MMU
    1130     opts = getopt32(argv,   "vS" IF_FEATURE_FTP_WRITE("w") "t:T:", &G.timeout, &abs_timeout, &G.verbose, &verbose_S);
     1135    opts = getopt32(argv,    "vS" IF_FEATURE_FTP_WRITE("w") "t:T:", &G.timeout, &abs_timeout, &G.verbose, &verbose_S);
    11311136#else
    1132     opts = getopt32(argv, "l1vS" IF_FEATURE_FTP_WRITE("w") "t:T:", &G.timeout, &abs_timeout, &G.verbose, &verbose_S);
     1137    opts = getopt32(argv, "l1AvS" IF_FEATURE_FTP_WRITE("w") "t:T:", &G.timeout, &abs_timeout, &G.verbose, &verbose_S);
    11331138    if (opts & (OPT_l|OPT_1)) {
    11341139        /* Our secret backdoor to ls */
    1135 /* TODO: pass -n? It prevents user/group resolution, which may not work in chroot anyway */
    1136 /* TODO: pass -A? It shows dot files */
    11371140/* TODO: pass --group-directories-first? would be nice, but ls doesn't do that yet */
    1138         xchdir(argv[2]);
    1139         argv[2] = (char*)"--";
     1141        if (fchdir(3) != 0)
     1142            _exit(127);
    11401143        /* memset(&G, 0, sizeof(G)); - ls_main does it */
    11411144        return ls_main(argc, argv);
     
    11751178        applet_name = xasprintf("%s[%u]", applet_name, (int)getpid());
    11761179
    1177 #if !BB_MMU
    1178     G.root_fd = xopen("/", O_RDONLY | O_DIRECTORY);
    1179     close_on_exec_on(G.root_fd);
    1180 #endif
    1181 
    1182     if (argv[optind]) {
    1183         xchroot(argv[optind]);
    1184     }
    1185 
    11861180    //umask(077); - admin can set umask before starting us
    11871181
    1188     /* Signals. We'll always take -EPIPE rather than a rude signal, thanks */
    1189     signal(SIGPIPE, SIG_IGN);
     1182    /* Signals */
     1183    bb_signals(0
     1184        /* We'll always take EPIPE rather than a rude signal, thanks */
     1185        + (1 << SIGPIPE)
     1186        /* LIST command spawns chilren. Prevent zombies */
     1187        + (1 << SIGCHLD)
     1188        , SIG_IGN);
    11901189
    11911190    /* Set up options on the command socket (do we need these all? why?) */
    1192     setsockopt(STDIN_FILENO, IPPROTO_TCP, TCP_NODELAY, &const_int_1, sizeof(const_int_1));
    1193     setsockopt(STDIN_FILENO, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1));
     1191    setsockopt_1(STDIN_FILENO, IPPROTO_TCP, TCP_NODELAY);
     1192    setsockopt_keepalive(STDIN_FILENO);
    11941193    /* Telnet protocol over command link may send "urgent" data,
    11951194     * we prefer it to be received in the "normal" data stream: */
    1196     setsockopt(STDIN_FILENO, SOL_SOCKET, SO_OOBINLINE, &const_int_1, sizeof(const_int_1));
     1195    setsockopt_1(STDIN_FILENO, SOL_SOCKET, SO_OOBINLINE);
    11971196
    11981197    WRITE_OK(FTP_GREET);
    11991198    signal(SIGALRM, timeout_handler);
    12001199
    1201 #ifdef IF_WE_WANT_TO_REQUIRE_LOGIN
    1202     {
    1203         smallint user_was_specified = 0;
    1204         while (1) {
    1205             uint32_t cmdval = cmdio_get_cmd_and_arg();
    1206 
     1200#if ENABLE_FEATURE_FTP_AUTHENTICATION
     1201    while (1) {
     1202        uint32_t cmdval = cmdio_get_cmd_and_arg();
    12071203            if (cmdval == const_USER) {
    1208                 if (G.ftp_arg == NULL || strcasecmp(G.ftp_arg, "anonymous") != 0)
    1209                     cmdio_write_raw(STR(FTP_LOGINERR)" Server is anonymous only\r\n");
    1210                 else {
    1211                     user_was_specified = 1;
    1212                     cmdio_write_raw(STR(FTP_GIVEPWORD)" Please specify the password\r\n");
    1213                 }
    1214             } else if (cmdval == const_PASS) {
    1215                 if (user_was_specified)
    1216                     break;
    1217                 cmdio_write_raw(STR(FTP_NEEDUSER)" Login with USER\r\n");
    1218             } else if (cmdval == const_QUIT) {
    1219                 WRITE_OK(FTP_GOODBYE);
    1220                 return 0;
    1221             } else {
    1222                 cmdio_write_raw(STR(FTP_LOGINERR)" Login with USER and PASS\r\n");
     1204            pw = getpwnam(G.ftp_arg);
     1205            cmdio_write_raw(STR(FTP_GIVEPWORD)" Please specify password\r\n");
     1206        } else if (cmdval == const_PASS) {
     1207            if (check_password(pw, G.ftp_arg) > 0) {
     1208                break;  /* login success */
    12231209            }
     1210            cmdio_write_raw(STR(FTP_LOGINERR)" Login failed\r\n");
     1211            pw = NULL;
     1212        } else if (cmdval == const_QUIT) {
     1213            WRITE_OK(FTP_GOODBYE);
     1214            return 0;
     1215        } else {
     1216            cmdio_write_raw(STR(FTP_LOGINERR)" Login with USER and PASS\r\n");
    12241217        }
    12251218    }
    12261219    WRITE_OK(FTP_LOGINOK);
     1220#endif
     1221
     1222    /* Do this after auth, else /etc/passwd is not accessible */
     1223#if !BB_MMU
     1224    G.root_fd = -1;
     1225#endif
     1226    argv += optind;
     1227    if (argv[0]) {
     1228        const char *basedir = argv[0];
     1229#if !BB_MMU
     1230        G.root_fd = xopen("/", O_RDONLY | O_DIRECTORY);
     1231        close_on_exec_on(G.root_fd);
     1232#endif
     1233        if (chroot(basedir) == 0)
     1234            basedir = "/";
     1235#if !BB_MMU
     1236        else {
     1237            close(G.root_fd);
     1238            G.root_fd = -1;
     1239        }
     1240#endif
     1241        /*
     1242         * If chroot failed, assume that we aren't root,
     1243         * and at least chdir to the specified DIR
     1244         * (older versions were dying with error message).
     1245         * If chroot worked, move current dir to new "/":
     1246         */
     1247        xchdir(basedir);
     1248    }
     1249
     1250#if ENABLE_FEATURE_FTP_AUTHENTICATION
     1251    change_identity(pw);
    12271252#endif
    12281253
     
    12931318        else if (cmdval == const_SYST)
    12941319            cmdio_write_raw(STR(FTP_SYSTOK)" UNIX Type: L8\r\n");
    1295         else if (cmdval == const_PWD)
     1320        else if (cmdval == const_PWD || cmdval == const_XPWD)
    12961321            handle_pwd();
    12971322        else if (cmdval == const_CWD)
Note: See TracChangeset for help on using the changeset viewer.