diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-03-17 09:10:39 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-03-17 09:10:39 +0000 |
commit | aa9b1828b91bc4b60f1164b7929a6a0ac091419e (patch) | |
tree | 31a2278e3998160a7c40ac5882736a2f48768a2d | |
parent | 1d42665b6b0571b9fa5d3b10fbf2dd03382f0ba2 (diff) | |
download | busybox-w32-aa9b1828b91bc4b60f1164b7929a6a0ac091419e.tar.gz busybox-w32-aa9b1828b91bc4b60f1164b7929a6a0ac091419e.tar.bz2 busybox-w32-aa9b1828b91bc4b60f1164b7929a6a0ac091419e.zip |
tftpd: new applet (mostly using existing code for tftp)
function old new delta
tftp_protocol - 1173 +1173
tftpd_main - 500 +500
tftp_option_get - 102 +102
packed_usage 23650 23662 +12
applet_names 1809 1815 +6
applet_main 1100 1104 +4
applet_nameofs 550 552 +2
tftp_main 302 301 -1
get_nport 32 - -32
tftp 1172 - -1172
------------------------------------------------------------------------------
(add/remove: 3/2 grow/shrink: 4/1 up/down: 1799/-1205) Total: 594 bytes
text data bss dec hex filename
796479 662 7420 804561 c46d1 busybox_old
797153 662 7420 805235 c4973 busybox_unstripped
-rw-r--r-- | TODO_config_nommu | 4 | ||||
-rw-r--r-- | include/applets.h | 1 | ||||
-rw-r--r-- | include/usage.h | 8 | ||||
-rw-r--r-- | ipsvd/Config.in | 2 | ||||
-rw-r--r-- | ipsvd/tcpudp.c | 2 | ||||
-rw-r--r-- | networking/Config.in | 23 | ||||
-rw-r--r-- | networking/Kbuild | 1 | ||||
-rw-r--r-- | networking/tftp.c | 334 | ||||
-rw-r--r-- | printutils/Config.in | 2 |
9 files changed, 274 insertions, 103 deletions
diff --git a/TODO_config_nommu b/TODO_config_nommu index 8bf7b215c..042f622bb 100644 --- a/TODO_config_nommu +++ b/TODO_config_nommu | |||
@@ -835,14 +835,14 @@ CONFIG_SOFTLIMIT=y | |||
835 | # CONFIG_SESTATUS is not set | 835 | # CONFIG_SESTATUS is not set |
836 | 836 | ||
837 | # | 837 | # |
838 | # print support | 838 | # Print Utilities |
839 | # | 839 | # |
840 | CONFIG_LPD=y | 840 | CONFIG_LPD=y |
841 | CONFIG_LPR=y | 841 | CONFIG_LPR=y |
842 | CONFIG_LPQ=y | 842 | CONFIG_LPQ=y |
843 | 843 | ||
844 | # | 844 | # |
845 | # ipsvd utilities | 845 | # ipsvd Utilities |
846 | # | 846 | # |
847 | CONFIG_TCPSVD=y | 847 | CONFIG_TCPSVD=y |
848 | CONFIG_UDPSVD=y | 848 | CONFIG_UDPSVD=y |
diff --git a/include/applets.h b/include/applets.h index d4b6dbeaa..c2a089c69 100644 --- a/include/applets.h +++ b/include/applets.h | |||
@@ -355,6 +355,7 @@ USE_TELNETD(APPLET(telnetd, _BB_DIR_USR_SBIN, _BB_SUID_NEVER)) | |||
355 | USE_TEST(APPLET_NOEXEC(test, test, _BB_DIR_USR_BIN, _BB_SUID_NEVER, test)) | 355 | USE_TEST(APPLET_NOEXEC(test, test, _BB_DIR_USR_BIN, _BB_SUID_NEVER, test)) |
356 | #if ENABLE_FEATURE_TFTP_GET || ENABLE_FEATURE_TFTP_PUT | 356 | #if ENABLE_FEATURE_TFTP_GET || ENABLE_FEATURE_TFTP_PUT |
357 | USE_TFTP(APPLET(tftp, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) | 357 | USE_TFTP(APPLET(tftp, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) |
358 | USE_TFTPD(APPLET(tftpd, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) | ||
358 | #endif | 359 | #endif |
359 | USE_TIME(APPLET(time, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) | 360 | USE_TIME(APPLET(time, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) |
360 | USE_TOP(APPLET(top, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) | 361 | USE_TOP(APPLET(top, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) |
diff --git a/include/usage.h b/include/usage.h index 507a52dab..8f563f55e 100644 --- a/include/usage.h +++ b/include/usage.h | |||
@@ -3961,7 +3961,7 @@ | |||
3961 | #define tftp_trivial_usage \ | 3961 | #define tftp_trivial_usage \ |
3962 | "[OPTION]... HOST [PORT]" | 3962 | "[OPTION]... HOST [PORT]" |
3963 | #define tftp_full_usage \ | 3963 | #define tftp_full_usage \ |
3964 | "Transfer a file from/to tftp server using \"octet\" mode\n" \ | 3964 | "Transfer a file from/to tftp server\n" \ |
3965 | "\nOptions:" \ | 3965 | "\nOptions:" \ |
3966 | "\n -l FILE Local FILE" \ | 3966 | "\n -l FILE Local FILE" \ |
3967 | "\n -r FILE Remote FILE" \ | 3967 | "\n -r FILE Remote FILE" \ |
@@ -3974,6 +3974,12 @@ | |||
3974 | USE_FEATURE_TFTP_BLOCKSIZE( \ | 3974 | USE_FEATURE_TFTP_BLOCKSIZE( \ |
3975 | "\n -b SIZE Transfer blocks of SIZE octets" \ | 3975 | "\n -b SIZE Transfer blocks of SIZE octets" \ |
3976 | ) | 3976 | ) |
3977 | |||
3978 | #define tftpd_trivial_usage \ | ||
3979 | "[DIR]" | ||
3980 | #define tftpd_full_usage \ | ||
3981 | "Transfer a file on request from a tftp client" \ | ||
3982 | |||
3977 | #define time_trivial_usage \ | 3983 | #define time_trivial_usage \ |
3978 | "[OPTION]... COMMAND [ARGS...]" | 3984 | "[OPTION]... COMMAND [ARGS...]" |
3979 | #define time_full_usage \ | 3985 | #define time_full_usage \ |
diff --git a/ipsvd/Config.in b/ipsvd/Config.in index 8522ef9eb..0cb8c62de 100644 --- a/ipsvd/Config.in +++ b/ipsvd/Config.in | |||
@@ -3,7 +3,7 @@ | |||
3 | # see scripts/kbuild/config-language.txt. | 3 | # see scripts/kbuild/config-language.txt. |
4 | # | 4 | # |
5 | 5 | ||
6 | menu "ipsvd utilities" | 6 | menu "ipsvd Utilities" |
7 | 7 | ||
8 | config TCPSVD | 8 | config TCPSVD |
9 | bool "tcpsvd" | 9 | bool "tcpsvd" |
diff --git a/ipsvd/tcpudp.c b/ipsvd/tcpudp.c index 8f6616fe0..729b7bca9 100644 --- a/ipsvd/tcpudp.c +++ b/ipsvd/tcpudp.c | |||
@@ -322,7 +322,7 @@ int tcpudpsvd_main(int argc ATTRIBUTE_UNUSED, char **argv) | |||
322 | /* In case recv_from_to won't be able to recover local addr. | 322 | /* In case recv_from_to won't be able to recover local addr. |
323 | * Also sets port - recv_from_to is unable to do it. */ | 323 | * Also sets port - recv_from_to is unable to do it. */ |
324 | local = *lsa; | 324 | local = *lsa; |
325 | conn = recv_from_to(sock, NULL, 0, MSG_DONTWAIT | MSG_PEEK, | 325 | conn = recv_from_to(sock, NULL, 0, MSG_PEEK, |
326 | &remote.u.sa, &local.u.sa, sa_len); | 326 | &remote.u.sa, &local.u.sa, sa_len); |
327 | } | 327 | } |
328 | sig_block(SIGCHLD); | 328 | sig_block(SIGCHLD); |
diff --git a/networking/Config.in b/networking/Config.in index 3c53c1115..729cca148 100644 --- a/networking/Config.in +++ b/networking/Config.in | |||
@@ -774,28 +774,41 @@ config TFTP | |||
774 | is usually used for simple, small transfers such as a root image | 774 | is usually used for simple, small transfers such as a root image |
775 | for a network-enabled bootloader. | 775 | for a network-enabled bootloader. |
776 | 776 | ||
777 | config TFTPD | ||
778 | bool "tftpd" | ||
779 | default n | ||
780 | help | ||
781 | This enables the Trivial File Transfer Protocol server program. | ||
782 | It expects that stdin is a datagram socket and a packet | ||
783 | is already pending on it. It will exit after one transfer. | ||
784 | In other words: it should be run from inetd in nowait mode, | ||
785 | or from udpsvd. Example: "udpsvd -E 0 69 tftpd DIR" | ||
786 | |||
777 | config FEATURE_TFTP_GET | 787 | config FEATURE_TFTP_GET |
778 | bool "Enable \"get\" command" | 788 | bool "Enable \"get\" command" |
779 | default y | 789 | default y |
780 | depends on TFTP | 790 | depends on TFTP || TFTPD |
781 | help | 791 | help |
782 | Add support for the GET command within the TFTP client. This allows | 792 | Add support for the GET command within the TFTP client. This allows |
783 | a client to retrieve a file from a TFTP server. | 793 | a client to retrieve a file from a TFTP server. |
794 | Also enable upload support in tftpd, if tftpd is selected. | ||
784 | 795 | ||
785 | config FEATURE_TFTP_PUT | 796 | config FEATURE_TFTP_PUT |
786 | bool "Enable \"put\" command" | 797 | bool "Enable \"put\" command" |
787 | default y | 798 | default y |
788 | depends on TFTP | 799 | depends on TFTP || TFTPD |
789 | help | 800 | help |
790 | Add support for the PUT command within the TFTP client. This allows | 801 | Add support for the PUT command within the TFTP client. This allows |
791 | a client to transfer a file to a TFTP server. | 802 | a client to transfer a file to a TFTP server. |
803 | Also enable download support in tftpd, if tftpd is selected. | ||
792 | 804 | ||
793 | config FEATURE_TFTP_BLOCKSIZE | 805 | config FEATURE_TFTP_BLOCKSIZE |
794 | bool "Enable \"blocksize\" command" | 806 | bool "Enable \"blksize\" protocol option" |
795 | default n | 807 | default n |
796 | depends on TFTP | 808 | depends on TFTP || TFTPD |
797 | help | 809 | help |
798 | Allow the client to specify the desired block size for transfers. | 810 | Allow tftp to specify block size, and tftpd to understand |
811 | "blksize" option. | ||
799 | 812 | ||
800 | config DEBUG_TFTP | 813 | config DEBUG_TFTP |
801 | bool "Enable debug" | 814 | bool "Enable debug" |
diff --git a/networking/Kbuild b/networking/Kbuild index 44258e9b0..bf9ba9960 100644 --- a/networking/Kbuild +++ b/networking/Kbuild | |||
@@ -35,6 +35,7 @@ lib-$(CONFIG_SLATTACH) += slattach.o | |||
35 | lib-$(CONFIG_TELNET) += telnet.o | 35 | lib-$(CONFIG_TELNET) += telnet.o |
36 | lib-$(CONFIG_TELNETD) += telnetd.o | 36 | lib-$(CONFIG_TELNETD) += telnetd.o |
37 | lib-$(CONFIG_TFTP) += tftp.o | 37 | lib-$(CONFIG_TFTP) += tftp.o |
38 | lib-$(CONFIG_TFTPD) += tftp.o | ||
38 | lib-$(CONFIG_TRACEROUTE) += traceroute.o | 39 | lib-$(CONFIG_TRACEROUTE) += traceroute.o |
39 | lib-$(CONFIG_VCONFIG) += vconfig.o | 40 | lib-$(CONFIG_VCONFIG) += vconfig.o |
40 | lib-$(CONFIG_WGET) += wget.o | 41 | lib-$(CONFIG_WGET) += wget.o |
diff --git a/networking/tftp.c b/networking/tftp.c index 187261568..23a24139b 100644 --- a/networking/tftp.c +++ b/networking/tftp.c | |||
@@ -2,7 +2,7 @@ | |||
2 | /* ------------------------------------------------------------------------- | 2 | /* ------------------------------------------------------------------------- |
3 | * tftp.c | 3 | * tftp.c |
4 | * | 4 | * |
5 | * A simple tftp client for busybox. | 5 | * A simple tftp client/server for busybox. |
6 | * Tries to follow RFC1350. | 6 | * Tries to follow RFC1350. |
7 | * Only "octet" mode supported. | 7 | * Only "octet" mode supported. |
8 | * Optional blocksize negotiation (RFC2347 + RFC2348) | 8 | * Optional blocksize negotiation (RFC2347 + RFC2348) |
@@ -16,6 +16,8 @@ | |||
16 | * | 16 | * |
17 | * utftp: Copyright (C) 1999 Uwe Ohse <uwe@ohse.de> | 17 | * utftp: Copyright (C) 1999 Uwe Ohse <uwe@ohse.de> |
18 | * | 18 | * |
19 | * tftpd added by Denys Vlasenko | ||
20 | * | ||
19 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. | 21 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. |
20 | * ------------------------------------------------------------------------- */ | 22 | * ------------------------------------------------------------------------- */ |
21 | 23 | ||
@@ -46,7 +48,7 @@ | |||
46 | #define CMD_PUT(cmd) 1 | 48 | #define CMD_PUT(cmd) 1 |
47 | #else | 49 | #else |
48 | #define USE_GETPUT(...) __VA_ARGS__ | 50 | #define USE_GETPUT(...) __VA_ARGS__ |
49 | /* masks coming from getpot32 */ | 51 | /* masks coming from getopt32 */ |
50 | #define CMD_GET(cmd) ((cmd) & 1) | 52 | #define CMD_GET(cmd) ((cmd) & 1) |
51 | #define CMD_PUT(cmd) ((cmd) & 2) | 53 | #define CMD_PUT(cmd) ((cmd) & 2) |
52 | #endif | 54 | #endif |
@@ -64,14 +66,12 @@ static int tftp_blocksize_check(int blocksize, int bufsize) | |||
64 | * but our implementation makes it impossible | 66 | * but our implementation makes it impossible |
65 | * to use blocksizes smaller than 22 octets. | 67 | * to use blocksizes smaller than 22 octets. |
66 | */ | 68 | */ |
67 | |||
68 | if ((bufsize && (blocksize > bufsize)) | 69 | if ((bufsize && (blocksize > bufsize)) |
69 | || (blocksize < 8) || (blocksize > 65564) | 70 | || (blocksize < 24) || (blocksize > 65564) |
70 | ) { | 71 | ) { |
71 | bb_error_msg("bad blocksize"); | 72 | bb_error_msg("bad blocksize"); |
72 | return 0; | 73 | return 0; |
73 | } | 74 | } |
74 | |||
75 | return blocksize; | 75 | return blocksize; |
76 | } | 76 | } |
77 | 77 | ||
@@ -81,8 +81,11 @@ static char *tftp_option_get(char *buf, int len, const char *option) | |||
81 | int opt_found = 0; | 81 | int opt_found = 0; |
82 | int k; | 82 | int k; |
83 | 83 | ||
84 | /* buf points to: | ||
85 | * "opt_name<NUL>opt_val<NUL>opt_name2<NUL>opt_val2<NUL>..." */ | ||
86 | |||
84 | while (len > 0) { | 87 | while (len > 0) { |
85 | /* Make sure the options are terminated correctly */ | 88 | /* Make sure options are terminated correctly */ |
86 | for (k = 0; k < len; k++) { | 89 | for (k = 0; k < len; k++) { |
87 | if (buf[k] == '\0') { | 90 | if (buf[k] == '\0') { |
88 | goto nul_found; | 91 | goto nul_found; |
@@ -90,7 +93,7 @@ static char *tftp_option_get(char *buf, int len, const char *option) | |||
90 | } | 93 | } |
91 | return NULL; | 94 | return NULL; |
92 | nul_found: | 95 | nul_found: |
93 | if (opt_val == 0) { | 96 | if (opt_val == 0) { /* it's "name" part */ |
94 | if (strcasecmp(buf, option) == 0) { | 97 | if (strcasecmp(buf, option) == 0) { |
95 | opt_found = 1; | 98 | opt_found = 1; |
96 | } | 99 | } |
@@ -109,77 +112,116 @@ static char *tftp_option_get(char *buf, int len, const char *option) | |||
109 | 112 | ||
110 | #endif | 113 | #endif |
111 | 114 | ||
112 | static int tftp( USE_GETPUT(const int cmd,) | 115 | static int tftp_protocol( |
116 | USE_GETPUT(int cmd,) | ||
117 | len_and_sockaddr *our_lsa, | ||
113 | len_and_sockaddr *peer_lsa, | 118 | len_and_sockaddr *peer_lsa, |
114 | const char *remotefile, const int localfd, | 119 | USE_TFTP(const char *remote_file,) |
115 | unsigned port, int tftp_bufsize) | 120 | int local_fd, |
121 | int blocksize) | ||
116 | { | 122 | { |
123 | #if !ENABLE_TFTP | ||
124 | #define remote_file NULL | ||
125 | #endif | ||
117 | struct pollfd pfd[1]; | 126 | struct pollfd pfd[1]; |
118 | #define socketfd (pfd[0].fd) | 127 | #define socket_fd (pfd[0].fd) |
119 | int len; | 128 | int len; |
120 | int send_len; | 129 | int send_len; |
121 | USE_FEATURE_TFTP_BLOCKSIZE(smallint want_option_ack = 0;) | 130 | USE_FEATURE_TFTP_BLOCKSIZE(smallint want_option_ack = 0;) |
122 | smallint finished = 0; | 131 | smallint finished = 0; |
123 | uint16_t opcode; | 132 | uint16_t opcode; |
124 | uint16_t block_nr = 1; | 133 | uint16_t block_nr; |
125 | uint16_t recv_blk; | 134 | uint16_t recv_blk; |
126 | int retries, waittime_ms; | 135 | int retries, waittime_ms; |
136 | int tftp_bufsize = blocksize + 4; | ||
127 | char *cp; | 137 | char *cp; |
128 | |||
129 | unsigned org_port; | ||
130 | len_and_sockaddr *const from = alloca(LSA_LEN_SIZE + peer_lsa->len); | ||
131 | |||
132 | /* Can't use RESERVE_CONFIG_BUFFER here since the allocation | 138 | /* Can't use RESERVE_CONFIG_BUFFER here since the allocation |
133 | * size varies meaning BUFFERS_GO_ON_STACK would fail */ | 139 | * size varies meaning BUFFERS_GO_ON_STACK would fail */ |
134 | /* We must keep the transmit and receive buffers seperate */ | 140 | /* We must keep the transmit and receive buffers seperate */ |
135 | /* In case we rcv a garbage pkt and we need to rexmit the last pkt */ | 141 | /* In case we rcv a garbage pkt and we need to rexmit the last pkt */ |
136 | char *xbuf = xmalloc(tftp_bufsize += 4); | 142 | char *xbuf = xmalloc(tftp_bufsize); |
137 | char *rbuf = xmalloc(tftp_bufsize); | 143 | char *rbuf = xmalloc(tftp_bufsize); |
138 | 144 | ||
139 | port = org_port = htons(port); | 145 | socket_fd = xsocket(peer_lsa->u.sa.sa_family, SOCK_DGRAM, 0); |
146 | setsockopt_reuseaddr(socket_fd); | ||
140 | 147 | ||
141 | socketfd = xsocket(peer_lsa->u.sa.sa_family, SOCK_DGRAM, 0); | 148 | if (!ENABLE_TFTP || our_lsa) { |
149 | /* tftpd */ | ||
150 | block_nr = 0; | ||
142 | 151 | ||
143 | /* build opcode */ | 152 | /* Create a socket which is: |
144 | opcode = TFTP_WRQ; | 153 | * 1. bound to IP:port peer sent 1st datagram to, |
145 | if (CMD_GET(cmd)) { | 154 | * 2. connected to peer's IP:port |
146 | opcode = TFTP_RRQ; | 155 | * This way we will answer from the IP:port peer |
147 | } | 156 | * expects, will not get any other packets on |
148 | cp = xbuf + 2; | 157 | * the socket, and also plain read/write will work. */ |
149 | /* add filename and mode */ | 158 | xbind(socket_fd, &our_lsa->u.sa, our_lsa->len); |
150 | /* fill in packet if the filename fits into xbuf */ | 159 | xconnect(socket_fd, &peer_lsa->u.sa, peer_lsa->len); |
151 | len = strlen(remotefile) + 1; | ||
152 | if (2 + len + sizeof("octet") >= tftp_bufsize) { | ||
153 | bb_error_msg("remote filename is too long"); | ||
154 | goto ret; | ||
155 | } | ||
156 | strcpy(cp, remotefile); | ||
157 | cp += len; | ||
158 | /* add "mode" part of the package */ | ||
159 | strcpy(cp, "octet"); | ||
160 | cp += sizeof("octet"); | ||
161 | 160 | ||
162 | #if ENABLE_FEATURE_TFTP_BLOCKSIZE | 161 | #if ENABLE_FEATURE_TFTP_BLOCKSIZE |
163 | len = tftp_bufsize - 4; /* data block size */ | 162 | if (blocksize != TFTP_BLOCKSIZE_DEFAULT) { |
164 | if (len != TFTP_BLOCKSIZE_DEFAULT) { | 163 | /* Create and send OACK packet */ |
165 | /* rfc2348 says that 65464 is a max allowed value */ | 164 | opcode = TFTP_OACK; |
166 | if ((&xbuf[tftp_bufsize - 1] - cp) < sizeof("blksize NNNNN")) { | 165 | cp = xbuf + 2; |
166 | goto add_blksize_opt; | ||
167 | } | ||
168 | /* else: just fall into while (1) loop below */ | ||
169 | #endif | ||
170 | } else { | ||
171 | /* tftp */ | ||
172 | block_nr = 1; | ||
173 | |||
174 | /* We can't (and don't really need to) bind the socket: | ||
175 | * we don't know from which local IP datagrams will be sent, | ||
176 | * but kernel will pick the same IP every time (unless routing | ||
177 | * table is changed), thus peer will see dgrams consistently | ||
178 | * coming from the same IP. | ||
179 | * We would like to connect the socket, but since peer's | ||
180 | * UDP code can be less perfect than ours, _peer's_ IP:port | ||
181 | * in replies may differ from IP:port we used to send | ||
182 | * our first packet. We can connect() only when we get | ||
183 | * first reply. */ | ||
184 | |||
185 | /* build opcode */ | ||
186 | opcode = TFTP_WRQ; | ||
187 | if (CMD_GET(cmd)) { | ||
188 | opcode = TFTP_RRQ; | ||
189 | } | ||
190 | cp = xbuf + 2; | ||
191 | /* add filename and mode */ | ||
192 | /* fill in packet if the filename fits into xbuf */ | ||
193 | len = strlen(remote_file) + 1; | ||
194 | if (2 + len + sizeof("octet") >= tftp_bufsize) { | ||
167 | bb_error_msg("remote filename is too long"); | 195 | bb_error_msg("remote filename is too long"); |
168 | goto ret; | 196 | goto ret; |
169 | } | 197 | } |
170 | /* add "blksize", <nul>, blocksize */ | 198 | strcpy(cp, remote_file); |
171 | strcpy(cp, "blksize"); | 199 | cp += len; |
172 | cp += sizeof("blksize"); | 200 | /* add "mode" part of the package */ |
173 | cp += snprintf(cp, 6, "%d", len) + 1; | 201 | strcpy(cp, "octet"); |
174 | want_option_ack = 1; | 202 | cp += sizeof("octet"); |
175 | } | 203 | |
204 | #if ENABLE_FEATURE_TFTP_BLOCKSIZE | ||
205 | if (blocksize != TFTP_BLOCKSIZE_DEFAULT) { | ||
206 | /* rfc2348 says that 65464 is a max allowed value */ | ||
207 | if ((&xbuf[tftp_bufsize - 1] - cp) < sizeof("blksize NNNNN")) { | ||
208 | bb_error_msg("remote filename is too long"); | ||
209 | goto ret; | ||
210 | } | ||
211 | want_option_ack = 1; | ||
212 | add_blksize_opt: | ||
213 | /* add "blksize", <nul>, blocksize, <nul> */ | ||
214 | strcpy(cp, "blksize"); | ||
215 | cp += sizeof("blksize"); | ||
216 | cp += snprintf(cp, 6, "%d", blocksize) + 1; | ||
217 | } | ||
176 | #endif | 218 | #endif |
177 | /* First packet is built, so skip packet generation */ | 219 | /* First packet is built, so skip packet generation */ |
178 | goto send_pkt; | 220 | goto send_pkt; |
221 | } | ||
179 | 222 | ||
180 | /* Using mostly goto's - continue/break will be less clear | 223 | /* Using mostly goto's - continue/break will be less clear |
181 | * in where we actually jump to */ | 224 | * in where we actually jump to */ |
182 | |||
183 | while (1) { | 225 | while (1) { |
184 | /* Build ACK or DATA */ | 226 | /* Build ACK or DATA */ |
185 | cp = xbuf + 2; | 227 | cp = xbuf + 2; |
@@ -189,7 +231,7 @@ static int tftp( USE_GETPUT(const int cmd,) | |||
189 | opcode = TFTP_ACK; | 231 | opcode = TFTP_ACK; |
190 | if (CMD_PUT(cmd)) { | 232 | if (CMD_PUT(cmd)) { |
191 | opcode = TFTP_DATA; | 233 | opcode = TFTP_DATA; |
192 | len = full_read(localfd, cp, tftp_bufsize - 4); | 234 | len = full_read(local_fd, cp, tftp_bufsize - 4); |
193 | if (len < 0) { | 235 | if (len < 0) { |
194 | bb_perror_msg(bb_msg_read_error); | 236 | bb_perror_msg(bb_msg_read_error); |
195 | goto ret; | 237 | goto ret; |
@@ -216,36 +258,36 @@ static int tftp( USE_GETPUT(const int cmd,) | |||
216 | fprintf(stderr, "%02x ", (unsigned char) *cp); | 258 | fprintf(stderr, "%02x ", (unsigned char) *cp); |
217 | fprintf(stderr, "\n"); | 259 | fprintf(stderr, "\n"); |
218 | #endif | 260 | #endif |
219 | xsendto(socketfd, xbuf, send_len, &peer_lsa->u.sa, peer_lsa->len); | 261 | xsendto(socket_fd, xbuf, send_len, &peer_lsa->u.sa, peer_lsa->len); |
220 | /* Was it final ACK? then exit */ | 262 | /* Was it final ACK? then exit */ |
221 | if (finished && (opcode == TFTP_ACK)) | 263 | if (finished && (opcode == TFTP_ACK)) |
222 | goto ret; | 264 | goto ret; |
223 | 265 | ||
224 | recv_again: | 266 | recv_again: |
225 | /* Receive packet */ | 267 | /* Receive packet */ |
226 | /*pfd[0].fd = socketfd;*/ | 268 | /*pfd[0].fd = socket_fd;*/ |
227 | pfd[0].events = POLLIN; | 269 | pfd[0].events = POLLIN; |
228 | switch (safe_poll(pfd, 1, waittime_ms)) { | 270 | switch (safe_poll(pfd, 1, waittime_ms)) { |
229 | unsigned from_port; | ||
230 | case 1: | 271 | case 1: |
231 | from->len = peer_lsa->len; | 272 | if (!our_lsa) { |
232 | memset(&from->u.sa, 0, peer_lsa->len); | 273 | /* tftp (not tftpd!) receiving 1st packet */ |
233 | len = recvfrom(socketfd, rbuf, tftp_bufsize, 0, | 274 | our_lsa = ((void*)(ptrdiff_t)-1); /* not NULL */ |
234 | &from->u.sa, &from->len); | 275 | len = recvfrom(socket_fd, rbuf, tftp_bufsize, 0, |
276 | &peer_lsa->u.sa, &peer_lsa->len); | ||
277 | /* Our first dgram went to port 69 | ||
278 | * but reply may come from different one. | ||
279 | * Remember and use this new port (and IP) */ | ||
280 | if (len >= 0) | ||
281 | xconnect(socket_fd, &peer_lsa->u.sa, peer_lsa->len); | ||
282 | } else { | ||
283 | /* tftpd, or not the very first packet: | ||
284 | * socket is connect()ed, can just read from it. */ | ||
285 | len = safe_read(socket_fd, rbuf, tftp_bufsize); | ||
286 | } | ||
235 | if (len < 0) { | 287 | if (len < 0) { |
236 | bb_perror_msg("recvfrom"); | 288 | bb_perror_msg("read"); |
237 | goto ret; | 289 | goto ret; |
238 | } | 290 | } |
239 | from_port = get_nport(&from->u.sa); | ||
240 | if (port == org_port) { | ||
241 | /* Our first query went to port 69 | ||
242 | * but reply will come from different one. | ||
243 | * Remember and use this new port */ | ||
244 | port = from_port; | ||
245 | set_nport(peer_lsa, from_port); | ||
246 | } | ||
247 | if (port != from_port) | ||
248 | goto recv_again; | ||
249 | goto process_pkt; | 291 | goto process_pkt; |
250 | case 0: | 292 | case 0: |
251 | retries--; | 293 | retries--; |
@@ -316,7 +358,7 @@ static int tftp( USE_GETPUT(const int cmd,) | |||
316 | /*static const uint16_t error_8[2] = { htons(TFTP_ERROR), htons(8) };*/ | 358 | /*static const uint16_t error_8[2] = { htons(TFTP_ERROR), htons(8) };*/ |
317 | /* thus we open-code big-endian layout */ | 359 | /* thus we open-code big-endian layout */ |
318 | static const uint8_t error_8[4] = { 0,TFTP_ERROR, 0,8 }; | 360 | static const uint8_t error_8[4] = { 0,TFTP_ERROR, 0,8 }; |
319 | xsendto(socketfd, error_8, 4, &peer_lsa->u.sa, peer_lsa->len); | 361 | xsendto(socket_fd, error_8, 4, &peer_lsa->u.sa, peer_lsa->len); |
320 | bb_error_msg("server proposes bad blksize %d, exiting", blksize); | 362 | bb_error_msg("server proposes bad blksize %d, exiting", blksize); |
321 | goto ret; | 363 | goto ret; |
322 | } | 364 | } |
@@ -345,7 +387,7 @@ static int tftp( USE_GETPUT(const int cmd,) | |||
345 | 387 | ||
346 | if (CMD_GET(cmd) && (opcode == TFTP_DATA)) { | 388 | if (CMD_GET(cmd) && (opcode == TFTP_DATA)) { |
347 | if (recv_blk == block_nr) { | 389 | if (recv_blk == block_nr) { |
348 | len = full_write(localfd, &rbuf[4], len - 4); | 390 | len = full_write(local_fd, &rbuf[4], len - 4); |
349 | if (len < 0) { | 391 | if (len < 0) { |
350 | bb_perror_msg(bb_msg_write_error); | 392 | bb_perror_msg(bb_msg_write_error); |
351 | goto ret; | 393 | goto ret; |
@@ -363,7 +405,7 @@ static int tftp( USE_GETPUT(const int cmd,) | |||
363 | } | 405 | } |
364 | 406 | ||
365 | if (CMD_PUT(cmd) && (opcode == TFTP_ACK)) { | 407 | if (CMD_PUT(cmd) && (opcode == TFTP_ACK)) { |
366 | /* did server ACK our last DATA pkt? */ | 408 | /* did peer ACK our last DATA pkt? */ |
367 | if (recv_blk == (uint16_t) (block_nr - 1)) { | 409 | if (recv_blk == (uint16_t) (block_nr - 1)) { |
368 | if (finished) | 410 | if (finished) |
369 | goto ret; | 411 | goto ret; |
@@ -381,25 +423,27 @@ static int tftp( USE_GETPUT(const int cmd,) | |||
381 | * See: | 423 | * See: |
382 | * http://en.wikipedia.org/wiki/Sorcerer's_Apprentice_Syndrome | 424 | * http://en.wikipedia.org/wiki/Sorcerer's_Apprentice_Syndrome |
383 | */ | 425 | */ |
384 | } | 426 | } /* end of "while (1)" */ |
385 | ret: | 427 | ret: |
386 | if (ENABLE_FEATURE_CLEAN_UP) { | 428 | if (ENABLE_FEATURE_CLEAN_UP) { |
387 | close(socketfd); | 429 | close(socket_fd); |
388 | free(xbuf); | 430 | free(xbuf); |
389 | free(rbuf); | 431 | free(rbuf); |
390 | } | 432 | } |
391 | return finished == 0; /* returns 1 on failure */ | 433 | return finished == 0; /* returns 1 on failure */ |
392 | } | 434 | } |
393 | 435 | ||
436 | #if ENABLE_TFTP | ||
437 | |||
394 | int tftp_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 438 | int tftp_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
395 | int tftp_main(int argc ATTRIBUTE_UNUSED, char **argv) | 439 | int tftp_main(int argc ATTRIBUTE_UNUSED, char **argv) |
396 | { | 440 | { |
397 | len_and_sockaddr *peer_lsa; | 441 | len_and_sockaddr *peer_lsa; |
398 | const char *localfile = NULL; | 442 | const char *local_file = NULL; |
399 | const char *remotefile = NULL; | 443 | const char *remote_file = NULL; |
400 | int port; | 444 | int port; |
401 | USE_GETPUT(int cmd;) | 445 | USE_GETPUT(int cmd;) |
402 | int fd = -1; | 446 | int local_fd; |
403 | int flags = 0; | 447 | int flags = 0; |
404 | int result; | 448 | int result; |
405 | int blocksize = TFTP_BLOCKSIZE_DEFAULT; | 449 | int blocksize = TFTP_BLOCKSIZE_DEFAULT; |
@@ -412,7 +456,7 @@ int tftp_main(int argc ATTRIBUTE_UNUSED, char **argv) | |||
412 | USE_GETPUT(cmd =) getopt32(argv, | 456 | USE_GETPUT(cmd =) getopt32(argv, |
413 | USE_FEATURE_TFTP_GET("g") USE_FEATURE_TFTP_PUT("p") | 457 | USE_FEATURE_TFTP_GET("g") USE_FEATURE_TFTP_PUT("p") |
414 | "l:r:" USE_FEATURE_TFTP_BLOCKSIZE("b:"), | 458 | "l:r:" USE_FEATURE_TFTP_BLOCKSIZE("b:"), |
415 | &localfile, &remotefile | 459 | &local_file, &remote_file |
416 | USE_FEATURE_TFTP_BLOCKSIZE(, &blocksize)); | 460 | USE_FEATURE_TFTP_BLOCKSIZE(, &blocksize)); |
417 | argv += optind; | 461 | argv += optind; |
418 | 462 | ||
@@ -425,36 +469,142 @@ int tftp_main(int argc ATTRIBUTE_UNUSED, char **argv) | |||
425 | return EXIT_FAILURE; | 469 | return EXIT_FAILURE; |
426 | #endif | 470 | #endif |
427 | 471 | ||
428 | if (!localfile) | 472 | if (!local_file) |
429 | localfile = remotefile; | 473 | local_file = remote_file; |
430 | if (!remotefile) | 474 | if (!remote_file) |
431 | remotefile = localfile; | 475 | remote_file = local_file; |
432 | /* Error if filename or host is not known */ | 476 | /* Error if filename or host is not known */ |
433 | if (!remotefile || !argv[0]) | 477 | if (!remote_file || !argv[0]) |
434 | bb_show_usage(); | 478 | bb_show_usage(); |
435 | 479 | ||
436 | fd = CMD_GET(cmd) ? STDOUT_FILENO : STDIN_FILENO; | 480 | local_fd = CMD_GET(cmd) ? STDOUT_FILENO : STDIN_FILENO; |
437 | if (!LONE_DASH(localfile)) { | 481 | if (!LONE_DASH(local_file)) { |
438 | fd = xopen(localfile, flags); | 482 | local_fd = xopen(local_file, flags); |
439 | } | 483 | } |
440 | 484 | ||
441 | port = bb_lookup_port(argv[1], "udp", 69); | 485 | port = bb_lookup_port(argv[1], "udp", 69); |
442 | peer_lsa = xhost2sockaddr(argv[0], port); | 486 | peer_lsa = xhost2sockaddr(argv[0], port); |
443 | 487 | ||
444 | #if ENABLE_DEBUG_TFTP | 488 | #if ENABLE_DEBUG_TFTP |
445 | fprintf(stderr, "using server '%s', remotefile '%s', localfile '%s'\n", | 489 | fprintf(stderr, "using server '%s', remote_file '%s', local_file '%s'\n", |
446 | xmalloc_sockaddr2dotted(&peer_lsa->u.sa), | 490 | xmalloc_sockaddr2dotted(&peer_lsa->u.sa), |
447 | remotefile, localfile); | 491 | remote_file, local_file); |
448 | #endif | 492 | #endif |
449 | 493 | ||
450 | result = tftp( USE_GETPUT(cmd,) peer_lsa, remotefile, fd, port, blocksize); | 494 | result = tftp_protocol( |
495 | USE_GETPUT(cmd,) | ||
496 | NULL /* our_lsa*/, | ||
497 | peer_lsa, | ||
498 | remote_file, local_fd, blocksize); | ||
451 | 499 | ||
452 | if (ENABLE_FEATURE_CLEAN_UP) | 500 | if (ENABLE_FEATURE_CLEAN_UP) |
453 | close(fd); | 501 | close(local_fd); |
454 | if (result != EXIT_SUCCESS && !LONE_DASH(localfile) && CMD_GET(cmd)) { | 502 | if (result != EXIT_SUCCESS && !LONE_DASH(local_file) && CMD_GET(cmd)) { |
455 | unlink(localfile); | 503 | unlink(local_file); |
456 | } | 504 | } |
457 | return result; | 505 | return result; |
458 | } | 506 | } |
459 | 507 | ||
508 | #endif /* ENABLE_TFTP */ | ||
509 | |||
510 | #if ENABLE_TFTPD | ||
511 | |||
512 | /* TODO: libbb candidate? */ | ||
513 | static len_and_sockaddr *get_sock_lsa(int s) | ||
514 | { | ||
515 | len_and_sockaddr *lsa; | ||
516 | socklen_t len = 0; | ||
517 | |||
518 | if (getsockname(s, NULL, &len) != 0) | ||
519 | return NULL; | ||
520 | lsa = xzalloc(LSA_LEN_SIZE + len); | ||
521 | lsa->len = len; | ||
522 | getsockname(s, &lsa->u.sa, &lsa->len); | ||
523 | return lsa; | ||
524 | } | ||
525 | |||
526 | int tftpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
527 | int tftpd_main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) | ||
528 | { | ||
529 | struct stat statbuf; | ||
530 | char block_buf[TFTP_BLOCKSIZE_DEFAULT]; | ||
531 | len_and_sockaddr *our_lsa; | ||
532 | len_and_sockaddr *peer_lsa; | ||
533 | char *filename, *mode, *opt_str; | ||
534 | int result, opcode, cmd, req_modebits, open_mode, local_fd, blksize; | ||
535 | |||
536 | our_lsa = get_sock_lsa(STDIN_FILENO); | ||
537 | if (!our_lsa) | ||
538 | bb_perror_msg_and_die("stdin is not a socket"); | ||
539 | peer_lsa = xzalloc(LSA_LEN_SIZE + our_lsa->len); | ||
540 | peer_lsa->len = our_lsa->len; | ||
541 | |||
542 | if (argv[1]) | ||
543 | xchdir(argv[1]); | ||
544 | |||
545 | result = recv_from_to(STDIN_FILENO, block_buf, sizeof(block_buf), | ||
546 | 0 /* flags */, | ||
547 | &peer_lsa->u.sa, &our_lsa->u.sa, our_lsa->len); | ||
548 | |||
549 | opcode = ntohs(*(uint16_t*)block_buf); | ||
550 | if (result < 4 || result >= sizeof(block_buf) | ||
551 | || block_buf[result-1] != '\0' | ||
552 | || (opcode != TFTP_RRQ && opcode != TFTP_WRQ) | ||
553 | ) { | ||
554 | bb_error_msg_and_die("malformed packet"); | ||
555 | } | ||
556 | filename = block_buf + 2; | ||
557 | if (filename[0] == '.' || strstr(filename, "/.")) { | ||
558 | bb_error_msg_and_die("dot in filename"); | ||
559 | } | ||
560 | mode = filename + strlen(filename) + 1; | ||
561 | if (mode >= block_buf + sizeof(block_buf) | ||
562 | || strcmp(mode, "octet") != 0 | ||
563 | ) { | ||
564 | bb_error_msg_and_die("malformed packet"); | ||
565 | } | ||
566 | blksize = TFTP_BLOCKSIZE_DEFAULT; | ||
567 | #if ENABLE_FEATURE_TFTP_BLOCKSIZE | ||
568 | opt_str = mode + 6; | ||
569 | if (opt_str < block_buf + sizeof(block_buf)) { | ||
570 | char *res = tftp_option_get(opt_str, block_buf + sizeof(block_buf) - opt_str, "blksize"); | ||
571 | if (res) { | ||
572 | int sz = xatoi_u(res); | ||
573 | if (tftp_blocksize_check(sz, 0)) | ||
574 | blksize = sz; | ||
575 | } | ||
576 | } | ||
577 | #endif | ||
578 | xstat(filename, &statbuf); | ||
579 | /* if opcode == TFTP_WRQ: */ | ||
580 | cmd = 1; /* CMD_GET: we will receive file's data */ | ||
581 | req_modebits = 0222; /* writable by anyone */ | ||
582 | open_mode = O_WRONLY | O_TRUNC; | ||
583 | if (opcode == TFTP_RRQ) { | ||
584 | cmd = 2; /* CMD_PUT */ | ||
585 | req_modebits = 0444; /* readable by anyone */ | ||
586 | open_mode = O_RDONLY; | ||
587 | } | ||
588 | if (!S_ISREG(statbuf.st_mode) | ||
589 | || (statbuf.st_mode & req_modebits) != req_modebits | ||
590 | ) { | ||
591 | bb_error_msg_and_die("access to '%s' is denied", filename); | ||
592 | } | ||
593 | local_fd = xopen(filename, open_mode); | ||
594 | |||
595 | close(STDIN_FILENO); /* close old, possibly wildcard socket */ | ||
596 | /* tftp_protocol() will create new one, bound to particular local IP */ | ||
597 | result = tftp_protocol( | ||
598 | USE_GETPUT(cmd,) | ||
599 | our_lsa, peer_lsa, | ||
600 | USE_TFTP(NULL /*remote_file*/,) | ||
601 | local_fd, | ||
602 | blksize | ||
603 | ); | ||
604 | |||
605 | return result; | ||
606 | } | ||
607 | |||
608 | #endif /* ENABLE_TFTPD */ | ||
609 | |||
460 | #endif /* ENABLE_FEATURE_TFTP_GET || ENABLE_FEATURE_TFTP_PUT */ | 610 | #endif /* ENABLE_FEATURE_TFTP_GET || ENABLE_FEATURE_TFTP_PUT */ |
diff --git a/printutils/Config.in b/printutils/Config.in index e5f18646c..e0bf71b07 100644 --- a/printutils/Config.in +++ b/printutils/Config.in | |||
@@ -1,4 +1,4 @@ | |||
1 | menu "print support" | 1 | menu "Print Utilities" |
2 | 2 | ||
3 | config LPD | 3 | config LPD |
4 | bool "lpd" | 4 | bool "lpd" |