postlogin.c
上传用户:ig0539
上传日期:2022-05-21
资源大小:181k
文件大小:55k
源码类别:

Ftp客户端

开发平台:

C/C++

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