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

Ftp客户端

开发平台:

C/C++

  1. /*
  2.  * Part of Very Secure FTPd
  3.  * License: GPL v2
  4.  * Author: Chris Evans
  5.  * privops.c
  6.  *
  7.  * Code implementing the privileged operations that the unprivileged client
  8.  * might request.
  9.  * Look for suitable paranoia in this file.
  10.  */
  11. #include "privops.h"
  12. #include "session.h"
  13. #include "sysdeputil.h"
  14. #include "sysutil.h"
  15. #include "utility.h"
  16. #include "str.h"
  17. #include "tunables.h"
  18. #include "defs.h"
  19. #include "logging.h"
  20. /* File private functions */
  21. static enum EVSFPrivopLoginResult handle_anonymous_login(
  22.   struct vsf_session* p_sess, const struct mystr* p_pass_str);
  23. static enum EVSFPrivopLoginResult handle_local_login(
  24.   struct vsf_session* p_sess, struct mystr* p_user_str,
  25.   const struct mystr* p_pass_str);
  26. static void setup_username_globals(struct vsf_session* p_sess,
  27.                                    const struct mystr* p_str);
  28. static enum EVSFPrivopLoginResult handle_login(
  29.   struct vsf_session* p_sess, struct mystr* p_user_str,
  30.   const struct mystr* p_pass_str);
  31. int
  32. vsf_privop_get_ftp_port_sock(struct vsf_session* p_sess,
  33.                              unsigned short remote_port)
  34. {
  35.   static struct vsf_sysutil_sockaddr* p_sockaddr;
  36.   int retval;
  37.   int i;
  38.   int s = vsf_sysutil_get_ipsock(p_sess->p_local_addr);
  39.   int port = 0;
  40.   if (vsf_sysutil_is_port_reserved(remote_port))
  41.   {
  42.     die("Illegal port request");
  43.   }
  44.   if (tunable_connect_from_port_20)
  45.   {
  46.     port = tunable_ftp_data_port;
  47.   }
  48.   vsf_sysutil_activate_reuseaddr(s);
  49.   /* A report of failure here on Solaris, presumably buggy address reuse
  50.    * support? We'll retry.
  51.    */
  52.   for (i = 0; i < 2; ++i)
  53.   {
  54.     double sleep_for;
  55.     vsf_sysutil_sockaddr_clone(&p_sockaddr, p_sess->p_local_addr);
  56.     vsf_sysutil_sockaddr_set_port(p_sockaddr, port);
  57.     retval = vsf_sysutil_bind(s, p_sockaddr);
  58.     if (retval == 0)
  59.     {
  60.       break;
  61.     }
  62.     if (vsf_sysutil_get_error() != kVSFSysUtilErrADDRINUSE || i == 1)
  63.     {
  64.       die("vsf_sysutil_bind");
  65.     }
  66.     sleep_for = vsf_sysutil_get_random_byte();
  67.     sleep_for /= 256.0;
  68.     sleep_for += 1.0;
  69.     vsf_sysutil_sleep(sleep_for);
  70.   }
  71.   vsf_sysutil_sockaddr_set_port(p_sess->p_remote_addr, remote_port);
  72.   retval = vsf_sysutil_connect_timeout(s, p_sess->p_remote_addr,
  73.                                        tunable_connect_timeout);
  74.   if (vsf_sysutil_retval_is_error(retval))
  75.   {
  76.     vsf_sysutil_close(s);
  77.     s = -1;
  78.   }
  79.   return s;
  80. }
  81. void
  82. vsf_privop_pasv_cleanup(struct vsf_session* p_sess)
  83. {
  84.   if (p_sess->pasv_listen_fd != -1)
  85.   {
  86.     vsf_sysutil_close(p_sess->pasv_listen_fd);
  87.     p_sess->pasv_listen_fd = -1;
  88.   }
  89. }
  90. int
  91. vsf_privop_pasv_active(struct vsf_session* p_sess)
  92. {
  93.   if (p_sess->pasv_listen_fd != -1)
  94.   {
  95.     return 1;
  96.   }
  97.   return 0;
  98. }
  99. unsigned short
  100. vsf_privop_pasv_listen(struct vsf_session* p_sess)
  101. {
  102.   static struct vsf_sysutil_sockaddr* s_p_sockaddr;
  103.   int bind_retries = 10;
  104.   unsigned short the_port = 0;
  105.   /* IPPORT_RESERVED */
  106.   unsigned short min_port = 1024;
  107.   unsigned short max_port = 65535;
  108.   int is_ipv6 = vsf_sysutil_sockaddr_is_ipv6(p_sess->p_local_addr);
  109.   if (is_ipv6)
  110.   {
  111.     p_sess->pasv_listen_fd = vsf_sysutil_get_ipv6_sock();
  112.   }
  113.   else
  114.   {
  115.     p_sess->pasv_listen_fd = vsf_sysutil_get_ipv4_sock();
  116.   }
  117.   vsf_sysutil_activate_reuseaddr(p_sess->pasv_listen_fd);
  118.   if (tunable_pasv_min_port > min_port && tunable_pasv_min_port <= max_port)
  119.   {
  120.     min_port = tunable_pasv_min_port;
  121.   }
  122.   if (tunable_pasv_max_port >= min_port && tunable_pasv_max_port < max_port)
  123.   {
  124.     max_port = tunable_pasv_max_port;
  125.   }
  126.   while (--bind_retries)
  127.   {
  128.     int retval;
  129.     double scaled_port;
  130.     the_port = vsf_sysutil_get_random_byte();
  131.     the_port <<= 8;
  132.     the_port |= vsf_sysutil_get_random_byte();
  133.     scaled_port = (double) min_port;
  134.     scaled_port += ((double) the_port / (double) 65536) *
  135.                    ((double) max_port - min_port + 1);
  136.     the_port = (unsigned short) scaled_port;
  137.     vsf_sysutil_sockaddr_clone(&s_p_sockaddr, p_sess->p_local_addr);
  138.     vsf_sysutil_sockaddr_set_port(s_p_sockaddr, the_port);
  139.     retval = vsf_sysutil_bind(p_sess->pasv_listen_fd, s_p_sockaddr);
  140.     if (!vsf_sysutil_retval_is_error(retval))
  141.     {
  142.       retval = vsf_sysutil_listen(p_sess->pasv_listen_fd, 1);
  143.       if (!vsf_sysutil_retval_is_error(retval))
  144.       {
  145.         break;
  146.       }
  147.     }
  148.     /* SELinux systems can give you an inopportune EACCES, it seems. */
  149.     if (vsf_sysutil_get_error() == kVSFSysUtilErrADDRINUSE ||
  150.         vsf_sysutil_get_error() == kVSFSysUtilErrACCES)
  151.     {
  152.       continue;
  153.     }
  154.     die("vsf_sysutil_bind / listen");
  155.   }
  156.   if (!bind_retries)
  157.   {
  158.     die("vsf_sysutil_bind");
  159.   }
  160.   return the_port;
  161. }
  162. int
  163. vsf_privop_accept_pasv(struct vsf_session* p_sess)
  164. {
  165.   struct vsf_sysutil_sockaddr* p_accept_addr = 0;
  166.   int remote_fd;
  167.   vsf_sysutil_sockaddr_alloc(&p_accept_addr);
  168.   remote_fd = vsf_sysutil_accept_timeout(p_sess->pasv_listen_fd, p_accept_addr,
  169.                                          tunable_accept_timeout);
  170.   if (vsf_sysutil_retval_is_error(remote_fd))
  171.   {
  172.     vsf_sysutil_sockaddr_clear(&p_accept_addr);
  173.     return -1;
  174.   }
  175.   /* SECURITY:
  176.    * Reject the connection if it wasn't from the same IP as the
  177.    * control connection.
  178.    */
  179.   if (!tunable_pasv_promiscuous)
  180.   {
  181.     if (!vsf_sysutil_sockaddr_addr_equal(p_sess->p_remote_addr, p_accept_addr))
  182.     {
  183.       vsf_sysutil_close(remote_fd);
  184.       vsf_sysutil_sockaddr_clear(&p_accept_addr);
  185.       return -2;
  186.     }
  187.   }
  188.   vsf_sysutil_sockaddr_clear(&p_accept_addr);
  189.   return remote_fd;
  190. }
  191. void
  192. vsf_privop_do_file_chown(struct vsf_session* p_sess, int fd)
  193. {
  194.   static struct vsf_sysutil_statbuf* s_p_statbuf;
  195.   vsf_sysutil_fstat(fd, &s_p_statbuf);
  196.   /* Do nothing if it is already owned by the desired user. */
  197.   if (vsf_sysutil_statbuf_get_uid(s_p_statbuf) ==
  198.       p_sess->anon_upload_chown_uid)
  199.   {
  200.     return;
  201.   }
  202.   /* Drop it like a hot potato unless it's a regular file owned by
  203.    * the the anonymous ftp user
  204.    */
  205.   if (p_sess->anon_upload_chown_uid == -1 ||
  206.       !vsf_sysutil_statbuf_is_regfile(s_p_statbuf) ||
  207.       (vsf_sysutil_statbuf_get_uid(s_p_statbuf) != p_sess->anon_ftp_uid &&
  208.        vsf_sysutil_statbuf_get_uid(s_p_statbuf) != p_sess->guest_user_uid))
  209.   {
  210.     die("invalid fd in cmd_process_chown");
  211.   }
  212.   /* SECURITY! You need an OS which strips SUID/SGID bits on chown(),
  213.    * otherwise a compromise of the FTP user will lead to compromise of
  214.    * the "anon_upload_chown_uid" user (think chmod +s).
  215.    */
  216.   vsf_sysutil_fchown(fd, p_sess->anon_upload_chown_uid, -1);
  217. }
  218. enum EVSFPrivopLoginResult
  219. vsf_privop_do_login(struct vsf_session* p_sess,
  220.                     const struct mystr* p_pass_str)
  221. {
  222.   enum EVSFPrivopLoginResult result =
  223.     handle_login(p_sess, &p_sess->user_str, p_pass_str);
  224.   vsf_log_start_entry(p_sess, kVSFLogEntryLogin);
  225.   if (result == kVSFLoginFail)
  226.   {
  227.     vsf_log_do_log(p_sess, 0);
  228.     if (tunable_delay_failed_login)
  229.     {
  230.       vsf_sysutil_sleep((double) tunable_delay_failed_login);
  231.     }
  232.   }
  233.   else
  234.   {
  235.     vsf_log_do_log(p_sess, 1);
  236.     if (tunable_delay_successful_login)
  237.     {
  238.       vsf_sysutil_sleep((double) tunable_delay_successful_login);
  239.     }
  240.   }
  241.   return result;
  242. }
  243. static enum EVSFPrivopLoginResult
  244. handle_login(struct vsf_session* p_sess, struct mystr* p_user_str,
  245.              const struct mystr* p_pass_str)
  246. {
  247.   /* Do not assume PAM can cope with dodgy input, even though it
  248.    * almost certainly can.
  249.    */
  250.   int anonymous_login = 0;
  251.   char first_char;
  252.   unsigned int len = str_getlen(p_user_str);
  253.   if (len == 0 || len > VSFTP_USERNAME_MAX)
  254.   {
  255.     return kVSFLoginFail;
  256.   }
  257.   /* Throw out dodgy start characters */
  258.   first_char = str_get_char_at(p_user_str, 0);
  259.   if (!vsf_sysutil_isalnum(first_char) &&
  260.       first_char != '_' &&
  261.       first_char != '.')
  262.   {
  263.     return kVSFLoginFail;
  264.   }
  265.   /* Throw out non-printable characters and space in username */
  266.   if (str_contains_space(p_user_str) ||
  267.       str_contains_unprintable(p_user_str))
  268.   {
  269.     return kVSFLoginFail;
  270.   }
  271.   /* Throw out excessive length passwords */
  272.   len = str_getlen(p_pass_str);
  273.   if (len > VSFTP_PASSWORD_MAX)
  274.   {
  275.     return kVSFLoginFail;
  276.   }
  277.   /* Check for an anonymous login or "real" login */
  278.   if (tunable_anonymous_enable)
  279.   {
  280.     struct mystr upper_str = INIT_MYSTR;
  281.     str_copy(&upper_str, p_user_str);
  282.     str_upper(&upper_str);
  283.     if (str_equal_text(&upper_str, "FTP") ||
  284.         str_equal_text(&upper_str, "ANONYMOUS"))
  285.     {
  286.       anonymous_login = 1;
  287.     }
  288.     str_free(&upper_str);
  289.   }
  290.   {
  291.     enum EVSFPrivopLoginResult result = kVSFLoginFail;
  292.     if (anonymous_login)
  293.     {
  294.       result = handle_anonymous_login(p_sess, p_pass_str);
  295.     }
  296.     else
  297.     {
  298.       if (!tunable_local_enable)
  299.       {
  300.         die("unexpected local login in handle_login");
  301.       }
  302.       result = handle_local_login(p_sess, p_user_str, p_pass_str);
  303.     }
  304.     return result;
  305.   }
  306. }
  307. static enum EVSFPrivopLoginResult
  308. handle_anonymous_login(struct vsf_session* p_sess,
  309.                        const struct mystr* p_pass_str)
  310. {
  311.   if (!str_isempty(&p_sess->banned_email_str) &&
  312.       str_contains_line(&p_sess->banned_email_str, p_pass_str))
  313.   {
  314.     return kVSFLoginFail;
  315.   }
  316.   if (!str_isempty(&p_sess->email_passwords_str) &&
  317.       (!str_contains_line(&p_sess->email_passwords_str, p_pass_str) ||
  318.        str_isempty(p_pass_str)))
  319.   {
  320.     return kVSFLoginFail;
  321.   }
  322.   /* Store the anonymous identity string */
  323.   str_copy(&p_sess->anon_pass_str, p_pass_str);
  324.   if (str_isempty(&p_sess->anon_pass_str))
  325.   {
  326.     str_alloc_text(&p_sess->anon_pass_str, "?");
  327.   }
  328.   /* "Fix" any characters which might upset the log processing */
  329.   str_replace_char(&p_sess->anon_pass_str, ' ', '_');
  330.   str_replace_char(&p_sess->anon_pass_str, 'n', '?');
  331.   {
  332.     struct mystr ftp_username_str = INIT_MYSTR;
  333.     str_alloc_text(&ftp_username_str, tunable_ftp_username);
  334.     setup_username_globals(p_sess, &ftp_username_str);
  335.     str_free(&ftp_username_str);
  336.   }
  337.   str_free(&p_sess->banned_email_str);
  338.   str_free(&p_sess->email_passwords_str);
  339.   return kVSFLoginAnon;
  340. }
  341. static enum EVSFPrivopLoginResult
  342. handle_local_login(struct vsf_session* p_sess,
  343.                    struct mystr* p_user_str,
  344.                    const struct mystr* p_pass_str)
  345. {
  346.   if (!vsf_sysdep_check_auth(p_user_str, p_pass_str, &p_sess->remote_ip_str))
  347.   {
  348.     return kVSFLoginFail;
  349.   }
  350.   setup_username_globals(p_sess, p_user_str);
  351.   return kVSFLoginReal;
  352. }
  353. static void
  354. setup_username_globals(struct vsf_session* p_sess, const struct mystr* p_str)
  355. {
  356.   str_copy(&p_sess->user_str, p_str);
  357.   if (tunable_setproctitle_enable)
  358.   {
  359.     struct mystr prefix_str = INIT_MYSTR;
  360.     str_copy(&prefix_str, &p_sess->remote_ip_str);
  361.     str_append_char(&prefix_str, '/');
  362.     str_append_str(&prefix_str, p_str);
  363.     vsf_sysutil_set_proctitle_prefix(&prefix_str);
  364.     str_free(&prefix_str);
  365.   }
  366. }