[PATCH installer v3 1/1] assistant: validate: add verify-root-password option
Peter
pjcreath+proxmox at gmail.com
Wed Sep 17 23:10:59 CEST 2025
bump?
On Wed, Sep 10, 2025 at 3:47 PM Peter <pjcreath+proxmox at gmail.com> wrote:
> Adds an option to interactively verify the hashed root password in
> the answer file, so that mistakes can be caught before installation.
>
> Signed-off-by: Peter <pjcreath+proxmox at gmail.com>
> ---
>
> changes since v2:
> * updated debian/control for new dependency
> * cleaned up the proxmox_sys use statements
> * cleaned up messages and usage description as requested
>
> debian/control | 1 +
> proxmox-auto-install-assistant/Cargo.toml | 1 +
> proxmox-auto-install-assistant/src/main.rs | 37 +++++++++++++++++++---
> 3 files changed, 35 insertions(+), 4 deletions(-)
>
> diff --git a/debian/control b/debian/control
> index 5a6a8cf..9659924 100644
> --- a/debian/control
> +++ b/debian/control
> @@ -18,6 +18,7 @@ Build-Depends: cargo:native,
> librust-native-tls-dev,
> librust-pico-args-0.5-dev,
> librust-pretty-assertions-1.4-dev,
> + librust-proxmox-sys+crypt-dev,
> librust-regex-1+default-dev (>= 1.7~~),
> librust-rustls-0.23-dev,
> librust-rustls-native-certs-dev,
> diff --git a/proxmox-auto-install-assistant/Cargo.toml
> b/proxmox-auto-install-assistant/Cargo.toml
> index 9b4a9c4..eeba42f 100644
> --- a/proxmox-auto-install-assistant/Cargo.toml
> +++ b/proxmox-auto-install-assistant/Cargo.toml
> @@ -17,4 +17,5 @@ proxmox-installer-common = { workspace = true, features
> = [ "cli" ] }
> serde_json.workspace = true
> toml.workspace = true
>
> +proxmox-sys = { version = "1.0.0", features = [ "crypt" ] }
> glob = "0.3"
> diff --git a/proxmox-auto-install-assistant/src/main.rs
> b/proxmox-auto-install-assistant/src/main.rs
> index 5d6c1d5..c0d932c 100644
> --- a/proxmox-auto-install-assistant/src/main.rs
> +++ b/proxmox-auto-install-assistant/src/main.rs
> @@ -6,10 +6,11 @@
>
> use anyhow::{Context, Result, bail, format_err};
> use glob::Pattern;
> +use proxmox_sys::{crypt::verify_crypt_pw, linux::tty::read_password};
> use std::{
> collections::BTreeMap,
> fmt, fs,
> - io::{self, Read},
> + io::{self, IsTerminal, Read},
> path::{Path, PathBuf},
> process::{self, Command, Stdio},
> str::FromStr,
> @@ -153,12 +154,15 @@ struct CommandValidateAnswerArgs {
> path: PathBuf,
> /// Whether to also show the full answer as parsed.
> debug: bool,
> + /// Interactively verify the hashed root password.
> + verify_password: bool,
> }
>
> impl cli::Subcommand for CommandValidateAnswerArgs {
> fn parse(args: &mut cli::Arguments) -> Result<Self> {
> Ok(Self {
> debug: args.contains(["-d", "--debug"]),
> + verify_password: args.contains("--verify-root-password"),
> // Needs to be last
> path: args.free_from_str()?,
> })
> @@ -175,15 +179,20 @@ ARGUMENTS:
> <PATH> Path to the answer file.
>
> OPTIONS:
> - -d, --debug Also show the full answer as parsed.
> - -h, --help Print this help
> - -V, --version Print version
> + -d, --debug Also show the full answer as parsed.
> + --verify-root-password Interactively verify the hashed root
> password.
> + -h, --help Print this help
> + -V, --version Print version
> "#,
> env!("CARGO_PKG_NAME")
> );
> }
>
> fn run(&self) -> Result<()> {
> + if self.verify_password && !std::io::stdin().is_terminal() {
> + Self::print_usage();
> + bail!("Verifying the root password requires an interactive
> terminal.");
> + }
> validate_answer(self)
> }
> }
> @@ -545,6 +554,20 @@ fn validate_answer_file_keys(path: impl AsRef<Path> +
> fmt::Debug) -> Result<bool
> }
> }
>
> +fn verify_hashed_password_interactive(answer: &Answer) -> Result<()> {
> + if let Some(hashed) = &answer.global.root_password_hashed {
> + println!("Verifying hashed root password.");
> +
> + let password = String::from_utf8(read_password("Enter root
> password to verify: ")?)?;
> + verify_crypt_pw(&password, hashed).context("Failed to verify
> hashed root password")?;
> +
> + println!("Password matches hashed root password.");
> + Ok(())
> + } else {
> + bail!("'root-password-hashed' not set in answer file, cannot
> verify.");
> + }
> +}
> +
> fn validate_answer(args: &CommandValidateAnswerArgs) -> Result<()> {
> let mut valid = validate_answer_file_keys(&args.path)?;
>
> @@ -553,6 +576,12 @@ fn validate_answer(args: &CommandValidateAnswerArgs)
> -> Result<()> {
> if args.debug {
> println!("Parsed data from answer file:\n{:#?}", answer);
> }
> + if args.verify_password {
> + if let Err(err) =
> verify_hashed_password_interactive(&answer) {
> + eprintln!("{err:#}");
> + valid = false;
> + }
> + }
> }
> Err(err) => {
> eprintln!("{err:#}");
> --
> 2.47.2
>
>
More information about the pve-devel
mailing list