1
0
mirror of https://github.com/InfrastructureServices/vsftpd.git synced 2025-04-19 01:24:02 +03:00

Updated to v2.2.0pre2

This commit is contained in:
Dag Wieers 2009-07-14 00:00:00 +02:00
parent b93ee04314
commit 78c098b53f
12 changed files with 163 additions and 73 deletions

View File

@ -1150,3 +1150,15 @@ process for sockets. Moderate code disturbance - hope for no breakage :-/
can benefit from the no-network isolation of the unprivileged process (where
available).
(vsftpd-2.2.0pre1)
- Call pam_get_item(PAM_GETUSER) after authentication in case a PAM module
remapped the username. Based on a patch from John McNair <john.mcnair@ihg.com>.
- Apply a couple of IPv6 fixes from Corinna Schultz <corinna.schultz@gmail.com>,
particularly when MS operating systems are talking on link local addresses.
- Handle the error case for accepting a PASV connection in the two process
model properly.
- Pull in a couple of minor tidyup patches from Openwall.
- Add "-o" command line option to specify option, e.g. vsftpd -olisten=NO. Also
respect ordering with respect config files, e.g.
vsftpd -olisten=NO /etc/vsftpd.conf -olocal_enable=NO
Inspiration from Solar / Openwall.
(vsftpd-2.2.0pre2)

68
main.c
View File

@ -66,45 +66,55 @@ main(int argc, const char* argv[])
/* Login fails */
0
};
int config_specified = 0;
const char* p_config_name = VSFTP_DEFAULT_CONFIG;
int config_loaded = 0;
int i;
tunables_load_defaults();
/* Zero or one argument supported. If one argument is passed, it is the
* path to the config file
*/
if (argc > 2)
{
die("vsftpd: too many arguments (I take an optional config file only)");
}
else if (argc == 0)
{
die("vsftpd: missing argv[0]");
}
if (argc == 2)
{
if (!vsf_sysutil_strcmp(argv[1], "-v"))
{
vsf_exit("vsftpd: version " VSF_VERSION "\n");
}
p_config_name = argv[1];
config_specified = 1;
}
/* This might need to open /dev/zero on systems lacking MAP_ANON. Needs
* to be done early (i.e. before config file parse, which may use
* anonymous pages
*/
vsf_sysutil_map_anon_pages_init();
/* Parse config file if it's there */
/* Argument parsing. Any argument not starting with "-" is a config file,
* loaded in the order encountered. -o opt=value options are loading in the
* order encountered, including correct ordering with respect intermingled
* config files.
* If we see -v (version) or an unknown option, parsing bails and exits.
*/
if (argc == 0)
{
die("vsftpd: missing argv[0]");
}
for (i = 1; i < argc; ++i)
{
const char* p_arg = argv[i];
if (p_arg[0] != '-')
{
config_loaded = 1;
vsf_parseconf_load_file(p_arg, 1);
}
else
{
if (p_arg[1] == 'v')
{
vsf_exit("vsftpd: version " VSF_VERSION "\n");
}
else if (p_arg[1] == 'o')
{
vsf_parseconf_load_setting(&p_arg[2], 1);
}
else
{
die2("unrecognise option: ", p_arg);
}
}
}
/* Parse default config file if necessary */
if (!config_loaded) {
struct vsf_sysutil_statbuf* p_statbuf = 0;
int retval = vsf_sysutil_stat(p_config_name, &p_statbuf);
int retval = vsf_sysutil_stat(VSFTP_DEFAULT_CONFIG, &p_statbuf);
if (!vsf_sysutil_retval_is_error(retval))
{
vsf_parseconf_load_file(p_config_name, 1);
}
else if (config_specified)
{
die2("vsftpd: cannot open config file:", p_config_name);
vsf_parseconf_load_file(VSFTP_DEFAULT_CONFIG, 1);
}
vsf_sysutil_free(p_statbuf);
}

View File

@ -18,11 +18,6 @@
static const char* s_p_saved_filename;
/* File local functions */
static void handle_config_setting(struct mystr* p_setting_str,
struct mystr* p_value_str,
int errs_fatal);
/* Tables mapping setting names to runtime variables */
/* Boolean settings */
static struct parseconf_bool_setting
@ -211,7 +206,7 @@ vsf_parseconf_load_file(const char* p_filename, int errs_fatal)
{
if (errs_fatal)
{
die2("cannot open config file:", p_filename);
die2("cannot open config file: ", p_filename);
}
else
{
@ -241,50 +236,55 @@ vsf_parseconf_load_file(const char* p_filename, int errs_fatal)
{
continue;
}
/* Split into name=value pair */
str_split_char(&config_setting_str, &config_value_str, '=');
handle_config_setting(&config_setting_str, &config_value_str, errs_fatal);
vsf_parseconf_load_setting(str_getbuf(&config_setting_str), errs_fatal);
}
str_free(&config_file_str);
str_free(&config_setting_str);
str_free(&config_value_str);
}
static void
handle_config_setting(struct mystr* p_setting_str, struct mystr* p_value_str,
int errs_fatal)
void
vsf_parseconf_load_setting(const char* p_setting, int errs_fatal)
{
static struct mystr s_setting_str;
static struct mystr s_value_str;
while (vsf_sysutil_isspace(*p_setting))
{
p_setting++;
}
str_alloc_text(&s_setting_str, p_setting);
str_split_char(&s_setting_str, &s_value_str, '=');
/* Is it a string setting? */
{
const struct parseconf_str_setting* p_str_setting = parseconf_str_array;
while (p_str_setting->p_setting_name != 0)
{
if (str_equal_text(p_setting_str, p_str_setting->p_setting_name))
if (str_equal_text(&s_setting_str, p_str_setting->p_setting_name))
{
/* Got it */
const char** p_curr_setting = p_str_setting->p_variable;
if (*p_curr_setting)
{
vsf_sysutil_free((char*)*p_curr_setting);
vsf_sysutil_free((char*) *p_curr_setting);
}
if (str_isempty(p_value_str))
if (str_isempty(&s_value_str))
{
*p_curr_setting = 0;
}
else
{
*p_curr_setting = str_strdup(p_value_str);
*p_curr_setting = str_strdup(&s_value_str);
}
return;
}
p_str_setting++;
}
}
if (str_isempty(p_value_str))
if (str_isempty(&s_value_str))
{
if (errs_fatal)
{
die2("missing value in config file for: ", str_getbuf(p_setting_str));
die2("missing value in config file for: ", str_getbuf(&s_setting_str));
}
else
{
@ -296,26 +296,26 @@ handle_config_setting(struct mystr* p_setting_str, struct mystr* p_value_str,
const struct parseconf_bool_setting* p_bool_setting = parseconf_bool_array;
while (p_bool_setting->p_setting_name != 0)
{
if (str_equal_text(p_setting_str, p_bool_setting->p_setting_name))
if (str_equal_text(&s_setting_str, p_bool_setting->p_setting_name))
{
/* Got it */
str_upper(p_value_str);
if (str_equal_text(p_value_str, "YES") ||
str_equal_text(p_value_str, "TRUE") ||
str_equal_text(p_value_str, "1"))
str_upper(&s_value_str);
if (str_equal_text(&s_value_str, "YES") ||
str_equal_text(&s_value_str, "TRUE") ||
str_equal_text(&s_value_str, "1"))
{
*(p_bool_setting->p_variable) = 1;
}
else if (str_equal_text(p_value_str, "NO") ||
str_equal_text(p_value_str, "FALSE") ||
str_equal_text(p_value_str, "0"))
else if (str_equal_text(&s_value_str, "NO") ||
str_equal_text(&s_value_str, "FALSE") ||
str_equal_text(&s_value_str, "0"))
{
*(p_bool_setting->p_variable) = 0;
}
else if (errs_fatal)
{
die2("bad bool value in config file for: ",
str_getbuf(p_setting_str));
str_getbuf(&s_setting_str));
}
return;
}
@ -327,18 +327,18 @@ handle_config_setting(struct mystr* p_setting_str, struct mystr* p_value_str,
const struct parseconf_uint_setting* p_uint_setting = parseconf_uint_array;
while (p_uint_setting->p_setting_name != 0)
{
if (str_equal_text(p_setting_str, p_uint_setting->p_setting_name))
if (str_equal_text(&s_setting_str, p_uint_setting->p_setting_name))
{
/* Got it */
/* If the value starts with 0, assume it's an octal value */
if (!str_isempty(p_value_str) &&
str_get_char_at(p_value_str, 0) == '0')
if (!str_isempty(&s_value_str) &&
str_get_char_at(&s_value_str, 0) == '0')
{
*(p_uint_setting->p_variable) = str_octal_to_uint(p_value_str);
*(p_uint_setting->p_variable) = str_octal_to_uint(&s_value_str);
}
else
{
*(p_uint_setting->p_variable) = str_atoi(p_value_str);
*(p_uint_setting->p_variable) = str_atoi(&s_value_str);
}
return;
}
@ -347,6 +347,6 @@ handle_config_setting(struct mystr* p_setting_str, struct mystr* p_value_str,
}
if (errs_fatal)
{
die2("unrecognised variable in config file: ", str_getbuf(p_setting_str));
die2("unrecognised variable in config file: ", str_getbuf(&s_setting_str));
}
}

View File

@ -17,5 +17,15 @@
*/
void vsf_parseconf_load_file(const char* p_filename, int errs_fatal);
/* vsf_parseconf_parse_setting()
* PURPOSE
* Handle a given name=value setting and apply it. Any whitespace at the
* beginning is skipped.
* PARAMETERS
* p_settings - the name=value pair to apply
* errs_fatal - errors will cause the calling process to exit if not 0
*/
void vsf_parseconf_load_setting(const char* p_setting, int errs_fatal);
#endif /* VSF_PARSECONF_H */

View File

@ -1620,6 +1620,7 @@ handle_eprt(struct vsf_session* p_sess)
{
static struct mystr s_part1_str;
static struct mystr s_part2_str;
static struct mystr s_scopeid_str;
int proto;
int port;
const unsigned char* p_raw_addr;
@ -1644,6 +1645,7 @@ handle_eprt(struct vsf_session* p_sess)
str_split_char(&s_part1_str, &s_part2_str, '|');
if (proto == 2)
{
str_split_char(&s_part1_str, &s_scopeid_str, '%');
p_raw_addr = vsf_sysutil_parse_ipv6(&s_part1_str);
}
else

View File

@ -161,6 +161,13 @@ static void
cmd_process_pasv_accept(struct vsf_session* p_sess)
{
int fd = vsf_privop_accept_pasv(p_sess);
if (fd < 0)
{
priv_sock_send_result(p_sess->parent_fd, PRIV_SOCK_RESULT_BAD);
priv_sock_send_int(p_sess->parent_fd, fd);
return;
}
priv_sock_send_result(p_sess->parent_fd, PRIV_SOCK_RESULT_OK);
priv_sock_send_fd(p_sess->parent_fd, fd);
vsf_sysutil_close(fd);
}

View File

@ -23,12 +23,12 @@
static enum EVSFPrivopLoginResult handle_anonymous_login(
struct vsf_session* p_sess, const struct mystr* p_pass_str);
static enum EVSFPrivopLoginResult handle_local_login(
struct vsf_session* p_sess, const struct mystr* p_user_str,
struct vsf_session* p_sess, struct mystr* p_user_str,
const struct mystr* p_pass_str);
static void setup_username_globals(struct vsf_session* p_sess,
const struct mystr* p_str);
static enum EVSFPrivopLoginResult handle_login(
struct vsf_session* p_sess, const struct mystr* p_user_str,
struct vsf_session* p_sess, struct mystr* p_user_str,
const struct mystr* p_pass_str);
int
@ -249,7 +249,7 @@ vsf_privop_do_login(struct vsf_session* p_sess,
}
static enum EVSFPrivopLoginResult
handle_login(struct vsf_session* p_sess, const struct mystr* p_user_str,
handle_login(struct vsf_session* p_sess, struct mystr* p_user_str,
const struct mystr* p_pass_str)
{
/* Do not assume PAM can cope with dodgy input, even though it
@ -350,7 +350,7 @@ handle_anonymous_login(struct vsf_session* p_sess,
static enum EVSFPrivopLoginResult
handle_local_login(struct vsf_session* p_sess,
const struct mystr* p_user_str,
struct mystr* p_user_str,
const struct mystr* p_pass_str)
{
if (!vsf_sysdep_check_auth(p_user_str, p_pass_str, &p_sess->remote_ip_str))

View File

@ -65,6 +65,8 @@
/* BEGIN config */
#if defined(__linux__)
#include <errno.h>
#include <syscall.h>
#define VSF_SYSDEP_HAVE_LINUX_CLONE
#include <sched.h>
#ifndef CLONE_NEWPID
@ -309,11 +311,12 @@ static int pam_conv_func(int nmsg, const struct pam_message** p_msg,
static void vsf_auth_shutdown(void);
int
vsf_sysdep_check_auth(const struct mystr* p_user_str,
vsf_sysdep_check_auth(struct mystr* p_user_str,
const struct mystr* p_pass_str,
const struct mystr* p_remote_host)
{
int retval;
const char* pam_user_name = 0;
struct pam_conv the_conv =
{
&pam_conv_func,
@ -365,6 +368,16 @@ vsf_sysdep_check_auth(const struct mystr* p_user_str,
s_pamh = 0;
return 0;
}
#ifdef PAM_USER
retval = pam_get_item(s_pamh, PAM_USER, (const void**) &pam_user_name);
if (retval != PAM_SUCCESS)
{
(void) pam_end(s_pamh, retval);
s_pamh = 0;
return 0;
}
str_alloc_text(p_user_str, pam_user_name);
#endif
retval = pam_acct_mgmt(s_pamh, 0);
if (retval != PAM_SUCCESS)
{

View File

@ -15,7 +15,7 @@ struct mystr;
/* Authentication of local users */
/* Return 0 for fail, 1 for success */
int vsf_sysdep_check_auth(const struct mystr* p_user,
int vsf_sysdep_check_auth(struct mystr* p_user,
const struct mystr* p_pass,
const struct mystr* p_remote_host);

View File

@ -1925,6 +1925,8 @@ vsf_sysutil_sockaddr_clone(struct vsf_sysutil_sockaddr** p_sockptr,
vsf_sysutil_memcpy(&p_sockaddr->u.u_sockaddr_in6.sin6_addr,
&p_src->u.u_sockaddr_in6.sin6_addr,
sizeof(p_sockaddr->u.u_sockaddr_in6.sin6_addr));
p_sockaddr->u.u_sockaddr_in6.sin6_scope_id =
p_src->u.u_sockaddr_in6.sin6_scope_id;
}
else
{

View File

@ -252,7 +252,17 @@ vsf_two_process_listen(struct vsf_session* p_sess)
int
vsf_two_process_get_pasv_fd(struct vsf_session* p_sess)
{
char res;
priv_sock_send_cmd(p_sess->child_fd, PRIV_SOCK_PASV_ACCEPT);
res = priv_sock_get_result(p_sess->child_fd);
if (res == PRIV_SOCK_RESULT_BAD)
{
return priv_sock_get_int(p_sess->child_fd);
}
else if (res != PRIV_SOCK_RESULT_OK)
{
die("could not accept on listening socket");
}
return priv_sock_recv_fd(p_sess->child_fd);
}

View File

@ -6,7 +6,7 @@
.Nd Very Secure FTP Daemon
.Sh SYNOPSIS
.Nm vsftpd
.Op Ar configuration file
.Op Ar configuration file and / or options
.Sh DESCRIPTION
.Nm vsftpd
is the Very Secure File Transfer Protocol Daemon. The server can be launched
@ -27,9 +27,33 @@ Direct execution of the
binary will then launch the FTP service ready for immediate client connections.
.Sh OPTIONS
An optional
.Op configuration file
may be given on the command line. This file must be owned as root if running as
root. The default configuration file is
.Pa /etc/vsftpd.conf .
configuration file or files
may be given on the command line. These files must be owned as root if running
as root. Any command line option not starting with a "-" character is treated
as a config file that will be loaded. Note that config files are loaded in the
strict order that they are encountered on the command line.
If no config files are specified, the default configuration file of
.Pa /etc/vsftpd.conf
will be loaded, after all other command line options are processed.
.Pp
Supported options are:
.Bl -tag -width Ds
.It Fl v
Print the version information and exit, even if other options are encountered.
.It Fl ooption=value
Set a single option, value pair as per the format in the config file. Multiple
-o options are supported, and they are applied in strict order relative to
their appearance on the command line, including intermingling with loading of
config files.
.Sh EXAMPLES
vsftpd -olisten=NO /etc/vsftpd.conf -oftpd_banner=blah
.Pp
That example overrides vsftpd's built-in default for the "listen" option to be
NO, but then loads /etc/vsftpd.conf which may override that setting. Finally,
the "ftpd_banner" setting is set to "blah", which overrides any default vsftpd
setting and any identical setting that was in the config file.
.Sh FILES
.Pa /etc/vsftpd.conf
.Sh SEE ALSO
.Xr vsftpd.conf 5
.end