1
0
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:
Dag Wieers 2004-07-01 00:00:00 +02:00
parent 8e72d5f29a
commit b16a99f9dc
52 changed files with 1760 additions and 467 deletions

1
BUGS
View File

@ -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.

View File

@ -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
View File

@ -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.

View File

@ -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)

View File

@ -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)

View File

@ -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
View File

@ -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?
=============

View File

@ -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
View 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
View 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

View File

@ -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.

View File

@ -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
View File

@ -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
===========

View File

@ -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)

View File

@ -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
View File

@ -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
View 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
View 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
View 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 */

View File

@ -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 */

View File

@ -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

View File

@ -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;
}

View File

@ -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,

View File

@ -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;

View File

@ -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
View File

@ -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,

View File

@ -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;
}

View File

@ -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 */

View File

@ -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 }
};

View File

@ -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);
}
}
}
}
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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
View 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
View 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 */

View File

@ -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
View 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
View 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
View File

@ -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

View File

@ -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

View File

@ -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)
{

View File

@ -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);

View File

@ -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);
}

View File

@ -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 */

View File

@ -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 */

View File

@ -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";

View File

@ -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 */

View File

@ -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");
}

View File

@ -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;

View File

@ -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

View File

@ -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 */