Merge pull request #2660 from cgwalters/postprocess-rs-nsswitch

Oxidize postprocessing `altfiles` addition to `/etc/nsswitch.conf`
This commit is contained in:
Luca Bruno 2021-03-15 08:32:05 +00:00 committed by GitHub
commit 9deeeedc5d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 114 additions and 104 deletions

View File

@ -11,9 +11,10 @@
use crate::cxxrsutil::CxxResult;
use anyhow::Result;
use fn_error_context::context;
use openat_ext::OpenatDirExt;
use rayon::prelude::*;
use std::io;
use std::io::{self, Read};
use std::io::{BufRead, Write};
use std::path::Path;
@ -117,3 +118,113 @@ pub(crate) fn compose_postprocess_final(rootfs_dfd: i32) -> CxxResult<()> {
];
Ok(tasks.par_iter().try_for_each(|f| f(&rootfs_dfd))?)
}
/// Given a string and a set of possible prefixes, return the split
/// prefix and remaining string, or `None` if no matches.
fn strip_any_prefix<'a, 'b>(s: &'a str, prefixes: &[&'b str]) -> Option<(&'b str, &'a str)> {
prefixes
.iter()
.find_map(|&p| s.strip_prefix(p).map(|r| (p, r)))
}
/// Inject `altfiles` after `files` for `passwd:` and `group:` entries.
fn add_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);
let mut inserted = false;
for elt in rest.split_whitespace() {
// Already have altfiles? We're done
if elt == "altfiles" {
return Ok(buf.to_string());
}
// We prefer `files altfiles`
if !inserted && elt == "files" {
r.push_str(" files altfiles");
inserted = true;
} else {
r.push(' ');
r.push_str(elt);
}
}
if !inserted {
r.push_str(" altfiles");
}
r.push('\n');
}
Ok(r)
}
/// rpm-ostree currently depends on `altfiles`
#[context("Adding altfiles to /etc/nsswitch.conf")]
pub(crate) fn composepost_nsswitch_altfiles(rootfs_dfd: i32) -> CxxResult<()> {
let path = "usr/etc/nsswitch.conf";
let rootfs_dfd = crate::ffiutil::ffi_view_openat_dir(rootfs_dfd);
let nsswitch = {
let mut nsswitch = rootfs_dfd.open_file(path)?;
let mut buf = String::new();
nsswitch.read_to_string(&mut buf)?;
buf
};
let nsswitch = add_altfiles(&nsswitch)?;
rootfs_dfd.write_file_contents(path, 0o644, nsswitch.as_bytes())?;
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn stripany() {
let s = "foo: bar";
assert!(strip_any_prefix(s, &[]).is_none());
assert_eq!(
strip_any_prefix(s, &["baz:", "foo:", "bar:"]).unwrap(),
("foo:", " bar")
);
}
#[test]
fn altfiles_replaced() {
let orig = r##"# blah blah nss stuff
# more blah blah
# passwd: db files
# shadow: db files
# shadow: db files
passwd: sss files systemd
shadow: files
group: sss files systemd
hosts: files resolve [!UNAVAIL=return] myhostname dns
automount: files sss
"##;
let expected = r##"# blah blah nss stuff
# more blah blah
# passwd: db files
# shadow: db files
# shadow: db files
passwd: sss files altfiles systemd
shadow: files
group: sss files altfiles systemd
hosts: files resolve [!UNAVAIL=return] myhostname dns
automount: files sss
"##;
let replaced = add_altfiles(orig).unwrap();
assert_eq!(replaced.as_str(), expected);
let replaced2 = add_altfiles(replaced.as_str()).unwrap();
assert_eq!(replaced2.as_str(), expected);
}
}

View File

@ -87,6 +87,7 @@ pub mod ffi {
// composepost.rs
extern "Rust" {
fn composepost_nsswitch_altfiles(rootfs_dfd: i32) -> Result<()>;
fn compose_postprocess_final(rootfs_dfd: i32) -> Result<()>;
}

View File

@ -753,103 +753,6 @@ rpmostree_prepare_rootfs_get_sepolicy (int dfd,
return TRUE;
}
static char *
replace_nsswitch_string (const char *buf,
GError **error)
{
gboolean is_passwd;
gboolean is_group;
is_passwd = g_str_has_prefix (buf, "passwd:");
is_group = g_str_has_prefix (buf, "group:");
if (!(is_passwd || is_group))
return g_strdup (buf);
const char *colon = strchr (buf, ':');
g_assert (colon);
g_autoptr(GString) retbuf = g_string_new ("");
/* Insert the prefix */
g_string_append_len (retbuf, buf, (colon - buf) + 1);
/* Now parse the elements and try to insert `altfiles`
* after `files`.
*/
g_auto(GStrv) elts = g_strsplit_set (colon + 1, " \t", -1);
gboolean inserted = FALSE;
for (char **iter = elts; iter && *iter; iter++)
{
const char *v = *iter;
if (!*v)
continue;
/* Already have altfiles? We're done */
if (strcmp (v, "altfiles") == 0)
return g_strdup (buf);
/* We prefer `files altfiles` */
else if (!inserted && strcmp (v, "files") == 0)
{
g_string_append (retbuf, " files altfiles");
inserted = TRUE;
}
else
{
g_string_append_c (retbuf, ' ');
g_string_append (retbuf, v);
}
}
/* Last ditch effort if we didn't find `files` */
if (!inserted)
g_string_append (retbuf, " altfiles");
return g_string_free (util::move_nullify (retbuf), FALSE);
}
char *
rpmostree_postprocess_replace_nsswitch (const char *buf,
GError **error)
{
g_autoptr(GString) new_buf = g_string_new ("");
g_auto(GStrv) lines = g_strsplit (buf, "\n", -1);
for (char **iter = lines; iter && *iter; iter++)
{
const char *line = *iter;
g_autofree char *replaced_line = replace_nsswitch_string (line, error);
if (!replaced_line)
return NULL;
g_string_append (new_buf, replaced_line);
if (*(iter+1))
g_string_append_c (new_buf, '\n');
}
return g_string_free (util::move_nullify (new_buf), FALSE);
}
static gboolean
replace_nsswitch (int dfd,
GCancellable *cancellable,
GError **error)
{
g_autofree char *nsswitch_contents =
glnx_file_get_contents_utf8_at (dfd, "usr/etc/nsswitch.conf", NULL,
cancellable, error);
if (!nsswitch_contents)
return FALSE;
g_autofree char *new_nsswitch_contents =
rpmostree_postprocess_replace_nsswitch (nsswitch_contents, error);
if (!new_nsswitch_contents)
return FALSE;
if (!glnx_file_replace_contents_at (dfd, "usr/etc/nsswitch.conf",
(guint8*)new_nsswitch_contents, -1,
GLNX_FILE_REPLACE_NODATASYNC,
cancellable, error))
return FALSE;
return TRUE;
}
/* Change the policy store location.
* Part of SELinux in Fedora >= 24: https://bugzilla.redhat.com/show_bug.cgi?id=1290659
*/
@ -1028,8 +931,7 @@ rpmostree_postprocess_final (int rootfs_dfd,
}
/* NSS configuration to look at the new files */
if (!replace_nsswitch (rootfs_dfd, cancellable, error))
return glnx_prefix_error (error, "nsswitch replacement");
rpmostreecxx::composepost_nsswitch_altfiles(rootfs_dfd);
if (selinux)
{

View File

@ -26,10 +26,6 @@
G_BEGIN_DECLS
/* "public" for unit tests */
char *
rpmostree_postprocess_replace_nsswitch (const char *buf,
GError **error);
gboolean
rpmostree_treefile_postprocessing (int rootfs_fd,