postprivparent.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. /*
  2. * Part of Very Secure FTPd
  3. * Licence: GPL v2
  4. * Author: Chris Evans
  5. * postprivparent.c
  6. *
  7. * This file contains all privileged parent services offered after logging
  8. * in. This includes e.g. chown() of uploaded files, issuing of port 20
  9. * sockets.
  10. */
  11. #include "postprivparent.h"
  12. #include "session.h"
  13. #include "privops.h"
  14. #include "privsock.h"
  15. #include "utility.h"
  16. #include "tunables.h"
  17. #include "defs.h"
  18. #include "sysutil.h"
  19. #include "str.h"
  20. #include "secutil.h"
  21. #include "sysstr.h"
  22. #include "sysdeputil.h"
  23. #include "seccompsandbox.h"
  24. static void minimize_privilege(struct vsf_session* p_sess);
  25. static void process_post_login_req(struct vsf_session* p_sess);
  26. static void cmd_process_chown(struct vsf_session* p_sess);
  27. static void cmd_process_get_data_sock(struct vsf_session* p_sess);
  28. static void cmd_process_pasv_cleanup(struct vsf_session* p_sess);
  29. static void cmd_process_pasv_active(struct vsf_session* p_sess);
  30. static void cmd_process_pasv_listen(struct vsf_session* p_sess);
  31. static void cmd_process_pasv_accept(struct vsf_session* p_sess);
  32. void
  33. vsf_priv_parent_postlogin(struct vsf_session* p_sess)
  34. {
  35. minimize_privilege(p_sess);
  36. /* We're still here... */
  37. while (1)
  38. {
  39. process_post_login_req(p_sess);
  40. }
  41. }
  42. static void
  43. process_post_login_req(struct vsf_session* p_sess)
  44. {
  45. char cmd;
  46. /* Blocks */
  47. cmd = priv_sock_get_cmd(p_sess->parent_fd);
  48. if (tunable_chown_uploads && cmd == PRIV_SOCK_CHOWN)
  49. {
  50. cmd_process_chown(p_sess);
  51. }
  52. else if (cmd == PRIV_SOCK_GET_DATA_SOCK)
  53. {
  54. cmd_process_get_data_sock(p_sess);
  55. }
  56. else if (cmd == PRIV_SOCK_PASV_CLEANUP)
  57. {
  58. cmd_process_pasv_cleanup(p_sess);
  59. }
  60. else if (cmd == PRIV_SOCK_PASV_ACTIVE)
  61. {
  62. cmd_process_pasv_active(p_sess);
  63. }
  64. else if (cmd == PRIV_SOCK_PASV_LISTEN)
  65. {
  66. cmd_process_pasv_listen(p_sess);
  67. }
  68. else if (cmd == PRIV_SOCK_PASV_ACCEPT)
  69. {
  70. cmd_process_pasv_accept(p_sess);
  71. }
  72. else
  73. {
  74. die("bad request in process_post_login_req");
  75. }
  76. }
  77. static void
  78. minimize_privilege(struct vsf_session* p_sess)
  79. {
  80. /* So, we logged in and forked a totally unprivileged child. Our job
  81. * now is to minimize the privilege we need in order to act as a helper
  82. * to the child.
  83. */
  84. if (!p_sess->is_anonymous && tunable_session_support)
  85. {
  86. /* Need to hang around to update logs, utmp, wtmp etc. on logout.
  87. * Need to keep privs to do this. */
  88. return;
  89. }
  90. {
  91. unsigned int caps = 0;
  92. struct mystr user_str = INIT_MYSTR;
  93. struct mystr dir_str = INIT_MYSTR;
  94. if (tunable_nopriv_user)
  95. {
  96. str_alloc_text(&user_str, tunable_nopriv_user);
  97. }
  98. if (tunable_secure_chroot_dir)
  99. {
  100. str_alloc_text(&dir_str, tunable_secure_chroot_dir);
  101. }
  102. if (tunable_chown_uploads)
  103. {
  104. caps |= kCapabilityCAP_CHOWN;
  105. }
  106. if (tunable_connect_from_port_20)
  107. {
  108. caps |= kCapabilityCAP_NET_BIND_SERVICE;
  109. }
  110. vsf_secutil_change_credentials(&user_str, &dir_str, 0, caps,
  111. VSF_SECUTIL_OPTION_CHROOT);
  112. str_free(&user_str);
  113. str_free(&dir_str);
  114. }
  115. seccomp_sandbox_init();
  116. seccomp_sandbox_setup_postlogin_broker();
  117. seccomp_sandbox_lockdown();
  118. }
  119. static void
  120. cmd_process_chown(struct vsf_session* p_sess)
  121. {
  122. int the_fd = priv_sock_recv_fd(p_sess->parent_fd);
  123. vsf_privop_do_file_chown(p_sess, the_fd);
  124. vsf_sysutil_close(the_fd);
  125. priv_sock_send_result(p_sess->parent_fd, PRIV_SOCK_RESULT_OK);
  126. }
  127. static void
  128. cmd_process_get_data_sock(struct vsf_session* p_sess)
  129. {
  130. unsigned short port = (unsigned short) priv_sock_get_int(p_sess->parent_fd);
  131. int sock_fd = vsf_privop_get_ftp_port_sock(p_sess, port, 0);
  132. if (sock_fd == -1)
  133. {
  134. priv_sock_send_result(p_sess->parent_fd, PRIV_SOCK_RESULT_BAD);
  135. return;
  136. }
  137. priv_sock_send_result(p_sess->parent_fd, PRIV_SOCK_RESULT_OK);
  138. priv_sock_send_fd(p_sess->parent_fd, sock_fd);
  139. vsf_sysutil_close(sock_fd);
  140. }
  141. static void
  142. cmd_process_pasv_cleanup(struct vsf_session* p_sess)
  143. {
  144. vsf_privop_pasv_cleanup(p_sess);
  145. priv_sock_send_result(p_sess->parent_fd, PRIV_SOCK_RESULT_OK);
  146. }
  147. static void
  148. cmd_process_pasv_active(struct vsf_session* p_sess)
  149. {
  150. int active = vsf_privop_pasv_active(p_sess);
  151. priv_sock_send_int(p_sess->parent_fd, active);
  152. }
  153. static void
  154. cmd_process_pasv_listen(struct vsf_session* p_sess)
  155. {
  156. unsigned short port = vsf_privop_pasv_listen(p_sess);
  157. priv_sock_send_int(p_sess->parent_fd, port);
  158. }
  159. static void
  160. cmd_process_pasv_accept(struct vsf_session* p_sess)
  161. {
  162. int fd = vsf_privop_accept_pasv(p_sess);
  163. if (fd < 0)
  164. {
  165. priv_sock_send_result(p_sess->parent_fd, PRIV_SOCK_RESULT_BAD);
  166. priv_sock_send_int(p_sess->parent_fd, fd);
  167. return;
  168. }
  169. priv_sock_send_result(p_sess->parent_fd, PRIV_SOCK_RESULT_OK);
  170. priv_sock_send_fd(p_sess->parent_fd, fd);
  171. vsf_sysutil_close(fd);
  172. }