Merge pull request #320 from WhatAmISupposedToPutHere/master

Ask for password via systemd-ask-password
This commit is contained in:
koverstreet 2024-08-02 09:33:46 -04:00 committed by GitHub
commit 6958dd8df2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 36 additions and 8 deletions

View File

@ -331,8 +331,9 @@ fn handle_unlock(cli: &Cli, sb: &bch_sb_handle) -> Result<KeyHandle> {
return Passphrase::new_from_file(path).and_then(|p| KeyHandle::new(sb, &p));
}
KeyHandle::new_from_search(&sb.sb().uuid())
.or_else(|_| Passphrase::new().and_then(|p| KeyHandle::new(sb, &p)))
let uuid = sb.sb().uuid();
KeyHandle::new_from_search(&uuid)
.or_else(|_| Passphrase::new(&uuid).and_then(|p| KeyHandle::new(sb, &p)))
}
fn cmd_mount_inner(cli: &Cli) -> Result<()> {

View File

@ -7,7 +7,7 @@ use std::{
ptr, thread,
time::Duration,
};
use std::process::{Command, Stdio};
use anyhow::{anyhow, ensure, Result};
use bch_bindgen::{
bcachefs::{self, bch_key, bch_sb_handle},
@ -15,7 +15,7 @@ use bch_bindgen::{
keyutils::{self, keyctl_search},
};
use byteorder::{LittleEndian, ReadBytesExt};
use log::info;
use log::{debug, info};
use rustix::termios;
use uuid::Uuid;
use zeroize::{ZeroizeOnDrop, Zeroizing};
@ -46,7 +46,7 @@ impl UnlockPolicy {
match self {
Self::Fail => KeyHandle::new_from_search(&uuid),
Self::Wait => Ok(KeyHandle::wait_for_unlock(&uuid)?),
Self::Ask => Passphrase::new_from_prompt().and_then(|p| KeyHandle::new(sb, &p)),
Self::Ask => Passphrase::new_from_prompt(&uuid).and_then(|p| KeyHandle::new(sb, &p)),
Self::Stdin => Passphrase::new_from_stdin().and_then(|p| KeyHandle::new(sb, &p)),
}
}
@ -142,16 +142,43 @@ impl Passphrase {
&self.0
}
pub fn new() -> Result<Self> {
pub fn new(uuid: &Uuid) -> Result<Self> {
if stdin().is_terminal() {
Self::new_from_prompt()
Self::new_from_prompt(uuid)
} else {
Self::new_from_stdin()
}
}
// The outer result represents a failure when trying to run systemd-ask-password,
// it is non-critical and will cause the password to be asked internally.
// The inner result represent a successful request that returned an error
// this one results in an error.
fn new_from_askpassword(uuid: &Uuid) -> Result<Result<Self>> {
let output = Command::new("systemd-ask-password")
.arg("--icon=drive-harddisk")
.arg(format!("--id=bcachefs:{}", uuid.as_hyphenated()))
.arg("-n")
.arg("Enter passphrase: ")
.stdin(Stdio::inherit())
.stderr(Stdio::inherit())
.output()?;
Ok(if output.status.success() {
match CString::new(output.stdout) {
Ok(cstr) => Ok(Self(cstr)),
Err(e) => Err(e.into())
}
} else {
Err(anyhow!("systemd-ask-password returned an error"))
})
}
// blocks indefinitely if no input is available on stdin
pub fn new_from_prompt() -> Result<Self> {
pub fn new_from_prompt(uuid: &Uuid) -> Result<Self> {
match Self::new_from_askpassword(uuid) {
Ok(phrase) => return phrase,
Err(_) => debug!("Failed to start systemd-ask-password, doing the prompt ourselves"),
}
let old = termios::tcgetattr(stdin())?;
let mut new = old.clone();
new.local_modes.remove(termios::LocalModes::ECHO);