ftpd: code chrink, fixed some minor bugs
authorDenis Vlasenko <vda.linux@googlemail.com>
Sun, 8 Mar 2009 23:46:48 +0000 (23:46 -0000)
committerDenis Vlasenko <vda.linux@googlemail.com>
Sun, 8 Mar 2009 23:46:48 +0000 (23:46 -0000)
ls: update comment
*: openlog fixes (added LOG_PID, set LOG_DAEMON as appropriate)

function                                             old     new   delta
xwrite_str                                             -      26     +26
cmdio_write_ok                                         -      15     +15
handle_cwd                                            40      45      +5
packed_usage                                       25668   25670      +2
cmdio_write_raw                                        7       9      +2
handle_upload_common                                 322     320      -2
udhcpd_main                                         1375    1372      -3
udhcpc_main                                         2362    2359      -3
port_cleanup                                          27      23      -4
handle_dir_common                                    221     209     -12
str_netfd_write                                       26       -     -26
cmdio_get_cmd_and_arg                                122       -    -122
ftpd_main                                           2208    2050    -158
------------------------------------------------------------------------------
   text    data     bss     dec     hex filename
 809933     476    7864  818273   c7c61 busybox_old
 809199     476    7864  817539   c7983 busybox_unstripped

coreutils/ls.c
include/usage.h
networking/Config.in
networking/ftpd.c
networking/isrv_identd.c
networking/telnetd.c
networking/udhcp/dhcpc.c
networking/udhcp/dhcpd.c

index edb6300ba3ba69d92f8327a34d0077ec2b2ebf71..7b65d049ead084905c5b0d57c975784f391262e5 100644 (file)
@@ -6,7 +6,7 @@
  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
  */
 
-/*
+/* [date unknown. Perhaps before year 2000]
  * To achieve a small memory footprint, this version of 'ls' doesn't do any
  * file sorting, and only has the most essential command line switches
  * (i.e., the ones I couldn't live without :-) All features which involve
@@ -18,8 +18,7 @@
  *
  * KNOWN BUGS:
  * 1. ls -l of a directory doesn't give "total <blocks>" header
- * 2. ls of a symlink to a directory doesn't list directory contents
- * 3. hidden files can make column width too large
+ * 2. hidden files can make column width too large
  *
  * NON-OPTIMAL BEHAVIOUR:
  * 1. autowidth reads directories twice
@@ -27,6 +26,9 @@
  *    appended, there's no need to stat each one
  * PORTABILITY:
  * 1. requires lstat (BSD) - how do you do it without?
+ *
+ * [2009-03]
+ * ls sorts listing now, and supports almost all options.
  */
 
 #include "libbb.h"
index fb43fa36967407eb509800044c524c45b7b687cf..e3905eb8a1aa1c43f723e0bdd4e64bdf0c888026 100644 (file)
      "\n       -f      Force file system check" \
 
 #define ftpd_trivial_usage \
-       "[-w] [DIR]"
+       "[-vw] [DIR]"
 #define ftpd_full_usage "\n\n" \
        "FTP server\n" \
        "\n" \
        "It also can be ran from tcpsvd:\n" \
        "       tcpsvd -vE 0.0.0.0 21 ftpd /files/to/serve\n" \
      "\nOptions:" \
+     "\n       -v      Log also to stderr" \
      "\n       -w      Allow upload" \
      "\n       DIR     Change root to ths directory" \
 
index f3ba85620a75a6779e3b5c7d93ebc65e05dfc94e..392afcf8917d5dade1fe893ecf2d52c4ba386085 100644 (file)
@@ -100,11 +100,11 @@ config FTPD
          simple FTP daemon. You have to run it via inetd.
 
 config FEATURE_FTP_WRITE
-       bool "enable write"
+       bool "Enable upload commands"
        default y
        depends on FTPD
        help
-         Enable all kinds of FTP write commands (you have to add -w parameter)
+         Enable all kinds of FTP upload commands (-w option)
 
 config FTPGET
        bool "ftpget"
index ab7308be9a00122eb79512487a92f286414ae4e6..91cbc17f47311681de257a6caeb6123f38a2e036 100644 (file)
  */
 
 #include "libbb.h"
+#include <syslog.h>
 #include <netinet/tcp.h>
 
 enum {
+       OPT_v = (1 << 0),
+       OPT_w = (1 << 1),
+
        FTP_DATACONN            = 150,
        FTP_NOOPOK              = 200,
        FTP_TYPEOK              = 200,
@@ -32,20 +36,14 @@ enum {
        FTP_PASVOK              = 227,
        FTP_LOGINOK             = 230,
        FTP_CWDOK               = 250,
-#if ENABLE_FEATURE_FTP_WRITE
        FTP_RMDIROK             = 250,
        FTP_DELEOK              = 250,
        FTP_RENAMEOK            = 250,
-#endif
        FTP_PWDOK               = 257,
-#if ENABLE_FEATURE_FTP_WRITE
        FTP_MKDIROK             = 257,
-#endif
        FTP_GIVEPWORD           = 331,
        FTP_RESTOK              = 350,
-#if ENABLE_FEATURE_FTP_WRITE
        FTP_RNFROK              = 350,
-#endif
        FTP_BADSENDCONN         = 425,
        FTP_BADSENDNET          = 426,
        FTP_BADSENDFILE         = 451,
@@ -100,16 +98,23 @@ struct globals {
        int data_fd;
        off_t restart_pos;
        char *ftp_cmp;
-       char *ftp_arg;
+       const char *ftp_arg;
 #if ENABLE_FEATURE_FTP_WRITE
        char *rnfr_filename;
-       smallint write_enable;
 #endif
+       smallint opts;
 };
 #define G (*(struct globals*)&bb_common_bufsiz1)
 #define INIT_G() do { } while (0)
 
 
+// libbb candidate?
+static void
+xwrite_str(int fd, const char *str)
+{
+       xwrite(fd, str, strlen(str));
+}
+
 static char *
 replace_text(const char *str, const char from, const char *to)
 {
@@ -119,11 +124,10 @@ replace_text(const char *str, const char from, const char *to)
 
        remain = str;
        remainlen = strlen(str);
-
        tolen = strlen(to);
 
-       /* simply alloc strlen(str)*strlen(to). To is max 2 so it's allowed */
-       ret = xmalloc(remainlen * strlen(to) + 1);
+       /* Simply alloc strlen(str)*strlen(to). "to" is max 2 so it's ok */
+       ret = xmalloc(remainlen * tolen + 1);
        retlen = 0;
 
        for (;;) {
@@ -155,19 +159,8 @@ replace_text(const char *str, const char from, const char *to)
 static void
 replace_char(char *str, char from, char to)
 {
-       char *ptr;
-
-       /* Don't use strchr here...*/
-       while ((ptr = strchr(str, from)) != NULL) {
-               *ptr = to;
-               str = ptr + 1;
-       }
-}
-
-static void
-str_netfd_write(const char *str, int fd)
-{
-       xwrite(fd, str, strlen(str));
+       while ((str = strchr(str, from)) != NULL)
+               *str++ = to;
 }
 
 static void
@@ -182,7 +175,7 @@ ftp_write_str_common(unsigned int status, const char *str, char sep)
        free(escaped_str);
 
        len = strlen(response);
-       replace_char(escaped_str, '\n', '\0');
+       replace_char(response, '\n', '\0');
 
        /* Change trailing '\0' back to '\n' */
        response[len - 1] = '\n';
@@ -195,6 +188,12 @@ cmdio_write(int status, const char *p_text)
        ftp_write_str_common(status, p_text, ' ');
 }
 
+static void
+cmdio_write_ok(int status)
+{
+       ftp_write_str_common(status, "Operation successful", ' ');
+}
+
 static void
 cmdio_write_hyphen(int status, const char *p_text)
 {
@@ -204,24 +203,22 @@ cmdio_write_hyphen(int status, const char *p_text)
 static void
 cmdio_write_raw(const char *p_text)
 {
-       str_netfd_write(p_text, STDIN_FILENO);
+       xwrite_str(STDIN_FILENO, p_text);
 }
 
 static uint32_t
 cmdio_get_cmd_and_arg(void)
 {
-       int len;
+       size_t len;
        uint32_t cmdval;
        char *cmd;
 
        free(G.ftp_cmp);
-       G.ftp_cmp = cmd = xmalloc_reads(STDIN_FILENO, NULL, NULL);
-/*
- * TODO:
- *
- * now we should change all '\0' to '\n' - xmalloc_reads will be improved,
- * probably
- */
+       len = 8 * 1024; /* Paranoia. Peer may send 1 gigabyte long cmd... */
+       G.ftp_cmp = cmd = xmalloc_reads(STDIN_FILENO, NULL, &len);
+       if (!cmd)
+               exit(0);
+
        len = strlen(cmd) - 1;
        while (len >= 0 && cmd[len] == '\r') {
                cmd[len] = '\0';
@@ -230,7 +227,7 @@ cmdio_get_cmd_and_arg(void)
 
        G.ftp_arg = strchr(cmd, ' ');
        if (G.ftp_arg != NULL) {
-               *G.ftp_arg = '\0';
+               *(char *)G.ftp_arg = '\0';
                G.ftp_arg++;
        }
        cmdval = 0;
@@ -338,7 +335,7 @@ handle_pwd(void)
        if (cwd == NULL)
                cwd = xstrdup("");
 
-       /* We _have to_ promote each " to "" */
+       /* We have to promote each " to "" */
        promoted_cwd = replace_text(cwd, '\"', "\"\"");
        free(cwd);
        response = xasprintf("\"%s\"", promoted_cwd);
@@ -350,22 +347,18 @@ handle_pwd(void)
 static void
 handle_cwd(void)
 {
-       int retval;
-
-       /* XXX Do we need check ftp_arg != NULL? */
-       retval = chdir(G.ftp_arg);
-       if (retval == 0)
-               cmdio_write(FTP_CWDOK, "Directory changed");
-       else
+       if (!G.ftp_arg || chdir(G.ftp_arg) != 0) {
                cmdio_write(FTP_FILEFAIL, "Can't change directory");
+               return;
+       }
+       cmdio_write_ok(FTP_CWDOK);
 }
 
 static void
 handle_cdup(void)
 {
-       G.ftp_arg = xstrdup("..");
+       G.ftp_arg = "..";
        handle_cwd();
-       free(G.ftp_arg);
 }
 
 static int
@@ -382,9 +375,7 @@ data_transfer_checks_ok(void)
 static void
 port_cleanup(void)
 {
-       if (G.port_addr != NULL)
-               free(G.port_addr);
-
+       free(G.port_addr);
        G.port_addr = NULL;
 }
 
@@ -396,6 +387,162 @@ pasv_cleanup(void)
        G.pasv_listen_fd = -1;
 }
 
+static void
+handle_pasv(void)
+{
+       int bind_retries = 10;
+       unsigned short port;
+       enum { min_port = 1024, max_port = 65535 };
+       char *addr, *wire_addr, *response;
+
+       pasv_cleanup();
+       port_cleanup();
+       G.pasv_listen_fd = xsocket(G.local_addr->u.sa.sa_family, SOCK_STREAM, 0);
+       setsockopt_reuseaddr(G.pasv_listen_fd);
+
+       /* TODO bind() with port == 0 and then call getsockname */
+       while (--bind_retries) {
+               port = rand() % max_port;
+               if (port < min_port) {
+                       port += min_port;
+               }
+
+               set_nport(G.local_addr, htons(port));
+               /* We don't want to use xbind, it'll die if port is in use */
+               if (bind(G.pasv_listen_fd, &G.local_addr->u.sa, G.local_addr->len) != 0) {
+                       /* do we want check if errno == EADDRINUSE ? */
+                       continue;
+               }
+               xlisten(G.pasv_listen_fd, 1);
+               break;
+       }
+
+       if (!bind_retries)
+               bb_error_msg_and_die("can't create pasv socket");
+
+       addr = xmalloc_sockaddr2dotted_noport(&G.local_addr->u.sa);
+       wire_addr = replace_text(addr, '.', ",");
+       free(addr);
+
+       response = xasprintf("Entering Passive Mode (%s,%u,%u)",
+                       wire_addr, (int)(port >> 8), (int)(port & 255));
+
+       cmdio_write(FTP_PASVOK, response);
+       free(wire_addr);
+       free(response);
+}
+
+static void
+handle_port(void)
+{
+       unsigned short port;
+       char *raw = NULL, *port_part;
+       len_and_sockaddr *lsa = NULL;
+
+       pasv_cleanup();
+       port_cleanup();
+
+       if (G.ftp_arg == NULL)
+               goto bail;
+
+       raw = replace_text(G.ftp_arg, ',', ".");
+
+       port_part = strrchr(raw, '.');
+       if (port_part == NULL)
+               goto bail;
+
+       port = xatou16(&port_part[1]);
+       *port_part = '\0';
+
+       port_part = strrchr(raw, '.');
+       if (port_part == NULL)
+               goto bail;
+
+       port |= xatou16(&port_part[1]) << 8;
+       *port_part = '\0';
+
+       lsa = xdotted2sockaddr(raw, port);
+
+bail:
+       free(raw);
+
+       if (lsa == NULL) {
+               cmdio_write(FTP_BADCMD, "Illegal PORT command");
+               return;
+       }
+
+       G.port_addr = lsa;
+       cmdio_write_ok(FTP_PORTOK);
+}
+
+static void
+handle_rest(void)
+{
+       /* When ftp_arg == NULL simply restart from beginning */
+       G.restart_pos = G.ftp_arg ? xatoi_u(G.ftp_arg) : 0;
+       cmdio_write_ok(FTP_RESTOK);
+}
+
+static void
+handle_retr(void)
+{
+       struct stat statbuf;
+       int trans_ret, retval;
+       int remote_fd;
+       int opened_file;
+       off_t offset = G.restart_pos;
+       char *response;
+
+       G.restart_pos = 0;
+
+       if (!data_transfer_checks_ok())
+               return;
+
+       /* O_NONBLOCK is useful if file happens to be a device node */
+       opened_file = G.ftp_arg ? open(G.ftp_arg, O_RDONLY | O_NONBLOCK) : -1;
+       if (opened_file < 0) {
+               cmdio_write(FTP_FILEFAIL, "Can't open file");
+               return;
+       }
+
+       retval = fstat(opened_file, &statbuf);
+       if (retval < 0 || !S_ISREG(statbuf.st_mode)) {
+               /* Note - pretend open failed */
+               cmdio_write(FTP_FILEFAIL, "Can't open file");
+               goto file_close_out;
+       }
+
+       /* Now deactive O_NONBLOCK, otherwise we have a problem on DMAPI filesystems
+        * such as XFS DMAPI.
+        */
+       ndelay_off(opened_file);
+
+       /* Set the download offset (from REST) if any */
+       if (offset != 0)
+               xlseek(opened_file, offset, SEEK_SET);
+
+       response = xasprintf(
+               "Opening BINARY mode data connection for %s (%"OFF_FMT"u bytes)",
+               G.ftp_arg, statbuf.st_size);
+       remote_fd = get_remote_transfer_fd(response);
+       free(response);
+       if (remote_fd < 0)
+               goto port_pasv_cleanup_out;
+
+       trans_ret = bb_copyfd_eof(opened_file, remote_fd);
+       ftpdataio_dispose_transfer_fd();
+       if (trans_ret < 0)
+               cmdio_write(FTP_BADSENDFILE, "Error sending local file");
+       else
+               cmdio_write_ok(FTP_TRANSFEROK);
+
+port_pasv_cleanup_out:
+       port_cleanup();
+       pasv_cleanup();
+file_close_out:
+       close(opened_file);
+}
+
 static char *
 statbuf_getperms(const struct stat *statbuf)
 {
@@ -472,14 +619,14 @@ write_filestats(int fd, const char *filename,
        } else
                stats = xstrdup(name);
 
-       str_netfd_write(stats, fd);
+       xwrite_str(fd, stats);
        free(stats);
        if (lnkname != NULL) {
-               str_netfd_write(" -> ", fd);
-               str_netfd_write(lnkname, fd);
+               xwrite_str(fd, " -> ");
+               xwrite_str(fd, lnkname);
                free(lnkname);
        }
-       str_netfd_write("\r\n", fd);
+       xwrite_str(fd, "\r\n");
 }
 
 static void
@@ -510,7 +657,7 @@ write_dirstats(int fd, const char *dname, int details)
                        filename = xasprintf("%s/%s", dname, dirent->d_name);
                        if (lstat(filename, &statbuf) != 0) {
                                free(filename);
-                               goto bail;
+                               break;
                        }
                } else
                        filename = xstrdup(dirent->d_name);
@@ -519,116 +666,9 @@ write_dirstats(int fd, const char *dname, int details)
                free(filename);
        }
 
-bail:
        closedir(dir);
 }
 
-static void
-handle_pasv(void)
-{
-       int bind_retries = 10;
-       unsigned short port;
-       enum { min_port = 1024, max_port = 65535 };
-       char *addr, *wire_addr, *response;
-
-       pasv_cleanup();
-       port_cleanup();
-       G.pasv_listen_fd = xsocket(G.local_addr->u.sa.sa_family, SOCK_STREAM, 0);
-       setsockopt_reuseaddr(G.pasv_listen_fd);
-
-       /* TODO bind() with port == 0 and then call getsockname */
-       while (--bind_retries) {
-               port = rand() % max_port;
-               if (port < min_port) {
-                       port += min_port;
-               }
-
-               set_nport(G.local_addr, htons(port));
-               /* We don't want to use xbind, it'll die if port is in use */
-               if (bind(G.pasv_listen_fd, &G.local_addr->u.sa, G.local_addr->len) != 0) {
-                       /* do we want check if errno == EADDRINUSE ? */
-                       continue;
-               }
-               xlisten(G.pasv_listen_fd, 1);
-               break;
-       }
-
-       if (!bind_retries)
-               bb_error_msg_and_die("can't create pasv socket");
-
-       addr = xmalloc_sockaddr2dotted_noport(&G.local_addr->u.sa);
-       wire_addr = replace_text(addr, '.', ",");
-       free(addr);
-
-       response = xasprintf("Entering Passive Mode (%s,%u,%u)",
-                       wire_addr, (int)(port >> 8), (int)(port & 255));
-
-       cmdio_write(FTP_PASVOK, response);
-       free(wire_addr);
-       free(response);
-}
-
-static void
-handle_retr(void)
-{
-       struct stat statbuf;
-       int trans_ret, retval;
-       int remote_fd;
-       int opened_file;
-       off_t offset = G.restart_pos;
-       char *response;
-
-       G.restart_pos = 0;
-
-       if (!data_transfer_checks_ok())
-               return;
-
-       /* XXX Do we need check if ftp_arg != NULL? */
-       opened_file = open(G.ftp_arg, O_RDONLY | O_NONBLOCK);
-       if (opened_file < 0) {
-               cmdio_write(FTP_FILEFAIL, "Can't open file");
-               return;
-       }
-
-       retval = fstat(opened_file, &statbuf);
-       if (retval < 0 || !S_ISREG(statbuf.st_mode)) {
-               /* Note - pretend open failed */
-               cmdio_write(FTP_FILEFAIL, "Can't open file");
-               goto file_close_out;
-       }
-
-       /* Now deactive O_NONBLOCK, otherwise we have a problem on DMAPI filesystems
-        * such as XFS DMAPI.
-        */
-       ndelay_off(opened_file);
-
-       /* Set the download offset (from REST) if any */
-       if (offset != 0)
-               xlseek(opened_file, offset, SEEK_SET);
-
-       response = xasprintf(
-               "Opening BINARY mode data connection for (%s %"OFF_FMT"u bytes).",
-               G.ftp_arg, statbuf.st_size);
-
-       remote_fd = get_remote_transfer_fd(response);
-       free(response);
-       if (remote_fd < 0)
-               goto port_pasv_cleanup_out;
-
-       trans_ret = bb_copyfd_eof(opened_file, remote_fd);
-       ftpdataio_dispose_transfer_fd();
-       if (trans_ret < 0)
-               cmdio_write(FTP_BADSENDFILE, "Error sending local file");
-       else
-               cmdio_write(FTP_TRANSFEROK, "File sent OK");
-
-port_pasv_cleanup_out:
-       port_cleanup();
-       pasv_cleanup();
-file_close_out:
-       close(opened_file);
-}
-
 static void
 handle_dir_common(int full_details, int stat_cmd)
 {
@@ -647,7 +687,7 @@ handle_dir_common(int full_details, int stat_cmd)
                        goto bail;
        }
 
-       if (G.ftp_arg != NULL) {
+       if (G.ftp_arg) {
                if (lstat(G.ftp_arg, &statbuf) != 0) {
                        /* Dir doesn't exist => return ok to client */
                        goto bail;
@@ -665,9 +705,9 @@ bail:
                ftpdataio_dispose_transfer_fd();
                pasv_cleanup();
                port_cleanup();
-               cmdio_write(FTP_TRANSFEROK, "OK");
+               cmdio_write_ok(FTP_TRANSFEROK);
        } else
-               cmdio_write(FTP_STATFILE_OK, "End of status");
+               cmdio_write_ok(FTP_STATFILE_OK);
 }
 
 static void
@@ -676,6 +716,26 @@ handle_list(void)
        handle_dir_common(1, 0);
 }
 
+static void
+handle_nlst(void)
+{
+       handle_dir_common(0, 0);
+}
+
+static void
+handle_stat_file(void)
+{
+       handle_dir_common(1, 1);
+}
+
+static void
+handle_stat(void)
+{
+       cmdio_write_hyphen(FTP_STATOK, "FTP server status:");
+       cmdio_write_raw(" TYPE: BINARY\r\n");
+       cmdio_write_ok(FTP_STATOK);
+}
+
 static void
 handle_type(void)
 {
@@ -685,81 +745,47 @@ handle_type(void)
            || !strcasecmp(G.ftp_arg, "L 8")
            )
        ) {
-               cmdio_write(FTP_TYPEOK, "Switching to Binary mode");
+               cmdio_write_ok(FTP_TYPEOK);
        } else {
                cmdio_write(FTP_BADCMD, "Unrecognised TYPE command");
        }
 }
 
 static void
-handle_port(void)
+handle_help(void)
 {
-       unsigned short port;
-       char *raw = NULL, *port_part;
-       len_and_sockaddr *lsa = NULL;
-
-       pasv_cleanup();
-       port_cleanup();
-
-       if (G.ftp_arg == NULL)
-               goto bail;
-
-       raw = replace_text(G.ftp_arg, ',', ".");
-
-       port_part = strrchr(raw, '.');
-       if (port_part == NULL)
-               goto bail;
-
-       port = xatou16(&port_part[1]);
-       *port_part = '\0';
-
-       port_part = strrchr(raw, '.');
-       if (port_part == NULL)
-               goto bail;
-
-       port |= xatou16(&port_part[1]) << 8;
-       *port_part = '\0';
-
-       lsa = xdotted2sockaddr(raw, port);
-
-bail:
-       free(raw);
-
-       if (lsa == NULL) {
-               cmdio_write(FTP_BADCMD, "Illegal PORT command");
-               return;
-       }
-
-       G.port_addr = lsa;
-       cmdio_write(FTP_PORTOK, "PORT command successful. Consider using PASV");
+       cmdio_write_hyphen(FTP_HELP, "Recognized commands:");
+       cmdio_write_raw(" ALLO CDUP CWD HELP LIST\r\n"
+                       " MODE NLST NOOP PASS PASV PORT PWD QUIT\r\n"
+                       " REST RETR STAT STRU SYST TYPE USER\r\n"
+#if ENABLE_FEATURE_FTP_WRITE
+                       " APPE DELE MKD RMD RNFR RNTO STOR STOU\r\n"
+#endif
+       );
+       cmdio_write(FTP_HELP, "Help OK");
 }
 
 #if ENABLE_FEATURE_FTP_WRITE
 static void
 handle_upload_common(int is_append, int is_unique)
 {
-       char *template = NULL;
+       char *tempname = NULL;
        int trans_ret;
        int new_file_fd;
        int remote_fd;
-
-       enum {
-               fileflags = O_CREAT | O_WRONLY | O_APPEND,
-       };
-
        off_t offset = G.restart_pos;
 
        G.restart_pos = 0;
-       if (!data_transfer_checks_ok())
+       if (!G.ftp_arg || !data_transfer_checks_ok())
                return;
 
        if (is_unique) {
-               template = xstrdup("uniq.XXXXXX");
+               tempname = xstrdup("FILE: uniq.XXXXXX");
                /*
                 * XXX Use mkostemp here? vsftpd opens file with O_CREAT, O_WRONLY, 
                 * O_APPEND and O_EXCL flags...
                 */
-               new_file_fd = mkstemp(template);
+               new_file_fd = mkstemp(tempname + 6);
        } else {
                /* XXX Do we need check if ftp_arg != NULL? */
                if (!is_append && offset == 0)
@@ -778,11 +804,9 @@ handle_upload_common(int is_append, int is_unique)
                xlseek(new_file_fd, offset, SEEK_SET);
        }
 
-       if (is_unique) {
-               char *resp = xasprintf("FILE: %s", template);
-               remote_fd = get_remote_transfer_fd(resp);
-               free(resp);
-               free(template);
+       if (tempname) {
+               remote_fd = get_remote_transfer_fd(tempname);
+               free(tempname);
        } else
                remote_fd = get_remote_transfer_fd("Ok to send data");
 
@@ -795,7 +819,7 @@ handle_upload_common(int is_append, int is_unique)
        if (trans_ret < 0)
                cmdio_write(FTP_BADSENDFILE, "Failure writing to local file");
        else
-               cmdio_write(FTP_TRANSFEROK, "File receive OK");
+               cmdio_write_ok(FTP_TRANSFEROK);
 
 bail:
        port_cleanup();
@@ -803,80 +827,54 @@ bail:
        close(new_file_fd);
 }
 
-static void
-handle_stor(void)
-{
-       handle_upload_common(0, 0);
-}
-
 static void
 handle_mkd(void)
 {
-       int retval;
-
-       /* Do we need check if ftp_arg != NULL? */
-       retval = mkdir(G.ftp_arg, 0770);
-       if (retval != 0) {
+       if (!G.ftp_arg || mkdir(G.ftp_arg, 0777) != 0) {
                cmdio_write(FTP_FILEFAIL, "Create directory operation failed");
                return;
        }
-
-       cmdio_write(FTP_MKDIROK, "created");
+       cmdio_write_ok(FTP_MKDIROK);
 }
 
 static void
 handle_rmd(void)
 {
-       int retval;
-
-       /* Do we need check if ftp_arg != NULL? */
-       retval = rmdir(G.ftp_arg);
-       if (retval != 0)
-               cmdio_write(FTP_FILEFAIL, "rmdir failed");
-       else
-               cmdio_write(FTP_RMDIROK, "rmdir successful");
+       if (!G.ftp_arg || rmdir(G.ftp_arg) != 0) {
+               cmdio_write(FTP_FILEFAIL, "Deletion failed");
+               return;
+       }
+       cmdio_write_ok(FTP_RMDIROK);
 }
 
 static void
 handle_dele(void)
 {
-       int retval;
-
-       /* Do we need check if ftp_arg != NULL? */
-       retval = unlink(G.ftp_arg);
-       if (retval != 0)
-               cmdio_write(FTP_FILEFAIL, "Delete failed");
-       else
-               cmdio_write(FTP_DELEOK, "Delete successful");
-}
-#endif /* ENABLE_FEATURE_FTP_WRITE */
-
-static void
-handle_rest(void)
-{
-       /* When ftp_arg == NULL simply restart from beginning */
-       G.restart_pos = xatoi_u(G.ftp_arg);
-       cmdio_write(FTP_RESTOK, "Restart OK");
+       if (!G.ftp_arg || unlink(G.ftp_arg) != 0) {
+               cmdio_write(FTP_FILEFAIL, "Deletion failed");
+               return;
+       }
+       cmdio_write_ok(FTP_DELEOK);
 }
 
-#if ENABLE_FEATURE_FTP_WRITE
 static void
 handle_rnfr(void)
 {
        struct stat statbuf;
-       int retval;
 
        /* Clear old value */
        free(G.rnfr_filename);
+       G.rnfr_filename = NULL;
 
-       /* Does it exist? Do we need check if ftp_arg != NULL? */
-       retval = stat(G.ftp_arg, &statbuf);
-       if (retval == 0) {
-               /* Yes */
-               G.rnfr_filename = xstrdup(G.ftp_arg);
-               cmdio_write(FTP_RNFROK, "Ready for RNTO");
-       } else
+       if (!G.ftp_arg
+        || stat(G.ftp_arg, &statbuf) != 0
+       /* || it isn't a regular file or a directory? */
+       ) {
                cmdio_write(FTP_FILEFAIL, "RNFR command failed");
+               return;
+       }
+       G.rnfr_filename = xstrdup(G.ftp_arg);
+       cmdio_write_ok(FTP_RNFROK);
 }
 
 static void
@@ -885,72 +883,40 @@ handle_rnto(void)
        int retval;
 
        /* If we didn't get a RNFR, throw a wobbly */
-       if (G.rnfr_filename == NULL) {
+       if (G.rnfr_filename == NULL || G.ftp_arg == NULL) {
                cmdio_write(FTP_NEEDRNFR, "RNFR required first");
                return;
        }
 
-       /* XXX Do we need check if ftp_arg != NULL? */
        retval = rename(G.rnfr_filename, G.ftp_arg);
-
        free(G.rnfr_filename);
+       G.rnfr_filename = NULL;
 
-       if (retval == 0)
-               cmdio_write(FTP_RENAMEOK, "Rename successful");
-       else
+       if (retval) {
                cmdio_write(FTP_FILEFAIL, "Rename failed");
+               return;
+       }
+       cmdio_write_ok(FTP_RENAMEOK);
 }
-#endif /* ENABLE_FEATURE_FTP_WRITE */
 
 static void
-handle_nlst(void)
+handle_stor(void)
 {
-       handle_dir_common(0, 0);
+       handle_upload_common(0, 0);
 }
 
-#if ENABLE_FEATURE_FTP_WRITE
 static void
 handle_appe(void)
 {
        handle_upload_common(1, 0);
 }
-#endif
 
-static void
-handle_help(void)
-{
-       cmdio_write_hyphen(FTP_HELP, "Recognized commands:");
-       cmdio_write_raw(" ALLO CDUP CWD HELP LIST\r\n"
-                       " MODE NLST NOOP PASS PASV PORT PWD QUIT\r\n"
-                       " REST RETR STAT STRU SYST TYPE USER\r\n"
-#if ENABLE_FEATURE_FTP_WRITE
-                       " APPE DELE MKD RMD RNFR RNTO STOR STOU\r\n"
-#endif
-       );
-       cmdio_write(FTP_HELP, "Help OK");
-}
-
-#if ENABLE_FEATURE_FTP_WRITE
 static void
 handle_stou(void)
 {
        handle_upload_common(0, 1);
 }
-#endif
-
-static void
-handle_stat(void)
-{
-       cmdio_write_hyphen(FTP_STATOK, "FTP server status:");
-       cmdio_write_raw(" TYPE: BINARY\r\n");
-       cmdio_write(FTP_STATOK, "End of status");
-}
-
-static void
-handle_stat_file(void)
-{
-       handle_dir_common(1, 1);
-}
+#endif /* ENABLE_FEATURE_FTP_WRITE */
 
 /* TODO: libbb candidate (tftp has another copy) */
 static len_and_sockaddr *get_sock_lsa(int s)
@@ -969,8 +935,6 @@ static len_and_sockaddr *get_sock_lsa(int s)
 int ftpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 int ftpd_main(int argc UNUSED_PARAM, char **argv)
 {
-       smallint user_was_specified = 0;
-
        INIT_G();
 
        G.local_addr = get_sock_lsa(STDIN_FILENO);
@@ -984,52 +948,95 @@ int ftpd_main(int argc UNUSED_PARAM, char **argv)
                 * failure */
        }
 
-       logmode = LOGMODE_SYSLOG;
+       G.opts = getopt32(argv, "v" USE_FEATURE_FTP_WRITE("w"));
+
+       openlog(applet_name, LOG_PID, LOG_DAEMON);
+       logmode |= LOGMODE_SYSLOG;
+       if (!(G.opts & OPT_v))
+               logmode = LOGMODE_SYSLOG;
 
-       USE_FEATURE_FTP_WRITE(G.write_enable =) getopt32(argv, "" USE_FEATURE_FTP_WRITE("w"));
        if (argv[optind]) {
                xchdir(argv[optind]);
                chroot(".");
        }
 
-//     if (G.local_addr->u.sa.sa_family != AF_INET)
-//             bb_error_msg_and_die("Only IPv4 is supported");
+       //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);
 
-       /* Set up options on the command socket */
+       /* 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(STDIN_FILENO, SOL_SOCKET, SO_OOBINLINE, &const_int_1, sizeof(const_int_1));
 
        cmdio_write(FTP_GREET, "Welcome");
 
-       while (1) {
-               uint32_t cmdval = cmdio_get_cmd_and_arg();
-
-               if (cmdval == const_USER) {
-                       if (G.ftp_arg == NULL || strcasecmp(G.ftp_arg, "anonymous") != 0)
-                               cmdio_write(FTP_LOGINERR, "Server is anonymous only");
-                       else {
-                               user_was_specified = 1;
-                               cmdio_write(FTP_GIVEPWORD, "Please specify the password");
+#ifdef IF_WE_WANT_TO_REQUIRE_LOGIN
+       {
+               smallint user_was_specified = 0;
+               while (1) {
+                       uint32_t cmdval = cmdio_get_cmd_and_arg();
+
+                       if (cmdval == const_USER) {
+                               if (G.ftp_arg == NULL || strcasecmp(G.ftp_arg, "anonymous") != 0)
+                                       cmdio_write(FTP_LOGINERR, "Server is anonymous only");
+                               else {
+                                       user_was_specified = 1;
+                                       cmdio_write(FTP_GIVEPWORD, "Please specify the password");
+                               }
+                       } else if (cmdval == const_PASS) {
+                               if (user_was_specified)
+                                       break;
+                               cmdio_write(FTP_NEEDUSER, "Login with USER");
+                       } else if (cmdval == const_QUIT) {
+                               cmdio_write(FTP_GOODBYE, "Goodbye");
+                               return 0;
+                       } else {
+                               cmdio_write(FTP_LOGINERR, "Login with USER and PASS");
                        }
-               } else if (cmdval == const_PASS) {
-                       if (user_was_specified)
-                               break;
-                       cmdio_write(FTP_NEEDUSER, "Login with USER");
-               } else if (cmdval == const_QUIT) {
-                       cmdio_write(FTP_GOODBYE, "Goodbye");
-                       return 0;
-               } else {
-                       cmdio_write(FTP_LOGINERR,
-                               "Login with USER and PASS");
                }
        }
+       cmdio_write_ok(FTP_LOGINOK);
+#endif
 
-       umask(077);
-       cmdio_write(FTP_LOGINOK, "Login successful");
+       /* 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
+        * file system or operating system does not allow or support
+        * a particular command.
+        * Type: ASCII Non-print, IMAGE, LOCAL 8
+        * Mode: Stream
+        * Structure: File, Record*
+        * (Record structure is REQUIRED only for hosts whose file
+        *  systems support record structure).
+        * Commands:
+        * USER, PASS, ACCT, [bbox: ACCT not supported]
+        * PORT, PASV,
+        * TYPE, MODE, STRU,
+        * RETR, STOR, APPE,
+        * RNFR, RNTO, DELE,
+        * CWD,  CDUP, RMD,  MKD,  PWD,
+        * LIST, NLST,
+        * SYST, STAT,
+        * HELP, NOOP, QUIT.
+        */
+       /* ACCOUNT (ACCT)
+        * The argument field is a Telnet string identifying the user's account.
+        * The command is not necessarily related to the USER command, as some
+        * sites may require an account for login and others only for specific
+        * access, such as storing files. In the latter case the command may
+        * arrive at any time.
+        * There are reply codes to differentiate these cases for the automation:
+        * when account information is required for login, the response to
+        * a successful PASSword command is reply code 332. On the other hand,
+        * if account information is NOT required for login, the reply to
+        * a successful PASSword command is 230; and if the account information
+        * is needed for a command issued later in the dialogue, the server
+        * should return a 332 or 532 reply depending on whether it stores
+        * (pending receipt of the ACCounT command) or discards the command,
+        * respectively.
+        */
 
        while (1) {
                uint32_t cmdval = cmdio_get_cmd_and_arg();
@@ -1042,19 +1049,19 @@ int ftpd_main(int argc UNUSED_PARAM, char **argv)
                        handle_pwd();
                else if (cmdval == const_CWD)
                        handle_cwd();
-               else if (cmdval == const_CDUP)
+               else if (cmdval == const_CDUP) /* cd .. */
                        handle_cdup();
                else if (cmdval == const_PASV)
                        handle_pasv();
                else if (cmdval == const_RETR)
                        handle_retr();
                else if (cmdval == const_NOOP)
-                       cmdio_write(FTP_NOOPOK, "NOOP ok");
+                       cmdio_write_ok(FTP_NOOPOK);
                else if (cmdval == const_SYST)
                        cmdio_write(FTP_SYSTOK, "UNIX Type: L8");
                else if (cmdval == const_HELP)
                        handle_help();
-               else if (cmdval == const_LIST)
+               else if (cmdval == const_LIST) /* ls -l */
                        handle_list();
                else if (cmdval == const_TYPE)
                        handle_type();
@@ -1062,10 +1069,40 @@ int ftpd_main(int argc UNUSED_PARAM, char **argv)
                        handle_port();
                else if (cmdval == const_REST)
                        handle_rest();
-               else if (cmdval == const_NLST)
+               else if (cmdval == const_NLST) /* "name list", bare ls */
                        handle_nlst();
+               else if (cmdval == const_STRU) {
+                       //if (G.ftp_arg
+                       // && (G.ftp_arg[0] | 0x20) == 'f'
+                       // && G.ftp_arg[1] == '\0'
+                       //) {
+                               cmdio_write(FTP_STRUOK, "Command ignored");
+                       //} else
+                       //      cmdio_write(FTP_BADSTRU, "Bad STRU command");
+               } else if (cmdval == const_MODE) {
+                       //if (G.ftp_arg
+                       // && (G.ftp_arg[0] | 0x20) == 's'
+                       // && G.ftp_arg[1] == '\0'
+                       //) {
+                               cmdio_write(FTP_MODEOK, "Command ignored");
+                       //} else
+                       //      cmdio_write(FTP_BADMODE, "Bad MODE command");
+               }
+               else if (cmdval == const_ALLO)
+                       cmdio_write(FTP_ALLOOK, "Command ignored");
+               else if (cmdval == const_STAT) {
+                       if (G.ftp_arg == NULL)
+                               handle_stat();
+                       else
+                               handle_stat_file();
+               } else if (cmdval == const_USER) {
+                       /* FTP_LOGINERR confuses clients: */
+                       /* cmdio_write(FTP_LOGINERR, "Can't change to another user"); */
+                       cmdio_write(FTP_GIVEPWORD, "Command ignored");
+               } else if (cmdval == const_PASS)
+                       cmdio_write(FTP_LOGINOK, "Command ignored");
 #if ENABLE_FEATURE_FTP_WRITE
-               else if (G.write_enable) {
+               else if (G.opts & OPT_w) {
                        if (cmdval == const_STOR)
                                handle_stor();
                        else if (cmdval == const_MKD)
@@ -1074,45 +1111,17 @@ int ftpd_main(int argc UNUSED_PARAM, char **argv)
                                handle_rmd();
                        else if (cmdval == const_DELE)
                                handle_dele();
-                       else if (cmdval == const_RNFR)
+                       else if (cmdval == const_RNFR) /* "rename from" */
                                handle_rnfr();
-                       else if (cmdval == const_RNTO)
+                       else if (cmdval == const_RNTO) /* "rename to" */
                                handle_rnto();
                        else if (cmdval == const_APPE)
                                handle_appe();
-                       else if (cmdval == const_STOU)
+                       else if (cmdval == const_STOU) /* "store unique" */
                                handle_stou();
                }
 #endif
-               else if (cmdval == const_STRU) {
-                       if (G.ftp_arg
-                        && (G.ftp_arg[0] | 0x20) == 'f'
-                        && G.ftp_arg[1] == '\0'
-                       ) {
-                               cmdio_write(FTP_STRUOK, "Structure set to F");
-                       } else
-                               cmdio_write(FTP_BADSTRU, "Bad STRU command");
-
-               } else if (cmdval == const_MODE) {
-                       if (G.ftp_arg
-                        && (G.ftp_arg[0] | 0x20) == 's'
-                        && G.ftp_arg[1] == '\0'
-                       ) {
-                               cmdio_write(FTP_MODEOK, "Mode set to S");
-                       } else
-                               cmdio_write(FTP_BADMODE, "Bad MODE command");
-               }
-               else if (cmdval == const_ALLO)
-                       cmdio_write(FTP_ALLOOK, "ALLO command ignored");
-               else if (cmdval == const_STAT) {
-                       if (G.ftp_arg == NULL)
-                               handle_stat();
-                       else
-                               handle_stat_file();
-               } else if (cmdval == const_USER)
-                       cmdio_write(FTP_LOGINERR, "Can't change to another user");
-               else if (cmdval == const_PASS)
-                       cmdio_write(FTP_LOGINOK, "Already logged in");
+#if 0
                else if (cmdval == const_STOR
                 || cmdval == const_MKD
                 || cmdval == const_RMD
@@ -1123,7 +1132,14 @@ int ftpd_main(int argc UNUSED_PARAM, char **argv)
                 || cmdval == const_STOU
                ) {
                        cmdio_write(FTP_NOPERM, "Permission denied");
-               } else {
+               }
+#endif
+               else {
+                       /* Which unsupported commands were seen in the wild
+                        * (doesn't necessarily mean "we must support them")
+                        * wget 1.11.4: SIZE - todo.
+                        * lftp 3.6.3: MDTM - works fine without it anyway.
+                        */
                        cmdio_write(FTP_BADCMD, "Unknown command");
                }
        }
index e08ebd4b3dacad4c5c577e8e6ec0f87b5e631752..e8ba007667255e51519062dc208a60355f551be5 100644 (file)
@@ -122,7 +122,7 @@ int fakeidentd_main(int argc UNUSED_PARAM, char **argv)
         * log to stderr. I like daemontools more. Go their way.
         * (Or maybe we need yet another option "log to syslog") */
        if (!(opt & OPT_fiw) /* || (opt & OPT_syslog) */) {
-               openlog(applet_name, 0, LOG_DAEMON);
+               openlog(applet_name, LOG_PID, LOG_DAEMON);
                logmode = LOGMODE_SYSLOG;
        }
 
index 59d609bc8ed0672c9781fddfa35481adb9a2f500..ccf32892508a45397dae392f4a8e79f66cf05153 100644 (file)
@@ -452,7 +452,7 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv)
        }
        /* Redirect log to syslog early, if needed */
        if (IS_INETD || !(opt & OPT_FOREGROUND)) {
-               openlog(applet_name, 0, LOG_USER);
+               openlog(applet_name, LOG_PID, LOG_DAEMON);
                logmode = LOGMODE_SYSLOG;
        }
        USE_FEATURE_TELNETD_STANDALONE(
index da58a5a8e87cdf5d0e5eaa1622f3911d7e8f58b7..903f3d3267281fca4325dc1f6569230c9c966bbb 100644 (file)
@@ -284,7 +284,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
        }
 #endif
        if (opt & OPT_S) {
-               openlog(applet_name, LOG_PID, LOG_LOCAL0);
+               openlog(applet_name, LOG_PID, LOG_DAEMON);
                logmode |= LOGMODE_SYSLOG;
        }
 
index ebf30178ac13ba01aa3a262c84f22b50ff065706..15b31eb3dc8c6073a4265a8f4d68b4502d0f83bc 100644 (file)
@@ -53,7 +53,7 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv)
        }
 
        if (opt & 2) { /* -S */
-               openlog(applet_name, LOG_PID, LOG_LOCAL0);
+               openlog(applet_name, LOG_PID, LOG_DAEMON);
                logmode |= LOGMODE_SYSLOG;
        }
 #if ENABLE_FEATURE_UDHCP_PORT