diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2009-03-08 23:46:48 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2009-03-08 23:46:48 +0000 |
commit | 5e4fda0affaa0a80a5ff33dd72c702b8f905be33 (patch) | |
tree | 9e31fd173276aa6c8e03ba70511c72fe8550e68a /networking | |
parent | bf9d17949ee8b5ba8bbfdcd9a78b9a12fb122b63 (diff) | |
download | busybox-w32-5e4fda0affaa0a80a5ff33dd72c702b8f905be33.tar.gz busybox-w32-5e4fda0affaa0a80a5ff33dd72c702b8f905be33.tar.bz2 busybox-w32-5e4fda0affaa0a80a5ff33dd72c702b8f905be33.zip |
ftpd: code chrink, fixed some minor bugs
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
Diffstat (limited to 'networking')
-rw-r--r-- | networking/Config.in | 4 | ||||
-rw-r--r-- | networking/ftpd.c | 760 | ||||
-rw-r--r-- | networking/isrv_identd.c | 2 | ||||
-rw-r--r-- | networking/telnetd.c | 2 | ||||
-rw-r--r-- | networking/udhcp/dhcpc.c | 2 | ||||
-rw-r--r-- | networking/udhcp/dhcpd.c | 2 |
6 files changed, 394 insertions, 378 deletions
diff --git a/networking/Config.in b/networking/Config.in index f3ba85620..392afcf89 100644 --- a/networking/Config.in +++ b/networking/Config.in | |||
@@ -100,11 +100,11 @@ config FTPD | |||
100 | simple FTP daemon. You have to run it via inetd. | 100 | simple FTP daemon. You have to run it via inetd. |
101 | 101 | ||
102 | config FEATURE_FTP_WRITE | 102 | config FEATURE_FTP_WRITE |
103 | bool "enable write" | 103 | bool "Enable upload commands" |
104 | default y | 104 | default y |
105 | depends on FTPD | 105 | depends on FTPD |
106 | help | 106 | help |
107 | Enable all kinds of FTP write commands (you have to add -w parameter) | 107 | Enable all kinds of FTP upload commands (-w option) |
108 | 108 | ||
109 | config FTPGET | 109 | config FTPGET |
110 | bool "ftpget" | 110 | bool "ftpget" |
diff --git a/networking/ftpd.c b/networking/ftpd.c index ab7308be9..91cbc17f4 100644 --- a/networking/ftpd.c +++ b/networking/ftpd.c | |||
@@ -12,9 +12,13 @@ | |||
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include "libbb.h" | 14 | #include "libbb.h" |
15 | #include <syslog.h> | ||
15 | #include <netinet/tcp.h> | 16 | #include <netinet/tcp.h> |
16 | 17 | ||
17 | enum { | 18 | enum { |
19 | OPT_v = (1 << 0), | ||
20 | OPT_w = (1 << 1), | ||
21 | |||
18 | FTP_DATACONN = 150, | 22 | FTP_DATACONN = 150, |
19 | FTP_NOOPOK = 200, | 23 | FTP_NOOPOK = 200, |
20 | FTP_TYPEOK = 200, | 24 | FTP_TYPEOK = 200, |
@@ -32,20 +36,14 @@ enum { | |||
32 | FTP_PASVOK = 227, | 36 | FTP_PASVOK = 227, |
33 | FTP_LOGINOK = 230, | 37 | FTP_LOGINOK = 230, |
34 | FTP_CWDOK = 250, | 38 | FTP_CWDOK = 250, |
35 | #if ENABLE_FEATURE_FTP_WRITE | ||
36 | FTP_RMDIROK = 250, | 39 | FTP_RMDIROK = 250, |
37 | FTP_DELEOK = 250, | 40 | FTP_DELEOK = 250, |
38 | FTP_RENAMEOK = 250, | 41 | FTP_RENAMEOK = 250, |
39 | #endif | ||
40 | FTP_PWDOK = 257, | 42 | FTP_PWDOK = 257, |
41 | #if ENABLE_FEATURE_FTP_WRITE | ||
42 | FTP_MKDIROK = 257, | 43 | FTP_MKDIROK = 257, |
43 | #endif | ||
44 | FTP_GIVEPWORD = 331, | 44 | FTP_GIVEPWORD = 331, |
45 | FTP_RESTOK = 350, | 45 | FTP_RESTOK = 350, |
46 | #if ENABLE_FEATURE_FTP_WRITE | ||
47 | FTP_RNFROK = 350, | 46 | FTP_RNFROK = 350, |
48 | #endif | ||
49 | FTP_BADSENDCONN = 425, | 47 | FTP_BADSENDCONN = 425, |
50 | FTP_BADSENDNET = 426, | 48 | FTP_BADSENDNET = 426, |
51 | FTP_BADSENDFILE = 451, | 49 | FTP_BADSENDFILE = 451, |
@@ -100,16 +98,23 @@ struct globals { | |||
100 | int data_fd; | 98 | int data_fd; |
101 | off_t restart_pos; | 99 | off_t restart_pos; |
102 | char *ftp_cmp; | 100 | char *ftp_cmp; |
103 | char *ftp_arg; | 101 | const char *ftp_arg; |
104 | #if ENABLE_FEATURE_FTP_WRITE | 102 | #if ENABLE_FEATURE_FTP_WRITE |
105 | char *rnfr_filename; | 103 | char *rnfr_filename; |
106 | smallint write_enable; | ||
107 | #endif | 104 | #endif |
105 | smallint opts; | ||
108 | }; | 106 | }; |
109 | #define G (*(struct globals*)&bb_common_bufsiz1) | 107 | #define G (*(struct globals*)&bb_common_bufsiz1) |
110 | #define INIT_G() do { } while (0) | 108 | #define INIT_G() do { } while (0) |
111 | 109 | ||
112 | 110 | ||
111 | // libbb candidate? | ||
112 | static void | ||
113 | xwrite_str(int fd, const char *str) | ||
114 | { | ||
115 | xwrite(fd, str, strlen(str)); | ||
116 | } | ||
117 | |||
113 | static char * | 118 | static char * |
114 | replace_text(const char *str, const char from, const char *to) | 119 | replace_text(const char *str, const char from, const char *to) |
115 | { | 120 | { |
@@ -119,11 +124,10 @@ replace_text(const char *str, const char from, const char *to) | |||
119 | 124 | ||
120 | remain = str; | 125 | remain = str; |
121 | remainlen = strlen(str); | 126 | remainlen = strlen(str); |
122 | |||
123 | tolen = strlen(to); | 127 | tolen = strlen(to); |
124 | 128 | ||
125 | /* simply alloc strlen(str)*strlen(to). To is max 2 so it's allowed */ | 129 | /* Simply alloc strlen(str)*strlen(to). "to" is max 2 so it's ok */ |
126 | ret = xmalloc(remainlen * strlen(to) + 1); | 130 | ret = xmalloc(remainlen * tolen + 1); |
127 | retlen = 0; | 131 | retlen = 0; |
128 | 132 | ||
129 | for (;;) { | 133 | for (;;) { |
@@ -155,19 +159,8 @@ replace_text(const char *str, const char from, const char *to) | |||
155 | static void | 159 | static void |
156 | replace_char(char *str, char from, char to) | 160 | replace_char(char *str, char from, char to) |
157 | { | 161 | { |
158 | char *ptr; | 162 | while ((str = strchr(str, from)) != NULL) |
159 | 163 | *str++ = to; | |
160 | /* Don't use strchr here...*/ | ||
161 | while ((ptr = strchr(str, from)) != NULL) { | ||
162 | *ptr = to; | ||
163 | str = ptr + 1; | ||
164 | } | ||
165 | } | ||
166 | |||
167 | static void | ||
168 | str_netfd_write(const char *str, int fd) | ||
169 | { | ||
170 | xwrite(fd, str, strlen(str)); | ||
171 | } | 164 | } |
172 | 165 | ||
173 | static void | 166 | static void |
@@ -182,7 +175,7 @@ ftp_write_str_common(unsigned int status, const char *str, char sep) | |||
182 | free(escaped_str); | 175 | free(escaped_str); |
183 | 176 | ||
184 | len = strlen(response); | 177 | len = strlen(response); |
185 | replace_char(escaped_str, '\n', '\0'); | 178 | replace_char(response, '\n', '\0'); |
186 | 179 | ||
187 | /* Change trailing '\0' back to '\n' */ | 180 | /* Change trailing '\0' back to '\n' */ |
188 | response[len - 1] = '\n'; | 181 | response[len - 1] = '\n'; |
@@ -196,6 +189,12 @@ cmdio_write(int status, const char *p_text) | |||
196 | } | 189 | } |
197 | 190 | ||
198 | static void | 191 | static void |
192 | cmdio_write_ok(int status) | ||
193 | { | ||
194 | ftp_write_str_common(status, "Operation successful", ' '); | ||
195 | } | ||
196 | |||
197 | static void | ||
199 | cmdio_write_hyphen(int status, const char *p_text) | 198 | cmdio_write_hyphen(int status, const char *p_text) |
200 | { | 199 | { |
201 | ftp_write_str_common(status, p_text, '-'); | 200 | ftp_write_str_common(status, p_text, '-'); |
@@ -204,24 +203,22 @@ cmdio_write_hyphen(int status, const char *p_text) | |||
204 | static void | 203 | static void |
205 | cmdio_write_raw(const char *p_text) | 204 | cmdio_write_raw(const char *p_text) |
206 | { | 205 | { |
207 | str_netfd_write(p_text, STDIN_FILENO); | 206 | xwrite_str(STDIN_FILENO, p_text); |
208 | } | 207 | } |
209 | 208 | ||
210 | static uint32_t | 209 | static uint32_t |
211 | cmdio_get_cmd_and_arg(void) | 210 | cmdio_get_cmd_and_arg(void) |
212 | { | 211 | { |
213 | int len; | 212 | size_t len; |
214 | uint32_t cmdval; | 213 | uint32_t cmdval; |
215 | char *cmd; | 214 | char *cmd; |
216 | 215 | ||
217 | free(G.ftp_cmp); | 216 | free(G.ftp_cmp); |
218 | G.ftp_cmp = cmd = xmalloc_reads(STDIN_FILENO, NULL, NULL); | 217 | len = 8 * 1024; /* Paranoia. Peer may send 1 gigabyte long cmd... */ |
219 | /* | 218 | G.ftp_cmp = cmd = xmalloc_reads(STDIN_FILENO, NULL, &len); |
220 | * TODO: | 219 | if (!cmd) |
221 | * | 220 | exit(0); |
222 | * now we should change all '\0' to '\n' - xmalloc_reads will be improved, | 221 | |
223 | * probably | ||
224 | */ | ||
225 | len = strlen(cmd) - 1; | 222 | len = strlen(cmd) - 1; |
226 | while (len >= 0 && cmd[len] == '\r') { | 223 | while (len >= 0 && cmd[len] == '\r') { |
227 | cmd[len] = '\0'; | 224 | cmd[len] = '\0'; |
@@ -230,7 +227,7 @@ cmdio_get_cmd_and_arg(void) | |||
230 | 227 | ||
231 | G.ftp_arg = strchr(cmd, ' '); | 228 | G.ftp_arg = strchr(cmd, ' '); |
232 | if (G.ftp_arg != NULL) { | 229 | if (G.ftp_arg != NULL) { |
233 | *G.ftp_arg = '\0'; | 230 | *(char *)G.ftp_arg = '\0'; |
234 | G.ftp_arg++; | 231 | G.ftp_arg++; |
235 | } | 232 | } |
236 | cmdval = 0; | 233 | cmdval = 0; |
@@ -338,7 +335,7 @@ handle_pwd(void) | |||
338 | if (cwd == NULL) | 335 | if (cwd == NULL) |
339 | cwd = xstrdup(""); | 336 | cwd = xstrdup(""); |
340 | 337 | ||
341 | /* We _have to_ promote each " to "" */ | 338 | /* We have to promote each " to "" */ |
342 | promoted_cwd = replace_text(cwd, '\"', "\"\""); | 339 | promoted_cwd = replace_text(cwd, '\"', "\"\""); |
343 | free(cwd); | 340 | free(cwd); |
344 | response = xasprintf("\"%s\"", promoted_cwd); | 341 | response = xasprintf("\"%s\"", promoted_cwd); |
@@ -350,22 +347,18 @@ handle_pwd(void) | |||
350 | static void | 347 | static void |
351 | handle_cwd(void) | 348 | handle_cwd(void) |
352 | { | 349 | { |
353 | int retval; | 350 | if (!G.ftp_arg || chdir(G.ftp_arg) != 0) { |
354 | |||
355 | /* XXX Do we need check ftp_arg != NULL? */ | ||
356 | retval = chdir(G.ftp_arg); | ||
357 | if (retval == 0) | ||
358 | cmdio_write(FTP_CWDOK, "Directory changed"); | ||
359 | else | ||
360 | cmdio_write(FTP_FILEFAIL, "Can't change directory"); | 351 | cmdio_write(FTP_FILEFAIL, "Can't change directory"); |
352 | return; | ||
353 | } | ||
354 | cmdio_write_ok(FTP_CWDOK); | ||
361 | } | 355 | } |
362 | 356 | ||
363 | static void | 357 | static void |
364 | handle_cdup(void) | 358 | handle_cdup(void) |
365 | { | 359 | { |
366 | G.ftp_arg = xstrdup(".."); | 360 | G.ftp_arg = ".."; |
367 | handle_cwd(); | 361 | handle_cwd(); |
368 | free(G.ftp_arg); | ||
369 | } | 362 | } |
370 | 363 | ||
371 | static int | 364 | static int |
@@ -382,9 +375,7 @@ data_transfer_checks_ok(void) | |||
382 | static void | 375 | static void |
383 | port_cleanup(void) | 376 | port_cleanup(void) |
384 | { | 377 | { |
385 | if (G.port_addr != NULL) | 378 | free(G.port_addr); |
386 | free(G.port_addr); | ||
387 | |||
388 | G.port_addr = NULL; | 379 | G.port_addr = NULL; |
389 | } | 380 | } |
390 | 381 | ||
@@ -396,6 +387,162 @@ pasv_cleanup(void) | |||
396 | G.pasv_listen_fd = -1; | 387 | G.pasv_listen_fd = -1; |
397 | } | 388 | } |
398 | 389 | ||
390 | static void | ||
391 | handle_pasv(void) | ||
392 | { | ||
393 | int bind_retries = 10; | ||
394 | unsigned short port; | ||
395 | enum { min_port = 1024, max_port = 65535 }; | ||
396 | char *addr, *wire_addr, *response; | ||
397 | |||
398 | pasv_cleanup(); | ||
399 | port_cleanup(); | ||
400 | G.pasv_listen_fd = xsocket(G.local_addr->u.sa.sa_family, SOCK_STREAM, 0); | ||
401 | setsockopt_reuseaddr(G.pasv_listen_fd); | ||
402 | |||
403 | /* TODO bind() with port == 0 and then call getsockname */ | ||
404 | while (--bind_retries) { | ||
405 | port = rand() % max_port; | ||
406 | if (port < min_port) { | ||
407 | port += min_port; | ||
408 | } | ||
409 | |||
410 | set_nport(G.local_addr, htons(port)); | ||
411 | /* We don't want to use xbind, it'll die if port is in use */ | ||
412 | if (bind(G.pasv_listen_fd, &G.local_addr->u.sa, G.local_addr->len) != 0) { | ||
413 | /* do we want check if errno == EADDRINUSE ? */ | ||
414 | continue; | ||
415 | } | ||
416 | xlisten(G.pasv_listen_fd, 1); | ||
417 | break; | ||
418 | } | ||
419 | |||
420 | if (!bind_retries) | ||
421 | bb_error_msg_and_die("can't create pasv socket"); | ||
422 | |||
423 | addr = xmalloc_sockaddr2dotted_noport(&G.local_addr->u.sa); | ||
424 | wire_addr = replace_text(addr, '.', ","); | ||
425 | free(addr); | ||
426 | |||
427 | response = xasprintf("Entering Passive Mode (%s,%u,%u)", | ||
428 | wire_addr, (int)(port >> 8), (int)(port & 255)); | ||
429 | |||
430 | cmdio_write(FTP_PASVOK, response); | ||
431 | free(wire_addr); | ||
432 | free(response); | ||
433 | } | ||
434 | |||
435 | static void | ||
436 | handle_port(void) | ||
437 | { | ||
438 | unsigned short port; | ||
439 | char *raw = NULL, *port_part; | ||
440 | len_and_sockaddr *lsa = NULL; | ||
441 | |||
442 | pasv_cleanup(); | ||
443 | port_cleanup(); | ||
444 | |||
445 | if (G.ftp_arg == NULL) | ||
446 | goto bail; | ||
447 | |||
448 | raw = replace_text(G.ftp_arg, ',', "."); | ||
449 | |||
450 | port_part = strrchr(raw, '.'); | ||
451 | if (port_part == NULL) | ||
452 | goto bail; | ||
453 | |||
454 | port = xatou16(&port_part[1]); | ||
455 | *port_part = '\0'; | ||
456 | |||
457 | port_part = strrchr(raw, '.'); | ||
458 | if (port_part == NULL) | ||
459 | goto bail; | ||
460 | |||
461 | port |= xatou16(&port_part[1]) << 8; | ||
462 | *port_part = '\0'; | ||
463 | |||
464 | lsa = xdotted2sockaddr(raw, port); | ||
465 | |||
466 | bail: | ||
467 | free(raw); | ||
468 | |||
469 | if (lsa == NULL) { | ||
470 | cmdio_write(FTP_BADCMD, "Illegal PORT command"); | ||
471 | return; | ||
472 | } | ||
473 | |||
474 | G.port_addr = lsa; | ||
475 | cmdio_write_ok(FTP_PORTOK); | ||
476 | } | ||
477 | |||
478 | static void | ||
479 | handle_rest(void) | ||
480 | { | ||
481 | /* When ftp_arg == NULL simply restart from beginning */ | ||
482 | G.restart_pos = G.ftp_arg ? xatoi_u(G.ftp_arg) : 0; | ||
483 | cmdio_write_ok(FTP_RESTOK); | ||
484 | } | ||
485 | |||
486 | static void | ||
487 | handle_retr(void) | ||
488 | { | ||
489 | struct stat statbuf; | ||
490 | int trans_ret, retval; | ||
491 | int remote_fd; | ||
492 | int opened_file; | ||
493 | off_t offset = G.restart_pos; | ||
494 | char *response; | ||
495 | |||
496 | G.restart_pos = 0; | ||
497 | |||
498 | if (!data_transfer_checks_ok()) | ||
499 | return; | ||
500 | |||
501 | /* O_NONBLOCK is useful if file happens to be a device node */ | ||
502 | opened_file = G.ftp_arg ? open(G.ftp_arg, O_RDONLY | O_NONBLOCK) : -1; | ||
503 | if (opened_file < 0) { | ||
504 | cmdio_write(FTP_FILEFAIL, "Can't open file"); | ||
505 | return; | ||
506 | } | ||
507 | |||
508 | retval = fstat(opened_file, &statbuf); | ||
509 | if (retval < 0 || !S_ISREG(statbuf.st_mode)) { | ||
510 | /* Note - pretend open failed */ | ||
511 | cmdio_write(FTP_FILEFAIL, "Can't open file"); | ||
512 | goto file_close_out; | ||
513 | } | ||
514 | |||
515 | /* Now deactive O_NONBLOCK, otherwise we have a problem on DMAPI filesystems | ||
516 | * such as XFS DMAPI. | ||
517 | */ | ||
518 | ndelay_off(opened_file); | ||
519 | |||
520 | /* Set the download offset (from REST) if any */ | ||
521 | if (offset != 0) | ||
522 | xlseek(opened_file, offset, SEEK_SET); | ||
523 | |||
524 | response = xasprintf( | ||
525 | "Opening BINARY mode data connection for %s (%"OFF_FMT"u bytes)", | ||
526 | G.ftp_arg, statbuf.st_size); | ||
527 | remote_fd = get_remote_transfer_fd(response); | ||
528 | free(response); | ||
529 | if (remote_fd < 0) | ||
530 | goto port_pasv_cleanup_out; | ||
531 | |||
532 | trans_ret = bb_copyfd_eof(opened_file, remote_fd); | ||
533 | ftpdataio_dispose_transfer_fd(); | ||
534 | if (trans_ret < 0) | ||
535 | cmdio_write(FTP_BADSENDFILE, "Error sending local file"); | ||
536 | else | ||
537 | cmdio_write_ok(FTP_TRANSFEROK); | ||
538 | |||
539 | port_pasv_cleanup_out: | ||
540 | port_cleanup(); | ||
541 | pasv_cleanup(); | ||
542 | file_close_out: | ||
543 | close(opened_file); | ||
544 | } | ||
545 | |||
399 | static char * | 546 | static char * |
400 | statbuf_getperms(const struct stat *statbuf) | 547 | statbuf_getperms(const struct stat *statbuf) |
401 | { | 548 | { |
@@ -472,14 +619,14 @@ write_filestats(int fd, const char *filename, | |||
472 | } else | 619 | } else |
473 | stats = xstrdup(name); | 620 | stats = xstrdup(name); |
474 | 621 | ||
475 | str_netfd_write(stats, fd); | 622 | xwrite_str(fd, stats); |
476 | free(stats); | 623 | free(stats); |
477 | if (lnkname != NULL) { | 624 | if (lnkname != NULL) { |
478 | str_netfd_write(" -> ", fd); | 625 | xwrite_str(fd, " -> "); |
479 | str_netfd_write(lnkname, fd); | 626 | xwrite_str(fd, lnkname); |
480 | free(lnkname); | 627 | free(lnkname); |
481 | } | 628 | } |
482 | str_netfd_write("\r\n", fd); | 629 | xwrite_str(fd, "\r\n"); |
483 | } | 630 | } |
484 | 631 | ||
485 | static void | 632 | static void |
@@ -510,7 +657,7 @@ write_dirstats(int fd, const char *dname, int details) | |||
510 | filename = xasprintf("%s/%s", dname, dirent->d_name); | 657 | filename = xasprintf("%s/%s", dname, dirent->d_name); |
511 | if (lstat(filename, &statbuf) != 0) { | 658 | if (lstat(filename, &statbuf) != 0) { |
512 | free(filename); | 659 | free(filename); |
513 | goto bail; | 660 | break; |
514 | } | 661 | } |
515 | } else | 662 | } else |
516 | filename = xstrdup(dirent->d_name); | 663 | filename = xstrdup(dirent->d_name); |
@@ -519,117 +666,10 @@ write_dirstats(int fd, const char *dname, int details) | |||
519 | free(filename); | 666 | free(filename); |
520 | } | 667 | } |
521 | 668 | ||
522 | bail: | ||
523 | closedir(dir); | 669 | closedir(dir); |
524 | } | 670 | } |
525 | 671 | ||
526 | static void | 672 | static void |
527 | handle_pasv(void) | ||
528 | { | ||
529 | int bind_retries = 10; | ||
530 | unsigned short port; | ||
531 | enum { min_port = 1024, max_port = 65535 }; | ||
532 | char *addr, *wire_addr, *response; | ||
533 | |||
534 | pasv_cleanup(); | ||
535 | port_cleanup(); | ||
536 | G.pasv_listen_fd = xsocket(G.local_addr->u.sa.sa_family, SOCK_STREAM, 0); | ||
537 | setsockopt_reuseaddr(G.pasv_listen_fd); | ||
538 | |||
539 | /* TODO bind() with port == 0 and then call getsockname */ | ||
540 | while (--bind_retries) { | ||
541 | port = rand() % max_port; | ||
542 | if (port < min_port) { | ||
543 | port += min_port; | ||
544 | } | ||
545 | |||
546 | set_nport(G.local_addr, htons(port)); | ||
547 | /* We don't want to use xbind, it'll die if port is in use */ | ||
548 | if (bind(G.pasv_listen_fd, &G.local_addr->u.sa, G.local_addr->len) != 0) { | ||
549 | /* do we want check if errno == EADDRINUSE ? */ | ||
550 | continue; | ||
551 | } | ||
552 | xlisten(G.pasv_listen_fd, 1); | ||
553 | break; | ||
554 | } | ||
555 | |||
556 | if (!bind_retries) | ||
557 | bb_error_msg_and_die("can't create pasv socket"); | ||
558 | |||
559 | addr = xmalloc_sockaddr2dotted_noport(&G.local_addr->u.sa); | ||
560 | wire_addr = replace_text(addr, '.', ","); | ||
561 | free(addr); | ||
562 | |||
563 | response = xasprintf("Entering Passive Mode (%s,%u,%u)", | ||
564 | wire_addr, (int)(port >> 8), (int)(port & 255)); | ||
565 | |||
566 | cmdio_write(FTP_PASVOK, response); | ||
567 | free(wire_addr); | ||
568 | free(response); | ||
569 | } | ||
570 | |||
571 | static void | ||
572 | handle_retr(void) | ||
573 | { | ||
574 | struct stat statbuf; | ||
575 | int trans_ret, retval; | ||
576 | int remote_fd; | ||
577 | int opened_file; | ||
578 | off_t offset = G.restart_pos; | ||
579 | char *response; | ||
580 | |||
581 | G.restart_pos = 0; | ||
582 | |||
583 | if (!data_transfer_checks_ok()) | ||
584 | return; | ||
585 | |||
586 | /* XXX Do we need check if ftp_arg != NULL? */ | ||
587 | opened_file = open(G.ftp_arg, O_RDONLY | O_NONBLOCK); | ||
588 | if (opened_file < 0) { | ||
589 | cmdio_write(FTP_FILEFAIL, "Can't open file"); | ||
590 | return; | ||
591 | } | ||
592 | |||
593 | retval = fstat(opened_file, &statbuf); | ||
594 | if (retval < 0 || !S_ISREG(statbuf.st_mode)) { | ||
595 | /* Note - pretend open failed */ | ||
596 | cmdio_write(FTP_FILEFAIL, "Can't open file"); | ||
597 | goto file_close_out; | ||
598 | } | ||
599 | |||
600 | /* Now deactive O_NONBLOCK, otherwise we have a problem on DMAPI filesystems | ||
601 | * such as XFS DMAPI. | ||
602 | */ | ||
603 | ndelay_off(opened_file); | ||
604 | |||
605 | /* Set the download offset (from REST) if any */ | ||
606 | if (offset != 0) | ||
607 | xlseek(opened_file, offset, SEEK_SET); | ||
608 | |||
609 | response = xasprintf( | ||
610 | "Opening BINARY mode data connection for (%s %"OFF_FMT"u bytes).", | ||
611 | G.ftp_arg, statbuf.st_size); | ||
612 | |||
613 | remote_fd = get_remote_transfer_fd(response); | ||
614 | free(response); | ||
615 | if (remote_fd < 0) | ||
616 | goto port_pasv_cleanup_out; | ||
617 | |||
618 | trans_ret = bb_copyfd_eof(opened_file, remote_fd); | ||
619 | ftpdataio_dispose_transfer_fd(); | ||
620 | if (trans_ret < 0) | ||
621 | cmdio_write(FTP_BADSENDFILE, "Error sending local file"); | ||
622 | else | ||
623 | cmdio_write(FTP_TRANSFEROK, "File sent OK"); | ||
624 | |||
625 | port_pasv_cleanup_out: | ||
626 | port_cleanup(); | ||
627 | pasv_cleanup(); | ||
628 | file_close_out: | ||
629 | close(opened_file); | ||
630 | } | ||
631 | |||
632 | static void | ||
633 | handle_dir_common(int full_details, int stat_cmd) | 673 | handle_dir_common(int full_details, int stat_cmd) |
634 | { | 674 | { |
635 | int fd; | 675 | int fd; |
@@ -647,7 +687,7 @@ handle_dir_common(int full_details, int stat_cmd) | |||
647 | goto bail; | 687 | goto bail; |
648 | } | 688 | } |
649 | 689 | ||
650 | if (G.ftp_arg != NULL) { | 690 | if (G.ftp_arg) { |
651 | if (lstat(G.ftp_arg, &statbuf) != 0) { | 691 | if (lstat(G.ftp_arg, &statbuf) != 0) { |
652 | /* Dir doesn't exist => return ok to client */ | 692 | /* Dir doesn't exist => return ok to client */ |
653 | goto bail; | 693 | goto bail; |
@@ -665,9 +705,9 @@ bail: | |||
665 | ftpdataio_dispose_transfer_fd(); | 705 | ftpdataio_dispose_transfer_fd(); |
666 | pasv_cleanup(); | 706 | pasv_cleanup(); |
667 | port_cleanup(); | 707 | port_cleanup(); |
668 | cmdio_write(FTP_TRANSFEROK, "OK"); | 708 | cmdio_write_ok(FTP_TRANSFEROK); |
669 | } else | 709 | } else |
670 | cmdio_write(FTP_STATFILE_OK, "End of status"); | 710 | cmdio_write_ok(FTP_STATFILE_OK); |
671 | } | 711 | } |
672 | 712 | ||
673 | static void | 713 | static void |
@@ -677,6 +717,26 @@ handle_list(void) | |||
677 | } | 717 | } |
678 | 718 | ||
679 | static void | 719 | static void |
720 | handle_nlst(void) | ||
721 | { | ||
722 | handle_dir_common(0, 0); | ||
723 | } | ||
724 | |||
725 | static void | ||
726 | handle_stat_file(void) | ||
727 | { | ||
728 | handle_dir_common(1, 1); | ||
729 | } | ||
730 | |||
731 | static void | ||
732 | handle_stat(void) | ||
733 | { | ||
734 | cmdio_write_hyphen(FTP_STATOK, "FTP server status:"); | ||
735 | cmdio_write_raw(" TYPE: BINARY\r\n"); | ||
736 | cmdio_write_ok(FTP_STATOK); | ||
737 | } | ||
738 | |||
739 | static void | ||
680 | handle_type(void) | 740 | handle_type(void) |
681 | { | 741 | { |
682 | if (G.ftp_arg | 742 | if (G.ftp_arg |
@@ -685,81 +745,47 @@ handle_type(void) | |||
685 | || !strcasecmp(G.ftp_arg, "L 8") | 745 | || !strcasecmp(G.ftp_arg, "L 8") |
686 | ) | 746 | ) |
687 | ) { | 747 | ) { |
688 | cmdio_write(FTP_TYPEOK, "Switching to Binary mode"); | 748 | cmdio_write_ok(FTP_TYPEOK); |
689 | } else { | 749 | } else { |
690 | cmdio_write(FTP_BADCMD, "Unrecognised TYPE command"); | 750 | cmdio_write(FTP_BADCMD, "Unrecognised TYPE command"); |
691 | } | 751 | } |
692 | } | 752 | } |
693 | 753 | ||
694 | static void | 754 | static void |
695 | handle_port(void) | 755 | handle_help(void) |
696 | { | 756 | { |
697 | unsigned short port; | 757 | cmdio_write_hyphen(FTP_HELP, "Recognized commands:"); |
698 | char *raw = NULL, *port_part; | 758 | cmdio_write_raw(" ALLO CDUP CWD HELP LIST\r\n" |
699 | len_and_sockaddr *lsa = NULL; | 759 | " MODE NLST NOOP PASS PASV PORT PWD QUIT\r\n" |
700 | 760 | " REST RETR STAT STRU SYST TYPE USER\r\n" | |
701 | pasv_cleanup(); | 761 | #if ENABLE_FEATURE_FTP_WRITE |
702 | port_cleanup(); | 762 | " APPE DELE MKD RMD RNFR RNTO STOR STOU\r\n" |
703 | 763 | #endif | |
704 | if (G.ftp_arg == NULL) | 764 | ); |
705 | goto bail; | 765 | cmdio_write(FTP_HELP, "Help OK"); |
706 | |||
707 | raw = replace_text(G.ftp_arg, ',', "."); | ||
708 | |||
709 | port_part = strrchr(raw, '.'); | ||
710 | if (port_part == NULL) | ||
711 | goto bail; | ||
712 | |||
713 | port = xatou16(&port_part[1]); | ||
714 | *port_part = '\0'; | ||
715 | |||
716 | port_part = strrchr(raw, '.'); | ||
717 | if (port_part == NULL) | ||
718 | goto bail; | ||
719 | |||
720 | port |= xatou16(&port_part[1]) << 8; | ||
721 | *port_part = '\0'; | ||
722 | |||
723 | lsa = xdotted2sockaddr(raw, port); | ||
724 | |||
725 | bail: | ||
726 | free(raw); | ||
727 | |||
728 | if (lsa == NULL) { | ||
729 | cmdio_write(FTP_BADCMD, "Illegal PORT command"); | ||
730 | return; | ||
731 | } | ||
732 | |||
733 | G.port_addr = lsa; | ||
734 | cmdio_write(FTP_PORTOK, "PORT command successful. Consider using PASV"); | ||
735 | } | 766 | } |
736 | 767 | ||
737 | #if ENABLE_FEATURE_FTP_WRITE | 768 | #if ENABLE_FEATURE_FTP_WRITE |
738 | static void | 769 | static void |
739 | handle_upload_common(int is_append, int is_unique) | 770 | handle_upload_common(int is_append, int is_unique) |
740 | { | 771 | { |
741 | char *template = NULL; | 772 | char *tempname = NULL; |
742 | int trans_ret; | 773 | int trans_ret; |
743 | int new_file_fd; | 774 | int new_file_fd; |
744 | int remote_fd; | 775 | int remote_fd; |
745 | |||
746 | enum { | ||
747 | fileflags = O_CREAT | O_WRONLY | O_APPEND, | ||
748 | }; | ||
749 | |||
750 | off_t offset = G.restart_pos; | 776 | off_t offset = G.restart_pos; |
751 | 777 | ||
752 | G.restart_pos = 0; | 778 | G.restart_pos = 0; |
753 | if (!data_transfer_checks_ok()) | 779 | if (!G.ftp_arg || !data_transfer_checks_ok()) |
754 | return; | 780 | return; |
755 | 781 | ||
756 | if (is_unique) { | 782 | if (is_unique) { |
757 | template = xstrdup("uniq.XXXXXX"); | 783 | tempname = xstrdup("FILE: uniq.XXXXXX"); |
758 | /* | 784 | /* |
759 | * XXX Use mkostemp here? vsftpd opens file with O_CREAT, O_WRONLY, | 785 | * XXX Use mkostemp here? vsftpd opens file with O_CREAT, O_WRONLY, |
760 | * O_APPEND and O_EXCL flags... | 786 | * O_APPEND and O_EXCL flags... |
761 | */ | 787 | */ |
762 | new_file_fd = mkstemp(template); | 788 | new_file_fd = mkstemp(tempname + 6); |
763 | } else { | 789 | } else { |
764 | /* XXX Do we need check if ftp_arg != NULL? */ | 790 | /* XXX Do we need check if ftp_arg != NULL? */ |
765 | if (!is_append && offset == 0) | 791 | if (!is_append && offset == 0) |
@@ -778,11 +804,9 @@ handle_upload_common(int is_append, int is_unique) | |||
778 | xlseek(new_file_fd, offset, SEEK_SET); | 804 | xlseek(new_file_fd, offset, SEEK_SET); |
779 | } | 805 | } |
780 | 806 | ||
781 | if (is_unique) { | 807 | if (tempname) { |
782 | char *resp = xasprintf("FILE: %s", template); | 808 | remote_fd = get_remote_transfer_fd(tempname); |
783 | remote_fd = get_remote_transfer_fd(resp); | 809 | free(tempname); |
784 | free(resp); | ||
785 | free(template); | ||
786 | } else | 810 | } else |
787 | remote_fd = get_remote_transfer_fd("Ok to send data"); | 811 | remote_fd = get_remote_transfer_fd("Ok to send data"); |
788 | 812 | ||
@@ -795,7 +819,7 @@ handle_upload_common(int is_append, int is_unique) | |||
795 | if (trans_ret < 0) | 819 | if (trans_ret < 0) |
796 | cmdio_write(FTP_BADSENDFILE, "Failure writing to local file"); | 820 | cmdio_write(FTP_BADSENDFILE, "Failure writing to local file"); |
797 | else | 821 | else |
798 | cmdio_write(FTP_TRANSFEROK, "File receive OK"); | 822 | cmdio_write_ok(FTP_TRANSFEROK); |
799 | 823 | ||
800 | bail: | 824 | bail: |
801 | port_cleanup(); | 825 | port_cleanup(); |
@@ -804,79 +828,53 @@ bail: | |||
804 | } | 828 | } |
805 | 829 | ||
806 | static void | 830 | static void |
807 | handle_stor(void) | ||
808 | { | ||
809 | handle_upload_common(0, 0); | ||
810 | } | ||
811 | |||
812 | static void | ||
813 | handle_mkd(void) | 831 | handle_mkd(void) |
814 | { | 832 | { |
815 | int retval; | 833 | if (!G.ftp_arg || mkdir(G.ftp_arg, 0777) != 0) { |
816 | |||
817 | /* Do we need check if ftp_arg != NULL? */ | ||
818 | retval = mkdir(G.ftp_arg, 0770); | ||
819 | if (retval != 0) { | ||
820 | cmdio_write(FTP_FILEFAIL, "Create directory operation failed"); | 834 | cmdio_write(FTP_FILEFAIL, "Create directory operation failed"); |
821 | return; | 835 | return; |
822 | } | 836 | } |
823 | 837 | cmdio_write_ok(FTP_MKDIROK); | |
824 | cmdio_write(FTP_MKDIROK, "created"); | ||
825 | } | 838 | } |
826 | 839 | ||
827 | static void | 840 | static void |
828 | handle_rmd(void) | 841 | handle_rmd(void) |
829 | { | 842 | { |
830 | int retval; | 843 | if (!G.ftp_arg || rmdir(G.ftp_arg) != 0) { |
831 | 844 | cmdio_write(FTP_FILEFAIL, "Deletion failed"); | |
832 | /* Do we need check if ftp_arg != NULL? */ | 845 | return; |
833 | retval = rmdir(G.ftp_arg); | 846 | } |
834 | if (retval != 0) | 847 | cmdio_write_ok(FTP_RMDIROK); |
835 | cmdio_write(FTP_FILEFAIL, "rmdir failed"); | ||
836 | else | ||
837 | cmdio_write(FTP_RMDIROK, "rmdir successful"); | ||
838 | } | 848 | } |
839 | 849 | ||
840 | static void | 850 | static void |
841 | handle_dele(void) | 851 | handle_dele(void) |
842 | { | 852 | { |
843 | int retval; | 853 | if (!G.ftp_arg || unlink(G.ftp_arg) != 0) { |
844 | 854 | cmdio_write(FTP_FILEFAIL, "Deletion failed"); | |
845 | /* Do we need check if ftp_arg != NULL? */ | 855 | return; |
846 | retval = unlink(G.ftp_arg); | 856 | } |
847 | if (retval != 0) | 857 | cmdio_write_ok(FTP_DELEOK); |
848 | cmdio_write(FTP_FILEFAIL, "Delete failed"); | ||
849 | else | ||
850 | cmdio_write(FTP_DELEOK, "Delete successful"); | ||
851 | } | ||
852 | #endif /* ENABLE_FEATURE_FTP_WRITE */ | ||
853 | |||
854 | static void | ||
855 | handle_rest(void) | ||
856 | { | ||
857 | /* When ftp_arg == NULL simply restart from beginning */ | ||
858 | G.restart_pos = xatoi_u(G.ftp_arg); | ||
859 | cmdio_write(FTP_RESTOK, "Restart OK"); | ||
860 | } | 858 | } |
861 | 859 | ||
862 | #if ENABLE_FEATURE_FTP_WRITE | ||
863 | static void | 860 | static void |
864 | handle_rnfr(void) | 861 | handle_rnfr(void) |
865 | { | 862 | { |
866 | struct stat statbuf; | 863 | struct stat statbuf; |
867 | int retval; | ||
868 | 864 | ||
869 | /* Clear old value */ | 865 | /* Clear old value */ |
870 | free(G.rnfr_filename); | 866 | free(G.rnfr_filename); |
867 | G.rnfr_filename = NULL; | ||
871 | 868 | ||
872 | /* Does it exist? Do we need check if ftp_arg != NULL? */ | 869 | if (!G.ftp_arg |
873 | retval = stat(G.ftp_arg, &statbuf); | 870 | || stat(G.ftp_arg, &statbuf) != 0 |
874 | if (retval == 0) { | 871 | /* || it isn't a regular file or a directory? */ |
875 | /* Yes */ | 872 | ) { |
876 | G.rnfr_filename = xstrdup(G.ftp_arg); | ||
877 | cmdio_write(FTP_RNFROK, "Ready for RNTO"); | ||
878 | } else | ||
879 | cmdio_write(FTP_FILEFAIL, "RNFR command failed"); | 873 | cmdio_write(FTP_FILEFAIL, "RNFR command failed"); |
874 | return; | ||
875 | } | ||
876 | G.rnfr_filename = xstrdup(G.ftp_arg); | ||
877 | cmdio_write_ok(FTP_RNFROK); | ||
880 | } | 878 | } |
881 | 879 | ||
882 | static void | 880 | static void |
@@ -885,72 +883,40 @@ handle_rnto(void) | |||
885 | int retval; | 883 | int retval; |
886 | 884 | ||
887 | /* If we didn't get a RNFR, throw a wobbly */ | 885 | /* If we didn't get a RNFR, throw a wobbly */ |
888 | if (G.rnfr_filename == NULL) { | 886 | if (G.rnfr_filename == NULL || G.ftp_arg == NULL) { |
889 | cmdio_write(FTP_NEEDRNFR, "RNFR required first"); | 887 | cmdio_write(FTP_NEEDRNFR, "RNFR required first"); |
890 | return; | 888 | return; |
891 | } | 889 | } |
892 | 890 | ||
893 | /* XXX Do we need check if ftp_arg != NULL? */ | ||
894 | retval = rename(G.rnfr_filename, G.ftp_arg); | 891 | retval = rename(G.rnfr_filename, G.ftp_arg); |
895 | |||
896 | free(G.rnfr_filename); | 892 | free(G.rnfr_filename); |
893 | G.rnfr_filename = NULL; | ||
897 | 894 | ||
898 | if (retval == 0) | 895 | if (retval) { |
899 | cmdio_write(FTP_RENAMEOK, "Rename successful"); | ||
900 | else | ||
901 | cmdio_write(FTP_FILEFAIL, "Rename failed"); | 896 | cmdio_write(FTP_FILEFAIL, "Rename failed"); |
897 | return; | ||
898 | } | ||
899 | cmdio_write_ok(FTP_RENAMEOK); | ||
902 | } | 900 | } |
903 | #endif /* ENABLE_FEATURE_FTP_WRITE */ | ||
904 | 901 | ||
905 | static void | 902 | static void |
906 | handle_nlst(void) | 903 | handle_stor(void) |
907 | { | 904 | { |
908 | handle_dir_common(0, 0); | 905 | handle_upload_common(0, 0); |
909 | } | 906 | } |
910 | 907 | ||
911 | #if ENABLE_FEATURE_FTP_WRITE | ||
912 | static void | 908 | static void |
913 | handle_appe(void) | 909 | handle_appe(void) |
914 | { | 910 | { |
915 | handle_upload_common(1, 0); | 911 | handle_upload_common(1, 0); |
916 | } | 912 | } |
917 | #endif | ||
918 | 913 | ||
919 | static void | 914 | static void |
920 | handle_help(void) | ||
921 | { | ||
922 | cmdio_write_hyphen(FTP_HELP, "Recognized commands:"); | ||
923 | cmdio_write_raw(" ALLO CDUP CWD HELP LIST\r\n" | ||
924 | " MODE NLST NOOP PASS PASV PORT PWD QUIT\r\n" | ||
925 | " REST RETR STAT STRU SYST TYPE USER\r\n" | ||
926 | #if ENABLE_FEATURE_FTP_WRITE | ||
927 | " APPE DELE MKD RMD RNFR RNTO STOR STOU\r\n" | ||
928 | #endif | ||
929 | ); | ||
930 | cmdio_write(FTP_HELP, "Help OK"); | ||
931 | } | ||
932 | |||
933 | #if ENABLE_FEATURE_FTP_WRITE | ||
934 | static void | ||
935 | handle_stou(void) | 915 | handle_stou(void) |
936 | { | 916 | { |
937 | handle_upload_common(0, 1); | 917 | handle_upload_common(0, 1); |
938 | } | 918 | } |
939 | #endif | 919 | #endif /* ENABLE_FEATURE_FTP_WRITE */ |
940 | |||
941 | static void | ||
942 | handle_stat(void) | ||
943 | { | ||
944 | cmdio_write_hyphen(FTP_STATOK, "FTP server status:"); | ||
945 | cmdio_write_raw(" TYPE: BINARY\r\n"); | ||
946 | cmdio_write(FTP_STATOK, "End of status"); | ||
947 | } | ||
948 | |||
949 | static void | ||
950 | handle_stat_file(void) | ||
951 | { | ||
952 | handle_dir_common(1, 1); | ||
953 | } | ||
954 | 920 | ||
955 | /* TODO: libbb candidate (tftp has another copy) */ | 921 | /* TODO: libbb candidate (tftp has another copy) */ |
956 | static len_and_sockaddr *get_sock_lsa(int s) | 922 | static len_and_sockaddr *get_sock_lsa(int s) |
@@ -969,8 +935,6 @@ static len_and_sockaddr *get_sock_lsa(int s) | |||
969 | int ftpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 935 | int ftpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
970 | int ftpd_main(int argc UNUSED_PARAM, char **argv) | 936 | int ftpd_main(int argc UNUSED_PARAM, char **argv) |
971 | { | 937 | { |
972 | smallint user_was_specified = 0; | ||
973 | |||
974 | INIT_G(); | 938 | INIT_G(); |
975 | 939 | ||
976 | G.local_addr = get_sock_lsa(STDIN_FILENO); | 940 | G.local_addr = get_sock_lsa(STDIN_FILENO); |
@@ -984,52 +948,95 @@ int ftpd_main(int argc UNUSED_PARAM, char **argv) | |||
984 | * failure */ | 948 | * failure */ |
985 | } | 949 | } |
986 | 950 | ||
987 | logmode = LOGMODE_SYSLOG; | 951 | G.opts = getopt32(argv, "v" USE_FEATURE_FTP_WRITE("w")); |
952 | |||
953 | openlog(applet_name, LOG_PID, LOG_DAEMON); | ||
954 | logmode |= LOGMODE_SYSLOG; | ||
955 | if (!(G.opts & OPT_v)) | ||
956 | logmode = LOGMODE_SYSLOG; | ||
988 | 957 | ||
989 | USE_FEATURE_FTP_WRITE(G.write_enable =) getopt32(argv, "" USE_FEATURE_FTP_WRITE("w")); | ||
990 | if (argv[optind]) { | 958 | if (argv[optind]) { |
991 | xchdir(argv[optind]); | 959 | xchdir(argv[optind]); |
992 | chroot("."); | 960 | chroot("."); |
993 | } | 961 | } |
994 | 962 | ||
995 | // if (G.local_addr->u.sa.sa_family != AF_INET) | 963 | //umask(077); - admin can set umask before starting us |
996 | // bb_error_msg_and_die("Only IPv4 is supported"); | ||
997 | 964 | ||
998 | /* Signals. We'll always take -EPIPE rather than a rude signal, thanks */ | 965 | /* Signals. We'll always take -EPIPE rather than a rude signal, thanks */ |
999 | signal(SIGPIPE, SIG_IGN); | 966 | signal(SIGPIPE, SIG_IGN); |
1000 | 967 | ||
1001 | /* Set up options on the command socket */ | 968 | /* Set up options on the command socket (do we need these all? why?) */ |
1002 | setsockopt(STDIN_FILENO, IPPROTO_TCP, TCP_NODELAY, &const_int_1, sizeof(const_int_1)); | 969 | setsockopt(STDIN_FILENO, IPPROTO_TCP, TCP_NODELAY, &const_int_1, sizeof(const_int_1)); |
1003 | setsockopt(STDIN_FILENO, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1)); | 970 | setsockopt(STDIN_FILENO, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1)); |
1004 | setsockopt(STDIN_FILENO, SOL_SOCKET, SO_OOBINLINE, &const_int_1, sizeof(const_int_1)); | 971 | setsockopt(STDIN_FILENO, SOL_SOCKET, SO_OOBINLINE, &const_int_1, sizeof(const_int_1)); |
1005 | 972 | ||
1006 | cmdio_write(FTP_GREET, "Welcome"); | 973 | cmdio_write(FTP_GREET, "Welcome"); |
1007 | 974 | ||
1008 | while (1) { | 975 | #ifdef IF_WE_WANT_TO_REQUIRE_LOGIN |
1009 | uint32_t cmdval = cmdio_get_cmd_and_arg(); | 976 | { |
1010 | 977 | smallint user_was_specified = 0; | |
1011 | if (cmdval == const_USER) { | 978 | while (1) { |
1012 | if (G.ftp_arg == NULL || strcasecmp(G.ftp_arg, "anonymous") != 0) | 979 | uint32_t cmdval = cmdio_get_cmd_and_arg(); |
1013 | cmdio_write(FTP_LOGINERR, "Server is anonymous only"); | 980 | |
1014 | else { | 981 | if (cmdval == const_USER) { |
1015 | user_was_specified = 1; | 982 | if (G.ftp_arg == NULL || strcasecmp(G.ftp_arg, "anonymous") != 0) |
1016 | cmdio_write(FTP_GIVEPWORD, "Please specify the password"); | 983 | cmdio_write(FTP_LOGINERR, "Server is anonymous only"); |
984 | else { | ||
985 | user_was_specified = 1; | ||
986 | cmdio_write(FTP_GIVEPWORD, "Please specify the password"); | ||
987 | } | ||
988 | } else if (cmdval == const_PASS) { | ||
989 | if (user_was_specified) | ||
990 | break; | ||
991 | cmdio_write(FTP_NEEDUSER, "Login with USER"); | ||
992 | } else if (cmdval == const_QUIT) { | ||
993 | cmdio_write(FTP_GOODBYE, "Goodbye"); | ||
994 | return 0; | ||
995 | } else { | ||
996 | cmdio_write(FTP_LOGINERR, "Login with USER and PASS"); | ||
1017 | } | 997 | } |
1018 | } else if (cmdval == const_PASS) { | ||
1019 | if (user_was_specified) | ||
1020 | break; | ||
1021 | cmdio_write(FTP_NEEDUSER, "Login with USER"); | ||
1022 | } else if (cmdval == const_QUIT) { | ||
1023 | cmdio_write(FTP_GOODBYE, "Goodbye"); | ||
1024 | return 0; | ||
1025 | } else { | ||
1026 | cmdio_write(FTP_LOGINERR, | ||
1027 | "Login with USER and PASS"); | ||
1028 | } | 998 | } |
1029 | } | 999 | } |
1000 | cmdio_write_ok(FTP_LOGINOK); | ||
1001 | #endif | ||
1030 | 1002 | ||
1031 | umask(077); | 1003 | /* RFC-959 Section 5.1 |
1032 | cmdio_write(FTP_LOGINOK, "Login successful"); | 1004 | * The following commands and options MUST be supported by every |
1005 | * server-FTP and user-FTP, except in cases where the underlying | ||
1006 | * file system or operating system does not allow or support | ||
1007 | * a particular command. | ||
1008 | * Type: ASCII Non-print, IMAGE, LOCAL 8 | ||
1009 | * Mode: Stream | ||
1010 | * Structure: File, Record* | ||
1011 | * (Record structure is REQUIRED only for hosts whose file | ||
1012 | * systems support record structure). | ||
1013 | * Commands: | ||
1014 | * USER, PASS, ACCT, [bbox: ACCT not supported] | ||
1015 | * PORT, PASV, | ||
1016 | * TYPE, MODE, STRU, | ||
1017 | * RETR, STOR, APPE, | ||
1018 | * RNFR, RNTO, DELE, | ||
1019 | * CWD, CDUP, RMD, MKD, PWD, | ||
1020 | * LIST, NLST, | ||
1021 | * SYST, STAT, | ||
1022 | * HELP, NOOP, QUIT. | ||
1023 | */ | ||
1024 | /* ACCOUNT (ACCT) | ||
1025 | * The argument field is a Telnet string identifying the user's account. | ||
1026 | * The command is not necessarily related to the USER command, as some | ||
1027 | * sites may require an account for login and others only for specific | ||
1028 | * access, such as storing files. In the latter case the command may | ||
1029 | * arrive at any time. | ||
1030 | * There are reply codes to differentiate these cases for the automation: | ||
1031 | * when account information is required for login, the response to | ||
1032 | * a successful PASSword command is reply code 332. On the other hand, | ||
1033 | * if account information is NOT required for login, the reply to | ||
1034 | * a successful PASSword command is 230; and if the account information | ||
1035 | * is needed for a command issued later in the dialogue, the server | ||
1036 | * should return a 332 or 532 reply depending on whether it stores | ||
1037 | * (pending receipt of the ACCounT command) or discards the command, | ||
1038 | * respectively. | ||
1039 | */ | ||
1033 | 1040 | ||
1034 | while (1) { | 1041 | while (1) { |
1035 | uint32_t cmdval = cmdio_get_cmd_and_arg(); | 1042 | uint32_t cmdval = cmdio_get_cmd_and_arg(); |
@@ -1042,19 +1049,19 @@ int ftpd_main(int argc UNUSED_PARAM, char **argv) | |||
1042 | handle_pwd(); | 1049 | handle_pwd(); |
1043 | else if (cmdval == const_CWD) | 1050 | else if (cmdval == const_CWD) |
1044 | handle_cwd(); | 1051 | handle_cwd(); |
1045 | else if (cmdval == const_CDUP) | 1052 | else if (cmdval == const_CDUP) /* cd .. */ |
1046 | handle_cdup(); | 1053 | handle_cdup(); |
1047 | else if (cmdval == const_PASV) | 1054 | else if (cmdval == const_PASV) |
1048 | handle_pasv(); | 1055 | handle_pasv(); |
1049 | else if (cmdval == const_RETR) | 1056 | else if (cmdval == const_RETR) |
1050 | handle_retr(); | 1057 | handle_retr(); |
1051 | else if (cmdval == const_NOOP) | 1058 | else if (cmdval == const_NOOP) |
1052 | cmdio_write(FTP_NOOPOK, "NOOP ok"); | 1059 | cmdio_write_ok(FTP_NOOPOK); |
1053 | else if (cmdval == const_SYST) | 1060 | else if (cmdval == const_SYST) |
1054 | cmdio_write(FTP_SYSTOK, "UNIX Type: L8"); | 1061 | cmdio_write(FTP_SYSTOK, "UNIX Type: L8"); |
1055 | else if (cmdval == const_HELP) | 1062 | else if (cmdval == const_HELP) |
1056 | handle_help(); | 1063 | handle_help(); |
1057 | else if (cmdval == const_LIST) | 1064 | else if (cmdval == const_LIST) /* ls -l */ |
1058 | handle_list(); | 1065 | handle_list(); |
1059 | else if (cmdval == const_TYPE) | 1066 | else if (cmdval == const_TYPE) |
1060 | handle_type(); | 1067 | handle_type(); |
@@ -1062,10 +1069,40 @@ int ftpd_main(int argc UNUSED_PARAM, char **argv) | |||
1062 | handle_port(); | 1069 | handle_port(); |
1063 | else if (cmdval == const_REST) | 1070 | else if (cmdval == const_REST) |
1064 | handle_rest(); | 1071 | handle_rest(); |
1065 | else if (cmdval == const_NLST) | 1072 | else if (cmdval == const_NLST) /* "name list", bare ls */ |
1066 | handle_nlst(); | 1073 | handle_nlst(); |
1074 | else if (cmdval == const_STRU) { | ||
1075 | //if (G.ftp_arg | ||
1076 | // && (G.ftp_arg[0] | 0x20) == 'f' | ||
1077 | // && G.ftp_arg[1] == '\0' | ||
1078 | //) { | ||
1079 | cmdio_write(FTP_STRUOK, "Command ignored"); | ||
1080 | //} else | ||
1081 | // cmdio_write(FTP_BADSTRU, "Bad STRU command"); | ||
1082 | } else if (cmdval == const_MODE) { | ||
1083 | //if (G.ftp_arg | ||
1084 | // && (G.ftp_arg[0] | 0x20) == 's' | ||
1085 | // && G.ftp_arg[1] == '\0' | ||
1086 | //) { | ||
1087 | cmdio_write(FTP_MODEOK, "Command ignored"); | ||
1088 | //} else | ||
1089 | // cmdio_write(FTP_BADMODE, "Bad MODE command"); | ||
1090 | } | ||
1091 | else if (cmdval == const_ALLO) | ||
1092 | cmdio_write(FTP_ALLOOK, "Command ignored"); | ||
1093 | else if (cmdval == const_STAT) { | ||
1094 | if (G.ftp_arg == NULL) | ||
1095 | handle_stat(); | ||
1096 | else | ||
1097 | handle_stat_file(); | ||
1098 | } else if (cmdval == const_USER) { | ||
1099 | /* FTP_LOGINERR confuses clients: */ | ||
1100 | /* cmdio_write(FTP_LOGINERR, "Can't change to another user"); */ | ||
1101 | cmdio_write(FTP_GIVEPWORD, "Command ignored"); | ||
1102 | } else if (cmdval == const_PASS) | ||
1103 | cmdio_write(FTP_LOGINOK, "Command ignored"); | ||
1067 | #if ENABLE_FEATURE_FTP_WRITE | 1104 | #if ENABLE_FEATURE_FTP_WRITE |
1068 | else if (G.write_enable) { | 1105 | else if (G.opts & OPT_w) { |
1069 | if (cmdval == const_STOR) | 1106 | if (cmdval == const_STOR) |
1070 | handle_stor(); | 1107 | handle_stor(); |
1071 | else if (cmdval == const_MKD) | 1108 | else if (cmdval == const_MKD) |
@@ -1074,45 +1111,17 @@ int ftpd_main(int argc UNUSED_PARAM, char **argv) | |||
1074 | handle_rmd(); | 1111 | handle_rmd(); |
1075 | else if (cmdval == const_DELE) | 1112 | else if (cmdval == const_DELE) |
1076 | handle_dele(); | 1113 | handle_dele(); |
1077 | else if (cmdval == const_RNFR) | 1114 | else if (cmdval == const_RNFR) /* "rename from" */ |
1078 | handle_rnfr(); | 1115 | handle_rnfr(); |
1079 | else if (cmdval == const_RNTO) | 1116 | else if (cmdval == const_RNTO) /* "rename to" */ |
1080 | handle_rnto(); | 1117 | handle_rnto(); |
1081 | else if (cmdval == const_APPE) | 1118 | else if (cmdval == const_APPE) |
1082 | handle_appe(); | 1119 | handle_appe(); |
1083 | else if (cmdval == const_STOU) | 1120 | else if (cmdval == const_STOU) /* "store unique" */ |
1084 | handle_stou(); | 1121 | handle_stou(); |
1085 | } | 1122 | } |
1086 | #endif | 1123 | #endif |
1087 | else if (cmdval == const_STRU) { | 1124 | #if 0 |
1088 | if (G.ftp_arg | ||
1089 | && (G.ftp_arg[0] | 0x20) == 'f' | ||
1090 | && G.ftp_arg[1] == '\0' | ||
1091 | ) { | ||
1092 | cmdio_write(FTP_STRUOK, "Structure set to F"); | ||
1093 | } else | ||
1094 | cmdio_write(FTP_BADSTRU, "Bad STRU command"); | ||
1095 | |||
1096 | } else if (cmdval == const_MODE) { | ||
1097 | if (G.ftp_arg | ||
1098 | && (G.ftp_arg[0] | 0x20) == 's' | ||
1099 | && G.ftp_arg[1] == '\0' | ||
1100 | ) { | ||
1101 | cmdio_write(FTP_MODEOK, "Mode set to S"); | ||
1102 | } else | ||
1103 | cmdio_write(FTP_BADMODE, "Bad MODE command"); | ||
1104 | } | ||
1105 | else if (cmdval == const_ALLO) | ||
1106 | cmdio_write(FTP_ALLOOK, "ALLO command ignored"); | ||
1107 | else if (cmdval == const_STAT) { | ||
1108 | if (G.ftp_arg == NULL) | ||
1109 | handle_stat(); | ||
1110 | else | ||
1111 | handle_stat_file(); | ||
1112 | } else if (cmdval == const_USER) | ||
1113 | cmdio_write(FTP_LOGINERR, "Can't change to another user"); | ||
1114 | else if (cmdval == const_PASS) | ||
1115 | cmdio_write(FTP_LOGINOK, "Already logged in"); | ||
1116 | else if (cmdval == const_STOR | 1125 | else if (cmdval == const_STOR |
1117 | || cmdval == const_MKD | 1126 | || cmdval == const_MKD |
1118 | || cmdval == const_RMD | 1127 | || cmdval == const_RMD |
@@ -1123,7 +1132,14 @@ int ftpd_main(int argc UNUSED_PARAM, char **argv) | |||
1123 | || cmdval == const_STOU | 1132 | || cmdval == const_STOU |
1124 | ) { | 1133 | ) { |
1125 | cmdio_write(FTP_NOPERM, "Permission denied"); | 1134 | cmdio_write(FTP_NOPERM, "Permission denied"); |
1126 | } else { | 1135 | } |
1136 | #endif | ||
1137 | else { | ||
1138 | /* Which unsupported commands were seen in the wild | ||
1139 | * (doesn't necessarily mean "we must support them") | ||
1140 | * wget 1.11.4: SIZE - todo. | ||
1141 | * lftp 3.6.3: MDTM - works fine without it anyway. | ||
1142 | */ | ||
1127 | cmdio_write(FTP_BADCMD, "Unknown command"); | 1143 | cmdio_write(FTP_BADCMD, "Unknown command"); |
1128 | } | 1144 | } |
1129 | } | 1145 | } |
diff --git a/networking/isrv_identd.c b/networking/isrv_identd.c index e08ebd4b3..e8ba00766 100644 --- a/networking/isrv_identd.c +++ b/networking/isrv_identd.c | |||
@@ -122,7 +122,7 @@ int fakeidentd_main(int argc UNUSED_PARAM, char **argv) | |||
122 | * log to stderr. I like daemontools more. Go their way. | 122 | * log to stderr. I like daemontools more. Go their way. |
123 | * (Or maybe we need yet another option "log to syslog") */ | 123 | * (Or maybe we need yet another option "log to syslog") */ |
124 | if (!(opt & OPT_fiw) /* || (opt & OPT_syslog) */) { | 124 | if (!(opt & OPT_fiw) /* || (opt & OPT_syslog) */) { |
125 | openlog(applet_name, 0, LOG_DAEMON); | 125 | openlog(applet_name, LOG_PID, LOG_DAEMON); |
126 | logmode = LOGMODE_SYSLOG; | 126 | logmode = LOGMODE_SYSLOG; |
127 | } | 127 | } |
128 | 128 | ||
diff --git a/networking/telnetd.c b/networking/telnetd.c index 59d609bc8..ccf328925 100644 --- a/networking/telnetd.c +++ b/networking/telnetd.c | |||
@@ -452,7 +452,7 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv) | |||
452 | } | 452 | } |
453 | /* Redirect log to syslog early, if needed */ | 453 | /* Redirect log to syslog early, if needed */ |
454 | if (IS_INETD || !(opt & OPT_FOREGROUND)) { | 454 | if (IS_INETD || !(opt & OPT_FOREGROUND)) { |
455 | openlog(applet_name, 0, LOG_USER); | 455 | openlog(applet_name, LOG_PID, LOG_DAEMON); |
456 | logmode = LOGMODE_SYSLOG; | 456 | logmode = LOGMODE_SYSLOG; |
457 | } | 457 | } |
458 | USE_FEATURE_TELNETD_STANDALONE( | 458 | USE_FEATURE_TELNETD_STANDALONE( |
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index da58a5a8e..903f3d326 100644 --- a/networking/udhcp/dhcpc.c +++ b/networking/udhcp/dhcpc.c | |||
@@ -284,7 +284,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
284 | } | 284 | } |
285 | #endif | 285 | #endif |
286 | if (opt & OPT_S) { | 286 | if (opt & OPT_S) { |
287 | openlog(applet_name, LOG_PID, LOG_LOCAL0); | 287 | openlog(applet_name, LOG_PID, LOG_DAEMON); |
288 | logmode |= LOGMODE_SYSLOG; | 288 | logmode |= LOGMODE_SYSLOG; |
289 | } | 289 | } |
290 | 290 | ||
diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c index ebf30178a..15b31eb3d 100644 --- a/networking/udhcp/dhcpd.c +++ b/networking/udhcp/dhcpd.c | |||
@@ -53,7 +53,7 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) | |||
53 | } | 53 | } |
54 | 54 | ||
55 | if (opt & 2) { /* -S */ | 55 | if (opt & 2) { /* -S */ |
56 | openlog(applet_name, LOG_PID, LOG_LOCAL0); | 56 | openlog(applet_name, LOG_PID, LOG_DAEMON); |
57 | logmode |= LOGMODE_SYSLOG; | 57 | logmode |= LOGMODE_SYSLOG; |
58 | } | 58 | } |
59 | #if ENABLE_FEATURE_UDHCP_PORT | 59 | #if ENABLE_FEATURE_UDHCP_PORT |