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

Hilmar Preuße (@hilmar) gitlab at salsa.debian.org
Tue Oct 27 22:06:47 GMT 2026



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


Commits:
e7963d08 by Hilmar Preuße at 2026-10-27T23:05:26+01:00
[skip-ci] Remove obsolete patches.

- - - - -


12 changed files:

- debian/changelog
- − debian/patches/04d89957d8ace325ef76fdfab22049df16a40c0b.diff
- − debian/patches/07797aba88dca902da7eaf1dfe262c8896943de7.diff
- − debian/patches/1a5ce6467756e92f42f89c53f0f370dc0f0206d7.diff
- − debian/patches/2148.diff
- − debian/patches/3d3a936b696d73f24a7f1a99bf7aa26735ff2306.diff
- − debian/patches/415395b795436ae47cc25b2394e80033b80f11be.diff
- − debian/patches/508eb4d1b8c550b5f3059ad5b33d60c6b6c76bc7.diff
- − debian/patches/536608f849dddd2b551e7c1e4fd930a50a527ffe.diff
- − debian/patches/7e076e844ab5da63a0887b875aca2c3cfbc83a49.diff
- − debian/patches/d4ff72c0c32db68ef2cecfe08c53ac42a7bf85dd.diff
- debian/patches/series


Changes:

=====================================
debian/changelog
=====================================
@@ -1,5 +1,6 @@
 proftpd-dfsg (1.3.9e~dfsg-2) UNRELEASED; urgency=medium
 
+  * Remove obsolete patches.
   * apply patch for upstream issue #2411.
 
  -- Hilmar Preuße <hille42 at debian.org>  Tue, 27 Oct 2026 21:36:28 +0100


=====================================
debian/patches/04d89957d8ace325ef76fdfab22049df16a40c0b.diff deleted
=====================================
@@ -1,30 +0,0 @@
-From 04d89957d8ace325ef76fdfab22049df16a40c0b Mon Sep 17 00:00:00 2001
-From: TJ Saunders <tj at castaglia.org>
-Date: Tue, 5 May 2026 17:22:18 -0700
-Subject: [PATCH] Issue #2052: It is possible that some note values come from
- client-supplied text, and as such, they should always be escaped as well.
-
----
- contrib/mod_sql.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/contrib/mod_sql.c b/contrib/mod_sql.c
-index 4872f5fa6..bafe175ff 100644
---- a/contrib/mod_sql.c
-+++ b/contrib/mod_sql.c
-@@ -987,6 +987,7 @@ static int sql_resolve_on_meta(pool *p, pr_jot_ctx_t *jot_ctx,
-       case LOGFMT_META_FILENAME:
-       case LOGFMT_META_IDENT_USER:
-       case LOGFMT_META_METHOD:
-+      case LOGFMT_META_NOTE_VAR:
-       case LOGFMT_META_ORIGINAL_USER:
-       case LOGFMT_META_RESPONSE_STR:
-       case LOGFMT_META_REMOTE_HOST:
-@@ -1016,7 +1017,6 @@ static int sql_resolve_on_meta(pool *p, pr_jot_ctx_t *jot_ctx,
-       case LOGFMT_META_LOCAL_FQDN:
-       case LOGFMT_META_LOCAL_IP:
-       case LOGFMT_META_LOCAL_NAME:
--      case LOGFMT_META_NOTE_VAR:
-       case LOGFMT_META_PROTOCOL:
-       case LOGFMT_META_REMOTE_IP:
-       case LOGFMT_META_VERSION:


=====================================
debian/patches/07797aba88dca902da7eaf1dfe262c8896943de7.diff deleted
=====================================
@@ -1,103 +0,0 @@
-From 07797aba88dca902da7eaf1dfe262c8896943de7 Mon Sep 17 00:00:00 2001
-From: TJ Saunders <tj at castaglia.org>
-Date: Tue, 5 May 2026 09:56:33 -0700
-Subject: [PATCH] Issue #2057: Properly escape the "name" provided when doing
- SQL lookups for allowed/denied client IP addresses or DNS names.
-
----
- contrib/mod_wrap2_sql.c | 49 +++++++++++++++++++++++++++++++++++++----
- 1 file changed, 45 insertions(+), 4 deletions(-)
-
-diff --git a/contrib/mod_wrap2_sql.c b/contrib/mod_wrap2_sql.c
-index eaf6ea7dc5..d4fd56e699 100644
---- a/contrib/mod_wrap2_sql.c
-+++ b/contrib/mod_wrap2_sql.c
-@@ -1,7 +1,7 @@
- /*
-  * ProFTPD: mod_wrap2_sql -- a mod_wrap2 sub-module for supplying IP-based
-  *                           access control data via SQL tables
-- * Copyright (c) 2002-2016 TJ Saunders
-+ * Copyright (c) 2002-2026 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
-@@ -25,7 +25,7 @@
- #include "mod_wrap2.h"
- #include "mod_sql.h"
- 
--#define MOD_WRAP2_SQL_VERSION		"mod_wrap2_sql/1.0"
-+#define MOD_WRAP2_SQL_VERSION		"mod_wrap2_sql/1.1"
- 
- #define WRAP2_SQL_NSLOTS		2
- #define WRAP2_SQL_CLIENT_QUERY_IDX	0
-@@ -62,6 +62,41 @@ static int sqltab_close_cb(wrap2_table_t *sqltab) {
-   return 0;
- }
- 
-+static char *sqltab_get_escaped_text(pool *p, wrap2_table_t *sqltab,
-+    const char *text) {
-+  pool *tmp_pool = NULL;
-+  cmdtable *sql_cmdtab = NULL;
-+  cmd_rec *sql_cmd = NULL;
-+  modret_t *sql_res = NULL;
-+
-+  /* Find the cmdtable for the sql_escapestr command, as the provided
-+   * name needs to be properly escaped for SQL syntax; see Issue #2057.
-+   */
-+  sql_cmdtab = pr_stash_get_symbol2(PR_SYM_HOOK, "sql_escapestr", NULL, NULL,
-+    NULL);
-+  if (sql_cmdtab == NULL) {
-+    wrap2_log("error: unable to find SQL hook symbol 'sql_escapestr': "
-+      "perhaps your proftpd.conf needs 'LoadModule mod_sql.c'?");
-+    return NULL;
-+  }
-+
-+  sql_cmd = sql_cmd_create(tmp_pool, 1, text);
-+  sql_res = pr_module_call(sql_cmdtab->m, sql_cmdtab->handler, sql_cmd);
-+  if (sql_res == NULL) {
-+    wrap2_log("sql_escapestr '%s' returned no data; "
-+      "see the mod_sql.c SQLLogFile for more details", text);
-+    return NULL;
-+  }
-+
-+  if (MODRET_ISERROR(sql_res)) {
-+    wrap2_log("error processing sql_escapestr '%s': "
-+      "check the mod_sql.c SQLLogFile for more details", text);
-+    return NULL;
-+  }
-+
-+  return sql_res->data;
-+}
-+
- static array_header *sqltab_fetch_clients_cb(wrap2_table_t *sqltab,
-     const char *name) {
-   register unsigned int i;
-@@ -70,12 +105,18 @@ static array_header *sqltab_fetch_clients_cb(wrap2_table_t *sqltab,
-   cmd_rec *sql_cmd = NULL;
-   modret_t *sql_res = NULL;
-   array_header *sql_data = NULL;
--  char *query = NULL, **vals = NULL;
-+  char *escaped_name = NULL, *query = NULL, **vals = NULL;
-   array_header *clients_list = NULL;
- 
-   /* Allocate a temporary pool for the duration of this read. */
-   tmp_pool = make_sub_pool(sqltab->tab_pool);
- 
-+  escaped_name = sqltab_get_escaped_text(tmp_pool, sqltab, name);
-+  if (escaped_name == NULL) {
-+    destroy_pool(tmp_pool);
-+    return NULL;
-+  }
-+
-   query = ((char **) sqltab->tab_data)[WRAP2_SQL_CLIENT_QUERY_IDX];
- 
-   /* Find the cmdtable for the sql_lookup command. */
-@@ -89,7 +130,7 @@ static array_header *sqltab_fetch_clients_cb(wrap2_table_t *sqltab,
-   }
- 
-   /* Prepare the SELECT query. */
--  sql_cmd = sql_cmd_create(tmp_pool, 3, "sql_lookup", query, name);
-+  sql_cmd = sql_cmd_create(tmp_pool, 3, "sql_lookup", query, escaped_name);
- 
-   /* Call the handler. */
-   sql_res = pr_module_call(sql_cmdtab->m, sql_cmdtab->handler, sql_cmd);


=====================================
debian/patches/1a5ce6467756e92f42f89c53f0f370dc0f0206d7.diff deleted
=====================================
@@ -1,27 +0,0 @@
-From 1a5ce6467756e92f42f89c53f0f370dc0f0206d7 Mon Sep 17 00:00:00 2001
-From: TJ Saunders <tj at castaglia.org>
-Date: Tue, 19 May 2026 08:01:11 -0700
-Subject: [PATCH] Issue #2052: Address another avenue for SQL injection, via
- custom SQLUserInfo queries.
-
----
- contrib/mod_sql.c | 5 ++++-
- 1 file changed, 4 insertions(+), 1 deletion(-)
-
-diff --git a/contrib/mod_sql.c b/contrib/mod_sql.c
-index b90725942..d28b483d1 100644
---- a/contrib/mod_sql.c
-+++ b/contrib/mod_sql.c
-@@ -1999,8 +1999,11 @@ static struct passwd *sql_getpasswd(cmd_rec *cmd, struct passwd *p) {
-       }
- 
-     } else {
-+      /* The username has been escaped according to the backend database' rules
-+       * at this point.
-+       */
-       mr = sql_lookup(sql_make_cmd(cmd->tmp_pool, 3, MOD_SQL_DEF_CONN_NAME,
--        cmap.usercustom, realname ? realname : "NULL"));
-+        cmap.usercustom, username ? username : "NULL"));
- 
-       if (check_response(mr, 0) < 0) {
-         return NULL;


=====================================
debian/patches/2148.diff deleted
=====================================
@@ -1,43 +0,0 @@
-From 7d11db17726fc468a7af0caff2a3b735604f8257 Mon Sep 17 00:00:00 2001
-From: TJ Saunders <tj at castaglia.org>
-Date: Fri, 12 Jun 2026 12:26:30 -0700
-Subject: [PATCH] Issue #2143: Fix an implicit dependency ordering issue with
- the mod_auth_otp Makefile when building its `auth-otp` command-line
- executable.
-
----
- contrib/mod_auth_otp/Makefile.in | 7 ++++++-
- 1 file changed, 6 insertions(+), 1 deletion(-)
-
-diff --git a/contrib/mod_auth_otp/Makefile.in b/contrib/mod_auth_otp/Makefile.in
-index 4026969f0e..8d8776c0ae 100644
---- a/contrib/mod_auth_otp/Makefile.in
-+++ b/contrib/mod_auth_otp/Makefile.in
-@@ -17,7 +17,7 @@ MODULE_NAME=mod_auth_otp
- MODULE_OBJS=mod_auth_otp.o base32.o otp.o crypto.o db.o
- SHARED_MODULE_OBJS=mod_auth_otp.lo base32.lo otp.lo crypto.lo db.lo
- UTILS_LIBS=@UTILS_LIBS@
--UTILS_OBJS=base32.o otp.o crypto.o auth-otp.o
-+UTILS_OBJS=utils/base32.o utils/otp.o utils/crypto.o auth-otp.o
- UTILS_API_OBJS=../../src/pool.o \
-   ../../src/str.o \
-   ../../lib/prbase.a
-@@ -33,6 +33,10 @@ LDFLAGS=-L../../lib @LDFLAGS@
- .c.lo:
- 	$(LIBTOOL) --mode=compile --tag=CC $(CC) $(CPPFLAGS) $(CFLAGS) $(SHARED_CFLAGS) -c $<
- 
-+utils/%.o: %.c
-+	-mkdir -p utils/
-+	$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
-+
- shared: $(SHARED_MODULE_OBJS) auth-otp$(EXEEXT)
- 	$(LIBTOOL) --mode=link --tag=CC $(CC) -o $(MODULE_NAME).la $(SHARED_MODULE_OBJS) -rpath $(LIBEXECDIR) $(LDFLAGS) $(SHARED_LDFLAGS) $(SHARED_MODULE_LIBS) `cat $(top_srcdir)/$(MODULE_NAME).c | grep '$$Libraries:' | sed -e 's/^.*\$$Libraries: \(.*\)\\$$/\1/'`
- 
-@@ -68,6 +72,7 @@ install-utils: $(DESTDIR)$(sbindir)
- clean:
- 	$(LIBTOOL) --mode=clean $(RM) $(MODULE_NAME).a $(MODULE_NAME).la *.o *.lo .libs/*.o
- 	-$(RM) auth-otp$(EXEEXT)
-+	-$(RM) -r utils/
- 
- distclean: clean
- 	$(RM) Makefile t/Makefile $(MODULE_NAME).h config.status config.cache config.log *.gcda *.gcno


=====================================
debian/patches/3d3a936b696d73f24a7f1a99bf7aa26735ff2306.diff deleted
=====================================
@@ -1,66 +0,0 @@
-From 3d3a936b696d73f24a7f1a99bf7aa26735ff2306 Mon Sep 17 00:00:00 2001
-From: Samuel Thibault <samuel.thibault at ens-lyon.org>
-Date: Wed, 27 Aug 2025 16:20:02 +0200
-Subject: [PATCH] Fix GNU/Hurd build (#1975)
-Origin: https://github.com/proftpd/proftpd/commit/3d3a936b696d73f24a7f1a99bf7aa26735ff2306
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-GNU/Hurd uses the same glibc as Linux, and as such also follows posix by
-making the 2nd parameter of iconv() a char**.
-
-Otherwise, we get:
-```
-encode.c: In function ‘str_convert’:
-encode.c:71:25: error: passing argument 2 of ‘iconv’ from incompatible pointer type [-Wincompatible-pointer-types]
-   71 |     nconv = iconv(conv, &inbuf, inbuflen, &outbuf, outbuflen);
-      |                         ^~~~~~
-      |                         |
-      |                         const char **
-In file included from encode.c:32:
-/usr/include/iconv.h:49:54: note: expected ‘char ** restrict’ but argument is of type ‘const char **’
-   49 | extern size_t iconv (iconv_t __cd, char **__restrict __inbuf,
-      |                                    ~~~~~~~~~~~~~~~~~~^~~~~~~
-```
----
- contrib/mod_sftp/utf8.c | 4 ++--
- src/encode.c            | 4 ++--
- 2 files changed, 4 insertions(+), 4 deletions(-)
-
-diff --git a/contrib/mod_sftp/utf8.c b/contrib/mod_sftp/utf8.c
-index d8078239b..021aa2739 100644
---- a/contrib/mod_sftp/utf8.c
-+++ b/contrib/mod_sftp/utf8.c
-@@ -52,11 +52,11 @@ static int utf8_convert(iconv_t conv, const char *inbuf, size_t *inbuflen,
-     pr_signals_handle();
- 
-     /* Solaris/FreeBSD's iconv(3) takes a const char ** for the input buffer,
--     * whereas Linux/Mac OSX iconv(3) use char ** for the input buffer.
-+     * whereas Linux/Mac OSX/GNU iconv(3) use char ** for the input buffer.
-      */
- #if defined(LINUX) || defined(DARWIN6) || defined(DARWIN7) || \
-     defined(DARWIN8) || defined(DARWIN9) || defined(DARWIN10) || \
--    defined(DARWIN11) || defined(DARWIN12)
-+    defined(DARWIN11) || defined(DARWIN12) || defined(GNU)
- 
-     nconv = iconv(conv, (char **) &inbuf, inbuflen, &outbuf, outbuflen);
- #else
-diff --git a/src/encode.c b/src/encode.c
-index 245b2d43a..3af7fad50 100644
---- a/src/encode.c
-+++ b/src/encode.c
-@@ -60,11 +60,11 @@ static int str_convert(iconv_t conv, const char *inbuf, size_t *inbuflen,
-     pr_signals_handle();
- 
-     /* Solaris/FreeBSD's iconv(3) takes a const char ** for the input buffer,
--     * whereas Linux/Mac OSX iconv(3) use char ** for the input buffer.
-+     * whereas Linux/Mac OSX/GNU iconv(3) use char ** for the input buffer.
-      */
- #if defined(LINUX) || defined(DARWIN6) || defined(DARWIN7) || \
-     defined(DARWIN8) || defined(DARWIN9) || defined(DARWIN10) || \
--    defined(DARWIN11) || defined(DARWIN12)
-+    defined(DARWIN11) || defined(DARWIN12) || defined(GNU)
- 
-     nconv = iconv(conv, (char **) &inbuf, inbuflen, &outbuf, outbuflen);
- #else


=====================================
debian/patches/415395b795436ae47cc25b2394e80033b80f11be.diff deleted
=====================================
@@ -1,195 +0,0 @@
-From 415395b795436ae47cc25b2394e80033b80f11be Mon Sep 17 00:00:00 2001
-From: TJ Saunders <tj at castaglia.org>
-Date: Mon, 27 Apr 2026 12:13:09 -0700
-Subject: [PATCH] Issue #2052: When resolving any variable whose value is
- supplied by the client, make sure we **always** escape that value text.
-
----
- contrib/mod_sql.c | 103 ++++++++++++++++++++++++++++------------------
- 1 file changed, 64 insertions(+), 39 deletions(-)
-
-diff --git a/contrib/mod_sql.c b/contrib/mod_sql.c
-index 4978b38b70..4872f5fa64 100644
---- a/contrib/mod_sql.c
-+++ b/contrib/mod_sql.c
-@@ -2,7 +2,7 @@
-  * ProFTPD: mod_sql -- SQL frontend
-  * Copyright (c) 1998-1999 Johnie Ingram.
-  * Copyright (c) 2001 Andrew Houghton.
-- * Copyright (c) 2004-2025 TJ Saunders
-+ * Copyright (c) 2004-2026 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
-@@ -759,40 +759,46 @@ static int is_escaped_text(const char *text, size_t text_len) {
- }
- 
- static int sql_resolved_append_text(pool *p, struct sql_resolved *resolved,
--    const char *text, size_t text_len) {
--  char *new_text;
--  size_t new_textlen;
-+    const char *text, size_t text_len, int already_escaped) {
-+  char *new_text = NULL;
-+  size_t new_textlen = 0;
- 
-   if (text == NULL ||
-       text_len == 0) {
-     return 0;
-   }
- 
--  /* For backward compatibility (see Issue #1149), we indulge in a little
--   * heuristic here, and only escape the text if it hasn't already been
--   * escaped.  How to properly tell?  If the first and last characters of
--   * the given text are `'`, AND there are no other occurrences of that
--   * character in the text, assume it has already been quoted.
--   */
--  if (is_escaped_text(text, text_len) == FALSE) {
--    modret_t *mr;
-+  new_text = (char *) text;
-+  new_textlen = text_len;
- 
--    mr = sql_dispatch(sql_make_cmd(p, 2, resolved->conn_name, text),
--      "sql_escapestring");
--    if (check_response(mr, resolved->conn_flags) < 0) {
--      errno = EIO;
--      return -1;
--    }
-+  if (already_escaped == FALSE) {
-+    /* For backward compatibility (see Issue #1149), we indulge in a little
-+     * heuristic here, and only escape the text if it hasn't already been
-+     * escaped.  How to properly tell?  If the first and last characters of
-+     * the given text are `'`, AND there are no other occurrences of that
-+     * character in the text, assume it has already been quoted.
-+     *
-+     * Per Issue #2052, we refine this to use this heuristic only if we do
-+     * not already know that the text has been escaped.  Some callers may
-+     * have already escaped the provided text for us.
-+     */
-+    if (is_escaped_text(text, text_len) == FALSE) {
-+      modret_t *mr;
- 
--    new_text = (char *) mr->data;
--    new_textlen = strlen(new_text);
-+      mr = sql_dispatch(sql_make_cmd(p, 2, resolved->conn_name, text),
-+        "sql_escapestring");
-+      if (check_response(mr, resolved->conn_flags) < 0) {
-+        errno = EIO;
-+        return -1;
-+      }
- 
--  } else {
--    pr_trace_msg(trace_channel, 17,
--      "text '%s' is already escaped, skipping escaping it again", text);
-+      new_text = (char *) mr->data;
-+      new_textlen = strlen(new_text);
- 
--    new_text = (char *) text;
--    new_textlen = text_len;
-+    } else {
-+      pr_trace_msg(trace_channel, 17,
-+        "text '%s' is already escaped, skipping escaping it again", text);
-+    }
-   }
- 
-   if (new_textlen > resolved->buflen) {
-@@ -810,7 +816,7 @@ static int sql_resolved_append_text(pool *p, struct sql_resolved *resolved,
- 
- static int sql_resolve_on_meta(pool *p, pr_jot_ctx_t *jot_ctx,
-     unsigned char logfmt_id, const char *jot_hint, const void *val) {
--  int res = 0;
-+  int res = 0, already_escaped = FALSE;
-   struct sql_resolved *resolved;
- 
-   resolved = jot_ctx->log;
-@@ -969,35 +975,53 @@ static int sql_resolve_on_meta(pool *p, pr_jot_ctx_t *jot_ctx,
-         break;
-       }
- 
-+      /* Per Issue #2052, the following variable values can all be supplied
-+       * remotely by the client.  As such, they should be escaped preemptively.
-+       */
-       case LOGFMT_META_ANON_PASS:
-       case LOGFMT_META_BASENAME:
--      case LOGFMT_META_CLASS:
-       case LOGFMT_META_CMD_PARAMS:
-       case LOGFMT_META_COMMAND:
-       case LOGFMT_META_DIR_NAME:
-       case LOGFMT_META_DIR_PATH:
-+      case LOGFMT_META_FILENAME:
-+      case LOGFMT_META_IDENT_USER:
-+      case LOGFMT_META_METHOD:
-+      case LOGFMT_META_ORIGINAL_USER:
-+      case LOGFMT_META_RESPONSE_STR:
-+      case LOGFMT_META_REMOTE_HOST:
-+      case LOGFMT_META_RENAME_FROM:
-+      case LOGFMT_META_USER:
-+      case LOGFMT_META_XFER_PATH: {
-+        modret_t *mr;
-+
-+        mr = sql_dispatch(sql_make_cmd(p, 2, resolved->conn_name,
-+          (const char *) val), "sql_escapestring");
-+        if (check_response(mr, resolved->conn_flags) < 0) {
-+          errno = EIO;
-+          return -1;
-+        }
-+
-+        text = (char *) mr->data;
-+        text_len = strlen(text);
-+        already_escaped = TRUE;
-+        break;
-+      }
-+
-+      case LOGFMT_META_CLASS:
-       case LOGFMT_META_ENV_VAR:
-       case LOGFMT_META_EOS_REASON:
--      case LOGFMT_META_FILENAME:
-       case LOGFMT_META_GROUP:
--      case LOGFMT_META_IDENT_USER:
-       case LOGFMT_META_ISO8601:
-       case LOGFMT_META_LOCAL_FQDN:
-       case LOGFMT_META_LOCAL_IP:
-       case LOGFMT_META_LOCAL_NAME:
--      case LOGFMT_META_METHOD:
-       case LOGFMT_META_NOTE_VAR:
--      case LOGFMT_META_ORIGINAL_USER:
-       case LOGFMT_META_PROTOCOL:
--      case LOGFMT_META_REMOTE_HOST:
-       case LOGFMT_META_REMOTE_IP:
--      case LOGFMT_META_RENAME_FROM:
--      case LOGFMT_META_RESPONSE_STR:
--      case LOGFMT_META_USER:
-       case LOGFMT_META_VERSION:
-       case LOGFMT_META_VHOST_IP:
-       case LOGFMT_META_XFER_FAILURE:
--      case LOGFMT_META_XFER_PATH:
-       case LOGFMT_META_XFER_SPEED:
-       case LOGFMT_META_XFER_STATUS:
-       case LOGFMT_META_XFER_TYPE:
-@@ -1011,7 +1035,8 @@ static int sql_resolve_on_meta(pool *p, pr_jot_ctx_t *jot_ctx,
-       text_len = strlen(text);
-     }
- 
--    res = sql_resolved_append_text(p, resolved, text, text_len);
-+    res = sql_resolved_append_text(p, resolved, text, text_len,
-+      already_escaped);
-   }
- 
-   return res;
-@@ -1074,7 +1099,7 @@ static int sql_resolve_on_default(pool *p, pr_jot_ctx_t *jot_ctx,
-         break;
-     }
- 
--    res = sql_resolved_append_text(p, resolved, text, text_len);
-+    res = sql_resolved_append_text(p, resolved, text, text_len, FALSE);
-   }
- 
-   return res;
-@@ -3177,7 +3202,7 @@ static int showinfo_on_meta(pool *p, pr_jot_ctx_t *jot_ctx,
-       }
- 
-       text_len = strlen(text);
--      res = sql_resolved_append_text(p, resolved, text, text_len);
-+      res = sql_resolved_append_text(p, resolved, text, text_len, FALSE);
- 
-     } else {
-       res = sql_resolve_on_meta(p, jot_ctx, logfmt_id, jot_hint, val);


=====================================
debian/patches/508eb4d1b8c550b5f3059ad5b33d60c6b6c76bc7.diff deleted
=====================================
@@ -1,41 +0,0 @@
-From 508eb4d1b8c550b5f3059ad5b33d60c6b6c76bc7 Mon Sep 17 00:00:00 2001
-From: TJ Saunders <tj at castaglia.org>
-Date: Sun, 10 May 2026 09:37:17 -0700
-Subject: [PATCH] Issue #2056: Initial testing with OpenSSL 3.5.5 shows that
- the prior changes for Issue #1963 were insufficient; adding a manual refcount
- increment works.
-
----
- contrib/mod_tls.c | 18 ++++++++++++++++--
- 1 file changed, 16 insertions(+), 2 deletions(-)
-
-diff --git a/contrib/mod_tls.c b/contrib/mod_tls.c
-index e78e4c17b..fede5b8cd 100644
---- a/contrib/mod_tls.c
-+++ b/contrib/mod_tls.c
-@@ -9095,9 +9095,23 @@ static void tls_end_sess(SSL *ssl, conn_t *conn, int flags) {
-      */
-     pr_trace_msg(trace_channel, 29,
-       "data SSL %p being ended has same SSL_SESSION %p as control SSL, "
--      "clearing the data SSL pointer manually (Issue #1963)", ssl,
-+      "clearing the data SSL pointer manually (see Issue #1963)", ssl,
-       SSL_get_session(ssl));
--    SSL_set_session(ssl, NULL);
-+    if (SSL_set_session(ssl, NULL) != 1) {
-+      pr_trace_msg(trace_channel, 29,
-+        "error setting NULL session on SSL %p: %s", ssl, tls_get_errors());
-+    }
-+
-+    /* Note that, per findings in Issue #2056, we also need to manually
-+     * increment the refcount of the ctrl_ssl session, lest we still
-+     * inadvertently corrupt the OpenSSL internal session cache state.
-+     * Sigh.
-+     */
-+    if (SSL_SESSION_up_ref(SSL_get_session(ctrl_ssl)) != 1) {
-+      pr_trace_msg(trace_channel, 29,
-+        "error incrementing session refcount on SSL %p: %s", ctrl_ssl,
-+        tls_get_errors());
-+    }
-   }
- 
-   SSL_free(ssl);


=====================================
debian/patches/536608f849dddd2b551e7c1e4fd930a50a527ffe.diff deleted
=====================================
@@ -1,962 +0,0 @@
-From 536608f849dddd2b551e7c1e4fd930a50a527ffe Mon Sep 17 00:00:00 2001
-From: TJ Saunders <tj at castaglia.org>
-Date: Sun, 23 Mar 2025 12:47:04 -0700
-Subject: [PATCH] Issue #1886: Fix the handling of SCP target paths that might
- contain spaces.
-Origin: https://github.com/proftpd/proftpd/commit/b8acdd8754a0dbb13af105c9ffe98e9be4118bbc
-
----
- contrib/mod_sftp/scp.c                        | 229 +++++-----
- tests/t/lib/ProFTPD/Tests/Modules/mod_sftp.pm | 399 +++++++++++++++---
- 2 files changed, 475 insertions(+), 153 deletions(-)
-
-diff --git a/contrib/mod_sftp/scp.c b/contrib/mod_sftp/scp.c
-index 397cea41c..ea8154343 100644
---- a/contrib/mod_sftp/scp.c
-+++ b/contrib/mod_sftp/scp.c
-@@ -1,6 +1,6 @@
- /*
-  * ProFTPD - mod_sftp SCP
-- * Copyright (c) 2008-2023 TJ Saunders
-+ * Copyright (c) 2008-2025 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
-@@ -2458,13 +2458,36 @@ int sftp_scp_handle_packet(pool *p, void *ssh2, uint32_t channel_id,
-   return 0;
- }
- 
-+static char *scp_canonicalize_target(pool *p, char *target) {
-+  size_t target_len;
-+
-+  target_len = strlen(target);
-+
-+  /* Remove any enclosing shell quotations, e.g. single and double quotation
-+   * marks.  Some SCP clients (i.e. newer libssh2) will quote the paths,
-+   * assuming that the handling server (us) uses a shell to handle the
-+   * command.  Sigh.
-+   */
-+
-+  if ((target[0] == '\'' &&
-+       target[target_len-1] == '\'') ||
-+      (target[0] == '"' &&
-+       target[target_len-1] == '"')) {
-+    target[target_len-1] = '\0';
-+    return pstrdup(p, target + 1);
-+  }
-+
-+  return target;
-+}
-+
- int sftp_scp_set_params(pool *p, uint32_t channel_id, array_header *req) {
-   register unsigned int i;
-   int optc, use_glob = TRUE;
--  char **reqargv;
-+  char **reqargv, *target_path = NULL;
-   const char *opts = "dfprtv";
-   config_rec *c;
-   struct scp_paths *paths;
-+  struct scp_path *sp;
- 
-   if (!(sftp_services & SFTP_SERVICE_FL_SCP)) {
-     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
-@@ -2487,13 +2510,13 @@ int sftp_scp_set_params(pool *p, uint32_t channel_id, array_header *req) {
- 
-   reqargv = (char **) req->elts;
-   for (i = 0; i < req->nelts; i++) {
--    if (reqargv[i]) {
-+    if (reqargv[i] != NULL) {
-       pr_trace_msg(trace_channel, 5, "reqargv[%u] = '%s'", i, reqargv[i]);
-     }
-   }
- 
-   c = find_config(main_server->conf, CONF_PARAM, "UseGlobbing", FALSE);
--  if (c) {
-+  if (c != NULL) {
-     use_glob = *((unsigned char *) c->argv[0]);
-   }
- 
-@@ -2546,128 +2569,130 @@ int sftp_scp_set_params(pool *p, uint32_t channel_id, array_header *req) {
-     return -1;
-   }
- 
--  /* Make a copy of the remaining paths, for later handling. */
-+  /* Make a copy of the remaining paths, for later handling.
-+   *
-+   * Normally there's only one path, but we might be handling a glob which
-+   * matches multiple paths.
-+   */
-   paths->paths = make_array(paths->pool, 1, sizeof(struct scp_path *));
-   paths->path_idx = 0;
- 
-+  /* First concatenate any remaining command-line arguments, using spaces,
-+   * in order to handle paths that contain spaces; see Issue #1886.
-+   */
-   for (i = optind; i < req->nelts; i++) {
-     pr_signals_handle();
- 
--    if (reqargv[i]) {
--      struct scp_path *sp;
--      size_t pathlen;
--      char *glob_path;
-+    if (reqargv[i] != NULL) {
-+      size_t reqarg_len;
- 
--      if (use_glob &&
--          (scp_opts & SFTP_SCP_OPT_ISSRC) &&
--          strpbrk(reqargv[i], "{[*?") != NULL) {
--        int res, xerrno;
--        glob_t gl;
-+      /* Note that we might be dealing with an empty-length argument, which
-+       * we get from pr_str_get_word() parsing the client-provided string,
-+       * which might have spaces.  Watch for them.
-+       */
- 
--        /* Whee, glob characters.  Need to expand the pattern to the
--         * list of matching files, just as the shell would do.
--         */
-+      reqarg_len = strlen(reqargv[i]);
-+      if (reqarg_len == 0) {
-+        continue;
-+      }
- 
--        memset(&gl, 0, sizeof(gl));
-+      if (target_path != NULL) {
-+        target_path = pstrcat(p, target_path, " ", reqargv[i], NULL);
- 
--        glob_path = pstrdup(paths->pool, reqargv[i]);
--        pathlen = strlen(glob_path);
-+      } else {
-+        target_path = pstrdup(p, reqargv[i]);
-+      }
-+    }
-+  }
- 
--        /* Remove any enclosing shell quotations, e.g. single and double
--         * quotation marks.  Some SCP clients (i.e. newer libssh2) will
--         * quote the paths, assuming that the handling server (us) uses
--         * a shell to handle the command.  Sigh.
--         */
--        if ((glob_path[0] == '\'' &&
--             glob_path[pathlen-1] == '\'') ||
--            (glob_path[0] == '"' &&
--             glob_path[pathlen-1] == '"')) {
--          glob_path[pathlen-1] = '\0';
--          glob_path = (glob_path + 1);
--        }
-+  target_path = scp_canonicalize_target(p, target_path);
- 
--        res = pr_fs_glob(glob_path, GLOB_NOSORT|GLOB_BRACE, NULL, &gl);
--        switch (res) {
--          case 0: {
--            register unsigned int j;
-+  if (use_glob == TRUE &&
-+      (scp_opts & SFTP_SCP_OPT_ISSRC) &&
-+      strpbrk(target_path, "{[*?") != NULL) {
-+    int res, xerrno;
-+    char *glob_path;
-+    size_t path_len;
-+    glob_t gl;
- 
--            for (j = 0; j < gl.gl_pathc; j++) {
--              pr_signals_handle();
-+    /* Whee, glob characters.  Need to expand the pattern to the
-+     * list of matching files, just as the shell would do.
-+     */
- 
--              sp = pcalloc(paths->pool, sizeof(struct scp_path));
--              sp->path = pstrdup(paths->pool, gl.gl_pathv[j]);
--              pathlen = strlen(sp->path);
-+    memset(&gl, 0, sizeof(gl));
- 
--              /* Trim any trailing path separators.  It's important. */
--              while (pathlen > 1 &&
--                     sp->path[pathlen-1] == '/') {
--                pr_signals_handle();
--                sp->path[--pathlen] = '\0';
--              }
-+    glob_path = pstrdup(paths->pool, target_path);
-+    path_len = strlen(glob_path);
- 
--              sp->orig_path = pstrdup(paths->pool, sp->path);
-+    res = pr_fs_glob(glob_path, GLOB_NOSORT|GLOB_BRACE, NULL, &gl);
-+    switch (res) {
-+      case 0: {
-+        register unsigned int j;
- 
--              if (pathlen > 0) {
--                *((struct scp_path **) push_array(paths->paths)) = sp;
--              }
--            }
-+        for (j = 0; j < gl.gl_pathc; j++) {
-+          pr_signals_handle();
- 
--            break;
-+          sp = pcalloc(paths->pool, sizeof(struct scp_path));
-+          sp->path = pstrdup(paths->pool, gl.gl_pathv[j]);
-+          path_len = strlen(sp->path);
-+
-+          /* Trim any trailing path separators.  It's important. */
-+          while (path_len > 1 &&
-+                 sp->path[path_len-1] == '/') {
-+            pr_signals_handle();
-+            sp->path[--path_len] = '\0';
-           }
- 
--          case GLOB_NOSPACE:
--            xerrno = errno;
--            pr_trace_msg(trace_channel, 1, "error globbing '%s': Not "
--              "enough memory (%s)", reqargv[i], strerror(xerrno));
--            write_confirm(p, channel_id, 1, pstrcat(p, reqargv[i], ": ",
--              strerror(xerrno), NULL));
--            errno = xerrno;
--            return 0;
--
--          case GLOB_NOMATCH:
--            xerrno = ENOENT;
--            pr_trace_msg(trace_channel, 1, "error globbing '%s': No "
--              "matches found (%s)", reqargv[i], strerror(xerrno));
--            write_confirm(p, channel_id, 1, pstrcat(p, reqargv[i], ": ",
--              strerror(xerrno), NULL));
--            errno = xerrno;
--            return 0;
-+          sp->orig_path = pstrdup(paths->pool, sp->path);
-+
-+          if (path_len > 0) {
-+            *((struct scp_path **) push_array(paths->paths)) = sp;
-+          }
-         }
- 
--        pr_fs_globfree(&gl);
-+        break;
-+      }
- 
--      } else {
--        sp = pcalloc(paths->pool, sizeof(struct scp_path));
--        sp->path = pstrdup(paths->pool, reqargv[i]);
--        pathlen = strlen(sp->path);
--
--        /* Remove any enclosing shell quotations, e.g. single and double
--         * quotation marks.  Some SCP clients (i.e. newer libssh2) will
--         * quote the paths, assuming that the handling server (us) uses
--         * a shell to handle the command.  Sigh.
--         */
--        if ((sp->path[0] == '\'' &&
--             sp->path[pathlen-1] == '\'') ||
--            (sp->path[0] == '"' &&
--             sp->path[pathlen-1] == '"')) {
--          sp->path[pathlen-1] = '\0';
--          sp->path = (sp->path + 1);
--          pathlen -= 2;
--        }
-+      case GLOB_NOSPACE:
-+        xerrno = errno;
-+        pr_trace_msg(trace_channel, 1, "error globbing '%s': Not "
-+          "enough memory (%s)", reqargv[i], strerror(xerrno));
-+        write_confirm(p, channel_id, 1, pstrcat(p, target_path, ": ",
-+          strerror(xerrno), NULL));
-+        errno = xerrno;
-+        return 0;
- 
--        /* Trim any trailing path separators.  It's important. */
--        while (pathlen > 1 &&
--               sp->path[pathlen-1] == '/') {
--          pr_signals_handle();
--          sp->path[--pathlen] = '\0';
--        }
-+      case GLOB_NOMATCH:
-+        xerrno = ENOENT;
-+        pr_trace_msg(trace_channel, 1, "error globbing '%s': No "
-+          "matches found (%s)", reqargv[i], strerror(xerrno));
-+        write_confirm(p, channel_id, 1, pstrcat(p, target_path, ": ",
-+          strerror(xerrno), NULL));
-+        errno = xerrno;
-+        return 0;
-+    }
- 
--        sp->orig_path = pstrdup(paths->pool, sp->path);
-+    pr_fs_globfree(&gl);
- 
--        if (pathlen > 0) {
--          *((struct scp_path **) push_array(paths->paths)) = sp;
--        }
--      }
-+  } else {
-+    size_t path_len;
-+
-+    sp = pcalloc(paths->pool, sizeof(struct scp_path));
-+    sp->path = pstrdup(paths->pool, target_path);
-+
-+    path_len = strlen(sp->path);
-+
-+    /* Trim any trailing path separators.  It's important. */
-+    while (path_len > 1 &&
-+           sp->path[path_len-1] == '/') {
-+      pr_signals_handle();
-+      sp->path[--path_len] = '\0';
-+    }
-+
-+    sp->orig_path = pstrdup(paths->pool, sp->path);
-+
-+    if (path_len > 0) {
-+      *((struct scp_path **) push_array(paths->paths)) = sp;
-     }
-   }
- 
-@@ -2687,8 +2712,8 @@ int sftp_scp_set_params(pool *p, uint32_t channel_id, array_header *req) {
-     struct scp_path *sp;
- 
-     sp = ((struct scp_path **) paths->paths->elts)[i];
--    if (sp) {
--      pr_trace_msg(trace_channel, 5, "scp_path[%u] = '%s'", i, sp->path);
-+    if (sp != NULL) {
-+      pr_trace_msg(trace_channel, 5, "scp path[%u] = '%s'", i, sp->path);
-     }
-   }
- 
-diff --git a/tests/t/lib/ProFTPD/Tests/Modules/mod_sftp.pm b/tests/t/lib/ProFTPD/Tests/Modules/mod_sftp.pm
-index be37f1eb3..c445399ff 100644
---- a/tests/t/lib/ProFTPD/Tests/Modules/mod_sftp.pm
-+++ b/tests/t/lib/ProFTPD/Tests/Modules/mod_sftp.pm
-@@ -1676,6 +1676,11 @@ my $TESTS = {
-     test_class => [qw(forking scp ssh2)],
-   },
- 
-+  scp_upload_filename_with_spaces_issue1886 => {
-+    order => ++$order,
-+    test_class => [qw(bug forking scp ssh2)],
-+  },
-+
-   scp_upload_abs_symlink => {
-     order => ++$order,
-     test_class => [qw(forking scp ssh2)],
-@@ -1806,6 +1811,11 @@ my $TESTS = {
-     test_class => [qw(bug forking rootprivs scp ssh2)],
-   },
- 
-+  scp_download_filename_with_spaces_issue1886 => {
-+    order => ++$order,
-+    test_class => [qw(bug forking scp ssh2)],
-+  },
-+
-   scp_ext_download_bug3544 => {
-     order => ++$order,
-     test_class => [qw(bug forking scp ssh2)],
-@@ -56731,6 +56741,166 @@ sub scp_upload_largefile {
-   test_cleanup($setup->{log_file}, $ex);
- }
- 
-+sub scp_upload_filename_with_spaces_issue1886 {
-+  my $self = shift;
-+  my $tmpdir = $self->{tmpdir};
-+  my $setup = test_setup($tmpdir, 'scp');
-+
-+  my $src_file = File::Spec->rel2abs("$tmpdir/src.txt");
-+  if (open(my $fh, "> $src_file")) {
-+    print $fh "ABCDefgh" x 32;
-+    unless (close($fh)) {
-+      die("Can't write $src_file: $!");
-+    }
-+
-+  } else {
-+    die("Can't open $src_file: $!");
-+  }
-+
-+  # Calculate the MD5 checksum of this file, for comparison with the
-+  # downloaded file.
-+  my $ctx = Digest::MD5->new();
-+  my $expected_md5;
-+
-+  if (open(my $fh, "< $src_file")) {
-+    binmode($fh);
-+    $ctx->addfile($fh);
-+    $expected_md5 = $ctx->hexdigest();
-+    close($fh);
-+
-+  } else {
-+    die("Can't read $src_file: $!");
-+  }
-+
-+  my $dst_file = File::Spec->rel2abs("$tmpdir/test filename with spaces.txt");
-+
-+  my $rsa_host_key = File::Spec->rel2abs('t/etc/modules/mod_sftp/ssh_host_rsa_key');
-+  my $dsa_host_key = File::Spec->rel2abs('t/etc/modules/mod_sftp/ssh_host_dsa_key');
-+
-+  my $config = {
-+    PidFile => $setup->{pid_file},
-+    ScoreboardFile => $setup->{scoreboard_file},
-+    SystemLog => $setup->{log_file},
-+    TraceLog => $setup->{log_file},
-+    Trace => 'ssh2:10 scp:30',
-+
-+    AuthUserFile => $setup->{auth_user_file},
-+    AuthGroupFile => $setup->{auth_group_file},
-+    AuthOrder => 'mod_auth_file.c',
-+
-+    IfModules => {
-+      'mod_delay.c' => {
-+        DelayEngine => 'off',
-+      },
-+
-+      'mod_sftp.c' => [
-+        "SFTPEngine on",
-+        "SFTPLog $setup->{log_file}",
-+        "SFTPHostKey $rsa_host_key",
-+        "SFTPHostKey $dsa_host_key",
-+      ],
-+    },
-+  };
-+
-+  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: $!");
-+  }
-+
-+  require Net::SSH2;
-+
-+  my $ex;
-+
-+  # Ignore SIGPIPE
-+  local $SIG{PIPE} = sub { };
-+
-+  # Fork child
-+  $self->handle_sigchld();
-+  defined(my $pid = fork()) or die("Can't fork: $!");
-+  if ($pid) {
-+    eval {
-+      my $ssh2 = Net::SSH2->new();
-+
-+      sleep(1);
-+
-+      unless ($ssh2->connect('127.0.0.1', $port)) {
-+        my ($err_code, $err_name, $err_str) = $ssh2->error();
-+        die("Can't connect to SSH2 server: [$err_name] ($err_code) $err_str");
-+      }
-+
-+      unless ($ssh2->auth_password($setup->{user}, $setup->{passwd})) {
-+        my ($err_code, $err_name, $err_str) = $ssh2->error();
-+        die("Can't login to SSH2 server: [$err_name] ($err_code) $err_str");
-+      }
-+
-+      my $res = $ssh2->scp_put($src_file, 'test filename with spaces.txt');
-+      unless ($res) {
-+        my ($err_code, $err_name, $err_str) = $ssh2->error();
-+        die("Can't upload to server: [$err_name] ($err_code) $err_str");
-+      }
-+
-+      $ssh2->disconnect();
-+
-+      $self->assert(-f $dst_file,
-+        test_msg("File '$dst_file' does not exist as expected"));
-+    };
-+    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);
-+
-+  if ($ex) {
-+    test_cleanup($setup->{log_file}, $ex);
-+  }
-+
-+  # Calculate the MD5 checksum of the uploaded file, for comparison with the
-+  # file that was uploaded.
-+  $ctx->reset();
-+  my $md5;
-+
-+  eval {
-+    if (open(my $fh, "< $dst_file")) {
-+      binmode($fh);
-+      $ctx->addfile($fh);
-+      $md5 = $ctx->hexdigest();
-+      close($fh);
-+
-+    } else {
-+      die("Can't read $dst_file: $!");
-+    }
-+
-+    $self->assert($expected_md5 eq $md5,
-+      test_msg("Expected '$expected_md5', got '$md5'"));
-+  };
-+  if ($@) {
-+    $ex = $@;
-+  }
-+
-+  test_cleanup($setup->{log_file}, $ex);
-+}
-+
- sub scp_upload_abs_symlink {
-   my $self = shift;
-   my $tmpdir = $self->{tmpdir};
-@@ -58019,7 +58189,8 @@ sub scp_ext_null_ptr_issue1043 {
-         '-oStrictHostKeyChecking=no',
-         '-oUserKnownHostsFile=/dev/null',
-         "$setup->{user}\@127.0.0.1",
--        'scp'
-+        'scp',
-+        '-O'
-       );
- 
-       my $scp_rh = IO::Handle->new();
-@@ -58305,6 +58476,7 @@ sub scp_ext_upload_recursive_dir_bug3447 {
-         'scp',
-         '-r',
-         '-v',
-+        '-O',
-         '-oBatchMode=yes',
-         '-oCheckHostIP=no',
-         "-oPort=$port",
-@@ -58606,6 +58778,7 @@ sub scp_ext_upload_recursive_dir_bug3792 {
-         '-r',
-         '-v',
-         '-p',
-+        '-O',
-         '-oBatchMode=yes',
-         '-oCheckHostIP=no',
-         "-oPort=$port",
-@@ -58922,6 +59095,7 @@ sub scp_ext_upload_recursive_dir_bug4004 {
-         '-r',
-         '-p',
-         '-v',
-+        '-O',
-         '-oBatchMode=yes',
-         '-oCheckHostIP=no',
-         "-oPort=$port",
-@@ -59183,6 +59357,7 @@ sub scp_ext_upload_recursive_dirs_bug4257 {
-         '-r',
-         '-p',
-         '-v',
-+        '-O',
-         '-oBatchMode=yes',
-         '-oCheckHostIP=no',
-         "-oPort=$port",
-@@ -59407,6 +59582,7 @@ sub scp_ext_upload_different_name_bug3425 {
-       my @cmd = (
-         'scp',
-         '-v',
-+        '-O',
-         '-oBatchMode=yes',
-         '-oCheckHostIP=no',
-         "-oPort=$port",
-@@ -59607,6 +59783,7 @@ sub scp_ext_upload_recursive_empty_dir {
-         'scp',
-         '-r',
-         '-v',
-+        '-O',
-         '-oBatchMode=yes',
-         '-oCheckHostIP=no',
-         "-oPort=$port",
-@@ -59830,6 +60007,7 @@ sub scp_ext_upload_shorter_file_bug4013 {
-       my @cmd = (
-         'scp',
-         '-v',
-+        '-O',
-         '-oBatchMode=yes',
-         '-oCheckHostIP=no',
-         "-oPort=$port",
-@@ -59928,22 +60106,7 @@ sub scp_ext_upload_shorter_file_bug4013 {
- sub scp_ext_upload_file_with_timestamp_bug4026 {
-   my $self = shift;
-   my $tmpdir = $self->{tmpdir};
--
--  my $config_file = "$tmpdir/sftp.conf";
--  my $pid_file = File::Spec->rel2abs("$tmpdir/sftp.pid");
--  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sftp.scoreboard");
--
--  my $log_file = test_get_logfile();
--
--  my $auth_user_file = File::Spec->rel2abs("$tmpdir/sftp.passwd");
--  my $auth_group_file = File::Spec->rel2abs("$tmpdir/sftp.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, 'scp');
- 
-   my $sub_dir = File::Spec->rel2abs("$tmpdir/sub.d");
-   mkpath($sub_dir);
-@@ -59951,19 +60114,15 @@ sub scp_ext_upload_file_with_timestamp_bug4026 {
-   # 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_dir)) {
--      die("Can't set perms on $home_dir to 0755: $!");
-+    unless (chmod(0755, $sub_dir)) {
-+      die("Can't set perms on $sub_dir to 0755: $!");
-     }
- 
--    unless (chown($uid, $gid, $home_dir, $sub_dir)) {
--      die("Can't set owner of $home_dir to $uid/$gid: $!");
-+    unless (chown($setup->{uid}, $setup->{gid}, $sub_dir)) {
-+      die("Can't set owner of $sub_dir 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 $rsa_host_key = File::Spec->rel2abs('t/etc/modules/mod_sftp/ssh_host_rsa_key');
-   my $dsa_host_key = File::Spec->rel2abs('t/etc/modules/mod_sftp/ssh_host_dsa_key');
- 
-@@ -59994,18 +60153,18 @@ sub scp_ext_upload_file_with_timestamp_bug4026 {
-   my $dst_file = File::Spec->rel2abs("$sub_dir/dst.txt");
- 
-   my $config = {
--    PidFile => $pid_file,
--    ScoreboardFile => $scoreboard_file,
--    SystemLog => $log_file,
--    TraceLog => $log_file,
--    Trace => 'DEFAULT:10 ssh2:20 sftp:20 scp:20',
-+    PidFile => $setup->{pid_file},
-+    ScoreboardFile => $setup->{scoreboard_file},
-+    SystemLog => $setup->{log_file},
-+    TraceLog => $setup->{log_file},
-+    Trace => 'ssh2:20 sftp:20 scp:20',
- 
--    AuthUserFile => $auth_user_file,
--    AuthGroupFile => $auth_group_file,
-+    AuthUserFile => $setup->{auth_user_file},
-+    AuthGroupFile => $setup->{auth_group_file},
-     AuthOrder => 'mod_auth_file.c',
- 
-     AllowOverwrite => 'on',
--    DefaultRoot => '~',
-+#    DefaultRoot => '~',
- 
-     IfModules => {
-       'mod_delay.c' => {
-@@ -60014,7 +60173,7 @@ sub scp_ext_upload_file_with_timestamp_bug4026 {
- 
-       'mod_sftp.c' => [
-         "SFTPEngine on",
--        "SFTPLog $log_file",
-+        "SFTPLog $setup->{log_file}",
-         "SFTPHostKey $rsa_host_key",
-         "SFTPHostKey $dsa_host_key",
-         "SFTPAuthorizedUserKeys file:~/.authorized_keys",
-@@ -60022,7 +60181,8 @@ sub scp_ext_upload_file_with_timestamp_bug4026 {
-     },
-   };
- 
--  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
-@@ -60046,8 +60206,9 @@ sub scp_ext_upload_file_with_timestamp_bug4026 {
-     eval {
-       my @cmd = (
-         'scp',
--        '-v',
-+        '-vvv',
-         '-p',
-+        '-O',
-         '-oBatchMode=yes',
-         '-oCheckHostIP=no',
-         "-oPort=$port",
-@@ -60056,7 +60217,7 @@ sub scp_ext_upload_file_with_timestamp_bug4026 {
-         '-oStrictHostKeyChecking=no',
-         '-oUserKnownHostsFile=/dev/null',
-         "$src_file",
--        "$user\@127.0.0.1:sub.d/dst.txt",
-+        "$setup->{user}\@127.0.0.1:sub.d/dst.txt",
-       );
- 
-       my $scp_rh = IO::Handle->new();
-@@ -60102,6 +60263,10 @@ sub scp_ext_upload_file_with_timestamp_bug4026 {
-         $res = 1;
-       }
- 
-+if ($ENV{TEST_VERBOSE}) {
-+  print STDERR "# Errstr:\n$errstr\n";
-+}
-+
-       unless ($res == 0) {
-         die("Can't upload $src_file to server: $errstr");
-       }
-@@ -60113,7 +60278,6 @@ sub scp_ext_upload_file_with_timestamp_bug4026 {
-       $self->assert($atime == 0, test_msg("Expected atime 0, got $atime"));
-       $self->assert($mtime == 0, test_msg("Expected mtime 0, got $mtime"));
-     };
--
-     if ($@) {
-       $ex = $@;
-     }
-@@ -60122,7 +60286,7 @@ sub scp_ext_upload_file_with_timestamp_bug4026 {
-     $wfh->flush();
- 
-   } else {
--    eval { server_wait($config_file, $rfh) };
-+    eval { server_wait($setup->{config_file}, $rfh) };
-     if ($@) {
-       warn($@);
-       exit 1;
-@@ -60132,18 +60296,10 @@ sub scp_ext_upload_file_with_timestamp_bug4026 {
-   }
- 
-   # 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 scp_download {
-@@ -60161,7 +60317,7 @@ sub scp_download {
-     ScoreboardFile => $setup->{scoreboard_file},
-     SystemLog => $setup->{log_file},
-     TraceLog => $setup->{log_file},
--    Trace => 'DEFAULT:10 ssh2:20 sftp:20 scp:20',
-+    Trace => 'ssh2:20 sftp:20 scp:20',
- 
-     AuthUserFile => $setup->{auth_user_file},
-     AuthGroupFile => $setup->{auth_group_file},
-@@ -61488,6 +61644,139 @@ sub scp_download_rel_symlink_chrooted_bug4219 {
-   test_cleanup($setup->{log_file}, $ex);
- }
- 
-+sub scp_download_filename_with_spaces_issue1886 {
-+  my $self = shift;
-+  my $tmpdir = $self->{tmpdir};
-+  my $setup = test_setup($tmpdir, 'scp');
-+
-+  my $src_file = File::Spec->rel2abs("$tmpdir/src.txt");
-+  if (open(my $fh, "> $src_file")) {
-+    print $fh "ABCDefgh" x 32;
-+    unless (close($fh)) {
-+      die("Can't write $src_file: $!");
-+    }
-+
-+  } else {
-+    die("Can't open $src_file: $!");
-+  }
-+
-+  # Calculate the MD5 checksum of this file, for comparison with the
-+  # downloaded file.
-+  my $ctx = Digest::MD5->new();
-+  my $expected_md5;
-+
-+  if (open(my $fh, "< $src_file")) {
-+    binmode($fh);
-+    $ctx->addfile($fh);
-+    $expected_md5 = $ctx->hexdigest();
-+    close($fh);
-+
-+  } else {
-+    die("Can't read $src_file: $!");
-+  }
-+
-+  my $dst_file = File::Spec->rel2abs("$tmpdir/test filename with spaces.txt");
-+
-+  my $rsa_host_key = File::Spec->rel2abs('t/etc/modules/mod_sftp/ssh_host_rsa_key');
-+  my $dsa_host_key = File::Spec->rel2abs('t/etc/modules/mod_sftp/ssh_host_dsa_key');
-+
-+  my $config = {
-+    PidFile => $setup->{pid_file},
-+    ScoreboardFile => $setup->{scoreboard_file},
-+    SystemLog => $setup->{log_file},
-+    TraceLog => $setup->{log_file},
-+    Trace => 'ssh2:10 scp:20',
-+
-+    AuthUserFile => $setup->{auth_user_file},
-+    AuthGroupFile => $setup->{auth_group_file},
-+    AuthOrder => 'mod_auth_file.c',
-+
-+    IfModules => {
-+      'mod_delay.c' => {
-+        DelayEngine => 'off',
-+      },
-+
-+      'mod_sftp.c' => [
-+        "SFTPEngine on",
-+        "SFTPLog $setup->{log_file}",
-+        "SFTPHostKey $rsa_host_key",
-+        "SFTPHostKey $dsa_host_key",
-+      ],
-+    },
-+  };
-+
-+  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: $!");
-+  }
-+
-+  require Net::SSH2;
-+
-+  my $ex;
-+
-+  # Ignore SIGPIPE
-+  local $SIG{PIPE} = sub { };
-+
-+  # Fork child
-+  $self->handle_sigchld();
-+  defined(my $pid = fork()) or die("Can't fork: $!");
-+  if ($pid) {
-+    eval {
-+      my $ssh2 = Net::SSH2->new();
-+
-+      sleep(1);
-+
-+      unless ($ssh2->connect('127.0.0.1', $port)) {
-+        my ($err_code, $err_name, $err_str) = $ssh2->error();
-+        die("Can't connect to SSH2 server: [$err_name] ($err_code) $err_str");
-+      }
-+
-+      unless ($ssh2->auth_password($setup->{user}, $setup->{passwd})) {
-+        my ($err_code, $err_name, $err_str) = $ssh2->error();
-+        die("Can't login to SSH2 server: [$err_name] ($err_code) $err_str");
-+      }
-+
-+      my $res = $ssh2->scp_get('src.txt', $dst_file);
-+      unless ($res) {
-+        my ($err_code, $err_name, $err_str) = $ssh2->error();
-+        die("Can't download $src_file from server: [$err_name] ($err_code) $err_str");
-+      }
-+
-+      $ssh2->disconnect();
-+
-+      $self->assert(-f $dst_file,
-+        test_msg("File $dst_file file does not exist"));
-+    };
-+    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 scp_ext_download_bug3544 {
-   my $self = shift;
-   my $tmpdir = $self->{tmpdir};
-@@ -61545,7 +61834,7 @@ sub scp_ext_download_bug3544 {
-     ScoreboardFile => $scoreboard_file,
-     SystemLog => $log_file,
-     TraceLog => $log_file,
--    Trace => 'DEFAULT:10 ssh2:20 sftp:20 scp:20',
-+    Trace => 'ssh2:20 sftp:20 scp:20',
- 
-     AuthUserFile => $auth_user_file,
-     AuthGroupFile => $auth_group_file,
-@@ -61562,6 +61851,7 @@ sub scp_ext_download_bug3544 {
-         "SFTPHostKey $rsa_host_key",
-         "SFTPHostKey $dsa_host_key",
-         "SFTPAuthorizedUserKeys file:~/.authorized_keys",
-+'SFTPTrafficPolicy none',
-       ],
-     },
-   };
-@@ -61591,6 +61881,7 @@ sub scp_ext_download_bug3544 {
-       my @cmd = (
-         'scp',
-         '-vvv',
-+        '-O',
-         '-oBatchMode=yes',
-         '-oCheckHostIP=no',
-         "-oPort=$port",
-@@ -61789,6 +62080,7 @@ sub scp_ext_download_bug3798 {
-       my @cmd = (
-         'scp',
-         '-vvv',
-+        '-O',
-         '-oBatchMode=yes',
-         '-oCheckHostIP=no',
-         "-oPort=$port",
-@@ -61988,6 +62280,7 @@ sub scp_ext_download_glob_single_match_bug3904 {
-       my @cmd = (
-         'scp',
-         '-vvv',
-+        '-O',
-         '-oBatchMode=yes',
-         '-oCheckHostIP=no',
-         "-oPort=$port",
-@@ -62216,6 +62509,7 @@ sub scp_ext_download_glob_multiple_matches_bug3904 {
-       my @cmd = (
-         'scp',
-         '-vvv',
-+        '-O',
-         '-oBatchMode=yes',
-         '-oCheckHostIP=no',
-         "-oPort=$port",
-@@ -62506,6 +62800,7 @@ sub scp_ext_download_recursive_dir_bug3456 {
-         'scp',
-         '-r',
-         '-vvv',
-+        '-O',
-         '-oBatchMode=yes',
-         '-oCheckHostIP=no',
-         "-oPort=$port",
-@@ -62733,6 +63028,7 @@ sub scp_ext_download_recursive_empty_dir {
-         'scp',
-         '-r',
-         '-v',
-+        '-O',
-         '-oBatchMode=yes',
-         '-oCheckHostIP=no',
-         "-oPort=$port",
-@@ -62935,6 +63231,7 @@ sub scp_ext_download_glob_no_matches_bug3935 {
-       my @cmd = (
-         'scp',
-         '-vvv',
-+        '-O',
-         '-oBatchMode=yes',
-         '-oCheckHostIP=no',
-         "-oPort=$port",


=====================================
debian/patches/7e076e844ab5da63a0887b875aca2c3cfbc83a49.diff deleted
=====================================
@@ -1,31 +0,0 @@
-From 7e076e844ab5da63a0887b875aca2c3cfbc83a49 Mon Sep 17 00:00:00 2001
-From: TJ Saunders <tj at castaglia.org>
-Date: Thu, 7 May 2026 09:15:08 -0700
-Subject: [PATCH] Issue #2052: It is possible that some environment values come
- from user-supplied text, so we should always escape `%{env:...}` variables,
- too.
-
----
- contrib/mod_sql.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/contrib/mod_sql.c b/contrib/mod_sql.c
-index bafe175ff..b90725942 100644
---- a/contrib/mod_sql.c
-+++ b/contrib/mod_sql.c
-@@ -984,6 +984,7 @@ static int sql_resolve_on_meta(pool *p, pr_jot_ctx_t *jot_ctx,
-       case LOGFMT_META_COMMAND:
-       case LOGFMT_META_DIR_NAME:
-       case LOGFMT_META_DIR_PATH:
-+      case LOGFMT_META_ENV_VAR:
-       case LOGFMT_META_FILENAME:
-       case LOGFMT_META_IDENT_USER:
-       case LOGFMT_META_METHOD:
-@@ -1010,7 +1011,6 @@ static int sql_resolve_on_meta(pool *p, pr_jot_ctx_t *jot_ctx,
-       }
- 
-       case LOGFMT_META_CLASS:
--      case LOGFMT_META_ENV_VAR:
-       case LOGFMT_META_EOS_REASON:
-       case LOGFMT_META_GROUP:
-       case LOGFMT_META_ISO8601:


=====================================
debian/patches/d4ff72c0c32db68ef2cecfe08c53ac42a7bf85dd.diff deleted
=====================================
@@ -1,395 +0,0 @@
-From d4ff72c0c32db68ef2cecfe08c53ac42a7bf85dd Mon Sep 17 00:00:00 2001
-From: TJ Saunders <tj at castaglia.org>
-Date: Wed, 20 May 2026 11:37:10 -0700
-Subject: [PATCH] Issue #2098: Make sure that mod_quotatab provides a
- `pwrite(2)` FSIO handler as well, so that uploads via SFTP using `pwrite(2)`
- have hard upload limits enforced.
-
----
- contrib/mod_quotatab.c                        |  68 +++++
- .../Tests/Modules/mod_sftp/quotatab.pm        | 271 ++++++++++++++++++
- tests/t/modules/mod_sftp/quotatab.t           |  11 +
- 3 files changed, 350 insertions(+)
- create mode 100644 tests/t/lib/ProFTPD/Tests/Modules/mod_sftp/quotatab.pm
- create mode 100644 tests/t/modules/mod_sftp/quotatab.t
-
-diff --git a/contrib/mod_quotatab.c b/contrib/mod_quotatab.c
-index 903dca4b61..30d4f0348d 100644
---- a/contrib/mod_quotatab.c
-+++ b/contrib/mod_quotatab.c
-@@ -1432,6 +1432,73 @@ int quotatab_write(quota_tally_t *tally,
- 
- static off_t copied_bytes = 0;
- 
-+static ssize_t quotatab_fsio_pwrite(pr_fh_t *fh, int fd, const void *buf,
-+    size_t bufsz, off_t offset) {
-+  ssize_t res;
-+  off_t total_bytes;
-+
-+  res = pwrite(fd, buf, bufsz, offset);
-+  if (res < 0) {
-+    return res;
-+  }
-+
-+  if (have_quota_update == 0) {
-+    return res;
-+  }
-+
-+  /* Check to see if we've exceeded our upload limit.  mod_xfer will
-+   * have called pr_data_xfer(), which will have updated
-+   * session.xfer.total_bytes, before calling pr_fsio_write(), so
-+   * we do not have to worry about updated/changing session.xfer.total_bytes
-+   * ourselves.
-+   *
-+   * Note that there is a race condition here: it is possible for the same
-+   * user to be writing to the same file in chunks from multiple
-+   * simultaneous connections.
-+   */
-+
-+  /* If the client is copying a file (versus uploading a file), then we need
-+   * to track the "total bytes" differently.
-+   */
-+  if (session.curr_cmd_id == PR_CMD_SITE_ID &&
-+      (session.curr_cmd_rec->argc >= 2 &&
-+       (strcasecmp(session.curr_cmd_rec->argv[1], "CPTO") == 0 ||
-+        strcasecmp(session.curr_cmd_rec->argv[1], "COPY") == 0))) {
-+    copied_bytes += res;
-+    total_bytes = copied_bytes;
-+
-+  } else {
-+    total_bytes = session.xfer.total_bytes;
-+  }
-+
-+  if (sess_limit.bytes_in_avail > 0.0 &&
-+      sess_tally.bytes_in_used + total_bytes > sess_limit.bytes_in_avail) {
-+    int xerrno;
-+    char *errstr = NULL;
-+
-+    xerrno = get_quota_exceeded_errno(EIO, &errstr);
-+    quotatab_log("quotatab write(): limit exceeded, returning %s", errstr);
-+
-+    errno = xerrno;
-+    return -1;
-+  }
-+
-+  if (sess_limit.bytes_xfer_avail > 0.0 &&
-+      sess_tally.bytes_xfer_used + total_bytes > sess_limit.bytes_xfer_avail) {
-+    int xerrno;
-+    char *errstr = NULL;
-+
-+    xerrno = get_quota_exceeded_errno(EIO, &errstr);
-+    quotatab_log("quotatab write(): transfer limit exceeded, returning %s",
-+      errstr);
-+
-+    errno = xerrno;
-+    return -1;
-+  }
-+
-+  return res;
-+}
-+
- static int quotatab_fsio_write(pr_fh_t *fh, int fd, const char *buf,
-     size_t bufsz) {
-   int res;
-@@ -3214,6 +3281,7 @@ MODRET quotatab_post_pass(cmd_rec *cmd) {
-          * For Issue #1764, this is not a problem due to the fact that
-          * mod_vroot does not override the system FS write callbacks.
-          */
-+        fs->pwrite = quotatab_fsio_pwrite;
-         fs->write = quotatab_fsio_write;
- 
-       } else {
-diff --git a/tests/t/lib/ProFTPD/Tests/Modules/mod_sftp/quotatab.pm b/tests/t/lib/ProFTPD/Tests/Modules/mod_sftp/quotatab.pm
-new file mode 100644
-index 0000000000..d3a9a4e93b
---- /dev/null
-+++ b/tests/t/lib/ProFTPD/Tests/Modules/mod_sftp/quotatab.pm
-@@ -0,0 +1,271 @@
-+package ProFTPD::Tests::Modules::mod_sftp::quotatab;
-+
-+use lib qw(t/lib);
-+use base qw(ProFTPD::TestSuite::Child);
-+use strict;
-+
-+use File::Path qw(mkpath);
-+use File::Spec;
-+use IO::Handle;
-+use POSIX qw(:fcntl_h);
-+
-+use ProFTPD::TestSuite::FTP;
-+use ProFTPD::TestSuite::Utils qw(:auth :config :running :test :testsuite);
-+
-+$| = 1;
-+
-+my $order = 0;
-+
-+my $TESTS = {
-+  sftp_quotatab_upload_hard_limit_issue2098 => {
-+    order => ++$order,
-+    test_class => [qw(bug forking mod_quotatab_sql mod_sql_sqlite)],
-+  },
-+
-+};
-+
-+sub new {
-+  return shift()->SUPER::new(@_);
-+}
-+
-+sub list_tests {
-+  return testsuite_get_runnable_tests($TESTS);
-+}
-+
-+sub set_up {
-+  my $self = shift;
-+  $self->SUPER::set_up(@_);
-+
-+  # Make sure that mod_sftp does not complain about permissions on the hostkey
-+  # files.
-+
-+  my $rsa_host_key = File::Spec->rel2abs('t/etc/modules/mod_sftp/ssh_host_rsa_key');
-+  my $dsa_host_key = File::Spec->rel2abs('t/etc/modules/mod_sftp/ssh_host_dsa_key');
-+
-+  unless (chmod(0400, $rsa_host_key, $dsa_host_key)) {
-+    die("Can't set perms on $rsa_host_key, $dsa_host_key: $!");
-+  }
-+}
-+
-+sub sftp_quotatab_upload_hard_limit_issue2098 {
-+  my $self = shift;
-+  my $tmpdir = $self->{tmpdir};
-+  my $setup = test_setup($tmpdir, 'quotatab');
-+
-+  my $rsa_host_key = File::Spec->rel2abs('t/etc/modules/mod_sftp/ssh_host_rsa_key');
-+  my $dsa_host_key = File::Spec->rel2abs('t/etc/modules/mod_sftp/ssh_host_dsa_key');
-+
-+  my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db");
-+
-+  my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql");
-+
-+  if (open(my $fh, "> $db_script")) {
-+    print $fh <<EOS;
-+CREATE TABLE quotalimits (
-+  name TEXT NOT NULL PRIMARY KEY,
-+  quota_type TEXT NOT NULL,
-+  per_session TEXT NOT NULL,
-+  limit_type TEXT NOT NULL,
-+  bytes_in_avail REAL NOT NULL,
-+  bytes_out_avail REAL NOT NULL,
-+  bytes_xfer_avail REAL NOT NULL,
-+  files_in_avail INTEGER NOT NULL,
-+  files_out_avail INTEGER NOT NULL,
-+  files_xfer_avail INTEGER NOT NULL
-+);
-+INSERT INTO quotalimits (name, quota_type, per_session, limit_type, bytes_in_avail, bytes_out_avail, bytes_xfer_avail, files_in_avail, files_out_avail, files_xfer_avail) VALUES ('$setup->{user}', 'user', 'false', 'hard', 32, 0, 0, 2, 0, 0);
-+
-+CREATE TABLE quotatallies (
-+  name TEXT NOT NULL PRIMARY KEY,
-+  quota_type TEXT NOT NULL,
-+  bytes_in_used REAL NOT NULL,
-+  bytes_out_used REAL NOT NULL,
-+  bytes_xfer_used REAL NOT NULL,
-+  files_in_used INTEGER NOT NULL,
-+  files_out_used INTEGER NOT NULL,
-+  files_xfer_used INTEGER NOT NULL
-+);
-+EOS
-+
-+    unless (close($fh)) {
-+      die("Can't write $db_script: $!");
-+    }
-+
-+  } else {
-+    die("Can't open $db_script: $!");
-+  }
-+
-+  my $cmd = "sqlite3 $db_file < $db_script";
-+
-+  if ($ENV{TEST_VERBOSE}) {
-+    print STDERR "Executing sqlite3: $cmd\n";
-+  }
-+
-+  my @output = `$cmd`;
-+  if (scalar(@output) &&
-+      $ENV{TEST_VERBOSE}) {
-+    print STDERR "Output: ", join('', @output), "\n";
-+  }
-+
-+  # Make sure that, if we're running as root, the database file has
-+  # the permissions/privs set for use by proftpd
-+  if ($< == 0) {
-+    unless (chmod(0666, $db_file)) {
-+      die("Can't set perms on $db_file to 0666: $!");
-+    }
-+  }
-+
-+  my $config = {
-+    PidFile => $setup->{pid_file},
-+    ScoreboardFile => $setup->{scoreboard_file},
-+    SystemLog => $setup->{log_file},
-+    TraceLog => $setup->{log_file},
-+    Trace => 'fsio:20 quotatab:20 sql:20 ssh2:20 sftp:30',
-+
-+    AuthUserFile => $setup->{auth_user_file},
-+    AuthGroupFile => $setup->{auth_group_file},
-+    AuthOrder => 'mod_auth_file.c',
-+
-+    IfModules => {
-+      'mod_delay.c' => {
-+        DelayEngine => 'off',
-+      },
-+
-+      'mod_quotatab_sql.c' => [
-+        'SQLNamedQuery get-quota-limit SELECT "name, quota_type, per_session, limit_type, bytes_in_avail, bytes_out_avail, bytes_xfer_avail, files_in_avail, files_out_avail, files_xfer_avail FROM quotalimits WHERE name = \'%{0}\' AND quota_type = \'%{1}\'"',
-+        'SQLNamedQuery get-quota-tally SELECT "name, quota_type, bytes_in_used, bytes_out_used, bytes_xfer_used, files_in_used, files_out_used, files_xfer_used FROM quotatallies WHERE name = \'%{0}\' AND quota_type = \'%{1}\'"',
-+        'SQLNamedQuery update-quota-tally UPDATE "bytes_in_used = bytes_in_used + %{0}, bytes_out_used = bytes_out_used + %{1}, bytes_xfer_used = bytes_xfer_used + %{2}, files_in_used = files_in_used + %{3}, files_out_used = files_out_used + %{4}, files_xfer_used = files_xfer_used + %{5} WHERE name = \'%{6}\' AND quota_type = \'%{7}\'" quotatallies',
-+        'SQLNamedQuery insert-quota-tally INSERT "%{0}, %{1}, %{2}, %{3}, %{4}, %{5}, %{6}, %{7}" quotatallies',
-+
-+        'QuotaEngine on',
-+        "QuotaLog $setup->{log_file}",
-+        'QuotaLimitTable sql:/get-quota-limit',
-+        'QuotaTallyTable sql:/get-quota-tally/update-quota-tally/insert-quota-tally',
-+      ],
-+
-+      'mod_sftp.c' => [
-+        "SFTPEngine on",
-+        "SFTPLog $setup->{log_file}",
-+        "SFTPHostKey $rsa_host_key",
-+        "SFTPHostKey $dsa_host_key",
-+      ],
-+
-+      'mod_sql.c' => {
-+        SQLEngine => 'log',
-+        SQLBackend => 'sqlite3',
-+        SQLConnectInfo => $db_file,
-+        SQLLogFile => $setup->{log_file},
-+      },
-+    },
-+  };
-+
-+  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: $!");
-+  }
-+
-+  require Net::SSH2;
-+
-+  my $ex;
-+
-+  # Fork child
-+  $self->handle_sigchld();
-+  defined(my $pid = fork()) or die("Can't fork: $!");
-+  if ($pid) {
-+    eval {
-+      my $ssh2 = Net::SSH2->new();
-+
-+      sleep(1);
-+
-+      unless ($ssh2->connect('127.0.0.1', $port)) {
-+        my ($err_code, $err_name, $err_str) = $ssh2->error();
-+        die("Can't connect to SSH2 server: [$err_name] ($err_code) $err_str");
-+      }
-+
-+      unless ($ssh2->auth_password($setup->{user}, $setup->{passwd})) {
-+        my ($err_code, $err_name, $err_str) = $ssh2->error();
-+        die("Can't login to SSH2 server: [$err_name] ($err_code) $err_str");
-+      }
-+
-+      my $sftp = $ssh2->sftp();
-+      unless ($sftp) {
-+        my ($err_code, $err_name, $err_str) = $ssh2->error();
-+        die("Can't use SFTP on SSH2 server: [$err_name] ($err_code) $err_str");
-+      }
-+
-+      my $fh = $sftp->open('test.dat', O_WRONLY|O_CREAT|O_TRUNC, 0644);
-+      unless ($fh) {
-+        my ($err_code, $err_name) = $sftp->error();
-+        die("Can't open test.txt: [$err_name] ($err_code)");
-+      }
-+
-+      my $count = 20;
-+      for (my $i = 0; $i < $count; $i++) {
-+        print $fh "ABCD" x 8192;
-+      }
-+
-+      # To issue the FXP_CLOSE, we have to explicitly destroy the filehandle
-+      $fh = undef;
-+
-+      $sftp = undef;
-+      $ssh2->disconnect();
-+    };
-+    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 =~ /limit exceeded/) {
-+          $ok = 1;
-+          last;
-+        }
-+      }
-+
-+      close($fh);
-+      $self->assert($ok, test_msg("Did not see expected QuotaLog message"));
-+
-+    } else {
-+      die("Can't read $setup->{log_file}: $!");
-+    }
-+  };
-+  if ($@) {
-+    $ex = $@;
-+  }
-+
-+  test_cleanup($setup->{log_file}, $ex);
-+}
-+
-+1;
-diff --git a/tests/t/modules/mod_sftp/quotatab.t b/tests/t/modules/mod_sftp/quotatab.t
-new file mode 100644
-index 0000000000..ddcf1ccf42
---- /dev/null
-+++ b/tests/t/modules/mod_sftp/quotatab.t
-@@ -0,0 +1,11 @@
-+#!/usr/bin/env perl
-+
-+use lib qw(t/lib);
-+use strict;
-+
-+use Test::Unit::HarnessUnit;
-+
-+$| = 1;
-+
-+my $r = Test::Unit::HarnessUnit->new();
-+$r->start("ProFTPD::Tests::Modules::mod_sftp::quotatab");


=====================================
debian/patches/series
=====================================
@@ -8,15 +8,5 @@ odbc
 01_disable_inet_connect_ipv4_test.diff
 02_disable_redis_sentinel_conn_new_test.diff
 #04_disable_base_netaddr_get_addr_test.diff
-#536608f849dddd2b551e7c1e4fd930a50a527ffe.diff
-#3d3a936b696d73f24a7f1a99bf7aa26735ff2306.diff
-#415395b795436ae47cc25b2394e80033b80f11be.diff
-#07797aba88dca902da7eaf1dfe262c8896943de7.diff
-#04d89957d8ace325ef76fdfab22049df16a40c0b.diff
-#7e076e844ab5da63a0887b875aca2c3cfbc83a49.diff
-#1a5ce6467756e92f42f89c53f0f370dc0f0206d7.diff
-#508eb4d1b8c550b5f3059ad5b33d60c6b6c76bc7.diff
-#d4ff72c0c32db68ef2cecfe08c53ac42a7bf85dd.diff
-#2148.diff
 #ca9a7469ced3a7baf8ab9cc97f7c6b4c5ee3de75.diff
 933abc9ae115ffc59e4b2a98495ec267bf341d23.diff



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

-- 
View it on GitLab: https://salsa.debian.org/debian-proftpd-team/proftpd/-/commit/e7963d086d3d584e2408f10120896d8fbc4fa8a7
You're receiving this email because of your account on salsa.debian.org. Manage all notifications: https://salsa.debian.org/-/profile/notifications | Help: https://salsa.debian.org/help




More information about the Pkg-proftpd-maintainers mailing list