diff options
Diffstat (limited to 'rust-src/src/key.rs')
-rw-r--r-- | rust-src/src/key.rs | 144 |
1 files changed, 0 insertions, 144 deletions
diff --git a/rust-src/src/key.rs b/rust-src/src/key.rs deleted file mode 100644 index 93daa263..00000000 --- a/rust-src/src/key.rs +++ /dev/null @@ -1,144 +0,0 @@ -use log::{info}; -use bch_bindgen::bcachefs::bch_sb_handle; -use clap::builder::PossibleValue; -use crate::c_str; -use anyhow::anyhow; - -#[derive(Clone, Debug)] -pub enum KeyLocation { - None, - Fail, - Wait, - Ask, -} - -impl std::str::FromStr for KeyLocation { - type Err = anyhow::Error; - fn from_str(s: &str) -> anyhow::Result<Self> { - match s { - ""|"none" => Ok(KeyLocation::None), - "fail" => Ok(KeyLocation::Fail), - "wait" => Ok(KeyLocation::Wait), - "ask" => Ok(KeyLocation::Ask), - _ => Err(anyhow!("invalid password option")), - } - } -} - -impl clap::ValueEnum for KeyLocation { - fn value_variants<'a>() -> &'a [Self] { - &[ - KeyLocation::None, - KeyLocation::Fail, - KeyLocation::Wait, - KeyLocation::Ask, - ] - } - - fn to_possible_value(&self) -> Option<PossibleValue> { - Some(match self { - Self::None => PossibleValue::new("none").alias(""), - Self::Fail => PossibleValue::new("fail"), - Self::Wait => PossibleValue::new("wait"), - Self::Ask => PossibleValue::new("ask"), - }) - } -} - -fn check_for_key(key_name: &std::ffi::CStr) -> anyhow::Result<bool> { - use bch_bindgen::keyutils::{self, keyctl_search}; - let key_name = key_name.to_bytes_with_nul().as_ptr() as *const _; - let key_type = c_str!("user"); - - let key_id = unsafe { keyctl_search(keyutils::KEY_SPEC_USER_KEYRING, key_type, key_name, 0) }; - if key_id > 0 { - info!("Key has became available"); - Ok(true) - } else { - match errno::errno().0 { - libc::ENOKEY | libc::EKEYREVOKED => Ok(false), - _ => Err(crate::ErrnoError(errno::errno()).into()), - } - } -} - -fn wait_for_key(uuid: &uuid::Uuid) -> anyhow::Result<()> { - let key_name = std::ffi::CString::new(format!("bcachefs:{}", uuid)).unwrap(); - loop { - if check_for_key(&key_name)? { - break Ok(()); - } - - std::thread::sleep(std::time::Duration::from_secs(1)); - } -} - -const BCH_KEY_MAGIC: &str = "bch**key"; -fn ask_for_key(sb: &bch_sb_handle) -> anyhow::Result<()> { - use bch_bindgen::bcachefs::{self, bch2_chacha_encrypt_key, bch_encrypted_key, bch_key}; - use byteorder::{LittleEndian, ReadBytesExt}; - use std::os::raw::c_char; - - let key_name = std::ffi::CString::new(format!("bcachefs:{}", sb.sb().uuid())).unwrap(); - if check_for_key(&key_name)? { - return Ok(()); - } - - let bch_key_magic = BCH_KEY_MAGIC.as_bytes().read_u64::<LittleEndian>().unwrap(); - let crypt = sb.sb().crypt().unwrap(); - let pass = if atty::is(atty::Stream::Stdin) { - rpassword::read_password_from_tty(Some("Enter passphrase: "))? - } else { - let mut line = String::new(); - std::io::stdin().read_line(&mut line)?; - line - }; - let pass = std::ffi::CString::new(pass.trim_end())?; // bind to keep the CString alive - let mut output: bch_key = unsafe { - bcachefs::derive_passphrase( - crypt as *const _ as *mut _, - pass.as_c_str().to_bytes_with_nul().as_ptr() as *const _, - ) - }; - - let mut key = crypt.key().clone(); - let ret = unsafe { - bch2_chacha_encrypt_key( - &mut output as *mut _, - sb.sb().nonce(), - &mut key as *mut _ as *mut _, - std::mem::size_of::<bch_encrypted_key>() as usize, - ) - }; - if ret != 0 { - Err(anyhow!("chacha decryption failure")) - } else if key.magic != bch_key_magic { - Err(anyhow!("failed to verify the password")) - } else { - let key_type = c_str!("user"); - let ret = unsafe { - bch_bindgen::keyutils::add_key( - key_type, - key_name.as_c_str().to_bytes_with_nul() as *const _ as *const c_char, - &output as *const _ as *const _, - std::mem::size_of::<bch_key>() as usize, - bch_bindgen::keyutils::KEY_SPEC_USER_KEYRING, - ) - }; - if ret == -1 { - Err(anyhow!("failed to add key to keyring: {}", errno::errno())) - } else { - Ok(()) - } - } -} - -pub fn prepare_key(sb: &bch_sb_handle, password: KeyLocation) -> anyhow::Result<()> { - info!("checking if key exists for filesystem {}", sb.sb().uuid()); - match password { - KeyLocation::Fail => Err(anyhow!("no key available")), - KeyLocation::Wait => Ok(wait_for_key(&sb.sb().uuid())?), - KeyLocation::Ask => ask_for_key(sb), - _ => Err(anyhow!("no keyoption specified for locked filesystem")), - } -} |