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 <stdio.h> 26 27/* 28 * Forward decls of helper functions 29 */ 30static void die_unless_privileged(void); 31static void do_sanity_checks(void); 32static void session_init(struct vsf_session* p_sess); 33static void env_init(void); 34 35int 36main(int argc, const char* argv[]) 37{ 38 struct vsf_session the_session = 39 { 40 /* Control connection */ 41 0, 0, 0, 42 /* Data connection */ 43 -1, 0, -1, 0, 0, 0, 0, 44 /* Login */ 45 1, INIT_MYSTR, INIT_MYSTR, 46 /* Protocol state */ 47 0, 1, INIT_MYSTR, 0, 0, 48 /* Session state */ 49 0, 50 /* Userids */ 51 -1, -1, -1, 52 /* Pre-chroot() cache */ 53 INIT_MYSTR, INIT_MYSTR, INIT_MYSTR, INIT_MYSTR, 1, 54 /* Logging */ 55 -1, -1, INIT_MYSTR, 0, 0, 0, INIT_MYSTR, 0, 56 /* Buffers */ 57 INIT_MYSTR, INIT_MYSTR, 0, 0, 58 /* Parent <-> child comms */ 59 -1, -1, 60 /* Number of clients */ 61 0, 0, 62 /* Home directory */ 63 INIT_MYSTR, 64 /* Secure connection state */ 65 0, 0, 0, 0, 0, 0, -1, -1, 66 /* write_enable */ 67 0 68 }; 69 int config_specified = 0; 70 const char* p_config_name = VSFTP_DEFAULT_CONFIG; 71 /* Zero or one argument supported. If one argument is passed, it is the 72 * path to the config file 73 */ 74 if (argc > 2) 75 { 76 die("vsftpd: too many arguments (I take an optional config file only)"); 77 } 78 else if (argc == 0) 79 { 80 die("vsftpd: missing argv[0]"); 81 } 82 if (argc == 2) 83 { 84 if (!vsf_sysutil_strcmp(argv[1], "-v")) 85 { 86 vsf_exit("vsftpd: version " VSF_VERSION "\n"); 87 } 88 p_config_name = argv[1]; 89 config_specified = 1; 90 } 91 /* This might need to open /dev/zero on systems lacking MAP_ANON. Needs 92 * to be done early (i.e. before config file parse, which may use 93 * anonymous pages 94 */ 95 vsf_sysutil_map_anon_pages_init(); 96 /* Parse config file if it's there */ 97 { 98 struct vsf_sysutil_statbuf* p_statbuf = 0; 99 int retval = vsf_sysutil_stat(p_config_name, &p_statbuf); 100 if (!vsf_sysutil_retval_is_error(retval)) 101 { 102 vsf_parseconf_load_file(p_config_name, 1); 103 } 104 else if (config_specified) 105 { 106 die2("vsftpd: cannot open config file:", p_config_name); 107 } 108 vsf_sysutil_free(p_statbuf); 109 } 110 /* Resolve pasv_address if required */ 111 if (tunable_pasv_address && tunable_pasv_addr_resolve) 112 { 113 struct vsf_sysutil_sockaddr* p_addr = 0; 114 const char* p_numeric_addr; 115 vsf_sysutil_dns_resolve(&p_addr, tunable_pasv_address); 116 vsf_sysutil_free((char*) tunable_pasv_address); 117 p_numeric_addr = vsf_sysutil_inet_ntop(p_addr); 118 tunable_pasv_address = vsf_sysutil_strdup(p_numeric_addr); 119 vsf_sysutil_free(p_addr); 120 } 121 if (!tunable_run_as_launching_user) 122 { 123 /* Just get out unless we start with requisite privilege */ 124 die_unless_privileged(); 125 } 126 if (tunable_setproctitle_enable) 127 { 128 /* Warning -- warning -- may nuke argv, environ */ 129 vsf_sysutil_setproctitle_init(argc, argv); 130 } 131 /* Initialize the SSL system here if needed - saves the overhead of each 132 * child doing this itself. 133 */ 134 if (tunable_ssl_enable) 135 { 136 ssl_init(&the_session); 137 } 138 if (tunable_listen || tunable_listen_ipv6) 139 { 140 /* Standalone mode */ 141 struct vsf_client_launch ret = vsf_standalone_main(); 142 the_session.num_clients = ret.num_children; 143 the_session.num_this_ip = ret.num_this_ip; 144 } 145 if (tunable_tcp_wrappers) 146 { 147 the_session.tcp_wrapper_ok = vsf_tcp_wrapper_ok(VSFTP_COMMAND_FD); 148 } 149 { 150 const char* p_load_conf = vsf_sysutil_getenv("VSFTPD_LOAD_CONF"); 151 if (p_load_conf) 152 { 153 vsf_parseconf_load_file(p_load_conf, 1); 154 } 155 } 156 /* Sanity checks - exit with a graceful error message if our STDIN is not 157 * a socket. Also check various config options don't collide. 158 */ 159 do_sanity_checks(); 160 /* Initializes session globals - e.g. IP addr's etc. */ 161 session_init(&the_session); 162 /* Set up "environment", e.g. process group etc. */ 163 env_init(); 164 /* Set up logging - must come after global init because we need the remote 165 * address to convert into text 166 */ 167 vsf_log_init(&the_session); 168 str_alloc_text(&the_session.remote_ip_str, 169 vsf_sysutil_inet_ntop(the_session.p_remote_addr)); 170 /* Set up options on the command socket */ 171 vsf_cmdio_sock_setup(); 172 if (tunable_setproctitle_enable) 173 { 174 vsf_sysutil_set_proctitle_prefix(&the_session.remote_ip_str); 175 vsf_sysutil_setproctitle("connected"); 176 } 177 /* We might chroot() very soon (one process model), so we need to open 178 * any required config files here. 179 */ 180 /* SSL may have been enabled by a per-IP configuration.. */ 181 if (tunable_ssl_enable) 182 { 183 ssl_init(&the_session); 184 } 185 if (tunable_deny_email_enable) 186 { 187 int retval = str_fileread(&the_session.banned_email_str, 188 tunable_banned_email_file, VSFTP_CONF_FILE_MAX); 189 if (vsf_sysutil_retval_is_error(retval)) 190 { 191 die2("cannot open anon e-mail list file:", tunable_banned_email_file); 192 } 193 } 194 if (tunable_banner_file) 195 { 196 int retval = str_fileread(&the_session.banner_str, tunable_banner_file, 197 VSFTP_CONF_FILE_MAX); 198 if (vsf_sysutil_retval_is_error(retval)) 199 { 200 die2("cannot open banner file:", tunable_banner_file); 201 } 202 } 203 if (tunable_secure_email_list_enable) 204 { 205 int retval = str_fileread(&the_session.email_passwords_str, 206 tunable_email_password_file, 207 VSFTP_CONF_FILE_MAX); 208 if (vsf_sysutil_retval_is_error(retval)) 209 { 210 die2("cannot open email passwords file:", tunable_email_password_file); 211 } 212 } 213 /* Special case - can force one process model if we've got a setup 214 * needing _no_ privs 215 */ 216 if (!tunable_local_enable && !tunable_connect_from_port_20 && 217 !tunable_chown_uploads) 218 { 219 tunable_one_process_model = 1; 220 } 221 if (tunable_run_as_launching_user) 222 { 223 tunable_one_process_model = 1; 224 if (!vsf_sysutil_running_as_root()) 225 { 226 tunable_connect_from_port_20 = 0; 227 tunable_chown_uploads = 0; 228 } 229 } 230 if (tunable_one_process_model) 231 { 232 vsf_one_process_start(&the_session); 233 } 234 else 235 { 236 vsf_two_process_start(&the_session); 237 } 238 /* NOTREACHED */ 239 bug("should not get here: main"); 240 return 1; 241} 242 243static void 244die_unless_privileged(void) 245{ 246 if (!vsf_sysutil_running_as_root()) 247 { 248 die("vsftpd: must be started as root (see run_as_launching_user option)"); 249 } 250} 251 252static void 253do_sanity_checks(void) 254{ 255 { 256 struct vsf_sysutil_statbuf* p_statbuf = 0; 257 vsf_sysutil_fstat(VSFTP_COMMAND_FD, &p_statbuf); 258 if (!vsf_sysutil_statbuf_is_socket(p_statbuf)) 259 { 260 die("vsftpd: not configured for standalone, must be started from inetd"); 261 } 262 vsf_sysutil_free(p_statbuf); 263 } 264 if (tunable_one_process_model) 265 { 266 if (tunable_local_enable) 267 { 268 die("vsftpd: security: 'one_process_model' is anonymous only"); 269 } 270 if (!vsf_sysdep_has_capabilities_as_non_root()) 271 { 272 die("vsftpd: security: 'one_process_model' needs a better OS"); 273 } 274 } 275 if (!tunable_local_enable && !tunable_anonymous_enable) 276 { 277 die("vsftpd: both local and anonymous access disabled!"); 278 } 279} 280 281static void 282env_init(void) 283{ 284 vsf_sysutil_make_session_leader(); 285 /* Set up a secure umask - we'll set the proper one after login */ 286 vsf_sysutil_set_umask(VSFTP_SECURE_UMASK); 287 /* Fire up libc's timezone initialisation, before we chroot()! */ 288 vsf_sysutil_tzset(); 289 /* Signals. We'll always take -EPIPE rather than a rude signal, thanks */ 290 vsf_sysutil_install_null_sighandler(kVSFSysUtilSigPIPE); 291} 292 293static void 294session_init(struct vsf_session* p_sess) 295{ 296 /* Get the addresses of the control connection */ 297 vsf_sysutil_getpeername(VSFTP_COMMAND_FD, &p_sess->p_remote_addr); 298 vsf_sysutil_getsockname(VSFTP_COMMAND_FD, &p_sess->p_local_addr); 299 300 /* If anonymous mode is active, fetch the uid of the anonymous user */ 301 if (tunable_anonymous_enable) 302 { 303 const struct vsf_sysutil_user* p_user = vsf_sysutil_getpwnam(tunable_ftp_username); 304 305 if (p_user == 0) 306 { 307 die2("vsftpd: cannot locate user specified in 'ftp_username':", 308 tunable_ftp_username); 309 } 310 p_sess->anon_ftp_uid = vsf_sysutil_user_getuid(p_user); 311 } 312 313 if (tunable_guest_enable) 314 { 315 const struct vsf_sysutil_user* p_user = vsf_sysutil_getpwnam(tunable_guest_username); 316 317 if (p_user == 0) 318 { 319 die2("vsftpd: cannot locate user specified in 'guest_username':", 320 tunable_guest_username); 321 } 322 p_sess->guest_user_uid = vsf_sysutil_user_getuid(p_user); 323 } 324 325 if (tunable_chown_uploads) 326 { 327 const struct vsf_sysutil_user* p_user = vsf_sysutil_getpwnam(tunable_chown_username); 328 329 if (p_user == 0) 330 { 331 die2("vsftpd: cannot locate user specified in 'chown_username':", 332 tunable_chown_username); 333 } 334 p_sess->anon_upload_chown_uid = vsf_sysutil_user_getuid(p_user); 335 } 336} 337