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