123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162 |
- use btlib::{
- blocktree::Blocktree,
- crypto::{tpm::TpmCredStore, CredStore},
- };
- use fuse_backend_rs::{api::server::Server, transport::{FuseSession, Error}};
- use log::error;
- use std::{
- ffi::{c_char, CString},
- fs::{self, File},
- io,
- os::fd::FromRawFd,
- os::{raw::c_int, unix::ffi::OsStrExt},
- path::{Path, PathBuf},
- str::FromStr,
- };
- use tss_esapi::{
- tcti_ldr::{TabrmdConfig, TctiNameConf},
- Context,
- };
- const DEFAULT_TABRMD: &str = "bus_type=session";
- const MOUNT_OPTIONS: &str = "default_permissions";
- const FSNAME: &str = "btfuse";
- const FSTYPE: &str = "bt";
- trait PathExt {
- fn try_create_dir(&self) -> io::Result<()>;
- }
- impl<T: AsRef<Path>> PathExt for T {
- fn try_create_dir(&self) -> io::Result<()> {
- match fs::create_dir(self) {
- Ok(_) => Ok(()),
- Err(err) => match err.kind() {
- io::ErrorKind::AlreadyExists => Ok(()),
- _ => Err(err),
- },
- }
- }
- }
- #[link(name = "fuse3")]
- extern "C" {
- /// Opens a channel to the kernel.
- fn fuse_open_channel(mountpoint: *const c_char, options: *const c_char) -> c_int;
- }
- /// Calls into libfuse3 to mount this file system at the given path. The file descriptor to use
- /// to communicate with the kernel is returned.
- fn mount_at<P: AsRef<Path>>(mountpoint: P) -> File {
- let mountpoint = CString::new(mountpoint.as_ref().as_os_str().as_bytes()).unwrap();
- let options = CString::new(MOUNT_OPTIONS).unwrap();
- let raw_fd = unsafe { fuse_open_channel(mountpoint.as_ptr(), options.as_ptr()) };
- unsafe { File::from_raw_fd(raw_fd) }
- }
- /// A fuse daemon process.
- struct FuseDaemon<'a> {
- /// The path of the directory to store all file system information in.
- path: &'a Path,
- /// The configuration string to use to connect to a Tabrmd instance.
- tabrmd_config: &'a str,
- }
- impl<'a> FuseDaemon<'a> {
- fn new(path: &'a Path, tabrmd_config: &'a str) -> FuseDaemon<'_> {
- FuseDaemon {
- path,
- tabrmd_config,
- }
- }
- fn start(&self) {
- self.path
- .try_create_dir()
- .expect("failed to create main directory");
- let mnt_path = self.path.join("mnt");
- mnt_path
- .try_create_dir()
- .expect("failed to create mount directory");
- let empty = fs::read_dir(&mnt_path)
- .expect("failed to read mountdir")
- .next()
- .is_none();
- let context = Context::new(TctiNameConf::Tabrmd(
- TabrmdConfig::from_str(self.tabrmd_config).expect("failed to parse Tabrmd config"),
- ))
- .expect("failed to connect to Tabrmd");
- let cred_store = TpmCredStore::new(context, self.path.join("tpm_state"))
- .expect("failed to create TpmCredStore");
- let node_creds = cred_store
- .node_creds()
- .expect("failed to retrieve node creds");
- let bt_path = self.path.join("bt");
- bt_path
- .try_create_dir()
- .expect("failed to create blocktree directory");
- let fs = if empty {
- Blocktree::new_empty(bt_path, 0, node_creds)
- } else {
- Blocktree::new_existing(bt_path, node_creds)
- }
- .expect("failed to create blocktree");
- let server = Server::new(fs);
- let mut session = FuseSession::new(&mnt_path, FSNAME, FSTYPE, false)
- .expect("failed to create FUSE session");
- session.set_fuse_file(mount_at(&mnt_path));
- let mut channel = session
- .new_channel()
- .expect("failed to create FUSE channel");
- loop {
- match channel.get_request() {
- Ok(Some((reader, writer))) => {
- if let Err(err) = server.handle_message(reader, writer.into(), None, None) {
- error!("error while handling FUSE message: {err}");
- }
- }
- Ok(None) => break,
- Err(err) => {
- match err {
- // Occurs when the file system is unmounted.
- Error::SessionFailure(_) => break,
- _ => error!("{err}"),
- }
- }
- }
- }
- }
- }
- fn main() {
- env_logger::init();
- let main_dir = std::env::args().nth(1).expect("no mount point given");
- let main_dir =
- PathBuf::from_str(main_dir.as_str()).expect("failed to convert mount point to PathBuf");
- let tabrmd_string = std::env::var("BT_TABRMD").ok();
- let tabrmd_str = tabrmd_string
- .as_ref()
- .map_or(DEFAULT_TABRMD, |s| s.as_str());
- let daemon = FuseDaemon::new(&main_dir, tabrmd_str);
- daemon.start();
- }
- #[cfg(test)]
- mod test {
- use btlib::test_helpers;
- use tempdir::TempDir;
- use super::*;
- /// Starts the `FuseDaemon` in a new temporary directory prefixed by "btfuse".
- #[test]
- fn server_start() {
- std::env::set_var("RUST_LOG", "info");
- env_logger::init();
- let temp_dir = TempDir::new("btfuse").expect("failed to create TempDir");
- let swtpm = test_helpers::SwtpmHarness::new().expect("failed to start swtpm");
- let daemon = FuseDaemon::new(temp_dir.path(), swtpm.tabrmd_config());
- daemon.start();
- }
- }
|