Merge pull request #2660 from cgwalters/postprocess-rs-nsswitch
Oxidize postprocessing `altfiles` addition to `/etc/nsswitch.conf`
This commit is contained in:
commit
9deeeedc5d
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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<()>;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user