From 0ec167f47f3ff125559b61193e67794f4daeedf3 Mon Sep 17 00:00:00 2001 From: Huijing Hei Date: Mon, 17 Jul 2023 22:27:01 +0800 Subject: [PATCH] passwd: sync `etc/{,g}shadow` according to `etc/{passwd,group}` Refer to https://github.com/coreos/rpm-ostree/issues/49#issuecomment-1612626563, do testing: 1. Remove bin line in group and passwd 2. Build FCOS, see logs: ``` systemd.post: Creating group 'bin' with GID 1. systemd.post: Creating user 'bin' (bin) with UID 1 and GID 1. systemd.post: /etc/gshadow: Group "bin" already exists. ``` According to @cgwalters 's pointer: The above log will lead systemd-sysusers (during systemd.post) exit early before saving the updated `/etc/{passwd,group}` refer to [code](https://github.com/systemd/systemd/blob/main/src/sysusers/sysusers.c#L820), and bin user/group will not be saved finally. The root cause is that `gshadow` is not consistent with group, `gshadow` is from setup, and we override group according to https://github.com/coreos/fedora-coreos-config/blob/testing-devel/manifests/group. The `shadow` is also from setup, and is not consistent with passwd, we should also sync it. Fix https://github.com/coreos/fedora-coreos-tracker/issues/1525 --- rust/src/passwd.rs | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/rust/src/passwd.rs b/rust/src/passwd.rs index 6a6dbf8409..74893761ac 100644 --- a/rust/src/passwd.rs +++ b/rust/src/passwd.rs @@ -389,6 +389,40 @@ fn write_data_from_treefile( }) .with_context(|| format!("failed to write /{}", &target_etc_filename))?; + // Regenerate etc/{,g}shadow to sync with etc/{password,group} + let db = rootfs.open(target_etc_filename).map(BufReader::new)?; + let shadow_name = if target == "passwd" { + "shadow" + } else { + "gshadow" + }; + let target_etc_shadow = format!("{}{}", dest_path, shadow_name); + + match shadow_name { + "shadow" => { + let entries = nameservice::passwd::parse_passwd_content(db)?; + rootfs + .atomic_replace_with(&target_etc_shadow, |target_shadow| -> Result<()> { + for user in entries { + writeln!(target_shadow, "{}:*::0:99999:7:::", user.name)?; + } + Ok(()) + }) + .with_context(|| format!("Writing {target_etc_shadow}"))?; + } + "gshadow" => { + let entries = nameservice::group::parse_group_content(db)?; + rootfs + .atomic_replace_with(&target_etc_shadow, |target_shadow| -> Result<()> { + for group in entries { + writeln!(target_shadow, "{}:::", group.name)?; + } + Ok(()) + }) + .with_context(|| format!("Writing {target_etc_shadow}"))?; + } + _ => unreachable!("invalid file path: {}", target_etc_shadow), + } Ok(true) }