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

Ftp客户端

开发平台:

C/C++

  1. /*
  2.  * Part of Very Secure FTPd
  3.  * Licence: GPL v2
  4.  * Author: Chris Evans
  5.  * prelogin.c
  6.  *
  7.  * Code to parse the FTP protocol prior to a successful login.
  8.  */
  9. #include "prelogin.h"
  10. #include "ftpcmdio.h"
  11. #include "ftpcodes.h"
  12. #include "str.h"
  13. #include "vsftpver.h"
  14. #include "tunables.h"
  15. #include "oneprocess.h"
  16. #include "twoprocess.h"
  17. #include "sysdeputil.h"
  18. #include "sysutil.h"
  19. #include "session.h"
  20. #include "banner.h"
  21. #include "logging.h"
  22. #include "ssl.h"
  23. #include "features.h"
  24. #include "defs.h"
  25. #include "opts.h"
  26. /* Functions used */
  27. static void check_limits(struct vsf_session* p_sess);
  28. static void emit_greeting(struct vsf_session* p_sess);
  29. static void parse_username_password(struct vsf_session* p_sess);
  30. static void handle_user_command(struct vsf_session* p_sess);
  31. static void handle_pass_command(struct vsf_session* p_sess);
  32. static void check_login_delay();
  33. static void check_login_fails(struct vsf_session* p_sess);
  34. void
  35. init_connection(struct vsf_session* p_sess)
  36. {
  37.   if (tunable_setproctitle_enable)
  38.   {
  39.     vsf_sysutil_setproctitle("not logged in");
  40.   }
  41.   /* Before we talk to the remote, make sure an alarm is set up in case
  42.    * writing the initial greetings should block.
  43.    */
  44.   vsf_cmdio_set_alarm(p_sess);
  45.   /* Check limits before doing an implicit SSL handshake, to avoid DoS
  46.    * attacks. This will result in plain text messages being sent to the SSL
  47.    * client, but we can live with that.
  48.    */
  49.   check_limits(p_sess);
  50.   if (tunable_ssl_enable && tunable_implicit_ssl)
  51.   {
  52.     ssl_control_handshake(p_sess);
  53.   }
  54.   emit_greeting(p_sess);
  55.   parse_username_password(p_sess);
  56. }
  57. static void
  58. check_limits(struct vsf_session* p_sess)
  59. {
  60.   struct mystr str_log_line = INIT_MYSTR;
  61.   /* Check for client limits (standalone mode only) */
  62.   if (tunable_max_clients > 0 &&
  63.       p_sess->num_clients > tunable_max_clients)
  64.   {
  65.     str_alloc_text(&str_log_line, "Connection refused: too many sessions.");
  66.     vsf_log_line(p_sess, kVSFLogEntryConnection, &str_log_line);
  67.     vsf_cmdio_write_exit(p_sess, FTP_TOO_MANY_USERS,
  68.       "There are too many connected users, please try later.");
  69.   }
  70.   if (tunable_max_per_ip > 0 &&
  71.       p_sess->num_this_ip > tunable_max_per_ip)
  72.   {
  73.     str_alloc_text(&str_log_line,
  74.                    "Connection refused: too many sessions for this address.");
  75.     vsf_log_line(p_sess, kVSFLogEntryConnection, &str_log_line);
  76.     vsf_cmdio_write_exit(p_sess, FTP_IP_LIMIT,
  77.       "There are too many connections from your internet address.");
  78.   }
  79.   if (!p_sess->tcp_wrapper_ok)
  80.   {
  81.     str_alloc_text(&str_log_line,
  82.                    "Connection refused: tcp_wrappers denial.");
  83.     vsf_log_line(p_sess, kVSFLogEntryConnection, &str_log_line);
  84.     vsf_cmdio_write_exit(p_sess, FTP_IP_DENY, "Service not available.");
  85.   }
  86.   vsf_log_line(p_sess, kVSFLogEntryConnection, &str_log_line);
  87. }
  88. static void
  89. emit_greeting(struct vsf_session* p_sess)
  90. {
  91.   if (!str_isempty(&p_sess->banner_str))
  92.   {
  93.     vsf_banner_write(p_sess, &p_sess->banner_str, FTP_GREET);
  94.     str_free(&p_sess->banner_str);
  95.     vsf_cmdio_write(p_sess, FTP_GREET, "");
  96.   }
  97.   else if (tunable_ftpd_banner == 0)
  98.   {
  99.     vsf_cmdio_write(p_sess, FTP_GREET, "(vsFTPd " VSF_VERSION 
  100.                     ")");
  101.   }
  102.   else
  103.   {
  104.     vsf_cmdio_write(p_sess, FTP_GREET, tunable_ftpd_banner);
  105.   }
  106. }
  107. static void
  108. parse_username_password(struct vsf_session* p_sess)
  109. {
  110.   while (1)
  111.   {
  112.     vsf_cmdio_get_cmd_and_arg(p_sess, &p_sess->ftp_cmd_str,
  113.                               &p_sess->ftp_arg_str, 1);
  114.     if (str_equal_text(&p_sess->ftp_cmd_str, "USER"))
  115.     {
  116.       handle_user_command(p_sess);
  117.     }
  118.     else if (str_equal_text(&p_sess->ftp_cmd_str, "PASS"))
  119.     {
  120.       handle_pass_command(p_sess);
  121.     }
  122.     else if (str_equal_text(&p_sess->ftp_cmd_str, "QUIT"))
  123.     {
  124.       vsf_cmdio_write_exit(p_sess, FTP_GOODBYE, "Goodbye.");
  125.     }
  126.     else if (str_equal_text(&p_sess->ftp_cmd_str, "FEAT"))
  127.     {
  128.       handle_feat(p_sess);
  129.     }
  130.     else if (str_equal_text(&p_sess->ftp_cmd_str, "OPTS"))
  131.     {
  132.       handle_opts(p_sess);
  133.     }
  134.     else if (tunable_ssl_enable &&
  135.              str_equal_text(&p_sess->ftp_cmd_str, "AUTH") &&
  136.              !p_sess->control_use_ssl)
  137.     {
  138.       handle_auth(p_sess);
  139.     }
  140.     else if (tunable_ssl_enable && str_equal_text(&p_sess->ftp_cmd_str, "PBSZ"))
  141.     {
  142.       handle_pbsz(p_sess);
  143.     }
  144.     else if (tunable_ssl_enable && str_equal_text(&p_sess->ftp_cmd_str, "PROT"))
  145.     {
  146.       handle_prot(p_sess);
  147.     }
  148.     else if (str_isempty(&p_sess->ftp_cmd_str) &&
  149.              str_isempty(&p_sess->ftp_arg_str))
  150.     {
  151.       /* Deliberately ignore to avoid NAT device bugs. ProFTPd does the same. */
  152.     }
  153.     else
  154.     {
  155.       vsf_cmdio_write(p_sess, FTP_LOGINERR,
  156.                       "Please login with USER and PASS.");
  157.     }
  158.   }
  159. }
  160. static void
  161. handle_user_command(struct vsf_session* p_sess)
  162. {
  163.   /* SECURITY: If we're in anonymous only-mode, immediately reject
  164.    * non-anonymous usernames in the hope we save passwords going plaintext
  165.    * over the network
  166.    */
  167.   int is_anon = 1;
  168.   str_copy(&p_sess->user_str, &p_sess->ftp_arg_str);
  169.   str_upper(&p_sess->ftp_arg_str);
  170.   if (!str_equal_text(&p_sess->ftp_arg_str, "FTP") &&
  171.       !str_equal_text(&p_sess->ftp_arg_str, "ANONYMOUS"))
  172.   {
  173.     is_anon = 0;
  174.   }
  175.   if (!tunable_local_enable && !is_anon)
  176.   {
  177.     vsf_cmdio_write(
  178.       p_sess, FTP_LOGINERR, "This FTP server is anonymous only.");
  179.     str_empty(&p_sess->user_str);
  180.     return;
  181.   }
  182.   if (is_anon && p_sess->control_use_ssl && !tunable_allow_anon_ssl &&
  183.       !tunable_force_anon_logins_ssl)
  184.   {
  185.     vsf_cmdio_write(
  186.       p_sess, FTP_LOGINERR, "Anonymous sessions may not use encryption.");
  187.     str_empty(&p_sess->user_str);
  188.     return;
  189.   }
  190.   if (tunable_ssl_enable && !is_anon && !p_sess->control_use_ssl &&
  191.       tunable_force_local_logins_ssl)
  192.   {
  193.     vsf_cmdio_write(
  194.       p_sess, FTP_LOGINERR, "Non-anonymous sessions must use encryption.");
  195.     str_empty(&p_sess->user_str);
  196.     return;
  197.   }
  198.   if (tunable_ssl_enable && is_anon && !p_sess->control_use_ssl &&
  199.       tunable_force_anon_logins_ssl)
  200.   { 
  201.     vsf_cmdio_write(
  202.       p_sess, FTP_LOGINERR, "Anonymous sessions must use encryption.");
  203.     str_empty(&p_sess->user_str);
  204.     return;
  205.   }
  206.   if (tunable_userlist_enable)
  207.   {
  208.     int located = str_contains_line(&p_sess->userlist_str, &p_sess->user_str);
  209.     if ((located && tunable_userlist_deny) ||
  210.         (!located && !tunable_userlist_deny))
  211.     {
  212.       check_login_delay();
  213.       vsf_cmdio_write(p_sess, FTP_LOGINERR, "Permission denied.");
  214.       check_login_fails(p_sess);
  215.       str_empty(&p_sess->user_str);
  216.       return;
  217.     }
  218.   }
  219.   if (is_anon && tunable_no_anon_password)
  220.   {
  221.     /* Fake a password */
  222.     str_alloc_text(&p_sess->ftp_arg_str, "<no password>");
  223.     handle_pass_command(p_sess);
  224.   }
  225.   else
  226.   {
  227.     vsf_cmdio_write(p_sess, FTP_GIVEPWORD, "Please specify the password.");
  228.   }
  229. }
  230. static void
  231. handle_pass_command(struct vsf_session* p_sess)
  232. {
  233.   if (str_isempty(&p_sess->user_str))
  234.   {
  235.     vsf_cmdio_write(p_sess, FTP_NEEDUSER, "Login with USER first.");
  236.     return;
  237.   }
  238.   /* These login calls never return if successful */
  239.   if (tunable_one_process_model)
  240.   {
  241.     vsf_one_process_login(p_sess, &p_sess->ftp_arg_str);
  242.   }
  243.   else
  244.   {
  245.     vsf_two_process_login(p_sess, &p_sess->ftp_arg_str);
  246.   }
  247.   vsf_cmdio_write(p_sess, FTP_LOGINERR, "Login incorrect.");
  248.   check_login_fails(p_sess);
  249.   str_empty(&p_sess->user_str);
  250.   /* FALLTHRU if login fails */
  251. }
  252. static void check_login_delay()
  253. {
  254.   if (tunable_delay_failed_login)
  255.   {
  256.     vsf_sysutil_sleep((double) tunable_delay_failed_login);
  257.   }
  258. }
  259. static void check_login_fails(struct vsf_session* p_sess)
  260. {
  261.   if (++p_sess->login_fails >= tunable_max_login_fails)
  262.   {
  263.     vsf_sysutil_exit(0);
  264.   }
  265. }