aboutsummaryrefslogtreecommitdiff
path: root/networking/ftpgetput.c
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-01-03 21:55:50 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-01-03 21:55:50 +0000
commit562dc249e039878e927f8250c82507e6e844f547 (patch)
treefe5381f0a3c76db23bc36ce4279ca1d37b205292 /networking/ftpgetput.c
parent6eebed561a4d7a022f9b44e2ddc1347a43eaa866 (diff)
downloadbusybox-w32-562dc249e039878e927f8250c82507e6e844f547.tar.gz
busybox-w32-562dc249e039878e927f8250c82507e6e844f547.tar.bz2
busybox-w32-562dc249e039878e927f8250c82507e6e844f547.zip
ftpgetput: fix PASV mode, fix xatou0induced breakage,
improve error message, guard against garbage from remote server being printed. ~20 bytes code growth
Diffstat (limited to 'networking/ftpgetput.c')
-rw-r--r--networking/ftpgetput.c94
1 files changed, 59 insertions, 35 deletions
diff --git a/networking/ftpgetput.c b/networking/ftpgetput.c
index 9d054428f..9e64ff98a 100644
--- a/networking/ftpgetput.c
+++ b/networking/ftpgetput.c
@@ -25,15 +25,28 @@ typedef struct ftp_host_info_s {
25static char verbose_flag; 25static char verbose_flag;
26static char do_continue; 26static char do_continue;
27 27
28static void ftp_die(const char *msg, const char *remote) ATTRIBUTE_NORETURN;
29static void ftp_die(const char *msg, const char *remote)
30{
31 /* Guard against garbage from remote server */
32 const char *cp = remote;
33 while (*cp >= ' ' && *cp < '\x7f') cp++;
34 bb_error_msg_and_die("unexpected server response%s%s: %.*s",
35 msg ? " to " : "", msg ? msg : "",
36 (int)(cp - remote), remote);
37}
38
39
28static int ftpcmd(const char *s1, const char *s2, FILE *stream, char *buf) 40static int ftpcmd(const char *s1, const char *s2, FILE *stream, char *buf)
29{ 41{
42 unsigned n;
30 if (verbose_flag) { 43 if (verbose_flag) {
31 bb_error_msg("cmd %s%s", s1, s2); 44 bb_error_msg("cmd %s%s", s1, s2);
32 } 45 }
33 46
34 if (s1) { 47 if (s1) {
35 if (s2) { 48 if (s2) {
36 fprintf(stream, "%s%s\r\n", s1, s2); 49 fprintf(stream, "%s %s\r\n", s1, s2);
37 } else { 50 } else {
38 fprintf(stream, "%s\r\n", s1); 51 fprintf(stream, "%s\r\n", s1);
39 } 52 }
@@ -50,14 +63,23 @@ static int ftpcmd(const char *s1, const char *s2, FILE *stream, char *buf)
50 } 63 }
51 } while (!isdigit(buf[0]) || buf[3] != ' '); 64 } while (!isdigit(buf[0]) || buf[3] != ' ');
52 65
53 return xatou(buf); 66 buf[3] = '\0';
67 n = xatou(buf);
68 buf[3] = ' ';
69 return n;
54} 70}
55 71
56static int xconnect_ftpdata(ftp_host_info_t *server, const char *buf) 72static int xconnect_ftpdata(ftp_host_info_t *server, char *buf)
57{ 73{
58 char *buf_ptr; 74 char *buf_ptr;
59 unsigned short port_num; 75 unsigned short port_num;
60 76
77 /* Response is "NNN garbageN1,N2,N3,N4,P1,P2[)garbage]
78 * Server's IP is N1.N2.N3.N4 (we ignore it)
79 * Server's port for data connection is P1*256+P2 */
80 buf_ptr = strrchr(buf, ')');
81 if (buf_ptr) *buf_ptr = '\0';
82
61 buf_ptr = strrchr(buf, ','); 83 buf_ptr = strrchr(buf, ',');
62 *buf_ptr = '\0'; 84 *buf_ptr = '\0';
63 port_num = xatoul_range(buf_ptr + 1, 0, 255); 85 port_num = xatoul_range(buf_ptr + 1, 0, 255);
@@ -78,24 +100,25 @@ static FILE *ftp_login(ftp_host_info_t *server)
78 /* Connect to the command socket */ 100 /* Connect to the command socket */
79 control_stream = fdopen(xconnect_tcp_v4(server->s_in), "r+"); 101 control_stream = fdopen(xconnect_tcp_v4(server->s_in), "r+");
80 if (control_stream == NULL) { 102 if (control_stream == NULL) {
81 bb_perror_msg_and_die("cannot open control stream"); 103 /* Extremely unlikely */
104 bb_perror_nomsg_and_die();
82 } 105 }
83 106
84 if (ftpcmd(NULL, NULL, control_stream, buf) != 220) { 107 if (ftpcmd(NULL, NULL, control_stream, buf) != 220) {
85 bb_error_msg_and_die("%s", buf + 4); 108 ftp_die(NULL, buf);
86 } 109 }
87 110
88 /* Login to the server */ 111 /* Login to the server */
89 switch (ftpcmd("USER ", server->user, control_stream, buf)) { 112 switch (ftpcmd("USER", server->user, control_stream, buf)) {
90 case 230: 113 case 230:
91 break; 114 break;
92 case 331: 115 case 331:
93 if (ftpcmd("PASS ", server->password, control_stream, buf) != 230) { 116 if (ftpcmd("PASS", server->password, control_stream, buf) != 230) {
94 bb_error_msg_and_die("PASS error: %s", buf + 4); 117 ftp_die("PASS", buf);
95 } 118 }
96 break; 119 break;
97 default: 120 default:
98 bb_error_msg_and_die("USER error: %s", buf + 4); 121 ftp_die("USER", buf);
99 } 122 }
100 123
101 ftpcmd("TYPE I", NULL, control_stream, buf); 124 ftpcmd("TYPE I", NULL, control_stream, buf);
@@ -121,14 +144,14 @@ int ftp_receive(ftp_host_info_t *server, FILE *control_stream,
121 144
122 /* Connect to the data socket */ 145 /* Connect to the data socket */
123 if (ftpcmd("PASV", NULL, control_stream, buf) != 227) { 146 if (ftpcmd("PASV", NULL, control_stream, buf) != 227) {
124 bb_error_msg_and_die("PASV error: %s", buf + 4); 147 ftp_die("PASV", buf);
125 } 148 }
126 fd_data = xconnect_ftpdata(server, buf); 149 fd_data = xconnect_ftpdata(server, buf);
127 150
128 if (ftpcmd("SIZE ", server_path, control_stream, buf) == 213) { 151 if (ftpcmd("SIZE", server_path, control_stream, buf) == 213) {
129 //filesize = BB_STRTOOFF(buf + 4, NULL, 10); 152 //filesize = BB_STRTOOFF(buf + 4, NULL, 10);
130 //if (errno || filesize < 0) 153 //if (errno || filesize < 0)
131 // bb_error_msg_and_die("SIZE error: %s", buf + 4); 154 // ftp_die("SIZE", buf);
132 } else { 155 } else {
133 do_continue = 0; 156 do_continue = 0;
134 } 157 }
@@ -160,8 +183,8 @@ int ftp_receive(ftp_host_info_t *server, FILE *control_stream,
160 } 183 }
161 } 184 }
162 185
163 if (ftpcmd("RETR ", server_path, control_stream, buf) > 150) { 186 if (ftpcmd("RETR", server_path, control_stream, buf) > 150) {
164 bb_error_msg_and_die("RETR error: %s", buf + 4); 187 ftp_die("RETR", buf);
165 } 188 }
166 189
167 /* only make a local file if we know that one exists on the remote server */ 190 /* only make a local file if we know that one exists on the remote server */
@@ -185,7 +208,7 @@ int ftp_receive(ftp_host_info_t *server, FILE *control_stream,
185 /* close it all down */ 208 /* close it all down */
186 close(fd_data); 209 close(fd_data);
187 if (ftpcmd(NULL, NULL, control_stream, buf) != 226) { 210 if (ftpcmd(NULL, NULL, control_stream, buf) != 226) {
188 bb_error_msg_and_die("ftp error: %s", buf + 4); 211 ftp_die(NULL, buf);
189 } 212 }
190 ftpcmd("QUIT", NULL, control_stream, buf); 213 ftpcmd("QUIT", NULL, control_stream, buf);
191 214
@@ -209,7 +232,7 @@ int ftp_send(ftp_host_info_t *server, FILE *control_stream,
209 232
210 /* Connect to the data socket */ 233 /* Connect to the data socket */
211 if (ftpcmd("PASV", NULL, control_stream, buf) != 227) { 234 if (ftpcmd("PASV", NULL, control_stream, buf) != 227) {
212 bb_error_msg_and_die("PASV error: %s", buf + 4); 235 ftp_die("PASV", buf);
213 } 236 }
214 fd_data = xconnect_ftpdata(server, buf); 237 fd_data = xconnect_ftpdata(server, buf);
215 238
@@ -219,7 +242,7 @@ int ftp_send(ftp_host_info_t *server, FILE *control_stream,
219 fd_local = xopen(local_path, O_RDONLY); 242 fd_local = xopen(local_path, O_RDONLY);
220 fstat(fd_local, &sbuf); 243 fstat(fd_local, &sbuf);
221 244
222 sprintf(buf, "ALLO %lu", (unsigned long)sbuf.st_size); 245 sprintf(buf, "ALLO %"OFF_FMT"u", sbuf.st_size);
223 response = ftpcmd(buf, NULL, control_stream, buf); 246 response = ftpcmd(buf, NULL, control_stream, buf);
224 switch (response) { 247 switch (response) {
225 case 200: 248 case 200:
@@ -227,18 +250,18 @@ int ftp_send(ftp_host_info_t *server, FILE *control_stream,
227 break; 250 break;
228 default: 251 default:
229 close(fd_local); 252 close(fd_local);
230 bb_error_msg_and_die("ALLO error: %s", buf + 4); 253 ftp_die("ALLO", buf);
231 break; 254 break;
232 } 255 }
233 } 256 }
234 response = ftpcmd("STOR ", server_path, control_stream, buf); 257 response = ftpcmd("STOR", server_path, control_stream, buf);
235 switch (response) { 258 switch (response) {
236 case 125: 259 case 125:
237 case 150: 260 case 150:
238 break; 261 break;
239 default: 262 default:
240 close(fd_local); 263 close(fd_local);
241 bb_error_msg_and_die("STOR error: %s", buf + 4); 264 ftp_die("STOR", buf);
242 } 265 }
243 266
244 /* transfer the file */ 267 /* transfer the file */
@@ -249,7 +272,7 @@ int ftp_send(ftp_host_info_t *server, FILE *control_stream,
249 /* close it all down */ 272 /* close it all down */
250 close(fd_data); 273 close(fd_data);
251 if (ftpcmd(NULL, NULL, control_stream, buf) != 226) { 274 if (ftpcmd(NULL, NULL, control_stream, buf) != 226) {
252 bb_error_msg_and_die("error: %s", buf + 4); 275 ftp_die("close", buf);
253 } 276 }
254 ftpcmd("QUIT", NULL, control_stream, buf); 277 ftpcmd("QUIT", NULL, control_stream, buf);
255 278
@@ -278,21 +301,24 @@ int ftpgetput_main(int argc, char **argv)
278{ 301{
279 /* content-length of the file */ 302 /* content-length of the file */
280 unsigned opt; 303 unsigned opt;
281 char *port = "ftp"; 304 const char *port = "ftp";
282 /* socket to ftp server */ 305 /* socket to ftp server */
283 FILE *control_stream; 306 FILE *control_stream;
284 struct sockaddr_in s_in; 307 struct sockaddr_in s_in;
285 /* continue a prev transfer (-c) */ 308 /* continue previous transfer (-c) */
286 ftp_host_info_t *server; 309 ftp_host_info_t *server;
287 int (*ftp_action)(ftp_host_info_t *, FILE *, const char *, char *) = NULL;
288 310
311#if ENABLE_FTPPUT && !ENABLE_FTPGET
312# define ftp_action ftp_send
313#elif ENABLE_FTPGET && !ENABLE_FTPPUT
314# define ftp_action ftp_receive
315#else
316 int (*ftp_action)(ftp_host_info_t *, FILE *, const char *, char *) = ftp_send;
289 /* Check to see if the command is ftpget or ftput */ 317 /* Check to see if the command is ftpget or ftput */
290 if (ENABLE_FTPPUT && (!ENABLE_FTPGET || applet_name[3] == 'p')) { 318 if (applet_name[3] == 'g') {
291 ftp_action = ftp_send;
292 }
293 if (ENABLE_FTPGET && (!ENABLE_FTPPUT || applet_name[3] == 'g')) {
294 ftp_action = ftp_receive; 319 ftp_action = ftp_receive;
295 } 320 }
321#endif
296 322
297 /* Set default values */ 323 /* Set default values */
298 server = xmalloc(sizeof(ftp_host_info_t)); 324 server = xmalloc(sizeof(ftp_host_info_t));
@@ -306,13 +332,11 @@ int ftpgetput_main(int argc, char **argv)
306#if ENABLE_FEATURE_FTPGETPUT_LONG_OPTIONS 332#if ENABLE_FEATURE_FTPGETPUT_LONG_OPTIONS
307 applet_long_options = ftpgetput_long_options; 333 applet_long_options = ftpgetput_long_options;
308#endif 334#endif
335 opt_complementary = "=3"; /* must have 3 params */
309 opt = getopt32(argc, argv, "cvu:p:P:", &server->user, &server->password, &port); 336 opt = getopt32(argc, argv, "cvu:p:P:", &server->user, &server->password, &port);
337 argv += optind;
310 338
311 /* Process the non-option command line arguments */ 339 /* Process the non-option command line arguments */
312 if (argc - optind != 3) {
313 bb_show_usage();
314 }
315
316 if (opt & FTPGETPUT_OPT_CONTINUE) { 340 if (opt & FTPGETPUT_OPT_CONTINUE) {
317 do_continue = 1; 341 do_continue = 1;
318 } 342 }
@@ -324,15 +348,15 @@ int ftpgetput_main(int argc, char **argv)
324 * sites (i.e. ftp.us.debian.org) use round-robin DNS 348 * sites (i.e. ftp.us.debian.org) use round-robin DNS
325 * and we want to connect to only one IP... */ 349 * and we want to connect to only one IP... */
326 server->s_in = &s_in; 350 server->s_in = &s_in;
327 bb_lookup_host(&s_in, argv[optind]); 351 bb_lookup_host(&s_in, argv[0]);
328 s_in.sin_port = bb_lookup_port(port, "tcp", 21); 352 s_in.sin_port = bb_lookup_port(port, "tcp", 21);
329 if (verbose_flag) { 353 if (verbose_flag) {
330 printf("Connecting to %s[%s]:%d\n", 354 printf("Connecting to %s[%s]:%d\n",
331 argv[optind], inet_ntoa(s_in.sin_addr), ntohs(s_in.sin_port)); 355 argv[0], inet_ntoa(s_in.sin_addr), ntohs(s_in.sin_port));
332 } 356 }
333 357
334 /* Connect/Setup/Configure the FTP session */ 358 /* Connect/Setup/Configure the FTP session */
335 control_stream = ftp_login(server); 359 control_stream = ftp_login(server);
336 360
337 return ftp_action(server, control_stream, argv[optind + 1], argv[optind + 2]); 361 return ftp_action(server, control_stream, argv[1], argv[2]);
338} 362}