diff --git a/src/commands.rs b/src/commands.rs index ca18cef..115322b 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -9,37 +9,10 @@ use serde_json::{json, Value}; use proxmox_backup::backup::*; use proxmox_backup::client::*; -use chrono::{Utc, DateTime}; - +use super::BackupSetup; use crate::capi_types::*; use crate::upload_queue::*; -#[derive(Clone)] -pub(crate) struct BackupSetup { - pub host: String, - pub store: String, - pub user: String, - pub chunk_size: u64, - pub backup_id: String, - pub backup_time: DateTime, - pub password: Option, - pub keyfile: Option, - pub key_password: Option, - pub fingerprint: Option, -} - -impl BackupSetup { - - pub(crate) async fn connect(&self) -> Result, Error> { - let options = HttpClientOptions::new() - .fingerprint(self.fingerprint.clone()) - .password(self.password.clone()); - - let client = HttpClient::new(&self.host, &self.user, options)?; - BackupWriter::start(client, &self.store, "vm", &self.backup_id, self.backup_time, false).await - } -} - struct ImageUploadInfo { wid: u64, device_name: String, diff --git a/src/lib.rs b/src/lib.rs index ee6dc6d..9ae4f9d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,10 +5,9 @@ use std::os::raw::{c_uchar, c_char, c_int, c_void}; use std::sync::{Mutex, Condvar}; use proxmox::try_block; -use proxmox_backup::backup::*; use proxmox_backup::client::BackupRepository; -use chrono::{Utc, TimeZone}; +use chrono::{DateTime, Utc, TimeZone}; mod capi_types; use capi_types::*; @@ -16,7 +15,6 @@ use capi_types::*; mod upload_queue; mod commands; -use commands::*; mod worker_task; use worker_task::*; @@ -55,6 +53,20 @@ macro_rules! raise_error_int { }} } +#[derive(Clone)] +pub(crate) struct BackupSetup { + pub host: String, + pub store: String, + pub user: String, + pub chunk_size: u64, + pub backup_id: String, + pub backup_time: DateTime, + pub password: Option, + pub keyfile: Option, + pub key_password: Option, + pub fingerprint: Option, +} + // helper class to implement synchrounous interface struct GotResultCondition { lock: Mutex, @@ -665,14 +677,27 @@ pub extern "C" fn proxmox_backup_disconnect(handle: *mut ProxmoxBackupHandle) { #[allow(clippy::not_unsafe_ptr_arg_deref)] pub extern "C" fn proxmox_restore_connect( repo: *const c_char, - snapshot: *const c_char, + backup_id: *const c_char, + backup_time: u64, + password: *const c_char, keyfile: *const c_char, + key_password: *const c_char, + fingerprint: *const c_char, error: * mut * mut c_char, ) -> *mut ProxmoxRestoreHandle { let result: Result<_, Error> = try_block!({ let repo = unsafe { CStr::from_ptr(repo).to_str()?.to_owned() }; let repo: BackupRepository = repo.parse()?; + let backup_id = unsafe { CStr::from_ptr(backup_id).to_str()?.to_owned() }; + + let backup_time = Utc.timestamp(backup_time as i64, 0); + + let password = if password.is_null() { + None + } else { + Some(unsafe { CStr::from_ptr(password).to_str()?.to_owned() }) + }; let keyfile = if keyfile.is_null() { None @@ -680,10 +705,32 @@ pub extern "C" fn proxmox_restore_connect( Some(unsafe { CStr::from_ptr(keyfile).to_str().map(std::path::PathBuf::from)? }) }; - let snapshot = unsafe { CStr::from_ptr(snapshot).to_string_lossy().into_owned() }; - let snapshot = BackupDir::parse(&snapshot)?; + let key_password = if key_password.is_null() { + None + } else { + Some(unsafe { CStr::from_ptr(key_password).to_str()?.to_owned() }) + }; - ProxmoxRestore::new(repo, snapshot, keyfile) + let fingerprint = if fingerprint.is_null() { + None + } else { + Some(unsafe { CStr::from_ptr(fingerprint).to_str()?.to_owned() }) + }; + + let setup = BackupSetup { + host: repo.host().to_owned(), + user: repo.user().to_owned(), + store: repo.store().to_owned(), + chunk_size: PROXMOX_BACKUP_DEFAULT_CHUNK_SIZE, // not used by restore + backup_id, + password, + backup_time, + keyfile, + key_password, + fingerprint, + }; + + ProxmoxRestore::new(setup) }); match result { diff --git a/src/restore.rs b/src/restore.rs index 199369a..ba87744 100644 --- a/src/restore.rs +++ b/src/restore.rs @@ -4,7 +4,9 @@ use std::os::unix::fs::OpenOptionsExt; use proxmox_backup::tools::runtime::block_on; use proxmox_backup::backup::*; -use proxmox_backup::client::{HttpClient, HttpClientOptions, BackupReader, BackupRepository, RemoteChunkReader}; +use proxmox_backup::client::{HttpClient, HttpClientOptions, BackupReader, RemoteChunkReader}; + +use super::BackupSetup; pub(crate) struct ProxmoxRestore { pub client: Arc, @@ -14,31 +16,28 @@ pub(crate) struct ProxmoxRestore { impl ProxmoxRestore { - pub fn new( - repo: BackupRepository, - snapshot: BackupDir, - keyfile: Option, - ) -> Result { + pub fn new(setup: BackupSetup) -> Result { - let host = repo.host().to_owned(); - let user = repo.user().to_owned(); - let store = repo.store().to_owned(); - let backup_type = snapshot.group().backup_type(); - let backup_id = snapshot.group().backup_id().to_owned(); - let backup_time = snapshot.backup_time(); - - if backup_type != "vm" { - bail!("wrong backup type ({} != vm)", backup_type); - } - - let crypt_config = match keyfile { + let crypt_config = match setup.keyfile { None => None, - Some(path) => { - let (key, _) = load_and_decrypt_key(&path, &get_encryption_key_password)?; + Some(ref path) => { + let (key, _) = load_and_decrypt_key(path, & || { + match setup.key_password { + Some(ref key_password) => Ok(key_password.as_bytes().to_vec()), + None => bail!("no key_password specified"), + } + })?; Some(Arc::new(CryptConfig::new(key)?)) } }; + let host = setup.host; + let user = setup.user; + let store = setup.store; + let backup_type = String::from("vm"); + let backup_id = setup.backup_id; + let backup_time = setup.backup_time; + let result: Result<_, Error> = block_on(async { let options = HttpClientOptions::new(); @@ -174,15 +173,3 @@ impl ProxmoxRestore { Ok(()) } } - -// helper to get encrtyption key password -fn get_encryption_key_password() -> Result, Error> { - use std::env::VarError::*; - match std::env::var("PBS_ENCRYPTION_PASSWORD") { - Ok(p) => Ok(p.as_bytes().to_vec()), - Err(NotUnicode(_)) => bail!("PBS_ENCRYPTION_PASSWORD contains bad characters"), - Err(NotPresent) => { - bail!("env PBS_ENCRYPTION_PASSWORD not set"); - } - } -} diff --git a/src/worker_task.rs b/src/worker_task.rs index ac84002..fef9ff8 100644 --- a/src/worker_task.rs +++ b/src/worker_task.rs @@ -10,7 +10,9 @@ use futures::future::{Future, Either, FutureExt}; use proxmox_backup::tools::BroadcastFuture; use proxmox_backup::backup::{CryptConfig, load_and_decrypt_key}; +use proxmox_backup::client::{HttpClient, HttpClientOptions, BackupWriter}; +use super::BackupSetup; use crate::capi_types::*; use crate::commands::*; @@ -141,11 +143,17 @@ fn backup_worker_task( match msg { BackupMessage::Connect { callback_info } => { - let client = client.clone(); let setup = setup.clone(); + let client = client.clone(); let command_future = async move { - let writer = setup.connect().await?; + let options = HttpClientOptions::new() + .fingerprint(setup.fingerprint.clone()) + .password(setup.password.clone()); + + let http = HttpClient::new(&setup.host, &setup.user, options)?; + let writer = BackupWriter::start(http, &setup.store, "vm", &setup.backup_id, setup.backup_time, false).await?; + let mut guard = client.lock().unwrap(); *guard = Some(writer); Ok(0)