aboutsummaryrefslogtreecommitdiff
path: root/networking/ftpd.c
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2009-03-16 16:19:53 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2009-03-16 16:19:53 +0000
commit20c82168976a511237b45eef94891e9124f47f7a (patch)
tree034de657c181a5dbe623b9fc670cec637231b257 /networking/ftpd.c
parentf2160b6a09f4e4879fb718526106c548d8f8ec23 (diff)
downloadbusybox-w32-20c82168976a511237b45eef94891e9124f47f7a.tar.gz
busybox-w32-20c82168976a511237b45eef94891e9124f47f7a.tar.bz2
busybox-w32-20c82168976a511237b45eef94891e9124f47f7a.zip
ftpd: add idle and absolute timeouts. This is a security issue,
otherwise ftpd may end up hanging indefinitely. function old new delta timeout_handler - 110 +110 ftpd_main 2019 2115 +96 packed_usage 25662 25685 +23 handle_upload_common 306 322 +16 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 3/0 up/down: 245/0) Total: 245 bytes
Diffstat (limited to 'networking/ftpd.c')
-rw-r--r--networking/ftpd.c70
1 files changed, 50 insertions, 20 deletions
diff --git a/networking/ftpd.c b/networking/ftpd.c
index 22cec83a8..d63fd9bed 100644
--- a/networking/ftpd.c
+++ b/networking/ftpd.c
@@ -8,11 +8,6 @@
8 * 8 *
9 * Only subset of FTP protocol is implemented but vast majority of clients 9 * Only subset of FTP protocol is implemented but vast majority of clients
10 * should not have any problem. You have to run this daemon via inetd. 10 * should not have any problem. You have to run this daemon via inetd.
11 *
12 * Options:
13 * -w - enable FTP write commands
14 *
15 * TODO: implement "421 Timeout" thingy (alarm(60) while waiting for a cmd).
16 */ 11 */
17 12
18#include "libbb.h" 13#include "libbb.h"
@@ -46,6 +41,7 @@
46#define FTP_GIVEPWORD 331 41#define FTP_GIVEPWORD 331
47#define FTP_RESTOK 350 42#define FTP_RESTOK 350
48#define FTP_RNFROK 350 43#define FTP_RNFROK 350
44#define FTP_TIMEOUT 421
49#define FTP_BADSENDCONN 425 45#define FTP_BADSENDCONN 425
50#define FTP_BADSENDNET 426 46#define FTP_BADSENDNET 426
51#define FTP_BADSENDFILE 451 47#define FTP_BADSENDFILE 451
@@ -77,12 +73,16 @@ enum {
77) 73)
78 74
79struct globals { 75struct globals {
80 char *p_control_line_buf;
81 len_and_sockaddr *local_addr;
82 len_and_sockaddr *port_addr;
83 int pasv_listen_fd; 76 int pasv_listen_fd;
84 int proc_self_fd; 77 int proc_self_fd;
78 int local_file_fd;
79 int start_time;
80 int abs_timeout;
81 int timeout;
82 off_t local_file_pos;
85 off_t restart_pos; 83 off_t restart_pos;
84 len_and_sockaddr *local_addr;
85 len_and_sockaddr *port_addr;
86 char *ftp_cmd; 86 char *ftp_cmd;
87 char *ftp_arg; 87 char *ftp_arg;
88#if ENABLE_FEATURE_FTP_WRITE 88#if ENABLE_FEATURE_FTP_WRITE
@@ -179,6 +179,33 @@ cmdio_write_raw(const char *p_text)
179 xwrite_str(STDOUT_FILENO, p_text); 179 xwrite_str(STDOUT_FILENO, p_text);
180} 180}
181 181
182static void
183timeout_handler(int sig UNUSED_PARAM)
184{
185 off_t pos;
186 int sv_errno = errno;
187
188 if (monotonic_sec() - G.start_time > G.abs_timeout)
189 goto timed_out;
190
191 if (!G.local_file_fd)
192 goto timed_out;
193
194 pos = xlseek(G.local_file_fd, 0, SEEK_CUR);
195 if (pos == G.local_file_pos)
196 goto timed_out;
197 G.local_file_pos = pos;
198
199 alarm(G.timeout);
200 errno = sv_errno;
201 return;
202
203 timed_out:
204 cmdio_write_raw(STR(FTP_TIMEOUT)" Timeout\r\n");
205/* TODO: do we need to abort (as opposed to usual shutdown) data transfer? */
206 exit(1);
207}
208
182/* Simple commands */ 209/* Simple commands */
183 210
184static void 211static void
@@ -488,6 +515,7 @@ handle_retr(void)
488 cmdio_write_error(FTP_FILEFAIL); 515 cmdio_write_error(FTP_FILEFAIL);
489 goto file_close_out; 516 goto file_close_out;
490 } 517 }
518 G.local_file_fd = local_file_fd;
491 519
492 /* Now deactive O_NONBLOCK, otherwise we have a problem 520 /* Now deactive O_NONBLOCK, otherwise we have a problem
493 * on DMAPI filesystems such as XFS DMAPI. 521 * on DMAPI filesystems such as XFS DMAPI.
@@ -506,11 +534,6 @@ handle_retr(void)
506 if (remote_fd < 0) 534 if (remote_fd < 0)
507 goto file_close_out; 535 goto file_close_out;
508 536
509/* TODO: if we'll implement timeout, this will need more clever handling.
510 * Perhaps alarm(N) + checking that current position on local_file_fd
511 * is advancing. As of now, peer may stall us indefinitely.
512 */
513
514 bytes_transferred = bb_copyfd_eof(local_file_fd, remote_fd); 537 bytes_transferred = bb_copyfd_eof(local_file_fd, remote_fd);
515 close(remote_fd); 538 close(remote_fd);
516 if (bytes_transferred < 0) 539 if (bytes_transferred < 0)
@@ -520,6 +543,7 @@ handle_retr(void)
520 543
521 file_close_out: 544 file_close_out:
522 close(local_file_fd); 545 close(local_file_fd);
546 G.local_file_fd = 0;
523} 547}
524 548
525/* List commands */ 549/* List commands */
@@ -753,6 +777,7 @@ handle_upload_common(int is_append, int is_unique)
753 goto close_local_and_bail; 777 goto close_local_and_bail;
754 return; 778 return;
755 } 779 }
780 G.local_file_fd = local_file_fd;
756 781
757 if (offset) 782 if (offset)
758 xlseek(local_file_fd, offset, SEEK_SET); 783 xlseek(local_file_fd, offset, SEEK_SET);
@@ -763,11 +788,6 @@ handle_upload_common(int is_append, int is_unique)
763 if (remote_fd < 0) 788 if (remote_fd < 0)
764 goto close_local_and_bail; 789 goto close_local_and_bail;
765 790
766/* TODO: if we'll implement timeout, this will need more clever handling.
767 * Perhaps alarm(N) + checking that current position on local_file_fd
768 * is advancing. As of now, peer may stall us indefinitely.
769 */
770
771 bytes_transferred = bb_copyfd_eof(remote_fd, local_file_fd); 791 bytes_transferred = bb_copyfd_eof(remote_fd, local_file_fd);
772 close(remote_fd); 792 close(remote_fd);
773 if (bytes_transferred < 0) 793 if (bytes_transferred < 0)
@@ -777,6 +797,7 @@ handle_upload_common(int is_append, int is_unique)
777 797
778 close_local_and_bail: 798 close_local_and_bail:
779 close(local_file_fd); 799 close(local_file_fd);
800 G.local_file_fd = 0;
780} 801}
781 802
782static void 803static void
@@ -807,6 +828,8 @@ cmdio_get_cmd_and_arg(void)
807 uint32_t cmdval; 828 uint32_t cmdval;
808 char *cmd; 829 char *cmd;
809 830
831 alarm(G.timeout);
832
810 free(G.ftp_cmd); 833 free(G.ftp_cmd);
811 len = 8 * 1024; /* Paranoia. Peer may send 1 gigabyte long cmd... */ 834 len = 8 * 1024; /* Paranoia. Peer may send 1 gigabyte long cmd... */
812 G.ftp_cmd = cmd = xmalloc_reads(STDIN_FILENO, NULL, &len); 835 G.ftp_cmd = cmd = xmalloc_reads(STDIN_FILENO, NULL, &len);
@@ -878,17 +901,23 @@ int ftpd_main(int argc, char **argv)
878{ 901{
879 smallint opts; 902 smallint opts;
880 903
881 opts = getopt32(argv, "l1vS" USE_FEATURE_FTP_WRITE("w")); 904 INIT_G();
905
906 G.start_time = monotonic_sec();
907 G.abs_timeout = 1 * 60 * 60;
908 G.timeout = 2 * 60;
909 opt_complementary = "t+:T+";
910 opts = getopt32(argv, "l1vS" USE_FEATURE_FTP_WRITE("w") "t:T:", &G.timeout, &G.abs_timeout);
882 911
883 if (opts & (OPT_l|OPT_1)) { 912 if (opts & (OPT_l|OPT_1)) {
884 /* Our secret backdoor to ls */ 913 /* Our secret backdoor to ls */
914 memset(&G, 0, sizeof(G));
885/* TODO: pass -n too? */ 915/* TODO: pass -n too? */
886 xchdir(argv[2]); 916 xchdir(argv[2]);
887 argv[2] = (char*)"--"; 917 argv[2] = (char*)"--";
888 return ls_main(argc, argv); 918 return ls_main(argc, argv);
889 } 919 }
890 920
891 INIT_G();
892 921
893 G.local_addr = get_sock_lsa(STDIN_FILENO); 922 G.local_addr = get_sock_lsa(STDIN_FILENO);
894 if (!G.local_addr) { 923 if (!G.local_addr) {
@@ -927,6 +956,7 @@ int ftpd_main(int argc, char **argv)
927 setsockopt(STDIN_FILENO, SOL_SOCKET, SO_OOBINLINE, &const_int_1, sizeof(const_int_1)); 956 setsockopt(STDIN_FILENO, SOL_SOCKET, SO_OOBINLINE, &const_int_1, sizeof(const_int_1));
928 957
929 cmdio_write_ok(FTP_GREET); 958 cmdio_write_ok(FTP_GREET);
959 signal(SIGALRM, timeout_handler);
930 960
931#ifdef IF_WE_WANT_TO_REQUIRE_LOGIN 961#ifdef IF_WE_WANT_TO_REQUIRE_LOGIN
932 { 962 {