[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