standalone.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. /*
  2. * Part of Very Secure FTPd
  3. * Licence: GPL v2
  4. * Author: Chris Evans
  5. * standalone.c
  6. *
  7. * Code to listen on the network and launch children servants.
  8. */
  9. #include "standalone.h"
  10. #include "parseconf.h"
  11. #include "tunables.h"
  12. #include "sysutil.h"
  13. #include "sysdeputil.h"
  14. #include "utility.h"
  15. #include "defs.h"
  16. #include "hash.h"
  17. #include "str.h"
  18. #include "ipaddrparse.h"
  19. static unsigned int s_children;
  20. static struct hash* s_p_ip_count_hash;
  21. static struct hash* s_p_pid_ip_hash;
  22. static unsigned int s_ipaddr_size;
  23. static void handle_sigchld(void* duff);
  24. static void handle_sighup(void* duff);
  25. static void prepare_child(int sockfd);
  26. static unsigned int handle_ip_count(void* p_raw_addr);
  27. static void drop_ip_count(void* p_raw_addr);
  28. static unsigned int hash_ip(unsigned int buckets, void* p_key);
  29. static unsigned int hash_pid(unsigned int buckets, void* p_key);
  30. struct vsf_client_launch
  31. vsf_standalone_main(void)
  32. {
  33. struct vsf_sysutil_sockaddr* p_accept_addr = 0;
  34. int listen_sock = -1;
  35. int retval;
  36. s_ipaddr_size = vsf_sysutil_get_ipaddr_size();
  37. if (tunable_listen && tunable_listen_ipv6)
  38. {
  39. die("run two copies of ftpz one for IPv4 and one for IPv6");
  40. }
  41. if (tunable_background)
  42. {
  43. int forkret = vsf_sysutil_fork();
  44. if (forkret > 0)
  45. {
  46. /* Parent, just exit */
  47. vsf_sysutil_exit(0);
  48. }
  49. /* Son, close standard FDs to avoid SSH hang-on-exit */
  50. vsf_sysutil_reopen_standard_fds();
  51. vsf_sysutil_make_session_leader();
  52. }
  53. if (tunable_listen)
  54. {
  55. listen_sock = vsf_sysutil_get_ipv4_sock();
  56. }
  57. else
  58. {
  59. listen_sock = vsf_sysutil_get_ipv6_sock();
  60. }
  61. vsf_sysutil_activate_reuseaddr(listen_sock);
  62. s_p_ip_count_hash = hash_alloc(256, s_ipaddr_size,
  63. sizeof(unsigned int), hash_ip);
  64. s_p_pid_ip_hash = hash_alloc(256, sizeof(int),
  65. s_ipaddr_size, hash_pid);
  66. if (tunable_setproctitle_enable)
  67. {
  68. vsf_sysutil_setproctitle("LISTENER");
  69. }
  70. vsf_sysutil_install_sighandler(kVSFSysUtilSigCHLD, handle_sigchld, 0, 1);
  71. vsf_sysutil_install_sighandler(kVSFSysUtilSigHUP, handle_sighup, 0, 1);
  72. if (tunable_listen)
  73. {
  74. struct vsf_sysutil_sockaddr* p_sockaddr = 0;
  75. vsf_sysutil_sockaddr_alloc_ipv4(&p_sockaddr);
  76. vsf_sysutil_sockaddr_set_port(p_sockaddr,
  77. (unsigned short) tunable_listen_port);
  78. if (!tunable_listen_address)
  79. {
  80. vsf_sysutil_sockaddr_set_any(p_sockaddr);
  81. }
  82. else
  83. {
  84. if (!vsf_sysutil_inet_aton(tunable_listen_address, p_sockaddr))
  85. {
  86. die2("bad listen_address: ", tunable_listen_address);
  87. }
  88. }
  89. retval = vsf_sysutil_bind(listen_sock, p_sockaddr);
  90. vsf_sysutil_free(p_sockaddr);
  91. if (vsf_sysutil_retval_is_error(retval))
  92. {
  93. die("could not bind listening IP socket");
  94. }
  95. }
  96. else
  97. {
  98. struct vsf_sysutil_sockaddr* p_sockaddr = 0;
  99. vsf_sysutil_sockaddr_alloc_ipv6(&p_sockaddr);
  100. vsf_sysutil_sockaddr_set_port(p_sockaddr,
  101. (unsigned short) tunable_listen_port);
  102. if (!tunable_listen_address6)
  103. {
  104. vsf_sysutil_sockaddr_set_any(p_sockaddr);
  105. }
  106. else
  107. {
  108. struct mystr addr_str = INIT_MYSTR;
  109. const unsigned char* p_raw_addr;
  110. str_alloc_text(&addr_str, tunable_listen_address6);
  111. p_raw_addr = vsf_sysutil_parse_ipv6(&addr_str);
  112. str_free(&addr_str);
  113. if (!p_raw_addr)
  114. {
  115. die2("bad listen_address6: ", tunable_listen_address6);
  116. }
  117. vsf_sysutil_sockaddr_set_ipv6addr(p_sockaddr, p_raw_addr);
  118. }
  119. retval = vsf_sysutil_bind(listen_sock, p_sockaddr);
  120. vsf_sysutil_free(p_sockaddr);
  121. if (vsf_sysutil_retval_is_error(retval))
  122. {
  123. die("could not bind listening IP6 socket");
  124. }
  125. }
  126. retval = vsf_sysutil_listen(listen_sock, VSFTP_LISTEN_BACKLOG);
  127. if (vsf_sysutil_retval_is_error(retval))
  128. {
  129. die("could not listen");
  130. }
  131. vsf_sysutil_sockaddr_alloc(&p_accept_addr);
  132. while (1)
  133. {
  134. struct vsf_client_launch child_info;
  135. void* p_raw_addr;
  136. int new_child;
  137. int new_client_sock;
  138. new_client_sock = vsf_sysutil_accept_timeout(
  139. listen_sock, p_accept_addr, 0);
  140. if (vsf_sysutil_retval_is_error(new_client_sock))
  141. {
  142. continue;
  143. }
  144. ++s_children;
  145. child_info.num_children = s_children;
  146. child_info.num_this_ip = 0;
  147. p_raw_addr = vsf_sysutil_sockaddr_get_raw_addr(p_accept_addr);
  148. child_info.num_this_ip = handle_ip_count(p_raw_addr);
  149. if (tunable_isolate)
  150. {
  151. if (tunable_http_enable && tunable_isolate_network)
  152. {
  153. new_child = vsf_sysutil_fork_isolate_all_failok();
  154. }
  155. else
  156. {
  157. new_child = vsf_sysutil_fork_isolate_failok();
  158. }
  159. }
  160. else
  161. {
  162. new_child = vsf_sysutil_fork_failok();
  163. }
  164. if (new_child != 0)
  165. {
  166. /* Parent context */
  167. vsf_sysutil_close(new_client_sock);
  168. if (new_child > 0)
  169. {
  170. hash_add_entry(s_p_pid_ip_hash, (void*)&new_child, p_raw_addr);
  171. }
  172. else
  173. {
  174. /* fork() failed, clear up! */
  175. --s_children;
  176. drop_ip_count(p_raw_addr);
  177. }
  178. /* Fall through to while() loop and accept() again */
  179. }
  180. else
  181. {
  182. /* Child context */
  183. vsf_set_die_if_parent_dies();
  184. vsf_sysutil_close(listen_sock);
  185. prepare_child(new_client_sock);
  186. /* By returning here we "launch" the child process with the same
  187. * contract as xinetd would provide.
  188. */
  189. return child_info;
  190. }
  191. }
  192. }
  193. static void
  194. prepare_child(int new_client_sock)
  195. {
  196. /* We must satisfy the contract: command socket on fd 0, 1, 2 */
  197. vsf_sysutil_dupfd2(new_client_sock, 0);
  198. vsf_sysutil_dupfd2(new_client_sock, 1);
  199. vsf_sysutil_dupfd2(new_client_sock, 2);
  200. if (new_client_sock > 2)
  201. {
  202. vsf_sysutil_close(new_client_sock);
  203. }
  204. }
  205. static void
  206. drop_ip_count(void* p_raw_addr)
  207. {
  208. unsigned int count;
  209. unsigned int* p_count =
  210. (unsigned int*)hash_lookup_entry(s_p_ip_count_hash, p_raw_addr);
  211. if (!p_count)
  212. {
  213. bug("IP address missing from hash");
  214. }
  215. count = *p_count;
  216. if (!count)
  217. {
  218. bug("zero count for IP address");
  219. }
  220. count--;
  221. *p_count = count;
  222. if (!count)
  223. {
  224. hash_free_entry(s_p_ip_count_hash, p_raw_addr);
  225. }
  226. }
  227. static void
  228. handle_sigchld(void* duff)
  229. {
  230. unsigned int reap_one = 1;
  231. (void) duff;
  232. while (reap_one)
  233. {
  234. reap_one = (unsigned int)vsf_sysutil_wait_reap_one();
  235. if (reap_one)
  236. {
  237. struct vsf_sysutil_ipaddr* p_ip;
  238. /* Account total number of instances */
  239. --s_children;
  240. /* Account per-IP limit */
  241. p_ip = (struct vsf_sysutil_ipaddr*)
  242. hash_lookup_entry(s_p_pid_ip_hash, (void*)&reap_one);
  243. drop_ip_count(p_ip);
  244. hash_free_entry(s_p_pid_ip_hash, (void*)&reap_one);
  245. }
  246. }
  247. }
  248. static void
  249. handle_sighup(void* duff)
  250. {
  251. (void) duff;
  252. /* We don't crash the out the listener if an invalid config was added */
  253. tunables_load_defaults();
  254. vsf_parseconf_load_file(0, 0);
  255. }
  256. static unsigned int
  257. hash_ip(unsigned int buckets, void* p_key)
  258. {
  259. const unsigned char* p_raw_ip = (const unsigned char*)p_key;
  260. unsigned int val = 0;
  261. int shift = 24;
  262. unsigned int i;
  263. for (i = 0; i < s_ipaddr_size; ++i)
  264. {
  265. val = val ^ (unsigned int) (p_raw_ip[i] << shift);
  266. shift -= 8;
  267. if (shift < 0)
  268. {
  269. shift = 24;
  270. }
  271. }
  272. return val % buckets;
  273. }
  274. static unsigned int
  275. hash_pid(unsigned int buckets, void* p_key)
  276. {
  277. unsigned int* p_pid = (unsigned int*)p_key;
  278. return (*p_pid) % buckets;
  279. }
  280. static unsigned int
  281. handle_ip_count(void* p_ipaddr)
  282. {
  283. unsigned int* p_count =
  284. (unsigned int*)hash_lookup_entry(s_p_ip_count_hash, p_ipaddr);
  285. unsigned int count;
  286. if (!p_count)
  287. {
  288. count = 1;
  289. hash_add_entry(s_p_ip_count_hash, p_ipaddr, (void*)&count);
  290. }
  291. else
  292. {
  293. count = *p_count;
  294. count++;
  295. *p_count = count;
  296. }
  297. return count;
  298. }