]> git.sesse.net Git - bcachefs-tools-debian/blob - mount/src/key.rs
Add upstream files
[bcachefs-tools-debian] / mount / src / key.rs
1 use log::info;
2
3 fn check_for_key(key_name: &std::ffi::CStr) -> anyhow::Result<bool> {
4         use crate::keyutils::{self, keyctl_search};
5         let key_name = key_name.to_bytes_with_nul().as_ptr() as *const _;
6         let key_type = c_str!("logon");
7
8         let key_id =
9                 unsafe { keyctl_search(keyutils::KEY_SPEC_USER_KEYRING, key_type, key_name, 0) };
10         if key_id > 0 {
11                 info!("Key has became avaiable");
12                 Ok(true)
13         } else if errno::errno().0 != libc::ENOKEY {
14                 Err(crate::ErrnoError(errno::errno()).into())
15         } else {
16                 Ok(false)
17         }
18 }
19
20 fn wait_for_key(uuid: &uuid::Uuid) -> anyhow::Result<()> {
21         let key_name = std::ffi::CString::new(format!("bcachefs:{}", uuid)).unwrap();
22         loop {
23                 if check_for_key(&key_name)? {
24                         break Ok(());
25                 }
26
27                 std::thread::sleep(std::time::Duration::from_secs(1));
28         }
29 }
30
31 const BCH_KEY_MAGIC: &str = "bch**key";
32 use crate::filesystem::FileSystem;
33 fn ask_for_key(fs: &FileSystem) -> anyhow::Result<()> {
34         use crate::bcachefs::{self, bch2_chacha_encrypt_key, bch_encrypted_key, bch_key};
35         use anyhow::anyhow;
36         use byteorder::{LittleEndian, ReadBytesExt};
37         use std::os::raw::c_char;
38
39         let key_name = std::ffi::CString::new(format!("bcachefs:{}", fs.uuid())).unwrap();
40         if check_for_key(&key_name)? {
41                 return Ok(());
42         }
43
44         let bch_key_magic = BCH_KEY_MAGIC.as_bytes().read_u64::<LittleEndian>().unwrap();
45         let crypt = fs.sb().sb().crypt().unwrap();
46         let pass = rpassword::read_password_from_tty(Some("Enter passphrase: "))?;
47         let pass = std::ffi::CString::new(pass.trim_end())?; // bind to keep the CString alive
48         let mut output: bch_key = unsafe {
49                 bcachefs::derive_passphrase(
50                         crypt as *const _ as *mut _,
51                         pass.as_c_str().to_bytes_with_nul().as_ptr() as *const _,
52                 )
53         };
54
55         let mut key = crypt.key().clone();
56         let ret = unsafe {
57                 bch2_chacha_encrypt_key(
58                         &mut output as *mut _,
59                         fs.sb().sb().nonce(),
60                         &mut key as *mut _ as *mut _,
61                         std::mem::size_of::<bch_encrypted_key>() as u64,
62                 )
63         };
64         if ret != 0 {
65                 Err(anyhow!("chache decryption failure"))
66         } else if key.magic != bch_key_magic {
67                 Err(anyhow!("failed to verify the password"))
68         } else {
69                 let key_type = c_str!("logon");
70                 let ret = unsafe {
71                         crate::keyutils::add_key(
72                                 key_type,
73                                 key_name.as_c_str().to_bytes_with_nul() as *const _
74                                         as *const c_char,
75                                 &output as *const _ as *const _,
76                                 std::mem::size_of::<bch_key>() as u64,
77                                 crate::keyutils::KEY_SPEC_USER_KEYRING,
78                         )
79                 };
80                 if ret == -1 {
81                         Err(anyhow!("failed to add key to keyring: {}", errno::errno()))
82                 } else {
83                         Ok(())
84                 }
85         }
86 }
87
88 pub(crate) fn prepare_key(fs: &FileSystem, password: crate::KeyLocation) -> anyhow::Result<()> {
89         use crate::KeyLocation::*;
90         use anyhow::anyhow;
91         match password {
92                 Fail => Err(anyhow!("no key available")),
93                 Wait => Ok(wait_for_key(fs.uuid())?),
94                 Ask => ask_for_key(fs),
95         }
96 }