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

Updated to v1.1.0

This commit is contained in:
Dag Wieers 2002-07-31 00:00:00 +02:00
parent 20e89955e0
commit 8b211d30ac
69 changed files with 2287 additions and 320 deletions

2
AUDIT
View File

@ -6,6 +6,7 @@ The important rule is that when a file is changed, the audit status goes back
to 1, _unless_ the change(s) are audited very carefully as they go in.
ascii.c 3
banner.c 2
dirchange.c 3
filestr.c 3
ftpcmdio.c 3
@ -24,6 +25,7 @@ privparent.c 3
privsock.c 3
secbuf.c 3
secutil.c 3
standalone.c 2
str.c 2
strlist.c 2
sysdeputil.c 2

View File

@ -1,3 +1,11 @@
- See also SPEED
Update 2nd Nov 2001
ftp.redhat.com ran vsftpd for the RedHat 7.2 release. vsftpd achieved 4,000
concurrent users on a single machine with 1Gb RAM. Even with this insane user
count, bandwidth remained totally saturated. The user count could have been
higher, but the machine ran out of processes.
--
Below are some quick benchmark figures vs. wu-ftpd. This is an untuned BETA
version of vsftpd (0.0.10)

342
COPYING Normal file
View File

@ -0,0 +1,342 @@
vsftpd is licensed under version 2 of the GNU GPL
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

View File

@ -477,7 +477,7 @@ Lars Hecking <lhecking@nmrc.ie>.
- Fix chown_upload bug noted by brett <beldridg@best.com>.
- Add concept of guest user, idea from Andrew Anderson <andrew@redhat.com>.
- Simple bandwidth limitation, inspired by Mads Martin Jørgensen
<mmj@suse.com>.
<mmj@suse.de>.
- Fix chown_upload bug in a different way.
- Correct *_umask details in vsftpd.conf.5, from brett <beldridg@best.com>.
- Don't show .files unless "ls -a" was specified, n.b. this differs in
@ -498,3 +498,91 @@ cleartext password!!
0.9.2 packaged
--------------
- Fix potential leak in PAM handling code.
- Fix build in the non-PAM case (dammit!!). Reported by Alexey E. Korchagin
<Webmaster@buzuluk.ru> and Michael Fengler <michael.fengler@adpag.de>.
- Include filename and size in bytes in the "here comes the data" 150 message.
- Change link flags from "-s" to "-Wl,-s"
- Add libcap support - should fix ia64, Alpha build problems with syscalls.
- Tidy up vsf_findlibs.sh
- Work with NFS mounted home dirs and root_squash, thanks to Hunter Matthews
<thm@duke.edu> for the report.
- Add FAQ.
- Improve "make install".
- Fix Solaris build (nanosleep is in a separate library, typical).
- Fix REST + STOR combination, investigation inspired by Mike Batchelor
<mikebat@tmcs.net>.
0.9.3 packaged
--------------
- Update xinetd file to reflect /usr/local location. Thanks to Fridtjof
Busse <fridtjof@fbunet.de>.
- Make our 150 response code match wu-ftpd - allows broken "ange-ftp" of
emacs to do a percentage complete indicator. Reported by Jonathan Kamens
<jik@kamens.brookline.ma.us> via Andrew Anderson <andrew@redhat.com>.
- Fix build on S390, ia64 platforms (poor kernel includes). Patch from
<mmj@suse.de>.
- Fix up vsf_findlibs.sh to cater for RedHat7.2 which has libcap. Reported
by Chris Burton <chris@post.cpac.uk.com>.
- Boast some more in BENCHMARKS.
- Add anon_root and local_root, inspired by Ole Tange <tange@tange.dk>.
- Fix up vsf_findlibs.sh to cater for broken Mandrake, and also consider
the case of missing PAM headers (no pam-devel installed). Thanks to
Jeff Baldwin <jeff_baldwin@unc.edu> for access to Mandrake.
At this point: 1.0.0 packaged and released
------------------------------------------
Ah, the wonderful psychology of release numbers
-----------------------------------------------
- Fix IRIX build (capabilities issue), Jan-Frode Myklebust
<janfrode@parallab.uib.no>.
- Fix FreeBSD build, reported by Jim Breton
<jamesb-security-audit@alongtheway.com>.
- Fix Debian build, reported by Brian Clark <brianj@fusionwerks.com>.
1.0.1 packaged
--------------
- Fix .spec files to use /usr/local/sbin not /usr/sbin, noted by Bill Unruh
<unruh@physics.ubc.ca>.
- Small doc tweaks and improvements(?)
- Add COPYING, the GNU GPL version 2.
- Add use_localtime config option to override the use of GMT times.
- Add tunable_check_shell (default YES) so people can disable this if they
are not using PAM.
- AIX 5.1 build support, thanks to Jan-Frode Myklebust
<janfrode@parallab.uib.no>.
- Add "hide_ids" option to show user/group in directory listings as "ftp".
Request from Solar.
- Use the seemingly more portable setreuid() and setregid(), poxy HP.
- Use status 550 instead of 500 for known but disabled commands.
- Rename "dirchange.[ch]" to "banner.[ch]".
- Multiline connect banner support via "banner_file" config option.
- Minor error message changes.
- Add more FAQ entries.
- Add patch to specify PASV address - thanks to Mike McLean <mikem@redhat.com>.
- Drop the 2.4.0 kernel warning file
- Rudimentary standalone listener support - to be expanded in a later release.
- If sendfile() returns EINVAL just fall back to normal routines - handles
non-pagecache backed files.
- Add "port_promiscuous" setting - should help enabling FXP.
- Modify anon_root and local_root to change directory _before_ applying the
chroot().
- Open all files O_NONBLOCK to avoid pipes blocking on open.
- Support wu-ftpd style per-user chroot() via /./ in /etc/passwd HOMEDIR.
- Add SIGHUP support to new built in listener.
- Per-user config overrides, via "user_config_dir" - woohoo!
- Warning fixes, i.e. change "index" to "indexx" thanks to Olaf Kirch
<okir@suse.de>.
- Make sure the standalone daemon doesn't leak zombies!
- Supposedly fix kernel messages about MSG_PEEK race - thanks to advice from
Alexey <kuznet@ms2.inr.ac.ru>.
- Add global client limit for standalone mode.
- Add username that failed when we die with str_getpwnam.
- Add a bunch of documentation under EXAMPLES.
At this point: 1.1.0 package released
-------------------------------------

View File

@ -0,0 +1,138 @@
This example shows how you might set up a (possibly large) internet facing
FTP site.
The emphasis will be on security and performance.
We will see how by integrating vsftpd with xinetd, we get a powerful
combination.
Step 1) Set up your xinetd configuration file.
An example xinetd configuration file "vsftpd.xinetd" is supplied.
To install it:
cp vsftpd.xinetd /etc/xinetd.d/vsftpd
Let's look at the important content in this file and see what it does:
disable = no
socket_type = stream
wait = no
This says that the service is active, and it is using standard TCP sockets.
user = root
server = /usr/local/sbin/vsftpd
The server program /usr/local/sbin/vsftpd is used to handle incoming FTP
requests, and the program is started as root (vsftpd will of course quickly
drop as much privilege as possible). NOTE! Make sure that you have the vsftpd
binary installed in /usr/local/sbin (or change the file path in the xinetd
file).
per_source = 5
instances = 200
For security, the maximum allowed connections from a single IP address is 5.
The total maximum concurrent connections is 200.
no_access = 192.168.1.3
As an example of how to ban certain sites from connecting, 192.168.1.3 will
be denied access.
banner_fail = /etc/vsftpd.busy_banner
This is the file to display to users if the connection is refused for whatever
reason (too many users, IP banned).
Example of how to populate it:
echo "421 Server busy, please try later." > /etc/vsftpd.busy_banner
log_on_success += PID HOST DURATION
log_on_failure += HOST
This will log the IP address of all connection attempts - successful or not,
along with the time. If an FTP server is launched for the connection, it's
process ID and usage duration will be logged too. If you are using RedHat
like me, this log information will appear in /var/log/secure.
Step 2) Set up your vsftpd configuration file.
An example file is supplied. Install it like this:
cp vsftpd.conf /etc
Let's example the contents of the file:
# Access rights
anonymous_enable=YES
local_enable=NO
write_enable=NO
anon_upload_enable=NO
anon_mkdir_write_enable=NO
anon_other_write_enable=NO
This makes sure the FTP server is in anonymous-only mode and that all write
and upload permissions are disabled. Note that most of these settings are
the same as the default values anyway - but where security is concerned, it
is good to be clear.
# Security
anon_world_readable_only=YES
connect_from_port_20=YES
hide_ids=YES
pasv_min_port=50000
pasv_max_port=60000
These settings, in order
- Make sure only world-readable files and directories are served.
- Originates FTP port connections from a secure port - so users on the FTP
server cannot try and fake file content.
- Hide the FTP server user IDs and just display "ftp" in directory listings.
This is also a performance boost.
- Set a 50000-60000 port range for passive connections - may enable easier
firewall setup!
# Features
xferlog_enable=YES
ls_recurse_enable=NO
ascii_download_enable=NO
async_abor_enable=YES
In order,
- Enables recording of transfer stats to /var/log/vsftpd.log
- Disables "ls -R", to prevent it being used as a DoS attack. Note - sites
wanting to be copied via the "mirror" program might need to enable this.
- Disables downloading in ASCII mode, to prevent it being used as a DoS
attack (ASCII downloads are CPU heavy).
- Enables older FTP clients to cancel in-progress transfers.
# Performance
one_process_model=YES
idle_session_timeout=120
data_connection_timeout=300
accept_timeout=60
connect_timeout=60
anon_max_rate=50000
In order,
- Activates a faster "one process per connection" model. Note! To maintain
security, this feature is only available on systems with capabilities - e.g.
Linux kernel 2.4.
- Boots off idle users after 2 minutes.
- Boots off idle downloads after 5 minutes.
- Boots off hung passive connects after 1 minute.
- Boots off hung active connects after 1 minute.
- Limits a single client to ~50kbytes / sec download speed.
Step 3) Restart xinetd.
(on RedHat)
/etc/rc.d/init.d/xinetd restart
If you run into problems, check:
1) Your /etc/xinetd.d directory only has one FTP service.

View File

@ -0,0 +1,25 @@
# Access rights
anonymous_enable=YES
local_enable=NO
write_enable=NO
anon_upload_enable=NO
anon_mkdir_write_enable=NO
anon_other_write_enable=NO
# Security
anon_world_readable_only=YES
connect_from_port_20=YES
hide_ids=YES
pasv_min_port=50000
pasv_max_port=60000
# Features
xferlog_enable=YES
ls_recurse_enable=NO
ascii_download_enable=NO
async_abor_enable=YES
# Performance
one_process_model=YES
idle_session_timeout=120
data_connection_timeout=300
accept_timeout=60
connect_timeout=60
anon_max_rate=50000

View File

@ -0,0 +1,15 @@
# vsftpd is the secure FTP server.
service ftp
{
disable = no
socket_type = stream
wait = no
user = root
server = /usr/local/sbin/vsftpd
per_source = 5
instances = 200
no_access = 192.168.1.3
banner_fail = /etc/vsftpd.busy_banner
log_on_success += PID HOST DURATION
log_on_failure += HOST
}

15
EXAMPLE/README Normal file
View File

@ -0,0 +1,15 @@
These subdirectories contain examples of vsftpd usage.
These examples are known to work on a RedHat 7.2 installation. Some of them
rely on xinetd and / or a highly functional version of PAM.
The examples should serve to illustrate how vsftpd becomes extremely powerful
when intregration with xinetd for connection handling and PAM for
authentication.
Contents
========
INTERNET_SITE How you might configure vsftpd for an internet site.
VIRTUAL_HOSTS How to set up vsftpd with virtual hosting.
VIRTUAL_USERS How to set up virtual users with vsftpd.
VIRTUAL_USERS_2 Advanced virtual users - different access rights.

View File

@ -0,0 +1,77 @@
This example shows how you might set up virtual hosts. Virtual hosting is
where different clients access your machine on different IP addresses (virtual
IPs) and get redirected to different ftp sites.
For example, if your machine responds to two IPs - 127.0.0.1 and 127.0.0.2,
you could have the two different IPs represent two totally different FTP sites.
For this example, we are going to build on the "INTERNET_SITE" example.
Step 1) Set up a virtual IP address.
ifconfig eth0:1 192.168.1.10 up
(the standard IP address is 192.168.1.2)
(note - this isn't quite complete, the route for local connects hasn't been
added, but it will do for now)
Step 2) Create a user / location for the new virtual site.
useradd -d /var/ftp_site2 ftp_site2
chown root.root /var/ftp_site2
chmod a+rx /var/ftp_site2
umask 022
mkdir /var/ftp_site2/pub
echo "test" > /var/ftp_site2/pub/content
Step 3) Modify the existing site to respond to the primary IP.
Edit /etc/xinetd.d/vsftpd, and add the config line:
bind = 192.168.1.2
Step 4) Create the new site, responding on the virtual IP.
cp /etc/xinetd.d/vsftpd /etc/xinetd.d/vsftpd2
Edit vsftpd2, and change
- The bind line to refer to the IP address 192.168.1.10
- Add the line
server_args = /etc/vsftpd_site2.conf
This launches this FTP site with a different vsftpd configuration file.
cp /etc/vsftpd.conf /etc/vsftpd_site2.conf
Add two lines:
ftp_username=ftp_site2
ftpd_banner=This is the alternative FTP site.
Step 5) Restart xinetd and test!
/etc/rc.d/init.d/xinetd restart
[chris@localhost vsftpd]$ ftp 192.168.1.2
Connected to 192.168.1.2 (192.168.1.2).
220 ready, dude (vsFTPd 1.1.0: beat me, break me)
Name (192.168.1.2:chris): [chris@localhost vsftpd]$
[chris@localhost vsftpd]$ ftp 192.168.1.2
Connected to 192.168.1.2 (192.168.1.2).
220 ready, dude (vsFTPd 1.1.0: beat me, break me)
Name (192.168.1.2:chris):
530 This FTP server is anonymous only.
Login failed.
ftp> quit
221 Goodbye.
[chris@localhost vsftpd]$ ftp 192.168.1.10
Connected to 192.168.1.10 (192.168.1.10).
220 This is the alternative FTP site.
Name (192.168.1.10:chris):
530 This FTP server is anonymous only.
Login failed.
ftp>

View File

@ -0,0 +1,150 @@
This example shows how to set up vsftpd / PAM with "virtual users".
A virtual user is a user login which does not exist as a real login on the
system. Virtual users can therefore be more secure than real users, beacuse
a compromised account can only use the FTP server.
Virtual users are often used to serve content that should be accessible to
untrusted users, but not generally accessible to the public.
Step 1) Create the virtual users database.
We are going to use pam_userdb to authenticate the virtual users. This needs
a username / password file in "db" format - a common database format.
To create a "db" format file, first create a plain text files with the
usernames and password on alternating lines.
See example file "logins.txt" - this specifies "tom" with password "foo" and
"fred" with password "bar".
Whilst logged in as root, create the actual database file like this:
db_load -T -t hash -f logins.txt /etc/vsftpd_login.db
(Requires the Berkeley db program installed).
This will create /etc/vsftpd_login.db. Obviously, you may want to make sure
the permissions are restricted:
chmod 600 /etc/vsftpd_login.db
For more information on maintaing your login database, look around for
documentation on "Berkeley DB", e.g.
http://www.sleepycat.com/docs/utility/index.html
Step 2) Create a PAM file which uses your new database.
See the example file vsftpd.pam. It contains two lines:
auth required /lib/security/pam_userdb.so db=/etc/vsftpd_login
account required /lib/security/pam_userdb.so db=/etc/vsftpd_login
This tells PAM to authenticate users using our new database. Copy this PAM
file to the PAM directory - typically /etc/pam.d/
cp vsftpd.pam /etc/pam.d/ftp
Step 3) Set up the location of the files for the virtual users.
useradd -d /home/ftpsite virtual
ls -ld /home/ftpsite
(which should give):
drwx------ 3 virtual virtual 4096 Jul 30 00:39 /home/ftpsite
We have created a user called "virtual" with a home directory "/home/ftpsite".
Let's add some content to this download area:
cp /etc/hosts /home/ftpsite
chown virtual.virtual /home/ftpsite/hosts
Step 4) Create your vsftpd.conf config file.
See the example in this directory. Let's go through it line by line:
anonymous_enable=NO
local_enable=YES
This disables anonymous FTP for security, and enables non-anonymous FTP (which
is what virtual users use).
write_enable=NO
anon_upload_enable=NO
anon_mkdir_write_enable=NO
anon_other_write_enable=NO
These ensure that for security purposes, no write commands are allowed.
chroot_local_user=YES
This makes sure that the virtual user is restricted to the virtual FTP area
/home/ftpsite we set up above.
guest_enable=YES
guest_username=virtual
The guest_enable is very important - it activates virtual users! And
guest_username says that all virtual users are mapped to the real user
"virtual" that we set up above. This will also determine where on the
filesystem the virtual users end up - the home directory of the user
"virtual", /home/ftpsite.
listen=YES
listen_port=10021
This puts vsftpd in "standalone" mode - i.e. not running from an inetd. This
means you just run the vsftpd executable and it will start up. This also
makes vsftpd listen for FTP requests on the non-standard port of 10021 (FTP
is usually 21).
pasv_min_port=30000
pasv_max_port=30999
These put a port range on passive FTP incoming requests - very useful if
you are configuring a firewall.
Copy the example vsftpd.conf file to /etc:
cp vsftpd.conf /etc/
Step 5) Start up vsftpd.
Go to the directory with the vsftpd binary in it, and:
./vsftpd
If all is well, the command will sit there. If all is not well, you will
likely see some error message.
Step 6) Test.
Launch another shell session (or background vsftpd with CTRL-Z and then "bg").
Here is an example of an FTP session:
ftp localhost 10021
Connected to localhost (127.0.0.1).
220 ready, dude (vsFTPd 1.1.0: beat me, break me)
Name (localhost:chris): tom
331 Please specify the password.
Password:
230 Login successful. Have fun.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> pwd
257 "/"
ftp> ls
227 Entering Passive Mode (127,0,0,1,117,135)
150 Here comes the directory listing.
226 Transfer done (but failed to open directory).
ftp> size hosts
213 147
ftp>
Comments:
The password we gave was "foo".
Do not be alarmed by the "failed to open directory". That is because the
directory /home/ftpsite is not world readable (we could change this
behaviour if we wanted using anon_world_readable_only=NO but maybe we want
it this way for security.
We can see that we have access to the "hosts" file we copied into the virtual
FTP area, via the size command.

View File

@ -0,0 +1,4 @@
tom
foo
fred
bar

View File

@ -0,0 +1,13 @@
anonymous_enable=NO
local_enable=YES
write_enable=NO
anon_upload_enable=NO
anon_mkdir_write_enable=NO
anon_other_write_enable=NO
chroot_local_user=YES
guest_enable=YES
guest_username=virtual
listen=YES
listen_port=10021
pasv_min_port=30000
pasv_max_port=30999

View File

@ -0,0 +1,2 @@
auth required /lib/security/pam_userdb.so db=/etc/vsftpd_login
account required /lib/security/pam_userdb.so db=/etc/vsftpd_login

View File

@ -0,0 +1,55 @@
This example shows how to extend the "VIRTUAL_USERS" example to reflect
a slightly more complex setup.
Let's assume that we want two types of virtual user - one that can only browse
and download content, and another that can upload new content as well as
download existing content.
To achieve this setup, we can use use of vsftpd's powerful per-user
configurability (new in v1.1.0).
In the previous virtual user example, we created two users - tom and fred.
Let's say that we want fred to have write access to upload new files whilst
tom can only download.
Step 1) Activate per-user configurability.
To activate this powerful vsftpd feature, add the following to
/etc/vsftpd.conf:
user_config_dir=/etc/vsftpd_user_conf
And, create this directory:
mkdir /etc/vsftpd_user_conf
Step 2) Give tom the ability to read all files / directories.
At the end of the last example, we noted that the virtual users can only
see world-readable files and directories. We could make the /home/ftpsite
directory world readable, and upload files with world-read permission. But
another way of doing this is giving tom the ability to download files which
are not world-readable.
For the tom user, supply a config setting override for
anon_world_readable_only:
echo "anon_world_readable_only=NO" > /etc/vsftpd_user_conf/tom
Check it out - login as tom and now "ls" will return a directory listing!
Log in as fred and it won't.
NOTE - restart vsftpd to pick up the config setting changes to
/etc/vsftpd.conf. (Advanced users can send SIGHUP to the vsftpd listener
process).
Step 3) Give fred the ability to read all files / directories and create
new ones but not interfere with existing files.
echo "anon_world_readable_only=NO" > /etc/vsftpd_user_conf/fred
echo "write_enable=YES" >> /etc/vsftpd_user_conf/fred
echo "anon_upload_enable=YES" >> /etc/vsftpd_user_conf/fred
Check it out - login as tom and you can't upload. Log in as fred and you can!
Try and delete a file as both tom and fred - you can't.

79
FAQ Normal file
View File

@ -0,0 +1,79 @@
vsftpd frequently asked questions!!
-----------------------------------
Q) Does vsftpd support a limit on the number of users connected?
A) Yes, indirectly. vsftpd is an inetd-based service. If use the popular
"xinetd" as your inetd, this supports per-service per-IP connection limits.
Q) Help! I'm getting the error message "refusing to run with writable anonymous
root".
A) vsftpd is protecting against dangerous configurations. The cause of this
message is usually dodgy ownership of the ftp home directory. The home
directory should NOT be owned by the ftp user itself. Neither should it
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.
Q) Help! Local users cannot log in.
A) There are various possible problems.
A1) By default, vsftpd disables any logins other than anonymous logins. Put
local_enable=YES in your /etc/vsftpd.conf to allow local users to log in.
A2) vsftpd tries to link with PAM. (Run "ldd vsftpd" and look for libpam to
find out whether this has happened or not). If vsftpd links with PAM, then
you will need to have a PAM file installed for the vsftpd service. There is
a sample one for RedHat systems included in the "RedHat" directory - put it
under /etc/pam.d
A3) If vsftpd didn't link with PAM, then there are various possible issues. Is
the user's shell in /etc/shells? If you have shadowed passwords, does your
system have a "shadow.h" file in the include path?
A4) If you are not using PAM, then vsftpd will do its own check for a valid
user shell in /etc/shells. You may need to disable this if you use an invalid
shell to disable logins other than FTP logins. Put check_shell=NO in your
/etc/vsftpd.conf.
Q) Help! Uploads or other write commands give me "500 Unknown command.".
A) By default, write commands, including uploads and new directories, are
disabled. This is a security measure. To enable writes, put write_enable=YES
in your /etc/vsftpd.conf.
Q) Help! What are the security implications referred to in the
"chroot_local_user" option?
A) Firstly note that other ftp daemons have the same implications. It is a
generic problem.
The problem isn't too severe, but it is this: Some people have FTP user
accounts which are not trusted to have full shell access. If these
accounts can also upload files, there is a small risk. A bad user now has
control of the filesystem root, which is their home directory. The ftp
daemon might cause some config file to be read - e.g. /etc/some_file. With
chroot(), this file is now under the control of the user. vsftpd is
careful in this area. But, the system's libc might want to open locale
config files or other settings...
Q) Help! Uploaded files are appearing with permissions -rw-------.
A) Depending on if this is an upload by a local user or an anonymous user,
use "local_umask" or "anon_umask" to change this. For example, use
"anon_umask=022" to give anonymously uploaded files permissions
-rw-r--r--. Note that the "0" before the "22" is important.
Q) Help! How do I integrate with LDAP users and logins?
A) Use vsftpd's PAM integration to do this, and have PAM authenticate against
an LDAP repository.
Q) Help! Does vsftpd do virtual hosting setups?
A) Yes. If you integrate vsftpd with xinetd, you can use xinetd to bind to
several different IP addresses. For each IP address, get xinetd to launch
vsftpd with a different config file. This way, you can get different behaviour
per virtual address.
Q) Help! Does vsftpd support virtual users?
A) Yes, via PAM integration. Set "guest_enable=YES" in /etc/vsftpd.conf. This
has the effect of mapping every non-anonymous successful login to the local
username specified in "guest_username". Then, use PAM and (e.g.) its pam_userdb
module to provide authentication against an external (i.e. non-/etc/passwd)
repository of users.
Note - currently there is a restriction that with guest_enable enabled, local
users also get mapped to guest_username.

View File

@ -1,9 +1,13 @@
For now, just type "make" and mail me if it doesn't build.
Running "make install" will try to copy the binary, man pages, etc. to
somewhere sensible.
Once built, you will need to run the binary from an inetd of some kind.
The FTP server will refuse to start up unless you satisfy a few prerequisites:
1) You will need the user "ftp" to exist and have a valid home directory.
1) You will need the user "ftp" to exist and have a valid home directory. The
home directory must NOT be owned by the "ftp" user, nor must it be writable
by the FTP user.
2) You will need the user "nobody" to exist.
3) You will need an empty directory /usr/share/empty to exist.
@ -28,6 +32,8 @@ as opposed to xinetd, be careful to specify the program name argv[0] before
the config file location argv[1]!
Tested platforms (well, it builds)
- RedHat Linux 7.3
- RedHat Linux 7.2
- RedHat Linux 7.0
- RedHat Linux 6.1
- RedHat Linux 6.2

View File

@ -1,9 +0,0 @@
WARNING
-------
vsftpd seems to under some conditions kill kernels 2.4.0 and 2.4.1 dead. The
problem has been observed by several people. The problem has been reported,
and was fixed in kernel version 2.4.2-pre1.
The problem seems to trigger when vsftpd exits.

View File

@ -1 +1,4 @@
GPL v2
See "COPYING"
Everything within the vsftpd tarball is licensed under version 2 of the GPL.

View File

@ -2,16 +2,17 @@
CC = gcc
INSTALL = install
IFLAGS = -idirafter dummyinc
#CFLAGS = -g
CFLAGS = -O2 -Wall -W -Wshadow #-pedantic -Werror -Wconversion
LIBS = `./vsf_findlibs.sh`
LINK = -s
LINK = -Wl,-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 \
banner.o filestr.o parseconf.o secutil.o \
ascii.o oneprocess.o twoprocess.o privops.o standalone.o \
sysutil.o sysdeputil.o
.c.o:
@ -21,7 +22,19 @@ vsftpd: $(OBJS)
$(CC) -o vsftpd $(OBJS) $(LINK) $(LIBS)
install:
$(INSTALL) -m 755 vsftpd /usr/sbin/vsftpd
if [ -x /usr/local/sbin ]; then \
$(INSTALL) -m 755 vsftpd /usr/local/sbin/vsftpd; \
else \
$(INSTALL) -m 755 vsftpd /usr/sbin/vsftpd; fi
if [ -x /usr/local/man ]; then \
$(INSTALL) -m 644 vsftpd.8 /usr/local/man/man8/vsftpd.8; \
$(INSTALL) -m 644 vsftpd.conf.5 /usr/local/man/man5/vsftpd.conf.5; \
elif [ -x /usr/share/man ]; then \
$(INSTALL) -m 644 vsftpd.8 /usr/share/man/man8/vsftpd.8; \
$(INSTALL) -m 644 vsftpd.conf.5 /usr/share/man/man5/vsftpd.conf.5; \
else \
$(INSTALL) -m 644 vsftpd.8 /usr/man/man8/vsftpd.8; \
$(INSTALL) -m 644 vsftpd.conf.5 /usr/man/man5/vsftpd.conf.5; fi
if [ -x /etc/xinetd.d ]; then \
$(INSTALL) -m 644 xinetd.d/vsftpd /etc/xinetd.d/vsftpd; fi

21
README
View File

@ -1,4 +1,4 @@
This is vsftpd, version 0.9.2
This is vsftpd, version 1.1.0
Author: Chris Evans
Contact: chris@scary.beasts.org
@ -10,12 +10,17 @@ this is not a guarantee, but a reflection that I have written the entire
codebase with security in mind, and carefully designed the program to be
resilient to attack.
Recent evidence suggests that vsftpd is also extremely fast (and this is
before any explicit performance tuning!) In tests against wu-ftpd, vsftpd
was always faster, supporting over twice as many users in some tests.
Recent evidence shows that vsftpd is also extremely fast and scalable. vsftpd
has achieved ~4000 concurrent users on a single machine, in a production
environment.
Note - this is currently very much a work in progress, so some areas of the
source are a bit of a mess. Please don't take this as indicative of the
quality of my completed work ;-)
vsftpd is now a proven stable solution. Of particular note, RedHat used vsftpd
to enable ftp.redhat.com to support 15,000 concurrent users across their
server pool. This extreme load was generated by the release of RedHat 7.2 to
the world.
Installation
============
Please see the INSTALL file.
This document will be expanded in a future release!

View File

@ -1,6 +1,6 @@
Summary: vsftpd - Very Secure Ftp Daemon
Name: vsftpd
Version: 0.9.2
Version: 1.1.0
Release: rh6_1
Copyright: GPL
Group: System Environment/Daemons
@ -31,7 +31,7 @@ mkdir -p $RPM_BUILD_ROOT/etc/pam.d
mkdir -p $RPM_BUILD_ROOT/etc/logrotate.d
mkdir -p $RPM_BUILD_ROOT/%{_mandir}/man5
mkdir -p $RPM_BUILD_ROOT/%{_mandir}/man8
install -m 755 vsftpd $RPM_BUILD_ROOT/usr/sbin/vsftpd
install -m 755 vsftpd $RPM_BUILD_ROOT/usr/local/sbin/vsftpd
install -m 600 vsftpd.conf $RPM_BUILD_ROOT/etc/vsftpd.conf
install -m 644 RedHat/vsftpd.pam $RPM_BUILD_ROOT/etc/pam.d/ftp
install -m 644 vsftpd.conf.5 $RPM_BUILD_ROOT/%{_mandir}/man5/
@ -43,7 +43,7 @@ install -m 644 RedHat/vsftpd.log $RPM_BUILD_ROOT/etc/logrotate.d/vsftpd.log
%files
%defattr(-,root,root)
/usr/sbin/vsftpd
/usr/local/sbin/vsftpd
%dir /usr/share/empty
%config /etc/vsftpd.conf
%config /etc/pam.d/ftp

View File

@ -1,6 +1,6 @@
Summary: vsftpd - Very Secure Ftp Daemon
Name: vsftpd
Version: 0.9.2
Version: 1.1.0
Release: rh7_2
Copyright: GPL
Group: System Environment/Daemons
@ -24,7 +24,7 @@ make
%install
[ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT
mkdir -p $RPM_BUILD_ROOT/usr/sbin
mkdir -p $RPM_BUILD_ROOT/usr/local/sbin
mkdir -p $RPM_BUILD_ROOT/usr/share/empty
mkdir -p $RPM_BUILD_ROOT/etc
mkdir -p $RPM_BUILD_ROOT/etc/xinetd.d
@ -32,7 +32,7 @@ mkdir -p $RPM_BUILD_ROOT/etc/pam.d
mkdir -p $RPM_BUILD_ROOT%{_mandir}/man5
mkdir -p $RPM_BUILD_ROOT%{_mandir}/man8
mkdir -p $RPM_BUILD_ROOT/etc/logrotate.d
install -m 755 vsftpd $RPM_BUILD_ROOT/usr/sbin/vsftpd
install -m 755 vsftpd $RPM_BUILD_ROOT/usr/local/sbin/vsftpd
install -m 600 vsftpd.conf $RPM_BUILD_ROOT/etc/vsftpd.conf
install -m 644 RedHat/vsftpd.pam $RPM_BUILD_ROOT/etc/pam.d/ftp
install -m 644 xinetd.d/vsftpd $RPM_BUILD_ROOT/etc/xinetd.d/vsftpd
@ -45,7 +45,7 @@ install -m 644 RedHat/vsftpd.log $RPM_BUILD_ROOT/etc/logrotate.d/vsftpd.log
%files
%defattr(-,root,root)
/usr/sbin/vsftpd
/usr/local/sbin/vsftpd
%dir /usr/share/empty
%config /etc/vsftpd.conf
%config /etc/xinetd.d/vsftpd

4
SPEED
View File

@ -1,3 +1,5 @@
- See also BENCHMARKS
This FTPd should be very performant. The reasons for this are below, followed
by specific benchmarks as and when I get them.
@ -15,7 +17,7 @@ of the fork(), exec(), ELF loader startup, etc.
It is not all good news, of course. Potential sources of poor performance
include
1) Overhead of two processes per session (in common configurations).
1) Overhead of two processes per session (in some common configurations).
2) Excessive heap usage hidden behind the string API.

16
TODO
View File

@ -4,19 +4,19 @@ CRITICAL
NOT SO CRITICAL
===============
- separate upload/download max rates
- select() is assuming Linux behaviour (not threatening stability)
- IPv6 support
- "make install" should install man pages
- enhance standalone support (IP filtering, concurrent connection limits)
ON THE BACK BURNER
==================
- "Minimal" build support
- pam_session - I don't think it buys me wtmp
- transfer stats
- Small race: signal might come in just before we start a blocking call
- Support for "welcome.msg" on initial connection
- wtmp support
- wtmp support (should be done through pam_session support?)
- OpenSSL support
- transparent compression support
- transparent tar support
NOT PLANNED
===========
@ -24,4 +24,6 @@ NOT PLANNED
- syslog() support - I don't want to encourage the broken beast
- telnet strings (no demand)
- better pattern matching in "ls" (no demand)
- standalone support (no demand, connections not a bottleneck)
- "Minimal" build support
- transparent tar / compression support (no demand)

2
TUNING
View File

@ -13,7 +13,7 @@ operating systems. Currently, Linux 2.2+ and FreeBSD 3.0+ use sendfile().
Consider running on these excellent operating systems.
3) Irritated by vsftpd using _two_ processes per connection? Don't be, it's
a very secure architecture. However, if you run Linux 2.4+, or Linux 2.2.19, a
a very secure architecture. However, if you run Linux 2.4+, or Linux 2.2.19+, a
"one process" security model is possible thanks to nifty security features.
See the vsftpd.conf man page.

16
ascii.c
View File

@ -14,17 +14,17 @@ vsf_ascii_ascii_to_bin(const char* p_in, char* p_out, unsigned int in_len)
* For simplicity, I'm cheating and just ripping out all \r. If someone
* complains about it breaking something, it'll get fixed.
*/
unsigned int index = 0;
unsigned int indexx = 0;
unsigned int written = 0;
while (index < in_len)
while (indexx < in_len)
{
char the_char = p_in[index];
char the_char = p_in[indexx];
if (the_char != '\r')
{
*p_out++ = the_char;
written++;
}
index++;
indexx++;
}
return written;
}
@ -35,11 +35,11 @@ vsf_ascii_bin_to_ascii(const char* p_in, char* p_out, unsigned int in_len)
/* Task: translate all \n into \r\n. Note that \r\n becomes \r\r\n. That's
* what wu-ftpd does, and it's easier :-)
*/
unsigned int index = 0;
unsigned int indexx = 0;
unsigned int written = 0;
while (index < in_len)
while (indexx < in_len)
{
char the_char = p_in[index];
char the_char = p_in[indexx];
if (the_char == '\n')
{
*p_out++ = '\r';
@ -47,7 +47,7 @@ vsf_ascii_bin_to_ascii(const char* p_in, char* p_out, unsigned int in_len)
}
*p_out++ = the_char;
written++;
index++;
indexx++;
}
return written;
}

View File

@ -2,13 +2,14 @@
* Part of Very Secure FTPd
* Licence: GPL
* Author: Chris Evans
* dirchange.c
* banner.c
*
* Calls exposed to handle the junk a typical FTP server has to do upon
* entering a new directory (messages, etc).
* entering a new directory (messages, etc), as well as general banner
* writing support.
*/
#include "dirchange.h"
#include "banner.h"
#include "strlist.h"
#include "str.h"
#include "sysstr.h"
@ -23,7 +24,7 @@
#define VSFTP_MAX_MSGFILE_SIZE 1000
void
dir_changed(struct vsf_session* p_sess, int ftpcode)
vsf_banner_dir_changed(struct vsf_session* p_sess, int ftpcode)
{
struct mystr dir_str = INIT_MYSTR;
/* Do nothing if .message support is off */
@ -52,18 +53,24 @@ dir_changed(struct vsf_session* p_sess, int ftpcode)
*/
{
struct mystr msg_file_str = INIT_MYSTR;
struct mystr msg_line_str = INIT_MYSTR;
unsigned int str_pos = 0;
(void) str_fileread(&msg_file_str, tunable_message_file,
VSFTP_MAX_MSGFILE_SIZE);
while (str_getline(&msg_file_str, &msg_line_str, &str_pos))
{
vsf_cmdio_write_str_hyphen(p_sess, ftpcode, &msg_line_str);
}
vsf_banner_write(p_sess, &msg_file_str, ftpcode);
str_free(&msg_file_str);
str_free(&msg_line_str);
}
}
str_free(&dir_str);
}
void
vsf_banner_write(struct vsf_session* p_sess, struct mystr* p_str, int ftpcode)
{
struct mystr msg_line_str = INIT_MYSTR;
unsigned int str_pos = 0;
while (str_getline(p_str, &msg_line_str, &str_pos))
{
vsf_cmdio_write_str_hyphen(p_sess, ftpcode, &msg_line_str);
}
str_free(&msg_line_str);
}

33
banner.h Normal file
View File

@ -0,0 +1,33 @@
#ifndef VSF_BANNER_H
#define VSF_BANNER_H
struct vsf_session;
struct mystr;
/* vsf_banner_dir_changed()
* PURPOSE
* This function, when called, will check if the current directory has just
* been entered for the first time in this session. If so, and message file
* support is on, a message file is looked for (default .message), and output
* to the FTP control connection with the FTP code prefix specified by
* "ftpcode".
* PARAMETERS
* p_sess - the current FTP session object
* ftpcode - the FTP code to show with the message
*/
void vsf_banner_dir_changed(struct vsf_session* p_sess, int ftpcode);
/* vsf_banner_write()
* PURPOSE
* This function, when called, will write the specified string as a multiline
* FTP banner, using the specified FTP response code.
* PARAMETERS
* p_sess - the current FTP session object
* p_str - the string to write
* ftpcode - the FTP code to show with the message
*/
void vsf_banner_write(struct vsf_session* p_sess, struct mystr* p_str,
int ftpcode);
#endif /* VSF_BANNER_H */

3
defs.h
View File

@ -13,8 +13,9 @@
#define VSFTP_DIR_BUFSIZE 16384
#define VSFTP_PATH_MAX 4096
#define VSFTP_CONF_FILE_MAX 100000
#define VSFTP_LISTEN_BACKLOG 32
#define VSFTP_SECURE_UMASK 077
#define VSFTP_ROOT_UID 0
#endif /* VSF_DEFS_H */

View File

@ -1,20 +0,0 @@
#ifndef VSF_DIRCHANGE_H
#define VSF_DIRCHANGE_H
struct vsf_session;
/* dir_changed()
* PURPOSE
* This function, when called, will check if the current directory has just
* been entered for the first time in this session. If so, and message file
* support is on, a message file is looked for (default .message), and output
* to the FTP control connection with the FTP code prefix specified by
* "ftpcode".
* PARAMETERS
* p_sess - the current FTP session object
* ftpcode - the FTP code to show with the message
*/
void dir_changed(struct vsf_session* p_sess, int ftpcode);
#endif /* VSF_DIRCHANGE_H */

View File

@ -4,3 +4,4 @@
#undef VSF_SYSDEP_HAVE_PAM
#endif /* VSF_DUMMYINC_PAM_APPL_H */

View File

@ -0,0 +1,7 @@
#ifndef VSF_DUMMYINC_CAPABILITY_H
#define VSF_DUMMYINC_CAPABILITY_H
#undef VSF_SYSDEP_HAVE_LIBCAP
#endif /* VSF_DUMMYINC_CAPABILITY_H */

7
filesize.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef VSF_FILESIZE_H
#define VSF_FILESIZE_H
typedef long long filesize_t;
#endif /* VSF_FILESIZE_H */

View File

@ -20,7 +20,7 @@ str_fileread(struct mystr* p_str, const char* p_filename, unsigned int maxsize)
{
int fd;
int retval;
unsigned long size;
filesize_t size;
char* p_sec_buf = 0;
struct vsf_sysutil_statbuf* p_stat = 0;
/* In case we fail, make sure we return an empty string */

View File

@ -33,6 +33,7 @@ vsf_cmdio_sock_setup(void)
{
vsf_sysutil_activate_keepalive(VSFTP_COMMAND_FD);
vsf_sysutil_set_nodelay(VSFTP_COMMAND_FD);
vsf_sysutil_activate_oobinline(VSFTP_COMMAND_FD);
}
static void

View File

@ -31,6 +31,7 @@
#define FTP_IDLE_TIMEOUT 421
#define FTP_DATA_TIMEOUT 421
#define FTP_TOO_MANY_USERS 421
#define FTP_BADSENDCONN 425
#define FTP_BADSENDNET 426
#define FTP_BADSENDFILE 451
@ -41,6 +42,7 @@
#define FTP_NEEDRNFR 503
#define FTP_LOGINERR 530
#define FTP_FILEFAIL 550
#define FTP_NOPERM 550
#define FTP_UPLOADFAIL 553
#endif /* VSF_FTPCODES_H */

View File

@ -450,10 +450,10 @@ do_file_send_binary(struct vsf_session* p_sess, int net_fd, int file_fd)
{
static struct vsf_sysutil_statbuf* s_p_statbuf;
int retval;
unsigned long bytes_to_send;
unsigned long init_file_offset;
unsigned long curr_file_offset;
unsigned long bytes_sent;
filesize_t bytes_to_send;
filesize_t init_file_offset;
filesize_t curr_file_offset;
filesize_t bytes_sent;
unsigned int chunk_size;
struct vsf_transfer_ret ret_struct = { 0, 0 };
/* Work out how many bytes to send based on file size minus current offset */
@ -461,6 +461,10 @@ do_file_send_binary(struct vsf_session* p_sess, int net_fd, int file_fd)
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)

View File

@ -1,6 +1,8 @@
#ifndef VSF_FTPDATAIO_H
#define VSF_FTPDATAIO_H
#include "filesize.h"
struct mystr;
struct vsf_sysutil_sockaddr;
struct vsf_sysutil_dir;
@ -55,7 +57,7 @@ int vsf_ftpdataio_get_port_fd(struct vsf_session* p_sess);
struct vsf_transfer_ret
{
int retval;
unsigned long transferred;
filesize_t transferred;
};
struct vsf_transfer_ret vsf_ftpdataio_transfer_file(
struct vsf_session* p_sess,

View File

@ -135,7 +135,7 @@ vsf_log_do_log_wuftpd_format(struct vsf_session* p_sess, struct mystr* p_str,
str_append_str(p_str, &p_sess->remote_ip_str);
str_append_char(p_str, ' ');
/* Bytes transferred */
str_append_ulong(p_str, p_sess->transfer_size);
str_append_filesize_t(p_str, p_sess->transfer_size);
str_append_char(p_str, ' ');
/* Filename */
str_append_str(p_str, &p_sess->log_str);
@ -259,7 +259,7 @@ vsf_log_do_log_vsftpd_format(struct vsf_session* p_sess, struct mystr* p_str,
if (p_sess->transfer_size)
{
str_append_text(p_str, ", ");
str_append_ulong(p_str, p_sess->transfer_size);
str_append_filesize_t(p_str, p_sess->transfer_size);
str_append_text(p_str, " bytes");
}
if (vsf_log_type_is_transfer(what))

31
ls.c
View File

@ -206,9 +206,9 @@ filename_passes_filter(const struct mystr* p_filename_str,
/* Isolate text leading up to wildcard (if any) - needs to be matched */
if (locate_result.found)
{
unsigned int index = locate_result.index;
str_left(&s_filter_remain_str, &s_match_needed_str, index);
str_mid_to_end(&s_filter_remain_str, &s_temp_str, index + 1);
unsigned int indexx = locate_result.index;
str_left(&s_filter_remain_str, &s_match_needed_str, indexx);
str_mid_to_end(&s_filter_remain_str, &s_temp_str, indexx + 1);
str_copy(&s_filter_remain_str, &s_temp_str);
}
else
@ -223,22 +223,22 @@ filename_passes_filter(const struct mystr* p_filename_str,
/* Need to match something.. could be a match which has to start at
* current position, or we could allow it to start anywhere
*/
unsigned int index;
unsigned int indexx;
locate_result = str_locate_str(&s_name_remain_str, &s_match_needed_str);
if (!locate_result.found)
{
/* Fail */
return 0;
}
index = locate_result.index;
if (must_match_at_current_pos && index > 0)
indexx = locate_result.index;
if (must_match_at_current_pos && indexx > 0)
{
/* Fail */
return 0;
}
/* Chop matched string out of remainder */
str_mid_to_end(&s_name_remain_str, &s_temp_str,
index + str_getlen(&s_match_needed_str));
indexx + str_getlen(&s_match_needed_str));
str_copy(&s_name_remain_str, &s_temp_str);
}
/* Only the first iteration can require a match at current position -
@ -260,7 +260,7 @@ build_dir_line(struct mystr* p_str, const struct mystr* p_filename_str,
const struct vsf_sysutil_statbuf* p_stat)
{
static struct mystr s_tmp_str;
unsigned long size = vsf_sysutil_statbuf_get_size(p_stat);
filesize_t size = vsf_sysutil_statbuf_get_size(p_stat);
/* Permissions */
str_alloc_text(p_str, vsf_sysutil_statbuf_get_perms(p_stat));
str_append_char(p_str, ' ');
@ -270,6 +270,11 @@ build_dir_line(struct mystr* p_str, const struct mystr* p_filename_str,
str_append_str(p_str, &s_tmp_str);
str_append_char(p_str, ' ');
/* User */
if (tunable_hide_ids)
{
str_alloc_text(&s_tmp_str, "ftp");
}
else
{
int uid = vsf_sysutil_statbuf_get_uid(p_stat);
struct vsf_sysutil_user* p_user = 0;
@ -290,6 +295,11 @@ build_dir_line(struct mystr* p_str, const struct mystr* p_filename_str,
str_append_str(p_str, &s_tmp_str);
str_append_char(p_str, ' ');
/* Group */
if (tunable_hide_ids)
{
str_alloc_text(&s_tmp_str, "ftp");
}
else
{
int gid = vsf_sysutil_statbuf_get_gid(p_stat);
struct vsf_sysutil_group* p_group = 0;
@ -310,12 +320,13 @@ build_dir_line(struct mystr* p_str, const struct mystr* p_filename_str,
str_append_str(p_str, &s_tmp_str);
str_append_char(p_str, ' ');
/* Size in bytes */
str_alloc_ulong(&s_tmp_str, size);
str_alloc_filesize_t(&s_tmp_str, size);
str_lpad(&s_tmp_str, 8);
str_append_str(p_str, &s_tmp_str);
str_append_char(p_str, ' ');
/* Date stamp */
str_append_text(p_str, vsf_sysutil_statbuf_get_date(p_stat));
str_append_text(p_str, vsf_sysutil_statbuf_get_date(p_stat,
tunable_use_localtime));
str_append_char(p_str, ' ');
/* Filename */
str_append_str(p_str, p_filename_str);

40
main.c
View File

@ -18,6 +18,7 @@
#include "parseconf.h"
#include "oneprocess.h"
#include "twoprocess.h"
#include "standalone.h"
/*
* Forward decls of helper functions
@ -45,13 +46,15 @@ main(int argc, const char* argv[])
/* Userids */
-1, -1,
/* Pre-chroot() cache */
INIT_MYSTR, INIT_MYSTR,
INIT_MYSTR, INIT_MYSTR, INIT_MYSTR,
/* Logging */
-1, INIT_MYSTR, 0, 0, 0, INIT_MYSTR, 0,
/* Buffers */
INIT_MYSTR, INIT_MYSTR,
/* Parent <-> child comms */
0, -1, -1
0, -1, -1,
/* Number of clients */
-1
};
int config_specified = 0;
const char* p_config_name = VSFTP_DEFAULT_CONFIG;
@ -71,6 +74,8 @@ main(int argc, const char* argv[])
p_config_name = argv[1];
config_specified = 1;
}
/* Just get out unless we start with requisite privilege */
die_unless_privileged();
/* This might need to open /dev/zero on systems lacking MAP_ANON. Needs
* to be done early (i.e. before config file parse, which may use
* anonymous pages
@ -90,12 +95,20 @@ main(int argc, const char* argv[])
}
vsf_sysutil_free(p_statbuf);
}
if (tunable_setproctitle_enable)
{
/* Warning -- warning -- may nuke argv, environ */
vsf_sysutil_setproctitle_init(argc, argv);
}
if (tunable_listen)
{
/* Standalone mode */
the_session.num_clients = vsf_standalone_main();
}
/* Sanity checks - exit with a graceful error message if our STDIN is not
* a socket. Also check various config options don't collide.
*/
do_sanity_checks();
/* Just get out unless we start with requisite privilege */
die_unless_privileged();
/* Initializes session globals - e.g. IP addr's etc. */
session_init(&the_session);
/* Set up "environment", e.g. process group etc. */
@ -110,8 +123,6 @@ main(int argc, const char* argv[])
vsf_cmdio_sock_setup();
if (tunable_setproctitle_enable)
{
/* Warning -- warning -- may nuke argv, environ */
vsf_sysutil_setproctitle_init(argc, argv);
vsf_sysutil_set_proctitle_prefix(&the_session.remote_ip_str);
vsf_sysutil_setproctitle("connected");
}
@ -127,6 +138,15 @@ main(int argc, const char* argv[])
die("cannot open banned e-mail list file");
}
}
if (tunable_banner_file)
{
int retval = str_fileread(&the_session.banner_str, tunable_banner_file,
VSFTP_CONF_FILE_MAX);
if (vsf_sysutil_retval_is_error(retval))
{
die("cannot open banner file");
}
}
/* Special case - can force one process model if we've got a setup
* needing _no_ privs
*/
@ -173,11 +193,11 @@ do_sanity_checks(void)
{
if (tunable_local_enable)
{
die("vsftpd: security: 'tunable_one_process_model' is anonymous only");
die("vsftpd: security: 'one_process_model' is anonymous only");
}
if (!vsf_sysdep_has_capabilities_as_non_root())
{
die("vsftpd: security: 'tunable_one_process_model' needs a better OS");
die("vsftpd: security: 'one_process_model' needs a better OS");
}
}
if (!tunable_local_enable && !tunable_anonymous_enable)
@ -211,7 +231,7 @@ session_init(struct vsf_session* p_sess)
vsf_sysutil_getpwnam(tunable_ftp_username);
if (p_user == 0)
{
die("vsftpd: cannot locate user specified in 'tunable_ftp_username'");
die("vsftpd: cannot locate user specified in 'ftp_username'");
}
p_sess->anon_ftp_uid = vsf_sysutil_user_getuid(p_user);
@ -220,7 +240,7 @@ session_init(struct vsf_session* p_sess)
p_user = vsf_sysutil_getpwnam(tunable_chown_username);
if (p_user == 0)
{
die("vsf_sysutil_getpwnam");
die("vsftpd: cannot locate user specified in 'chown_username'");
}
p_sess->anon_upload_chown_uid = vsf_sysutil_user_getuid(p_user);
}

View File

@ -36,9 +36,16 @@ vsf_one_process_start(struct vsf_session* p_sess)
}
{
struct mystr user_name = INIT_MYSTR;
struct mystr chdir_str = INIT_MYSTR;
str_alloc_text(&user_name, tunable_ftp_username);
vsf_secutil_change_credentials(&user_name, 0, 1, 1, caps);
if (tunable_anon_root)
{
str_alloc_text(&chdir_str, tunable_anon_root);
}
vsf_secutil_change_credentials(&user_name, 0, &chdir_str, caps,
VSF_SECUTIL_OPTION_CHROOT | VSF_SECUTIL_OPTION_USE_GROUPS);
str_free(&user_name);
str_free(&chdir_str);
}
init_connection(p_sess);
}

View File

@ -16,10 +16,15 @@
#include "sysutil.h"
#include "utility.h"
static const char* s_p_saved_filename;
static int s_strings_copied;
/* File local functions */
static void handle_config_setting(struct mystr* p_setting_str,
struct mystr* p_value_str);
static void copy_string_settings(void);
/* Tables mapping setting names to runtime variables */
/* Boolean settings */
static struct parseconf_bool_setting
@ -58,6 +63,11 @@ parseconf_bool_array[] =
{ "guest_enable", &tunable_guest_enable },
{ "userlist_enable", &tunable_userlist_enable },
{ "userlist_deny", &tunable_userlist_deny },
{ "use_localtime", &tunable_use_localtime },
{ "check_shell", &tunable_check_shell },
{ "hide_ids", &tunable_hide_ids },
{ "listen", &tunable_listen },
{ "passwd_chroot_enable", &tunable_passwd_chroot_enable },
{ 0, 0 }
};
@ -79,6 +89,8 @@ parseconf_uint_array[] =
{ "pasv_max_port", &tunable_pasv_max_port },
{ "anon_max_rate", &tunable_anon_max_rate },
{ "local_max_rate", &tunable_local_max_rate },
{ "listen_port", &tunable_listen_port },
{ "max_clients", &tunable_max_clients },
{ 0, 0 }
};
@ -101,6 +113,12 @@ parseconf_str_array[] =
{ "pam_service_name", &tunable_pam_service_name },
{ "guest_username", &tunable_guest_username },
{ "userlist_file", &tunable_userlist_file },
{ "anon_root", &tunable_anon_root },
{ "local_root", &tunable_local_root },
{ "banner_file", &tunable_banner_file },
{ "pasv_address", &tunable_pasv_address },
{ "listen_address", &tunable_listen_address },
{ "user_config_dir", &tunable_user_config_dir },
{ 0, 0 }
};
@ -111,7 +129,33 @@ vsf_parseconf_load_file(const char* p_filename)
struct mystr config_setting_str = INIT_MYSTR;
struct mystr config_value_str = INIT_MYSTR;
unsigned int str_pos = 0;
int retval = str_fileread(&config_file_str, p_filename, VSFTP_CONF_FILE_MAX);
int retval;
if (!p_filename)
{
p_filename = s_p_saved_filename;
}
else
{
if (s_p_saved_filename)
{
vsf_sysutil_free((char*)s_p_saved_filename);
}
s_p_saved_filename = vsf_sysutil_strdup(p_filename);
}
if (!p_filename)
{
bug("null filename in vsf_parseconf_load_file");
}
if (!s_strings_copied)
{
s_strings_copied = 1;
/* A minor hack to make sure all strings are malloc()'ed so we can free
* them at some later date. Specifically handles strings embedded in the
* binary.
*/
copy_string_settings();
}
retval = str_fileread(&config_file_str, p_filename, VSFTP_CONF_FILE_MAX);
if (vsf_sysutil_retval_is_error(retval))
{
die("cannot open config file");
@ -200,7 +244,12 @@ handle_config_setting(struct mystr* p_setting_str, struct mystr* p_value_str)
if (str_equal_text(p_setting_str, p_str_setting->p_setting_name))
{
/* Got it */
*(p_str_setting->p_variable) = str_strdup(p_value_str);
const char** p_curr_setting = p_str_setting->p_variable;
if (*p_curr_setting)
{
vsf_sysutil_free((char*)*p_curr_setting);
}
*p_curr_setting = str_strdup(p_value_str);
return;
}
p_str_setting++;
@ -209,3 +258,18 @@ handle_config_setting(struct mystr* p_setting_str, struct mystr* p_value_str)
die("unrecognised variable in config file");
}
static void
copy_string_settings(void)
{
const struct parseconf_str_setting* p_str_setting = parseconf_str_array;
while (p_str_setting->p_setting_name != 0)
{
if (*p_str_setting->p_variable != 0)
{
*p_str_setting->p_variable =
vsf_sysutil_strdup(*p_str_setting->p_variable);
}
p_str_setting++;
}
}

View File

@ -10,6 +10,9 @@
* parsed and the global config settings will have been updated.
* PARAMETERS
* p_filename - the name of the config file to parse
* NOTES
* If p_filename is NULL, then the last filename passed to this function is
* used to reload the configuration details.
*/
void vsf_parseconf_load_file(const char* p_filename);

8
port/aix_bogons.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef VSF_AIX_BOGONS_H
#define VSF_AIX_BOGONS_H
/* Need dirfd() */
#include "dirfd_extras.h"
#endif /* VSF_AIX_BOGONS_H */

View File

@ -13,6 +13,10 @@
#include "hpux_bogons.h"
#endif
#ifdef _AIX
#include "aix_bogons.h"
#endif
/* So many older systems lack these, that it's too much hassle to list all
* the errant systems
*/

View File

@ -17,7 +17,7 @@
#include "defs.h"
#include "str.h"
#include "sysstr.h"
#include "dirchange.h"
#include "banner.h"
#include "sysutil.h"
#include "logging.h"
#include "sysdeputil.h"
@ -75,11 +75,10 @@ process_post_login(struct vsf_session* p_sess)
if (tunable_async_abor_enable)
{
vsf_sysutil_install_sighandler(kVSFSysUtilSigURG, handle_sigurg, p_sess);
vsf_sysutil_activate_oobinline(VSFTP_COMMAND_FD);
vsf_sysutil_activate_sigurg(VSFTP_COMMAND_FD);
}
/* Handle any login message */
dir_changed(p_sess, FTP_LOGINOK);
vsf_banner_dir_changed(p_sess, FTP_LOGINOK);
vsf_cmdio_write(p_sess, FTP_LOGINOK, "Login successful. Have fun.");
while(1)
{
@ -227,6 +226,21 @@ process_post_login(struct vsf_session* p_sess)
{
handle_mdtm(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") ||
str_equal_text(&p_sess->ftp_cmd_str, "MKD") ||
str_equal_text(&p_sess->ftp_cmd_str, "XMKD") ||
str_equal_text(&p_sess->ftp_cmd_str, "RMD") ||
str_equal_text(&p_sess->ftp_cmd_str, "XRMD") ||
str_equal_text(&p_sess->ftp_cmd_str, "DELE") ||
str_equal_text(&p_sess->ftp_cmd_str, "RNFR") ||
str_equal_text(&p_sess->ftp_cmd_str, "RNTO") ||
str_equal_text(&p_sess->ftp_cmd_str, "SITE") ||
str_equal_text(&p_sess->ftp_cmd_str, "APPE"))
{
vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
}
else
{
vsf_cmdio_write(p_sess, FTP_BADCMD, "Unknown command.");
@ -256,7 +270,7 @@ handle_cwd(struct vsf_session* p_sess)
if (retval == 0)
{
/* Handle any messages */
dir_changed(p_sess, FTP_CWDOK);
vsf_banner_dir_changed(p_sess, FTP_CWDOK);
vsf_cmdio_write(p_sess, FTP_CWDOK, "Directory successfully changed.");
}
else
@ -383,7 +397,19 @@ handle_pasv(struct vsf_session* p_sess)
vsf_sysutil_listen(p_sess->pasv_listen_fd, 1);
/* Get the address of the bound socket, for the port */
vsf_sysutil_getsockname(p_sess->pasv_listen_fd, &s_p_sockaddr);
listen_ipaddr = vsf_sysutil_sockaddr_get_ipaddr(s_p_sockaddr);
if (tunable_pasv_address != 0)
{
/* Report passive address as specified in configuration */
if (vsf_sysutil_inet_aton(tunable_pasv_address, &listen_ipaddr) == 0)
{
die("invalid pasv_address");
}
}
else
{
/* Use address of bound socket for passive address */
listen_ipaddr = vsf_sysutil_sockaddr_get_ipaddr(s_p_sockaddr);
}
listen_port = vsf_sysutil_sockaddr_get_port(s_p_sockaddr);
str_alloc_text(&s_pasv_res_str, "Entering Passive Mode (");
str_append_ulong(&s_pasv_res_str, listen_ipaddr.data[0]);
@ -404,12 +430,14 @@ handle_pasv(struct vsf_session* p_sess)
static void
handle_retr(struct vsf_session* p_sess)
{
static struct mystr s_mark_str;
static struct vsf_sysutil_statbuf* s_p_statbuf;
struct vsf_transfer_ret trans_ret;
int retval;
int remote_fd;
int opened_file;
unsigned long offset = p_sess->restart_pos;
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))
{
@ -446,7 +474,7 @@ handle_retr(struct vsf_session* p_sess)
/* Set the download offset (from REST) if any */
if (offset != 0)
{
(void) vsf_sysutil_lseek_to(opened_file, offset);
vsf_sysutil_lseek_to(opened_file, offset);
}
remote_fd = get_remote_transfer_fd(p_sess);
if (vsf_sysutil_retval_is_error(remote_fd))
@ -456,19 +484,25 @@ handle_retr(struct vsf_session* 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);
str_alloc_text(&s_mark_str, "Opening ");
if (tunable_ascii_download_enable && p_sess->is_ascii)
{
vsf_cmdio_write(p_sess, FTP_DATACONN,
"Here comes the data. WARNING - ASCII.");
trans_ret = vsf_ftpdataio_transfer_file(p_sess, remote_fd,
opened_file, 0, 1);
str_append_text(&s_mark_str, "ASCII");
is_ascii = 1;
}
else
{
vsf_cmdio_write(p_sess, FTP_DATACONN, "Here comes the data.");
trans_ret = vsf_ftpdataio_transfer_file(p_sess, remote_fd,
opened_file, 0, 0);
str_append_text(&s_mark_str, "BINARY");
}
str_append_text(&s_mark_str, " mode data connection for ");
str_append_str(&s_mark_str, &p_sess->ftp_arg_str);
str_append_text(&s_mark_str, " (");
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);
trans_ret = vsf_ftpdataio_transfer_file(p_sess, remote_fd,
opened_file, 0, is_ascii);
p_sess->transfer_size = trans_ret.transferred;
retval = dispose_remote_transfer_fd(p_sess);
/* Log _after_ the blocking dispose call, so we get transfer times right */
@ -668,13 +702,16 @@ handle_port(struct vsf_session* p_sess)
* 1) Reject requests not connecting to the control socket IP
* 2) Reject connects to privileged ports
*/
if (vsf_sysutil_memcmp(the_addr.data, remote_addr.data,
sizeof(the_addr.data)) != 0 ||
vsf_sysutil_is_port_reserved(the_port))
if (!tunable_port_promiscuous)
{
vsf_cmdio_write(p_sess, FTP_BADCMD, "Illegal PORT command.");
port_cleanup(p_sess);
return;
if (vsf_sysutil_memcmp(the_addr.data, remote_addr.data,
sizeof(the_addr.data)) != 0 ||
vsf_sysutil_is_port_reserved(the_port))
{
vsf_cmdio_write(p_sess, FTP_BADCMD, "Illegal PORT command.");
port_cleanup(p_sess);
return;
}
}
vsf_sysutil_sockaddr_alloc_ipv4(&p_sess->p_port_sockaddr);
vsf_sysutil_sockaddr_set_port(p_sess->p_port_sockaddr, the_port);
@ -696,6 +733,8 @@ handle_upload_common(struct vsf_session* p_sess, int is_append)
int new_file_fd;
int remote_fd;
int retval;
filesize_t offset = p_sess->restart_pos;
p_sess->restart_pos = 0;
if (!pasv_active(p_sess) && !port_active(p_sess))
{
vsf_cmdio_write(p_sess, FTP_BADSENDCONN, "Use PORT or PASV first.");
@ -712,7 +751,7 @@ handle_upload_common(struct vsf_session* p_sess, int is_append)
else
{
/* For non-anonymous, allow open() to overwrite or append existing files */
if (!is_append)
if (!is_append && offset == 0)
{
new_file_fd = str_create_overwrite(&p_sess->ftp_arg_str);
}
@ -738,6 +777,11 @@ handle_upload_common(struct vsf_session* p_sess, int is_append)
vsf_two_process_chown_upload(p_sess, new_file_fd);
}
}
if (!is_append && offset != 0)
{
/* 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))
{
@ -841,12 +885,12 @@ handle_dele(struct vsf_session* p_sess)
static void
handle_rest(struct vsf_session* p_sess)
{
long val = str_atol(&p_sess->ftp_arg_str);
filesize_t val = str_a_to_filesize_t(&p_sess->ftp_arg_str);
if (val < 0)
{
val = 0;
}
p_sess->restart_pos = (unsigned long) val;
p_sess->restart_pos = val;
vsf_cmdio_write(p_sess, FTP_RESTOK, "Restart position accepted.");
}
@ -1017,8 +1061,8 @@ handle_size(struct vsf_session* p_sess)
else
{
static struct mystr s_size_res_str;
str_alloc_ulong(&s_size_res_str,
vsf_sysutil_statbuf_get_size(s_p_statbuf));
str_alloc_filesize_t(&s_size_res_str,
vsf_sysutil_statbuf_get_size(s_p_statbuf));
vsf_cmdio_write_str(p_sess, FTP_SIZEOK, &s_size_res_str);
}
}
@ -1118,7 +1162,8 @@ handle_mdtm(struct vsf_session* p_sess)
{
static struct mystr s_mdtm_res_str;
str_alloc_text(&s_mdtm_res_str,
vsf_sysutil_statbuf_get_numeric_date(s_p_statbuf));
vsf_sysutil_statbuf_get_numeric_date(
s_p_statbuf, tunable_use_localtime));
vsf_cmdio_write_str(p_sess, FTP_MDTMOK, &s_mdtm_res_str);
}
}

View File

@ -87,7 +87,8 @@ minimize_privilege(struct vsf_session* p_sess)
{
caps |= kCapabilityCAP_NET_BIND_SERVICE;
}
vsf_secutil_change_credentials(&user_str, &dir_str, 1, 0, caps);
vsf_secutil_change_credentials(&user_str, &dir_str, 0, caps,
VSF_SECUTIL_OPTION_CHROOT);
str_free(&user_str);
str_free(&dir_str);
}

View File

@ -18,6 +18,7 @@
#include "sysdeputil.h"
#include "sysutil.h"
#include "session.h"
#include "banner.h"
/* Functions used */
static void emit_greeting(struct vsf_session* p_sess);
@ -43,7 +44,21 @@ init_connection(struct vsf_session* p_sess)
static void
emit_greeting(struct vsf_session* p_sess)
{
if (tunable_ftpd_banner == 0)
/* Check for client limit (standalone mode only) */
if (tunable_max_clients > 0 &&
p_sess->num_clients > (int)tunable_max_clients)
{
vsf_cmdio_write(p_sess, FTP_TOO_MANY_USERS,
"There are too many connected users, please try later.");
vsf_sysutil_exit(0);
}
if (!str_isempty(&p_sess->banner_str))
{
vsf_banner_write(p_sess, &p_sess->banner_str, FTP_GREET);
str_free(&p_sess->banner_str);
vsf_cmdio_write(p_sess, FTP_GREET, "");
}
else if (tunable_ftpd_banner == 0)
{
vsf_cmdio_write(p_sess, FTP_GREET, "ready, dude (vsFTPd " VSF_VERSION
": beat me, break me)");

View File

@ -15,9 +15,8 @@
void
vsf_secutil_change_credentials(const struct mystr* p_user_str,
const struct mystr* p_dir_str,
int do_chroot,
int activate_supplementary_groups,
unsigned int caps)
const struct mystr* p_ext_dir_str,
unsigned int caps, unsigned int options)
{
struct vsf_sysutil_user* p_user;
if (!vsf_sysutil_running_as_root())
@ -27,7 +26,10 @@ vsf_secutil_change_credentials(const struct mystr* p_user_str,
p_user = str_getpwnam(p_user_str);
if (p_user == 0)
{
die("str_getpwnam");
struct mystr death_str = INIT_MYSTR;
str_alloc_text(&death_str, "str_getpwnam: ");
str_append_str(&death_str, p_user_str);
die(str_getbuf(&death_str));
}
{
struct mystr dir_str = INIT_MYSTR;
@ -43,7 +45,7 @@ vsf_secutil_change_credentials(const struct mystr* p_user_str,
/* Sort out supplementary groups before the chroot(). We need to access
* /etc/groups
*/
if (activate_supplementary_groups)
if (options & VSF_SECUTIL_OPTION_USE_GROUPS)
{
vsf_sysutil_initgroups(p_user);
}
@ -51,16 +53,44 @@ vsf_secutil_change_credentials(const struct mystr* p_user_str,
{
vsf_sysutil_clear_supp_groups();
}
/* Always do the chdir() regardless of whether we are chroot()'ing */
{
int retval = str_chdir(&dir_str);
/* Do chdir() with the target effective IDs to cater for NFS mounted
* home directories.
*/
int saved_euid = 0;
int saved_egid = 0;
int retval;
if (options & VSF_SECUTIL_OPTION_CHANGE_EUID)
{
saved_euid = vsf_sysutil_geteuid();
saved_egid = vsf_sysutil_getegid();
vsf_sysutil_setegid(p_user);
vsf_sysutil_seteuid(p_user);
}
retval = str_chdir(&dir_str);
if (retval == 0 && p_ext_dir_str && !str_isempty(p_ext_dir_str))
{
retval = str_chdir(p_ext_dir_str);
/* Failure on the extra directory is OK as long as we're not in
* chroot() mode
*/
if (retval != 0 && !(options & VSF_SECUTIL_OPTION_CHROOT))
{
retval = 0;
}
}
if (retval != 0)
{
die("chdir");
}
if (options & VSF_SECUTIL_OPTION_CHANGE_EUID)
{
vsf_sysutil_seteuid_numeric(saved_euid);
vsf_sysutil_setegid_numeric(saved_egid);
}
/* Do the chroot() if required */
if (do_chroot)
if (options & VSF_SECUTIL_OPTION_CHROOT)
{
vsf_sysutil_chroot(".");
}

View File

@ -12,18 +12,26 @@ struct mystr;
* p_user_str - the name of the user to become
* p_dir_str - the directory to chdir() and possibly chroot() to.
* (if NULL, the user's home directory is used)
* do_chroot - if non-zero, chroot() the new user into the directory
* activate_supplementary_groups -
* if non-zero, activate any supplementary groups
* p_ext_dir_str - the directory to chdir() and possibly chroot() to,
* applied in addition to the directory calculated by
* p_user_str and p_dir_str.
* caps - bitmap of capabilities to adopt. NOTE, if the underlying
* OS does not support capabilities as a non-root user, and
* the capability bitset is non-empty, then root privileges
* will have to be retained.
* options - see bitmask definitions below
*/
/* chroot() the user into the new directory */
#define VSF_SECUTIL_OPTION_CHROOT 1
/* Activate any supplementary groups the user may have */
#define VSF_SECUTIL_OPTION_USE_GROUPS 2
/* Do the chdir() as the effective userid of the target user */
#define VSF_SECUTIL_OPTION_CHANGE_EUID 4
void vsf_secutil_change_credentials(const struct mystr* p_user_str,
const struct mystr* p_dir_str,
int do_chroot,
int activate_supplementary_groups,
unsigned int caps);
const struct mystr* p_ext_dir_str,
unsigned int caps, unsigned int options);
#endif /* VSF_SECUTIL_H */

View File

@ -5,6 +5,10 @@
#include "str.h"
#endif
#ifndef VSF_FILESIZE_H
#include "filesize.h"
#endif
struct vsf_sysutil_sockaddr;
struct mystr_list;
@ -32,7 +36,7 @@ struct vsf_session
struct mystr anon_pass_str;
/* Details of the FTP protocol state */
unsigned long restart_pos;
filesize_t restart_pos;
int is_ascii;
struct mystr rnfr_filename_str;
int abor_received;
@ -47,6 +51,7 @@ struct vsf_session
/* Things we need to cache before we chroot() */
struct mystr banned_email_str;
struct mystr userlist_str;
struct mystr banner_str;
/* Logging related details */
int log_fd;
@ -55,7 +60,7 @@ struct vsf_session
long log_start_sec;
long log_start_usec;
struct mystr log_str;
unsigned long transfer_size;
filesize_t transfer_size;
/* Buffers */
struct mystr ftp_cmd_str;
@ -65,6 +70,9 @@ struct vsf_session
int privsock_inited;
int parent_fd;
int child_fd;
/* Other details */
int num_clients;
};
#endif /* VSF_SESSION_H */

146
standalone.c Normal file
View File

@ -0,0 +1,146 @@
/*
* Part of Very Secure FTPd
* Licence: GPL
* Author: Chris Evans
* standalone.c
*
* Code to listen on the network and launch children servants.
*/
#include "standalone.h"
#include "parseconf.h"
#include "tunables.h"
#include "sysutil.h"
#include "sysdeputil.h"
#include "utility.h"
#include "defs.h"
static int s_reload_needed;
static int s_children;
static void handle_sigchld(int duff);
static void handle_sighup(int duff);
static void do_reload(void);
static void prepare_child(int sockfd);
int
vsf_standalone_main(void)
{
struct vsf_sysutil_sockaddr* p_sockaddr = 0;
struct vsf_sysutil_ipv4addr listen_ipaddr;
int listen_sock = vsf_sysutil_get_ipv4_sock();
int retval;
if (tunable_setproctitle_enable)
{
vsf_sysutil_setproctitle("LISTENER");
}
vsf_sysutil_install_async_sighandler(kVSFSysUtilSigCHLD, handle_sigchld);
vsf_sysutil_install_async_sighandler(kVSFSysUtilSigHUP, handle_sighup);
vsf_sysutil_activate_reuseaddr(listen_sock);
vsf_sysutil_sockaddr_alloc_ipv4(&p_sockaddr);
vsf_sysutil_sockaddr_set_port(
p_sockaddr, vsf_sysutil_ipv4port_from_int(tunable_listen_port));
if (!tunable_listen_address ||
vsf_sysutil_inet_aton(tunable_listen_address, &listen_ipaddr) == 0)
{
listen_ipaddr = vsf_sysutil_sockaddr_get_any();
}
vsf_sysutil_sockaddr_set_ipaddr(p_sockaddr, listen_ipaddr);
retval = vsf_sysutil_bind(listen_sock, p_sockaddr);
vsf_sysutil_free(p_sockaddr);
if (vsf_sysutil_retval_is_error(retval))
{
die("could not bind listening socket");
}
vsf_sysutil_listen(listen_sock, VSFTP_LISTEN_BACKLOG);
while (1)
{
int new_child;
int new_client_sock = vsf_sysutil_accept_timeout(listen_sock, 0, 0);
if (s_reload_needed)
{
s_reload_needed = 0;
do_reload();
}
if (vsf_sysutil_retval_is_error(new_client_sock))
{
if (vsf_sysutil_get_error() == kVSFSysUtilErrINTR)
{
continue;
}
die("accept");
}
++s_children;
new_child = vsf_sysutil_fork();
if (new_child)
{
/* Parent context */
vsf_sysutil_close(new_client_sock);
/* Fall through to while() loop and accept() again */
}
else
{
/* Child context */
vsf_sysutil_close(listen_sock);
prepare_child(new_client_sock);
/* By returning here we "launch" the child process with the same
* contract as xinetd would provide.
*/
return s_children;
}
}
}
static void
prepare_child(int new_client_sock)
{
/* We must satisfy the contract: command socket on fd 0, 1, 2 */
vsf_sysutil_dupfd2(new_client_sock, 0);
vsf_sysutil_dupfd2(new_client_sock, 1);
vsf_sysutil_dupfd2(new_client_sock, 2);
if (new_client_sock > 2)
{
vsf_sysutil_close(new_client_sock);
}
}
static void
handle_sigchld(int duff)
{
/* WARNING - async handler. Must not call anything which might have
* re-entrancy issues
*/
int reap_one = 1;
(void) duff;
while (reap_one)
{
reap_one = vsf_sysutil_wait_reap_one();
if (reap_one)
{
--s_children;
}
}
}
static void
handle_sighup(int duff)
{
/* WARNING - async handler. Must not call anything which might have
* re-entrancy issues
*/
(void) duff;
s_reload_needed = 1;
}
static void
do_reload(void)
{
vsf_parseconf_load_file(0);
}

16
standalone.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef VSF_STANDALONE_H
#define VSF_STANDALONE_H
/* vsf_standalone_main()
* PURPOSE
* This function starts listening on the network for incoming FTP connections.
* When it gets one, it returns to the caller in a new process, with file
* descriptor 0, 1 and 2 set to the network socket of the new client.
*
* RETURNS
* Returns the current number of clients.
*/
int vsf_standalone_main(void);
#endif /* VSF_STANDALONE_H */

53
str.c
View File

@ -108,6 +108,12 @@ str_alloc_ulong(struct mystr* p_str, unsigned long the_long)
str_alloc_text(p_str, vsf_sysutil_ulong_to_str(the_long));
}
void
str_alloc_filesize_t(struct mystr* p_str, filesize_t the_filesize)
{
str_alloc_text(p_str, vsf_sysutil_filesize_t_to_str(the_filesize));
}
void
str_free(struct mystr* p_str)
{
@ -237,6 +243,12 @@ str_append_ulong(struct mystr* p_str, unsigned long the_ulong)
str_append_text(p_str, vsf_sysutil_ulong_to_str(the_ulong));
}
void
str_append_filesize_t(struct mystr* p_str, filesize_t the_filesize)
{
str_append_text(p_str, vsf_sysutil_filesize_t_to_str(the_filesize));
}
void
str_append_double(struct mystr* p_str, double the_double)
{
@ -360,7 +372,7 @@ str_split_text_common(struct mystr* p_src, struct mystr* p_rhs,
const char* p_text, int is_reverse)
{
struct str_locate_result locate_result;
unsigned int index;
unsigned int indexx;
if (is_reverse)
{
locate_result = str_locate_text_reverse(p_src, p_text);
@ -375,16 +387,16 @@ str_split_text_common(struct mystr* p_src, struct mystr* p_rhs,
str_empty(p_rhs);
return;
}
index = locate_result.index;
if (index + vsf_sysutil_strlen(p_text) > p_src->len)
indexx = locate_result.index;
if (indexx + vsf_sysutil_strlen(p_text) > p_src->len)
{
bug("index invalid in str_split_text");
bug("indexx invalid in str_split_text");
}
/* Build rhs */
private_str_alloc_memchunk(p_rhs, p_src->p_buf + index + 1,
p_src->len - index - 1);
private_str_alloc_memchunk(p_rhs, p_src->p_buf + indexx + 1,
p_src->len - indexx - 1);
/* Build lhs */
str_trunc(p_src, index);
str_trunc(p_src, indexx);
}
struct str_locate_result
@ -480,33 +492,34 @@ str_left(const struct mystr* p_str, struct mystr* p_out, unsigned int chars)
void
str_right(const struct mystr* p_str, struct mystr* p_out, unsigned int chars)
{
unsigned int index = p_str->len - chars;
unsigned int indexx = p_str->len - chars;
if (chars > p_str->len)
{
bug("chars invalid in str_right");
}
private_str_alloc_memchunk(p_out, p_str->p_buf + index, chars);
private_str_alloc_memchunk(p_out, p_str->p_buf + indexx, chars);
}
void
str_mid_to_end(const struct mystr* p_str, struct mystr* p_out,
unsigned int index)
unsigned int indexx)
{
if (index > p_str->len)
if (indexx > p_str->len)
{
bug("invalid index in str_mid_to_end");
bug("invalid indexx in str_mid_to_end");
}
private_str_alloc_memchunk(p_out, p_str->p_buf + index, p_str->len - index);
private_str_alloc_memchunk(p_out, p_str->p_buf + indexx,
p_str->len - indexx);
}
char
str_get_char_at(const struct mystr* p_str, const unsigned int index)
str_get_char_at(const struct mystr* p_str, const unsigned int indexx)
{
if (index >= p_str->len)
if (indexx >= p_str->len)
{
bug("bad index in str_get_char_at");
bug("bad indexx in str_get_char_at");
}
return p_str->p_buf[index];
return p_str->p_buf[indexx];
}
int
@ -543,10 +556,10 @@ str_atoi(const struct mystr* p_str)
return vsf_sysutil_atoi(str_getbuf(p_str));
}
long
str_atol(const struct mystr* p_str)
filesize_t
str_a_to_filesize_t(const struct mystr* p_str)
{
return vsf_sysutil_atol(str_getbuf(p_str));
return vsf_sysutil_a_to_filesize_t(str_getbuf(p_str));
}
unsigned int

12
str.h
View File

@ -3,6 +3,10 @@
/* TODO - document these functions ;-) */
#ifndef VSF_FILESIZE_H
#include "filesize.h"
#endif
struct mystr
{
char* PRIVATE_HANDS_OFF_p_buf;
@ -24,6 +28,7 @@ void str_alloc_text(struct mystr* p_str, const char* p_src);
/* NOTE: String buffer data does NOT include terminating character */
void str_alloc_alt_term(struct mystr* p_str, const char* p_src, char term);
void str_alloc_ulong(struct mystr* p_str, unsigned long the_ulong);
void str_alloc_filesize_t(struct mystr* p_str, filesize_t the_filesize);
void str_copy(struct mystr* p_dest, const struct mystr* p_src);
const char* str_strdup(const struct mystr* p_str);
void str_empty(struct mystr* p_str);
@ -42,6 +47,7 @@ int str_equal_text(const struct mystr* p_str, const char* p_text);
void str_append_str(struct mystr* p_str, const struct mystr* p_other);
void str_append_text(struct mystr* p_str, const char* p_src);
void str_append_ulong(struct mystr* p_str, unsigned long the_long);
void str_append_filesize_t(struct mystr* p_str, filesize_t the_filesize);
void str_append_char(struct mystr* p_str, char the_char);
void str_append_double(struct mystr* p_str, double the_double);
@ -81,14 +87,14 @@ void str_left(const struct mystr* p_str, struct mystr* p_out,
void str_right(const struct mystr* p_str, struct mystr* p_out,
unsigned int chars);
void str_mid_to_end(const struct mystr* p_str, struct mystr* p_out,
unsigned int index);
unsigned int indexx);
char str_get_char_at(const struct mystr* p_str, const unsigned int index);
char str_get_char_at(const struct mystr* p_str, const unsigned int indexx);
int str_contains_space(const struct mystr* p_str);
int str_contains_unprintable(const struct mystr* p_str);
void str_replace_unprintable(struct mystr* p_str, char new_char);
int str_atoi(const struct mystr* p_str);
long str_atol(const struct mystr* p_str);
filesize_t str_a_to_filesize_t(const struct mystr* p_str);
unsigned int str_octal_to_uint(const struct mystr* p_str);
/* PURPOSE: Extract a line of text (delimited by \n or EOF) from a string

View File

@ -163,12 +163,12 @@ sort_compare_common(const void* p1, const void* p2, int reverse)
}
const struct mystr*
str_list_get_pstr(const struct mystr_list* p_list, unsigned int index)
str_list_get_pstr(const struct mystr_list* p_list, unsigned int indexx)
{
if (index >= p_list->list_len)
if (indexx >= p_list->list_len)
{
bug("index out of range in str_list_get_str");
bug("indexx out of range in str_list_get_str");
}
return &p_list->p_nodes[index].str;
return &p_list->p_nodes[indexx].str;
}

View File

@ -26,7 +26,7 @@ int str_list_contains_str(const struct mystr_list* p_list,
const struct mystr* p_str);
const struct mystr* str_list_get_pstr(const struct mystr_list* p_list,
unsigned int index);
unsigned int indexx);
#endif /* VSF_STRLIST_H */

View File

@ -42,9 +42,10 @@
#define VSF_SYSDEP_HAVE_PAM
#define VSF_SYSDEP_HAVE_SHADOW
#define VSF_SYSDEP_HAVE_USERSHELL
#define VSF_SYSDEP_HAVE_LIBCAP
/* BEGIN config */
#ifdef __linux__
#if defined(__linux__) && !defined(__ia64__) && !defined(__s390__)
#define VSF_SYSDEP_TRY_LINUX_SETPROCTITLE_HACK
#include <linux/version.h>
#if defined(LINUX_VERSION_CODE) && defined(KERNEL_VERSION)
@ -84,6 +85,7 @@
#ifdef __sgi
#undef VSF_SYSDEP_HAVE_USERSHELL
#undef VSF_SYSDEP_HAVE_LIBCAP
#endif
#if (defined(__sgi) || defined(__hpux))
@ -102,7 +104,10 @@
#include <unistd.h>
#endif
#ifdef VSF_SYSDEP_HAVE_CAPABILITIES
/* Prefer libcap based capabilities over raw syscall capabilities */
#include <sys/capability.h>
#if defined(VSF_SYSDEP_HAVE_CAPABILITIES) && !defined(VSF_SYSDEP_HAVE_LIBCAP)
#include <linux/capability.h>
#include <errno.h>
#include <syscall.h>
@ -144,7 +149,7 @@ static int s_zero_fd = -1;
/* File private functions/variables */
static int do_sendfile(const int out_fd, const int in_fd,
long* p_offset, unsigned int num_send);
unsigned int num_send, filesize_t start_pos);
static void vsf_sysutil_setproctitle_internal(const char* p_text);
static struct mystr s_proctitle_prefix_str;
@ -156,24 +161,27 @@ vsf_sysdep_check_auth(const struct mystr* p_user_str,
{
const char* p_shell;
const char* p_crypted;
(void) p_remote_host;
const struct passwd* p_pwd = getpwnam(str_getbuf(p_user_str));
(void) p_remote_host;
if (p_pwd == NULL)
{
return 0;
}
#ifdef VSF_SYSDEP_HAVE_USERSHELL
while ((p_shell = getusershell()) != NULL)
if (tunable_check_shell)
{
if (!vsf_sysutil_strcmp(p_shell, p_pwd->pw_shell))
while ((p_shell = getusershell()) != NULL)
{
break;
if (!vsf_sysutil_strcmp(p_shell, p_pwd->pw_shell))
{
break;
}
}
endusershell();
if (p_shell == NULL)
{
return 0;
}
}
endusershell();
if (p_shell == NULL)
{
return 0;
}
#endif
#ifdef VSF_SYSDEP_HAVE_SHADOW
@ -283,19 +291,11 @@ pam_conv_func(int nmsg, const struct pam_message** p_msg,
{
bug("dodgy nmsg in pam_conv_func");
}
/* XXX sometimes leaks */
p_resps = vsf_sysutil_malloc(sizeof(struct pam_response) * nmsg);
if (p_resps == 0)
{
return PAM_CONV_ERR;
}
for (i=0; i<nmsg; i++)
{
switch (p_msg[i]->msg_style)
{
case PAM_PROMPT_ECHO_ON:
return PAM_CONV_ERR;
break;
case PAM_PROMPT_ECHO_OFF:
p_resps[i].resp_retcode = PAM_SUCCESS;
p_resps[i].resp = (char*) str_strdup(&s_pword_str);
@ -305,7 +305,9 @@ pam_conv_func(int nmsg, const struct pam_message** p_msg,
p_resps[i].resp_retcode = PAM_SUCCESS;
p_resps[i].resp = 0;
break;
case PAM_PROMPT_ECHO_ON:
default:
vsf_sysutil_free(p_resps);
return PAM_CONV_ERR;
break;
}
@ -334,7 +336,7 @@ vsf_sysdep_keep_capabilities(void)
}
#endif /* VSF_SYSDEP_HAVE_SETKEEPCAPS */
}
#ifndef VSF_SYSDEP_HAVE_CAPABILITIES
#if !defined(VSF_SYSDEP_HAVE_CAPABILITIES) && !defined(VSF_SYSDEP_HAVE_LIBCAP)
int
vsf_sysdep_has_capabilities(void)
@ -355,29 +357,9 @@ vsf_sysdep_adopt_capabilities(unsigned int caps)
bug("asked to adopt capabilities, but no support exists");
}
#else /* VSF_SYSDEP_HAVE_CAPABILITIES */
#else /* VSF_SYSDEP_HAVE_CAPABILITIES || VSF_SYSDEP_HAVE_LIBCAP */
int
vsf_sysdep_has_capabilities(void)
{
/* Even though compiled with capabilities, the runtime system may lack them.
* Also, RH7.0 kernel headers advertise a 2.4.0 box, but on a 2.2.x kernel!
*/
static int s_caps_checked;
static int s_runtime_has_caps;
if (!s_caps_checked)
{
/* EFAULT (EINVAL if page 0 mapped) vs. ENOSYS */
int retval = capset(0, 0);
if (!vsf_sysutil_retval_is_error(retval) ||
vsf_sysutil_get_error() != kVSFSysUtilErrNOSYS)
{
s_runtime_has_caps = 1;
}
s_caps_checked = 1;
}
return s_runtime_has_caps;
}
static int do_checkcap(void);
int
vsf_sysdep_has_capabilities_as_non_root(void)
@ -398,6 +380,36 @@ vsf_sysdep_has_capabilities_as_non_root(void)
return s_runtime_prctl_works;
}
int
vsf_sysdep_has_capabilities(void)
{
/* Even though compiled with capabilities, the runtime system may lack them.
* Also, RH7.0 kernel headers advertise a 2.4.0 box, but on a 2.2.x kernel!
*/
static int s_caps_checked;
static int s_runtime_has_caps;
if (!s_caps_checked)
{
s_runtime_has_caps = do_checkcap();
s_caps_checked = 1;
}
return s_runtime_has_caps;
}
#ifndef VSF_SYSDEP_HAVE_LIBCAP
static int
do_checkcap(void)
{
/* EFAULT (EINVAL if page 0 mapped) vs. ENOSYS */
int retval = capset(0, 0);
if (!vsf_sysutil_retval_is_error(retval) ||
vsf_sysutil_get_error() != kVSFSysUtilErrNOSYS)
{
return 1;
}
return 0;
}
void
vsf_sysdep_adopt_capabilities(unsigned int caps)
{
@ -431,58 +443,99 @@ vsf_sysdep_adopt_capabilities(unsigned int caps)
}
}
#endif /* VSF_SYSDEP_HAVE_CAPABILITIES */
#else /* VSF_SYSDEP_HAVE_LIBCAP */
static int
do_checkcap(void)
{
cap_t current_caps = cap_get_proc();
cap_free(current_caps);
if (current_caps != NULL)
{
return 1;
}
return 0;
}
void
vsf_sysdep_adopt_capabilities(unsigned int caps)
{
int retval;
cap_value_t cap_value;
cap_t adopt_caps = cap_init();
if (caps & kCapabilityCAP_CHOWN)
{
cap_value = CAP_CHOWN;
cap_set_flag(adopt_caps, CAP_EFFECTIVE, 1, &cap_value, CAP_SET);
cap_set_flag(adopt_caps, CAP_PERMITTED, 1, &cap_value, CAP_SET);
}
if (caps & kCapabilityCAP_NET_BIND_SERVICE)
{
cap_value = CAP_NET_BIND_SERVICE;
cap_set_flag(adopt_caps, CAP_EFFECTIVE, 1, &cap_value, CAP_SET);
cap_set_flag(adopt_caps, CAP_PERMITTED, 1, &cap_value, CAP_SET);
}
retval = cap_set_proc(adopt_caps);
if (retval != 0)
{
die("cap_set_proc");
}
cap_free(adopt_caps);
}
#endif /* !VSF_SYSDEP_HAVE_LIBCAP */
#endif /* VSF_SYSDEP_HAVE_CAPABILITIES || VSF_SYSDEP_HAVE_LIBCAP */
int
vsf_sysutil_sendfile(const int out_fd, const int in_fd,
unsigned long* p_offset, unsigned long num_send,
filesize_t* p_offset, filesize_t num_send,
unsigned int max_chunk)
{
/* Grr - why is off_t signed? */
long real_offset = *p_offset;
if (real_offset < 0)
if (*p_offset < 0 || num_send < 0)
{
die("invalid offset in vsf_sysutil_sendfile");
die("invalid offset or send count in vsf_sysutil_sendfile");
}
if (max_chunk == 0)
{
max_chunk = INT_MAX;
}
while (num_send > 0)
{
int retval;
unsigned int send_this_time;
/* For 64-bit platforms */
if (num_send > INT_MAX)
if (num_send > max_chunk)
{
send_this_time = INT_MAX;
send_this_time = max_chunk;
}
else
{
send_this_time = (unsigned int) num_send;
}
if (max_chunk != 0 && send_this_time > max_chunk)
{
send_this_time = max_chunk;
}
retval = do_sendfile(out_fd, in_fd, &real_offset, send_this_time);
if (real_offset < 0)
/* Keep input file position in line with sendfile() calls */
vsf_sysutil_lseek_to(in_fd, *p_offset);
retval = do_sendfile(out_fd, in_fd, send_this_time, *p_offset);
if (*p_offset < 0)
{
die("invalid offset returned in vsf_sysutil_sendfile");
}
*p_offset = real_offset;
if (vsf_sysutil_retval_is_error(retval) || retval == 0)
{
return retval;
}
num_send -= (unsigned long) retval;
num_send -= retval;
*p_offset += retval;
}
return 0;
}
static int do_sendfile(const int out_fd, const int in_fd,
long* p_offset, unsigned int num_send)
unsigned int num_send, filesize_t start_pos)
{
/* Probably should one day be shared with instance in ftpdataio.c */
static char* p_recvbuf;
unsigned int total_written = 0;
int retval;
(void) start_pos;
#if defined(VSF_SYSDEP_HAVE_LINUX_SENDFILE) || \
defined(VSF_SYSDEP_HAVE_FREEBSD_SENDFILE) || \
defined(VSF_SYSDEP_HAVE_HPUX_SENDFILE)
@ -494,27 +547,24 @@ static int do_sendfile(const int out_fd, const int in_fd,
do
{
#ifdef VSF_SYSDEP_HAVE_LINUX_SENDFILE
retval = sendfile(out_fd, in_fd, p_offset, num_send);
retval = sendfile(out_fd, in_fd, NULL, num_send);
#elif defined(VSF_SYSDEP_HAVE_FREEBSD_SENDFILE)
{
/* XXX - start_pos will truncate on 32-bit machines - can we
* say "start from current pos"?
*/
off_t written = 0;
retval = sendfile(in_fd, out_fd, *p_offset, num_send, NULL,
retval = sendfile(in_fd, out_fd, start_pos, num_send, NULL,
&written, 0);
/* Translate to Linux-like retval */
if (written > 0)
{
retval = (int) written;
*p_offset += retval;
}
}
#else /* must be VSF_SYSDEP_HAVE_HPUX_SENDFILE */
{
retval = sendfile(out_fd, in_fd, *p_offset, num_send, NULL, 0);
/* Translate to Linux-like retval */
if (retval > 0)
{
*p_offset += retval;
}
retval = sendfile(out_fd, in_fd, start_pos, num_send, NULL, 0);
}
#endif /* VSF_SYSDEP_HAVE_LINUX_SENDFILE */
vsf_sysutil_check_pending_actions(kVSFSysUtilIO, retval, out_fd);
@ -530,11 +580,16 @@ static int do_sendfile(const int out_fd, const int in_fd,
s_runtime_sendfile_works = 1;
}
}
if (s_runtime_sendfile_works)
if (s_runtime_sendfile_works &&
vsf_sysutil_get_error() != kVSFSysUtilErrINVAL)
{
return retval;
}
/* Fall thru to normal implementation. We won't check again. */
/* Fall thru to normal implementation. We won't check again. NOTE -
* also falls through if sendfile() is OK but it returns EINVAL. For
* Linux this means the file was not page cache backed. Original
* complaint was trying to serve files from an NTFS filesystem!
*/
}
}
#endif /* VSF_SYSDEP_HAVE_LINUX_SENDFILE || VSF_SYSDEP_HAVE_FREEBSD_SENDFILE */
@ -561,7 +616,6 @@ static int do_sendfile(const int out_fd, const int in_fd,
return -1;
}
num_read = (unsigned int) retval;
*p_offset += num_read;
retval = vsf_sysutil_write_loop(out_fd, p_recvbuf, num_read);
if (retval < 0)
{

View File

@ -1,6 +1,10 @@
#ifndef VSF_SYSDEPUTIL_H
#define VSF_SYSDEPUTIL_H
#ifndef VSF_FILESIZE_H
#include "filesize.h"
#endif
/* VSF_SYSDEPUTIL_H:
* Support for highly system dependent features, and querying for support
* or lack thereof
@ -31,7 +35,7 @@ void vsf_sysdep_adopt_capabilities(unsigned int caps);
* loop under the covers if the target system lacks support.
*/
int vsf_sysutil_sendfile(const int out_fd, const int in_fd,
unsigned long* p_offset, unsigned long num_send,
filesize_t* p_offset, filesize_t num_send,
unsigned int max_chunk);
/* Support for changing the process name as reported by the operating system.

227
sysutil.c
View File

@ -15,6 +15,9 @@
#include "sysutil.h"
#include "utility.h"
/* Activate 64-bit file support on Linux/32bit */
#define _FILE_OFFSET_BITS 64
/* For Linux, this adds nothing :-) */
#include "port/porting_junk.h"
@ -148,6 +151,9 @@ vsf_sysutil_translate_sig(const enum EVSFSysUtilSignal sig)
case kVSFSysUtilSigURG:
realsig = SIGURG;
break;
case kVSFSysUtilSigHUP:
realsig = SIGHUP;
break;
default:
bug("unknown signal in vsf_sysutil_translate_sig");
break;
@ -351,32 +357,30 @@ vsf_sysutil_write_loop(const int fd, const void* p_buf, unsigned int size)
}
}
unsigned long
filesize_t
vsf_sysutil_get_file_offset(const int file_fd)
{
off_t retval = lseek(file_fd, 0, SEEK_CUR);
filesize_t retval = lseek(file_fd, 0, SEEK_CUR);
if (retval < 0)
{
die("lseek");
}
return (unsigned long) retval;
return retval;
}
unsigned long
vsf_sysutil_lseek_to(const int fd, unsigned long seek_pos)
void
vsf_sysutil_lseek_to(const int fd, filesize_t seek_pos)
{
off_t retval;
off_t real_seek_pos = (off_t) seek_pos;
if (real_seek_pos < 0)
filesize_t retval;
if (seek_pos < 0)
{
die("negative seek_pos in vsf_sysutil_lseek_to");
}
retval = lseek(fd, real_seek_pos, SEEK_SET);
retval = lseek(fd, seek_pos, SEEK_SET);
if (retval < 0)
{
die("lseek");
}
return (unsigned long) retval;
}
void*
@ -471,6 +475,19 @@ vsf_sysutil_wait(void)
}
}
int
vsf_sysutil_wait_reap_one(void)
{
int retval = waitpid(-1, NULL, WNOHANG);
if (retval == 0 || (retval < 0 && errno == ECHILD))
{
/* No more children */
return 0;
}
/* Got one */
return 1;
}
int
vsf_sysutil_wait_get_retval(const struct vsf_sysutil_wait_retval* p_waitret)
{
@ -645,24 +662,42 @@ vsf_sysutil_atoi(const char* p_str)
return atoi(p_str);
}
long
vsf_sysutil_atol(const char* p_str)
filesize_t
vsf_sysutil_a_to_filesize_t(const char* p_str)
{
return atol(p_str);
/* atoll() is C99 standard - may break build on older platforms */
return atoll(p_str);
}
const char*
vsf_sysutil_ulong_to_str(unsigned long the_ulong)
{
static char int_buf[128];
(void) snprintf(int_buf, sizeof(int_buf), "%lu", the_ulong);
return int_buf;
static char ulong_buf[32];
(void) snprintf(ulong_buf, sizeof(ulong_buf), "%lu", the_ulong);
return ulong_buf;
}
const char*
vsf_sysutil_filesize_t_to_str(filesize_t the_filesize)
{
static char filesize_buf[32];
if (sizeof(long) == 8)
{
/* Avoid using non-standard %ll if we can */
(void) snprintf(filesize_buf, sizeof(filesize_buf), "%ld",
(long) the_filesize);
}
else
{
(void) snprintf(filesize_buf, sizeof(filesize_buf), "%lld", the_filesize);
}
return filesize_buf;
}
const char*
vsf_sysutil_double_to_str(double the_double)
{
static char double_buf[128];
static char double_buf[32];
(void) snprintf(double_buf, sizeof(double_buf), "%.2f", the_double);
return double_buf;
}
@ -670,7 +705,7 @@ vsf_sysutil_double_to_str(double the_double)
const char*
vsf_sysutil_uint_to_octal(unsigned int the_uint)
{
static char octal_buf[128];
static char octal_buf[32];
if (the_uint == 0)
{
octal_buf[0] = '0';
@ -943,7 +978,7 @@ int
vsf_sysutil_open_file(const char* p_filename,
const enum EVSFSysUtilOpenMode mode)
{
return open(p_filename, vsf_sysutil_translate_openmode(mode));
return open(p_filename, vsf_sysutil_translate_openmode(mode) | O_NONBLOCK);
}
int
@ -956,13 +991,29 @@ vsf_sysutil_create_file(const char* p_filename)
int
vsf_sysutil_create_overwrite_file(const char* p_filename)
{
return open(p_filename, O_CREAT | O_TRUNC | O_WRONLY | O_APPEND, 0666);
return open(p_filename, O_CREAT | O_TRUNC | O_WRONLY |
O_APPEND | O_NONBLOCK, 0666);
}
int
vsf_sysutil_create_or_open_file(const char* p_filename, unsigned int mode)
{
return open(p_filename, O_CREAT | O_WRONLY | O_APPEND, mode);
return open(p_filename, O_CREAT | O_WRONLY | O_APPEND | O_NONBLOCK, mode);
}
void
vsf_sysutil_dupfd2(int old_fd, int new_fd)
{
int retval;
if (old_fd == new_fd)
{
return;
}
retval = dup2(old_fd, new_fd);
if (retval != new_fd)
{
die("dup2");
}
}
void
@ -1112,15 +1163,23 @@ vsf_sysutil_statbuf_get_perms(const struct vsf_sysutil_statbuf* p_statbuf)
}
const char*
vsf_sysutil_statbuf_get_date(const struct vsf_sysutil_statbuf* p_statbuf)
vsf_sysutil_statbuf_get_date(const struct vsf_sysutil_statbuf* p_statbuf,
int use_localtime)
{
static char datebuf[128];
static char datebuf[64];
int retval;
struct tm* p_tm;
const struct stat* p_stat = (const struct stat*) p_statbuf;
long local_time = vsf_sysutil_get_cached_time_sec();
const char* p_date_format = "%b %d %H:%M";
p_tm = gmtime(&p_stat->st_mtime);
if (!use_localtime)
{
p_tm = gmtime(&p_stat->st_mtime);
}
else
{
p_tm = localtime(&p_stat->st_mtime);
}
/* Is this a future or 6 months old date? If so, we drop to year format */
if (p_stat->st_mtime > local_time ||
(local_time - p_stat->st_mtime) > 60*60*24*182)
@ -1138,12 +1197,22 @@ vsf_sysutil_statbuf_get_date(const struct vsf_sysutil_statbuf* p_statbuf)
const char*
vsf_sysutil_statbuf_get_numeric_date(
const struct vsf_sysutil_statbuf* p_statbuf)
const struct vsf_sysutil_statbuf* p_statbuf,
int use_localtime)
{
static char datebuf[15];
const struct stat* p_stat = (const struct stat*) p_statbuf;
struct tm* p_tm = gmtime(&p_stat->st_mtime);
int retval = strftime(datebuf, sizeof(datebuf), "%Y%m%d%H%M%S", p_tm);
struct tm* p_tm;
int retval;
if (!use_localtime)
{
p_tm = gmtime(&p_stat->st_mtime);
}
else
{
p_tm = localtime(&p_stat->st_mtime);
}
retval = strftime(datebuf, sizeof(datebuf), "%Y%m%d%H%M%S", p_tm);
if (retval == 0)
{
die("strftime");
@ -1151,7 +1220,7 @@ vsf_sysutil_statbuf_get_numeric_date(
return datebuf;
}
unsigned long
filesize_t
vsf_sysutil_statbuf_get_size(const struct vsf_sysutil_statbuf* p_statbuf)
{
const struct stat* p_stat = (const struct stat*) p_statbuf;
@ -1159,7 +1228,7 @@ vsf_sysutil_statbuf_get_size(const struct vsf_sysutil_statbuf* p_statbuf)
{
die("invalid inode size in vsf_sysutil_statbuf_get_size");
}
return (unsigned long) p_stat->st_size;
return p_stat->st_size;
}
int
@ -1300,6 +1369,9 @@ vsf_sysutil_get_error(void)
case EINTR:
retval = kVSFSysUtilErrINTR;
break;
case EINVAL:
retval = kVSFSysUtilErrINVAL;
break;
}
return retval;
}
@ -1315,7 +1387,7 @@ vsf_sysutil_get_ipv4_sock(void)
return retval;
}
const struct vsf_sysutil_socketpair_retval
struct vsf_sysutil_socketpair_retval
vsf_sysutil_unix_dgram_socketpair(void)
{
struct vsf_sysutil_socketpair_retval retval;
@ -1356,7 +1428,10 @@ vsf_sysutil_accept_timeout(int fd, struct vsf_sysutil_sockaddr** p_sockptr,
fd_set accept_fdset;
struct timeval timeout;
unsigned int socklen = sizeof(remote_addr);
vsf_sysutil_sockaddr_clear(p_sockptr);
if (p_sockptr)
{
vsf_sysutil_sockaddr_clear(p_sockptr);
}
if (wait_seconds > 0)
{
FD_ZERO(&accept_fdset);
@ -1388,8 +1463,11 @@ vsf_sysutil_accept_timeout(int fd, struct vsf_sysutil_sockaddr** p_sockptr,
{
die("can only support ipv4 currently");
}
*p_sockptr = vsf_sysutil_malloc(sizeof(remote_addr));
vsf_sysutil_memcpy(*p_sockptr, &remote_addr, sizeof(remote_addr));
if (p_sockptr)
{
*p_sockptr = vsf_sysutil_malloc(sizeof(remote_addr));
vsf_sysutil_memcpy(*p_sockptr, &remote_addr, sizeof(remote_addr));
}
return retval;
}
@ -1531,6 +1609,14 @@ vsf_sysutil_sockaddr_get_ipaddr(const struct vsf_sysutil_sockaddr* p_sockptr)
return retval;
}
struct vsf_sysutil_ipv4addr
vsf_sysutil_sockaddr_get_any(void)
{
struct vsf_sysutil_ipv4addr retval;
vsf_sysutil_memclr(&retval, sizeof(retval));
return retval;
}
struct vsf_sysutil_ipv4port
vsf_sysutil_sockaddr_get_port(const struct vsf_sysutil_sockaddr* p_sockptr)
{
@ -1577,6 +1663,21 @@ vsf_sysutil_inet_ntoa(const struct vsf_sysutil_sockaddr* p_sockptr)
return inet_ntoa(p_sockaddr->sin_addr);
}
int
vsf_sysutil_inet_aton(const char* p_text, struct vsf_sysutil_ipv4addr* p_addr)
{
struct in_addr sin_addr;
if (inet_aton(p_text, &sin_addr))
{
vsf_sysutil_memcpy(p_addr, &sin_addr.s_addr, sizeof(*p_addr));
return 1;
}
else
{
return 0;
}
}
struct vsf_sysutil_user*
vsf_sysutil_getpwuid(const int uid)
{
@ -1703,6 +1804,64 @@ vsf_sysutil_setgid_numeric(int gid)
}
}
int
vsf_sysutil_geteuid(void)
{
int retval = geteuid();
if (retval < 0)
{
die("geteuid");
}
return retval;
}
int
vsf_sysutil_getegid(void)
{
int retval = getegid();
if (retval < 0)
{
die("getegid");
}
return retval;
}
void
vsf_sysutil_seteuid(const struct vsf_sysutil_user* p_user)
{
const struct passwd* p_passwd = (const struct passwd*) p_user;
vsf_sysutil_seteuid_numeric(p_passwd->pw_uid);
}
void
vsf_sysutil_setegid(const struct vsf_sysutil_user* p_user)
{
const struct passwd* p_passwd = (const struct passwd*) p_user;
vsf_sysutil_setegid_numeric(p_passwd->pw_gid);
}
void
vsf_sysutil_seteuid_numeric(int uid)
{
/* setreuid() would seem to be more portable than seteuid() */
int retval = setreuid(-1, uid);
if (retval != 0)
{
die("seteuid");
}
}
void
vsf_sysutil_setegid_numeric(int gid)
{
/* setregid() would seem to be more portable than setegid() */
int retval = setregid(-1, gid);
if (retval != 0)
{
die("setegid");
}
}
void
vsf_sysutil_clear_supp_groups(void)
{
@ -1768,7 +1927,7 @@ vsf_sysutil_tzset(void)
const char*
vsf_sysutil_get_current_date(void)
{
static char datebuf[128];
static char datebuf[64];
time_t curr_time;
const struct tm* p_tm;
vsf_sysutil_update_cached_time();

View File

@ -3,6 +3,10 @@
/* TODO: these functions need proper documenting! */
#ifndef VSF_FILESIZE_H
#include "filesize.h"
#endif
/* Return value queries */
int vsf_sysutil_retval_is_error(int retval);
enum EVSFSysUtilError
@ -10,7 +14,8 @@ enum EVSFSysUtilError
kVSFSysUtilErrUnknown = 1,
kVSFSysUtilErrADDRINUSE,
kVSFSysUtilErrNOSYS,
kVSFSysUtilErrINTR
kVSFSysUtilErrINTR,
kVSFSysUtilErrINVAL
};
enum EVSFSysUtilError vsf_sysutil_get_error(void);
@ -21,7 +26,8 @@ enum EVSFSysUtilSignal
kVSFSysUtilSigTERM,
kVSFSysUtilSigCHLD,
kVSFSysUtilSigPIPE,
kVSFSysUtilSigURG
kVSFSysUtilSigURG,
kVSFSysUtilSigHUP
};
enum EVSFSysUtilInterruptContext
{
@ -76,14 +82,15 @@ int vsf_sysutil_create_overwrite_file(const char* p_filename);
int vsf_sysutil_create_append_file(const char* p_filename);
/* Creates or appends */
int vsf_sysutil_create_or_open_file(const char* p_filename, unsigned int mode);
void vsf_sysutil_dupfd2(int old_fd, int new_fd);
void vsf_sysutil_close(int fd);
int vsf_sysutil_close_failok(int fd);
int vsf_sysutil_unlink(const char* p_dead);
int vsf_sysutil_write_access(const char* p_filename);
/* Reading and writing */
unsigned long vsf_sysutil_lseek_to(const int fd, unsigned long seek_pos);
unsigned long vsf_sysutil_get_file_offset(const int file_fd);
void vsf_sysutil_lseek_to(const int fd, filesize_t seek_pos);
filesize_t vsf_sysutil_get_file_offset(const int file_fd);
int vsf_sysutil_read(const int fd, void* p_buf, const unsigned int size);
int vsf_sysutil_write(const int fd, const void* p_buf,
const unsigned int size);
@ -103,14 +110,14 @@ int vsf_sysutil_statbuf_is_regfile(const struct vsf_sysutil_statbuf* p_stat);
int vsf_sysutil_statbuf_is_symlink(const struct vsf_sysutil_statbuf* p_stat);
int vsf_sysutil_statbuf_is_socket(const struct vsf_sysutil_statbuf* p_stat);
int vsf_sysutil_statbuf_is_dir(const struct vsf_sysutil_statbuf* p_stat);
unsigned long vsf_sysutil_statbuf_get_size(
filesize_t vsf_sysutil_statbuf_get_size(
const struct vsf_sysutil_statbuf* p_stat);
const char* vsf_sysutil_statbuf_get_perms(
const struct vsf_sysutil_statbuf* p_stat);
const char* vsf_sysutil_statbuf_get_date(
const struct vsf_sysutil_statbuf* p_stat);
const struct vsf_sysutil_statbuf* p_stat, int use_localtime);
const char* vsf_sysutil_statbuf_get_numeric_date(
const struct vsf_sysutil_statbuf* p_stat);
const struct vsf_sysutil_statbuf* p_stat, int use_localtime);
unsigned int vsf_sysutil_statbuf_get_links(
const struct vsf_sysutil_statbuf* p_stat);
int vsf_sysutil_statbuf_get_uid(const struct vsf_sysutil_statbuf* p_stat);
@ -154,6 +161,7 @@ struct vsf_sysutil_wait_retval
int PRIVATE_HANDS_OFF_exit_status;
};
struct vsf_sysutil_wait_retval vsf_sysutil_wait(void);
int vsf_sysutil_wait_reap_one(void);
int vsf_sysutil_wait_get_retval(
const struct vsf_sysutil_wait_retval* p_waitret);
int vsf_sysutil_wait_exited_normally(
@ -171,8 +179,9 @@ int vsf_sysutil_memcmp(const void* p_src1, const void* p_src2,
unsigned int size);
int vsf_sysutil_strcmp(const char* p_src1, const char* p_src2);
int vsf_sysutil_atoi(const char* p_str);
long vsf_sysutil_atol(const char* p_str);
filesize_t vsf_sysutil_a_to_filesize_t(const char* p_str);
const char* vsf_sysutil_ulong_to_str(unsigned long the_ulong);
const char* vsf_sysutil_filesize_t_to_str(filesize_t the_filesize);
const char* vsf_sysutil_double_to_str(double the_double);
const char* vsf_sysutil_uint_to_octal(unsigned int the_uint);
unsigned int vsf_sysutil_octal_to_uint(const char* p_str);
@ -202,6 +211,7 @@ void vsf_sysutil_sockaddr_set_ipaddr(struct vsf_sysutil_sockaddr* p_sockptr,
struct vsf_sysutil_ipv4addr the_addr);
struct vsf_sysutil_ipv4addr vsf_sysutil_sockaddr_get_ipaddr(
const struct vsf_sysutil_sockaddr* p_sockptr);
struct vsf_sysutil_ipv4addr vsf_sysutil_sockaddr_get_any(void);
struct vsf_sysutil_ipv4port vsf_sysutil_ipv4port_from_int(unsigned int port);
void vsf_sysutil_sockaddr_set_port(struct vsf_sysutil_sockaddr* p_sockptr,
struct vsf_sysutil_ipv4port the_port);
@ -209,7 +219,7 @@ struct vsf_sysutil_ipv4port vsf_sysutil_sockaddr_get_port(
const struct vsf_sysutil_sockaddr* p_sockptr);
int vsf_sysutil_is_port_reserved(const struct vsf_sysutil_ipv4port);
int vsf_sysutil_get_ipv4_sock(void);
const struct vsf_sysutil_socketpair_retval
struct vsf_sysutil_socketpair_retval
vsf_sysutil_unix_dgram_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);
@ -237,6 +247,8 @@ int vsf_sysutil_recv_peek(const int fd, void* p_buf, unsigned int len);
const char* vsf_sysutil_inet_ntoa(
const struct vsf_sysutil_sockaddr* p_sockptr);
int vsf_sysutil_inet_aton(
const char* p_text, struct vsf_sysutil_ipv4addr* p_addr);
/* User database queries etc. */
struct vsf_sysutil_user;
@ -268,9 +280,15 @@ void vsf_sysutil_qsort(void* p_base, unsigned int num_elem,
/* Credentials handling */
int vsf_sysutil_running_as_root(void);
void vsf_sysutil_setuid(const struct vsf_sysutil_user* p_user);
void vsf_sysutil_setuid_numeric(int uid);
void vsf_sysutil_setgid(const struct vsf_sysutil_user* p_user);
void vsf_sysutil_setuid_numeric(int uid);
void vsf_sysutil_setgid_numeric(int gid);
int vsf_sysutil_geteuid(void);
int vsf_sysutil_getegid(void);
void vsf_sysutil_seteuid(const struct vsf_sysutil_user* p_user);
void vsf_sysutil_setegid(const struct vsf_sysutil_user* p_user);
void vsf_sysutil_seteuid_numeric(int uid);
void vsf_sysutil_setegid_numeric(int gid);
void vsf_sysutil_clear_supp_groups(void);
void vsf_sysutil_initgroups(const struct vsf_sysutil_user* p_user);
void vsf_sysutil_chroot(const char* p_root_path);

View File

@ -36,6 +36,12 @@ int tunable_log_ftp_protocol = 0;
int tunable_guest_enable = 0;
int tunable_userlist_enable = 0;
int tunable_userlist_deny = 1;
int tunable_use_localtime = 0;
int tunable_check_shell = 1;
int tunable_hide_ids = 0;
int tunable_listen = 0;
int tunable_port_promiscuous = 0;
int tunable_passwd_chroot_enable = 0;
unsigned int tunable_accept_timeout = 60;
unsigned int tunable_connect_timeout = 60;
@ -49,6 +55,9 @@ unsigned int tunable_pasv_min_port = 5001;
unsigned int tunable_pasv_max_port = 0;
unsigned int tunable_anon_max_rate = 0;
unsigned int tunable_local_max_rate = 0;
/* IPPORT_FTP */
unsigned int tunable_listen_port = 21;
unsigned int tunable_max_clients = 0;
const char* tunable_secure_chroot_dir = "/usr/share/empty";
const char* tunable_ftp_username = "ftp";
@ -63,4 +72,10 @@ const char* tunable_chroot_list_file = "/etc/vsftpd.chroot_list";
const char* tunable_pam_service_name = "ftp";
const char* tunable_guest_username = "ftp";
const char* tunable_userlist_file = "/etc/vsftpd.user_list";
const char* tunable_anon_root = 0;
const char* tunable_local_root = 0;
const char* tunable_banner_file = 0;
const char* tunable_pasv_address = 0;
const char* tunable_listen_address = 0;
const char* tunable_user_config_dir = 0;

View File

@ -32,6 +32,12 @@ extern int tunable_log_ftp_protocol; /* Log FTP requests/responses */
extern int tunable_guest_enable; /* Remap guest users */
extern int tunable_userlist_enable; /* Explicit user allow or deny */
extern int tunable_userlist_deny; /* Is user list allow or deny? */
extern int tunable_use_localtime; /* Use local time or GMT? */
extern int tunable_check_shell; /* Use /etc/shells for non-PAM */
extern int tunable_hide_ids; /* Show "ftp" in ls listings */
extern int tunable_listen; /* Standalone (no inetd) mode? */
extern int tunable_port_promiscuous; /* Any any PORT connect IP */
extern int tunable_passwd_chroot_enable; /* chroot() based on passwd */
/* Integer/numeric defines */
extern unsigned int tunable_accept_timeout;
@ -45,6 +51,8 @@ extern unsigned int tunable_pasv_min_port;
extern unsigned int tunable_pasv_max_port;
extern unsigned int tunable_anon_max_rate;
extern unsigned int tunable_local_max_rate;
extern unsigned int tunable_listen_port;
extern unsigned int tunable_max_clients;
/* String defines */
extern const char* tunable_secure_chroot_dir;
@ -59,6 +67,12 @@ extern const char* tunable_chroot_list_file;
extern const char* tunable_pam_service_name;
extern const char* tunable_guest_username;
extern const char* tunable_userlist_file;
extern const char* tunable_anon_root;
extern const char* tunable_local_root;
extern const char* tunable_banner_file;
extern const char* tunable_pasv_address;
extern const char* tunable_listen_address;
extern const char* tunable_user_config_dir;
#endif /* VSF_TUNABLES_H */

View File

@ -22,6 +22,7 @@
#include "utility.h"
#include "tunables.h"
#include "defs.h"
#include "parseconf.h"
static void drop_all_privs(void);
static void handle_sigchld(int duff);
@ -29,6 +30,9 @@ static void process_login_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);
static void handle_per_user_config(const struct mystr* p_user_str);
static void calculate_chdir_dir(int anon, struct mystr* p_chroot_str,
const struct mystr* p_user_str);
static void
handle_sigchld(int duff)
@ -101,11 +105,12 @@ drop_all_privs(void)
struct vsf_sysutil_statbuf* p_statbuf = 0;
if (vsf_sysutil_retval_is_error(str_lstat(&dir_str, &p_statbuf)))
{
die("vsftpd: not found: directory given in 'tunable_secure_chroot_dir'");
die("vsftpd: not found: directory given in 'secure_chroot_dir'");
}
vsf_sysutil_free(p_statbuf);
}
vsf_secutil_change_credentials(&user_str, &dir_str, 1, 0, 0);
vsf_secutil_change_credentials(&user_str, &dir_str, 0, 0,
VSF_SECUTIL_OPTION_CHROOT);
str_free(&user_str);
str_free(&dir_str);
}
@ -235,16 +240,26 @@ static void
common_do_login(struct vsf_session* p_sess, const struct mystr* p_user_str,
int do_chroot, int anon)
{
int was_anon = anon;
int newpid;
vsf_sysutil_default_sig(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();
/* Handle loading per-user config options */
handle_per_user_config(p_user_str);
vsf_sysutil_install_async_sighandler(kVSFSysUtilSigCHLD, handle_sigchld);
newpid = vsf_sysutil_fork();
newpid = vsf_sysutil_fork();
if (newpid == 0)
{
struct mystr guest_user_str = INIT_MYSTR;
struct mystr chdir_str = INIT_MYSTR;
unsigned int secutil_option = VSF_SECUTIL_OPTION_USE_GROUPS;
calculate_chdir_dir(anon, &chdir_str, p_user_str);
if (do_chroot)
{
secutil_option |= VSF_SECUTIL_OPTION_CHROOT;
}
/* Child - drop privs and start proper FTP! */
if (tunable_guest_enable && !anon)
{
@ -256,12 +271,18 @@ common_do_login(struct vsf_session* p_sess, const struct mystr* p_user_str,
*/
anon = 1;
}
vsf_secutil_change_credentials(p_user_str, 0, do_chroot, 1, 0);
if (!anon)
{
secutil_option |= VSF_SECUTIL_OPTION_CHANGE_EUID;
}
vsf_secutil_change_credentials(p_user_str, 0, &chdir_str,
0, secutil_option);
str_free(&guest_user_str);
str_free(&chdir_str);
/* Guard against the config error of having the anonymous ftp tree owned
* by the user we are running as
*/
if (anon && vsf_sysutil_write_access("/"))
if (was_anon && vsf_sysutil_write_access("/"))
{
die("vsftpd: refusing to run with writable anonymous root");
}
@ -274,3 +295,66 @@ common_do_login(struct vsf_session* p_sess, const struct mystr* p_user_str,
bug("should not get here in common_do_login");
}
static void
handle_per_user_config(const struct mystr* p_user_str)
{
if (tunable_user_config_dir)
{
struct mystr filename_str = INIT_MYSTR;
struct vsf_sysutil_statbuf* p_statbuf = 0;
int retval;
str_alloc_text(&filename_str, tunable_user_config_dir);
str_append_char(&filename_str, '/');
str_append_str(&filename_str, p_user_str);
retval = str_stat(&filename_str, &p_statbuf);
/* Security - ignore unless owned by root */
if (!vsf_sysutil_retval_is_error(retval) &&
vsf_sysutil_statbuf_get_uid(p_statbuf) == VSFTP_ROOT_UID)
{
vsf_parseconf_load_file(str_getbuf(&filename_str));
}
str_free(&filename_str);
vsf_sysutil_free(p_statbuf);
}
}
static void
calculate_chdir_dir(int anon, struct mystr* p_chroot_str,
const struct mystr* p_user_str)
{
if (anon && tunable_anon_root)
{
str_alloc_text(p_chroot_str, tunable_anon_root);
}
else if (!anon && tunable_local_root)
{
str_alloc_text(p_chroot_str, tunable_local_root);
}
/* If enabled, the chroot() location embedded in the HOMEDIR takes
* precedence.
*/
if (!anon && tunable_passwd_chroot_enable)
{
struct mystr homedir_str = INIT_MYSTR;
const struct vsf_sysutil_user* p_user = str_getpwnam(p_user_str);
struct str_locate_result loc_result;
if (p_user == 0)
{
struct mystr death_str = INIT_MYSTR;
str_alloc_text(&death_str, "str_getpwnam: ");
str_append_str(&death_str, p_user_str);
die(str_getbuf(&death_str));
}
str_alloc_text(&homedir_str, vsf_sysutil_user_get_homedir(p_user));
loc_result = str_locate_text(&homedir_str, "/./");
if (loc_result.found)
{
struct mystr tmp_str = INIT_MYSTR;
str_split_text(&homedir_str, &tmp_str, "/./");
str_free(&tmp_str);
str_copy(p_chroot_str, &homedir_str);
}
str_free(&homedir_str);
}
}

View File

@ -1,25 +1,44 @@
#!/bin/sh
# Cheesy hacky location of additional link libraries.
# Optimizations for specific platforms, to avoid unneccessary libraries
if [ -r /etc/redhat-release ]; then
grep '7\.' /etc/redhat-release >/dev/null && echo "-lpam" && exit
grep '6\.' /etc/redhat-release >/dev/null && echo "-lpam -ldl" && exit
fi
locate_library() { [ ! "$1*" = "`echo $1*`" ]; }
# Look for PAM
locate_library /lib/libpam.so && echo "-lpam";
# 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
fi
# Look for PAM in alternate location (FreeBSD)
# 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"
# Look for the crypt library (FreeBSD)
locate_library /usr/lib/libcrypt.so && echo "-lcrypt"
# Look for the dynamic linker library. Needed by older RedHat when
@ -41,3 +60,12 @@ 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";
# Solaris needs this for nanosleep()..
locate_library /lib/libposix4.so /usr/lib/libposix4.so && echo "-lposix4";

View File

@ -95,6 +95,12 @@ so you may wish to enable it.
Default: NO
.TP
.B check_shell
Note! This option only has an effect for non-PAM builds of vsftpd. If disabled,
vsftpd will not check /etc/shells for a valid user shell for local logins.
Default: YES
.TP
.B chown_uploads
If enabled, all anonymously uploaded files will have the ownership changed
to the user specified in the setting
@ -119,8 +125,10 @@ Default: NO
If set to YES, local users will be placed in a chroot() jail in their home
directory after login.
.BR Warning:
This option has security implications, especially if the users also have
shell access. Only enable if you know what you are doing.
This option has security implications, especially if the users have upload
permission, or shell access. Only enable if you know what you are doing.
Note that these security implications are not vsftpd specific. They apply to
all FTP daemons which offer to put local users in chroot() jails.
Default: NO
.TP
@ -155,6 +163,20 @@ login is remapped to the user specified in the
.BR guest_username
setting.
Default: NO
.TP
.B hide_ids
If enabled, all user and group information in directory listings will be
displayed as "ftp".
Default: NO
.TP
.B listen
If enabled, vsftpd will run in standalone mode. This means that vsftpd must
not be run from an inetd of some kind. Instead, the vsftpd executable is
run once directly. vsftpd itself will then take care of listening for and
handling incoming connections.
Default: NO
.TP
.B local_enable
@ -183,6 +205,16 @@ model, but gains you performance. You really don't want to enable this unless
you know what you are doing, and your site supports huge numbers of
simultaneously connected users.
Default: NO
.TP
.B passwd_chroot_enable
If enabled, along with
.BR chroot_local_user
, then a chroot() jail location may be specified on a per-user basis. Each
user's jail is derived from their home directory string in /etc/passwd. The
occurence of /./ in the home directory string denotes that the jail is at that
particular location in the path.
Default: NO
.TP
.B pasv_enable
@ -205,6 +237,13 @@ connection.
Default: YES
.TP
.B tunable_port_promiscuous
Set to YES if you want to disable the PORT security check that ensures that
outgoing data connections can only connect to the client. Only enable if
you know what you are doing!
Default: NO
.TP
.B setproctitle_enable
If enabled, vsftpd will try and show session status information in the system
process listing. In other words, the reported name of the process will change
@ -231,6 +270,13 @@ password.
Default: YES
.TP
.B use_localtime
If enabled, vsftpd will display directory listings with the 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.
Default: NO
.TP
.B userlist_enable
If enabled, vsftpd will load a list of usernames, from the filename given by
.BR userlist_file .
@ -314,6 +360,12 @@ off.
Default: 300
.TP
.B listen_port
If vsftpd is in standalone mode, this is the port it will listen on for
incoming FTP connections.
Default: 21
.TP
.B local_max_rate
The maximum data transfer rate permitted, in bytes per second, for local
authenticated users.
@ -327,6 +379,12 @@ will be treated as a base 10 integer!
Default: 077
.TP
.B max_clients
If vsftpd is in standalone mode, this is the maximum number of clients which
may be connected. Any additional clients connecting will get an error message.
Default: 0 (unlimited)
.TP
.B pasv_max_port
The maximum port to allocate for PASV style data connections. Can be used to
specify a narrow port range to assist firewalling.
@ -342,6 +400,12 @@ Default: 0 (use any port)
.SH STRING OPTIONS
Below is a list of string options.
.TP
.B anon_root
This option represents a directory which vsftpd will try to change into
after an anonymous login. Failure is silently ignored.
Default: (none)
.TP
.B banned_email_file
This option is the name of a file containing a list of anonymous e-mail
@ -351,6 +415,15 @@ is enabled.
Default: /etc/vsftpd.banned_emails
.TP
.B banner_file
This option is the name of a file containing text to display when someone
connects to the server. If set, it overrides the banner string provided by
the
.BR ftpd_banner
option.
Default: (none)
.TP
.B chown_username
This is the name of the user who is given ownership of anonymously uploaded
files. This option is only relevant if another option,
@ -390,6 +463,18 @@ by vsftpd when a connection first comes in.
Default: (none - default vsftpd banner is displayed)
.TP
.B listen_address
If vsftpd is in standalone mode, the default listen address (of all local
interfaces) may be overridden by this setting. Provide a numeric IP address.
Default: (none)
.TP
.B local_root
This option represents a directory which vsftpd will try to change into
after a local (i.e. non-anonymous) login. Failure is silently ignored.
Default: (none)
.TP
.B message_file
This option is the name of the file we look for when a new directory is
entered. The contents are displayed to the remote user. This option is
@ -412,6 +497,12 @@ This string is the name of the PAM service vsftpd will use.
Default: ftp
.TP
.B pasv_address
Use this option to override the IP address that vsftpd will advertise in
response to the PASV command. Provide a numeric IP address.
Default: (none - the address is taken from the incoming connected socket)
.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
@ -419,6 +510,21 @@ as a secure chroot() jail at times vsftpd does not require filesystem access.
Default: /usr/share/empty
.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
with an example. If you set
.BR user_config_dir
to be
.BR /etc/vsftpd_user_conf
and then log on as the user "chris", then vsftpd will apply the settings in
the file
.BR /etc/vsftpd_user_conf/chris
for the duration of the session. The format of this file is as detailed in
this manual page!
Default: (none)
.TP
.B userlist_file
This option is the name of the file loaded when the
.BR userlist_enable

View File

@ -1,7 +1,7 @@
#ifndef VSF_VERSION_H
#define VSF_VERSION_H
#define VSF_VERSION "0.9.2"
#define VSF_VERSION "1.1.0"
#endif /* VSF_VERSION_H */

View File

@ -8,7 +8,7 @@ service ftp
socket_type = stream
wait = no
user = root
server = /usr/sbin/vsftpd
server = /usr/local/sbin/vsftpd
# server_args =
# log_on_success += DURATION USERID
# log_on_failure += USERID