privops.c 11 KB

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