From 77fbaa4e9a6b97735947d575ade3f167fad09b59 Mon Sep 17 00:00:00 2001 From: Debarshi Ray Date: Thu, 22 Jan 2026 15:21:36 +0100 Subject: [PATCH 1/9] Rebase to version 4.19.3 Resolves: #2426288 https://src.fedoraproject.org/rpms/shadow-utils/pull-request/27 --- .gitignore | 4 + 1520.patch | 40 --------- shadow-4.19.0-chkhash1.patch | 88 ------------------- shadow-4.19.0-usermod-add-optimizations.patch | 75 ---------------- ...hash2.patch => shadow-4.19.3-chkhash.patch | 65 ++++---------- shadow-utils.spec | 27 +++--- sources | 4 +- 7 files changed, 32 insertions(+), 271 deletions(-) delete mode 100644 1520.patch delete mode 100644 shadow-4.19.0-chkhash1.patch delete mode 100644 shadow-4.19.0-usermod-add-optimizations.patch rename shadow-4.19.0-chkhash2.patch => shadow-4.19.3-chkhash.patch (59%) diff --git a/.gitignore b/.gitignore index 0ceb6c8..7db552e 100644 --- a/.gitignore +++ b/.gitignore @@ -44,3 +44,7 @@ shadow-4.1.4.2.tar.bz2 /shadow-4.18.0.tar.xz.asc /shadow-4.19.0.tar.xz /shadow-4.19.0.tar.xz.asc +/shadow-4.19.2.tar.xz +/shadow-4.19.2.tar.xz.asc +/shadow-4.19.3.tar.xz +/shadow-4.19.3.tar.xz.asc diff --git a/1520.patch b/1520.patch deleted file mode 100644 index 069eebb..0000000 --- a/1520.patch +++ /dev/null @@ -1,40 +0,0 @@ -From b721cdd03daa3416127289da02fe781efb2562df Mon Sep 17 00:00:00 2001 -From: Adam Williamson -Date: Tue, 27 Jan 2026 15:11:07 -0800 -Subject: [PATCH] lib/chkhash.c: fix escaping in SHA-256 / SHA-512 / MD5 - regexes - -`\\n` inside square brackets doesn't include or exclude the -newline character. It includes or excludes a literal slash and -the literal character 'n'. - -Fixes: c44f1e096a19 (2025-07-20; "chpasswd: Check hash before write when using -e") -Closes: -Signed-off-by: Adam Williamson ---- - lib/chkhash.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/lib/chkhash.c b/lib/chkhash.c -index 101f2004e8..9123038ade 100644 ---- a/lib/chkhash.c -+++ b/lib/chkhash.c -@@ -62,15 +62,15 @@ is_valid_hash(const char *hash) - return true; - - // SHA-512: $6$ + salt + $ + 86-char hash -- if (match_regex("^\\$6\\$(rounds=[1-9][0-9]{3,8}\\$)?[^$:\\n]{1,16}\\$[./A-Za-z0-9]{86}$", hash)) -+ if (match_regex("^\\$6\\$(rounds=[1-9][0-9]{3,8}\\$)?[^$:\n]{1,16}\\$[./A-Za-z0-9]{86}$", hash)) - return true; - - // SHA-256: $5$ + salt + $ + 43-char hash -- if (match_regex("^\\$5\\$(rounds=[1-9][0-9]{3,8}\\$)?[^$:\\n]{1,16}\\$[./A-Za-z0-9]{43}$", hash)) -+ if (match_regex("^\\$5\\$(rounds=[1-9][0-9]{3,8}\\$)?[^$:\n]{1,16}\\$[./A-Za-z0-9]{43}$", hash)) - return true; - - // MD5: $1$ + salt + $ + 22-char hash -- if (match_regex("^\\$1\\$[^$:\\n]{1,8}\\$[./A-Za-z0-9]{22}$", hash)) -+ if (match_regex("^\\$1\\$[^$:\n]{1,8}\\$[./A-Za-z0-9]{22}$", hash)) - return true; - - // DES: exactly 13 characters from [A-Za-z0-9./] diff --git a/shadow-4.19.0-chkhash1.patch b/shadow-4.19.0-chkhash1.patch deleted file mode 100644 index 986f10b..0000000 --- a/shadow-4.19.0-chkhash1.patch +++ /dev/null @@ -1,88 +0,0 @@ -From 87ec7a52ab25dd6e91253c274fd651f16844cf2a Mon Sep 17 00:00:00 2001 -From: Alejandro Colomar -Date: Wed, 7 Jan 2026 23:39:53 +0100 -Subject: [PATCH 1/2] lib/chkhash.c: is_valid_hash(): Accept a leading '!' - -A leading '!' means that the account is locked. - -Fixes: c44f1e096a19 (2025-07-20; "chpasswd: Check hash before write when using -e") -Link: -Link: -Reported-by: Chris Hofstaedtler -Reviewed-by: Chris Hofstaedtler -Cc: vinz -Signed-off-by: Alejandro Colomar ---- - lib/chkhash.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/lib/chkhash.c b/lib/chkhash.c -index 66870500..cb45f3aa 100644 ---- a/lib/chkhash.c -+++ b/lib/chkhash.c -@@ -7,6 +7,8 @@ - #include - #include - -+#include "string/strcmp/strprefix.h" -+ - - /* - * match_regex - return true if match, false if not -@@ -37,6 +39,8 @@ match_regex(const char *pattern, const char *string) - bool - is_valid_hash(const char *hash) - { -+ hash = strprefix(hash, "!") ?: hash; -+ - // Minimum hash length - if (strlen(hash) < 13) - return false; --- -2.52.0 - - -From ddc2549f87e3001f663d5179e9b6d7fe2e1f3b3f Mon Sep 17 00:00:00 2001 -From: Alejandro Colomar -Date: Wed, 7 Jan 2026 23:44:26 +0100 -Subject: [PATCH 2/2] lib/chkhash.c: is_valid_hash(): Accept '*' as the hash - -This is widely accepted as an invalid hash, to remove password access -for an account (that is, no passwords will match the "hash"). - -Fixes: c44f1e096a19 (2025-07-20; "chpasswd: Check hash before write when using -e") -Closes: -Closes: -Reported-by: Chris Hofstaedtler -Reviewed-by: Chris Hofstaedtler -Cc: vinz -Signed-off-by: Alejandro Colomar ---- - lib/chkhash.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/lib/chkhash.c b/lib/chkhash.c -index cb45f3aa..71e0fb4e 100644 ---- a/lib/chkhash.c -+++ b/lib/chkhash.c -@@ -7,6 +7,7 @@ - #include - #include - -+#include "string/strcmp/streq.h" - #include "string/strcmp/strprefix.h" - - -@@ -41,6 +42,9 @@ is_valid_hash(const char *hash) - { - hash = strprefix(hash, "!") ?: hash; - -+ if (streq(hash, "*")) -+ return true; -+ - // Minimum hash length - if (strlen(hash) < 13) - return false; --- -2.52.0 - diff --git a/shadow-4.19.0-usermod-add-optimizations.patch b/shadow-4.19.0-usermod-add-optimizations.patch deleted file mode 100644 index 4a883e6..0000000 --- a/shadow-4.19.0-usermod-add-optimizations.patch +++ /dev/null @@ -1,75 +0,0 @@ -From 958b4859991e700b61af2f9e07e3aa87ad1d9218 Mon Sep 17 00:00:00 2001 -From: Alejandro Colomar -Date: Sat, 17 Jan 2026 00:56:21 +0100 -Subject: [PATCH] Revert "src/usermod.c: Remove optimizations" - -This wasn't only an optimization; it also skipped some checks that were -now spuriously triggering errors. We may be able to get rid of the -optimizations, but that will need more analysis. For now, let's revert -to a known-good state. - -Fixes: 6a8a25dc7de6 (2025-10-15; "src/usermod.c: Remove optimizations") -Reverts: 6a8a25dc7de6 (2025-10-15; "src/usermod.c: Remove optimizations") -Closes: -Reported-by: Adam Williamson -Signed-off-by: Alejandro Colomar ---- - src/usermod.c | 42 ++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 42 insertions(+) - -diff --git a/src/usermod.c b/src/usermod.c -index 7400bf84..7cd7a859 100644 ---- a/src/usermod.c -+++ b/src/usermod.c -@@ -1391,6 +1391,48 @@ process_flags(int argc, char **argv, struct option_flags *flags) - } - #endif /* WITH_SELINUX */ - -+ if (user_newid == user_id) { -+ uflg = false; -+ oflg = false; -+ } -+ if (user_newgid == user_gid) { -+ gflg = false; -+ } -+ if ( (NULL != user_newshell) -+ && streq(user_newshell, user_shell)) { -+ sflg = false; -+ } -+ if (streq(user_newname, user_name)) { -+ lflg = false; -+ } -+ if (user_newinactive == user_inactive) { -+ fflg = false; -+ } -+ if (user_newexpire == user_expire) { -+ eflg = false; -+ } -+ if ( (NULL != user_newhome) -+ && streq(user_newhome, user_home)) { -+ dflg = false; -+ mflg = false; -+ } -+ if ( (NULL != user_newcomment) -+ && streq(user_newcomment, user_comment)) { -+ cflg = false; -+ } -+ -+ if (!(Uflg || uflg || sflg || pflg || mflg || Lflg || -+ lflg || Gflg || gflg || fflg || eflg || dflg || cflg -+#ifdef ENABLE_SUBIDS -+ || vflg || Vflg || wflg || Wflg -+#endif /* ENABLE_SUBIDS */ -+#ifdef WITH_SELINUX -+ || Zflg -+#endif /* WITH_SELINUX */ -+ )) { -+ exit (E_SUCCESS); -+ } -+ - if (!is_shadow_pwd && (eflg || fflg)) { - fprintf (stderr, - _("%s: shadow passwords required for -e and -f\n"), --- -2.52.0 - diff --git a/shadow-4.19.0-chkhash2.patch b/shadow-4.19.3-chkhash.patch similarity index 59% rename from shadow-4.19.0-chkhash2.patch rename to shadow-4.19.3-chkhash.patch index 1742544..6dfc159 100644 --- a/shadow-4.19.0-chkhash2.patch +++ b/shadow-4.19.3-chkhash.patch @@ -1,57 +1,20 @@ -From 9b67543987e3d140c86f1b8e2b5db5c10d8bc3c5 Mon Sep 17 00:00:00 2001 -From: Alejandro Colomar -Date: Thu, 15 Jan 2026 01:11:52 +0100 -Subject: [PATCH 1/4] lib/chkhash.c: is_valid_hash(): Accept an empty hash - -It represents a passwordless account. -That is discouraged, but accepted. - -Fixes: c44f1e096a19 (2025-07-20; "chpasswd: Check hash before write when using -e") -Link: -Reported-by: Marc 'Zugschlus' Haber -Reported-by: "Serge E. Hallyn" -Reported-by: Adam Williamson -Co-authored-by: "Serge E. Hallyn" -Signed-off-by: Alejandro Colomar ---- - lib/chkhash.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/lib/chkhash.c b/lib/chkhash.c -index 71e0fb4e..d0a8dc01 100644 ---- a/lib/chkhash.c -+++ b/lib/chkhash.c -@@ -42,6 +42,10 @@ is_valid_hash(const char *hash) - { - hash = strprefix(hash, "!") ?: hash; - -+ // Passwordless account; discouraged -+ if (streq(hash, "")) -+ return true; -+ - if (streq(hash, "*")) - return true; - --- -2.52.0 - - -From bce404a7a831de911cf20fc8d4c548957f70bc72 Mon Sep 17 00:00:00 2001 +From 4b2e669441438a6ae91c82a24c796894aa6a53b2 Mon Sep 17 00:00:00 2001 From: Alejandro Colomar Date: Thu, 15 Jan 2026 01:14:46 +0100 -Subject: [PATCH 2/4] lib/chkhash.c: is_valid_hash(): Update comment +Subject: [PATCH 1/3] lib/chkhash.c: is_valid_hash(): Update comment This checks the entire shadow(5) 2nd field, which is more than just a hash. Reported-by: Tobias Stoeckmann Signed-off-by: Alejandro Colomar +(cherry picked from commit bce404a7a831de911cf20fc8d4c548957f70bc72) --- lib/chkhash.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/chkhash.c b/lib/chkhash.c -index d0a8dc01..1723f862 100644 +index 348dfe7478f8..48aaa417e9a9 100644 --- a/lib/chkhash.c +++ b/lib/chkhash.c @@ -31,9 +31,7 @@ match_regex(const char *pattern, const char *string) @@ -66,22 +29,23 @@ index d0a8dc01..1723f862 100644 * regex from: https://man.archlinux.org/man/crypt.5.en */ -- -2.52.0 +2.53.0 -From 9a86c515a1e7caeeb9e60fa63871170a2dfd98f0 Mon Sep 17 00:00:00 2001 +From b72386978e0c994c5efc91d548da68a8d97088ab Mon Sep 17 00:00:00 2001 From: Alejandro Colomar Date: Thu, 15 Jan 2026 01:24:10 +0100 -Subject: [PATCH 3/4] lib/chkhash.c: is_valid_hash(): Comment meaning of !hash +Subject: [PATCH 2/3] lib/chkhash.c: is_valid_hash(): Comment meaning of !hash and * Signed-off-by: Alejandro Colomar +(cherry picked from commit 9a86c515a1e7caeeb9e60fa63871170a2dfd98f0) --- lib/chkhash.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/chkhash.c b/lib/chkhash.c -index 1723f862..101f2004 100644 +index 48aaa417e9a9..9123038adef0 100644 --- a/lib/chkhash.c +++ b/lib/chkhash.c @@ -38,12 +38,14 @@ match_regex(const char *pattern, const char *string) @@ -100,21 +64,22 @@ index 1723f862..101f2004 100644 return true; -- -2.52.0 +2.53.0 -From 6be13b2f84a2c1a0d0f4129b5258b4b443e7f86c Mon Sep 17 00:00:00 2001 +From 4486e3e0f8b74e6af27b5dcb4114fd776afdd605 Mon Sep 17 00:00:00 2001 From: Alejandro Colomar Date: Fri, 16 Jan 2026 01:52:32 +0100 -Subject: [PATCH 4/4] man/shadow.5.xml: Document "*" +Subject: [PATCH 3/3] man/shadow.5.xml: Document "*" Signed-off-by: Alejandro Colomar +(cherry picked from commit 6be13b2f84a2c1a0d0f4129b5258b4b443e7f86c) --- man/shadow.5.xml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/man/shadow.5.xml b/man/shadow.5.xml -index dc7fdfde..d3cc0398 100644 +index dc7fdfde542f..d3cc03982c47 100644 --- a/man/shadow.5.xml +++ b/man/shadow.5.xml @@ -82,8 +82,12 @@ @@ -133,5 +98,5 @@ index dc7fdfde..d3cc0398 100644 Refer to crypt -- -2.52.0 +2.53.0 diff --git a/shadow-utils.spec b/shadow-utils.spec index ec8df78..426f19b 100644 --- a/shadow-utils.spec +++ b/shadow-utils.spec @@ -1,12 +1,12 @@ Summary: Utilities for managing accounts and shadow password files Name: shadow-utils -Version: 4.19.0 -Release: 6%{?dist} +Version: 4.19.3 +Release: 1%{?dist} Epoch: 2 License: BSD-3-Clause AND GPL-2.0-or-later URL: https://github.com/shadow-maint/shadow -Source0: https://github.com/shadow-maint/shadow/releases/download/4.19.0/shadow-4.19.0.tar.xz -Source1: https://github.com/shadow-maint/shadow/releases/download/4.19.0/shadow-4.19.0.tar.xz.asc +Source0: https://github.com/shadow-maint/shadow/releases/download/4.19.3/shadow-4.19.3.tar.xz +Source1: https://github.com/shadow-maint/shadow/releases/download/4.19.3/shadow-4.19.3.tar.xz.asc Source2: shadow-utils.useradd Source3: shadow-utils.login.defs Source4: shadow-bsd.txt @@ -26,17 +26,8 @@ Patch0: shadow-4.15.0-manfix.patch Patch1: shadow-4.19.0-account-tools-setuid.patch # https://github.com/shadow-maint/shadow/commit/3e8c105f0703264e947d8c034b90419794955d49 Patch2: shadow-4-19-useradd-support-btrfs.patch -# https://github.com/shadow-maint/shadow/commit/3e8c105f0703264e947d8c034b90419794955d49 -Patch3: shadow-4.19.0-chkhash1.patch -# https://github.com/shadow-maint/shadow/commit/9b67543987e3d140c86f1b8e2b5db5c10d8bc3c5 -Patch4: shadow-4.19.0-chkhash2.patch -# https://github.com/shadow-maint/shadow/commit/958b4859991e700b61af2f9e07e3aa87ad1d9218 -Patch5: shadow-4.19.0-usermod-add-optimizations.patch -# https://github.com/shadow-maint/shadow/pull/1520 -# Approved by upstream for 4.19.3 this weekend: -# https://github.com/shadow-maint/shadow/issues/1521 -# Fixes the hash check to accept hashes with \ or n in the salt -Patch6: 1520.patch +# https://github.com/shadow-maint/shadow/commit/6be13b2f84a2c1a0d0f4129b5258b4b443e7f86c +Patch3: shadow-4.19.3-chkhash.patch ### Dependencies ### Requires: audit-libs >= 1.6.5 @@ -115,7 +106,7 @@ Requires: shadow-utils-subid = %{epoch}:%{version}-%{release} Development files for shadow-utils-subid. %prep -%autosetup -p 1 -S git -n shadow-4.19.0 +%autosetup -p 1 -S git -n shadow-4.19.3 iconv -f ISO88591 -t utf-8 doc/HOWTO > doc/HOWTO.utf8 cp -f doc/HOWTO.utf8 doc/HOWTO @@ -286,6 +277,10 @@ rm -f $RPM_BUILD_ROOT/%{_libdir}/libsubid.a %{_libdir}/libsubid.so %changelog +* Wed Feb 11 2026 Debarshi Ray - 2:4.19.3-1 +- Rebase to version 4.19.3 + Resolves: #2426288 + * Tue Jan 27 2026 Adam Williamson - 2:4.19.0-6 - chkhash.c: fix escaping in SHA-256 / SHA-512 / MD5 regexes diff --git a/sources b/sources index 22ae907..d12859f 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (shadow-4.19.0.tar.xz) = 0846c34f426101213ab6277bbcdc58c28b3a54df2f68d1c1addcc8c5aa79ce3e15d5d8dfcb9cc6dbd1b758e0cd8676c68ca65268f5a037d4c24aa7d358c9a390 -SHA512 (shadow-4.19.0.tar.xz.asc) = 34c1a764d06a5d24533cbb57310de7462eb632c1de904901699d48f44401b1b1f4751db35f2b0e2b9a057cf1a777ccddbae4bc6b19a6db865ebc3e30fde0d060 +SHA512 (shadow-4.19.3.tar.xz) = f2b41f8186681eb98dae0da87ed1a1f03327c5005c9d4bf9500801352e318de6f5954dc5b8f30ab9aece728b1efb74b4ff8fb2720acc4c2aaef701331a4a5a05 +SHA512 (shadow-4.19.3.tar.xz.asc) = 295a6bffefd333a9ea84fa59b368f5c48d0ac5224199624b768087098110b0f0c19bef37f5c474c45277980758dcb6728e8bb17eb7ab1a57603cad41f1dd00ab From 0fba1e26ce07e5cb003b594266f8b34fdb3477f6 Mon Sep 17 00:00:00 2001 From: Iker Pedrosa Date: Thu, 23 Apr 2026 15:20:03 +0200 Subject: [PATCH 2/9] btrfs: simplify checks improve useradd behavior for non-btrfs Signed-off-by: Iker Pedrosa --- shadow-4.19.3-useradd-fix-btrfs.patch | 492 ++++++++++++++++++++++++++ shadow-utils.spec | 7 +- 2 files changed, 498 insertions(+), 1 deletion(-) create mode 100644 shadow-4.19.3-useradd-fix-btrfs.patch diff --git a/shadow-4.19.3-useradd-fix-btrfs.patch b/shadow-4.19.3-useradd-fix-btrfs.patch new file mode 100644 index 0000000..47671d9 --- /dev/null +++ b/shadow-4.19.3-useradd-fix-btrfs.patch @@ -0,0 +1,492 @@ +From 4079070c4b8ced8df9d86366ad113fc3c2e4e49c Mon Sep 17 00:00:00 2001 +From: Alejandro Colomar +Date: Wed, 22 Apr 2026 11:02:36 +0200 +Subject: [PATCH 1/5] lib/btrfs.c: btrfs_is_subvolume(): Simplify error check + +Signed-off-by: Alejandro Colomar +--- + lib/btrfs.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/lib/btrfs.c b/lib/btrfs.c +index 85ec7dbc..fe20cf30 100644 +--- a/lib/btrfs.c ++++ b/lib/btrfs.c +@@ -67,8 +67,7 @@ int btrfs_is_subvolume(const char *path) + if (ret <= 0) + return ret; + +- ret = stat(path, &st); +- if (ret == -1) ++ if (stat(path, &st) == -1) + return -1; + + if (st.st_ino != BTRFS_FIRST_FREE_OBJECTID || !S_ISDIR(st.st_mode)) { +-- +2.53.0 + + +From 7a4faaaf46314547cc5e6c8264c3a11753ef9352 Mon Sep 17 00:00:00 2001 +From: Alejandro Colomar +Date: Wed, 22 Apr 2026 11:14:20 +0200 +Subject: [PATCH 2/5] lib/, src/: Move statfs(2) call out of is_btrfs() + +This simplifies the return value of is_btrfs() into a boolean. + +Signed-off-by: Alejandro Colomar +--- + lib/btrfs.c | 25 +++++++++---------------- + lib/prototypes.h | 3 ++- + src/useradd.c | 11 +++++++++-- + 3 files changed, 20 insertions(+), 19 deletions(-) + +diff --git a/lib/btrfs.c b/lib/btrfs.c +index fe20cf30..065c7938 100644 +--- a/lib/btrfs.c ++++ b/lib/btrfs.c +@@ -60,12 +60,13 @@ int btrfs_remove_subvolume(const char *path) + */ + int btrfs_is_subvolume(const char *path) + { +- struct stat st; +- int ret; ++ struct stat st; ++ struct statfs sfs; + +- ret = is_btrfs(path); +- if (ret <= 0) +- return ret; ++ if (statfs(path, &sfs) == -1) ++ return -1; ++ if (!is_btrfs(&sfs)) ++ return 0; + + if (stat(path, &st) == -1) + return -1; +@@ -78,16 +79,8 @@ int btrfs_is_subvolume(const char *path) + } + + +-/* Adapted from btrfsprogs */ +-int is_btrfs(const char *path) ++bool ++is_btrfs(const struct statfs *sfs) + { +- struct statfs sfs; +- int ret; +- +- ret = statfs(path, &sfs); +- if (ret == -1) +- return -1; +- +- return sfs.f_type == BTRFS_SUPER_MAGIC; ++ return sfs->f_type == BTRFS_SUPER_MAGIC; + } +- +diff --git a/lib/prototypes.h b/lib/prototypes.h +index 9a03e312..42aa2923 100644 +--- a/lib/prototypes.h ++++ b/lib/prototypes.h +@@ -23,6 +23,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -54,7 +55,7 @@ extern int isexpired (const struct passwd *, /*@null@*/const struct spwd *); + extern int btrfs_create_subvolume(const char *path); + extern int btrfs_remove_subvolume(const char *path); + extern int btrfs_is_subvolume(const char *path); +-extern int is_btrfs(const char *path); ++extern bool is_btrfs(const struct statfs *sfs); + #endif + + /* basename() renamed to Basename() to avoid libc name space confusion */ +diff --git a/src/useradd.c b/src/useradd.c +index df679d28..5ce6cd6a 100644 +--- a/src/useradd.c ++++ b/src/useradd.c +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -2265,6 +2266,7 @@ static void create_home(const struct option_flags *flags) + #if WITH_BTRFS + if (subvolflg && (strlen(prefix_user_home) - (int)strlen(path)) <= 1) { + char *btrfs_check = strdup(path); ++ struct statfs sfs; + + if (!btrfs_check) { + fprintf(stderr, +@@ -2273,13 +2275,18 @@ static void create_home(const struct option_flags *flags) + fail_exit(E_HOMEDIR, process_selinux); + } + stpcpy(&btrfs_check[strlen(path) - strlen(cp) - 1], ""); +- if (is_btrfs(btrfs_check) <= 0) { ++ if (statfs(btrfs_check, &sfs) == -1) { ++ fprintf(stderr, "%s: statfs(\"%s\"): %s\n", ++ Prog, btrfs_check, strerrno()); ++ fail_exit(E_HOMEDIR, process_selinux); ++ } ++ free(btrfs_check); ++ if (!is_btrfs(&sfs)) { + fprintf(stderr, + _("%s: home directory \"%s\" must be mounted on BTRFS\n"), + Prog, path); + fail_exit(E_HOMEDIR, process_selinux); + } +- free(btrfs_check); + // make subvolume to mount for user instead of directory + if (btrfs_create_subvolume(path)) { + fprintf(stderr, +-- +2.53.0 + + +From 96460c7240264c0022cebc9ba1774993ee2594cf Mon Sep 17 00:00:00 2001 +From: Alejandro Colomar +Date: Wed, 22 Apr 2026 11:21:14 +0200 +Subject: [PATCH 3/5] lib/, src/: Move btrfs.c prototypes to lib/btrfs.h + +Signed-off-by: Alejandro Colomar +--- + lib/Makefile.am | 2 +- + lib/btrfs.c | 4 ++++ + lib/btrfs.h | 23 +++++++++++++++++++++++ + lib/prototypes.h | 9 --------- + src/useradd.c | 1 + + src/userdel.c | 1 + + src/usermod.c | 1 + + 7 files changed, 31 insertions(+), 10 deletions(-) + create mode 100644 lib/btrfs.h + +diff --git a/lib/Makefile.am b/lib/Makefile.am +index 7c488f82..0664e610 100644 +--- a/lib/Makefile.am ++++ b/lib/Makefile.am +@@ -290,7 +290,7 @@ libshadow_la_SOURCES += tcbfuncs.c tcbfuncs.h + endif + + if WITH_BTRFS +-libshadow_la_SOURCES += btrfs.c ++libshadow_la_SOURCES += btrfs.c btrfs.h + endif + + if ENABLE_LASTLOG +diff --git a/lib/btrfs.c b/lib/btrfs.c +index 065c7938..15b6b315 100644 +--- a/lib/btrfs.c ++++ b/lib/btrfs.c +@@ -1,3 +1,7 @@ ++#include "config.h" ++ ++#include "btrfs.h" ++ + #include + #include + #include +diff --git a/lib/btrfs.h b/lib/btrfs.h +new file mode 100644 +index 00000000..50b70488 +--- /dev/null ++++ b/lib/btrfs.h +@@ -0,0 +1,23 @@ ++// SPDX-FileCopyrightText: 2026, Alejandro Colomar ++// SPDX-License-Identifier: BSD-3-Clause ++ ++ ++#ifndef SHADOW_INCLUDE_LIB_BTRFS_H_ ++#define SHADOW_INCLUDE_LIB_BTRFS_H_ ++ ++ ++#include "config.h" ++ ++#include ++#include ++ ++ ++#ifdef WITH_BTRFS ++int btrfs_create_subvolume(const char *path); ++int btrfs_remove_subvolume(const char *path); ++int btrfs_is_subvolume(const char *path); ++bool is_btrfs(const struct statfs *sfs); ++#endif ++ ++ ++#endif // include guard +diff --git a/lib/prototypes.h b/lib/prototypes.h +index 42aa2923..d22c477a 100644 +--- a/lib/prototypes.h ++++ b/lib/prototypes.h +@@ -23,7 +23,6 @@ + + #include + #include +-#include + #include + #include + #include +@@ -50,14 +49,6 @@ extern int expire (const struct passwd *, /*@null@*/const struct spwd *); + /* isexpired.c */ + extern int isexpired (const struct passwd *, /*@null@*/const struct spwd *); + +-/* btrfs.c */ +-#ifdef WITH_BTRFS +-extern int btrfs_create_subvolume(const char *path); +-extern int btrfs_remove_subvolume(const char *path); +-extern int btrfs_is_subvolume(const char *path); +-extern bool is_btrfs(const struct statfs *sfs); +-#endif +- + /* basename() renamed to Basename() to avoid libc name space confusion */ + /* basename.c */ + extern /*@observer@*/const char *Basename (const char *str); +diff --git a/src/useradd.c b/src/useradd.c +index 5ce6cd6a..9bd32b11 100644 +--- a/src/useradd.c ++++ b/src/useradd.c +@@ -34,6 +34,7 @@ + #include "alloc/malloc.h" + #include "atoi/a2i.h" + #include "atoi/getnum.h" ++#include "btrfs.h" + #include "chkname.h" + #include "defines.h" + #include "faillog.h" +diff --git a/src/userdel.c b/src/userdel.c +index 9b7d81be..ebd064c0 100644 +--- a/src/userdel.c ++++ b/src/userdel.c +@@ -20,6 +20,7 @@ + #include + #include + ++#include "btrfs.h" + #ifdef ACCT_TOOLS_SETUID + #ifdef USE_PAM + #include "pam_defs.h" +diff --git a/src/usermod.c b/src/usermod.c +index 7c0321a6..3afe19ea 100644 +--- a/src/usermod.c ++++ b/src/usermod.c +@@ -32,6 +32,7 @@ + #include "alloc/malloc.h" + #include "atoi/a2i.h" + #include "atoi/getnum.h" ++#include "btrfs.h" + #include "chkname.h" + #include "defines.h" + #include "faillog.h" +-- +2.53.0 + + +From 7be9a6540f1cad477fd4f4e83d25904a5095bb86 Mon Sep 17 00:00:00 2001 +From: Hadi Chokr +Date: Tue, 21 Apr 2026 09:18:19 +0200 +Subject: [PATCH 4/5] useradd(8): fallback to regular dir for BTRFS home on + non-BTRFS parent + +When the --btrfs-subvolume-home option is used but the parent directory +is not on a BTRFS filesystem, useradd previously failed with an error. +This is too strict; instead, fall back to creating a regular directory +and issue a warning. The subvolume creation is attempted only when the +parent is BTRFS. Otherwise, a regular directory is created and a +syslog(3) warning is logged. + +Fixes: 3e8c105 (2026-01-02; "src/useradd: Support config for creating home dirs as Btrfs subvolumes") +Co-authored-by: Hadi Chokr +Co-authored-by: Alejandro Colomar +Signed-off-by: Alejandro Colomar +--- + man/useradd.8.xml | 27 ++++++++++++++++++++++-- + src/useradd.c | 52 +++++++++++++++++++++++------------------------ + 2 files changed, 51 insertions(+), 28 deletions(-) + +diff --git a/man/useradd.8.xml b/man/useradd.8.xml +index 8a087e13..0bde6683 100644 +--- a/man/useradd.8.xml ++++ b/man/useradd.8.xml +@@ -2,6 +2,7 @@ + + + +- Note: this feature works only if the underlying filesystem supports +- Btrfs subvolumes. ++ If the parent directory of the user's home directory is ++ not on a Btrfs filesystem, ++ useradd will not create a ++ subvolume. ++ Instead, it creates a regular directory, ++ prints a warning to standard error, ++ and logs the event via syslog at level ++ LOG_WARN. ++ The user account is still created successfully. ++ ++ ++ If the filesystem type cannot be determined (e.g., because of ++ insufficient permissions, an I/O error, ++ or a ++ ++ statfs ++ 2 ++ ++ failure), ++ useradd treats this as a fatal error: ++ the home directory is not created, ++ the command exits with a non‑zero status ++ (E_HOMEDIR, 12), ++ and an error message is printed. + + + +diff --git a/src/useradd.c b/src/useradd.c +index 9bd32b11..9210379c 100644 +--- a/src/useradd.c ++++ b/src/useradd.c +@@ -1,11 +1,11 @@ +-/* +- * SPDX-FileCopyrightText: 1991 - 1994, Julianne Frances Haugh +- * SPDX-FileCopyrightText: 1996 - 2000, Marek Michałkiewicz +- * SPDX-FileCopyrightText: 2000 - 2006, Tomasz Kłoczko +- * SPDX-FileCopyrightText: 2007 - 2012, Nicolas François +- * +- * SPDX-License-Identifier: BSD-3-Clause +- */ ++// SPDX-FileCopyrightText: 1991-1994, Julianne Frances Haugh ++// SPDX-FileCopyrightText: 1996-2000, Marek Michałkiewicz ++// SPDX-FileCopyrightText: 2000-2006, Tomasz Kłoczko ++// SPDX-FileCopyrightText: 2007-2012, Nicolas François ++// SPDX-FileCopyrightText: 2025-2026, Hadi Chokr ++// SPDX-FileCopyrightText: 2026, Alejandro Colomar ++// SPDX-License-Identifier: BSD-3-Clause ++ + + #include "config.h" + +@@ -2251,6 +2251,8 @@ static void create_home(const struct option_flags *flags) + owner root:root. + */ + for (cp = strtok(bhome, "/"); cp != NULL; cp = strtok(NULL, "/")) { ++ bool dir_created; ++ + /* Avoid turning a relative path into an absolute path. */ + if (strprefix(bhome, "/") || !streq(path, "")) + strcat(path, "/"); +@@ -2260,10 +2262,7 @@ static void create_home(const struct option_flags *flags) + continue; + } + +- /* Check if parent directory is BTRFS, fail if requesting +- subvolume but no BTRFS. The paths could be different by the +- trailing slash +- */ ++ dir_created = false; + #if WITH_BTRFS + if (subvolflg && (strlen(prefix_user_home) - (int)strlen(path)) <= 1) { + char *btrfs_check = strdup(path); +@@ -2284,25 +2283,26 @@ static void create_home(const struct option_flags *flags) + free(btrfs_check); + if (!is_btrfs(&sfs)) { + fprintf(stderr, +- _("%s: home directory \"%s\" must be mounted on BTRFS\n"), +- Prog, path); +- fail_exit(E_HOMEDIR, process_selinux); ++ _("%s: warning: \"%s\" is not on BTRFS; creating regular directory instead of subvolume\n"), ++ Prog, prefix_user_home); ++ } else { ++ if (btrfs_create_subvolume(path)) { ++ fprintf(stderr, ++ _("%s: failed to create BTRFS subvolume: %s\n"), ++ Prog, path); ++ fail_exit(E_HOMEDIR, process_selinux); ++ } ++ dir_created = true; + } +- // make subvolume to mount for user instead of directory +- if (btrfs_create_subvolume(path)) { +- fprintf(stderr, +- _("%s: failed to create BTRFS subvolume: %s\n"), ++ } ++#endif ++ if (!dir_created) { ++ if (mkdir(path, 0) != 0) { ++ fprintf(stderr, _("%s: cannot create directory %s\n"), + Prog, path); + fail_exit(E_HOMEDIR, process_selinux); + } + } +- else +-#endif +- if (mkdir(path, 0) != 0) { +- fprintf(stderr, _("%s: cannot create directory %s\n"), +- Prog, path); +- fail_exit(E_HOMEDIR, process_selinux); +- } + if (chown(path, 0, 0) < 0) { + fprintf(stderr, + _("%s: warning: chown on `%s' failed: %m\n"), +-- +2.53.0 + + +From 827f69b864461ab6d7549762bef06ab4495d2587 Mon Sep 17 00:00:00 2001 +From: Hadi Chokr +Date: Mon, 20 Apr 2026 12:27:31 +0200 +Subject: [PATCH 5/5] man/useradd.8.xml: Remove trailing spaces from + useradd.8.xml + +Signed-off-by: Hadi Chokr +Reviewed-by: Alejandro Colomar +--- + man/useradd.8.xml | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/man/useradd.8.xml b/man/useradd.8.xml +index 0bde6683..f85780e2 100644 +--- a/man/useradd.8.xml ++++ b/man/useradd.8.xml +@@ -207,7 +207,7 @@ + user's login directory. The default is to append the + LOGIN name to + BASE_DIR and use that as the +- login directory name. ++ login directory name. + The directory HOME_DIR is not created by + default. However it will be created for non-system users if either the + flag is specifed or +@@ -422,7 +422,7 @@ + + + +- Create the user's home directory if it does not exist. ++ Create the user's home directory if it does not exist. + The files and directories contained in the skeleton directory + (which can be defined with the option) + will be copied to the home directory. +@@ -512,7 +512,7 @@ + password himself. + + +- Note:Avoid this option on the command ++ Note:Avoid this option on the command + line because the password (or encrypted password) will + be visible by users listing the processes. + +-- +2.53.0 + diff --git a/shadow-utils.spec b/shadow-utils.spec index 426f19b..d381c31 100644 --- a/shadow-utils.spec +++ b/shadow-utils.spec @@ -1,7 +1,7 @@ Summary: Utilities for managing accounts and shadow password files Name: shadow-utils Version: 4.19.3 -Release: 1%{?dist} +Release: 2%{?dist} Epoch: 2 License: BSD-3-Clause AND GPL-2.0-or-later URL: https://github.com/shadow-maint/shadow @@ -28,6 +28,8 @@ Patch1: shadow-4.19.0-account-tools-setuid.patch Patch2: shadow-4-19-useradd-support-btrfs.patch # https://github.com/shadow-maint/shadow/commit/6be13b2f84a2c1a0d0f4129b5258b4b443e7f86c Patch3: shadow-4.19.3-chkhash.patch +# https://github.com/shadow-maint/shadow/commit/827f69b864461ab6d7549762bef06ab4495d2587 +Patch4: shadow-4.19.3-useradd-fix-btrfs.patch ### Dependencies ### Requires: audit-libs >= 1.6.5 @@ -277,6 +279,9 @@ rm -f $RPM_BUILD_ROOT/%{_libdir}/libsubid.a %{_libdir}/libsubid.so %changelog +* Thu Apr 23 2026 Iker Pedrosa - 2:4.19.3-2 +- btrfs: simplify checks improve useradd behavior for non-btrfs + * Wed Feb 11 2026 Debarshi Ray - 2:4.19.3-1 - Rebase to version 4.19.3 Resolves: #2426288 From 90cbfea201b6bb6d45c88c39c98b6a266e122bc9 Mon Sep 17 00:00:00 2001 From: Iker Pedrosa Date: Thu, 23 Apr 2026 15:20:03 +0200 Subject: [PATCH 3/9] btrfs: simplify checks improve useradd behavior for non-btrfs Signed-off-by: Iker Pedrosa --- shadow-4.19.0-useradd-fix-btrfs.patch | 492 ++++++++++++++++++++++++++ shadow-utils.spec | 7 +- 2 files changed, 498 insertions(+), 1 deletion(-) create mode 100644 shadow-4.19.0-useradd-fix-btrfs.patch diff --git a/shadow-4.19.0-useradd-fix-btrfs.patch b/shadow-4.19.0-useradd-fix-btrfs.patch new file mode 100644 index 0000000..47671d9 --- /dev/null +++ b/shadow-4.19.0-useradd-fix-btrfs.patch @@ -0,0 +1,492 @@ +From 4079070c4b8ced8df9d86366ad113fc3c2e4e49c Mon Sep 17 00:00:00 2001 +From: Alejandro Colomar +Date: Wed, 22 Apr 2026 11:02:36 +0200 +Subject: [PATCH 1/5] lib/btrfs.c: btrfs_is_subvolume(): Simplify error check + +Signed-off-by: Alejandro Colomar +--- + lib/btrfs.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/lib/btrfs.c b/lib/btrfs.c +index 85ec7dbc..fe20cf30 100644 +--- a/lib/btrfs.c ++++ b/lib/btrfs.c +@@ -67,8 +67,7 @@ int btrfs_is_subvolume(const char *path) + if (ret <= 0) + return ret; + +- ret = stat(path, &st); +- if (ret == -1) ++ if (stat(path, &st) == -1) + return -1; + + if (st.st_ino != BTRFS_FIRST_FREE_OBJECTID || !S_ISDIR(st.st_mode)) { +-- +2.53.0 + + +From 7a4faaaf46314547cc5e6c8264c3a11753ef9352 Mon Sep 17 00:00:00 2001 +From: Alejandro Colomar +Date: Wed, 22 Apr 2026 11:14:20 +0200 +Subject: [PATCH 2/5] lib/, src/: Move statfs(2) call out of is_btrfs() + +This simplifies the return value of is_btrfs() into a boolean. + +Signed-off-by: Alejandro Colomar +--- + lib/btrfs.c | 25 +++++++++---------------- + lib/prototypes.h | 3 ++- + src/useradd.c | 11 +++++++++-- + 3 files changed, 20 insertions(+), 19 deletions(-) + +diff --git a/lib/btrfs.c b/lib/btrfs.c +index fe20cf30..065c7938 100644 +--- a/lib/btrfs.c ++++ b/lib/btrfs.c +@@ -60,12 +60,13 @@ int btrfs_remove_subvolume(const char *path) + */ + int btrfs_is_subvolume(const char *path) + { +- struct stat st; +- int ret; ++ struct stat st; ++ struct statfs sfs; + +- ret = is_btrfs(path); +- if (ret <= 0) +- return ret; ++ if (statfs(path, &sfs) == -1) ++ return -1; ++ if (!is_btrfs(&sfs)) ++ return 0; + + if (stat(path, &st) == -1) + return -1; +@@ -78,16 +79,8 @@ int btrfs_is_subvolume(const char *path) + } + + +-/* Adapted from btrfsprogs */ +-int is_btrfs(const char *path) ++bool ++is_btrfs(const struct statfs *sfs) + { +- struct statfs sfs; +- int ret; +- +- ret = statfs(path, &sfs); +- if (ret == -1) +- return -1; +- +- return sfs.f_type == BTRFS_SUPER_MAGIC; ++ return sfs->f_type == BTRFS_SUPER_MAGIC; + } +- +diff --git a/lib/prototypes.h b/lib/prototypes.h +index 9a03e312..42aa2923 100644 +--- a/lib/prototypes.h ++++ b/lib/prototypes.h +@@ -23,6 +23,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -54,7 +55,7 @@ extern int isexpired (const struct passwd *, /*@null@*/const struct spwd *); + extern int btrfs_create_subvolume(const char *path); + extern int btrfs_remove_subvolume(const char *path); + extern int btrfs_is_subvolume(const char *path); +-extern int is_btrfs(const char *path); ++extern bool is_btrfs(const struct statfs *sfs); + #endif + + /* basename() renamed to Basename() to avoid libc name space confusion */ +diff --git a/src/useradd.c b/src/useradd.c +index df679d28..5ce6cd6a 100644 +--- a/src/useradd.c ++++ b/src/useradd.c +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -2265,6 +2266,7 @@ static void create_home(const struct option_flags *flags) + #if WITH_BTRFS + if (subvolflg && (strlen(prefix_user_home) - (int)strlen(path)) <= 1) { + char *btrfs_check = strdup(path); ++ struct statfs sfs; + + if (!btrfs_check) { + fprintf(stderr, +@@ -2273,13 +2275,18 @@ static void create_home(const struct option_flags *flags) + fail_exit(E_HOMEDIR, process_selinux); + } + stpcpy(&btrfs_check[strlen(path) - strlen(cp) - 1], ""); +- if (is_btrfs(btrfs_check) <= 0) { ++ if (statfs(btrfs_check, &sfs) == -1) { ++ fprintf(stderr, "%s: statfs(\"%s\"): %s\n", ++ Prog, btrfs_check, strerrno()); ++ fail_exit(E_HOMEDIR, process_selinux); ++ } ++ free(btrfs_check); ++ if (!is_btrfs(&sfs)) { + fprintf(stderr, + _("%s: home directory \"%s\" must be mounted on BTRFS\n"), + Prog, path); + fail_exit(E_HOMEDIR, process_selinux); + } +- free(btrfs_check); + // make subvolume to mount for user instead of directory + if (btrfs_create_subvolume(path)) { + fprintf(stderr, +-- +2.53.0 + + +From 96460c7240264c0022cebc9ba1774993ee2594cf Mon Sep 17 00:00:00 2001 +From: Alejandro Colomar +Date: Wed, 22 Apr 2026 11:21:14 +0200 +Subject: [PATCH 3/5] lib/, src/: Move btrfs.c prototypes to lib/btrfs.h + +Signed-off-by: Alejandro Colomar +--- + lib/Makefile.am | 2 +- + lib/btrfs.c | 4 ++++ + lib/btrfs.h | 23 +++++++++++++++++++++++ + lib/prototypes.h | 9 --------- + src/useradd.c | 1 + + src/userdel.c | 1 + + src/usermod.c | 1 + + 7 files changed, 31 insertions(+), 10 deletions(-) + create mode 100644 lib/btrfs.h + +diff --git a/lib/Makefile.am b/lib/Makefile.am +index 7c488f82..0664e610 100644 +--- a/lib/Makefile.am ++++ b/lib/Makefile.am +@@ -290,7 +290,7 @@ libshadow_la_SOURCES += tcbfuncs.c tcbfuncs.h + endif + + if WITH_BTRFS +-libshadow_la_SOURCES += btrfs.c ++libshadow_la_SOURCES += btrfs.c btrfs.h + endif + + if ENABLE_LASTLOG +diff --git a/lib/btrfs.c b/lib/btrfs.c +index 065c7938..15b6b315 100644 +--- a/lib/btrfs.c ++++ b/lib/btrfs.c +@@ -1,3 +1,7 @@ ++#include "config.h" ++ ++#include "btrfs.h" ++ + #include + #include + #include +diff --git a/lib/btrfs.h b/lib/btrfs.h +new file mode 100644 +index 00000000..50b70488 +--- /dev/null ++++ b/lib/btrfs.h +@@ -0,0 +1,23 @@ ++// SPDX-FileCopyrightText: 2026, Alejandro Colomar ++// SPDX-License-Identifier: BSD-3-Clause ++ ++ ++#ifndef SHADOW_INCLUDE_LIB_BTRFS_H_ ++#define SHADOW_INCLUDE_LIB_BTRFS_H_ ++ ++ ++#include "config.h" ++ ++#include ++#include ++ ++ ++#ifdef WITH_BTRFS ++int btrfs_create_subvolume(const char *path); ++int btrfs_remove_subvolume(const char *path); ++int btrfs_is_subvolume(const char *path); ++bool is_btrfs(const struct statfs *sfs); ++#endif ++ ++ ++#endif // include guard +diff --git a/lib/prototypes.h b/lib/prototypes.h +index 42aa2923..d22c477a 100644 +--- a/lib/prototypes.h ++++ b/lib/prototypes.h +@@ -23,7 +23,6 @@ + + #include + #include +-#include + #include + #include + #include +@@ -50,14 +49,6 @@ extern int expire (const struct passwd *, /*@null@*/const struct spwd *); + /* isexpired.c */ + extern int isexpired (const struct passwd *, /*@null@*/const struct spwd *); + +-/* btrfs.c */ +-#ifdef WITH_BTRFS +-extern int btrfs_create_subvolume(const char *path); +-extern int btrfs_remove_subvolume(const char *path); +-extern int btrfs_is_subvolume(const char *path); +-extern bool is_btrfs(const struct statfs *sfs); +-#endif +- + /* basename() renamed to Basename() to avoid libc name space confusion */ + /* basename.c */ + extern /*@observer@*/const char *Basename (const char *str); +diff --git a/src/useradd.c b/src/useradd.c +index 5ce6cd6a..9bd32b11 100644 +--- a/src/useradd.c ++++ b/src/useradd.c +@@ -34,6 +34,7 @@ + #include "alloc/malloc.h" + #include "atoi/a2i.h" + #include "atoi/getnum.h" ++#include "btrfs.h" + #include "chkname.h" + #include "defines.h" + #include "faillog.h" +diff --git a/src/userdel.c b/src/userdel.c +index 9b7d81be..ebd064c0 100644 +--- a/src/userdel.c ++++ b/src/userdel.c +@@ -20,6 +20,7 @@ + #include + #include + ++#include "btrfs.h" + #ifdef ACCT_TOOLS_SETUID + #ifdef USE_PAM + #include "pam_defs.h" +diff --git a/src/usermod.c b/src/usermod.c +index 7c0321a6..3afe19ea 100644 +--- a/src/usermod.c ++++ b/src/usermod.c +@@ -32,6 +32,7 @@ + #include "alloc/malloc.h" + #include "atoi/a2i.h" + #include "atoi/getnum.h" ++#include "btrfs.h" + #include "chkname.h" + #include "defines.h" + #include "faillog.h" +-- +2.53.0 + + +From 7be9a6540f1cad477fd4f4e83d25904a5095bb86 Mon Sep 17 00:00:00 2001 +From: Hadi Chokr +Date: Tue, 21 Apr 2026 09:18:19 +0200 +Subject: [PATCH 4/5] useradd(8): fallback to regular dir for BTRFS home on + non-BTRFS parent + +When the --btrfs-subvolume-home option is used but the parent directory +is not on a BTRFS filesystem, useradd previously failed with an error. +This is too strict; instead, fall back to creating a regular directory +and issue a warning. The subvolume creation is attempted only when the +parent is BTRFS. Otherwise, a regular directory is created and a +syslog(3) warning is logged. + +Fixes: 3e8c105 (2026-01-02; "src/useradd: Support config for creating home dirs as Btrfs subvolumes") +Co-authored-by: Hadi Chokr +Co-authored-by: Alejandro Colomar +Signed-off-by: Alejandro Colomar +--- + man/useradd.8.xml | 27 ++++++++++++++++++++++-- + src/useradd.c | 52 +++++++++++++++++++++++------------------------ + 2 files changed, 51 insertions(+), 28 deletions(-) + +diff --git a/man/useradd.8.xml b/man/useradd.8.xml +index 8a087e13..0bde6683 100644 +--- a/man/useradd.8.xml ++++ b/man/useradd.8.xml +@@ -2,6 +2,7 @@ + + + +- Note: this feature works only if the underlying filesystem supports +- Btrfs subvolumes. ++ If the parent directory of the user's home directory is ++ not on a Btrfs filesystem, ++ useradd will not create a ++ subvolume. ++ Instead, it creates a regular directory, ++ prints a warning to standard error, ++ and logs the event via syslog at level ++ LOG_WARN. ++ The user account is still created successfully. ++ ++ ++ If the filesystem type cannot be determined (e.g., because of ++ insufficient permissions, an I/O error, ++ or a ++ ++ statfs ++ 2 ++ ++ failure), ++ useradd treats this as a fatal error: ++ the home directory is not created, ++ the command exits with a non‑zero status ++ (E_HOMEDIR, 12), ++ and an error message is printed. + + + +diff --git a/src/useradd.c b/src/useradd.c +index 9bd32b11..9210379c 100644 +--- a/src/useradd.c ++++ b/src/useradd.c +@@ -1,11 +1,11 @@ +-/* +- * SPDX-FileCopyrightText: 1991 - 1994, Julianne Frances Haugh +- * SPDX-FileCopyrightText: 1996 - 2000, Marek Michałkiewicz +- * SPDX-FileCopyrightText: 2000 - 2006, Tomasz Kłoczko +- * SPDX-FileCopyrightText: 2007 - 2012, Nicolas François +- * +- * SPDX-License-Identifier: BSD-3-Clause +- */ ++// SPDX-FileCopyrightText: 1991-1994, Julianne Frances Haugh ++// SPDX-FileCopyrightText: 1996-2000, Marek Michałkiewicz ++// SPDX-FileCopyrightText: 2000-2006, Tomasz Kłoczko ++// SPDX-FileCopyrightText: 2007-2012, Nicolas François ++// SPDX-FileCopyrightText: 2025-2026, Hadi Chokr ++// SPDX-FileCopyrightText: 2026, Alejandro Colomar ++// SPDX-License-Identifier: BSD-3-Clause ++ + + #include "config.h" + +@@ -2251,6 +2251,8 @@ static void create_home(const struct option_flags *flags) + owner root:root. + */ + for (cp = strtok(bhome, "/"); cp != NULL; cp = strtok(NULL, "/")) { ++ bool dir_created; ++ + /* Avoid turning a relative path into an absolute path. */ + if (strprefix(bhome, "/") || !streq(path, "")) + strcat(path, "/"); +@@ -2260,10 +2262,7 @@ static void create_home(const struct option_flags *flags) + continue; + } + +- /* Check if parent directory is BTRFS, fail if requesting +- subvolume but no BTRFS. The paths could be different by the +- trailing slash +- */ ++ dir_created = false; + #if WITH_BTRFS + if (subvolflg && (strlen(prefix_user_home) - (int)strlen(path)) <= 1) { + char *btrfs_check = strdup(path); +@@ -2284,25 +2283,26 @@ static void create_home(const struct option_flags *flags) + free(btrfs_check); + if (!is_btrfs(&sfs)) { + fprintf(stderr, +- _("%s: home directory \"%s\" must be mounted on BTRFS\n"), +- Prog, path); +- fail_exit(E_HOMEDIR, process_selinux); ++ _("%s: warning: \"%s\" is not on BTRFS; creating regular directory instead of subvolume\n"), ++ Prog, prefix_user_home); ++ } else { ++ if (btrfs_create_subvolume(path)) { ++ fprintf(stderr, ++ _("%s: failed to create BTRFS subvolume: %s\n"), ++ Prog, path); ++ fail_exit(E_HOMEDIR, process_selinux); ++ } ++ dir_created = true; + } +- // make subvolume to mount for user instead of directory +- if (btrfs_create_subvolume(path)) { +- fprintf(stderr, +- _("%s: failed to create BTRFS subvolume: %s\n"), ++ } ++#endif ++ if (!dir_created) { ++ if (mkdir(path, 0) != 0) { ++ fprintf(stderr, _("%s: cannot create directory %s\n"), + Prog, path); + fail_exit(E_HOMEDIR, process_selinux); + } + } +- else +-#endif +- if (mkdir(path, 0) != 0) { +- fprintf(stderr, _("%s: cannot create directory %s\n"), +- Prog, path); +- fail_exit(E_HOMEDIR, process_selinux); +- } + if (chown(path, 0, 0) < 0) { + fprintf(stderr, + _("%s: warning: chown on `%s' failed: %m\n"), +-- +2.53.0 + + +From 827f69b864461ab6d7549762bef06ab4495d2587 Mon Sep 17 00:00:00 2001 +From: Hadi Chokr +Date: Mon, 20 Apr 2026 12:27:31 +0200 +Subject: [PATCH 5/5] man/useradd.8.xml: Remove trailing spaces from + useradd.8.xml + +Signed-off-by: Hadi Chokr +Reviewed-by: Alejandro Colomar +--- + man/useradd.8.xml | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/man/useradd.8.xml b/man/useradd.8.xml +index 0bde6683..f85780e2 100644 +--- a/man/useradd.8.xml ++++ b/man/useradd.8.xml +@@ -207,7 +207,7 @@ + user's login directory. The default is to append the + LOGIN name to + BASE_DIR and use that as the +- login directory name. ++ login directory name. + The directory HOME_DIR is not created by + default. However it will be created for non-system users if either the + flag is specifed or +@@ -422,7 +422,7 @@ + + + +- Create the user's home directory if it does not exist. ++ Create the user's home directory if it does not exist. + The files and directories contained in the skeleton directory + (which can be defined with the option) + will be copied to the home directory. +@@ -512,7 +512,7 @@ + password himself. + + +- Note:Avoid this option on the command ++ Note:Avoid this option on the command + line because the password (or encrypted password) will + be visible by users listing the processes. + +-- +2.53.0 + diff --git a/shadow-utils.spec b/shadow-utils.spec index ec8df78..e62258a 100644 --- a/shadow-utils.spec +++ b/shadow-utils.spec @@ -1,7 +1,7 @@ Summary: Utilities for managing accounts and shadow password files Name: shadow-utils Version: 4.19.0 -Release: 6%{?dist} +Release: 7%{?dist} Epoch: 2 License: BSD-3-Clause AND GPL-2.0-or-later URL: https://github.com/shadow-maint/shadow @@ -37,6 +37,8 @@ Patch5: shadow-4.19.0-usermod-add-optimizations.patch # https://github.com/shadow-maint/shadow/issues/1521 # Fixes the hash check to accept hashes with \ or n in the salt Patch6: 1520.patch +# https://github.com/shadow-maint/shadow/commit/827f69b864461ab6d7549762bef06ab4495d2587 +Patch7: shadow-4.19.0-useradd-fix-btrfs.patch ### Dependencies ### Requires: audit-libs >= 1.6.5 @@ -286,6 +288,9 @@ rm -f $RPM_BUILD_ROOT/%{_libdir}/libsubid.a %{_libdir}/libsubid.so %changelog +* Wed Apr 29 2026 Iker Pedrosa - 2:4.19.0-7 +- btrfs: simplify checks improve useradd behavior for non-btrfs + * Tue Jan 27 2026 Adam Williamson - 2:4.19.0-6 - chkhash.c: fix escaping in SHA-256 / SHA-512 / MD5 regexes From 4a56d06039633e31494bf759e96673dd632925a7 Mon Sep 17 00:00:00 2001 From: Iker Pedrosa Date: Tue, 14 Apr 2026 16:25:41 +0200 Subject: [PATCH 4/9] Tests: run system tests Tests comprehensive functionality from shadow using the upstream system test suite in testing farm. - Add plans/system-tests.fmf: run upstream shadow system tests via pytest-mh. - Add tests/mhc-fedora-ci.yaml: topology configuration to connect to the test system. - Add .fmf/version: enable testing farm integration. Signed-off-by: Iker Pedrosa --- .fmf/version | 1 + plans/tier0-functional.fmf | 48 ++++++++++++++++++++++++++++++++++++++ tests/mhc-fedora-ci.yaml | 13 +++++++++++ 3 files changed, 62 insertions(+) create mode 100644 .fmf/version create mode 100644 plans/tier0-functional.fmf create mode 100644 tests/mhc-fedora-ci.yaml diff --git a/.fmf/version b/.fmf/version new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/.fmf/version @@ -0,0 +1 @@ +1 diff --git a/plans/tier0-functional.fmf b/plans/tier0-functional.fmf new file mode 100644 index 0000000..7fb6f9c --- /dev/null +++ b/plans/tier0-functional.fmf @@ -0,0 +1,48 @@ +summary: Tier 0 functional tests for shadow-utils +description: | + Run comprehensive system tests for shadow-utils. These tests validate user and group + account management functionality by testing actual system operations including user + creation, password management, group operations, and verification of system files + (i.e. /etc/passwd, /etc/shadow). + +provision: + how: virtual + image: fedora + +prepare: + - name: Install general dependencies + how: install + package: + - expect + - git + - python3-pip + + - name: Setup SSH keys for localhost testing + how: shell + script: + - ssh-keygen -t rsa -f /root/.ssh/id_rsa -N "" -q + - cat /root/.ssh/id_rsa.pub >> /root/.ssh/authorized_keys + - chmod 600 /root/.ssh/authorized_keys + - ssh-keyscan -H localhost >> /root/.ssh/known_hosts + + - name: Clone shadow repository + how: shell + script: + - git clone https://github.com/shadow-maint/shadow.git /tmp/shadow-test + + - name: Copy test topology for Fedora CI + how: shell + script: + - cp tests/mhc-fedora-ci.yaml /tmp/shadow-test/tests/system + + - name: Install test dependencies + how: shell + script: + - pip3 install -r /tmp/shadow-test/tests/system/requirements.txt + +execute: + how: tmt + duration: 30m + script: | + cd /tmp/shadow-test/tests/system + pytest --mh-config=mhc-fedora-ci.yaml --mh-lazy-ssh -v diff --git a/tests/mhc-fedora-ci.yaml b/tests/mhc-fedora-ci.yaml new file mode 100644 index 0000000..8747e67 --- /dev/null +++ b/tests/mhc-fedora-ci.yaml @@ -0,0 +1,13 @@ +provisioned_topologies: +- shadow +domains: +- id: shadow + hosts: + - hostname: localhost + role: shadow + conn: + type: ssh + host: localhost + user: root + artifacts: + - /var/log/* From 871df3223d7cf041a69d1b19bb9d1fdf4d3220b9 Mon Sep 17 00:00:00 2001 From: Iker Pedrosa Date: Wed, 27 May 2026 11:40:27 +0200 Subject: [PATCH 5/9] Enable use of PAM for chpasswd and newusers Resolves: #2461179 and #2283963 Signed-off-by: Iker Pedrosa --- shadow-4.19.0-account-tools-setuid.patch | 377 ----------------------- shadow-utils.spec | 14 +- 2 files changed, 9 insertions(+), 382 deletions(-) delete mode 100644 shadow-4.19.0-account-tools-setuid.patch diff --git a/shadow-4.19.0-account-tools-setuid.patch b/shadow-4.19.0-account-tools-setuid.patch deleted file mode 100644 index 9452582..0000000 --- a/shadow-4.19.0-account-tools-setuid.patch +++ /dev/null @@ -1,377 +0,0 @@ -diff -up shadow-4.19.0-rc1/src/chpasswd.c.account-tools-setuid shadow-4.19.0-rc1/src/chpasswd.c ---- shadow-4.19.0-rc1/src/chpasswd.c.account-tools-setuid 2025-12-07 16:56:38.563285789 +0100 -+++ shadow-4.19.0-rc1/src/chpasswd.c 2025-12-09 14:54:29.232282499 +0100 -@@ -466,9 +466,11 @@ int main (int argc, char **argv) - char *newpwd; - const char *salt; - -+#ifdef ACCT_TOOLS_SETUID - #ifdef USE_PAM - bool use_pam = true; - #endif /* USE_PAM */ -+#endif /* ACCT_TOOLS_SETUID */ - - bool errors = false; - intmax_t line = 0; -@@ -495,19 +497,23 @@ int main (int argc, char **argv) - process_root_flag ("-R", argc, argv); - prefix = process_prefix_flag ("-P", argc, argv); - -+#ifdef ACCT_TOOLS_SETUID - #ifdef USE_PAM - if (md5flg || eflg || cflg || prefix[0]) { - use_pam = false; - } - #endif /* USE_PAM */ -+#endif /* ACCT_TOOLS_SETUID */ - - OPENLOG (Prog); - - check_perms (); - -+#ifdef ACCT_TOOLS_SETUID - #ifdef USE_PAM - if (!use_pam) - #endif /* USE_PAM */ -+#endif /* ACCT_TOOLS_SETUID */ - { - is_shadow_pwd = spw_file_present (); - -@@ -562,6 +568,7 @@ int main (int argc, char **argv) - } - newpwd = cp; - -+#ifdef ACCT_TOOLS_SETUID - #ifdef USE_PAM - if (use_pam) { - if (do_pam_passwd_non_interactive (Prog, name, newpwd) != 0) { -@@ -572,6 +579,7 @@ int main (int argc, char **argv) - } - } else - #endif /* USE_PAM */ -+#endif /* ACCT_TOOLS_SETUID */ - { - - /* -@@ -706,9 +714,11 @@ int main (int argc, char **argv) - * password database. - */ - if (errors) { -+#ifdef ACCT_TOOLS_SETUID - #ifdef USE_PAM - if (!use_pam) - #endif /* USE_PAM */ -+#endif /* ACCT_TOOLS_SETUID */ - { - fprintf (stderr, - _("%s: error detected, changes ignored\n"), -@@ -717,9 +727,11 @@ int main (int argc, char **argv) - fail_exit (1, process_selinux); - } - -+#ifdef ACCT_TOOLS_SETUID - #ifdef USE_PAM - if (!use_pam) - #endif /* USE_PAM */ -+#endif /* ACCT_TOOLS_SETUID */ - { - /* Save the changes */ - close_files (&flags); -diff -up shadow-4.19.0-rc1/src/groupmems.c.account-tools-setuid shadow-4.19.0-rc1/src/groupmems.c ---- shadow-4.19.0-rc1/src/groupmems.c.account-tools-setuid 2025-12-07 16:56:38.564285805 +0100 -+++ shadow-4.19.0-rc1/src/groupmems.c 2025-12-09 14:57:23.767054141 +0100 -@@ -14,9 +14,11 @@ - #include - #include - #include -+#ifdef ACCT_TOOLS_SETUID - #ifdef USE_PAM - #include "pam_defs.h" - #endif /* USE_PAM */ -+#endif /* ACCT_TOOLS_SETUID */ - #include - - #include "alloc/malloc.h" -@@ -432,6 +434,7 @@ static void - check_perms(MAYBE_UNUSED bool process_selinux) - { - if (!list) { -+#ifdef ACCT_TOOLS_SETUID - #ifdef USE_PAM - pam_handle_t *pamh = NULL; - int retval; -@@ -465,7 +468,8 @@ check_perms(MAYBE_UNUSED bool process_se - fail_exit (1, process_selinux); - } - (void) pam_end (pamh, retval); --#endif -+#endif /* USE_PAM */ -+#endif /* ACCT_TOOLS_SETUID */ - } - } - -diff -up shadow-4.19.0-rc1/src/newusers.c.account-tools-setuid shadow-4.19.0-rc1/src/newusers.c ---- shadow-4.19.0-rc1/src/newusers.c.account-tools-setuid 2025-12-07 16:56:38.565285821 +0100 -+++ shadow-4.19.0-rc1/src/newusers.c 2025-12-09 15:07:40.115500988 +0100 -@@ -74,6 +74,7 @@ struct option_flags { - static const char Prog[] = "newusers"; - - static bool rflg = false; /* create a system account */ -+#ifndef ACCT_TOOLS_SETUID - #ifndef USE_PAM - static /*@null@*//*@observer@*/char *crypt_method = NULL; - #define cflg (NULL != crypt_method) -@@ -90,6 +91,7 @@ static long bcrypt_rounds = 13; - static long yescrypt_cost = 5; - #endif /* USE_YESCRYPT */ - #endif /* !USE_PAM */ -+#endif /* !ACCT_TOOLS_SETUID */ - - static bool is_shadow; - #ifdef SHADOWGRP -@@ -112,9 +114,11 @@ NORETURN static void fail_exit (int, boo - static int add_group (const char *, const char *, gid_t *, gid_t); - static int get_user_id (const char *, uid_t *); - static int add_user (const char *, uid_t, gid_t); -+#ifndef ACCT_TOOLS_SETUID - #ifndef USE_PAM - static int update_passwd (struct passwd *, const char *); - #endif /* !USE_PAM */ -+#endif /* !ACCT_TOOLS_SETUID */ - static int add_passwd (struct passwd *, const char *); - static void process_flags (int argc, char **argv, struct option_flags *flags); - static void check_flags (void); -@@ -136,6 +140,7 @@ static void usage (int status) - "Options:\n"), - Prog); - (void) fputs (_(" -b, --badname allow bad names\n"), usageout); -+#ifndef ACCT_TOOLS_SETUID - #ifndef USE_PAM - (void) fprintf (usageout, - _(" -c, --crypt-method METHOD the crypt method (one of %s)\n"), -@@ -151,9 +156,11 @@ static void usage (int status) - #endif - ); - #endif /* !USE_PAM */ -+#endif /* !ACCT_TOOLS_SETUID */ - (void) fputs (_(" -h, --help display this help message and exit\n"), usageout); - (void) fputs (_(" -r, --system create system accounts\n"), usageout); - (void) fputs (_(" -R, --root CHROOT_DIR directory to chroot into\n"), usageout); -+#ifndef ACCT_TOOLS_SETUID - #ifndef USE_PAM - #if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) || defined(USE_YESCRYPT) - (void) fputs (_(" -s, --sha-rounds number of rounds for the SHA, BCRYPT\n" -@@ -161,6 +168,7 @@ static void usage (int status) - usageout); - #endif /* USE_SHA_CRYPT || USE_BCRYPT || USE_YESCRYPT */ - #endif /* !USE_PAM */ -+#endif /* !ACCT_TOOLS_SETUID */ - (void) fputs ("\n", usageout); - - exit (status); -@@ -426,6 +434,7 @@ static int add_user (const char *name, u - return (pw_update (&pwent) == 0) ? -1 : 0; - } - -+#ifndef ACCT_TOOLS_SETUID - #ifndef USE_PAM - /* - * update_passwd - update the password in the passwd entry -@@ -478,6 +487,7 @@ static int update_passwd (struct passwd - return 0; - } - #endif /* !USE_PAM */ -+#endif /* !ACCT_TOOLS_SETUID */ - - /* - * add_passwd - add or update the encrypted password -@@ -487,10 +497,13 @@ add_passwd(struct passwd *pwd, MAYBE_UNU - { - const struct spwd *sp; - struct spwd spent; -+#ifndef ACCT_TOOLS_SETUID - #ifndef USE_PAM - char *cp; - #endif /* !USE_PAM */ -+#endif /* !ACCT_TOOLS_SETUID */ - -+#ifndef ACCT_TOOLS_SETUID - #ifndef USE_PAM - void *crypt_arg = NULL; - if (NULL != crypt_method) { -@@ -528,13 +541,14 @@ add_passwd(struct passwd *pwd, MAYBE_UNU - return update_passwd (pwd, password); - } - #endif /* USE_PAM */ -+#endif /* !ACCT_TOOLS_SETUID */ - - /* - * Do the first and easiest shadow file case. The user already - * exists in the shadow password file. - */ - sp = spw_locate (pwd->pw_name); --#ifndef USE_PAM -+#if !defined(ACCT_TOOLS_SETUID) && !defined(USE_PAM) - if (NULL != sp) { - spent = *sp; - if ( (NULL != crypt_method) -@@ -571,7 +585,7 @@ add_passwd(struct passwd *pwd, MAYBE_UNU - if (!streq(pwd->pw_passwd, "x")) { - return update_passwd (pwd, password); - } --#else /* USE_PAM */ -+#else /* !ACCT_TOOLS_SETUID && !USE_PAM */ - /* - * If there is already a shadow entry, do not touch it. - * If there is already a passwd entry with a password, do not -@@ -582,14 +596,14 @@ add_passwd(struct passwd *pwd, MAYBE_UNU - || !streq(pwd->pw_passwd, "x")) { - return 0; - } --#endif /* USE_PAM */ -+#endif /* !ACCT_TOOLS_SETUID && !USE_PAM */ - - /* - * Now the really hard case - I need to create an entirely new - * shadow password file entry. - */ - spent.sp_namp = pwd->pw_name; --#ifndef USE_PAM -+#if !defined(ACCT_TOOLS_SETUID) && !defined(USE_PAM) - if ((crypt_method != NULL) && streq(crypt_method, "NONE")) { - spent.sp_pwdp = (char *)password; - } else { -@@ -647,32 +647,38 @@ add_passwd(struct passwd *pwd, MAYBE_UNU - static void process_flags (int argc, char **argv, struct option_flags *flags) - { - int c; -+#ifndef ACCT_TOOLS_SETUID - #ifndef USE_PAM - #if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) || defined(USE_YESCRYPT) - int bad_s; - #endif /* USE_SHA_CRYPT || USE_BCRYPT || USE_YESCRYPT */ - #endif /* !USE_PAM */ -+#endif /* !ACCT_TOOLS_SETUID */ - static struct option long_options[] = { - {"badname", no_argument, NULL, 'b'}, -+#ifndef ACCT_TOOLS_SETUID - #ifndef USE_PAM - {"crypt-method", required_argument, NULL, 'c'}, - #endif /* !USE_PAM */ -+#endif /* !ACCT_TOOLS_SETUID */ - {"help", no_argument, NULL, 'h'}, - {"system", no_argument, NULL, 'r'}, - {"root", required_argument, NULL, 'R'}, -+#ifndef ACCT_TOOLS_SETUID - #ifndef USE_PAM - #if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) || defined(USE_YESCRYPT) - {"sha-rounds", required_argument, NULL, 's'}, - #endif /* USE_SHA_CRYPT || USE_BCRYPT || USE_YESCRYPT */ - #endif /* !USE_PAM */ -+#endif /* !ACCT_TOOLS_SETUID */ - {NULL, 0, NULL, '\0'} - }; - - while ((c = getopt_long (argc, argv, --#ifndef USE_PAM -+#if !defined(ACCT_TOOLS_SETUID) && !defined(USE_PAM) - #if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) || defined(USE_YESCRYPT) - "c:bhrs:", --#else /* !USE_SHA_CRYPT && !USE_BCRYPT && !USE_YESCRYPT */ -+#else /* !ACCT_TOOLS_SETUID && !USE_PAM */ - "c:bhr", - #endif /* USE_SHA_CRYPT || USE_BCRYPT || USE_YESCRYPT */ - #else /* USE_PAM */ -@@ -670,11 +690,13 @@ static void process_flags (int argc, cha - case 'b': - allow_bad_names = true; - break; -+#ifndef ACCT_TOOLS_SETUID - #ifndef USE_PAM - case 'c': - crypt_method = optarg; - break; - #endif /* !USE_PAM */ -+#endif /* !ACCT_TOOLS_SETUID */ - case 'h': - usage (EXIT_SUCCESS); - break; -@@ -684,6 +706,7 @@ static void process_flags (int argc, cha - case 'R': /* no-op, handled in process_root_flag () */ - flags->chroot = true; - break; -+#ifndef ACCT_TOOLS_SETUID - #ifndef USE_PAM - #if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) || defined(USE_YESCRYPT) - case 's': -@@ -723,6 +746,7 @@ static void process_flags (int argc, cha - break; - #endif /* USE_SHA_CRYPT || USE_BCRYPT || USE_YESCRYPT */ - #endif /* !USE_PAM */ -+#endif /* !ACCT_TOOLS_SETUID */ - default: - usage (EXIT_FAILURE); - break; -@@ -755,6 +779,7 @@ static void process_flags (int argc, cha - */ - static void check_flags (void) - { -+#ifndef ACCT_TOOLS_SETUID - #ifndef USE_PAM - #if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) || defined(USE_YESCRYPT) - if (sflg && !cflg) { -@@ -787,6 +812,7 @@ static void check_flags (void) - } - } - #endif /* !USE_PAM */ -+#endif /* !ACCT_TOOLS_SETUID */ - } - - /* -@@ -1065,12 +1091,14 @@ int main (int argc, char **argv) - intmax_t line = 0; - uid_t uid; - gid_t gid; -+#ifdef ACCT_TOOLS_SETUID - #ifdef USE_PAM - intmax_t *lines = NULL; - char **usernames = NULL; - char **passwords = NULL; - size_t nusers = 0; - #endif /* USE_PAM */ -+#endif /* ACCT_TOOLS_SETUID */ - struct option_flags flags = {.chroot = false}; - bool process_selinux; - -@@ -1193,6 +1221,7 @@ int main (int argc, char **argv) - } - newpw = *pw; - -+#ifdef ACCT_TOOLS_SETUID - #ifdef USE_PAM - /* keep the list of user/password for later update by PAM */ - nusers++; -@@ -1207,6 +1236,7 @@ int main (int argc, char **argv) - usernames[nusers-1] = xstrdup(fields[0]); - passwords[nusers-1] = xstrdup(fields[1]); - #endif /* USE_PAM */ -+#endif /* ACCT_TOOLS_SETUID */ - if (!streq(fields[1], "") && add_passwd(&newpw, fields[1]) != 0) { - fprintf (stderr, - _("%s: line %jd: can't update password\n"), -@@ -1321,6 +1351,7 @@ int main (int argc, char **argv) - nscd_flush_cache ("group"); - sssd_flush_cache (SSSD_DB_PASSWD | SSSD_DB_GROUP); - -+#ifdef ACCT_TOOLS_SETUID - #ifdef USE_PAM - /* Now update the passwords using PAM */ - for (size_t i = 0; i < nusers; i++) { -@@ -1334,6 +1365,7 @@ int main (int argc, char **argv) - } - } - #endif /* USE_PAM */ -+#endif /* ACCT_TOOLS_SETUID */ - - exit (EXIT_SUCCESS); - } diff --git a/shadow-utils.spec b/shadow-utils.spec index d381c31..11243dd 100644 --- a/shadow-utils.spec +++ b/shadow-utils.spec @@ -1,7 +1,7 @@ Summary: Utilities for managing accounts and shadow password files Name: shadow-utils Version: 4.19.3 -Release: 2%{?dist} +Release: 3%{?dist} Epoch: 2 License: BSD-3-Clause AND GPL-2.0-or-later URL: https://github.com/shadow-maint/shadow @@ -22,8 +22,6 @@ Source7: passwd.pamd ### Patches ### # Misc manual page changes - non-upstreamable Patch0: shadow-4.15.0-manfix.patch -# Probably non-upstreamable -Patch1: shadow-4.19.0-account-tools-setuid.patch # https://github.com/shadow-maint/shadow/commit/3e8c105f0703264e947d8c034b90419794955d49 Patch2: shadow-4-19-useradd-support-btrfs.patch # https://github.com/shadow-maint/shadow/commit/6be13b2f84a2c1a0d0f4129b5258b4b443e7f86c @@ -146,6 +144,8 @@ install -d -m 755 $RPM_BUILD_ROOT%{_sysconfdir}/default install -p -c -m 0644 %{SOURCE3} $RPM_BUILD_ROOT%{_sysconfdir}/login.defs install -p -c -m 0600 %{SOURCE2} $RPM_BUILD_ROOT%{_sysconfdir}/default/useradd install -d -m 755 $RPM_BUILD_ROOT%{_pam_confdir} +install -m 644 %{SOURCE7} $RPM_BUILD_ROOT%{_pam_confdir}/chpasswd +install -m 644 %{SOURCE7} $RPM_BUILD_ROOT%{_pam_confdir}/newusers install -m 644 %{SOURCE7} $RPM_BUILD_ROOT%{_pam_confdir}/passwd @@ -194,11 +194,9 @@ rm $RPM_BUILD_ROOT%{_mandir}/*/man8/faillog.* # Remove PAM service files we don't use. rm $RPM_BUILD_ROOT%{_pam_confdir}/chfn -rm $RPM_BUILD_ROOT%{_pam_confdir}/chpasswd rm $RPM_BUILD_ROOT%{_pam_confdir}/chsh rm $RPM_BUILD_ROOT%{_pam_confdir}/groupmems rm $RPM_BUILD_ROOT%{_pam_confdir}/login -rm $RPM_BUILD_ROOT%{_pam_confdir}/newusers rm $RPM_BUILD_ROOT%{_pam_confdir}/su find $RPM_BUILD_ROOT%{_mandir} -depth -type d -empty -delete @@ -225,6 +223,8 @@ rm -f $RPM_BUILD_ROOT/%{_libdir}/libsubid.a %license gpl-2.0.txt shadow-bsd.txt %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/login.defs %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/default/useradd +%config(noreplace) %{_pam_confdir}/chpasswd +%config(noreplace) %{_pam_confdir}/newusers %config(noreplace) %{_pam_confdir}/passwd %{_bindir}/sg %attr(4755,root,root) %{_bindir}/chage @@ -279,6 +279,10 @@ rm -f $RPM_BUILD_ROOT/%{_libdir}/libsubid.a %{_libdir}/libsubid.so %changelog +* Wed May 27 2026 Iker Pedrosa - 2:4.19.3-3 +- Enable use of PAM for chpasswd and newusers + Resolves: #2461179 and #2283963 + * Thu Apr 23 2026 Iker Pedrosa - 2:4.19.3-2 - btrfs: simplify checks improve useradd behavior for non-btrfs From 8bd71d9f9156a632eb3850c1b2658fc21959f892 Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Fri, 17 Jul 2026 06:27:57 +0000 Subject: [PATCH 6/9] Rebuilt for https://fedoraproject.org/wiki/Fedora_45_Mass_Rebuild --- shadow-utils.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/shadow-utils.spec b/shadow-utils.spec index 11243dd..4f94261 100644 --- a/shadow-utils.spec +++ b/shadow-utils.spec @@ -1,7 +1,7 @@ Summary: Utilities for managing accounts and shadow password files Name: shadow-utils Version: 4.19.3 -Release: 3%{?dist} +Release: 4%{?dist} Epoch: 2 License: BSD-3-Clause AND GPL-2.0-or-later URL: https://github.com/shadow-maint/shadow @@ -279,6 +279,9 @@ rm -f $RPM_BUILD_ROOT/%{_libdir}/libsubid.a %{_libdir}/libsubid.so %changelog +* Fri Jul 17 2026 Fedora Release Engineering - 2:4.19.3-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_45_Mass_Rebuild + * Wed May 27 2026 Iker Pedrosa - 2:4.19.3-3 - Enable use of PAM for chpasswd and newusers Resolves: #2461179 and #2283963 From 8cb145bd7377a26dae190cc3b7ea46a293ac0a45 Mon Sep 17 00:00:00 2001 From: Iker Pedrosa Date: Thu, 2 Jul 2026 16:26:11 +0200 Subject: [PATCH 7/9] Rebase to v4.20.0-rc3 Signed-off-by: Iker Pedrosa --- .gitignore | 4 + shadow-4-19-useradd-support-btrfs.patch | 149 ------- shadow-4.15.0-manfix.patch | 162 -------- shadow-4.19.3-chkhash.patch | 102 ----- shadow-4.19.3-useradd-fix-btrfs.patch | 492 ------------------------ shadow-utils.spec | 28 +- sources | 4 +- 7 files changed, 14 insertions(+), 927 deletions(-) delete mode 100644 shadow-4-19-useradd-support-btrfs.patch delete mode 100644 shadow-4.15.0-manfix.patch delete mode 100644 shadow-4.19.3-chkhash.patch delete mode 100644 shadow-4.19.3-useradd-fix-btrfs.patch diff --git a/.gitignore b/.gitignore index 7db552e..13adb8c 100644 --- a/.gitignore +++ b/.gitignore @@ -48,3 +48,7 @@ shadow-4.1.4.2.tar.bz2 /shadow-4.19.2.tar.xz.asc /shadow-4.19.3.tar.xz /shadow-4.19.3.tar.xz.asc +/shadow-4.20.0-rc2.tar.xz +/shadow-4.20.0-rc2.tar.xz.asc +/shadow-4.20.0-rc3.tar.xz +/shadow-4.20.0-rc3.tar.xz.asc diff --git a/shadow-4-19-useradd-support-btrfs.patch b/shadow-4-19-useradd-support-btrfs.patch deleted file mode 100644 index b801289..0000000 --- a/shadow-4-19-useradd-support-btrfs.patch +++ /dev/null @@ -1,149 +0,0 @@ -From 3e8c105f0703264e947d8c034b90419794955d49 Mon Sep 17 00:00:00 2001 -From: Hadi Chokr -Date: Fri, 12 Dec 2025 11:18:06 +0100 -Subject: [PATCH] src/useradd: Support config for creating home dirs as Btrfs - subvolumes - -Closes: #1162 - -Co-authored-by: Neal Gompa -Signed-off-by: Hadi Chokr -Signed-off-by: Neal Gompa -Reviewed-by: Alejandro Colomar ---- - man/useradd.8.xml | 27 +++++++++++++++++++++++++++ - src/useradd.c | 24 ++++++++++++++++++++++++ - 2 files changed, 51 insertions(+) - -diff --git a/man/useradd.8.xml b/man/useradd.8.xml -index e6db7f6d..c745a620 100644 ---- a/man/useradd.8.xml -+++ b/man/useradd.8.xml -@@ -134,6 +134,33 @@ - - - -+ -+ -+ -+ -+ -+ -+ Create the user's home directory as a Btrfs subvolume. -+ -+ -+ If this option is not specified, -+ useradd will follow the default behavior -+ defined by the variable -+ in /etc/default/useradd. -+ If this variable is not set, the default value is no. -+ -+ -+ When the command-line option -+ is specified, -+ a Btrfs subvolume is created -+ regardless of any configuration file settings. -+ -+ -+ Note: this feature works only if the underlying filesystem supports -+ Btrfs subvolumes. -+ -+ -+ - - - ,  COMMENT -diff --git a/src/useradd.c b/src/useradd.c -index 899efe3c..8433ed8a 100644 ---- a/src/useradd.c -+++ b/src/useradd.c -@@ -114,6 +114,7 @@ static const char *def_shell = "/bin/bash"; - static const char *def_template = SKEL_DIR; - static const char *def_usrtemplate = USRSKELDIR; - static const char *def_create_mail_spool = "yes"; -+static const char *def_btrfs_subvolume_home = "no"; - static const char *def_log_init = "yes"; - - static long def_inactive = -1; -@@ -222,6 +223,7 @@ static bool home_added = false; - #define DSKEL "SKEL" - #define DUSRSKEL "USRSKEL" - #define DCREATE_MAIL_SPOOL "CREATE_MAIL_SPOOL" -+#define DBTRFS_SUBVOLUME_HOME "BTRFS_SUBVOLUME_HOME" - #define DLOG_INIT "LOG_INIT" - - /* local function prototypes */ -@@ -456,6 +458,7 @@ get_defaults(const struct option_flags *flags) - def_usrtemplate = xstrdup(ccp); - } - } -+ - /* - * Create by default user mail spool or not ? - */ -@@ -466,6 +469,15 @@ get_defaults(const struct option_flags *flags) - def_create_mail_spool = xstrdup(ccp); - } - -+ /* -+ * Create home directories as Btrfs subvolumes by default? -+ */ -+ else if (streq(buf, DBTRFS_SUBVOLUME_HOME)) { -+ if (streq(ccp, "")) -+ ccp = "no"; -+ def_btrfs_subvolume_home = xstrdup(ccp); -+ } -+ - /* - * By default do we add the user to the lastlog and faillog databases ? - */ -@@ -500,6 +512,7 @@ static void show_defaults (void) - printf ("SKEL=%s\n", def_template); - printf ("USRSKEL=%s\n", def_usrtemplate); - printf ("CREATE_MAIL_SPOOL=%s\n", def_create_mail_spool); -+ printf ("BTRFS_SUBVOLUME_HOME=%s\n", def_btrfs_subvolume_home); - printf ("LOG_INIT=%s\n", def_log_init); - } - -@@ -523,6 +536,7 @@ set_defaults(void) - bool out_skel = false; - bool out_usrskel = false; - bool out_create_mail_spool = false; -+ bool out_btrfs_subvolume_home = false; - bool out_log_init = false; - char buf[1024]; - char *new_file = NULL; -@@ -639,6 +653,11 @@ set_defaults(void) - DCREATE_MAIL_SPOOL "=%s\n", - def_create_mail_spool); - out_create_mail_spool = true; -+ } else if (!out_btrfs_subvolume_home && streq(buf, DBTRFS_SUBVOLUME_HOME)) { -+ fprintf(ofp, -+ DBTRFS_SUBVOLUME_HOME "=%s\n", -+ def_btrfs_subvolume_home); -+ out_btrfs_subvolume_home = true; - } else if (!out_log_init && streq(buf, DLOG_INIT)) { - fprintf(ofp, DLOG_INIT "=%s\n", def_log_init); - out_log_init = true; -@@ -673,6 +692,8 @@ set_defaults(void) - - if (!out_create_mail_spool) - fprintf (ofp, DCREATE_MAIL_SPOOL "=%s\n", def_create_mail_spool); -+ if (!out_btrfs_subvolume_home) -+ fprintf (ofp, DBTRFS_SUBVOLUME_HOME "=%s\n", def_btrfs_subvolume_home); - if (!out_log_init) - fprintf (ofp, DLOG_INIT "=%s\n", def_log_init); - /* -@@ -1431,6 +1452,9 @@ static void process_flags (int argc, char **argv, struct option_flags *flags) - } - } - -+ if (!subvolflg && strcaseeq(def_btrfs_subvolume_home, "yes")) -+ subvolflg = true; -+ - if (!gflg && !Nflg && !Uflg) { - /* Get the settings from login.defs */ - Uflg = getdef_bool ("USERGROUPS_ENAB"); --- -2.52.0 - diff --git a/shadow-4.15.0-manfix.patch b/shadow-4.15.0-manfix.patch deleted file mode 100644 index 34e62f9..0000000 --- a/shadow-4.15.0-manfix.patch +++ /dev/null @@ -1,162 +0,0 @@ -diff -up shadow-4.15.0/man/groupmems.8.xml.manfix shadow-4.15.0/man/groupmems.8.xml ---- shadow-4.15.0/man/groupmems.8.xml.manfix 2023-05-26 04:56:11.000000000 +0200 -+++ shadow-4.15.0/man/groupmems.8.xml 2024-02-09 10:42:20.337036378 +0100 -@@ -156,20 +156,10 @@ - - SETUP - -- The groupmems executable should be in mode -- 2710 as user root and in group -- groups. The system administrator can add users to -- group groups to allow or disallow them using the -- groupmems utility to manage their own group -- membership list. -+ In this operating system the groupmems executable -+ is not setuid and regular users cannot use it to manipulate -+ the membership of their own group. - -- -- -- $ groupadd -r groups -- $ chmod 2710 groupmems -- $ chown root:groups groupmems -- $ groupmems -g groups -a gk4 -- - - - -diff -up shadow-4.15.0/man/ja/man5/login.defs.5.manfix shadow-4.15.0/man/ja/man5/login.defs.5 ---- shadow-4.15.0/man/ja/man5/login.defs.5.manfix 2023-03-13 21:58:56.000000000 +0100 -+++ shadow-4.15.0/man/ja/man5/login.defs.5 2024-02-09 10:42:20.337036378 +0100 -@@ -123,10 +123,6 @@ 以下の参照表は、 - shadow パスワード機能のどのプログラムが - どのパラメータを使用するかを示したものである。 - .na --.IP chfn 12 --CHFN_AUTH CHFN_RESTRICT --.IP chsh 12 --CHFN_AUTH - .IP groupadd 12 - GID_MAX GID_MIN - .IP newusers 12 -diff -up shadow-4.15.0/man/login.defs.5.xml.manfix shadow-4.15.0/man/login.defs.5.xml ---- shadow-4.15.0/man/login.defs.5.xml.manfix 2024-01-22 22:36:43.000000000 +0100 -+++ shadow-4.15.0/man/login.defs.5.xml 2024-02-09 10:45:49.014407259 +0100 -@@ -144,6 +144,17 @@ - long numeric parameters is machine-dependent. - - -+ -+ Please note that the parameters in this configuration file control the -+ behavior of the tools from the shadow-utils component. None of these -+ tools uses the PAM mechanism, and the utilities that use PAM (such as the -+ passwd command) should be configured elsewhere. The only values that -+ affect PAM modules are ENCRYPT_METHOD and SHA_CRYPT_MAX_ROUNDS -+ for pam_unix module, FAIL_DELAY for pam_faildelay module, -+ and UMASK for pam_umask module. Refer to -+ pam(8) for more information. -+ -+ - The following configuration items are provided: - - -@@ -240,16 +251,6 @@ - - - -- chfn -- -- -- CHFN_AUTH -- CHFN_RESTRICT -- LOGIN_STRING -- -- -- -- - chgpasswd - - -@@ -276,14 +277,6 @@ - - - -- -- chsh -- -- -- CHSH_AUTH LOGIN_STRING -- -- -- - - - -@@ -352,34 +345,6 @@ - LASTLOG_UID_MAX - - -- -- login -- -- -- CONSOLE -- CONSOLE_GROUPS DEFAULT_HOME -- ENV_HZ ENV_PATH ENV_SUPATH -- ENV_TZ ENVIRON_FILE -- ERASECHAR FAIL_DELAY -- FAILLOG_ENAB -- FAKE_SHELL -- FTMP_FILE -- HUSHLOGIN_FILE -- ISSUE_FILE -- KILLCHAR -- LASTLOG_ENAB LASTLOG_UID_MAX -- LOGIN_RETRIES -- LOGIN_STRING -- LOGIN_TIMEOUT LOG_OK_LOGINS LOG_UNKFAIL_ENAB -- MAIL_CHECK_ENAB MAIL_DIR MAIL_FILE -- MOTD_FILE NOLOGINS_FILE PORTTIME_CHECKS_ENAB -- QUOTAS_ENAB -- TTYGROUP TTYPERM TTYTYPE_FILE -- ULIMIT UMASK -- USERGROUPS_ENAB -- -- -- - - - newgrp / sg -@@ -451,32 +416,6 @@ - - - -- -- su -- -- -- CONSOLE -- CONSOLE_GROUPS DEFAULT_HOME -- ENV_HZ ENVIRON_FILE -- ENV_PATH ENV_SUPATH -- ENV_TZ LOGIN_STRING MAIL_CHECK_ENAB -- MAIL_DIR MAIL_FILE QUOTAS_ENAB -- SULOG_FILE SU_NAME -- SU_WHEEL_ONLY -- SYSLOG_SU_ENAB -- USERGROUPS_ENAB -- -- -- -- -- sulogin -- -- -- ENV_HZ -- ENV_TZ -- -- -- - - useradd - diff --git a/shadow-4.19.3-chkhash.patch b/shadow-4.19.3-chkhash.patch deleted file mode 100644 index 6dfc159..0000000 --- a/shadow-4.19.3-chkhash.patch +++ /dev/null @@ -1,102 +0,0 @@ -From 4b2e669441438a6ae91c82a24c796894aa6a53b2 Mon Sep 17 00:00:00 2001 -From: Alejandro Colomar -Date: Thu, 15 Jan 2026 01:14:46 +0100 -Subject: [PATCH 1/3] lib/chkhash.c: is_valid_hash(): Update comment - -This checks the entire shadow(5) 2nd field, which is more than just -a hash. - -Reported-by: Tobias Stoeckmann -Signed-off-by: Alejandro Colomar -(cherry picked from commit bce404a7a831de911cf20fc8d4c548957f70bc72) ---- - lib/chkhash.c | 4 +--- - 1 file changed, 1 insertion(+), 3 deletions(-) - -diff --git a/lib/chkhash.c b/lib/chkhash.c -index 348dfe7478f8..48aaa417e9a9 100644 ---- a/lib/chkhash.c -+++ b/lib/chkhash.c -@@ -31,9 +31,7 @@ match_regex(const char *pattern, const char *string) - - - /* -- * is_valid_hash - check if the given string is a valid password hash -- * -- * Returns true if the string appears to be a valid hash, false otherwise. -+ * is_valid_hash - check if the string is a valid shadow(5) 2nd field. - * - * regex from: https://man.archlinux.org/man/crypt.5.en - */ --- -2.53.0 - - -From b72386978e0c994c5efc91d548da68a8d97088ab Mon Sep 17 00:00:00 2001 -From: Alejandro Colomar -Date: Thu, 15 Jan 2026 01:24:10 +0100 -Subject: [PATCH 2/3] lib/chkhash.c: is_valid_hash(): Comment meaning of !hash - and * - -Signed-off-by: Alejandro Colomar -(cherry picked from commit 9a86c515a1e7caeeb9e60fa63871170a2dfd98f0) ---- - lib/chkhash.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/lib/chkhash.c b/lib/chkhash.c -index 48aaa417e9a9..9123038adef0 100644 ---- a/lib/chkhash.c -+++ b/lib/chkhash.c -@@ -38,12 +38,14 @@ match_regex(const char *pattern, const char *string) - bool - is_valid_hash(const char *hash) - { -+ // Password temporarily locked - hash = strprefix(hash, "!") ?: hash; - - // Passwordless account; discouraged - if (streq(hash, "")) - return true; - -+ // Password permanently locked (and forgotten) - if (streq(hash, "*")) - return true; - --- -2.53.0 - - -From 4486e3e0f8b74e6af27b5dcb4114fd776afdd605 Mon Sep 17 00:00:00 2001 -From: Alejandro Colomar -Date: Fri, 16 Jan 2026 01:52:32 +0100 -Subject: [PATCH 3/3] man/shadow.5.xml: Document "*" - -Signed-off-by: Alejandro Colomar -(cherry picked from commit 6be13b2f84a2c1a0d0f4129b5258b4b443e7f86c) ---- - man/shadow.5.xml | 8 ++++++-- - 1 file changed, 6 insertions(+), 2 deletions(-) - -diff --git a/man/shadow.5.xml b/man/shadow.5.xml -index dc7fdfde542f..d3cc03982c47 100644 ---- a/man/shadow.5.xml -+++ b/man/shadow.5.xml -@@ -82,8 +82,12 @@ - If the password field begins with an exclamation mark !, - the password is locked. - The remaining characters on the -- line represent the password field before the password was -- locked. -+ line represent the password hash. -+ -+ -+ If the password hash consists of a star *, -+ password access is effectively disallowed; -+ this is because no password can produce a hash like this. - - - Refer to crypt --- -2.53.0 - diff --git a/shadow-4.19.3-useradd-fix-btrfs.patch b/shadow-4.19.3-useradd-fix-btrfs.patch deleted file mode 100644 index 47671d9..0000000 --- a/shadow-4.19.3-useradd-fix-btrfs.patch +++ /dev/null @@ -1,492 +0,0 @@ -From 4079070c4b8ced8df9d86366ad113fc3c2e4e49c Mon Sep 17 00:00:00 2001 -From: Alejandro Colomar -Date: Wed, 22 Apr 2026 11:02:36 +0200 -Subject: [PATCH 1/5] lib/btrfs.c: btrfs_is_subvolume(): Simplify error check - -Signed-off-by: Alejandro Colomar ---- - lib/btrfs.c | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) - -diff --git a/lib/btrfs.c b/lib/btrfs.c -index 85ec7dbc..fe20cf30 100644 ---- a/lib/btrfs.c -+++ b/lib/btrfs.c -@@ -67,8 +67,7 @@ int btrfs_is_subvolume(const char *path) - if (ret <= 0) - return ret; - -- ret = stat(path, &st); -- if (ret == -1) -+ if (stat(path, &st) == -1) - return -1; - - if (st.st_ino != BTRFS_FIRST_FREE_OBJECTID || !S_ISDIR(st.st_mode)) { --- -2.53.0 - - -From 7a4faaaf46314547cc5e6c8264c3a11753ef9352 Mon Sep 17 00:00:00 2001 -From: Alejandro Colomar -Date: Wed, 22 Apr 2026 11:14:20 +0200 -Subject: [PATCH 2/5] lib/, src/: Move statfs(2) call out of is_btrfs() - -This simplifies the return value of is_btrfs() into a boolean. - -Signed-off-by: Alejandro Colomar ---- - lib/btrfs.c | 25 +++++++++---------------- - lib/prototypes.h | 3 ++- - src/useradd.c | 11 +++++++++-- - 3 files changed, 20 insertions(+), 19 deletions(-) - -diff --git a/lib/btrfs.c b/lib/btrfs.c -index fe20cf30..065c7938 100644 ---- a/lib/btrfs.c -+++ b/lib/btrfs.c -@@ -60,12 +60,13 @@ int btrfs_remove_subvolume(const char *path) - */ - int btrfs_is_subvolume(const char *path) - { -- struct stat st; -- int ret; -+ struct stat st; -+ struct statfs sfs; - -- ret = is_btrfs(path); -- if (ret <= 0) -- return ret; -+ if (statfs(path, &sfs) == -1) -+ return -1; -+ if (!is_btrfs(&sfs)) -+ return 0; - - if (stat(path, &st) == -1) - return -1; -@@ -78,16 +79,8 @@ int btrfs_is_subvolume(const char *path) - } - - --/* Adapted from btrfsprogs */ --int is_btrfs(const char *path) -+bool -+is_btrfs(const struct statfs *sfs) - { -- struct statfs sfs; -- int ret; -- -- ret = statfs(path, &sfs); -- if (ret == -1) -- return -1; -- -- return sfs.f_type == BTRFS_SUPER_MAGIC; -+ return sfs->f_type == BTRFS_SUPER_MAGIC; - } -- -diff --git a/lib/prototypes.h b/lib/prototypes.h -index 9a03e312..42aa2923 100644 ---- a/lib/prototypes.h -+++ b/lib/prototypes.h -@@ -23,6 +23,7 @@ - - #include - #include -+#include - #include - #include - #include -@@ -54,7 +55,7 @@ extern int isexpired (const struct passwd *, /*@null@*/const struct spwd *); - extern int btrfs_create_subvolume(const char *path); - extern int btrfs_remove_subvolume(const char *path); - extern int btrfs_is_subvolume(const char *path); --extern int is_btrfs(const char *path); -+extern bool is_btrfs(const struct statfs *sfs); - #endif - - /* basename() renamed to Basename() to avoid libc name space confusion */ -diff --git a/src/useradd.c b/src/useradd.c -index df679d28..5ce6cd6a 100644 ---- a/src/useradd.c -+++ b/src/useradd.c -@@ -25,6 +25,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -2265,6 +2266,7 @@ static void create_home(const struct option_flags *flags) - #if WITH_BTRFS - if (subvolflg && (strlen(prefix_user_home) - (int)strlen(path)) <= 1) { - char *btrfs_check = strdup(path); -+ struct statfs sfs; - - if (!btrfs_check) { - fprintf(stderr, -@@ -2273,13 +2275,18 @@ static void create_home(const struct option_flags *flags) - fail_exit(E_HOMEDIR, process_selinux); - } - stpcpy(&btrfs_check[strlen(path) - strlen(cp) - 1], ""); -- if (is_btrfs(btrfs_check) <= 0) { -+ if (statfs(btrfs_check, &sfs) == -1) { -+ fprintf(stderr, "%s: statfs(\"%s\"): %s\n", -+ Prog, btrfs_check, strerrno()); -+ fail_exit(E_HOMEDIR, process_selinux); -+ } -+ free(btrfs_check); -+ if (!is_btrfs(&sfs)) { - fprintf(stderr, - _("%s: home directory \"%s\" must be mounted on BTRFS\n"), - Prog, path); - fail_exit(E_HOMEDIR, process_selinux); - } -- free(btrfs_check); - // make subvolume to mount for user instead of directory - if (btrfs_create_subvolume(path)) { - fprintf(stderr, --- -2.53.0 - - -From 96460c7240264c0022cebc9ba1774993ee2594cf Mon Sep 17 00:00:00 2001 -From: Alejandro Colomar -Date: Wed, 22 Apr 2026 11:21:14 +0200 -Subject: [PATCH 3/5] lib/, src/: Move btrfs.c prototypes to lib/btrfs.h - -Signed-off-by: Alejandro Colomar ---- - lib/Makefile.am | 2 +- - lib/btrfs.c | 4 ++++ - lib/btrfs.h | 23 +++++++++++++++++++++++ - lib/prototypes.h | 9 --------- - src/useradd.c | 1 + - src/userdel.c | 1 + - src/usermod.c | 1 + - 7 files changed, 31 insertions(+), 10 deletions(-) - create mode 100644 lib/btrfs.h - -diff --git a/lib/Makefile.am b/lib/Makefile.am -index 7c488f82..0664e610 100644 ---- a/lib/Makefile.am -+++ b/lib/Makefile.am -@@ -290,7 +290,7 @@ libshadow_la_SOURCES += tcbfuncs.c tcbfuncs.h - endif - - if WITH_BTRFS --libshadow_la_SOURCES += btrfs.c -+libshadow_la_SOURCES += btrfs.c btrfs.h - endif - - if ENABLE_LASTLOG -diff --git a/lib/btrfs.c b/lib/btrfs.c -index 065c7938..15b6b315 100644 ---- a/lib/btrfs.c -+++ b/lib/btrfs.c -@@ -1,3 +1,7 @@ -+#include "config.h" -+ -+#include "btrfs.h" -+ - #include - #include - #include -diff --git a/lib/btrfs.h b/lib/btrfs.h -new file mode 100644 -index 00000000..50b70488 ---- /dev/null -+++ b/lib/btrfs.h -@@ -0,0 +1,23 @@ -+// SPDX-FileCopyrightText: 2026, Alejandro Colomar -+// SPDX-License-Identifier: BSD-3-Clause -+ -+ -+#ifndef SHADOW_INCLUDE_LIB_BTRFS_H_ -+#define SHADOW_INCLUDE_LIB_BTRFS_H_ -+ -+ -+#include "config.h" -+ -+#include -+#include -+ -+ -+#ifdef WITH_BTRFS -+int btrfs_create_subvolume(const char *path); -+int btrfs_remove_subvolume(const char *path); -+int btrfs_is_subvolume(const char *path); -+bool is_btrfs(const struct statfs *sfs); -+#endif -+ -+ -+#endif // include guard -diff --git a/lib/prototypes.h b/lib/prototypes.h -index 42aa2923..d22c477a 100644 ---- a/lib/prototypes.h -+++ b/lib/prototypes.h -@@ -23,7 +23,6 @@ - - #include - #include --#include - #include - #include - #include -@@ -50,14 +49,6 @@ extern int expire (const struct passwd *, /*@null@*/const struct spwd *); - /* isexpired.c */ - extern int isexpired (const struct passwd *, /*@null@*/const struct spwd *); - --/* btrfs.c */ --#ifdef WITH_BTRFS --extern int btrfs_create_subvolume(const char *path); --extern int btrfs_remove_subvolume(const char *path); --extern int btrfs_is_subvolume(const char *path); --extern bool is_btrfs(const struct statfs *sfs); --#endif -- - /* basename() renamed to Basename() to avoid libc name space confusion */ - /* basename.c */ - extern /*@observer@*/const char *Basename (const char *str); -diff --git a/src/useradd.c b/src/useradd.c -index 5ce6cd6a..9bd32b11 100644 ---- a/src/useradd.c -+++ b/src/useradd.c -@@ -34,6 +34,7 @@ - #include "alloc/malloc.h" - #include "atoi/a2i.h" - #include "atoi/getnum.h" -+#include "btrfs.h" - #include "chkname.h" - #include "defines.h" - #include "faillog.h" -diff --git a/src/userdel.c b/src/userdel.c -index 9b7d81be..ebd064c0 100644 ---- a/src/userdel.c -+++ b/src/userdel.c -@@ -20,6 +20,7 @@ - #include - #include - -+#include "btrfs.h" - #ifdef ACCT_TOOLS_SETUID - #ifdef USE_PAM - #include "pam_defs.h" -diff --git a/src/usermod.c b/src/usermod.c -index 7c0321a6..3afe19ea 100644 ---- a/src/usermod.c -+++ b/src/usermod.c -@@ -32,6 +32,7 @@ - #include "alloc/malloc.h" - #include "atoi/a2i.h" - #include "atoi/getnum.h" -+#include "btrfs.h" - #include "chkname.h" - #include "defines.h" - #include "faillog.h" --- -2.53.0 - - -From 7be9a6540f1cad477fd4f4e83d25904a5095bb86 Mon Sep 17 00:00:00 2001 -From: Hadi Chokr -Date: Tue, 21 Apr 2026 09:18:19 +0200 -Subject: [PATCH 4/5] useradd(8): fallback to regular dir for BTRFS home on - non-BTRFS parent - -When the --btrfs-subvolume-home option is used but the parent directory -is not on a BTRFS filesystem, useradd previously failed with an error. -This is too strict; instead, fall back to creating a regular directory -and issue a warning. The subvolume creation is attempted only when the -parent is BTRFS. Otherwise, a regular directory is created and a -syslog(3) warning is logged. - -Fixes: 3e8c105 (2026-01-02; "src/useradd: Support config for creating home dirs as Btrfs subvolumes") -Co-authored-by: Hadi Chokr -Co-authored-by: Alejandro Colomar -Signed-off-by: Alejandro Colomar ---- - man/useradd.8.xml | 27 ++++++++++++++++++++++-- - src/useradd.c | 52 +++++++++++++++++++++++------------------------ - 2 files changed, 51 insertions(+), 28 deletions(-) - -diff --git a/man/useradd.8.xml b/man/useradd.8.xml -index 8a087e13..0bde6683 100644 ---- a/man/useradd.8.xml -+++ b/man/useradd.8.xml -@@ -2,6 +2,7 @@ - - - -- Note: this feature works only if the underlying filesystem supports -- Btrfs subvolumes. -+ If the parent directory of the user's home directory is -+ not on a Btrfs filesystem, -+ useradd will not create a -+ subvolume. -+ Instead, it creates a regular directory, -+ prints a warning to standard error, -+ and logs the event via syslog at level -+ LOG_WARN. -+ The user account is still created successfully. -+ -+ -+ If the filesystem type cannot be determined (e.g., because of -+ insufficient permissions, an I/O error, -+ or a -+ -+ statfs -+ 2 -+ -+ failure), -+ useradd treats this as a fatal error: -+ the home directory is not created, -+ the command exits with a non‑zero status -+ (E_HOMEDIR, 12), -+ and an error message is printed. - - - -diff --git a/src/useradd.c b/src/useradd.c -index 9bd32b11..9210379c 100644 ---- a/src/useradd.c -+++ b/src/useradd.c -@@ -1,11 +1,11 @@ --/* -- * SPDX-FileCopyrightText: 1991 - 1994, Julianne Frances Haugh -- * SPDX-FileCopyrightText: 1996 - 2000, Marek Michałkiewicz -- * SPDX-FileCopyrightText: 2000 - 2006, Tomasz Kłoczko -- * SPDX-FileCopyrightText: 2007 - 2012, Nicolas François -- * -- * SPDX-License-Identifier: BSD-3-Clause -- */ -+// SPDX-FileCopyrightText: 1991-1994, Julianne Frances Haugh -+// SPDX-FileCopyrightText: 1996-2000, Marek Michałkiewicz -+// SPDX-FileCopyrightText: 2000-2006, Tomasz Kłoczko -+// SPDX-FileCopyrightText: 2007-2012, Nicolas François -+// SPDX-FileCopyrightText: 2025-2026, Hadi Chokr -+// SPDX-FileCopyrightText: 2026, Alejandro Colomar -+// SPDX-License-Identifier: BSD-3-Clause -+ - - #include "config.h" - -@@ -2251,6 +2251,8 @@ static void create_home(const struct option_flags *flags) - owner root:root. - */ - for (cp = strtok(bhome, "/"); cp != NULL; cp = strtok(NULL, "/")) { -+ bool dir_created; -+ - /* Avoid turning a relative path into an absolute path. */ - if (strprefix(bhome, "/") || !streq(path, "")) - strcat(path, "/"); -@@ -2260,10 +2262,7 @@ static void create_home(const struct option_flags *flags) - continue; - } - -- /* Check if parent directory is BTRFS, fail if requesting -- subvolume but no BTRFS. The paths could be different by the -- trailing slash -- */ -+ dir_created = false; - #if WITH_BTRFS - if (subvolflg && (strlen(prefix_user_home) - (int)strlen(path)) <= 1) { - char *btrfs_check = strdup(path); -@@ -2284,25 +2283,26 @@ static void create_home(const struct option_flags *flags) - free(btrfs_check); - if (!is_btrfs(&sfs)) { - fprintf(stderr, -- _("%s: home directory \"%s\" must be mounted on BTRFS\n"), -- Prog, path); -- fail_exit(E_HOMEDIR, process_selinux); -+ _("%s: warning: \"%s\" is not on BTRFS; creating regular directory instead of subvolume\n"), -+ Prog, prefix_user_home); -+ } else { -+ if (btrfs_create_subvolume(path)) { -+ fprintf(stderr, -+ _("%s: failed to create BTRFS subvolume: %s\n"), -+ Prog, path); -+ fail_exit(E_HOMEDIR, process_selinux); -+ } -+ dir_created = true; - } -- // make subvolume to mount for user instead of directory -- if (btrfs_create_subvolume(path)) { -- fprintf(stderr, -- _("%s: failed to create BTRFS subvolume: %s\n"), -+ } -+#endif -+ if (!dir_created) { -+ if (mkdir(path, 0) != 0) { -+ fprintf(stderr, _("%s: cannot create directory %s\n"), - Prog, path); - fail_exit(E_HOMEDIR, process_selinux); - } - } -- else --#endif -- if (mkdir(path, 0) != 0) { -- fprintf(stderr, _("%s: cannot create directory %s\n"), -- Prog, path); -- fail_exit(E_HOMEDIR, process_selinux); -- } - if (chown(path, 0, 0) < 0) { - fprintf(stderr, - _("%s: warning: chown on `%s' failed: %m\n"), --- -2.53.0 - - -From 827f69b864461ab6d7549762bef06ab4495d2587 Mon Sep 17 00:00:00 2001 -From: Hadi Chokr -Date: Mon, 20 Apr 2026 12:27:31 +0200 -Subject: [PATCH 5/5] man/useradd.8.xml: Remove trailing spaces from - useradd.8.xml - -Signed-off-by: Hadi Chokr -Reviewed-by: Alejandro Colomar ---- - man/useradd.8.xml | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/man/useradd.8.xml b/man/useradd.8.xml -index 0bde6683..f85780e2 100644 ---- a/man/useradd.8.xml -+++ b/man/useradd.8.xml -@@ -207,7 +207,7 @@ - user's login directory. The default is to append the - LOGIN name to - BASE_DIR and use that as the -- login directory name. -+ login directory name. - The directory HOME_DIR is not created by - default. However it will be created for non-system users if either the - flag is specifed or -@@ -422,7 +422,7 @@ - - - -- Create the user's home directory if it does not exist. -+ Create the user's home directory if it does not exist. - The files and directories contained in the skeleton directory - (which can be defined with the option) - will be copied to the home directory. -@@ -512,7 +512,7 @@ - password himself. - - -- Note:Avoid this option on the command -+ Note:Avoid this option on the command - line because the password (or encrypted password) will - be visible by users listing the processes. - --- -2.53.0 - diff --git a/shadow-utils.spec b/shadow-utils.spec index 4f94261..a56f0b7 100644 --- a/shadow-utils.spec +++ b/shadow-utils.spec @@ -1,12 +1,12 @@ Summary: Utilities for managing accounts and shadow password files Name: shadow-utils -Version: 4.19.3 -Release: 4%{?dist} +Version: 4.20.0.rc3 +Release: 1%{?dist} Epoch: 2 License: BSD-3-Clause AND GPL-2.0-or-later URL: https://github.com/shadow-maint/shadow -Source0: https://github.com/shadow-maint/shadow/releases/download/4.19.3/shadow-4.19.3.tar.xz -Source1: https://github.com/shadow-maint/shadow/releases/download/4.19.3/shadow-4.19.3.tar.xz.asc +Source0: https://github.com/shadow-maint/shadow/releases/download/4.20.0-rc3/shadow-4.20.0-rc3.tar.xz +Source1: https://github.com/shadow-maint/shadow/releases/download/4.20.0-rc3/shadow-4.20.0-rc3.tar.xz.asc Source2: shadow-utils.useradd Source3: shadow-utils.login.defs Source4: shadow-bsd.txt @@ -20,14 +20,6 @@ Source7: passwd.pamd %global _ld_strict_symbol_defs 1 ### Patches ### -# Misc manual page changes - non-upstreamable -Patch0: shadow-4.15.0-manfix.patch -# https://github.com/shadow-maint/shadow/commit/3e8c105f0703264e947d8c034b90419794955d49 -Patch2: shadow-4-19-useradd-support-btrfs.patch -# https://github.com/shadow-maint/shadow/commit/6be13b2f84a2c1a0d0f4129b5258b4b443e7f86c -Patch3: shadow-4.19.3-chkhash.patch -# https://github.com/shadow-maint/shadow/commit/827f69b864461ab6d7549762bef06ab4495d2587 -Patch4: shadow-4.19.3-useradd-fix-btrfs.patch ### Dependencies ### Requires: audit-libs >= 1.6.5 @@ -106,7 +98,7 @@ Requires: shadow-utils-subid = %{epoch}:%{version}-%{release} Development files for shadow-utils-subid. %prep -%autosetup -p 1 -S git -n shadow-4.19.3 +%autosetup -p 1 -S git -n shadow-4.20.0-rc3 iconv -f ISO88591 -t utf-8 doc/HOWTO > doc/HOWTO.utf8 cp -f doc/HOWTO.utf8 doc/HOWTO @@ -163,26 +155,20 @@ mv -v $RPM_BUILD_ROOT/usr/sbin/* $RPM_BUILD_ROOT%{_bindir}/ # Remove binaries we don't use. rm $RPM_BUILD_ROOT%{_bindir}/chfn rm $RPM_BUILD_ROOT%{_bindir}/chsh -rm $RPM_BUILD_ROOT%{_bindir}/expiry rm $RPM_BUILD_ROOT%{_bindir}/login rm $RPM_BUILD_ROOT%{_bindir}/su rm $RPM_BUILD_ROOT%{_bindir}/faillog -rm $RPM_BUILD_ROOT%{_sbindir}/logoutd rm $RPM_BUILD_ROOT%{_sbindir}/nologin rm $RPM_BUILD_ROOT%{_mandir}/man1/chfn.* rm $RPM_BUILD_ROOT%{_mandir}/*/man1/chfn.* rm $RPM_BUILD_ROOT%{_mandir}/man1/chsh.* rm $RPM_BUILD_ROOT%{_mandir}/*/man1/chsh.* -rm $RPM_BUILD_ROOT%{_mandir}/man1/expiry.* -rm $RPM_BUILD_ROOT%{_mandir}/*/man1/expiry.* rm $RPM_BUILD_ROOT%{_mandir}/man1/login.* rm $RPM_BUILD_ROOT%{_mandir}/*/man1/login.* rm $RPM_BUILD_ROOT%{_mandir}/man1/su.* rm $RPM_BUILD_ROOT%{_mandir}/*/man1/su.* rm $RPM_BUILD_ROOT%{_mandir}/man5/passwd.* rm $RPM_BUILD_ROOT%{_mandir}/*/man5/passwd.* -rm $RPM_BUILD_ROOT%{_mandir}/man8/logoutd.* -rm $RPM_BUILD_ROOT%{_mandir}/*/man8/logoutd.* rm $RPM_BUILD_ROOT%{_mandir}/man8/nologin.* rm $RPM_BUILD_ROOT%{_mandir}/*/man8/nologin.* rm $RPM_BUILD_ROOT%{_mandir}/man3/getspnam.* @@ -195,7 +181,6 @@ rm $RPM_BUILD_ROOT%{_mandir}/*/man8/faillog.* # Remove PAM service files we don't use. rm $RPM_BUILD_ROOT%{_pam_confdir}/chfn rm $RPM_BUILD_ROOT%{_pam_confdir}/chsh -rm $RPM_BUILD_ROOT%{_pam_confdir}/groupmems rm $RPM_BUILD_ROOT%{_pam_confdir}/login rm $RPM_BUILD_ROOT%{_pam_confdir}/su @@ -279,6 +264,9 @@ rm -f $RPM_BUILD_ROOT/%{_libdir}/libsubid.a %{_libdir}/libsubid.so %changelog +* Wed Jul 22 2026 Iker Pedrosa - 2:4.20.0-rc3-1 +- Rebase to version 4.20.0-rc3 + * Fri Jul 17 2026 Fedora Release Engineering - 2:4.19.3-4 - Rebuilt for https://fedoraproject.org/wiki/Fedora_45_Mass_Rebuild diff --git a/sources b/sources index d12859f..d0fb76c 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (shadow-4.19.3.tar.xz) = f2b41f8186681eb98dae0da87ed1a1f03327c5005c9d4bf9500801352e318de6f5954dc5b8f30ab9aece728b1efb74b4ff8fb2720acc4c2aaef701331a4a5a05 -SHA512 (shadow-4.19.3.tar.xz.asc) = 295a6bffefd333a9ea84fa59b368f5c48d0ac5224199624b768087098110b0f0c19bef37f5c474c45277980758dcb6728e8bb17eb7ab1a57603cad41f1dd00ab +SHA512 (shadow-4.20.0-rc3.tar.xz) = 49a3662d10669c5f34af012b2397324ffe11544c1f09d89a32408a9c8928cd4d313c16ed3afaa6ff8665f8f224de139170dc0d9c5dea127986c2b9350c117d1a +SHA512 (shadow-4.20.0-rc3.tar.xz.asc) = 719b80d1331fe825c0f0279309e7eb56b0a767e61fda845ea051c60128fdbc4abc1b9e9f0569fa6b9073c7a8712ce0b144f33b472cf3eebd32e75668f745cd1c From c8aec6bdba74d16b628a0bd1c440f17ed91bd050 Mon Sep 17 00:00:00 2001 From: Iker Pedrosa Date: Wed, 22 Jul 2026 16:44:45 +0200 Subject: [PATCH 8/9] Tests: update dependencies System test framework requires gcc, python3-devel and libssh-devel installed before pip tries to compile ansible-pylibssh. Signed-off-by: Iker Pedrosa --- plans/tier0-functional.fmf | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plans/tier0-functional.fmf b/plans/tier0-functional.fmf index 7fb6f9c..a9939b5 100644 --- a/plans/tier0-functional.fmf +++ b/plans/tier0-functional.fmf @@ -14,7 +14,10 @@ prepare: how: install package: - expect + - gcc - git + - libssh-devel + - python3-devel - python3-pip - name: Setup SSH keys for localhost testing From 103ee1cc475003e8c32e3f54792aaca0cef33250 Mon Sep 17 00:00:00 2001 From: Iker Pedrosa Date: Wed, 29 Jul 2026 15:27:11 +0200 Subject: [PATCH 9/9] Rebase to version 4.20.0 Signed-off-by: Iker Pedrosa --- .gitignore | 2 ++ shadow-utils.spec | 11 +++++++---- sources | 4 ++-- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 13adb8c..3023995 100644 --- a/.gitignore +++ b/.gitignore @@ -52,3 +52,5 @@ shadow-4.1.4.2.tar.bz2 /shadow-4.20.0-rc2.tar.xz.asc /shadow-4.20.0-rc3.tar.xz /shadow-4.20.0-rc3.tar.xz.asc +/shadow-4.20.0.tar.xz +/shadow-4.20.0.tar.xz.asc diff --git a/shadow-utils.spec b/shadow-utils.spec index a56f0b7..7bc7e8b 100644 --- a/shadow-utils.spec +++ b/shadow-utils.spec @@ -1,12 +1,12 @@ Summary: Utilities for managing accounts and shadow password files Name: shadow-utils -Version: 4.20.0.rc3 +Version: 4.20.0 Release: 1%{?dist} Epoch: 2 License: BSD-3-Clause AND GPL-2.0-or-later URL: https://github.com/shadow-maint/shadow -Source0: https://github.com/shadow-maint/shadow/releases/download/4.20.0-rc3/shadow-4.20.0-rc3.tar.xz -Source1: https://github.com/shadow-maint/shadow/releases/download/4.20.0-rc3/shadow-4.20.0-rc3.tar.xz.asc +Source0: https://github.com/shadow-maint/shadow/releases/download/4.20.0/shadow-4.20.0.tar.xz +Source1: https://github.com/shadow-maint/shadow/releases/download/4.20.0/shadow-4.20.0.tar.xz.asc Source2: shadow-utils.useradd Source3: shadow-utils.login.defs Source4: shadow-bsd.txt @@ -98,7 +98,7 @@ Requires: shadow-utils-subid = %{epoch}:%{version}-%{release} Development files for shadow-utils-subid. %prep -%autosetup -p 1 -S git -n shadow-4.20.0-rc3 +%autosetup -p 1 -S git -n shadow-4.20.0 iconv -f ISO88591 -t utf-8 doc/HOWTO > doc/HOWTO.utf8 cp -f doc/HOWTO.utf8 doc/HOWTO @@ -264,6 +264,9 @@ rm -f $RPM_BUILD_ROOT/%{_libdir}/libsubid.a %{_libdir}/libsubid.so %changelog +* Wed Jul 29 2026 Iker Pedrosa - 2:4.20.0-1 +- Rebase to version 4.20.0 + * Wed Jul 22 2026 Iker Pedrosa - 2:4.20.0-rc3-1 - Rebase to version 4.20.0-rc3 diff --git a/sources b/sources index d0fb76c..7669083 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (shadow-4.20.0-rc3.tar.xz) = 49a3662d10669c5f34af012b2397324ffe11544c1f09d89a32408a9c8928cd4d313c16ed3afaa6ff8665f8f224de139170dc0d9c5dea127986c2b9350c117d1a -SHA512 (shadow-4.20.0-rc3.tar.xz.asc) = 719b80d1331fe825c0f0279309e7eb56b0a767e61fda845ea051c60128fdbc4abc1b9e9f0569fa6b9073c7a8712ce0b144f33b472cf3eebd32e75668f745cd1c +SHA512 (shadow-4.20.0.tar.xz) = 0b8afded372e4d37a78f38cb972c0ab877870ef6356cdd1c45be3c708af3d1496c6f87de6bf6a5b1d217d4d52d7e2d15c28b26530949cc6de0231a4028930406 +SHA512 (shadow-4.20.0.tar.xz.asc) = e4b134543768f323df30a1e450c22086d013020928d62bd3207db7f633beea3587b67802da5b575d5a794e8c2bebd7a0abeba6ed69d44bf08adc37df3bf352ac