mirror of
https://github.com/InfrastructureServices/vsftpd.git
synced 2025-04-19 01:24:02 +03:00
Updated to v2.0.0
This commit is contained in:
parent
8e72d5f29a
commit
b16a99f9dc
1
BUGS
1
BUGS
@ -17,7 +17,6 @@ the file _after_ ASCII linefeed mangling?
|
||||
but I rip them out unconditionally.
|
||||
- Security model: vsf_privop_get_ftp_port_sock() should probably do the
|
||||
connect() to the remote location itself.
|
||||
- If a user's homedir doesn't exist, we ungracefully exit with "OOPS: chdir"
|
||||
- If someone has one of the timeouts (command, data) setup, but not the other,
|
||||
then timeout will behave whackily.
|
||||
|
||||
|
36
Changelog
36
Changelog
@ -766,3 +766,39 @@ deny_file of *..* is useful.
|
||||
At this point: v1.2.2 released! (need to get the listener fix out)
|
||||
==================================================================
|
||||
|
||||
- Improve logging (log deletes, renames, chmods, etc. as requested by users).
|
||||
- Add no_log_lock to work around Solaris / Veritas locking hangs.
|
||||
- Add EPRT, EPSV, PASV and TVFS to FEAT response.
|
||||
- Implement use of MDTM to set timestamps.
|
||||
- Recognize FEAT prior to login.
|
||||
- Add OpenSSL (AUTH TLS / SSL) support for encrypted control and data
|
||||
connections! Hurrah.
|
||||
- Increase max size of .message files to 4000 characters, thanks to Eric
|
||||
Pancer <epancer@security.depaul.edu> for the report.
|
||||
- Add easy builddefs.h ability to disable PAM builds even when PAM is installed.
|
||||
- Report vsftpd version in STAT output.
|
||||
- Add REFS file.
|
||||
- Change parent<->child socket comms from DGRAM to STREAM for increased
|
||||
reliability. The main benefit is should the parent be killed (or crash out)
|
||||
then the child won't block on a read() that will never return.
|
||||
- Make str_reserve reserve space for the trailing zero as well, so we don't
|
||||
cause a reallocation if we exactly fill the buffer.
|
||||
- Optimize the sending of strings over the parent<->child comms links.
|
||||
- Improve the build system so tcp_wrappers, PAM and OpenSSL can be forcibly
|
||||
compiled out.
|
||||
- Fix vsftpd.conf.5 typos, thanks to Dmitry V. Levin <ldv@altlinux.org>.
|
||||
- If trans_chunk_size is between 1 and 4096, use 4096 rather than ignoring
|
||||
totally. Thanks to Brad <brad@intradonline.com>.
|
||||
- Lose Makefile.sun and README.solaris special cases.
|
||||
- Add SSL / TLS info to SECURITY texts.
|
||||
- Add README.ssl
|
||||
- Add documentation for new SSL options to vsftpd.conf.5.
|
||||
- Add support for CWD ~ (and in general support ~ at start of any filename).
|
||||
Also support stuff like ~chris/pics, if tilde_user_enable=YES is set. Note that
|
||||
all of this is for very very broken clients :-(
|
||||
- Fix compile warnings.
|
||||
- Update INSTALL with (recent) OS X as a working platform.
|
||||
|
||||
At this point: v2.0.0 released!
|
||||
===============================
|
||||
|
||||
|
22
FAQ
22
FAQ
@ -27,8 +27,9 @@ be writable by the ftp user. A way to fix this is:
|
||||
chown root ~ftp; chmod -w ~ftp
|
||||
|
||||
Q) Help! I'm getting the error message "str_getpwnam".
|
||||
A) The most likely cause of this is that the "nobody" user does not exist on
|
||||
your system. vsftpd needs this user to run bits of itself with no privilege.
|
||||
A) The most likely cause of this is that the user that is configured as the
|
||||
'nopriv_user' setting (often 'nobody') does not exist on your system. vsftpd
|
||||
needs this user to run bits of itself with no privilege.
|
||||
|
||||
Q) Help! Local users cannot log in.
|
||||
A) There are various possible problems.
|
||||
@ -198,6 +199,23 @@ A3) FreeBSD large file support wasn't fixed until v1.2.2.
|
||||
A4) The early Linux 2.6 kernels had a bug in this area - use v2.6.6 or newer.
|
||||
A5) Are you sure your FTP _client_ correctly supports large files?
|
||||
|
||||
Q) Help! The built-in vsftpd listener is hanging or crashing!
|
||||
A) A bug in this area is fixed in vsftpd v1.2.2. The problem has always existed
|
||||
but seems to frequently trigger only on certain platforms. For example,
|
||||
Fedora Core 1 - the suspected trigger is a glibc-2.3 platform, possibly in
|
||||
combination with a NPTL-enabled kernel.
|
||||
|
||||
Q) Help! I'm using Solaris / Veritas and vsftpd is hanging!
|
||||
A) Suspected bug with the Solaris / Veritas combination. With vsftpd-1.2.3
|
||||
there is a possible workaround: no_log_lock=YES in your vsftpd.conf.5.
|
||||
|
||||
Q) Does vsftpd support SSL / TLS based encryption?
|
||||
A) Yes, as of v2.0.0, this is supported for the control and data connections
|
||||
(hurrah). You need a build of vsftpd with this support enabled, and then you
|
||||
need to activate the ssl_enable setting. NOTE there are security considerations
|
||||
with this support. Please make sure to read the ssl_enable section in the
|
||||
vsftpd.conf.5 man page thoroughly before using.
|
||||
|
||||
Q) Blah.. blah..
|
||||
A) For a good idea of what vsftpd can do, read the vsftpd.conf.5 man page
|
||||
and the EXAMPLES.
|
||||
|
3
INSTALL
3
INSTALL
@ -152,7 +152,7 @@ Tested platforms (well, it builds)
|
||||
the platforms listed below, and often older ones, should work fine.
|
||||
- RedHat Linux
|
||||
- RedHat Enterprise Linux
|
||||
- Solaris / GNU tools (note - Solaris 8 or newer recommended)
|
||||
- Solaris / GNU tools (Solaris 8 or newer)
|
||||
- SuSE Linux
|
||||
- Debian Linux
|
||||
- OpenBSD
|
||||
@ -160,4 +160,5 @@ the platforms listed below, and often older ones, should work fine.
|
||||
- NetBSD
|
||||
- HP-UX / GNU tools
|
||||
- IRIX / GNU tools
|
||||
- Mac OS X (note; older versions have setgroups() problem. 10.3.4 reported OK)
|
||||
|
||||
|
5
Makefile
5
Makefile
@ -13,8 +13,9 @@ OBJS = main.o utility.o prelogin.o ftpcmdio.o postlogin.o privsock.o \
|
||||
postprivparent.o logging.o str.o netstr.o sysstr.o strlist.o \
|
||||
banner.o filestr.o parseconf.o secutil.o \
|
||||
ascii.o oneprocess.o twoprocess.o privops.o standalone.o hash.o \
|
||||
tcpwrap.o ipv6parse.o access.o \
|
||||
sysutil.o sysdeputil.o
|
||||
tcpwrap.o ipv6parse.o access.o features.o readwrite.o \
|
||||
ssl.o sysutil.o sysdeputil.o
|
||||
|
||||
|
||||
.c.o:
|
||||
$(CC) -c $*.c $(CFLAGS) $(IFLAGS)
|
||||
|
30
Makefile.sun
30
Makefile.sun
@ -1,30 +0,0 @@
|
||||
# Makefile for SUNWspro compiler and tools
|
||||
# Contributed by Mike Batchelor <mikebat@electabuzz.tech.tmcs>
|
||||
CC = cc
|
||||
INSTALL = /usr/ucb/install
|
||||
CFLAGS = -xO5
|
||||
|
||||
LIBS = -lsocket -lnsl -lpam
|
||||
LINK = -s
|
||||
|
||||
OBJS = main.o utility.o prelogin.o ftpcmdio.o postlogin.o privsock.o \
|
||||
tunables.o ftpdataio.o secbuf.o ls.o \
|
||||
postprivparent.o logging.o str.o netstr.o sysstr.o strlist.o \
|
||||
dirchange.o filestr.o parseconf.o secutil.o \
|
||||
ascii.o oneprocess.o twoprocess.o privops.o \
|
||||
sysutil.o sysdeputil.o
|
||||
|
||||
.c.o:
|
||||
$(CC) -c $*.c $(CFLAGS)
|
||||
|
||||
vsftpd: $(OBJS)
|
||||
$(CC) -o vsftpd $(OBJS) $(LINK) $(LIBS)
|
||||
|
||||
install:
|
||||
$(INSTALL) -m 755 vsftpd /usr/sbin/vsftpd
|
||||
if [ -x /etc/xinetd.d ]; then \
|
||||
$(INSTALL) -m 644 xinetd.d/vsftpd /etc/xinetd.d/vsftpd; fi
|
||||
|
||||
clean:
|
||||
rm -f *.o vsftpd
|
||||
|
6
README
6
README
@ -1,6 +1,10 @@
|
||||
This is vsftpd, version 1.2.2
|
||||
This is vsftpd, version 2.0.0
|
||||
Author: Chris Evans
|
||||
Contact: chris@scary.beasts.org
|
||||
Website: http://vsftpd.beasts.org/
|
||||
- All options are documented in the vsftpd.conf.5 manual page.
|
||||
- See the FAQ file for solutions to frequently asked questions.
|
||||
- Visit http://vsftpd.beasts.org/ for vsftpd news and releases.
|
||||
|
||||
What is this?
|
||||
=============
|
||||
|
@ -1,23 +0,0 @@
|
||||
Solaris specific notes
|
||||
======================
|
||||
|
||||
NOTE - you are recommended to use a modern version of Solaris, which comes
|
||||
with the GNU tools. You can then use the normal Makefile.
|
||||
|
||||
Modern releases of Solaris (2.6+ ?) ship with PAM. PAM is an excellent
|
||||
generic authentication framework. Unfortunately, Solaris seems to be a
|
||||
little sparse in the number of PAM modules supported.
|
||||
|
||||
Specifically, many ftp daemon users will want to enable /etc/ftpusers control,
|
||||
as well login control based on the validity of a user's shell (/etc/shells).
|
||||
To perform these two tasks, pam_listfile and pam_shells are required.
|
||||
Neither of these ships with Solaris.
|
||||
|
||||
Luckily, thanks to Mike Batchelor <mikebat@tmcs.net>, you may locate builds
|
||||
of these modules at:
|
||||
ftp://ftp.tmcs.net/pub/PAM-0.75-listfile+shells-sparc-5.8.tar.gz
|
||||
|
||||
From Mike:
|
||||
"To install, just unpack it in /usr/lib/security, and edit /etc/pam.conf,
|
||||
using "ftp" as the service name."
|
||||
|
40
README.ssl
Normal file
40
README.ssl
Normal file
@ -0,0 +1,40 @@
|
||||
As of vsftpd version 2.0.0, SSL / TLS support is provided.
|
||||
|
||||
The SSL / TLS support provides the ability to encrypt FTP logins and subsequent
|
||||
commands, as well as the data transfers themselves. The encyption will, for
|
||||
example, stop the stealing of sensitive passwords via network snooping.
|
||||
|
||||
By default, SSL support is disabled both at compile time and at runtime.
|
||||
Before considering enabling / using SSL support, there are some security
|
||||
considerations:
|
||||
|
||||
- Only enable SSL if absolutely necessary. Enabling SSL will allow attackers
|
||||
to make use of any security problems in the OpenSSL libraries. Note that
|
||||
the OpenSSL libraries are a large quantity of code and have had the occasional
|
||||
security problem in the past.
|
||||
For example, your server might use virtual users to control access to
|
||||
non-sensitive download content. In this case, the passwords might not be
|
||||
worth securing with SSL.
|
||||
|
||||
- After enabling SSL, consider restricting access to an SSL enabled server
|
||||
where feasible. For example, only the internal network might need access.
|
||||
|
||||
|
||||
In order to enable and use SSL support, you need the following:
|
||||
|
||||
- vsftpd built with OpenSSL support. This is a decision your vsftpd packager
|
||||
made, or if you are building vsftpd yourself, edit "builddefs.h" and change the
|
||||
"#undef VSF_BUILD_SSL" to "#define VSF_BUILD_SSL".
|
||||
- "ssl_enable=YES" in your vsftpd.conf.
|
||||
- A SSL certificate. By default, an RSA certificate is looked for at the
|
||||
location /usr/share/ssl/certs/vsftpd.pem. To get an RSA certificate, either
|
||||
buy one from a certificate authority, or you can create your own self-signed
|
||||
certificate. If you have OpenSSL installed, you may find a "Makefile" in
|
||||
your shared certificates directory, e.g. /usr/share/ssl/certs. In that case,
|
||||
go to that directory and type e.g. "make vsftpd.pem". Then answer the
|
||||
questions you are asked. Alternatively, read the man page for "openssl".
|
||||
- Also be aware of the following SSL related parameters. Read the vsftpd.conf.5
|
||||
manual page to learn about them: allow_anon_ssl, force_local_logins_ssl,
|
||||
force_local_data_ssl, ssl_sslv2, ssl_sslv3, ssl_tlsv1, rsa_cert_file,
|
||||
dsa_cert_file, ssl_ciphers.
|
||||
|
45
REFS
Normal file
45
REFS
Normal file
@ -0,0 +1,45 @@
|
||||
The following FTP related references are useful:
|
||||
(Implemented or partially implemented in vsftpd):
|
||||
=================================================
|
||||
|
||||
RFC-959, original FTP spec.
|
||||
http://www.rfc-editor.org/rfc/rfc959.txt
|
||||
|
||||
RFC-1123, the small FTP related section extends / clarifies RFC-959.
|
||||
http://www.rfc-editor.org/rfc/rfc1123.txt
|
||||
|
||||
RFC-2228, FTP security extensions. vsftpd implements the small subset needed
|
||||
to support TLS / SSL connections.
|
||||
http://www.rfc-editor.org/rfc/rfc2228.txt
|
||||
|
||||
RFC-2389. Proposes FEAT and OPTS commands.
|
||||
http://www.rfc-editor.org/rfc/rfc2389.txt
|
||||
|
||||
RFC-2428. Essentially IPv6 support.
|
||||
http://www.rfc-editor.org/rfc/rfc2428.txt
|
||||
|
||||
"Securing FTP with TLS" (draft-murray-auth-ftp-ssl-09.txt). Document that
|
||||
dives into the standardized behaviour of SSL / TLS connections in conjunction
|
||||
with RFC-2228.
|
||||
http://www.isaserver.org/articles/Securing_FTP_with_TLS.html
|
||||
|
||||
"Extensions to FTP" (draft-ietf-ftpext-mlst-16.txt). Standardizes SIZE, MDTM,
|
||||
MLST and MLSD. Note that vsftpd has not implemented MLST and MLSD due to lack
|
||||
of demand from users. Perhaps the client support just isn't there.
|
||||
http://www.ietf.org/internet-drafts/draft-ietf-ftpext-mlst-16.txt
|
||||
|
||||
(Not implemented in vsftpd):
|
||||
============================
|
||||
|
||||
RFC-1579. Proposes an APSV command. No users have requested this in vsftpd;
|
||||
perhaps the client support just isn't there.
|
||||
http://www.rfc-editor.org/rfc/rfc1579.txt
|
||||
|
||||
RFC-1639. Proposes commands LPRT and LPSV. Seems to be deprecated in favour of
|
||||
EPRT and EPSV in RFC-2428.
|
||||
http://www.rfc-editor.org/rfc/rfc1639.txt
|
||||
|
||||
RFC-2640. Deals with internationalization and the LANG command. I'm not seeing
|
||||
any vsftpd users with requirements in this area.
|
||||
http://www.rfc-editor.org/rfc/rfc2640.txt
|
||||
|
@ -135,6 +135,12 @@ privileges it requires. In some cases, this amounts to no privilege, and the
|
||||
privileged parent just exits, leaving no part of vsftpd running with
|
||||
privilege.
|
||||
|
||||
5) vsftpd-2.0.0 introduces SSL / TLS support using OpenSSL. ALL OpenSSL
|
||||
protocol parsing is performed in a chroot() jail, running under an unprivileged
|
||||
user. This means both pre-authenticated and post-authenticated OpenSSL protocol
|
||||
parsing; it's actually quite hard to do, but vsftpd manages it in the name of
|
||||
being secure. I'm unaware of any other FTP server which supports both SSL / TLS
|
||||
and privilege separatation, and gets this right.
|
||||
|
||||
Comments on this document are welcomed.
|
||||
|
||||
|
@ -101,6 +101,13 @@ named "sysutil.c", and "sysdeputil.c" (for the more variable/system dependent
|
||||
calls). This provides a convenient audit point for ascertaining which calls
|
||||
vsftpd trusts.
|
||||
|
||||
vsftpd-2.0.0 introduces SSL / TLS support using OpenSSL. OpenSSL is a massive
|
||||
quantity of code which is essentially parsing complex protocol under the full
|
||||
control of remote malicious clients. SSL / TLS is disabled by default, both
|
||||
at compile time and run time. This forces packagers and administrators to make
|
||||
the decision that they trust the OpenSSL library. I personally haven't yet
|
||||
formed an opinion on whether I consider the OpenSSL code trustworthy.
|
||||
|
||||
|
||||
Summary
|
||||
=======
|
||||
|
28
TODO
28
TODO
@ -3,32 +3,27 @@ CRITICAL
|
||||
|
||||
- Improve FAQ, docs (ongoing..)
|
||||
- Integrated test suite (I'm so lazy..)
|
||||
- Allow easy disabling of log file lock (Solaris / Veritas Cluster Service bug?)
|
||||
|
||||
NOT SO CRITICAL
|
||||
===============
|
||||
|
||||
- Consider CWD ~
|
||||
- Log DELE (and chmod, rnto, etc.)
|
||||
- Fix SIGHUP config file reload to correctly reset _removed_ settings to
|
||||
their default values.
|
||||
- Allow listener to listen on multiple IPs; bonus points if the different
|
||||
IPs can have different configs.
|
||||
- Upload file size limits.
|
||||
- Allow groups to be listed in user lists.
|
||||
- Allow space in username.
|
||||
- Max OSX setgroups() issue.
|
||||
- Minor: background should happen after listen has completed so that failure
|
||||
can result in a non-zero exit code.
|
||||
- Better reporting of failed uploads due to out of device space or quota all
|
||||
used.
|
||||
- OpenSSL support.
|
||||
- Fix for systems with no IPv6 (e.g. Solaris 7).
|
||||
- PASV auto address guessing?
|
||||
- option to chroot to home dir and THEN apply init_dir
|
||||
- pasv_addr_file option (patch from Adam Luter)
|
||||
- Sweedish characters showing as ? in the log.
|
||||
- Handle SIGINT.
|
||||
- More stuff in the STAT output (session stats, etc. Perhaps even an "admin"
|
||||
mode which dumps session details?).
|
||||
|
||||
- separate upload/download max rates
|
||||
- select() is assuming Linux behaviour (not threatening stability)
|
||||
- some FTP clients are trying to use MDTM to _set_ timestamps?
|
||||
- add example global bandwidth limiting.
|
||||
- put anon FTP users in wtmp too?
|
||||
- switch to new signal model
|
||||
@ -36,10 +31,21 @@ mode which dumps session details?).
|
||||
ON THE BACK BURNER
|
||||
==================
|
||||
|
||||
- MLST, MLSD
|
||||
- LPRT, LPSV
|
||||
- lock the files being modified?
|
||||
- Small race: signal might come in just before we start a blocking call
|
||||
- log logout (pam session support provides this for locals)
|
||||
- Limits on GIDs allowed to authenticate?
|
||||
- Dynamic login info e.g. you are user XXX of YYY.
|
||||
- Handle SIGINT.
|
||||
- Session byte transfer counts in STAT output.
|
||||
- OOPS: capset issue with some 2.6 kernel / distro combinations (cannot
|
||||
reproduce; kernel bug?)
|
||||
- Mac OS X setgroups() issue (report of success with 10.3.4, maybe OS X bug
|
||||
has been fixed?)
|
||||
- Fix for systems with no IPv6 (e.g. Solaris 7) (I'm only getting limited
|
||||
numbers of these reports)
|
||||
|
||||
NOT PLANNED
|
||||
===========
|
||||
|
2
banner.c
2
banner.c
@ -21,7 +21,7 @@
|
||||
|
||||
/* Definitions */
|
||||
#define VSFTP_MAX_VISIT_REMEMBER 100
|
||||
#define VSFTP_MAX_MSGFILE_SIZE 1000
|
||||
#define VSFTP_MAX_MSGFILE_SIZE 4000
|
||||
|
||||
void
|
||||
vsf_banner_dir_changed(struct vsf_session* p_sess, int ftpcode)
|
||||
|
@ -2,6 +2,8 @@
|
||||
#define VSF_BUILDDEFS_H
|
||||
|
||||
#undef VSF_BUILD_TCPWRAPPERS
|
||||
#define VSF_BUILD_PAM
|
||||
#undef VSF_BUILD_SSL
|
||||
|
||||
#endif /* VSF_BUILDDEFS_H */
|
||||
|
||||
|
3
defs.h
3
defs.h
@ -8,7 +8,6 @@
|
||||
#define VSFTP_PASSWORD_MAX 128
|
||||
#define VSFTP_USERNAME_MAX 32
|
||||
#define VSFTP_MAX_COMMAND_LINE 4096
|
||||
#define VSFTP_PRIVSOCK_MAXSTR 1024
|
||||
#define VSFTP_DATA_BUFSIZE 65536
|
||||
#define VSFTP_DIR_BUFSIZE 16384
|
||||
#define VSFTP_PATH_MAX 4096
|
||||
@ -16,6 +15,8 @@
|
||||
#define VSFTP_LISTEN_BACKLOG 32
|
||||
#define VSFTP_SECURE_UMASK 077
|
||||
#define VSFTP_ROOT_UID 0
|
||||
/* Must be greater than both VSFTP_MAX_COMMAND_LINE and VSFTP_DIR_BUFSIZE */
|
||||
#define VSFTP_PRIVSOCK_MAXSTR VSFTP_DIR_BUFSIZE
|
||||
|
||||
#endif /* VSF_DEFS_H */
|
||||
|
||||
|
7
dummyinc/openssl/ssl.h
Normal file
7
dummyinc/openssl/ssl.h
Normal file
@ -0,0 +1,7 @@
|
||||
#ifndef VSF_DUMMYINC_SSL_H
|
||||
#define VSF_DUMMYINC_SSL_H
|
||||
|
||||
#undef VSF_BUILD_SSL
|
||||
|
||||
#endif /* VSF_DUMMYINC_SSL_H */
|
||||
|
38
features.c
Normal file
38
features.c
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Part of Very Secure FTPd
|
||||
* Licence: GPL
|
||||
* Author: Chris Evans
|
||||
* features.c
|
||||
*
|
||||
* Routines to tell the client what features we support.
|
||||
*/
|
||||
|
||||
#include "features.h"
|
||||
#include "ftpcodes.h"
|
||||
#include "ftpcmdio.h"
|
||||
#include "tunables.h"
|
||||
|
||||
void
|
||||
handle_feat(struct vsf_session* p_sess)
|
||||
{
|
||||
vsf_cmdio_write_hyphen(p_sess, FTP_FEAT, "Features:");
|
||||
if (tunable_ssl_enable)
|
||||
{
|
||||
vsf_cmdio_write_raw(p_sess, " AUTH SSL\r\n");
|
||||
vsf_cmdio_write_raw(p_sess, " AUTH TLS\r\n");
|
||||
}
|
||||
vsf_cmdio_write_raw(p_sess, " EPRT\r\n");
|
||||
vsf_cmdio_write_raw(p_sess, " EPSV\r\n");
|
||||
vsf_cmdio_write_raw(p_sess, " MDTM\r\n");
|
||||
vsf_cmdio_write_raw(p_sess, " PASV\r\n");
|
||||
if (tunable_ssl_enable)
|
||||
{
|
||||
vsf_cmdio_write_raw(p_sess, " PBSZ\r\n");
|
||||
vsf_cmdio_write_raw(p_sess, " PROT\r\n");
|
||||
}
|
||||
vsf_cmdio_write_raw(p_sess, " REST STREAM\r\n");
|
||||
vsf_cmdio_write_raw(p_sess, " SIZE\r\n");
|
||||
vsf_cmdio_write_raw(p_sess, " TVFS\r\n");
|
||||
vsf_cmdio_write(p_sess, FTP_FEAT, "End");
|
||||
}
|
||||
|
9
features.h
Normal file
9
features.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef VSF_FEATURES_H
|
||||
#define VSF_FEATURES_H
|
||||
|
||||
struct vsf_session;
|
||||
|
||||
void handle_feat(struct vsf_session* p_sess);
|
||||
|
||||
#endif /* VSF_FEATURES_H */
|
||||
|
35
ftpcmdio.c
35
ftpcmdio.c
@ -18,9 +18,10 @@
|
||||
#include "utility.h"
|
||||
#include "logging.h"
|
||||
#include "session.h"
|
||||
#include "readwrite.h"
|
||||
|
||||
/* Internal functions */
|
||||
static void ftp_getline(struct mystr* p_str);
|
||||
static void control_getline(struct mystr* p_str, struct vsf_session* p_sess);
|
||||
static void ftp_write_text_common(struct vsf_session* p_sess, int status,
|
||||
const char* p_text, int noblock, char sep);
|
||||
static void ftp_write_str_common(struct vsf_session* p_sess, int status,
|
||||
@ -67,10 +68,10 @@ vsf_cmdio_write_raw(struct vsf_session* p_sess, const char* p_text)
|
||||
{
|
||||
vsf_log_line(p_sess, kVSFLogEntryFTPOutput, &s_the_str);
|
||||
}
|
||||
retval = str_netfd_write(&s_the_str, VSFTP_COMMAND_FD);
|
||||
retval = ftp_write_str(p_sess, &s_the_str, kVSFRWControl);
|
||||
if (retval != 0)
|
||||
{
|
||||
die("str_netfd_write");
|
||||
die("ftp_write_str");
|
||||
}
|
||||
}
|
||||
|
||||
@ -111,6 +112,7 @@ ftp_write_str_common(struct vsf_session* p_sess, int status, char sep,
|
||||
{
|
||||
static struct mystr s_write_buf_str;
|
||||
static struct mystr s_text_mangle_str;
|
||||
int retval;
|
||||
if (tunable_log_ftp_protocol)
|
||||
{
|
||||
str_alloc_ulong(&s_write_buf_str, (unsigned long) status);
|
||||
@ -131,15 +133,16 @@ ftp_write_str_common(struct vsf_session* p_sess, int status, char sep,
|
||||
str_append_text(&s_write_buf_str, "\r\n");
|
||||
if (noblock)
|
||||
{
|
||||
(void) str_netfd_write_noblock(&s_write_buf_str, VSFTP_COMMAND_FD);
|
||||
vsf_sysutil_activate_noblock(VSFTP_COMMAND_FD);
|
||||
}
|
||||
else
|
||||
retval = ftp_write_str(p_sess, &s_write_buf_str, kVSFRWControl);
|
||||
if (retval != 0 && !noblock)
|
||||
{
|
||||
int retval = str_netfd_write(&s_write_buf_str, VSFTP_COMMAND_FD);
|
||||
if (retval != 0)
|
||||
{
|
||||
die("str_netfd_write");
|
||||
}
|
||||
die("ftp_write");
|
||||
}
|
||||
if (noblock)
|
||||
{
|
||||
vsf_sysutil_deactivate_noblock(VSFTP_COMMAND_FD);
|
||||
}
|
||||
}
|
||||
|
||||
@ -164,7 +167,7 @@ vsf_cmdio_get_cmd_and_arg(struct vsf_session* p_sess, struct mystr* p_cmd_str,
|
||||
vsf_cmdio_set_alarm(p_sess);
|
||||
}
|
||||
/* Blocks */
|
||||
ftp_getline(p_cmd_str);
|
||||
control_getline(p_cmd_str, p_sess);
|
||||
str_split_char(p_cmd_str, p_arg_str, ' ');
|
||||
str_upper(p_cmd_str);
|
||||
if (tunable_log_ftp_protocol)
|
||||
@ -188,15 +191,13 @@ vsf_cmdio_get_cmd_and_arg(struct vsf_session* p_sess, struct mystr* p_cmd_str,
|
||||
}
|
||||
|
||||
static void
|
||||
ftp_getline(struct mystr* p_str)
|
||||
control_getline(struct mystr* p_str, struct vsf_session* p_sess)
|
||||
{
|
||||
static char* s_p_readline_buf;
|
||||
if (s_p_readline_buf == 0)
|
||||
if (p_sess->p_control_line_buf == 0)
|
||||
{
|
||||
vsf_secbuf_alloc(&s_p_readline_buf, VSFTP_MAX_COMMAND_LINE);
|
||||
vsf_secbuf_alloc(&p_sess->p_control_line_buf, VSFTP_MAX_COMMAND_LINE);
|
||||
}
|
||||
str_netfd_alloc(p_str, VSFTP_COMMAND_FD, '\n', s_p_readline_buf,
|
||||
VSFTP_MAX_COMMAND_LINE);
|
||||
ftp_getline(p_sess, p_str, p_sess->p_control_line_buf);
|
||||
/* As mandated by the FTP specifications.. */
|
||||
str_replace_char(p_str, '\0', '\n');
|
||||
/* If the last character is a \r, strip it */
|
||||
|
11
ftpcodes.h
11
ftpcodes.h
@ -12,6 +12,8 @@
|
||||
#define FTP_EPSVALLOK 200
|
||||
#define FTP_STRUOK 200
|
||||
#define FTP_MODEOK 200
|
||||
#define FTP_PBSZOK 200
|
||||
#define FTP_PROTOK 200
|
||||
#define FTP_ALLOOK 202
|
||||
#define FTP_FEAT 211
|
||||
#define FTP_STATOK 211
|
||||
@ -29,6 +31,7 @@
|
||||
#define FTP_PASVOK 227
|
||||
#define FTP_EPSVOK 229
|
||||
#define FTP_LOGINOK 230
|
||||
#define FTP_AUTHOK 234
|
||||
#define FTP_CWDOK 250
|
||||
#define FTP_RMDIROK 250
|
||||
#define FTP_DELEOK 250
|
||||
@ -45,6 +48,7 @@
|
||||
#define FTP_TOO_MANY_USERS 421
|
||||
#define FTP_IP_LIMIT 421
|
||||
#define FTP_IP_DENY 421
|
||||
#define FTP_TLS_FAIL 421
|
||||
#define FTP_BADSENDCONN 425
|
||||
#define FTP_BADSENDNET 426
|
||||
#define FTP_BADSENDFILE 451
|
||||
@ -54,10 +58,17 @@
|
||||
#define FTP_COMMANDNOTIMPL 502
|
||||
#define FTP_NEEDUSER 503
|
||||
#define FTP_NEEDRNFR 503
|
||||
#define FTP_BADPBSZ 503
|
||||
#define FTP_BADPROT 503
|
||||
#define FTP_BADSTRU 504
|
||||
#define FTP_BADMODE 504
|
||||
#define FTP_BADAUTH 504
|
||||
#define FTP_NOSUCHPROT 504
|
||||
#define FTP_NEEDENCRYPT 521
|
||||
#define FTP_EPSVBAD 522
|
||||
#define FTP_DATATLSBAD 522
|
||||
#define FTP_LOGINERR 530
|
||||
#define FTP_NOHANDLEPROT 536
|
||||
#define FTP_FILEFAIL 550
|
||||
#define FTP_NOPERM 550
|
||||
#define FTP_UPLOADFAIL 553
|
||||
|
205
ftpdataio.c
205
ftpdataio.c
@ -27,24 +27,29 @@
|
||||
#include "oneprocess.h"
|
||||
#include "twoprocess.h"
|
||||
#include "ls.h"
|
||||
#include "netstr.h"
|
||||
#include "ssl.h"
|
||||
#include "readwrite.h"
|
||||
|
||||
static void init_data_sock_params(struct vsf_session* p_sess, int sock_fd);
|
||||
static struct vsf_transfer_ret do_file_send_binary(struct vsf_session* p_sess,
|
||||
int net_fd, int file_fd);
|
||||
static struct vsf_transfer_ret do_file_send_ascii(struct vsf_session* p_sess,
|
||||
int net_fd, int file_fd);
|
||||
static filesize_t calc_num_send(int file_fd, filesize_t init_offset);
|
||||
static struct vsf_transfer_ret do_file_send_sendfile(
|
||||
struct vsf_session* p_sess, int net_fd, int file_fd,
|
||||
filesize_t curr_file_offset, filesize_t bytes_to_send);
|
||||
static struct vsf_transfer_ret do_file_send_rwloop(
|
||||
struct vsf_session* p_sess, int file_fd, int is_ascii);
|
||||
static struct vsf_transfer_ret do_file_recv(
|
||||
struct vsf_session* p_sess, int net_fd, int file_fd, int is_ascii);
|
||||
struct vsf_session* p_sess, int file_fd, int is_ascii);
|
||||
static void handle_sigalrm(void* p_private);
|
||||
static void start_data_alarm(struct vsf_session* p_sess);
|
||||
static void handle_io(int retval, int fd, void* p_private);
|
||||
static int transfer_dir_internal(
|
||||
struct vsf_session* p_sess, const int remote_fd,
|
||||
struct vsf_sysutil_dir* p_dir, const struct mystr* p_base_dir_str,
|
||||
const struct mystr* p_option_str, const struct mystr* p_filter_str,
|
||||
int is_verbose);
|
||||
static int write_dir_list(struct mystr_list* p_dir_list, int remote_fd);
|
||||
struct vsf_session* p_sess, int is_control, struct vsf_sysutil_dir* p_dir,
|
||||
const struct mystr* p_base_dir_str, const struct mystr* p_option_str,
|
||||
const struct mystr* p_filter_str, int is_verbose);
|
||||
static int write_dir_list(struct vsf_session* p_sess,
|
||||
struct mystr_list* p_dir_list,
|
||||
enum EVSFRWTarget target);
|
||||
static unsigned int get_chunk_size();
|
||||
|
||||
void
|
||||
vsf_ftpdataio_dispose_transfer_fd(struct vsf_session* p_sess)
|
||||
@ -57,6 +62,10 @@ vsf_ftpdataio_dispose_transfer_fd(struct vsf_session* p_sess)
|
||||
/* Clear the data connection alarm */
|
||||
vsf_sysutil_clear_alarm();
|
||||
vsf_sysutil_uninstall_io_handler();
|
||||
if (p_sess->p_data_ssl != 0)
|
||||
{
|
||||
ssl_data_close(p_sess);
|
||||
}
|
||||
/* This close() blocks because we set SO_LINGER */
|
||||
retval = vsf_sysutil_close_failok(p_sess->data_fd);
|
||||
if (vsf_sysutil_retval_is_error(retval))
|
||||
@ -146,6 +155,21 @@ vsf_ftpdataio_get_port_fd(struct vsf_session* p_sess)
|
||||
return remote_fd;
|
||||
}
|
||||
|
||||
int
|
||||
vsf_ftpdataio_post_mark_connect(struct vsf_session* p_sess)
|
||||
{
|
||||
if (p_sess->data_use_ssl)
|
||||
{
|
||||
if (!ssl_accept(p_sess, p_sess->data_fd))
|
||||
{
|
||||
vsf_cmdio_write(
|
||||
p_sess, FTP_DATATLSBAD, "Secure connection negotiation failed.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
handle_sigalrm(void* p_private)
|
||||
{
|
||||
@ -241,19 +265,19 @@ handle_io(int retval, int fd, void* p_private)
|
||||
}
|
||||
|
||||
int
|
||||
vsf_ftpdataio_transfer_dir(struct vsf_session* p_sess, const int remote_fd,
|
||||
vsf_ftpdataio_transfer_dir(struct vsf_session* p_sess, int is_control,
|
||||
struct vsf_sysutil_dir* p_dir,
|
||||
const struct mystr* p_base_dir_str,
|
||||
const struct mystr* p_option_str,
|
||||
const struct mystr* p_filter_str,
|
||||
int is_verbose)
|
||||
{
|
||||
return transfer_dir_internal(p_sess, remote_fd, p_dir, p_base_dir_str,
|
||||
return transfer_dir_internal(p_sess, is_control, p_dir, p_base_dir_str,
|
||||
p_option_str, p_filter_str, is_verbose);
|
||||
}
|
||||
|
||||
static int
|
||||
transfer_dir_internal(struct vsf_session* p_sess, const int remote_fd,
|
||||
transfer_dir_internal(struct vsf_session* p_sess, int is_control,
|
||||
struct vsf_sysutil_dir* p_dir,
|
||||
const struct mystr* p_base_dir_str,
|
||||
const struct mystr* p_option_str,
|
||||
@ -266,6 +290,11 @@ transfer_dir_internal(struct vsf_session* p_sess, const int remote_fd,
|
||||
struct mystr_list* p_subdir_list = 0;
|
||||
struct str_locate_result loc_result = str_locate_char(p_option_str, 'R');
|
||||
int failed = 0;
|
||||
enum EVSFRWTarget target = kVSFRWData;
|
||||
if (is_control)
|
||||
{
|
||||
target = kVSFRWControl;
|
||||
}
|
||||
if (loc_result.found && tunable_ls_recurse_enable)
|
||||
{
|
||||
p_subdir_list = &subdir_list;
|
||||
@ -277,7 +306,7 @@ transfer_dir_internal(struct vsf_session* p_sess, const int remote_fd,
|
||||
int retval;
|
||||
str_copy(&dir_prefix_str, p_base_dir_str);
|
||||
str_append_text(&dir_prefix_str, ":\r\n");
|
||||
retval = str_netfd_write(&dir_prefix_str, remote_fd);
|
||||
retval = ftp_write_str(p_sess, &dir_prefix_str, target);
|
||||
if (retval != 0)
|
||||
{
|
||||
failed = 1;
|
||||
@ -285,7 +314,7 @@ transfer_dir_internal(struct vsf_session* p_sess, const int remote_fd,
|
||||
}
|
||||
if (!failed)
|
||||
{
|
||||
failed = write_dir_list(&dir_list, remote_fd);
|
||||
failed = write_dir_list(p_sess, &dir_list, target);
|
||||
}
|
||||
/* Recurse into the subdirectories if required... */
|
||||
if (!failed)
|
||||
@ -314,13 +343,13 @@ transfer_dir_internal(struct vsf_session* p_sess, const int remote_fd,
|
||||
continue;
|
||||
}
|
||||
str_alloc_text(&dir_prefix_str, "\r\n");
|
||||
retval = str_netfd_write(&dir_prefix_str, remote_fd);
|
||||
retval = ftp_write_str(p_sess, &dir_prefix_str, target);
|
||||
if (retval != 0)
|
||||
{
|
||||
failed = 1;
|
||||
break;
|
||||
}
|
||||
retval = transfer_dir_internal(p_sess, remote_fd, p_subdir, &sub_str,
|
||||
retval = transfer_dir_internal(p_sess, is_control, p_subdir, &sub_str,
|
||||
p_option_str, p_filter_str, is_verbose);
|
||||
vsf_sysutil_closedir(p_subdir);
|
||||
if (retval != 0)
|
||||
@ -346,7 +375,8 @@ transfer_dir_internal(struct vsf_session* p_sess, const int remote_fd,
|
||||
|
||||
/* XXX - really, this should be refactored into a "buffered writer" object */
|
||||
static int
|
||||
write_dir_list(struct mystr_list* p_dir_list, int remote_fd)
|
||||
write_dir_list(struct vsf_session* p_sess, struct mystr_list* p_dir_list,
|
||||
enum EVSFRWTarget target)
|
||||
{
|
||||
/* This function writes out a list of strings to the client, over the
|
||||
* data socket. We now coalesce the strings into fewer write() syscalls,
|
||||
@ -366,7 +396,7 @@ write_dir_list(struct mystr_list* p_dir_list, int remote_fd)
|
||||
VSFTP_DIR_BUFSIZE)
|
||||
{
|
||||
/* Writeout needed - we're either at the end, or we filled the buffer */
|
||||
int writeret = str_netfd_write(&buf_str, remote_fd);
|
||||
int writeret = ftp_write_str(p_sess, &buf_str, target);
|
||||
if (writeret != 0)
|
||||
{
|
||||
retval = 1;
|
||||
@ -385,33 +415,32 @@ vsf_ftpdataio_transfer_file(struct vsf_session* p_sess, int remote_fd,
|
||||
{
|
||||
if (!is_recv)
|
||||
{
|
||||
if (is_ascii)
|
||||
if (is_ascii || p_sess->data_use_ssl)
|
||||
{
|
||||
return do_file_send_ascii(p_sess, remote_fd, file_fd);
|
||||
return do_file_send_rwloop(p_sess, file_fd, is_ascii);
|
||||
}
|
||||
else
|
||||
{
|
||||
return do_file_send_binary(p_sess, remote_fd, file_fd);
|
||||
filesize_t curr_offset = vsf_sysutil_get_file_offset(file_fd);
|
||||
filesize_t num_send = calc_num_send(file_fd, curr_offset);
|
||||
return do_file_send_sendfile(
|
||||
p_sess, remote_fd, file_fd, curr_offset, num_send);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return do_file_recv(p_sess, remote_fd, file_fd, is_ascii);
|
||||
return do_file_recv(p_sess, file_fd, is_ascii);
|
||||
}
|
||||
}
|
||||
|
||||
static struct vsf_transfer_ret
|
||||
do_file_send_ascii(struct vsf_session* p_sess, int net_fd, int file_fd)
|
||||
do_file_send_rwloop(struct vsf_session* p_sess, int file_fd, int is_ascii)
|
||||
{
|
||||
static char* p_readbuf;
|
||||
static char* p_asciibuf;
|
||||
struct vsf_transfer_ret ret_struct = { 0, 0 };
|
||||
unsigned int chunk_size = VSFTP_DATA_BUFSIZE;
|
||||
if (tunable_trans_chunk_size < VSFTP_DATA_BUFSIZE &&
|
||||
tunable_trans_chunk_size >= 4096)
|
||||
{
|
||||
chunk_size = tunable_trans_chunk_size;
|
||||
}
|
||||
unsigned int chunk_size = get_chunk_size();
|
||||
char* p_writefrom_buf;
|
||||
if (p_readbuf == 0)
|
||||
{
|
||||
/* NOTE!! * 2 factor because we can double the data by doing our ASCII
|
||||
@ -420,6 +449,14 @@ do_file_send_ascii(struct vsf_session* p_sess, int net_fd, int file_fd)
|
||||
vsf_secbuf_alloc(&p_asciibuf, VSFTP_DATA_BUFSIZE * 2);
|
||||
vsf_secbuf_alloc(&p_readbuf, VSFTP_DATA_BUFSIZE);
|
||||
}
|
||||
if (is_ascii)
|
||||
{
|
||||
p_writefrom_buf = p_asciibuf;
|
||||
}
|
||||
else
|
||||
{
|
||||
p_writefrom_buf = p_readbuf;
|
||||
}
|
||||
while (1)
|
||||
{
|
||||
unsigned int num_to_write;
|
||||
@ -436,9 +473,16 @@ do_file_send_ascii(struct vsf_session* p_sess, int net_fd, int file_fd)
|
||||
vsf_cmdio_write(p_sess, FTP_TRANSFEROK, "File send OK.");
|
||||
return ret_struct;
|
||||
}
|
||||
num_to_write = vsf_ascii_bin_to_ascii(p_readbuf, p_asciibuf,
|
||||
(unsigned int) retval);
|
||||
retval = vsf_sysutil_write_loop(net_fd, p_asciibuf, num_to_write);
|
||||
if (is_ascii)
|
||||
{
|
||||
num_to_write = vsf_ascii_bin_to_ascii(p_readbuf, p_asciibuf,
|
||||
(unsigned int) retval);
|
||||
}
|
||||
else
|
||||
{
|
||||
num_to_write = (unsigned int) retval;
|
||||
}
|
||||
retval = ftp_write_data(p_sess, p_writefrom_buf, num_to_write);
|
||||
if (vsf_sysutil_retval_is_error(retval) ||
|
||||
(unsigned int) retval != num_to_write)
|
||||
{
|
||||
@ -452,47 +496,17 @@ do_file_send_ascii(struct vsf_session* p_sess, int net_fd, int file_fd)
|
||||
}
|
||||
|
||||
static struct vsf_transfer_ret
|
||||
do_file_send_binary(struct vsf_session* p_sess, int net_fd, int file_fd)
|
||||
do_file_send_sendfile(struct vsf_session* p_sess, int net_fd, int file_fd,
|
||||
filesize_t curr_file_offset, filesize_t bytes_to_send)
|
||||
{
|
||||
static struct vsf_sysutil_statbuf* s_p_statbuf;
|
||||
int retval;
|
||||
filesize_t bytes_to_send;
|
||||
filesize_t init_file_offset;
|
||||
filesize_t curr_file_offset;
|
||||
filesize_t bytes_sent;
|
||||
unsigned int chunk_size;
|
||||
unsigned int chunk_size = 0;
|
||||
struct vsf_transfer_ret ret_struct = { 0, 0 };
|
||||
/* Work out how many bytes to send based on file size minus current offset */
|
||||
/* NOTE - if we're being pedantic here are two duplicated syscalls */
|
||||
vsf_sysutil_fstat(file_fd, &s_p_statbuf);
|
||||
bytes_to_send = vsf_sysutil_statbuf_get_size(s_p_statbuf);
|
||||
init_file_offset = vsf_sysutil_get_file_offset(file_fd);
|
||||
if (init_file_offset < 0 || bytes_to_send < 0)
|
||||
{
|
||||
die("do_file_send_binary: negative file offset or send count");
|
||||
}
|
||||
curr_file_offset = init_file_offset;
|
||||
/* Don't underflow if some bonehead sets a REST greater than the file size */
|
||||
if (init_file_offset > bytes_to_send)
|
||||
{
|
||||
bytes_to_send = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
bytes_to_send -= init_file_offset;
|
||||
}
|
||||
filesize_t init_file_offset = curr_file_offset;
|
||||
filesize_t bytes_sent;
|
||||
if (p_sess->bw_rate_max)
|
||||
{
|
||||
chunk_size = VSFTP_DATA_BUFSIZE;
|
||||
if (tunable_trans_chunk_size < VSFTP_DATA_BUFSIZE &&
|
||||
tunable_trans_chunk_size >= 4096)
|
||||
{
|
||||
chunk_size = tunable_trans_chunk_size;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
chunk_size = 0;
|
||||
chunk_size = get_chunk_size();
|
||||
}
|
||||
/* Just because I can ;-) */
|
||||
retval = vsf_sysutil_sendfile(net_fd, file_fd, &curr_file_offset,
|
||||
@ -516,25 +530,44 @@ do_file_send_binary(struct vsf_session* p_sess, int net_fd, int file_fd)
|
||||
return ret_struct;
|
||||
}
|
||||
|
||||
static filesize_t
|
||||
calc_num_send(int file_fd, filesize_t init_offset)
|
||||
{
|
||||
static struct vsf_sysutil_statbuf* s_p_statbuf;
|
||||
filesize_t bytes_to_send;
|
||||
/* Work out how many bytes to send based on file size minus current offset */
|
||||
vsf_sysutil_fstat(file_fd, &s_p_statbuf);
|
||||
bytes_to_send = vsf_sysutil_statbuf_get_size(s_p_statbuf);
|
||||
if (init_offset < 0 || bytes_to_send < 0)
|
||||
{
|
||||
die("calc_num_send: negative file offset or send count");
|
||||
}
|
||||
/* Don't underflow if some bonehead sets a REST greater than the file size */
|
||||
if (init_offset > bytes_to_send)
|
||||
{
|
||||
bytes_to_send = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
bytes_to_send -= init_offset;
|
||||
}
|
||||
return bytes_to_send;
|
||||
}
|
||||
|
||||
static struct vsf_transfer_ret
|
||||
do_file_recv(struct vsf_session* p_sess, int net_fd, int file_fd, int is_ascii)
|
||||
do_file_recv(struct vsf_session* p_sess, int file_fd, int is_ascii)
|
||||
{
|
||||
static char* p_recvbuf;
|
||||
unsigned int num_to_write;
|
||||
struct vsf_transfer_ret ret_struct = { 0, 0 };
|
||||
unsigned int chunk_size = VSFTP_DATA_BUFSIZE;
|
||||
unsigned int chunk_size = get_chunk_size();
|
||||
if (p_recvbuf == 0)
|
||||
{
|
||||
vsf_secbuf_alloc(&p_recvbuf, VSFTP_DATA_BUFSIZE);
|
||||
}
|
||||
if (tunable_trans_chunk_size < VSFTP_DATA_BUFSIZE &&
|
||||
tunable_trans_chunk_size >= 4096)
|
||||
{
|
||||
chunk_size = tunable_trans_chunk_size;
|
||||
}
|
||||
while (1)
|
||||
{
|
||||
int retval = vsf_sysutil_read(net_fd, p_recvbuf, chunk_size);
|
||||
int retval = ftp_read_data(p_sess, p_recvbuf, chunk_size);
|
||||
if (vsf_sysutil_retval_is_error(retval))
|
||||
{
|
||||
vsf_cmdio_write(p_sess, FTP_BADSENDNET,
|
||||
@ -571,3 +604,19 @@ do_file_recv(struct vsf_session* p_sess, int net_fd, int file_fd, int is_ascii)
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
get_chunk_size()
|
||||
{
|
||||
unsigned int ret = VSFTP_DATA_BUFSIZE;
|
||||
if (tunable_trans_chunk_size < VSFTP_DATA_BUFSIZE &&
|
||||
tunable_trans_chunk_size > 0)
|
||||
{
|
||||
ret = tunable_trans_chunk_size;
|
||||
if (ret < 4096)
|
||||
{
|
||||
ret = 4096;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
17
ftpdataio.h
17
ftpdataio.h
@ -40,6 +40,17 @@ int vsf_ftpdataio_get_pasv_fd(struct vsf_session* p_sess);
|
||||
*/
|
||||
int vsf_ftpdataio_get_port_fd(struct vsf_session* p_sess);
|
||||
|
||||
/* vsf_ftpdataio_post_mark_connect()
|
||||
* PURPOSE
|
||||
* Perform any post-150-status-mark setup on the data connection. For example,
|
||||
* the negotiation of SSL.
|
||||
* PARAMETERS
|
||||
* p_sess - the current FTP session object
|
||||
* RETURNS
|
||||
* 1 on success, 0 otherwise.
|
||||
*/
|
||||
int vsf_ftpdataio_post_mark_connect(struct vsf_session* p_sess);
|
||||
|
||||
/* vsf_ftpdataio_transfer_file()
|
||||
* PURPOSE
|
||||
* Send data between the network and a local file. Send and receive are
|
||||
@ -69,15 +80,15 @@ struct vsf_transfer_ret vsf_ftpdataio_transfer_file(
|
||||
* client.
|
||||
* PARAMETERS
|
||||
* p_sess - the current session object
|
||||
* remote_fd - the file descriptor of the remote data connection
|
||||
* is_control - whether to send on the control connection or data connection
|
||||
* p_dir - the local directory object
|
||||
* p_base_dir_str - the directory we opened relative to the current one
|
||||
* p_option_str - the options list provided to "ls"
|
||||
* p_filter_str - the filter string provided to "ls"
|
||||
* is_verbose - set to 0 if NLST used, 1 if LIST used
|
||||
*/
|
||||
int vsf_ftpdataio_transfer_dir(struct vsf_session* p_sess,
|
||||
int remote_fd, struct vsf_sysutil_dir* p_dir,
|
||||
int vsf_ftpdataio_transfer_dir(struct vsf_session* p_sess, int is_control,
|
||||
struct vsf_sysutil_dir* p_dir,
|
||||
const struct mystr* p_base_dir_str,
|
||||
const struct mystr* p_option_str,
|
||||
const struct mystr* p_filter_str,
|
||||
|
36
logging.c
36
logging.c
@ -95,6 +95,16 @@ vsf_log_line(struct vsf_session* p_sess, enum EVSFLogEntryType what,
|
||||
vsf_log_common(p_sess, 1, what, p_str);
|
||||
}
|
||||
|
||||
int
|
||||
vsf_log_entry_pending(struct vsf_session* p_sess)
|
||||
{
|
||||
if (p_sess->log_type == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
vsf_log_do_log(struct vsf_session* p_sess, int succeeded)
|
||||
{
|
||||
@ -136,16 +146,22 @@ vsf_log_common(struct vsf_session* p_sess, int succeeded,
|
||||
static void
|
||||
vsf_log_do_log_to_file(int fd, struct mystr* p_str)
|
||||
{
|
||||
int retval = vsf_sysutil_lock_file(fd);
|
||||
if (vsf_sysutil_retval_is_error(retval))
|
||||
if (!tunable_no_log_lock)
|
||||
{
|
||||
return;
|
||||
int retval = vsf_sysutil_lock_file(fd);
|
||||
if (vsf_sysutil_retval_is_error(retval))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
str_replace_unprintable(p_str, '?');
|
||||
str_append_char(p_str, '\n');
|
||||
/* Ignore write failure; maybe the disk filled etc. */
|
||||
(void) str_write_loop(p_str, fd);
|
||||
vsf_sysutil_unlock_file(fd);
|
||||
if (!tunable_no_log_lock)
|
||||
{
|
||||
vsf_sysutil_unlock_file(fd);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@ -273,6 +289,18 @@ vsf_log_do_log_vsftpd_format(struct vsf_session* p_sess, struct mystr* p_str,
|
||||
case kVSFLogEntryConnection:
|
||||
str_append_text(p_str, "CONNECT");
|
||||
break;
|
||||
case kVSFLogEntryDelete:
|
||||
str_append_text(p_str, "DELETE");
|
||||
break;
|
||||
case kVSFLogEntryRename:
|
||||
str_append_text(p_str, "RENAME");
|
||||
break;
|
||||
case kVSFLogEntryRmdir:
|
||||
str_append_text(p_str, "RMDIR");
|
||||
break;
|
||||
case kVSFLogEntryChmod:
|
||||
str_append_text(p_str, "CHMOD");
|
||||
break;
|
||||
default:
|
||||
bug("bad entry_type in vsf_log_do_log");
|
||||
break;
|
||||
|
14
logging.h
14
logging.h
@ -14,7 +14,11 @@ enum EVSFLogEntryType
|
||||
kVSFLogEntryLogin,
|
||||
kVSFLogEntryFTPInput,
|
||||
kVSFLogEntryFTPOutput,
|
||||
kVSFLogEntryConnection
|
||||
kVSFLogEntryConnection,
|
||||
kVSFLogEntryDelete,
|
||||
kVSFLogEntryRename,
|
||||
kVSFLogEntryRmdir,
|
||||
kVSFLogEntryChmod
|
||||
};
|
||||
|
||||
/* vsf_log_init()
|
||||
@ -37,6 +41,14 @@ void vsf_log_init(struct vsf_session* p_sess);
|
||||
void vsf_log_start_entry(struct vsf_session* p_sess,
|
||||
enum EVSFLogEntryType what);
|
||||
|
||||
/* vsf_log_entry_pending()
|
||||
* PURPOSE
|
||||
* Determine whether a log entry has been started and not yet closed.
|
||||
* RETURNS
|
||||
* 0 if no log entry is pending; 1 if one is.
|
||||
*/
|
||||
int vsf_log_entry_pending(struct vsf_session* p_sess);
|
||||
|
||||
/* vsf_log_do_log()
|
||||
* PURPOSE
|
||||
* Denote the end of a logged operation, specifying whether the operation
|
||||
|
23
main.c
23
main.c
@ -21,6 +21,7 @@
|
||||
#include "standalone.h"
|
||||
#include "tcpwrap.h"
|
||||
#include "vsftpver.h"
|
||||
#include "ssl.h"
|
||||
|
||||
/*
|
||||
* Forward decls of helper functions
|
||||
@ -36,7 +37,7 @@ main(int argc, const char* argv[])
|
||||
struct vsf_session the_session =
|
||||
{
|
||||
/* Control connection */
|
||||
0, 0,
|
||||
0, 0, 0,
|
||||
/* Data connection */
|
||||
-1, 0, -1, 0, 0, 0, 0,
|
||||
/* Login */
|
||||
@ -54,9 +55,13 @@ main(int argc, const char* argv[])
|
||||
/* Buffers */
|
||||
INIT_MYSTR, INIT_MYSTR,
|
||||
/* Parent <-> child comms */
|
||||
0, -1, -1,
|
||||
-1, -1,
|
||||
/* Number of clients */
|
||||
0, 0
|
||||
0, 0,
|
||||
/* Home directory */
|
||||
INIT_MYSTR,
|
||||
/* Secure connection state */
|
||||
0, 0, 0, 0, 0, 0, -1, -1
|
||||
};
|
||||
int config_specified = 0;
|
||||
const char* p_config_name = VSFTP_DEFAULT_CONFIG;
|
||||
@ -109,6 +114,13 @@ main(int argc, const char* argv[])
|
||||
/* Warning -- warning -- may nuke argv, environ */
|
||||
vsf_sysutil_setproctitle_init(argc, argv);
|
||||
}
|
||||
/* Initialize the SSL system here if needed - saves the overhead of each
|
||||
* child doing this itself.
|
||||
*/
|
||||
if (tunable_ssl_enable)
|
||||
{
|
||||
ssl_init(&the_session);
|
||||
}
|
||||
if (tunable_listen || tunable_listen_ipv6)
|
||||
{
|
||||
/* Standalone mode */
|
||||
@ -151,6 +163,11 @@ main(int argc, const char* argv[])
|
||||
vsf_parseconf_load_file(p_load_conf, 1);
|
||||
}
|
||||
}
|
||||
/* SSL may have been enabled by a per-IP configuration.. */
|
||||
if (tunable_ssl_enable)
|
||||
{
|
||||
ssl_init(&the_session);
|
||||
}
|
||||
if (tunable_deny_email_enable)
|
||||
{
|
||||
int retval = str_fileread(&the_session.banned_email_str,
|
||||
|
35
netstr.c
35
netstr.c
@ -15,9 +15,6 @@
|
||||
#include "utility.h"
|
||||
#include "sysutil.h"
|
||||
|
||||
static int str_netfd_write_common(const struct mystr* p_str, int fd,
|
||||
int noblock);
|
||||
|
||||
void
|
||||
str_netfd_alloc(struct mystr* p_str, int fd, char term, char* p_readbuf,
|
||||
unsigned int maxlen)
|
||||
@ -85,41 +82,35 @@ str_netfd_alloc(struct mystr* p_str, int fd, char term, char* p_readbuf,
|
||||
} /* END: while(1) */
|
||||
}
|
||||
|
||||
static int
|
||||
str_netfd_write_common(const struct mystr* p_str, int fd, int noblock)
|
||||
int
|
||||
str_netfd_write(const struct mystr* p_str, int fd)
|
||||
{
|
||||
int ret = 0;
|
||||
int retval;
|
||||
unsigned int str_len = str_getlen(p_str);
|
||||
if (str_len == 0)
|
||||
{
|
||||
bug("zero str_len in str_netfd_write_common");
|
||||
}
|
||||
if (noblock)
|
||||
{
|
||||
vsf_sysutil_activate_noblock(fd);
|
||||
bug("zero str_len in str_netfd_write");
|
||||
}
|
||||
retval = str_write_loop(p_str, fd);
|
||||
if (vsf_sysutil_retval_is_error(retval) || (unsigned int) retval != str_len)
|
||||
{
|
||||
ret = -1;
|
||||
}
|
||||
if (noblock)
|
||||
{
|
||||
vsf_sysutil_deactivate_noblock(fd);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
str_netfd_write(const struct mystr* p_str, int fd)
|
||||
str_netfd_read(struct mystr* p_str, int fd, unsigned int len)
|
||||
{
|
||||
return str_netfd_write_common(p_str, fd, 0);
|
||||
}
|
||||
|
||||
int
|
||||
str_netfd_write_noblock(const struct mystr* p_str, int fd)
|
||||
{
|
||||
return str_netfd_write_common(p_str, fd, 1);
|
||||
int retval;
|
||||
str_reserve(p_str, len);
|
||||
str_trunc(p_str, len);
|
||||
retval = str_read_loop(p_str, fd);
|
||||
if (vsf_sysutil_retval_is_error(retval) || (unsigned int) retval != len)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
36
netstr.h
36
netstr.h
@ -23,30 +23,32 @@ struct mystr;
|
||||
void str_netfd_alloc(struct mystr* p_str, int fd, char term,
|
||||
char* p_readbuf, unsigned int maxlen);
|
||||
|
||||
/* str_netfd_read()
|
||||
* PURPOSE
|
||||
* Fills contents of a string buffer object from a (typically network) file
|
||||
* descriptor.
|
||||
* PARAMETERS
|
||||
* p_str - the string object to be filled
|
||||
* fd - the file descriptor to read from
|
||||
* len - the number of bytes to read
|
||||
* RETURNS
|
||||
* Number read on success, -1 on failure. The read is considered a failure
|
||||
* unless the full requested byte count is read.
|
||||
*/
|
||||
int str_netfd_read(struct mystr* p_str, int fd, unsigned int len);
|
||||
|
||||
/* str_netfd_write()
|
||||
* PURPOSE
|
||||
* Write the contents of a string buffer object out to a network file
|
||||
* descriptor. Failure will cause this call to exit the program.
|
||||
* Write the contents of a string buffer object out to a (typically network)
|
||||
* file descriptor.
|
||||
* PARAMETERS
|
||||
* p_str - the string object to send
|
||||
* fd - the file descriptor of the remote network socket
|
||||
* fd - the file descriptor to write to
|
||||
* RETURNS
|
||||
* 0 on success, -1 on failure
|
||||
* Number written on success, -1 on failure. The write is considered a failure
|
||||
* unless the full string buffer object is written.
|
||||
*/
|
||||
int str_netfd_write(const struct mystr* p_str, int fd);
|
||||
|
||||
/* str_netfd_write_noblock()
|
||||
* PURPOSE
|
||||
* Write the contents of a string buffer object out to a network file
|
||||
* descriptor. This call will NOT BLOCK. Furthermore, any errors encountered
|
||||
* will be ignored.
|
||||
* PARAMETERS
|
||||
* p_str - the string object to send
|
||||
* fd - the file descriptor of the remote network socket
|
||||
* RETURNS
|
||||
* 0 on success, -1 on failure
|
||||
*/
|
||||
int str_netfd_write_noblock(const struct mystr* p_str, int fd);
|
||||
|
||||
#endif /* VSFTP_NETSTR_H */
|
||||
|
||||
|
12
parseconf.c
12
parseconf.c
@ -85,6 +85,15 @@ parseconf_bool_array[] =
|
||||
{ "chmod_enable", &tunable_chmod_enable },
|
||||
{ "secure_email_list_enable", &tunable_secure_email_list_enable },
|
||||
{ "run_as_launching_user", &tunable_run_as_launching_user },
|
||||
{ "no_log_lock", &tunable_no_log_lock },
|
||||
{ "ssl_enable", &tunable_ssl_enable },
|
||||
{ "allow_anon_ssl", &tunable_allow_anon_ssl },
|
||||
{ "force_local_logins_ssl", &tunable_force_local_logins_ssl },
|
||||
{ "force_local_data_ssl", &tunable_force_local_data_ssl },
|
||||
{ "ssl_sslv2", &tunable_sslv2 },
|
||||
{ "ssl_sslv3", &tunable_sslv3 },
|
||||
{ "ssl_tlsv1", &tunable_tlsv1 },
|
||||
{ "tilde_user_enable", &tunable_tilde_user_enable },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
@ -146,6 +155,9 @@ parseconf_str_array[] =
|
||||
{ "deny_file", &tunable_deny_file },
|
||||
{ "user_sub_token", &tunable_user_sub_token },
|
||||
{ "email_password_file", &tunable_email_password_file },
|
||||
{ "rsa_cert_file", &tunable_rsa_cert_file },
|
||||
{ "dsa_cert_file", &tunable_dsa_cert_file },
|
||||
{ "ssl_ciphers", &tunable_ssl_ciphers },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
|
307
postlogin.c
307
postlogin.c
@ -23,6 +23,9 @@
|
||||
#include "sysdeputil.h"
|
||||
#include "ipv6parse.h"
|
||||
#include "access.h"
|
||||
#include "features.h"
|
||||
#include "ssl.h"
|
||||
#include "vsftpver.h"
|
||||
|
||||
/* Private local functions */
|
||||
static void handle_pwd(struct vsf_session* p_sess);
|
||||
@ -62,17 +65,21 @@ static void port_cleanup(struct vsf_session* p_sess);
|
||||
static void handle_dir_common(struct vsf_session* p_sess, int full_details,
|
||||
int stat_cmd);
|
||||
static void prepend_path_to_filename(struct mystr* p_str);
|
||||
static int get_remote_transfer_fd(struct vsf_session* p_sess);
|
||||
static int get_remote_transfer_fd(struct vsf_session* p_sess,
|
||||
const char* p_status_msg);
|
||||
static int dispose_remote_transfer_fd(struct vsf_session* p_sess);
|
||||
static void handle_sigurg(void* p_private);
|
||||
static void handle_upload_common(struct vsf_session* p_sess, int is_append,
|
||||
int is_unique);
|
||||
static void get_unique_filename(struct mystr* p_outstr,
|
||||
const struct mystr* p_base);
|
||||
static int data_transfer_checks_ok(struct vsf_session* p_sess);
|
||||
static void resolve_tilde(struct mystr* p_str, struct vsf_session* p_sess);
|
||||
|
||||
void
|
||||
process_post_login(struct vsf_session* p_sess)
|
||||
{
|
||||
str_getcwd(&p_sess->home_str);
|
||||
if (p_sess->is_anonymous)
|
||||
{
|
||||
vsf_sysutil_set_umask(tunable_anon_umask);
|
||||
@ -329,11 +336,7 @@ process_post_login(struct vsf_session* p_sess)
|
||||
}
|
||||
else if (str_equal_text(&p_sess->ftp_cmd_str, "FEAT"))
|
||||
{
|
||||
vsf_cmdio_write_hyphen(p_sess, FTP_FEAT, "Features:");
|
||||
vsf_cmdio_write_raw(p_sess, " MDTM\r\n");
|
||||
vsf_cmdio_write_raw(p_sess, " REST STREAM\r\n");
|
||||
vsf_cmdio_write_raw(p_sess, " SIZE\r\n");
|
||||
vsf_cmdio_write(p_sess, FTP_FEAT, "End");
|
||||
handle_feat(p_sess);
|
||||
}
|
||||
else if (str_equal_text(&p_sess->ftp_cmd_str, "OPTS"))
|
||||
{
|
||||
@ -344,11 +347,19 @@ process_post_login(struct vsf_session* p_sess)
|
||||
{
|
||||
handle_stat(p_sess);
|
||||
}
|
||||
else if (tunable_dirlist_enable &&
|
||||
else if (tunable_dirlist_enable &&
|
||||
str_equal_text(&p_sess->ftp_cmd_str, "STAT"))
|
||||
{
|
||||
handle_stat_file(p_sess);
|
||||
}
|
||||
else if (tunable_ssl_enable && str_equal_text(&p_sess->ftp_cmd_str, "PBSZ"))
|
||||
{
|
||||
handle_pbsz(p_sess);
|
||||
}
|
||||
else if (tunable_ssl_enable && str_equal_text(&p_sess->ftp_cmd_str, "PROT"))
|
||||
{
|
||||
handle_prot(p_sess);
|
||||
}
|
||||
else if (str_equal_text(&p_sess->ftp_cmd_str, "PASV") ||
|
||||
str_equal_text(&p_sess->ftp_cmd_str, "PORT") ||
|
||||
str_equal_text(&p_sess->ftp_cmd_str, "STOR") ||
|
||||
@ -373,7 +384,9 @@ process_post_login(struct vsf_session* p_sess)
|
||||
str_equal_text(&p_sess->ftp_cmd_str, "SMNT") ||
|
||||
str_equal_text(&p_sess->ftp_cmd_str, "FEAT") ||
|
||||
str_equal_text(&p_sess->ftp_cmd_str, "OPTS") ||
|
||||
str_equal_text(&p_sess->ftp_cmd_str, "STAT"))
|
||||
str_equal_text(&p_sess->ftp_cmd_str, "STAT") ||
|
||||
str_equal_text(&p_sess->ftp_cmd_str, "PBSZ") ||
|
||||
str_equal_text(&p_sess->ftp_cmd_str, "PROT"))
|
||||
{
|
||||
vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
|
||||
}
|
||||
@ -381,6 +394,10 @@ process_post_login(struct vsf_session* p_sess)
|
||||
{
|
||||
vsf_cmdio_write(p_sess, FTP_BADCMD, "Unknown command.");
|
||||
}
|
||||
if (vsf_log_entry_pending(p_sess))
|
||||
{
|
||||
vsf_log_do_log(p_sess, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -403,6 +420,7 @@ static void
|
||||
handle_cwd(struct vsf_session* p_sess)
|
||||
{
|
||||
int retval;
|
||||
resolve_tilde(&p_sess->ftp_arg_str, p_sess);
|
||||
if (!vsf_access_check_file(&p_sess->ftp_arg_str))
|
||||
{
|
||||
vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
|
||||
@ -600,9 +618,8 @@ handle_retr(struct vsf_session* p_sess)
|
||||
int is_ascii = 0;
|
||||
filesize_t offset = p_sess->restart_pos;
|
||||
p_sess->restart_pos = 0;
|
||||
if (!pasv_active(p_sess) && !port_active(p_sess))
|
||||
if (!data_transfer_checks_ok(p_sess))
|
||||
{
|
||||
vsf_cmdio_write(p_sess, FTP_BADSENDCONN, "Use PORT or PASV first.");
|
||||
return;
|
||||
}
|
||||
if (p_sess->is_ascii && offset != 0)
|
||||
@ -611,6 +628,10 @@ handle_retr(struct vsf_session* p_sess)
|
||||
"No support for resume of ASCII transfer.");
|
||||
return;
|
||||
}
|
||||
resolve_tilde(&p_sess->ftp_arg_str, p_sess);
|
||||
vsf_log_start_entry(p_sess, kVSFLogEntryDownload);
|
||||
str_copy(&p_sess->log_str, &p_sess->ftp_arg_str);
|
||||
prepend_path_to_filename(&p_sess->log_str);
|
||||
if (!vsf_access_check_file(&p_sess->ftp_arg_str))
|
||||
{
|
||||
vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
|
||||
@ -642,14 +663,6 @@ handle_retr(struct vsf_session* p_sess)
|
||||
{
|
||||
vsf_sysutil_lseek_to(opened_file, offset);
|
||||
}
|
||||
remote_fd = get_remote_transfer_fd(p_sess);
|
||||
if (vsf_sysutil_retval_is_error(remote_fd))
|
||||
{
|
||||
goto port_pasv_cleanup_out;
|
||||
}
|
||||
vsf_log_start_entry(p_sess, kVSFLogEntryDownload);
|
||||
str_copy(&p_sess->log_str, &p_sess->ftp_arg_str);
|
||||
prepend_path_to_filename(&p_sess->log_str);
|
||||
str_alloc_text(&s_mark_str, "Opening ");
|
||||
if (tunable_ascii_download_enable && p_sess->is_ascii)
|
||||
{
|
||||
@ -666,7 +679,11 @@ handle_retr(struct vsf_session* p_sess)
|
||||
str_append_filesize_t(&s_mark_str,
|
||||
vsf_sysutil_statbuf_get_size(s_p_statbuf));
|
||||
str_append_text(&s_mark_str, " bytes).");
|
||||
vsf_cmdio_write_str(p_sess, FTP_DATACONN, &s_mark_str);
|
||||
remote_fd = get_remote_transfer_fd(p_sess, str_getbuf(&s_mark_str));
|
||||
if (vsf_sysutil_retval_is_error(remote_fd))
|
||||
{
|
||||
goto port_pasv_cleanup_out;
|
||||
}
|
||||
trans_ret = vsf_ftpdataio_transfer_file(p_sess, remote_fd,
|
||||
opened_file, 0, is_ascii);
|
||||
p_sess->transfer_size = trans_ret.transferred;
|
||||
@ -676,10 +693,6 @@ handle_retr(struct vsf_session* p_sess)
|
||||
{
|
||||
vsf_log_do_log(p_sess, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
vsf_log_do_log(p_sess, 0);
|
||||
}
|
||||
port_pasv_cleanup_out:
|
||||
port_cleanup(p_sess);
|
||||
pasv_cleanup(p_sess);
|
||||
@ -700,17 +713,16 @@ handle_dir_common(struct vsf_session* p_sess, int full_details, int stat_cmd)
|
||||
static struct mystr s_filter_str;
|
||||
static struct mystr s_dir_name_str;
|
||||
static struct vsf_sysutil_statbuf* s_p_dirstat;
|
||||
int remote_fd;
|
||||
int dir_allow_read = 1;
|
||||
struct vsf_sysutil_dir* p_dir = 0;
|
||||
int retval = 0;
|
||||
int use_control = 0;
|
||||
str_empty(&s_option_str);
|
||||
str_empty(&s_filter_str);
|
||||
/* By default open the current directory */
|
||||
str_alloc_text(&s_dir_name_str, ".");
|
||||
if (!stat_cmd && !pasv_active(p_sess) && !port_active(p_sess))
|
||||
if (!stat_cmd && !data_transfer_checks_ok(p_sess))
|
||||
{
|
||||
vsf_cmdio_write(p_sess, FTP_BADSENDCONN, "Use PORT or PASV first.");
|
||||
return;
|
||||
}
|
||||
/* Do we have an option? Going to be strict here - the option must come
|
||||
@ -731,6 +743,7 @@ handle_dir_common(struct vsf_session* p_sess, int full_details, int stat_cmd)
|
||||
}
|
||||
if (!str_isempty(&s_filter_str))
|
||||
{
|
||||
resolve_tilde(&s_filter_str, p_sess);
|
||||
if (!vsf_access_check_file(&s_filter_str))
|
||||
{
|
||||
vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
|
||||
@ -773,24 +786,18 @@ handle_dir_common(struct vsf_session* p_sess, int full_details, int stat_cmd)
|
||||
/* Fine, do it */
|
||||
if (stat_cmd)
|
||||
{
|
||||
remote_fd = VSFTP_COMMAND_FD;
|
||||
use_control = 1;
|
||||
str_append_char(&s_option_str, 'a');
|
||||
}
|
||||
else
|
||||
{
|
||||
remote_fd = get_remote_transfer_fd(p_sess);
|
||||
}
|
||||
if (vsf_sysutil_retval_is_error(remote_fd))
|
||||
{
|
||||
goto dir_close_out;
|
||||
}
|
||||
if (stat_cmd)
|
||||
{
|
||||
vsf_cmdio_write_hyphen(p_sess, FTP_STATFILE_OK, "Status follows:");
|
||||
}
|
||||
else
|
||||
{
|
||||
vsf_cmdio_write(p_sess, FTP_DATACONN, "Here comes the directory listing.");
|
||||
int remote_fd = get_remote_transfer_fd(
|
||||
p_sess, "Here comes the directory listing.");
|
||||
if (vsf_sysutil_retval_is_error(remote_fd))
|
||||
{
|
||||
goto dir_close_out;
|
||||
}
|
||||
}
|
||||
if (p_sess->is_anonymous && p_dir && tunable_anon_world_readable_only)
|
||||
{
|
||||
@ -802,7 +809,7 @@ handle_dir_common(struct vsf_session* p_sess, int full_details, int stat_cmd)
|
||||
}
|
||||
if (p_dir != 0 && dir_allow_read)
|
||||
{
|
||||
retval = vsf_ftpdataio_transfer_dir(p_sess, remote_fd, p_dir,
|
||||
retval = vsf_ftpdataio_transfer_dir(p_sess, use_control, p_dir,
|
||||
&s_dir_name_str, &s_option_str,
|
||||
&s_filter_str, full_details);
|
||||
}
|
||||
@ -939,17 +946,20 @@ handle_upload_common(struct vsf_session* p_sess, int is_append, int is_unique)
|
||||
int retval;
|
||||
filesize_t offset = p_sess->restart_pos;
|
||||
p_sess->restart_pos = 0;
|
||||
if (!pasv_active(p_sess) && !port_active(p_sess))
|
||||
if (!data_transfer_checks_ok(p_sess))
|
||||
{
|
||||
vsf_cmdio_write(p_sess, FTP_BADSENDCONN, "Use PORT or PASV first.");
|
||||
return;
|
||||
}
|
||||
resolve_tilde(&p_sess->ftp_arg_str, p_sess);
|
||||
p_filename = &p_sess->ftp_arg_str;
|
||||
if (is_unique)
|
||||
{
|
||||
get_unique_filename(&s_filename, p_filename);
|
||||
p_filename = &s_filename;
|
||||
}
|
||||
vsf_log_start_entry(p_sess, kVSFLogEntryUpload);
|
||||
str_copy(&p_sess->log_str, &p_sess->ftp_arg_str);
|
||||
prepend_path_to_filename(&p_sess->log_str);
|
||||
if (!vsf_access_check_file(p_filename))
|
||||
{
|
||||
vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
|
||||
@ -998,26 +1008,23 @@ handle_upload_common(struct vsf_session* p_sess, int is_append, int is_unique)
|
||||
/* XXX - warning, allows seek past end of file! Check for seek > size? */
|
||||
vsf_sysutil_lseek_to(new_file_fd, offset);
|
||||
}
|
||||
remote_fd = get_remote_transfer_fd(p_sess);
|
||||
if (vsf_sysutil_retval_is_error(remote_fd))
|
||||
{
|
||||
goto port_pasv_cleanup_out;
|
||||
}
|
||||
if (is_unique)
|
||||
{
|
||||
struct mystr resp_str = INIT_MYSTR;
|
||||
str_alloc_text(&resp_str, "FILE: ");
|
||||
str_append_str(&resp_str, p_filename);
|
||||
vsf_cmdio_write_str(p_sess, FTP_DATACONN, &resp_str);
|
||||
remote_fd = get_remote_transfer_fd(p_sess, str_getbuf(&resp_str));
|
||||
str_free(&resp_str);
|
||||
}
|
||||
else
|
||||
{
|
||||
vsf_cmdio_write(p_sess, FTP_DATACONN, "Ok to send data.");
|
||||
remote_fd = get_remote_transfer_fd(p_sess, "Ok to send data.");
|
||||
}
|
||||
if (vsf_sysutil_retval_is_error(remote_fd))
|
||||
{
|
||||
goto port_pasv_cleanup_out;
|
||||
}
|
||||
vsf_log_start_entry(p_sess, kVSFLogEntryUpload);
|
||||
str_copy(&p_sess->log_str, &p_sess->ftp_arg_str);
|
||||
prepend_path_to_filename(&p_sess->log_str);
|
||||
if (tunable_ascii_upload_enable && p_sess->is_ascii)
|
||||
{
|
||||
trans_ret = vsf_ftpdataio_transfer_file(p_sess, remote_fd,
|
||||
@ -1036,10 +1043,6 @@ handle_upload_common(struct vsf_session* p_sess, int is_append, int is_unique)
|
||||
{
|
||||
vsf_log_do_log(p_sess, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
vsf_log_do_log(p_sess, 0);
|
||||
}
|
||||
port_pasv_cleanup_out:
|
||||
port_cleanup(p_sess);
|
||||
pasv_cleanup(p_sess);
|
||||
@ -1050,19 +1053,19 @@ static void
|
||||
handle_mkd(struct vsf_session* p_sess)
|
||||
{
|
||||
int retval;
|
||||
resolve_tilde(&p_sess->ftp_arg_str, p_sess);
|
||||
vsf_log_start_entry(p_sess, kVSFLogEntryMkdir);
|
||||
str_copy(&p_sess->log_str, &p_sess->ftp_arg_str);
|
||||
prepend_path_to_filename(&p_sess->log_str);
|
||||
if (!vsf_access_check_file(&p_sess->ftp_arg_str))
|
||||
{
|
||||
vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
|
||||
return;
|
||||
}
|
||||
vsf_log_start_entry(p_sess, kVSFLogEntryMkdir);
|
||||
str_copy(&p_sess->log_str, &p_sess->ftp_arg_str);
|
||||
prepend_path_to_filename(&p_sess->log_str);
|
||||
/* NOTE! Actual permissions will be governed by the tunable umask */
|
||||
retval = str_mkdir(&p_sess->ftp_arg_str, 0777);
|
||||
if (retval != 0)
|
||||
{
|
||||
vsf_log_do_log(p_sess, 0);
|
||||
vsf_cmdio_write(p_sess, FTP_FILEFAIL,
|
||||
"Create directory operation failed.");
|
||||
return;
|
||||
@ -1087,6 +1090,10 @@ static void
|
||||
handle_rmd(struct vsf_session* p_sess)
|
||||
{
|
||||
int retval;
|
||||
resolve_tilde(&p_sess->ftp_arg_str, p_sess);
|
||||
vsf_log_start_entry(p_sess, kVSFLogEntryRmdir);
|
||||
str_copy(&p_sess->log_str, &p_sess->ftp_arg_str);
|
||||
prepend_path_to_filename(&p_sess->log_str);
|
||||
if (!vsf_access_check_file(&p_sess->ftp_arg_str))
|
||||
{
|
||||
vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
|
||||
@ -1100,6 +1107,7 @@ handle_rmd(struct vsf_session* p_sess)
|
||||
}
|
||||
else
|
||||
{
|
||||
vsf_log_do_log(p_sess, 1);
|
||||
vsf_cmdio_write(p_sess, FTP_RMDIROK,
|
||||
"Remove directory operation successful.");
|
||||
}
|
||||
@ -1109,6 +1117,10 @@ static void
|
||||
handle_dele(struct vsf_session* p_sess)
|
||||
{
|
||||
int retval;
|
||||
resolve_tilde(&p_sess->ftp_arg_str, p_sess);
|
||||
vsf_log_start_entry(p_sess, kVSFLogEntryDelete);
|
||||
str_copy(&p_sess->log_str, &p_sess->ftp_arg_str);
|
||||
prepend_path_to_filename(&p_sess->log_str);
|
||||
if (!vsf_access_check_file(&p_sess->ftp_arg_str))
|
||||
{
|
||||
vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
|
||||
@ -1121,6 +1133,7 @@ handle_dele(struct vsf_session* p_sess)
|
||||
}
|
||||
else
|
||||
{
|
||||
vsf_log_do_log(p_sess, 1);
|
||||
vsf_cmdio_write(p_sess, FTP_DELEOK, "Delete operation successful.");
|
||||
}
|
||||
}
|
||||
@ -1148,8 +1161,12 @@ handle_rnfr(struct vsf_session* p_sess)
|
||||
int retval;
|
||||
/* Clear old value */
|
||||
str_free(&p_sess->rnfr_filename_str);
|
||||
resolve_tilde(&p_sess->ftp_arg_str, p_sess);
|
||||
if (!vsf_access_check_file(&p_sess->ftp_arg_str))
|
||||
{
|
||||
vsf_log_start_entry(p_sess, kVSFLogEntryRename);
|
||||
str_copy(&p_sess->log_str, &p_sess->ftp_arg_str);
|
||||
prepend_path_to_filename(&p_sess->log_str);
|
||||
vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
|
||||
return;
|
||||
}
|
||||
@ -1163,6 +1180,9 @@ handle_rnfr(struct vsf_session* p_sess)
|
||||
}
|
||||
else
|
||||
{
|
||||
vsf_log_start_entry(p_sess, kVSFLogEntryRename);
|
||||
str_copy(&p_sess->log_str, &p_sess->ftp_arg_str);
|
||||
prepend_path_to_filename(&p_sess->log_str);
|
||||
vsf_cmdio_write(p_sess, FTP_FILEFAIL, "RNFR command failed.");
|
||||
}
|
||||
}
|
||||
@ -1170,6 +1190,7 @@ handle_rnfr(struct vsf_session* p_sess)
|
||||
static void
|
||||
handle_rnto(struct vsf_session* p_sess)
|
||||
{
|
||||
static struct mystr s_tmp_str;
|
||||
int retval;
|
||||
/* If we didn't get a RNFR, throw a wobbly */
|
||||
if (str_isempty(&p_sess->rnfr_filename_str))
|
||||
@ -1178,6 +1199,14 @@ handle_rnto(struct vsf_session* p_sess)
|
||||
"RNFR required first.");
|
||||
return;
|
||||
}
|
||||
resolve_tilde(&p_sess->ftp_arg_str, p_sess);
|
||||
vsf_log_start_entry(p_sess, kVSFLogEntryRename);
|
||||
str_copy(&p_sess->log_str, &p_sess->rnfr_filename_str);
|
||||
prepend_path_to_filename(&p_sess->log_str);
|
||||
str_append_char(&p_sess->log_str, ' ');
|
||||
str_copy(&s_tmp_str, &p_sess->ftp_arg_str);
|
||||
prepend_path_to_filename(&s_tmp_str);
|
||||
str_append_str(&p_sess->log_str, &s_tmp_str);
|
||||
if (!vsf_access_check_file(&p_sess->ftp_arg_str))
|
||||
{
|
||||
vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
|
||||
@ -1191,6 +1220,7 @@ handle_rnto(struct vsf_session* p_sess)
|
||||
str_free(&p_sess->rnfr_filename_str);
|
||||
if (retval == 0)
|
||||
{
|
||||
vsf_log_do_log(p_sess, 1);
|
||||
vsf_cmdio_write(p_sess, FTP_RENAMEOK, "Rename successful.");
|
||||
}
|
||||
else
|
||||
@ -1268,7 +1298,7 @@ handle_sigurg(void* p_private)
|
||||
}
|
||||
|
||||
static int
|
||||
get_remote_transfer_fd(struct vsf_session* p_sess)
|
||||
get_remote_transfer_fd(struct vsf_session* p_sess, const char* p_status_msg)
|
||||
{
|
||||
int remote_fd;
|
||||
if (!pasv_active(p_sess) && !port_active(p_sess))
|
||||
@ -1284,6 +1314,16 @@ get_remote_transfer_fd(struct vsf_session* p_sess)
|
||||
{
|
||||
remote_fd = vsf_ftpdataio_get_port_fd(p_sess);
|
||||
}
|
||||
if (vsf_sysutil_retval_is_error(remote_fd))
|
||||
{
|
||||
return remote_fd;
|
||||
}
|
||||
vsf_cmdio_write(p_sess, FTP_DATACONN, p_status_msg);
|
||||
if (vsf_ftpdataio_post_mark_connect(p_sess) != 1)
|
||||
{
|
||||
vsf_ftpdataio_dispose_transfer_fd(p_sess);
|
||||
return -1;
|
||||
}
|
||||
return remote_fd;
|
||||
}
|
||||
|
||||
@ -1311,6 +1351,7 @@ handle_size(struct vsf_session* p_sess)
|
||||
*/
|
||||
static struct vsf_sysutil_statbuf* s_p_statbuf;
|
||||
int retval;
|
||||
resolve_tilde(&p_sess->ftp_arg_str, p_sess);
|
||||
if (!vsf_access_check_file(&p_sess->ftp_arg_str))
|
||||
{
|
||||
vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
|
||||
@ -1374,6 +1415,12 @@ handle_site_chmod(struct vsf_session* p_sess, struct mystr* p_arg_str)
|
||||
vsf_cmdio_write(p_sess, FTP_BADCMD, "SITE CHMOD needs 2 arguments.");
|
||||
return;
|
||||
}
|
||||
resolve_tilde(&s_chmod_file_str, p_sess);
|
||||
vsf_log_start_entry(p_sess, kVSFLogEntryChmod);
|
||||
str_copy(&p_sess->log_str, &s_chmod_file_str);
|
||||
prepend_path_to_filename(&p_sess->log_str);
|
||||
str_append_char(&p_sess->log_str, ' ');
|
||||
str_append_str(&p_sess->log_str, p_arg_str);
|
||||
if (!vsf_access_check_file(&s_chmod_file_str))
|
||||
{
|
||||
vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
|
||||
@ -1388,6 +1435,7 @@ handle_site_chmod(struct vsf_session* p_sess, struct mystr* p_arg_str)
|
||||
}
|
||||
else
|
||||
{
|
||||
vsf_log_do_log(p_sess, 1);
|
||||
vsf_cmdio_write(p_sess, FTP_CHMODOK, "SITE CHMOD command ok.");
|
||||
}
|
||||
}
|
||||
@ -1424,26 +1472,73 @@ handle_appe(struct vsf_session* p_sess)
|
||||
static void
|
||||
handle_mdtm(struct vsf_session* p_sess)
|
||||
{
|
||||
static struct mystr s_filename_str;
|
||||
static struct vsf_sysutil_statbuf* s_p_statbuf;
|
||||
int retval;
|
||||
int do_write = 0;
|
||||
long modtime = 0;
|
||||
struct str_locate_result loc = str_locate_char(&p_sess->ftp_arg_str, ' ');
|
||||
int retval = str_stat(&p_sess->ftp_arg_str, &s_p_statbuf);
|
||||
if (retval != 0 && loc.found &&
|
||||
vsf_sysutil_isdigit(str_get_char_at(&p_sess->ftp_arg_str, 0)))
|
||||
{
|
||||
if (loc.index == 8 || loc.index == 14 ||
|
||||
(loc.index > 15 && str_get_char_at(&p_sess->ftp_arg_str, 14) == '.'))
|
||||
{
|
||||
do_write = 1;
|
||||
}
|
||||
}
|
||||
if (do_write != 0)
|
||||
{
|
||||
str_split_char(&p_sess->ftp_arg_str, &s_filename_str, ' ');
|
||||
modtime = vsf_sysutil_parse_time(str_getbuf(&p_sess->ftp_arg_str));
|
||||
str_copy(&p_sess->ftp_arg_str, &s_filename_str);
|
||||
}
|
||||
resolve_tilde(&p_sess->ftp_arg_str, p_sess);
|
||||
if (!vsf_access_check_file(&p_sess->ftp_arg_str))
|
||||
{
|
||||
vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
|
||||
return;
|
||||
}
|
||||
retval = str_stat(&p_sess->ftp_arg_str, &s_p_statbuf);
|
||||
if (retval != 0 || !vsf_sysutil_statbuf_is_regfile(s_p_statbuf))
|
||||
if (do_write && tunable_write_enable &&
|
||||
(tunable_anon_other_write_enable || !p_sess->is_anonymous))
|
||||
{
|
||||
vsf_cmdio_write(p_sess, FTP_FILEFAIL,
|
||||
"Could not get file modification time.");
|
||||
retval = str_stat(&p_sess->ftp_arg_str, &s_p_statbuf);
|
||||
if (retval != 0 || !vsf_sysutil_statbuf_is_regfile(s_p_statbuf))
|
||||
{
|
||||
vsf_cmdio_write(p_sess, FTP_FILEFAIL,
|
||||
"Could not set file modification time.");
|
||||
}
|
||||
else
|
||||
{
|
||||
retval = vsf_sysutil_setmodtime(
|
||||
str_getbuf(&p_sess->ftp_arg_str), modtime, tunable_use_localtime);
|
||||
if (retval != 0)
|
||||
{
|
||||
vsf_cmdio_write(p_sess, FTP_FILEFAIL,
|
||||
"Could not set file modification time.");
|
||||
}
|
||||
else
|
||||
{
|
||||
vsf_cmdio_write(p_sess, FTP_MDTMOK,
|
||||
"File modification time set.");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
static struct mystr s_mdtm_res_str;
|
||||
str_alloc_text(&s_mdtm_res_str,
|
||||
vsf_sysutil_statbuf_get_numeric_date(
|
||||
s_p_statbuf, tunable_use_localtime));
|
||||
vsf_cmdio_write_str(p_sess, FTP_MDTMOK, &s_mdtm_res_str);
|
||||
if (!vsf_sysutil_statbuf_is_regfile(s_p_statbuf))
|
||||
{
|
||||
vsf_cmdio_write(p_sess, FTP_FILEFAIL,
|
||||
"Could not get file modification time.");
|
||||
}
|
||||
else
|
||||
{
|
||||
static struct mystr s_mdtm_res_str;
|
||||
str_alloc_text(&s_mdtm_res_str,
|
||||
vsf_sysutil_statbuf_get_numeric_date(
|
||||
s_p_statbuf, tunable_use_localtime));
|
||||
vsf_cmdio_write_str(p_sess, FTP_MDTMOK, &s_mdtm_res_str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1515,6 +1610,7 @@ bad_eprt:
|
||||
vsf_cmdio_write(p_sess, FTP_BADCMD, "Bad EPRT command.");
|
||||
}
|
||||
|
||||
/* XXX - add AUTH etc. */
|
||||
static void
|
||||
handle_help(struct vsf_session* p_sess)
|
||||
{
|
||||
@ -1598,13 +1694,30 @@ handle_stat(struct vsf_session* p_sess)
|
||||
vsf_sysutil_ulong_to_str(tunable_idle_session_timeout));
|
||||
vsf_cmdio_write_raw(p_sess, "\r\n");
|
||||
}
|
||||
if (p_sess->control_use_ssl)
|
||||
{
|
||||
vsf_cmdio_write_raw(p_sess, " Control connection is encrypted\r\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
vsf_cmdio_write_raw(p_sess, " Control connection is plain text\r\n");
|
||||
}
|
||||
if (p_sess->data_use_ssl)
|
||||
{
|
||||
vsf_cmdio_write_raw(p_sess, " Data connections will be encrypted\r\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
vsf_cmdio_write_raw(p_sess, " Data connections will be plain text\r\n");
|
||||
}
|
||||
if (p_sess->num_clients > 0)
|
||||
{
|
||||
vsf_cmdio_write_raw(p_sess, " At session startup, client count was ");
|
||||
vsf_cmdio_write_raw(p_sess, vsf_sysutil_ulong_to_str(p_sess->num_clients));
|
||||
vsf_cmdio_write_raw(p_sess, "\r\n");
|
||||
}
|
||||
vsf_cmdio_write_raw(p_sess, " vsFTPd - secure, fast, stable\r\n");
|
||||
vsf_cmdio_write_raw(p_sess,
|
||||
" vsFTPd " VSF_VERSION " - secure, fast, stable\r\n");
|
||||
vsf_cmdio_write(p_sess, FTP_STATOK, "End of status");
|
||||
}
|
||||
|
||||
@ -1614,3 +1727,55 @@ handle_stat_file(struct vsf_session* p_sess)
|
||||
handle_dir_common(p_sess, 1, 1);
|
||||
}
|
||||
|
||||
static int
|
||||
data_transfer_checks_ok(struct vsf_session* p_sess)
|
||||
{
|
||||
if (!pasv_active(p_sess) && !port_active(p_sess))
|
||||
{
|
||||
vsf_cmdio_write(p_sess, FTP_BADSENDCONN, "Use PORT or PASV first.");
|
||||
return 0;
|
||||
}
|
||||
if (!p_sess->is_anonymous && tunable_ssl_enable &&
|
||||
tunable_force_local_data_ssl && !p_sess->data_use_ssl)
|
||||
{
|
||||
vsf_cmdio_write(
|
||||
p_sess, FTP_NEEDENCRYPT, "Data connections must be encrypted.");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
resolve_tilde(struct mystr* p_str, struct vsf_session* p_sess)
|
||||
{
|
||||
unsigned int len = str_getlen(p_str);
|
||||
if (len > 0 && str_get_char_at(p_str, 0) == '~')
|
||||
{
|
||||
static struct mystr s_rhs_str;
|
||||
if (len == 1 || str_get_char_at(p_str, 1) == '/')
|
||||
{
|
||||
str_split_char(p_str, &s_rhs_str, '~');
|
||||
str_copy(p_str, &p_sess->home_str);
|
||||
str_append_str(p_str, &s_rhs_str);
|
||||
}
|
||||
else if (tunable_tilde_user_enable && len > 1)
|
||||
{
|
||||
static struct mystr s_user_str;
|
||||
struct vsf_sysutil_user* p_user;
|
||||
str_copy(&s_rhs_str, p_str);
|
||||
str_split_char(&s_rhs_str, &s_user_str, '~');
|
||||
str_split_char(&s_user_str, &s_rhs_str, '/');
|
||||
p_user = str_getpwnam(&s_user_str);
|
||||
if (p_user != 0)
|
||||
{
|
||||
str_alloc_text(p_str, vsf_sysutil_user_get_homedir(p_user));
|
||||
if (!str_isempty(&s_rhs_str))
|
||||
{
|
||||
str_append_char(p_str, '/');
|
||||
str_append_str(p_str, &s_rhs_str);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,7 +44,7 @@ process_post_login_req(struct vsf_session* p_sess)
|
||||
char cmd;
|
||||
vsf_sysutil_unblock_sig(kVSFSysUtilSigCHLD);
|
||||
/* Blocks */
|
||||
cmd = priv_sock_get_cmd(p_sess);
|
||||
cmd = priv_sock_get_cmd(p_sess->parent_fd);
|
||||
vsf_sysutil_block_sig(kVSFSysUtilSigCHLD);
|
||||
if (tunable_chown_uploads && cmd == PRIV_SOCK_CHOWN)
|
||||
{
|
||||
@ -106,18 +106,18 @@ minimize_privilege(struct vsf_session* p_sess)
|
||||
static void
|
||||
cmd_process_chown(struct vsf_session* p_sess)
|
||||
{
|
||||
int the_fd = priv_sock_parent_recv_fd(p_sess);
|
||||
int the_fd = priv_sock_recv_fd(p_sess->parent_fd);
|
||||
vsf_privop_do_file_chown(p_sess, the_fd);
|
||||
vsf_sysutil_close(the_fd);
|
||||
priv_sock_send_result(p_sess, PRIV_SOCK_RESULT_OK);
|
||||
priv_sock_send_result(p_sess->parent_fd, PRIV_SOCK_RESULT_OK);
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_process_get_data_sock(struct vsf_session* p_sess)
|
||||
{
|
||||
int sock_fd = vsf_privop_get_ftp_port_sock(p_sess);
|
||||
priv_sock_send_result(p_sess, PRIV_SOCK_RESULT_OK);
|
||||
priv_sock_parent_send_fd(p_sess, sock_fd);
|
||||
priv_sock_send_result(p_sess->parent_fd, PRIV_SOCK_RESULT_OK);
|
||||
priv_sock_send_fd(p_sess->parent_fd, sock_fd);
|
||||
vsf_sysutil_close(sock_fd);
|
||||
}
|
||||
|
||||
|
37
prelogin.c
37
prelogin.c
@ -20,6 +20,8 @@
|
||||
#include "session.h"
|
||||
#include "banner.h"
|
||||
#include "logging.h"
|
||||
#include "ssl.h"
|
||||
#include "features.h"
|
||||
|
||||
/* Functions used */
|
||||
static void emit_greeting(struct vsf_session* p_sess);
|
||||
@ -112,6 +114,22 @@ parse_username_password(struct vsf_session* p_sess)
|
||||
vsf_cmdio_write(p_sess, FTP_GOODBYE, "Goodbye.");
|
||||
vsf_sysutil_exit(0);
|
||||
}
|
||||
else if (str_equal_text(&p_sess->ftp_cmd_str, "FEAT"))
|
||||
{
|
||||
handle_feat(p_sess);
|
||||
}
|
||||
else if (tunable_ssl_enable && str_equal_text(&p_sess->ftp_cmd_str, "AUTH"))
|
||||
{
|
||||
handle_auth(p_sess);
|
||||
}
|
||||
else if (tunable_ssl_enable && str_equal_text(&p_sess->ftp_cmd_str, "PBSZ"))
|
||||
{
|
||||
handle_pbsz(p_sess);
|
||||
}
|
||||
else if (tunable_ssl_enable && str_equal_text(&p_sess->ftp_cmd_str, "PROT"))
|
||||
{
|
||||
handle_prot(p_sess);
|
||||
}
|
||||
else
|
||||
{
|
||||
vsf_cmdio_write(p_sess, FTP_LOGINERR,
|
||||
@ -137,8 +155,23 @@ handle_user_command(struct vsf_session* p_sess)
|
||||
}
|
||||
if (!tunable_local_enable && !is_anon)
|
||||
{
|
||||
vsf_cmdio_write(p_sess, FTP_LOGINERR,
|
||||
"This FTP server is anonymous only.");
|
||||
vsf_cmdio_write(
|
||||
p_sess, FTP_LOGINERR, "This FTP server is anonymous only.");
|
||||
str_empty(&p_sess->user_str);
|
||||
return;
|
||||
}
|
||||
if (is_anon && p_sess->control_use_ssl && !tunable_allow_anon_ssl)
|
||||
{
|
||||
vsf_cmdio_write(
|
||||
p_sess, FTP_LOGINERR, "Anonymous sessions may not use encryption.");
|
||||
str_empty(&p_sess->user_str);
|
||||
return;
|
||||
}
|
||||
if (tunable_ssl_enable && !is_anon && !p_sess->control_use_ssl &&
|
||||
tunable_force_local_logins_ssl)
|
||||
{
|
||||
vsf_cmdio_write(
|
||||
p_sess, FTP_LOGINERR, "Non-anonymous sessions must use encryption.");
|
||||
str_empty(&p_sess->user_str);
|
||||
return;
|
||||
}
|
||||
|
96
privsock.c
96
privsock.c
@ -18,115 +18,115 @@
|
||||
#include "netstr.h"
|
||||
#include "sysutil.h"
|
||||
#include "sysdeputil.h"
|
||||
#include "secbuf.h"
|
||||
#include "session.h"
|
||||
|
||||
void
|
||||
priv_sock_init(struct vsf_session* p_sess)
|
||||
{
|
||||
const struct vsf_sysutil_socketpair_retval retval =
|
||||
vsf_sysutil_unix_dgram_socketpair();
|
||||
if (p_sess->privsock_inited)
|
||||
{
|
||||
bug("priv_sock_init called twice");
|
||||
}
|
||||
vsf_sysutil_unix_stream_socketpair();
|
||||
p_sess->parent_fd = retval.socket_one;
|
||||
p_sess->child_fd = retval.socket_two;
|
||||
p_sess->privsock_inited = 1;
|
||||
}
|
||||
|
||||
void
|
||||
priv_sock_send_cmd(struct vsf_session* p_sess, char cmd)
|
||||
priv_sock_send_cmd(int fd, char cmd)
|
||||
{
|
||||
/* DGRAM socket -> message boundaries retained -> use plain write */
|
||||
int retval = vsf_sysutil_write(p_sess->child_fd, &cmd, sizeof(cmd));
|
||||
int retval = vsf_sysutil_write_loop(fd, &cmd, sizeof(cmd));
|
||||
if (retval != sizeof(cmd))
|
||||
{
|
||||
die("vsf_sysutil_write");
|
||||
die("priv_sock_send_cmd");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
priv_sock_send_str(struct vsf_session* p_sess, const struct mystr* p_str)
|
||||
priv_sock_send_str(int fd, const struct mystr* p_str)
|
||||
{
|
||||
struct mystr null_term_str = INIT_MYSTR;
|
||||
str_copy(&null_term_str, p_str);
|
||||
str_append_char(&null_term_str, '\0');
|
||||
str_netfd_write(&null_term_str, p_sess->child_fd);
|
||||
str_free(&null_term_str);
|
||||
priv_sock_send_int(fd, (int) str_getlen(p_str));
|
||||
str_netfd_write(p_str, fd);
|
||||
}
|
||||
|
||||
char
|
||||
priv_sock_get_result(struct vsf_session* p_sess)
|
||||
priv_sock_get_result(int fd)
|
||||
{
|
||||
char res;
|
||||
/* DGRAM socket -> message boundaries retained -> use plain read */
|
||||
int retval = vsf_sysutil_read(p_sess->child_fd, &res, sizeof(res));
|
||||
int retval = vsf_sysutil_read_loop(fd, &res, sizeof(res));
|
||||
if (retval != sizeof(res))
|
||||
{
|
||||
die("vsf_sysutil_read");
|
||||
die("priv_sock_get_result");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
char
|
||||
priv_sock_get_cmd(struct vsf_session* p_sess)
|
||||
priv_sock_get_cmd(int fd)
|
||||
{
|
||||
char res;
|
||||
/* DGRAM socket -> message boundaries retained -> use plain read */
|
||||
int retval = vsf_sysutil_read(p_sess->parent_fd, &res, sizeof(res));
|
||||
int retval = vsf_sysutil_read_loop(fd, &res, sizeof(res));
|
||||
if (retval != sizeof(res))
|
||||
{
|
||||
die("vsf_sysutil_read");
|
||||
die("priv_sock_get_cmd");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void
|
||||
priv_sock_get_str(struct vsf_session* p_sess, struct mystr* p_dest)
|
||||
priv_sock_get_str(int fd, struct mystr* p_dest)
|
||||
{
|
||||
static char* s_p_privsock_str_buf;
|
||||
if (s_p_privsock_str_buf == 0)
|
||||
int retval;
|
||||
unsigned int len = (unsigned int) priv_sock_get_int(fd);
|
||||
if (len > VSFTP_PRIVSOCK_MAXSTR)
|
||||
{
|
||||
vsf_secbuf_alloc(&s_p_privsock_str_buf, VSFTP_PRIVSOCK_MAXSTR);
|
||||
die("priv_sock_get_str: too big");
|
||||
}
|
||||
retval = str_netfd_read(p_dest, fd, len);
|
||||
if ((unsigned int) retval != len)
|
||||
{
|
||||
die("priv_sock_get_str: read error");
|
||||
}
|
||||
/* XXX - alert - will return truncated string if sender embedded a \0 */
|
||||
str_netfd_alloc(p_dest, p_sess->parent_fd, '\0', s_p_privsock_str_buf,
|
||||
VSFTP_PRIVSOCK_MAXSTR);
|
||||
}
|
||||
|
||||
void
|
||||
priv_sock_send_result(struct vsf_session* p_sess, char res)
|
||||
priv_sock_send_result(int fd, char res)
|
||||
{
|
||||
/* DGRAM socket -> message boundaries retained -> use plain write */
|
||||
int retval = vsf_sysutil_write(p_sess->parent_fd, &res, sizeof(res));
|
||||
int retval = vsf_sysutil_write_loop(fd, &res, sizeof(res));
|
||||
if (retval != sizeof(res))
|
||||
{
|
||||
die("vsf_sysutil_write");
|
||||
die("priv_sock_send_result");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
priv_sock_child_send_fd(struct vsf_session* p_sess, int fd)
|
||||
priv_sock_send_fd(int fd, int send_fd)
|
||||
{
|
||||
vsf_sysutil_send_fd(p_sess->child_fd, fd);
|
||||
vsf_sysutil_send_fd(fd, send_fd);
|
||||
}
|
||||
|
||||
int
|
||||
priv_sock_recv_fd(int fd)
|
||||
{
|
||||
return vsf_sysutil_recv_fd(fd);
|
||||
}
|
||||
|
||||
void
|
||||
priv_sock_parent_send_fd(struct vsf_session* p_sess, int fd)
|
||||
priv_sock_send_int(int fd, int the_int)
|
||||
{
|
||||
vsf_sysutil_send_fd(p_sess->parent_fd, fd);
|
||||
int retval = vsf_sysutil_write_loop(fd, &the_int, sizeof(the_int));
|
||||
if (retval != sizeof(the_int))
|
||||
{
|
||||
die("priv_sock_send_int");
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
priv_sock_parent_recv_fd(struct vsf_session* p_sess)
|
||||
priv_sock_get_int(int fd)
|
||||
{
|
||||
return vsf_sysutil_recv_fd(p_sess->parent_fd);
|
||||
}
|
||||
|
||||
int
|
||||
priv_sock_child_recv_fd(struct vsf_session* p_sess)
|
||||
{
|
||||
return vsf_sysutil_recv_fd(p_sess->child_fd);
|
||||
int the_int;
|
||||
int retval = vsf_sysutil_read_loop(fd, &the_int, sizeof(the_int));
|
||||
if (retval != sizeof(the_int))
|
||||
{
|
||||
die("priv_sock_get_int");
|
||||
}
|
||||
return the_int;
|
||||
}
|
||||
|
||||
|
76
privsock.h
76
privsock.h
@ -14,101 +14,103 @@ void priv_sock_init(struct vsf_session* p_sess);
|
||||
|
||||
/* priv_sock_send_cmd()
|
||||
* PURPOSE
|
||||
* Sends a command to the privileged side of the channel.
|
||||
* Sends a command, typically to the privileged side of the channel.
|
||||
* PARAMETERS
|
||||
* p_sess - the current session object
|
||||
* fd - the fd on which to send the command
|
||||
* cmd - the command to send
|
||||
*/
|
||||
void priv_sock_send_cmd(struct vsf_session* p_sess, char cmd);
|
||||
void priv_sock_send_cmd(int fd, char cmd);
|
||||
|
||||
/* priv_sock_send_str()
|
||||
* PURPOSE
|
||||
* Sends a string to the privileged side of the channel.
|
||||
* Sends a string to the other side of the channel.
|
||||
* PARAMETERS
|
||||
* p_sess - the current session object
|
||||
* fd - the fd on which to send the string
|
||||
* p_str - the string to send
|
||||
*/
|
||||
void priv_sock_send_str(struct vsf_session* p_sess, const struct mystr* p_str);
|
||||
void priv_sock_send_str(int fd, const struct mystr* p_str);
|
||||
|
||||
/* priv_sock_get_result()
|
||||
* PURPOSE
|
||||
* Receives a response from the privileged side of the channel.
|
||||
* Receives a response, typically from the privileged side of the channel.
|
||||
* PARAMETERS
|
||||
* p_sess - the current session object
|
||||
* fd - the fd on which to receive the response
|
||||
* RETURNS
|
||||
* The response code.
|
||||
*/
|
||||
char priv_sock_get_result(struct vsf_session* p_sess);
|
||||
char priv_sock_get_result(int fd);
|
||||
|
||||
/* priv_sock_get_cmd()
|
||||
* PURPOSE
|
||||
* Receives a command on the privileged side of the channel.
|
||||
* Receives a command, typically on the privileged side of the channel.
|
||||
* PARAMETERS
|
||||
* p_sess - the current session object
|
||||
* fd - the fd on which to receive the command.
|
||||
* RETURNS
|
||||
* The command that was sent.
|
||||
*/
|
||||
char priv_sock_get_cmd(struct vsf_session* p_sess);
|
||||
char priv_sock_get_cmd(int fd);
|
||||
|
||||
/* priv_sock_get_str()
|
||||
* PURPOSE
|
||||
* Receives a string on the privileged side of the channel.
|
||||
* Receives a string from the other side of the channel.
|
||||
* PARAMETERS
|
||||
* p_sess - the current session object
|
||||
* fd - the fd on which to receive the string
|
||||
* p_dest - where to copy the received string
|
||||
*/
|
||||
void priv_sock_get_str(struct vsf_session* p_sess, struct mystr* p_dest);
|
||||
void priv_sock_get_str(int fd, struct mystr* p_dest);
|
||||
|
||||
/* priv_sock_send_result()
|
||||
* PURPOSE
|
||||
* Sends a command result to the unprivileged side of the channel.
|
||||
* Sends a command result, typically to the unprivileged side of the channel.
|
||||
* PARAMETERS
|
||||
* p_sess - the current session object
|
||||
* fd - the fd on which to send the result
|
||||
* res - the result to send
|
||||
*/
|
||||
void priv_sock_send_result(struct vsf_session* p_sess, char res);
|
||||
void priv_sock_send_result(int fd, char res);
|
||||
|
||||
/* priv_sock_child_send_fd()
|
||||
/* priv_sock_send_fd()
|
||||
* PURPOSE
|
||||
* Sends a file descriptor to the privileged side of the channel.
|
||||
* Sends a file descriptor to the other side of the channel.
|
||||
* PARAMETERS
|
||||
* p_sess - the current session object
|
||||
* fd - the descriptor to send
|
||||
* fd - the fd on which to send the descriptor
|
||||
* send_fd - the descriptor to send
|
||||
*/
|
||||
void priv_sock_child_send_fd(struct vsf_session* p_sess, int fd);
|
||||
void priv_sock_send_fd(int fd, int send_fd);
|
||||
|
||||
/* priv_sock_parent_recv_fd()
|
||||
/* priv_sock_recv_fd()
|
||||
* PURPOSE
|
||||
* Receives a file descriptor on the privileged side of the channel.
|
||||
* Receives a file descriptor from the other side of the channel.
|
||||
* PARAMETERS
|
||||
* p_sess - the current session object
|
||||
* fd - the fd on which to receive the descriptor
|
||||
* RETURNS
|
||||
* The received file descriptor
|
||||
*/
|
||||
int priv_sock_parent_recv_fd(struct vsf_session* p_sess);
|
||||
int priv_sock_recv_fd(int fd);
|
||||
|
||||
/* priv_sock_parent_send_fd()
|
||||
/* priv_sock_send_int()
|
||||
* PURPOSE
|
||||
* Sends a file descriptor to the unprivileged side of the channel.
|
||||
* Sends an integer to the other side of the channel.
|
||||
* PARAMETERS
|
||||
* p_sess - the current session object
|
||||
* fd - the descriptor to send
|
||||
* fd - the fd on which to send the integer
|
||||
* the_int - the integer to send
|
||||
*/
|
||||
void priv_sock_parent_send_fd(struct vsf_session* p_sess, int fd);
|
||||
void priv_sock_send_int(int fd, int the_int);
|
||||
|
||||
/* priv_sock_child_recv_fd()
|
||||
/* priv_sock_get_int()
|
||||
* PURPOSE
|
||||
* Receives a file descriptor on the unprivileged side of the channel.
|
||||
* Receives an integer from the other side of the channel.
|
||||
* PARAMETERS
|
||||
* p_sess - the current session object
|
||||
* fd - the fd on which to receive the integer
|
||||
* RETURNS
|
||||
* The received file descriptor
|
||||
* The integer that was sent.
|
||||
*/
|
||||
int priv_sock_child_recv_fd(struct vsf_session* p_sess);
|
||||
int priv_sock_get_int(int fd);
|
||||
|
||||
#define PRIV_SOCK_LOGIN 1
|
||||
#define PRIV_SOCK_CHOWN 2
|
||||
#define PRIV_SOCK_GET_DATA_SOCK 3
|
||||
#define PRIV_SOCK_GET_USER_CMD 4
|
||||
#define PRIV_SOCK_WRITE_USER_RESP 5
|
||||
|
||||
#define PRIV_SOCK_RESULT_OK 1
|
||||
#define PRIV_SOCK_RESULT_BAD 2
|
||||
|
98
readwrite.c
Normal file
98
readwrite.c
Normal file
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Part of Very Secure FTPd
|
||||
* Licence: GPL
|
||||
* Author: Chris Evans
|
||||
* readwrite.c
|
||||
*
|
||||
* Routines to encapsulate the underlying read / write mechanism (OpenSSL vs.
|
||||
* plain read()/write()).
|
||||
*/
|
||||
|
||||
#include "readwrite.h"
|
||||
#include "session.h"
|
||||
#include "netstr.h"
|
||||
#include "ssl.h"
|
||||
#include "privsock.h"
|
||||
#include "defs.h"
|
||||
#include "sysutil.h"
|
||||
|
||||
int
|
||||
ftp_write_str(const struct vsf_session* p_sess, const struct mystr* p_str,
|
||||
enum EVSFRWTarget target)
|
||||
{
|
||||
if (target == kVSFRWData)
|
||||
{
|
||||
if (p_sess->data_use_ssl)
|
||||
{
|
||||
return ssl_write_str(p_sess->p_data_ssl, p_str);
|
||||
}
|
||||
else
|
||||
{
|
||||
return str_netfd_write(p_str, p_sess->data_fd);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (p_sess->control_use_ssl && p_sess->ssl_slave_active)
|
||||
{
|
||||
priv_sock_send_cmd(p_sess->ssl_consumer_fd, PRIV_SOCK_WRITE_USER_RESP);
|
||||
priv_sock_send_str(p_sess->ssl_consumer_fd, p_str);
|
||||
return priv_sock_get_int(p_sess->ssl_consumer_fd);
|
||||
}
|
||||
else if (p_sess->control_use_ssl)
|
||||
{
|
||||
return ssl_write_str(p_sess->p_control_ssl, p_str);
|
||||
}
|
||||
else
|
||||
{
|
||||
return str_netfd_write(p_str, VSFTP_COMMAND_FD);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
ftp_read_data(const struct vsf_session* p_sess, char* p_buf, unsigned int len)
|
||||
{
|
||||
if (p_sess->data_use_ssl)
|
||||
{
|
||||
return ssl_read(p_sess->p_data_ssl, p_buf, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
return vsf_sysutil_read(p_sess->data_fd, p_buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
ftp_write_data(const struct vsf_session* p_sess, const char* p_buf,
|
||||
unsigned int len)
|
||||
{
|
||||
if (p_sess->data_use_ssl)
|
||||
{
|
||||
return ssl_write(p_sess->p_data_ssl, p_buf, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
return vsf_sysutil_write_loop(p_sess->data_fd, p_buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ftp_getline(const struct vsf_session* p_sess, struct mystr* p_str, char* p_buf)
|
||||
{
|
||||
if (p_sess->control_use_ssl && p_sess->ssl_slave_active)
|
||||
{
|
||||
priv_sock_send_cmd(p_sess->ssl_consumer_fd, PRIV_SOCK_GET_USER_CMD);
|
||||
priv_sock_get_str(p_sess->ssl_consumer_fd, p_str);
|
||||
}
|
||||
else if (p_sess->control_use_ssl)
|
||||
{
|
||||
ssl_getline(p_sess, p_str, '\n', p_buf, VSFTP_MAX_COMMAND_LINE);
|
||||
}
|
||||
else
|
||||
{
|
||||
str_netfd_alloc(
|
||||
p_str, VSFTP_COMMAND_FD, '\n', p_buf, VSFTP_MAX_COMMAND_LINE);
|
||||
}
|
||||
}
|
||||
|
23
readwrite.h
Normal file
23
readwrite.h
Normal file
@ -0,0 +1,23 @@
|
||||
#ifndef VSF_READWRITE_H
|
||||
#define VSF_READWRITE_H
|
||||
|
||||
struct vsf_session;
|
||||
struct mystr;
|
||||
|
||||
enum EVSFRWTarget
|
||||
{
|
||||
kVSFRWControl = 1,
|
||||
kVSFRWData
|
||||
};
|
||||
|
||||
int ftp_write_str(const struct vsf_session* p_sess, const struct mystr* p_str,
|
||||
enum EVSFRWTarget target);
|
||||
int ftp_read_data(const struct vsf_session* p_sess, char* p_buf,
|
||||
unsigned int len);
|
||||
int ftp_write_data(const struct vsf_session* p_sess, const char* p_buf,
|
||||
unsigned int len);
|
||||
void ftp_getline(const struct vsf_session* p_sess, struct mystr* p_str,
|
||||
char* p_buf);
|
||||
|
||||
#endif /* VSF_READWRITE_H */
|
||||
|
13
session.h
13
session.h
@ -20,6 +20,7 @@ struct vsf_session
|
||||
/* Details of the control connection */
|
||||
struct vsf_sysutil_sockaddr* p_local_addr;
|
||||
struct vsf_sysutil_sockaddr* p_remote_addr;
|
||||
char* p_control_line_buf;
|
||||
|
||||
/* Details of the data connection */
|
||||
int pasv_listen_fd;
|
||||
@ -72,13 +73,23 @@ struct vsf_session
|
||||
struct mystr ftp_arg_str;
|
||||
|
||||
/* Parent<->child comms channel */
|
||||
int privsock_inited;
|
||||
int parent_fd;
|
||||
int child_fd;
|
||||
|
||||
/* Other details */
|
||||
unsigned int num_clients;
|
||||
unsigned int num_this_ip;
|
||||
struct mystr home_str;
|
||||
|
||||
/* Secure connections state */
|
||||
int control_use_ssl;
|
||||
int data_use_ssl;
|
||||
void* p_ssl_ctx;
|
||||
void* p_control_ssl;
|
||||
void* p_data_ssl;
|
||||
int ssl_slave_active;
|
||||
int ssl_slave_fd;
|
||||
int ssl_consumer_fd;
|
||||
};
|
||||
|
||||
#endif /* VSF_SESSION_H */
|
||||
|
378
ssl.c
Normal file
378
ssl.c
Normal file
@ -0,0 +1,378 @@
|
||||
/*
|
||||
* Part of Very Secure FTPd
|
||||
* Licence: GPL
|
||||
* Author: Chris Evans
|
||||
* ssl.c
|
||||
*
|
||||
* Routines to handle a SSL/TLS-based implementation of RFC 2228, i.e.
|
||||
* encryption.
|
||||
*/
|
||||
|
||||
#include "ssl.h"
|
||||
#include "session.h"
|
||||
#include "ftpcodes.h"
|
||||
#include "ftpcmdio.h"
|
||||
#include "defs.h"
|
||||
#include "str.h"
|
||||
#include "sysutil.h"
|
||||
#include "tunables.h"
|
||||
#include "utility.h"
|
||||
#include "builddefs.h"
|
||||
|
||||
#ifdef VSF_BUILD_SSL
|
||||
#include <openssl/ssl.h>
|
||||
#endif
|
||||
|
||||
#ifdef VSF_BUILD_SSL
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/rand.h>
|
||||
|
||||
static char* get_ssl_error();
|
||||
static SSL* get_ssl(struct vsf_session* p_sess, int fd);
|
||||
static int ssl_session_init(struct vsf_session* p_sess);
|
||||
|
||||
static int ssl_inited;
|
||||
|
||||
void
|
||||
ssl_init(struct vsf_session* p_sess)
|
||||
{
|
||||
if (!ssl_inited)
|
||||
{
|
||||
SSL_CTX* p_ctx;
|
||||
long options;
|
||||
SSL_library_init();
|
||||
p_ctx = SSL_CTX_new(SSLv23_server_method());
|
||||
if (p_ctx == NULL)
|
||||
{
|
||||
die("SSL: could not allocate SSL context");
|
||||
}
|
||||
options = SSL_OP_ALL;
|
||||
if (!tunable_sslv2)
|
||||
{
|
||||
options |= SSL_OP_NO_SSLv2;
|
||||
}
|
||||
if (!tunable_sslv3)
|
||||
{
|
||||
options |= SSL_OP_NO_SSLv3;
|
||||
}
|
||||
if (!tunable_tlsv1)
|
||||
{
|
||||
options |= SSL_OP_NO_TLSv1;
|
||||
}
|
||||
SSL_CTX_set_options(p_ctx, options);
|
||||
if (tunable_rsa_cert_file)
|
||||
{
|
||||
if (SSL_CTX_use_certificate_file(
|
||||
p_ctx, tunable_rsa_cert_file, X509_FILETYPE_PEM) != 1)
|
||||
{
|
||||
die("SSL: cannot load RSA key");
|
||||
}
|
||||
if (SSL_CTX_use_PrivateKey_file(
|
||||
p_ctx, tunable_rsa_cert_file, X509_FILETYPE_PEM) != 1)
|
||||
{
|
||||
die("SSL: cannot load RSA key");
|
||||
}
|
||||
}
|
||||
if (tunable_dsa_cert_file)
|
||||
{
|
||||
if (SSL_CTX_use_certificate_file(
|
||||
p_ctx, tunable_dsa_cert_file, X509_FILETYPE_PEM) != 1)
|
||||
{
|
||||
die("SSL: cannot load DSA key");
|
||||
}
|
||||
if (SSL_CTX_use_PrivateKey_file(
|
||||
p_ctx, tunable_dsa_cert_file, X509_FILETYPE_PEM) != 1)
|
||||
{
|
||||
die("SSL: cannot load DSA key");
|
||||
}
|
||||
}
|
||||
if (SSL_CTX_set_cipher_list(p_ctx, tunable_ssl_ciphers) != 1)
|
||||
{
|
||||
die("SSL: could not set cipher list");
|
||||
}
|
||||
if (RAND_status() != 1)
|
||||
{
|
||||
die("SSL: RNG is not seeded");
|
||||
}
|
||||
p_sess->p_ssl_ctx = p_ctx;
|
||||
ssl_inited = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
handle_auth(struct vsf_session* p_sess)
|
||||
{
|
||||
str_upper(&p_sess->ftp_arg_str);
|
||||
if (str_equal_text(&p_sess->ftp_arg_str, "TLS") ||
|
||||
str_equal_text(&p_sess->ftp_arg_str, "TLS-C") ||
|
||||
str_equal_text(&p_sess->ftp_arg_str, "SSL") ||
|
||||
str_equal_text(&p_sess->ftp_arg_str, "TLS-P"))
|
||||
{
|
||||
vsf_cmdio_write(p_sess, FTP_AUTHOK, "Proceed with negotiation.");
|
||||
if (!ssl_session_init(p_sess))
|
||||
{
|
||||
struct mystr err_str = INIT_MYSTR;
|
||||
str_alloc_text(&err_str, "Negotiation failed: ");
|
||||
str_append_text(&err_str, get_ssl_error());
|
||||
vsf_cmdio_write_str(p_sess, FTP_TLS_FAIL, &err_str);
|
||||
vsf_sysutil_exit(0);
|
||||
}
|
||||
p_sess->control_use_ssl = 1;
|
||||
if (str_equal_text(&p_sess->ftp_arg_str, "SSL") ||
|
||||
str_equal_text(&p_sess->ftp_arg_str, "TLS-P"))
|
||||
{
|
||||
p_sess->data_use_ssl = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
vsf_cmdio_write(p_sess, FTP_BADAUTH, "Unknown AUTH type.");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
handle_pbsz(struct vsf_session* p_sess)
|
||||
{
|
||||
if (!p_sess->control_use_ssl)
|
||||
{
|
||||
vsf_cmdio_write(p_sess, FTP_BADPBSZ, "PBSZ needs a secure connection.");
|
||||
}
|
||||
else
|
||||
{
|
||||
vsf_cmdio_write(p_sess, FTP_PBSZOK, "PBSZ set to 0.");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
handle_prot(struct vsf_session* p_sess)
|
||||
{
|
||||
str_upper(&p_sess->ftp_arg_str);
|
||||
if (!p_sess->control_use_ssl)
|
||||
{
|
||||
vsf_cmdio_write(p_sess, FTP_BADPROT, "PROT needs a secure connection.");
|
||||
}
|
||||
else if (str_equal_text(&p_sess->ftp_arg_str, "C"))
|
||||
{
|
||||
p_sess->data_use_ssl = 0;
|
||||
vsf_cmdio_write(p_sess, FTP_PROTOK, "PROT now Clear.");
|
||||
}
|
||||
else if (str_equal_text(&p_sess->ftp_arg_str, "P"))
|
||||
{
|
||||
p_sess->data_use_ssl = 1;
|
||||
vsf_cmdio_write(p_sess, FTP_PROTOK, "PROT now Private.");
|
||||
}
|
||||
else if (str_equal_text(&p_sess->ftp_arg_str, "S") ||
|
||||
str_equal_text(&p_sess->ftp_arg_str, "E"))
|
||||
{
|
||||
vsf_cmdio_write(p_sess, FTP_NOHANDLEPROT, "PROT not supported.");
|
||||
}
|
||||
else
|
||||
{
|
||||
vsf_cmdio_write(p_sess, FTP_NOSUCHPROT, "PROT not recognized.");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ssl_getline(const struct vsf_session* p_sess, struct mystr* p_str,
|
||||
char end_char, char* p_buf, unsigned int buflen)
|
||||
{
|
||||
char* p_buf_start = p_buf;
|
||||
p_buf[buflen - 1] = '\0';
|
||||
buflen--;
|
||||
while (1)
|
||||
{
|
||||
int retval = SSL_read(p_sess->p_control_ssl, p_buf, buflen);
|
||||
if (retval <= 0)
|
||||
{
|
||||
die("SSL_read");
|
||||
}
|
||||
p_buf[retval] = '\0';
|
||||
buflen -= retval;
|
||||
if (p_buf[retval - 1] == end_char || buflen == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
p_buf += retval;
|
||||
}
|
||||
str_alloc_alt_term(p_str, p_buf_start, end_char);
|
||||
}
|
||||
|
||||
int
|
||||
ssl_read(void* p_ssl, char* p_buf, unsigned int len)
|
||||
{
|
||||
return SSL_read((SSL*) p_ssl, p_buf, len);
|
||||
}
|
||||
|
||||
int
|
||||
ssl_write(void* p_ssl, const char* p_buf, unsigned int len)
|
||||
{
|
||||
return SSL_write((SSL*) p_ssl, p_buf, len);
|
||||
}
|
||||
|
||||
int
|
||||
ssl_write_str(void* p_ssl, const struct mystr* p_str)
|
||||
{
|
||||
unsigned int len = str_getlen(p_str);
|
||||
int ret = SSL_write((SSL*) p_ssl, str_getbuf(p_str), len);
|
||||
if ((unsigned int) ret != len)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ssl_accept(struct vsf_session* p_sess, int fd)
|
||||
{
|
||||
SSL* p_ssl = get_ssl(p_sess, fd);
|
||||
if (p_ssl == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
p_sess->p_data_ssl = p_ssl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
ssl_data_close(struct vsf_session* p_sess)
|
||||
{
|
||||
SSL_free(p_sess->p_data_ssl);
|
||||
}
|
||||
|
||||
void
|
||||
ssl_comm_channel_init(struct vsf_session* p_sess)
|
||||
{
|
||||
const struct vsf_sysutil_socketpair_retval retval =
|
||||
vsf_sysutil_unix_stream_socketpair();
|
||||
p_sess->ssl_consumer_fd = retval.socket_one;
|
||||
p_sess->ssl_slave_fd = retval.socket_two;
|
||||
}
|
||||
|
||||
static SSL*
|
||||
get_ssl(struct vsf_session* p_sess, int fd)
|
||||
{
|
||||
SSL* p_ssl = SSL_new(p_sess->p_ssl_ctx);
|
||||
if (p_ssl == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
if (!SSL_set_fd(p_ssl, fd))
|
||||
{
|
||||
SSL_free(p_ssl);
|
||||
return NULL;
|
||||
}
|
||||
if (SSL_accept(p_ssl) != 1)
|
||||
{
|
||||
die(get_ssl_error());
|
||||
SSL_free(p_ssl);
|
||||
return NULL;
|
||||
}
|
||||
return p_ssl;
|
||||
}
|
||||
|
||||
static int
|
||||
ssl_session_init(struct vsf_session* p_sess)
|
||||
{
|
||||
SSL* p_ssl = get_ssl(p_sess, VSFTP_COMMAND_FD);
|
||||
if (p_ssl == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
p_sess->p_control_ssl = p_ssl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static char*
|
||||
get_ssl_error()
|
||||
{
|
||||
SSL_load_error_strings();
|
||||
return ERR_error_string(ERR_get_error(), NULL);
|
||||
}
|
||||
|
||||
#else /* VSF_BUILD_SSL */
|
||||
|
||||
void
|
||||
ssl_init(struct vsf_session* p_sess)
|
||||
{
|
||||
(void) p_sess;
|
||||
die("SSL: ssl_enable is set but SSL support not compiled in");
|
||||
}
|
||||
|
||||
void
|
||||
handle_auth(struct vsf_session* p_sess)
|
||||
{
|
||||
(void) p_sess;
|
||||
}
|
||||
|
||||
void
|
||||
handle_pbsz(struct vsf_session* p_sess)
|
||||
{
|
||||
(void) p_sess;
|
||||
}
|
||||
|
||||
void
|
||||
handle_prot(struct vsf_session* p_sess)
|
||||
{
|
||||
(void) p_sess;
|
||||
}
|
||||
|
||||
void
|
||||
ssl_getline(const struct vsf_session* p_sess, struct mystr* p_str,
|
||||
char end_char, char* p_buf, unsigned int buflen)
|
||||
{
|
||||
(void) p_sess;
|
||||
(void) p_str;
|
||||
(void) end_char;
|
||||
(void) p_buf;
|
||||
(void) buflen;
|
||||
}
|
||||
|
||||
int
|
||||
ssl_read(void* p_ssl, char* p_buf, unsigned int len)
|
||||
{
|
||||
(void) p_ssl;
|
||||
(void) p_buf;
|
||||
(void) len;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
ssl_write(void* p_ssl, const char* p_buf, unsigned int len)
|
||||
{
|
||||
(void) p_ssl;
|
||||
(void) p_buf;
|
||||
(void) len;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
ssl_write_str(void* p_ssl, const struct mystr* p_str)
|
||||
{
|
||||
(void) p_ssl;
|
||||
(void) p_str;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
ssl_accept(struct vsf_session* p_sess, int fd)
|
||||
{
|
||||
(void) p_sess;
|
||||
(void) fd;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
ssl_data_close(struct vsf_session* p_sess)
|
||||
{
|
||||
(void) p_sess;
|
||||
}
|
||||
|
||||
void
|
||||
ssl_comm_channel_init(struct vsf_session* p_sess)
|
||||
{
|
||||
(void) p_sess;
|
||||
}
|
||||
|
||||
#endif /* VSF_BUILD_SSL */
|
||||
|
21
ssl.h
Normal file
21
ssl.h
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef VSF_SSL_H
|
||||
#define VSF_SSL_H
|
||||
|
||||
struct vsf_session;
|
||||
struct mystr;
|
||||
|
||||
void ssl_getline(const struct vsf_session* p_sess, struct mystr* p_str,
|
||||
char end_char, char* p_buf, unsigned int buflen);
|
||||
int ssl_read(void* p_ssl, char* p_buf, unsigned int len);
|
||||
int ssl_write(void* p_ssl, const char* p_buf, unsigned int len);
|
||||
int ssl_write_str(void* p_ssl, const struct mystr* p_str);
|
||||
void ssl_init(struct vsf_session* p_sess);
|
||||
int ssl_accept(struct vsf_session* p_sess, int fd);
|
||||
void ssl_data_close(struct vsf_session* p_sess);
|
||||
void ssl_comm_channel_init(struct vsf_session* p_sess);
|
||||
void handle_auth(struct vsf_session* p_sess);
|
||||
void handle_pbsz(struct vsf_session* p_sess);
|
||||
void handle_prot(struct vsf_session* p_sess);
|
||||
|
||||
#endif /* VSF_SSL_H */
|
||||
|
7
str.c
7
str.c
@ -135,9 +135,9 @@ str_empty(struct mystr* p_str)
|
||||
void
|
||||
str_trunc(struct mystr* p_str, unsigned int trunc_len)
|
||||
{
|
||||
if (trunc_len >= p_str->len)
|
||||
if (trunc_len >= p_str->alloc_bytes)
|
||||
{
|
||||
bug("trunc_len not smaller than len in str_trunc");
|
||||
bug("trunc_len not smaller than alloc_bytes in str_trunc");
|
||||
}
|
||||
p_str->len = trunc_len;
|
||||
p_str->p_buf[p_str->len] = '\0';
|
||||
@ -146,11 +146,14 @@ str_trunc(struct mystr* p_str, unsigned int trunc_len)
|
||||
void
|
||||
str_reserve(struct mystr* p_str, unsigned int res_len)
|
||||
{
|
||||
/* Reserve space for the trailing zero as well. */
|
||||
res_len++;
|
||||
if (res_len > p_str->alloc_bytes)
|
||||
{
|
||||
p_str->p_buf = vsf_sysutil_realloc(p_str->p_buf, res_len);
|
||||
p_str->alloc_bytes = res_len;
|
||||
}
|
||||
p_str->p_buf[res_len - 1] = '\0';
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "secbuf.h"
|
||||
#include "defs.h"
|
||||
#include "tunables.h"
|
||||
#include "builddefs.h"
|
||||
|
||||
/* For Linux, this adds nothing :-) */
|
||||
#include "port/porting_junk.h"
|
||||
@ -46,7 +47,9 @@
|
||||
#undef VSF_SYSDEP_HAVE_HPUX_SETPROCTITLE
|
||||
#undef VSF_SYSDEP_HAVE_MAP_ANON
|
||||
#undef VSF_SYSDEP_NEED_OLD_FD_PASSING
|
||||
#define VSF_SYSDEP_HAVE_PAM
|
||||
#ifdef VSF_BUILD_PAM
|
||||
#define VSF_SYSDEP_HAVE_PAM
|
||||
#endif
|
||||
#define VSF_SYSDEP_HAVE_SHADOW
|
||||
#define VSF_SYSDEP_HAVE_USERSHELL
|
||||
#define VSF_SYSDEP_HAVE_LIBCAP
|
||||
|
7
sysstr.c
7
sysstr.c
@ -40,6 +40,13 @@ str_write_loop(const struct mystr* p_str, const int fd)
|
||||
return vsf_sysutil_write_loop(fd, str_getbuf(p_str), str_getlen(p_str));
|
||||
}
|
||||
|
||||
int
|
||||
str_read_loop(struct mystr* p_str, const int fd)
|
||||
{
|
||||
return vsf_sysutil_read_loop(
|
||||
fd, (char*) str_getbuf(p_str), str_getlen(p_str));
|
||||
}
|
||||
|
||||
int
|
||||
str_mkdir(const struct mystr* p_str, const unsigned int mode)
|
||||
{
|
||||
|
1
sysstr.h
1
sysstr.h
@ -10,6 +10,7 @@ struct vsf_sysutil_user;
|
||||
void str_getcwd(struct mystr* p_str);
|
||||
int str_readlink(struct mystr* p_str, const struct mystr* p_filename_str);
|
||||
int str_write_loop(const struct mystr* p_str, const int fd);
|
||||
int str_read_loop(struct mystr* p_str, const int fd);
|
||||
int str_mkdir(const struct mystr* p_str, const unsigned int mode);
|
||||
int str_rmdir(const struct mystr* p_str);
|
||||
int str_unlink(const struct mystr* p_str);
|
||||
|
58
sysutil.c
58
sysutil.c
@ -50,6 +50,7 @@
|
||||
#include <netinet/tcp.h>
|
||||
#include <limits.h>
|
||||
#include <syslog.h>
|
||||
#include <utime.h>
|
||||
|
||||
/* Private variables to this file */
|
||||
/* Current umask() */
|
||||
@ -899,6 +900,12 @@ vsf_sysutil_isalnum(int the_char)
|
||||
return isalnum(the_char);
|
||||
}
|
||||
|
||||
int
|
||||
vsf_sysutil_isdigit(int the_char)
|
||||
{
|
||||
return isdigit(the_char);
|
||||
}
|
||||
|
||||
char*
|
||||
vsf_sysutil_getcwd(char* p_dest, const unsigned int buf_size)
|
||||
{
|
||||
@ -1540,11 +1547,11 @@ vsf_sysutil_get_ipv6_sock(void)
|
||||
}
|
||||
|
||||
struct vsf_sysutil_socketpair_retval
|
||||
vsf_sysutil_unix_dgram_socketpair(void)
|
||||
vsf_sysutil_unix_stream_socketpair(void)
|
||||
{
|
||||
struct vsf_sysutil_socketpair_retval retval;
|
||||
int the_sockets[2];
|
||||
int sys_retval = socketpair(PF_UNIX, SOCK_DGRAM, 0, the_sockets);
|
||||
int sys_retval = socketpair(PF_UNIX, SOCK_STREAM, 0, the_sockets);
|
||||
if (sys_retval != 0)
|
||||
{
|
||||
die("socketpair");
|
||||
@ -2449,3 +2456,50 @@ vsf_sysutil_syslog(const char* p_text, int severe)
|
||||
syslog(prio, "%s", p_text);
|
||||
}
|
||||
|
||||
long
|
||||
vsf_sysutil_parse_time(const char* p_text)
|
||||
{
|
||||
struct tm the_time;
|
||||
unsigned int len = vsf_sysutil_strlen(p_text);
|
||||
vsf_sysutil_memclr(&the_time, sizeof(the_time));
|
||||
if (len >= 8)
|
||||
{
|
||||
char yr[5];
|
||||
char mon[3];
|
||||
char day[3];
|
||||
vsf_sysutil_strcpy(yr, p_text, 5);
|
||||
vsf_sysutil_strcpy(mon, p_text + 4, 3);
|
||||
vsf_sysutil_strcpy(day, p_text + 6, 3);
|
||||
the_time.tm_year = vsf_sysutil_atoi(yr) - 1900;
|
||||
the_time.tm_mon = vsf_sysutil_atoi(mon) - 1;
|
||||
the_time.tm_mday = vsf_sysutil_atoi(day);
|
||||
}
|
||||
if (len >= 14)
|
||||
{
|
||||
char hr[3];
|
||||
char mins[3];
|
||||
char sec[3];
|
||||
vsf_sysutil_strcpy(hr, p_text + 8, 3);
|
||||
vsf_sysutil_strcpy(mins, p_text + 10, 3);
|
||||
vsf_sysutil_strcpy(sec, p_text + 12, 3);
|
||||
the_time.tm_hour = vsf_sysutil_atoi(hr);
|
||||
the_time.tm_min = vsf_sysutil_atoi(mins);
|
||||
the_time.tm_sec = vsf_sysutil_atoi(sec);
|
||||
}
|
||||
return mktime(&the_time);
|
||||
}
|
||||
|
||||
int
|
||||
vsf_sysutil_setmodtime(const char* p_file, long the_time, int is_localtime)
|
||||
{
|
||||
struct utimbuf new_times;
|
||||
if (!is_localtime)
|
||||
{
|
||||
the_time -= timezone;
|
||||
}
|
||||
vsf_sysutil_memclr(&new_times, sizeof(new_times));
|
||||
new_times.actime = the_time;
|
||||
new_times.modtime = the_time;
|
||||
return utime(p_file, &new_times);
|
||||
}
|
||||
|
||||
|
@ -195,6 +195,7 @@ int vsf_sysutil_toupper(int the_char);
|
||||
int vsf_sysutil_isspace(int the_char);
|
||||
int vsf_sysutil_isprint(int the_char);
|
||||
int vsf_sysutil_isalnum(int the_char);
|
||||
int vsf_sysutil_isdigit(int the_char);
|
||||
|
||||
/* Socket handling */
|
||||
struct vsf_sysutil_sockaddr;
|
||||
@ -234,7 +235,7 @@ const void* vsf_sysutil_sockaddr_ipv6_v4(
|
||||
int vsf_sysutil_get_ipv4_sock(void);
|
||||
int vsf_sysutil_get_ipv6_sock(void);
|
||||
struct vsf_sysutil_socketpair_retval
|
||||
vsf_sysutil_unix_dgram_socketpair(void);
|
||||
vsf_sysutil_unix_stream_socketpair(void);
|
||||
int vsf_sysutil_bind(int fd, const struct vsf_sysutil_sockaddr* p_sockptr);
|
||||
void vsf_sysutil_listen(int fd, const unsigned int backlog);
|
||||
void vsf_sysutil_getsockname(int fd, struct vsf_sysutil_sockaddr** p_sockptr);
|
||||
@ -319,7 +320,9 @@ void vsf_sysutil_chroot(const char* p_root_path);
|
||||
void vsf_sysutil_update_cached_time(void);
|
||||
long vsf_sysutil_get_cached_time_sec(void);
|
||||
long vsf_sysutil_get_cached_time_usec(void);
|
||||
long vsf_sysutil_parse_time(const char* p_text);
|
||||
void vsf_sysutil_sleep(double seconds);
|
||||
int vsf_sysutil_setmodtime(const char* p_file, long the_time, int is_localtime);
|
||||
|
||||
#endif /* VSF_SYSUTIL_H */
|
||||
|
||||
|
25
tcpwrap.c
25
tcpwrap.c
@ -9,19 +9,14 @@
|
||||
|
||||
#include "tcpwrap.h"
|
||||
#include "builddefs.h"
|
||||
#include "utility.h"
|
||||
|
||||
#ifndef VSF_BUILD_TCPWRAPPERS
|
||||
#ifdef VSF_BUILD_TCPWRAPPERS
|
||||
#include <tcpd.h>
|
||||
#endif
|
||||
|
||||
int
|
||||
vsf_tcp_wrapper_ok(int remote_fd)
|
||||
{
|
||||
(void) remote_fd;
|
||||
return 1;
|
||||
}
|
||||
#ifdef VSF_BUILD_TCPWRAPPERS
|
||||
|
||||
#else /* VSF_BUILD_TCPWRAPPERS = yes */
|
||||
|
||||
#include <tcpd.h>
|
||||
#include <sys/syslog.h>
|
||||
|
||||
int deny_severity = LOG_WARNING;
|
||||
@ -40,5 +35,15 @@ vsf_tcp_wrapper_ok(int remote_fd)
|
||||
return 1;
|
||||
}
|
||||
|
||||
#else /* VSF_BUILD_TCPWRAPPERS */
|
||||
|
||||
int
|
||||
vsf_tcp_wrapper_ok(int remote_fd)
|
||||
{
|
||||
(void) remote_fd;
|
||||
die("tcp_wrappers is set to YES but no tcp wrapper support compiled in");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* VSF_BUILD_TCPWRAPPERS */
|
||||
|
||||
|
12
tunables.c
12
tunables.c
@ -57,6 +57,15 @@ int tunable_dirlist_enable = 1;
|
||||
int tunable_chmod_enable = 1;
|
||||
int tunable_secure_email_list_enable = 0;
|
||||
int tunable_run_as_launching_user = 0;
|
||||
int tunable_no_log_lock = 0;
|
||||
int tunable_ssl_enable = 0;
|
||||
int tunable_allow_anon_ssl = 0;
|
||||
int tunable_force_local_logins_ssl = 1;
|
||||
int tunable_force_local_data_ssl = 1;
|
||||
int tunable_sslv2 = 0;
|
||||
int tunable_sslv3 = 0;
|
||||
int tunable_tlsv1 = 1;
|
||||
int tunable_tilde_user_enable = 0;
|
||||
|
||||
unsigned int tunable_accept_timeout = 60;
|
||||
unsigned int tunable_connect_timeout = 60;
|
||||
@ -103,4 +112,7 @@ const char* tunable_hide_file = 0;
|
||||
const char* tunable_deny_file = 0;
|
||||
const char* tunable_user_sub_token = 0;
|
||||
const char* tunable_email_password_file = "/etc/vsftpd.email_passwords";
|
||||
const char* tunable_rsa_cert_file = "/usr/share/ssl/certs/vsftpd.pem";
|
||||
const char* tunable_dsa_cert_file = 0;
|
||||
const char* tunable_ssl_ciphers = "DES-CBC3-SHA";
|
||||
|
||||
|
12
tunables.h
12
tunables.h
@ -53,6 +53,15 @@ extern int tunable_dirlist_enable; /* Can see any dirs? */
|
||||
extern int tunable_chmod_enable; /* Is CHMOD allowed? (local) */
|
||||
extern int tunable_secure_email_list_enable; /* Require specific anon email */
|
||||
extern int tunable_run_as_launching_user; /* Runs as launching user */
|
||||
extern int tunable_no_log_lock; /* Don't lock log files */
|
||||
extern int tunable_ssl_enable; /* Allow SSL/TLS AUTH */
|
||||
extern int tunable_allow_anon_ssl; /* Allow anonymous use of SSL */
|
||||
extern int tunable_force_local_logins_ssl; /* Require local logins use SSL */
|
||||
extern int tunable_force_local_data_ssl; /* Require local data uses SSL */
|
||||
extern int tunable_sslv2; /* Allow SSLv2 */
|
||||
extern int tunable_sslv3; /* Allow SSLv3 */
|
||||
extern int tunable_tlsv1; /* Allow TLSv1 */
|
||||
extern int tunable_tilde_user_enable; /* Support e.g. ~chris */
|
||||
|
||||
/* Integer/numeric defines */
|
||||
extern unsigned int tunable_accept_timeout;
|
||||
@ -98,6 +107,9 @@ extern const char* tunable_hide_file;
|
||||
extern const char* tunable_deny_file;
|
||||
extern const char* tunable_user_sub_token;
|
||||
extern const char* tunable_email_password_file;
|
||||
extern const char* tunable_rsa_cert_file;
|
||||
extern const char* tunable_dsa_cert_file;
|
||||
extern const char* tunable_ssl_ciphers;
|
||||
|
||||
#endif /* VSF_TUNABLES_H */
|
||||
|
||||
|
124
twoprocess.c
124
twoprocess.c
@ -15,7 +15,6 @@
|
||||
#include "session.h"
|
||||
#include "privsock.h"
|
||||
#include "secutil.h"
|
||||
#include "sysutil.h"
|
||||
#include "filestr.h"
|
||||
#include "str.h"
|
||||
#include "sysstr.h"
|
||||
@ -23,10 +22,18 @@
|
||||
#include "tunables.h"
|
||||
#include "defs.h"
|
||||
#include "parseconf.h"
|
||||
#include "ssl.h"
|
||||
#include "readwrite.h"
|
||||
#include "sysutil.h"
|
||||
#include "sysdeputil.h"
|
||||
|
||||
// XXX
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
static void drop_all_privs(void);
|
||||
static void handle_sigchld(int duff);
|
||||
static void process_login_req(struct vsf_session* p_sess);
|
||||
static void process_ssl_slave_req(struct vsf_session* p_sess);
|
||||
static void common_do_login(struct vsf_session* p_sess,
|
||||
const struct mystr* p_user_str, int do_chroot,
|
||||
int anon);
|
||||
@ -62,6 +69,13 @@ vsf_two_process_start(struct vsf_session* p_sess)
|
||||
{
|
||||
/* Create the comms channel between privileged parent and no-priv child */
|
||||
priv_sock_init(p_sess);
|
||||
if (tunable_ssl_enable)
|
||||
{
|
||||
/* Create the comms channel between the no-priv SSL child and the low-priv
|
||||
* protocol handling child.
|
||||
*/
|
||||
ssl_comm_channel_init(p_sess);
|
||||
}
|
||||
vsf_sysutil_install_async_sighandler(kVSFSysUtilSigCHLD, handle_sigchld);
|
||||
{
|
||||
int newpid = vsf_sysutil_fork();
|
||||
@ -77,6 +91,11 @@ vsf_two_process_start(struct vsf_session* p_sess)
|
||||
/* Child process - time to lose as much privilege as possible and do the
|
||||
* login processing
|
||||
*/
|
||||
vsf_sysutil_close(p_sess->parent_fd);
|
||||
if (tunable_ssl_enable)
|
||||
{
|
||||
vsf_sysutil_close(p_sess->ssl_consumer_fd);
|
||||
}
|
||||
if (tunable_local_enable && tunable_userlist_enable)
|
||||
{
|
||||
int retval = str_fileread(&p_sess->userlist_str, tunable_userlist_file,
|
||||
@ -119,17 +138,33 @@ vsf_two_process_login(struct vsf_session* p_sess,
|
||||
const struct mystr* p_pass_str)
|
||||
{
|
||||
char result;
|
||||
priv_sock_send_cmd(p_sess, PRIV_SOCK_LOGIN);
|
||||
priv_sock_send_str(p_sess, &p_sess->user_str);
|
||||
priv_sock_send_str(p_sess, p_pass_str);
|
||||
result = priv_sock_get_result(p_sess);
|
||||
priv_sock_send_cmd(p_sess->child_fd, PRIV_SOCK_LOGIN);
|
||||
priv_sock_send_str(p_sess->child_fd, &p_sess->user_str);
|
||||
priv_sock_send_str(p_sess->child_fd, p_pass_str);
|
||||
priv_sock_send_int(p_sess->child_fd, p_sess->control_use_ssl);
|
||||
priv_sock_send_int(p_sess->child_fd, p_sess->data_use_ssl);
|
||||
result = priv_sock_get_result(p_sess->child_fd);
|
||||
if (result == PRIV_SOCK_RESULT_OK)
|
||||
{
|
||||
/* Miracle. We don't emit the success message here. That is left to
|
||||
* process_post_login().
|
||||
* Exit normally, parent will wait for this and launch new child
|
||||
* Exit normally, unless we are remaining as the SSL read / write child.
|
||||
*/
|
||||
vsf_sysutil_exit(0);
|
||||
if (!p_sess->control_use_ssl)
|
||||
{
|
||||
vsf_sysutil_exit(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
vsf_sysutil_clear_alarm();
|
||||
vsf_sysutil_close(p_sess->child_fd);
|
||||
if (tunable_setproctitle_enable)
|
||||
{
|
||||
vsf_sysutil_setproctitle("SSL handler");
|
||||
}
|
||||
process_ssl_slave_req(p_sess);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
else if (result == PRIV_SOCK_RESULT_BAD)
|
||||
{
|
||||
@ -146,22 +181,22 @@ int
|
||||
vsf_two_process_get_priv_data_sock(struct vsf_session* p_sess)
|
||||
{
|
||||
char res;
|
||||
priv_sock_send_cmd(p_sess, PRIV_SOCK_GET_DATA_SOCK);
|
||||
res = priv_sock_get_result(p_sess);
|
||||
priv_sock_send_cmd(p_sess->child_fd, PRIV_SOCK_GET_DATA_SOCK);
|
||||
res = priv_sock_get_result(p_sess->child_fd);
|
||||
if (res != PRIV_SOCK_RESULT_OK)
|
||||
{
|
||||
die("could not get privileged socket");
|
||||
}
|
||||
return priv_sock_child_recv_fd(p_sess);
|
||||
return priv_sock_recv_fd(p_sess->child_fd);
|
||||
}
|
||||
|
||||
void
|
||||
vsf_two_process_chown_upload(struct vsf_session* p_sess, int fd)
|
||||
{
|
||||
char res;
|
||||
priv_sock_send_cmd(p_sess, PRIV_SOCK_CHOWN);
|
||||
priv_sock_child_send_fd(p_sess, fd);
|
||||
res = priv_sock_get_result(p_sess);
|
||||
priv_sock_send_cmd(p_sess->child_fd, PRIV_SOCK_CHOWN);
|
||||
priv_sock_send_fd(p_sess->child_fd, fd);
|
||||
res = priv_sock_get_result(p_sess->child_fd);
|
||||
if (res != PRIV_SOCK_RESULT_OK)
|
||||
{
|
||||
die("unexpected failure in vsf_two_process_chown_upload");
|
||||
@ -175,7 +210,7 @@ process_login_req(struct vsf_session* p_sess)
|
||||
char cmd;
|
||||
vsf_sysutil_unblock_sig(kVSFSysUtilSigCHLD);
|
||||
/* Blocks */
|
||||
cmd = priv_sock_get_cmd(p_sess);
|
||||
cmd = priv_sock_get_cmd(p_sess->parent_fd);
|
||||
vsf_sysutil_block_sig(kVSFSysUtilSigCHLD);
|
||||
if (cmd != PRIV_SOCK_LOGIN)
|
||||
{
|
||||
@ -184,15 +219,22 @@ process_login_req(struct vsf_session* p_sess)
|
||||
/* Get username and password - we must distrust these */
|
||||
{
|
||||
struct mystr password_str = INIT_MYSTR;
|
||||
priv_sock_get_str(p_sess, &p_sess->user_str);
|
||||
priv_sock_get_str(p_sess, &password_str);
|
||||
priv_sock_get_str(p_sess->parent_fd, &p_sess->user_str);
|
||||
priv_sock_get_str(p_sess->parent_fd, &password_str);
|
||||
p_sess->control_use_ssl = priv_sock_get_int(p_sess->parent_fd);
|
||||
p_sess->data_use_ssl = priv_sock_get_int(p_sess->parent_fd);
|
||||
if (!tunable_ssl_enable)
|
||||
{
|
||||
p_sess->control_use_ssl = 0;
|
||||
p_sess->data_use_ssl = 0;
|
||||
}
|
||||
e_login_result = vsf_privop_do_login(p_sess, &password_str);
|
||||
str_free(&password_str);
|
||||
}
|
||||
switch (e_login_result)
|
||||
{
|
||||
case kVSFLoginFail:
|
||||
priv_sock_send_result(p_sess, PRIV_SOCK_RESULT_BAD);
|
||||
priv_sock_send_result(p_sess->parent_fd, PRIV_SOCK_RESULT_BAD);
|
||||
return;
|
||||
break;
|
||||
case kVSFLoginAnon:
|
||||
@ -240,6 +282,31 @@ process_login_req(struct vsf_session* p_sess)
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
static void
|
||||
process_ssl_slave_req(struct vsf_session* p_sess)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
char cmd = priv_sock_get_cmd(p_sess->ssl_slave_fd);
|
||||
int retval;
|
||||
if (cmd == PRIV_SOCK_GET_USER_CMD)
|
||||
{
|
||||
ftp_getline(p_sess, &p_sess->ftp_cmd_str, p_sess->p_control_line_buf);
|
||||
priv_sock_send_str(p_sess->ssl_slave_fd, &p_sess->ftp_cmd_str);
|
||||
}
|
||||
else if (cmd == PRIV_SOCK_WRITE_USER_RESP)
|
||||
{
|
||||
priv_sock_get_str(p_sess->ssl_slave_fd, &p_sess->ftp_cmd_str);
|
||||
retval = ftp_write_str(p_sess, &p_sess->ftp_cmd_str, kVSFRWControl);
|
||||
priv_sock_send_int(p_sess->ssl_slave_fd, retval);
|
||||
}
|
||||
else
|
||||
{
|
||||
die("bad request in process_ssl_slave_req");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
common_do_login(struct vsf_session* p_sess, const struct mystr* p_user_str,
|
||||
int do_chroot, int anon)
|
||||
@ -248,9 +315,16 @@ common_do_login(struct vsf_session* p_sess, const struct mystr* p_user_str,
|
||||
const struct mystr* p_orig_user_str = p_user_str;
|
||||
int newpid;
|
||||
vsf_sysutil_install_null_sighandler(kVSFSysUtilSigCHLD);
|
||||
/* Asks the pre-login child to go away (by exiting) */
|
||||
priv_sock_send_result(p_sess, PRIV_SOCK_RESULT_OK);
|
||||
(void) vsf_sysutil_wait();
|
||||
/* Tells the pre-login child all is OK (it may exit in response) */
|
||||
priv_sock_send_result(p_sess->parent_fd, PRIV_SOCK_RESULT_OK);
|
||||
if (!p_sess->control_use_ssl)
|
||||
{
|
||||
(void) vsf_sysutil_wait();
|
||||
}
|
||||
else
|
||||
{
|
||||
p_sess->ssl_slave_active = 1;
|
||||
}
|
||||
/* Absorb the SIGCHLD */
|
||||
vsf_sysutil_unblock_sig(kVSFSysUtilSigCHLD);
|
||||
/* Handle loading per-user config options */
|
||||
@ -267,6 +341,11 @@ common_do_login(struct vsf_session* p_sess, const struct mystr* p_user_str,
|
||||
struct mystr userdir_str = INIT_MYSTR;
|
||||
unsigned int secutil_option = VSF_SECUTIL_OPTION_USE_GROUPS;
|
||||
/* Child - drop privs and start proper FTP! */
|
||||
vsf_sysutil_close(p_sess->parent_fd);
|
||||
if (tunable_ssl_enable)
|
||||
{
|
||||
vsf_sysutil_close(p_sess->ssl_slave_fd);
|
||||
}
|
||||
if (tunable_guest_enable && !anon)
|
||||
{
|
||||
/* Remap to the guest user */
|
||||
@ -310,6 +389,11 @@ common_do_login(struct vsf_session* p_sess, const struct mystr* p_user_str,
|
||||
bug("should not get here: common_do_login");
|
||||
}
|
||||
/* Parent */
|
||||
if (tunable_ssl_enable)
|
||||
{
|
||||
vsf_sysutil_close(p_sess->ssl_consumer_fd);
|
||||
/* Keep the SSL slave fd around so we can shutdown() upon exit */
|
||||
}
|
||||
vsf_priv_parent_postlogin(p_sess);
|
||||
bug("should not get here in common_do_login");
|
||||
}
|
||||
|
@ -2,50 +2,27 @@
|
||||
# Cheesy hacky location of additional link libraries.
|
||||
|
||||
locate_library() { [ ! "$1*" = "`echo $1*`" ]; }
|
||||
enabled() { grep "#define $1" builddefs.h >/dev/null; }
|
||||
|
||||
if (grep "#define VSF_BUILD_TCPWRAPPERS" builddefs.h >/dev/null); then
|
||||
if enabled VSF_BUILD_TCPWRAPPERS; then
|
||||
echo "-lwrap";
|
||||
locate_library /lib/libnsl.so && echo "-lnsl";
|
||||
fi
|
||||
|
||||
# Optimizations for specific platforms, to avoid unneccessary libraries
|
||||
# Check for Mandrake first, because it also pretends to be RedHat!!
|
||||
if [ -r /etc/mandrake-release ]; then
|
||||
if [ -r /usr/include/security/pam_appl.h ]; then
|
||||
# Yes, Mandrake's PAM installation is broken
|
||||
echo "/lib/libpam.so.0";
|
||||
else
|
||||
echo "-lcrypt";
|
||||
fi
|
||||
if [ -r /usr/include/sys/capability.h ]; then
|
||||
echo "-lcap";
|
||||
fi
|
||||
exit
|
||||
elif [ -r /etc/redhat-release ]; then
|
||||
if [ -r /usr/include/security/pam_appl.h ]; then
|
||||
echo "-lpam";
|
||||
grep '6\.' /etc/redhat-release >/dev/null && echo "-ldl"
|
||||
grep '5\.' /etc/redhat-release >/dev/null && echo "-ldl"
|
||||
else
|
||||
echo "-lcrypt";
|
||||
fi
|
||||
# Look for libcap, seems to be an optional RH7.2 thing (and may have been
|
||||
# hand installed anyway)
|
||||
if [ -r /usr/include/sys/capability.h ]; then
|
||||
echo "-lcap";
|
||||
fi
|
||||
exit
|
||||
# Look for PAM (done weirdly due to distribution bugs (e.g. Debian) or the
|
||||
# crypt library.
|
||||
if enabled VSF_BUILD_PAM; then
|
||||
locate_library /lib/libpam.so.0 && echo "/lib/libpam.so.0";
|
||||
locate_library /usr/lib/libpam.so && echo "-lpam";
|
||||
# HP-UX ends shared libraries with .sl
|
||||
locate_library /usr/lib/libpam.sl && echo "-lpam";
|
||||
# AIX ends shared libraries with .a
|
||||
locate_library /usr/lib/libpam.a && echo "-lpam";
|
||||
else
|
||||
locate_library /lib/libcrypt.so && echo "-lcrypt";
|
||||
locate_library /usr/lib/libcrypt.so && echo "-lcrypt";
|
||||
fi
|
||||
|
||||
# Look for PAM (done weirdly due to distribution bugs (e.g. Debian)
|
||||
locate_library /lib/libpam.so.0 && echo "/lib/libpam.so.0";
|
||||
locate_library /usr/lib/libpam.so && echo "-lpam";
|
||||
|
||||
# Look for the crypt library
|
||||
# XXX - adds a link library even if it's not needed
|
||||
locate_library /lib/libcrypt.so && echo "-lcrypt"
|
||||
locate_library /usr/lib/libcrypt.so && echo "-lcrypt"
|
||||
|
||||
# Look for the dynamic linker library. Needed by older RedHat when
|
||||
# you link in PAM
|
||||
locate_library /lib/libdl.so && echo "-ldl";
|
||||
@ -62,20 +39,16 @@ locate_library /lib/libresolv.so && echo "-lresolv";
|
||||
# Look for libutil. Older FreeBSD need this for setproctitle().
|
||||
locate_library /usr/lib/libutil.so && echo "-lutil";
|
||||
|
||||
# HP-UX ends shared libraries with .sl
|
||||
locate_library /usr/lib/libpam.sl && echo "-lpam";
|
||||
|
||||
# For older HP-UX...
|
||||
locate_library /usr/lib/libsec.sl && echo "-lsec";
|
||||
|
||||
# AIX ends shared libraries with .a
|
||||
locate_library /usr/lib/libpam.a && echo "-lpam";
|
||||
|
||||
# Look for libcap (capabilities)
|
||||
locate_library /lib/libcap.so /usr/lib/libcap.so && echo "-lcap";
|
||||
locate_library /lib/libcap.so && echo "-lcap";
|
||||
locate_library /usr/lib/libcap.so && echo "-lcap";
|
||||
|
||||
# Solaris needs this for nanosleep()..
|
||||
locate_library /lib/libposix4.so /usr/lib/libposix4.so && echo "-lposix4";
|
||||
locate_library /lib/libposix4.so && echo "-lposix4";
|
||||
locate_library /usr/lib/libposix4.so && echo "-lposix4";
|
||||
|
||||
# Tru64 (nanosleep)
|
||||
locate_library /usr/shlib/librt.so && echo "-lrt";
|
||||
@ -83,5 +56,10 @@ locate_library /usr/shlib/librt.so && echo "-lrt";
|
||||
# Solaris sendfile
|
||||
locate_library /usr/lib/libsendfile.so && echo "-lsendfile";
|
||||
|
||||
# OpenSSL
|
||||
if enabled VSF_BUILD_SSL; then
|
||||
echo "-lssl";
|
||||
fi
|
||||
|
||||
exit 0;
|
||||
|
||||
|
105
vsftpd.conf.5
105
vsftpd.conf.5
@ -33,6 +33,14 @@ to
|
||||
or
|
||||
.BR NO .
|
||||
|
||||
.TP
|
||||
.B allow_anon_ssl
|
||||
Only applies if
|
||||
.BR ssl_enable
|
||||
is active. If set to YES, anonymous users will be allowed to use secured SSL
|
||||
connections.
|
||||
|
||||
Default: NO
|
||||
.TP
|
||||
.B anon_mkdir_write_enable
|
||||
If set to YES, anonymous users will be permitted to create new directories
|
||||
@ -197,6 +205,22 @@ excludes the "." and ".." entries.
|
||||
|
||||
Default: NO
|
||||
.TP
|
||||
.B force_local_data_ssl
|
||||
Only applies if
|
||||
.BR ssl_enable
|
||||
is activated. If activated, all non-anonymous logins are forced to use a secure
|
||||
SSL connection in order to send and receive data on data connections.
|
||||
|
||||
Default: YES
|
||||
.TP
|
||||
.B force_local_logins_ssl
|
||||
Only applies if
|
||||
.BR ssl_enable
|
||||
is activated. If activated, all non-anonymous logins are forced to use a secure
|
||||
SSL connection in order to send the password.
|
||||
|
||||
Default: YES
|
||||
.TP
|
||||
.B guest_enable
|
||||
If enabled, all non-anonymous logins are classed as "guest" logins. A guest
|
||||
login is remapped to the user specified in the
|
||||
@ -249,6 +273,14 @@ Default: NO
|
||||
When enabled, this prevents vsftpd from asking for an anonymous password -
|
||||
the anonymous user will log straight in.
|
||||
|
||||
Default: NO
|
||||
.TP
|
||||
.B no_log_lock
|
||||
When enabled, this prevents vsftpd from taking a file lock when writing to log
|
||||
files. This option should generally not be enabled. It exists to workaround
|
||||
operating system bugs such as the Solaris / Veritas filesystem combination
|
||||
which has been observed to sometimes exhibit hangs trying to lock log files.
|
||||
|
||||
Default: NO
|
||||
.TP
|
||||
.B one_process_model
|
||||
@ -336,7 +368,7 @@ logging, and you wish to give vsftpd more opportunity to run with less
|
||||
processes and / or less privilege. NOTE - utmp and wtmp support is only
|
||||
provided with PAM enabled builds.
|
||||
|
||||
Default: YES
|
||||
Default: NO
|
||||
.TP
|
||||
.B setproctitle_enable
|
||||
If enabled, vsftpd will try and show session status information in the system
|
||||
@ -346,6 +378,41 @@ probably want to leave this off for security purposes.
|
||||
|
||||
Default: NO
|
||||
.TP
|
||||
.B ssl_enable
|
||||
If enabled, and vsftpd was compiled against OpenSSL, vsftpd will support secure
|
||||
connections via SSL. This applies to the control connection (including login)
|
||||
and also data connections. You'll need a client with SSL support too. NOTE!!
|
||||
Beware enabling this option. Only enable it if you need it. vsftpd can make no
|
||||
guarantees about the security of the OpenSSL libraries. By enabling this
|
||||
option, you are declaring that you trust the security of your installed
|
||||
OpenSSL library.
|
||||
|
||||
Default: NO
|
||||
.TP
|
||||
.B ssl_sslv2
|
||||
Only applies if
|
||||
.BR ssl_enable
|
||||
is activated. If enabled, this option will permit SSL v2 protocol connections.
|
||||
TLS v1 connections are preferred.
|
||||
|
||||
Default: NO
|
||||
.TP
|
||||
.B ssl_sslv3
|
||||
Only applies if
|
||||
.BR ssl_enable
|
||||
is activated. If enabled, this option will permit SSL v2 protocol connections.
|
||||
TLS v1 connections are preferred.
|
||||
|
||||
Default: NO
|
||||
.TP
|
||||
.B ssl_tlsv1
|
||||
Only applies if
|
||||
.BR ssl_enable
|
||||
is activated. If enabled, this option will permit TLS v1 protocol connections.
|
||||
TLS v1 connections are preferred.
|
||||
|
||||
Default: YES
|
||||
.TP
|
||||
.B syslog_enable
|
||||
If enabled, then any log output which would have gone to /var/log/vsftpd.log
|
||||
goes to the system log instead. Logging is done under the FTPD facility.
|
||||
@ -366,10 +433,20 @@ By default, numeric IDs are shown in the user and group fields of directory
|
||||
listings. You can get textual names by enabling this parameter. It is off
|
||||
by default for performance reasons.
|
||||
|
||||
Default: NO
|
||||
.TP
|
||||
.B tilde_user_enable
|
||||
If enabled, vsftpd will try and resolve pathnames such as ~chris/pics, i.e. a
|
||||
tilde followed by a username. Note that vsftpd will always resolve the
|
||||
pathnames ~ and ~/something (in this case the ~ resolves to the initial
|
||||
login directory). Note that ~user paths will only resolve if the file
|
||||
.BR /etc/passwd
|
||||
may be found within the _current_ chroot() jail.
|
||||
|
||||
Default: NO
|
||||
.TP
|
||||
.B use_localtime
|
||||
If enabled, vsftpd will display directory listings with the the time in your
|
||||
If enabled, vsftpd will display directory listings with the time in your
|
||||
local time zone. The default is to display GMT. The times returned by the
|
||||
MDTM FTP command are also affected by this option.
|
||||
|
||||
@ -618,6 +695,12 @@ deny_file={*.mp3,*.mov,.private}
|
||||
|
||||
Default: (none)
|
||||
.TP
|
||||
.B dsa_cert_file
|
||||
This option specifies the location of the DSA certificate to use for SSL
|
||||
encrypted connections.
|
||||
|
||||
Default: (none - an RSA certificate suffices)
|
||||
.TP
|
||||
.B email_password_file
|
||||
This option can be used to provide an alternate file for usage by the
|
||||
.BR secure_email_list_enable
|
||||
@ -686,7 +769,7 @@ is enabled.
|
||||
Default: .message
|
||||
.TP
|
||||
.B nopriv_user
|
||||
This is the name of the user that is used by vsftpd when it want to be
|
||||
This is the name of the user that is used by vsftpd when it wants to be
|
||||
totally unprivileged. Note that this should be a dedicated user, rather
|
||||
than nobody. The user nobody tends to be used for rather a lot of important
|
||||
things on most machines.
|
||||
@ -704,6 +787,12 @@ response to the PASV command. Provide a numeric IP address.
|
||||
|
||||
Default: (none - the address is taken from the incoming connected socket)
|
||||
.TP
|
||||
.B rsa_cert_file
|
||||
This option specifies the location of the RSA certificate to use for SSL
|
||||
encrypted connections.
|
||||
|
||||
Default: /usr/share/ssl/certs/vsftpd.pem
|
||||
.TP
|
||||
.B secure_chroot_dir
|
||||
This option should be the name of a directory which is empty. Also, the
|
||||
directory should not be writable by the ftp user. This directory is used
|
||||
@ -711,6 +800,16 @@ as a secure chroot() jail at times vsftpd does not require filesystem access.
|
||||
|
||||
Default: /usr/share/empty
|
||||
.TP
|
||||
.B ssl_ciphers
|
||||
This option can be used to select which SSL ciphers vsftpd will allow for
|
||||
encrpyted SSL connections. See the
|
||||
.BR ciphers
|
||||
man page for further details. Note that restricting ciphers can be a useful
|
||||
security precaution as it prevents malicious remote parties forcing a cipher
|
||||
which they have found problems with.
|
||||
|
||||
Default: DES-CBC3-SHA
|
||||
.TP
|
||||
.B user_config_dir
|
||||
This powerful option allows the override of any config option specified in
|
||||
the manual page, on a per-user basis. Usage is simple, and is best illustrated
|
||||
|
@ -1,7 +1,7 @@
|
||||
#ifndef VSF_VERSION_H
|
||||
#define VSF_VERSION_H
|
||||
|
||||
#define VSF_VERSION "1.2.2"
|
||||
#define VSF_VERSION "2.0.0"
|
||||
|
||||
#endif /* VSF_VERSION_H */
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user