tftpd: make open() check r/w permissions instead of doing it ourself.
authorDenis Vlasenko <vda.linux@googlemail.com>
Tue, 18 Mar 2008 01:13:11 +0000 (01:13 -0000)
committerDenis Vlasenko <vda.linux@googlemail.com>
Tue, 18 Mar 2008 01:13:11 +0000 (01:13 -0000)
Add -r "prohibit upload" opt for those lazy people who run tftpd as root.
-40 bytes.

include/usage.h
networking/tftp.c

index 1fa40ce987e763abfe56fe790855df51883631ac..7fe9ad0635e5f94f6fc269c35cedb65c72fa10c4 100644 (file)
        )
 
 #define tftpd_trivial_usage \
-       "[DIR]"
+       "[-r] [DIR]"
 #define tftpd_full_usage \
-       "Transfer a file on request from a tftp client" \
+       "Transfer a file on request from a tftp client.\n" \
+     "\nOptions:" \
+     "\n       -r      Prohibit upload" \
 
 #define time_trivial_usage \
        "[OPTION]... COMMAND [ARGS...]"
index 25001c22c05654fccd53ed35c3e09ac83f5b4a21..3075ab04bd97df0f8294c1111160fcc8e35cc64e 100644 (file)
@@ -56,6 +56,8 @@
  * CMD_GET(cmd) and CMD_PUT(cmd) are mutually exclusive
  */
 
+// TODO: emit error packets before dying
+
 
 #if ENABLE_FEATURE_TFTP_BLOCKSIZE
 
@@ -340,7 +342,7 @@ static int tftp_protocol(
 
                        const char *msg = "";
 
-                       if (rbuf[4] != '\0') {
+                       if (len > 4 && rbuf[4] != '\0') {
                                msg = &rbuf[4];
                                rbuf[tftp_bufsize - 1] = '\0';
                        } else if (recv_blk < ARRAY_SIZE(errcode_str)) {
@@ -533,14 +535,14 @@ static len_and_sockaddr *get_sock_lsa(int s)
 }
 
 int tftpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
-int tftpd_main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
+int tftpd_main(int argc ATTRIBUTE_UNUSED, char **argv)
 {
-       struct stat statbuf;
        char block_buf[TFTP_BLOCKSIZE_DEFAULT];
        len_and_sockaddr *our_lsa;
        len_and_sockaddr *peer_lsa;
        char *filename, *mode, *opt_str;
-       int result, opcode, cmd, req_modebits, open_mode, local_fd, blksize;
+       int opt_r, result, opcode, open_mode, local_fd, blksize;
+       USE_GETPUT(int cmd;)
 
        our_lsa = get_sock_lsa(STDIN_FILENO);
        if (!our_lsa)
@@ -548,8 +550,10 @@ int tftpd_main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
        peer_lsa = xzalloc(LSA_LEN_SIZE + our_lsa->len);
        peer_lsa->len = our_lsa->len;
 
-       if (argv[1])
-               xchdir(argv[1]);
+       opt_r = getopt32(argv, "r");
+       argv += optind;
+       if (argv[0])
+               xchdir(argv[0]);
 
        result = recv_from_to(STDIN_FILENO, block_buf, sizeof(block_buf),
                        0 /* flags */,
@@ -558,7 +562,10 @@ int tftpd_main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
        opcode = ntohs(*(uint16_t*)block_buf);
        if (result < 4 || result >= sizeof(block_buf)
         || block_buf[result-1] != '\0'
-        || (opcode != TFTP_RRQ && opcode != TFTP_WRQ)
+        || (USE_FEATURE_TFTP_GET(opcode != TFTP_RRQ) /* not download */
+            USE_GETPUT(&&)
+            USE_FEATURE_TFTP_GET(opcode != TFTP_WRQ) /* not upload */
+           )
        ) {
                bb_error_msg_and_die("malformed packet");
        }
@@ -584,21 +591,20 @@ int tftpd_main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
                }
        }
 #endif
-       xstat(filename, &statbuf);
-       /* if opcode == TFTP_WRQ: */
-       cmd = 1; /* CMD_GET: we will receive file's data */
-       req_modebits = 0222; /* writable by anyone */
-       open_mode = O_WRONLY | O_TRUNC;
-       if (opcode == TFTP_RRQ) {
-               cmd = 2; /* CMD_PUT */
-               req_modebits = 0444; /* readable by anyone */
-               open_mode = O_RDONLY;
-       }
-       if (!S_ISREG(statbuf.st_mode)
-        || (statbuf.st_mode & req_modebits) != req_modebits
-       ) {
-               bb_error_msg_and_die("access to '%s' is denied", filename);
+
+#if ENABLE_FEATURE_TFTP_PUT
+       /* in case opcode is TFTP_RRQ: */
+       USE_GETPUT(cmd = 2;) /* CMD_PUT: we will send file's data */
+       open_mode = O_RDONLY;
+#endif
+#if ENABLE_FEATURE_TFTP_GET
+       if (!ENABLE_FEATURE_TFTP_PUT || opcode == TFTP_WRQ) {
+               if (opt_r)
+                       bb_error_msg_and_die("upload is prohibited");
+               USE_GETPUT(cmd = 1;) /* CMD_GET: we will receive file's data */
+               open_mode = O_WRONLY | O_TRUNC;
        }
+#endif
        local_fd = xopen(filename, open_mode);
 
        close(STDIN_FILENO); /* close old, possibly wildcard socket */