Rebase to v4.20.0-rc3

Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
This commit is contained in:
Iker Pedrosa 2026-07-02 16:26:11 +02:00
commit 8cb145bd73
7 changed files with 14 additions and 927 deletions

4
.gitignore vendored
View file

@ -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

View file

@ -1,149 +0,0 @@
From 3e8c105f0703264e947d8c034b90419794955d49 Mon Sep 17 00:00:00 2001
From: Hadi Chokr <hadichokr@icloud.com>
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 <ngompa@velocitylimitless.com>
Signed-off-by: Hadi Chokr <hadichokr@icloud.com>
Signed-off-by: Neal Gompa <ngompa@velocitylimitless.com>
Reviewed-by: Alejandro Colomar <alx@kernel.org>
---
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 @@
</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term>
+ <option>--btrfs-subvolume-home</option>
+ </term>
+ <listitem>
+ <para>
+ Create the user's home directory as a Btrfs subvolume.
+ </para>
+ <para>
+ If this option is not specified,
+ <command>useradd</command> will follow the default behavior
+ defined by the <option>BTRFS_SUBVOLUME_HOME</option> variable
+ in <filename>/etc/default/useradd</filename>.
+ If this variable is not set, the default value is no.
+ </para>
+ <para>
+ When the <option>--btrfs-subvolume-home</option> command-line option
+ is specified,
+ a Btrfs subvolume is created
+ regardless of any configuration file settings.
+ </para>
+ <para>
+ Note: this feature works only if the underlying filesystem supports
+ Btrfs subvolumes.
+ </para>
+ </listitem>
+ </varlistentry>
<varlistentry>
<term>
<option>-c</option>, <option>--comment</option>&nbsp;<replaceable>COMMENT</replaceable>
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

View file

@ -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 @@
<refsect1 id='setup'>
<title>SETUP</title>
<para>
- The <command>groupmems</command> executable should be in mode
- <literal>2710</literal> as user <emphasis>root</emphasis> and in group
- <emphasis>groups</emphasis>. The system administrator can add users to
- group <emphasis>groups</emphasis> to allow or disallow them using the
- <command>groupmems</command> utility to manage their own group
- membership list.
+ In this operating system the <command>groupmems</command> executable
+ is not setuid and regular users cannot use it to manipulate
+ the membership of their own group.
</para>
-
- <programlisting>
- $ groupadd -r groups
- $ chmod 2710 groupmems
- $ chown root:groups groupmems
- $ groupmems -g groups -a gk4
- </programlisting>
</refsect1>
<refsect1 id='configuration'>
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.
</para>
+ <para>
+ 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 <emphasis>ENCRYPT_METHOD</emphasis> and <emphasis>SHA_CRYPT_MAX_ROUNDS</emphasis>
+ for pam_unix module, <emphasis>FAIL_DELAY</emphasis> for pam_faildelay module,
+ and <emphasis>UMASK</emphasis> for pam_umask module. Refer to
+ pam(8) for more information.
+ </para>
+
<para>The following configuration items are provided:</para>
<variablelist remap='IP'>
@@ -240,16 +251,6 @@
</listitem>
</varlistentry>
<varlistentry>
- <term>chfn</term>
- <listitem>
- <para>
- <phrase condition="no_pam">CHFN_AUTH</phrase>
- CHFN_RESTRICT
- <phrase condition="no_pam">LOGIN_STRING</phrase>
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
<term>chgpasswd</term>
<listitem>
<para>
@@ -276,14 +277,6 @@
</para>
</listitem>
</varlistentry>
- <varlistentry condition="no_pam">
- <term>chsh</term>
- <listitem>
- <para>
- CHSH_AUTH LOGIN_STRING
- </para>
- </listitem>
- </varlistentry>
<!-- expiry: no variables (CONSOLE_GROUPS linked, but not used) -->
<!-- faillog: no variables -->
<varlistentry>
@@ -352,34 +345,6 @@
<para>LASTLOG_UID_MAX</para>
</listitem>
</varlistentry>
- <varlistentry>
- <term>login</term>
- <listitem>
- <para>
- <phrase condition="no_pam">CONSOLE</phrase>
- CONSOLE_GROUPS DEFAULT_HOME
- <phrase condition="no_pam">ENV_HZ ENV_PATH ENV_SUPATH
- ENV_TZ ENVIRON_FILE</phrase>
- ERASECHAR FAIL_DELAY
- <phrase condition="no_pam">FAILLOG_ENAB</phrase>
- FAKE_SHELL
- <phrase condition="no_pam">FTMP_FILE</phrase>
- HUSHLOGIN_FILE
- <phrase condition="no_pam">ISSUE_FILE</phrase>
- KILLCHAR
- <phrase condition="no_pam">LASTLOG_ENAB LASTLOG_UID_MAX</phrase>
- LOGIN_RETRIES
- <phrase condition="no_pam">LOGIN_STRING</phrase>
- LOGIN_TIMEOUT LOG_OK_LOGINS LOG_UNKFAIL_ENAB
- <phrase condition="no_pam">MAIL_CHECK_ENAB MAIL_DIR MAIL_FILE
- MOTD_FILE NOLOGINS_FILE PORTTIME_CHECKS_ENAB
- QUOTAS_ENAB</phrase>
- TTYGROUP TTYPERM TTYTYPE_FILE
- <phrase condition="no_pam">ULIMIT UMASK</phrase>
- USERGROUPS_ENAB
- </para>
- </listitem>
- </varlistentry>
<!-- logoutd: no variables -->
<varlistentry>
<term>newgrp / sg</term>
@@ -451,32 +416,6 @@
</para>
</listitem>
</varlistentry>
- <varlistentry>
- <term>su</term>
- <listitem>
- <para>
- <phrase condition="no_pam">CONSOLE</phrase>
- CONSOLE_GROUPS DEFAULT_HOME
- <phrase condition="no_pam">ENV_HZ ENVIRON_FILE</phrase>
- ENV_PATH ENV_SUPATH
- <phrase condition="no_pam">ENV_TZ LOGIN_STRING MAIL_CHECK_ENAB
- MAIL_DIR MAIL_FILE QUOTAS_ENAB</phrase>
- SULOG_FILE SU_NAME
- <phrase condition="no_pam">SU_WHEEL_ONLY</phrase>
- SYSLOG_SU_ENAB
- <phrase condition="no_pam">USERGROUPS_ENAB</phrase>
- </para>
- </listitem>
- </varlistentry>
- <varlistentry condition="no_pam">
- <term>sulogin</term>
- <listitem>
- <para>
- ENV_HZ
- ENV_TZ
- </para>
- </listitem>
- </varlistentry>
<varlistentry>
<term>useradd</term>
<listitem>

View file

@ -1,102 +0,0 @@
From 4b2e669441438a6ae91c82a24c796894aa6a53b2 Mon Sep 17 00:00:00 2001
From: Alejandro Colomar <alx@kernel.org>
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 <tobias@stoeckmann.org>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
(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 <alx@kernel.org>
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 <alx@kernel.org>
(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 <alx@kernel.org>
Date: Fri, 16 Jan 2026 01:52:32 +0100
Subject: [PATCH 3/3] man/shadow.5.xml: Document "*"
Signed-off-by: Alejandro Colomar <alx@kernel.org>
(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 <emphasis>!</emphasis>,
the password is locked.
The remaining characters on the
- line represent the password field before the password was
- locked.
+ line represent the password hash.
+ </para>
+ <para>
+ If the password hash consists of a star <emphasis>*</emphasis>,
+ password access is effectively disallowed;
+ this is because no password can produce a hash like this.
</para>
<para>
Refer to <citerefentry><refentrytitle>crypt</refentrytitle>
--
2.53.0

View file

@ -1,492 +0,0 @@
From 4079070c4b8ced8df9d86366ad113fc3c2e4e49c Mon Sep 17 00:00:00 2001
From: Alejandro Colomar <alx@kernel.org>
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 <alx@kernel.org>
---
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 <alx@kernel.org>
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 <alx@kernel.org>
---
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 <sys/socket.h>
#include <sys/stat.h>
+#include <sys/statfs.h>
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
@@ -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 <stdio.h>
#include <string.h>
#include <sys/stat.h>
+#include <sys/statfs.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
@@ -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 <alx@kernel.org>
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 <alx@kernel.org>
---
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 <linux/btrfs_tree.h>
#include <linux/magic.h>
#include <sys/statfs.h>
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 <alx@kernel.org>
+// SPDX-License-Identifier: BSD-3-Clause
+
+
+#ifndef SHADOW_INCLUDE_LIB_BTRFS_H_
+#define SHADOW_INCLUDE_LIB_BTRFS_H_
+
+
+#include "config.h"
+
+#include <stdbool.h>
+#include <sys/statfs.h>
+
+
+#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 <sys/socket.h>
#include <sys/stat.h>
-#include <sys/statfs.h>
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
@@ -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 <sys/types.h>
#include <unistd.h>
+#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 <hadichokr@icloud.com>
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 <hadichokr@icloud.com>
Co-authored-by: Alejandro Colomar <alx@kernel.org>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
---
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 @@
<!--
SPDX-FileCopyrightText: 1991 - 1994, Julianne Frances Haugh
SPDX-FileCopyrightText: 2007 - 2011, Nicolas François
+ SPDX-FileCopyrightText: 2025 - 2026, Hadi Chokr
SPDX-License-Identifier: BSD-3-Clause
-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.5//EN"
@@ -156,8 +157,30 @@
regardless of any configuration file settings.
</para>
<para>
- Note: this feature works only if the underlying filesystem supports
- Btrfs subvolumes.
+ If the parent directory of the user's home directory is
+ <emphasis>not</emphasis> on a Btrfs filesystem,
+ <command>useradd</command> will <emphasis>not</emphasis> create a
+ subvolume.
+ Instead, it creates a regular directory,
+ prints a warning to standard error,
+ and logs the event via syslog at level
+ <constant>LOG_WARN</constant>.
+ The user account is still created successfully.
+ </para>
+ <para>
+ If the filesystem type cannot be determined (e.g., because of
+ insufficient permissions, an I/O error,
+ or a
+ <citerefentry>
+ <refentrytitle>statfs</refentrytitle>
+ <manvolnum>2</manvolnum>
+ </citerefentry>
+ failure),
+ <command>useradd</command> treats this as a fatal error:
+ the home directory is not created,
+ the command exits with a nonzero status
+ (<literal>E_HOMEDIR</literal>, 12),
+ and an error message is printed.
</para>
</listitem>
</varlistentry>
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 <alx@kernel.org>
+// 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 <hadichokr@icloud.com>
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 <hadichokr@icloud.com>
Reviewed-by: Alejandro Colomar <alx@kernel.org>
---
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
<replaceable>LOGIN</replaceable> name to
<replaceable>BASE_DIR</replaceable> and use that as the
- login directory name.
+ login directory name.
The directory <replaceable>HOME_DIR</replaceable> is not created by
default. However it will be created for non-system users if either the
<option>-m</option> flag is specifed or
@@ -422,7 +422,7 @@
</term>
<listitem>
<para>
- 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>-k</option> option)
will be copied to the home directory.
@@ -512,7 +512,7 @@
password himself.
</para>
<para>
- <emphasis role="bold">Note:</emphasis>Avoid this option on the command
+ <emphasis role="bold">Note:</emphasis>Avoid this option on the command
line because the password (or encrypted password) will
be visible by users listing the processes.
</para>
--
2.53.0

View file

@ -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 <ipedrosa@redhat.com> - 2:4.20.0-rc3-1
- Rebase to version 4.20.0-rc3
* Fri Jul 17 2026 Fedora Release Engineering <releng@fedoraproject.org> - 2:4.19.3-4
- Rebuilt for https://fedoraproject.org/wiki/Fedora_45_Mass_Rebuild

View file

@ -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