1 /*
2 * Part of Very Secure FTPd
3 * Licence: GPL v2
4 * Author: Chris Evans
5 * main.c
6 */
7
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"
25 #include "charconv.h"
26 #include "pasvrules.h"
27 #include "usersip.h"
28 #include "http_msg.h"
29
30 /*
31 * Forward decls of helper functions
32 */
33 static void die_unless_privileged(void);
34 static void do_sanity_checks(void);
35 static void session_init(struct vsf_session* p_sess);
36 static void env_init(void);
37 static void limits_init(void);
38
39 int
main(int argc,const char * argv[])40 main(int argc, const char* argv[])
41 {
42 struct vsf_session the_session =
43 {
44 /* Control connection */
45 0, 0, 0, 0, 0,
46 /* Data connection */
47 -1, 0, -1, 0, 0, 0, 0, 0, 0,
48 /* Login */
49 1, 0, INIT_MYSTR, INIT_MYSTR,
50 /* Protocol state */
51 0, 1, INIT_MYSTR, 0, 0, 0, 0,
52 /* HTTP hacks */
53 0, INIT_MYSTR,
54 /* Session state */
55 0,
56 /* Userids */
57 -1, -1, -1, -1,
58 /* Pre-chroot() cache */
59 INIT_MYSTR, INIT_MYSTR, INIT_MYSTR, INIT_MYSTR, INIT_MYSTR, 1,
60 /* Logging */
61 -1, -1, INIT_MYSTR, 0, 0, 0, INIT_MYSTR, 0,
62 /* Buffers */
63 INIT_MYSTR, INIT_MYSTR,
64 /* Parent <-> child comms */
65 -1, -1,
66 /* Number of clients */
67 0, 0,
68 /* Home directory */
69 INIT_MYSTR,
70 /* Secure connection state */
71 0, 0, 0, 0, 0, INIT_MYSTR, 0, -1, -1,
72 /* Login fails */
73 0,
74 /* Owner UID */
75 0
76 };
77 int config_loaded = 0;
78 int i;
79 tunables_load_defaults();
80 /* This might need to open /dev/zero on systems lacking MAP_ANON. Needs
81 * to be done early (i.e. before config file parse, which may use
82 * anonymous pages
83 */
84 vsf_sysutil_map_anon_pages_init();
85 /* Argument parsing. Any argument not starting with "-" is a config file,
86 * loaded in the order encountered. -o opt=value options are loading in the
87 * order encountered, including correct ordering with respect intermingled
88 * config files.
89 * If we see -v (version) or an unknown option, parsing bails and exits.
90 */
91 if (argc == 0)
92 {
93 die("vsftpd: missing argv[0]");
94 }
95 for (i = 1; i < argc; ++i)
96 {
97 const char* p_arg = argv[i];
98 if (p_arg[0] != '-')
99 {
100 config_loaded = 1;
101 vsf_parseconf_load_file(p_arg, 1);
102 }
103 else
104 {
105 if (p_arg[1] == '?')
106 {
107 vsf_print("vsFTPd version " VSF_VERSION "\n");
108 vsf_print("Type 'vsftpd -v' to see the program version\n");
109 vsf_print("Usage: vsftpd <config> [options]\n");
110 vsf_print(" <config> - full path to configuration file\n");
111 vsf_print("Options:\n");
112 vsf_print(" -o<parameter>=<value>\n");
113 vsf_print(" parameter and value you can look in vsftpd configuration file manual\n");
114 vsf_exit("");
115 }
116 if (p_arg[1] == 'v')
117 {
118 vsf_exit("vsFTPd version " VSF_VERSION "\n");
119 }
120 else if (p_arg[1] == 'o')
121 {
122 vsf_parseconf_load_setting(&p_arg[2], 1);
123 }
124 else
125 {
126 die2("unrecognise option: ", p_arg);
127 }
128 }
129 }
130 /* Parse default config file if necessary */
131 if (!config_loaded) {
132 struct vsf_sysutil_statbuf* p_statbuf = 0;
133 int retval = vsf_sysutil_stat(VSFTP_DEFAULT_CONFIG, &p_statbuf);
134 if (!vsf_sysutil_retval_is_error(retval))
135 {
136 vsf_parseconf_load_file(VSFTP_DEFAULT_CONFIG, 1);
137 }
138 vsf_sysutil_free(p_statbuf);
139 }
140 if (tunable_convert_charset_enable)
141 {
142 tunable_local_codepage = vsf_charconv_codepage(tunable_local_charset);
143 tunable_convert_charset_enable = (tunable_local_codepage) ? 1 : 0;
144 }
145 if (!tunable_run_as_launching_user)
146 {
147 /* Just get out unless we start with requisite privilege */
148 die_unless_privileged();
149 }
150 if (tunable_setproctitle_enable)
151 {
152 /* Warning -- warning -- may nuke argv, environ */
153 vsf_sysutil_setproctitle_init(argc, argv);
154 }
155 /* Initialize the SSL system here if needed - saves the overhead of each
156 * child doing this itself.
157 */
158 if (tunable_ssl_enable)
159 {
160 ssl_init(&the_session);
161 }
162 if (tunable_listen || tunable_listen_ipv6)
163 {
164 /* Standalone mode */
165 struct vsf_client_launch ret = vsf_standalone_main();
166 the_session.num_clients = ret.num_children;
167 the_session.num_this_ip = ret.num_this_ip;
168 }
169 if (tunable_tcp_wrappers)
170 {
171 the_session.tcp_wrapper_ok = vsf_tcp_wrapper_ok(VSFTP_COMMAND_FD);
172 }
173 {
174 const char* p_load_conf = vsf_sysutil_getenv("VSFTPD_LOAD_CONF");
175 if (p_load_conf)
176 {
177 vsf_parseconf_load_file(p_load_conf, 1);
178 }
179 }
180 /* Sanity checks - exit with a graceful error message if our STDIN is not
181 * a socket. Also check various config options don't collide.
182 */
183 do_sanity_checks();
184 /* Initializes session globals - e.g. IP addr's etc. */
185 session_init(&the_session);
186 /* Set up "environment", e.g. process group etc. */
187 env_init();
188 /* Set up resource limits. */
189 limits_init();
190 /* Set up logging - must come after global init because we need the remote
191 * address to convert into text
192 */
193 vsf_log_init(&the_session);
194 str_alloc_text(&the_session.remote_ip_str,
195 vsf_sysutil_inet_ntop(the_session.p_remote_addr));
196 /* Set up options on the command socket */
197 vsf_cmdio_sock_setup();
198 if (tunable_setproctitle_enable)
199 {
200 vsf_sysutil_set_proctitle_prefix(&the_session.remote_ip_str);
201 vsf_sysutil_setproctitle("connected");
202 }
203 /* We might chroot() very soon (one process model), so we need to open
204 * any required config files here.
205 */
206 /* SSL may have been enabled by a per-IP configuration.. */
207 if (tunable_ssl_enable)
208 {
209 ssl_init(&the_session);
210 ssl_add_entropy(&the_session);
211 }
212 if (tunable_deny_email_enable)
213 {
214 int retval = -1;
215 if (tunable_banned_email_file)
216 {
217 retval = str_fileread(&the_session.banned_email_str,
218 tunable_banned_email_file, VSFTP_CONF_FILE_MAX);
219 }
220 if (vsf_sysutil_retval_is_error(retval))
221 {
222 die2("cannot read anon e-mail list file:", tunable_banned_email_file);
223 }
224 }
225 if (tunable_banner_file)
226 {
227 int retval = str_fileread(&the_session.banner_str, tunable_banner_file,
228 VSFTP_CONF_FILE_MAX);
229 if (vsf_sysutil_retval_is_error(retval))
230 {
231 die2("cannot read banner file:", tunable_banner_file);
232 }
233 }
234 if (tunable_secure_email_list_enable)
235 {
236 int retval = -1;
237 if (tunable_email_password_file)
238 {
239 retval = str_fileread(&the_session.email_passwords_str,
240 tunable_email_password_file,
241 VSFTP_CONF_FILE_MAX);
242 }
243 if (vsf_sysutil_retval_is_error(retval))
244 {
245 die2("cannot read email passwords file:", tunable_email_password_file);
246 }
247 }
248 if (tunable_run_as_launching_user)
249 {
250 tunable_one_process_model = 1;
251 if (!vsf_sysutil_running_as_root())
252 {
253 tunable_connect_from_port_20 = 0;
254 tunable_chown_uploads = 0;
255 }
256 }
257 if (tunable_pasv_addr_rules) {
258 vsf_pasvrules_load(tunable_pasv_addr_rules);
259 }
260 vsf_pasvrules_define(&the_session);
261 if (tunable_users_access_ip) {
262 vsf_userip_load(tunable_users_access_ip);
263 }
264 if (tunable_http_enable)
265 {
266 vsf_http_messages_load();
267 }
268 if (tunable_one_process_model)
269 {
270 vsf_one_process_start(&the_session);
271 }
272 else
273 {
274 vsf_two_process_start(&the_session);
275 }
276 /* NOTREACHED */
277 bug("should not get here: main");
278 return 1;
279 }
280
281 static void
die_unless_privileged(void)282 die_unless_privileged(void)
283 {
284 if (!vsf_sysutil_running_as_root())
285 {
286 die("vsftpd: must be started as root (see run_as_launching_user option)");
287 }
288 }
289
290 static void
do_sanity_checks(void)291 do_sanity_checks(void)
292 {
293 {
294 struct vsf_sysutil_statbuf* p_statbuf = 0;
295 vsf_sysutil_fstat(VSFTP_COMMAND_FD, &p_statbuf);
296 if (!vsf_sysutil_statbuf_is_socket(p_statbuf))
297 {
298 die("vsftpd: not configured for standalone, must be started from inetd");
299 }
300 vsf_sysutil_free(p_statbuf);
301 }
302 if (!tunable_ftp_enable && !tunable_http_enable)
303 {
304 die("vsftpd: both FTP and HTTP disabled!");
305 }
306 if (tunable_ftp_enable && tunable_http_enable)
307 {
308 die("vsftpd: both FTP and HTTP enabled!");
309 }
310 if (tunable_http_enable && !tunable_one_process_model)
311 {
312 die("vsftpd: HTTP needs 'one_process_model' for now");
313 }
314 if (!tunable_local_enable && !tunable_anonymous_enable)
315 {
316 die("vsftpd: both local and anonymous access disabled!");
317 }
318 if (tunable_one_process_model)
319 {
320 if (tunable_local_enable)
321 {
322 die("vsftpd: security: 'one_process_model' is anonymous only");
323 }
324 if (!vsf_sysdep_has_capabilities_as_non_root())
325 {
326 die("vsftpd: security: 'one_process_model' needs a better OS");
327 }
328 }
329 }
330
331 static void
env_init(void)332 env_init(void)
333 {
334 vsf_sysutil_make_session_leader();
335 /* Set up a secure umask - we'll set the proper one after login */
336 vsf_sysutil_set_umask(VSFTP_SECURE_UMASK);
337 /* Fire up libc's timezone initialisation, before we chroot()! */
338 vsf_sysutil_tzset();
339 /* Signals. We'll always take -EPIPE rather than a rude signal, thanks */
340 vsf_sysutil_install_null_sighandler(kVSFSysUtilSigPIPE);
341 }
342
343 static void
limits_init(void)344 limits_init(void)
345 {
346 unsigned long limit = VSFTP_AS_LIMIT;
347 if (tunable_text_userdb_names)
348 {
349 /* Turns out, LDAP lookups for lots of userid -> name mappings can really
350 * bloat memory usage.
351 */
352 limit *= 3;
353 }
354 vsf_sysutil_set_address_space_limit(limit);
355 }
356
357 static void
session_init(struct vsf_session * p_sess)358 session_init(struct vsf_session* p_sess)
359 {
360 /* Get the addresses of the control connection */
361 vsf_sysutil_getpeername(VSFTP_COMMAND_FD, &p_sess->p_remote_addr);
362 vsf_sysutil_getsockname(VSFTP_COMMAND_FD, &p_sess->p_local_addr);
363 /* If anonymous mode is active, fetch the uid of the anonymous user */
364 if (tunable_anonymous_enable)
365 {
366 const struct vsf_sysutil_user* p_user = 0;
367 if (tunable_ftp_username)
368 {
369 p_user = vsf_sysutil_getpwnam(tunable_ftp_username);
370 }
371 if (p_user == 0)
372 {
373 die2("vsftpd: cannot locate user specified in 'ftp_username':",
374 tunable_ftp_username);
375 }
376 p_sess->anon_ftp_uid = vsf_sysutil_user_getuid(p_user);
377 }
378 if (tunable_guest_enable)
379 {
380 const struct vsf_sysutil_user* p_user = 0;
381 if (tunable_guest_username)
382 {
383 p_user = vsf_sysutil_getpwnam(tunable_guest_username);
384 }
385 if (p_user == 0)
386 {
387 die2("vsftpd: cannot locate user specified in 'guest_username':",
388 tunable_guest_username);
389 }
390 p_sess->guest_user_uid = vsf_sysutil_user_getuid(p_user);
391 }
392 if (tunable_chown_uploads)
393 {
394 const struct vsf_sysutil_user* p_user = 0;
395 if (tunable_chown_username)
396 {
397 p_user = vsf_sysutil_getpwnam(tunable_chown_username);
398 }
399 if (p_user == 0)
400 {
401 die2("vsftpd: cannot locate user specified in 'chown_username':",
402 tunable_chown_username);
403 }
404 p_sess->anon_upload_chown_uid = vsf_sysutil_user_getuid(p_user);
405 if (tunable_chown_group)
406 {
407 p_sess->anon_upload_chown_gid = vsf_sysutil_user_getgid(p_user);
408 }
409 }
410 }
411
412