Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sysusers: add a treefile option in rpm-ostree #4680

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/treefile.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ It supports the following parameters:
* `selinux`: boolean, optional: Defaults to `true`. If `false`, then
no SELinux labeling will be performed on the server side.

* `sysusers`: boolean, optional: Defaults to `false`.
If `true`, this turns off `altfiles` and disables the `passwd` / `group`
files migration to `/usr/lib`.

* `ima`: boolean, optional: Defaults to `false`. Propagate any
IMA signatures in input RPMs into the final OSTree commit.

Expand Down
18 changes: 15 additions & 3 deletions rpmostree-cxxrs.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -1749,6 +1749,7 @@ struct Treefile final : public ::rust::Opaque
bool get_recommends () const noexcept;
bool get_selinux () const noexcept;
::std::uint32_t get_selinux_label_version () const noexcept;
bool get_sysusers () const noexcept;
::rust::String get_gpg_key () const noexcept;
::rust::String get_automatic_version_suffix () const noexcept;
bool get_container () const noexcept;
Expand Down Expand Up @@ -2164,7 +2165,8 @@ extern "C"
::rpmostreecxx::Treefile &treefile) noexcept;

::rust::repr::PtrLen
rpmostreecxx$cxxbridge1$composepost_nsswitch_altfiles (::std::int32_t rootfs_dfd) noexcept;
rpmostreecxx$cxxbridge1$composepost_nsswitch_altfiles (::std::int32_t rootfs_dfd,
bool sysusers) noexcept;

::rust::repr::PtrLen rpmostreecxx$cxxbridge1$compose_postprocess (
::std::int32_t rootfs_dfd, ::rpmostreecxx::Treefile &treefile, ::rust::Str next_version,
Expand Down Expand Up @@ -2592,6 +2594,9 @@ extern "C"
::std::uint32_t rpmostreecxx$cxxbridge1$Treefile$get_selinux_label_version (
::rpmostreecxx::Treefile const &self) noexcept;

bool
rpmostreecxx$cxxbridge1$Treefile$get_sysusers (::rpmostreecxx::Treefile const &self) noexcept;

void rpmostreecxx$cxxbridge1$Treefile$get_gpg_key (::rpmostreecxx::Treefile const &self,
::rust::String *return$) noexcept;

Expand Down Expand Up @@ -3941,9 +3946,10 @@ compose_prepare_rootfs (::std::int32_t src_rootfs_dfd, ::std::int32_t dest_rootf
}

void
composepost_nsswitch_altfiles (::std::int32_t rootfs_dfd)
composepost_nsswitch_altfiles (::std::int32_t rootfs_dfd, bool sysusers)
{
::rust::repr::PtrLen error$ = rpmostreecxx$cxxbridge1$composepost_nsswitch_altfiles (rootfs_dfd);
::rust::repr::PtrLen error$
= rpmostreecxx$cxxbridge1$composepost_nsswitch_altfiles (rootfs_dfd, sysusers);
if (error$.ptr)
{
throw ::rust::impl< ::rust::Error>::error (error$);
Expand Down Expand Up @@ -5143,6 +5149,12 @@ Treefile::get_selinux_label_version () const noexcept
return rpmostreecxx$cxxbridge1$Treefile$get_selinux_label_version (*this);
}

bool
Treefile::get_sysusers () const noexcept
{
return rpmostreecxx$cxxbridge1$Treefile$get_sysusers (*this);
}

::rust::String
Treefile::get_gpg_key () const noexcept
{
Expand Down
3 changes: 2 additions & 1 deletion rpmostree-cxxrs.h
Original file line number Diff line number Diff line change
Expand Up @@ -1531,6 +1531,7 @@ struct Treefile final : public ::rust::Opaque
bool get_recommends () const noexcept;
bool get_selinux () const noexcept;
::std::uint32_t get_selinux_label_version () const noexcept;
bool get_sysusers () const noexcept;
::rust::String get_gpg_key () const noexcept;
::rust::String get_automatic_version_suffix () const noexcept;
bool get_container () const noexcept;
Expand Down Expand Up @@ -1836,7 +1837,7 @@ void configure_build_repo_from_target (::rpmostreecxx::OstreeRepo const &build_r
void compose_prepare_rootfs (::std::int32_t src_rootfs_dfd, ::std::int32_t dest_rootfs_dfd,
::rpmostreecxx::Treefile &treefile);

void composepost_nsswitch_altfiles (::std::int32_t rootfs_dfd);
void composepost_nsswitch_altfiles (::std::int32_t rootfs_dfd, bool sysusers);

void compose_postprocess (::std::int32_t rootfs_dfd, ::rpmostreecxx::Treefile &treefile,
::rust::Str next_version, bool unified_core);
Expand Down
56 changes: 49 additions & 7 deletions rust/src/composepost.rs
Original file line number Diff line number Diff line change
Expand Up @@ -640,7 +640,36 @@ fn strip_any_prefix<'a, 'b>(s: &'a str, prefixes: &[&'b str]) -> Option<(&'b str
.find_map(|&p| s.strip_prefix(p).map(|r| (p, r)))
}

#[context("Delete altfiles for passwd and group entries")]
fn del_altfiles(buf: &str) -> Result<String> {
let mut r = String::with_capacity(buf.len());
for line in buf.lines() {
let parts = if let Some(p) = strip_any_prefix(line, &["passwd:", "group:"]) {
p
} else {
r.push_str(line);
r.push('\n');
continue;
};
let (prefix, rest) = parts;
r.push_str(prefix);

for elt in rest.split_whitespace() {
if elt == "altfiles" {
// skip altfiles
continue;
} else {
r.push(' ');
r.push_str(elt);
}
}
r.push('\n');
}
Ok(r)
}

/// Inject `altfiles` after `files` for `passwd:` and `group:` entries.
#[allow(dead_code)]
fn add_altfiles(buf: &str) -> Result<String> {
let mut r = String::with_capacity(buf.len());
for line in buf.lines() {
Expand Down Expand Up @@ -677,20 +706,33 @@ fn add_altfiles(buf: &str) -> Result<String> {
Ok(r)
}

/// Add `altfiles` entries to `nsswitch.conf`.
/// Add or delete `altfiles` entries to `nsswitch.conf`.
///
/// rpm-ostree currently depends on `altfiles`
#[context("Adding altfiles to /etc/nsswitch.conf")]
pub fn composepost_nsswitch_altfiles(rootfs_dfd: i32) -> CxxResult<()> {
/// rpm-ostree currently depends on `altfiles`, should remove it when
/// transfer to systemd-sysusers.
#[context("Adding / deleting altfiles to /etc/nsswitch.conf")]
pub fn composepost_nsswitch_altfiles(rootfs_dfd: i32, sysusers: bool) -> CxxResult<()> {
let rootfs_dfd = unsafe { &crate::ffiutil::ffi_dirfd(rootfs_dfd)? };
let path = "usr/etc/nsswitch.conf";
if let Some(meta) = rootfs_dfd.symlink_metadata_optional(path)? {
// If it's a symlink, then something else e.g. authselect must own it.
// Do nothing if disable systemd-sysusers.
if meta.is_symlink() {
return Ok(());
if !sysusers {
return Ok(());
}
}
let nsswitch = rootfs_dfd.read_to_string(path)?;
let nsswitch = add_altfiles(&nsswitch)?;
// Delete the symlink, create and update the config.
let target = "usr/etc/authselect/nsswitch.conf";
let nsswitch = rootfs_dfd
.read_to_string(target)
.with_context(|| format!("Reading target {}", target))?;
rootfs_dfd
.remove_file(path)
.with_context(|| format!("Removing {}", path))?;
rootfs_dfd.create(path)?;

let nsswitch = del_altfiles(&nsswitch)?;
rootfs_dfd.atomic_write(path, nsswitch.as_bytes())?;
}

Expand Down
3 changes: 2 additions & 1 deletion rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ pub mod ffi {
dest_rootfs_dfd: i32,
treefile: &mut Treefile,
) -> Result<()>;
fn composepost_nsswitch_altfiles(rootfs_dfd: i32) -> Result<()>;
fn composepost_nsswitch_altfiles(rootfs_dfd: i32, sysusers: bool) -> Result<()>;
fn compose_postprocess(
rootfs_dfd: i32,
treefile: &mut Treefile,
Expand Down Expand Up @@ -608,6 +608,7 @@ pub mod ffi {
fn get_recommends(&self) -> bool;
fn get_selinux(&self) -> bool;
fn get_selinux_label_version(&self) -> u32;
fn get_sysusers(&self) -> bool;
fn get_gpg_key(&self) -> String;
fn get_automatic_version_suffix(&self) -> String;
fn get_container(&self) -> bool;
Expand Down
15 changes: 11 additions & 4 deletions rust/src/passwd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,7 @@ fn complete_pwgrp(rootfs: &Dir) -> Result<()> {
/// This is a pre-commit validation hook which ensures that the upcoming
/// users/groups entries are somehow sane. See treefile `check-passwd` and
/// `check-groups` fields for a description of available validation knobs.
#[context("Validate users/groups refer to treefile check-passwd/check-groups configuration")]
pub fn check_passwd_group_entries(
ffi_repo: &crate::ffi::OstreeRepo,
rootfs_dfd: i32,
Expand All @@ -630,8 +631,12 @@ pub fn check_passwd_group_entries(

// Parse entries in the upcoming commit content.
let mut new_entities = PasswdEntries::default();
new_entities.add_passwd_content(rootfs.as_raw_fd(), "usr/lib/passwd")?;
new_entities.add_group_content(rootfs.as_raw_fd(), "usr/lib/group")?;
new_entities.add_passwd_content(rootfs.as_raw_fd(), "usr/etc/passwd")?;
new_entities.add_group_content(rootfs.as_raw_fd(), "usr/etc/group")?;
if has_usrlib_passwd(&rootfs)? {
new_entities.add_passwd_content(rootfs.as_raw_fd(), "usr/lib/passwd")?;
new_entities.add_group_content(rootfs.as_raw_fd(), "usr/lib/group")?;
}

// Fetch entries from treefile and previous commit, according to config.
// These are used as ground-truth by the validation steps below.
Expand Down Expand Up @@ -679,9 +684,11 @@ impl PasswdDB {
pub(crate) fn populate_new(rootfs: &Dir) -> Result<Self> {
let mut db = Self::default();
db.add_passwd_content(rootfs.as_raw_fd(), "usr/etc/passwd")?;
db.add_passwd_content(rootfs.as_raw_fd(), "usr/lib/passwd")?;
db.add_group_content(rootfs.as_raw_fd(), "usr/etc/group")?;
db.add_group_content(rootfs.as_raw_fd(), "usr/lib/group")?;
if has_usrlib_passwd(&rootfs)? {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this change can land now if you want

db.add_passwd_content(rootfs.as_raw_fd(), "usr/lib/passwd")?;
db.add_group_content(rootfs.as_raw_fd(), "usr/lib/group")?;
}
Ok(db)
}

Expand Down
7 changes: 7 additions & 0 deletions rust/src/treefile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,7 @@ fn treefile_merge(dest: &mut TreeComposeConfig, src: &mut TreeComposeConfig) {
rojig,
selinux,
selinux_label_version,
sysusers,
ima,
gpg_key,
include,
Expand Down Expand Up @@ -1337,6 +1338,10 @@ impl Treefile {
self.parsed.base.selinux_label_version.unwrap_or_default()
}

pub(crate) fn get_sysusers(&self) -> bool {
self.parsed.base.sysusers.unwrap_or(false)
}

pub(crate) fn get_gpg_key(&self) -> String {
self.parsed.base.gpg_key.clone().unwrap_or_default()
}
Expand Down Expand Up @@ -2484,6 +2489,8 @@ pub(crate) struct BaseComposeConfigFields {
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) selinux_label_version: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) sysusers: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) ima: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) gpg_key: Option<String>,
Expand Down
20 changes: 13 additions & 7 deletions src/libpriv/rpmostree-postprocess.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -406,16 +406,22 @@ postprocess_final (int rootfs_dfd, rpmostreecxx::Treefile &treefile, gboolean un

auto container = treefile.get_container ();

g_print ("Migrating /usr/etc/passwd to /usr/lib/\n");
ROSCXX_TRY (migrate_passwd_except_root (rootfs_dfd), error);
bool sysusers = treefile.get_sysusers ();

rust::Vec<rust::String> preserve_groups_set = treefile.get_etc_group_members ();
if (!sysusers)
{
g_print ("Migrating /usr/etc/passwd to /usr/lib/\n");
ROSCXX_TRY (migrate_passwd_except_root (rootfs_dfd), error);

rust::Vec<rust::String> preserve_groups_set = treefile.get_etc_group_members ();

g_print ("Migrating /usr/etc/group to /usr/lib/\n");
ROSCXX_TRY (migrate_group_except_root (rootfs_dfd, preserve_groups_set), error);
g_print ("Migrating /usr/etc/group to /usr/lib/\n");
ROSCXX_TRY (migrate_group_except_root (rootfs_dfd, preserve_groups_set), error);
}

/* NSS configuration to look at the new files */
ROSCXX_TRY (composepost_nsswitch_altfiles (rootfs_dfd), error);
/* NSS configuration to look at the new files. */
/* Should remove altfiles if we transfer to systemd-sysusers. */
ROSCXX_TRY (composepost_nsswitch_altfiles (rootfs_dfd, sysusers), error);

if (selinux)
{
Expand Down