aboutsummaryrefslogtreecommitdiff
path: root/networking
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2009-03-08 23:46:48 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2009-03-08 23:46:48 +0000
commit5e4fda0affaa0a80a5ff33dd72c702b8f905be33 (patch)
tree9e31fd173276aa6c8e03ba70511c72fe8550e68a /networking
parentbf9d17949ee8b5ba8bbfdcd9a78b9a12fb122b63 (diff)
downloadbusybox-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.in4
-rw-r--r--networking/ftpd.c760
-rw-r--r--networking/isrv_identd.c2
-rw-r--r--networking/telnetd.c2
-rw-r--r--networking/udhcp/dhcpc.c2
-rw-r--r--networking/udhcp/dhcpd.c2
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
102config FEATURE_FTP_WRITE 102config 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
109config FTPGET 109config 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
17enum { 18enum {
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?
112static void
113xwrite_str(int fd, const char *str)
114{
115 xwrite(fd, str, strlen(str));
116}
117
113static char * 118static char *
114replace_text(const char *str, const char from, const char *to) 119replace_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)
155static void 159static void
156replace_char(char *str, char from, char to) 160replace_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
167static void
168str_netfd_write(const char *str, int fd)
169{
170 xwrite(fd, str, strlen(str));
171} 164}
172 165
173static void 166static 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
198static void 191static void
192cmdio_write_ok(int status)
193{
194 ftp_write_str_common(status, "Operation successful", ' ');
195}
196
197static void
199cmdio_write_hyphen(int status, const char *p_text) 198cmdio_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)
204static void 203static void
205cmdio_write_raw(const char *p_text) 204cmdio_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
210static uint32_t 209static uint32_t
211cmdio_get_cmd_and_arg(void) 210cmdio_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)
350static void 347static void
351handle_cwd(void) 348handle_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
363static void 357static void
364handle_cdup(void) 358handle_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
371static int 364static int
@@ -382,9 +375,7 @@ data_transfer_checks_ok(void)
382static void 375static void
383port_cleanup(void) 376port_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
390static void
391handle_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
435static void
436handle_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
466bail:
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
478static void
479handle_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
486static void
487handle_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
539port_pasv_cleanup_out:
540 port_cleanup();
541 pasv_cleanup();
542file_close_out:
543 close(opened_file);
544}
545
399static char * 546static char *
400statbuf_getperms(const struct stat *statbuf) 547statbuf_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
485static void 632static 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
522bail:
523 closedir(dir); 669 closedir(dir);
524} 670}
525 671
526static void 672static void
527handle_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
571static void
572handle_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
625port_pasv_cleanup_out:
626 port_cleanup();
627 pasv_cleanup();
628file_close_out:
629 close(opened_file);
630}
631
632static void
633handle_dir_common(int full_details, int stat_cmd) 673handle_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
673static void 713static void
@@ -677,6 +717,26 @@ handle_list(void)
677} 717}
678 718
679static void 719static void
720handle_nlst(void)
721{
722 handle_dir_common(0, 0);
723}
724
725static void
726handle_stat_file(void)
727{
728 handle_dir_common(1, 1);
729}
730
731static void
732handle_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
739static void
680handle_type(void) 740handle_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
694static void 754static void
695handle_port(void) 755handle_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
725bail:
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
738static void 769static void
739handle_upload_common(int is_append, int is_unique) 770handle_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
800bail: 824bail:
801 port_cleanup(); 825 port_cleanup();
@@ -804,79 +828,53 @@ bail:
804} 828}
805 829
806static void 830static void
807handle_stor(void)
808{
809 handle_upload_common(0, 0);
810}
811
812static void
813handle_mkd(void) 831handle_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
827static void 840static void
828handle_rmd(void) 841handle_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
840static void 850static void
841handle_dele(void) 851handle_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
854static void
855handle_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
863static void 860static void
864handle_rnfr(void) 861handle_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
882static void 880static 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
905static void 902static void
906handle_nlst(void) 903handle_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
912static void 908static void
913handle_appe(void) 909handle_appe(void)
914{ 910{
915 handle_upload_common(1, 0); 911 handle_upload_common(1, 0);
916} 912}
917#endif
918 913
919static void 914static void
920handle_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
934static void
935handle_stou(void) 915handle_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
941static void
942handle_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
949static void
950handle_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) */
956static len_and_sockaddr *get_sock_lsa(int s) 922static len_and_sockaddr *get_sock_lsa(int s)
@@ -969,8 +935,6 @@ static len_and_sockaddr *get_sock_lsa(int s)
969int ftpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 935int ftpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
970int ftpd_main(int argc UNUSED_PARAM, char **argv) 936int 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