Version in base suite: 1.3.8.c+dfsg-4+deb13u1 Base version: proftpd-dfsg_1.3.8.c+dfsg-4+deb13u1 Target version: proftpd-dfsg_1.3.8.c+dfsg-4+deb13u2 Base file: /srv/ftp-master.debian.org/ftp/pool/main/p/proftpd-dfsg/proftpd-dfsg_1.3.8.c+dfsg-4+deb13u1.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/p/proftpd-dfsg/proftpd-dfsg_1.3.8.c+dfsg-4+deb13u2.dsc changelog | 7 + patches/2052_pghmcfc.diff | 195 ++++++++++++++++++++++++++++++++++++++++++++++ patches/series | 1 3 files changed, 203 insertions(+) dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmppina8tr8/proftpd-dfsg_1.3.8.c+dfsg-4+deb13u1.dsc: no acceptable signature found dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmppina8tr8/proftpd-dfsg_1.3.8.c+dfsg-4+deb13u2.dsc: no acceptable signature found diff -Nru proftpd-dfsg-1.3.8.c+dfsg/debian/changelog proftpd-dfsg-1.3.8.c+dfsg/debian/changelog --- proftpd-dfsg-1.3.8.c+dfsg/debian/changelog 2025-11-09 13:49:42.000000000 +0000 +++ proftpd-dfsg-1.3.8.c+dfsg/debian/changelog 2026-05-01 10:48:15.000000000 +0000 @@ -1,3 +1,10 @@ +proftpd-dfsg (1.3.8.c+dfsg-4+deb13u2) trixie; urgency=medium + + * Add patch for CVE-2026-42167 (Closes: #1135119). + Thanks to Paul Howarth for adaption to 1.3.8c. + + -- Hilmar Preuße Fri, 01 May 2026 12:48:15 +0200 + proftpd-dfsg (1.3.8.c+dfsg-4+deb13u1) trixie; urgency=medium [ Evgeni Golov ] diff -Nru proftpd-dfsg-1.3.8.c+dfsg/debian/patches/2052_pghmcfc.diff proftpd-dfsg-1.3.8.c+dfsg/debian/patches/2052_pghmcfc.diff --- proftpd-dfsg-1.3.8.c+dfsg/debian/patches/2052_pghmcfc.diff 1970-01-01 00:00:00.000000000 +0000 +++ proftpd-dfsg-1.3.8.c+dfsg/debian/patches/2052_pghmcfc.diff 2026-05-01 10:47:52.000000000 +0000 @@ -0,0 +1,195 @@ +From 415395b795436ae47cc25b2394e80033b80f11be Mon Sep 17 00:00:00 2001 +From: TJ Saunders +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-2022 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 +@@ -760,40 +760,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) { +@@ -811,7 +817,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; +@@ -970,35 +976,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_STATUS: + case LOGFMT_META_XFER_TYPE: + default: +@@ -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; +@@ -3175,7 +3200,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); diff -Nru proftpd-dfsg-1.3.8.c+dfsg/debian/patches/series proftpd-dfsg-1.3.8.c+dfsg/debian/patches/series --- proftpd-dfsg-1.3.8.c+dfsg/debian/patches/series 2025-11-09 13:48:21.000000000 +0000 +++ proftpd-dfsg-1.3.8.c+dfsg/debian/patches/series 2026-05-01 10:47:52.000000000 +0000 @@ -20,3 +20,4 @@ e7539bd772ca6e12d3e05fb56da274cf78ee1edf.diff 14c006b62c09d1efe302c57b2d183a489bcb22dc.diff 9b2b4a3e32d251798bf8fa841b124ab15ba58f11.diff +2052_pghmcfc.diff