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:
parent
b93ee04314
commit
78c098b53f
12
Changelog
12
Changelog
@ -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
68
main.c
@ -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);
|
||||
}
|
||||
|
66
parseconf.c
66
parseconf.c
@ -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));
|
||||
}
|
||||
}
|
||||
|
10
parseconf.h
10
parseconf.h
@ -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 */
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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))
|
||||
|
15
sysdeputil.c
15
sysdeputil.c
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
{
|
||||
|
10
twoprocess.c
10
twoprocess.c
@ -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);
|
||||
}
|
||||
|
||||
|
34
vsftpd.8
34
vsftpd.8
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user