twoprocess.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568
  1. /*
  2. * Part of Very Secure FTPd
  3. * License: GPL v2
  4. * Author: Chris Evans
  5. * twoprocess.c
  6. *
  7. * Code implementing the standard, secure two process security model.
  8. */
  9. #include "twoprocess.h"
  10. #include "privops.h"
  11. #include "prelogin.h"
  12. #include "postlogin.h"
  13. #include "postprivparent.h"
  14. #include "session.h"
  15. #include "privsock.h"
  16. #include "secutil.h"
  17. #include "filestr.h"
  18. #include "str.h"
  19. #include "sysstr.h"
  20. #include "utility.h"
  21. #include "tunables.h"
  22. #include "defs.h"
  23. #include "parseconf.h"
  24. #include "ssl.h"
  25. #include "readwrite.h"
  26. #include "sysutil.h"
  27. #include "sysdeputil.h"
  28. #include "sslslave.h"
  29. #include "seccompsandbox.h"
  30. static void drop_all_privs(void);
  31. static void handle_sigchld(void* duff);
  32. static void handle_sigterm(void* duff);
  33. static void process_login_req(struct vsf_session* p_sess);
  34. static void common_do_login(struct vsf_session* p_sess,
  35. const struct mystr* p_user_str, int do_chroot,
  36. int anon);
  37. static void handle_per_user_config(const struct mystr* p_user_str);
  38. static void calculate_chdir_dir(int anon, struct mystr* p_userdir_str,
  39. struct mystr* p_chroot_str,
  40. struct mystr* p_chdir_str,
  41. const struct mystr* p_user_str,
  42. const struct mystr* p_orig_user_str);
  43. static void
  44. handle_sigchld(void* duff)
  45. {
  46. struct vsf_sysutil_wait_retval wait_retval = vsf_sysutil_wait();
  47. (void) duff;
  48. /* Child died, so we'll do the same! Report it as an error unless the child
  49. * exited normally with zero exit code
  50. */
  51. if (vsf_sysutil_retval_is_error(vsf_sysutil_wait_get_retval(&wait_retval)))
  52. {
  53. die("waiting for child");
  54. }
  55. else if (!vsf_sysutil_wait_exited_normally(&wait_retval))
  56. {
  57. die("child died");
  58. }
  59. vsf_sysutil_exit(0);
  60. }
  61. static void
  62. handle_sigterm(void* duff)
  63. {
  64. (void) duff;
  65. /* Blow away the connection to make sure no process lingers. */
  66. vsf_sysutil_shutdown_failok(VSFTP_COMMAND_FD);
  67. /* Will call the registered exit function to clean up u/wtmp if needed. */
  68. vsf_sysutil_exit(1);
  69. }
  70. void
  71. vsf_two_process_start(struct vsf_session* p_sess)
  72. {
  73. vsf_sysutil_install_sighandler(kVSFSysUtilSigTERM, handle_sigterm, 0, 1);
  74. /* Overrides the SIGKILL setting set by the standalone listener. */
  75. vsf_set_term_if_parent_dies();
  76. /* Create the comms channel between privileged parent and no-priv child */
  77. priv_sock_init(p_sess);
  78. if (tunable_ssl_enable)
  79. {
  80. /* Create the comms channel between the no-priv SSL child and the low-priv
  81. * protocol handling child.
  82. */
  83. ssl_comm_channel_init(p_sess);
  84. }
  85. vsf_sysutil_install_sighandler(kVSFSysUtilSigCHLD, handle_sigchld, 0, 1);
  86. {
  87. int newpid;
  88. if (tunable_isolate_network)
  89. {
  90. newpid = vsf_sysutil_fork_newnet();
  91. }
  92. else
  93. {
  94. newpid = vsf_sysutil_fork();
  95. }
  96. if (newpid != 0)
  97. {
  98. priv_sock_set_parent_context(p_sess);
  99. if (tunable_ssl_enable)
  100. {
  101. ssl_comm_channel_set_consumer_context(p_sess);
  102. }
  103. /* Parent - go into pre-login parent process mode */
  104. while (1)
  105. {
  106. process_login_req(p_sess);
  107. }
  108. }
  109. }
  110. /* Child process - time to lose as much privilege as possible and do the
  111. * login processing
  112. */
  113. vsf_set_die_if_parent_dies();
  114. priv_sock_set_child_context(p_sess);
  115. if (tunable_ssl_enable)
  116. {
  117. ssl_comm_channel_set_producer_context(p_sess);
  118. }
  119. if (tunable_local_enable && tunable_userlist_enable)
  120. {
  121. int retval = -1;
  122. if (tunable_userlist_file)
  123. {
  124. retval = str_fileread(&p_sess->userlist_str, tunable_userlist_file,
  125. VSFTP_CONF_FILE_MAX);
  126. }
  127. if (vsf_sysutil_retval_is_error(retval))
  128. {
  129. die2("cannot read user list file:", tunable_userlist_file);
  130. }
  131. }
  132. drop_all_privs();
  133. seccomp_sandbox_init();
  134. seccomp_sandbox_setup_prelogin(p_sess);
  135. seccomp_sandbox_lockdown();
  136. init_connection(p_sess);
  137. /* NOTREACHED */
  138. }
  139. static void
  140. drop_all_privs(void)
  141. {
  142. struct mystr user_str = INIT_MYSTR;
  143. struct mystr dir_str = INIT_MYSTR;
  144. unsigned int option = VSF_SECUTIL_OPTION_CHROOT | VSF_SECUTIL_OPTION_NO_PROCS;
  145. if (!tunable_ssl_enable)
  146. {
  147. /* Unfortunately, can only enable this if we can be sure of not using SSL.
  148. * In the SSL case, we'll need to receive data transfer file descriptors.
  149. */
  150. option |= VSF_SECUTIL_OPTION_NO_FDS;
  151. }
  152. if (tunable_nopriv_user)
  153. {
  154. str_alloc_text(&user_str, tunable_nopriv_user);
  155. }
  156. if (tunable_secure_chroot_dir)
  157. {
  158. str_alloc_text(&dir_str, tunable_secure_chroot_dir);
  159. }
  160. /* Be kind: give good error message if the secure dir is missing */
  161. {
  162. struct vsf_sysutil_statbuf* p_statbuf = 0;
  163. if (vsf_sysutil_retval_is_error(str_lstat(&dir_str, &p_statbuf)))
  164. {
  165. die2("directory given in 'secure_chroot_dir':",
  166. tunable_secure_chroot_dir);
  167. }
  168. vsf_sysutil_free(p_statbuf);
  169. }
  170. vsf_secutil_change_credentials(&user_str, &dir_str, 0, 0, option);
  171. str_free(&user_str);
  172. str_free(&dir_str);
  173. }
  174. void
  175. vsf_two_process_login(struct vsf_session* p_sess,
  176. const struct mystr* p_pass_str)
  177. {
  178. char result;
  179. priv_sock_send_cmd(p_sess->child_fd, PRIV_SOCK_LOGIN);
  180. priv_sock_send_str(p_sess->child_fd, &p_sess->user_str);
  181. priv_sock_send_str(p_sess->child_fd, p_pass_str);
  182. priv_sock_send_int(p_sess->child_fd, p_sess->control_use_ssl);
  183. priv_sock_send_int(p_sess->child_fd, p_sess->data_use_ssl);
  184. result = priv_sock_get_result(p_sess->child_fd);
  185. if (result == PRIV_SOCK_RESULT_OK)
  186. {
  187. /* Miracle. We don't emit the success message here. That is left to
  188. * process_post_login().
  189. * Exit normally, unless we are remaining as the SSL read / write child.
  190. */
  191. if (!p_sess->control_use_ssl)
  192. {
  193. vsf_sysutil_exit(0);
  194. }
  195. else
  196. {
  197. ssl_slave(p_sess);
  198. }
  199. /* NOTREACHED */
  200. }
  201. else if (result == PRIV_SOCK_RESULT_BAD)
  202. {
  203. /* Continue the processing loop.. */
  204. return;
  205. }
  206. else
  207. {
  208. die("priv_sock_get_result");
  209. }
  210. }
  211. int
  212. vsf_two_process_get_priv_data_sock(struct vsf_session* p_sess)
  213. {
  214. char res;
  215. unsigned short port = vsf_sysutil_sockaddr_get_port(p_sess->p_port_sockaddr);
  216. priv_sock_send_cmd(p_sess->child_fd, PRIV_SOCK_GET_DATA_SOCK);
  217. priv_sock_send_int(p_sess->child_fd, port);
  218. res = priv_sock_get_result(p_sess->child_fd);
  219. if (res == PRIV_SOCK_RESULT_BAD)
  220. {
  221. return -1;
  222. }
  223. else if (res != PRIV_SOCK_RESULT_OK)
  224. {
  225. die("could not get privileged socket");
  226. }
  227. return priv_sock_recv_fd(p_sess->child_fd);
  228. }
  229. void
  230. vsf_two_process_pasv_cleanup(struct vsf_session* p_sess)
  231. {
  232. char res;
  233. priv_sock_send_cmd(p_sess->child_fd, PRIV_SOCK_PASV_CLEANUP);
  234. res = priv_sock_get_result(p_sess->child_fd);
  235. if (res != PRIV_SOCK_RESULT_OK)
  236. {
  237. die("could not clean up socket");
  238. }
  239. }
  240. int
  241. vsf_two_process_pasv_active(struct vsf_session* p_sess)
  242. {
  243. priv_sock_send_cmd(p_sess->child_fd, PRIV_SOCK_PASV_ACTIVE);
  244. return priv_sock_get_int(p_sess->child_fd);
  245. }
  246. unsigned short
  247. vsf_two_process_listen(struct vsf_session* p_sess)
  248. {
  249. priv_sock_send_cmd(p_sess->child_fd, PRIV_SOCK_PASV_LISTEN);
  250. return (unsigned short) priv_sock_get_int(p_sess->child_fd);
  251. }
  252. int
  253. vsf_two_process_get_pasv_fd(struct vsf_session* p_sess)
  254. {
  255. char res;
  256. priv_sock_send_cmd(p_sess->child_fd, PRIV_SOCK_PASV_ACCEPT);
  257. res = priv_sock_get_result(p_sess->child_fd);
  258. if (res == PRIV_SOCK_RESULT_BAD)
  259. {
  260. return priv_sock_get_int(p_sess->child_fd);
  261. }
  262. else if (res != PRIV_SOCK_RESULT_OK)
  263. {
  264. die("could not accept on listening socket");
  265. }
  266. return priv_sock_recv_fd(p_sess->child_fd);
  267. }
  268. void
  269. vsf_two_process_chown_upload(struct vsf_session* p_sess, int fd)
  270. {
  271. char res;
  272. priv_sock_send_cmd(p_sess->child_fd, PRIV_SOCK_CHOWN);
  273. priv_sock_send_fd(p_sess->child_fd, fd);
  274. res = priv_sock_get_result(p_sess->child_fd);
  275. if (res != PRIV_SOCK_RESULT_OK)
  276. {
  277. die("unexpected failure in vsf_two_process_chown_upload");
  278. }
  279. }
  280. static void
  281. process_login_req(struct vsf_session* p_sess)
  282. {
  283. enum EVSFPrivopLoginResult e_login_result = kVSFLoginNull;
  284. char cmd;
  285. /* Blocks */
  286. cmd = priv_sock_get_cmd(p_sess->parent_fd);
  287. if (cmd != PRIV_SOCK_LOGIN)
  288. {
  289. die("bad request");
  290. }
  291. /* Get username and password - we must distrust these */
  292. {
  293. struct mystr password_str = INIT_MYSTR;
  294. priv_sock_get_str(p_sess->parent_fd, &p_sess->user_str);
  295. priv_sock_get_str(p_sess->parent_fd, &password_str);
  296. p_sess->control_use_ssl = priv_sock_get_int(p_sess->parent_fd);
  297. p_sess->data_use_ssl = priv_sock_get_int(p_sess->parent_fd);
  298. if (!tunable_ssl_enable)
  299. {
  300. p_sess->control_use_ssl = 0;
  301. p_sess->data_use_ssl = 0;
  302. }
  303. e_login_result = vsf_privop_do_login(p_sess, &password_str);
  304. str_free(&password_str);
  305. }
  306. switch (e_login_result)
  307. {
  308. case kVSFLoginFail:
  309. priv_sock_send_result(p_sess->parent_fd, PRIV_SOCK_RESULT_BAD);
  310. return;
  311. break;
  312. case kVSFLoginAnon:
  313. str_free(&p_sess->user_str);
  314. if (tunable_ftp_username)
  315. {
  316. str_alloc_text(&p_sess->user_str, tunable_ftp_username);
  317. }
  318. common_do_login(p_sess, &p_sess->user_str, 1, 1);
  319. break;
  320. case kVSFLoginReal:
  321. {
  322. int do_chroot = 0;
  323. if (tunable_chroot_local_user)
  324. {
  325. do_chroot = 1;
  326. }
  327. if (tunable_chroot_list_enable)
  328. {
  329. struct mystr chroot_list_file = INIT_MYSTR;
  330. int retval = -1;
  331. if (tunable_chroot_list_file)
  332. {
  333. retval = str_fileread(&chroot_list_file, tunable_chroot_list_file,
  334. VSFTP_CONF_FILE_MAX);
  335. }
  336. if (vsf_sysutil_retval_is_error(retval))
  337. {
  338. die2("could not read chroot() list file:",
  339. tunable_chroot_list_file);
  340. }
  341. if (str_contains_line(&chroot_list_file, &p_sess->user_str))
  342. {
  343. if (do_chroot)
  344. {
  345. do_chroot = 0;
  346. }
  347. else
  348. {
  349. do_chroot = 1;
  350. }
  351. }
  352. str_free(&chroot_list_file);
  353. }
  354. common_do_login(p_sess, &p_sess->user_str, do_chroot, 0);
  355. }
  356. break;
  357. case kVSFLoginNull:
  358. /* Fall through */
  359. default:
  360. bug("weird state in process_login_request");
  361. break;
  362. }
  363. /* NOTREACHED */
  364. }
  365. static void
  366. common_do_login(struct vsf_session* p_sess, const struct mystr* p_user_str,
  367. int do_chroot, int anon)
  368. {
  369. int was_anon = anon;
  370. const struct mystr* p_orig_user_str = p_user_str;
  371. int newpid;
  372. vsf_sysutil_install_null_sighandler(kVSFSysUtilSigCHLD);
  373. /* Tells the pre-login child all is OK (it may exit in response) */
  374. priv_sock_send_result(p_sess->parent_fd, PRIV_SOCK_RESULT_OK);
  375. if (!p_sess->control_use_ssl)
  376. {
  377. (void) vsf_sysutil_wait();
  378. }
  379. else
  380. {
  381. p_sess->ssl_slave_active = 1;
  382. }
  383. /* Handle loading per-user config options */
  384. handle_per_user_config(p_user_str);
  385. /* Set this before we fork */
  386. p_sess->is_anonymous = anon;
  387. priv_sock_close(p_sess);
  388. priv_sock_init(p_sess);
  389. vsf_sysutil_install_sighandler(kVSFSysUtilSigCHLD, handle_sigchld, 0, 1);
  390. if (tunable_isolate_network && !tunable_port_promiscuous)
  391. {
  392. newpid = vsf_sysutil_fork_newnet();
  393. }
  394. else
  395. {
  396. newpid = vsf_sysutil_fork();
  397. }
  398. if (newpid == 0)
  399. {
  400. struct mystr guest_user_str = INIT_MYSTR;
  401. struct mystr chroot_str = INIT_MYSTR;
  402. struct mystr chdir_str = INIT_MYSTR;
  403. struct mystr userdir_str = INIT_MYSTR;
  404. unsigned int secutil_option = VSF_SECUTIL_OPTION_USE_GROUPS |
  405. VSF_SECUTIL_OPTION_NO_PROCS;
  406. /* Child - drop privs and start proper FTP! */
  407. /* This PR_SET_PDEATHSIG doesn't work for all possible process tree setups.
  408. * The other cases are taken care of by a shutdown() of the command
  409. * connection in our SIGTERM handler.
  410. */
  411. vsf_set_die_if_parent_dies();
  412. priv_sock_set_child_context(p_sess);
  413. if (tunable_guest_enable && !anon)
  414. {
  415. p_sess->is_guest = 1;
  416. /* Remap to the guest user */
  417. if (tunable_guest_username)
  418. {
  419. str_alloc_text(&guest_user_str, tunable_guest_username);
  420. }
  421. p_user_str = &guest_user_str;
  422. if (!tunable_virtual_use_local_privs)
  423. {
  424. anon = 1;
  425. do_chroot = 1;
  426. }
  427. }
  428. if (do_chroot)
  429. {
  430. secutil_option |= VSF_SECUTIL_OPTION_CHROOT;
  431. }
  432. if (!anon)
  433. {
  434. secutil_option |= VSF_SECUTIL_OPTION_CHANGE_EUID;
  435. }
  436. if (!was_anon && tunable_allow_writeable_chroot)
  437. {
  438. secutil_option |= VSF_SECUTIL_OPTION_ALLOW_WRITEABLE_ROOT;
  439. }
  440. calculate_chdir_dir(was_anon, &userdir_str, &chroot_str, &chdir_str,
  441. p_user_str, p_orig_user_str);
  442. vsf_secutil_change_credentials(p_user_str, &userdir_str, &chroot_str,
  443. 0, secutil_option);
  444. if (!str_isempty(&chdir_str))
  445. {
  446. (void) str_chdir(&chdir_str);
  447. }
  448. str_free(&guest_user_str);
  449. str_free(&chroot_str);
  450. str_free(&chdir_str);
  451. str_free(&userdir_str);
  452. p_sess->is_anonymous = anon;
  453. seccomp_sandbox_init();
  454. seccomp_sandbox_setup_postlogin(p_sess);
  455. seccomp_sandbox_lockdown();
  456. process_post_login(p_sess);
  457. bug("should not get here: common_do_login");
  458. }
  459. /* Parent */
  460. priv_sock_set_parent_context(p_sess);
  461. if (tunable_ssl_enable)
  462. {
  463. ssl_comm_channel_set_producer_context(p_sess);
  464. }
  465. /* The seccomp sandbox lockdown for the priv parent is done inside here */
  466. vsf_priv_parent_postlogin(p_sess);
  467. bug("should not get here in common_do_login");
  468. }
  469. static void
  470. handle_per_user_config(const struct mystr* p_user_str)
  471. {
  472. struct mystr filename_str = INIT_MYSTR;
  473. struct vsf_sysutil_statbuf* p_statbuf = 0;
  474. struct str_locate_result loc_result;
  475. int retval;
  476. if (!tunable_user_config_dir)
  477. {
  478. return;
  479. }
  480. /* Security paranoia - ignore if user has a / in it. */
  481. loc_result = str_locate_char(p_user_str, '/');
  482. if (loc_result.found)
  483. {
  484. return;
  485. }
  486. str_alloc_text(&filename_str, tunable_user_config_dir);
  487. str_append_char(&filename_str, '/');
  488. str_append_str(&filename_str, p_user_str);
  489. retval = str_stat(&filename_str, &p_statbuf);
  490. if (!vsf_sysutil_retval_is_error(retval))
  491. {
  492. /* Security - file ownership check now in vsf_parseconf_load_file() */
  493. vsf_parseconf_load_file(str_getbuf(&filename_str), 1);
  494. }
  495. else if (vsf_sysutil_get_error() != kVSFSysUtilErrNOENT)
  496. {
  497. die("error opening per-user config file");
  498. }
  499. str_free(&filename_str);
  500. vsf_sysutil_free(p_statbuf);
  501. }
  502. static void
  503. calculate_chdir_dir(int anon_login, struct mystr* p_userdir_str,
  504. struct mystr* p_chroot_str,
  505. struct mystr* p_chdir_str,
  506. const struct mystr* p_user_str,
  507. const struct mystr* p_orig_user_str)
  508. {
  509. if (!anon_login)
  510. {
  511. const struct vsf_sysutil_user* p_user = str_getpwnam(p_user_str);
  512. if (p_user == 0)
  513. {
  514. die2("cannot locate user entry:", str_getbuf(p_user_str));
  515. }
  516. str_alloc_text(p_userdir_str, vsf_sysutil_user_get_homedir(p_user));
  517. if (tunable_user_sub_token)
  518. {
  519. str_replace_text(p_userdir_str, tunable_user_sub_token,
  520. str_getbuf(p_orig_user_str));
  521. }
  522. }
  523. if (anon_login && tunable_anon_root)
  524. {
  525. str_alloc_text(p_chroot_str, tunable_anon_root);
  526. }
  527. else if (!anon_login && tunable_local_root)
  528. {
  529. str_alloc_text(p_chroot_str, tunable_local_root);
  530. if (tunable_user_sub_token)
  531. {
  532. str_replace_text(p_chroot_str, tunable_user_sub_token,
  533. str_getbuf(p_orig_user_str));
  534. }
  535. }
  536. /* If enabled, the chroot() location embedded in the HOMEDIR takes
  537. * precedence.
  538. */
  539. if (!anon_login && tunable_passwd_chroot_enable)
  540. {
  541. struct str_locate_result loc_result;
  542. loc_result = str_locate_text(p_userdir_str, "/./");
  543. if (loc_result.found)
  544. {
  545. str_split_text(p_userdir_str, p_chdir_str, "/./");
  546. str_copy(p_chroot_str, p_userdir_str);
  547. }
  548. }
  549. }