From 57c94df2dcebe0b75f65519fac394b377237234c Mon Sep 17 00:00:00 2001 From: Richard Lescak Date: Fri, 17 Feb 2023 16:32:19 +0100 Subject: [PATCH] make vsftpd compatible with Openssl 3.0+ replace old network functions --- ...-support-for-DHE-based-cipher-suites.patch | 112 +++----------- ...upport-for-EDDHE-based-cipher-suites.patch | 28 ++-- ...ment-patch-to-build-with-OpenSSL-1.1.patch | 74 ---------- ...replace-deprecated-openssl-functions.patch | 70 +++++++++ ...5-replace-old-network-addr-functions.patch | 139 ++++++++++++++++++ vsftpd.spec | 16 +- 6 files changed, 252 insertions(+), 187 deletions(-) delete mode 100644 0035-Modify-DH-enablement-patch-to-build-with-OpenSSL-1.1.patch create mode 100644 vsftpd-3.0.5-replace-deprecated-openssl-functions.patch create mode 100644 vsftpd-3.0.5-replace-old-network-addr-functions.patch diff --git a/0021-Introduce-support-for-DHE-based-cipher-suites.patch b/0021-Introduce-support-for-DHE-based-cipher-suites.patch index cfa23bb..bbf99a8 100644 --- a/0021-Introduce-support-for-DHE-based-cipher-suites.patch +++ b/0021-Introduce-support-for-DHE-based-cipher-suites.patch @@ -31,81 +31,36 @@ index c362983..22b69b3 100644 #include #include #include -+#include +#include ++#include #include #include -@@ -38,6 +40,7 @@ - static char* get_ssl_error(); - static SSL* get_ssl(struct vsf_session* p_sess, int fd); - static int ssl_session_init(struct vsf_session* p_sess); -+static DH *ssl_tmp_dh_callback(SSL *ssl, int is_export, int keylength); - static void setup_bio_callbacks(); - static long bio_callback( - BIO* p_bio, int oper, const char* p_arg, int argi, long argl, long retval); -@@ -51,6 +54,60 @@ static int ssl_read_common(struct vsf_session* p_sess, +@@ -58,6 +60,23 @@ static int ssl_inited; static struct mystr debug_str; ++EVP_PKEY * ++DH_get_dh() ++{ ++ OSSL_PARAM dh_params[2]; ++ EVP_PKEY *dh_key = NULL; ++ EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", NULL); + -+// Grab prime number from OpenSSL; -+// (get_rfc*) for all available primes. -+// wraps selection of comparable algorithm strength -+#if !defined(match_dh_bits) -+ #define match_dh_bits(keylen) \ -+ keylen >= 8191 ? 8192 : \ -+ keylen >= 6143 ? 6144 : \ -+ keylen >= 4095 ? 4096 : \ -+ keylen >= 3071 ? 3072 : \ -+ keylen >= 2047 ? 2048 : \ -+ keylen >= 1535 ? 1536 : \ -+ keylen >= 1023 ? 1024 : 768 -+#endif ++ dh_params[0] = OSSL_PARAM_construct_utf8_string("group", "ffdhe2048", 0); ++ dh_params[1] = OSSL_PARAM_construct_end(); + -+#if !defined(DH_get_prime) -+ BIGNUM * -+ DH_get_prime(int bits) -+ { -+ switch (bits) { -+ case 768: return get_rfc2409_prime_768(NULL); -+ case 1024: return get_rfc2409_prime_1024(NULL); -+ case 1536: return get_rfc3526_prime_1536(NULL); -+ case 2048: return get_rfc3526_prime_2048(NULL); -+ case 3072: return get_rfc3526_prime_3072(NULL); -+ case 4096: return get_rfc3526_prime_4096(NULL); -+ case 6144: return get_rfc3526_prime_6144(NULL); -+ case 8192: return get_rfc3526_prime_8192(NULL); -+ // shouldn't happen when used match_dh_bits; strict compiler -+ default: return NULL; -+ } ++ if (EVP_PKEY_keygen_init(pctx) <= 0 || EVP_PKEY_CTX_set_params(pctx, dh_params) <= 0) ++ return NULL; ++ EVP_PKEY_generate(pctx, &dh_key); ++ EVP_PKEY_CTX_free(pctx); ++ return dh_key; +} -+#endif -+ -+#if !defined(DH_get_dh) -+ // Grab DH parameters -+ DH * -+ DH_get_dh(int size) -+ { -+ DH *dh = DH_new(); -+ if (!dh) { -+ return NULL; -+ } -+ dh->p = DH_get_prime(match_dh_bits(size)); -+ BN_dec2bn(&dh->g, "2"); -+ if (!dh->p || !dh->g) -+ { -+ DH_free(dh); -+ return NULL; -+ } -+ return dh; -+ } -+#endif + void ssl_init(struct vsf_session* p_sess) { -@@ -65,7 +122,7 @@ ssl_init(struct vsf_session* p_sess) +@@ -72,7 +89,7 @@ { die("SSL: could not allocate SSL context"); } @@ -114,61 +69,42 @@ index c362983..22b69b3 100644 if (!tunable_sslv2) { options |= SSL_OP_NO_SSLv2; -@@ -111,6 +168,25 @@ ssl_init(struct vsf_session* p_sess) +@@ -130,6 +147,25 @@ die("SSL: cannot load DSA private key"); } } + if (tunable_dh_param_file) + { + BIO *bio; -+ DH *dhparams = NULL; ++ EVP_PKEY *dh_params = NULL; + if ((bio = BIO_new_file(tunable_dh_param_file, "r")) == NULL) + { + die("SSL: cannot load custom DH params"); + } + else + { -+ dhparams = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); ++ dh_params = PEM_read_bio_Parameters(bio, NULL); + BIO_free(bio); + -+ if (!SSL_CTX_set_tmp_dh(p_ctx, dhparams)) -+ { ++ if (!SSL_CTX_set0_tmp_dh_pkey(p_ctx, dh_params)) ++ { + die("SSL: setting custom DH params failed"); -+ } ++ } + } + } if (tunable_ssl_ciphers && SSL_CTX_set_cipher_list(p_ctx, tunable_ssl_ciphers) != 1) { -@@ -184,6 +260,9 @@ +@@ -184,6 +226,9 @@ /* Ensure cached session doesn't expire */ SSL_CTX_set_timeout(p_ctx, INT_MAX); } + -+ SSL_CTX_set_tmp_dh_callback(p_ctx, ssl_tmp_dh_callback); ++ SSL_CTX_set0_tmp_dh_pkey(p_ctx, DH_get_dh()); + /* Set up ALPN to check for FTP protocol intention of client. */ SSL_CTX_set_alpn_select_cb(p_ctx, ssl_alpn_callback, p_sess); /* Set up SNI callback for an optional hostname check. */ -@@ -854,6 +933,18 @@ ssl_verify_callback(int verify_ok, X509_STORE_CTX* p_ctx) - } - } - -+#define UNUSED(x) ( (void)(x) ) -+ -+static DH * -+ssl_tmp_dh_callback(SSL *ssl, int is_export, int keylength) -+{ -+ // strict compiler bypassing -+ UNUSED(ssl); -+ UNUSED(is_export); -+ -+ return DH_get_dh(keylength); -+} -+ - void - ssl_add_entropy(struct vsf_session* p_sess) - { diff --git a/tunables.c b/tunables.c index c737465..1ea7227 100644 --- a/tunables.c diff --git a/0022-Introduce-support-for-EDDHE-based-cipher-suites.patch b/0022-Introduce-support-for-EDDHE-based-cipher-suites.patch index 9cb56cd..0a09a2c 100644 --- a/0022-Introduce-support-for-EDDHE-based-cipher-suites.patch +++ b/0022-Introduce-support-for-EDDHE-based-cipher-suites.patch @@ -36,45 +36,37 @@ index 22b69b3..96bf8ad 100644 if (!tunable_sslv2) { options |= SSL_OP_NO_SSLv2; -@@ -244,6 +244,41 @@ +@@ -244,6 +244,33 @@ - SSL_CTX_set_tmp_dh_callback(p_ctx, ssl_tmp_dh_callback); + SSL_CTX_set0_tmp_dh_pkey(p_ctx, DH_get_dh()); + if (tunable_ecdh_param_file) + { + BIO *bio; -+ int nid; -+ EC_GROUP *ecparams = NULL; -+ EC_KEY *eckey; ++ EVP_PKEY *ec_params = NULL; + + if ((bio = BIO_new_file(tunable_ecdh_param_file, "r")) == NULL) + die("SSL: cannot load custom ec params"); + else + { -+ ecparams = PEM_read_bio_ECPKParameters(bio, NULL, NULL, NULL); ++ ec_params = PEM_read_bio_Parameters(bio, NULL); + BIO_free(bio); + -+ if (ecparams && (nid = EC_GROUP_get_curve_name(ecparams)) && -+ (eckey = EC_KEY_new_by_curve_name(nid))) ++ if (ec_params != NULL) + { -+ if (!SSL_CTX_set_tmp_ecdh(p_ctx, eckey)) ++ if (!SSL_CTX_set1_groups_list(p_ctx, ec_params)) + die("SSL: setting custom EC params failed"); -+ } -+ else ++ } ++ else + { + die("SSL: getting ec group or key failed"); -+ } ++ } + } + } + else + { -+#if defined(SSL_CTX_set_ecdh_auto) -+ SSL_CTX_set_ecdh_auto(p_ctx, 1); -+#else -+ SSL_CTX_set_tmp_ecdh(p_ctx, EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)); -+#endif ++ SSL_CTX_set1_groups_list(p_ctx, "P-256"); + } -+ /* Set up ALPN to check for FTP protocol intention of client. */ SSL_CTX_set_alpn_select_cb(p_ctx, ssl_alpn_callback, p_sess); /* Set up SNI callback for an optional hostname check. */ diff --git a/0035-Modify-DH-enablement-patch-to-build-with-OpenSSL-1.1.patch b/0035-Modify-DH-enablement-patch-to-build-with-OpenSSL-1.1.patch deleted file mode 100644 index 1cebc18..0000000 --- a/0035-Modify-DH-enablement-patch-to-build-with-OpenSSL-1.1.patch +++ /dev/null @@ -1,74 +0,0 @@ -From 6c8dd87f311e411bcb1c72c1c780497881a5621c Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Ond=C5=99ej=20Lyson=C4=9Bk?= -Date: Mon, 4 Sep 2017 11:32:03 +0200 -Subject: [PATCH 35/59] Modify DH enablement patch to build with OpenSSL 1.1 - ---- - ssl.c | 41 ++++++++++++++++++++++++++++++++++++++--- - 1 file changed, 38 insertions(+), 3 deletions(-) - -diff --git a/ssl.c b/ssl.c -index ba8a613..09ec96a 100644 ---- a/ssl.c -+++ b/ssl.c -@@ -88,19 +88,54 @@ static struct mystr debug_str; - } - #endif - -+#if OPENSSL_VERSION_NUMBER < 0x10100000L -+int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g) -+{ -+ /* If the fields p and g in d are NULL, the corresponding input -+ * parameters MUST be non-NULL. q may remain NULL. -+ */ -+ if ((dh->p == NULL && p == NULL) -+ || (dh->g == NULL && g == NULL)) -+ return 0; -+ -+ if (p != NULL) { -+ BN_free(dh->p); -+ dh->p = p; -+ } -+ if (q != NULL) { -+ BN_free(dh->q); -+ dh->q = q; -+ } -+ if (g != NULL) { -+ BN_free(dh->g); -+ dh->g = g; -+ } -+ -+ if (q != NULL) { -+ dh->length = BN_num_bits(q); -+ } -+ -+ return 1; -+} -+#endif -+ - #if !defined(DH_get_dh) - // Grab DH parameters - DH * - DH_get_dh(int size) - { -+ BIGNUM *g = NULL; -+ BIGNUM *p = NULL; - DH *dh = DH_new(); - if (!dh) { - return NULL; - } -- dh->p = DH_get_prime(match_dh_bits(size)); -- BN_dec2bn(&dh->g, "2"); -- if (!dh->p || !dh->g) -+ p = DH_get_prime(match_dh_bits(size)); -+ BN_dec2bn(&g, "2"); -+ if (!p || !g || !DH_set0_pqg(dh, p, NULL, g)) - { -+ BN_free(g); -+ BN_free(p); - DH_free(dh); - return NULL; - } --- -2.14.4 - diff --git a/vsftpd-3.0.5-replace-deprecated-openssl-functions.patch b/vsftpd-3.0.5-replace-deprecated-openssl-functions.patch new file mode 100644 index 0000000..c6f8f7d --- /dev/null +++ b/vsftpd-3.0.5-replace-deprecated-openssl-functions.patch @@ -0,0 +1,70 @@ +diff --git a/ssl.c b/ssl.c +--- ssl.c ++++ ssl.c +@@ -28,17 +28,17 @@ + #include + #include + #include + #include + #include + #include + #include + + static char* get_ssl_error(); + static SSL* get_ssl(struct vsf_session* p_sess, int fd); + static int ssl_session_init(struct vsf_session* p_sess); + static void setup_bio_callbacks(); + static long bio_callback( +- BIO* p_bio, int oper, const char* p_arg, int argi, long argl, long retval); ++ BIO* p_bio, int oper, const char* p_arg, size_t len, int argi, long argl, int ret, size_t *processed); + static int ssl_verify_callback(int verify_ok, X509_STORE_CTX* p_ctx); + static int ssl_alpn_callback(SSL* p_ssl, + const unsigned char** p_out, +@@ -88,7 +88,7 @@ + long options; + int verify_option = 0; + SSL_library_init(); +- p_ctx = SSL_CTX_new(SSLv23_server_method()); ++ p_ctx = SSL_CTX_new_ex(NULL, NULL, SSLv23_server_method()); + if (p_ctx == NULL) + { + die("SSL: could not allocate SSL context"); +@@ -180,13 +180,10 @@ + die("SSL: RNG is not seeded"); + } + { +- EC_KEY* key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); +- if (key == NULL) ++ if (!SSL_CTX_set1_groups_list(p_ctx, "P-256")) + { + die("SSL: failed to get curve p256"); + } +- SSL_CTX_set_tmp_ecdh(p_ctx, key); +- EC_KEY_free(key); + } + if (tunable_ssl_request_cert) + { +@@ -692,17 +689,19 @@ + static void setup_bio_callbacks(SSL* p_ssl) + { + BIO* p_bio = SSL_get_rbio(p_ssl); +- BIO_set_callback(p_bio, bio_callback); ++ BIO_set_callback_ex(p_bio, bio_callback); + p_bio = SSL_get_wbio(p_ssl); +- BIO_set_callback(p_bio, bio_callback); ++ BIO_set_callback_ex(p_bio, bio_callback); + } + + static long + bio_callback( +- BIO* p_bio, int oper, const char* p_arg, int argi, long argl, long ret) ++ BIO* p_bio, int oper, const char* p_arg, size_t len, int argi, long argl, int ret, size_t *processed) + { + int retval = 0; + int fd = 0; ++ (void) len; ++ (void) processed; + (void) p_arg; + (void) argi; + (void) argl; + diff --git a/vsftpd-3.0.5-replace-old-network-addr-functions.patch b/vsftpd-3.0.5-replace-old-network-addr-functions.patch new file mode 100644 index 0000000..89e6257 --- /dev/null +++ b/vsftpd-3.0.5-replace-old-network-addr-functions.patch @@ -0,0 +1,139 @@ +diff -urN vsftpd-3.0.5-orig/postlogin.c vsftpd-3.0.5/postlogin.c +--- vsftpd-3.0.5-orig/postlogin.c 2015-07-22 21:03:22.000000000 +0200 ++++ vsftpd-3.0.5/postlogin.c 2023-02-13 16:34:05.244467476 +0100 +@@ -27,4 +27,6 @@ + #include "ssl.h" + #include "vsftpver.h" ++#include ++#include + #include "opts.h" + +@@ -628,9 +629,10 @@ + else + { + const void* p_v4addr = vsf_sysutil_sockaddr_ipv6_v4(s_p_sockaddr); ++ static char result[INET_ADDRSTRLEN]; + if (p_v4addr) + { +- str_append_text(&s_pasv_res_str, vsf_sysutil_inet_ntoa(p_v4addr)); ++ str_append_text(&s_pasv_res_str, inet_ntop(AF_INET, p_v4addr, result, INET_ADDRSTRLEN)); + } + else + { +diff -urN vsftpd-3.0.5-orig/sysutil.c vsftpd-3.0.5/sysutil.c +--- vsftpd-3.0.5-orig/sysutil.c 2012-09-16 09:07:38.000000000 +0200 ++++ vsftpd-3.0.5/sysutil.c 2023-02-13 16:08:58.557153109 +0100 +@@ -2205,20 +2205,13 @@ + const struct sockaddr* p_sockaddr = &p_sockptr->u.u_sockaddr; + if (p_sockaddr->sa_family == AF_INET) + { +- return inet_ntoa(p_sockptr->u.u_sockaddr_in.sin_addr); ++ static char result[INET_ADDRSTRLEN]; ++ return inet_ntop(AF_INET, &p_sockptr->u.u_sockaddr_in.sin_addr, result, INET_ADDRSTRLEN); + } + else if (p_sockaddr->sa_family == AF_INET6) + { +- static char inaddr_buf[64]; +- const char* p_ret = inet_ntop(AF_INET6, +- &p_sockptr->u.u_sockaddr_in6.sin6_addr, +- inaddr_buf, sizeof(inaddr_buf)); +- inaddr_buf[sizeof(inaddr_buf) - 1] = '\0'; +- if (p_ret == NULL) +- { +- inaddr_buf[0] = '\0'; +- } +- return inaddr_buf; ++ static char result[INET6_ADDRSTRLEN]; ++ return inet_ntop(AF_INET6, &p_sockptr->u.u_sockaddr_in6.sin6_addr, result, INET6_ADDRSTRLEN); + } + else + { +@@ -2227,12 +2220,6 @@ + } + } + +-const char* +-vsf_sysutil_inet_ntoa(const void* p_raw_addr) +-{ +- return inet_ntoa(*((struct in_addr*)p_raw_addr)); +-} +- + int + vsf_sysutil_inet_aton(const char* p_text, struct vsf_sysutil_sockaddr* p_addr) + { +@@ -2241,7 +2228,7 @@ + { + bug("bad family"); + } +- if (inet_aton(p_text, &sin_addr)) ++ if (inet_pton(AF_INET, p_text, &sin_addr)) + { + vsf_sysutil_memcpy(&p_addr->u.u_sockaddr_in.sin_addr, + &sin_addr, sizeof(p_addr->u.u_sockaddr_in.sin_addr)); +@@ -2257,37 +2244,46 @@ + vsf_sysutil_dns_resolve(struct vsf_sysutil_sockaddr** p_sockptr, + const char* p_name) + { +- struct hostent* hent = gethostbyname(p_name); +- if (hent == NULL) ++ struct addrinfo *result; ++ struct addrinfo hints; ++ int ret; ++ ++ memset(&hints, 0, sizeof(struct addrinfo)); ++ hints.ai_family = AF_UNSPEC; ++ ++ if ((ret = getaddrinfo(p_name, NULL, &hints, &result)) != 0) + { ++ fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(ret)); + die2("cannot resolve host:", p_name); + } + vsf_sysutil_sockaddr_clear(p_sockptr); +- if (hent->h_addrtype == AF_INET) ++ if (result->ai_family == AF_INET) + { +- unsigned int len = hent->h_length; ++ unsigned int len = result->ai_addrlen; + if (len > sizeof((*p_sockptr)->u.u_sockaddr_in.sin_addr)) + { + len = sizeof((*p_sockptr)->u.u_sockaddr_in.sin_addr); + } + vsf_sysutil_sockaddr_alloc_ipv4(p_sockptr); + vsf_sysutil_memcpy(&(*p_sockptr)->u.u_sockaddr_in.sin_addr, +- hent->h_addr_list[0], len); ++ &result->ai_addrlen, len); + } +- else if (hent->h_addrtype == AF_INET6) ++ else if (result->ai_family == AF_INET6) + { +- unsigned int len = hent->h_length; ++ unsigned int len = result->ai_addrlen; + if (len > sizeof((*p_sockptr)->u.u_sockaddr_in6.sin6_addr)) + { + len = sizeof((*p_sockptr)->u.u_sockaddr_in6.sin6_addr); + } + vsf_sysutil_sockaddr_alloc_ipv6(p_sockptr); + vsf_sysutil_memcpy(&(*p_sockptr)->u.u_sockaddr_in6.sin6_addr, +- hent->h_addr_list[0], len); ++ &result->ai_addrlen, len); + } + else + { +- die("gethostbyname(): neither IPv4 nor IPv6"); ++ freeaddrinfo(result); ++ die("getaddrinfo(): neither IPv4 nor IPv6"); + } ++ freeaddrinfo(result); + } + +diff -urN vsftpd-3.0.5-orig/sysutil.h vsftpd-3.0.5/sysutil.h +--- vsftpd-3.0.5-orig/sysutil.h 2021-05-18 08:50:21.000000000 +0200 ++++ vsftpd-3.0.5/sysutil.h 2023-02-13 15:59:22.088331075 +0100 +@@ -277,7 +277,6 @@ + + const char* vsf_sysutil_inet_ntop( + const struct vsf_sysutil_sockaddr* p_sockptr); +-const char* vsf_sysutil_inet_ntoa(const void* p_raw_addr); + int vsf_sysutil_inet_aton( + const char* p_text, struct vsf_sysutil_sockaddr* p_addr); + diff --git a/vsftpd.spec b/vsftpd.spec index 7efc847..72ce764 100644 --- a/vsftpd.spec +++ b/vsftpd.spec @@ -2,7 +2,7 @@ Name: vsftpd Version: 3.0.5 -Release: 2%{?dist} +Release: 3%{?dist} Summary: Very Secure Ftp Daemon # OpenSSL link exception @@ -63,7 +63,6 @@ Patch31: 0031-Fix-question-mark-wildcard-withing-a-file-name.patch Patch32: 0032-Propagate-errors-from-nfs-with-quota-to-client.patch #Patch33: 0033-Introduce-TLSv1.1-and-TLSv1.2-options.patch Patch34: 0034-Turn-off-seccomp-sandbox-because-it-is-too-strict.patch -Patch35: 0035-Modify-DH-enablement-patch-to-build-with-OpenSSL-1.1.patch Patch36: 0036-Redefine-VSFTP_COMMAND_FD-to-1.patch Patch37: 0037-Document-the-relationship-of-text_userdb_names-and-c.patch Patch38: 0038-Document-allow_writeable_chroot-in-the-man-page.patch @@ -98,7 +97,8 @@ Patch68: 0002-Drop-an-unused-global-variable.patch Patch69: 0001-Remove-a-hint-about-the-ftp_home_dir-SELinux-boolean.patch Patch70: fix-str_open.patch Patch71: vsftpd-3.0.5-enable_wc_logs-replace_unprintable_with_hex.patch -# upstream commits 56402c0, 8b82e73 +Patch72: vsftpd-3.0.5-replace-old-network-addr-functions.patch +Patch73: vsftpd-3.0.5-replace-deprecated-openssl-functions.patch %description vsftpd is a Very Secure FTP daemon. It was written completely from @@ -109,13 +109,11 @@ scratch. cp %{SOURCE1} . %build -# temporary ignore deprecated warnings to be able to build against OpenSSL 3.0 -%define ignore_deprecated -Wno-deprecated-declarations %ifarch s390x sparcv9 sparc64 -%make_build CFLAGS="$RPM_OPT_FLAGS -fPIE -pipe -Wextra -Werror %ignore_deprecated" \ +%make_build CFLAGS="$RPM_OPT_FLAGS -fPIE -pipe -Wextra -Werror" \ %else -%make_build CFLAGS="$RPM_OPT_FLAGS -fpie -pipe -Wextra -Werror %ignore_deprecated" \ +%make_build CFLAGS="$RPM_OPT_FLAGS -fpie -pipe -Wextra -Werror" \ %endif LINK="-pie -lssl $RPM_LD_FLAGS" %{?_smp_mflags} @@ -170,6 +168,10 @@ mkdir -p $RPM_BUILD_ROOT/%{_var}/ftp/pub %{_var}/ftp %changelog +* Fri Feb 17 2023 Richard Lescak - 3.0.5-3 +- make vsftpd compatible with Openssl 3.0+ +- replace old network functions + * Sat Jan 21 2023 Fedora Release Engineering - 3.0.5-2 - Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild