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:
parent
20e89955e0
commit
8b211d30ac
2
AUDIT
2
AUDIT
@ -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
|
||||
|
@ -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
342
COPYING
Normal 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.
|
90
Changelog
90
Changelog
@ -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
|
||||
-------------------------------------
|
||||
|
||||
|
138
EXAMPLE/INTERNET_SITE/README
Normal file
138
EXAMPLE/INTERNET_SITE/README
Normal 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.
|
||||
|
25
EXAMPLE/INTERNET_SITE/vsftpd.conf
Normal file
25
EXAMPLE/INTERNET_SITE/vsftpd.conf
Normal 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
|
15
EXAMPLE/INTERNET_SITE/vsftpd.xinetd
Normal file
15
EXAMPLE/INTERNET_SITE/vsftpd.xinetd
Normal 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
15
EXAMPLE/README
Normal 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.
|
||||
|
77
EXAMPLE/VIRTUAL_HOSTS/README
Normal file
77
EXAMPLE/VIRTUAL_HOSTS/README
Normal 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>
|
||||
|
150
EXAMPLE/VIRTUAL_USERS/README
Normal file
150
EXAMPLE/VIRTUAL_USERS/README
Normal 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.
|
||||
|
4
EXAMPLE/VIRTUAL_USERS/logins.txt
Normal file
4
EXAMPLE/VIRTUAL_USERS/logins.txt
Normal file
@ -0,0 +1,4 @@
|
||||
tom
|
||||
foo
|
||||
fred
|
||||
bar
|
13
EXAMPLE/VIRTUAL_USERS/vsftpd.conf
Normal file
13
EXAMPLE/VIRTUAL_USERS/vsftpd.conf
Normal 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
|
2
EXAMPLE/VIRTUAL_USERS/vsftpd.pam
Normal file
2
EXAMPLE/VIRTUAL_USERS/vsftpd.pam
Normal 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
|
55
EXAMPLE/VIRTUAL_USERS_2/README
Normal file
55
EXAMPLE/VIRTUAL_USERS_2/README
Normal 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
79
FAQ
Normal 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.
|
||||
|
8
INSTALL
8
INSTALL
@ -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
|
||||
|
@ -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.
|
||||
|
5
LICENSE
5
LICENSE
@ -1 +1,4 @@
|
||||
GPL v2
|
||||
See "COPYING"
|
||||
|
||||
Everything within the vsftpd tarball is licensed under version 2 of the GPL.
|
||||
|
||||
|
21
Makefile
21
Makefile
@ -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
21
README
@ -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!
|
||||
|
@ -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
|
||||
|
@ -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
4
SPEED
@ -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
16
TODO
@ -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
2
TUNING
@ -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
16
ascii.c
@ -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;
|
||||
}
|
||||
|
@ -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
33
banner.h
Normal 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
3
defs.h
@ -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 */
|
||||
|
||||
|
20
dirchange.h
20
dirchange.h
@ -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 */
|
||||
|
@ -4,3 +4,4 @@
|
||||
#undef VSF_SYSDEP_HAVE_PAM
|
||||
|
||||
#endif /* VSF_DUMMYINC_PAM_APPL_H */
|
||||
|
||||
|
7
dummyinc/sys/capability.h
Normal file
7
dummyinc/sys/capability.h
Normal 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
7
filesize.h
Normal file
@ -0,0 +1,7 @@
|
||||
#ifndef VSF_FILESIZE_H
|
||||
#define VSF_FILESIZE_H
|
||||
|
||||
typedef long long filesize_t;
|
||||
|
||||
#endif /* VSF_FILESIZE_H */
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
12
ftpdataio.c
12
ftpdataio.c
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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
31
ls.c
@ -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
40
main.c
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
68
parseconf.c
68
parseconf.c
@ -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++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
8
port/aix_bogons.h
Normal 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 */
|
||||
|
@ -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
|
||||
*/
|
||||
|
97
postlogin.c
97
postlogin.c
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
17
prelogin.c
17
prelogin.c
@ -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)");
|
||||
|
46
secutil.c
46
secutil.c
@ -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(".");
|
||||
}
|
||||
|
20
secutil.h
20
secutil.h
@ -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 */
|
||||
|
||||
|
12
session.h
12
session.h
@ -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
146
standalone.c
Normal 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
16
standalone.h
Normal 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
53
str.c
@ -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
12
str.h
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
|
||||
|
198
sysdeputil.c
198
sysdeputil.c
@ -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)
|
||||
{
|
||||
|
@ -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
227
sysutil.c
@ -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();
|
||||
|
38
sysutil.h
38
sysutil.h
@ -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);
|
||||
|
15
tunables.c
15
tunables.c
@ -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;
|
||||
|
||||
|
14
tunables.h
14
tunables.h
@ -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 */
|
||||
|
||||
|
94
twoprocess.c
94
twoprocess.c
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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";
|
||||
|
||||
|
110
vsftpd.conf.5
110
vsftpd.conf.5
@ -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
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user