[Git][debian-proftpd-team/proftpd][master] Add some patches from upstream. See debian/changelog.
Hilmar Preuße
gitlab at salsa.debian.org
Thu Jul 30 22:59:33 BST 2020
Hilmar Preuße pushed to branch master at Debian ProFTPD Team / proftpd
Commits:
18c0faa2 by Hilmar Preusse at 2020-07-30T23:58:46+02:00
Add some patches from upstream. See debian/changelog.
- - - - -
5 changed files:
- debian/changelog
- debian/patches/series
- + debian/patches/upstream_1061
- + debian/patches/upstream_1063
- + debian/patches/upstream_1070
Changes:
=====================================
debian/changelog
=====================================
@@ -1,3 +1,16 @@
+proftpd-dfsg (1.3.7a-2) UNRELEASED; urgency=medium
+
+ * Applied some patches pulled from upstream.
+ - upstream_1063: Avoid segfaults for TLSv1.3 data transfers in
+ our session tickey callback by checking the status before using
+ SSL_SESSION pointer.
+ - upstream_1070: Implement support for Redis 6.x AUTH semantics.
+ - upstream_1061: While investigating some reported issues with
+ Ed25519 keys and mod_sftp, I reproduced one segfault when verifying
+ such keys during publickey authentication.
+
+ -- Hilmar Preusse <hille42 at web.de> Thu, 30 Jul 2020 23:16:38 +0200
+
proftpd-dfsg (1.3.7a-1) unstable; urgency=medium
New upstream release 1.3.7a:
=====================================
debian/patches/series
=====================================
@@ -11,3 +11,6 @@ odbc
wrong-path-for-interpreter_perl.diff
#cd9036f4ef7a05c107f0ffcb19a018b20267c531.patch
# proftpd-mysql-password-backend.patch
+upstream_1063
+upstream_1070
+upstream_1061
=====================================
debian/patches/upstream_1061
=====================================
@@ -0,0 +1,50 @@
+From 1117b003fa25c2e29e3a679ba3a1a3b92b5a4587 Mon Sep 17 00:00:00 2001
+From: TJ Saunders <tj at castaglia.org>
+Date: Sat, 25 Jul 2020 16:51:26 -0700
+Subject: [PATCH] Issue #1061: While investigating some reported issues with
+ Ed25519 keys and mod_sftp, I reproduced one segfault when verifying such keys
+ during publickey authentication.
+
+---
+ contrib/mod_sftp/kex.c | 2 +-
+ contrib/mod_sftp/keys.c | 7 +++++--
+ 2 files changed, 6 insertions(+), 3 deletions(-)
+
+diff --git a/contrib/mod_sftp/kex.c b/contrib/mod_sftp/kex.c
+index 17e853fe2..59c76f3c0 100644
+--- a/contrib/mod_sftp/kex.c
++++ b/contrib/mod_sftp/kex.c
+@@ -2869,7 +2869,7 @@ static int write_ext_info_server_sig_algs(struct ssh2_packet *pkt, char **buf,
+ char *sig_algs = "";
+
+ #if defined(PR_USE_SODIUM)
+- sig_algs = pstrcat(pkt->pool, sig_algs, *sig_algs ? "," : "", "ssh-ec25519",
++ sig_algs = pstrcat(pkt->pool, sig_algs, *sig_algs ? "," : "", "ssh-ed25519",
+ NULL);
+ #endif /* PR_USE_SODIUM */
+
+diff --git a/contrib/mod_sftp/keys.c b/contrib/mod_sftp/keys.c
+index b2e03f722..c94a3b201 100644
+--- a/contrib/mod_sftp/keys.c
++++ b/contrib/mod_sftp/keys.c
+@@ -4453,7 +4453,7 @@ const unsigned char *sftp_keys_sign_data(pool *p,
+
+ int sftp_keys_verify_pubkey_type(pool *p, unsigned char *pubkey_data,
+ uint32_t pubkey_len, enum sftp_key_type_e pubkey_type) {
+- EVP_PKEY *pkey;
++ EVP_PKEY *pkey = NULL;
+ int res = FALSE;
+ uint32_t len;
+
+@@ -4542,7 +4542,10 @@ int sftp_keys_verify_pubkey_type(pool *p, unsigned char *pubkey_data,
+ break;
+ }
+
+- EVP_PKEY_free(pkey);
++ if (pkey != NULL) {
++ EVP_PKEY_free(pkey);
++ }
++
+ return res;
+ }
+
=====================================
debian/patches/upstream_1063
=====================================
@@ -0,0 +1,45 @@
+From adf43dd4ddaab0332e74abc86bbcef9cf27ee54a Mon Sep 17 00:00:00 2001
+From: TJ Saunders <tj at castaglia.org>
+Date: Sat, 25 Jul 2020 11:10:07 -0700
+Subject: [PATCH] Issue #1063: Avoid segfaults for TLSv1.3 data transfers in
+ our session tickey callback by checking the status before using SSL_SESSION
+ pointer.
+
+---
+ contrib/mod_tls.c | 21 +++++++++++++++------
+ 1 file changed, 15 insertions(+), 6 deletions(-)
+
+diff --git a/contrib/mod_tls.c b/contrib/mod_tls.c
+index c4e3a2f18..3cab789c9 100644
+--- a/contrib/mod_tls.c
++++ b/contrib/mod_tls.c
+@@ -6833,14 +6833,23 @@ static SSL_TICKET_RETURN tls_decrypt_session_ticket_data_upload_cb(SSL *ssl,
+ SSL_SESSION *ssl_session, const unsigned char *key_name, size_t key_namelen,
+ SSL_TICKET_STATUS status, void *user_data) {
+ SSL_TICKET_RETURN res;
+- int ssl_version, renew_tickets = TRUE;
++ int renew_tickets = TRUE;
+
+- ssl_version = SSL_SESSION_get_protocol_version(ssl_session);
++ /* Avoid using the given SSL_SESSION pointer unless the status indicates that
++ * that pointer is valid (Issue #1063).
++ */
++
++ if (status != SSL_TICKET_EMPTY &&
++ status != SSL_TICKET_NO_DECRYPT) {
++ int ssl_version;
++
++ ssl_version = SSL_SESSION_get_protocol_version(ssl_session);
+ # if defined(TLS1_3_VERSION)
+- if (ssl_version == TLS1_3_VERSION) {
+- pr_trace_msg(trace_channel, 29,
+- "suppressing renewal of TLSv1.3 tickets for data transfers");
+- renew_tickets = FALSE;
++ if (ssl_version == TLS1_3_VERSION) {
++ pr_trace_msg(trace_channel, 29,
++ "suppressing renewal of TLSv1.3 tickets for data transfers");
++ renew_tickets = FALSE;
++ }
+ }
+ # endif /* TLS1_3_VERSION */
+
=====================================
debian/patches/upstream_1070
=====================================
@@ -0,0 +1,705 @@
+From 3fe77bd7088af1e0f5822e12555a4f4221301dbe Mon Sep 17 00:00:00 2001
+From: TJ Saunders <tj at castaglia.org>
+Date: Sun, 26 Jul 2020 13:38:42 -0700
+Subject: [PATCH] Issue #1070: Implement support for Redis 6.x AUTH semantics.
+
+---
+ include/redis.h | 10 ++-
+ src/redis.c | 128 +++++++++++++++++++++++++--
+ tests/api/env.c | 8 +-
+ tests/api/redis.c | 210 ++++++++++++++++++++++++++++++++++++++-------
+ tests/api/sets.c | 24 +++---
+ tests/api/str.c | 8 +-
+ tests/api/timers.c | 2 +-
+ 7 files changed, 334 insertions(+), 56 deletions(-)
+
+diff --git a/include/redis.h b/include/redis.h
+index 27f71e454..eae519bfb 100644
+--- a/include/redis.h
++++ b/include/redis.h
+@@ -1,6 +1,6 @@
+ /*
+ * ProFTPD - FTP server daemon
+- * Copyright (c) 2017 The ProFTPD Project team
++ * Copyright (c) 2017-2020 The ProFTPD Project team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+@@ -55,8 +55,14 @@ int pr_redis_conn_destroy(pr_redis_t *redis);
+ int pr_redis_conn_set_namespace(pr_redis_t *redis, module *m,
+ const void *prefix, size_t prefixsz);
+
++/* Redis server version. */
++int pr_redis_conn_get_version(pr_redis_t *redis, unsigned int *major_version,
++ unsigned int *minor_version, unsigned int *patch_version);
++
+ /* Authenticate to a password-protected Redis server. */
+ int pr_redis_auth(pr_redis_t *redis, const char *password);
++int pr_redis_auth2(pr_redis_t *redis, const char *username,
++ const char *password);
+
+ /* Select the database used by the Redis server. */
+ int pr_redis_select(pr_redis_t *redis, const char *db_idx);
+@@ -304,6 +310,8 @@ int pr_redis_sentinel_get_masters(pool *p, pr_redis_t *redis,
+ /* For internal use only */
+ int redis_set_server(const char *server, int port, unsigned long flags,
+ const char *password, const char *db_idx);
++int redis_set_server2(const char *server, int port, unsigned long flags,
++ const char *username, const char *password, const char *db_idx);
+ int redis_set_sentinels(array_header *sentinels, const char *name);
+ int redis_set_timeouts(unsigned long connect_millis, unsigned long io_millis);
+
+diff --git a/src/redis.c b/src/redis.c
+index 5bd99623f..cca05bd3f 100644
+--- a/src/redis.c
++++ b/src/redis.c
+@@ -49,6 +49,11 @@ struct redis_rec {
+ */
+ unsigned int refcount;
+
++ /* Redis server version. */
++ unsigned int major_version;
++ unsigned int minor_version;
++ unsigned int patch_version;
++
+ /* Table mapping modules to their namespaces */
+ pr_table_t *namespace_tab;
+ };
+@@ -59,6 +64,7 @@ static const char *redis_sentinel_master = NULL;
+ static const char *redis_server = NULL;
+ static int redis_port = -1;
+ static unsigned long redis_flags = 0UL;
++static const char *redis_username = NULL;
+ static const char *redis_password = NULL;
+ static const char *redis_db_idx = NULL;
+
+@@ -69,6 +75,8 @@ static unsigned long redis_io_millis = 500;
+
+ static const char *trace_channel = "redis";
+
++static const char *get_reply_type(int reply_type);
++
+ static void millis2timeval(struct timeval *tv, unsigned long millis) {
+ tv->tv_sec = (millis / 1000);
+ tv->tv_usec = (millis - (tv->tv_sec * 1000)) * 1000;
+@@ -194,6 +202,48 @@ static int ping_server(pr_redis_t *redis) {
+ return 0;
+ }
+
++static void parse_redis_version(pr_redis_t *redis, redisReply *info) {
++ pool *tmp_pool;
++ unsigned int major, minor, patch;
++ char *text, *version_text;
++
++ if (info->type != REDIS_REPLY_STRING) {
++ pr_trace_msg(trace_channel, 1, "expected STRING reply for INFO, got %s",
++ get_reply_type(info->type));
++ return;
++ }
++
++ tmp_pool = make_sub_pool(redis->pool);
++ pr_pool_tag(tmp_pool, "Redis version parsing pool");
++ text = pstrndup(tmp_pool, info->str, info->len);
++
++ /* Scan the entire INFO string for "redis_version:N.N.N". */
++
++ version_text = strstr(text, "redis_version:");
++ if (version_text == NULL) {
++ pr_trace_msg(trace_channel, 1, "no `redis_version` found in INFO reply");
++ destroy_pool(tmp_pool);
++ return;
++ }
++
++ if (sscanf(version_text, "redis_version:%u.%u.%u", &major, &minor,
++ &patch) == 3) {
++ redis->major_version = major;
++ redis->minor_version = minor;
++ redis->patch_version = patch;
++
++ pr_trace_msg(trace_channel, 9,
++ "parsed Redis version %u (major), %u (minor), %u (patch) out of INFO",
++ redis->major_version, redis->minor_version, redis->patch_version);
++
++ } else {
++ pr_trace_msg(trace_channel, 1, "failed to scan Redis version '%s'",
++ version_text);
++ }
++
++ destroy_pool(tmp_pool);
++}
++
+ static int stat_server(pr_redis_t *redis, const char *section) {
+ const char *cmd;
+ redisReply *reply;
+@@ -214,6 +264,18 @@ static int stat_server(pr_redis_t *redis, const char *section) {
+ (unsigned long) reply->len);
+ }
+
++ if (redis->major_version == 0 &&
++ (strcmp(section, "server") == 0 || strcmp(section, "") == 0)) {
++ /* We are particularly interested in the Redis server version; we key
++ * off of this version to detect when to change our command semantics,
++ * such as for AUTH.
++ *
++ * Thus we parse the server version out of the "server" info, unless
++ * the version is already known.
++ */
++ parse_redis_version(redis, reply);
++ }
++
+ freeReplyObject(reply);
+ return 0;
+ }
+@@ -508,7 +570,13 @@ pr_redis_t *pr_redis_conn_new(pool *p, module *m, unsigned long flags) {
+ }
+
+ if (redis_password != NULL) {
+- res = pr_redis_auth(redis, redis_password);
++ if (redis_username != NULL) {
++ res = pr_redis_auth2(redis, redis_username, redis_password);
++
++ } else {
++ res = pr_redis_auth(redis, redis_password);
++ }
++
+ if (res < 0) {
+ xerrno = errno;
+
+@@ -682,6 +750,36 @@ int pr_redis_conn_set_namespace(pr_redis_t *redis, module *m,
+ return 0;
+ }
+
++int pr_redis_conn_get_version(pr_redis_t *redis, unsigned int *major_version,
++ unsigned int *minor_version, unsigned int *patch_version) {
++
++ if (redis == NULL) {
++ errno = EINVAL;
++ return -1;
++ }
++
++ if (major_version == NULL &&
++ minor_version == NULL &&
++ patch_version == NULL) {
++ errno = EINVAL;
++ return -1;
++ }
++
++ if (major_version != NULL) {
++ *major_version = redis->major_version;
++ }
++
++ if (minor_version != NULL) {
++ *minor_version = redis->minor_version;
++ }
++
++ if (patch_version != NULL) {
++ *patch_version = redis->patch_version;
++ }
++
++ return 0;
++}
++
+ int pr_redis_add(pr_redis_t *redis, module *m, const char *key, void *value,
+ size_t valuesz, time_t expires) {
+ int res;
+@@ -2003,12 +2101,14 @@ int pr_redis_command(pr_redis_t *redis, const array_header *args,
+ return 0;
+ }
+
+-int pr_redis_auth(pr_redis_t *redis, const char *password) {
++int pr_redis_auth2(pr_redis_t *redis, const char *username,
++ const char *password) {
+ const char *cmd;
+ pool *tmp_pool;
+ redisReply *reply;
+
+ if (redis == NULL ||
++ username == NULL ||
+ password == NULL) {
+ errno = EINVAL;
+ return -1;
+@@ -2019,7 +2119,15 @@ int pr_redis_auth(pr_redis_t *redis, const char *password) {
+
+ cmd = "AUTH";
+ pr_trace_msg(trace_channel, 7, "sending command: %s", cmd);
+- reply = redisCommand(redis->ctx, "%s %s", cmd, password);
++
++ /* Redis 6.x changed the AUTH semantics, now requiring a username. */
++ if (redis->major_version >= 6) {
++ reply = redisCommand(redis->ctx, "%s %s %s", cmd, username, password);
++
++ } else {
++ reply = redisCommand(redis->ctx, "%s %s", cmd, password);
++ }
++
+ reply = handle_reply(redis, cmd, reply);
+ if (reply == NULL) {
+ pr_trace_msg(trace_channel, 2,
+@@ -2053,6 +2161,10 @@ int pr_redis_auth(pr_redis_t *redis, const char *password) {
+ return 0;
+ }
+
++int pr_redis_auth(pr_redis_t *redis, const char *password) {
++ return pr_redis_auth2(redis, "default", password);
++}
++
+ int pr_redis_select(pr_redis_t *redis, const char *db_idx) {
+ const char *cmd;
+ pool *tmp_pool;
+@@ -5632,8 +5744,8 @@ int pr_redis_sentinel_get_masters(pool *p, pr_redis_t *redis,
+ return res;
+ }
+
+-int redis_set_server(const char *server, int port, unsigned long flags,
+- const char *password, const char *db_idx) {
++int redis_set_server2(const char *server, int port, unsigned long flags,
++ const char *username, const char *password, const char *db_idx) {
+
+ if (server == NULL) {
+ /* By using a port of -2 specifically, we can use this function to
+@@ -5649,12 +5761,18 @@ int redis_set_server(const char *server, int port, unsigned long flags,
+ redis_server = server;
+ redis_port = port;
+ redis_flags = flags;
++ redis_username = username;
+ redis_password = password;
+ redis_db_idx = db_idx;
+
+ return 0;
+ }
+
++int redis_set_server(const char *server, int port, unsigned long flags,
++ const char *password, const char *db_idx) {
++ return redis_set_server2(server, port, flags, "default", password, db_idx);
++}
++
+ int redis_set_sentinels(array_header *sentinels, const char *name) {
+
+ if (sentinels != NULL &&
+diff --git a/tests/api/env.c b/tests/api/env.c
+index ad126385e..b839f2ea4 100644
+--- a/tests/api/env.c
++++ b/tests/api/env.c
+@@ -1,6 +1,6 @@
+ /*
+ * ProFTPD - FTP server testsuite
+- * Copyright (c) 2008-2015 The ProFTPD Project team
++ * Copyright (c) 2008-2020 The ProFTPD Project team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+@@ -61,11 +61,13 @@ START_TEST (env_get_test) {
+ pr_env_unset(p, key);
+
+ res = pr_env_get(p, key);
+- fail_unless(res == NULL);
++ fail_unless(res == NULL, "Unexpectedly found value '%s' for key '%s'",
++ res, key);
+
+ /* XXX PATH should always be set in the environment, right? */
+ res = pr_env_get(p, "PATH");
+- fail_unless(res != NULL);
++ fail_unless(res != NULL, "Failed to get value for 'PATH': %s",
++ strerror(errno));
+
+ #else
+ res = pr_env_get(p, key);
+diff --git a/tests/api/redis.c b/tests/api/redis.c
+index 7e95893ee..e44d5a4bd 100644
+--- a/tests/api/redis.c
++++ b/tests/api/redis.c
+@@ -222,11 +222,44 @@ START_TEST (redis_conn_set_namespace_test) {
+ }
+ END_TEST
+
++START_TEST (redis_conn_get_version_test) {
++ int res;
++ pr_redis_t *redis;
++ unsigned int major = 0, minor = 0, patch = 0;
++
++ mark_point();
++ res = pr_redis_conn_get_version(NULL, NULL, NULL, NULL);
++ fail_unless(res < 0, "Failed to handle null redis");
++ fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
++ strerror(errno), errno);
++
++ mark_point();
++ redis = pr_redis_conn_new(p, NULL, 0);
++ fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
++ strerror(errno));
++
++ mark_point();
++ res = pr_redis_conn_get_version(redis, NULL, NULL, NULL);
++ fail_unless(res < 0, "Failed to handle null version arguments");
++ fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
++ strerror(errno), errno);
++
++ mark_point();
++ res = pr_redis_conn_get_version(redis, &major, &minor, &patch);
++ fail_unless(res == 0, "Failed to get Redis version: %s", strerror(errno));
++
++ mark_point();
++ res = pr_redis_conn_destroy(redis);
++ fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
++}
++END_TEST
++
+ START_TEST (redis_conn_auth_test) {
+ int res;
+ pr_redis_t *redis;
+ const char *text;
+ array_header *args;
++ unsigned int major_version = 0;
+
+ mark_point();
+ res = pr_redis_auth(NULL, NULL);
+@@ -245,52 +278,167 @@ START_TEST (redis_conn_auth_test) {
+ fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
+ strerror(errno), errno);
+
+- text = "password";
+-
+ /* What happens if we try to AUTH to a non-password-protected Redis?
+ * Answer: Redis returns an error indicating that no password is required.
++ *
++ * Note that this behavior changed with Redis 6.x. In particular, any
++ * "AUTH default ..." command automatically succeeds with Redis 6.x,
++ * regardless of the actual password given. Sigh.
+ */
++
++ mark_point();
++ res = pr_redis_conn_get_version(redis, &major_version, NULL, NULL);
++ fail_unless(res == 0, "Failed to get Redis version: %s", strerror(errno));
++
+ mark_point();
++ text = "password";
+ res = pr_redis_auth(redis, text);
+- fail_unless(res < 0, "Failed to handle lack of need for authentication");
++
++ if (major_version < 6) {
++ fail_unless(res < 0, "Failed to handle lack of need for authentication");
++ fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
++ strerror(errno), errno);
++
++ /* Use CONFIG SET to require a password. */
++ args = make_array(p, 0, sizeof(char *));
++ *((char **) push_array(args)) = pstrdup(p, "CONFIG");
++ *((char **) push_array(args)) = pstrdup(p, "SET");
++ *((char **) push_array(args)) = pstrdup(p, "requirepass");
++ *((char **) push_array(args)) = pstrdup(p, text);
++
++ mark_point();
++ res = pr_redis_command(redis, args, PR_REDIS_REPLY_TYPE_STATUS);
++ fail_unless(res == 0, "Failed to enable authentication: %s",
++ strerror(errno));
++
++ args = make_array(p, 0, sizeof(char *));
++ *((char **) push_array(args)) = pstrdup(p, "TIME");
++
++ mark_point();
++ res = pr_redis_command(redis, args, PR_REDIS_REPLY_TYPE_ARRAY);
++ fail_unless(res < 0, "Failed to handle required authentication");
++ fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
++ strerror(errno), errno);
++
++ mark_point();
++ res = pr_redis_auth(redis, text);
++ fail_unless(res == 0, "Failed to authenticate client: %s", strerror(errno));
++
++ /* Don't forget to remove the password. */
++ args = make_array(p, 0, sizeof(char *));
++ *((char **) push_array(args)) = pstrdup(p, "CONFIG");
++ *((char **) push_array(args)) = pstrdup(p, "SET");
++ *((char **) push_array(args)) = pstrdup(p, "requirepass");
++ *((char **) push_array(args)) = pstrdup(p, "");
++
++ mark_point();
++ res = pr_redis_command(redis, args, PR_REDIS_REPLY_TYPE_STATUS);
++ fail_unless(res == 0, "Failed to remove password authentication: %s",
++ strerror(errno));
++
++ } else {
++ fail_unless(res == 0, "Failed to handle AUTH command: %s",
++ strerror(errno));
++ }
++
++ mark_point();
++ res = pr_redis_conn_destroy(redis);
++ fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
++}
++END_TEST
++
++START_TEST (redis_conn_auth2_test) {
++ int res;
++ pr_redis_t *redis;
++ const char *username, *password;
++ array_header *args;
++ unsigned int major_version = 0;
++
++ mark_point();
++ res = pr_redis_auth2(NULL, NULL, NULL);
++ fail_unless(res < 0, "Failed to handle null redis");
+ fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
+ strerror(errno), errno);
+
+- /* Use CONFIG SET to require a password. */
+- args = make_array(p, 0, sizeof(char *));
+- *((char **) push_array(args)) = pstrdup(p, "CONFIG");
+- *((char **) push_array(args)) = pstrdup(p, "SET");
+- *((char **) push_array(args)) = pstrdup(p, "requirepass");
+- *((char **) push_array(args)) = pstrdup(p, text);
++ mark_point();
++ redis = pr_redis_conn_new(p, NULL, 0);
++ fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
++ strerror(errno));
+
+ mark_point();
+- res = pr_redis_command(redis, args, PR_REDIS_REPLY_TYPE_STATUS);
+- fail_unless(res == 0, "Failed to enable authentication: %s", strerror(errno));
++ res = pr_redis_auth2(redis, NULL, NULL);
++ fail_unless(res < 0, "Failed to handle null username");
++ fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
++ strerror(errno), errno);
+
+- args = make_array(p, 0, sizeof(char *));
+- *((char **) push_array(args)) = pstrdup(p, "TIME");
++ /* Note: Do NOT use "default" as the initial username; that name has
++ * specific semantics for Redis 6.x and later.
++ */
++ username = "foobar";
+
+ mark_point();
+- res = pr_redis_command(redis, args, PR_REDIS_REPLY_TYPE_ARRAY);
+- fail_unless(res < 0, "Failed to handle required authentication");
++ res = pr_redis_auth2(redis, username, NULL);
++ fail_unless(res < 0, "Failed to handle null password");
+ fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
+ strerror(errno), errno);
+
+- mark_point();
+- res = pr_redis_auth(redis, text);
+- fail_unless(res == 0, "Failed to authenticate client: %s", strerror(errno));
++ /* What happens if we try to AUTH to a non-password-protected Redis?
++ * Answer: Redis returns an error indicating that no password is required.
++ *
++ * Note that this behavior changed with Redis 6.x. In particular, any
++ * "AUTH default ..." command automatically succeeds with Redis 6.x,
++ * regardless of the actual password given. Sigh.
++ */
+
+- /* Don't forget to remove the password. */
+- args = make_array(p, 0, sizeof(char *));
+- *((char **) push_array(args)) = pstrdup(p, "CONFIG");
+- *((char **) push_array(args)) = pstrdup(p, "SET");
+- *((char **) push_array(args)) = pstrdup(p, "requirepass");
+- *((char **) push_array(args)) = pstrdup(p, "");
++ mark_point();
++ res = pr_redis_conn_get_version(redis, &major_version, NULL, NULL);
++ fail_unless(res == 0, "Failed to get Redis version: %s", strerror(errno));
+
+ mark_point();
+- res = pr_redis_command(redis, args, PR_REDIS_REPLY_TYPE_STATUS);
+- fail_unless(res == 0, "Failed to remove password authentication: %s",
+- strerror(errno));
++ password = "password";
++ res = pr_redis_auth2(redis, username, password);
++ fail_unless(res < 0, "Failed to handle lack of need for authentication");
++ fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
++ strerror(errno), errno);
++
++ if (major_version < 6) {
++ /* Use CONFIG SET to require a password. */
++ args = make_array(p, 0, sizeof(char *));
++ *((char **) push_array(args)) = pstrdup(p, "CONFIG");
++ *((char **) push_array(args)) = pstrdup(p, "SET");
++ *((char **) push_array(args)) = pstrdup(p, "requirepass");
++ *((char **) push_array(args)) = pstrdup(p, password);
++
++ mark_point();
++ res = pr_redis_command(redis, args, PR_REDIS_REPLY_TYPE_STATUS);
++ fail_unless(res == 0, "Failed to enable authentication: %s",
++ strerror(errno));
++
++ args = make_array(p, 0, sizeof(char *));
++ *((char **) push_array(args)) = pstrdup(p, "TIME");
++
++ mark_point();
++ res = pr_redis_command(redis, args, PR_REDIS_REPLY_TYPE_ARRAY);
++ fail_unless(res < 0, "Failed to handle required authentication");
++ fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
++ strerror(errno), errno);
++
++ mark_point();
++ res = pr_redis_auth2(redis, username, password);
++ fail_unless(res == 0, "Failed to authenticate client: %s", strerror(errno));
++
++ /* Don't forget to remove the password. */
++ args = make_array(p, 0, sizeof(char *));
++ *((char **) push_array(args)) = pstrdup(p, "CONFIG");
++ *((char **) push_array(args)) = pstrdup(p, "SET");
++ *((char **) push_array(args)) = pstrdup(p, "requirepass");
++ *((char **) push_array(args)) = pstrdup(p, "");
++
++ mark_point();
++ res = pr_redis_command(redis, args, PR_REDIS_REPLY_TYPE_STATUS);
++ fail_unless(res == 0, "Failed to remove password authentication: %s",
++ strerror(errno));
++ }
+
+ mark_point();
+ res = pr_redis_conn_destroy(redis);
+@@ -1987,7 +2135,7 @@ START_TEST (redis_hash_keys_test) {
+ mark_point();
+ res = pr_redis_hash_keys(p, redis, &m, key, &fields);
+ fail_unless(res == 0, "Failed to handle existing fields: %s", strerror(errno));
+- fail_unless(fields != NULL);
++ fail_unless(fields != NULL, "Failed to get hash fields");
+ fail_unless(fields->nelts == 2, "Expected 2, got %u", fields->nelts);
+
+ (void) pr_redis_remove(redis, &m, key);
+@@ -2074,7 +2222,7 @@ START_TEST (redis_hash_values_test) {
+ mark_point();
+ res = pr_redis_hash_values(p, redis, &m, key, &values);
+ fail_unless(res == 0, "Failed to handle existing values: %s", strerror(errno));
+- fail_unless(values != NULL);
++ fail_unless(values != NULL, "Failed to get hash values");
+ fail_unless(values->nelts == 2, "Expected 2, got %u", values->nelts);
+
+ (void) pr_redis_remove(redis, &m, key);
+@@ -2161,7 +2309,7 @@ START_TEST (redis_hash_getall_test) {
+ mark_point();
+ res = pr_redis_hash_getall(p, redis, &m, key, &hash);
+ fail_unless(res == 0, "Failed to handle existing fields: %s", strerror(errno));
+- fail_unless(hash != NULL);
++ fail_unless(hash != NULL, "Failed to get hash");
+ res = pr_table_count(hash);
+ fail_unless(res == 2, "Expected 2, got %d", res);
+
+@@ -4743,7 +4891,9 @@ Suite *tests_get_redis_suite(void) {
+ tcase_add_test(testcase, redis_conn_new_test);
+ tcase_add_test(testcase, redis_conn_get_test);
+ tcase_add_test(testcase, redis_conn_set_namespace_test);
++ tcase_add_test(testcase, redis_conn_get_version_test);
+ tcase_add_test(testcase, redis_conn_auth_test);
++ tcase_add_test(testcase, redis_conn_auth2_test);
+ tcase_add_test(testcase, redis_conn_select_test);
+ tcase_add_test(testcase, redis_conn_reconnect_test);
+ tcase_add_test(testcase, redis_command_test);
+diff --git a/tests/api/sets.c b/tests/api/sets.c
+index 9f3deafc2..9459454f2 100644
+--- a/tests/api/sets.c
++++ b/tests/api/sets.c
+@@ -1,6 +1,6 @@
+ /*
+ * ProFTPD - FTP server testsuite
+- * Copyright (c) 2008-2011 The ProFTPD Project team
++ * Copyright (c) 2008-2020 The ProFTPD Project team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+@@ -97,20 +97,20 @@ START_TEST (set_create_test) {
+ fail_unless(errno == EPERM, "Failed to set errno to EPERM");
+
+ res = xaset_create(p, NULL);
+- fail_unless(res != NULL);
++ fail_unless(res != NULL, "Expected non-null result");
+ fail_unless(res->pool == p, "Expected %p, got %p", p, res->pool);
+
+ permanent_pool = make_sub_pool(p);
+
+ res = xaset_create(NULL, NULL);
+- fail_unless(res != NULL);
++ fail_unless(res != NULL, "Expected non-null result");
+ fail_unless(res->pool == permanent_pool, "Expected %p, got %p",
+ permanent_pool, res->pool);
+ fail_unless(res->xas_compare == NULL, "Expected NULL, got %p",
+ res->xas_compare);
+
+ res = xaset_create(p, (XASET_COMPARE) item_cmp);
+- fail_unless(res != NULL);
++ fail_unless(res != NULL, "Expected non-null result");
+ fail_unless(res->pool == p, "Expected %p, got %p", p, res->pool);
+ fail_unless(res->xas_compare == (XASET_COMPARE) item_cmp,
+ "Expected %p, got %p", item_cmp, res->xas_compare);
+@@ -355,12 +355,12 @@ START_TEST (set_remove_test) {
+ fail_unless(res == 0, "Failed to add item2");
+
+ member = (xasetmember_t *) item1;
+- fail_unless(member->next == NULL);
+- fail_unless(member->prev != NULL);
++ fail_unless(member->next == NULL, "Expected member->next to be null");
++ fail_unless(member->prev != NULL, "Expected member->prev to not be null");
+
+ member = (xasetmember_t *) item2;
+- fail_unless(member->next != NULL);
+- fail_unless(member->prev == NULL);
++ fail_unless(member->next != NULL, "Expected member->next to not be null");
++ fail_unless(member->prev == NULL, "Expected member->prev to be null");
+
+ member = set->xas_list;
+ fail_unless(member == (xasetmember_t *) item2,
+@@ -371,8 +371,8 @@ START_TEST (set_remove_test) {
+ strerror(errno));
+
+ member = (xasetmember_t *) item2;
+- fail_unless(member->next == NULL);
+- fail_unless(member->prev == NULL);
++ fail_unless(member->next == NULL, "Expected member->next to be null");
++ fail_unless(member->prev == NULL, "Expected member->prev to be null");
+
+ member = set->xas_list;
+ fail_unless(member == (xasetmember_t *) item1,
+@@ -383,8 +383,8 @@ START_TEST (set_remove_test) {
+ strerror(errno));
+
+ member = (xasetmember_t *) item1;
+- fail_unless(member->next == NULL);
+- fail_unless(member->prev == NULL);
++ fail_unless(member->next == NULL, "Expected member->next to be null");
++ fail_unless(member->prev == NULL, "Expected member->prev to be null");
+
+ member = set->xas_list;
+ fail_unless(member == NULL, "Expected list to be empty, got %p", member);
+diff --git a/tests/api/str.c b/tests/api/str.c
+index 9dce95820..050f5c563 100644
+--- a/tests/api/str.c
++++ b/tests/api/str.c
+@@ -1539,10 +1539,10 @@ START_TEST (uid2str_test) {
+ const char *res;
+
+ res = pr_uid2str(NULL, (uid_t) 1);
+- fail_unless(strcmp(res, "1") == 0);
++ fail_unless(strcmp(res, "1") == 0, "Expected '1', got '%s'", res);
+
+ res = pr_uid2str(NULL, (uid_t) -1);
+- fail_unless(strcmp(res, "-1") == 0);
++ fail_unless(strcmp(res, "-1") == 0, "Expected '-1', got '%s'", res);
+ }
+ END_TEST
+
+@@ -1550,10 +1550,10 @@ START_TEST (gid2str_test) {
+ const char *res;
+
+ res = pr_gid2str(NULL, (gid_t) 1);
+- fail_unless(strcmp(res, "1") == 0);
++ fail_unless(strcmp(res, "1") == 0, "Expected '1', got '%s'", res);
+
+ res = pr_gid2str(NULL, (gid_t) -1);
+- fail_unless(strcmp(res, "-1") == 0);
++ fail_unless(strcmp(res, "-1") == 0, "Expected '-1', got '%s'", res);
+ }
+ END_TEST
+
+diff --git a/tests/api/timers.c b/tests/api/timers.c
+index 99b6348e9..0616a7989 100644
+--- a/tests/api/timers.c
++++ b/tests/api/timers.c
+@@ -157,7 +157,7 @@ START_TEST (timer_remove_test) {
+ int res;
+
+ res = pr_timer_remove(0, NULL);
+- fail_unless(res == 0);
++ fail_unless(res == 0, "Failed to remove timer: %s", strerror(errno));
+
+ res = pr_timer_add(1, 0, NULL, timers_test_cb, "test");
+ fail_unless(res == 0, "Failed to add timer (%d): %s", res, strerror(errno));
View it on GitLab: https://salsa.debian.org/debian-proftpd-team/proftpd/-/commit/18c0faa2d7acbe48fb47bc16461b7b2c7bb97fe8
--
View it on GitLab: https://salsa.debian.org/debian-proftpd-team/proftpd/-/commit/18c0faa2d7acbe48fb47bc16461b7b2c7bb97fe8
You're receiving this email because of your account on salsa.debian.org.
More information about the Pkg-proftpd-maintainers
mailing list