tape: add hardware encryption key managenent api
This commit is contained in:
@ -9,6 +9,8 @@ use nix::fcntl::{fcntl, FcntlArg, OFlag};
|
||||
use proxmox::sys::error::SysResult;
|
||||
|
||||
use crate::{
|
||||
config,
|
||||
backup::Fingerprint,
|
||||
tools::run_command,
|
||||
api2::types::{
|
||||
TapeDensity,
|
||||
@ -24,6 +26,7 @@ use crate::{
|
||||
mam_extract_media_usage,
|
||||
read_tape_alert_flags,
|
||||
read_volume_statistics,
|
||||
set_encryption,
|
||||
drive::{
|
||||
LinuxTapeDrive,
|
||||
TapeDriver,
|
||||
@ -504,6 +507,43 @@ impl TapeDriver for LinuxTapeHandle {
|
||||
.map_err(|err| format_err!("{}", err))
|
||||
.map(|bits| TapeAlertFlags::from_bits_truncate(bits))
|
||||
}
|
||||
|
||||
/// Set or clear encryption key
|
||||
///
|
||||
/// Note: Only 'root' user may run RAW SG commands, so we need to
|
||||
/// spawn setuid binary 'sg-tape-cmd'. Also, encryption key file
|
||||
/// is only readable by root.
|
||||
fn set_encryption(&mut self, key_fingerprint: Option<Fingerprint>) -> Result<(), Error> {
|
||||
|
||||
if nix::unistd::Uid::effective().is_root() {
|
||||
|
||||
if let Some(ref key_fingerprint) = key_fingerprint {
|
||||
|
||||
let (key_map, _digest) = config::tape_encryption_keys::load_keys()?;
|
||||
match key_map.get(key_fingerprint) {
|
||||
Some(item) => {
|
||||
return set_encryption(&mut self.file, Some(item.key));
|
||||
}
|
||||
None => bail!("unknown tape encryption key '{}'", key_fingerprint),
|
||||
}
|
||||
} else {
|
||||
return set_encryption(&mut self.file, None);
|
||||
}
|
||||
}
|
||||
|
||||
let mut command = std::process::Command::new(
|
||||
"/usr/lib/x86_64-linux-gnu/proxmox-backup/sg-tape-cmd");
|
||||
command.args(&["encryption"]);
|
||||
if let Some(fingerprint) = key_fingerprint {
|
||||
let fingerprint = crate::tools::format::as_fingerprint(fingerprint.bytes());
|
||||
command.args(&["--fingerprint", &fingerprint]);
|
||||
}
|
||||
command.args(&["--stdin"]);
|
||||
command.stdin(unsafe { std::process::Stdio::from_raw_fd(self.file.as_raw_fd())});
|
||||
let output = run_command(command, None)?;
|
||||
let result: Result<(), String> = serde_json::from_str(&output)?;
|
||||
result.map_err(|err| format_err!("{}", err))
|
||||
}
|
||||
}
|
||||
|
||||
/// Write a single EOF mark without flushing buffers
|
||||
|
@ -25,6 +25,7 @@ use proxmox::tools::io::ReadExt;
|
||||
use proxmox::api::section_config::SectionConfigData;
|
||||
|
||||
use crate::{
|
||||
backup::Fingerprint,
|
||||
api2::types::{
|
||||
VirtualTapeDrive,
|
||||
LinuxTapeDrive,
|
||||
@ -163,6 +164,14 @@ pub trait TapeDriver {
|
||||
fn tape_alert_flags(&mut self) -> Result<TapeAlertFlags, Error> {
|
||||
Ok(TapeAlertFlags::empty())
|
||||
}
|
||||
|
||||
/// Set or clear encryption key
|
||||
fn set_encryption(&mut self, key_fingerprint: Option<Fingerprint>) -> Result<(), Error> {
|
||||
if key_fingerprint.is_some() {
|
||||
bail!("drive does not support encryption");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the media changer (MediaChange + name) associated with a tape drive.
|
||||
@ -234,14 +243,12 @@ pub fn open_drive(
|
||||
match section_type_name.as_ref() {
|
||||
"virtual" => {
|
||||
let tape = VirtualTapeDrive::deserialize(config)?;
|
||||
let handle = tape.open()
|
||||
.map_err(|err| format_err!("open drive '{}' ({}) failed - {}", drive, tape.path, err))?;
|
||||
Ok(Box::new(handle))
|
||||
let handle = tape.open()?;
|
||||
Ok(Box::new(handle))
|
||||
}
|
||||
"linux" => {
|
||||
let tape = LinuxTapeDrive::deserialize(config)?;
|
||||
let handle = tape.open()
|
||||
.map_err(|err| format_err!("open drive '{}' ({}) failed - {}", drive, tape.path, err))?;
|
||||
let handle = tape.open()?;
|
||||
Ok(Box::new(handle))
|
||||
}
|
||||
_ => bail!("unknown drive type '{}' - internal error"),
|
||||
|
@ -40,18 +40,20 @@ impl VirtualTapeDrive {
|
||||
|
||||
/// This needs to lock the drive
|
||||
pub fn open(&self) -> Result<VirtualTapeHandle, Error> {
|
||||
let mut lock_path = std::path::PathBuf::from(&self.path);
|
||||
lock_path.push(".drive.lck");
|
||||
proxmox::try_block!({
|
||||
let mut lock_path = std::path::PathBuf::from(&self.path);
|
||||
lock_path.push(".drive.lck");
|
||||
|
||||
let timeout = std::time::Duration::new(10, 0);
|
||||
let lock = proxmox::tools::fs::open_file_locked(&lock_path, timeout, true)?;
|
||||
let timeout = std::time::Duration::new(10, 0);
|
||||
let lock = proxmox::tools::fs::open_file_locked(&lock_path, timeout, true)?;
|
||||
|
||||
Ok(VirtualTapeHandle {
|
||||
_lock: lock,
|
||||
drive_name: self.name.clone(),
|
||||
max_size: self.max_size.unwrap_or(64*1024*1024),
|
||||
path: std::path::PathBuf::from(&self.path),
|
||||
})
|
||||
Ok(VirtualTapeHandle {
|
||||
_lock: lock,
|
||||
drive_name: self.name.clone(),
|
||||
max_size: self.max_size.unwrap_or(64*1024*1024),
|
||||
path: std::path::PathBuf::from(&self.path),
|
||||
})
|
||||
}).map_err(|err: Error| format_err!("open drive '{}' ({}) failed - {}", self.name, self.path, err))
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user