vsftpd 2.0.7 - initial checkin.
[tomato.git] / release / src / router / vsftpd / main.c
blob93c67d4203cb5d3b8108c81fa779dde2549079d9
1 /*
2 * Part of Very Secure FTPd
3 * Licence: GPL v2
4 * Author: Chris Evans
5 * main.c
6 */
8 #include "session.h"
9 #include "utility.h"
10 #include "tunables.h"
11 #include "logging.h"
12 #include "str.h"
13 #include "filestr.h"
14 #include "ftpcmdio.h"
15 #include "sysutil.h"
16 #include "sysdeputil.h"
17 #include "defs.h"
18 #include "parseconf.h"
19 #include "oneprocess.h"
20 #include "twoprocess.h"
21 #include "standalone.h"
22 #include "tcpwrap.h"
23 #include "vsftpver.h"
24 #include "ssl.h"
27 * Forward decls of helper functions
29 static void die_unless_privileged(void);
30 static void do_sanity_checks(void);
31 static void session_init(struct vsf_session* p_sess);
32 static void env_init(void);
34 int
35 main(int argc, const char* argv[])
37 struct vsf_session the_session =
39 /* Control connection */
40 0, 0, 0,
41 /* Data connection */
42 -1, 0, -1, 0, 0, 0, 0,
43 /* Login */
44 1, 0, INIT_MYSTR, INIT_MYSTR,
45 /* Protocol state */
46 0, 1, INIT_MYSTR, 0, 0,
47 /* Session state */
49 /* Userids */
50 -1, -1, -1,
51 /* Pre-chroot() cache */
52 INIT_MYSTR, INIT_MYSTR, INIT_MYSTR, INIT_MYSTR, 1,
53 /* Logging */
54 -1, -1, INIT_MYSTR, 0, 0, 0, INIT_MYSTR, 0,
55 /* Buffers */
56 INIT_MYSTR, INIT_MYSTR,
57 /* Parent <-> child comms */
58 -1, -1,
59 /* Number of clients */
60 0, 0,
61 /* Home directory */
62 INIT_MYSTR,
63 /* Secure connection state */
64 0, 0, 0, 0, 0, INIT_MYSTR, 0, -1, -1,
65 /* Login fails */
68 int config_specified = 0;
69 const char* p_config_name = VSFTP_DEFAULT_CONFIG;
70 /* Zero or one argument supported. If one argument is passed, it is the
71 * path to the config file
73 if (argc > 2)
75 die("vsftpd: too many arguments (I take an optional config file only)");
77 else if (argc == 0)
79 die("vsftpd: missing argv[0]");
81 if (argc == 2)
83 if (!vsf_sysutil_strcmp(argv[1], "-v"))
85 vsf_exit("vsftpd: version " VSF_VERSION "\n");
87 p_config_name = argv[1];
88 config_specified = 1;
90 /* This might need to open /dev/zero on systems lacking MAP_ANON. Needs
91 * to be done early (i.e. before config file parse, which may use
92 * anonymous pages
94 vsf_sysutil_map_anon_pages_init();
95 /* Parse config file if it's there */
97 struct vsf_sysutil_statbuf* p_statbuf = 0;
98 int retval = vsf_sysutil_stat(p_config_name, &p_statbuf);
99 if (!vsf_sysutil_retval_is_error(retval))
101 vsf_parseconf_load_file(p_config_name, 1);
103 else if (config_specified)
105 die2("vsftpd: cannot open config file:", p_config_name);
107 vsf_sysutil_free(p_statbuf);
109 /* Resolve pasv_address if required */
110 if (tunable_pasv_address && tunable_pasv_addr_resolve)
112 struct vsf_sysutil_sockaddr* p_addr = 0;
113 const char* p_numeric_addr;
114 vsf_sysutil_dns_resolve(&p_addr, tunable_pasv_address);
115 vsf_sysutil_free((char*) tunable_pasv_address);
116 p_numeric_addr = vsf_sysutil_inet_ntop(p_addr);
117 tunable_pasv_address = vsf_sysutil_strdup(p_numeric_addr);
118 vsf_sysutil_free(p_addr);
120 if (!tunable_run_as_launching_user)
122 /* Just get out unless we start with requisite privilege */
123 die_unless_privileged();
125 if (tunable_setproctitle_enable)
127 /* Warning -- warning -- may nuke argv, environ */
128 vsf_sysutil_setproctitle_init(argc, argv);
130 /* Initialize the SSL system here if needed - saves the overhead of each
131 * child doing this itself.
133 if (tunable_ssl_enable)
135 ssl_init(&the_session);
137 if (tunable_listen || tunable_listen_ipv6)
139 /* Standalone mode */
140 struct vsf_client_launch ret = vsf_standalone_main();
141 the_session.num_clients = ret.num_children;
142 the_session.num_this_ip = ret.num_this_ip;
144 if (tunable_tcp_wrappers)
146 the_session.tcp_wrapper_ok = vsf_tcp_wrapper_ok(VSFTP_COMMAND_FD);
149 const char* p_load_conf = vsf_sysutil_getenv("VSFTPD_LOAD_CONF");
150 if (p_load_conf)
152 vsf_parseconf_load_file(p_load_conf, 1);
155 /* Sanity checks - exit with a graceful error message if our STDIN is not
156 * a socket. Also check various config options don't collide.
158 do_sanity_checks();
159 /* Initializes session globals - e.g. IP addr's etc. */
160 session_init(&the_session);
161 /* Set up "environment", e.g. process group etc. */
162 env_init();
163 /* Set up logging - must come after global init because we need the remote
164 * address to convert into text
166 vsf_log_init(&the_session);
167 str_alloc_text(&the_session.remote_ip_str,
168 vsf_sysutil_inet_ntop(the_session.p_remote_addr));
169 /* Set up options on the command socket */
170 vsf_cmdio_sock_setup();
171 if (tunable_setproctitle_enable)
173 vsf_sysutil_set_proctitle_prefix(&the_session.remote_ip_str);
174 vsf_sysutil_setproctitle("connected");
176 /* We might chroot() very soon (one process model), so we need to open
177 * any required config files here.
179 /* SSL may have been enabled by a per-IP configuration.. */
180 if (tunable_ssl_enable)
182 ssl_init(&the_session);
184 if (tunable_deny_email_enable)
186 int retval = str_fileread(&the_session.banned_email_str,
187 tunable_banned_email_file, VSFTP_CONF_FILE_MAX);
188 if (vsf_sysutil_retval_is_error(retval))
190 die2("cannot open anon e-mail list file:", tunable_banned_email_file);
193 if (tunable_banner_file)
195 int retval = str_fileread(&the_session.banner_str, tunable_banner_file,
196 VSFTP_CONF_FILE_MAX);
197 if (vsf_sysutil_retval_is_error(retval))
199 die2("cannot open banner file:", tunable_banner_file);
202 if (tunable_secure_email_list_enable)
204 int retval = str_fileread(&the_session.email_passwords_str,
205 tunable_email_password_file,
206 VSFTP_CONF_FILE_MAX);
207 if (vsf_sysutil_retval_is_error(retval))
209 die2("cannot open email passwords file:", tunable_email_password_file);
212 /* Special case - can force one process model if we've got a setup
213 * needing _no_ privs
215 if (!tunable_local_enable && !tunable_connect_from_port_20 &&
216 !tunable_chown_uploads)
218 tunable_one_process_model = 1;
220 if (tunable_run_as_launching_user)
222 tunable_one_process_model = 1;
223 if (!vsf_sysutil_running_as_root())
225 tunable_connect_from_port_20 = 0;
226 tunable_chown_uploads = 0;
229 if (tunable_one_process_model)
231 vsf_one_process_start(&the_session);
233 else
235 vsf_two_process_start(&the_session);
237 /* NOTREACHED */
238 bug("should not get here: main");
239 return 1;
242 static void
243 die_unless_privileged(void)
245 if (!vsf_sysutil_running_as_root())
247 die("vsftpd: must be started as root (see run_as_launching_user option)");
251 static void
252 do_sanity_checks(void)
255 struct vsf_sysutil_statbuf* p_statbuf = 0;
256 vsf_sysutil_fstat(VSFTP_COMMAND_FD, &p_statbuf);
257 if (!vsf_sysutil_statbuf_is_socket(p_statbuf))
259 die("vsftpd: not configured for standalone, must be started from inetd");
261 vsf_sysutil_free(p_statbuf);
263 if (tunable_one_process_model)
265 if (tunable_local_enable)
267 die("vsftpd: security: 'one_process_model' is anonymous only");
269 if (!vsf_sysdep_has_capabilities_as_non_root())
271 die("vsftpd: security: 'one_process_model' needs a better OS");
273 if (tunable_ssl_enable)
275 die("vsftpd: SSL mode not compatible with 'one_process_model'");
278 if (!tunable_local_enable && !tunable_anonymous_enable)
280 die("vsftpd: both local and anonymous access disabled!");
284 static void
285 env_init(void)
287 vsf_sysutil_make_session_leader();
288 /* Set up a secure umask - we'll set the proper one after login */
289 vsf_sysutil_set_umask(VSFTP_SECURE_UMASK);
290 /* Fire up libc's timezone initialisation, before we chroot()! */
291 vsf_sysutil_tzset();
292 /* Signals. We'll always take -EPIPE rather than a rude signal, thanks */
293 vsf_sysutil_install_null_sighandler(kVSFSysUtilSigPIPE);
296 static void
297 session_init(struct vsf_session* p_sess)
299 /* Get the addresses of the control connection */
300 vsf_sysutil_getpeername(VSFTP_COMMAND_FD, &p_sess->p_remote_addr);
301 vsf_sysutil_getsockname(VSFTP_COMMAND_FD, &p_sess->p_local_addr);
302 /* If anonymous mode is active, fetch the uid of the anonymous user */
303 if (tunable_anonymous_enable)
305 const struct vsf_sysutil_user* p_user =
306 vsf_sysutil_getpwnam(tunable_ftp_username);
307 if (p_user == 0)
309 die2("vsftpd: cannot locate user specified in 'ftp_username':",
310 tunable_ftp_username);
312 p_sess->anon_ftp_uid = vsf_sysutil_user_getuid(p_user);
314 if (tunable_guest_enable)
316 const struct vsf_sysutil_user* p_user =
317 vsf_sysutil_getpwnam(tunable_guest_username);
318 if (p_user == 0)
320 die2("vsftpd: cannot locate user specified in 'guest_username':",
321 tunable_guest_username);
323 p_sess->guest_user_uid = vsf_sysutil_user_getuid(p_user);
325 if (tunable_chown_uploads)
327 const struct vsf_sysutil_user* p_user =
328 vsf_sysutil_getpwnam(tunable_chown_username);
329 if (p_user == 0)
331 die2("vsftpd: cannot locate user specified in 'chown_username':",
332 tunable_chown_username);
334 p_sess->anon_upload_chown_uid = vsf_sysutil_user_getuid(p_user);