[Git][debian-proftpd-team/proftpd][master] [skip-ci] Remove obsolete upstream patches.

Hilmar Preuße (@hilmar-guest) gitlab at salsa.debian.org
Mon Mar 6 19:31:56 GMT 2023



Hilmar Preuße pushed to branch master at Debian ProFTPD Team / proftpd


Commits:
7c4d3644 by Hilmar Preusse at 2023-03-06T20:30:53+01:00
[skip-ci] Remove obsolete upstream patches.

- - - - -


18 changed files:

- − debian/patches/0d932cf9c39071d3c053b811e9ca5f6c9823fe6e.diff
- − debian/patches/2eadd82f392573235432a9cb60266f6472d08884.diff
- − debian/patches/3c73f39f0db6724db597646eb6e476278f76edf5.diff
- − debian/patches/bug_4467
- − debian/patches/cd9036f4ef7a05c107f0ffcb19a018b20267c531.patch
- − debian/patches/pr_1094.diff
- debian/patches/series
- − debian/patches/spelling_error_in_contrib_mod_tls.c
- − debian/patches/spelling_errors
- − debian/patches/upstream_1061
- − debian/patches/upstream_1063
- − debian/patches/upstream_1070
- − debian/patches/upstream_1284
- − debian/patches/upstream_1322
- − debian/patches/upstream_1325
- − debian/patches/upstream_1346
- − debian/patches/upstream_1450.diff
- − debian/patches/upstream_long_AuthGroupFile_lines


Changes:

=====================================
debian/patches/0d932cf9c39071d3c053b811e9ca5f6c9823fe6e.diff deleted
=====================================
@@ -1,32 +0,0 @@
-From 0d932cf9c39071d3c053b811e9ca5f6c9823fe6e Mon Sep 17 00:00:00 2001
-From: TJ Saunders <tj at castaglia.org>
-Date: Sat, 14 May 2022 05:45:30 -0700
-Subject: [PATCH] Backport of fix for Issue #1445 to the 1.3.7 branch.
-
----
- contrib/mod_ban.c | 6 +++---
- 1 file changed, 3 insertions(+), 3 deletions(-)
-
-diff --git a/contrib/mod_ban.c b/contrib/mod_ban.c
-index 25f4625e32..3d3a088b1c 100644
---- a/contrib/mod_ban.c
-+++ b/contrib/mod_ban.c
-@@ -1,6 +1,6 @@
- /*
-  * ProFTPD: mod_ban -- a module implementing ban lists using the Controls API
-- * Copyright (c) 2004-2020 TJ Saunders
-+ * Copyright (c) 2004-2022 TJ Saunders
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -3163,8 +3163,8 @@ static void ban_anonrejectpasswords_ev(const void *event_data,
- 
- static void ban_badprotocol_ev(const void *event_data, void *user_data) {
- 
--  /* For this event, event_data is the client. */
--  conn_t *c = (conn_t *) event_data;
-+  /* For this event, event_data is the bad command in question. */
-+  conn_t *c = session.c;
-   const char *ipstr;
- 
-   /* user_data is a template of the ban event entry. */


=====================================
debian/patches/2eadd82f392573235432a9cb60266f6472d08884.diff deleted
=====================================
@@ -1,140 +0,0 @@
-From 2eadd82f392573235432a9cb60266f6472d08884 Mon Sep 17 00:00:00 2001
-From: TJ Saunders <tj at castaglia.org>
-Date: Sun, 16 Aug 2020 08:51:10 -0700
-Subject: [PATCH] Issue #1074: Properly handle the `TLSCertificateChainFile`
- directive when SNI is used.
-
----
- contrib/mod_tls.c | 56 ++++++++++++++++++++++++++++++++++++++++-------
- src/main.c        |  4 ++++
- 2 files changed, 52 insertions(+), 8 deletions(-)
-
-Index: proftpd/contrib/mod_tls.c
-===================================================================
---- proftpd.orig/contrib/mod_tls.c	2020-09-10 23:48:30.260677792 +0200
-+++ proftpd/contrib/mod_tls.c	2020-09-10 23:48:30.228662195 +0200
-@@ -16172,6 +16172,30 @@
- 
- /* SSL setters */
- 
-+static int tls_ssl_set_cert_chain(SSL *ssl) {
-+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
-+    !defined(HAVE_LIBRESSL)
-+  int res;
-+
-+  if (tls_ca_chain == NULL) {
-+    return 0;
-+  }
-+
-+  tls_log("adding certs from '%s' to SSL certificate chain", tls_ca_chain);
-+  PRIVS_ROOT
-+  res = SSL_use_certificate_chain_file(ssl, tls_ca_chain);
-+  PRIVS_RELINQUISH
-+
-+  if (res != 1) {
-+    tls_log("unable to read certificate chain '%s': %s", tls_ca_chain,
-+      tls_get_errors());
-+    return -1;
-+  }
-+#endif /* OpenSSL 1.1.x and later */
-+
-+  return 0;
-+}
-+
- static int tls_ssl_set_ciphers(SSL *ssl) {
-   SSL_set_cipher_list(ssl, tls_cipher_suite);
-   return 0;
-@@ -16689,6 +16713,13 @@
-     return -1;
-   }
- 
-+  /* Inexplicable OpenSSL errors occur if the cert chain is updated after
-+   * calling SSL_set_SSL_CTX, so we do it beforehand.
-+   */
-+  if (tls_ssl_set_cert_chain(ssl) < 0) {
-+    return -1;
-+  }
-+
- #if OPENSSL_VERSION_NUMBER > 0x009080cfL
-   /* Note that it is important that we update the SSL with the new SSL_CTX
-    * AFTER it has been provisioned.  That way, the new/changed certs in the
-@@ -17333,10 +17364,10 @@
- 
- static int tls_ctx_set_cert_chain(SSL_CTX *ctx, X509 *dsa_cert, X509 *ec_cert,
-     X509 *rsa_cert) {
-+#if defined(SSL_CTRL_CHAIN_CERT)
-   BIO *bio;
-   X509 *cert;
-   unsigned int count = 0;
--  int res;
- 
-   if (tls_ca_chain == NULL) {
-     return 0;
-@@ -17344,14 +17375,20 @@
- 
-   PRIVS_ROOT
-   bio = BIO_new_file(tls_ca_chain, "r");
--  if (bio == NULL) {
--    PRIVS_RELINQUISH
-+  PRIVS_RELINQUISH
- 
-+  if (bio == NULL) {
-     tls_log("unable to read certificate chain '%s': %s", tls_ca_chain,
-       tls_get_errors());
-     return 0;
-   }
- 
-+  if (SSL_CTX_clear_chain_certs(ctx) != 1) {
-+    tls_log("error clearing SSL_CTX chain certs: %s", tls_get_errors());
-+    BIO_free(bio);
-+    return -1;
-+  }
-+
-   cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
-   while (cert != NULL) {
-     pr_signals_handle();
-@@ -17383,9 +17420,9 @@
-       }
-     }
- 
--    res = SSL_CTX_add_extra_chain_cert(ctx, cert);
--    if (res != 1) {
--      tls_log("error adding cert to certificate chain: %s", tls_get_errors());
-+    if (SSL_CTX_add1_chain_cert(ctx, cert) != 1) {
-+      tls_log("error adding cert to SSL_CTX certificate chain: %s",
-+        tls_get_errors());
-       X509_free(cert);
-       break;
-     }
-@@ -17394,10 +17431,13 @@
-     cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
-   }
- 
--  PRIVS_RELINQUISH
-   BIO_free(bio);
-+  ERR_clear_error();
-+
-+  tls_log("added %u certs from '%s' to SSL_CTX certificate chain", count,
-+    tls_ca_chain);
-+#endif /* SSL_CTRL_CHAIN_CERT */
- 
--  tls_log("added %u certs from '%s' to certificate chain", count, tls_ca_chain);
-   return 0;
- }
- 
-Index: proftpd/src/main.c
-===================================================================
---- proftpd.orig/src/main.c	2020-09-10 23:48:30.260677792 +0200
-+++ proftpd/src/main.c	2020-09-10 23:48:30.244669994 +0200
-@@ -2102,7 +2102,11 @@
- # ifdef PR_USE_OPENSSL_FIPS
-     printf("    + OpenSSL support (%s, FIPS enabled)\n", OPENSSL_VERSION_TEXT);
- # else
-+#  ifdef LIBRESSL_VERSION_NUMBER
-+    printf("    + OpenSSL support (%s, LibreSSL)\n", OPENSSL_VERSION_TEXT);
-+#  else
-     printf("    + OpenSSL support (%s)\n", OPENSSL_VERSION_TEXT);
-+#  endif /* Have LibreSSL */
- # endif /* PR_USE_OPENSSL_FIPS */
- #else
-   printf("%s", "    - OpenSSL support\n");


=====================================
debian/patches/3c73f39f0db6724db597646eb6e476278f76edf5.diff deleted
=====================================
@@ -1,163 +0,0 @@
-From 3c73f39f0db6724db597646eb6e476278f76edf5 Mon Sep 17 00:00:00 2001
-From: TJ Saunders <tj at castaglia.org>
-Date: Sat, 8 Aug 2020 09:18:58 -0700
-Subject: [PATCH] Bug #4405: Allocate the algorithm name strings for ciphers,
- MACs out of pools other than the KEX pool, as the strings have different
- lifetimes.
-
----
- contrib/mod_sftp/cipher.c | 35 +++++++++++++++++++++++++++++------
- contrib/mod_sftp/mac.c    | 37 ++++++++++++++++++++++++++++++-------
- 2 files changed, 59 insertions(+), 13 deletions(-)
-
-diff --git a/contrib/mod_sftp/cipher.c b/contrib/mod_sftp/cipher.c
-index c3b51efe2..77c79e067 100644
---- a/contrib/mod_sftp/cipher.c
-+++ b/contrib/mod_sftp/cipher.c
-@@ -32,6 +32,7 @@
- #include "interop.h"
- 
- struct sftp_cipher {
-+  pool *pool;
-   const char *algo;
-   const EVP_CIPHER *cipher;
- 
-@@ -51,14 +52,14 @@ struct sftp_cipher {
-  */
- 
- static struct sftp_cipher read_ciphers[2] = {
--  { NULL, NULL, NULL, 0, NULL, 0, 0 },
--  { NULL, NULL, NULL, 0, NULL, 0, 0 }
-+  { NULL, NULL, NULL, NULL, 0, NULL, 0, 0 },
-+  { NULL, NULL, NULL, NULL, 0, NULL, 0, 0 }
- };
- static EVP_CIPHER_CTX *read_ctxs[2];
- 
- static struct sftp_cipher write_ciphers[2] = {
--  { NULL, NULL, NULL, 0, NULL, 0, 0 },
--  { NULL, NULL, NULL, 0, NULL, 0, 0 }
-+  { NULL, NULL, NULL, NULL, 0, NULL, 0, 0 },
-+  { NULL, NULL, NULL, NULL, 0, NULL, 0, 0 }
- };
- static EVP_CIPHER_CTX *write_ctxs[2];
- 
-@@ -387,7 +388,18 @@ int sftp_cipher_set_read_algo(const char *algo) {
-       (unsigned long) discard_len);
-   }
- 
--  read_ciphers[idx].algo = algo;
-+  /* Note that we use a new pool, each time the algorithm is set (which
-+   * happens during key exchange) to prevent undue memory growth for
-+   * long-lived sessions with many rekeys.
-+   */
-+  if (read_ciphers[idx].pool != NULL) {
-+    destroy_pool(read_ciphers[idx].pool);
-+  }
-+
-+  read_ciphers[idx].pool = make_sub_pool(sftp_pool);
-+  pr_pool_tag(read_ciphers[idx].pool, "SFTP cipher read pool");
-+  read_ciphers[idx].algo = pstrdup(read_ciphers[idx].pool, algo);
-+
-   read_ciphers[idx].key_len = (uint32_t) key_len;
-   read_ciphers[idx].discard_len = discard_len;
-   return 0;
-@@ -586,7 +598,18 @@ int sftp_cipher_set_write_algo(const char *algo) {
-       (unsigned long) discard_len);
-   }
- 
--  write_ciphers[idx].algo = algo;
-+  /* Note that we use a new pool, each time the algorithm is set (which
-+   * happens during key exchange) to prevent undue memory growth for
-+   * long-lived sessions with many rekeys.
-+   */
-+  if (write_ciphers[idx].pool != NULL) {
-+    destroy_pool(write_ciphers[idx].pool);
-+  }
-+
-+  write_ciphers[idx].pool = make_sub_pool(sftp_pool);
-+  pr_pool_tag(write_ciphers[idx].pool, "SFTP cipher write pool");
-+  write_ciphers[idx].algo = pstrdup(write_ciphers[idx].pool, algo);
-+
-   write_ciphers[idx].key_len = (uint32_t) key_len;
-   write_ciphers[idx].discard_len = discard_len;
-   return 0;
-diff --git a/contrib/mod_sftp/mac.c b/contrib/mod_sftp/mac.c
-index d78e1e775..d5e1ef505 100644
---- a/contrib/mod_sftp/mac.c
-+++ b/contrib/mod_sftp/mac.c
-@@ -1,6 +1,6 @@
- /*
-  * ProFTPD - mod_sftp MACs
-- * Copyright (c) 2008-2017 TJ Saunders
-+ * Copyright (c) 2008-2020 TJ Saunders
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -34,6 +34,7 @@
- #include "umac.h"
- 
- struct sftp_mac {
-+  pool *pool;
-   const char *algo;
-   int algo_type;
- 
-@@ -64,15 +65,15 @@ struct sftp_mac {
-  */
- 
- static struct sftp_mac read_macs[] = {
--  { NULL, 0, NULL, NULL, 0 },
--  { NULL, 0, NULL, NULL, 0 }
-+  { NULL, NULL, 0, NULL, NULL, 0, 0, 0 },
-+  { NULL, NULL, 0, NULL, NULL, 0, 0, 0 }
- };
- static HMAC_CTX *hmac_read_ctxs[2];
- static struct umac_ctx *umac_read_ctxs[2];
- 
- static struct sftp_mac write_macs[] = {
--  { NULL, 0, NULL, NULL, 0 },
--  { NULL, 0, NULL, NULL, 0 }
-+  { NULL, NULL, 0, NULL, NULL, 0, 0, 0 },
-+  { NULL, NULL, 0, NULL, NULL, 0, 0, 0 }
- };
- static HMAC_CTX *hmac_write_ctxs[2];
- static struct umac_ctx *umac_write_ctxs[2];
-@@ -687,7 +688,18 @@ int sftp_mac_set_read_algo(const char *algo) {
-     return -1;
-   }
- 
--  read_macs[idx].algo = algo;
-+  /* Note that we use a new pool, each time the algorithm is set (which
-+   * happens during key exchange) to prevent undue memory growth for
-+   * long-lived sessions with many rekeys.
-+   */
-+  if (read_macs[idx].pool != NULL) {
-+    destroy_pool(read_macs[idx].pool);
-+  }
-+
-+  read_macs[idx].pool = make_sub_pool(sftp_pool);
-+  pr_pool_tag(read_macs[idx].pool, "SFTP MAC read pool");
-+  read_macs[idx].algo = pstrdup(read_macs[idx].pool, algo);
-+
-   if (strncmp(read_macs[idx].algo, "umac-64 at openssh.com", 12) == 0) {
-     read_macs[idx].algo_type = SFTP_MAC_ALGO_TYPE_UMAC64;
-     umac_read_ctxs[idx] = umac_alloc();
-@@ -820,7 +832,18 @@ int sftp_mac_set_write_algo(const char *algo) {
-     return -1;
-   }
- 
--  write_macs[idx].algo = algo;
-+  /* Note that we use a new pool, each time the algorithm is set (which
-+   * happens during key exchange) to prevent undue memory growth for
-+   * long-lived sessions with many rekeys.
-+   */
-+  if (write_macs[idx].pool != NULL) {
-+    destroy_pool(write_macs[idx].pool);
-+  }
-+
-+  write_macs[idx].pool = make_sub_pool(sftp_pool);
-+  pr_pool_tag(write_macs[idx].pool, "SFTP MAC write pool");
-+  write_macs[idx].algo = pstrdup(write_macs[idx].pool, algo);
-+
-   if (strncmp(write_macs[idx].algo, "umac-64 at openssh.com", 12) == 0) {
-     write_macs[idx].algo_type = SFTP_MAC_ALGO_TYPE_UMAC64;
-     umac_write_ctxs[idx] = umac_alloc();


=====================================
debian/patches/bug_4467 deleted
=====================================
@@ -1,34 +0,0 @@
-From ed101eed833bdb53d6bcecdb4448040bd4ce9b5f Mon Sep 17 00:00:00 2001
-From: TJ Saunders <tj at castaglia.org>
-Date: Sat, 29 Jan 2022 11:20:14 -0800
-Subject: [PATCH] Backport of fix for Bug#4467 to the 1.3.7 branch.
-
----
- NEWS               | 2 ++
- modules/mod_xfer.c | 5 ++---
- 2 files changed, 4 insertions(+), 3 deletions(-)
-
-diff --git a/modules/mod_xfer.c b/modules/mod_xfer.c
-index 9348118c00..b7fcf74e94 100644
---- a/modules/mod_xfer.c
-+++ b/modules/mod_xfer.c
-@@ -2,7 +2,7 @@
-  * ProFTPD - FTP server daemon
-  * Copyright (c) 1997, 1998 Public Flood Software
-  * Copyright (c) 1999, 2000 MacGyver aka Habeeb J. Dihu <macgyver at tos.net>
-- * Copyright (c) 2001-2020 The ProFTPD Project team
-+ * Copyright (c) 2001-2022 The ProFTPD Project team
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -1014,9 +1014,8 @@ static void stor_abort(pool *p) {
-         } 
-       }
-     }
--  }
- 
--  if (session.xfer.path != NULL) {
-+  } else if (session.xfer.path != NULL) {
-     if (delete_stores != NULL &&
-         *delete_stores == TRUE) {
-       pr_log_debug(DEBUG5, "removing aborted file '%s'", session.xfer.path);


=====================================
debian/patches/cd9036f4ef7a05c107f0ffcb19a018b20267c531.patch deleted
=====================================
@@ -1,24 +0,0 @@
-From cd9036f4ef7a05c107f0ffcb19a018b20267c531 Mon Sep 17 00:00:00 2001
-From: TJ Saunders <tj at castaglia.org>
-Date: Sat, 22 Feb 2020 09:40:32 -0800
-Subject: [PATCH] Issue #903: We want to remove the data transfer command pool,
- but we _do_ want some memory pool, lest we regress the %{transfer-status}
- LogFormat functionality.
-
----
- src/data.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/data.c b/src/data.c
-index 6ef6d420e..e7b03e231 100644
---- a/src/data.c
-+++ b/src/data.c
-@@ -897,7 +897,7 @@ void pr_data_abort(int err, int quiet) {
-     /* Forcibly clear the data-transfer instigating command pool from the
-      * Response API.
-      */
--    pr_response_set_pool(NULL);
-+    pr_response_set_pool(session.pool);
-   }
- 
-   if (true_abort) {


=====================================
debian/patches/pr_1094.diff deleted
=====================================
@@ -1,57 +0,0 @@
-From dfd5abe7b47648311c8bca4e9a3f6e90582b5143 Mon Sep 17 00:00:00 2001
-From: TJ Saunders <tj at castaglia.org>
-Date: Sun, 30 Aug 2020 09:07:07 -0700
-Subject: [PATCH] Issue #1079: Improve prxs detection of `configure` scripts
- for modules.
-
----
- src/prxs.in | 15 ++++++++++-----
- 1 file changed, 10 insertions(+), 5 deletions(-)
-
-Index: proftpd/src/prxs.in
-===================================================================
---- proftpd.orig/src/prxs.in	2020-09-06 19:53:55.818043780 +0200
-+++ proftpd/src/prxs.in	2020-09-06 19:53:55.802035781 +0200
-@@ -1,7 +1,7 @@
- #!/usr/bin/perl
- 
- # ---------------------------------------------------------------------------
--# Copyright (C) 2008-2012 TJ Saunders <tj at castaglia.org>
-+# Copyright (C) 2008-2020 TJ Saunders <tj at castaglia.org>
- #
- # This program is free software; you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
-@@ -16,8 +16,6 @@
- # You should have received a copy of the GNU General Public License
- # along with this program; if not, write to the Free Software
- # Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
--#
--#  $Id: prxs.in,v 1.10 2012-09-19 00:11:39 castaglia Exp $
- # ---------------------------------------------------------------------------
- 
- use strict;
-@@ -101,7 +99,11 @@
- 
-       if ($file =~ /\/?mod_[^\/]+\.c$/) {
-         $configure_script = $file;
--        $configure_script =~ s/\/?mod_[^\/]+\.c$/\/configure/;
-+        $configure_script =~ s/(\/?)mod_[^\/]+\.c$/\1configure/;
-+
-+        if ($configure_script !~ /^\//) {
-+          $configure_script = './' . $configure_script;
-+        }
-       }
- 
-       my $obj = $file;
-@@ -123,7 +125,10 @@
-     # Check for any configure script for this module.  If present, error out
-     # for now.
-     if (-f $configure_script) {
--      print STDERR "Cannot compile $mod_name using prxs; use $configure_script instead\n";
-+      print STDERR "Cannot compile $mod_name using prxs; use existing $configure_script script instead:\n\n";
-+      print STDERR "  $configure_script\n";
-+      print STDERR "  make\n";
-+      print STDERR "  make install\n";
-       exit 1;
-     }
-   }


=====================================
debian/patches/series
=====================================
@@ -7,23 +7,6 @@ ftpstats
 #mod_cap
 odbc
 #reproducible_build
-#spelling_errors
 #wrong-path-for-interpreter_perl.diff
-#cd9036f4ef7a05c107f0ffcb19a018b20267c531.patch
 #proftpd-mysql-password-backend.diff
-#upstream_1063
-#upstream_1070
-#upstream_1061
-#3c73f39f0db6724db597646eb6e476278f76edf5.diff
-#pr_1094.diff
-#2eadd82f392573235432a9cb60266f6472d08884.diff
-#upstream_1284
-#spelling_error_in_contrib_mod_tls.c
-#upstream_1322
-#upstream_1325
-#upstream_1346
-#upstream_long_AuthGroupFile_lines
-#bug_4467
-#0d932cf9c39071d3c053b811e9ca5f6c9823fe6e.diff
-#upstream_1450.diff
 upstream_1592.diff


=====================================
debian/patches/spelling_error_in_contrib_mod_tls.c deleted
=====================================
@@ -1,15 +0,0 @@
-Author: Hilmar Preusse <hille42 at web.de>
-Last-Update: 20220111
-Forwarded: https://github.com/proftpd/proftpd/issues/1375
-
---- proftpd.orig/contrib/mod_tls.c
-+++ proftpd/contrib/mod_tls.c
-@@ -16592,7 +16592,7 @@
-     data[datalen] = '\0';
- 
-   } else {
--    data = "UKNOWN";
-+    data = "UNKNOWN";
-   }
- 
-   return data;


=====================================
debian/patches/spelling_errors deleted
=====================================
@@ -1,107 +0,0 @@
-Description: Fixed some spelling errors in sources
-Author: Francesco Paolo Lovergine <frankie at debian.org>
-Last-Update: 2017-01-09
-Forwarded: https://github.com/proftpd/proftpd/pull/666
-
---- proftpd-dfsg-1.3.6c.orig/contrib/mod_sftp/date.c
-+++ proftpd-dfsg-1.3.6c/contrib/mod_sftp/date.c
-@@ -124,7 +124,7 @@
-       case '?':
-         /* Ignore unsupported options */
-         (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
--          "ingoring supported date(1) option '%c'", (char) optopt);
-+          "ignoring supported date(1) option '%c'", (char) optopt);
-         break;
-     }
-   }
---- proftpd-dfsg-1.3.6c.orig/contrib/mod_sftp/keys.c
-+++ proftpd-dfsg-1.3.6c/contrib/mod_sftp/keys.c
-@@ -1121,7 +1121,7 @@
- 
-     if (sftp_keys_validate_ecdsa_params(curve, point) < 0) {
-       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
--        "erorr validating EC public key: %s", strerror(errno));
-+        "error validating EC public key: %s", strerror(errno));
-       EC_POINT_free(point);
-       EC_KEY_free(ec);
-       return NULL;
-@@ -2101,7 +2101,7 @@
-       if (sftp_keys_validate_ecdsa_params(EC_KEY_get0_group(ec),
-           EC_KEY_get0_public_key(ec)) < 0) {
-         (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
--          "erorr validating EC public key: %s", strerror(errno));
-+          "error validating EC public key: %s", strerror(errno));
-         EC_KEY_free(ec);
-         EVP_PKEY_free(pkey);
-         return -1;
-@@ -2109,7 +2109,7 @@
- 
-       if (validate_ecdsa_private_key(ec)) {
-         (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
--          "erorr validating EC private key: %s", strerror(errno));
-+          "error validating EC private key: %s", strerror(errno));
-         EC_KEY_free(ec);
-         EVP_PKEY_free(pkey);
-         return -1;
---- proftpd-dfsg-1.3.6c.orig/contrib/mod_tls.c
-+++ proftpd-dfsg-1.3.6c/contrib/mod_tls.c
-@@ -2172,7 +2172,7 @@
-   if (idx < 0) {
-     pr_trace_msg(trace_channel, 12,
-       "unable to check certificate CommonName against '%s': "
--      "no CommoName atribute found", name);
-+      "no CommoName attribute found", name);
-     return 0;
-   }
- 
-@@ -2180,7 +2180,7 @@
-   if (cn_entry == NULL) {
-     pr_trace_msg(trace_channel, 12,
-       "unable to check certificate CommonName against '%s': "
--      "error obtaining CommoName atribute found: %s", name, tls_get_errors());
-+      "error obtaining CommoName attribute found: %s", name, tls_get_errors());
-     return 0;
-   }
- 
-@@ -2189,7 +2189,7 @@
-   if (cn_asn1 == NULL) {
-     pr_trace_msg(trace_channel, 12,
-       "unable to check certificate CommonName against '%s': "
--      "error converting CommoName atribute to ASN.1: %s", name,
-+      "error converting CommoName attribute to ASN.1: %s", name,
-       tls_get_errors());
-     return 0;
-   }
---- proftpd-dfsg-1.3.6c.orig/doc/utils/ftpwho.html
-+++ proftpd-dfsg-1.3.6c/doc/utils/ftpwho.html
-@@ -14,7 +14,7 @@
- 
- The <B>ftpwho</B> command shows process information for all active proftpd
- connections, and a count of all connected users off of each server.  Proftpd
--sesssions spawned from inetd are counted seperately from those created by a
-+sessions spawned from inetd are counted seperately from those created by a
- master proftpd <I>standalone</I> server.
- 
- <H2>OPTIONS</H2>
---- proftpd-dfsg-1.3.6c.orig/utils/ftpwho.1.in
-+++ proftpd-dfsg-1.3.6c/utils/ftpwho.1.in
-@@ -10,7 +10,7 @@
- The
- .BI ftpwho
- command shows process information for all active proftpd connections,
--and a count of all connected users off of each server.  Proftpd sesssions
-+and a count of all connected users off of each server.  Proftpd sessions
- spawned from inetd are counted separately from those created by a
- master proftpd
- .I standalone
---- proftpd-dfsg-1.3.6c.orig/contrib/mod_ldap.c
-+++ proftpd-dfsg-1.3.6c/contrib/mod_ldap.c
-@@ -930,7 +930,7 @@
-   cached_quota->nelts = 1;
- 
-   (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
--    "parsing ftpQuota atribute value '%s'", str);
-+    "parsing ftpQuota attribute value '%s'", str);
- 
-   while ((token = strsep(&str, ","))) {
-     pr_signals_handle();


=====================================
debian/patches/upstream_1061 deleted
=====================================
@@ -1,50 +0,0 @@
-From 1117b003fa25c2e29e3a679ba3a1a3b92b5a4587 Mon Sep 17 00:00:00 2001
-From: TJ Saunders <tj at castaglia.org>
-Date: Sat, 25 Jul 2020 16:51:26 -0700
-Subject: [PATCH] Issue #1061: While investigating some reported issues with
- Ed25519 keys and mod_sftp, I reproduced one segfault when verifying such keys
- during publickey authentication.
-
----
- contrib/mod_sftp/kex.c  | 2 +-
- contrib/mod_sftp/keys.c | 7 +++++--
- 2 files changed, 6 insertions(+), 3 deletions(-)
-
-diff --git a/contrib/mod_sftp/kex.c b/contrib/mod_sftp/kex.c
-index 17e853fe2..59c76f3c0 100644
---- a/contrib/mod_sftp/kex.c
-+++ b/contrib/mod_sftp/kex.c
-@@ -2869,7 +2869,7 @@ static int write_ext_info_server_sig_algs(struct ssh2_packet *pkt, char **buf,
-   char *sig_algs = "";
- 
- #if defined(PR_USE_SODIUM)
--  sig_algs = pstrcat(pkt->pool, sig_algs, *sig_algs ? "," : "", "ssh-ec25519",
-+  sig_algs = pstrcat(pkt->pool, sig_algs, *sig_algs ? "," : "", "ssh-ed25519",
-     NULL);
- #endif /* PR_USE_SODIUM */
- 
-diff --git a/contrib/mod_sftp/keys.c b/contrib/mod_sftp/keys.c
-index b2e03f722..c94a3b201 100644
---- a/contrib/mod_sftp/keys.c
-+++ b/contrib/mod_sftp/keys.c
-@@ -4453,7 +4453,7 @@ const unsigned char *sftp_keys_sign_data(pool *p,
- 
- int sftp_keys_verify_pubkey_type(pool *p, unsigned char *pubkey_data,
-     uint32_t pubkey_len, enum sftp_key_type_e pubkey_type) {
--  EVP_PKEY *pkey;
-+  EVP_PKEY *pkey = NULL;
-   int res = FALSE;
-   uint32_t len;
- 
-@@ -4542,7 +4542,10 @@ int sftp_keys_verify_pubkey_type(pool *p, unsigned char *pubkey_data,
-       break;
-   }
- 
--  EVP_PKEY_free(pkey);
-+  if (pkey != NULL) {
-+    EVP_PKEY_free(pkey);
-+  }
-+
-   return res;
- }
- 


=====================================
debian/patches/upstream_1063 deleted
=====================================
@@ -1,45 +0,0 @@
-From adf43dd4ddaab0332e74abc86bbcef9cf27ee54a Mon Sep 17 00:00:00 2001
-From: TJ Saunders <tj at castaglia.org>
-Date: Sat, 25 Jul 2020 11:10:07 -0700
-Subject: [PATCH] Issue #1063: Avoid segfaults for TLSv1.3 data transfers in
- our session tickey callback by checking the status before using SSL_SESSION
- pointer.
-
----
- contrib/mod_tls.c | 21 +++++++++++++++------
- 1 file changed, 15 insertions(+), 6 deletions(-)
-
-diff --git a/contrib/mod_tls.c b/contrib/mod_tls.c
-index c4e3a2f18..3cab789c9 100644
---- a/contrib/mod_tls.c
-+++ b/contrib/mod_tls.c
-@@ -6833,14 +6833,23 @@ static SSL_TICKET_RETURN tls_decrypt_session_ticket_data_upload_cb(SSL *ssl,
-     SSL_SESSION *ssl_session, const unsigned char *key_name, size_t key_namelen,
-     SSL_TICKET_STATUS status, void *user_data) {
-   SSL_TICKET_RETURN res;
--  int ssl_version, renew_tickets = TRUE;
-+  int renew_tickets = TRUE;
- 
--  ssl_version = SSL_SESSION_get_protocol_version(ssl_session);
-+  /* Avoid using the given SSL_SESSION pointer unless the status indicates that
-+   * that pointer is valid (Issue #1063).
-+   */
-+
-+  if (status != SSL_TICKET_EMPTY &&
-+      status != SSL_TICKET_NO_DECRYPT) {
-+    int ssl_version;
-+
-+    ssl_version = SSL_SESSION_get_protocol_version(ssl_session);
- # if defined(TLS1_3_VERSION)
--  if (ssl_version == TLS1_3_VERSION) {
--    pr_trace_msg(trace_channel, 29,
--      "suppressing renewal of TLSv1.3 tickets for data transfers");
--    renew_tickets = FALSE;
-+    if (ssl_version == TLS1_3_VERSION) {
-+      pr_trace_msg(trace_channel, 29,
-+        "suppressing renewal of TLSv1.3 tickets for data transfers");
-+      renew_tickets = FALSE;
-+    }
-   }
- # endif /* TLS1_3_VERSION */
- 


=====================================
debian/patches/upstream_1070 deleted
=====================================
@@ -1,705 +0,0 @@
-From 3fe77bd7088af1e0f5822e12555a4f4221301dbe Mon Sep 17 00:00:00 2001
-From: TJ Saunders <tj at castaglia.org>
-Date: Sun, 26 Jul 2020 13:38:42 -0700
-Subject: [PATCH] Issue #1070: Implement support for Redis 6.x AUTH semantics.
-
----
- include/redis.h    |  10 ++-
- src/redis.c        | 128 +++++++++++++++++++++++++--
- tests/api/env.c    |   8 +-
- tests/api/redis.c  | 210 ++++++++++++++++++++++++++++++++++++++-------
- tests/api/sets.c   |  24 +++---
- tests/api/str.c    |   8 +-
- tests/api/timers.c |   2 +-
- 7 files changed, 334 insertions(+), 56 deletions(-)
-
-diff --git a/include/redis.h b/include/redis.h
-index 27f71e454..eae519bfb 100644
---- a/include/redis.h
-+++ b/include/redis.h
-@@ -1,6 +1,6 @@
- /*
-  * ProFTPD - FTP server daemon
-- * Copyright (c) 2017 The ProFTPD Project team
-+ * Copyright (c) 2017-2020 The ProFTPD Project team
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -55,8 +55,14 @@ int pr_redis_conn_destroy(pr_redis_t *redis);
- int pr_redis_conn_set_namespace(pr_redis_t *redis, module *m,
-   const void *prefix, size_t prefixsz);
- 
-+/* Redis server version. */
-+int pr_redis_conn_get_version(pr_redis_t *redis, unsigned int *major_version,
-+  unsigned int *minor_version, unsigned int *patch_version);
-+
- /* Authenticate to a password-protected Redis server. */
- int pr_redis_auth(pr_redis_t *redis, const char *password);
-+int pr_redis_auth2(pr_redis_t *redis, const char *username,
-+  const char *password);
- 
- /* Select the database used by the Redis server. */
- int pr_redis_select(pr_redis_t *redis, const char *db_idx);
-@@ -304,6 +310,8 @@ int pr_redis_sentinel_get_masters(pool *p, pr_redis_t *redis,
- /* For internal use only */
- int redis_set_server(const char *server, int port, unsigned long flags,
-   const char *password, const char *db_idx);
-+int redis_set_server2(const char *server, int port, unsigned long flags,
-+  const char *username, const char *password, const char *db_idx);
- int redis_set_sentinels(array_header *sentinels, const char *name);
- int redis_set_timeouts(unsigned long connect_millis, unsigned long io_millis);
- 
-diff --git a/src/redis.c b/src/redis.c
-index 5bd99623f..cca05bd3f 100644
---- a/src/redis.c
-+++ b/src/redis.c
-@@ -49,6 +49,11 @@ struct redis_rec {
-    */
-   unsigned int refcount;
- 
-+  /* Redis server version. */
-+  unsigned int major_version;
-+  unsigned int minor_version;
-+  unsigned int patch_version;
-+
-   /* Table mapping modules to their namespaces */
-   pr_table_t *namespace_tab;
- };
-@@ -59,6 +64,7 @@ static const char *redis_sentinel_master = NULL;
- static const char *redis_server = NULL;
- static int redis_port = -1;
- static unsigned long redis_flags = 0UL;
-+static const char *redis_username = NULL;
- static const char *redis_password = NULL;
- static const char *redis_db_idx = NULL;
- 
-@@ -69,6 +75,8 @@ static unsigned long redis_io_millis = 500;
- 
- static const char *trace_channel = "redis";
- 
-+static const char *get_reply_type(int reply_type);
-+
- static void millis2timeval(struct timeval *tv, unsigned long millis) {
-   tv->tv_sec = (millis / 1000);
-   tv->tv_usec = (millis - (tv->tv_sec * 1000)) * 1000;
-@@ -194,6 +202,48 @@ static int ping_server(pr_redis_t *redis) {
-   return 0;
- }
- 
-+static void parse_redis_version(pr_redis_t *redis, redisReply *info) {
-+  pool *tmp_pool;
-+  unsigned int major, minor, patch;
-+  char *text, *version_text;
-+
-+  if (info->type != REDIS_REPLY_STRING) {
-+    pr_trace_msg(trace_channel, 1, "expected STRING reply for INFO, got %s",
-+      get_reply_type(info->type));
-+    return;
-+  }
-+
-+  tmp_pool = make_sub_pool(redis->pool);
-+  pr_pool_tag(tmp_pool, "Redis version parsing pool");
-+  text = pstrndup(tmp_pool, info->str, info->len);
-+
-+  /* Scan the entire INFO string for "redis_version:N.N.N". */
-+
-+  version_text = strstr(text, "redis_version:");
-+  if (version_text == NULL) {
-+    pr_trace_msg(trace_channel, 1, "no `redis_version` found in INFO reply");
-+    destroy_pool(tmp_pool);
-+    return;
-+  }
-+
-+  if (sscanf(version_text, "redis_version:%u.%u.%u", &major, &minor,
-+      &patch) == 3) {
-+    redis->major_version = major;
-+    redis->minor_version = minor;
-+    redis->patch_version = patch;
-+
-+    pr_trace_msg(trace_channel, 9,
-+      "parsed Redis version %u (major), %u (minor), %u (patch) out of INFO",
-+      redis->major_version, redis->minor_version, redis->patch_version);
-+
-+  } else {
-+    pr_trace_msg(trace_channel, 1, "failed to scan Redis version '%s'",
-+      version_text);
-+  }
-+
-+  destroy_pool(tmp_pool);
-+}
-+
- static int stat_server(pr_redis_t *redis, const char *section) {
-   const char *cmd;
-   redisReply *reply;
-@@ -214,6 +264,18 @@ static int stat_server(pr_redis_t *redis, const char *section) {
-       (unsigned long) reply->len);
-   }
- 
-+  if (redis->major_version == 0 &&
-+      (strcmp(section, "server") == 0 || strcmp(section, "") == 0)) {
-+    /* We are particularly interested in the Redis server version; we key
-+     * off of this version to detect when to change our command semantics,
-+     * such as for AUTH.
-+     *
-+     * Thus we parse the server version out of the "server" info, unless
-+     * the version is already known.
-+     */
-+    parse_redis_version(redis, reply);
-+  }
-+
-   freeReplyObject(reply);
-   return 0;
- }
-@@ -508,7 +570,13 @@ pr_redis_t *pr_redis_conn_new(pool *p, module *m, unsigned long flags) {
-   }
- 
-   if (redis_password != NULL) {
--    res = pr_redis_auth(redis, redis_password);
-+    if (redis_username != NULL) {
-+      res = pr_redis_auth2(redis, redis_username, redis_password);
-+
-+    } else {
-+      res = pr_redis_auth(redis, redis_password);
-+    }
-+
-     if (res < 0) {
-       xerrno = errno;
- 
-@@ -682,6 +750,36 @@ int pr_redis_conn_set_namespace(pr_redis_t *redis, module *m,
-   return 0;
- }
- 
-+int pr_redis_conn_get_version(pr_redis_t *redis, unsigned int *major_version,
-+    unsigned int *minor_version, unsigned int *patch_version) {
-+
-+  if (redis == NULL) {
-+    errno = EINVAL;
-+    return -1;
-+  }
-+
-+  if (major_version == NULL &&
-+      minor_version == NULL &&
-+      patch_version == NULL) {
-+    errno = EINVAL;
-+    return -1;
-+  }
-+
-+  if (major_version != NULL) {
-+    *major_version = redis->major_version;
-+  }
-+
-+  if (minor_version != NULL) {
-+    *minor_version = redis->minor_version;
-+  }
-+
-+  if (patch_version != NULL) {
-+    *patch_version = redis->patch_version;
-+  }
-+
-+  return 0;
-+}
-+
- int pr_redis_add(pr_redis_t *redis, module *m, const char *key, void *value,
-     size_t valuesz, time_t expires) {
-   int res;
-@@ -2003,12 +2101,14 @@ int pr_redis_command(pr_redis_t *redis, const array_header *args,
-   return 0;
- }
- 
--int pr_redis_auth(pr_redis_t *redis, const char *password) {
-+int pr_redis_auth2(pr_redis_t *redis, const char *username,
-+    const char *password) {
-   const char *cmd;
-   pool *tmp_pool;
-   redisReply *reply;
- 
-   if (redis == NULL ||
-+      username == NULL ||
-       password == NULL) {
-     errno = EINVAL;
-     return -1;
-@@ -2019,7 +2119,15 @@ int pr_redis_auth(pr_redis_t *redis, const char *password) {
- 
-   cmd = "AUTH";
-   pr_trace_msg(trace_channel, 7, "sending command: %s", cmd);
--  reply = redisCommand(redis->ctx, "%s %s", cmd, password);
-+
-+  /* Redis 6.x changed the AUTH semantics, now requiring a username. */
-+  if (redis->major_version >= 6) {
-+    reply = redisCommand(redis->ctx, "%s %s %s", cmd, username, password);
-+
-+  } else {
-+    reply = redisCommand(redis->ctx, "%s %s", cmd, password);
-+  }
-+
-   reply = handle_reply(redis, cmd, reply);
-   if (reply == NULL) {
-     pr_trace_msg(trace_channel, 2,
-@@ -2053,6 +2161,10 @@ int pr_redis_auth(pr_redis_t *redis, const char *password) {
-   return 0;
- }
- 
-+int pr_redis_auth(pr_redis_t *redis, const char *password) {
-+  return pr_redis_auth2(redis, "default", password);
-+}
-+
- int pr_redis_select(pr_redis_t *redis, const char *db_idx) {
-   const char *cmd;
-   pool *tmp_pool;
-@@ -5632,8 +5744,8 @@ int pr_redis_sentinel_get_masters(pool *p, pr_redis_t *redis,
-   return res;
- }
- 
--int redis_set_server(const char *server, int port, unsigned long flags,
--    const char *password, const char *db_idx) {
-+int redis_set_server2(const char *server, int port, unsigned long flags,
-+    const char *username, const char *password, const char *db_idx) {
- 
-   if (server == NULL) {
-     /* By using a port of -2 specifically, we can use this function to
-@@ -5649,12 +5761,18 @@ int redis_set_server(const char *server, int port, unsigned long flags,
-   redis_server = server;
-   redis_port = port;
-   redis_flags = flags;
-+  redis_username = username;
-   redis_password = password;
-   redis_db_idx = db_idx;
- 
-   return 0;
- }
- 
-+int redis_set_server(const char *server, int port, unsigned long flags,
-+    const char *password, const char *db_idx) {
-+  return redis_set_server2(server, port, flags, "default", password, db_idx);
-+}
-+
- int redis_set_sentinels(array_header *sentinels, const char *name) {
- 
-   if (sentinels != NULL &&
-diff --git a/tests/api/env.c b/tests/api/env.c
-index ad126385e..b839f2ea4 100644
---- a/tests/api/env.c
-+++ b/tests/api/env.c
-@@ -1,6 +1,6 @@
- /*
-  * ProFTPD - FTP server testsuite
-- * Copyright (c) 2008-2015 The ProFTPD Project team
-+ * Copyright (c) 2008-2020 The ProFTPD Project team
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -61,11 +61,13 @@ START_TEST (env_get_test) {
-   pr_env_unset(p, key);
- 
-   res = pr_env_get(p, key);
--  fail_unless(res == NULL);
-+  fail_unless(res == NULL, "Unexpectedly found value '%s' for key '%s'",
-+    res, key);
- 
-   /* XXX PATH should always be set in the environment, right? */
-   res = pr_env_get(p, "PATH");
--  fail_unless(res != NULL);
-+  fail_unless(res != NULL, "Failed to get value for 'PATH': %s",
-+    strerror(errno));
- 
- #else
-   res = pr_env_get(p, key);
-diff --git a/tests/api/redis.c b/tests/api/redis.c
-index 7e95893ee..e44d5a4bd 100644
---- a/tests/api/redis.c
-+++ b/tests/api/redis.c
-@@ -222,11 +222,44 @@ START_TEST (redis_conn_set_namespace_test) {
- }
- END_TEST
- 
-+START_TEST (redis_conn_get_version_test) {
-+  int res;
-+  pr_redis_t *redis;
-+  unsigned int major = 0, minor = 0, patch = 0;
-+
-+  mark_point();
-+  res = pr_redis_conn_get_version(NULL, NULL, NULL, NULL);
-+  fail_unless(res < 0, "Failed to handle null redis");
-+  fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
-+    strerror(errno), errno);
-+
-+  mark_point();
-+  redis = pr_redis_conn_new(p, NULL, 0);
-+  fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
-+    strerror(errno));
-+
-+  mark_point();
-+  res = pr_redis_conn_get_version(redis, NULL, NULL, NULL);
-+  fail_unless(res < 0, "Failed to handle null version arguments");
-+  fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
-+    strerror(errno), errno);
-+
-+  mark_point();
-+  res = pr_redis_conn_get_version(redis, &major, &minor, &patch);
-+  fail_unless(res == 0, "Failed to get Redis version: %s", strerror(errno));
-+
-+  mark_point();
-+  res = pr_redis_conn_destroy(redis);
-+  fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
-+}
-+END_TEST
-+
- START_TEST (redis_conn_auth_test) {
-   int res;
-   pr_redis_t *redis;
-   const char *text;
-   array_header *args;
-+  unsigned int major_version = 0;
- 
-   mark_point();
-   res = pr_redis_auth(NULL, NULL);
-@@ -245,52 +278,167 @@ START_TEST (redis_conn_auth_test) {
-   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
-     strerror(errno), errno);
- 
--  text = "password";
--
-   /* What happens if we try to AUTH to a non-password-protected Redis?
-    * Answer: Redis returns an error indicating that no password is required.
-+   *
-+   * Note that this behavior changed with Redis 6.x.  In particular, any
-+   * "AUTH default ..." command automatically succeeds with Redis 6.x,
-+   * regardless of the actual password given.  Sigh.
-    */
-+
-+  mark_point();
-+  res = pr_redis_conn_get_version(redis, &major_version, NULL, NULL);
-+  fail_unless(res == 0, "Failed to get Redis version: %s", strerror(errno));
-+
-   mark_point();
-+  text = "password";
-   res = pr_redis_auth(redis, text);
--  fail_unless(res < 0, "Failed to handle lack of need for authentication");
-+
-+  if (major_version < 6) {
-+    fail_unless(res < 0, "Failed to handle lack of need for authentication");
-+    fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
-+      strerror(errno), errno);
-+
-+    /* Use CONFIG SET to require a password. */
-+    args = make_array(p, 0, sizeof(char *));
-+    *((char **) push_array(args)) = pstrdup(p, "CONFIG");
-+    *((char **) push_array(args)) = pstrdup(p, "SET");
-+    *((char **) push_array(args)) = pstrdup(p, "requirepass");
-+    *((char **) push_array(args)) = pstrdup(p, text);
-+
-+    mark_point();
-+    res = pr_redis_command(redis, args, PR_REDIS_REPLY_TYPE_STATUS);
-+    fail_unless(res == 0, "Failed to enable authentication: %s",
-+      strerror(errno));
-+
-+    args = make_array(p, 0, sizeof(char *));
-+    *((char **) push_array(args)) = pstrdup(p, "TIME");
-+
-+    mark_point();
-+    res = pr_redis_command(redis, args, PR_REDIS_REPLY_TYPE_ARRAY);
-+    fail_unless(res < 0, "Failed to handle required authentication");
-+    fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
-+      strerror(errno), errno);
-+
-+    mark_point();
-+    res = pr_redis_auth(redis, text);
-+    fail_unless(res == 0, "Failed to authenticate client: %s", strerror(errno));
-+
-+    /* Don't forget to remove the password. */
-+    args = make_array(p, 0, sizeof(char *));
-+    *((char **) push_array(args)) = pstrdup(p, "CONFIG");
-+    *((char **) push_array(args)) = pstrdup(p, "SET");
-+    *((char **) push_array(args)) = pstrdup(p, "requirepass");
-+    *((char **) push_array(args)) = pstrdup(p, "");
-+
-+    mark_point();
-+    res = pr_redis_command(redis, args, PR_REDIS_REPLY_TYPE_STATUS);
-+    fail_unless(res == 0, "Failed to remove password authentication: %s",
-+      strerror(errno));
-+
-+  } else {
-+    fail_unless(res == 0, "Failed to handle AUTH command: %s",
-+      strerror(errno));
-+  }
-+
-+  mark_point();
-+  res = pr_redis_conn_destroy(redis);
-+  fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
-+}
-+END_TEST
-+
-+START_TEST (redis_conn_auth2_test) {
-+  int res;
-+  pr_redis_t *redis;
-+  const char *username, *password;
-+  array_header *args;
-+  unsigned int major_version = 0;
-+
-+  mark_point();
-+  res = pr_redis_auth2(NULL, NULL, NULL);
-+  fail_unless(res < 0, "Failed to handle null redis");
-   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
-     strerror(errno), errno);
- 
--  /* Use CONFIG SET to require a password. */
--  args = make_array(p, 0, sizeof(char *));
--  *((char **) push_array(args)) = pstrdup(p, "CONFIG");
--  *((char **) push_array(args)) = pstrdup(p, "SET");
--  *((char **) push_array(args)) = pstrdup(p, "requirepass");
--  *((char **) push_array(args)) = pstrdup(p, text);
-+  mark_point();
-+  redis = pr_redis_conn_new(p, NULL, 0);
-+  fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
-+    strerror(errno));
- 
-   mark_point();
--  res = pr_redis_command(redis, args, PR_REDIS_REPLY_TYPE_STATUS);
--  fail_unless(res == 0, "Failed to enable authentication: %s", strerror(errno));
-+  res = pr_redis_auth2(redis, NULL, NULL);
-+  fail_unless(res < 0, "Failed to handle null username");
-+  fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
-+    strerror(errno), errno);
- 
--  args = make_array(p, 0, sizeof(char *));
--  *((char **) push_array(args)) = pstrdup(p, "TIME");
-+  /* Note: Do NOT use "default" as the initial username; that name has
-+   * specific semantics for Redis 6.x and later.
-+   */
-+  username = "foobar";
- 
-   mark_point();
--  res = pr_redis_command(redis, args, PR_REDIS_REPLY_TYPE_ARRAY);
--  fail_unless(res < 0, "Failed to handle required authentication");
-+  res = pr_redis_auth2(redis, username, NULL);
-+  fail_unless(res < 0, "Failed to handle null password");
-   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
-     strerror(errno), errno);
- 
--  mark_point();
--  res = pr_redis_auth(redis, text);
--  fail_unless(res == 0, "Failed to authenticate client: %s", strerror(errno));
-+  /* What happens if we try to AUTH to a non-password-protected Redis?
-+   * Answer: Redis returns an error indicating that no password is required.
-+   *
-+   * Note that this behavior changed with Redis 6.x.  In particular, any
-+   * "AUTH default ..." command automatically succeeds with Redis 6.x,
-+   * regardless of the actual password given.  Sigh.
-+   */
- 
--  /* Don't forget to remove the password. */
--  args = make_array(p, 0, sizeof(char *));
--  *((char **) push_array(args)) = pstrdup(p, "CONFIG");
--  *((char **) push_array(args)) = pstrdup(p, "SET");
--  *((char **) push_array(args)) = pstrdup(p, "requirepass");
--  *((char **) push_array(args)) = pstrdup(p, "");
-+  mark_point();
-+  res = pr_redis_conn_get_version(redis, &major_version, NULL, NULL);
-+  fail_unless(res == 0, "Failed to get Redis version: %s", strerror(errno));
- 
-   mark_point();
--  res = pr_redis_command(redis, args, PR_REDIS_REPLY_TYPE_STATUS);
--  fail_unless(res == 0, "Failed to remove password authentication: %s",
--    strerror(errno));
-+  password = "password";
-+  res = pr_redis_auth2(redis, username, password);
-+  fail_unless(res < 0, "Failed to handle lack of need for authentication");
-+  fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
-+    strerror(errno), errno);
-+
-+  if (major_version < 6) {
-+    /* Use CONFIG SET to require a password. */
-+    args = make_array(p, 0, sizeof(char *));
-+    *((char **) push_array(args)) = pstrdup(p, "CONFIG");
-+    *((char **) push_array(args)) = pstrdup(p, "SET");
-+    *((char **) push_array(args)) = pstrdup(p, "requirepass");
-+    *((char **) push_array(args)) = pstrdup(p, password);
-+
-+    mark_point();
-+    res = pr_redis_command(redis, args, PR_REDIS_REPLY_TYPE_STATUS);
-+    fail_unless(res == 0, "Failed to enable authentication: %s",
-+      strerror(errno));
-+
-+    args = make_array(p, 0, sizeof(char *));
-+    *((char **) push_array(args)) = pstrdup(p, "TIME");
-+
-+    mark_point();
-+    res = pr_redis_command(redis, args, PR_REDIS_REPLY_TYPE_ARRAY);
-+    fail_unless(res < 0, "Failed to handle required authentication");
-+    fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
-+      strerror(errno), errno);
-+
-+    mark_point();
-+    res = pr_redis_auth2(redis, username, password);
-+    fail_unless(res == 0, "Failed to authenticate client: %s", strerror(errno));
-+
-+    /* Don't forget to remove the password. */
-+    args = make_array(p, 0, sizeof(char *));
-+    *((char **) push_array(args)) = pstrdup(p, "CONFIG");
-+    *((char **) push_array(args)) = pstrdup(p, "SET");
-+    *((char **) push_array(args)) = pstrdup(p, "requirepass");
-+    *((char **) push_array(args)) = pstrdup(p, "");
-+
-+    mark_point();
-+    res = pr_redis_command(redis, args, PR_REDIS_REPLY_TYPE_STATUS);
-+    fail_unless(res == 0, "Failed to remove password authentication: %s",
-+      strerror(errno));
-+  }
- 
-   mark_point();
-   res = pr_redis_conn_destroy(redis);
-@@ -1987,7 +2135,7 @@ START_TEST (redis_hash_keys_test) {
-   mark_point();
-   res = pr_redis_hash_keys(p, redis, &m, key, &fields);
-   fail_unless(res == 0, "Failed to handle existing fields: %s", strerror(errno));
--  fail_unless(fields != NULL);
-+  fail_unless(fields != NULL, "Failed to get hash fields");
-   fail_unless(fields->nelts == 2, "Expected 2, got %u", fields->nelts);
- 
-   (void) pr_redis_remove(redis, &m, key);
-@@ -2074,7 +2222,7 @@ START_TEST (redis_hash_values_test) {
-   mark_point();
-   res = pr_redis_hash_values(p, redis, &m, key, &values);
-   fail_unless(res == 0, "Failed to handle existing values: %s", strerror(errno));
--  fail_unless(values != NULL);
-+  fail_unless(values != NULL, "Failed to get hash values");
-   fail_unless(values->nelts == 2, "Expected 2, got %u", values->nelts);
- 
-   (void) pr_redis_remove(redis, &m, key);
-@@ -2161,7 +2309,7 @@ START_TEST (redis_hash_getall_test) {
-   mark_point();
-   res = pr_redis_hash_getall(p, redis, &m, key, &hash);
-   fail_unless(res == 0, "Failed to handle existing fields: %s", strerror(errno));
--  fail_unless(hash != NULL);
-+  fail_unless(hash != NULL, "Failed to get hash");
-   res = pr_table_count(hash);
-   fail_unless(res == 2, "Expected 2, got %d", res);
- 
-@@ -4743,7 +4891,9 @@ Suite *tests_get_redis_suite(void) {
-   tcase_add_test(testcase, redis_conn_new_test);
-   tcase_add_test(testcase, redis_conn_get_test);
-   tcase_add_test(testcase, redis_conn_set_namespace_test);
-+  tcase_add_test(testcase, redis_conn_get_version_test);
-   tcase_add_test(testcase, redis_conn_auth_test);
-+  tcase_add_test(testcase, redis_conn_auth2_test);
-   tcase_add_test(testcase, redis_conn_select_test);
-   tcase_add_test(testcase, redis_conn_reconnect_test);
-   tcase_add_test(testcase, redis_command_test);
-diff --git a/tests/api/sets.c b/tests/api/sets.c
-index 9f3deafc2..9459454f2 100644
---- a/tests/api/sets.c
-+++ b/tests/api/sets.c
-@@ -1,6 +1,6 @@
- /*
-  * ProFTPD - FTP server testsuite
-- * Copyright (c) 2008-2011 The ProFTPD Project team
-+ * Copyright (c) 2008-2020 The ProFTPD Project team
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -97,20 +97,20 @@ START_TEST (set_create_test) {
-   fail_unless(errno == EPERM, "Failed to set errno to EPERM");
- 
-   res = xaset_create(p, NULL);
--  fail_unless(res != NULL);
-+  fail_unless(res != NULL, "Expected non-null result");
-   fail_unless(res->pool == p, "Expected %p, got %p", p, res->pool);
- 
-   permanent_pool = make_sub_pool(p);
- 
-   res = xaset_create(NULL, NULL);
--  fail_unless(res != NULL);
-+  fail_unless(res != NULL, "Expected non-null result");
-   fail_unless(res->pool == permanent_pool, "Expected %p, got %p",
-     permanent_pool, res->pool);
-   fail_unless(res->xas_compare == NULL, "Expected NULL, got %p",
-     res->xas_compare);
- 
-   res = xaset_create(p, (XASET_COMPARE) item_cmp);
--  fail_unless(res != NULL);
-+  fail_unless(res != NULL, "Expected non-null result");
-   fail_unless(res->pool == p, "Expected %p, got %p", p, res->pool);
-   fail_unless(res->xas_compare == (XASET_COMPARE) item_cmp,
-     "Expected %p, got %p", item_cmp, res->xas_compare);
-@@ -355,12 +355,12 @@ START_TEST (set_remove_test) {
-   fail_unless(res == 0, "Failed to add item2");
- 
-   member = (xasetmember_t *) item1;
--  fail_unless(member->next == NULL);
--  fail_unless(member->prev != NULL);
-+  fail_unless(member->next == NULL, "Expected member->next to be null");
-+  fail_unless(member->prev != NULL, "Expected member->prev to not be null");
- 
-   member = (xasetmember_t *) item2;
--  fail_unless(member->next != NULL);
--  fail_unless(member->prev == NULL);
-+  fail_unless(member->next != NULL, "Expected member->next to not be null");
-+  fail_unless(member->prev == NULL, "Expected member->prev to be null");
- 
-   member = set->xas_list;
-   fail_unless(member == (xasetmember_t *) item2,
-@@ -371,8 +371,8 @@ START_TEST (set_remove_test) {
-     strerror(errno));
- 
-   member = (xasetmember_t *) item2;
--  fail_unless(member->next == NULL);
--  fail_unless(member->prev == NULL);
-+  fail_unless(member->next == NULL, "Expected member->next to be null");
-+  fail_unless(member->prev == NULL, "Expected member->prev to be null");
- 
-   member = set->xas_list;
-   fail_unless(member == (xasetmember_t *) item1,
-@@ -383,8 +383,8 @@ START_TEST (set_remove_test) {
-     strerror(errno));
- 
-   member = (xasetmember_t *) item1;
--  fail_unless(member->next == NULL);
--  fail_unless(member->prev == NULL);
-+  fail_unless(member->next == NULL, "Expected member->next to be null");
-+  fail_unless(member->prev == NULL, "Expected member->prev to be null");
- 
-   member = set->xas_list;
-   fail_unless(member == NULL, "Expected list to be empty, got %p", member);
-diff --git a/tests/api/str.c b/tests/api/str.c
-index 9dce95820..050f5c563 100644
---- a/tests/api/str.c
-+++ b/tests/api/str.c
-@@ -1539,10 +1539,10 @@ START_TEST (uid2str_test) {
-   const char *res;
- 
-   res = pr_uid2str(NULL, (uid_t) 1);
--  fail_unless(strcmp(res, "1") == 0);
-+  fail_unless(strcmp(res, "1") == 0, "Expected '1', got '%s'", res);
- 
-   res = pr_uid2str(NULL, (uid_t) -1);
--  fail_unless(strcmp(res, "-1") == 0);
-+  fail_unless(strcmp(res, "-1") == 0, "Expected '-1', got '%s'", res);
- }
- END_TEST
- 
-@@ -1550,10 +1550,10 @@ START_TEST (gid2str_test) {
-   const char *res;
- 
-   res = pr_gid2str(NULL, (gid_t) 1);
--  fail_unless(strcmp(res, "1") == 0);
-+  fail_unless(strcmp(res, "1") == 0, "Expected '1', got '%s'", res);
- 
-   res = pr_gid2str(NULL, (gid_t) -1);
--  fail_unless(strcmp(res, "-1") == 0);
-+  fail_unless(strcmp(res, "-1") == 0, "Expected '-1', got '%s'", res);
- }
- END_TEST
- 
-diff --git a/tests/api/timers.c b/tests/api/timers.c
-index 99b6348e9..0616a7989 100644
---- a/tests/api/timers.c
-+++ b/tests/api/timers.c
-@@ -157,7 +157,7 @@ START_TEST (timer_remove_test) {
-   int res;
- 
-   res = pr_timer_remove(0, NULL);
--  fail_unless(res == 0);
-+  fail_unless(res == 0, "Failed to remove timer: %s", strerror(errno));
- 
-   res = pr_timer_add(1, 0, NULL, timers_test_cb, "test");
-   fail_unless(res == 0, "Failed to add timer (%d): %s", res, strerror(errno));


=====================================
debian/patches/upstream_1284 deleted
=====================================
@@ -1,43 +0,0 @@
-From 10a227b4d50e0a2cd2faf87926f58d865da44e43 Mon Sep 17 00:00:00 2001
-From: Chris Hofstaedtler <chris.hofstaedtler at deduktiva.com>
-Date: Tue, 3 Aug 2021 21:53:28 +0200
-Subject: [PATCH] mod_radius: copy _only_ the password
-
----
- contrib/mod_radius.c | 11 ++++++++---
- 1 file changed, 8 insertions(+), 3 deletions(-)
-
-Index: proftpd/contrib/mod_radius.c
-===================================================================
---- proftpd.orig/contrib/mod_radius.c	2021-08-28 16:10:46.810595478 +0200
-+++ proftpd/contrib/mod_radius.c	2021-08-28 16:10:46.782595919 +0200
-@@ -2319,21 +2319,26 @@
- 
-   pwlen = strlen((const char *) passwd);
- 
-+  /* Clear the buffers. */
-+  memset(pwhash, '\0', sizeof(pwhash));
-+
-   if (pwlen == 0) {
-     pwlen = RADIUS_PASSWD_LEN;
- 
-   } if ((pwlen & (RADIUS_PASSWD_LEN - 1)) != 0) {
-+    /* pwlen is not a multiple of RADIUS_PASSWD_LEN, need to prepare a proper buffer */
-+    memcpy(pwhash, passwd, pwlen);
- 
-     /* Round up the length. */
-     pwlen += (RADIUS_PASSWD_LEN - 1);
- 
-     /* Truncate the length, as necessary. */
-     pwlen &= ~(RADIUS_PASSWD_LEN - 1);
-+  } else {
-+    /* pwlen is a multiple of RADIUS_PASSWD_LEN, we can just use it. */
-+    memcpy(pwhash, passwd, pwlen);
-   }
- 
--  /* Clear the buffers. */
--  memset(pwhash, '\0', sizeof(pwhash));
--  memcpy(pwhash, passwd, pwlen);
- 
-   /* Find the password attribute. */
-   attrib = radius_get_attrib(packet, RADIUS_PASSWORD);


=====================================
debian/patches/upstream_1322 deleted
=====================================
@@ -1,154 +0,0 @@
-From e428a379fc97db8400a497045a57a69468666901 Mon Sep 17 00:00:00 2001
-From: TJ Saunders <tj at castaglia.org>
-Date: Sat, 4 Sep 2021 10:19:01 -0700
-Subject: [PATCH] Issue #1321: When processing very long lines from an
- `AuthGroupFile`, allocate larger buffers in smaller increments, as
- `fgetgrent(3)` does.
-
----
- modules/mod_auth_file.c                       | 11 ++-
- tests/t/lib/ProFTPD/TestSuite/Utils.pm        |  4 +-
- .../ProFTPD/Tests/Modules/mod_auth_file.pm    | 80 +++++++++++++++++++
- 3 files changed, 92 insertions(+), 3 deletions(-)
-
---- proftpd.orig/modules/mod_auth_file.c
-+++ proftpd/modules/mod_auth_file.c
-@@ -332,6 +332,9 @@
- static char *af_getgrentline(char **buf, int *buflen, pr_fh_t *fh,
-     unsigned int *lineno) {
-   char *cp = *buf;
-+  int original_buflen;
-+
-+  original_buflen = *buflen;
- 
-   while (pr_fsio_gets(cp, (*buflen) - (cp - *buf), fh) != NULL) {
-     pr_signals_handle();
-@@ -343,8 +346,12 @@
-       return *buf;
-     }
- 
--    /* No -- allocate a larger buffer, doubling buflen. */
--    *buflen += *buflen;
-+    /* No -- allocate a larger buffer.  Note that doubling the buflen
-+     * each time may cause issues; fgetgrent(3) would increment the
-+     * allocated buffer by the original buffer length each time.  So we
-+     * do the same (Issue #1321).
-+     */
-+    *buflen += original_buflen;
- 
-     {
-       char *new_buf;
---- proftpd.orig/tests/t/lib/ProFTPD/TestSuite/Utils.pm
-+++ proftpd/tests/t/lib/ProFTPD/TestSuite/Utils.pm
-@@ -1210,6 +1210,8 @@
-   my $gid = shift;
-   $gid = 500 unless defined($gid);
-   my $home_dir = shift;
-+  my $groups = shift;
-+  $groups = $user unless defined($groups);
- 
-   my $config_file = "$tmpdir/$name.conf";
-   my $pid_file = File::Spec->rel2abs("$tmpdir/$name.pid");
-@@ -1238,7 +1240,7 @@
- 
-   auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
-     '/bin/bash');
--  auth_group_write($auth_group_file, $group, $gid, $user);
-+  auth_group_write($auth_group_file, $group, $gid, $groups);
- 
-   my $setup = {
-     auth_user_file => $auth_user_file,
---- proftpd.orig/tests/t/lib/ProFTPD/Tests/Modules/mod_auth_file.pm
-+++ proftpd/tests/t/lib/ProFTPD/Tests/Modules/mod_auth_file.pm
-@@ -122,6 +122,10 @@
-     test_class => [qw(bug forking)],
-   },
- 
-+  auth_file_line_too_long_issue1321 => {
-+    order => ++$order,
-+    test_class => [qw(bug forking)],
-+  },
- };
- 
- sub new {
-@@ -2271,4 +2275,80 @@
-   unlink($log_file);
- }
- 
-+sub auth_file_line_too_long_issue1321 {
-+  my $self = shift;
-+  my $tmpdir = $self->{tmpdir};
-+
-+  # For Issue #1321, we create a very long AuthGroupFile entry with many
-+  # group names.
-+
-+  my $groups = 'proftpd';
-+  for (my $i = 0; $i < 200; $i++) {
-+    $groups .= ",quite.long.example.group.$i";
-+  }
-+
-+  my $setup = test_setup($tmpdir, 'authfile', undef, undef, undef, undef, undef,
-+    undef, $groups);
-+
-+  my $config = {
-+    PidFile => $setup->{pid_file},
-+    ScoreboardFile => $setup->{scoreboard_file},
-+    SystemLog => $setup->{log_file},
-+
-+    AuthUserFile => $setup->{auth_user_file},
-+    AuthGroupFile => $setup->{auth_group_file},
-+
-+    IfModules => {
-+      'mod_delay.c' => {
-+        DelayEngine => 'off',
-+      },
-+    },
-+  };
-+
-+  my ($port, $config_user, $config_group) = config_write($setup->{config_file},
-+    $config);
-+
-+  # Open pipes, for use between the parent and child processes.  Specifically,
-+  # the child will indicate when it's done with its test by writing a message
-+  # to the parent.
-+  my ($rfh, $wfh);
-+  unless (pipe($rfh, $wfh)) {
-+    die("Can't open pipe: $!");
-+  }
-+
-+  my $ex;
-+
-+  # Fork child
-+  $self->handle_sigchld();
-+  defined(my $pid = fork()) or die("Can't fork: $!");
-+  if ($pid) {
-+    eval {
-+      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
-+      $client->login($setup->{user}, $setup->{passwd});
-+      $client->quit();
-+    };
-+    if ($@) {
-+      $ex = $@;
-+    }
-+
-+    $wfh->print("done\n");
-+    $wfh->flush();
-+
-+  } else {
-+    eval { server_wait($setup->{config_file}, $rfh) };
-+    if ($@) {
-+      warn($@);
-+      exit 1;
-+    }
-+
-+    exit 0;
-+  }
-+
-+  # Stop server
-+  server_stop($setup->{pid_file});
-+  $self->assert_child_ok($pid);
-+
-+  test_cleanup($setup->{log_file}, $ex);
-+}
-+
- 1;


=====================================
debian/patches/upstream_1325 deleted
=====================================
@@ -1,569 +0,0 @@
-From 6e3d8debc14f1b532fae27994120f591b39fb183 Mon Sep 17 00:00:00 2001
-From: TJ Saunders <tj at castaglia.org>
-Date: Sat, 11 Sep 2021 14:22:31 -0700
-Subject: [PATCH] Backport fix for Issue #1325 to the 1.3.7 branch.
-
----
- NEWS                                       |   1 +
- modules/mod_ls.c                           |   6 +-
- tests/t/lib/ProFTPD/Tests/Commands/NLST.pm | 453 +++++++++++++++++++--
- 3 files changed, 412 insertions(+), 48 deletions(-)
-
-diff --git a/modules/mod_ls.c b/modules/mod_ls.c
-index 45a3187bd9..c7a44c450a 100644
---- a/modules/mod_ls.c
-+++ b/modules/mod_ls.c
-@@ -2,7 +2,7 @@
-  * ProFTPD - FTP server daemon
-  * Copyright (c) 1997, 1998 Public Flood Software
-  * Copyright (c) 1999, 2000 MacGyver aka Habeeb J. Dihu <macgyver at tos.net>
-- * Copyright (c) 2001-2020 The ProFTPD Project
-+ * Copyright (c) 2001-2021 The ProFTPD Project
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -3163,10 +3163,6 @@ MODRET ls_nlst(cmd_rec *cmd) {
-       p = *path;
-       path++;
- 
--      if (*p == '.' && (!opt_A || is_dotdir(p))) {
--        continue;
--      }
--
-       pr_fs_clear_cache2(p);
-       if (pr_fsio_stat(p, &st) == 0) {
-         /* If it's a directory... */
-diff --git a/tests/t/lib/ProFTPD/Tests/Commands/NLST.pm b/tests/t/lib/ProFTPD/Tests/Commands/NLST.pm
-index 7fa5c84177..eac38ea24d 100644
---- a/tests/t/lib/ProFTPD/Tests/Commands/NLST.pm
-+++ b/tests/t/lib/ProFTPD/Tests/Commands/NLST.pm
-@@ -157,6 +157,16 @@ my $TESTS = {
-     test_class => [qw(forking rootprivs)],
-   },
- 
-+  nlst_glob_with_rel_path_issue1325 => {
-+    order => ++$order,
-+    test_class => [qw(bug forking)],
-+  },
-+
-+  nlst_glob_with_rel_path_dotdir_issue1325 => {
-+    order => ++$order,
-+    test_class => [qw(bug forking)],
-+  },
-+
- };
- 
- sub new {
-@@ -3616,22 +3626,7 @@ sub nlst_rel_path_chrooted_bug2496 {
- sub nlst_parent_dir_bug4011 {
-   my $self = shift;
-   my $tmpdir = $self->{tmpdir};
--
--  my $config_file = "$tmpdir/cmds.conf";
--  my $pid_file = File::Spec->rel2abs("$tmpdir/cmds.pid");
--  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/cmds.scoreboard");
--
--  my $log_file = test_get_logfile();
--
--  my $auth_user_file = File::Spec->rel2abs("$tmpdir/cmds.passwd");
--  my $auth_group_file = File::Spec->rel2abs("$tmpdir/cmds.group");
--
--  my $user = 'proftpd';
--  my $passwd = 'test';
--  my $group = 'ftpd';
--  my $home_dir = File::Spec->rel2abs($tmpdir);
--  my $uid = 500;
--  my $gid = 500;
-+  my $setup = test_setup($tmpdir, 'cmds');
- 
-   my $sub_dir1 = File::Spec->rel2abs("$tmpdir/dir1");
-   my $sub_dir2 = File::Spec->rel2abs("$tmpdir/dir1/dir2");
-@@ -3662,26 +3657,22 @@ sub nlst_parent_dir_bug4011 {
-   # Make sure that, if we're running as root, that the home directory has
-   # permissions/privs set for the account we create
-   if ($< == 0) {
--    unless (chmod(0755, $home_dir, $sub_dir1)) {
--      die("Can't set perms on $home_dir to 0755: $!");
-+    unless (chmod(0755, $sub_dir1)) {
-+      die("Can't set perms on $sub_dir1 to 0755: $!");
-     }
- 
--    unless (chown($uid, $gid, $home_dir, $sub_dir1)) {
--      die("Can't set owner of $home_dir to $uid/$gid: $!");
-+    unless (chown($setup->{uid}, $setup->{gid}, $sub_dir1)) {
-+      die("Can't set owner of $sub_dir1 to $setup->{uid}/$setup->{gid}: $!");
-     }
-   }
- 
--  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
--    '/bin/bash');
--  auth_group_write($auth_group_file, $group, $gid, $user);
--
-   my $config = {
--    PidFile => $pid_file,
--    ScoreboardFile => $scoreboard_file,
--    SystemLog => $log_file,
-+    PidFile => $setup->{pid_file},
-+    ScoreboardFile => $setup->{scoreboard_file},
-+    SystemLog => $setup->{log_file},
- 
--    AuthUserFile => $auth_user_file,
--    AuthGroupFile => $auth_group_file,
-+    AuthUserFile => $setup->{auth_user_file},
-+    AuthGroupFile => $setup->{auth_group_file},
- 
-     IfModules => {
-       'mod_delay.c' => {
-@@ -3690,7 +3681,8 @@ sub nlst_parent_dir_bug4011 {
-     },
-   };
- 
--  my ($port, $config_user, $config_group) = config_write($config_file, $config);
-+  my ($port, $config_user, $config_group) = config_write($setup->{config_file},
-+    $config);
- 
-   # Open pipes, for use between the parent and child processes.  Specifically,
-   # the child will indicate when it's done with its test by writing a message
-@@ -3708,7 +3700,7 @@ sub nlst_parent_dir_bug4011 {
-   if ($pid) {
-     eval {
-       my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
--      $client->login($user, $passwd);
-+      $client->login($setup->{user}, $setup->{passwd});
-       $client->cwd("dir1");
-       $client->cwd("dir2");
- 
-@@ -3722,6 +3714,12 @@ sub nlst_parent_dir_bug4011 {
-       $conn->read($buf, 8192, 25);
-       eval { $conn->close() };
- 
-+      $client->quit();
-+
-+      if ($ENV{TEST_VERBOSE}) {
-+        print STDERR "# response:\n$buf\n";
-+      }
-+
-       # We have to be careful of the fact that readdir returns directory
-       # entries in an unordered fashion.
-       my $res = {};
-@@ -3749,7 +3747,6 @@ sub nlst_parent_dir_bug4011 {
-         die("Unexpected name '$mismatch' appeared in NLST data")
-       }
-     };
--
-     if ($@) {
-       $ex = $@;
-     }
-@@ -3758,7 +3755,7 @@ sub nlst_parent_dir_bug4011 {
-     $wfh->flush();
- 
-   } else {
--    eval { server_wait($config_file, $rfh) };
-+    eval { server_wait($setup->{config_file}, $rfh) };
-     if ($@) {
-       warn($@);
-       exit 1;
-@@ -3768,18 +3765,10 @@ sub nlst_parent_dir_bug4011 {
-   }
- 
-   # Stop server
--  server_stop($pid_file);
--
-+  server_stop($setup->{pid_file});
-   $self->assert_child_ok($pid);
- 
--  if ($ex) {
--    test_append_logfile($log_file, $ex);
--    unlink($log_file);
--
--    die($ex);
--  }
--
--  unlink($log_file);
-+  test_cleanup($setup->{log_file}, $ex);
- }
- 
- sub nlst_opt_a_root_dir_bug4069 {
-@@ -4080,4 +4069,382 @@ sub nlst_opt_1_with_chroot {
-   unlink($log_file);
- }
- 
-+sub nlst_glob_with_rel_path_issue1325 {
-+  my $self = shift;
-+  my $tmpdir = $self->{tmpdir};
-+  my $setup = test_setup($tmpdir, 'cmds');
-+
-+  my $test_path = File::Spec->rel2abs("$tmpdir/test.d");
-+  mkpath($test_path);
-+
-+  for (my $i = 0; $i < 10; $i++) {
-+    my $test_file = File::Spec->rel2abs("$test_path/TEST000$i.dat");
-+    if (open(my $fh, "> $test_file")) {
-+      print $fh "Hello, World!\n";
-+      unless (close($fh)) {
-+        die("Can't write $test_file: $!");
-+      }
-+
-+    } else {
-+      die("Can't open $test_file: $!");
-+    }
-+  }
-+
-+  my $config = {
-+    PidFile => $setup->{pid_file},
-+    ScoreboardFile => $setup->{scoreboard_file},
-+    SystemLog => $setup->{log_file},
-+
-+    AuthUserFile => $setup->{auth_user_file},
-+    AuthGroupFile => $setup->{auth_group_file},
-+
-+    IfModules => {
-+      'mod_delay.c' => {
-+        DelayEngine => 'off',
-+      },
-+    },
-+  };
-+
-+  my ($port, $config_user, $config_group) = config_write($setup->{config_file},
-+    $config);
-+
-+  # Open pipes, for use between the parent and child processes.  Specifically,
-+  # the child will indicate when it's done with its test by writing a message
-+  # to the parent.
-+  my ($rfh, $wfh);
-+  unless (pipe($rfh, $wfh)) {
-+    die("Can't open pipe: $!");
-+  }
-+
-+  my $ex;
-+
-+  # Fork child
-+  $self->handle_sigchld();
-+  defined(my $pid = fork()) or die("Can't fork: $!");
-+  if ($pid) {
-+    eval {
-+      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
-+      $client->login($setup->{user}, $setup->{passwd});
-+
-+      my $conn = $client->nlst_raw('test.d/TEST????.dat');
-+      unless ($conn) {
-+        die("Failed to NLST: " . $client->response_code() . " " .
-+          $client->response_msg());
-+      }
-+
-+      my $buf;
-+      $conn->read($buf, 8192, 25);
-+      eval { $conn->close() };
-+
-+      if ($ENV{TEST_VERBOSE}) {
-+        print STDERR "# response:\n$buf\n";
-+      }
-+
-+      # We have to be careful of the fact that readdir returns directory
-+      # entries in an unordered fashion.
-+      my $res = {};
-+      my $names = [split(/\n/, $buf)];
-+      foreach my $name (@$names) {
-+        $res->{$name} = 1;
-+      }
-+
-+      $self->assert(scalar(@$names) > 0,
-+        test_msg("Expected multiple names, got 0"));
-+
-+      my $expected = {
-+        'test.d/TEST0000.dat' => 1,
-+        'test.d/TEST0001.dat' => 1,
-+        'test.d/TEST0002.dat' => 1,
-+        'test.d/TEST0003.dat' => 1,
-+        'test.d/TEST0004.dat' => 1,
-+        'test.d/TEST0005.dat' => 1,
-+        'test.d/TEST0006.dat' => 1,
-+        'test.d/TEST0007.dat' => 1,
-+        'test.d/TEST0008.dat' => 1,
-+        'test.d/TEST0009.dat' => 1,
-+      };
-+
-+      my $ok = 1;
-+      my $mismatch;
-+      foreach my $name (keys(%$res)) {
-+        unless (defined($expected->{$name})) {
-+          $mismatch = $name;
-+          $ok = 0;
-+          last;
-+        }
-+      }
-+
-+      unless ($ok) {
-+        die("Unexpected name '$mismatch' appeared in NLST data")
-+      }
-+
-+      # Now do it again, this time using an explicit relative path.
-+
-+      $conn = $client->nlst_raw('./test.d/TEST????.dat');
-+      unless ($conn) {
-+        die("Failed to NLST: " . $client->response_code() . " " .
-+          $client->response_msg());
-+      }
-+
-+      $buf = '';
-+      $conn->read($buf, 8192, 25);
-+      eval { $conn->close() };
-+
-+      if ($ENV{TEST_VERBOSE}) {
-+        print STDERR "# response:\n$buf\n";
-+      }
-+
-+      # We have to be careful of the fact that readdir returns directory
-+      # entries in an unordered fashion.
-+      $res = {};
-+      $names = [split(/\n/, $buf)];
-+      foreach my $name (@$names) {
-+        $res->{$name} = 1;
-+      }
-+
-+      $self->assert(scalar(@$names) > 0,
-+        test_msg("Expected multiple names, got 0"));
-+
-+      $expected = {
-+        './test.d/TEST0000.dat' => 1,
-+        './test.d/TEST0001.dat' => 1,
-+        './test.d/TEST0002.dat' => 1,
-+        './test.d/TEST0003.dat' => 1,
-+        './test.d/TEST0004.dat' => 1,
-+        './test.d/TEST0005.dat' => 1,
-+        './test.d/TEST0006.dat' => 1,
-+        './test.d/TEST0007.dat' => 1,
-+        './test.d/TEST0008.dat' => 1,
-+        './test.d/TEST0009.dat' => 1,
-+      };
-+
-+      $ok = 1;
-+      $mismatch = '';
-+      foreach my $name (keys(%$res)) {
-+        unless (defined($expected->{$name})) {
-+          $mismatch = $name;
-+          $ok = 0;
-+          last;
-+        }
-+      }
-+
-+      unless ($ok) {
-+        die("Unexpected name '$mismatch' appeared in NLST data")
-+      }
-+
-+      $client->quit();
-+    };
-+    if ($@) {
-+      $ex = $@;
-+    }
-+
-+    $wfh->print("done\n");
-+    $wfh->flush();
-+
-+  } else {
-+    eval { server_wait($setup->{config_file}, $rfh) };
-+    if ($@) {
-+      warn($@);
-+      exit 1;
-+    }
-+
-+    exit 0;
-+  }
-+
-+  # Stop server
-+  server_stop($setup->{pid_file});
-+  $self->assert_child_ok($pid);
-+
-+  test_cleanup($setup->{log_file}, $ex);
-+}
-+
-+sub nlst_glob_with_rel_path_dotdir_issue1325 {
-+  my $self = shift;
-+  my $tmpdir = $self->{tmpdir};
-+  my $setup = test_setup($tmpdir, 'cmds');
-+
-+  my $test_path = File::Spec->rel2abs("$tmpdir/.test.d");
-+  mkpath($test_path);
-+
-+  for (my $i = 0; $i < 10; $i++) {
-+    my $test_file = File::Spec->rel2abs("$test_path/TEST000$i.dat");
-+    if (open(my $fh, "> $test_file")) {
-+      print $fh "Hello, World!\n";
-+      unless (close($fh)) {
-+        die("Can't write $test_file: $!");
-+      }
-+
-+    } else {
-+      die("Can't open $test_file: $!");
-+    }
-+  }
-+
-+  my $config = {
-+    PidFile => $setup->{pid_file},
-+    ScoreboardFile => $setup->{scoreboard_file},
-+    SystemLog => $setup->{log_file},
-+
-+    AuthUserFile => $setup->{auth_user_file},
-+    AuthGroupFile => $setup->{auth_group_file},
-+
-+    IfModules => {
-+      'mod_delay.c' => {
-+        DelayEngine => 'off',
-+      },
-+    },
-+  };
-+
-+  my ($port, $config_user, $config_group) = config_write($setup->{config_file},
-+    $config);
-+
-+  # Open pipes, for use between the parent and child processes.  Specifically,
-+  # the child will indicate when it's done with its test by writing a message
-+  # to the parent.
-+  my ($rfh, $wfh);
-+  unless (pipe($rfh, $wfh)) {
-+    die("Can't open pipe: $!");
-+  }
-+
-+  my $ex;
-+
-+  # Fork child
-+  $self->handle_sigchld();
-+  defined(my $pid = fork()) or die("Can't fork: $!");
-+  if ($pid) {
-+    eval {
-+      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
-+      $client->login($setup->{user}, $setup->{passwd});
-+
-+      my $conn = $client->nlst_raw('.test.d/TEST????.dat');
-+      unless ($conn) {
-+        die("Failed to NLST: " . $client->response_code() . " " .
-+          $client->response_msg());
-+      }
-+
-+      my $buf;
-+      $conn->read($buf, 8192, 25);
-+      eval { $conn->close() };
-+
-+      if ($ENV{TEST_VERBOSE}) {
-+        print STDERR "# response:\n$buf\n";
-+      }
-+
-+      # We have to be careful of the fact that readdir returns directory
-+      # entries in an unordered fashion.
-+      my $res = {};
-+      my $names = [split(/\n/, $buf)];
-+      foreach my $name (@$names) {
-+        $res->{$name} = 1;
-+      }
-+
-+      $self->assert(scalar(@$names) > 0,
-+        test_msg("Expected multiple names, got 0"));
-+
-+      my $expected = {
-+        '.test.d/TEST0000.dat' => 1,
-+        '.test.d/TEST0001.dat' => 1,
-+        '.test.d/TEST0002.dat' => 1,
-+        '.test.d/TEST0003.dat' => 1,
-+        '.test.d/TEST0004.dat' => 1,
-+        '.test.d/TEST0005.dat' => 1,
-+        '.test.d/TEST0006.dat' => 1,
-+        '.test.d/TEST0007.dat' => 1,
-+        '.test.d/TEST0008.dat' => 1,
-+        '.test.d/TEST0009.dat' => 1,
-+      };
-+
-+      my $ok = 1;
-+      my $mismatch;
-+      foreach my $name (keys(%$res)) {
-+        unless (defined($expected->{$name})) {
-+          $mismatch = $name;
-+          $ok = 0;
-+          last;
-+        }
-+      }
-+
-+      unless ($ok) {
-+        die("Unexpected name '$mismatch' appeared in NLST data")
-+      }
-+
-+      # Now do it again, this time using an explicit relative path.
-+
-+      $conn = $client->nlst_raw('./.test.d/TEST????.dat');
-+      unless ($conn) {
-+        die("Failed to NLST: " . $client->response_code() . " " .
-+          $client->response_msg());
-+      }
-+
-+      $buf = '';
-+      $conn->read($buf, 8192, 25);
-+      eval { $conn->close() };
-+
-+      if ($ENV{TEST_VERBOSE}) {
-+        print STDERR "# response:\n$buf\n";
-+      }
-+
-+      # We have to be careful of the fact that readdir returns directory
-+      # entries in an unordered fashion.
-+      $res = {};
-+      $names = [split(/\n/, $buf)];
-+      foreach my $name (@$names) {
-+        $res->{$name} = 1;
-+      }
-+
-+      $self->assert(scalar(@$names) > 0,
-+        test_msg("Expected multiple names, got 0"));
-+
-+      $expected = {
-+        './.test.d/TEST0000.dat' => 1,
-+        './.test.d/TEST0001.dat' => 1,
-+        './.test.d/TEST0002.dat' => 1,
-+        './.test.d/TEST0003.dat' => 1,
-+        './.test.d/TEST0004.dat' => 1,
-+        './.test.d/TEST0005.dat' => 1,
-+        './.test.d/TEST0006.dat' => 1,
-+        './.test.d/TEST0007.dat' => 1,
-+        './.test.d/TEST0008.dat' => 1,
-+        './.test.d/TEST0009.dat' => 1,
-+      };
-+
-+      $ok = 1;
-+      $mismatch = '';
-+      foreach my $name (keys(%$res)) {
-+        unless (defined($expected->{$name})) {
-+          $mismatch = $name;
-+          $ok = 0;
-+          last;
-+        }
-+      }
-+
-+      unless ($ok) {
-+        die("Unexpected name '$mismatch' appeared in NLST data")
-+      }
-+
-+      $client->quit();
-+    };
-+    if ($@) {
-+      $ex = $@;
-+    }
-+
-+    $wfh->print("done\n");
-+    $wfh->flush();
-+
-+  } else {
-+    eval { server_wait($setup->{config_file}, $rfh) };
-+    if ($@) {
-+      warn($@);
-+      exit 1;
-+    }
-+
-+    exit 0;
-+  }
-+
-+  # Stop server
-+  server_stop($setup->{pid_file});
-+  $self->assert_child_ok($pid);
-+
-+  test_cleanup($setup->{log_file}, $ex);
-+}
-+
- 1;


=====================================
debian/patches/upstream_1346 deleted
=====================================
@@ -1,441 +0,0 @@
-From bb8116d21f7849bf36cc356de4d8cfec579eba64 Mon Sep 17 00:00:00 2001
-From: TJ Saunders <tj at castaglia.org>
-Date: Tue, 26 Oct 2021 19:10:59 -0700
-Subject: [PATCH] Issue #1346: When accept connections for passive data
- transfers, and a class name has been configured for `AllowForeignAddress`,
- check the connecting client against that class.
-
----
- src/inet.c                                    |  90 +++++--
- .../Tests/Config/AllowForeignAddress.pm       | 255 +++++++++++++++++-
- 2 files changed, 314 insertions(+), 31 deletions(-)
-
-diff --git a/src/inet.c b/src/inet.c
-index 33ce349aa3..81c1c99b1d 100644
---- a/src/inet.c
-+++ b/src/inet.c
-@@ -1522,9 +1522,9 @@ int pr_inet_accept_nowait(pool *p, conn_t *c) {
-  */
- conn_t *pr_inet_accept(pool *p, conn_t *d, conn_t *c, int rfd, int wfd,
-     unsigned char resolve) {
-+  config_rec *allow_foreign_addr_config = NULL;
-   conn_t *res = NULL;
--  unsigned char *foreign_addr = NULL;
--  int fd = -1, allow_foreign_address = FALSE;
-+  int fd = -1;
-   pr_netaddr_t na;
-   socklen_t nalen;
- 
-@@ -1540,13 +1540,10 @@ conn_t *pr_inet_accept(pool *p, conn_t *d, conn_t *c, int rfd, int wfd,
-   pr_netaddr_set_family(&na, pr_netaddr_get_family(c->remote_addr));
-   nalen = pr_netaddr_get_sockaddr_len(&na);
- 
-+  allow_foreign_addr_config = find_config(TOPLEVEL_CONF, CONF_PARAM,
-+    "AllowForeignAddress", FALSE);
-   d->mode = CM_ACCEPT;
- 
--  foreign_addr = get_param_ptr(TOPLEVEL_CONF, "AllowForeignAddress", FALSE);
--  if (foreign_addr != NULL) {
--    allow_foreign_address = *foreign_addr;
--  }
--
-   /* A directive could enforce only IPv4 or IPv6 connections here, by
-    * actually using a sockaddr argument to accept(2), and checking the
-    * family of the connecting entity.
-@@ -1566,28 +1563,67 @@ conn_t *pr_inet_accept(pool *p, conn_t *d, conn_t *c, int rfd, int wfd,
-       break;
-     }
- 
--    if (allow_foreign_address == FALSE) {
--      /* If foreign addresses (i.e. IP addresses that do not match the
--       * control connection's remote IP address) are not allowed, we
--       * need to see just what our remote address IS.
--       */
--      if (getpeername(fd, pr_netaddr_get_sockaddr(&na), &nalen) < 0) {
--        /* If getpeername(2) fails, should we still allow this connection?
--         * Caution (and the AllowForeignAddress setting say "no".
-+    if (allow_foreign_addr_config != NULL) {
-+      int allowed;
-+
-+      allowed = *((int *) allow_foreign_addr_config->argv[0]);
-+      if (allowed != TRUE) {
-+        /* If foreign addresses (i.e. IP addresses that do not match the
-+         * control connection's remote IP address) are not allowed, we
-+         * need to see just what our remote address IS.
-          */
--        pr_log_pri(PR_LOG_DEBUG, "rejecting passive connection; "
--          "failed to get address of remote peer: %s", strerror(errno));
--        (void) close(fd);
--        continue;
--      }
- 
--      if (pr_netaddr_cmp(&na, c->remote_addr) != 0) {
--        pr_log_pri(PR_LOG_NOTICE, "SECURITY VIOLATION: Passive connection "
--          "from foreign IP address %s rejected (does not match client "
--          "IP address %s).", pr_netaddr_get_ipstr(&na),
--          pr_netaddr_get_ipstr(c->remote_addr));
--        (void) close(fd);
--        continue;
-+        if (getpeername(fd, pr_netaddr_get_sockaddr(&na), &nalen) < 0) {
-+          /* If getpeername(2) fails, should we still allow this connection?
-+           * Caution (and the AllowForeignAddress setting) say "no".
-+           */
-+          pr_log_pri(PR_LOG_DEBUG, "rejecting passive connection; "
-+            "failed to get address of remote peer: %s", strerror(errno));
-+          (void) close(fd);
-+          continue;
-+        }
-+
-+        if (allowed == FALSE) {
-+          if (pr_netaddr_cmp(&na, c->remote_addr) != 0) {
-+            pr_log_pri(PR_LOG_NOTICE, "SECURITY VIOLATION: Passive connection "
-+              "from foreign IP address %s rejected (does not match client "
-+              "IP address %s).", pr_netaddr_get_ipstr(&na),
-+              pr_netaddr_get_ipstr(c->remote_addr));
-+
-+            (void) close(fd);
-+            d->mode = CM_ERROR;
-+            d->xerrno = EACCES;
-+
-+            return NULL;
-+          }
-+
-+        } else {
-+          char *class_name;
-+          const pr_class_t *cls;
-+
-+          class_name = allow_foreign_addr_config->argv[1];
-+          cls = pr_class_find(class_name);
-+          if (cls != NULL) {
-+            if (pr_class_satisfied(p, cls, &na) != TRUE) {
-+              pr_log_debug(DEBUG8, "<Class> '%s' not satisfied by foreign "
-+                "address '%s'", class_name, pr_netaddr_get_ipstr(&na));
-+
-+              pr_log_pri(PR_LOG_NOTICE,
-+                "SECURITY VIOLATION: Passive connection from foreign IP "
-+                "address %s rejected (does not match <Class %s>).",
-+                pr_netaddr_get_ipstr(&na), class_name);
-+
-+              (void) close(fd);
-+              d->mode = CM_ERROR;
-+              d->xerrno = EACCES;
-+              return NULL;
-+            }
-+
-+          } else {
-+            pr_log_debug(DEBUG8, "<Class> '%s' not found for filtering "
-+              "AllowForeignAddress", class_name);
-+          }
-+        }
-       }
-     }
- 
-diff --git a/tests/t/lib/ProFTPD/Tests/Config/AllowForeignAddress.pm b/tests/t/lib/ProFTPD/Tests/Config/AllowForeignAddress.pm
-index cd64b5578d..0ee36cbb4e 100644
---- a/tests/t/lib/ProFTPD/Tests/Config/AllowForeignAddress.pm
-+++ b/tests/t/lib/ProFTPD/Tests/Config/AllowForeignAddress.pm
-@@ -26,11 +26,16 @@ my $TESTS = {
-     test_class => [qw(forking)],
-   },
- 
--  fxp_denied_by_class => {
-+  fxp_port_denied_by_class => {
-     order => ++$order,
-     test_class => [qw(forking)],
-   },
- 
-+  fxp_pasv_denied_by_class_issue1346 => {
-+    order => ++$order,
-+    test_class => [qw(bug forking)],
-+  },
-+
-   fxp_allowed => {
-     order => ++$order,
-     test_class => [qw(forking)],
-@@ -41,11 +46,16 @@ my $TESTS = {
-     test_class => [qw(forking)],
-   },
- 
--  fxp_allowed_by_class => {
-+  fxp_port_allowed_by_class => {
-     order => ++$order,
-     test_class => [qw(forking)],
-   },
- 
-+  fxp_pasv_allowed_by_class_issue1346 => {
-+    order => ++$order,
-+    test_class => [qw(bug forking)],
-+  },
-+
-   fxp_allowed_2gb => {
-     order => ++$order,
-     test_class => [qw(forking)],
-@@ -353,7 +363,7 @@ sub fxp_denied_eprt {
-   test_cleanup($setup->{log_file}, $ex);
- }
- 
--sub fxp_denied_by_class {
-+sub fxp_port_denied_by_class {
-   my $self = shift;
-   my $tmpdir = $self->{tmpdir};
-   my $setup = test_setup($tmpdir, 'config');
-@@ -519,6 +529,139 @@ EOC
-   test_cleanup($setup->{log_file}, $ex);
- }
- 
-+sub fxp_pasv_denied_by_class_issue1346 {
-+  my $self = shift;
-+  my $tmpdir = $self->{tmpdir};
-+  my $setup = test_setup($tmpdir, 'config');
-+
-+  my $class_name = 'allowed_fxp';
-+
-+  my $config = {
-+    PidFile => $setup->{pid_file},
-+    ScoreboardFile => $setup->{scoreboard_file},
-+    SystemLog => $setup->{log_file},
-+
-+    AuthUserFile => $setup->{auth_user_file},
-+    AuthGroupFile => $setup->{auth_group_file},
-+
-+    AllowForeignAddress => $class_name,
-+
-+    IfModules => {
-+      'mod_delay.c' => {
-+        DelayEngine => 'off',
-+      },
-+    },
-+  };
-+
-+  my ($port, $config_user, $config_group) = config_write($setup->{config_file},
-+    $config);
-+
-+  if (open(my $fh, ">> $setup->{config_file}")) {
-+    print $fh <<EOC;
-+<Class $class_name>
-+  From none
-+</Class>
-+EOC
-+    unless (close($fh)) {
-+      die("Can't write $setup->{config_file}: $!");
-+    }
-+
-+  } else {
-+    die("Can't open $setup->{config_file}: $!");
-+  }
-+
-+  # Open pipes, for use between the parent and child processes.  Specifically,
-+  # the child will indicate when it's done with its test by writing a message
-+  # to the parent.
-+  my ($rfh, $wfh);
-+  unless (pipe($rfh, $wfh)) {
-+    die("Can't open pipe: $!");
-+  }
-+
-+  my $ex;
-+
-+  # Fork child
-+  $self->handle_sigchld();
-+  defined(my $pid = fork()) or die("Can't fork: $!");
-+  if ($pid) {
-+    eval {
-+      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port, 0, 3);
-+      $client->login($setup->{user}, $setup->{passwd});
-+
-+      # Attemping a data transfer should fail, due to the AllowForeignAddress
-+      # class restriction.
-+
-+      my $conn = $client->list_raw();
-+      if ($conn) {
-+        die("LIST succeeded unexpectedly");
-+      }
-+
-+      my $resp_code = $client->response_code();
-+      my $resp_msg = $client->response_msg();
-+
-+      my $expected = 425;
-+      $self->assert($expected == $resp_code,
-+        "Expected response code $expected, got $resp_code");
-+
-+      $expected = 'Unable to build data connection:';
-+      $self->assert(qr/$expected/, $resp_msg,
-+        "Expected response message '$expected', got '$resp_msg'");
-+
-+      $client->quit();
-+    };
-+    if ($@) {
-+      $ex = $@;
-+    }
-+
-+    $wfh->print("done\n");
-+    $wfh->flush();
-+
-+  } else {
-+    eval { server_wait($setup->{config_file}, $rfh) };
-+    if ($@) {
-+      warn($@);
-+      exit 1;
-+    }
-+
-+    exit 0;
-+  }
-+
-+  # Stop server
-+  server_stop($setup->{pid_file});
-+  $self->assert_child_ok($pid);
-+
-+  eval {
-+    if (open(my $fh, "< $setup->{log_file}")) {
-+      my $ok = 0;
-+
-+      while (my $line = <$fh>) {
-+        chomp($line);
-+
-+        if ($ENV{TEST_VERBOSE}) {
-+          print STDERR "$line\n";
-+        }
-+
-+        if ($line =~ /SECURITY VIOLATION: Passive connection from foreign IP address \S+ rejected \(does not match <Class \S+>\)/) {
-+          $ok = 1;
-+          last;
-+        }
-+      }
-+
-+      close($fh);
-+
-+      $self->assert($ok, "Did not see expected log messages");
-+
-+    } else {
-+      die("Can't read $setup->{log_file}: $!");
-+    }
-+  };
-+  if ($@) {
-+    $ex = $@;
-+  }
-+
-+  test_cleanup($setup->{log_file}, $ex);
-+}
-+
- sub fxp_allowed {
-   my $self = shift;
-   my $tmpdir = $self->{tmpdir};
-@@ -781,7 +924,7 @@ sub fxp_allowed_eprt {
-   test_cleanup($setup->{log_file}, $ex);
- }
- 
--sub fxp_allowed_by_class {
-+sub fxp_port_allowed_by_class {
-   my $self = shift;
-   my $tmpdir = $self->{tmpdir};
-   my $setup = test_setup($tmpdir, 'config');
-@@ -926,6 +1069,110 @@ EOC
-   test_cleanup($setup->{log_file}, $ex);
- }
- 
-+sub fxp_pasv_allowed_by_class_issue1346 {
-+  my $self = shift;
-+  my $tmpdir = $self->{tmpdir};
-+  my $setup = test_setup($tmpdir, 'config');
-+
-+  my $class_name = 'allowed_fxp';
-+
-+  my $config = {
-+    PidFile => $setup->{pid_file},
-+    ScoreboardFile => $setup->{scoreboard_file},
-+    SystemLog => $setup->{log_file},
-+    TraceLog => $setup->{log_file},
-+    Trace => 'class:20 inet:20',
-+
-+    AuthUserFile => $setup->{auth_user_file},
-+    AuthGroupFile => $setup->{auth_group_file},
-+
-+    AllowForeignAddress => $class_name,
-+
-+    IfModules => {
-+      'mod_delay.c' => {
-+        DelayEngine => 'off',
-+      },
-+    },
-+  };
-+
-+  my ($port, $config_user, $config_group) = config_write($setup->{config_file},
-+    $config);
-+
-+  if (open(my $fh, ">> $setup->{config_file}")) {
-+    print $fh <<EOC;
-+<Class $class_name>
-+  From 127.0.0.0/8
-+</Class>
-+EOC
-+    unless (close($fh)) {
-+      die("Can't write $setup->{config_file}: $!");
-+    }
-+
-+  } else {
-+    die("Can't open $setup->{config_file}: $!");
-+  }
-+
-+  # Open pipes, for use between the parent and child processes.  Specifically,
-+  # the child will indicate when it's done with its test by writing a message
-+  # to the parent.
-+  my ($rfh, $wfh);
-+  unless (pipe($rfh, $wfh)) {
-+    die("Can't open pipe: $!");
-+  }
-+
-+  my $ex;
-+
-+  # Fork child
-+  $self->handle_sigchld();
-+  defined(my $pid = fork()) or die("Can't fork: $!");
-+  if ($pid) {
-+    eval {
-+      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port, 0, 3);
-+      $client->login($setup->{user}, $setup->{passwd});
-+
-+      # Attemping a data transfer should succeed, due to the AllowForeignAddress
-+      # class restriction.
-+      my $conn = $client->list_raw();
-+      unless ($conn) {
-+        die("Failed to LIST: " . $client->response_code() . " " .
-+          $client->response_msg());
-+      }
-+
-+      my $buf;
-+      $conn->read($buf, 8192, 30);
-+      eval { $conn->close() };
-+
-+      my ($resp_code, $resp_msg);
-+      $resp_code = $client->response_code();
-+      $resp_msg = $client->response_msg();
-+
-+      $self->assert_transfer_ok($resp_code, $resp_msg);
-+      $client->quit();
-+    };
-+    if ($@) {
-+      $ex = $@;
-+    }
-+
-+    $wfh->print("done\n");
-+    $wfh->flush();
-+
-+  } else {
-+    eval { server_wait($setup->{config_file}, $rfh) };
-+    if ($@) {
-+      warn($@);
-+      exit 1;
-+    }
-+
-+    exit 0;
-+  }
-+
-+  # Stop server
-+  server_stop($setup->{pid_file});
-+  $self->assert_child_ok($pid);
-+
-+  test_cleanup($setup->{log_file}, $ex);
-+}
-+
- sub fxp_allowed_2gb {
-   my $self = shift;
-   my $tmpdir = $self->{tmpdir};


=====================================
debian/patches/upstream_1450.diff deleted
=====================================
@@ -1,557 +0,0 @@
-From 8aa39b27d8fd6ada556b51c4547a504956474078 Mon Sep 17 00:00:00 2001
-From: TJ Saunders <tj at castaglia.org>
-Date: Mon, 9 May 2022 17:49:08 -0700
-Subject: [PATCH] Issue #1448: Backporting the mod_sftp/OpenSSL 3.x fixes to
- the 1.3.7 branch.
-
----
- NEWS                           |   4 ++
- RELEASE_NOTES                  |   6 ++
- contrib/mod_sftp/cipher.c      |  79 ++++++++++++++++++---
- contrib/mod_sftp/configure     | 123 +++++++++++++++++++++++++++++++++
- contrib/mod_sftp/configure.in  |  74 +++++++++++++++++++-
- contrib/mod_sftp/crypto.c      |  14 +++-
- contrib/mod_sftp/keys.c        |   4 +-
- contrib/mod_sftp/mod_sftp.c    |  20 +++++-
- contrib/mod_sftp/mod_sftp.h.in |  14 +++-
- 9 files changed, 324 insertions(+), 14 deletions(-)
-
-diff --git a/NEWS b/NEWS
-index 52d4b58c94..6cf27d97ff 100644
---- a/NEWS
-+++ b/NEWS
-@@ -15,6 +15,10 @@
-   where `N' is the issue number.
- -----------------------------------------------------------------------------
- 
-+1.3.7e
-+--------------------------------
-+- Issue 1448 - Ensure that mod_sftp algorithms work properly with OpenSSL 3.x.
-+
- 1.3.7d - Released 23-Apr-2022
- --------------------------------
- - Issue 1321 - Crash with long lines in AuthGroupFile due to large realloc(3).
-diff --git a/RELEASE_NOTES b/RELEASE_NOTES
-index 7c274a01f6..ea583ca079 100644
---- a/RELEASE_NOTES
-+++ b/RELEASE_NOTES
-@@ -6,6 +6,12 @@ This file contains a description of the major changes to ProFTPD for the
- releases.  More information on these changes can be found in the NEWS and
- ChangeLog files.
- 
-+1.3.7e
-+---------
-+
-+  + Ensure that mod_sftp algorithms work properly when OpenSSL 3.x is used.
-+
-+
- 1.3.7d
- ---------
- 
-diff --git a/contrib/mod_sftp/cipher.c b/contrib/mod_sftp/cipher.c
-index 77c79e0672..57d4c2f996 100644
---- a/contrib/mod_sftp/cipher.c
-+++ b/contrib/mod_sftp/cipher.c
-@@ -1,6 +1,6 @@
- /*
-  * ProFTPD - mod_sftp ciphers
-- * Copyright (c) 2008-2020 TJ Saunders
-+ * Copyright (c) 2008-2022 TJ Saunders
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -192,14 +192,40 @@ static int set_cipher_iv(struct sftp_cipher *cipher, const EVP_MD *hash,
-   }
- 
-   ctx = EVP_MD_CTX_create();
--  EVP_DigestInit(ctx, hash);
-+  if (EVP_DigestInit(ctx, hash) != 1) {
-+    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
-+      "unable to initialize MD context for '%s': %s", EVP_MD_name(hash),
-+      sftp_crypto_get_errors());
-+    free(iv);
-+    errno = EINVAL;
-+    return -1;
-+  }
-+
-   if (sftp_interop_supports_feature(SFTP_SSH2_FEAT_CIPHER_USE_K)) {
-     EVP_DigestUpdate(ctx, k, klen);
-   }
--  EVP_DigestUpdate(ctx, h, hlen);
-+
-+  if (EVP_DigestUpdate(ctx, h, hlen) != 1) {
-+    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
-+      "unable to update MD context for '%s': %s", EVP_MD_name(hash),
-+      sftp_crypto_get_errors());
-+    free(iv);
-+    errno = EINVAL;
-+    return -1;
-+  }
-+
-   EVP_DigestUpdate(ctx, letter, sizeof(char));
-   EVP_DigestUpdate(ctx, (char *) id, id_len);
--  EVP_DigestFinal(ctx, iv, &iv_len);
-+
-+  if (EVP_DigestFinal(ctx, iv, &iv_len) != 1) {
-+    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
-+      "unable to finish MD context for '%s': %s", EVP_MD_name(hash),
-+      sftp_crypto_get_errors());
-+    free(iv);
-+    errno = EINVAL;
-+    return -1;
-+  }
-+
-   EVP_MD_CTX_destroy(ctx);
- 
-   /* If we need more, keep hashing, as per RFC, until we have enough
-@@ -264,12 +290,37 @@ static int set_cipher_key(struct sftp_cipher *cipher, const EVP_MD *hash,
-   }
- 
-   ctx = EVP_MD_CTX_create();
--  EVP_DigestInit(ctx, hash);
--  EVP_DigestUpdate(ctx, k, klen);
-+  if (EVP_DigestInit(ctx, hash) != 1) {
-+    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
-+      "unable to initialize MD context for '%s': %s", EVP_MD_name(hash),
-+      sftp_crypto_get_errors());
-+    free(key);
-+    errno = EINVAL;
-+    return -1;
-+  }
-+
-+  if (EVP_DigestUpdate(ctx, k, klen) != 1) {
-+    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
-+      "unable to update MD context for '%s': %s", EVP_MD_name(hash),
-+      sftp_crypto_get_errors());
-+    free(key);
-+    errno = EINVAL;
-+    return -1;
-+  }
-+
-   EVP_DigestUpdate(ctx, h, hlen);
-   EVP_DigestUpdate(ctx, letter, sizeof(char));
-   EVP_DigestUpdate(ctx, (char *) id, id_len);
--  EVP_DigestFinal(ctx, key, &key_len);
-+
-+  if (EVP_DigestFinal(ctx, key, &key_len) != 1) {
-+    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
-+      "unable to finish MD context for '%s': %s", EVP_MD_name(hash),
-+      sftp_crypto_get_errors());
-+    free(key);
-+    errno = EINVAL;
-+    return -1;
-+  }
-+
-   EVP_MD_CTX_destroy(ctx);
- 
-   pr_trace_msg(trace_channel, 19, "hashed data to produce key (%lu bytes)",
-@@ -507,7 +558,19 @@ int sftp_cipher_set_read_key(pool *p, const EVP_MD *hash, const BIGNUM *k,
-   }
- 
-   pr_memscrub(ptr, bufsz);
--  sftp_cipher_set_block_size(EVP_CIPHER_block_size(cipher->cipher));
-+
-+  if (strcmp(cipher->algo, "aes128-ctr") == 0 ||
-+      strcmp(cipher->algo, "aes192-ctr") == 0 ||
-+      strcmp(cipher->algo, "aes256-ctr") == 0) {
-+    /* For some reason, OpenSSL returns 8 for the AES block size (even
-+     * though the AES block size is 16, per RFC 5647), but OpenSSH wants 16.
-+     */
-+    sftp_cipher_set_block_size(16);
-+
-+  } else {
-+    sftp_cipher_set_block_size(EVP_CIPHER_block_size(cipher->cipher));
-+  }
-+
-   return 0;
- }
- 
-diff --git a/contrib/mod_sftp/configure b/contrib/mod_sftp/configure
-index f0cd88d445..0907fdbd14 100755
---- a/contrib/mod_sftp/configure
-+++ b/contrib/mod_sftp/configure
-@@ -3865,6 +3865,88 @@ $as_echo "no" >&6; }
-     LIBS="$saved_libs"
- 
- 
-+fi
-+rm -f core conftest.err conftest.$ac_objext \
-+    conftest$ac_exeext conftest.$ac_ext
-+
-+LIBS=`echo "$LIBS" | sed -e 's/-lsupp//g'`;
-+LIBS="-lcrypto $LIBS"
-+
-+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether OpenSSL supports EVP_aes_128_ctr" >&5
-+$as_echo_n "checking whether OpenSSL supports EVP_aes_128_ctr... " >&6; }
-+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-+/* end confdefs.h.  */
-+
-+    #include <openssl/evp.h>
-+
-+int
-+main ()
-+{
-+
-+    EVP_CIPHER *cipher;
-+    cipher = EVP_aes_128_ctr();
-+
-+  ;
-+  return 0;
-+}
-+_ACEOF
-+if ac_fn_c_try_link "$LINENO"; then :
-+
-+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-+$as_echo "yes" >&6; }
-+
-+$as_echo "#define HAVE_EVP_AES_128_CTR_OPENSSL 1" >>confdefs.h
-+
-+    LIBS="$saved_libs"
-+
-+else
-+
-+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-+$as_echo "no" >&6; }
-+    LIBS="$saved_libs"
-+
-+
-+fi
-+rm -f core conftest.err conftest.$ac_objext \
-+    conftest$ac_exeext conftest.$ac_ext
-+
-+LIBS=`echo "$LIBS" | sed -e 's/-lsupp//g'`;
-+LIBS="-lcrypto $LIBS"
-+
-+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether OpenSSL supports EVP_aes_192_ctr" >&5
-+$as_echo_n "checking whether OpenSSL supports EVP_aes_192_ctr... " >&6; }
-+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-+/* end confdefs.h.  */
-+
-+    #include <openssl/evp.h>
-+
-+int
-+main ()
-+{
-+
-+    EVP_CIPHER *cipher;
-+    cipher = EVP_aes_192_ctr();
-+
-+  ;
-+  return 0;
-+}
-+_ACEOF
-+if ac_fn_c_try_link "$LINENO"; then :
-+
-+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-+$as_echo "yes" >&6; }
-+
-+$as_echo "#define HAVE_EVP_AES_192_CTR_OPENSSL 1" >>confdefs.h
-+
-+    LIBS="$saved_libs"
-+
-+else
-+
-+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-+$as_echo "no" >&6; }
-+    LIBS="$saved_libs"
-+
-+
- fi
- rm -f core conftest.err conftest.$ac_objext \
-     conftest$ac_exeext conftest.$ac_ext
-@@ -3906,6 +3988,47 @@ $as_echo "no" >&6; }
-     LIBS="$saved_libs"
- 
- 
-+fi
-+rm -f core conftest.err conftest.$ac_objext \
-+    conftest$ac_exeext conftest.$ac_ext
-+
-+LIBS=`echo "$LIBS" | sed -e 's/-lsupp//g'`;
-+LIBS="-lcrypto $LIBS"
-+
-+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether OpenSSL supports OSSL_PROVIDER_load" >&5
-+$as_echo_n "checking whether OpenSSL supports OSSL_PROVIDER_load... " >&6; }
-+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-+/* end confdefs.h.  */
-+
-+    #include <openssl/provider.h>
-+
-+int
-+main ()
-+{
-+
-+    OSSL_PROVIDER *provider;
-+    provider = OSSL_PROVIDER_load(NULL, "default");
-+
-+  ;
-+  return 0;
-+}
-+_ACEOF
-+if ac_fn_c_try_link "$LINENO"; then :
-+
-+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-+$as_echo "yes" >&6; }
-+
-+$as_echo "#define HAVE_OSSL_PROVIDER_LOAD_OPENSSL 1" >>confdefs.h
-+
-+    LIBS="$saved_libs"
-+
-+else
-+
-+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-+$as_echo "no" >&6; }
-+    LIBS="$saved_libs"
-+
-+
- fi
- rm -f core conftest.err conftest.$ac_objext \
-     conftest$ac_exeext conftest.$ac_ext
-diff --git a/contrib/mod_sftp/configure.in b/contrib/mod_sftp/configure.in
-index b45d434fec..690efef3da 100644
---- a/contrib/mod_sftp/configure.in
-+++ b/contrib/mod_sftp/configure.in
-@@ -1,5 +1,5 @@
- dnl ProFTPD - mod_sftp
--dnl Copyright (c) 2012-2019 TJ Saunders <tj at castaglia.org>
-+dnl Copyright (c) 2012-2022 TJ Saunders <tj at castaglia.org>
- dnl
- dnl This program is free software; you can redistribute it and/or modify
- dnl it under the terms of the GNU General Public License as published by
-@@ -206,6 +206,54 @@ dnl Splice out -lsupp, since that library hasn't been built yet
- LIBS=`echo "$LIBS" | sed -e 's/-lsupp//g'`;
- LIBS="-lcrypto $LIBS"
- 
-+AC_MSG_CHECKING([whether OpenSSL supports EVP_aes_128_ctr])
-+AC_TRY_LINK(
-+  [
-+    #include <openssl/evp.h>
-+  ],
-+  [
-+    EVP_CIPHER *cipher;
-+    cipher = EVP_aes_128_ctr();
-+  ],
-+  [
-+    AC_MSG_RESULT(yes)
-+    AC_DEFINE(HAVE_EVP_AES_128_CTR_OPENSSL, 1, [OpenSSL supports EVP_aes_128_ctr])
-+    LIBS="$saved_libs"
-+  ],
-+  [
-+    AC_MSG_RESULT(no)
-+    LIBS="$saved_libs"
-+  ]
-+)
-+
-+dnl Splice out -lsupp, since that library hasn't been built yet
-+LIBS=`echo "$LIBS" | sed -e 's/-lsupp//g'`;
-+LIBS="-lcrypto $LIBS"
-+
-+AC_MSG_CHECKING([whether OpenSSL supports EVP_aes_192_ctr])
-+AC_TRY_LINK(
-+  [
-+    #include <openssl/evp.h>
-+  ],
-+  [
-+    EVP_CIPHER *cipher;
-+    cipher = EVP_aes_192_ctr();
-+  ],
-+  [
-+    AC_MSG_RESULT(yes)
-+    AC_DEFINE(HAVE_EVP_AES_192_CTR_OPENSSL, 1, [OpenSSL supports EVP_aes_192_ctr])
-+    LIBS="$saved_libs"
-+  ],
-+  [
-+    AC_MSG_RESULT(no)
-+    LIBS="$saved_libs"
-+  ]
-+)
-+
-+dnl Splice out -lsupp, since that library hasn't been built yet
-+LIBS=`echo "$LIBS" | sed -e 's/-lsupp//g'`;
-+LIBS="-lcrypto $LIBS"
-+
- AC_MSG_CHECKING([whether OpenSSL supports EVP_aes_256_ctr])
- AC_TRY_LINK(
-   [
-@@ -226,6 +274,30 @@ AC_TRY_LINK(
-   ]
- )
- 
-+dnl Splice out -lsupp, since that library hasn't been built yet
-+LIBS=`echo "$LIBS" | sed -e 's/-lsupp//g'`;
-+LIBS="-lcrypto $LIBS"
-+
-+AC_MSG_CHECKING([whether OpenSSL supports OSSL_PROVIDER_load])
-+AC_TRY_LINK(
-+  [
-+    #include <openssl/provider.h>
-+  ],
-+  [
-+    OSSL_PROVIDER *provider;
-+    provider = OSSL_PROVIDER_load(NULL, "default");
-+  ],
-+  [
-+    AC_MSG_RESULT(yes)
-+    AC_DEFINE(HAVE_OSSL_PROVIDER_LOAD_OPENSSL, 1, [OpenSSL supports OSSL_PROVIDER_load])
-+    LIBS="$saved_libs"
-+  ],
-+  [
-+    AC_MSG_RESULT(no)
-+    LIBS="$saved_libs"
-+  ]
-+)
-+
- LIBS="$saved_libs"
- 
- INCLUDES="$ac_build_addl_includes"
-diff --git a/contrib/mod_sftp/crypto.c b/contrib/mod_sftp/crypto.c
-index e9d776bcde..3ff94d4b3e 100644
---- a/contrib/mod_sftp/crypto.c
-+++ b/contrib/mod_sftp/crypto.c
-@@ -1,6 +1,6 @@
- /*
-  * ProFTPD - mod_sftp OpenSSL interface
-- * Copyright (c) 2008-2017 TJ Saunders
-+ * Copyright (c) 2008-2022 TJ Saunders
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -983,13 +983,25 @@ const EVP_CIPHER *sftp_crypto_get_cipher(const char *name, size_t *key_len,
- # endif /* !OPENSSL_NO_DES */
- 
-       } else if (strncmp(name, "aes256-ctr", 11) == 0) {
-+# if defined(HAVE_EVP_AES_256_CTR_OPENSSL)
-+        cipher = EVP_aes_256_ctr();
-+# else
-         cipher = get_aes_ctr_cipher(32);
-+# endif /* HAVE_EVP_AES_256_CTR_OPENSSL */
- 
-       } else if (strncmp(name, "aes192-ctr", 11) == 0) {
-+# if defined(HAVE_EVP_AES_192_CTR_OPENSSL)
-+        cipher = EVP_aes_192_ctr();
-+# else
-         cipher = get_aes_ctr_cipher(24);
-+# endif /* HAVE_EVP_AES_192_CTR_OPENSSL */
- 
-       } else if (strncmp(name, "aes128-ctr", 11) == 0) {
-+# if defined(HAVE_EVP_AES_128_CTR_OPENSSL)
-+        cipher = EVP_aes_128_ctr();
-+# else
-         cipher = get_aes_ctr_cipher(16);
-+# endif /* HAVE_EVP_AES_128_CTR_OPENSSL */
- #endif /* OpenSSL older than 0.9.7 */
- 
-       } else {
-diff --git a/contrib/mod_sftp/keys.c b/contrib/mod_sftp/keys.c
-index c6b88cf4de..54f19321db 100644
---- a/contrib/mod_sftp/keys.c
-+++ b/contrib/mod_sftp/keys.c
-@@ -1,6 +1,6 @@
- /*
-  * ProFTPD - mod_sftp key mgmt (keys)
-- * Copyright (c) 2008-2021 TJ Saunders
-+ * Copyright (c) 2008-2022 TJ Saunders
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -2903,7 +2903,7 @@ static int decrypt_openssh_data(pool *p, const char *path,
-    * trailing AEAD bytes.  Need to fix that in the future.
-    */
- 
--  if (EVP_Cipher(cipher_ctx, buf, encrypted_data, encrypted_len) != 1) {
-+  if (EVP_Cipher(cipher_ctx, buf, encrypted_data, encrypted_len) < 0) {
-     /* This might happen due to a wrong/bad passphrase. */
-     pr_trace_msg(trace_channel, 3,
-       "error decrypting %s data for key: %s", cipher->algo,
-diff --git a/contrib/mod_sftp/mod_sftp.c b/contrib/mod_sftp/mod_sftp.c
-index b84b1a77b6..f53407e88e 100644
---- a/contrib/mod_sftp/mod_sftp.c
-+++ b/contrib/mod_sftp/mod_sftp.c
-@@ -1,6 +1,6 @@
- /*
-  * ProFTPD - mod_sftp
-- * Copyright (c) 2008-2020 TJ Saunders
-+ * Copyright (c) 2008-2022 TJ Saunders
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -72,6 +72,10 @@ static const char *sftp_server_version = SFTP_ID_DEFAULT_STRING;
- #define SFTP_HOSTKEY_FL_CLEAR_ECDSA_KEY		0x004
- #define SFTP_HOSTKEY_FL_CLEAR_ED25519_KEY	0x008
- 
-+#if defined(HAVE_OSSL_PROVIDER_LOAD_OPENSSL)
-+static OSSL_PROVIDER *legacy_provider = NULL;
-+#endif /* HAVE_OSSL_PROVIDER_LOAD_OPENSSL */
-+
- static const char *trace_channel = "ssh2";
- 
- static int sftp_have_authenticated(cmd_rec *cmd) {
-@@ -1881,6 +1885,13 @@ static void sftp_shutdown_ev(const void *event_data, void *user_data) {
-   /* Clean up the OpenSSL stuff. */
-   sftp_crypto_free(0);
- 
-+#if defined(HAVE_OSSL_PROVIDER_LOAD_OPENSSL)
-+  if (legacy_provider != NULL) {
-+    OSSL_PROVIDER_unload(legacy_provider);
-+    legacy_provider = NULL;
-+  }
-+#endif /* HAVE_OSSL_PROVIDER_LOAD_OPENSSL */
-+
-   destroy_pool(sftp_pool);
-   sftp_pool = NULL;
- 
-@@ -2035,6 +2046,13 @@ static int sftp_init(void) {
-   }
- #endif /* HAVE_SODIUM_H */
- 
-+#if defined(HAVE_OSSL_PROVIDER_LOAD_OPENSSL)
-+  /* Load the "legacy" OpenSSL algorithm provider, for those SSH algorithms
-+   * that require support of algorithms that OpenSSL deemed "legacy".
-+   */
-+  legacy_provider = OSSL_PROVIDER_load(NULL, "legacy");
-+#endif /* HAVE_OSSL_PROVIDER_LOAD_OPENSSL */
-+
-   sftp_keystore_init();
-   sftp_cipher_init();
-   sftp_mac_init();
-diff --git a/contrib/mod_sftp/mod_sftp.h.in b/contrib/mod_sftp/mod_sftp.h.in
-index 065981c313..9af590e8e3 100644
---- a/contrib/mod_sftp/mod_sftp.h.in
-+++ b/contrib/mod_sftp/mod_sftp.h.in
-@@ -1,6 +1,6 @@
- /*
-  * ProFTPD - mod_sftp
-- * Copyright (c) 2008-2020 TJ Saunders
-+ * Copyright (c) 2008-2022 TJ Saunders
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -49,9 +49,18 @@
- /* Define if you have OpenSSL with crippled AES support. */
- #undef HAVE_AES_CRIPPLED_OPENSSL
- 
-+/* Define if you have OpenSSL with EVP_aes_128_ctr support. */
-+#undef HAVE_EVP_AES_128_CTR_OPENSSL
-+
-+/* Define if you have OpenSSL with EVP_aes_192_ctr support. */
-+#undef HAVE_EVP_AES_192_CTR_OPENSSL
-+
- /* Define if you have OpenSSL with EVP_aes_256_ctr support. */
- #undef HAVE_EVP_AES_256_CTR_OPENSSL
- 
-+/* Define if you have OpenSSL with OSSL_PROVIDER_load support. */
-+#undef HAVE_OSSL_PROVIDER_LOAD_OPENSSL
-+
- /* Define if you have OpenSSL with SHA256 support. */
- #undef HAVE_SHA256_OPENSSL
- 
-@@ -93,6 +102,9 @@
- # include <openssl/ec.h>
- # include <openssl/ecdh.h>
- #endif /* PR_USE_OPENSSL_ECC */
-+#if defined(HAVE_OSSL_PROVIDER_LOAD_OPENSSL)
-+# include <openssl/provider.h>
-+#endif /* HAVE_OSSL_PROVIDER_LOAD_OPENSSL */
- 
- /* Define if you have the LibreSSL library.  */
- #if defined(LIBRESSL_VERSION_NUMBER)


=====================================
debian/patches/upstream_long_AuthGroupFile_lines deleted
=====================================
@@ -1,187 +0,0 @@
-From 9aff151f6810b8f0e64cc9f7e15dd21ebecd4cc3 Mon Sep 17 00:00:00 2001
-From: TJ Saunders <tj at castaglia.org>
-Date: Fri, 28 Jan 2022 08:21:44 -0800
-Subject: [PATCH] Backporting buffering fixes when parsing long `AuthGroupFile`
- lines.
-
----
- modules/mod_auth_file.c | 87 ++++++++++++++++++++++++++++++++---------
- 1 file changed, 68 insertions(+), 19 deletions(-)
-
-diff --git a/modules/mod_auth_file.c b/modules/mod_auth_file.c
-index b1ccaa771..3530905f1 100644
---- a/modules/mod_auth_file.c
-+++ b/modules/mod_auth_file.c
-@@ -1,7 +1,7 @@
- /*
-  * ProFTPD: mod_auth_file - file-based authentication module that supports
-  *                          restrictions on the file contents
-- * Copyright (c) 2002-2021 The ProFTPD Project team
-+ * Copyright (c) 2002-2022 The ProFTPD Project team
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -325,24 +325,35 @@ static struct passwd *af_getpasswd(const char *buf, unsigned int lineno) {
- #define NGRPFIELDS      4
- 
- static char *grpbuf = NULL;
-+static size_t grpbufsz = 0;
- static struct group grent;
- static char *grpfields[NGRPFIELDS];
- static char *members[MAXMEMBERS+1];
- 
--static char *af_getgrentline(char **buf, int *buflen, pr_fh_t *fh,
-+static char *af_getgrentline(char **buf, size_t *bufsz, pr_fh_t *fh,
-     unsigned int *lineno) {
--  char *cp = *buf;
--  int original_buflen;
-+  char *ptr, *res;
-+  size_t original_bufsz, buflen;
- 
--  original_buflen = *buflen;
-+  original_bufsz = *bufsz;
-+  buflen = *bufsz;
- 
--  while (pr_fsio_gets(cp, (*buflen) - (cp - *buf), fh) != NULL) {
--    pr_signals_handle();
-+  /* Try to keep our unfilled buffer zeroed out, so that strlen(3) et al
-+   * work as expected.
-+   */
-+  memset(*buf, '\0', *bufsz);
- 
--    (*lineno)++;
-+  ptr = *buf;
-+  res = pr_fsio_gets(ptr, buflen, fh);
-+  while (res != NULL) {
-+    pr_signals_handle();
- 
-     /* Is this a full line? */
--    if (strchr(cp, '\n')) {
-+    if (strchr(*buf, '\n') != NULL) {
-+      pr_trace_msg(trace_channel, 25,
-+        "found LF, returning line: '%s' (%lu bytes)", *buf,
-+        (unsigned long) strlen(*buf));
-+      (*lineno)++;
-       return *buf;
-     }
- 
-@@ -351,26 +362,37 @@ static char *af_getgrentline(char **buf, int *buflen, pr_fh_t *fh,
-      * allocated buffer by the original buffer length each time.  So we
-      * do the same (Issue #1321).
-      */
--    *buflen += original_buflen;
--
-     {
-+      size_t new_bufsz;
-       char *new_buf;
- 
--      new_buf = realloc(*buf, *buflen);
-+      pr_trace_msg(trace_channel, 25, "getgrentline() buffer (%lu bytes): "
-+        "'%.*s'", (unsigned long) *bufsz, (int) *bufsz, *buf);
-+
-+      pr_trace_msg(trace_channel, 19,
-+        "no LF found in group line, increasing buffer (%lu bytes) by %lu bytes",
-+        (unsigned long) *bufsz, (unsigned long) original_bufsz);
-+      new_bufsz = *bufsz + original_bufsz;
-+
-+      new_buf = realloc(*buf, new_bufsz);
-       if (new_buf == NULL) {
-         break;
-       }
- 
-+      ptr = new_buf + *bufsz;
-       *buf = new_buf;
-+      *bufsz = new_bufsz;
-+      buflen = original_bufsz;
-+
-+      memset(ptr, '\0', buflen);
-     }
- 
--    cp = *buf + (cp - *buf);
--    cp = strchr(cp, '\0');
-+    res = pr_fsio_gets(ptr, buflen, fh);
-   }
- 
-   free(*buf);
-   *buf = NULL;
--  *buflen = 0;
-+  *bufsz = 0;
- 
-   return NULL;
- }
-@@ -401,22 +423,29 @@ static struct group *af_getgrp(const char *buf, unsigned int lineno) {
- 
-   i = strlen(buf) + 1;
- 
--  if (!grpbuf) {
-+  if (grpbuf == NULL) {
-+    grpbufsz = i;
-     grpbuf = malloc(i);
- 
--  } else {
-+  } else if (grpbufsz < (size_t) i) {
-     char *new_buf;
- 
-+    pr_trace_msg(trace_channel, 19,
-+      "parsing group line '%s' (%lu bytes), allocating %lu bytes via "
-+      "realloc(3)", buf, (unsigned long) i, (unsigned long) i);
-+
-     new_buf = realloc(grpbuf, i);
-     if (new_buf == NULL) {
-       return NULL;
-     }
- 
-     grpbuf = new_buf;
-+    grpbufsz = i;
-   }
- 
--  if (!grpbuf)
-+  if (grpbuf == NULL) {
-     return NULL;
-+  }
- 
-   sstrncpy(grpbuf, buf, i);
- 
-@@ -524,7 +553,16 @@ static struct group *af_getgrent(pool *p) {
- 
-   while (TRUE) {
-     char *cp = NULL, *buf = NULL;
--    int buflen = PR_TUNABLE_BUFFER_SIZE;
-+    size_t buflen;
-+
-+    buflen = PR_TUNABLE_BUFFER_SIZE;
-+
-+    if (af_group_file->af_file_fh->fh_iosz > 0) {
-+      /* This aligns our group(5) buffer with the preferred filesystem read
-+       * block size.
-+       */
-+      buflen = af_group_file->af_file_fh->fh_iosz;
-+    }
- 
-     pr_signals_handle();
- 
-@@ -533,6 +571,11 @@ static struct group *af_getgrent(pool *p) {
-       pr_log_pri(PR_LOG_ALERT, "Out of memory!");
-       _exit(1);
-     }
-+
-+    pr_trace_msg(trace_channel, 19,
-+      "getgrent(3): allocated buffer %p (%lu bytes)", buf,
-+      (unsigned long) buflen);
-+
-     grp = NULL;
- 
-     while (af_getgrentline(&buf, &buflen, af_group_file->af_file_fh,
-@@ -636,6 +679,12 @@ static int af_setgrent(pool *p) {
-         pbuf->remaining = pbuf->buflen;
-       }
- 
-+      if (grpbuf != NULL) {
-+        free(grpbuf);
-+        grpbuf = NULL;
-+      }
-+      grpbufsz = 0;
-+
-       return 0;
-     }
- 



View it on GitLab: https://salsa.debian.org/debian-proftpd-team/proftpd/-/commit/7c4d3644c46ff3922269b050d2456c366af1d021

-- 
View it on GitLab: https://salsa.debian.org/debian-proftpd-team/proftpd/-/commit/7c4d3644c46ff3922269b050d2456c366af1d021
You're receiving this email because of your account on salsa.debian.org.




More information about the Pkg-proftpd-maintainers mailing list