Skip to content

Commit

Permalink
passwd: add enum PasswdKind
Browse files Browse the repository at this point in the history
  • Loading branch information
HuijingHei committed Jul 19, 2023
1 parent 0ec167f commit e1850b8
Showing 1 changed file with 62 additions and 41 deletions.
103 changes: 62 additions & 41 deletions rust/src/passwd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -315,8 +315,8 @@ fn passwd_compose_prep_impl(
rootfs.create_dir_with(dest, &db)?;

// TODO(lucab): consider reworking these to avoid boolean results.
let found_passwd_data = write_data_from_treefile(rootfs, treefile, dest, "passwd")?;
let found_groups_data = write_data_from_treefile(rootfs, treefile, dest, "group")?;
let found_passwd_data = write_data_from_treefile(rootfs, treefile, dest, &PasswdKind::User)?;
let found_groups_data = write_data_from_treefile(rootfs, treefile, dest, &PasswdKind::Group)?;

// We should error if we are getting passwd data from JSON and group from
// previous commit, or vice versa, as that'll confuse everyone when it goes
Expand All @@ -340,88 +340,109 @@ fn passwd_compose_prep_impl(
Ok(())
}

// PasswdKind includes 2 types: user and group.
#[derive(Debug)]
enum PasswdKind {
User,
Group,
}

impl PasswdKind {
// Get user/group passwd file
fn passwd_file(&self) -> &'static str {
return match *self {
PasswdKind::User => "passwd",
PasswdKind::Group => "group",
};
}
// Get user/group shadow file
fn shadow_file(&self) -> &'static str {
return match *self {
PasswdKind::User => "shadow",
PasswdKind::Group => "gshadow",
};
}
}

// This function writes the static passwd/group data from the treefile to the
// target root filesystem.
fn write_data_from_treefile(
rootfs: &Dir,
treefile: &mut Treefile,
dest_path: &str,
target: &str,
target: &PasswdKind,
) -> Result<bool> {
anyhow::ensure!(!dest_path.is_empty(), "missing destination path");

let append_unique_entries = match target {
"passwd" => passwd_append_unique,
"group" => group_append_unique,
x => anyhow::bail!("invalid merge target '{}'", x),
PasswdKind::User => passwd_append_unique,
PasswdKind::Group => group_append_unique,
};

let target_etc_filename = format!("{}{}", dest_path, target);
let passwd_name = target.passwd_file();
let target_passwd_path = format!("{}{}", dest_path, passwd_name);

// Migrate the check data from the specified file to /etc.
let mut src_file = if target == "passwd" {
let check_passwd_file = match treefile.parsed.get_check_passwd() {
CheckPasswd::File(cfg) => cfg,
_ => return Ok(false),
};
treefile.externals.passwd_file_mut(check_passwd_file)?
} else if target == "group" {
let check_groups_file = match treefile.parsed.get_check_groups() {
CheckGroups::File(cfg) => cfg,
_ => return Ok(false),
};
treefile.externals.group_file_mut(check_groups_file)?
} else {
unreachable!("impossible merge target '{}'", target);
let mut src_file = match target {
PasswdKind::User => {
let check_passwd_file = match treefile.parsed.get_check_passwd() {
CheckPasswd::File(cfg) => cfg,
_ => return Ok(false),
};
treefile.externals.passwd_file_mut(check_passwd_file)?
}
PasswdKind::Group => {
let check_groups_file = match treefile.parsed.get_check_groups() {
CheckGroups::File(cfg) => cfg,
_ => return Ok(false),
};
treefile.externals.group_file_mut(check_groups_file)?
}
};

let mut seen_names = HashSet::new();
rootfs
.atomic_replace_with(&target_etc_filename, |dest_bufwr| -> Result<()> {
.atomic_replace_with(&target_passwd_path, |dest_bufwr| -> Result<()> {
dest_bufwr
.get_mut()
.as_file_mut()
.set_permissions(DEFAULT_PERMS.clone())?;
let mut buf_rd = BufReader::new(&mut src_file);
append_unique_entries(&mut buf_rd, &mut seen_names, dest_bufwr)
.with_context(|| format!("failed to process '{}' content from JSON", &target))?;
append_unique_entries(&mut buf_rd, &mut seen_names, dest_bufwr).with_context(|| {
format!("failed to process '{}' content from JSON", &passwd_name)
})?;
Ok(())
})
.with_context(|| format!("failed to write /{}", &target_etc_filename))?;
.with_context(|| format!("failed to write /{}", &target_passwd_path))?;

// 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);
// Regenerate etc/{,g}shadow to sync with etc/{passwd,group}
let db = rootfs.open(target_passwd_path).map(BufReader::new)?;
let shadow_name = target.shadow_file();
let target_shadow_path = format!("{}{}", dest_path, shadow_name);

match shadow_name {
"shadow" => {
match target {
PasswdKind::User => {
let entries = nameservice::passwd::parse_passwd_content(db)?;
rootfs
.atomic_replace_with(&target_etc_shadow, |target_shadow| -> Result<()> {
.atomic_replace_with(&target_shadow_path, |target_shadow| -> Result<()> {
for user in entries {
writeln!(target_shadow, "{}:*::0:99999:7:::", user.name)?;
}
Ok(())
})
.with_context(|| format!("Writing {target_etc_shadow}"))?;
.with_context(|| format!("Writing {target_shadow_path}"))?;
}
"gshadow" => {
PasswdKind::Group => {
let entries = nameservice::group::parse_group_content(db)?;
rootfs
.atomic_replace_with(&target_etc_shadow, |target_shadow| -> Result<()> {
.atomic_replace_with(&target_shadow_path, |target_shadow| -> Result<()> {
for group in entries {
writeln!(target_shadow, "{}:::", group.name)?;
}
Ok(())
})
.with_context(|| format!("Writing {target_etc_shadow}"))?;
.with_context(|| format!("Writing {target_shadow_path}"))?;
}
_ => unreachable!("invalid file path: {}", target_etc_shadow),
}
Ok(true)
}
Expand Down

0 comments on commit e1850b8

Please sign in to comment.