diff --git a/.gitignore b/.gitignore index 63a8518..64ab908 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ pure-ftpd-1.0.29.tar.bz2 /pure-ftpd-1.0.39.tar.bz2 /pure-ftpd-1.0.40.tar.bz2 /pure-ftpd-1.0.42.tar.bz2 +/pure-ftpd-1.0.47.tar.bz2 diff --git a/0001-Exit-when-given-an-invalid-cmdline-option.patch b/0001-Exit-when-given-an-invalid-cmdline-option.patch new file mode 100644 index 0000000..2e069d8 --- /dev/null +++ b/0001-Exit-when-given-an-invalid-cmdline-option.patch @@ -0,0 +1,25 @@ +From 8b6e9370ccbdff47107963c352caab24fdb0fcaa Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ond=C5=99ej=20Lyson=C4=9Bk?= +Date: Wed, 7 Feb 2018 13:28:02 +0100 +Subject: [PATCH 1/2] Exit when given an invalid cmdline option + +--- + src/ftpd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/ftpd.c b/src/ftpd.c +index e19d8de..5c77410 100644 +--- a/src/ftpd.c ++++ b/src/ftpd.c +@@ -6192,7 +6192,7 @@ int pureftpd_start(int argc, char *argv[], const char *home_directory_) + exit(EXIT_SUCCESS); + } + default: +- logfile(LOG_WARNING, MSG_ILLEGAL_OPTION); ++ die(421, LOG_ERR, MSG_ILLEGAL_OPTION); + } + } + #ifdef WITH_RFC2640 +-- +2.14.3 + diff --git a/0001-Fix-postgresql-authenticate-bug.patch b/0001-Fix-postgresql-authenticate-bug.patch new file mode 100644 index 0000000..b6044be --- /dev/null +++ b/0001-Fix-postgresql-authenticate-bug.patch @@ -0,0 +1,25 @@ +From 6a256a21e48177e1d73d7e70b2292c76ac40ffb7 Mon Sep 17 00:00:00 2001 +From: t-asaka +Date: Mon, 28 May 2018 22:29:25 +0900 +Subject: [PATCH] Fix postgresql authenticate bug + +--- + src/log_pgsql.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/log_pgsql.c b/src/log_pgsql.c +index 4df654e..3825afb 100644 +--- a/src/log_pgsql.c ++++ b/src/log_pgsql.c +@@ -504,7 +504,7 @@ void pw_pgsql_check(AuthResult * const result, + crypto_crypt++; + crypto_md5++; + crypto_sha1++; +- } else if (strcasecmp(crypto, PASSWD_SQL_ARGON2)) { ++ } else if (strcasecmp(crypto, PASSWD_SQL_ARGON2) == 0) { + crypto_argon2++; + } else if (strcasecmp(crypto, PASSWD_SQL_SCRYPT) == 0) { + crypto_scrypt++; +-- +2.20.1 + diff --git a/0001-Increase-MAX_DATA_SIZE-due-to-Argon2id-requirements.patch b/0001-Increase-MAX_DATA_SIZE-due-to-Argon2id-requirements.patch new file mode 100644 index 0000000..f9545bd --- /dev/null +++ b/0001-Increase-MAX_DATA_SIZE-due-to-Argon2id-requirements.patch @@ -0,0 +1,25 @@ +From 27a5c200f9643ce907118aad169279b3a66a9e8a Mon Sep 17 00:00:00 2001 +From: Frank Denis +Date: Sat, 4 Nov 2017 20:46:16 +0100 +Subject: [PATCH] Increase MAX_DATA_SIZE due to Argon2id requirements + +--- + src/ftpd.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/ftpd.h b/src/ftpd.h +index 1beeab8..5bb1f6b 100644 +--- a/src/ftpd.h ++++ b/src/ftpd.h +@@ -557,7 +557,7 @@ Your platform has a very large PATH_MAX, we should not trust it. + + #ifndef MAX_DATA_SIZE + # ifdef HAVE_LIBSODIUM +-# define MAX_DATA_SIZE (40 * 1024 * 1024) ++# define MAX_DATA_SIZE (70 * 1024 * 1024) + # elif defined(WITH_LDAP) || defined(WITH_MYSQL) || defined(WITH_PGSQL) + # define MAX_DATA_SIZE (16 * 1024 * 1024) /* Max memory usage - SQL/LDAP need more */ + # else +-- +2.14.3 + diff --git a/0001-Revert-After-20-years-say-goodbye-to-the-external-co.patch b/0001-Revert-After-20-years-say-goodbye-to-the-external-co.patch new file mode 100644 index 0000000..598b630 --- /dev/null +++ b/0001-Revert-After-20-years-say-goodbye-to-the-external-co.patch @@ -0,0 +1,406 @@ +From 54a54e837535f8582634ba18d9008d1ee84aadc1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ond=C5=99ej=20Lyson=C4=9Bk?= +Date: Wed, 6 Feb 2019 09:31:01 +0100 +Subject: [PATCH] Revert "After 20 years, say goodbye to the external config + file parsers" + +This reverts commit 623796f70f336225eb27dee4a82c43b53b9cc466. +--- + Makefile.am | 2 + + configuration-file/Makefile.am | 3 + + configuration-file/pure-config.pl.in | 127 ++++++++++++++++++ + configuration-file/pure-config.py.in | 188 +++++++++++++++++++++++++++ + configure.ac | 11 ++ + 5 files changed, 331 insertions(+) + create mode 100644 configuration-file/Makefile.am + create mode 100644 configuration-file/pure-config.pl.in + create mode 100644 configuration-file/pure-config.py.in + +diff --git a/Makefile.am b/Makefile.am +index 87da26e..a3c769f 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -5,6 +5,7 @@ EXTRA_DIST = \ + CONTACT \ + FAQ \ + Makefile.gui \ ++ README.Configuration-File \ + README.LDAP \ + README.MySQL \ + README.PGSQL \ +@@ -27,6 +28,7 @@ SUBDIRS = \ + man \ + pam \ + gui \ ++ configuration-file \ + m4 + + sysconf_DATA = \ +diff --git a/configuration-file/Makefile.am b/configuration-file/Makefile.am +new file mode 100644 +index 0000000..4639909 +--- /dev/null ++++ b/configuration-file/Makefile.am +@@ -0,0 +1,3 @@ ++CLEANFILES = \ ++ pure-config.pl \ ++ pure-config.py +diff --git a/configuration-file/pure-config.pl.in b/configuration-file/pure-config.pl.in +new file mode 100644 +index 0000000..ea675c8 +--- /dev/null ++++ b/configuration-file/pure-config.pl.in +@@ -0,0 +1,127 @@ ++#! @PERL@ ++ ++# (C) 2001-2013 Aristotle Pagaltzis ++# derived from code (C) 2001-2002 Frank Denis and Matthias Andree ++ ++use strict; ++ ++my ($conffile, @flg) = @ARGV; ++ ++my $PUREFTPD; ++-x && ($PUREFTPD=$_, last) for qw( ++ ${exec_prefix}/sbin/pure-ftpd ++ /usr/local/pure-ftpd/sbin/pure-ftpd ++ /usr/local/pureftpd/sbin/pure-ftpd ++ /usr/local/sbin/pure-ftpd ++ /usr/sbin/pure-ftpd ++); ++ ++my %simple_switch_for = ( ++ IPV4Only => "-4", ++ IPV6Only => "-6", ++ ChrootEveryone => "-A", ++ BrokenClientsCompatibility => "-b", ++ Daemonize => "-B", ++ VerboseLog => "-d", ++ DisplayDotFiles => "-D", ++ AnonymousOnly => "-e", ++ NoAnonymous => "-E", ++ DontResolve => "-H", ++ AnonymousCanCreateDirs => "-M", ++ NATmode => "-N", ++ CallUploadScript => "-o", ++ AntiWarez => "-s", ++ AllowUserFXP => "-w", ++ AllowAnonymousFXP => "-W", ++ ProhibitDotFilesWrite => "-x", ++ ProhibitDotFilesRead => "-X", ++ AllowDotFiles => "-z", ++ AutoRename => "-r", ++ AnonymousCantUpload => "-i", ++ LogPID => "-1", ++ NoChmod => "-R", ++ KeepAllFiles => "-K", ++ CreateHomeDir => "-j", ++ NoRename => "-G", ++ CustomerProof => "-Z", ++ NoTruncate => "-0", ++); ++ ++my %string_switch_for = ( ++ FileSystemCharset => "-8", ++ ClientCharset => "-9", ++ SyslogFacility => "-f", ++ FortunesFile => "-F", ++ ForcePassiveIP => "-P", ++ Bind => "-S", ++ AnonymousBandwidth => "-t", ++ UserBandwidth => "-T", ++ TrustedIP => "-V", ++ AltLog => "-O", ++ PIDFile => "-g", ++ TLSCipherSuite => "-J", ++ CertFile => "-2", ++); ++ ++my %numeric_switch_for = ( ++ MaxIdleTime => "-I", ++ MaxDiskUsage => "-k", ++ TrustedGID => "-a", ++ MaxClientsNumber => "-c", ++ MaxClientsPerIP => "-C", ++ MaxLoad => "-m", ++ MinUID => "-u", ++ TLS => "-Y", ++); ++ ++my %numpairb_switch_for = ( ++ LimitRecursion => "-L", ++ PassivePortRange => "-p", ++ AnonymousRatio => "-q", ++ UserRatio => "-Q", ++); ++ ++my %numpairc_switch_for = ( ++ Umask => "-U", ++ Quota => "-n", ++ PerUserLimits => "-y", ++); ++ ++my %auth_method_for = ( ++ LDAPConfigFile => "ldap", ++ MySQLConfigFile => "mysql", ++ PGSQLConfigFile => "pgsql", ++ PureDB => "puredb", ++ ExtAuth => "extauth", ++); ++ ++my $simple_switch = qr/(@{[join "|", keys %simple_switch_for ]})\s+yes/i; ++my $string_switch = qr/(@{[join "|", keys %string_switch_for ]})\s+(\S+)/i; ++my $numeric_switch = qr/(@{[join "|", keys %numeric_switch_for ]})\s+(\d+)/i; ++my $numpairb_switch = qr/(@{[join "|", keys %numpairb_switch_for ]})\s+(\d+)\s+(\d+)/i; ++my $numpairc_switch = qr/(@{[join "|", keys %numpairc_switch_for ]})\s+(\d+):(\d+)/i; ++my $auth_method = qr/(@{[join "|", keys %auth_method_for ]})\s+(\S+)/i; ++ ++die "Usage: pure-config.pl [extra options]\n" ++ unless defined $conffile; ++ ++open CONF, "< $conffile" or die "Can't open $conffile: $!\n"; ++ ++!/^\s*(?:$|#)/ and (chomp, push @flg, ++ /$simple_switch/i ? ($simple_switch_for{$1}) : ++ /$string_switch/i ? ($string_switch_for{$1} . $2) : ++ /$numeric_switch/i ? ($numeric_switch_for{$1} . $2) : ++ /$numpairb_switch/i ? ($numpairb_switch_for{$1} . "$2:$3") : ++ /$numpairc_switch/i ? ($numpairc_switch_for{$1} . "$2:$3") : ++ /$auth_method/i ? ("-l" . "$auth_method_for{$1}:$2") : ++ /UnixAuthentication\s+yes/i ? ("-l" . "unix") : ++ /PAMAuthentication\s+yes/i ? ("-l" . "pam") : ++ () ++) while ; ++ ++close CONF; ++ ++if (-t STDOUT) { ++ print "Running: $PUREFTPD ", join(" ", @flg), "\n"; ++} ++exec { $PUREFTPD } ($PUREFTPD, @flg) or die "cannot exec $PUREFTPD: $!"; +diff --git a/configuration-file/pure-config.py.in b/configuration-file/pure-config.py.in +new file mode 100644 +index 0000000..c458a20 +--- /dev/null ++++ b/configuration-file/pure-config.py.in +@@ -0,0 +1,188 @@ ++#! @PYTHON@ ++ ++# Original pure-config.py by Frank Denis ++# Copyright 2001 by Joshua Rodman , ++# Modifications Copyright 2001-2009 by Matthias Andree ++# ++# All Rights Reserved ++# ++# Permission to use, copy, modify, and distribute this software ++# in original or modified form for any purpose and without fee ++# is hereby granted, provided that the above copyright notice ++# appear in all copies. ++# ++# Joshua Rodman DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS ++# SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++# AND FITNESS, IN NO EVENT SHALL Joshua Rodman 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. ++ ++"""Pure-FTPd configuration parser. ++ ++ Parse pure-ftpd configuration file to options. ++ If run directly, execute the program. ++ ++""" ++import re ++import os ++import sys ++ ++# autoconf stuff ++if '@sbindir@'[0] == '/': ++ pureftpd = '@sbindir@/pure-ftpd' ++else: ++ pureftpd = '@prefix@/sbin/pure-ftpd' ++ ++argv = sys.argv[1:] ++try: ++ conffile = argv.pop(0) ++except IndexError: ++ print("Usage:", sys.argv[0], " [extra options]") ++ sys.exit(1) ++ ++comment = re.compile("[ ]*#+.*") ++ ++# option_tuple members are lists as follows: ++# 0 - case insensitive regex to match ++# 1 - flag to use ++# remaining - 'None' are placeholders for items matched by the regex ++# the matched items and literal strings are concatenated ++# into a literal option which follows the flag ++ ++option_tuple = ( ++ ["IPV4Only[\s]+yes", "-4" ], ++ ["IPV6Only[\s]+yes", "-6" ], ++ ["FileSystemCharset\s+(\S+)", "-8", None ], ++ ["ClientCharset\s+(\S+)", "-9", None ], ++ ["ChrootEveryone[\s]+yes", "-A" ], ++ ["TrustedGID[\s]+([\d]+)", "-a", None ], ++ ["BrokenClientsCompatibility[\s]+yes", "-b" ], ++ ["MaxClientsNumber\s+(\d+)", "-c", None ], ++ ["Daemonize\s+yes", "-B" ], ++ ["MaxClientsPerIP\s+(\d+)", "-C", None ], ++ ["VerboseLog\s+yes", "-d" ], ++ ["DisplayDotFiles\s+yes", "-D" ], ++ ["AnonymousOnly\s+yes", "-e" ], ++ ["MaxDiskUsage\s+(\d+)", "-k", None ], ++ ["NoAnonymous\s+yes", "-E" ], ++ ["SyslogFacility\s+(\S+)", "-f", None ], ++ ["FortunesFile\s+(\S+)", "-F", None ], ++ ["DontResolve\s+yes", "-H" ], ++ ["MaxIdleTime\s+(\d+)", "-I", None ], ++ ["LDAPConfigFile\s+(\S+)", "-l", "ldap:", None ], ++ ["MySQLConfigFile\s+(\S+)", "-l", "mysql:", None ], ++ ["PGSQLConfigFile\s+(\S+)", "-l", "pgsql:", None ], ++ ["PureDB\s+(\S+)", "-l", "puredb:", None ], ++ ["ExtAuth\s+(\S+)", "-l", "extauth:",None ], ++ ["PAMAuthentication\s+yes", "-l", "pam" ], ++ ["UnixAuthentication\s+yes", "-l", "unix" ], ++ ["LimitRecursion\s+(\d+)\s+(\d+)", "-L", None, ":", None ], ++ ["AnonymousCanCreateDirs\s+yes", "-M" ], ++ ["MaxLoad\s+(\d+)", "-m", None ], ++ ["NATmode\s+yes", "-N" ], ++ ["CallUploadScript\s+yes", "-o" ], ++ ["PassivePortRange\s+(\d+)\s+(\d+)", "-p", None, ":", None ], ++ ["ForcePassiveIP\s+(\S+)", "-P", None ], ++ ["AnonymousRatio\s+(\d+)\s+(\d+)", "-q", None, ":", None ], ++ ["UserRatio\s+(\d+)\s+(\d+)", "-Q", None, ":", None ], ++ ["AntiWarez\s+yes", "-s" ], ++ ["Bind\s+(\S+)", "-S", None ], ++ ["AnonymousBandwidth\s+([:0-9]+)", "-t", None ], ++ ["UserBandwidth\s+([:0-9]+)", "-T", None ], ++ ["Quota\s+([:0-9]+)", "-n", None ], ++ ["Umask\s+(\d+):(\d+)", "-U", None, ":", None ], ++ ["MinUID\s+(\d+)", "-u", None ], ++ ["AllowUserFXP\s+yes", "-w" ], ++ ["AllowAnonymousFXP\s+yes", "-W" ], ++ ["ProhibitDotFilesWrite\s+yes", "-x" ], ++ ["ProhibitDotFilesRead\s+yes", "-X" ], ++ ["AllowDotFiles\s+yes", "-z" ], ++ ["AutoRename\s+yes", "-r" ], ++ ["AnonymousCantUpload\s+yes", "-i" ], ++ ["TrustedIP\s+(\S+)", "-V", None ], ++ ["LogPID\s+yes", "-1" ], ++ ["AltLog\s+(\S+)", "-O", None ], ++ ["NoChmod\s+yes", "-R" ], ++ ["KeepAllFiles\s+yes", "-K" ], ++ ["CreateHomeDir\s+yes", "-j" ], ++ ["NoRename\s+yes", "-G" ], ++ ["CustomerProof\s+yes", "-Z" ], ++ ["NoTruncate\s+yes", "-0" ], ++ ["PIDFile\s+(\S+)", "-g", None ], ++ ["TLSCipherSuite\s+(\S+)", "-J", None ], ++ ["PerUserLimits\s+([:0-9]+)", "-y", None ], ++ ["CertFile\s+(\S+)", "-2", None ], ++ ["TLS\s+(\d)", "-Y", None ]) ++ ++for option in option_tuple: ++ option[0] = re.compile(option[0], re.IGNORECASE) ++ ++ ++def build_argument(match, controls): ++ """construct an argument string ++ match: a match object containing argument values ++ controls: a list controlling the format of the argument ++ ++ Return parameter as string""" ++ ++ argument = "" ++ value = 1 ++ ++ for control in controls: ++ if control: ++ # concat the literal string ++ argument = argument + control ++ else: ++ # concat a value ++ argument = argument + match.group(value) ++ value = value + 1 ++ ++ return argument ++ ++ ++def parse(file_obj): ++ """parse/extract a pure-ftpd configuration ++ file_obj: a readlines() capable object containing the configurion ++ ++ Returns list of arguments as appropriate for exec()""" ++ ++ args = [pureftpd] ++ ++ for line in file_obj.readlines(): ++ if comment.search(line): ++ continue ++ ++ for option in option_tuple: ++ match = option[0].search(line) ++ if match: ++ args.append(option[1]) ++ ++ if len(option) <= 2: ++ # The option takes no argument ++ continue ++ ++ argument = build_argument(match, option[2:]) ++ args.append(argument) ++ ++ return args ++ ++ ++def parse_filename(filename=conffile): ++ """parse/extract a pure-ftpd from a named file ++ filename: text path to file ++ ++ Returns list of arguments as appropriate for exec()""" ++ ++ file_obj = open(filename) ++ return parse(file_obj) ++ ++if __name__ == '__main__': ++ args = parse_filename() ++ ++ if os.isatty(1): ++ print("Running:", args + argv) ++ ++ os.execv(pureftpd, args + argv) +diff --git a/configure.ac b/configure.ac +index 5d91d12..e66a578 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -91,6 +91,14 @@ AX_CHECK_LINK_FLAG([-Wl,-z,relro], [LDFLAGS="$LDFLAGS -Wl,-z,relro"]) + AX_CHECK_LINK_FLAG([-Wl,-z,now], [LDFLAGS="$LDFLAGS -Wl,-z,now"]) + AX_CHECK_LINK_FLAG([-Wl,-z,noexecstack], [LDFLAGS="$LDFLAGS -Wl,-z,noexecstack"]) + ++AC_ARG_VAR(PERL,local path to the perl interpreter) ++perl_possible_path="/usr/bin:/usr/local/bin:/bin:/opt/perl/bin:/opt/perl/usr/bin:/opt/perl/usr/local/bin" ++AC_PATH_PROG(PERL,perl,/usr/bin/env perl,$perl_possible_path) ++ ++AC_ARG_VAR(PYTHON,local path to the python interpreter) ++python_possible_path="/usr/bin:/usr/local/bin:/bin:/opt/python/bin:/opt/python/usr/bin:/opt/python/usr/local/bin" ++AC_PATH_PROG(PYTHON,python,/usr/bin/env python,$python_possible_path) ++ + if test -d /usr/local/include; then + CPPFLAGS="$CPPFLAGS -I/usr/local/include" + fi +@@ -1462,6 +1470,9 @@ AH_VERBATIM([NDEBUG], [/* Never ever ignore assertions */ + AC_CONFIG_FILES(Makefile src/Makefile pam/Makefile man/Makefile + gui/Makefile m4/Makefile pure-ftpd.conf puredb/Makefile + puredb/src/Makefile ++configuration-file/Makefile ++configuration-file/pure-config.pl ++configuration-file/pure-config.py + man/pure-ftpd.8 man/pure-ftpwho.8 man/pure-mrtginfo.8 man/pure-uploadscript.8 + man/pure-statsdecode.8 man/pure-quotacheck.8 man/pure-pw.8 man/pure-pwconvert.8 + man/pure-authd.8) +-- +2.20.1 + diff --git a/0001-Revert-No-more-contrib-Makefile.in.patch b/0001-Revert-No-more-contrib-Makefile.in.patch new file mode 100644 index 0000000..0511017 --- /dev/null +++ b/0001-Revert-No-more-contrib-Makefile.in.patch @@ -0,0 +1,26 @@ +From 889562eeec40e667d76007285aed5d87acae29e1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ond=C5=99ej=20Lyson=C4=9Bk?= +Date: Wed, 6 Feb 2019 12:39:49 +0100 +Subject: [PATCH 1/3] Revert "No more contrib/Makefile.in" + +This reverts commit 86b1ec003b63a82f1bcb016f55f385c6cff89b6c. +--- + configure.ac | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/configure.ac b/configure.ac +index e66a578..cc2534b 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1468,7 +1468,7 @@ AH_VERBATIM([NDEBUG], [/* Never ever ignore assertions */ + #endif]) + + AC_CONFIG_FILES(Makefile src/Makefile pam/Makefile man/Makefile +-gui/Makefile m4/Makefile pure-ftpd.conf puredb/Makefile ++gui/Makefile contrib/Makefile m4/Makefile pure-ftpd.conf puredb/Makefile + puredb/src/Makefile + configuration-file/Makefile + configuration-file/pure-config.pl +-- +2.20.1 + diff --git a/0001-Temporarily-disable-TLSv1.3-support.patch b/0001-Temporarily-disable-TLSv1.3-support.patch new file mode 100644 index 0000000..5297028 --- /dev/null +++ b/0001-Temporarily-disable-TLSv1.3-support.patch @@ -0,0 +1,30 @@ +From f9e232ffb44c96538f2a12c4bc4970f228f971cd Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ond=C5=99ej=20Lyson=C4=9Bk?= +Date: Tue, 12 Feb 2019 11:17:16 +0100 +Subject: [PATCH] Temporarily disable TLSv1.3 support + +Disable TLSv1.3 until support for it is fixed in pure-ftpd. This is a +workaround for the following issue: +https://github.com/jedisct1/pure-ftpd/issues/102 +--- + src/tls.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/src/tls.c b/src/tls.c +index c4e2a1b..41d619f 100644 +--- a/src/tls.c ++++ b/src/tls.c +@@ -301,6 +301,10 @@ int tls_init_library(void) + # endif + # ifdef SSL_OP_NO_TLSv1_2 + SSL_CTX_clear_options(tls_ctx, SSL_OP_NO_TLSv1_2); ++# endif ++ /* Disable TLSv1.3 support until it works properly in pure-ftpd */ ++# ifdef SSL_OP_NO_TLSv1_3 ++ SSL_CTX_set_options(tls_ctx, SSL_OP_NO_TLSv1_3); + # endif + if (tlsciphersuite != NULL) { + if (SSL_CTX_set_cipher_list(tls_ctx, tlsciphersuite) != 1) { +-- +2.20.1 + diff --git a/0001-diraliases-always-set-the-tail-of-the-list-to-NULL.patch b/0001-diraliases-always-set-the-tail-of-the-list-to-NULL.patch new file mode 100644 index 0000000..d5b2523 --- /dev/null +++ b/0001-diraliases-always-set-the-tail-of-the-list-to-NULL.patch @@ -0,0 +1,34 @@ +From 8d0d42542e2cb7a56d645fbe4d0ef436e38bcefa Mon Sep 17 00:00:00 2001 +From: Frank Denis +Date: Tue, 18 Feb 2020 18:36:58 +0100 +Subject: [PATCH] diraliases: always set the tail of the list to NULL + +Spotted and reported by Antonio Norales from GitHub Security Labs. +Thanks! +--- + src/diraliases.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/diraliases.c b/src/diraliases.c +index 4002a36..fb70273 100644 +--- a/src/diraliases.c ++++ b/src/diraliases.c +@@ -93,7 +93,6 @@ int init_aliases(void) + (tail->dir = strdup(dir)) == NULL) { + die_mem(); + } +- tail->next = NULL; + } else { + DirAlias *curr; + +@@ -105,6 +104,7 @@ int init_aliases(void) + tail->next = curr; + tail = curr; + } ++ tail->next = NULL; + } + fclose(fp); + aliases_up++; +-- +2.25.4 + diff --git a/0001-listdir-reuse-a-single-buffer-to-store-every-file-na.patch b/0001-listdir-reuse-a-single-buffer-to-store-every-file-na.patch new file mode 100644 index 0000000..b858686 --- /dev/null +++ b/0001-listdir-reuse-a-single-buffer-to-store-every-file-na.patch @@ -0,0 +1,70 @@ +From a9cb173c3c07e4cdb82c9bb90a28c28289207a4e Mon Sep 17 00:00:00 2001 +From: Frank Denis +Date: Mon, 30 Dec 2019 17:40:04 +0100 +Subject: [PATCH] listdir(): reuse a single buffer to store every file name to + display + +Allocating a new buffer for each entry is useless. + +And as these buffers are allocated on the stack, on systems with a +small stack size, with many entries, the limit can easily be reached, +causing a stack exhaustion and aborting the user session. + +Reported by Antonio Morales from the GitHub Security Lab team, thanks! +--- + src/ls.c | 15 ++++++++------- + 1 file changed, 8 insertions(+), 7 deletions(-) + +diff --git a/src/ls.c b/src/ls.c +index 9d01ecf..d4dd653 100644 +--- a/src/ls.c ++++ b/src/ls.c +@@ -695,6 +695,8 @@ static void listdir(unsigned int depth, int f, void * const tls_fd, + PureFileInfo *s; + PureFileInfo *r; + char *c_buf; ++ char *alloca_subdir; ++ size_t sizeof_subdir; + int d; + + if (depth >= max_ls_depth || matches >= max_ls_files) { +@@ -729,14 +731,12 @@ static void listdir(unsigned int depth, int f, void * const tls_fd, + } + outputfiles(f, tls_fd); + r = dir; ++ sizeof_subdir = PATH_MAX + 1U; ++ if ((alloca_subdir = ALLOCA(sizeof_subdir)) == NULL) { ++ goto toomany; ++ } + while (opt_R && r != s) { + if (r->name_offset != (size_t) -1 && !chdir(FI_NAME(r))) { +- char *alloca_subdir; +- const size_t sizeof_subdir = PATH_MAX + 1U; +- +- if ((alloca_subdir = ALLOCA(sizeof_subdir)) == NULL) { +- goto toomany; +- } + if (SNCHECK(snprintf(alloca_subdir, sizeof_subdir, "%s/%s", + name, FI_NAME(r)), sizeof_subdir)) { + goto nolist; +@@ -765,8 +765,8 @@ static void listdir(unsigned int depth, int f, void * const tls_fd, + free(c_buf); + #endif + listdir(depth + 1U, f, tls_fd, alloca_subdir); ++ + nolist: +- ALLOCA_FREE(alloca_subdir); + if (matches >= max_ls_files) { + goto toomany; + } +@@ -779,6 +779,7 @@ static void listdir(unsigned int depth, int f, void * const tls_fd, + r++; + } + toomany: ++ ALLOCA_FREE(alloca_subdir); + free(names); + free(dir); + names = NULL; +-- +2.25.4 + diff --git a/0001-pure_strcmp-len-s2-can-be-len-s1.patch b/0001-pure_strcmp-len-s2-can-be-len-s1.patch new file mode 100644 index 0000000..375b970 --- /dev/null +++ b/0001-pure_strcmp-len-s2-can-be-len-s1.patch @@ -0,0 +1,28 @@ +From bf6fcd4935e95128cf22af5924cdc8fe5c0579da Mon Sep 17 00:00:00 2001 +From: Frank Denis +Date: Mon, 24 Feb 2020 15:19:43 +0100 +Subject: [PATCH] pure_strcmp(): len(s2) can be > len(s1) + +Reported by Antonio Morales from GitHub Security Labs, thanks! +--- + src/utils.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/src/utils.c b/src/utils.c +index f41492d..5e88104 100644 +--- a/src/utils.c ++++ b/src/utils.c +@@ -45,5 +45,9 @@ int pure_memcmp(const void * const b1_, const void * const b2_, size_t len) + + int pure_strcmp(const char * const s1, const char * const s2) + { +- return pure_memcmp(s1, s2, strlen(s1) + 1U); ++ const size_t s1_len = strlen(s1); ++ const size_t s2_len = strlen(s2); ++ const size_t len = (s1_len < s2_len) ? s1_len : s2_len; ++ ++ return pure_memcmp(s1, s2, len + 1); + } +-- +2.25.4 + diff --git a/0002-Complain-when-both-options-and-config-file-are-given.patch b/0002-Complain-when-both-options-and-config-file-are-given.patch new file mode 100644 index 0000000..16fe41a --- /dev/null +++ b/0002-Complain-when-both-options-and-config-file-are-given.patch @@ -0,0 +1,237 @@ +From 4328fd5142d0f981687a484f4be34333432d27d1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ond=C5=99ej=20Lyson=C4=9Bk?= +Date: Wed, 7 Feb 2018 15:05:25 +0100 +Subject: [PATCH 2/2] Complain when both options and config file are given on + cmdline + +--- + src/ftpd.c | 3 +++ + src/messages_cs_cz.h | 1 + + src/messages_da.h | 1 + + src/messages_de.h | 1 + + src/messages_en.h | 1 + + src/messages_es.h | 1 + + src/messages_fr.h | 1 + + src/messages_fr_funny.h | 1 + + src/messages_hu.h | 1 + + src/messages_it.h | 1 + + src/messages_kr.h | 1 + + src/messages_nl.h | 1 + + src/messages_no.h | 1 + + src/messages_pl.h | 1 + + src/messages_pt_br.h | 1 + + src/messages_ro.h | 1 + + src/messages_ru.h | 1 + + src/messages_sk.h | 1 + + src/messages_sv.h | 1 + + src/messages_tr.h | 1 + + src/messages_zh_cn.h | 1 + + src/messages_zh_tw.h | 1 + + 22 files changed, 24 insertions(+) + +diff --git a/src/ftpd.c b/src/ftpd.c +index 5c77410..3f474d2 100644 +--- a/src/ftpd.c ++++ b/src/ftpd.c +@@ -6195,6 +6195,9 @@ int pureftpd_start(int argc, char *argv[], const char *home_directory_) + die(421, LOG_ERR, MSG_ILLEGAL_OPTION); + } + } ++ if (optind < argc) { ++ die(421, LOG_ERR, MSG_INVALID_ARGUMENT, argv[optind]); ++ } + #ifdef WITH_RFC2640 + if (charset_fs == NULL) { + charset_fs = (char *) "utf-8"; +diff --git a/src/messages_cs_cz.h b/src/messages_cs_cz.h +index ef225ba..e103b37 100644 +--- a/src/messages_cs_cz.h ++++ b/src/messages_cs_cz.h +@@ -227,3 +227,4 @@ + #define MSG_PROT_BEFORE_PBSZ "PROT must be preceded by a successful PBSZ command" + #define MSG_WARN_LDAP_USERPASS_EMPTY "LDAP returned no userPassword attribute, check LDAP access rights." + #define MSG_LDAP_INVALID_AUTH_METHOD "Invalid LDAPAuthMethod in the configuration file. Should be 'bind' or 'password'." ++#define MSG_INVALID_ARGUMENT "Neplatn� argument: \"%s\"" +diff --git a/src/messages_da.h b/src/messages_da.h +index ed6f77c..c79ad5a 100644 +--- a/src/messages_da.h ++++ b/src/messages_da.h +@@ -227,3 +227,4 @@ + #define MSG_PROT_BEFORE_PBSZ "PROT must be preceded by a successful PBSZ command" + #define MSG_WARN_LDAP_USERPASS_EMPTY "LDAP returned no userPassword attribute, check LDAP access rights." + #define MSG_LDAP_INVALID_AUTH_METHOD "Invalid LDAPAuthMethod in the configuration file. Should be 'bind' or 'password'." ++#define MSG_INVALID_ARGUMENT "Invalid argument: \"%s\"" +diff --git a/src/messages_de.h b/src/messages_de.h +index e7ae9a9..cd6bc08 100644 +--- a/src/messages_de.h ++++ b/src/messages_de.h +@@ -227,3 +227,4 @@ + #define MSG_PROT_BEFORE_PBSZ "PROT must be preceded by a successful PBSZ command" + #define MSG_WARN_LDAP_USERPASS_EMPTY "LDAP returned no userPassword attribute, check LDAP access rights." + #define MSG_LDAP_INVALID_AUTH_METHOD "Invalid LDAPAuthMethod in the configuration file. Should be 'bind' or 'password'." ++#define MSG_INVALID_ARGUMENT "Invalid argument: \"%s\"" +diff --git a/src/messages_en.h b/src/messages_en.h +index e980131..cb9abf3 100644 +--- a/src/messages_en.h ++++ b/src/messages_en.h +@@ -227,3 +227,4 @@ + #define MSG_PROT_BEFORE_PBSZ "PROT must be preceded by a successful PBSZ command" + #define MSG_WARN_LDAP_USERPASS_EMPTY "LDAP returned no userPassword attribute, check LDAP access rights." + #define MSG_LDAP_INVALID_AUTH_METHOD "Invalid LDAPAuthMethod in the configuration file. Should be 'bind' or 'password'." ++#define MSG_INVALID_ARGUMENT "Invalid argument: \"%s\"" +diff --git a/src/messages_es.h b/src/messages_es.h +index 0c27d4f..60ed849 100644 +--- a/src/messages_es.h ++++ b/src/messages_es.h +@@ -227,3 +227,4 @@ + #define MSG_PROT_BEFORE_PBSZ "PROT must be preceded by a successful PBSZ command" + #define MSG_WARN_LDAP_USERPASS_EMPTY "LDAP returned no userPassword attribute, check LDAP access rights." + #define MSG_LDAP_INVALID_AUTH_METHOD "Invalid LDAPAuthMethod in the configuration file. Should be 'bind' or 'password'." ++#define MSG_INVALID_ARGUMENT "Invalid argument: \"%s\"" +diff --git a/src/messages_fr.h b/src/messages_fr.h +index 7f41dae..a012c05 100644 +--- a/src/messages_fr.h ++++ b/src/messages_fr.h +@@ -227,3 +227,4 @@ + #define MSG_PROT_BEFORE_PBSZ "PROT doit etre precede d'une commande PBSZ reussie" + #define MSG_WARN_LDAP_USERPASS_EMPTY "LDAP n'a pas retourne d'attribut userPassword, verifiez les droits d'acces LDAP." + #define MSG_LDAP_INVALID_AUTH_METHOD "Methode LDAPAuthMethod invalide dans le fichier de configuration. Ce doit etre 'bind' ou 'password'." ++#define MSG_INVALID_ARGUMENT "Invalid argument: \"%s\"" +diff --git a/src/messages_fr_funny.h b/src/messages_fr_funny.h +index c77e5bc..dff760b 100644 +--- a/src/messages_fr_funny.h ++++ b/src/messages_fr_funny.h +@@ -227,3 +227,4 @@ + #define MSG_PROT_BEFORE_PBSZ "PROT ca marche qu'apres un PBSZ reussi" + #define MSG_WARN_LDAP_USERPASS_EMPTY "LDAP n'a pas retourne d'attribut userPassword, ptet que les droits d'acces LDAP chient." + #define MSG_LDAP_INVALID_AUTH_METHOD "LDAPAuthMethod dans le fichier de conf, ca doit etre 'bind' ou 'password'." ++#define MSG_INVALID_ARGUMENT "Invalid argument: \"%s\"" +diff --git a/src/messages_hu.h b/src/messages_hu.h +index b3beead..7c5a101 100644 +--- a/src/messages_hu.h ++++ b/src/messages_hu.h +@@ -227,3 +227,4 @@ + #define MSG_PROT_BEFORE_PBSZ "PROT must be preceded by a successful PBSZ command" + #define MSG_WARN_LDAP_USERPASS_EMPTY "LDAP returned no userPassword attribute, check LDAP access rights." + #define MSG_LDAP_INVALID_AUTH_METHOD "Invalid LDAPAuthMethod in the configuration file. Should be 'bind' or 'password'." ++#define MSG_INVALID_ARGUMENT "Invalid argument: \"%s\"" +diff --git a/src/messages_it.h b/src/messages_it.h +index 4e6e984..e30f517 100644 +--- a/src/messages_it.h ++++ b/src/messages_it.h +@@ -227,3 +227,4 @@ + #define MSG_PROT_BEFORE_PBSZ "PROT must be preceded by a successful PBSZ command" + #define MSG_WARN_LDAP_USERPASS_EMPTY "LDAP returned no userPassword attribute, check LDAP access rights." + #define MSG_LDAP_INVALID_AUTH_METHOD "Invalid LDAPAuthMethod in the configuration file. Should be 'bind' or 'password'." ++#define MSG_INVALID_ARGUMENT "Invalid argument: \"%s\"" +diff --git a/src/messages_kr.h b/src/messages_kr.h +index 14d8300..c9faead 100644 +--- a/src/messages_kr.h ++++ b/src/messages_kr.h +@@ -227,3 +227,4 @@ + #define MSG_PROT_BEFORE_PBSZ "PROT must be preceded by a successful PBSZ command" + #define MSG_WARN_LDAP_USERPASS_EMPTY "LDAP returned no userPassword attribute, check LDAP access rights." + #define MSG_LDAP_INVALID_AUTH_METHOD "Invalid LDAPAuthMethod in the configuration file. Should be 'bind' or 'password'." ++#define MSG_INVALID_ARGUMENT "Invalid argument: \"%s\"" +diff --git a/src/messages_nl.h b/src/messages_nl.h +index 77efbb4..5a60d9e 100644 +--- a/src/messages_nl.h ++++ b/src/messages_nl.h +@@ -227,3 +227,4 @@ + #define MSG_PROT_BEFORE_PBSZ "PROT must be preceded by a successful PBSZ command" + #define MSG_WARN_LDAP_USERPASS_EMPTY "Geen userPassword attribuut aangetroffen. Controleer de toegangsrechten." + #define MSG_LDAP_INVALID_AUTH_METHOD "Onjuiste LDAPAuthMethod in de configuratie. Moet 'bind' of 'password' zijn." ++#define MSG_INVALID_ARGUMENT "Invalid argument: \"%s\"" +diff --git a/src/messages_no.h b/src/messages_no.h +index f0be1b4..4c84405 100644 +--- a/src/messages_no.h ++++ b/src/messages_no.h +@@ -227,3 +227,4 @@ + #define MSG_PROT_BEFORE_PBSZ "PROT must be preceded by a successful PBSZ command" + #define MSG_WARN_LDAP_USERPASS_EMPTY "LDAP returned no userPassword attribute, check LDAP access rights." + #define MSG_LDAP_INVALID_AUTH_METHOD "Invalid LDAPAuthMethod in the configuration file. Should be 'bind' or 'password'." ++#define MSG_INVALID_ARGUMENT "Invalid argument: \"%s\"" +diff --git a/src/messages_pl.h b/src/messages_pl.h +index c0be4d8..89d5af1 100644 +--- a/src/messages_pl.h ++++ b/src/messages_pl.h +@@ -227,3 +227,4 @@ + #define MSG_PROT_BEFORE_PBSZ "PROT must be preceded by a successful PBSZ command" + #define MSG_WARN_LDAP_USERPASS_EMPTY "LDAP returned no userPassword attribute, check LDAP access rights." + #define MSG_LDAP_INVALID_AUTH_METHOD "Invalid LDAPAuthMethod in the configuration file. Should be 'bind' or 'password'." ++#define MSG_INVALID_ARGUMENT "Invalid argument: \"%s\"" +diff --git a/src/messages_pt_br.h b/src/messages_pt_br.h +index e5557b9..1dcfb64 100644 +--- a/src/messages_pt_br.h ++++ b/src/messages_pt_br.h +@@ -227,3 +227,4 @@ + #define MSG_PROT_BEFORE_PBSZ "PROT must be preceded by a successful PBSZ command" + #define MSG_WARN_LDAP_USERPASS_EMPTY "LDAP returned no userPassword attribute, check LDAP access rights." + #define MSG_LDAP_INVALID_AUTH_METHOD "Invalid LDAPAuthMethod in the configuration file. Should be 'bind' or 'password'." ++#define MSG_INVALID_ARGUMENT "Invalid argument: \"%s\"" +diff --git a/src/messages_ro.h b/src/messages_ro.h +index 7bbcefe..da16a49 100644 +--- a/src/messages_ro.h ++++ b/src/messages_ro.h +@@ -227,3 +227,4 @@ + #define MSG_PROT_BEFORE_PBSZ "PROT must be preceded by a successful PBSZ command" + #define MSG_WARN_LDAP_USERPASS_EMPTY "LDAP returned no userPassword attribute, check LDAP access rights." + #define MSG_LDAP_INVALID_AUTH_METHOD "Invalid LDAPAuthMethod in the configuration file. Should be 'bind' or 'password'." ++#define MSG_INVALID_ARGUMENT "Invalid argument: \"%s\"" +diff --git a/src/messages_ru.h b/src/messages_ru.h +index e0c1842..f0e4031 100644 +--- a/src/messages_ru.h ++++ b/src/messages_ru.h +@@ -227,3 +227,4 @@ + #define MSG_PROT_BEFORE_PBSZ "PROT must be preceded by a successful PBSZ command" + #define MSG_WARN_LDAP_USERPASS_EMPTY "LDAP returned no userPassword attribute, check LDAP access rights." + #define MSG_LDAP_INVALID_AUTH_METHOD "Invalid LDAPAuthMethod in the configuration file. Should be 'bind' or 'password'." ++#define MSG_INVALID_ARGUMENT "Invalid argument: \"%s\"" +diff --git a/src/messages_sk.h b/src/messages_sk.h +index 24eca1b..e0ddd2a 100644 +--- a/src/messages_sk.h ++++ b/src/messages_sk.h +@@ -227,3 +227,4 @@ + #define MSG_PROT_BEFORE_PBSZ "PROT must be preceded by a successful PBSZ command" + #define MSG_WARN_LDAP_USERPASS_EMPTY "LDAP returned no userPassword attribute, check LDAP access rights." + #define MSG_LDAP_INVALID_AUTH_METHOD "Invalid LDAPAuthMethod in the configuration file. Should be 'bind' or 'password'." ++#define MSG_INVALID_ARGUMENT "Invalid argument: \"%s\"" +diff --git a/src/messages_sv.h b/src/messages_sv.h +index b55c474..be4bbc1 100644 +--- a/src/messages_sv.h ++++ b/src/messages_sv.h +@@ -227,3 +227,4 @@ + #define MSG_PROT_BEFORE_PBSZ "PROT must be preceded by a successful PBSZ command" + #define MSG_WARN_LDAP_USERPASS_EMPTY "LDAP returned no userPassword attribute, check LDAP access rights." + #define MSG_LDAP_INVALID_AUTH_METHOD "Invalid LDAPAuthMethod in the configuration file. Should be 'bind' or 'password'." ++#define MSG_INVALID_ARGUMENT "Invalid argument: \"%s\"" +diff --git a/src/messages_tr.h b/src/messages_tr.h +index 7d6db57..3ee84d2 100644 +--- a/src/messages_tr.h ++++ b/src/messages_tr.h +@@ -227,3 +227,4 @@ + #define MSG_PROT_BEFORE_PBSZ "PROT must be preceded by a successful PBSZ command" + #define MSG_WARN_LDAP_USERPASS_EMPTY "LDAP returned no userPassword attribute, check LDAP access rights." + #define MSG_LDAP_INVALID_AUTH_METHOD "Invalid LDAPAuthMethod in the configuration file. Should be 'bind' or 'password'." ++#define MSG_INVALID_ARGUMENT "Invalid argument: \"%s\"" +diff --git a/src/messages_zh_cn.h b/src/messages_zh_cn.h +index a8bfc6c..93844fd 100644 +--- a/src/messages_zh_cn.h ++++ b/src/messages_zh_cn.h +@@ -227,3 +227,4 @@ + #define MSG_PROT_BEFORE_PBSZ "PROT must be preceded by a successful PBSZ command" + #define MSG_WARN_LDAP_USERPASS_EMPTY "LDAP returned no userPassword attribute, check LDAP access rights." + #define MSG_LDAP_INVALID_AUTH_METHOD "Invalid LDAPAuthMethod in the configuration file. Should be 'bind' or 'password'." ++#define MSG_INVALID_ARGUMENT "Invalid argument: \"%s\"" +diff --git a/src/messages_zh_tw.h b/src/messages_zh_tw.h +index db99719..05581bb 100644 +--- a/src/messages_zh_tw.h ++++ b/src/messages_zh_tw.h +@@ -227,3 +227,4 @@ + #define MSG_PROT_BEFORE_PBSZ "PROT must be preceded by a successful PBSZ command" + #define MSG_WARN_LDAP_USERPASS_EMPTY "LDAP returned no userPassword attribute, check LDAP access rights." + #define MSG_LDAP_INVALID_AUTH_METHOD "Invalid LDAPAuthMethod in the configuration file. Should be 'bind' or 'password'." ++#define MSG_INVALID_ARGUMENT "Invalid argument: \"%s\"" +-- +2.14.3 + diff --git a/0002-Revert-Remove-contribs.-These-are-way-too-old-and-un.patch b/0002-Revert-Remove-contribs.-These-are-way-too-old-and-un.patch new file mode 100644 index 0000000..cc87ea1 --- /dev/null +++ b/0002-Revert-Remove-contribs.-These-are-way-too-old-and-un.patch @@ -0,0 +1,693 @@ +From 1956de44a6385a6a891a0f18468335884b30eb7c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ond=C5=99ej=20Lyson=C4=9Bk?= +Date: Wed, 6 Feb 2019 12:39:54 +0100 +Subject: [PATCH 2/3] Revert "Remove contribs. These are way too old and + unmaintained." + +This reverts commit ba526ef1525c09d63a309f3e0c22ecf1308d9070. +--- + Makefile.am | 2 + + README.Contrib | 137 +++++++++++++++ + contrib/Makefile.am | 3 + + contrib/pure-stat.pl | 213 +++++++++++++++++++++++ + contrib/xml_python_processors.txt | 274 ++++++++++++++++++++++++++++++ + 5 files changed, 629 insertions(+) + create mode 100644 README.Contrib + create mode 100644 contrib/Makefile.am + create mode 100755 contrib/pure-stat.pl + create mode 100644 contrib/xml_python_processors.txt + +diff --git a/Makefile.am b/Makefile.am +index a3c769f..635181a 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -10,6 +10,7 @@ EXTRA_DIST = \ + README.MySQL \ + README.PGSQL \ + README.Configuration-File \ ++ README.Contrib \ + README.Virtual-Users \ + README.Authentication-Modules \ + README.Windows \ +@@ -25,6 +26,7 @@ EXTRA_DIST = \ + SUBDIRS = \ + puredb \ + src \ ++ contrib \ + man \ + pam \ + gui \ +diff --git a/README.Contrib b/README.Contrib +new file mode 100644 +index 0000000..0a23ab5 +--- /dev/null ++++ b/README.Contrib +@@ -0,0 +1,137 @@ ++ ++ ++You can send whatever you want to be included in that list to ++ or to the mailing list. ++ ++ Thank you, ++ ++ ++ -Frank. ++ ++----------------------------------------------------------------------------- ++ ++Warning: contributed packages haven't received any code audit. Please ++report bugs directly to authors. ++ ++----------------------------------------------------------------------------- ++ ++* Redmine Pure-FTPd plugin ++http://github.com/bytemine/redmine_pureftpd_user/ ++ ++This Redmine plugin maintains a table with pureftpd compatible users. ++ ++ ++* FTPd Auth Handler ++http://onrails.org/articles/2009/03/06/integrating-ftp-with-rails ++ ++An extauth handler in Ruby. ++ ++ ++* Domain technologie control panel, as used on GPLHost ++http://github.com/carlosl/dtc ++ ++ ++* PureFTPd Manager ++http://jeanmatthieu.free.fr/pureftpd/ ++ ++PureFTPd Manager is a small Cocoa frontend to PureFTPd for Mac OS X. It ++includes a wizard to easily set up your server, Rendezvous support to ++publish your server efficiently, and groovy interfaces for virtual users and ++hosts management. ++ ++ ++* PureAdmin ++http://purify.sourceforge.net/ ++ ++PureAdmin is a graphical tool used to make the management of PureFTPd a ++little easier. It is not dependent on a specific desktop environment such as ++GNOME or KDE, but is designed with the GNOME Human Interface Guidelines in ++mind. ++ ++ ++* Pure-FTPd PHP User Manager ++http://ppum.sourceforge.net/ ++ ++ppum (PureFTPd PHP User Manager) is a PureFTPD PHP User Management System ++designed for an easy Web-based administration of SQL stored and ++authenticated FTP users. ++ ++ ++* User manager for Pure-FTPd ++http://machiel.generaal.net/index.php?subject=user_manager_pureftpd ++ ++User manager for PureFTPd allows administrators to easily create, change, or ++delete 'virtual' PureFTPd users. It comes with a set of very good ++documentation to help with the setup of PureFTPd, MySQL, and this application. ++ ++ ++* PureUserAdmin ++http://pureuseradmin.sourceforge.net/ ++ ++PureUserAdmin is a PHP based webbased application. Sys admins can use it to ++easily manage the virtual users for their FTP server. PureUserAdmin is ++developed to be used with Pure-FTPd but it should be able to be used with ++other FTP servers as long as the FTP server gets the useraccount info from ++MySQL or PostgreSQL. ++ ++ ++* PurePostPro ++http://82.71.1.246/stuff/purepostpro/ ++ ++PurePostPro is a Perl/MySQL script that enables user uploads to be managed ++more easily. New uploads are logged in a MySQL database, and duplicate files ++are tracked using MD5 checksums. ++ ++ ++* MySQmail Pure-FTPd logger ++http://www.gplhost.com/software-mysqmail.html ++http://packages.debian.org/en/squeeze/mail/mysqmail-pure-ftpd-logger ++ ++MySQMail is a set of tiny daemon loggers for mail and FTP servers that save ++traffic information in a MySQL database. The information is split by domain ++and by user so that it's easy to measure all the traffic for a given domain ++name in real time. ++ ++This package provides a logger for FTP traffic handled by Pure-FTPd. ++ ++ ++ ++ ---------- ++ ++ ++ ++Current content of the "contrib" directory: ++ ++* xml_python_processors.txt (author: Jason Lunz): ++ ++ Two scripts to postprocess pure-ftpwho XML output. One returns a list of ++dicts with the ftpwho data, each dict representing a connected client's ++attribute. If you want to develop something related to ftpwho in Python, ++this is a very good base. ++ ++ The other script creates a web page similar to "pure-ftpwho -w", but ++better: you can choose which columns you want in which order and sort ++the rows on multiple fields. You can also see bandwidth totals per ++account. ++ ++* redhat.init (author: Bernhard Weisshuhn): ++ ++ A sample Red Hat init script. ++ ++* suse.init (author: Marc Thoben): ++ ++ A sample SuSE init script. ++ ++* pure-vpopauth.pl (author: Dan Caescu): ++ ++ An external authentication module for pure-ftpd using vpasswd ++vpopmail password files. ++ Run it the standard way with pure-authd. ++ ++* pure-stat.pl (author: Julien Andrieux): ++ ++ This script parses Apache-like log files and generates nice text summaries. ++ ++* Vidibus::Pureftpd (author: Andre Pankratz): ++ A Ruby gem that p rovides an ActiveModel-based abstraction of Pure-FTPd's ++virtual users. +diff --git a/contrib/Makefile.am b/contrib/Makefile.am +new file mode 100644 +index 0000000..5056d5f +--- /dev/null ++++ b/contrib/Makefile.am +@@ -0,0 +1,3 @@ ++EXTRA_DIST = \ ++ xml_python_processors.txt \ ++ pure-stat.pl +diff --git a/contrib/pure-stat.pl b/contrib/pure-stat.pl +new file mode 100755 +index 0000000..c26a4f8 +--- /dev/null ++++ b/contrib/pure-stat.pl +@@ -0,0 +1,213 @@ ++#!/usr/bin/env perl -w ++#-------------------------------------------------------------- ++# PROJECT : pure-ftpd statistics ++# FILE : pure-stat.pl ++# DESCRIPTION : see below (Purpose) ++# AUTHOR : Chill ++# DATE : 08/01/2002 ++# COMMENT: ++# PARAMETER : none ++# FROM FILE : none ++#-------------------------------------------------------------- ++# PURPOSE ++# get the log file $CONST_LOGFILE ++# parse it and generate stats ++# to avoid loading a huge log file, a summary file ($CONST_SUMFILE), ++# is generated ++ ++#CONSTANT DELCARATION ++my $CONST_USER=0; ++my $CONST_TUPLOAD=1; ++my $CONST_TDOWNLOAD=2; ++my $CONST_LCONNECTION=3; ++my $CONST_LOGFILE="/var/log/pureftpd.log"; ++my $CONST_SUMFILE="/var/log/pureftpd.stat.log"; ++ ++#FUNCTION DECLARATION ++sub castSize; ++ ++#CREATE USERS ARRAY (UGLY, BUT USEFUL FOR DISPLAY) ++my @users = (["login", "upload", "download", "last connection"]); ++ ++#MAIN VARIABLES INIT ++my $total_upload = 0; ++my $total_download = 0; ++ ++ ++#FUNCTION DEFINITION ++ ++#MODIFY 1234bytes => 1.2Mb... ++sub castSize ++{ ++ my $value = shift; ++ ++ if ($value > 1073741824) ++ { ++ $value = $value / 1073741824; ++ @fvalue = ($value, "Gb"); ++ } ++ elsif ($value > 1048576) ++ { ++ $value = $value / 1048576; ++ @fvalue = ($value, "Mb"); ++ } ++ elsif ($value > 1024) ++ { ++ $value = $value / 1024; ++ @fvalue = ($value, "Kb"); ++ } ++ else ++ { ++ @fvalue = ($value, "b"); ++ } ++ return @fvalue; ++} ++#END sub castSize ++ ++#LOAD SUMMARY FILE INTO ARRAY ++open(SUMF,$CONST_SUMFILE); ++my @sumlist = ; ++close SUMF; ++ ++#PARSING SUMMARY FILE INTO ARRAY ++foreach $sumentry (@sumlist) ++{ ++ ($slogin, $sbytes_ul, $sbytes_dl, $sdate) = $sumentry =~ m/^(\S+) (\S+) (\S+) \[([^\]\[]+)\]/; ++ push @users, [$slogin, $sbytes_ul, $sbytes_dl, $sdate]; ++ $total_upload += $sbytes_ul; ++ $total_download += $sbytes_dl; ++} ++ ++#LOAD LOG FILE INTO ARRAY ++open(LOG,$CONST_LOGFILE); ++my @loglist = ; ++close LOG; ++ ++#PARSING ARRAY IF NOT EMPTY ++if ($#loglist != -1) ++{ ++ #GENERATE FILE EXTENSION AS yearmonthmdayhourmin ++ @dlist = gmtime(time); ++ $ext = sprintf("%02d%02d%02d%02d%02d", $dlist[5], $dlist[4]+1, $dlist[3], $dlist[2]+2, $dlist[1]); ++ undef @dlist; ++ ++ #WE BACKUP THE LOG FILE ++ system ("gzip $CONST_LOGFILE -S .$ext.gz && touch $CONST_LOGFILE"); ++ ++ foreach $logentry (@loglist) ++ { ++ #LET'S GRAB THE LOG ENTRY ++ ($ip, $tiret, $login, $date, $request, $status, $bytes) = $logentry =~ m/^(\S+) (\S+) (\S+) \[([^\]\[]+)\] \"([^"]*)\" (\S+) (\S+)/; ++ ++ #ADD OR MODIFY USERS ++ #IS THE USER IN THE SUMMARY FILE ++ my $gotuser = 0; ++ my $indexuser = 0; ++ ++ for $i ( 1 .. $#users ) ++ { ++ if ($users[$i][$CONST_USER] eq $login) ++ { ++ $gotuser = 1; ++ $indexuser = $i; ++ last; ++ } ++ } ++ ++ #YES, WE DON'T ADD HIM, WE UPGRADE HIM ++ if ($gotuser) ++ { ++ if ( $request =~ "PUT") ++ { ++ #UPLOAD CASE ++ $users[$indexuser][$CONST_TUPLOAD] += $bytes; ++ $total_upload += $bytes; ++ } ++ elsif ( $request =~ "GET") ++ { ++ #DOWNLOAD CASE ++ $users[$indexuser][$CONST_TDOWNLOAD] += $bytes; ++ $total_download += $bytes; ++ } ++ #LAST CONNECTION ++ $users[$indexuser][$CONST_LCONNECTION] = $date; ++ } ++ else ++ { ++ #NOPE, WE ADD HIM ++ if ( $request =~ "GET") ++ { ++ #DOWNLOAD CASE ++ push @users, [$login, 0, $bytes, $date]; ++ $total_download += $bytes; ++ } ++ elsif ( $request =~ "PUT") ++ { ++ #UPLOAD CASE ++ push @users, [$login, $bytes, 0, $date]; ++ $total_upload += $bytes; ++ } ++ } ++ } ++} ++ ++#PRINT RESULTS ++#LET'S CLEAN THE SUMMARY FILE ++system ("rm -f $CONST_SUMFILE && touch $CONST_SUMFILE"); ++ ++#TABLE HEADER ++print "----------------------------------------------\n"; ++print "$users[$i][$CONST_USER]\t|\t$users[$i][$CONST_TUPLOAD]\t\t|\t$users[$i][$CONST_TDOWNLOAD]\t\t|\t$users[$i][$CONST_LCONNECTION]\n"; ++print "----------------------------------------------\n"; ++ ++#TABLE BODY ++for $i ( 1 .. $#users ) ++{ ++ if ($total_upload <= 0) ++ { ++ $percent_upload=0; ++ } else { ++ $percent_upload= 100*$users[$i][$CONST_TUPLOAD]/$total_upload; ++ } ++ if ($total_download <= 0) ++ { ++ $percent_download=0; ++ } else { ++ $percent_download= 100*$users[$i][$CONST_TDOWNLOAD]/$total_download; ++ } ++ ++ @actual_upload = castSize $users[$i][$CONST_TUPLOAD]; ++ @actual_download = castSize $users[$i][$CONST_TDOWNLOAD]; ++ ++ $strLogin = sprintf "%s", $users[$i][$CONST_USER]; ++ $strUl = sprintf "%.1f %s (%.1f%%)", ($actual_upload[0],$actual_upload[1],$percent_upload); ++ $strDl = sprintf "%.1f %s (%.1f%%)", ($actual_download[0],$actual_download[1],$percent_download); ++ $strDate = sprintf "%s", ($users[$i][$CONST_LCONNECTION]); ++ ++ #PRINT ON STDOUT ++ printf "%s\t|\t%s\t", ($strLogin, $strUl); ++ if ( length($strUl) < 8) ++ { ++ printf "\t"; ++ } ++ printf "|\t%s\t", $strDl; ++ if ( length($strDl) < 8) ++ { ++ printf "\t"; ++ } ++ printf "|\t%s\n", $strDate; ++ printf "\n"; ++ ++ #PRINT SUMMARY FILE ++ system ("echo -e '$users[$i][$CONST_USER] $users[$i][$CONST_TUPLOAD] $users[$i][$CONST_TDOWNLOAD] [$users[$i][$CONST_LCONNECTION]]' >> $CONST_SUMFILE"); ++} ++ ++#PREPARE BYTES, MBYTES OR GBYTES ++@ftotal_upload = castSize $total_upload; ++@ftotal_download = castSize $total_download; ++ ++#TABLE FOOTER ++print "----------------------------------------------\n"; ++printf "*\t|\t%.2f %s\t|\t%.2f %s\n", ($ftotal_upload[0],$ftotal_upload[1],$ftotal_download[0],$ftotal_download[1]); ++print "----------------------------------------------\n"; ++ +diff --git a/contrib/xml_python_processors.txt b/contrib/xml_python_processors.txt +new file mode 100644 +index 0000000..c4f7ba9 +--- /dev/null ++++ b/contrib/xml_python_processors.txt +@@ -0,0 +1,274 @@ ++From: Jason Lunz ++ ++I've been fooling around with parsing the XML output of "pure-ftpwho -x" ++in python and doing things with it. The results could be useful to a lot ++of people, so I'm posting everything here. Maybe it can become part of a ++contrib/ dir in the distribution. ++ ++mind you, none of this has been written with elegance or efficiency in ++mind. but it's a good basis for other work. ++ ++Here's a python module that parses the XML pure-ftpwho data and returns ++a list of dicts, with each dict representing a connected client's ++attributes: ++ ++ #! /usr/bin/env python2 ++ ++ import os ++ from xml.sax import handler, make_parser ++ ++ class ftpwho_handler(handler.ContentHandler): ++ def __init__(self): ++ handler.ContentHandler.__init__(self) ++ self.clear() ++ ++ def startElement(self, name, attrs): ++ if name != 'client': return ++ d = {} ++ for (k, v) in attrs.items(): ++ d[k] = v ++ self.clients.append(d) ++ ++ def clear(self): ++ self.clients = [] ++ ++ parser = make_parser() ++ fh = ftpwho_handler() ++ parser.setContentHandler(fh) ++ ++ def numberize(dicts): ++ for c in dicts: ++ for k in ('pid', 'time', 'localport', 'percentage', 'bandwidth'): ++ if c.has_key(k): ++ c[k] = int(c[k]) ++ for k in ('current_size', 'resume', 'total_size'): ++ if c.has_key(k): ++ c[k] = long(c[k]) ++ return dicts ++ ++ def clients(): ++ fh.clear() ++ parser.parse(os.popen('pure-ftpwho -x')) ++ return numberize(fh.clients) ++ ++ ++Building on that, I wrote html_ftpwho.py, which turns the aforementioned ++client list into HTML output. The output resembles what you get with ++"pure-ftpwho -w", but you can choose which columns you want in which ++order, and sort the rows on multiple fields. You also can see bandwidth ++totals per account. ++ ++ #! /usr/bin/env python2 ++ ++ import getopt ++ import pure_ftpwho ++ import sys ++ from string import capitalize, lower ++ ++ def range_idx(list, first = 1, cmp_func = cmp): ++ for i in range(first+1, len(list)): ++ if cmp_func(list[first], list[i]): ++ return i ++ return len(list) ++ ++ def dcmp(a, b, key): ++ if a.has_key(key): ++ if b.has_key(key): ++ return cmp(a[key], b[key]) ++ else: ++ return 1 ++ else: ++ if b.has_key(key): ++ return -1 ++ else: ++ return 0 ++ ++ def multisort(dicts, keys): ++ if not keys: ++ return dicts ++ dicts.sort(lambda x, y, key=keys[0]: dcmp(x, y, key)) ++ ret = [] ++ first = last = 0 ++ while last < len(dicts): ++ last = range_idx(dicts, first, lambda x, y, k=keys[0]: dcmp(x, y, k)) ++ add = multisort(dicts[first:last], keys[1:]) ++ if(add): ++ ret.extend(add) ++ first = last ++ return ret ++ ++ def col_heading(key): ++ headings = {'pid' : 'PID'} ++ if headings.has_key(key): ++ return headings[key] ++ else: ++ return capitalize(lower(key)) ++ ++ def size_abbrev(num, order=-1): ++ abbr = ['b', 'K', 'M', 'G', 'T'] ++ if order == -1: ++ q = 1 ++ for i in range(len(abbr)): ++ p = pow(1024, i+1) ++ if num < p: ++ return (float(num)/q, abbr[i], i) ++ q = p ++ else: ++ return (float(num)/pow(1024, order), abbr[order], order) ++ ++ def celltext(dict, type): ++ sizes = ['current_size', 'total_size', 'percentage', 'bandwidth'] ++ align = '' ++ ret = '' ++ if type == 'stats': ++ align = ' align="right"' ++ if filter(lambda k, d=dict: d.has_key(k), sizes): ++ bw, abbr, order = size_abbrev(dict['bandwidth']) ++ if order == 0: ++ format = '%d' ++ else: ++ format = '%.1f' ++ sf = format + '/' + format ++ sf += ' %s (%d%% - ' + format ++ sf += ' %s/s)' ++ ret = sf % (size_abbrev(dict['current_size'], order)[0], ++ size_abbrev(dict['total_size'], order)[0], ++ abbr, dict['percentage'], bw, abbr) ++ elif not dict.has_key(type): ++ ret = ' ' ++ elif type in sizes: ++ ret = size_abbrev(dict[type]) ++ elif type == 'time': ++ align = ' align="right"' ++ str = '' ++ minutes, seconds = divmod(dict[type], 60) ++ hours, minutes = divmod(minutes, 60) ++ days, hours = divmod(hours, 24) ++ if(days): ++ str += '%dd' % days ++ if(hours): ++ str += '%02d:' % hours ++ ret = str + '%02d:%02d' % (minutes, seconds) ++ else: ++ ret = dict[type] ++ return '%s' % (align, ret) ++ ++ def html(dicts, order, headings, stream, totals): ++ sorted = multisort(dicts, order) ++ stream.write(''' ++ ++ Pure-FTPd server status ++ ++ ''') ++ if(totals): ++ stream.write('') ++ stream.write('') ++ for k in totals.keys(): ++ stream.write('' % k) ++ stream.write('\n' % size_abbrev(totals[k])[:2]) ++ stream.write('
AccountTotal Bandwidth
%s%d %s/s

\n') ++ stream.write('
') ++ stream.write('') ++ for k in headings: ++ stream.write('' % col_heading(k)) ++ stream.write('\n') ++ for d in sorted: ++ stream.write('\n') ++ for k in headings: ++ stream.write('%s' % celltext(d, k)) ++ stream.write('\n\n') ++ stream.write('
%s
\n') ++ ++ def arg_expand(list, opts): ++ optmap = { ++ 'A':'account', ++ 'B':'bandwidth', ++ 'C':'current_size', ++ 'F':'file', ++ 'H':'host', ++ 'L':'localhost', ++ 'O':'localport', ++ 'P':'percentage', ++ 'D':'pid', ++ 'R':'resume', ++ 'S':'state', ++ 'T':'time', ++ 'X':'stats', ++ 'Z':'total_size' } ++ for l in opts: ++ if optmap.has_key(l): ++ list.append(optmap[l]) ++ else: ++ print 'unrecognized column %s' % l ++ sys.exit(1) ++ ++ def usage(): ++ print '''usage: html_ftpwho.py [options] ++ -c columns to output (default "AXTSHF") ++ -o sort order (default "SABT") ++ -t show totals per account ++ ++ is a string of letters, each representing a client attribute: ++ A - account ++ B - bandwidth ++ C - current_size ++ F - file ++ H - host ++ L - localhost ++ O - localport ++ P - percentage ++ D - pid ++ R - resume ++ S - state ++ T - time ++ X - stats ++ Z - total_size ++ ''' ++ sys.exit(1) ++ ++ try: ++ optlist, args = getopt.getopt(sys.argv[1:], 'hc:o:t') ++ except getopt.error, msg: ++ print msg ++ usage() ++ ++ ord_arg = '' ++ col_arg = '' ++ show_totals = 0 ++ for opt in optlist: ++ if '-c' == opt[0]: ++ col_arg += opt[1] ++ elif '-h' == opt[0]: ++ usage() ++ elif '-o' == opt[0]: ++ ord_arg += opt[1] ++ elif '-t' == opt[0]: ++ show_totals = 1 ++ else: ++ print 'unrecognized option "%s"' % opt[0] ++ usage() ++ ++ if not ord_arg: ++ ord_arg = 'SABT' ++ if not col_arg: ++ col_arg = 'AXTSHF' ++ order = [] ++ columns = [] ++ arg_expand(order, ord_arg) ++ arg_expand(columns, col_arg) ++ ++ cl = pure_ftpwho.clients() ++ totals = {} ++ if show_totals: ++ for c in cl: ++ if c.has_key('bandwidth'): ++ try: ++ totals[c['account']] += c['bandwidth'] ++ except KeyError: ++ totals[c['account']] = c['bandwidth'] ++ ++ html(cl, order, columns, sys.stdout, totals) ++ ++suggestions/patches welcome, ++ ++Jason +-- +2.20.1 + diff --git a/0003-Revert-Remove-pure-vpopauth.-That-script-is-terrible.patch b/0003-Revert-Remove-pure-vpopauth.-That-script-is-terrible.patch new file mode 100644 index 0000000..e506c3c --- /dev/null +++ b/0003-Revert-Remove-pure-vpopauth.-That-script-is-terrible.patch @@ -0,0 +1,81 @@ +From 88e305cf8a70b940f15a2dff496887f388dfd4a9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ond=C5=99ej=20Lyson=C4=9Bk?= +Date: Wed, 6 Feb 2019 12:40:01 +0100 +Subject: [PATCH 3/3] Revert "Remove pure-vpopauth. That script is terrible." + +This reverts commit fe6419d70ccf5b4f3bfc5f8200f99f3915994a19. +--- + contrib/Makefile.am | 1 + + contrib/pure-vpopauth.pl | 51 ++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 52 insertions(+) + create mode 100755 contrib/pure-vpopauth.pl + +diff --git a/contrib/Makefile.am b/contrib/Makefile.am +index 5056d5f..81aae9a 100644 +--- a/contrib/Makefile.am ++++ b/contrib/Makefile.am +@@ -1,3 +1,4 @@ + EXTRA_DIST = \ + xml_python_processors.txt \ ++ pure-vpopauth.pl \ + pure-stat.pl +diff --git a/contrib/pure-vpopauth.pl b/contrib/pure-vpopauth.pl +new file mode 100755 +index 0000000..6a59a41 +--- /dev/null ++++ b/contrib/pure-vpopauth.pl +@@ -0,0 +1,51 @@ ++#! /usr/bin/env perl -w ++ ++# - authentication module for pure-ftpd using vpasswd vpopmail password files. ++# - Saturday, 12 May 2002 - released ++# - copyright (c) Dan Caescu - daniel@guitar.ro , jamie_fd@yahoo.com ++# - vpopmail has to be compiled with clear text passwords in order for ++# - this to work. ++# - also, there would be great if you would run pure-ftpd with chroot flags ++# - 17 Nov 2002, added e-mail checking, a hint from Frank Jedi @ pureftpd ++# - I guess it works..? :) ++# - greets to Rox (Roxana Raluca) . ++ ++# Change the following settings according to your needs ++ ++$VPOPMAIL_PATH = '/usr/local/vpopmail'; ++$UID = 1000; ++$GID = 1000; ++ ++# Don't change anything below that line ++ ++$AUTHD_ACCOUNT = $ENV{AUTHD_ACCOUNT} or die; ++$AUTHD_PASSWORD = $ENV{AUTHD_PASSWORD} or die; ++ ++# Checking if AUTHD_ACCOUNT is like user@domain ++ ++$AUTHD_ACCOUNT =~ /^[^@]+\@([a-z0-9]+\.)+[a-z]+$/i or die; ++ ++# We take care of the user/domain pair 'cause the user comes ++# in the user@domain style ++ ++@user_domain = split('@', $AUTHD_ACCOUNT); ++ ++open (FILE, "$VPOPMAIL_PATH/domains/" . $user_domain[1] . '/vpasswd') or die; ++ ++# We take care of the user/pass from vpasswd ++ ++while () { ++ chomp; ++ @date_useri = split ':'; ++ if ($user_domain[0] eq $date_useri[0] && ++ $AUTHD_PASSWORD eq $date_useri[7]) { ++ print "auth_ok:1\n", ++ "uid:$UID\n", ++ "gid:$GID\n", ++ "dir:$date_useri[5]\n", ++ "end\n"; ++ last; ++ } ++} ++ ++close FILE; +-- +2.20.1 + diff --git a/pure-ftpd-1.0.35-config.patch b/pure-ftpd-1.0.47-config.patch similarity index 50% rename from pure-ftpd-1.0.35-config.patch rename to pure-ftpd-1.0.47-config.patch index 845379e..725258f 100644 --- a/pure-ftpd-1.0.35-config.patch +++ b/pure-ftpd-1.0.47-config.patch @@ -1,61 +1,61 @@ -diff -up ./configuration-file/pure-ftpd.conf.in.config ./configuration-file/pure-ftpd.conf.in ---- ./configuration-file/pure-ftpd.conf.in.config 2009-11-20 14:15:01.000000000 +0100 -+++ ./configuration-file/pure-ftpd.conf.in 2009-12-04 22:09:21.461504212 +0100 +diff -up a/pure-ftpd.conf.in b/pure-ftpd.conf.in +--- a/pure-ftpd.conf.in 2017-09-07 13:47:26.000000000 +0200 ++++ b/pure-ftpd.conf.in 2019-02-05 17:27:07.475603616 +0100 @@ -9,7 +9,7 @@ # instead of command-line options, please run the # following command : # --# @prefix@/sbin/pure-config.pl @prefix@/etc/pure-ftpd.conf -+# @sbindir@/pure-config.pl @sysconfdir@/pure-ftpd.conf +-# @prefix@/sbin/pure-ftpd @sysconfdir@/etc/pure-ftpd.conf ++# @sbindir@/pure-ftpd @sysconfdir@/pure-ftpd.conf # - # Please don't forget to have a look at documentation at - # http://www.pureftpd.org/documentation.shtml for a complete list of -@@ -107,34 +107,34 @@ MaxIdleTime 15 + # Online documentation: + # https://www.pureftpd.org/project/pure-ftpd/doc +@@ -106,34 +106,34 @@ # LDAP configuration file (see README.LDAP) --# LDAPConfigFile /etc/pureftpd-ldap.conf +-# LDAPConfigFile /etc/pureftpd-ldap.conf +# LDAPConfigFile @sysconfdir@/pureftpd-ldap.conf # MySQL configuration file (see README.MySQL) --# MySQLConfigFile /etc/pureftpd-mysql.conf +-# MySQLConfigFile /etc/pureftpd-mysql.conf +# MySQLConfigFile @sysconfdir@/pureftpd-mysql.conf - # Postgres configuration file (see README.PGSQL) + # PostgreSQL configuration file (see README.PGSQL) --# PGSQLConfigFile /etc/pureftpd-pgsql.conf +-# PGSQLConfigFile /etc/pureftpd-pgsql.conf +# PGSQLConfigFile @sysconfdir@/pureftpd-pgsql.conf # PureDB user database (see README.Virtual-Users) --# PureDB /etc/pureftpd.pdb +-# PureDB /etc/pureftpd.pdb +# PureDB @sysconfdir@/pureftpd.pdb # Path to pure-authd socket (see README.Authentication-Modules) --# ExtAuth /var/run/ftpd.sock +-# ExtAuth /var/run/ftpd.sock +# ExtAuth @localstatedir@/run/ftpd.sock # If you want to enable PAM authentication, uncomment the following line --# PAMAuthentication yes +-# PAMAuthentication yes +PAMAuthentication yes -@@ -237,7 +237,14 @@ Umask 133:022 +@@ -238,7 +238,14 @@ + # For example, a value of 100 prevents all users whose user id is below + # 100 from logging in. If you want "root" to be able to log in, use 0. - # Minimum UID for an authenticated user to log in. - --MinUID 100 +-MinUID 100 +MinUID 1000 + + @@ -67,20 +67,20 @@ diff -up ./configuration-file/pure-ftpd.conf.in.config ./configuration-file/pure -@@ -276,7 +283,7 @@ AutoRename no +@@ -277,7 +284,7 @@ - # Disallow anonymous users to upload new files (no = upload is allowed) + # Prevent anonymous users from uploading new files (no = upload is allowed) --AnonymousCantUpload no +-AnonymousCantUpload no +AnonymousCantUpload yes -@@ -301,21 +308,21 @@ AnonymousCantUpload no - # fw.c9x.org - jedi [13/Dec/1975:19:36:39] "GET /ftp/linux.tar.bz2" 200 21809338 - # This log file can then be processed by www traffic analyzers. +@@ -301,21 +308,21 @@ + # fw.c9x.org - jedi [13/Apr/2017:19:36:39] "GET /ftp/linux.tar.bz2" 200 21809338 + # This log file can then be processed by common HTTP traffic analyzers. --# AltLog clf:/var/log/pureftpd.log +-# AltLog clf:/var/log/pureftpd.log +AltLog clf:@localstatedir@/log/pureftpd.log @@ -88,27 +88,27 @@ diff -up ./configuration-file/pure-ftpd.conf.in.config ./configuration-file/pure # Create an additional log file with transfers logged in a format optimized # for statistic reports. --# AltLog stats:/var/log/pureftpd.log +-# AltLog stats:/var/log/pureftpd.log +# AltLog stats:@localstatedir@/log/pureftpd.log # Create an additional log file with transfers logged in the standard W3C - # format (compatible with most commercial log analyzers) + # format (compatible with many HTTP log analyzers) --# AltLog w3c:/var/log/pureftpd.log +-# AltLog w3c:/var/log/pureftpd.log +# AltLog w3c:@localstatedir@/log/pureftpd.log -@@ -346,9 +353,9 @@ AnonymousCantUpload no +@@ -346,9 +353,9 @@ # If your pure-ftpd has been compiled with standalone support, you can change -# the location of the pid file. The default is /var/run/pure-ftpd.pid +# the location of the pid file. The default is @localstatedir@/run/pure-ftpd.pid --#PIDFile /var/run/pure-ftpd.pid +-# PIDFile /var/run/pure-ftpd.pid +#PIDFile @localstatedir@/run/pure-ftpd.pid diff --git a/pure-ftpd.spec b/pure-ftpd.spec index 21fca18..cfa2b0d 100644 --- a/pure-ftpd.spec +++ b/pure-ftpd.spec @@ -1,6 +1,6 @@ Name: pure-ftpd -Version: 1.0.42 -Release: 3%{?dist} +Version: 1.0.47 +Release: 4%{?dist} Summary: Lightweight, fast and secure FTP server Group: System Environment/Daemons @@ -14,8 +14,32 @@ Source4: pure-ftpd.pure-ftpwho.pam Source5: pure-ftpd.pure-ftpwho.consoleapp Source6: pure-ftpd.README.SELinux Source7: pure-ftpd.pureftpd.te -Patch0: pure-ftpd-1.0.35-config.patch +Patch0: pure-ftpd-1.0.47-config.patch Patch1: pure-ftpd-1.0.40-paminclude.patch +# Upstream patch: +Patch2: 0001-Exit-when-given-an-invalid-cmdline-option.patch +# Upstream patch: +Patch3: 0002-Complain-when-both-options-and-config-file-are-given.patch +# Upstream patch: +Patch4: 0001-Increase-MAX_DATA_SIZE-due-to-Argon2id-requirements.patch +# Upstream patch: +Patch6: 0001-Fix-postgresql-authenticate-bug.patch + +# Revert pure-config.pl and contrib removal: +Patch7: 0001-Revert-After-20-years-say-goodbye-to-the-external-co.patch +Patch8: 0001-Revert-No-more-contrib-Makefile.in.patch +Patch9: 0002-Revert-Remove-contribs.-These-are-way-too-old-and-un.patch +Patch10: 0003-Revert-Remove-pure-vpopauth.-That-script-is-terrible.patch + +# Temporarily disable TLSv1.3 to workaround +# https://github.com/jedisct1/pure-ftpd/issues/102 +Patch11: 0001-Temporarily-disable-TLSv1.3-support.patch +# Upstream patch: +Patch12: 0001-listdir-reuse-a-single-buffer-to-store-every-file-na.patch +# Upstream patch: +Patch13: 0001-diraliases-always-set-the-tail-of-the-list-to-NULL.patch +# Upstream patch: +Patch14: 0001-pure_strcmp-len-s2-can-be-len-s1.patch Provides: ftpserver BuildRequires: pam-devel, perl, python, libcap-devel @@ -25,6 +49,7 @@ BuildRequires: pam-devel, perl, python, libcap-devel %{!?_without_tls:BuildRequires: openssl-devel} BuildRequires: checkpolicy, selinux-policy-devel BuildRequires: systemd-units +BuildRequires: automake autoconf-archive Requires(post): systemd-sysv Requires(post): systemd-units Requires(preun): systemd-units @@ -66,14 +91,27 @@ Pure-FTPd to be protected in the same way other FTP servers are in Fedora %prep %setup -q -%patch0 -p0 -b .config +%patch0 -p1 -b .config %patch1 -p1 -b .paminclude +%patch2 -p1 +%patch3 -p1 +%patch4 -p1 +%patch6 -p1 +%patch7 -p1 +%patch8 -p1 +%patch9 -p1 +%patch10 -p1 +%patch11 -p1 +%patch12 -p1 +%patch13 -p1 +%patch14 -p1 install -pm 644 %{SOURCE6} README.SELinux mkdir selinux cp -p %{SOURCE7} selinux/pureftpd.te %build +autoreconf -fi %configure \ --sysconfdir=%{_sysconfdir}/%{name} \ --with-capabilities \ @@ -118,7 +156,7 @@ install -d -m 755 $RPM_BUILD_ROOT%{_localstatedir}/ftp # Conf install -p -m 755 configuration-file/pure-config.pl $RPM_BUILD_ROOT%{_sbindir} -install -p -m 644 configuration-file/pure-ftpd.conf $RPM_BUILD_ROOT%{_sysconfdir}/%{name} +install -p -m 644 pure-ftpd.conf $RPM_BUILD_ROOT%{_sysconfdir}/%{name} install -p -m 755 configuration-file/pure-config.py $RPM_BUILD_ROOT%{_sbindir} install -p -m 644 pureftpd-ldap.conf $RPM_BUILD_ROOT%{_sysconfdir}/%{name} install -p -m 644 pureftpd-mysql.conf $RPM_BUILD_ROOT%{_sysconfdir}/%{name} @@ -242,6 +280,23 @@ fi %changelog +* Wed May 06 2020 Ondřej Lysoněk - 1.0.47-4 +- Fix CVE-2020-9365 and CVE-2020-9274 +- Resolves: rhbz#1828689 +- Resolves: rhbz#1831060 + +* Mon Jan 27 2020 Ondřej Lysoněk - 1.0.47-3 +- Fix potential stack exhaustion in function listdir (CVE-2019-20176) +- Resolves: rhbz#1795152 + +* Wed Feb 13 2019 Ondřej Lysoněk - 1.0.47-2 +- Temporarily disable TLSv1.3 support until it's fully fixed + +* Tue Feb 05 2019 Ondřej Lysoněk - 1.0.47-1 +- New version +- Resolves: rhbz#1397962 +- Resolves: rhbz#1576825 + * Wed Dec 23 2015 Robert Scheck - 1.0.42-3 - Remove executable permission bits from pure-ftpd systemd unit diff --git a/sources b/sources index f3bc784..a5bbab1 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -4022f38939f6a112b18c1a43dee552c1 pure-ftpd-1.0.42.tar.bz2 +SHA512 (pure-ftpd-1.0.47.tar.bz2) = c1920a3f67f04635fde600fe226a7730b801e7e64658b25f1d9f9c0b35a704664be4adfb0b291594f7e0f10beade25eae9a5e6cc3b6777a3b413f3c2d9574e63