Hello community, here is the log from the commit of package uftpd for openSUSE:Leap:15.2 checked in at 2020-01-17 12:00:35 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Leap:15.2/uftpd (Old) and /work/SRC/openSUSE:Leap:15.2/.uftpd.new.26092 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "uftpd" Fri Jan 17 12:00:35 2020 rev:4 rq:763576 version:2.11 Changes: -------- --- /work/SRC/openSUSE:Leap:15.2/uftpd/uftpd.changes 2020-01-15 16:26:47.152698100 +0100 +++ /work/SRC/openSUSE:Leap:15.2/.uftpd.new.26092/uftpd.changes 2020-01-17 12:00:35.600481678 +0100 @@ -1,0 +2,46 @@ +Sun Jan 5 09:44:30 UTC 2020 - Martin Hauke <[email protected]> + +- Update to version 2.11 + * Increased logging at default log level. Now all relevant + interaction is logged. See the man page for how to adjust. + * Fix buffer overflow in FTP PORT parser + * Fix TFTP/FTP directory traversal regression + * Fix potential DOS through non-busy loop and segfault + * Fix potential segfault through empty FTP password + * Fix potential segfault through FTP PORT command + +------------------------------------------------------------------- +Mon Aug 26 20:56:41 UTC 2019 - Martin Hauke <[email protected]> + +- Update to version 2.10 + * Add support for TFTP WRQ, i.e. for clients sending files to + server + * Fix invalid TFTP error codes, now uses custom error string to + code 0 + * Slightly improved debug messages + +------------------------------------------------------------------- +Mon Jul 29 20:02:51 UTC 2019 - Martin Hauke <[email protected]> + +- Update to version 2.9 + * Check FTP root security after dropping privileges + * Revert insecure default: "writable FTP root", introduced in v2.8 + * Revert part of issue #18 to fix issue #23; "CWD /" doesn't work + * Fix spelling errors found by Lintian + * Fix package description, more formal and less personal + +------------------------------------------------------------------- +Tue May 28 17:44:15 UTC 2019 - Martin Hauke <[email protected]> + +- Update to version 2.8 + Changes: + * The FTP command processor now always converts all inbound + commands to uppercase to handle clients sending commands in + lowercase + * Any arguments to the FTP LIST command are now ignored + * Improved user feedback on bad FTP root error message + Fixes + * Fix #18: KDE Dolphin, FTP client interop problems. + * Fix off-by-one regression introduced in v2.5 + +------------------------------------------------------------------- Old: ---- uftpd-2.7.tar.gz New: ---- uftpd-2.11.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ uftpd.spec ++++++ --- /var/tmp/diff_new_pack.osGmRO/_old 2020-01-17 12:00:36.048481875 +0100 +++ /var/tmp/diff_new_pack.osGmRO/_new 2020-01-17 12:00:36.060481881 +0100 @@ -1,7 +1,7 @@ # # spec file for package uftpd # -# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2020 SUSE LINUX GmbH, Nuernberg, Germany. # Copyright (c) 2018, Martin Hauke <[email protected]> # # All modifications and additions to the file contributed by third parties @@ -18,7 +18,7 @@ Name: uftpd -Version: 2.7 +Version: 2.11 Release: 0 Summary: A combined TFTP/FTP server License: ISC ++++++ uftpd-2.7.tar.gz -> uftpd-2.11.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/uftpd-2.7/.gitignore new/uftpd-2.11/.gitignore --- old/uftpd-2.7/.gitignore 2019-03-03 15:52:00.000000000 +0100 +++ new/uftpd-2.11/.gitignore 2020-01-05 08:51:54.000000000 +0100 @@ -10,7 +10,7 @@ Makefile.in aclocal.m4 ar-lib -/autom4te.cache/* +autom4te.cache/* compile config.* configure @@ -18,19 +18,10 @@ install-sh libtool ltmain.sh -misc/ missing stamp-h1 -uftpd -debian/files -debian/uftpd.* TAGS -/GPATH -/GRTAGS -/GSYMS -/GTAGS -/CHANGELOG.html -/README.html -/uftpd.html -/tok -/uftp +GPATH +GRTAGS +GSYMS +GTAGS diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/uftpd-2.7/ChangeLog.md new/uftpd-2.11/ChangeLog.md --- old/uftpd-2.7/ChangeLog.md 2019-03-03 15:52:00.000000000 +0100 +++ new/uftpd-2.11/ChangeLog.md 2020-01-05 08:51:54.000000000 +0100 @@ -4,6 +4,66 @@ All notable changes to the project are documented in this file. +[v2.11][] - 2020-01-05 +---------------------- + +### Changes +- Increased logging at default log level. Now users logging in, + downloading, uploading, directory creation/removal is logged by + default. Start with `-l error` to silence uftpd again + +### Fixes +- Fix buffer overflow in FTP PORT parser, reported by Aaron Esau +- Fix TFTP/FTP directory traversal regression , reported by Aaron Esau +- Fix potential DOS through non-busy loop and segfault, by Aaron Esau +- Fix potential segfault through empty FTP password, by Aaron Esau +- Fix potential segfault through FTP PORT command, by Aaron Esau + + +[v2.10][] - 2019-08-15 +---------------------- + +### Changes +- Issue #25: Add support for TFTP write support (WRQ) +- Slightly improved debug messages. + +### Fixes +- Minor fix to TFTP error codes, only use standardized codes, and + code 0 + custom error message for everything else + + +[v2.9][] - 2019-07-29 +--------------------- + +### Changes +- Reduced log level for "Invalid path" and "Failed realpath()" syslog + messages. Only relevant when debugging. For use on the Internet it + will otherwise cause an excessive amount of logs due to GXHLGSL.txt +- Debian packaging fixes and updates: + - Reverts `-o writable`, due to fixing issue #22 + - Fixes failing `dpkg -P uftpd` due to bug in postrm script + +### Fixes +- Issue #21: Check for `pkg-config` before looking for deps. +- Issue #22: Check FTP root security *after* having dropped privs. + This means no longer having to run with `-o writable` by default +- Issue #23: FTP command `CWD /` does not work, affects all clients. + This is a regression introduced in v2.8 while fixing #18 + + +[v2.8][] - 2019-05-28 +--------------------- + +### Changes +- The FTP command processor now always converts all inbound commands + to uppercase to handle clients sending commands in lowercase +- Any arguments to the FTP `LIST` command are now ignored +- Improved user feedback on bad FTP root error message + +### Fixes +- Fix #18: KDE Dolphin, FTP client interop problems. + + [v2.7][] - 2019-03-03 --------------------- @@ -12,7 +72,7 @@ - Require libuEv v2.2, or later ### Fixes -- Issue #17: Issues with relative FTP root when running unpriviliged +- Issue #17: Issues with relative FTP root when running unprivileged [v2.6][] - 2018-07-03 @@ -58,7 +118,7 @@ ### Changes - Handle non-chrooted use-cases better, ensure CWD starts with / -- Increased default inactivty timer: 20 sec --> 180 sec +- Increased default inactivity timer: 20 sec --> 180 sec - Ensure FTP `PASV` and `PORT` sockets are set non-blocking to prevent blocking the event loop - [README.md][] updates, add usage section and improve build + install @@ -143,7 +203,7 @@ [v2.0][] - 2016-01-22 --------------------- -Sleak, smart, simple ... UNIX +Sleek, smart, simple ... UNIX ### Changes - Greatly simplified command line syntax @@ -188,7 +248,7 @@ - Major refactor of both FTP and TFTP servers to use libuEv better. - Move to use [libite][] v1.0.0 for `strlcpy()`, `strlcat()`, `pidfile()` and more. -- Add proper session timout to TFTP, like what FTP already has. +- Add proper session timeout to TFTP, like what FTP already has. - Add support for `NLST` FTP command, needed for multiple get operations. This fixes issue #2, thanks to @oz123 on GitHub for pointing this out! - Add support for `FEAT` and `HELP` FTP commands used by some clients. @@ -269,7 +329,7 @@ ### Fixes - Fix nasty invalid `sizeof()` argument to `recv()` causing uftpd to only read 4/8 bytes (32/64 bit arch) at a time from the FTP socket. - This should greatly reduce CPU utilisation and improve xfer speeds. + This should greatly reduce CPU utilization and improve xfer speeds. Found by [Coverity Scan][]. - Fix minor resource leak in `ftp_session()` when `getsockname()` or `getpeername()` fail. Minor fix because the session exits and the OS @@ -317,7 +377,7 @@ - Incompatible changes to the command line arguments, compared to v1.2! - Add libuEv as a GIT submodule, handles signals, timers, and all I/O. - Refactor all signal handling, timers, and socket `poll()` calls to - use libuEv instead. Much cleaner and maintaiable code as a result. + use libuEv instead. Much cleaner and maintainable code as a result. - Clarify copyright claims, not much remains of the original [FtpServer][] code, by [Xu Wang][]. @@ -392,7 +452,11 @@ Lines must end in the old `\r\n` format, rather than UNIX `\n`. -[UNRELEASED]: https://github.com/troglobit/uftpd/compare/v2.7...HEAD +[UNRELEASED]: https://github.com/troglobit/uftpd/compare/v2.11...HEAD +[v2.11]: https://github.com/troglobit/uftpd/compare/v2.10...v2.11 +[v2.10]: https://github.com/troglobit/uftpd/compare/v2.9...v2.10 +[v2.9]: https://github.com/troglobit/uftpd/compare/v2.8...v2.9 +[v2.8]: https://github.com/troglobit/uftpd/compare/v2.7...v2.8 [v2.7]: https://github.com/troglobit/uftpd/compare/v2.6...v2.7 [v2.6]: https://github.com/troglobit/uftpd/compare/v2.5...v2.6 [v2.5]: https://github.com/troglobit/uftpd/compare/v2.4...v2.5 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/uftpd-2.7/Makefile.am new/uftpd-2.11/Makefile.am --- old/uftpd-2.7/Makefile.am 2019-03-03 15:52:00.000000000 +0100 +++ new/uftpd-2.11/Makefile.am 2020-01-05 08:51:54.000000000 +0100 @@ -1,5 +1,5 @@ SUBDIRS = src man -doc_DATA = README.md LICENSE +doc_DATA = README.md LICENSE ChangeLog.md EXTRA_DIST = README.md LICENSE ChangeLog.md ## Generate .deb package diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/uftpd-2.7/README.md new/uftpd-2.11/README.md --- old/uftpd-2.7/README.md 2019-03-03 15:52:00.000000000 +0100 +++ new/uftpd-2.11/README.md 2020-01-05 08:51:54.000000000 +0100 @@ -25,7 +25,7 @@ uftpd [-hnsv] [-l LEVEL] [-o ftp=PORT,tftp=PORT,writable] [PATH] -h Show this help text - -l LEVEL Set log level: none, err, info, notice (default), debug + -l LEVEL Set log level: none, err, notice (default), info, debug -n Run in foreground, do not detach from controlling terminal -o OPT Options: ftp=PORT @@ -58,11 +58,14 @@ Set `PORT` to zero (0) to disable either service. -By default, uftpd will exit if it detects the FTP root is writable. To -allow writable FTP root: +New sessions are droppbed by default if uftpd detects the FTP root is +writable. To allow writable FTP root: uftpd -o writable PATH +> **Note:** since v2.11 uftpd logs a lot more events by default. Set up +> your syslogd to redirect `LOG_FTP` to a separate log file, or reduce +> the log level of uftpd using `-l error` to only log errors and higher. Running from inetd ------------------ @@ -88,7 +91,7 @@ Caveat ------ -uftpd is primarily not targetted at secure installations, it is targeted +uftpd is primarily not targeted at secure installations, it is targeted at users in need of a *simple* FTP/TFTP server. uftpd allows symlinks outside the FTP root, as well as a group writable @@ -105,14 +108,25 @@ and [lite][]. See their respective README for details, there should be no real surprises, both use the familiar configure, make, make install. +To find the two libraries uftpd depends on `pkg-config`. The package +name for your Linux distribution varies, on Debian/Ubuntu systems: + +```shell +user@example:~/> sudo apt install pkg-config +``` + uftpd, as well as its dependencies, can be built as `.deb` packages on -Debian or Ubuntu based distributions. Simply download each source -component and run +Debian or Ubuntu based distributions. Download and install each of the +dependencies, and then run ./autogen.sh <--- Only needed if using GIT sources ./configure make package +The `.deb` package takes care of setting up `/etc/inetd.conf`, create an +`ftp` user and an `/srv/ftp` home directory with write permissions for +all members of the `users` group. + If you are using a different Linux or UNIX distribution, check the output from `./configure --help`, followed by `make all install`. For instance, building on [Alpine Linux](https://alpinelinux.org/): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/uftpd-2.7/configure.ac new/uftpd-2.11/configure.ac --- old/uftpd-2.7/configure.ac 2019-03-03 15:52:00.000000000 +0100 +++ new/uftpd-2.11/configure.ac 2020-01-05 08:51:54.000000000 +0100 @@ -1,4 +1,5 @@ -AC_INIT([uftpd], [2.7], [https://github.com/troglobit/uftpd/issues],, [http://troglobit.com/uftpd.html]) +AC_INIT([uftpd], [2.11], [https://github.com/troglobit/uftpd/issues],, + [https://troglobit.com/projects/uftpd/]) AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz]) AM_SILENT_RULES([yes]) @@ -11,7 +12,6 @@ AC_PROG_INSTALL # Configuration. -AC_HEADER_STDC AC_CHECK_HEADERS(sys/time.h) AC_CHECK_FUNCS(strstr getopt getsubopt gettimeofday) @@ -20,6 +20,9 @@ AC_TYPE_UINT16_T AC_TYPE_UINT32_T +# Check for pkg-config first, warn if it's not installed +PKG_PROG_PKG_CONFIG + # Check for required libraries PKG_CHECK_MODULES([uev], [libuev >= 2.2.0]) PKG_CHECK_MODULES([lite], [libite >= 1.5.0]) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/uftpd-2.7/debian/.gitignore new/uftpd-2.11/debian/.gitignore --- old/uftpd-2.7/debian/.gitignore 1970-01-01 01:00:00.000000000 +0100 +++ new/uftpd-2.11/debian/.gitignore 2020-01-05 08:51:54.000000000 +0100 @@ -0,0 +1,8 @@ +autoreconf.* +debhelper-build-stamp +files +uftpd.debhelper.log +uftpd.post* +uftpd.pre* +uftpd.substvars +uftpd/ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/uftpd-2.7/debian/changelog new/uftpd-2.11/debian/changelog --- old/uftpd-2.7/debian/changelog 2019-03-03 15:52:00.000000000 +0100 +++ new/uftpd-2.11/debian/changelog 2020-01-05 08:51:54.000000000 +0100 @@ -1,7 +1,48 @@ +uftpd (2.11) unstable; urgency=medium + + * Increased logging at default log level. Now all relevant interaction + is logged. See the man page for how to adjust. + * Fix buffer overflow in FTP PORT parser + * Fix TFTP/FTP directory traversal regression + * Fix potential DOS through non-busy loop and segfault + * Fix potential segfault through empty FTP password + * Fix potential segfault through FTP PORT command + + -- Joachim Nilsson <[email protected]> Sun, 05 Jan 2020 08:49:56 +0100 + +uftpd (2.10) unstable; urgency=medium + + * Add support for TFTP WRQ, i.e. for clients sending files to server + * Fix invalid TFTP error codes, now uses custom error string to code 0 + * Slightly improved debug messages + + -- Joachim Nilsson <[email protected]> Thu, 15 Aug 2019 08:59:35 +0200 + +uftpd (2.9) unstable; urgency=medium + + * Check FTP root security after dropping privileges, issue #22 + * Revert insecure default: "writable FTP root", introduced in v2.8 + * Revert part of issue #18 to fix issue #23; "CWD /" doesn't work + * Update debian packaging to policy 4.3.0 + * Fix failing postrm script, causing dpkg -P uftpd to fail hard + * Fix spelling errors found by Lintian + * Fix package description, more formal and less personal, thanks Lintian + + -- Joachim Nilsson <[email protected]> Mon, 29 Jul 2019 10:52:49 +0200 + +uftpd (2.8) unstable; urgency=medium + + * Fix off-by-one regression introduced in v2.5 + * Convert all commands from user to uppercase for processing + * Skip any and *all* FTP LIST options + * Enable users group writable FTP root in /etc/inetd.conf + + -- Joachim Nilsson <[email protected]> Tue, 28 May 2019 06:22:18 +0200 + uftpd (2.7) unstable; urgency=medium * Bug fix release - * Fix running uftpd as unpriviliged user using a relative FTP root + * Fix running uftpd as unprivileged user using a relative FTP root -- Joachim Nilsson <[email protected]> Sun, 03 Mar 2019 11:39:03 +0100 @@ -52,7 +93,7 @@ A user must now be member of the users group to share files over TFTP/FTP. Simply add a user to 'users' and they can upload their - files to /srv/ftp. The TFT/FTP server itself has no rights to + files to /srv/ftp. The TFTP/FTP server itself has no rights to write there. Add an uploads/ sub-directory with write perms for the 'ftp' user if you want to enable anonymous uploads via FTP. @@ -113,7 +154,7 @@ * New upstream release: - Fix insecure chroot(), reported by Coverity Scan, CID #54523 - - Minor updates to README and a new CHANGLOG file + - Minor updates to README and a new CHANGELOG file -- Joachim Nilsson <[email protected]> Sun, 2 Feb 2015 06:45:06 +0100 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/uftpd-2.7/debian/compat new/uftpd-2.11/debian/compat --- old/uftpd-2.7/debian/compat 2019-03-03 15:52:00.000000000 +0100 +++ new/uftpd-2.11/debian/compat 2020-01-05 08:51:54.000000000 +0100 @@ -1 +1 @@ -7 +10 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/uftpd-2.7/debian/config new/uftpd-2.11/debian/config --- old/uftpd-2.7/debian/config 2019-03-03 15:52:00.000000000 +0100 +++ new/uftpd-2.11/debian/config 2020-01-05 08:51:54.000000000 +0100 @@ -1,4 +1,6 @@ -#!/bin/sh -e +#!/bin/sh + +set -e . /usr/share/debconf/confmodule db_title uftpd diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/uftpd-2.7/debian/control new/uftpd-2.11/debian/control --- old/uftpd-2.7/debian/control 2019-03-03 15:52:00.000000000 +0100 +++ new/uftpd-2.11/debian/control 2020-01-05 08:51:54.000000000 +0100 @@ -1,10 +1,10 @@ Source: uftpd Section: net -Priority: extra +Priority: optional Maintainer: Joachim Nilsson <[email protected]> -Build-Depends: debhelper (>= 7.0.0) -Standards-Version: 3.9.3 -Homepage: http://troglobit.com/uftpd.html +Build-Depends: debhelper (>= 10) +Standards-Version: 4.3.0 +Homepage: https://troglobit.com/projects/uftpd/ Package: uftpd Architecture: any @@ -12,12 +12,15 @@ Depends: openbsd-inetd | inet-superserver, debconf (>= 0.2.17), ${shlibs:Depends}, ${misc:Depends} Provides: ftp-server Conflicts: ftp-server, tftpd, tftpd-hpa -Description: The no nonsense TFTP/FTP server. - An excellent choice for those of us who never wanted to learn every - config file format on this planet. uftpd has no configuration, and - starts automatically from the traditional UNIX inetd super server, - neatly tcpwrapped for your safety. +Description: No nonsense TFTP/FTP server + uftpd is a small and simple TFTP and FTP server intended for LANs. Its + author runs it on the Internet, although this is not recommended. + . + uftpd is set up in a read-only configuration by default. It has no + users, except for anonymous, no configuration file, and is started + on-demand by the UNIX inetd super server, neatly tcpwrapped for your + safety. . Hardcore Internet users and anyone concerned about security should - probably consider a seperate TFTP server and for FTP look at one of: - vsftpd, proftpd or pure-ftpd. + probably consider a separate TFTP server and for FTP look at one of: + vsftpd, proftpd, or pure-ftpd. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/uftpd-2.7/debian/postinst new/uftpd-2.11/debian/postinst --- old/uftpd-2.7/debian/postinst 2019-03-03 15:52:00.000000000 +0100 +++ new/uftpd-2.11/debian/postinst 2020-01-05 08:51:54.000000000 +0100 @@ -1,4 +1,5 @@ #!/bin/sh + set -e [ "$1" = "configure" ] || exit 0 @@ -6,8 +7,8 @@ # Source debconf library. . /usr/share/debconf/confmodule -FTPENTRY="ftp stream tcp nowait root /usr/sbin/tcpd /usr/sbin/in.ftpd" -TFTPENTRY="tftp dgram udp wait root /usr/sbin/tcpd /usr/sbin/in.tftpd" +FTPENTRY="ftp stream tcp nowait root /usr/sbin/tcpd in.ftpd" +TFTPENTRY="tftp dgram udp wait root /usr/sbin/tcpd in.tftpd" if [ ! -f /etc/inetd.conf -a -d /etc/xinetd.d -a -x /usr/sbin/xinetd ]; then cat <<-TEXT diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/uftpd-2.7/debian/postrm new/uftpd-2.11/debian/postrm --- old/uftpd-2.7/debian/postrm 2019-03-03 15:52:00.000000000 +0100 +++ new/uftpd-2.11/debian/postrm 2020-01-05 08:51:54.000000000 +0100 @@ -1,24 +1,20 @@ #!/bin/sh - set -e if [ "$1" = "purge" ]; then if command -v update-inetd >/dev/null 2>&1; then - update-inetd --pattern '/usr/sbin/uftpd' --remove ".*ftp" - update-inetd --pattern '/usr/sbin/in.ftpd' --remove ftp - update-inetd --pattern '/usr/sbin/in.tftpd' --remove tftp + update-inetd --pattern 'uftpd' --remove ".*ftp" + update-inetd --pattern 'in.ftpd' --remove ftp + update-inetd --pattern 'in.tftpd' --remove tftp fi # Remove uftpd entries from db if [ -f /usr/share/debconf/confmodule ]; then . /usr/share/debconf/confmodule - db_purge uftpd/ftp - db_purge uftpd/tftp + db_purge fi fi -deluser ftp || true - -#DEBHELPER# +deluser --quiet --system ftp exit 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/uftpd-2.7/debian/preinst new/uftpd-2.11/debian/preinst --- old/uftpd-2.7/debian/preinst 2019-03-03 15:52:00.000000000 +0100 +++ new/uftpd-2.11/debian/preinst 1970-01-01 01:00:00.000000000 +0100 @@ -1,5 +0,0 @@ -#!/bin/sh - -set -e - -#DEBHELPER# diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/uftpd-2.7/debian/prerm new/uftpd-2.11/debian/prerm --- old/uftpd-2.7/debian/prerm 2019-03-03 15:52:00.000000000 +0100 +++ new/uftpd-2.11/debian/prerm 2020-01-05 08:51:54.000000000 +0100 @@ -2,7 +2,5 @@ set -e -update-inetd --pattern '/usr/sbin/in.ftpd' --multi --disable ftp -update-inetd --pattern '/usr/sbin/in.tftpd' --multi --disable tftp - -#DEBHELPER# +update-inetd --pattern 'in.ftpd' --multi --disable ftp +update-inetd --pattern 'in.tftpd' --multi --disable tftp diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/uftpd-2.7/debian/rules new/uftpd-2.11/debian/rules --- old/uftpd-2.7/debian/rules 2019-03-03 15:52:00.000000000 +0100 +++ new/uftpd-2.11/debian/rules 2020-01-05 08:51:54.000000000 +0100 @@ -1,45 +1,15 @@ #!/usr/bin/make -f -# Simple debian/rules that uses debhelper(7). -# GNU copyright 1997 by Joey Hess. -.PHONY: build clean binary-indep binary-arch binary install +# export DH_VERBOSE=1 +export DEB_BUILD_MAINT_OPTIONS = hardening=+all -build: - dh_testdir - dh_auto_configure - dh_auto_build +%: + dh $@ --with autoreconf,systemd -clean: - dh_testdir - dh_testroot - dh_clean +override_dh_installchangelogs: + dh_installchangelogs ChangeLog.md -install: build - dh_testdir - dh_testroot - dh_prep - dh_installdirs +# Remove LICENSE and ChangeLog.md per Debian Policy +override_dh_auto_install: dh_auto_install - -binary-indep: build install - dh_installdocs - dh_installdebconf - dh_installman - dh_installchangelogs - -binary-arch: build install - dh_strip - rm -f debian/uftpd/usr/share/doc/uftpd/LICENSE - rm -f debian/uftpd/usr/share/doc/uftpd/ChangeLog.md - dh_compress - dh_fixperms - dh_installdebconf - dh_installdeb - dh_shlibdeps - dh_gencontrol - dh_md5sums - dh_builddeb - -source diff: - @echo >&2 'source and diff are obsolete - use dpkg-source -b'; false - -binary: binary-indep binary-arch + rm -v debian/uftpd/usr/share/doc/uftpd/LICENSE + rm -v debian/uftpd/usr/share/doc/uftpd/ChangeLog.md diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/uftpd-2.7/debian/templates new/uftpd-2.11/debian/templates --- old/uftpd-2.7/debian/templates 2019-03-03 15:52:00.000000000 +0100 +++ new/uftpd-2.11/debian/templates 2020-01-05 08:51:54.000000000 +0100 @@ -1,10 +1,10 @@ Template: uftpd/ftp Type: boolean Default: true -Description: Enable FTP service +Description: Enable FTP service? Template: uftpd/tftp Type: boolean Default: true -Description: Enable TFTP service +Description: Enable TFTP service? diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/uftpd-2.7/man/uftpd.8 new/uftpd-2.11/man/uftpd.8 --- old/uftpd-2.7/man/uftpd.8 2019-03-03 15:52:00.000000000 +0100 +++ new/uftpd-2.11/man/uftpd.8 2020-01-05 08:51:54.000000000 +0100 @@ -13,9 +13,9 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd Mar 03, 2019 +.Dd Aug 12, 2019 .Dt UFTPD 8 -.Os "uftpd (2.7)" +.Os "uftpd (2.10)" .Sh NAME .Nm uftpd .Nd @@ -23,7 +23,7 @@ .Sh SYNOPSIS .Nm .Op Fl hnsv -.Op Fl l Ar LVL +.Op Fl l Ar LOG .Op Fl o Ar ftp=PORT,tftp=PORT,writable .Op Ar PATH .Sh DESCRIPTION @@ -41,8 +41,7 @@ .Nm this means listen to port 21 (FTP) and port 69 (TFTP), serve files from .Pa /srv/ftp , -and log anything out of the ordinary to syslog. Messages are written to -the syslog using the +and log to syslog. Messages are written to the syslog using the .Nm LOG_FTP facility. .Pp @@ -50,16 +49,25 @@ .Bl -tag -width Ds .It Fl h Show built-in help text -.It Fl l Ar LVL -Set log level: none, err, info, +.It Fl l Ar LOG +Set log level: none, err, .Ar notice , -debug +info, debug. By default the log level is +.Ar notice , +which is less verbose than +.Ar info , +but still logs all relevant events: users logging in, uploading, +downloading, creating and removing directories, etc. To reduce +the log level, start +.Nm +with +.Cm Fl l Ar error . .It Fl n Run in foreground, do not detach from controlling terminal .It Fl o Set .Nm -option, seprate multiple options with comma: +option, separate multiple options with comma: .Bl -tag .It Ar ftp=PORT .It Ar tftp=PORT @@ -130,7 +138,7 @@ The FTP server currently supports the following requests. The case of the requests is ignored. .Bl -column "Request" -offset indent -.It Request Ta "Description" +.It Sy Request Ta Sy "Description" .It ABOR Ta "abort current transfer" .It CDUP Ta "shorthand for CD .. command" .It CWD Ta "change working directory" @@ -174,15 +182,18 @@ .Pp The TFTP server currently supports the following requests. .Bl -column "Request" -offset indent -.It RRQ -.It ERROR -.It ACK +.It Sy Request Ta Sy Description +.It RRQ Ta Read Request for file, may have options +.It WRQ Ta Write Request for file, may have options +.It DATA Ta File data, preceded by block n:o +.It ERROR Ta Error, end of session +.It ACK Ta ACKnowledge DATA or WRQ without options +.It OACK Ta Option acknowledged, sent as response to RRQ/WRQ .El .Pp .Nm supports TFTP blocksize negotiation, according to RFC2348, so full sized -Ethernet frames can be used, which greatly speeds up transfers. Support -for WRQ is not yet implemented, patches welcome! +Ethernet frames can be used, which greatly speeds up transfers. .Pp .Sh FILES .Bl -tag -width /etc/ftpwelcome -compact diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/uftpd-2.7/src/.gitignore new/uftpd-2.11/src/.gitignore --- old/uftpd-2.7/src/.gitignore 1970-01-01 01:00:00.000000000 +0100 +++ new/uftpd-2.11/src/.gitignore 2020-01-05 08:51:54.000000000 +0100 @@ -0,0 +1 @@ +uftpd \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/uftpd-2.7/src/common.c new/uftpd-2.11/src/common.c --- old/uftpd-2.7/src/common.c 2019-03-03 15:52:00.000000000 +0100 +++ new/uftpd-2.11/src/common.c 2020-01-05 08:51:54.000000000 +0100 @@ -83,20 +83,24 @@ memset(rpath, 0, sizeof(rpath)); if (!realpath(ptr, rpath)) { - ERR(errno, "Failed realpath(%s)", ptr); + INFO("Failed realpath(%s): %m", ptr); return NULL; } + DBG("realpath(%s) => %s", ptr, rpath); + if (rpath[1] != 0) strlcat(rpath, "/", sizeof(rpath)); strlcat(rpath, name, sizeof(rpath)); } - if (!chrooted && strncmp(dir, home, strlen(home))) { + if (!chrooted && strncmp(rpath, home, strlen(home))) { DBG("Failed non-chroot dir:%s vs home:%s", dir, home); return NULL; } + DBG("Final path to file: %s", rpath); + return rpath; } @@ -260,6 +264,15 @@ if (!fail1 && !fail2) INFO("Successfully dropped privilges to %d:%d (uid:gid)", pw->pw_uid, pw->pw_gid); + /* + * Check we don't have write access to the FTP root, + * unless explicitly allowed + */ + if (!do_insecure && !access(home, W_OK)) { + ERR(0, "FTP root %s writable, possible security violation, aborting session!", home); + goto fail; + } + /* On failure, we tried at least. Only warn once. */ privs_dropped = 1; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/uftpd-2.7/src/ftpcmd.c new/uftpd-2.11/src/ftpcmd.c --- old/uftpd-2.7/src/ftpcmd.c 2019-03-03 15:52:00.000000000 +0100 +++ new/uftpd-2.11/src/ftpcmd.c 2020-01-05 08:51:54.000000000 +0100 @@ -16,6 +16,7 @@ */ #include "uftpd.h" +#include <ctype.h> #include <arpa/ftp.h> #ifdef HAVE_SYS_TIME_H # include <sys/time.h> @@ -126,7 +127,7 @@ *cmd = msg; *argument = NULL; - DBG("Recv: [%s], %d bytes", msg, bytes); + DBG("Recv: [%s], %zd bytes", msg, bytes); return 0; } @@ -149,6 +150,9 @@ if (ptr) *ptr = 0; + /* Convert command to std ftp upper case, issue #18 */ + for (ptr = msg; *ptr; ++ptr) *ptr = toupper(*ptr); + DBG("Recv: %s %s", *cmd, *argument ?: ""); return 0; @@ -329,6 +333,11 @@ return; } + if (!pass) { + send_msg(ctrl->sd, "503 No password given.\r\n"); + return; + } + strlcpy(ctrl->pass, pass, sizeof(ctrl->pass)); if (check_user_pass(ctrl) < 0) { LOG("User %s from %s, invalid password!", ctrl->name, ctrl->clientaddr); @@ -395,6 +404,8 @@ */ dir = compose_abspath(ctrl, path); if (!dir || stat(dir, &st) || !S_ISDIR(st.st_mode)) { + DBG("chrooted:%d, ctrl->cwd: %s, home:%s, dir:%s, len:%zd, dirlen:%zd", + chrooted, ctrl->cwd, home, dir, strlen(home), strlen(dir)); send_msg(ctrl->sd, "550 No such directory.\r\n"); return; } @@ -404,10 +415,13 @@ DBG("non-chrooted CWD, home:%s, dir:%s, len:%zd, dirlen:%zd", home, dir, len, strlen(dir)); - if (len <= strlen(dir)) - dir += len; + dir += len; } + snprintf(ctrl->cwd, sizeof(ctrl->cwd), "%s", dir); + if (ctrl->cwd[0] == 0) + snprintf(ctrl->cwd, sizeof(ctrl->cwd), "/"); + done: DBG("New CWD: '%s'", ctrl->cwd); send_msg(ctrl->sd, "250 OK\r\n"); @@ -430,9 +444,14 @@ ctrl->data_sd = -1; } + if (!str) { + send_msg(ctrl->sd, "500 No PORT specified.\r\n"); + return; + } + /* Convert PORT command's argument to IP address + port */ sscanf(str, "%d,%d,%d,%d,%d,%d", &a, &b, &c, &d, &e, &f); - sprintf(addr, "%d.%d.%d.%d", a, b, c, d); + snprintf(addr, sizeof(addr), "%d.%d.%d.%d", a, b, c, d); /* Check IPv4 address using inet_aton(), throw away converted result */ if (!inet_aton(addr, &(sin.sin_addr))) { @@ -748,12 +767,15 @@ /* Check if client sends ls arguments ... */ ptr = arg; while (*ptr) { - if (*ptr == ' ') + if (isspace(*ptr)) ptr++; - if (string_match(ptr, "-l")) - ptr += 2; - else - break; + + if (*ptr == '-') { + while (*ptr && !isspace(*ptr)) + ptr++; + } + + break; } /* Strip any "" from "<arg>" */ @@ -761,10 +783,11 @@ char *ptr2; ptr2 = strchr("[1], '"'); - if (ptr2) { - memmove(ptr2, &ptr2[1], strlen(ptr2)); - memmove(quot, "[1], strlen(quot)); - } + if (!ptr2) + break; + + memmove(ptr2, &ptr2[1], strlen(ptr2)); + memmove(quot, "[1], strlen(quot)); } arg = ptr; } @@ -782,8 +805,13 @@ ctrl->file = strdup(arg ? arg : ""); ctrl->i = 0; ctrl->d_num = scandir(path, &ctrl->d, NULL, alphasort); - DBG("Reading directory %s ... %d number of entries", path, ctrl->d_num); + if (ctrl->d_num == -1) { + send_msg(ctrl->sd, "550 No such file or directory.\r\n"); + DBG("Failed reading directory '%s': %s", path, strerror(errno)); + return; + } + DBG("Reading directory %s ... %d number of entries", path, ctrl->d_num); if (ctrl->data_sd > -1) { send_msg(ctrl->sd, "125 Data connection already open; transfer starting.\r\n"); uev_io_init(ctrl->ctx, &ctrl->data_watcher, do_LIST, ctrl, ctrl->data_sd, UEV_WRITE); @@ -903,7 +931,7 @@ return 1; } - INFO("Data server port estabished. Waiting for client connnect ..."); + INFO("Data server port established. Waiting for client to connect ..."); if (listen(ctrl->data_listen_sd, 1) < 0) { ERR(errno, "Client data connection failure"); send_msg(ctrl->sd, "426 Internal server error.\r\n"); @@ -993,7 +1021,7 @@ num = fread(buf, sizeof(char), sizeof(buf), ctrl->fp); if (!num) { if (feof(ctrl->fp)) - INFO("User %s from %s downloaded %s", ctrl->name, ctrl->clientaddr, ctrl->file); + LOG("User %s from %s downloaded '%s'", ctrl->name, ctrl->clientaddr, ctrl->file); else if (ferror(ctrl->fp)) ERR(0, "Error while reading %s", ctrl->file); do_abort(ctrl); @@ -1006,7 +1034,7 @@ gettimeofday(&tv, NULL); if (tv.tv_sec - ctrl->tv.tv_sec > 3) { - DBG("Sending %d bytes of %s to %s ...", num, ctrl->file, ctrl->clientaddr); + DBG("Sending %zd bytes of %s to %s ...", num, ctrl->file, ctrl->clientaddr); ctrl->tv.tv_sec = tv.tv_sec; } @@ -1073,7 +1101,13 @@ struct stat st; path = compose_abspath(ctrl, file); - if (!path || stat(path, &st) || !S_ISREG(st.st_mode)) { + if (!path || stat(path, &st)) { + LOG("%s: Failed opening '%s'. No such file or directory", ctrl->clientaddr, path); + send_msg(ctrl->sd, "550 No such file or directory.\r\n"); + return; + } + if (!S_ISREG(st.st_mode)) { + LOG("%s: Failed opening '%s'. Not a regular file", ctrl->clientaddr, path); send_msg(ctrl->sd, "550 Not a regular file.\r\n"); return; } @@ -1107,6 +1141,7 @@ do_PORT(ctrl, 2); } +/* Request to set mtime, ncftp does this */ static void handle_MDTM(ctrl_t *ctrl, char *file) { struct stat st; @@ -1115,16 +1150,19 @@ char *mtime = NULL; char buf[80]; - /* Request to set mtime, ncftp does this */ + if (!file) + goto missing; + ptr = strchr(file, ' '); if (ptr) { *ptr++ = 0; mtime = file; file = ptr; - } + } path = compose_abspath(ctrl, file); if (!path || stat(path, &st) || !S_ISREG(st.st_mode)) { + missing: send_msg(ctrl->sd, "550 Not a regular file.\r\n"); return; } @@ -1149,6 +1187,8 @@ ERR(errno, "Failed setting MTIME %s of %s", mtime, file); goto fail; } + + LOG("User %s from %s changed mtime of %s", ctrl->name, ctrl->clientaddr, file); (void)stat(path, &st); } @@ -1191,7 +1231,7 @@ return; } if (bytes == 0) { - INFO("User %s at %s uploaded file %s", ctrl->name, ctrl->clientaddr, ctrl->file); + LOG("User %s from %s uploaded file %s", ctrl->name, ctrl->clientaddr, ctrl->file); do_abort(ctrl); send_msg(ctrl->sd, "226 Transfer complete.\r\n"); return; @@ -1216,13 +1256,14 @@ path = compose_abspath(ctrl, file); if (!path) { - ERR(errno, "Invalid path for %s", file); + INFO("Invalid path for %s: %m", file); goto fail; } DBG("Trying to write to %s ...", path); fp = fopen(path, "wb"); if (!fp) { + /* If EACCESS client is trying to do something disallowed */ ERR(errno, "Failed writing %s", path); fail: send_msg(ctrl->sd, "451 Trouble storing file.\r\n"); @@ -1265,11 +1306,14 @@ fail: send_msg(ctrl->sd, "550 No such file or directory.\r\n"); else if (EPERM == errno) send_msg(ctrl->sd, "550 Not allowed to remove file or directory.\r\n"); + else if (ENOTEMPTY == errno) + send_msg(ctrl->sd, "550 Not allowed to remove directory, not empty.\r\n"); else send_msg(ctrl->sd, "550 Unknown error.\r\n"); return; } + LOG("User %s from %s deleted %s", ctrl->name, ctrl->clientaddr, file); send_msg(ctrl->sd, "200 Command OK\r\n"); } @@ -1279,7 +1323,7 @@ path = compose_abspath(ctrl, arg); if (!path) { - ERR(errno, "Invalid path for %s", arg); + INFO("Invalid path for %s: %m", arg); goto fail; } @@ -1291,6 +1335,7 @@ return; } + LOG("User %s from %s created directory %s", ctrl->name, ctrl->clientaddr, arg); send_msg(ctrl->sd, "200 Command OK\r\n"); } @@ -1393,7 +1438,7 @@ static void handle_OPTS(ctrl_t *ctrl, char *arg) { /* OPTS MLST type;size;modify;perm; */ - if (strstr(arg, "MLST")) { + if (arg && strstr(arg, "MLST")) { size_t i = 0; char *ptr; char buf[42] = "200 MLST OPTS "; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/uftpd-2.7/src/tftpcmd.c new/uftpd-2.11/src/tftpcmd.c --- old/uftpd-2.7/src/tftpcmd.c 2019-03-03 15:52:00.000000000 +0100 +++ new/uftpd-2.11/src/tftpcmd.c 2020-01-05 08:51:54.000000000 +0100 @@ -19,6 +19,28 @@ #include <poll.h> #include <arpa/tftp.h> +/* + * Theory of operation, from RFC1350: + * + * Client gets file, RRQ: + * + * client server + * |----------- RRQ ---------->| + * |<--------- DATA -----------| + * |----------- ACK ---------->| + * | | + * + * Client puts file, WRQ: + * + * client server + * |----------- WRQ ---------->| + * |<---------- ACK -----------| + * |---------- DATA ---------->| + * |<---------- ACK -----------| + * | | + * + */ + /* Send @len bytes data in @ctrl->buf */ static int do_send(ctrl_t *ctrl, size_t len) { @@ -32,7 +54,7 @@ if (ctrl->th->th_opcode == OACK) hdrsz = ctrl->th->th_stuff - ctrl->buf; - DBG("tftp sending %zd + %zd bytes ...", hdrsz, len); + DBG("SND %c: header size: %zd, data len: %zd ...", ctrl->th->th_code, hdrsz, len); result = sendto(ctrl->sd, ctrl->buf, hdrsz + len, 0, (struct sockaddr *)&ctrl->client_sa, salen); if (-1 == result) return 1; @@ -67,21 +89,22 @@ return do_send(ctrl, len); } -#if 0 /* TODO, for client op */ -static int send_ACK(ctrl_t *ctrl) +static int send_ACK(ctrl_t *ctrl, int block) { - return 0; + memset(ctrl->buf, 0, ctrl->bufsz); + + ctrl->th->th_opcode = htons(ACK); + ctrl->th->th_block = htons(block); + DBG("ACK block %d", block); + + return do_send(ctrl, 4); } -#endif /* Acknowledge options sent by client */ static int send_OACK(ctrl_t *ctrl) { char *ptr; - if (!ctrl->tftp_options) - return 0; - memset(ctrl->buf, 0, ctrl->bufsz); /* Create message */ @@ -99,10 +122,13 @@ return do_send(ctrl, ptr - ctrl->buf); } -static int send_ERROR(ctrl_t *ctrl, int code) +static int send_ERROR(ctrl_t *ctrl, int code, char *str) { - char *str = strerror(code); - size_t len = strlen(str); + size_t len; + + if (!str) + str = strerror(code); + len = strlen(str); memset(ctrl->buf, 0, ctrl->segsize); @@ -110,6 +136,7 @@ ctrl->th->th_opcode = htons(ERROR); ctrl->th->th_code = htons(code); strlcpy(ctrl->th->th_msg, str, len); + DBG("ERR %d: %s", code, str); /* Error is ASCIIZ string, hence +1 */ return do_send(ctrl, len + 1); @@ -138,15 +165,15 @@ return 0; } -/* Parse TFTP payload in RRQ to get filename and optional blksize & timeout */ -static int parse_RRQ(ctrl_t *ctrl, char *buf, size_t len) +/* Parse TFTP payload in WRQ/RRQ for filename and optional blksize+timeout */ +static int parse_RWRQ(ctrl_t *ctrl, char *buf, size_t len) { size_t opt_len = strlen(buf) + 1; /* First opt is always filename */ ctrl->file = strdup(buf); if (!ctrl->file) - return send_ERROR(ctrl, ENOMEM); + return send_ERROR(ctrl, EUNDEF, NULL); do { /* Prepare to read options */ @@ -167,13 +194,17 @@ if (alloc_buf(ctrl, sz)) { ERR(errno, "Failed reallocating TFTP buffer memory"); - return send_ERROR(ctrl, ENOMEM); + return send_ERROR(ctrl, EUNDEF, NULL); } + DBG("Negotiated blksize %zd", sz); setbit(&ctrl->tftp_options, 1); } } while (len); + if (!ctrl->tftp_options) + return 0; + return send_OACK(ctrl); } @@ -184,18 +215,67 @@ path = compose_path(ctrl, ctrl->file); if (!path) { ERR(errno, "%s: Invalid path to file %s", ctrl->clientaddr, ctrl->file); - return send_ERROR(ctrl, ENOTFOUND); + return send_ERROR(ctrl, ENOTFOUND, NULL); } ctrl->fp = fopen(path, "r"); if (!ctrl->fp) { - ERR(errno, "%s: Failed opening %s", ctrl->clientaddr, path); - return send_ERROR(ctrl, ENOTFOUND); + ERR(errno, "%s: Failed opening '%s'", ctrl->clientaddr, path); + return send_ERROR(ctrl, ENOTFOUND, NULL); } return !send_DATA(ctrl, 0); } +static int handle_WRQ(ctrl_t *ctrl) +{ + char *path; + + path = compose_path(ctrl, ctrl->file); + if (!path) { + ERR(errno, "%s: Invalid path to file %s", ctrl->clientaddr, ctrl->file); + return send_ERROR(ctrl, ENOTFOUND, NULL); + } + + ctrl->offset = 1; /* First expected block */ + ctrl->fp = fopen(path, "w"); + if (!ctrl->fp) { + ERR(errno, "%s: Failed opening '%s'", ctrl->clientaddr, path); + return send_ERROR(ctrl, ENOTFOUND, NULL); + } + + if (ctrl->tftp_options) + return 0; + + return send_ACK(ctrl, 0); +} + +static int handle_DATA(ctrl_t *ctrl, size_t len) +{ + char errmsg[80]; + int block; + + block = ntohs(ctrl->th->th_block); + if (block != ctrl->offset) { + snprintf(errmsg, sizeof(errmsg), "Expected block %ld, " + "got DATA for block %d", ctrl->offset, block); + return !send_ERROR(ctrl, EUNDEF, errmsg); + } + + DBG("tftp block %d writing %zd bytes ...", ctrl->th->th_block, len); + if (len != fwrite(ctrl->th->th_data, sizeof(char), len, ctrl->fp)) { + snprintf(errmsg, sizeof(errmsg), "Failed writing file: %s", + strerror(errno)); + return !send_ERROR(ctrl, ENOSPACE, errmsg); + } + + ctrl->offset++; + if (send_ACK(ctrl, block) || len < ctrl->segsize) + return 0; + + return 1; +} + /* TODO: Add support for ACK timeout and resend */ static int handle_ACK(ctrl_t *ctrl, int block) { @@ -243,22 +323,40 @@ switch (op) { case RRQ: len -= ctrl->th->th_stuff - ctrl->buf; - if (parse_RRQ(ctrl, ctrl->th->th_stuff, len)) { + if (parse_RWRQ(ctrl, ctrl->th->th_stuff, len)) { ERR(errno, "Failed parsing TFTP RRQ"); active = 0; break; } - DBG("tftp RRQ %s from %s:%d", ctrl->file, ctrl->clientaddr, port); + LOG("tftp RRQ '%s' from %s:%d", ctrl->file, ctrl->clientaddr, port); active = handle_RRQ(ctrl); free(ctrl->file); break; + case WRQ: + len -= ctrl->th->th_stuff - ctrl->buf; + if (parse_RWRQ(ctrl, ctrl->th->th_stuff, len)) { + ERR(errno, "Failed parsing TFTP WRQ"); + active = 0; + break; + } + LOG("tftp WRQ '%s' from %s:%d", ctrl->file, ctrl->clientaddr, port); + handle_WRQ(ctrl); + free(ctrl->file); + break; + + case DATA: /* Received data after WRQ */ + INFO("tftp DATA '%s' from %s:%d", ctrl->file, ctrl->clientaddr, port); + len -= ctrl->th->th_data - ctrl->buf; + active = handle_DATA(ctrl, len); + break; + case ERROR: DBG("tftp ERROR: %hd", ntohs(ctrl->th->th_code)); active = 0; break; - case ACK: + case ACK: /* Sent for each DATA we send in a RRQ */ DBG("tftp ACK, block # %hu", block); active = handle_ACK(ctrl, block); break; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/uftpd-2.7/src/uftpd.c new/uftpd-2.11/src/uftpd.c --- old/uftpd-2.7/src/uftpd.c 2019-03-03 15:52:00.000000000 +0100 +++ new/uftpd-2.11/src/uftpd.c 2020-01-05 08:51:54.000000000 +0100 @@ -55,7 +55,7 @@ printf("\nUsage: %s [-hnsv] [-l LEVEL] [-o ftp=PORT,tftp=PORT,writable] [PATH]\n\n", prognm); printf(" -h Show this help text\n" - " -l LEVEL Set log level: none, err, info, notice (default), debug\n"); + " -l LEVEL Set log level: none, err, notice (default), info, debug\n"); if (!is_inetd) printf(" -n Run in foreground, do not detach from controlling terminal\n" " -o OPT Options:\n" @@ -100,7 +100,7 @@ */ static void sigquit_cb(uev_t *w, void *arg, int events) { - INFO("Recieved signal %d, exiting ...", w->signo); + INFO("Received signal %d, exiting ...", w->signo); /* Forward signal to any children in this process group. */ if (killpg(getpgrp(), SIGTERM)) @@ -139,25 +139,6 @@ return port; } -/* - * Check that we don't have write access to the FTP root, - * unless explicitly allowed - */ -static int security_check(char *home) -{ - if (access(home, F_OK)) { - ERR(errno, "Cannot access FTP root %s", home); - return 1; - } - - if (!do_insecure && !access(home, W_OK)) { - ERR(0, "FTP root %s writable, possible security violation!", home); - return 1; - } - - return 0; -} - static int init(uev_ctx_t *ctx) { /* Figure out FTP/TFTP ports */ @@ -178,8 +159,10 @@ } } - if (!home || security_check(home)) + if (!home || access(home, F_OK)) { + ERR(errno, "Cannot access FTP root %s", home ? home : "NIL"); return 1; + } return uev_init(ctx); } @@ -359,7 +342,7 @@ if (optind < argc) { home = realpath(argv[optind], NULL); if (!home) { - ERR(errno, "Invalid FTP root"); + ERR(errno, "Invalid FTP root %s", argv[optind]); return 1; } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/uftpd-2.7/src/uftpd.h new/uftpd-2.11/src/uftpd.h --- old/uftpd-2.7/src/uftpd.h 2019-03-03 15:52:00.000000000 +0100 +++ new/uftpd-2.11/src/uftpd.h 2020-01-05 08:51:54.000000000 +0100 @@ -97,6 +97,7 @@ extern int do_syslog; /* Bool: False at daemon start */ extern int do_ftp; /* Port: FTP port, or disabled */ extern int do_tftp; /* Port: TFTP port, or disabled */ +extern int do_insecure; /* Bool: Allow writable root or not */ extern struct passwd *pw; /* FTP user's passwd entry */ typedef struct tftphdr tftp_t; @@ -125,7 +126,7 @@ char pending; /* Pending op: LIST, RETR, STOR */ char list_mode; /* Current LIST mode */ char *file; /* Current file name to fetch */ - off_t offset; /* Offset in current file, for REST */ + off_t offset; /* Offset/block in current file, for REST/WRQ */ FILE *fp; /* Current file in operation */ int i; /* i of d_num in 'd' */ int d_num; /* Number of entries in 'd' */
