2 * Part of Very Secure FTPd
7 * Code to listen on the network and launch children servants.
10 #include "standalone.h"
12 #include "parseconf.h"
15 #include "sysdeputil.h"
20 #include "ipaddrparse.h"
22 static unsigned int s_children
;
23 static struct hash
* s_p_ip_count_hash
;
24 static struct hash
* s_p_pid_ip_hash
;
25 static unsigned int s_ipaddr_size
;
27 static void handle_sigchld(void* duff
);
28 static void handle_sighup(void* duff
);
29 static void prepare_child(int sockfd
);
30 static unsigned int handle_ip_count(void* p_raw_addr
);
31 static void drop_ip_count(void* p_raw_addr
);
33 static unsigned int hash_ip(unsigned int buckets
, void* p_key
);
34 static unsigned int hash_pid(unsigned int buckets
, void* p_key
);
36 struct vsf_client_launch
37 vsf_standalone_main(void)
39 struct vsf_sysutil_sockaddr
* p_accept_addr
= 0;
42 s_ipaddr_size
= vsf_sysutil_get_ipaddr_size();
43 if (tunable_listen
&& tunable_listen_ipv6
)
45 die("run two copies of vsftpd for IPv4 and IPv6");
47 if (tunable_background
)
49 int forkret
= vsf_sysutil_fork();
52 /* Parent, just exit */
55 /* Son, close standard FDs to avoid SSH hang-on-exit */
56 vsf_sysutil_reopen_standard_fds();
57 vsf_sysutil_make_session_leader();
61 listen_sock
= vsf_sysutil_get_ipv4_sock();
65 listen_sock
= vsf_sysutil_get_ipv6_sock();
67 vsf_sysutil_activate_reuseaddr(listen_sock
);
69 s_p_ip_count_hash
= hash_alloc(256, s_ipaddr_size
,
70 sizeof(unsigned int), hash_ip
);
71 s_p_pid_ip_hash
= hash_alloc(256, sizeof(int),
72 s_ipaddr_size
, hash_pid
);
73 if (tunable_setproctitle_enable
)
75 vsf_sysutil_setproctitle("LISTENER");
77 vsf_sysutil_install_sighandler(kVSFSysUtilSigCHLD
, handle_sigchld
, 0, 1);
78 vsf_sysutil_install_sighandler(kVSFSysUtilSigHUP
, handle_sighup
, 0, 1);
81 struct vsf_sysutil_sockaddr
* p_sockaddr
= 0;
82 vsf_sysutil_sockaddr_alloc_ipv4(&p_sockaddr
);
83 vsf_sysutil_sockaddr_set_port(p_sockaddr
,
84 (unsigned short) tunable_listen_port
);
85 if (!tunable_listen_address
)
87 vsf_sysutil_sockaddr_set_any(p_sockaddr
);
91 if (!vsf_sysutil_inet_aton(tunable_listen_address
, p_sockaddr
))
93 die2("bad listen_address: ", tunable_listen_address
);
96 retval
= vsf_sysutil_bind(listen_sock
, p_sockaddr
);
97 vsf_sysutil_free(p_sockaddr
);
98 if (vsf_sysutil_retval_is_error(retval
))
100 die("could not bind listening IPv4 socket");
105 struct vsf_sysutil_sockaddr
* p_sockaddr
= 0;
106 vsf_sysutil_sockaddr_alloc_ipv6(&p_sockaddr
);
107 vsf_sysutil_sockaddr_set_port(p_sockaddr
,
108 (unsigned short) tunable_listen_port
);
109 if (!tunable_listen_address6
)
111 vsf_sysutil_sockaddr_set_any(p_sockaddr
);
115 struct mystr addr_str
= INIT_MYSTR
;
116 const unsigned char* p_raw_addr
;
117 str_alloc_text(&addr_str
, tunable_listen_address6
);
118 p_raw_addr
= vsf_sysutil_parse_ipv6(&addr_str
);
122 die2("bad listen_address6: ", tunable_listen_address6
);
124 vsf_sysutil_sockaddr_set_ipv6addr(p_sockaddr
, p_raw_addr
);
126 retval
= vsf_sysutil_bind(listen_sock
, p_sockaddr
);
127 vsf_sysutil_free(p_sockaddr
);
128 if (vsf_sysutil_retval_is_error(retval
))
130 die("could not bind listening IPv6 socket");
133 retval
= vsf_sysutil_listen(listen_sock
, VSFTP_LISTEN_BACKLOG
);
134 if (vsf_sysutil_retval_is_error(retval
))
136 die("could not listen");
138 vsf_sysutil_sockaddr_alloc(&p_accept_addr
);
141 struct vsf_client_launch child_info
;
145 new_client_sock
= vsf_sysutil_accept_timeout(
146 listen_sock
, p_accept_addr
, 0);
147 if (vsf_sysutil_retval_is_error(new_client_sock
))
152 child_info
.num_children
= s_children
;
153 child_info
.num_this_ip
= 0;
154 p_raw_addr
= vsf_sysutil_sockaddr_get_raw_addr(p_accept_addr
);
155 child_info
.num_this_ip
= handle_ip_count(p_raw_addr
);
158 if (tunable_http_enable
&& tunable_isolate_network
)
160 new_child
= vsf_sysutil_fork_isolate_all_failok();
164 new_child
= vsf_sysutil_fork_isolate_failok();
169 new_child
= vsf_sysutil_fork_failok();
174 vsf_sysutil_close(new_client_sock
);
177 hash_add_entry(s_p_pid_ip_hash
, (void*)&new_child
, p_raw_addr
);
181 /* fork() failed, clear up! */
183 drop_ip_count(p_raw_addr
);
185 /* Fall through to while() loop and accept() again */
190 vsf_set_die_if_parent_dies();
191 vsf_sysutil_close(listen_sock
);
192 prepare_child(new_client_sock
);
193 /* By returning here we "launch" the child process with the same
194 * contract as xinetd would provide.
202 prepare_child(int new_client_sock
)
204 /* We must satisfy the contract: command socket on fd 0, 1, 2 */
205 vsf_sysutil_dupfd2(new_client_sock
, 0);
206 vsf_sysutil_dupfd2(new_client_sock
, 1);
207 vsf_sysutil_dupfd2(new_client_sock
, 2);
208 if (new_client_sock
> 2)
210 vsf_sysutil_close(new_client_sock
);
215 drop_ip_count(void* p_raw_addr
)
218 unsigned int* p_count
=
219 (unsigned int*)hash_lookup_entry(s_p_ip_count_hash
, p_raw_addr
);
222 bug("IP address missing from hash");
227 bug("zero count for IP address");
233 hash_free_entry(s_p_ip_count_hash
, p_raw_addr
);
238 handle_sigchld(void* duff
)
240 unsigned int reap_one
= 1;
244 reap_one
= (unsigned int)vsf_sysutil_wait_reap_one();
247 struct vsf_sysutil_ipaddr
* p_ip
;
248 /* Account total number of instances */
250 /* Account per-IP limit */
251 p_ip
= (struct vsf_sysutil_ipaddr
*)
252 hash_lookup_entry(s_p_pid_ip_hash
, (void*)&reap_one
);
254 hash_free_entry(s_p_pid_ip_hash
, (void*)&reap_one
);
260 handle_sighup(void* duff
)
263 /* We don't crash the out the listener if an invalid config was added */
264 tunables_load_defaults();
265 vsf_parseconf_load_file(0, 0);
269 hash_ip(unsigned int buckets
, void* p_key
)
271 const unsigned char* p_raw_ip
= (const unsigned char*)p_key
;
272 unsigned int val
= 0;
275 for (i
= 0; i
< s_ipaddr_size
; ++i
)
277 val
= val
^ (unsigned int) (p_raw_ip
[i
] << shift
);
284 return val
% buckets
;
288 hash_pid(unsigned int buckets
, void* p_key
)
290 unsigned int* p_pid
= (unsigned int*)p_key
;
291 return (*p_pid
) % buckets
;
295 handle_ip_count(void* p_ipaddr
)
297 unsigned int* p_count
=
298 (unsigned int*)hash_lookup_entry(s_p_ip_count_hash
, p_ipaddr
);
303 hash_add_entry(s_p_ip_count_hash
, p_ipaddr
, (void*)&count
);