sysusers: gracefully handle existing group in /etc/gshadow

systemd-sysusers currently skips entries for groups that already exists.
However, if a group exists only in /etc/gshadow and not in /etc/group,
systemd-sysusers panics:

~# groupdel sgx
~# systemd-sysusers; echo $?
Creating group 'sgx' with GID 106.
0
~# systemd-sysusers; echo $?
0
~# sed -i '/sgx/d' /etc/group
~# systemd-sysusers; echo $?
Creating group 'sgx' with GID 106.
/etc/gshadow: Group "sgx" already exists.
1

To fix this, let's mirror the logic from the user path
(write_temporary_shadow()) where we simply drop the user from the "todo"
queue if it already exists in /etc/shadow instead of throwing an error.
This commit is contained in:
Frantisek Sumsal
2026-08-04 08:17:04 +09:00
committed by Yu Watanabe
parent f4cb4596a3
commit 36a9875c1d
12 changed files with 21 additions and 5 deletions
+7 -4
View File
@@ -932,10 +932,13 @@ static int write_temporary_gshadow(
while ((r = fgetsgent_sane(original, &sg)) > 0) {
i = ordered_hashmap_get(c->groups, sg->sg_namp);
if (i && i->todo_group)
return log_error_errno(SYNTHETIC_ERRNO(EEXIST),
"%s: Group \"%s\" already exists.",
gshadow_path, sg->sg_namp);
if (i && i->todo_group) {
/* The group already exists in /etc/gshadow. Only the
* /etc/gshadow stage is left, so we can safely remove
* the item from the todo set. */
i->todo_group = false;
ordered_hashmap_remove(c->todo_gids, GID_TO_PTR(i->gid));
}
r = putsgent_with_members(c, sg, gshadow);
if (r < 0)
+1 -1
View File
@@ -23,7 +23,7 @@ prepare_testdir() {
mkdir -p "$TESTDIR/etc/sysusers.d/"
mkdir -p "$TESTDIR/usr/lib/sysusers.d/"
rm -f "$TESTDIR"/etc/*{passwd,group,shadow}
for i in $1.initial-{passwd,group,shadow}; do
for i in $1.initial-{passwd,group,shadow,gshadow}; do
test -f "$i" && cp "$i" "$TESTDIR/etc/${i#*.initial-}"
done
return 0
@@ -0,0 +1 @@
testgroup:x:333:
@@ -0,0 +1 @@
testgroup:!::
+4
View File
@@ -0,0 +1,4 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
# Test that a group pre-existing in /etc/gshadow but missing from
# /etc/group is handled gracefully instead of failing with EEXIST.
g testgroup 333
@@ -0,0 +1 @@
testuser:x:444:
@@ -0,0 +1 @@
testuser:x:444:444:Test User:/:NOLOGIN
@@ -0,0 +1 @@
testuser:!*::0:99999:7:::
+4
View File
@@ -0,0 +1,4 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
# Test that a user pre-existing in /etc/shadow but missing from
# /etc/passwd is handled gracefully (existing entry is updated).
u testuser 444 "Test User"