vsftpd 3.0.2
[tomato/tomato-dir865l.git] / release / src / router / vsftpd / main.c
blobeaba265930d98fb207f0bb14e0bfcdebdfee15cf
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);
33 static void limits_init(void);
35 int
36 main(int argc, const char* argv[])
38 struct vsf_session the_session =
40 /* Control connection */
41 0, 0, 0, 0, 0,
42 /* Data connection */
43 -1, 0, -1, 0, 0, 0, 0,
44 /* Login */
45 1, 0, INIT_MYSTR, INIT_MYSTR,
46 /* Protocol state */
47 0, 1, INIT_MYSTR, 0, 0,
48 /* HTTP hacks */
49 0, INIT_MYSTR,
50 /* Session state */
52 /* Userids */
53 -1, -1, -1,
54 /* Pre-chroot() cache */
55 INIT_MYSTR, INIT_MYSTR, INIT_MYSTR, INIT_MYSTR, 1,
56 /* Logging */
57 -1, -1, INIT_MYSTR, 0, 0, 0, INIT_MYSTR, 0,
58 /* Buffers */
59 INIT_MYSTR, INIT_MYSTR,
60 /* Parent <-> child comms */
61 -1, -1,
62 /* Number of clients */
63 0, 0,
64 /* Home directory */
65 INIT_MYSTR,
66 /* Secure connection state */
67 0, 0, 0, 0, 0, INIT_MYSTR, 0, -1, -1,
68 /* Login fails */
71 int config_loaded = 0;
72 int i;
73 tunables_load_defaults();
74 /* This might need to open /dev/zero on systems lacking MAP_ANON. Needs
75 * to be done early (i.e. before config file parse, which may use
76 * anonymous pages
78 vsf_sysutil_map_anon_pages_init();
79 /* Argument parsing. Any argument not starting with "-" is a config file,
80 * loaded in the order encountered. -o opt=value options are loading in the
81 * order encountered, including correct ordering with respect intermingled
82 * config files.
83 * If we see -v (version) or an unknown option, parsing bails and exits.
85 if (argc == 0)
87 die("vsftpd: missing argv[0]");
89 for (i = 1; i < argc; ++i)
91 const char* p_arg = argv[i];
92 if (p_arg[0] != '-')
94 config_loaded = 1;
95 vsf_parseconf_load_file(p_arg, 1);
97 else
99 if (p_arg[1] == 'v')
101 vsf_exit("vsftpd: version " VSF_VERSION "\n");
103 else if (p_arg[1] == 'o')
105 vsf_parseconf_load_setting(&p_arg[2], 1);
107 else
109 die2("unrecognise option: ", p_arg);
113 /* Parse default config file if necessary */
114 if (!config_loaded) {
115 struct vsf_sysutil_statbuf* p_statbuf = 0;
116 int retval = vsf_sysutil_stat(VSFTP_DEFAULT_CONFIG, &p_statbuf);
117 if (!vsf_sysutil_retval_is_error(retval))
119 vsf_parseconf_load_file(VSFTP_DEFAULT_CONFIG, 1);
121 vsf_sysutil_free(p_statbuf);
123 /* Resolve pasv_address if required */
124 if (tunable_pasv_address && tunable_pasv_addr_resolve)
126 struct vsf_sysutil_sockaddr* p_addr = 0;
127 const char* p_numeric_addr;
128 vsf_sysutil_dns_resolve(&p_addr, tunable_pasv_address);
129 vsf_sysutil_free((char*) tunable_pasv_address);
130 p_numeric_addr = vsf_sysutil_inet_ntop(p_addr);
131 tunable_pasv_address = vsf_sysutil_strdup(p_numeric_addr);
132 vsf_sysutil_free(p_addr);
134 if (!tunable_run_as_launching_user)
136 /* Just get out unless we start with requisite privilege */
137 die_unless_privileged();
139 if (tunable_setproctitle_enable)
141 /* Warning -- warning -- may nuke argv, environ */
142 vsf_sysutil_setproctitle_init(argc, argv);
144 /* Initialize the SSL system here if needed - saves the overhead of each
145 * child doing this itself.
147 if (tunable_ssl_enable)
149 ssl_init(&the_session);
151 if (tunable_listen || tunable_listen_ipv6)
153 /* Standalone mode */
154 struct vsf_client_launch ret = vsf_standalone_main();
155 the_session.num_clients = ret.num_children;
156 the_session.num_this_ip = ret.num_this_ip;
158 if (tunable_tcp_wrappers)
160 the_session.tcp_wrapper_ok = vsf_tcp_wrapper_ok(VSFTP_COMMAND_FD);
163 const char* p_load_conf = vsf_sysutil_getenv("VSFTPD_LOAD_CONF");
164 if (p_load_conf)
166 vsf_parseconf_load_file(p_load_conf, 1);
169 /* Sanity checks - exit with a graceful error message if our STDIN is not
170 * a socket. Also check various config options don't collide.
172 do_sanity_checks();
173 /* Initializes session globals - e.g. IP addr's etc. */
174 session_init(&the_session);
175 /* Set up "environment", e.g. process group etc. */
176 env_init();
177 /* Set up resource limits. */
178 limits_init();
179 /* Set up logging - must come after global init because we need the remote
180 * address to convert into text
182 vsf_log_init(&the_session);
183 str_alloc_text(&the_session.remote_ip_str,
184 vsf_sysutil_inet_ntop(the_session.p_remote_addr));
185 /* Set up options on the command socket */
186 vsf_cmdio_sock_setup();
187 if (tunable_setproctitle_enable)
189 vsf_sysutil_set_proctitle_prefix(&the_session.remote_ip_str);
190 vsf_sysutil_setproctitle("connected");
192 /* We might chroot() very soon (one process model), so we need to open
193 * any required config files here.
195 /* SSL may have been enabled by a per-IP configuration.. */
196 if (tunable_ssl_enable)
198 ssl_init(&the_session);
199 ssl_add_entropy(&the_session);
201 if (tunable_deny_email_enable)
203 int retval = -1;
204 if (tunable_banned_email_file)
206 retval = str_fileread(&the_session.banned_email_str,
207 tunable_banned_email_file, VSFTP_CONF_FILE_MAX);
209 if (vsf_sysutil_retval_is_error(retval))
211 die2("cannot read anon e-mail list file:", tunable_banned_email_file);
214 if (tunable_banner_file)
216 int retval = str_fileread(&the_session.banner_str, tunable_banner_file,
217 VSFTP_CONF_FILE_MAX);
218 if (vsf_sysutil_retval_is_error(retval))
220 die2("cannot read banner file:", tunable_banner_file);
223 if (tunable_secure_email_list_enable)
225 int retval = -1;
226 if (tunable_email_password_file)
228 retval = str_fileread(&the_session.email_passwords_str,
229 tunable_email_password_file,
230 VSFTP_CONF_FILE_MAX);
232 if (vsf_sysutil_retval_is_error(retval))
234 die2("cannot read email passwords file:", tunable_email_password_file);
237 if (tunable_run_as_launching_user)
239 tunable_one_process_model = 1;
240 if (!vsf_sysutil_running_as_root())
242 tunable_connect_from_port_20 = 0;
243 tunable_chown_uploads = 0;
246 if (tunable_one_process_model)
248 vsf_one_process_start(&the_session);
250 else
252 vsf_two_process_start(&the_session);
254 /* NOTREACHED */
255 bug("should not get here: main");
256 return 1;
259 static void
260 die_unless_privileged(void)
262 if (!vsf_sysutil_running_as_root())
264 die("vsftpd: must be started as root (see run_as_launching_user option)");
268 static void
269 do_sanity_checks(void)
272 struct vsf_sysutil_statbuf* p_statbuf = 0;
273 vsf_sysutil_fstat(VSFTP_COMMAND_FD, &p_statbuf);
274 if (!vsf_sysutil_statbuf_is_socket(p_statbuf))
276 die("vsftpd: not configured for standalone, must be started from inetd");
278 vsf_sysutil_free(p_statbuf);
280 if (tunable_one_process_model)
282 if (tunable_local_enable)
284 die("vsftpd: security: 'one_process_model' is anonymous only");
286 if (!vsf_sysdep_has_capabilities_as_non_root())
288 die("vsftpd: security: 'one_process_model' needs a better OS");
291 if (!tunable_local_enable && !tunable_anonymous_enable)
293 die("vsftpd: both local and anonymous access disabled!");
295 if (!tunable_ftp_enable && !tunable_http_enable)
297 die("vsftpd: both FTP and HTTP disabled!");
299 if (tunable_http_enable && !tunable_one_process_model)
301 die("vsftpd: HTTP needs 'one_process_model' for now");
305 static void
306 env_init(void)
308 vsf_sysutil_make_session_leader();
309 /* Set up a secure umask - we'll set the proper one after login */
310 vsf_sysutil_set_umask(VSFTP_SECURE_UMASK);
311 /* Fire up libc's timezone initialisation, before we chroot()! */
312 vsf_sysutil_tzset();
313 /* Signals. We'll always take -EPIPE rather than a rude signal, thanks */
314 vsf_sysutil_install_null_sighandler(kVSFSysUtilSigPIPE);
317 static void
318 limits_init(void)
320 unsigned long limit = VSFTP_AS_LIMIT;
321 if (tunable_text_userdb_names)
323 /* Turns out, LDAP lookups for lots of userid -> name mappings can really
324 * bloat memory usage.
326 limit *= 3;
328 vsf_sysutil_set_address_space_limit(limit);
331 static void
332 session_init(struct vsf_session* p_sess)
334 /* Get the addresses of the control connection */
335 vsf_sysutil_getpeername(VSFTP_COMMAND_FD, &p_sess->p_remote_addr);
336 vsf_sysutil_getsockname(VSFTP_COMMAND_FD, &p_sess->p_local_addr);
337 /* If anonymous mode is active, fetch the uid of the anonymous user */
338 if (tunable_anonymous_enable)
340 const struct vsf_sysutil_user* p_user = 0;
341 if (tunable_ftp_username)
343 p_user = vsf_sysutil_getpwnam(tunable_ftp_username);
345 if (p_user == 0)
347 die2("vsftpd: cannot locate user specified in 'ftp_username':",
348 tunable_ftp_username);
350 p_sess->anon_ftp_uid = vsf_sysutil_user_getuid(p_user);
352 if (tunable_guest_enable)
354 const struct vsf_sysutil_user* p_user = 0;
355 if (tunable_guest_username)
357 p_user = vsf_sysutil_getpwnam(tunable_guest_username);
359 if (p_user == 0)
361 die2("vsftpd: cannot locate user specified in 'guest_username':",
362 tunable_guest_username);
364 p_sess->guest_user_uid = vsf_sysutil_user_getuid(p_user);
366 if (tunable_chown_uploads)
368 const struct vsf_sysutil_user* p_user = 0;
369 if (tunable_chown_username)
371 p_user = vsf_sysutil_getpwnam(tunable_chown_username);
373 if (p_user == 0)
375 die2("vsftpd: cannot locate user specified in 'chown_username':",
376 tunable_chown_username);
378 p_sess->anon_upload_chown_uid = vsf_sysutil_user_getuid(p_user);