PageRenderTime 47ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/release/src/router/vsftpd/postlogin.c

https://gitlab.com/envieidoc/tomato
C | 1696 lines | 1548 code | 40 blank | 108 comment | 335 complexity | 3d9d18f7c915d487b3c0c9ff3615afe5 MD5 | raw file
  1. /*
  2. * Part of Very Secure FTPd
  3. * Licence: GPL v2
  4. * Author: Chris Evans
  5. * postlogin.c
  6. */
  7. #include "postlogin.h"
  8. #include "session.h"
  9. #include "oneprocess.h"
  10. #include "twoprocess.h"
  11. #include "ftpcodes.h"
  12. #include "ftpcmdio.h"
  13. #include "ftpdataio.h"
  14. #include "utility.h"
  15. #include "tunables.h"
  16. #include "defs.h"
  17. #include "str.h"
  18. #include "sysstr.h"
  19. #include "banner.h"
  20. #include "sysutil.h"
  21. #include "logging.h"
  22. #include "sysdeputil.h"
  23. #include "ipaddrparse.h"
  24. #include "access.h"
  25. #include "features.h"
  26. #include "ssl.h"
  27. #include "vsftpver.h"
  28. #include "opts.h"
  29. /* Private local functions */
  30. static void handle_pwd(struct vsf_session* p_sess);
  31. static void handle_cwd(struct vsf_session* p_sess);
  32. static void handle_pasv(struct vsf_session* p_sess, int is_epsv);
  33. static void handle_retr(struct vsf_session* p_sess, int is_http);
  34. static void handle_cdup(struct vsf_session* p_sess);
  35. static void handle_list(struct vsf_session* p_sess);
  36. static void handle_type(struct vsf_session* p_sess);
  37. static void handle_port(struct vsf_session* p_sess);
  38. static void handle_stor(struct vsf_session* p_sess);
  39. static void handle_mkd(struct vsf_session* p_sess);
  40. static void handle_rmd(struct vsf_session* p_sess);
  41. static void handle_dele(struct vsf_session* p_sess);
  42. static void handle_rest(struct vsf_session* p_sess);
  43. static void handle_rnfr(struct vsf_session* p_sess);
  44. static void handle_rnto(struct vsf_session* p_sess);
  45. static void handle_nlst(struct vsf_session* p_sess);
  46. static void handle_size(struct vsf_session* p_sess);
  47. static void handle_site(struct vsf_session* p_sess);
  48. static void handle_appe(struct vsf_session* p_sess);
  49. static void handle_mdtm(struct vsf_session* p_sess);
  50. static void handle_site_chmod(struct vsf_session* p_sess,
  51. struct mystr* p_arg_str);
  52. static void handle_site_umask(struct vsf_session* p_sess,
  53. struct mystr* p_arg_str);
  54. static void handle_eprt(struct vsf_session* p_sess);
  55. static void handle_help(struct vsf_session* p_sess);
  56. static void handle_stou(struct vsf_session* p_sess);
  57. static void handle_stat(struct vsf_session* p_sess);
  58. static void handle_stat_file(struct vsf_session* p_sess);
  59. static void handle_logged_in_user(struct vsf_session* p_sess);
  60. static void handle_logged_in_pass(struct vsf_session* p_sess);
  61. static void handle_http(struct vsf_session* p_sess);
  62. static int pasv_active(struct vsf_session* p_sess);
  63. static int port_active(struct vsf_session* p_sess);
  64. static void pasv_cleanup(struct vsf_session* p_sess);
  65. static void port_cleanup(struct vsf_session* p_sess);
  66. static void handle_dir_common(struct vsf_session* p_sess, int full_details,
  67. int stat_cmd);
  68. static void prepend_path_to_filename(struct mystr* p_str);
  69. static int get_remote_transfer_fd(struct vsf_session* p_sess,
  70. const char* p_status_msg);
  71. static void check_abor(struct vsf_session* p_sess);
  72. static void handle_sigurg(void* p_private);
  73. static void handle_upload_common(struct vsf_session* p_sess, int is_append,
  74. int is_unique);
  75. static void get_unique_filename(struct mystr* p_outstr,
  76. const struct mystr* p_base);
  77. static int data_transfer_checks_ok(struct vsf_session* p_sess);
  78. static void resolve_tilde(struct mystr* p_str, struct vsf_session* p_sess);
  79. void
  80. process_post_login(struct vsf_session* p_sess)
  81. {
  82. str_getcwd(&p_sess->home_str);
  83. if (p_sess->is_anonymous)
  84. {
  85. vsf_sysutil_set_umask(tunable_anon_umask);
  86. p_sess->bw_rate_max = tunable_anon_max_rate;
  87. }
  88. else
  89. {
  90. vsf_sysutil_set_umask(tunable_local_umask);
  91. p_sess->bw_rate_max = tunable_local_max_rate;
  92. }
  93. if (p_sess->is_http)
  94. {
  95. handle_http(p_sess);
  96. bug("should not be reached");
  97. }
  98. /* Don't support async ABOR if we have an SSL channel. The spec says SHOULD
  99. * NOT, and I think there are synchronization issues between command and
  100. * data reads.
  101. */
  102. if (tunable_async_abor_enable && !p_sess->control_use_ssl)
  103. {
  104. vsf_sysutil_install_sighandler(kVSFSysUtilSigURG, handle_sigurg, p_sess, 0);
  105. vsf_sysutil_activate_sigurg(VSFTP_COMMAND_FD);
  106. }
  107. /* Handle any login message */
  108. vsf_banner_dir_changed(p_sess, FTP_LOGINOK);
  109. vsf_cmdio_write(p_sess, FTP_LOGINOK, "Login successful.");
  110. while(1)
  111. {
  112. int cmd_ok = 1;
  113. if (tunable_setproctitle_enable)
  114. {
  115. vsf_sysutil_setproctitle("IDLE");
  116. }
  117. /* Blocks */
  118. vsf_cmdio_get_cmd_and_arg(p_sess, &p_sess->ftp_cmd_str,
  119. &p_sess->ftp_arg_str, 1);
  120. if (tunable_setproctitle_enable)
  121. {
  122. struct mystr proctitle_str = INIT_MYSTR;
  123. str_copy(&proctitle_str, &p_sess->ftp_cmd_str);
  124. if (!str_isempty(&p_sess->ftp_arg_str))
  125. {
  126. str_append_char(&proctitle_str, ' ');
  127. str_append_str(&proctitle_str, &p_sess->ftp_arg_str);
  128. }
  129. /* Suggestion from Solar */
  130. str_replace_unprintable(&proctitle_str, '?');
  131. vsf_sysutil_setproctitle_str(&proctitle_str);
  132. str_free(&proctitle_str);
  133. }
  134. /* Test command against the allowed lists.. */
  135. if (tunable_cmds_allowed)
  136. {
  137. static struct mystr s_src_str;
  138. static struct mystr s_rhs_str;
  139. str_alloc_text(&s_src_str, tunable_cmds_allowed);
  140. while (1)
  141. {
  142. str_split_char(&s_src_str, &s_rhs_str, ',');
  143. if (str_isempty(&s_src_str))
  144. {
  145. cmd_ok = 0;
  146. break;
  147. }
  148. else if (str_equal(&s_src_str, &p_sess->ftp_cmd_str))
  149. {
  150. break;
  151. }
  152. str_copy(&s_src_str, &s_rhs_str);
  153. }
  154. }
  155. if (tunable_cmds_denied)
  156. {
  157. static struct mystr s_src_str;
  158. static struct mystr s_rhs_str;
  159. str_alloc_text(&s_src_str, tunable_cmds_denied);
  160. while (1)
  161. {
  162. str_split_char(&s_src_str, &s_rhs_str, ',');
  163. if (str_isempty(&s_src_str))
  164. {
  165. break;
  166. }
  167. else if (str_equal(&s_src_str, &p_sess->ftp_cmd_str))
  168. {
  169. cmd_ok = 0;
  170. break;
  171. }
  172. str_copy(&s_src_str, &s_rhs_str);
  173. }
  174. }
  175. if (!cmd_ok)
  176. {
  177. vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
  178. }
  179. else if (str_equal_text(&p_sess->ftp_cmd_str, "QUIT"))
  180. {
  181. vsf_cmdio_write_exit(p_sess, FTP_GOODBYE, "Goodbye.", 0);
  182. }
  183. else if (str_equal_text(&p_sess->ftp_cmd_str, "PWD") ||
  184. str_equal_text(&p_sess->ftp_cmd_str, "XPWD"))
  185. {
  186. handle_pwd(p_sess);
  187. }
  188. else if (str_equal_text(&p_sess->ftp_cmd_str, "CWD") ||
  189. str_equal_text(&p_sess->ftp_cmd_str, "XCWD"))
  190. {
  191. handle_cwd(p_sess);
  192. }
  193. else if (str_equal_text(&p_sess->ftp_cmd_str, "CDUP") ||
  194. str_equal_text(&p_sess->ftp_cmd_str, "XCUP"))
  195. {
  196. handle_cdup(p_sess);
  197. }
  198. else if (tunable_pasv_enable &&
  199. !p_sess->epsv_all &&
  200. (str_equal_text(&p_sess->ftp_cmd_str, "PASV") ||
  201. str_equal_text(&p_sess->ftp_cmd_str, "P@SW")))
  202. {
  203. handle_pasv(p_sess, 0);
  204. }
  205. else if (tunable_pasv_enable &&
  206. str_equal_text(&p_sess->ftp_cmd_str, "EPSV"))
  207. {
  208. handle_pasv(p_sess, 1);
  209. }
  210. else if (tunable_download_enable &&
  211. str_equal_text(&p_sess->ftp_cmd_str, "RETR"))
  212. {
  213. handle_retr(p_sess, 0);
  214. }
  215. else if (str_equal_text(&p_sess->ftp_cmd_str, "NOOP"))
  216. {
  217. vsf_cmdio_write(p_sess, FTP_NOOPOK, "NOOP ok.");
  218. }
  219. else if (str_equal_text(&p_sess->ftp_cmd_str, "SYST"))
  220. {
  221. vsf_cmdio_write(p_sess, FTP_SYSTOK, "UNIX Type: L8");
  222. }
  223. else if (str_equal_text(&p_sess->ftp_cmd_str, "HELP"))
  224. {
  225. handle_help(p_sess);
  226. }
  227. else if (tunable_dirlist_enable &&
  228. str_equal_text(&p_sess->ftp_cmd_str, "LIST"))
  229. {
  230. handle_list(p_sess);
  231. }
  232. else if (str_equal_text(&p_sess->ftp_cmd_str, "TYPE"))
  233. {
  234. handle_type(p_sess);
  235. }
  236. else if (tunable_port_enable &&
  237. !p_sess->epsv_all &&
  238. str_equal_text(&p_sess->ftp_cmd_str, "PORT"))
  239. {
  240. handle_port(p_sess);
  241. }
  242. else if (tunable_write_enable &&
  243. (tunable_anon_upload_enable || !p_sess->is_anonymous) &&
  244. str_equal_text(&p_sess->ftp_cmd_str, "STOR"))
  245. {
  246. handle_stor(p_sess);
  247. }
  248. else if (tunable_write_enable &&
  249. (tunable_anon_mkdir_write_enable || !p_sess->is_anonymous) &&
  250. (str_equal_text(&p_sess->ftp_cmd_str, "MKD") ||
  251. str_equal_text(&p_sess->ftp_cmd_str, "XMKD")))
  252. {
  253. handle_mkd(p_sess);
  254. }
  255. else if (tunable_write_enable &&
  256. (tunable_anon_other_write_enable || !p_sess->is_anonymous) &&
  257. (str_equal_text(&p_sess->ftp_cmd_str, "RMD") ||
  258. str_equal_text(&p_sess->ftp_cmd_str, "XRMD")))
  259. {
  260. handle_rmd(p_sess);
  261. }
  262. else if (tunable_write_enable &&
  263. (tunable_anon_other_write_enable || !p_sess->is_anonymous) &&
  264. str_equal_text(&p_sess->ftp_cmd_str, "DELE"))
  265. {
  266. handle_dele(p_sess);
  267. }
  268. else if (str_equal_text(&p_sess->ftp_cmd_str, "REST"))
  269. {
  270. handle_rest(p_sess);
  271. }
  272. else if (tunable_write_enable &&
  273. (tunable_anon_other_write_enable || !p_sess->is_anonymous) &&
  274. str_equal_text(&p_sess->ftp_cmd_str, "RNFR"))
  275. {
  276. handle_rnfr(p_sess);
  277. }
  278. else if (tunable_write_enable &&
  279. (tunable_anon_other_write_enable || !p_sess->is_anonymous) &&
  280. str_equal_text(&p_sess->ftp_cmd_str, "RNTO"))
  281. {
  282. handle_rnto(p_sess);
  283. }
  284. else if (tunable_dirlist_enable &&
  285. str_equal_text(&p_sess->ftp_cmd_str, "NLST"))
  286. {
  287. handle_nlst(p_sess);
  288. }
  289. else if (str_equal_text(&p_sess->ftp_cmd_str, "SIZE"))
  290. {
  291. handle_size(p_sess);
  292. }
  293. else if (!p_sess->is_anonymous &&
  294. str_equal_text(&p_sess->ftp_cmd_str, "SITE"))
  295. {
  296. handle_site(p_sess);
  297. }
  298. /* Note - the weird ABOR string is checking for an async ABOR arriving
  299. * without a SIGURG condition.
  300. */
  301. else if (str_equal_text(&p_sess->ftp_cmd_str, "ABOR") ||
  302. str_equal_text(&p_sess->ftp_cmd_str, "\377\364\377\362ABOR"))
  303. {
  304. vsf_cmdio_write(p_sess, FTP_ABOR_NOCONN, "No transfer to ABOR.");
  305. }
  306. else if (tunable_write_enable &&
  307. (tunable_anon_other_write_enable || !p_sess->is_anonymous) &&
  308. str_equal_text(&p_sess->ftp_cmd_str, "APPE"))
  309. {
  310. handle_appe(p_sess);
  311. }
  312. else if (str_equal_text(&p_sess->ftp_cmd_str, "MDTM"))
  313. {
  314. handle_mdtm(p_sess);
  315. }
  316. else if (tunable_port_enable &&
  317. str_equal_text(&p_sess->ftp_cmd_str, "EPRT"))
  318. {
  319. handle_eprt(p_sess);
  320. }
  321. else if (str_equal_text(&p_sess->ftp_cmd_str, "STRU"))
  322. {
  323. str_upper(&p_sess->ftp_arg_str);
  324. if (str_equal_text(&p_sess->ftp_arg_str, "F"))
  325. {
  326. vsf_cmdio_write(p_sess, FTP_STRUOK, "Structure set to F.");
  327. }
  328. else
  329. {
  330. vsf_cmdio_write(p_sess, FTP_BADSTRU, "Bad STRU command.");
  331. }
  332. }
  333. else if (str_equal_text(&p_sess->ftp_cmd_str, "MODE"))
  334. {
  335. str_upper(&p_sess->ftp_arg_str);
  336. if (str_equal_text(&p_sess->ftp_arg_str, "S"))
  337. {
  338. vsf_cmdio_write(p_sess, FTP_MODEOK, "Mode set to S.");
  339. }
  340. else
  341. {
  342. vsf_cmdio_write(p_sess, FTP_BADMODE, "Bad MODE command.");
  343. }
  344. }
  345. else if (tunable_write_enable &&
  346. (tunable_anon_upload_enable || !p_sess->is_anonymous) &&
  347. str_equal_text(&p_sess->ftp_cmd_str, "STOU"))
  348. {
  349. handle_stou(p_sess);
  350. }
  351. else if (str_equal_text(&p_sess->ftp_cmd_str, "ALLO"))
  352. {
  353. vsf_cmdio_write(p_sess, FTP_ALLOOK, "ALLO command ignored.");
  354. }
  355. else if (str_equal_text(&p_sess->ftp_cmd_str, "REIN"))
  356. {
  357. vsf_cmdio_write(p_sess, FTP_COMMANDNOTIMPL, "REIN not implemented.");
  358. }
  359. else if (str_equal_text(&p_sess->ftp_cmd_str, "ACCT"))
  360. {
  361. vsf_cmdio_write(p_sess, FTP_COMMANDNOTIMPL, "ACCT not implemented.");
  362. }
  363. else if (str_equal_text(&p_sess->ftp_cmd_str, "SMNT"))
  364. {
  365. vsf_cmdio_write(p_sess, FTP_COMMANDNOTIMPL, "SMNT not implemented.");
  366. }
  367. else if (str_equal_text(&p_sess->ftp_cmd_str, "FEAT"))
  368. {
  369. handle_feat(p_sess);
  370. }
  371. else if (str_equal_text(&p_sess->ftp_cmd_str, "OPTS"))
  372. {
  373. handle_opts(p_sess);
  374. }
  375. else if (str_equal_text(&p_sess->ftp_cmd_str, "STAT") &&
  376. str_isempty(&p_sess->ftp_arg_str))
  377. {
  378. handle_stat(p_sess);
  379. }
  380. else if (tunable_dirlist_enable &&
  381. str_equal_text(&p_sess->ftp_cmd_str, "STAT"))
  382. {
  383. handle_stat_file(p_sess);
  384. }
  385. else if (tunable_ssl_enable && str_equal_text(&p_sess->ftp_cmd_str, "PBSZ"))
  386. {
  387. handle_pbsz(p_sess);
  388. }
  389. else if (tunable_ssl_enable && str_equal_text(&p_sess->ftp_cmd_str, "PROT"))
  390. {
  391. handle_prot(p_sess);
  392. }
  393. else if (str_equal_text(&p_sess->ftp_cmd_str, "USER"))
  394. {
  395. handle_logged_in_user(p_sess);
  396. }
  397. else if (str_equal_text(&p_sess->ftp_cmd_str, "PASS"))
  398. {
  399. handle_logged_in_pass(p_sess);
  400. }
  401. else if (str_equal_text(&p_sess->ftp_cmd_str, "PASV") ||
  402. str_equal_text(&p_sess->ftp_cmd_str, "PORT") ||
  403. str_equal_text(&p_sess->ftp_cmd_str, "STOR") ||
  404. str_equal_text(&p_sess->ftp_cmd_str, "MKD") ||
  405. str_equal_text(&p_sess->ftp_cmd_str, "XMKD") ||
  406. str_equal_text(&p_sess->ftp_cmd_str, "RMD") ||
  407. str_equal_text(&p_sess->ftp_cmd_str, "XRMD") ||
  408. str_equal_text(&p_sess->ftp_cmd_str, "DELE") ||
  409. str_equal_text(&p_sess->ftp_cmd_str, "RNFR") ||
  410. str_equal_text(&p_sess->ftp_cmd_str, "RNTO") ||
  411. str_equal_text(&p_sess->ftp_cmd_str, "SITE") ||
  412. str_equal_text(&p_sess->ftp_cmd_str, "APPE") ||
  413. str_equal_text(&p_sess->ftp_cmd_str, "EPSV") ||
  414. str_equal_text(&p_sess->ftp_cmd_str, "EPRT") ||
  415. str_equal_text(&p_sess->ftp_cmd_str, "RETR") ||
  416. str_equal_text(&p_sess->ftp_cmd_str, "LIST") ||
  417. str_equal_text(&p_sess->ftp_cmd_str, "NLST") ||
  418. str_equal_text(&p_sess->ftp_cmd_str, "STOU") ||
  419. str_equal_text(&p_sess->ftp_cmd_str, "ALLO") ||
  420. str_equal_text(&p_sess->ftp_cmd_str, "REIN") ||
  421. str_equal_text(&p_sess->ftp_cmd_str, "ACCT") ||
  422. str_equal_text(&p_sess->ftp_cmd_str, "SMNT") ||
  423. str_equal_text(&p_sess->ftp_cmd_str, "FEAT") ||
  424. str_equal_text(&p_sess->ftp_cmd_str, "OPTS") ||
  425. str_equal_text(&p_sess->ftp_cmd_str, "STAT") ||
  426. str_equal_text(&p_sess->ftp_cmd_str, "PBSZ") ||
  427. str_equal_text(&p_sess->ftp_cmd_str, "PROT"))
  428. {
  429. vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
  430. }
  431. else if (str_isempty(&p_sess->ftp_cmd_str) &&
  432. str_isempty(&p_sess->ftp_arg_str))
  433. {
  434. /* Deliberately ignore to avoid NAT device bugs. ProFTPd does the same. */
  435. }
  436. else if (str_equal_text(&p_sess->ftp_cmd_str, "GET") ||
  437. str_equal_text(&p_sess->ftp_cmd_str, "POST") ||
  438. str_equal_text(&p_sess->ftp_cmd_str, "HEAD") ||
  439. str_equal_text(&p_sess->ftp_cmd_str, "OPTIONS") ||
  440. str_equal_text(&p_sess->ftp_cmd_str, "CONNECT"))
  441. {
  442. vsf_cmdio_write_exit(p_sess, FTP_BADCMD,
  443. "HTTP protocol commands not allowed.", 1);
  444. }
  445. else
  446. {
  447. vsf_cmdio_write(p_sess, FTP_BADCMD, "Unknown command.");
  448. }
  449. if (vsf_log_entry_pending(p_sess))
  450. {
  451. vsf_log_do_log(p_sess, 0);
  452. }
  453. if (p_sess->data_timeout)
  454. {
  455. vsf_cmdio_write_exit(p_sess, FTP_DATA_TIMEOUT,
  456. "Data timeout. Reconnect. Sorry.", 1);
  457. }
  458. }
  459. }
  460. static void
  461. handle_pwd(struct vsf_session* p_sess)
  462. {
  463. static struct mystr s_cwd_buf_mangle_str;
  464. static struct mystr s_pwd_res_str;
  465. str_getcwd(&s_cwd_buf_mangle_str);
  466. /* Double up any double-quotes in the pathname! */
  467. str_replace_text(&s_cwd_buf_mangle_str, "\"", "\"\"");
  468. /* Enclose pathname in quotes */
  469. str_alloc_text(&s_pwd_res_str, "\"");
  470. str_append_str(&s_pwd_res_str, &s_cwd_buf_mangle_str);
  471. str_append_text(&s_pwd_res_str, "\" is the current directory");
  472. vsf_cmdio_write_str(p_sess, FTP_PWDOK, &s_pwd_res_str);
  473. }
  474. static void
  475. handle_cwd(struct vsf_session* p_sess)
  476. {
  477. int retval;
  478. resolve_tilde(&p_sess->ftp_arg_str, p_sess);
  479. if (!vsf_access_check_file(&p_sess->ftp_arg_str))
  480. {
  481. vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
  482. return;
  483. }
  484. retval = str_chdir(&p_sess->ftp_arg_str);
  485. if (retval == 0)
  486. {
  487. /* Handle any messages */
  488. vsf_banner_dir_changed(p_sess, FTP_CWDOK);
  489. vsf_cmdio_write(p_sess, FTP_CWDOK, "Directory successfully changed.");
  490. }
  491. else
  492. {
  493. vsf_cmdio_write(p_sess, FTP_FILEFAIL, "Failed to change directory.");
  494. }
  495. }
  496. static void
  497. handle_cdup(struct vsf_session* p_sess)
  498. {
  499. str_alloc_text(&p_sess->ftp_arg_str, "..");
  500. handle_cwd(p_sess);
  501. }
  502. static int
  503. port_active(struct vsf_session* p_sess)
  504. {
  505. int ret = 0;
  506. if (p_sess->p_port_sockaddr != 0)
  507. {
  508. ret = 1;
  509. if (pasv_active(p_sess))
  510. {
  511. bug("port and pasv both active");
  512. }
  513. }
  514. return ret;
  515. }
  516. static int
  517. pasv_active(struct vsf_session* p_sess)
  518. {
  519. int ret = 0;
  520. if (tunable_one_process_model)
  521. {
  522. ret = vsf_one_process_pasv_active(p_sess);
  523. }
  524. else
  525. {
  526. ret = vsf_two_process_pasv_active(p_sess);
  527. }
  528. if (ret)
  529. {
  530. if (port_active(p_sess))
  531. {
  532. bug("pasv and port both active");
  533. }
  534. }
  535. return ret;
  536. }
  537. static void
  538. port_cleanup(struct vsf_session* p_sess)
  539. {
  540. vsf_sysutil_sockaddr_clear(&p_sess->p_port_sockaddr);
  541. }
  542. static void
  543. pasv_cleanup(struct vsf_session* p_sess)
  544. {
  545. if (tunable_one_process_model)
  546. {
  547. vsf_one_process_pasv_cleanup(p_sess);
  548. }
  549. else
  550. {
  551. vsf_two_process_pasv_cleanup(p_sess);
  552. }
  553. }
  554. static void
  555. handle_pasv(struct vsf_session* p_sess, int is_epsv)
  556. {
  557. unsigned short the_port;
  558. static struct mystr s_pasv_res_str;
  559. static struct vsf_sysutil_sockaddr* s_p_sockaddr;
  560. int is_ipv6 = vsf_sysutil_sockaddr_is_ipv6(p_sess->p_local_addr);
  561. if (is_epsv && !str_isempty(&p_sess->ftp_arg_str))
  562. {
  563. int argval;
  564. str_upper(&p_sess->ftp_arg_str);
  565. if (str_equal_text(&p_sess->ftp_arg_str, "ALL"))
  566. {
  567. p_sess->epsv_all = 1;
  568. vsf_cmdio_write(p_sess, FTP_EPSVALLOK, "EPSV ALL ok.");
  569. return;
  570. }
  571. argval = vsf_sysutil_atoi(str_getbuf(&p_sess->ftp_arg_str));
  572. if (argval < 1 || argval > 2 || (!is_ipv6 && argval == 2))
  573. {
  574. vsf_cmdio_write(p_sess, FTP_EPSVBAD, "Bad network protocol.");
  575. return;
  576. }
  577. }
  578. pasv_cleanup(p_sess);
  579. port_cleanup(p_sess);
  580. if (tunable_one_process_model)
  581. {
  582. the_port = vsf_one_process_listen(p_sess);
  583. }
  584. else
  585. {
  586. the_port = vsf_two_process_listen(p_sess);
  587. }
  588. if (is_epsv)
  589. {
  590. str_alloc_text(&s_pasv_res_str, "Entering Extended Passive Mode (|||");
  591. str_append_ulong(&s_pasv_res_str, (unsigned long) the_port);
  592. str_append_text(&s_pasv_res_str, "|)");
  593. vsf_cmdio_write_str(p_sess, FTP_EPSVOK, &s_pasv_res_str);
  594. return;
  595. }
  596. if (tunable_pasv_address != 0)
  597. {
  598. vsf_sysutil_sockaddr_alloc_ipv4(&s_p_sockaddr);
  599. /* Report passive address as specified in configuration */
  600. if (vsf_sysutil_inet_aton(tunable_pasv_address, s_p_sockaddr) == 0)
  601. {
  602. die("invalid pasv_address");
  603. }
  604. }
  605. else
  606. {
  607. vsf_sysutil_sockaddr_clone(&s_p_sockaddr, p_sess->p_local_addr);
  608. }
  609. str_alloc_text(&s_pasv_res_str, "Entering Passive Mode (");
  610. if (!is_ipv6)
  611. {
  612. str_append_text(&s_pasv_res_str, vsf_sysutil_inet_ntop(s_p_sockaddr));
  613. }
  614. else
  615. {
  616. const void* p_v4addr = vsf_sysutil_sockaddr_ipv6_v4(s_p_sockaddr);
  617. if (p_v4addr)
  618. {
  619. str_append_text(&s_pasv_res_str, vsf_sysutil_inet_ntoa(p_v4addr));
  620. }
  621. else
  622. {
  623. str_append_text(&s_pasv_res_str, "0,0,0,0");
  624. }
  625. }
  626. str_replace_char(&s_pasv_res_str, '.', ',');
  627. str_append_text(&s_pasv_res_str, ",");
  628. str_append_ulong(&s_pasv_res_str, the_port >> 8);
  629. str_append_text(&s_pasv_res_str, ",");
  630. str_append_ulong(&s_pasv_res_str, the_port & 255);
  631. str_append_text(&s_pasv_res_str, ").");
  632. vsf_cmdio_write_str(p_sess, FTP_PASVOK, &s_pasv_res_str);
  633. }
  634. static void
  635. handle_retr(struct vsf_session* p_sess, int is_http)
  636. {
  637. static struct mystr s_mark_str;
  638. static struct vsf_sysutil_statbuf* s_p_statbuf;
  639. struct vsf_transfer_ret trans_ret;
  640. int remote_fd;
  641. int opened_file;
  642. int is_ascii = 0;
  643. filesize_t offset = p_sess->restart_pos;
  644. p_sess->restart_pos = 0;
  645. if (!is_http && !data_transfer_checks_ok(p_sess))
  646. {
  647. return;
  648. }
  649. if (p_sess->is_ascii && offset != 0)
  650. {
  651. vsf_cmdio_write(p_sess, FTP_FILEFAIL,
  652. "No support for resume of ASCII transfer.");
  653. return;
  654. }
  655. resolve_tilde(&p_sess->ftp_arg_str, p_sess);
  656. vsf_log_start_entry(p_sess, kVSFLogEntryDownload);
  657. str_copy(&p_sess->log_str, &p_sess->ftp_arg_str);
  658. prepend_path_to_filename(&p_sess->log_str);
  659. if (!vsf_access_check_file(&p_sess->ftp_arg_str))
  660. {
  661. vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
  662. return;
  663. }
  664. opened_file = str_open(&p_sess->ftp_arg_str, kVSFSysStrOpenReadOnly);
  665. if (vsf_sysutil_retval_is_error(opened_file))
  666. {
  667. vsf_cmdio_write(p_sess, FTP_FILEFAIL, "Failed to open file.");
  668. return;
  669. }
  670. /* Lock file if required */
  671. if (tunable_lock_upload_files)
  672. {
  673. vsf_sysutil_lock_file_read(opened_file);
  674. }
  675. vsf_sysutil_fstat(opened_file, &s_p_statbuf);
  676. /* No games please */
  677. if (!vsf_sysutil_statbuf_is_regfile(s_p_statbuf))
  678. {
  679. /* Note - pretend open failed */
  680. vsf_cmdio_write(p_sess, FTP_FILEFAIL, "Failed to open file.");
  681. /* Irritating FireFox does RETR on directories, so avoid logging this
  682. * very common and noisy case.
  683. */
  684. if (vsf_sysutil_statbuf_is_dir(s_p_statbuf))
  685. {
  686. vsf_log_clear_entry(p_sess);
  687. }
  688. goto file_close_out;
  689. }
  690. /* Now deactive O_NONBLOCK, otherwise we have a problem on DMAPI filesystems
  691. * such as XFS DMAPI.
  692. */
  693. vsf_sysutil_deactivate_noblock(opened_file);
  694. /* Optionally, we'll be paranoid and only serve publicly readable stuff */
  695. if (p_sess->is_anonymous && tunable_anon_world_readable_only &&
  696. !vsf_sysutil_statbuf_is_readable_other(s_p_statbuf))
  697. {
  698. vsf_cmdio_write(p_sess, FTP_FILEFAIL, "Failed to open file.");
  699. goto file_close_out;
  700. }
  701. /* Set the download offset (from REST) if any */
  702. if (offset != 0)
  703. {
  704. vsf_sysutil_lseek_to(opened_file, offset);
  705. }
  706. str_alloc_text(&s_mark_str, "Opening ");
  707. if (tunable_ascii_download_enable && p_sess->is_ascii)
  708. {
  709. str_append_text(&s_mark_str, "ASCII");
  710. is_ascii = 1;
  711. }
  712. else
  713. {
  714. str_append_text(&s_mark_str, "BINARY");
  715. }
  716. str_append_text(&s_mark_str, " mode data connection for ");
  717. str_append_str(&s_mark_str, &p_sess->ftp_arg_str);
  718. str_append_text(&s_mark_str, " (");
  719. str_append_filesize_t(&s_mark_str,
  720. vsf_sysutil_statbuf_get_size(s_p_statbuf));
  721. str_append_text(&s_mark_str, " bytes).");
  722. if (is_http)
  723. {
  724. remote_fd = VSFTP_COMMAND_FD;
  725. }
  726. else
  727. {
  728. remote_fd = get_remote_transfer_fd(p_sess, str_getbuf(&s_mark_str));
  729. if (vsf_sysutil_retval_is_error(remote_fd))
  730. {
  731. goto port_pasv_cleanup_out;
  732. }
  733. }
  734. trans_ret = vsf_ftpdataio_transfer_file(p_sess, remote_fd,
  735. opened_file, 0, is_ascii);
  736. if (!is_http &&
  737. vsf_ftpdataio_dispose_transfer_fd(p_sess) != 1 &&
  738. trans_ret.retval == 0)
  739. {
  740. trans_ret.retval = -2;
  741. }
  742. p_sess->transfer_size = trans_ret.transferred;
  743. /* Log _after_ the blocking dispose call, so we get transfer times right */
  744. if (trans_ret.retval == 0)
  745. {
  746. vsf_log_do_log(p_sess, 1);
  747. }
  748. if (is_http)
  749. {
  750. goto file_close_out;
  751. }
  752. /* Emit status message _after_ blocking dispose call to avoid buggy FTP
  753. * clients truncating the transfer.
  754. */
  755. if (trans_ret.retval == -1)
  756. {
  757. vsf_cmdio_write(p_sess, FTP_BADSENDFILE, "Failure reading local file.");
  758. }
  759. else if (trans_ret.retval == -2)
  760. {
  761. if (!p_sess->data_timeout)
  762. {
  763. vsf_cmdio_write(p_sess, FTP_BADSENDNET,
  764. "Failure writing network stream.");
  765. }
  766. }
  767. else
  768. {
  769. vsf_cmdio_write(p_sess, FTP_TRANSFEROK, "Transfer complete.");
  770. }
  771. check_abor(p_sess);
  772. port_pasv_cleanup_out:
  773. port_cleanup(p_sess);
  774. pasv_cleanup(p_sess);
  775. file_close_out:
  776. vsf_sysutil_close(opened_file);
  777. }
  778. static void
  779. handle_list(struct vsf_session* p_sess)
  780. {
  781. handle_dir_common(p_sess, 1, 0);
  782. }
  783. static void
  784. handle_dir_common(struct vsf_session* p_sess, int full_details, int stat_cmd)
  785. {
  786. static struct mystr s_option_str;
  787. static struct mystr s_filter_str;
  788. static struct mystr s_dir_name_str;
  789. static struct vsf_sysutil_statbuf* s_p_dirstat;
  790. int dir_allow_read = 1;
  791. struct vsf_sysutil_dir* p_dir = 0;
  792. int retval = 0;
  793. int use_control = 0;
  794. str_empty(&s_option_str);
  795. str_empty(&s_filter_str);
  796. /* By default open the current directory */
  797. str_alloc_text(&s_dir_name_str, ".");
  798. if (!stat_cmd && !data_transfer_checks_ok(p_sess))
  799. {
  800. return;
  801. }
  802. /* Do we have an option? Going to be strict here - the option must come
  803. * first. e.g. "ls -a .." fine, "ls .. -a" not fine
  804. */
  805. if (!str_isempty(&p_sess->ftp_arg_str) &&
  806. str_get_char_at(&p_sess->ftp_arg_str, 0) == '-')
  807. {
  808. /* Chop off the '-' */
  809. str_mid_to_end(&p_sess->ftp_arg_str, &s_option_str, 1);
  810. /* A space will separate options from filter (if any) */
  811. str_split_char(&s_option_str, &s_filter_str, ' ');
  812. }
  813. else
  814. {
  815. /* The argument, if any, is just a filter */
  816. str_copy(&s_filter_str, &p_sess->ftp_arg_str);
  817. }
  818. if (!str_isempty(&s_filter_str))
  819. {
  820. resolve_tilde(&s_filter_str, p_sess);
  821. if (!vsf_access_check_file(&s_filter_str))
  822. {
  823. vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
  824. return;
  825. }
  826. /* First check - is it an outright directory, as in "ls /pub" */
  827. p_dir = str_opendir(&s_filter_str);
  828. if (p_dir != 0)
  829. {
  830. /* Listing a directory! */
  831. str_copy(&s_dir_name_str, &s_filter_str);
  832. str_free(&s_filter_str);
  833. }
  834. else
  835. {
  836. struct str_locate_result locate_result =
  837. str_locate_char(&s_filter_str, '/');
  838. if (locate_result.found)
  839. {
  840. /* Includes a path! Reverse scan for / in the arg, to get the
  841. * base directory and filter (if any)
  842. */
  843. str_copy(&s_dir_name_str, &s_filter_str);
  844. str_split_char_reverse(&s_dir_name_str, &s_filter_str, '/');
  845. /* If we have e.g. "ls /.message", we just ripped off the leading
  846. * slash because it is the only one!
  847. */
  848. if (str_isempty(&s_dir_name_str))
  849. {
  850. str_alloc_text(&s_dir_name_str, "/");
  851. }
  852. }
  853. }
  854. }
  855. if (p_dir == 0)
  856. {
  857. /* NOTE - failure check done below, it's not forgotten */
  858. p_dir = str_opendir(&s_dir_name_str);
  859. }
  860. /* Fine, do it */
  861. if (stat_cmd)
  862. {
  863. use_control = 1;
  864. str_append_char(&s_option_str, 'a');
  865. vsf_cmdio_write_hyphen(p_sess, FTP_STATFILE_OK, "Status follows:");
  866. }
  867. else
  868. {
  869. int remote_fd = get_remote_transfer_fd(
  870. p_sess, "Here comes the directory listing.");
  871. if (vsf_sysutil_retval_is_error(remote_fd))
  872. {
  873. goto dir_close_out;
  874. }
  875. }
  876. if (p_sess->is_anonymous && p_dir && tunable_anon_world_readable_only)
  877. {
  878. vsf_sysutil_dir_stat(p_dir, &s_p_dirstat);
  879. if (!vsf_sysutil_statbuf_is_readable_other(s_p_dirstat))
  880. {
  881. dir_allow_read = 0;
  882. }
  883. }
  884. if (p_dir != 0 && dir_allow_read)
  885. {
  886. retval = vsf_ftpdataio_transfer_dir(p_sess, use_control, p_dir,
  887. &s_dir_name_str, &s_option_str,
  888. &s_filter_str, full_details);
  889. }
  890. if (!stat_cmd)
  891. {
  892. if (vsf_ftpdataio_dispose_transfer_fd(p_sess) != 1 && retval == 0)
  893. {
  894. retval = -1;
  895. }
  896. }
  897. if (stat_cmd)
  898. {
  899. vsf_cmdio_write(p_sess, FTP_STATFILE_OK, "End of status");
  900. }
  901. else if (retval != 0)
  902. {
  903. if (!p_sess->data_timeout)
  904. {
  905. vsf_cmdio_write(p_sess, FTP_BADSENDNET,
  906. "Failure writing network stream.");
  907. }
  908. }
  909. else if (p_dir == 0 || !dir_allow_read)
  910. {
  911. vsf_cmdio_write(p_sess, FTP_TRANSFEROK,
  912. "Transfer done (but failed to open directory).");
  913. }
  914. else
  915. {
  916. vsf_cmdio_write(p_sess, FTP_TRANSFEROK, "Directory send OK.");
  917. }
  918. check_abor(p_sess);
  919. dir_close_out:
  920. if (p_dir)
  921. {
  922. vsf_sysutil_closedir(p_dir);
  923. }
  924. if (!stat_cmd)
  925. {
  926. port_cleanup(p_sess);
  927. pasv_cleanup(p_sess);
  928. }
  929. }
  930. static void
  931. handle_type(struct vsf_session* p_sess)
  932. {
  933. str_upper(&p_sess->ftp_arg_str);
  934. if (str_equal_text(&p_sess->ftp_arg_str, "I") ||
  935. str_equal_text(&p_sess->ftp_arg_str, "L8") ||
  936. str_equal_text(&p_sess->ftp_arg_str, "L 8"))
  937. {
  938. p_sess->is_ascii = 0;
  939. vsf_cmdio_write(p_sess, FTP_TYPEOK, "Switching to Binary mode.");
  940. }
  941. else if (str_equal_text(&p_sess->ftp_arg_str, "A") ||
  942. str_equal_text(&p_sess->ftp_arg_str, "A N"))
  943. {
  944. p_sess->is_ascii = 1;
  945. vsf_cmdio_write(p_sess, FTP_TYPEOK, "Switching to ASCII mode.");
  946. }
  947. else
  948. {
  949. vsf_cmdio_write(p_sess, FTP_BADCMD, "Unrecognised TYPE command.");
  950. }
  951. }
  952. static void
  953. handle_port(struct vsf_session* p_sess)
  954. {
  955. unsigned short the_port;
  956. unsigned char vals[6];
  957. const unsigned char* p_raw;
  958. pasv_cleanup(p_sess);
  959. port_cleanup(p_sess);
  960. p_raw = vsf_sysutil_parse_uchar_string_sep(&p_sess->ftp_arg_str, ',', vals,
  961. sizeof(vals));
  962. if (p_raw == 0)
  963. {
  964. vsf_cmdio_write(p_sess, FTP_BADCMD, "Illegal PORT command.");
  965. return;
  966. }
  967. the_port = (unsigned short) ((vals[4] << 8) | vals[5]);
  968. vsf_sysutil_sockaddr_clone(&p_sess->p_port_sockaddr, p_sess->p_local_addr);
  969. vsf_sysutil_sockaddr_set_ipv4addr(p_sess->p_port_sockaddr, vals);
  970. vsf_sysutil_sockaddr_set_port(p_sess->p_port_sockaddr, the_port);
  971. /* SECURITY:
  972. * 1) Reject requests not connecting to the control socket IP
  973. * 2) Reject connects to privileged ports
  974. */
  975. if (!tunable_port_promiscuous)
  976. {
  977. if (!vsf_sysutil_sockaddr_addr_equal(p_sess->p_remote_addr,
  978. p_sess->p_port_sockaddr) ||
  979. vsf_sysutil_is_port_reserved(the_port))
  980. {
  981. vsf_cmdio_write(p_sess, FTP_BADCMD, "Illegal PORT command.");
  982. port_cleanup(p_sess);
  983. return;
  984. }
  985. }
  986. vsf_cmdio_write(p_sess, FTP_PORTOK,
  987. "PORT command successful. Consider using PASV.");
  988. }
  989. static void
  990. handle_stor(struct vsf_session* p_sess)
  991. {
  992. handle_upload_common(p_sess, 0, 0);
  993. }
  994. static void
  995. handle_upload_common(struct vsf_session* p_sess, int is_append, int is_unique)
  996. {
  997. static struct vsf_sysutil_statbuf* s_p_statbuf;
  998. static struct mystr s_filename;
  999. struct mystr* p_filename;
  1000. struct vsf_transfer_ret trans_ret;
  1001. int new_file_fd;
  1002. int remote_fd;
  1003. int success = 0;
  1004. int created = 0;
  1005. int do_truncate = 0;
  1006. filesize_t offset = p_sess->restart_pos;
  1007. p_sess->restart_pos = 0;
  1008. if (!data_transfer_checks_ok(p_sess))
  1009. {
  1010. return;
  1011. }
  1012. resolve_tilde(&p_sess->ftp_arg_str, p_sess);
  1013. p_filename = &p_sess->ftp_arg_str;
  1014. if (is_unique)
  1015. {
  1016. get_unique_filename(&s_filename, p_filename);
  1017. p_filename = &s_filename;
  1018. }
  1019. vsf_log_start_entry(p_sess, kVSFLogEntryUpload);
  1020. str_copy(&p_sess->log_str, &p_sess->ftp_arg_str);
  1021. prepend_path_to_filename(&p_sess->log_str);
  1022. if (!vsf_access_check_file(p_filename))
  1023. {
  1024. vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
  1025. return;
  1026. }
  1027. /* NOTE - actual file permissions will be governed by the tunable umask */
  1028. /* XXX - do we care about race between create and chown() of anonymous
  1029. * upload?
  1030. */
  1031. if (is_unique || (p_sess->is_anonymous && !tunable_anon_other_write_enable))
  1032. {
  1033. new_file_fd = str_create_exclusive(p_filename);
  1034. }
  1035. else
  1036. {
  1037. /* For non-anonymous, allow open() to overwrite or append existing files */
  1038. new_file_fd = str_create(p_filename);
  1039. if (!is_append && offset == 0)
  1040. {
  1041. do_truncate = 1;
  1042. }
  1043. }
  1044. if (vsf_sysutil_retval_is_error(new_file_fd))
  1045. {
  1046. vsf_cmdio_write(p_sess, FTP_UPLOADFAIL, "Could not create file.");
  1047. return;
  1048. }
  1049. created = 1;
  1050. vsf_sysutil_fstat(new_file_fd, &s_p_statbuf);
  1051. if (vsf_sysutil_statbuf_is_regfile(s_p_statbuf))
  1052. {
  1053. /* Now deactive O_NONBLOCK, otherwise we have a problem on DMAPI filesystems
  1054. * such as XFS DMAPI.
  1055. */
  1056. vsf_sysutil_deactivate_noblock(new_file_fd);
  1057. }
  1058. /* Are we required to chown() this file for security? */
  1059. if (p_sess->is_anonymous && tunable_chown_uploads)
  1060. {
  1061. vsf_sysutil_fchmod(new_file_fd, tunable_chown_upload_mode);
  1062. if (tunable_one_process_model)
  1063. {
  1064. vsf_one_process_chown_upload(p_sess, new_file_fd);
  1065. }
  1066. else
  1067. {
  1068. vsf_two_process_chown_upload(p_sess, new_file_fd);
  1069. }
  1070. }
  1071. /* Are we required to lock this file? */
  1072. if (tunable_lock_upload_files)
  1073. {
  1074. vsf_sysutil_lock_file_write(new_file_fd);
  1075. }
  1076. /* Must truncate the file AFTER locking it! */
  1077. if (do_truncate)
  1078. {
  1079. vsf_sysutil_ftruncate(new_file_fd);
  1080. vsf_sysutil_lseek_to(new_file_fd, 0);
  1081. }
  1082. if (!is_append && offset != 0)
  1083. {
  1084. /* XXX - warning, allows seek past end of file! Check for seek > size? */
  1085. vsf_sysutil_lseek_to(new_file_fd, offset);
  1086. }
  1087. else if (is_append)
  1088. {
  1089. vsf_sysutil_lseek_end(new_file_fd);
  1090. }
  1091. if (is_unique)
  1092. {
  1093. struct mystr resp_str = INIT_MYSTR;
  1094. str_alloc_text(&resp_str, "FILE: ");
  1095. str_append_str(&resp_str, p_filename);
  1096. remote_fd = get_remote_transfer_fd(p_sess, str_getbuf(&resp_str));
  1097. str_free(&resp_str);
  1098. }
  1099. else
  1100. {
  1101. remote_fd = get_remote_transfer_fd(p_sess, "Ok to send data.");
  1102. }
  1103. if (vsf_sysutil_retval_is_error(remote_fd))
  1104. {
  1105. goto port_pasv_cleanup_out;
  1106. }
  1107. if (tunable_ascii_upload_enable && p_sess->is_ascii)
  1108. {
  1109. trans_ret = vsf_ftpdataio_transfer_file(p_sess, remote_fd,
  1110. new_file_fd, 1, 1);
  1111. }
  1112. else
  1113. {
  1114. trans_ret = vsf_ftpdataio_transfer_file(p_sess, remote_fd,
  1115. new_file_fd, 1, 0);
  1116. }
  1117. if (vsf_ftpdataio_dispose_transfer_fd(p_sess) != 1 && trans_ret.retval == 0)
  1118. {
  1119. trans_ret.retval = -2;
  1120. }
  1121. p_sess->transfer_size = trans_ret.transferred;
  1122. if (trans_ret.retval == 0)
  1123. {
  1124. success = 1;
  1125. vsf_log_do_log(p_sess, 1);
  1126. }
  1127. if (trans_ret.retval == -1)
  1128. {
  1129. vsf_cmdio_write(p_sess, FTP_BADSENDFILE, "Failure writing to local file.");
  1130. }
  1131. else if (trans_ret.retval == -2)
  1132. {
  1133. if (!p_sess->data_timeout)
  1134. {
  1135. vsf_cmdio_write(p_sess, FTP_BADSENDNET,
  1136. "Failure reading network stream.");
  1137. }
  1138. }
  1139. else
  1140. {
  1141. vsf_cmdio_write(p_sess, FTP_TRANSFEROK, "Transfer complete.");
  1142. }
  1143. check_abor(p_sess);
  1144. port_pasv_cleanup_out:
  1145. port_cleanup(p_sess);
  1146. pasv_cleanup(p_sess);
  1147. if (tunable_delete_failed_uploads && created && !success)
  1148. {
  1149. str_unlink(p_filename);
  1150. }
  1151. vsf_sysutil_close(new_file_fd);
  1152. }
  1153. static void
  1154. handle_mkd(struct vsf_session* p_sess)
  1155. {
  1156. int retval;
  1157. resolve_tilde(&p_sess->ftp_arg_str, p_sess);
  1158. vsf_log_start_entry(p_sess, kVSFLogEntryMkdir);
  1159. str_copy(&p_sess->log_str, &p_sess->ftp_arg_str);
  1160. prepend_path_to_filename(&p_sess->log_str);
  1161. if (!vsf_access_check_file(&p_sess->ftp_arg_str))
  1162. {
  1163. vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
  1164. return;
  1165. }
  1166. /* NOTE! Actual permissions will be governed by the tunable umask */
  1167. retval = str_mkdir(&p_sess->ftp_arg_str, 0777);
  1168. if (retval != 0)
  1169. {
  1170. vsf_cmdio_write(p_sess, FTP_FILEFAIL,
  1171. "Create directory operation failed.");
  1172. return;
  1173. }
  1174. vsf_log_do_log(p_sess, 1);
  1175. {
  1176. static struct mystr s_mkd_res;
  1177. static struct mystr s_tmp_str;
  1178. str_copy(&s_tmp_str, &p_sess->ftp_arg_str);
  1179. prepend_path_to_filename(&s_tmp_str);
  1180. /* Double up double quotes */
  1181. str_replace_text(&s_tmp_str, "\"", "\"\"");
  1182. /* Build result string */
  1183. str_alloc_text(&s_mkd_res, "\"");
  1184. str_append_str(&s_mkd_res, &s_tmp_str);
  1185. str_append_text(&s_mkd_res, "\" created");
  1186. vsf_cmdio_write_str(p_sess, FTP_MKDIROK, &s_mkd_res);
  1187. }
  1188. }
  1189. static void
  1190. handle_rmd(struct vsf_session* p_sess)
  1191. {
  1192. int retval;
  1193. resolve_tilde(&p_sess->ftp_arg_str, p_sess);
  1194. vsf_log_start_entry(p_sess, kVSFLogEntryRmdir);
  1195. str_copy(&p_sess->log_str, &p_sess->ftp_arg_str);
  1196. prepend_path_to_filename(&p_sess->log_str);
  1197. if (!vsf_access_check_file(&p_sess->ftp_arg_str))
  1198. {
  1199. vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
  1200. return;
  1201. }
  1202. retval = str_rmdir(&p_sess->ftp_arg_str);
  1203. if (retval != 0)
  1204. {
  1205. vsf_cmdio_write(p_sess, FTP_FILEFAIL,
  1206. "Remove directory operation failed.");
  1207. }
  1208. else
  1209. {
  1210. vsf_log_do_log(p_sess, 1);
  1211. vsf_cmdio_write(p_sess, FTP_RMDIROK,
  1212. "Remove directory operation successful.");
  1213. }
  1214. }
  1215. static void
  1216. handle_dele(struct vsf_session* p_sess)
  1217. {
  1218. int retval;
  1219. resolve_tilde(&p_sess->ftp_arg_str, p_sess);
  1220. vsf_log_start_entry(p_sess, kVSFLogEntryDelete);
  1221. str_copy(&p_sess->log_str, &p_sess->ftp_arg_str);
  1222. prepend_path_to_filename(&p_sess->log_str);
  1223. if (!vsf_access_check_file(&p_sess->ftp_arg_str))
  1224. {
  1225. vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
  1226. return;
  1227. }
  1228. retval = str_unlink(&p_sess->ftp_arg_str);
  1229. if (retval != 0)
  1230. {
  1231. vsf_cmdio_write(p_sess, FTP_FILEFAIL, "Delete operation failed.");
  1232. }
  1233. else
  1234. {
  1235. vsf_log_do_log(p_sess, 1);
  1236. vsf_cmdio_write(p_sess, FTP_DELEOK, "Delete operation successful.");
  1237. }
  1238. }
  1239. static void
  1240. handle_rest(struct vsf_session* p_sess)
  1241. {
  1242. static struct mystr s_rest_str;
  1243. filesize_t val = str_a_to_filesize_t(&p_sess->ftp_arg_str);
  1244. if (val < 0)
  1245. {
  1246. val = 0;
  1247. }
  1248. p_sess->restart_pos = val;
  1249. str_alloc_text(&s_rest_str, "Restart position accepted (");
  1250. str_append_filesize_t(&s_rest_str, val);
  1251. str_append_text(&s_rest_str, ").");
  1252. vsf_cmdio_write_str(p_sess, FTP_RESTOK, &s_rest_str);
  1253. }
  1254. static void
  1255. handle_rnfr(struct vsf_session* p_sess)
  1256. {
  1257. static struct vsf_sysutil_statbuf* p_statbuf;
  1258. int retval;
  1259. /* Clear old value */
  1260. str_free(&p_sess->rnfr_filename_str);
  1261. resolve_tilde(&p_sess->ftp_arg_str, p_sess);
  1262. if (!vsf_access_check_file(&p_sess->ftp_arg_str))
  1263. {
  1264. vsf_log_start_entry(p_sess, kVSFLogEntryRename);
  1265. str_copy(&p_sess->log_str, &p_sess->ftp_arg_str);
  1266. prepend_path_to_filename(&p_sess->log_str);
  1267. vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
  1268. return;
  1269. }
  1270. /* Does it exist? */
  1271. retval = str_stat(&p_sess->ftp_arg_str, &p_statbuf);
  1272. if (retval == 0)
  1273. {
  1274. /* Yes */
  1275. str_copy(&p_sess->rnfr_filename_str, &p_sess->ftp_arg_str);
  1276. vsf_cmdio_write(p_sess, FTP_RNFROK, "Ready for RNTO.");
  1277. }
  1278. else
  1279. {
  1280. vsf_log_start_entry(p_sess, kVSFLogEntryRename);
  1281. str_copy(&p_sess->log_str, &p_sess->ftp_arg_str);
  1282. prepend_path_to_filename(&p_sess->log_str);
  1283. vsf_cmdio_write(p_sess, FTP_FILEFAIL, "RNFR command failed.");
  1284. }
  1285. }
  1286. static void
  1287. handle_rnto(struct vsf_session* p_sess)
  1288. {
  1289. static struct mystr s_tmp_str;
  1290. int retval;
  1291. /* If we didn't get a RNFR, throw a wobbly */
  1292. if (str_isempty(&p_sess->rnfr_filename_str))
  1293. {
  1294. vsf_cmdio_write(p_sess, FTP_NEEDRNFR,
  1295. "RNFR required first.");
  1296. return;
  1297. }
  1298. resolve_tilde(&p_sess->ftp_arg_str, p_sess);
  1299. vsf_log_start_entry(p_sess, kVSFLogEntryRename);
  1300. str_copy(&p_sess->log_str, &p_sess->rnfr_filename_str);
  1301. prepend_path_to_filename(&p_sess->log_str);
  1302. str_append_char(&p_sess->log_str, ' ');
  1303. str_copy(&s_tmp_str, &p_sess->ftp_arg_str);
  1304. prepend_path_to_filename(&s_tmp_str);
  1305. str_append_str(&p_sess->log_str, &s_tmp_str);
  1306. if (!vsf_access_check_file(&p_sess->ftp_arg_str))
  1307. {
  1308. vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
  1309. return;
  1310. }
  1311. /* NOTE - might overwrite destination file. Not a concern because the same
  1312. * could be accomplished with DELE.
  1313. */
  1314. retval = str_rename(&p_sess->rnfr_filename_str, &p_sess->ftp_arg_str);
  1315. /* Clear the RNFR filename; start the two stage process again! */
  1316. str_free(&p_sess->rnfr_filename_str);
  1317. if (retval == 0)
  1318. {
  1319. vsf_log_do_log(p_sess, 1);
  1320. vsf_cmdio_write(p_sess, FTP_RENAMEOK, "Rename successful.");
  1321. }
  1322. else
  1323. {
  1324. vsf_cmdio_write(p_sess, FTP_FILEFAIL, "Rename failed.");
  1325. }
  1326. }
  1327. static void
  1328. handle_nlst(struct vsf_session* p_sess)
  1329. {
  1330. handle_dir_common(p_sess, 0, 0);
  1331. }
  1332. static void
  1333. prepend_path_to_filename(struct mystr* p_str)
  1334. {
  1335. static struct mystr s_tmp_str;
  1336. /* Only prepend current working directory if the incoming filename is
  1337. * relative
  1338. */
  1339. str_empty(&s_tmp_str);
  1340. if (str_isempty(p_str) || str_get_char_at(p_str, 0) != '/')
  1341. {
  1342. str_getcwd(&s_tmp_str);
  1343. /* Careful to not emit // if we are in directory / (common with chroot) */
  1344. if (str_isempty(&s_tmp_str) ||
  1345. str_get_char_at(&s_tmp_str, str_getlen(&s_tmp_str) - 1) != '/')
  1346. {
  1347. str_append_char(&s_tmp_str, '/');
  1348. }
  1349. }
  1350. str_append_str(&s_tmp_str, p_str);
  1351. str_copy(p_str, &s_tmp_str);
  1352. }
  1353. static void
  1354. handle_sigurg(void* p_private)
  1355. {
  1356. struct mystr async_cmd_str = INIT_MYSTR;
  1357. struct mystr async_arg_str = INIT_MYSTR;
  1358. struct mystr real_cmd_str = INIT_MYSTR;
  1359. unsigned int len;
  1360. struct vsf_session* p_sess = (struct vsf_session*) p_private;
  1361. /* Did stupid client sent something OOB without a data connection? */
  1362. if (p_sess->data_fd == -1)
  1363. {
  1364. return;
  1365. }
  1366. /* Get the async command - blocks (use data timeout alarm) */
  1367. vsf_cmdio_get_cmd_and_arg(p_sess, &async_cmd_str, &async_arg_str, 0);
  1368. /* Chop off first four characters; they are telnet characters. The client
  1369. * should have sent the first two normally and the second two as urgent
  1370. * data.
  1371. */
  1372. len = str_getlen(&async_cmd_str);
  1373. if (len >= 4)
  1374. {
  1375. str_right(&async_cmd_str, &real_cmd_str, len - 4);
  1376. }
  1377. if (str_equal_text(&real_cmd_str, "ABOR"))
  1378. {
  1379. p_sess->abor_received = 1;
  1380. /* This is failok because of a small race condition; the SIGURG might
  1381. * be raised after the data socket is closed, but before data_fd is
  1382. * set to -1.
  1383. */
  1384. vsf_sysutil_shutdown_failok(p_sess->data_fd);
  1385. }
  1386. else
  1387. {
  1388. /* Sorry! */
  1389. vsf_cmdio_write(p_sess, FTP_BADCMD, "Unknown command.");
  1390. }
  1391. str_free(&async_cmd_str);
  1392. str_free(&async_arg_str);
  1393. str_free(&real_cmd_str);
  1394. }
  1395. static int
  1396. get_remote_transfer_fd(struct vsf_session* p_sess, const char* p_status_msg)
  1397. {
  1398. int remote_fd;
  1399. if (!pasv_active(p_sess) && !port_active(p_sess))
  1400. {
  1401. bug("neither PORT nor PASV active in get_remote_transfer_fd");
  1402. }
  1403. p_sess->abor_received = 0;
  1404. if (pasv_active(p_sess))
  1405. {
  1406. remote_fd = vsf_ftpdataio_get_pasv_fd(p_sess);
  1407. }
  1408. else
  1409. {
  1410. remote_fd = vsf_ftpdataio_get_port_fd(p_sess);
  1411. }
  1412. if (vsf_sysutil_retval_is_error(remote_fd))
  1413. {
  1414. return remote_fd;
  1415. }
  1416. vsf_cmdio_write(p_sess, FTP_DATACONN, p_status_msg);
  1417. if (vsf_ftpdataio_post_mark_connect(p_sess) != 1)
  1418. {
  1419. vsf_ftpdataio_dispose_transfer_fd(p_sess);
  1420. return -1;
  1421. }
  1422. return remote_fd;
  1423. }
  1424. static void
  1425. check_abor(struct vsf_session* p_sess)
  1426. {
  1427. /* If the client sent ABOR, respond to it here */
  1428. if (p_sess->abor_received)
  1429. {
  1430. p_sess->abor_received = 0;
  1431. vsf_cmdio_write(p_sess, FTP_ABOROK, "ABOR successful.");
  1432. }
  1433. }
  1434. static void
  1435. handle_size(struct vsf_session* p_sess)
  1436. {
  1437. /* Note - in ASCII mode, are supposed to return the size after taking into
  1438. * account ASCII linefeed conversions. At least this is what wu-ftpd does in
  1439. * version 2.6.1. Proftpd-1.2.0pre fails to do this.
  1440. * I will not do it because it is a potential I/O DoS.
  1441. */
  1442. static struct vsf_sysutil_statbuf* s_p_statbuf;
  1443. int retval;
  1444. resolve_tilde(&p_sess->ftp_arg_str, p_sess);
  1445. if (!vsf_access_check_file(&p_sess->ftp_arg_str))
  1446. {
  1447. vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
  1448. return;
  1449. }
  1450. retval = str_stat(&p_sess->ftp_arg_str, &s_p_statbuf);
  1451. if (retval != 0 || !vsf_sysutil_statbuf_is_regfile(s_p_statbuf))
  1452. {
  1453. vsf_cmdio_write(p_sess, FTP_FILEFAIL, "Could not get file size.");
  1454. }
  1455. else
  1456. {
  1457. static struct mystr s_size_res_str;
  1458. str_alloc_filesize_t(&s_size_res_str,
  1459. vsf_sysutil_statbuf_get_size(s_p_statbuf));
  1460. vsf_cmdio_write_str(p_sess, FTP_SIZEOK, &s_size_res_str);
  1461. }
  1462. }
  1463. static void
  1464. handle_site(struct vsf_session* p_sess)
  1465. {
  1466. static struct mystr s_site_args_str;
  1467. /* What SITE sub-command is it? */
  1468. str_split_char(&p_sess->ftp_arg_str, &s_site_args_str, ' ');
  1469. str_upper(&p_sess->ftp_arg_str);
  1470. if (tunable_write_enable &&
  1471. tunable_chmod_enable &&
  1472. str_equal_text(&p_sess->ftp_arg_str, "CHMOD"))
  1473. {
  1474. handle_site_chmod(p_sess, &s_site_args_str);
  1475. }
  1476. else if (str_equal_text(&p_sess->ftp_arg_str, "UMASK"))
  1477. {
  1478. handle_site_umask(p_sess, &s_site_args_str);
  1479. }
  1480. else if (str_equal_text(&p_sess->ftp_arg_str, "HELP"))
  1481. {
  1482. if (tunable_write_enable &&
  1483. tunable_chmod_enable)
  1484. {
  1485. vsf_cmdio_write(p_sess, FTP_SITEHELP, "CHMOD UMASK HELP");
  1486. }
  1487. else
  1488. {
  1489. vsf_cmdio_write(p_sess, FTP_SITEHELP, "UMASK HELP");
  1490. }
  1491. }
  1492. else
  1493. {
  1494. vsf_cmdio_write(p_sess, FTP_BADCMD, "Unknown SITE command.");
  1495. }
  1496. }
  1497. static void
  1498. handle_site_chmod(struct vsf_session* p_sess, struct mystr* p_arg_str)
  1499. {
  1500. static struct mystr s_chmod_file_str;
  1501. unsigned int perms;
  1502. int retval;
  1503. if (str_isempty(p_arg_str))
  1504. {
  1505. vsf_cmdio_write(p_sess, FTP_BADCMD, "SITE CHMOD needs 2 arguments.");
  1506. return;
  1507. }
  1508. str_split_char(p_arg_str, &s_chmod_file_str, ' ');
  1509. if (str_isempty(&s_chmod_file_str))
  1510. {
  1511. vsf_cmdio_write(p_sess, FTP_BADCMD, "SITE CHMOD needs 2 arguments.");
  1512. return;
  1513. }
  1514. resolve_tilde(&s_chmod_file_str, p_sess);
  1515. vsf_log_start_entry(p_sess, kVSFLogEntryChmod);
  1516. str_copy(&p_sess->log_str, &s_chmod_file_str);
  1517. prepend_path_to_filename(&p_sess->log_str);
  1518. str_append_char(&p_sess->log_str, ' ');
  1519. str_append_str(&p_sess->log_str, p_arg_str);
  1520. if (!vsf_access_check_file(&s_chmod_file_str))
  1521. {
  1522. vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
  1523. return;
  1524. }
  1525. /* Don't worry - our chmod() implementation only allows 0 - 0777 */
  1526. perms = str_octal_to_uint(p_arg_str);
  1527. retval = str_chmod(&s_chmod_file_str, perms);
  1528. if (vsf_sysutil_retval_is_error(retval))
  1529. {
  1530. vsf_cmdio_write(p_sess, FTP_FILEFAIL, "SITE CHMOD command failed.");
  1531. }
  1532. else
  1533. {
  1534. vsf_log_do_log(p_sess, 1);
  1535. vsf_cmdio_write(p_sess, FTP_CHMODOK, "SITE CHMOD command ok.");
  1536. }
  1537. }
  1538. static void
  1539. handle_site_umask(struct vsf_session* p_sess, struct mystr* p_arg_str)
  1540. {
  1541. static struct mystr s_umask_resp_str;
  1542. if (str_isempty(p_arg_str))
  1543. {
  1544. /* Empty arg => report current umask */
  1545. str_alloc_text(&s_umask_resp_str, "Your current UMASK is ");
  1546. str_append_text(&s_umask_resp_str,
  1547. vsf_sysutil_uint_to_octal(vsf_sysutil_get_umask()));
  1548. }
  1549. else
  1550. {
  1551. /* Set current umask */
  1552. unsigned int new_umask = str_octal_to_uint(p_arg_str);
  1553. vsf_sysutil_set_umask(new_umask);
  1554. str_alloc_text(&s_umask_resp_str, "UMASK set to ");
  1555. str_append_text(&s_umask_resp_str,
  1556. vsf_sysutil_uint_to_octal(vsf_sysutil_get_umask()));
  1557. }
  1558. vsf_cmdio_write_str(p_sess, FTP_UMASKOK, &s_umask_resp_str);
  1559. }
  1560. static void
  1561. handle_appe(struct vsf_session* p_sess)
  1562. {
  1563. handle_upload_common(p_sess, 1, 0);
  1564. }
  1565. static void
  1566. handle_mdtm(struct vsf_session* p_sess)
  1567. {
  1568. static struct mystr s_filename_str;
  1569. static struct vsf_sysutil_statbuf* s_p_statbuf;
  1570. int do_write = 0;
  1571. long modtime = 0;
  1572. struct str_locate_result loc = str_locate_char(&p_sess->ftp_arg_str, ' ');
  1573. int retval = str_stat(&p_sess->ftp_arg_str, &s_p_statbuf);
  1574. if (tunable_mdtm_write && retval != 0 && loc.found &&
  1575. vsf_sysutil_isdigit(str_get_char_at(&p_sess->ftp_arg_str, 0)))
  1576. {
  1577. if (loc.index == 8 || loc.index == 14 ||
  1578. (loc.index > 15 && str_get_char_at(&p_sess->ftp_arg_str, 14) == '.'))
  1579. {
  1580. do_write = 1;
  1581. }
  1582. }
  1583. if (do_write != 0)
  1584. {
  1585. str_split_char(&p_sess->ftp_arg_str, &s_filename_str, ' ');
  1586. modtime = vsf_sysutil_parse_time(str_getbuf(&p_sess->ftp_arg_str));
  1587. str_copy(&p_sess->ftp_arg_str, &s_filename_str);
  1588. }
  1589. resolve_tilde(&p_sess->ftp_arg_str, p_sess);
  1590. if (!vsf_access_check_file(&p_sess->ftp_arg_str))
  1591. {
  1592. vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
  1593. return;
  1594. }
  1595. if (do_write && tunable_write_enable &&
  1596. (tunable_anon_other_write_enable || !p_sess->is_anonymous))
  1597. {
  1598. retval = str_stat(&p_sess->ftp_arg_str, &s_p_statbuf);
  1599. if (retval != 0 || !vsf_sysutil_statbuf_is_regfile(s_p_statbuf))
  1600. {
  1601. vsf_cmdio_write(p_sess, FTP_FILEFAIL,
  1602. "Could not set file modification time.");
  1603. }
  1604. else
  1605. {
  1606. retval = vsf_sysutil_setmodtime(
  1607. str_getbuf(&p_sess->ftp_arg_str), modtime, tunable_use_localtime);
  1608. if (retval != 0)
  1609. {
  1610. vsf_cmdio_write(p_sess, FTP_FILEFAIL,
  1611. "Could not set file modification time.");
  1612. }
  1613. else
  1614. {
  1615. vsf_cmdio_write(p_sess, FTP_MDTMOK,
  1616. "File modification time set.");
  1617. }
  1618. }
  1619. }
  1620. else
  1621. {
  1622. if (retval != 0 || !vsf_sysutil_statbuf_is_regfile(s_p_statbuf))
  1623. {
  1624. vsf_cmdio_write(p_sess, FTP_FILEFAIL,
  1625. "Could not get file modification time.");
  1626. }
  1627. else
  1628. {
  1629. static struct mystr s_mdtm_res_str;
  1630. str_alloc_text(&s_mdtm_res_str,
  1631. vsf_sysutil_statbuf_get_numeric_date(
  1632. s_p_statbuf, tunable_use_localtime));
  1633. vsf_cmdio_write_str(p_sess, FTP_MDTMOK, &s_mdtm_res_str);
  1634. }
  1635. }
  1636. }
  1637. static void
  1638. handle_eprt(struct vsf_session* p_sess)
  1639. {
  1640. static struct mystr s_part1_str;
  1641. static struct mystr s_part2_str;
  1642. static struct mystr s_scopeid_str;
  1643. int proto;
  1644. int port;
  1645. const unsigned char* p_raw_addr;
  1646. int is_ipv6 = vsf_sysutil_sockaddr_is_ipv6(p_sess->p_local_addr);
  1647. port_cleanup(p_sess);
  1648. pasv_cleanup(p_sess);
  1649. str_copy(&s_part1_str, &p_sess->ftp_arg_str);
  1650. str_split_char(&s_part1_str, &s_part2_str, '|');
  1651. if (!str_isempty(&s_part1_str))
  1652. {
  1653. goto bad_eprt;
  1654. }
  1655. /* Split out the protocol and check it */
  1656. str_spl