Changeset 3621 in MondoRescue for branches/3.3/mindi-busybox/networking/ftpd.c
- Timestamp:
- Dec 20, 2016, 4:07:32 PM (7 years ago)
- Location:
- branches/3.3
- Files:
-
- 1 edited
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
branches/3.3/mindi-busybox/networking/ftpd.c
r3232 r3621 30 30 31 31 #include "libbb.h" 32 #include "common_bufsiz.h" 32 33 #include <syslog.h> 33 34 #include <netinet/tcp.h> … … 124 125 char msg_err[(sizeof("NNN " MSG_ERR) + 3) & 0xfffc]; 125 126 } FIX_ALIASING; 126 #define G (*(struct globals*) &bb_common_bufsiz1)127 #define G (*(struct globals*)bb_common_bufsiz1) 127 128 #define INIT_G() do { \ 129 setup_common_bufsiz(); \ 128 130 /* Moved to main */ \ 129 131 /*strcpy(G.msg_ok + 4, MSG_OK );*/ \ … … 378 380 } 379 381 380 setsockopt (remote_fd, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1));382 setsockopt_keepalive(remote_fd); 381 383 return remote_fd; 382 384 } … … 623 625 624 626 argv[0] = "ftpd"; 625 argv[1] = opt; /* "-l" or "-1" */ 626 #if BB_MMU 627 argv[1] = opt; /* "-lA" or "-1A" */ 627 628 argv[2] = "--"; 628 #else629 /* NOMMU ftpd ls helper chdirs to argv[2],630 * preventing peer from seeing real root. */631 argv[2] = xrealloc_getcwd_or_warn(NULL);632 #endif633 629 argv[3] = G.ftp_arg; 634 630 argv[4] = NULL; … … 651 647 pid = BB_MMU ? xfork() : xvfork(); 652 648 if (pid == 0) { 649 #if !BB_MMU 650 int cur_fd; 651 #endif 653 652 /* child */ 654 #if !BB_MMU655 /* On NOMMU, we want to execute a child - copy of ourself.656 * In chroot we usually can't do it. Thus we chdir657 * out of the chroot back to original root,658 * and (see later below) execute bb_busybox_exec_path659 * relative to current directory */660 if (fchdir(G.root_fd) != 0)661 _exit(127);662 /*close(G.root_fd); - close_on_exec_on() took care of this */663 #endif664 653 /* NB: close _first_, then move fd! */ 665 654 close(outfd.rd); … … 675 664 exit(ls_main(ARRAY_SIZE(argv) - 1, (char**) argv)); 676 665 #else 677 /* + 1: we must use relative path here if in chroot. 678 * For example, execv("/proc/self/exe") will fail, since 679 * it looks for "/proc/self/exe" _relative to chroot!_ */ 680 execv(bb_busybox_exec_path + 1, (char**) argv); 666 cur_fd = xopen(".", O_RDONLY | O_DIRECTORY); 667 /* On NOMMU, we want to execute a child - copy of ourself 668 * in order to unblock parent after vfork. 669 * In chroot we usually can't re-exec. Thus we escape 670 * out of the chroot back to original root. 671 */ 672 if (G.root_fd >= 0) { 673 if (fchdir(G.root_fd) != 0 || chroot(".") != 0) 674 _exit(127); 675 /*close(G.root_fd); - close_on_exec_on() took care of this */ 676 } 677 /* Child expects directory to list on fd #3 */ 678 xmove_fd(cur_fd, 3); 679 execv(bb_busybox_exec_path, (char**) argv); 681 680 _exit(127); 682 681 #endif … … 685 684 /* parent */ 686 685 close(outfd.wr); 687 #if !BB_MMU688 free((char*)argv[2]);689 #endif690 686 return outfd.rd; 691 687 } … … 706 702 return; /* port_or_pasv_was_seen emitted error response */ 707 703 708 /* -n prevents user/groupname display, 709 * which can be problematic in chroot */ 710 ls_fd = popen_ls((opts & LONG_LISTING) ? "-l" : "-1"); 704 ls_fd = popen_ls((opts & LONG_LISTING) ? "-lA" : "-1A"); 711 705 ls_fp = xfdopen_for_read(ls_fd); 706 /* FIXME: filenames with embedded newlines are mishandled */ 712 707 713 708 if (opts & USE_CTRL_CONN) { … … 730 725 if (remote_fd >= 0) { 731 726 while (1) { 732 line = xmalloc_fgetline(ls_fp); 727 unsigned len; 728 729 line = xmalloc_fgets(ls_fp); 733 730 if (!line) 734 731 break; 735 732 /* I've seen clients complaining when they 736 733 * are fed with ls output with bare '\n'. 737 * Pity... that would be much simpler.734 * Replace trailing "\n\0" with "\r\n". 738 735 */ 739 /* TODO: need to s/LF/NUL/g here */ 740 xwrite_str(remote_fd, line); 741 xwrite(remote_fd, "\r\n", 2); 736 len = strlen(line); 737 if (len != 0) /* paranoia check */ 738 line[len - 1] = '\r'; 739 line[len] = '\n'; 740 xwrite(remote_fd, line, len + 1); 742 741 free(line); 743 742 } … … 1086 1085 const_PORT = mk_const4('P', 'O', 'R', 'T'), 1087 1086 const_PWD = mk_const3('P', 'W', 'D'), 1087 /* Same as PWD. Reportedly used by windows ftp client */ 1088 const_XPWD = mk_const4('X', 'P', 'W', 'D'), 1088 1089 const_QUIT = mk_const4('Q', 'U', 'I', 'T'), 1089 1090 const_REST = mk_const4('R', 'E', 'S', 'T'), … … 1104 1105 OPT_l = (1 << 0), 1105 1106 OPT_1 = (1 << 1), 1106 #endif 1107 OPT_v = (1 << ((!BB_MMU) * 2 + 0)), 1108 OPT_S = (1 << ((!BB_MMU) * 2 + 1)), 1109 OPT_w = (1 << ((!BB_MMU) * 2 + 2)) * ENABLE_FEATURE_FTP_WRITE, 1107 OPT_A = (1 << 2), 1108 #endif 1109 OPT_v = (1 << ((!BB_MMU) * 3 + 0)), 1110 OPT_S = (1 << ((!BB_MMU) * 3 + 1)), 1111 OPT_w = (1 << ((!BB_MMU) * 3 + 2)) * ENABLE_FEATURE_FTP_WRITE, 1110 1112 }; 1111 1113 … … 1117 1119 #endif 1118 1120 { 1121 #if ENABLE_FEATURE_FTP_AUTHENTICATION 1122 struct passwd *pw = NULL; 1123 #endif 1119 1124 unsigned abs_timeout; 1120 1125 unsigned verbose_S; … … 1128 1133 opt_complementary = "t+:T+:vv:SS"; 1129 1134 #if BB_MMU 1130 opts = getopt32(argv, "vS" IF_FEATURE_FTP_WRITE("w") "t:T:", &G.timeout, &abs_timeout, &G.verbose, &verbose_S);1135 opts = getopt32(argv, "vS" IF_FEATURE_FTP_WRITE("w") "t:T:", &G.timeout, &abs_timeout, &G.verbose, &verbose_S); 1131 1136 #else 1132 opts = getopt32(argv, "l1 vS" IF_FEATURE_FTP_WRITE("w") "t:T:", &G.timeout, &abs_timeout, &G.verbose, &verbose_S);1137 opts = getopt32(argv, "l1AvS" IF_FEATURE_FTP_WRITE("w") "t:T:", &G.timeout, &abs_timeout, &G.verbose, &verbose_S); 1133 1138 if (opts & (OPT_l|OPT_1)) { 1134 1139 /* Our secret backdoor to ls */ 1135 /* TODO: pass -n? It prevents user/group resolution, which may not work in chroot anyway */1136 /* TODO: pass -A? It shows dot files */1137 1140 /* TODO: pass --group-directories-first? would be nice, but ls doesn't do that yet */ 1138 xchdir(argv[2]);1139 argv[2] = (char*)"--";1141 if (fchdir(3) != 0) 1142 _exit(127); 1140 1143 /* memset(&G, 0, sizeof(G)); - ls_main does it */ 1141 1144 return ls_main(argc, argv); … … 1175 1178 applet_name = xasprintf("%s[%u]", applet_name, (int)getpid()); 1176 1179 1177 #if !BB_MMU1178 G.root_fd = xopen("/", O_RDONLY | O_DIRECTORY);1179 close_on_exec_on(G.root_fd);1180 #endif1181 1182 if (argv[optind]) {1183 xchroot(argv[optind]);1184 }1185 1186 1180 //umask(077); - admin can set umask before starting us 1187 1181 1188 /* Signals. We'll always take -EPIPE rather than a rude signal, thanks */ 1189 signal(SIGPIPE, SIG_IGN); 1182 /* Signals */ 1183 bb_signals(0 1184 /* We'll always take EPIPE rather than a rude signal, thanks */ 1185 + (1 << SIGPIPE) 1186 /* LIST command spawns chilren. Prevent zombies */ 1187 + (1 << SIGCHLD) 1188 , SIG_IGN); 1190 1189 1191 1190 /* Set up options on the command socket (do we need these all? why?) */ 1192 setsockopt (STDIN_FILENO, IPPROTO_TCP, TCP_NODELAY, &const_int_1, sizeof(const_int_1));1193 setsockopt (STDIN_FILENO, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1));1191 setsockopt_1(STDIN_FILENO, IPPROTO_TCP, TCP_NODELAY); 1192 setsockopt_keepalive(STDIN_FILENO); 1194 1193 /* Telnet protocol over command link may send "urgent" data, 1195 1194 * we prefer it to be received in the "normal" data stream: */ 1196 setsockopt (STDIN_FILENO, SOL_SOCKET, SO_OOBINLINE, &const_int_1, sizeof(const_int_1));1195 setsockopt_1(STDIN_FILENO, SOL_SOCKET, SO_OOBINLINE); 1197 1196 1198 1197 WRITE_OK(FTP_GREET); 1199 1198 signal(SIGALRM, timeout_handler); 1200 1199 1201 #ifdef IF_WE_WANT_TO_REQUIRE_LOGIN 1202 { 1203 smallint user_was_specified = 0; 1204 while (1) { 1205 uint32_t cmdval = cmdio_get_cmd_and_arg(); 1206 1200 #if ENABLE_FEATURE_FTP_AUTHENTICATION 1201 while (1) { 1202 uint32_t cmdval = cmdio_get_cmd_and_arg(); 1207 1203 if (cmdval == const_USER) { 1208 if (G.ftp_arg == NULL || strcasecmp(G.ftp_arg, "anonymous") != 0) 1209 cmdio_write_raw(STR(FTP_LOGINERR)" Server is anonymous only\r\n"); 1210 else { 1211 user_was_specified = 1; 1212 cmdio_write_raw(STR(FTP_GIVEPWORD)" Please specify the password\r\n"); 1213 } 1214 } else if (cmdval == const_PASS) { 1215 if (user_was_specified) 1216 break; 1217 cmdio_write_raw(STR(FTP_NEEDUSER)" Login with USER\r\n"); 1218 } else if (cmdval == const_QUIT) { 1219 WRITE_OK(FTP_GOODBYE); 1220 return 0; 1221 } else { 1222 cmdio_write_raw(STR(FTP_LOGINERR)" Login with USER and PASS\r\n"); 1204 pw = getpwnam(G.ftp_arg); 1205 cmdio_write_raw(STR(FTP_GIVEPWORD)" Please specify password\r\n"); 1206 } else if (cmdval == const_PASS) { 1207 if (check_password(pw, G.ftp_arg) > 0) { 1208 break; /* login success */ 1223 1209 } 1210 cmdio_write_raw(STR(FTP_LOGINERR)" Login failed\r\n"); 1211 pw = NULL; 1212 } else if (cmdval == const_QUIT) { 1213 WRITE_OK(FTP_GOODBYE); 1214 return 0; 1215 } else { 1216 cmdio_write_raw(STR(FTP_LOGINERR)" Login with USER and PASS\r\n"); 1224 1217 } 1225 1218 } 1226 1219 WRITE_OK(FTP_LOGINOK); 1220 #endif 1221 1222 /* Do this after auth, else /etc/passwd is not accessible */ 1223 #if !BB_MMU 1224 G.root_fd = -1; 1225 #endif 1226 argv += optind; 1227 if (argv[0]) { 1228 const char *basedir = argv[0]; 1229 #if !BB_MMU 1230 G.root_fd = xopen("/", O_RDONLY | O_DIRECTORY); 1231 close_on_exec_on(G.root_fd); 1232 #endif 1233 if (chroot(basedir) == 0) 1234 basedir = "/"; 1235 #if !BB_MMU 1236 else { 1237 close(G.root_fd); 1238 G.root_fd = -1; 1239 } 1240 #endif 1241 /* 1242 * If chroot failed, assume that we aren't root, 1243 * and at least chdir to the specified DIR 1244 * (older versions were dying with error message). 1245 * If chroot worked, move current dir to new "/": 1246 */ 1247 xchdir(basedir); 1248 } 1249 1250 #if ENABLE_FEATURE_FTP_AUTHENTICATION 1251 change_identity(pw); 1227 1252 #endif 1228 1253 … … 1293 1318 else if (cmdval == const_SYST) 1294 1319 cmdio_write_raw(STR(FTP_SYSTOK)" UNIX Type: L8\r\n"); 1295 else if (cmdval == const_PWD )1320 else if (cmdval == const_PWD || cmdval == const_XPWD) 1296 1321 handle_pwd(); 1297 1322 else if (cmdval == const_CWD)
Note:
See TracChangeset
for help on using the changeset viewer.