debian/0000755000000000000000000000000011735306240007167 5ustar debian/source/0000755000000000000000000000000011374740306010473 5ustar debian/source/format0000644000000000000000000000001411403406235011672 0ustar 3.0 (quilt) debian/postrm0000644000000000000000000000035611377010377010447 0ustar #!/bin/sh # $Id: postrm,v 1.1 1999/04/16 07:00:28 herbert Exp $ set -e if [ "$1" = purge ]; then if command -v update-inetd >/dev/null 2>&1; then update-inetd --pattern '/usr/sbin/in\.ftpd' --remove "## ftp" fi fi #DEBHELPER# debian/ftpchroot0000644000000000000000000000011410214544075011117 0ustar # /etc/ftpchroot: list of users who needs to be chrooted. See ftpchroot(5). debian/dirs0000644000000000000000000000007110214544075010052 0ustar etc/pam.d usr/share/man/man5 usr/share/man/man8 usr/sbin debian/preinst0000644000000000000000000000037311374740305010604 0ustar #!/bin/sh # $Id: preinst,v 1.1 1999/10/07 12:48:39 herbert Exp $ set -e # Rename old PAM conffile. if [ -n "$2" ] && dpkg --compare-versions "$2" lt 0.11-5; then cd /etc/pam.d if [ -f ftpd -a ! -f ftp ]; then cp -p ftpd ftp fi fi #DEBHELPER# debian/ftpd.xinetd0000644000000000000000000000030311374740305011340 0ustar service ftp { disable = no flags = IPv6 socket_type = stream wait = no user = root server = /usr/sbin/in.ftpd server_args = -l log_type = SYSLOG daemon info log_on_failure = HOST } debian/rules0000755000000000000000000000342711735156774010274 0ustar #!/usr/bin/make -f # Sample debian/rules that uses debhelper. GNU copyright 1997 by Joey Hess. # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 DEFS := -D_FILE_OFFSET_BITS=64 build: dh_testdir if [ ! -f MCONFIG ]; then \ USE_PAM=1 ./configure; \ sed -e 's/^CFLAGS=\(.*\)$$/CFLAGS= -g $(DEFS) \1 -fno-strict-aliasing/' \ MCONFIG > MCONFIG.new; \ mv MCONFIG.new MCONFIG; \ echo CFLAGS+=-DUSE_PAM=1 \ `dpkg-buildflags --get CFLAGS` \ `dpkg-buildflags --get CPPFLAGS` >> MCONFIG; \ echo LIBS+=-lpam `dpkg-buildflags --get LDFLAGS` >> MCONFIG; \ fi $(MAKE) clean: dh_testdir dh_testroot touch MCONFIG [ ! -f Makefile ] || $(MAKE) distclean dh_clean install: build dh_testdir dh_testroot dh_prep dh_installdirs cp ftpd/ftpd debian/ftpd/usr/sbin/in.ftpd cp ftpd/ftpd.8 debian/ftpd/usr/share/man/man8/in.ftpd.8 cp ftpd/*.5 debian/*.5 debian/ftpd/usr/share/man/man5 cp debian/ftpchroot debian/ftpusers debian/ftpd/etc cp debian/pam.d/ftp debian/ftpd/etc/pam.d touch install-stamp # Build architecture-independent files here. binary-indep: build install # We have nothing to do by default. # Build architecture-dependent files here. binary-arch: build install # dh_testversion dh_testdir dh_testroot # dh_installdebconf dh_installdocs dh_installexamples dh_installmenu # dh_installemacsen # dh_installinit dh_installcron # dh_installmanpages # dh_undocumented dh_installchangelogs ChangeLog dh_strip dh_compress dh_fixperms dh_installdeb dh_shlibdeps dh_gencontrol # dh_makeshlibs dh_md5sums dh_builddeb source diff: @echo >&2 'source and diff are obsolete - use dpkg-source -b'; false binary: binary-indep binary-arch .PHONY: build clean binary-indep binary-arch binary install debian/README.Debian0000644000000000000000000000656511377010073011242 0ustar ftpd for Debian --------------- (May 4th, 2010) ftpd is now able to use IPv4 and IPv6 for data transport, in active and in passive mode. The default behaviour is to service both address families. Two options, '-4' and '-6', are introduced to restrict traffic to a single addressing mode. (Prior to October 2008) ftpd now supports PAM. It is recommended that you leave the pam_ftp entry alone in the pam configuration file since ftpd uses it to figure out prompts and determining anonymity. The best way to disable anonymous ftp is to place ftp and anonymous in /etc/ftpusers. Removing the user ftp from the system also works. The -A option no longer has any effect since authentication is done by PAM. To recover its functionality, just uncomment the ftpchroot line in the pam configuration file. If you wish to receive reports from users of your ftp server, you should setup an alias for ftp-bugs@name.of.your.ftp.server. Cooperation with inetd-servers. ------------------------------- Once the address families IPv4 and IPv6 are mixed, the three usual super-servers 'openbsd-inetd', 'xinetd', and 'inetutils-inetd' behave each in its own way. The easiest one to use would be 'xinetd' in non-compatibility mode. A typical configuration is included in /usr/share/doc/ftpd/examples/ftpd.xinetd. Also 'inetutils-inetd' can use a drop-in snippet configuration deposited in '/etc/inetd.d/', but the text corresponds to the lines discussed here. The following comments concern entries in '/etc/inetd.conf'. These observations are written with 'net.ipv6.bindv6only=1' in effect. * openbsd-inetd (formerly netkit-inetd) Here 'tcp' and 'udp' are restricted to IPv4 sockets. Their counterparts are 'tcp6' and 'udp6'. Thus a dual listener needs a configuration similar to this: # /etc/inetd.conf ftp stream tcp nowait root /usr/sbin/tcpd /usr/sbin/in.ftpd -l ftp stream tcp6 nowait root /usr/sbin/tcpd /usr/sbin/in.ftpd -l Observe the minute difference compared to 'inetutils-inetd' as stated below, only one 'tcp6' versus one 'tcp4'. * xinetd When this server is used in compatibility mode (controlled by INETD_COMPAT=Yes in '/etc/default/xinetd') and when an IPv6 enabled host is detected, the protocols 'tcp' and 'udp', as used in '/etc/inetd.conf', will automatically activate IPv4 as well as IPv6. To single out one address family, use 'tcp4' or 'tcp6'. * inetutils-inetd On a dual stacked system, 'inetutils-inetd' considers 'tcp' and 'tcp6' to be synonymous. Thus, to listen for both address families one must write two entries: # /etc/inetd.conf ftp stream tcp nowait root /usr/sbin/tcpd /usr/sbin/in.ftpd ftp stream tcp4 nowait root /usr/sbin/tcpd /usr/sbin/in.ftpd Globbing Attacks ---------------- Globbing attacks aimed at exhausting memory/CPU resources (e.g., ls ../*/../*/../*/../*/../*/../*/../*/../*/../*/../*/../*/../*/../*) can be countered by setting the appropriate resource limits in /etc/security/limits.conf. To do so, you need to make sure that /etc/pam.d/ftp contains the line session required pam_limits.so Which is the case by default. The limits which are most important on Linux are "as" and "cpu". For example, to limit the memory usage to 10MB, you should put ftp hard as 10240 in /etc/security/limits.conf. Herbert $Id: README.Debian,v 1.4 2002/10/06 22:23:49 herbert Exp $ debian/prerm0000644000000000000000000000022711377010514010236 0ustar #!/bin/sh # $Id: prerm,v 1.1 1999/04/16 07:00:29 herbert Exp $ set -e update-inetd --pattern '/usr/sbin/in\.ftpd' --multi --disable ftp #DEBHELPER# debian/changelog0000644000000000000000000003117411735164253011055 0ustar linux-ftpd (0.17-34) unstable; urgency=low * Drop unneeded libcrypt linking: + debian/patches/040-refine_config.diff: New file. * Support GNU/Hurd: + debian/patches/044-support_gnu_hurd.diff: New file. + debian/control: Mention GNU/Hurd in package description. * Activate hardening flags. Suggested by Moritz Muehlenhoff. + debian/rules: Use 'dpkg-buildflags'. (Closes: #656005) * Bump Standards to 3.9.3. -- Mats Erik Andersson Fri, 30 Mar 2012 00:54:44 +0200 linux-ftpd (0.17-33) unstable; urgency=low * Correct implementation of EPSV for IPv4. + debian/patches/020-support_ipv6.diff: Updated file. * [lintian] Addition of DEP-3 header: + debian/patches/030-manpage_typos.diff: Description added. * debian/control: Spelling of 'kFreeBSD'. * Bumped Standards to 3.9.1. -- Mats Erik Andersson Wed, 06 Apr 2011 22:34:30 +0200 linux-ftpd (0.17-32) unstable; urgency=low * Fixed minor typos in ftpd.8. * Renamed patches to avoid future clashes with linux-ftpd-ssl. * Bumped Standards to 3.9.0 -- Alberto Gonzalez Iniesta Thu, 08 Jul 2010 13:28:07 +0200 linux-ftpd (0.17-31) unstable; urgency=low [Mats Erik Andersson] * debian/control: Expanded description. * debian/copyright: Added explicit license for the two IPv6-patches. * Describe effects of recent changes on three inetd-servers. + debian/NEWS: Short text addition. + debian/README.Debian: Added an extended discussion. * FTBFS GNU/kfreebsd, GNU/Hurd: * debian/patches/26-support_glibc_bsd_and_gnu.diff: New file. * debian/{postinst,prerm}: Use option '--multi' with 'update-inetd'. -- Mats Erik Andersson Tue, 25 May 2010 20:05:34 +0200 linux-ftpd (0.17-30) unstable; urgency=low * Migration to format "3.0 (quilt)". + Identified source code patches: + debian/patches/01-from_hamm.diff + debian/patches/02-from_sarge.diff + debian/patches/03-from_etch.diff + debian/patches/10-ftpd_csrf.diff * Standard 3.8.4, debhelper compatibility 7: + Using dh_prep. * debian/control: + Build depend includes ${misc:Depends} and 'debhelper (>= 7). + Source homepage stanza pointing to download site. * debian/watch: New file. * debian/postinst: Suppress error message if '/etc/inetd.conf' is missing. + Print a hint to the example xinetd configuration, if applicable. * debian/ftpd.examples: + debian/ftpd.xinetd: Configuration for use with xinetd. * Prepare migration to IPv6 support: + debian/rules: Use compiler flag '-fno-strict-aliasing'. + debian/patches/14-adjust_infrastruct.diff: New file. + debian/patches/16-family_independence.diff: New file. * Implement active IPv6 support: (Closes: #580251) + debian/patches/20-support_ipv6.diff: New file. + debian/NEWS: New file. + debian/README.Debian: A short explanation is added. * Uninitialized va_list causes segmentation faults on amd64: + debian/patches/24-failing_va_list.diff: New file. * [lintian] maintainer-script-without-set-e: + debian/{preinst,prerm,postinst,postrm} modified. * [lintian] debian-rules-ignores-make-clean-error: + debian/rules modified. * agi: Added Mats Erik Andersson as Uploader. -- Mats Erik Andersson Sun, 09 May 2010 16:17:20 +0200 linux-ftpd (0.17-29) unstable; urgency=high * Ian Beckwith: - Patch to fix cross-site request forgery (CSRF) attacks. CVE-2008-4247 (Closes: #500278) * Updated package description. (Closes: #493433) -- Alberto Gonzalez Iniesta Fri, 17 Oct 2008 20:34:17 +0200 linux-ftpd (0.17-28) unstable; urgency=low * Patch postrm/postinst files to handle update-inetd better. Thanks Ian Beckwith for the patch. (Closes: #482912) -- Alberto Gonzalez Iniesta Tue, 22 Jul 2008 17:13:19 +0200 linux-ftpd (0.17-27) unstable; urgency=low * Ignore missing ../MCONFIG in clean target. (Closes: #436720) -- Alberto Gonzalez Iniesta Wed, 08 Aug 2007 20:49:22 +0200 linux-ftpd (0.17-26) unstable; urgency=low * Removed Depends on update-inetd, since it should be provided by inetd-superserver. -- Alberto Gonzalez Iniesta Tue, 07 Aug 2007 18:02:11 +0200 linux-ftpd (0.17-25) unstable; urgency=low * Condition the call to update-inetd in postrm. (Closes: #416745) * Moved netbase dependency to openbsd-inetd | inet-superserver. * Added Depends on update-inetd * Moved to debhelper compat 4. (Removed debian/conffiles) * Bumped Standards-Version to 3.7.2.2. No change -- Alberto Gonzalez Iniesta Sat, 31 Mar 2007 19:43:37 +0200 linux-ftpd (0.17-24) unstable; urgency=low * pam.d/ftpd. Updated PAM configuration to used common-* files. Thanks a lot Pierre Gaufillet for the patch (Closes: #308651) -- Alberto Gonzalez Iniesta Thu, 14 Dec 2006 12:14:53 +0100 linux-ftpd (0.17-23) unstable; urgency=high * Urgency set due to security fix. * Corrected typo in patch used in previous upload that made the server run some commands with EGID 'root'. Thanks to Matt Power (for finding out) and Stefan Cornelius from Gentoo (for warning me). -- Alberto Gonzalez Iniesta Sat, 25 Nov 2006 18:54:59 +0100 linux-ftpd (0.17-22) unstable; urgency=high * Fixing two security bugs: - Fixed ftpd from doing chdir while running as root. (Closes: #384454) Thanks a lot to Paul Szabo for finding out and the patch. - Check the return value from setuid calls to avoid running code as root. Thanks Paul Szabo for the patch. -- Alberto Gonzalez Iniesta Fri, 15 Sep 2006 13:14:25 +0200 linux-ftpd (0.17-21) unstable; urgency=low * Patched ftpcmd.y to allow building on amd64 with gcc-4.0. Thanks Andreas Jochens for the patch. (Closes: #300245) -- Alberto Gonzalez Iniesta Sun, 10 Jul 2005 08:48:19 +0200 linux-ftpd (0.17-20) unstable; urgency=low * New maintainer. -- Alberto Gonzalez Iniesta Sat, 12 Mar 2005 12:07:29 +0100 linux-ftpd (0.17-19) unstable; urgency=low * Add -n option to log numeric IPs rather than doing reverse lookup (for improved log forensics in the event an attacker has control of their reverse DNS.). Thanks Dean Gaudet. (Closes: #258369) * Fix Build-Depends to avoid relying on virtual package 'libpam-dev' exclussively. * Convert changelog to UTF-8. -- Robert Millan Wed, 11 Aug 2004 22:08:44 +0200 linux-ftpd (0.17-18) unstable; urgency=low * New maintainer. (Closes: #249709) - control (Maintainer): Set myself. -- Robert Millan Wed, 19 May 2004 02:09:10 +0200 linux-ftpd (0.17-17) unstable; urgency=low * Documented the need for libnss_files.so.2 (closes: #241687). -- Herbert Xu Sat, 24 Apr 2004 17:48:37 +1000 linux-ftpd (0.17-16) unstable; urgency=low * Fixed ftpd entry existence test in postinst. * Added missing -q for last grep in postinst. * Removed debconf message about globbing attacks. * Fixed type-punning warning in pam_doit. * Removed stamp files for build and install. * Fixed const cast warning in ftpcmd.y. -- Herbert Xu Sat, 21 Jun 2003 14:20:35 +1000 linux-ftpd (0.17-15) unstable; urgency=low * Removed description of bogus -p option (closes: #180652). -- Herbert Xu Thu, 6 Mar 2003 20:26:16 +1100 linux-ftpd (0.17-14) unstable; urgency=low * Added Spanish debconf translation (Carlos Valdivia Yagüe, closes: #143956). * Call ls without -g (closes #156992). -- Herbert Xu Sun, 25 Aug 2002 10:09:07 +1000 linux-ftpd (0.17-13) unstable; urgency=low * Added Russian debconf translation (Ilgiz Kalmetev, closes: #135840). -- Herbert Xu Thu, 18 Apr 2002 19:18:28 +1000 linux-ftpd (0.17-12) unstable; urgency=low * Fixed REST/STOR combination with OpenBSD patch (closes: #132974). -- Herbert Xu Sat, 9 Feb 2002 14:50:45 +1100 linux-ftpd (0.17-11) unstable; urgency=low * REST now accepts intmax_t (closes: #126766). -- Herbert Xu Sun, 20 Jan 2002 19:03:22 +1100 linux-ftpd (0.17-10) unstable; urgency=low * Built with support for large files (closes: #122961). -- Herbert Xu Sun, 9 Dec 2001 17:45:53 +1100 linux-ftpd (0.17-9) unstable; urgency=low * Added sample limits.conf entry against globbing (closes: #121074). * Added Brazilian debconf template (Andre Luis Lopes, closes: #120835). * Always specify the syslog facility explicitly (closes: #121644). -- Herbert Xu Sat, 1 Dec 2001 18:28:51 +1100 linux-ftpd (0.17-8) unstable; urgency=low * Added German debconf template (Sebastian Feltel, closes: #113611). -- Herbert Xu Sat, 13 Oct 2001 08:13:55 +1000 linux-ftpd (0.17-7) unstable; urgency=low * Added debconf about globbing attacks. -- Herbert Xu Thu, 23 Aug 2001 19:49:01 +1000 linux-ftpd (0.17-6) unstable; urgency=low * Register sessions with PAM. * Use pam_limits by default. * Documented the procedure to counter globbing attacks. -- Herbert Xu Sat, 9 Jun 2001 13:25:27 +1000 linux-ftpd (0.17-5) unstable; urgency=low * Removed duplicate authentication error message (closes: #96640). -- Herbert Xu Mon, 7 May 2001 22:08:29 +1000 linux-ftpd (0.17-4) unstable; urgency=low * The value of unique is now passed to dataconn (closes: #93217). -- Herbert Xu Sun, 22 Apr 2001 09:33:26 +1000 linux-ftpd (0.17-3) unstable; urgency=low * Fixed anonymous authentication bug when PAM is disabled (Liviu Daia, Abraham vd Merwe, Rainer Weikusat, closes: #88837). * Fixed patterns used to check for existing ftp services (closes: #85579). -- Herbert Xu Fri, 9 Mar 2001 22:30:37 +1100 linux-ftpd (0.17-2) unstable; urgency=high * Applied bug fix from OpenBSD (closes: #78973). -- Herbert Xu Thu, 7 Dec 2000 19:47:47 +1100 linux-ftpd (0.17-1) unstable; urgency=low * New upstream release (identical to 0.16-2). -- Herbert Xu Sat, 12 Aug 2000 13:29:38 +1000 linux-ftpd (0.16-2) unstable; urgency=high * Fixed a security hole discovered by OpenBSD, thanks to Thomas Roessler for notifying me (closes: #66832). * Added build-time dependency on debhelper. -- Herbert Xu Fri, 7 Jul 2000 10:15:38 +1000 linux-ftpd (0.16-1) unstable; urgency=low * New upstream release. * Added Source-Depends on bison (closes: #61160). * Removed checks on the remote address of the data connection which violated RFC 959 (closes: #59251). -- Herbert Xu Mon, 24 Apr 2000 20:46:00 +1000 linux-ftpd (0.11-9) frozen unstable; urgency=low * Added Bource-Depends on libpam0g-dev (closes: #49917). -- Herbert Xu Sat, 18 Mar 2000 12:50:14 +1100 linux-ftpd (0.11-8) unstable; urgency=low * Added entry for ~ftp/lib in in.ftpd(8) (closes: #49035). -- Herbert Xu Sat, 6 Nov 1999 12:21:37 +1100 linux-ftpd (0.11-7) unstable; urgency=low * Added missing dependencies on netbase and libpam-modules (closes: #48411). -- Herbert Xu Wed, 27 Oct 1999 09:25:59 +1000 linux-ftpd (0.11-6) unstable; urgency=low * Anonymous users other than ftp should work now (closes: #48252). -- Herbert Xu Mon, 25 Oct 1999 16:38:16 +1000 linux-ftpd (0.11-5) unstable; urgency=low * Installed files according to the FHS. * Applied PAM patch from Olaf Kirch. * Renamed PAM file to ftp. -- Herbert Xu Thu, 7 Oct 1999 22:19:58 +1000 linux-ftpd (0.11-4) unstable; urgency=low * Rewritten PAM code to remove hack for ftp prompt. * Provide/conflict with ftp-server (fixes #42412). -- Herbert Xu Fri, 10 Sep 1999 10:32:04 +1000 linux-ftpd (0.11-3) unstable; urgency=low * Fixed incorrect usage of update-inetd in postinst (fixes #40771). -- Herbert Xu Mon, 5 Jul 1999 17:46:41 +1000 linux-ftpd (0.11-2) unstable; urgency=low * Don't use absoluet paths in PAM configuration file (fixes #38985). -- Herbert Xu Sat, 19 Jun 1999 12:10:03 +1000 linux-ftpd (0.11-1) unstable; urgency=low * Split from netstd. * Added support for PAM. * Pad with zeros instead of spaces in setproctitle. * Add a note about ftp-bugs in README (fixes #29733). * Made response to STOU commands conform to RFC 1123 (fixes #32490). -- Herbert Xu Thu, 1 Apr 1999 13:45:20 +1000 debian/pam.d/0000755000000000000000000000000010540231045010157 5ustar debian/pam.d/ftp0000644000000000000000000000063010540231045010672 0ustar # Standard behaviour for ftpd(8). auth required pam_listfile.so item=user sense=deny file=/etc/ftpusers onerr=succeed # This line is required by ftpd(8). auth sufficient pam_ftp.so # Uncomment this to achieve what used to be ftpd -A. #auth required pam_listfile.so item=user sense=allow file=/etc/ftpchroot onerr=fail # Standard blurb. @include common-auth @include common-account @include common-session debian/ftpchroot.50000644000000000000000000000155410214544075011273 0ustar .\" Copyright (c) 1999 Herbert Xu (herbert@gondor.apana.org.au), .\" Copyright (c) 1994 Peter Tobias (tobias@server.et-inf.fho-emden.de), .\" This file may be distributed under the GNU General Public License. .TH FTPCHROOT 5 "1999 April 1st" "Linux" "Linux Programmer's Manual" .SH NAME ftpchroot \- file which lists users who need to be chrooted .SH DESCRIPTION \fB/etc/ftpchroot\fP is used by .BR ftpd(8); the file contains a list of users who need to be chrooted before the ftp service is offered. Blank lines and lines beginning with "#" are ignored. Remember that the whole line will be used for the username, so please don't use the "#" character after a name to comment this entry. .SH EXAMPLES .B /etc/ftpchroot may contain the following entries: .sp # .br # /etc/ftpusers .br # .br not_so_anonymous .SH FILES /etc/ftpchroot .SH "SEE ALSO" .BR ftp "(1), " ftpd "(8)" debian/postinst0000644000000000000000000000200611377000111010761 0ustar #!/bin/sh # $Id: postinst,v 1.7 2003/06/21 02:31:44 herbert Exp $ set -e if grep -q '[[:blank:]]/usr/sbin/in\.ftpd.*-z' /etc/inetd.conf 2>/dev/null; then update-inetd --pattern '/usr/sbin/in\.ftpd' --remove ".*ftp" fi if grep -q '[[:blank:]]/usr/sbin/in\.ftpd\>' /etc/inetd.conf 2>/dev/null; then if ! grep -q '^ftp\>' /etc/inetd.conf; then update-inetd --pattern '/usr/sbin/in\.ftpd' --multi --enable ftp fi else FTPENTRY="ftp stream tcp nowait root /usr/sbin/tcpd /usr/sbin/in.ftpd" if grep -q '^ftp\>' /etc/inetd.conf 2>/dev/null; then update-inetd --group STANDARD --add "## $FTPENTRY" else update-inetd --group STANDARD --add "$FTPENTRY" fi fi if [ ! -f /etc/inetd.conf -a -d /etc/xinetd.d -a -x /usr/sbin/xinetd ]; then cat <<-TEXT ------------------------------------------------ There is an example configuration for using ftpd under the control of xinetd. It is delivered as /usr/share/doc/fptd/examples/ftpd.xinetd ------------------------------------------------ TEXT fi #DEBHELPER# debian/control0000644000000000000000000000162311735154655010607 0ustar Source: linux-ftpd Section: net Priority: extra Maintainer: Alberto Gonzalez Iniesta Uploaders: Mats Erik Andersson Build-Depends: bison, debhelper (>= 7.0.0), libpam0g-dev | libpam-dev Standards-Version: 3.9.3 Homepage: http://ftp.uk.linux.org/pub/linux/Networking/netkit/ Package: ftpd Architecture: any Depends: openbsd-inetd | inet-superserver, libpam-modules, ${shlibs:Depends}, ${misc:Depends} Provides: ftp-server Conflicts: ftp-server Replaces: netstd Description: File Transfer Protocol (FTP) server This is the netkit ftp server. You are recommended to use one of its alternatives, such as vsftpd, proftpd, or pure-ftpd. . This server supports IPv6, and can be used in standalone mode as well as in inetd-slave mode, but other servers have better long-term security screening. . The server can be used with GNU/Linux, GNU/kFreeBSD, and GNU/Hurd. debian/watch0000644000000000000000000000015311374740306010223 0ustar version=3 http://ftp.uk.linux.org/pub/linux/Networking/netkit/linux-ftpd-([.0-9]+)\.tar\.gz debian uupdate debian/ftpd.examples0000644000000000000000000000002311374740305011662 0ustar debian/ftpd.xinetd debian/ftpusers0000644000000000000000000000013310214544075010763 0ustar # /etc/ftpusers: list of users disallowed ftp access. See ftpusers(5). root ftp anonymous debian/patches/0000755000000000000000000000000011735154320010616 5ustar debian/patches/030-manpage_typos.diff0000644000000000000000000000165511547143230014624 0ustar Description: Spelling error in manual page. Author: Alberto Gonzalez Iniesta Forwarded: not-needed Last-Update: 2010-07-08 --- linux-ftpd-0.17.orig/ftpd/ftpd.8 2010-07-08 13:34:37.251457013 +0200 +++ linux-ftpd-0.17/ftpd/ftpd.8 2010-07-08 13:35:05.667542648 +0200 @@ -65,13 +65,13 @@ Available options: .Bl -tag -width Ds .It Fl 4 -Use IPv4 addressing only. Th default is to offer service for both families, IPv6 and IPv4. +Use IPv4 addressing only. The default is to offer service for both families, IPv6 and IPv4. .It Fl 6 Only provide IPv6 addressing capability. .It Fl A Permit only anonymous ftp connections or accounts listed in .Pa /etc/ftpchroot. -Other connection attempts are refused. This option is nolonger effective if +Other connection attempts are refused. This option is no longer effective if PAM is enabled. Please refer to the README file for instructions to doing this with PAM. .It Fl d debian/patches/001-from_hamm.diff0000644000000000000000000006674411374740305013737 0ustar Description: Patching recovered from linux-ftpd_0.17-13.diff.gz Author: Herbert Xu X-Comment: Bug #88837 contributed by Liviu Daia, Abraham van der Merwe, and Rainer Weikusat Forwarded: no Last-Update: 2002-02-09 --- linux-ftpd-0.17.orig/ftpd/ftpcmd.y +++ linux-ftpd-0.17/ftpd/ftpcmd.y @@ -55,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -111,8 +112,8 @@ %} %union { - int i; - char *s; + intmax_t i; + char *s; } %token @@ -595,9 +596,9 @@ { if ($2) { fromname = (char *) 0; - restart_point = $4; /* XXX $4 is only "int" */ - reply(350, "Restarting at %qd. %s", - (quad_t) restart_point, + restart_point = $4; + reply(350, "Restarting at %jd. %s", + (intmax_t) restart_point, "Send STORE or RETRIEVE to initiate transfer."); } } @@ -931,7 +932,7 @@ if (tmpline[c] == '\n') { *cs++ = '\0'; if (debug) - syslog(LOG_DEBUG, "command: %s", s); + syslog(LOG_FTP | LOG_DEBUG, "command: %s", s); tmpline[0] = '\0'; return(s); } @@ -973,7 +974,7 @@ if (debug) { if (!guest && strncasecmp("pass ", s, 5) == 0) { /* Don't syslog passwords */ - syslog(LOG_DEBUG, "command: %.5s ???", s); + syslog(LOG_FTP | LOG_DEBUG, "command: %.5s ???", s); } else { register char *cp; register int len; @@ -985,7 +986,7 @@ --cp; --len; } - syslog(LOG_DEBUG, "command: %.*s", len, s); + syslog(LOG_FTP | LOG_DEBUG, "command: %.*s", len, s); } } return (s); @@ -998,7 +999,7 @@ reply(421, "Timeout (%d seconds): closing control connection.", timeout); if (logging) - syslog(LOG_INFO, "User %s timed out after %d seconds", + syslog(LOG_FTP | LOG_INFO, "User %s timed out after %d seconds", (pw ? pw -> pw_name : "unknown"), timeout); dologout(1); } @@ -1143,7 +1144,7 @@ ; c = cbuf[cpos]; cbuf[cpos] = '\0'; - yylval.i = atoi(cp); + yylval.i = strtoimax(cp, 0, 10); cbuf[cpos] = c; state = STR1; return (NUMBER); @@ -1158,7 +1159,7 @@ ; c = cbuf[cpos]; cbuf[cpos] = '\0'; - yylval.i = atoi(cp); + yylval.i = strtoimax(cp, 0, 10); cbuf[cpos] = c; return (NUMBER); } @@ -1314,7 +1315,7 @@ if (stat(filename, &stbuf) < 0 || !S_ISREG(stbuf.st_mode)) reply(550, "%s: not a plain file.", filename); else - reply(213, "%qu", (quad_t) stbuf.st_size); + reply(213, "%ju", (uintmax_t) stbuf.st_size); break; } case TYPE_A: { FILE *fin; @@ -1340,7 +1341,7 @@ } (void) fclose(fin); - reply(213, "%qd", (quad_t) count); + reply(213, "%jd", (intmax_t) count); break; } default: reply(504, "SIZE not implemented for Type %c.", "?AEIL"[type]); --- linux-ftpd-0.17.orig/ftpd/ftpd.8 +++ linux-ftpd-0.17/ftpd/ftpd.8 @@ -67,7 +67,9 @@ .It Fl A Permit only anonymous ftp connections or accounts listed in .Pa /etc/ftpchroot. -Other connection attempts are refused. +Other connection attempts are refused. This option is nolonger effective if +PAM is enabled. Please refer to the README file for instructions to doing +this with PAM. .It Fl d Debugging information is written to the syslog using LOG_FTP. .It Fl D @@ -356,6 +358,21 @@ .Pa motd , if present, will be printed after a successful login. These files should be mode 444. +.It Pa ~ftp/lib +Make this directory owned by +.Dq root +and unwritable by anyone (mode 511). +The libraries +.Xr ld-linux.so.2 +and +.Xr libc.so.6 +(or whatever your +.Xr ls +command is linked to) +must be present. Note that if you're using a 2.2.* or later Linux kernel, +.Xr ld-linux.so.2 +must be executable as well as readable (555). All other files should be mode +444. .It Pa ~ftp/pub Make this directory mode 555 and owned by .Dq root . --- linux-ftpd-0.17.orig/ftpd/ftpd.c +++ linux-ftpd-0.17/ftpd/ftpd.c @@ -80,6 +80,7 @@ #include #include #include +#include #include #include #include @@ -95,8 +96,6 @@ #else #include /* for initgroups() */ /* #include * for L_SET et al. * <--- not used? */ -/*typedef int64_t quad_t;*/ -typedef unsigned int useconds_t; #endif #include "../version.h" @@ -132,6 +131,16 @@ #include #endif +#ifdef USE_PAM +#include +#include +#include +/* backward compatibility hack for libpam < 0.58 */ +#ifndef PAM_ESTABLISH_CRED +#define PAM_ESTABLISH_CRED PAM_CRED_ESTABLISH +#endif +#endif + static char versionpre[] = "Version 6.4/OpenBSD/Linux"; static char version[sizeof(versionpre)+sizeof(pkg)]; @@ -218,29 +227,37 @@ char proctitle[BUFSIZ]; /* initial part of title */ #endif /* HASSETPROCTITLE */ +#ifdef USE_PAM +static pam_handle_t *pamh; +static char *PAM_username; +static char *PAM_password; +static char *PAM_message; +static int PAM_accepted; +#endif + #define LOGCMD(cmd, file) \ if (logging > 1) \ - syslog(LOG_INFO,"%s %s%s", cmd, \ + syslog(LOG_FTP | LOG_INFO,"%s %s%s", cmd, \ *(file) == '/' ? "" : curdir(), file); #define LOGCMD2(cmd, file1, file2) \ if (logging > 1) \ - syslog(LOG_INFO,"%s %s%s %s%s", cmd, \ + syslog(LOG_FTP | LOG_INFO,"%s %s%s %s%s", cmd, \ *(file1) == '/' ? "" : curdir(), file1, \ *(file2) == '/' ? "" : curdir(), file2); #define LOGBYTES(cmd, file, cnt) \ if (logging > 1) { \ if (cnt == (off_t)-1) \ - syslog(LOG_INFO,"%s %s%s", cmd, \ + syslog(LOG_FTP | LOG_INFO,"%s %s%s", cmd, \ *(file) == '/' ? "" : curdir(), file); \ else \ - syslog(LOG_INFO, "%s %s%s = %qd bytes", cmd, \ - *(file) == '/' ? "" : curdir(), file, (quad_t)(cnt)); \ + syslog(LOG_FTP | LOG_INFO, "%s %s%s = %jd bytes", cmd, \ + *(file) == '/' ? "" : curdir(), file, (intmax_t)(cnt)); \ } static void ack __P((const char *)); static void myoob __P((int)); static int checkuser __P((const char *, const char *)); -static FILE *dataconn __P((const char *, off_t, const char *)); +static FILE *dataconn __P((const char *, off_t, const char *, int)); static void dolog __P((struct sockaddr_in *)); static const char *curdir __P((void)); static void end_login __P((void)); @@ -255,6 +272,7 @@ sgetpwnam __P((const char *)); static char *sgetsave __P((char *)); static void reapchild __P((int)); +static void authentication_setup(const char *); #if defined(TCPWRAPPERS) static int check_host __P((struct sockaddr_in *)); @@ -415,7 +433,7 @@ * Detach from parent. */ if (daemon(1, 1) < 0) { - syslog(LOG_ERR, "failed to become a daemon"); + syslog(LOG_FTP | LOG_ERR, "failed to become a daemon"); exit(1); } (void) signal(SIGCHLD, reapchild); @@ -424,7 +442,8 @@ */ sv = getservbyname("ftp", "tcp"); if (sv == NULL) { - syslog(LOG_ERR, "getservbyname for ftp failed"); + syslog(LOG_FTP | LOG_ERR, + "getservbyname for ftp failed"); exit(1); } /* @@ -433,22 +452,22 @@ */ ctl_sock = socket(AF_INET, SOCK_STREAM, 0); if (ctl_sock < 0) { - syslog(LOG_ERR, "control socket: %m"); + syslog(LOG_FTP | LOG_ERR, "control socket: %m"); exit(1); } if (setsockopt(ctl_sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0) - syslog(LOG_ERR, "control setsockopt: %m");; + syslog(LOG_FTP | LOG_ERR, "control setsockopt: %m");; server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = INADDR_ANY; server_addr.sin_port = sv->s_port; if (bind(ctl_sock, (struct sockaddr *)&server_addr, sizeof(server_addr))) { - syslog(LOG_ERR, "control bind: %m"); + syslog(LOG_FTP | LOG_ERR, "control bind: %m"); exit(1); } if (listen(ctl_sock, 32) < 0) { - syslog(LOG_ERR, "control listen: %m"); + syslog(LOG_FTP | LOG_ERR, "control listen: %m"); exit(1); } /* @@ -478,7 +497,8 @@ addrlen = sizeof(his_addr); if (getpeername(0, (struct sockaddr *)&his_addr, &addrlen) < 0) { - syslog(LOG_ERR, "getpeername (%s): %m", argv[0]); + syslog(LOG_FTP | LOG_ERR, "getpeername (%s): %m", + argv[0]); exit(1); } } @@ -490,29 +510,29 @@ (void) signal(SIGPIPE, lostconn); (void) signal(SIGCHLD, SIG_IGN); if (signal(SIGURG, myoob) == SIG_ERR) - syslog(LOG_ERR, "signal: %m"); + syslog(LOG_FTP | LOG_ERR, "signal: %m"); addrlen = sizeof(ctrl_addr); if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) { - syslog(LOG_ERR, "getsockname (%s): %m", argv[0]); + syslog(LOG_FTP | LOG_ERR, "getsockname (%s): %m", argv[0]); exit(1); } #ifdef IP_TOS tos = IPTOS_LOWDELAY; if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0) - syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); + syslog(LOG_FTP | LOG_WARNING, "setsockopt (IP_TOS): %m"); #endif data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1); /* Try to handle urgent data inline */ #ifdef SO_OOBINLINE if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0) - syslog(LOG_ERR, "setsockopt: %m"); + syslog(LOG_FTP | LOG_ERR, "setsockopt: %m"); #endif #ifdef F_SETOWN if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1) - syslog(LOG_ERR, "fcntl F_SETOWN: %m"); + syslog(LOG_FTP | LOG_ERR, "fcntl F_SETOWN: %m"); #endif dolog(&his_addr); /* @@ -583,13 +603,13 @@ (void)signo; if (debug) - syslog(LOG_DEBUG, "lost connection"); + syslog(LOG_FTP | LOG_DEBUG, "lost connection"); dologout(-1); } static void sigquit(int signo) { - syslog(LOG_ERR, "got signal %s", strsignal(signo)); + syslog(LOG_FTP | LOG_ERR, "got signal %s", strsignal(signo)); dologout(-1); } @@ -658,10 +678,15 @@ * requesting login privileges. Disallow anyone who does not have a standard * shell as returned by getusershell(). Disallow anyone mentioned in the file * _PATH_FTPUSERS to allow people such as root and uucp to be avoided. + * + * pw maybe unset if we're using PAM and the login turns out to be anonymous. + * -- herbert */ void user(char *name) { +#ifndef USE_PAM const char *cp, *shell; +#endif if (logged_in) { if (guest) { @@ -674,6 +699,9 @@ end_login(); } +#ifdef USE_PAM + authentication_setup(name); +#else guest = 0; if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) { if (checkuser(_PATH_FTPUSERS, "ftp") || @@ -687,7 +715,7 @@ } else reply(530, "User %s unknown.", name); if (!askpasswd && logging) - syslog(LOG_NOTICE, + syslog(LOG_FTP | LOG_NOTICE, "ANONYMOUS FTP LOGIN REFUSED FROM %s", remotehost); return; } @@ -707,17 +735,13 @@ if (cp == NULL || checkuser(_PATH_FTPUSERS, name)) { reply(530, "User %s access denied.", name); if (logging) - syslog(LOG_NOTICE, + syslog(LOG_FTP | LOG_NOTICE, "FTP LOGIN REFUSED FROM %s, %s", remotehost, name); pw = (struct passwd *) NULL; return; } } - if (logging) { - strncpy(curname, name, sizeof(curname)-1); - curname[sizeof(curname)-1] = '\0'; - } #ifdef SKEY if (!skey_haskey(name)) { char *myskey, *skey_keyinfo __P((char *name)); @@ -728,6 +752,11 @@ } else #endif reply(331, "Password required for %s.", name); +#endif + if (logging) { + strncpy(curname, name, sizeof(curname)-1); + curname[sizeof(curname)-1] = '\0'; + } askpasswd = 1; /* @@ -774,9 +803,19 @@ sigprocmask (SIG_BLOCK, &allsigs, NULL); (void) seteuid((uid_t)0); if (logged_in) { +#ifdef USE_PAM + int error; + error = pam_close_session(pamh, 0); + pam_end(pamh, error); + pamh = 0; +#endif ftpdlogwtmp(ttyline, "", ""); if (doutmp) logout(utmp.ut_line); +#if defined(KERBEROS) + if (!notickets && krbtkfile_env) + unlink(krbtkfile_env); +#endif } pw = NULL; logged_in = 0; @@ -784,9 +823,211 @@ dochroot = 0; } +#ifdef USE_PAM +/* + * PAM authentication, now using the PAM's async feature. + */ +static int PAM_conv (int num_msg, const struct pam_message **msg, + struct pam_response **resp, void *appdata_ptr) +{ + struct pam_response *repl = NULL; + int retval, count = 0, replies = 0; + int size = sizeof(struct pam_response); + +#define GET_MEM \ + if (!(repl = realloc(repl, size))) \ + return PAM_CONV_ERR; \ + size += sizeof(struct pam_response) +#define COPY_STRING(s) (s) ? strdup(s) : NULL + + (void) appdata_ptr; + retval = PAM_SUCCESS; + for (count = 0; count < num_msg; count++) { + int savemsg = 0; + + switch (msg[count]->msg_style) { + case PAM_PROMPT_ECHO_ON: + GET_MEM; + repl[replies].resp_retcode = PAM_SUCCESS; + repl[replies].resp = COPY_STRING(PAM_username); + replies++; + break; + case PAM_PROMPT_ECHO_OFF: + GET_MEM; + if (PAM_password == 0) { + savemsg = 1; + retval = PAM_CONV_AGAIN; + } else { + repl[replies].resp_retcode = PAM_SUCCESS; + repl[replies].resp = COPY_STRING(PAM_password); + replies++; + } + break; + case PAM_TEXT_INFO: + savemsg = 1; + break; + case PAM_ERROR_MSG: + default: + /* Must be an error of some sort... */ + retval = PAM_CONV_ERR; + } + + if (savemsg) { + char *sp; + + if (PAM_message) { + /* XXX: make sure we split newlines correctly */ + lreply(331, "%s", PAM_message); + free(PAM_message); + } + PAM_message = COPY_STRING(msg[count]->msg); + + /* Remove trailing `: ' */ + sp = PAM_message + strlen(PAM_message); + while (sp > PAM_message && strchr(" \t\n:", *--sp)) + *sp = '\0'; + } + + /* In case of error, drop responses and return */ + if (retval) { + _pam_drop_reply(repl, replies); + return retval; + } + } + if (repl) + *resp = repl; + return PAM_SUCCESS; +} + +static struct pam_conv PAM_conversation = { + &PAM_conv, + NULL +}; + +static int pam_doit(void) +{ + char *user; + int error; + + error = pam_authenticate(pamh, 0); + if (error == PAM_CONV_AGAIN || error == PAM_INCOMPLETE) { + /* Avoid overly terse passwd messages */ + if (PAM_message && !strcasecmp(PAM_message, "password")) { + free(PAM_message); + PAM_message = 0; + } + if (PAM_message == 0) { + reply(331, "Password required for %s.", PAM_username); + } else { + reply(331, "%s", PAM_message); + free(PAM_message); + PAM_message = 0; + } + return 1; + } + if (error == PAM_SUCCESS) { + /* Alright, we got it */ + error = pam_acct_mgmt(pamh, 0); + if (error == PAM_SUCCESS) + error = pam_open_session(pamh, 0); + if (error == PAM_SUCCESS) + error = pam_setcred(pamh, PAM_ESTABLISH_CRED); + if (error == PAM_SUCCESS) + error = pam_get_item(pamh, PAM_USER, (const void **) &user); + if (error == PAM_SUCCESS) { + if (strcmp(user, "ftp") == 0) { + guest = 1; + } + pw = sgetpwnam(user); + } + if (error == PAM_SUCCESS && pw) + PAM_accepted = 1; + } + + return (error == PAM_SUCCESS); +} + + +static void authentication_setup(const char *username) +{ + int error; + + if (pamh != 0) { + pam_end(pamh, PAM_ABORT); + pamh = 0; + } + + if (PAM_username) + free(PAM_username); + PAM_username = strdup(username); + PAM_password = 0; + PAM_message = 0; + PAM_accepted = 0; + + error = pam_start("ftp", PAM_username, &PAM_conversation, &pamh); + if (error == PAM_SUCCESS) + error = pam_set_item(pamh, PAM_RHOST, remotehost); + if (error != PAM_SUCCESS) { + reply(550, "Authentication failure"); + pam_end(pamh, error); + pamh = 0; + } + + if (pamh && !pam_doit()) + reply(550, "Authentication failure"); +} + +static int authenticate(char *passwd) +{ + if (PAM_accepted) + return 1; + + if (pamh == 0) + return 0; + + PAM_password = passwd; + pam_doit(); + PAM_password = 0; + return PAM_accepted; +} + +#else /* !USE_PAM */ +static int authenticate(char *passwd) +{ + if (pw == NULL) { + useconds_t us; + + /* Sleep between 1 and 3 seconds to emulate a crypt. */ +#ifndef __linux__ + us = arc4random() % 3000000; +#else + us = random() % 3000000; +#endif + usleep(us); + return 0; + } + +#if defined(KERBEROS) + if (klogin(pw, "", hostname, passwd) == 0) + return 1; +#endif +#ifdef SKEY + if (skey_haskey(pw->pw_name) == 0 && + (skey_passcheck(pw->pw_name, passwd) != -1)) + return 1; +#endif + /* the strcmp does not catch null passwords! */ + if (pw == NULL || *pw->pw_passwd == '\0' || + strcmp(crypt(passwd, pw->pw_passwd), pw->pw_passwd)) + return 0; /* failure */ + + return 1; +} +#endif /* !USE_PAM */ + + void pass(char *passwd) { - int rval; FILE *fd; static char homedir[MAXPATHLEN]; char rootdir[MAXPATHLEN]; @@ -797,84 +1038,54 @@ return; } askpasswd = 0; +#ifndef USE_PAM if (!guest) { /* "ftp" is only account allowed no password */ - if (pw == NULL) { - useconds_t us; - - /* Sleep between 1 and 3 seconds to emulate a crypt. */ -#ifndef __linux__ - us = arc4random() % 3000000; -#else - us = random() % 3000000; -#endif - usleep(us); - rval = 1; /* failure below */ - goto skip; - } -#if defined(KERBEROS) - rval = klogin(pw, "", hostname, passwd); - if (rval == 0) - goto skip; -#endif -#ifdef SKEY - if (skey_haskey(pw->pw_name) == 0 && - (skey_passcheck(pw->pw_name, passwd) != -1)) { - rval = 0; - goto skip; - } #endif - /* the strcmp does not catch null passwords! */ - if (strcmp(crypt(passwd, pw->pw_passwd), pw->pw_passwd) || - *pw->pw_passwd == '\0') { - rval = 1; /* failure */ - goto skip; - } - rval = 0; - -skip: /* - * If rval == 1, the user failed the authentication check - * above. If rval == 0, either Kerberos or local authentication - * succeeded. + * Try to authenticate the user */ - if (rval) { + if (!authenticate(passwd)) { reply(530, "Login incorrect."); if (logging) - syslog(LOG_NOTICE, + syslog(LOG_FTP | LOG_NOTICE, "FTP LOGIN FAILED FROM %s, %s", remotehost, curname); pw = NULL; if (login_attempts++ >= 5) { - syslog(LOG_NOTICE, + syslog(LOG_FTP | LOG_NOTICE, "repeated login failures from %s", remotehost); exit(0); } return; } +#ifdef USE_PAM + if (guest) { +#else } else { +#endif /* Save anonymous' password. */ guestpw = strdup(passwd); if (guestpw == (char *)NULL) fatal("Out of memory"); } login_attempts = 0; /* this time successful */ -#ifdef USE_SHADOW +#if defined(USE_SHADOW) && !defined(USE_PAM) switch (isexpired(spw)) { case 0: /* success */ break; case 1: - syslog(LOG_NOTICE, "expired password from %s, %s", + syslog(LOG_FTP | LOG_NOTICE, "expired password from %s, %s", remotehost, pw->pw_name); reply(530, "Please change your password and try again."); return; case 2: - syslog(LOG_NOTICE, "inactive login from %s, %s", + syslog(LOG_FTP | LOG_NOTICE, "inactive login from %s, %s", remotehost, pw->pw_name); reply(530, "Login inactive -- contact administrator."); return; case 3: - syslog(LOG_NOTICE, "expired login from %s, %s", + syslog(LOG_FTP | LOG_NOTICE, "expired login from %s, %s", remotehost, pw->pw_name); reply(530, "Account expired -- contact administrator."); return; @@ -991,7 +1202,8 @@ setproctitle("%s", proctitle); #endif /* HASSETPROCTITLE */ if (logging) - syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s, %s", + syslog(LOG_FTP | LOG_INFO, + "ANONYMOUS FTP LOGIN FROM %s, %s", remotehost, passwd); } else { reply(230, "User %s logged in.", pw->pw_name); @@ -1001,7 +1213,7 @@ setproctitle("%s", proctitle); #endif /* HASSETPROCTITLE */ if (logging) - syslog(LOG_INFO, "FTP LOGIN FROM %s as %s", + syslog(LOG_FTP | LOG_INFO, "FTP LOGIN FROM %s as %s", remotehost, pw->pw_name); } (void) umask(defumask); @@ -1064,7 +1276,7 @@ goto done; } } - dout = dataconn(name, st.st_size, "w"); + dout = dataconn(name, st.st_size, "w", 0); if (dout == NULL) goto done; time(&start); @@ -1088,6 +1300,9 @@ struct stat st; int fd; + if (restart_point && *mode != 'a') + mode = "r+"; + if (unique && stat(name, &st) == 0) { char *nam; @@ -1097,8 +1312,6 @@ return; } name = nam; - if (restart_point) - mode = "r+"; fout = fdopen(fd, mode); } else fout = fopen(name, mode); @@ -1139,7 +1352,7 @@ goto done; } } - din = dataconn(name, (off_t)-1, "r"); + din = dataconn(name, (off_t)-1, "r", unique); if (din == NULL) goto done; if (receive_data(din, fout) == 0) { @@ -1194,7 +1407,7 @@ #ifdef IP_TOS on = IPTOS_THROUGHPUT; if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0) - syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); + syslog(LOG_FTP | LOG_WARNING, "setsockopt (IP_TOS): %m"); #endif #ifdef TCP_NOPUSH /* @@ -1205,13 +1418,13 @@ */ on = 1; if (setsockopt(s, IPPROTO_TCP, TCP_NOPUSH, (char *)&on, sizeof on) < 0) - syslog(LOG_WARNING, "setsockopt (TCP_NOPUSH): %m"); + syslog(LOG_FTP | LOG_WARNING, "setsockopt (TCP_NOPUSH): %m"); #endif #if 0 /* Respect the user's settings */ #ifdef SO_SNDBUF on = 65536; if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&on, sizeof on) < 0) - syslog(LOG_WARNING, "setsockopt (SO_SNDBUF): %m"); + syslog(LOG_FTP | LOG_WARNING, "setsockopt (SO_SNDBUF): %m"); #endif #endif @@ -1227,7 +1440,7 @@ return (NULL); } -static FILE * dataconn(const char *name, off_t size, const char *mode) +static FILE * dataconn(const char *name, off_t size, const char *mode, int stou) { char sizebuf[32]; FILE *file; @@ -1236,8 +1449,8 @@ file_size = size; byte_count = 0; if (size != (off_t) -1) { - (void) snprintf(sizebuf, sizeof(sizebuf), " (%lld bytes)", - (quad_t) size); + (void) snprintf(sizebuf, sizeof(sizebuf), " (%jd bytes)", + (intmax_t) size); } else sizebuf[0] = '\0'; if (pdata >= 0) { @@ -1262,6 +1475,7 @@ pdata = -1; return (NULL); } +#ifdef BREAKRFC if (from.sin_addr.s_addr != his_addr.sin_addr.s_addr) { perror_reply(435, "Can't build data connection"); (void) close(pdata); @@ -1269,6 +1483,7 @@ pdata = -1; return (NULL); } +#endif (void) close(pdata); pdata = s; #ifdef IP_TOS @@ -1276,13 +1491,24 @@ (void) setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)); #endif - reply(150, "Opening %s mode data connection for '%s'%s.", - type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf); + if (stou) { + reply(150, "FILE: %s", name); + } else { + reply(150, + "Opening %s mode data connection for '%s'%s.", + type == TYPE_A ? "ASCII" : "BINARY", name, + sizebuf); + } return (fdopen(pdata, mode)); } if (data >= 0) { - reply(125, "Using existing data connection for '%s'%s.", - name, sizebuf); + if (stou) { + reply(125, "FILE: %s", name); + } else { + reply(125, + "Using existing data connection for '%s'%s.", + name, sizebuf); + } usedefault = 1; return (fdopen(data, mode)); } @@ -1309,12 +1535,14 @@ data = -1; return NULL; } +#ifdef BREAKRFC if (data_dest.sin_addr.s_addr != his_addr.sin_addr.s_addr) { perror_reply(435, "Can't build data connection"); (void) fclose(file); data = -1; return NULL; } +#endif while (connect(data, (struct sockaddr *)&data_dest, sizeof(data_dest)) < 0) { if (errno == EADDRINUSE && retry < swaitmax) { @@ -1327,8 +1555,14 @@ data = -1; return (NULL); } - reply(150, "Opening %s mode data connection for '%s'%s.", - type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf); + if (stou) { + reply(150, "FILE: %s", name); + } else { + reply(150, + "Opening %s mode data connection for '%s'%s.", + type == TYPE_A ? "ASCII" : "BINARY", name, + sizebuf); + } return (file); } @@ -1383,7 +1617,7 @@ buf = mmap(0, filesize, PROT_READ, MAP_SHARED, filefd, (off_t)0); if (buf==MAP_FAILED || buf==NULL) { - syslog(LOG_WARNING, "mmap(%lu): %m", + syslog(LOG_FTP | LOG_WARNING, "mmap(%lu): %m", (unsigned long)filesize); goto oldway; } @@ -1655,8 +1889,8 @@ (void)printf("\r\n"); (void)fflush(stdout); if (debug) { - syslog(LOG_DEBUG, "<--- %d ", n); - vsyslog(LOG_DEBUG, fmt, ap); + syslog(LOG_FTP | LOG_DEBUG, "<--- %d ", n); + vsyslog(LOG_FTP | LOG_DEBUG, fmt, ap); } } @@ -1681,8 +1915,8 @@ (void)printf("\r\n"); (void)fflush(stdout); if (debug) { - syslog(LOG_DEBUG, "<--- %d- ", n); - vsyslog(LOG_DEBUG, fmt, ap); + syslog(LOG_FTP | LOG_DEBUG, "<--- %d- ", n); + vsyslog(LOG_FTP | LOG_DEBUG, fmt, ap); } } @@ -1758,15 +1992,21 @@ void replydirname(const char *name, const char *message) { + char *p, *ep; char npath[MAXPATHLEN]; - int i; - for (i = 0; *name != '\0' && i < (int)sizeof(npath) - 1; i++, name++) { - npath[i] = *name; - if (*name == '"') - npath[++i] = '"'; + p = npath; + ep = &npath[sizeof(npath) - 1]; + while (*name) { + if (*name == '"' && ep - p >= 2) { + *p++ = *name++; + *p++ = '"'; + } else if (ep - p >= 1) + *p++ = *name++; + else + break; } - npath[i] = '\0'; + *p = '\0'; reply(257, "\"%s\" %s", npath, message); } @@ -1838,7 +2078,7 @@ #endif /* HASSETPROCTITLE */ if (logging) - syslog(LOG_INFO, "connection from %s", remotehost); + syslog(LOG_FTP | LOG_INFO, "connection from %s", remotehost); } /* @@ -1847,22 +2087,8 @@ */ void dologout(int status) { - sigset_t allsigs; - transflag = 0; - - if (logged_in) { - sigfillset(&allsigs); - sigprocmask(SIG_BLOCK, &allsigs, NULL); - (void) seteuid((uid_t)0); - ftpdlogwtmp(ttyline, "", ""); - if (doutmp) - logout(utmp.ut_line); -#if defined(KERBEROS) - if (!notickets && krbtkfile_env) - unlink(krbtkfile_env); -#endif - } + end_login(); /* beware of flushing buffers after a SIGPIPE */ _exit(status); } @@ -1891,11 +2117,11 @@ } if (strcmp(cp, "STAT\r\n") == 0) { if (file_size != (off_t) -1) - reply(213, "Status: %qd of %qd bytes transferred", - (quad_t) byte_count, (quad_t) file_size); + reply(213, "Status: %jd of %jd bytes transferred", + (intmax_t) byte_count, (intmax_t) file_size); else - reply(213, "Status: %qd bytes transferred", - (quad_t)byte_count); + reply(213, "Status: %jd bytes transferred", + (intmax_t)byte_count); } errno = save_errno; } @@ -2101,7 +2327,7 @@ if (S_ISREG(st.st_mode)) { if (dout == NULL) { - dout = dataconn("file list", (off_t)-1, "w"); + dout = dataconn("file list", (off_t)-1, "w", 0); if (dout == NULL) goto out; transflag++; @@ -2143,7 +2369,7 @@ S_ISREG(st.st_mode))) { if (dout == NULL) { dout = dataconn("file list", (off_t)-1, - "w"); + "w", 0); if (dout == NULL) goto out; transflag++; @@ -2238,13 +2464,15 @@ if (hp) { if (!hosts_ctl("ftpd", hp->h_name, addr, STRING_UNKNOWN)) { - syslog(LOG_NOTICE, "tcpwrappers rejected: %s [%s]", + syslog(LOG_FTP | LOG_NOTICE, + "tcpwrappers rejected: %s [%s]", hp->h_name, addr); return (0); } } else { if (!hosts_ctl("ftpd", STRING_UNKNOWN, addr, STRING_UNKNOWN)) { - syslog(LOG_NOTICE, "tcpwrappers rejected: [%s]", addr); + syslog(LOG_FTP | LOG_NOTICE, + "tcpwrappers rejected: [%s]", addr); return (0); } } --- linux-ftpd-0.17.orig/ftpd/logwtmp.c +++ linux-ftpd-0.17/ftpd/logwtmp.c @@ -41,7 +41,6 @@ "$Id: logwtmp.c,v 1.5 1999/07/16 00:34:29 dholland Exp $"; #include -#include #include #include @@ -49,6 +48,7 @@ #include #include #include +#include #include "extern.h" static int fd = -1; --- linux-ftpd-0.17.orig/support/Makefile +++ linux-ftpd-0.17/support/Makefile @@ -1,6 +1,6 @@ include ../MCONFIG -OBJS=daemon.o setproctitle.o isexpired.o vis.o +OBJS=setproctitle.o isexpired.o vis.o all: libsupport.a @@ -16,4 +16,3 @@ rm -f *.o libsupport.a setproctitle.o: setproctitle.h -daemon.o: daemon.h --- linux-ftpd-0.17.orig/support/setproctitle.c +++ linux-ftpd-0.17/support/setproctitle.c @@ -139,7 +139,7 @@ (void) strcpy(Argv[0], buf); p = &Argv[0][i]; while (p < LastArgv) - *p++ = ' '; + *p++ = '\0'; Argv[1] = NULL; } debian/patches/020-support_ipv6.diff0000644000000000000000000004544211547142265014446 0ustar Description: Activate support for IPv6 transport. This patch supplies working services for: . 1. Mixed IPv4 and IPv6 in inetd mode. . 2. Mixed IPv4 and IPv6 in standalone daemon mode. . 3. Selectable options '-4' and '-6' to activate a single address family. . 4. Registration in wtmp of the caller's address structure. This field in 'struct utmp' was earlier ignored, as it it an extension particular to Linux. . 5. Implementation of ABOR for use in idle state. . 6. Conversion of second time length in case a compatibility layer between 32 bits and 64 bits are in effect. . Testing was performed using xinetd and net.ipv6.bindv6only=1, on architectures i386 and amd64. Author: Mats Erik Andersson X-Depends: linux-ftpd-0.17/debian/patches/16-family_independence.diff X-Comment: This code is fully independent of any USAGI code, which is in use by the OpenBSD strand of this software. Forwarded: not-needed Last-Update: 2011-04-06 --- linux-ftpd-0.17.debian/ftpd/extern.h 2010-04-25 21:52:13.000000000 +0200 +++ linux-ftpd-0.17/ftpd/extern.h 2011-04-06 20:39:37.000000000 +0200 @@ -35,6 +35,8 @@ * $Id: extern.h,v 1.5 1999/07/16 01:12:54 dholland Exp $ */ +struct sockaddr_storage; + void blkfree __P((char **)); char **copyblk __P((char **)); void cwd __P((const char *)); @@ -44,12 +46,12 @@ void fatal __P((const char *)); int ftpd_pclose __P((FILE *)); FILE *ftpd_popen __P((char *, const char *)); int ftpd_getline __P((char *, int, FILE *)); -void ftpdlogwtmp __P((const char *, const char *, const char *)); +void ftpdlogwtmp __P((const char *, const char *, const char *, const struct sockaddr_storage *)); void lreply __P((int, const char *, ...)); void makedir __P((char *)); void nack __P((const char *)); void pass __P((char *)); -void passive __P((void)); +void passive __P((int)); void perror_reply __P((int, const char *)); void pwd __P((void)); void removedir __P((char *)); @@ -61,6 +63,7 @@ void send_file_list __P((const char *)); void statcmd __P((void)); void statfilecmd __P((char *)); void store __P((const char *, const char *, int)); +int test_eprt_string __P((char *)); void upper __P((char *)); void user __P((char *)); void yyerror __P((char *)); --- linux-ftpd-0.17.debian/ftpd/ftpcmd.y 2010-04-30 14:45:33.000000000 +0200 +++ linux-ftpd-0.17/ftpd/ftpcmd.y 2011-04-06 20:40:27.000000000 +0200 @@ -75,7 +75,7 @@ char ftpcmd_rcsid[] = #include "extern.h" -extern struct sockaddr_in data_dest; +extern struct sockaddr_storage data_dest; extern int logged_in; extern struct passwd *pw; extern int guest; @@ -92,7 +92,9 @@ extern int usedefault; extern int transflag; extern char tmpline[]; extern int portcheck; -extern struct sockaddr_in his_addr; +extern int use_ipv6; +extern int use_ipv4; +extern struct sockaddr_storage his_addr; off_t restart_point; @@ -167,6 +169,7 @@ cmp_addresses(struct sockaddr * left, st ABOR DELE CWD LIST NLST SITE STAT HELP NOOP MKD RMD PWD CDUP STOU SMNT SYST SIZE MDTM + EPRT EPSV UMASK IDLE CHMOD @@ -177,7 +180,7 @@ cmp_addresses(struct sockaddr * left, st %type check_login octal_number byte_size %type struct_code mode_code type_code form_code -%type pathstring pathname password username +%type pathstring pathname password username transport %type host_port %start cmd_list @@ -219,6 +222,7 @@ cmd reply(500, "Illegal PORT rejected (reserved port)."); } else if (portcheck && + data_dest.ss_family == his_addr.ss_family && cmp_addresses((struct sockaddr *) &data_dest, (struct sockaddr *) &his_addr)) { usedefault = 1; @@ -235,10 +239,49 @@ cmd } } } + | EPRT check_login SP transport CRLF + { + if ($2) { + int rc = test_eprt_string($4); + + switch (rc) { + case 1: /* Syntax error. */ + reply(500, "Syntax error, command unrecognized."); + break; + case 2: /* Protocol family error. */ + reply(522, "Network protocol not supported, use (%c).", + his_addr.ss_family == AF_INET6 ? '2' : '1'); + break; + case 3: /* Invalid address and port combination. */ + reply(501, "Illegal EPRT rejected (address wrong)."); + break; + case 0: /* Successful parsing. */ + reply(200, "EPRT command successful."); + } + } + } | PASV check_login CRLF { if ($2) { - passive(); + passive(0); + } + } + | EPSV check_login CRLF + { + if ($2) { + passive(1); + } + } + | EPSV check_login SP NUMBER CRLF + { + if ($2) { + if ( ($4 == 1 && his_addr.ss_family == AF_INET) + || ($4 == 2 && his_addr.ss_family == AF_INET6) ) + passive(1); + else + reply(501, + "Not a compatible address family, use (%c)", + his_addr.ss_family == AF_INET6 ? '2' : '1'); } } | TYPE check_login SP type_code CRLF @@ -395,8 +438,16 @@ cmd } | ABOR check_login CRLF { - if ($2) - reply(225, "ABOR command successful."); + if ($2) { + if (pdata >= 0) { + close(pdata); + pdata = -1; + usedefault = 1; + reply(226, "Closing data connection."); + } else { + reply(226, "ABOR command caused no action."); + } + } } | CWD check_login CRLF { @@ -675,10 +726,16 @@ host_port snprintf(port, sizeof(port), "%ju", 256 * $9 + $11); memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET; /* Enable mapped addressing? */ + hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST | AI_NUMERICSERV; + if (his_addr.ss_family == AF_INET6) { + hints.ai_family = AF_INET6; + if (use_ipv4) + hints.ai_flags |= AI_V4MAPPED; + } + if (getaddrinfo(ipaddr, port, &hints, &aiptr)) { $$ = 1; } else { @@ -692,6 +749,10 @@ host_port } ; +transport + : STRING + ; + form_code : N { @@ -890,6 +951,9 @@ struct tab cmdtab[] = { /* In order def { "QUIT", QUIT, ARGS, 1, "(terminate service)", }, { "PORT", PORT, ARGS, 1, " b0, b1, b2, b3, b4" }, { "PASV", PASV, ARGS, 1, "(set server in passive mode)" }, + /* Extensions introduced in RFC 2428: EPRT, EPSV. */ + { "EPRT", EPRT, STR1, 1, " addr_fam addr port " }, + { "EPSV", EPSV, ARGS, 1, "[ addr-fam ]"}, { "TYPE", TYPE, ARGS, 1, " [ A | E | I | L ]" }, { "STRU", STRU, ARGS, 1, "(specify file structure)" }, { "MODE", MODE, ARGS, 1, "(specify transfer mode)" }, --- linux-ftpd-0.17.debian/ftpd/ftpd.8 2010-04-25 21:52:13.000000000 +0200 +++ linux-ftpd-0.17/ftpd/ftpd.8 2010-05-08 01:23:15.000000000 +0200 @@ -64,6 +64,10 @@ service specification; see .Pp Available options: .Bl -tag -width Ds +.It Fl 4 +Use IPv4 addressing only. Th default is to offer service for both families, IPv6 and IPv4. +.It Fl 6 +Only provide IPv6 addressing capability. .It Fl A Permit only anonymous ftp connections or accounts listed in .Pa /etc/ftpchroot. @@ -180,6 +184,8 @@ The case of the requests is ignored. .It CDUP Ta "change to parent of current working directory" .It CWD Ta "change working directory" .It DELE Ta "delete a file" +.It EPRT Ta "specify data connection port, either IPv4 or IPv6" +.It EPSV Ta "ask for a server port for fetching data" .It HELP Ta "give help information" .It LIST Ta "give list files in a directory" Pq Dq Li "ls -lgA" .It MKD Ta "make a directory" --- linux-ftpd-0.17.debian/ftpd/ftpd.c 2010-04-30 14:46:19.000000000 +0200 +++ linux-ftpd-0.17/ftpd/ftpd.c 2011-04-06 20:43:42.000000000 +0200 @@ -148,12 +148,12 @@ static char version[sizeof(versionpre)+s extern off_t restart_point; extern char cbuf[]; -struct sockaddr_in server_addr; -struct sockaddr_in ctrl_addr; -struct sockaddr_in data_source; -struct sockaddr_in data_dest; -struct sockaddr_in his_addr; -struct sockaddr_in pasv_addr; +struct sockaddr_storage server_addr; +struct sockaddr_storage ctrl_addr; +struct sockaddr_storage data_source; +struct sockaddr_storage data_dest; +struct sockaddr_storage his_addr; +struct sockaddr_storage pasv_addr; int daemon_mode = 0; int data; @@ -169,6 +169,8 @@ int timeout = 900; /* timeout after 1 int maxtimeout = 7200; /* don't allow idle time to be set beyond 2 hours */ int numeric_hosts = 0; /* log numeric IP rather than doing lookup */ int logging; +int use_ipv6 = 1; /* Let listening socket use IPv6. */ +int use_ipv4 = 1; /* Let listening socket use IPv4. */ int high_data_ports = 0; int anon_only = 0; int multihome = 0; @@ -371,7 +373,7 @@ main(int argc, char *argv[], char **envp socklen_t addrlen; char *cp, line[LINE_MAX]; FILE *fd; - const char *argstr = "AdDhlMnSt:T:u:UvP"; + const char *argstr = "AdDhlMnSt:T:u:UvP46"; struct addrinfo hints, *aiptr; #ifdef __linux__ @@ -471,6 +473,16 @@ main(int argc, char *argv[], char **envp debug = 1; break; + case '6': + use_ipv6 = 1; + use_ipv4 = 0; + break; + + case '4': + use_ipv6 = 0; + use_ipv4 = 1; + break; + default: warnx("unknown flag -%c ignored", optopt); break; @@ -517,7 +529,7 @@ main(int argc, char *argv[], char **envp memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; hints.ai_socktype = SOCK_STREAM; - hints.ai_family = AF_INET; + hints.ai_family = use_ipv6 ? AF_INET6 : AF_INET; if ((rc = getaddrinfo(NULL, "ftp", &hints, &aiptr))) { syslog(LOG_FTP | LOG_ERR, @@ -535,6 +547,16 @@ main(int argc, char *argv[], char **envp (char *)&on, sizeof(on)) < 0) syslog(LOG_FTP | LOG_ERR, "control setsockopt: %m");; + /* Should the listening control socket be dual stacked? + * Only one case needs this: use_ipv6 = use_ipv4 = 1. */ + if (ai->ai_family == AF_INET6 && use_ipv4) { + socklen_t off = 0; + + if (setsockopt(ctl_sock, IPPROTO_IPV6, IPV6_V6ONLY, + &off, sizeof(off))) + syslog(LOG_FTP | LOG_ERR, "control setsockopt: %m"); + } + if (bind(ctl_sock, ai->ai_addr, ai->ai_addrlen)) { close(ctl_sock); continue; @@ -894,7 +916,7 @@ static void end_login(void) pam_end(pamh, error); pamh = 0; #endif - ftpdlogwtmp(ttyline, "", ""); + ftpdlogwtmp(ttyline, "", "", NULL); if (doutmp) logout(utmp.ut_line); #if defined(KERBEROS) @@ -1186,15 +1208,39 @@ void pass(char *passwd) (void) initgroups(pw->pw_name, pw->pw_gid); /* open wtmp before chroot */ - ftpdlogwtmp(ttyline, pw->pw_name, remotehost); + ftpdlogwtmp(ttyline, pw->pw_name, remotehost, &his_addr); /* open utmp before chroot */ if (doutmp) { memset((void *)&utmp, 0, sizeof(utmp)); + +#if __WORDSIZE == 64 && __WORDSIZE_COMPAT32 + /* Length of 'time_t' is 64 bits, but 'utmp.ut_time' has 32 bits.*/ + time_t now; + + (void)time(&now); + utmp.ut_time = now & 0xffffffff; /* Discard the upper 32 bits. */ +#else + /* Equal size time representations. */ (void)time(&utmp.ut_time); +#endif /* Mixed 64 and 32 bits time */ + (void)strncpy(utmp.ut_name, pw->pw_name, sizeof(utmp.ut_name)); (void)strncpy(utmp.ut_host, remotehost, sizeof(utmp.ut_host)); (void)strncpy(utmp.ut_line, ttyline, sizeof(utmp.ut_line)); + switch (his_addr.ss_family) { + case AF_INET6: + memcpy(&utmp.ut_addr, + &((struct sockaddr_in6 *) &his_addr)->sin6_addr, + sizeof(struct in6_addr)); + break; + case AF_INET: + memcpy(&utmp.ut_addr, + &((struct sockaddr_in *) &his_addr)->sin_addr, + sizeof(struct in_addr)); + default: + break; + } login(&utmp); } @@ -1465,6 +1511,7 @@ done: static FILE * getdatasock(const char *mode) { int on = 1, s, t, tries; + socklen_t off = 0; sigset_t allsigs; if (data >= 0) @@ -1472,12 +1519,17 @@ static FILE * getdatasock(const char *mo sigfillset(&allsigs); sigprocmask (SIG_BLOCK, &allsigs, NULL); (void) seteuid((uid_t)0); - s = socket(his_addr.sin_family, SOCK_STREAM, 0); + s = socket(his_addr.ss_family, SOCK_STREAM, 0); if (s < 0) goto bad; if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)) < 0) goto bad; + if (his_addr.ss_family == AF_INET6 && use_ipv4) + if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, + &off, sizeof(off))) + syslog(LOG_FTP | LOG_ERR, "getdatasock(), setsockopt: %m"); + /* anchor socket to avoid multi-homing problems */ memcpy(&data_source, &ctrl_addr, sizeof(data_source)); set_port((struct sockaddr *) &data_source, data_port); @@ -1568,7 +1620,6 @@ static FILE * dataconn(const char *name, return (NULL); } #ifdef BREAKRFC - //if (from.sin_addr.s_addr != his_addr.sin_addr.s_addr) { if (cmp_addresses((struct sockaddr *) &from, (struct sockaddr *) &his_addr)) { perror_reply(435, "Can't build data connection"); @@ -1636,7 +1687,6 @@ static FILE * dataconn(const char *name, return NULL; } #ifdef BREAKRFC - //if (data_dest.sin_addr.s_addr != his_addr.sin_addr.s_addr) { if (cmp_addresses((struct sockaddr *) &data_dest, (struct sockaddr *) &his_addr)) { perror_reply(435, "Can't build data connection"); @@ -2245,15 +2295,19 @@ static void myoob(int signo) errno = save_errno; } +#define IS_MAPPED_IPV4(a) \ + (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *) (a))->sin6_addr) || \ + IN6_IS_ADDR_V4COMPAT(&((struct sockaddr_in6 *) (a))->sin6_addr)) + /* * Note: a response of 425 is not mentioned as a possible response to * the PASV command in RFC959. However, it has been blessed as * a legitimate response by Jon Postel in a telephone conversation * with Rick Adams on 25 Jan 89. */ -void passive(void) +void passive(int extend) { - socklen_t len; + socklen_t len, off = 0; #ifdef IP_PORTRANGE int on; #else @@ -2266,11 +2320,15 @@ void passive(void) } if (pdata >= 0) close(pdata); - pdata = socket(his_addr.sin_family, SOCK_STREAM, 0); + pdata = socket(his_addr.ss_family, SOCK_STREAM, 0); if (pdata < 0) { perror_reply(425, "Can't open passive connection"); return; } + if (his_addr.ss_family == AF_INET6 && use_ipv4) + if (setsockopt(pdata, IPPROTO_IPV6, IPV6_V6ONLY, + &off, sizeof(off))) + syslog(LOG_FTP | LOG_ERR, "passive(), setsockopt: %m"); memcpy(&pasv_addr, &ctrl_addr, sizeof(pasv_addr)); @@ -2312,10 +2370,7 @@ void passive(void) #define UC(b) (((int) b) & 0xff) - if (((struct sockaddr *) &pasv_addr)->sa_family == AF_INET6) - reply(229, "Extended Passive Mode OK (|||%d|)", - get_port((struct sockaddr *) &pasv_addr)); - else { + if (!extend && (pasv_addr.ss_family == AF_INET || IS_MAPPED_IPV4(&pasv_addr))) { uint32_t ip4ad = get_ipv4address((struct sockaddr *) &pasv_addr); in_port_t port = get_port((struct sockaddr *) &pasv_addr); @@ -2323,6 +2378,9 @@ void passive(void) UC(ip4ad >> 24), UC(ip4ad >> 16), UC(ip4ad >> 8), UC(ip4ad), UC(port >> 8), UC(port)); + } else { + reply(229, "Extended Passive Mode OK (|||%d|)", + get_port((struct sockaddr *) &pasv_addr)); } #undef UC @@ -2337,6 +2395,93 @@ pasv_error: } /* + * test_eprt_string(char *) + * + * Parse the transport string used in EPRT command. + * + * Return values: + * + * 0: Success. Valid address in data_dest. + * 1: Syntax error. + * 2: Incorrect protocol family. + * 3: Invalid address, or port, specification. + */ +int test_eprt_string(char * trans) +{ + char delim, ipaddr[INET6_ADDRSTRLEN], portstr[12]; + int pf, port; + unsigned int j = 0; + struct addrinfo hints, *aiptr; + + /* Easy sanity checks first. */ + if ( ! trans || strlen(trans) < 10 ) + return 1; /* Syntax error. */ + + /* Parse the contents. */ + delim = *(trans++); + if ( *trans != '1' && *trans != '2') + return 2; /* Protocol family error. */ + + if ( *(trans+1) != delim ) + return 1; /* Syntax error. */ + + pf = *trans - '0'; /* The character is '1' or '2'. */ + + /* Check that address families match the claimed protocol. */ + if ((pf != 1 && his_addr.ss_family == AF_INET) + || (pf != 2 && his_addr.ss_family == AF_INET6)) + return 2; /* Protocol family error. */ + + trans += 2; /* Jump to IP address portion, and extract it. */ + while (*trans && (j < sizeof(ipaddr) - 1) && + strchr("0123456789abcdefABCDEF.:", *trans)) + ipaddr[j++] = *(trans++); + + ipaddr[j] = '\0'; + + if (*trans != delim) + return 1; /* Syntax error. */ + + ++trans; + + /* A port number should be next. */ + if (sscanf(trans, "%u", &port) != 1) + return 1; /* Syntax error. */ + + while (isdigit(*trans)) + ++trans; + + /* Last delimiter, at least one digit present by previous test. */ + if (*trans != delim) + return 1; /* Syntax error. */ + + /* All components are parsed. Now try establishing the address. */ + sprintf(portstr, "%d", port); + memset(&hints, 0, sizeof(hints)); + hints.ai_family = his_addr.ss_family; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST | AI_NUMERICSERV; + + if (getaddrinfo(ipaddr, portstr, &hints, &aiptr)) + return 3; /* Invalid address and port combination. */ + + /* Record the established address. */ + memcpy(&data_dest, aiptr->ai_addr, aiptr->ai_addrlen); + freeaddrinfo(aiptr); + + /* Close any previous passive socket. */ + if (pdata >= 0) { + close(pdata); + pdata = -1; + } + + /* Turn standard listening mechanism off. A valid address exists! */ + usedefault = 0; + + return 0; /* Success. */ +} /* test_eprt_string(char *) */ + +/* * Generate unique name for file with basename "local". * The file named "local" is already known to exist. * Generates failure reply on error. --- linux-ftpd-0.17.debian/ftpd/logwtmp.c 2010-04-25 21:52:13.000000000 +0200 +++ linux-ftpd-0.17/ftpd/logwtmp.c 2010-05-09 02:06:48.000000000 +0200 @@ -49,6 +49,7 @@ char logwtmp_rcsid[] = #include #include #include +#include #include "extern.h" static int fd = -1; @@ -59,7 +60,8 @@ static int fd = -1; * after login, but before logout). */ void -ftpdlogwtmp(const char *line, const char *name, const char *host) +ftpdlogwtmp(const char *line, const char *name, + const char *host, const struct sockaddr_storage *ss) { struct utmp ut; struct stat buf; @@ -72,10 +74,36 @@ ftpdlogwtmp(const char *line, const char ut.ut_type = *name ? USER_PROCESS : DEAD_PROCESS; ut.ut_pid = getpid(); #endif + +#if __WORDSIZE == 64 && __WORDSIZE_COMPAT32 + /* Length of 'time_t' is 64 bits, but 'ut.ut_time' has 32 bits.*/ + time_t now; + + (void)time(&now); + ut.ut_time = now & 0xffffffff; /* Discard the upper 32 bits. */ +#else + /* Equal size time representations. */ + (void)time(&ut.ut_time); +#endif /* Mixed 64 and 32 bits time */ + (void)strncpy(ut.ut_line, line, sizeof(ut.ut_line)); (void)strncpy(ut.ut_name, name, sizeof(ut.ut_name)); (void)strncpy(ut.ut_host, host, sizeof(ut.ut_host)); - (void)time(&ut.ut_time); + if (ss) { + switch (ss->ss_family) { + case AF_INET6: + memcpy(&ut.ut_addr, + &((const struct sockaddr_in6 *) ss)->sin6_addr, + sizeof(struct in6_addr)); + break; + case AF_INET: + memcpy(&ut.ut_addr, + &((const struct sockaddr_in *) ss)->sin_addr, + sizeof(struct in_addr)); + default: + break; + } + } if (write(fd, (char *)&ut, sizeof(struct utmp)) != sizeof(struct utmp)) (void)ftruncate(fd, buf.st_size); debian/patches/002-from_sarge.diff0000644000000000000000000001475311374740305014110 0ustar Description: Patches taken from linux-ftpd_0.17-20sarge2.diff.gz. Difference constructed against linux-ftpd_0.17-13.diff.gz. Author: Herber Xu Robert Millan Alberto Gonzalez Iniesta X-Comment: Contributions by Dean Gaudet and Paul Szabo. Forwarded: no Last-Update: 2006-09-25 diff -u linux-ftpd-0.17/ftpd/ftpcmd.y linux-ftpd-0.17/ftpd/ftpcmd.y --- linux-ftpd-0.17/ftpd/ftpcmd.y +++ linux-ftpd-0.17/ftpd/ftpcmd.y @@ -114,6 +114,7 @@ %union { intmax_t i; char *s; + const char *cs; } %token @@ -313,12 +314,12 @@ | LIST check_login CRLF { if ($2) - retrieve("/bin/ls -lgA", ""); + retrieve("/bin/ls -lA", ""); } | LIST check_login SP pathname CRLF { if ($2 && $4 != NULL) - retrieve("/bin/ls -lgA %s", $4); + retrieve("/bin/ls -lA %s", $4); if ($4 != NULL) free($4); } @@ -1053,7 +1054,7 @@ /* NOTREACHED */ } state = p->state; - yylval.s = (char *)p->name; /* XXX */ + yylval.cs = p->name; return (p->token); } break; @@ -1079,7 +1080,7 @@ /* NOTREACHED */ } state = p->state; - yylval.s = (char *) p->name; /* XXX */ + yylval.cs = p->name; return (p->token); } state = CMD; diff -u linux-ftpd-0.17/ftpd/ftpd.8 linux-ftpd-0.17/ftpd/ftpd.8 --- linux-ftpd-0.17/ftpd/ftpd.8 +++ linux-ftpd-0.17/ftpd/ftpd.8 @@ -46,7 +46,7 @@ Internet File Transfer Protocol server .Sh SYNOPSIS .Nm ftpd -.Op Fl AdDhlMPSU +.Op Fl AdDhlMnPSU .Op Fl T Ar maxtimeout .Op Fl t Ar timeout .Op Fl u Ar mask @@ -105,12 +105,8 @@ the IP number the client connected to, and located inside .Pa ~ftp is used instead. -.It Fl p -Disable passive mode ftp connections. This is useful if you are behind -a firewall that refuses connections to arbitrary high numbered ports. -Many ftp clients try passive mode first and do not always react gracefully -to a server that refuses connections to the port it asked the client to -connect to. +.It Fl n +Use numeric IP addresses in logs instead of doing hostname lookup. .It Fl P Permit illegal port numbers or addresses for PORT command initiated connects. By default @@ -369,7 +365,15 @@ (or whatever your .Xr ls command is linked to) -must be present. Note that if you're using a 2.2.* or later Linux kernel, +must be present. +In order to read +.Xr passwd 5 +and +.Xr group 5 , +the library +.Xr libnss_files.so.2 +is also needed. +Note that if you're using a 2.2.* or later Linux kernel, .Xr ld-linux.so.2 must be executable as well as readable (555). All other files should be mode 444. diff -u linux-ftpd-0.17/ftpd/ftpd.c linux-ftpd-0.17/ftpd/ftpd.c --- linux-ftpd-0.17/ftpd/ftpd.c +++ linux-ftpd-0.17/ftpd/ftpd.c @@ -165,7 +165,8 @@ #endif int debug = 0; int timeout = 900; /* timeout after 15 minutes of inactivity */ -int maxtimeout = 7200;/* don't allow idle time to be set beyond 2 hours */ +int maxtimeout = 7200; /* don't allow idle time to be set beyond 2 hours */ +int numeric_hosts = 0; /* log numeric IP rather than doing lookup */ int logging; int high_data_ports = 0; int anon_only = 0; @@ -312,7 +313,7 @@ socklen_t addrlen; char *cp, line[LINE_MAX]; FILE *fd; - const char *argstr = "AdDhlMSt:T:u:UvP"; + const char *argstr = "AdDhlMnSt:T:u:UvP"; struct hostent *hp; #ifdef __linux__ @@ -372,6 +373,10 @@ multihome = 1; break; + case 'n': + numeric_hosts = 1; + break; + case 'S': stats = 1; break; @@ -906,7 +911,6 @@ static int pam_doit(void) { - char *user; int error; error = pam_authenticate(pamh, 0); @@ -926,6 +930,8 @@ return 1; } if (error == PAM_SUCCESS) { + const void *vp; + /* Alright, we got it */ error = pam_acct_mgmt(pamh, 0); if (error == PAM_SUCCESS) @@ -933,8 +939,10 @@ if (error == PAM_SUCCESS) error = pam_setcred(pamh, PAM_ESTABLISH_CRED); if (error == PAM_SUCCESS) - error = pam_get_item(pamh, PAM_USER, (const void **) &user); + error = pam_get_item(pamh, PAM_USER, &vp); if (error == PAM_SUCCESS) { + const char *user = vp; + if (strcmp(user, "ftp") == 0) { guest = 1; } @@ -1151,6 +1159,13 @@ } strcpy(pw->pw_dir, "/"); setenv("HOME", "/", 1); + } + /* PSz 25 Aug 06 chdir for real users done after setting UID */ + if (seteuid((uid_t)pw->pw_uid) < 0) { + reply(550, "Can't set uid."); + goto bad; + } + if (guest || dochroot) { /* do nothing, handled above */ } else if (chdir(pw->pw_dir) < 0) { if (chdir("/") < 0) { reply(530, "User %s: can't change directory to %s.", @@ -1159,10 +1174,7 @@ } else lreply(230, "No directory! Logging in with home=/"); } - if (seteuid((uid_t)pw->pw_uid) < 0) { - reply(550, "Can't set uid."); - goto bad; - } + sigfillset(&allsigs); sigprocmask(SIG_UNBLOCK,&allsigs,NULL); @@ -1400,7 +1412,8 @@ goto bad; sleep(tries); } - (void) seteuid((uid_t)pw->pw_uid); +/* PSz 25 Aug 06 Check return status */ + if (seteuid((uid_t)pw->pw_uid) != 0) _exit(1); sigfillset(&allsigs); sigprocmask (SIG_UNBLOCK, &allsigs, NULL); @@ -1432,7 +1445,8 @@ bad: /* Return the real value of errno (close may change it) */ t = errno; - (void) seteuid((uid_t)pw->pw_uid); +/* PSz 25 Aug 06 Check return status */ + if (seteuid((uid_t)pw->pw_uid) != 0) _exit(1); sigfillset (&allsigs); sigprocmask (SIG_UNBLOCK, &allsigs, NULL); (void) close(s); @@ -1786,7 +1800,7 @@ int c; char line[LINE_MAX]; - (void)snprintf(line, sizeof(line), "/bin/ls -lgA %s", filename); + (void)snprintf(line, sizeof(line), "/bin/ls -lA %s", filename); fin = ftpd_popen(line, "r"); lreply(211, "status of %s:", filename); while ((c = getc(fin)) != EOF) { @@ -2063,10 +2077,11 @@ static void dolog(struct sockaddr_in *sn) { - struct hostent *hp = gethostbyaddr((char *)&sn->sin_addr, - sizeof(struct in_addr), AF_INET); + struct hostent *hp; - if (hp) + if (!numeric_hosts && + (hp = gethostbyaddr((char *)&sn->sin_addr, + sizeof(struct in_addr), AF_INET))) (void) strncpy(remotehost, hp->h_name, sizeof(remotehost)-1); else (void) strncpy(remotehost, inet_ntoa(sn->sin_addr), --- linux-ftpd-0.17.orig/ftpd/popen.c +++ linux-ftpd-0.17/ftpd/popen.c @@ -169,8 +169,13 @@ * XXX: this doesn't seem right... and shouldn't * we initgroups, or at least setgroups(0,0)? */ - setgid(getegid()); - setuid(i); + +/* + * PSz 25 Aug 06 Must check the return status of these setgid/setuid calls, + * see http://www.bress.net/blog/archives/34-setuid-madness.html + */ + if ( setgid(geteuid()) != 0 ) _exit(1); + if ( setuid(i) != 0 ) _exit(1); #ifndef __linux__ /* debian/patches/series0000644000000000000000000000044011735154014012031 0ustar 001-from_hamm.diff 002-from_sarge.diff 003-from_etch.diff 010-ftpd_csrf.diff 014-adjust_infrastruct.diff 016-family_independence.diff 020-support_ipv6.diff 024-failing_va_list.diff 026-support_glibc_bsd_and_gnu.diff 030-manpage_typos.diff 040-refine_config.diff 044-support_gnu_hurd.diff debian/patches/044-support_gnu_hurd.diff0000644000000000000000000000177211735154320015373 0ustar Description: Support GNU/Hurd. Since MAXPATHLEN and MAXHOSTNAMELEN are not prescribed by POSIX, GNU/Hurd need not specify these. Thus they are now assigned the default values as used on BSD systems. Author: Mats Erik Andersson Forwarded: no Last-Update: 2012-03-29 --- linux-ftpd-0.17.debian/ftpd/ftpd.c +++ linux-ftpd-0.17/ftpd/ftpd.c @@ -141,6 +141,17 @@ #endif #endif +/* POSIX does not requires these values, so GNU/Hurd + * needs them specified. They only occur statically. + * Use the BSD convention for these values. */ +#ifndef MAXPATHLEN +# define MAXPATHLEN 1024 +#endif + +#ifndef MAXHOSTNAMELEN +# define MAXHOSTNAMELEN 256 +#endif + static char versionpre[] = "Version 6.4/OpenBSD/Linux"; static char version[sizeof(versionpre)+sizeof(pkg)]; @@ -1314,7 +1325,7 @@ /* * Set home directory so that use of ~ (tilde) works correctly. */ - if (getcwd(homedir, MAXPATHLEN) != NULL) + if (getcwd(homedir, sizeof homedir) != NULL) setenv("HOME", homedir, 1); /* debian/patches/010-ftpd_csrf.diff0000644000000000000000000000666611374740305013741 0ustar Description: Fix cross-site request forgery (CSRF) attacks. Author: Ian Beckwith X-Original-Location: http://bugs.debian.org/cgi-bin/bugreport.cgi?msg=29;filename=ftpd-csrf.patch;att=1;bug=500278 X-Closes: Bug #500278 X-Comment: Recovered as interdiff between linux-ftpd_0.17-23.diff.gz and linux-ftpd_0.17-29.diff.gz. Forwarded: no Last-Update: 2008-10-17 --- linux-ftpd-0.17.orig/ftpd/extern.h +++ linux-ftpd-0.17/ftpd/extern.h @@ -43,7 +43,7 @@ void fatal __P((const char *)); int ftpd_pclose __P((FILE *)); FILE *ftpd_popen __P((char *, const char *)); -char *ftpd_getline __P((char *, int, FILE *)); +int ftpd_getline __P((char *, int, FILE *)); void ftpdlogwtmp __P((const char *, const char *, const char *)); void lreply __P((int, const char *, ...)); void makedir __P((char *)); diff -u linux-ftpd-0.17/ftpd/ftpcmd.y linux-ftpd-0.17/ftpd/ftpcmd.y --- linux-ftpd-0.17/ftpd/ftpcmd.y +++ linux-ftpd-0.17/ftpd/ftpcmd.y @@ -920,7 +920,7 @@ /* * getline - a hacked up version of fgets to ignore TELNET escape codes. */ -char * ftpd_getline(char *s, int n, FILE *iop) +int ftpd_getline(char *s, int n, FILE *iop) { int c; register char *cs; @@ -934,7 +934,7 @@ if (debug) syslog(LOG_FTP | LOG_DEBUG, "command: %s", s); tmpline[0] = '\0'; - return(s); + return(0); } if (c == 0) tmpline[0] = '\0'; @@ -965,11 +965,22 @@ } } *cs++ = c; - if (--n <= 0 || c == '\n') + if (--n <= 0) { + /* + * If command doesn't fit into buffer, discard the + * rest of the command and indicate truncation. + * This prevents the command to be split up into + * multiple commands. + */ + while (c != '\n' && (c = getc(iop)) != EOF) + ; + return (-2); + } + if (c == '\n') break; } if (c == EOF && cs == s) - return (NULL); + return (-1); *cs++ = '\0'; if (debug) { if (!guest && strncasecmp("pass ", s, 5) == 0) { @@ -989,7 +1000,7 @@ syslog(LOG_FTP | LOG_DEBUG, "command: %.*s", len, s); } } - return (s); + return (0); } void toolong(int signo) @@ -1018,9 +1029,14 @@ case CMD: (void) signal(SIGALRM, toolong); (void) alarm((unsigned) timeout); - if (ftpd_getline(cbuf, sizeof(cbuf)-1, stdin)==NULL) { - reply(221, "You could at least say goodbye."); - dologout(0); + n=ftpd_getline(cbuf, sizeof(cbuf)-1, stdin); + if (n == -1) { + reply(221, "You could at least say goodbye."); + dologout(0); + } else if (n == -2) { + reply(500, "Command too long."); + alarm(0); + continue; } (void) alarm(0); if ((cp = strchr(cbuf, '\r'))) { diff -u linux-ftpd-0.17/ftpd/ftpd.c linux-ftpd-0.17/ftpd/ftpd.c --- linux-ftpd-0.17/ftpd/ftpd.c +++ linux-ftpd-0.17/ftpd/ftpd.c @@ -2111,6 +2111,7 @@ static void myoob(int signo) { char *cp; + int ret; int save_errno = errno; (void)signo; @@ -2119,9 +2120,13 @@ if (!transflag) return; cp = tmpline; - if (ftpd_getline(cp, 7, stdin) == NULL) { + ret=ftpd_getline(cp, 7, stdin); + if (ret == -1) { reply(221, "You could at least say goodbye."); dologout(0); + } else if (ret == -2) { + /* Ignore truncated command */ + return; } upper(cp); if (strcmp(cp, "ABOR\r\n") == 0) { debian/patches/026-support_glibc_bsd_and_gnu.diff0000644000000000000000000001672211377011614017164 0ustar Description: Implement changes to support GNU/Hurd and GNU/kfreebsd. Several conditionals on '__linux__' are altered to react identical to '__GLIBC__' and '__GNU__'. This should produce working code also for the Debian ports GNU/kfreebsd and GNU/Hurd. . GNU/kfreebsd uses distinct options IP_PORTRANGE and IPV6_PORTRANGE depending on address family. . Use IP_TOS only for IPv4 when compiling for non-Linux. Author: Mats Erik Andersson Forwarded: not-needed Last-Update: 2010-05-25 --- linux-ftpd-0.17.debian/ftpd/extern.h +++ linux-ftpd-0.17/ftpd/extern.h @@ -74,7 +74,7 @@ struct utmp; void login(const struct utmp *); int logout(const char *line); -#ifdef __linux__ +#if defined(__linux__) || defined(__GLIBC__) || defined(__GNU__) #include "daemon.h" #include "setproctitle.h" #endif --- linux-ftpd-0.17.debian/ftpd/ftpcmd.y +++ linux-ftpd-0.17/ftpd/ftpcmd.y @@ -67,7 +67,7 @@ char ftpcmd_rcsid[] = #include #include -#ifndef __linux__ +#if !defined(__linux__) && !defined(__GLIBC__) && !defined(__GNU__) #include #else #define TM_YEAR_BASE 1900 @@ -851,7 +851,7 @@ pathname */ if (logged_in && $1 && strchr($1, '~') != NULL) { glob_t gl; -#ifdef __linux__ +#if defined(__linux__) || defined(__GLIBC__) || defined(__GNU__) /* see popen.c */ int flags = GLOB_NOCHECK; #else --- linux-ftpd-0.17.debian/ftpd/ftpd.c +++ linux-ftpd-0.17/ftpd/ftpd.c @@ -49,7 +49,7 @@ char copyright[] = * FTP server. */ -#ifdef __linux__ +#if defined(__linux__) || defined(__GLIBC__) || defined(__GNU__) #define _GNU_SOURCE #endif @@ -90,7 +90,7 @@ char copyright[] = #include #include -#ifndef __linux__ +#if !defined( __linux__) && !defined(__GLIBC__) && !defined(__GNU__) #include #include #else @@ -284,7 +284,7 @@ static int check_host __P((struct socka void logxfer __P((const char *, off_t, time_t)); -#ifdef __linux__ +#if defined(__linux__) || defined(__GLIBC__) || defined(__GNU__) static void warnx(const char *format, ...) { va_list ap; @@ -376,7 +376,7 @@ main(int argc, char *argv[], char **envp const char *argstr = "AdDhlMnSt:T:u:UvP46"; struct addrinfo hints, *aiptr; -#ifdef __linux__ +#if defined(__linux__) || defined(__GLIBC__) || defined(__GNU__) initsetproctitle(argc, argv, envp); srandom(time(NULL)^(getpid()<<8)); @@ -627,9 +627,16 @@ main(int argc, char *argv[], char **envp } #ifdef IP_TOS tos = IPTOS_LOWDELAY; +# if defined(__GLIBC__) && ! defined(__linux__) + if ( (his_addr.ss_family == AF_INET) + && (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos, + sizeof(int)) < 0) ) + syslog(LOG_FTP | LOG_WARNING, "setsockopt (IP_TOS): %m"); +# else /* __linux__ */ if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0) syslog(LOG_FTP | LOG_WARNING, "setsockopt (IP_TOS): %m"); -#endif +# endif /* GNU/kfreebsd */ +#endif /* IP_TOS */ data_port = get_port((struct sockaddr *) &ctrl_addr) - 1; /* Try to handle urgent data inline */ @@ -1108,7 +1115,7 @@ static int authenticate(char *passwd) useconds_t us; /* Sleep between 1 and 3 seconds to emulate a crypt. */ -#ifndef __linux__ +#if !defined(__linux__) && !defined(__GLIBC__) && !defined(__GNU__) us = arc4random() % 3000000; #else us = random() % 3000000; @@ -1549,9 +1556,16 @@ static FILE * getdatasock(const char *mo #ifdef IP_TOS on = IPTOS_THROUGHPUT; +# if defined(__GLIBC__) && ! defined(__linux__) + if ( (his_addr.ss_family == AF_INET) + && (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on, + sizeof(on)) < 0) ) + syslog(LOG_FTP | LOG_WARNING, "setsockopt (IP_TOS): %m"); +# else /* __linux__ */ if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0) syslog(LOG_FTP | LOG_WARNING, "setsockopt (IP_TOS): %m"); -#endif +# endif /* GNU/kfreebsd */ +#endif /* IP_TOS */ #ifdef TCP_NOPUSH /* * Turn off push flag to keep sender TCP from sending short packets @@ -1634,7 +1648,7 @@ static FILE * dataconn(const char *name, #ifdef IP_TOS tos = IPTOS_THROUGHPUT; (void) setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, - sizeof(int)); + sizeof(int)); /* Errors silently ignored: GNU/kfreebsd. */ #endif if (stou) { reply(150, "FILE: %s", name); @@ -2347,10 +2361,17 @@ void passive(void) memcpy(&pasv_addr, &ctrl_addr, sizeof(pasv_addr)); #ifdef IP_PORTRANGE - on = high_data_ports ? IP_PORTRANGE_HIGH : IP_PORTRANGE_DEFAULT; - if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE, - (char *)&on, sizeof(on)) < 0) - goto pasv_error; + if (his_addr.ss_family == AF_INET6) { + on = high_data_ports ? IPV6_PORTRANGE_HIGH : IPV6_PORTRANGE_DEFAULT; + if (setsockopt(pdata, IPPROTO_IPV6, IPV6_PORTRANGE, + (char *)&on, sizeof(on)) < 0) + goto pasv_error; + } else { + on = high_data_ports ? IP_PORTRANGE_HIGH : IP_PORTRANGE_DEFAULT; + if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE, + (char *)&on, sizeof(on)) < 0) + goto pasv_error; + } #else #define FTP_DATA_BOTTOM 40000 #define FTP_DATA_TOP 44999 @@ -2564,7 +2585,7 @@ void send_file_list(const char *whichf) /* XXX: should the { go away if __linux__? */ if (strpbrk(whichf, "~{[*?") != NULL) { -#ifdef __linux__ +#if defined(__linux__) || defined(__GLIBC__) || defined(__GNU__) /* see popen.c */ int flags = GLOB_NOCHECK; #else @@ -2634,7 +2655,7 @@ void send_file_list(const char *whichf) while ((dir = readdir(dirp)) != NULL) { char nbuf[MAXPATHLEN]; -#ifdef __linux__ +#if defined(__linux__) || defined(__GLIBC__) || defined(__GNU__) if (!strcmp(dir->d_name, ".")) continue; if (!strcmp(dir->d_name, "..")) --- linux-ftpd-0.17.debian/ftpd/logutmp.c +++ linux-ftpd-0.17/ftpd/logutmp.c @@ -47,14 +47,14 @@ char logutmp_rcsid[] = #include #include #include -#ifndef __linux__ +#if !defined(__linux__) && !defined(__GLIBC__) && !defined(__GNU__) #include #endif #include "extern.h" typedef struct utmp UTMP; -#ifndef __linux__ +#if !defined(__linux__) && !defined(__GLIBC__) && !defined(__GNU__) static int fd = -1; static int topslot = -1; #endif @@ -67,7 +67,7 @@ static int topslot = -1; void login(const UTMP *ut) { -#ifndef __linux__ +#if !defined(__linux__) && !defined(__GLIBC__) && !defined(__GNU__) UTMP ubuf; /* @@ -110,7 +110,7 @@ login(const UTMP *ut) int logout(register const char *line) { -#ifndef __linux__ +#if !defined(__linux__) && !defined(__GLIBC__) && !defined(__GNU__) UTMP ut; int rval; --- linux-ftpd-0.17.debian/ftpd/popen.c +++ linux-ftpd-0.17/ftpd/popen.c @@ -102,7 +102,7 @@ ftpd_popen(char *program, const char *ty gargv[0] = argv[0]; for (gargc = argc = 1; argv[argc]; argc++) { glob_t gl; -#ifdef __linux__ +#if defined(__linux__) || defined(__GLIBC__) || defined(__GNU__) /* * GLOB_QUOTE is default behavior. GLOB_BRACE and GLOB_TILDE * aren't available... @@ -177,7 +177,7 @@ ftpd_popen(char *program, const char *ty if ( setgid(getegid()) != 0 ) _exit(1); if ( setuid(i) != 0 ) _exit(1); -#ifndef __linux__ +#if !defined(__linux__) && !defined(__GLIBC__) && !defined(__GNU__) /* * Not yet. Porting BSD ls to Linux would be a big and irritating job, * and we can't use GNU ls because of licensing. --- linux-ftpd-0.17.debian/support/vis.c +++ linux-ftpd-0.17/support/vis.c @@ -40,7 +40,7 @@ char vis_rcsid[] = \ #include #include #include -#ifndef __linux__ +#if !defined(__linux__) && !defined(__GLIBC__) && !defined(__GNU__) #include #else #include "vis.h" debian/patches/003-from_etch.diff0000644000000000000000000000312211374740305013717 0ustar Description: Patches recovered from linux-ftpd_0.17-23.diff.gz. Interdiff against linux-ftpd_0.17-20sarge2.diff.gz. Author: Alberto Gonzalaez Iniesta X-Comment: Contribution by Matt Power, Stefan Cornelius, Paul Szabo, and Andreas Jochens. Forwarded: no Last-Update: 2006-11-25 diff -u linux-ftpd-0.17/ftpd/ftpcmd.y linux-ftpd-0.17/ftpd/ftpcmd.y --- linux-ftpd-0.17/ftpd/ftpcmd.y +++ linux-ftpd-0.17/ftpd/ftpcmd.y @@ -101,7 +101,14 @@ char cbuf[512]; char *fromname; -struct tab; +struct tab { + const char *name; + short token; + short state; + short implemented; /* 1 if command is implemented */ + const char *help; +}; + static int yylex __P((void)); static void sizecmd __P((char *)); static void help __P((struct tab *, char *)); @@ -834,14 +841,6 @@ #define SITECMD 7 /* SITE command */ #define NSTR 8 /* Number followed by a string */ -struct tab { - const char *name; - short token; - short state; - short implemented; /* 1 if command is implemented */ - const char *help; -}; - struct tab cmdtab[] = { /* In order defined in RFC 765 */ { "USER", USER, STR1, 1, " username" }, { "PASS", PASS, ZSTR1, 1, " password" }, diff -u linux-ftpd-0.17/ftpd/popen.c linux-ftpd-0.17/ftpd/popen.c --- linux-ftpd-0.17/ftpd/popen.c +++ linux-ftpd-0.17/ftpd/popen.c @@ -174,7 +174,7 @@ * PSz 25 Aug 06 Must check the return status of these setgid/setuid calls, * see http://www.bress.net/blog/archives/34-setuid-madness.html */ - if ( setgid(geteuid()) != 0 ) _exit(1); + if ( setgid(getegid()) != 0 ) _exit(1); if ( setuid(i) != 0 ) _exit(1); #ifndef __linux__ debian/patches/014-adjust_infrastruct.diff0000644000000000000000000000075611374740305015703 0ustar Description: Corrections to infrastructure for builds. Insert harmless omission that eases tailored builds. Author: Mats Erik Andersson Forwarded: no Last-Update: 2010-04-26 --- linux-ftpd-0.17.debian/ftpd/Makefile +++ linux-ftpd-0.17/ftpd/Makefile @@ -26,7 +26,7 @@ -mv -f y.tab.c $@ ftpd: $(OBJS) - $(CC) $(LDFLAGS) $^ $(LIBS) -o $@ + $(CC) $(LDFLAGS) $^ $(LIBS) $(LDADD) -o $@ install: ftpd install -s -m$(DAEMONMODE) ftpd $(INSTALLROOT)$(SBINDIR)/in.ftpd debian/patches/016-family_independence.diff0000644000000000000000000005134111374740305015745 0ustar Description: Make the TCP transport code independent of address family. Make sure to eliminate as much outdated dependency on AF_INET, even before migrating to true support for AF_INET6. . 1. Rewrite dolog() and check_host(). . 2. Eliminate inet_ntoa(), gethostbyname(), gethostbyaddr(). . 3. Introduce helper functions get_port() and set_port() in order to hide family dependency, as well as representation in network byte order. This isolates use of ntohs() and htons() to the above two functions, with a single exception. . 4. Make sure that the daemon initialization depends only on a single AF_INET used for getaddrinfo(). This will later be replaced by AF_UNSPEC. . 5. Make name and address lookup in main() independent of address family. . 6. Reconstruct passive() to inherit address family from the controlling socket, then building the listening socket in an address independent manner. . 7. Let statcmd() and passive() report on IPv6 sockets using the EPSV semantics '(|||portnum|)'. . 8. Let the parser in ftpcmd.y use getaddrinfo() with NI_NUMERICHOST when constructing the IP-address, instead of manipulating byte fields. Likewise, hide port extraction in get_port(). Author: Mats Erik Andersson X-Comment: This code is fully independent of any USAGI code, which is in use by the OpenBSD strand of this software. Forwarded: not-needed Last-Update: 2010-04-30 --- linux-ftpd-0.17.debian/ftpd/ftpd.c +++ linux-ftpd-0.17/ftpd/ftpd.c @@ -157,6 +157,7 @@ int daemon_mode = 0; int data; +in_port_t data_port; jmp_buf errcatch, urgcatch; int logged_in; struct passwd *pw; @@ -259,7 +260,7 @@ static void myoob __P((int)); static int checkuser __P((const char *, const char *)); static FILE *dataconn __P((const char *, off_t, const char *, int)); -static void dolog __P((struct sockaddr_in *)); +static void dolog __P((struct sockaddr *)); static const char *curdir __P((void)); static void end_login __P((void)); static FILE *getdatasock __P((const char *)); @@ -276,7 +277,7 @@ static void authentication_setup(const char *); #if defined(TCPWRAPPERS) -static int check_host __P((struct sockaddr_in *)); +static int check_host __P((struct sockaddr *)); #endif void logxfer __P((const char *, off_t, time_t)); @@ -306,6 +307,63 @@ curdir(void) return (guest ? path+1 : path); } +static uint32_t +get_ipv4address(struct sockaddr * ss) +{ + if (ss->sa_family == AF_INET) + return ntohl(((struct sockaddr_in *) ss)->sin_addr.s_addr); + else if(ss->sa_family == AF_INET6) { + return ntohl(((struct sockaddr_in6 *) ss)->sin6_addr.s6_addr32[3]); + } else + /* Should Never happen. Sensible return value? */ + return (uint32_t) -2; +} /* get_ipv4address( struct sockaddr_storage * ) */ + +static int +get_port(struct sockaddr * sa) +{ + switch (sa->sa_family) { + case AF_INET6: + return ntohs(((struct sockaddr_in6 *) sa)->sin6_port); + break; + case AF_INET: + default: + return ntohs(((struct sockaddr_in *) sa)->sin_port); + } +} /* get_port( struct sockaddr * ) */ + +static void +set_port(struct sockaddr * sa, short int port) +{ + switch (sa->sa_family) { + case AF_INET6: + ((struct sockaddr_in6 *) sa)->sin6_port = htons(port); + break; + case AF_INET: + default: + ((struct sockaddr_in *) sa)->sin_port = htons(port); + } +} /* set_port( struct sockaddr *, short int ) */ + +#ifdef BREAKRFC +static int +cmp_addresses(struct sockaddr * left, struct sockaddr * right) +{ + if (left->sa_family != right->sa_family) + /* Should mapped or compatible IPv4 be handled? */ + return 1; + + if (left->sa_family == AF_INET6) + return IN6_ARE_ADDR_EQUAL(&((struct sockaddr_in6 *) left)->sin6_addr, + &((struct sockaddr_in6 *) right)->sin6_addr) + ? 0 : 1; + + return (memcmp(&((struct sockaddr_in *) left)->sin_addr, + &((struct sockaddr_in *) right)->sin_addr, + sizeof(struct in_addr))); +} /* cmp_addresses(struct sockaddr *, struct sockaddr *) */ +#endif + int main(int argc, char *argv[], char **envp) { @@ -314,7 +372,7 @@ main(int argc, char *argv[], char **envp char *cp, line[LINE_MAX]; FILE *fd; const char *argstr = "AdDhlMnSt:T:u:UvP"; - struct hostent *hp; + struct addrinfo hints, *aiptr; #ifdef __linux__ initsetproctitle(argc, argv, envp); @@ -431,8 +489,9 @@ main(int argc, char *argv[], char **envp openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP); if (daemon_mode) { - int ctl_sock, fd2; + int ctl_sock, fd2, rc; struct servent *sv; + struct addrinfo hints, *ai, *aiptr; /* * Detach from parent. @@ -452,31 +511,53 @@ main(int argc, char *argv[], char **envp exit(1); } /* - * Open a socket, bind it to the FTP port, and start - * listening. + * Open a socket, bind it to the FTP port, + * and begin listening for calls. */ - ctl_sock = socket(AF_INET, SOCK_STREAM, 0); - if (ctl_sock < 0) { - syslog(LOG_FTP | LOG_ERR, "control socket: %m"); + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; + hints.ai_socktype = SOCK_STREAM; + hints.ai_family = AF_INET; + + if ((rc = getaddrinfo(NULL, "ftp", &hints, &aiptr))) { + syslog(LOG_FTP | LOG_ERR, + "getaddrinfo for ftp failed (%s)", + gai_strerror(rc)); exit(1); } - if (setsockopt(ctl_sock, SOL_SOCKET, SO_REUSEADDR, - (char *)&on, sizeof(on)) < 0) - syslog(LOG_FTP | LOG_ERR, "control setsockopt: %m");; - server_addr.sin_family = AF_INET; - server_addr.sin_addr.s_addr = INADDR_ANY; - server_addr.sin_port = sv->s_port; - if (bind(ctl_sock, (struct sockaddr *)&server_addr, - sizeof(server_addr))) { - syslog(LOG_FTP | LOG_ERR, "control bind: %m"); - exit(1); + /* Loop over possible alternatives. */ + for (ai = aiptr; ai; ai = ai->ai_next) { + if ((ctl_sock = socket(ai->ai_family, + ai->ai_socktype, ai->ai_protocol)) + < 0) + continue; + if (setsockopt(ctl_sock, SOL_SOCKET, SO_REUSEADDR, + (char *)&on, sizeof(on)) < 0) + syslog(LOG_FTP | LOG_ERR, "control setsockopt: %m");; + + if (bind(ctl_sock, ai->ai_addr, ai->ai_addrlen)) { + close(ctl_sock); + continue; + } + if (listen(ctl_sock, 32) < 0) { + close(ctl_sock); + continue; + } + + /* Socket successfully established: bound and listening. */ + break; } - if (listen(ctl_sock, 32) < 0) { - syslog(LOG_FTP | LOG_ERR, "control listen: %m"); + + freeaddrinfo(aiptr); + + if (ai == NULL) { + /* Failure, no socket established. */ + syslog(LOG_FTP | LOG_ERR, "listening socket failed"); exit(1); } + /* - * Loop forever accepting connection requests and forking off + * Loop forever, accepting connection requests, and forking off * children to handle them. */ while (1) { @@ -495,7 +576,7 @@ main(int argc, char *argv[], char **envp #if defined(TCPWRAPPERS) /* ..in the child. */ - if (!check_host(&his_addr)) + if (!check_host((struct sockaddr *) &his_addr)) exit(1); #endif /* TCPWRAPPERS */ } else { @@ -527,7 +608,7 @@ main(int argc, char *argv[], char **envp if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0) syslog(LOG_FTP | LOG_WARNING, "setsockopt (IP_TOS): %m"); #endif - data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1); + data_port = get_port((struct sockaddr *) &ctrl_addr) - 1; /* Try to handle urgent data inline */ #ifdef SO_OOBINLINE @@ -539,7 +620,7 @@ main(int argc, char *argv[], char **envp if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1) syslog(LOG_FTP | LOG_ERR, "fcntl F_SETOWN: %m"); #endif - dolog(&his_addr); + dolog((struct sockaddr *) &his_addr); /* * Set up default state */ @@ -574,22 +655,21 @@ main(int argc, char *argv[], char **envp } (void) gethostname(hostname, sizeof(hostname)); + memset(&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_STREAM; + hints.ai_family = AF_UNSPEC; + hints.ai_flags = AI_ADDRCONFIG | AI_CANONNAME; + /* Make sure hostname is fully qualified. */ - hp = gethostbyname(hostname); - if (hp != NULL) - strcpy(hostname, hp->h_name); - - if (multihome) { - hp = gethostbyaddr((char *) &ctrl_addr.sin_addr, - sizeof (struct in_addr), AF_INET); - if (hp != NULL) { - strcpy(dhostname, hp->h_name); - } else { - /* Default. */ - strcpy(dhostname, inet_ntoa(ctrl_addr.sin_addr)); - } + if (getaddrinfo(hostname, NULL, &hints, &aiptr) == 0) { + strncpy(hostname, aiptr->ai_canonname, sizeof(hostname)); + freeaddrinfo(aiptr); } + if (multihome) + (void) getnameinfo((struct sockaddr *) &ctrl_addr, addrlen, + dhostname, sizeof(dhostname), NULL, 0, 0); + reply(220, "%s FTP server (%s) ready.", (multihome ? dhostname : hostname), version); (void) setjmp(errcatch); @@ -1392,21 +1472,19 @@ static FILE * getdatasock(const char *mo sigfillset(&allsigs); sigprocmask (SIG_BLOCK, &allsigs, NULL); (void) seteuid((uid_t)0); - s = socket(AF_INET, SOCK_STREAM, 0); + s = socket(his_addr.sin_family, SOCK_STREAM, 0); if (s < 0) goto bad; if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)) < 0) goto bad; /* anchor socket to avoid multi-homing problems */ -#ifndef __linux__ - data_source.sin_len = sizeof(struct sockaddr_in); -#endif - data_source.sin_family = AF_INET; - data_source.sin_addr = ctrl_addr.sin_addr; + memcpy(&data_source, &ctrl_addr, sizeof(data_source)); + set_port((struct sockaddr *) &data_source, data_port); + for (tries = 1; ; tries++) { if (bind(s, (struct sockaddr *)&data_source, - sizeof(data_source)) >= 0) + sizeof(data_source)) >= 0) break; if (errno != EADDRINUSE || tries > 10) goto bad; @@ -1468,7 +1546,7 @@ static FILE * dataconn(const char *name, } else sizebuf[0] = '\0'; if (pdata >= 0) { - struct sockaddr_in from; + struct sockaddr_storage from; int s; socklen_t fromlen = sizeof(from); @@ -1482,7 +1560,7 @@ static FILE * dataconn(const char *name, pdata = -1; return (NULL); } - if (ntohs(from.sin_port) < IPPORT_RESERVED) { + if (get_port((struct sockaddr *) &from) < IPPORT_RESERVED) { perror_reply(425, "Can't build data connection"); (void) close(pdata); (void) close(s); @@ -1490,7 +1568,9 @@ static FILE * dataconn(const char *name, return (NULL); } #ifdef BREAKRFC - if (from.sin_addr.s_addr != his_addr.sin_addr.s_addr) { + //if (from.sin_addr.s_addr != his_addr.sin_addr.s_addr) { + if (cmp_addresses((struct sockaddr *) &from, + (struct sockaddr *) &his_addr)) { perror_reply(435, "Can't build data connection"); (void) close(pdata); (void) close(s); @@ -1527,13 +1607,19 @@ static FILE * dataconn(const char *name, return (fdopen(data, mode)); } if (usedefault) - data_dest = his_addr; + memcpy(&data_dest, &his_addr, sizeof(data_dest)); usedefault = 1; file = getdatasock(mode); if (file == NULL) { + char ipaddr[INET6_ADDRSTRLEN], port[12]; + + (void) getnameinfo((struct sockaddr *) &data_source, + sizeof(struct sockaddr_storage), + ipaddr, sizeof(ipaddr), port, sizeof(port), + NI_NUMERICHOST); + reply(425, "Can't create data socket (%s,%d): %s.", - inet_ntoa(data_source.sin_addr), - ntohs(data_source.sin_port), strerror(errno)); + ipaddr, port, strerror(errno)); return (NULL); } data = fileno(file); @@ -1542,15 +1628,17 @@ static FILE * dataconn(const char *name, * attempt to connect to reserved port on client machine; * this looks like an attack */ - if (ntohs(data_dest.sin_port) < IPPORT_RESERVED || - ntohs(data_dest.sin_port) == 2049) { /* XXX */ + if (get_port((struct sockaddr *) &data_dest) < IPPORT_RESERVED || + get_port((struct sockaddr *) &data_dest) == 2049) { /* XXX */ perror_reply(425, "Can't build data connection"); (void) fclose(file); data = -1; return NULL; } #ifdef BREAKRFC - if (data_dest.sin_addr.s_addr != his_addr.sin_addr.s_addr) { + //if (data_dest.sin_addr.s_addr != his_addr.sin_addr.s_addr) { + if (cmp_addresses((struct sockaddr *) &data_dest, + (struct sockaddr *) &his_addr)) { perror_reply(435, "Can't build data connection"); (void) fclose(file); data = -1; @@ -1826,14 +1914,19 @@ void statcmd(void) { - struct sockaddr_in *sn; - u_char *a, *p; + struct sockaddr *sn; + char ipaddr[INET6_ADDRSTRLEN]; lreply(211, "%s FTP server status:", hostname, version); printf(" %s\r\n", version); printf(" Connected to %s", remotehost); - if (!isdigit(remotehost[0])) - printf(" (%s)", inet_ntoa(his_addr.sin_addr)); + if (!isdigit(remotehost[0])) { + (void) getnameinfo((struct sockaddr *) &his_addr, + sizeof(struct sockaddr_storage), + ipaddr, sizeof(ipaddr), NULL, 0, + NI_NUMERICHOST); + printf(" (%s)", ipaddr); + } printf("\r\n"); if (logged_in) { if (guest) @@ -1859,17 +1952,24 @@ void statcmd(void) printf(" Data connection open\r\n"); else if (pdata != -1) { printf(" in Passive mode"); - sn = &pasv_addr; + sn = (struct sockaddr *) &pasv_addr; goto printaddr; } else if (usedefault == 0) { printf(" PORT"); - sn = &data_dest; + sn = (struct sockaddr *) &data_dest; printaddr: - a = (u_char *) &sn->sin_addr; - p = (u_char *) &sn->sin_port; #define UC(b) (((int) b) & 0xff) - printf(" (%d,%d,%d,%d,%d,%d)\r\n", UC(a[0]), - UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1])); + if (sn->sa_family == AF_INET6) + printf(" (|||%d|)\r\n", get_port(sn)); + else { + uint32_t ip4ad = get_ipv4address(sn); + in_port_t port = get_port(sn); + + printf(" (%d,%d,%d,%d,%d,%d)\r\n", + UC(ip4ad >> 24), UC(ip4ad >> 16), + UC(ip4ad >> 8), UC(ip4ad), + UC(port >> 8), UC(port)); + } #undef UC } else printf(" No data connection\r\n"); @@ -2075,18 +2175,17 @@ ack("RNTO"); } -static void dolog(struct sockaddr_in *sn) +static void dolog(struct sockaddr *sa) { - struct hostent *hp; + char host[NI_MAXHOST]; - if (!numeric_hosts && - (hp = gethostbyaddr((char *)&sn->sin_addr, - sizeof(struct in_addr), AF_INET))) - (void) strncpy(remotehost, hp->h_name, sizeof(remotehost)-1); - else - (void) strncpy(remotehost, inet_ntoa(sn->sin_addr), - sizeof(remotehost)-1); + getnameinfo(sa, sizeof(struct sockaddr_storage), + host, sizeof(host), NULL, 0, + numeric_hosts ? NI_NUMERICHOST : 0); + + (void) strncpy(remotehost, host, sizeof(remotehost)-1); remotehost[sizeof(remotehost)-1] = '\0'; + #ifdef HASSETPROCTITLE snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost); setproctitle("%s", proctitle); @@ -2158,9 +2257,8 @@ void passive(void) #ifdef IP_PORTRANGE int on; #else - u_short port; + in_port_t port; #endif - char *p, *a; if (pw == NULL) { reply(530, "Please login with USER and PASS"); @@ -2168,12 +2266,14 @@ void passive(void) } if (pdata >= 0) close(pdata); - pdata = socket(AF_INET, SOCK_STREAM, 0); + pdata = socket(his_addr.sin_family, SOCK_STREAM, 0); if (pdata < 0) { perror_reply(425, "Can't open passive connection"); return; } + memcpy(&pasv_addr, &ctrl_addr, sizeof(pasv_addr)); + #ifdef IP_PORTRANGE on = high_data_ports ? IP_PORTRANGE_HIGH : IP_PORTRANGE_DEFAULT; if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE, @@ -2184,8 +2284,8 @@ void passive(void) #define FTP_DATA_TOP 44999 if (high_data_ports) { for (port = FTP_DATA_BOTTOM; port <= FTP_DATA_TOP; port++) { - pasv_addr = ctrl_addr; - pasv_addr.sin_port = htons(port); + set_port((struct sockaddr *) &pasv_addr, port); + if (bind(pdata, (struct sockaddr *) &pasv_addr, sizeof(pasv_addr)) == 0) break; @@ -2198,8 +2298,7 @@ void passive(void) else #endif { - pasv_addr = ctrl_addr; - pasv_addr.sin_port = 0; + set_port((struct sockaddr *) &pasv_addr, 0); if (bind(pdata, (struct sockaddr *)&pasv_addr, sizeof(pasv_addr)) < 0) goto pasv_error; @@ -2210,13 +2309,24 @@ void passive(void) goto pasv_error; if (listen(pdata, 1) < 0) goto pasv_error; - a = (char *) &pasv_addr.sin_addr; - p = (char *) &pasv_addr.sin_port; #define UC(b) (((int) b) & 0xff) - reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]), - UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1])); + if (((struct sockaddr *) &pasv_addr)->sa_family == AF_INET6) + reply(229, "Extended Passive Mode OK (|||%d|)", + get_port((struct sockaddr *) &pasv_addr)); + else { + uint32_t ip4ad = get_ipv4address((struct sockaddr *) &pasv_addr); + in_port_t port = get_port((struct sockaddr *) &pasv_addr); + + reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", + UC(ip4ad >> 24), UC(ip4ad >> 16), + UC(ip4ad >> 8), UC(ip4ad), + UC(port >> 8), UC(port)); + } + +#undef UC + return; pasv_error: @@ -2476,23 +2586,25 @@ } #if defined(TCPWRAPPERS) -static int check_host(struct sockaddr_in *sin) +static int check_host(struct sockaddr *sa) { - struct hostent *hp = gethostbyaddr((char *)&sin->sin_addr, - sizeof(struct in_addr), AF_INET); - char *addr = inet_ntoa(sin->sin_addr); + char ipaddr[INET6_ADDRSTRLEN]; + char host[NI_MAXHOST]; + + getnameinfo(sa, sizeof(struct sockaddr_storage), + ipaddr, sizeof(ipaddr), NULL, 0, NI_NUMERICHOST); - if (hp) { - if (!hosts_ctl("ftpd", hp->h_name, addr, STRING_UNKNOWN)) { + if (! getnameinfo(sa, sizeof(struct sockaddr_storage), + host, sizeof(host), NULL, 0, NI_NAMEREQD) ) { + if (!hosts_ctl("ftpd", host, ipaddr, STRING_UNKNOWN)) { syslog(LOG_FTP | LOG_NOTICE, - "tcpwrappers rejected: %s [%s]", - hp->h_name, addr); + "tcpwrappers rejected: %s [%s]", host, ipaddr); return (0); } } else { - if (!hosts_ctl("ftpd", STRING_UNKNOWN, addr, STRING_UNKNOWN)) { + if (!hosts_ctl("ftpd", STRING_UNKNOWN, ipaddr, STRING_UNKNOWN)) { syslog(LOG_FTP | LOG_NOTICE, - "tcpwrappers rejected: [%s]", addr); + "tcpwrappers rejected: [%s]", ipaddr); return (0); } } --- linux-ftpd-0.17.debian/ftpd/ftpcmd.y +++ linux-ftpd-0.17/ftpd/ftpcmd.y @@ -51,6 +51,7 @@ #include #include +#include #include #include @@ -116,6 +117,35 @@ extern struct tab cmdtab[]; extern struct tab sitetab[]; +static int +get_port(struct sockaddr * sa) +{ + switch (sa->sa_family) { + case AF_INET6: + return (ntohs(((struct sockaddr_in6 *) sa)->sin6_port)); + break; + case AF_INET: + default: + return (ntohs(((struct sockaddr_in *) sa)->sin_port)); + } +} /* get_port( struct sockaddr * ) */ + +static int +cmp_addresses(struct sockaddr * left, struct sockaddr * right) +{ + if (left->sa_family != right->sa_family) + return 1; + + if (left->sa_family == AF_INET6) + return IN6_ARE_ADDR_EQUAL(&((struct sockaddr_in6 *) left)->sin6_addr, + &((struct sockaddr_in6 *) right)->sin6_addr) + ? 0 : 1; + + return (memcmp(&((struct sockaddr_in *) left)->sin_addr, + &((struct sockaddr_in *) right)->sin_addr, + sizeof(struct in_addr))); +} /* cmp_addresses( struct sockaddr *, struct sockaddr * ) */ + %} %union { @@ -184,14 +214,13 @@ cmd reply(500, "Illegal PORT rejected (range errors)."); } else if (portcheck && - ntohs(data_dest.sin_port) < IPPORT_RESERVED) { + get_port((struct sockaddr *) &data_dest) < IPPORT_RESERVED) { usedefault = 1; reply(500, "Illegal PORT rejected (reserved port)."); } else if (portcheck && - memcmp(&data_dest.sin_addr, - &his_addr.sin_addr, - sizeof data_dest.sin_addr)) { + cmp_addresses((struct sockaddr *) &data_dest, + (struct sockaddr *) &his_addr)) { usedefault = 1; reply(500, "Illegal PORT rejected (address wrong)."); @@ -201,6 +230,7 @@ cmd (void) close(pdata); pdata = -1; } + /* Valid remote address in 'data_dest'. */ reply(200, "PORT command successful."); } } @@ -632,22 +662,32 @@ host_port : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER { - char *a, *p; + char ipaddr[INET6_ADDRSTRLEN], port[12]; + struct addrinfo hints, *aiptr; if ($1 < 0 || $1 > 255 || $3 < 0 || $3 > 255 || $5 < 0 || $5 > 255 || $7 < 0 || $7 > 255 || $9 < 0 || $9 > 255 || $11 < 0 || $11 > 255) { $$ = 1; } else { -#ifndef __linux__ - data_dest.sin_len = sizeof(struct sockaddr_in); -#endif - data_dest.sin_family = AF_INET; - p = (char *)&data_dest.sin_port; - p[0] = $9; p[1] = $11; - a = (char *)&data_dest.sin_addr; - a[0] = $1; a[1] = $3; a[2] = $5; a[3] = $7; - $$ = 0; + snprintf(ipaddr, sizeof(ipaddr), "%ju.%ju.%ju.%ju", + $1, $3, $5, $7); + snprintf(port, sizeof(port), "%ju", 256 * $9 + $11); + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; /* Enable mapped addressing? */ + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST | AI_NUMERICSERV; + + if (getaddrinfo(ipaddr, port, &hints, &aiptr)) { + $$ = 1; + } else { + /* Store the generated address in 'data_dest'. + * This is the remote host! */ + memcpy(&data_dest, aiptr->ai_addr, aiptr->ai_addrlen); + freeaddrinfo(aiptr); + $$ = 0; + } } } ; debian/patches/024-failing_va_list.diff0000644000000000000000000000233511374740305015113 0ustar Description: Reinitialize variable argument list for vsyslog(). The use of vprintf(fmt, ap) leaves the second argument in an undefined state after execution. On a system using the amd64 architecture, this leads consistently to segmentation faults. The solution is to insert the required initialization before the call to vsyslog(). Author: Mats Erik Andersson Forwarded: no Last-Update: 2010-05-09 --- linux-ftpd-0.17/ftpd/ftpd.c.no-va_start +++ linux-ftpd-0.17/ftpd/ftpd.c @@ -2051,10 +2051,17 @@ reply(int n, char *fmt, va_dcl va_alist) (void)printf("%d ", n); (void)vprintf(fmt, ap); (void)printf("\r\n"); + va_end(ap); (void)fflush(stdout); if (debug) { +#ifdef __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif syslog(LOG_FTP | LOG_DEBUG, "<--- %d ", n); vsyslog(LOG_FTP | LOG_DEBUG, fmt, ap); + va_end(ap); } } @@ -2077,10 +2084,17 @@ lreply(n, fmt, va_alist) (void)printf("%d- ", n); (void)vprintf(fmt, ap); (void)printf("\r\n"); + va_end(ap); (void)fflush(stdout); if (debug) { +#ifdef __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif syslog(LOG_FTP | LOG_DEBUG, "<--- %d- ", n); vsyslog(LOG_FTP | LOG_DEBUG, fmt, ap); + va_end(ap); } } debian/patches/040-refine_config.diff0000644000000000000000000000134611735145504014556 0ustar Description: Do not link with libcrypt. The test for libcrypt is only needed in cases when USE_PAM is not set to active. Author: Mats Erik Andersson Forwarded: no Last-Update: 2012-03-29 --- linux-ftpd-0.17.debian/configure +++ linux-ftpd-0.17/configure @@ -261,6 +261,11 @@ ################################################## +# libcrypt is only needed in the absence of libpam. + +if test -z "$USE_PAM"; then +## Missing indentation in this clause! + echo -n 'Checking for crypt... ' cat <__conftest.c int main() { crypt("aa", "bb"); } @@ -285,6 +290,8 @@ fi rm -f __conftest* +fi # test -z "$USE_PAM" + ################################################## echo -n 'Checking for socklen_t... ' debian/docs0000644000000000000000000000000710214544075010040 0ustar README debian/compat0000644000000000000000000000000211374740305010370 0ustar 7 debian/copyright0000644000000000000000000000326311376775136011145 0ustar This package was split from netstd by Herbert Xu herbert@debian.org on Thu, 1 Apr 1999 16:42:48 +1000. netstd was created by Peter Tobias tobias@et-inf.fho-emden.de on Wed, 20 Jul 1994 17:23:21 +0200. It was downloaded from ftp://ftp.uk.linux.org/pub/linux/Networking/netkit/. Copyright: /************************************************************************ Copyright 1988, 1991 by Carnegie Mellon University All Rights Reserved Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of Carnegie Mellon University not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ************************************************************************/ Files: debian/patches/16-family_independence.diff debian/patches/20-support_ipv6.diff Copyright: 2010, Mats Erik Andersson License: BSD X-Comment: The license of the original software applies to these patches. debian/NEWS0000644000000000000000000000175511377011463007700 0ustar linux-ftpd (0.17-31) unstable; urgency=low The recent IPv6 capability is handled in distinct ways by the three usual super-servers: openbsd-inetd, xinetd, and inetutils-inetd. The differences are discussed in the file README.Debian. Depending on your old setup, 'update-inetd' might complain about multiple instances of 'ftp' in '/etc/inetd.conf'. The present version tries to counter-act this at future upgrades by inserting '--multi' in the maintainer scripts. -- Mats Erik Andersson Tue, 25 May 2010 20:12:28 +0200 linux-ftpd (0.17-30) unstable; urgency=low This packaging of linux-ftpd incorporates working support for the IPv6 address family, in stand alone mode, as well as under the control of a super server like xinetd. The records made in wtmp now include the caller's address structure, thus improving the prospects of tracing clients. -- Mats Erik Andersson Sat, 08 May 2010 19:54:28 +0200