tape: key recovery: refcator and split string/file case for cli params
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
This commit is contained in:
		| @ -10,7 +10,7 @@ use proxmox_sys::sortable; | ||||
| use proxmox_router::{ | ||||
|     list_subdirs_api_method, Permission, Router, RpcEnvironment, RpcEnvironmentType, SubdirMap, | ||||
| }; | ||||
| use proxmox_schema::{api, param_bail}; | ||||
| use proxmox_schema::api; | ||||
| use proxmox_section_config::SectionConfigData; | ||||
| use proxmox_uuid::Uuid; | ||||
| use proxmox_sys::{task_log, task_warn}; | ||||
| @ -609,13 +609,14 @@ fn write_media_label( | ||||
|         properties: { | ||||
|             drive: { | ||||
|                 schema: DRIVE_NAME_SCHEMA, | ||||
|                 //description: "Restore the key from this drive the (encrypted) key was saved on.", | ||||
|                 optional: true, | ||||
|             }, | ||||
|             password: { | ||||
|                 description: "Encryption key password.", | ||||
|                 description: "The password the key was encrypted with.", | ||||
|             }, | ||||
|             backupkey: { | ||||
|                 description: "A previously exported paperkey in JSON format.", | ||||
|             key: { | ||||
|                 description: "Restore the key from this JSON string. Clashes with drive.", | ||||
|                 type: String, | ||||
|                 min_length: 300, | ||||
|                 max_length: 600, | ||||
| @ -631,40 +632,34 @@ fn write_media_label( | ||||
| pub async fn restore_key( | ||||
|     drive: Option<String>, | ||||
|     password: String, | ||||
|     backupkey: Option<String>, | ||||
|     key: Option<String>, | ||||
| ) -> Result<(), Error> { | ||||
|  | ||||
|     if (drive.is_none() && backupkey.is_none()) || (drive.is_some() && backupkey.is_some()) { | ||||
|         param_bail!( | ||||
|             "drive", | ||||
|             format_err!("Please specify either a valid drive name or a backupkey") | ||||
|         ); | ||||
|     if drive.is_some() && key.is_some() { | ||||
|         bail!("cannot have both 'drive' and 'key' parameter set!"); | ||||
|     } else if !drive.is_some() && !key.is_some() { | ||||
|         bail!("one of either 'drive' or 'key' parameter must be set!"); | ||||
|     } | ||||
|  | ||||
|     if let Some(drive) = drive { | ||||
|         run_drive_blocking_task( | ||||
|             drive.clone(), | ||||
|             "restore key".to_string(), | ||||
|             move |config| { | ||||
|                 let mut drive = open_drive(&config, &drive)?; | ||||
|         run_drive_blocking_task(drive.clone(), "restore key".to_string(), move |config| { | ||||
|             let mut drive = open_drive(&config, &drive)?; | ||||
|  | ||||
|                 let (_media_id, key_config) = drive.read_label()?; | ||||
|             let (_media_id, key_config) = drive.read_label()?; | ||||
|  | ||||
|                 if let Some(key_config) = key_config { | ||||
|                     let password_fn = || { Ok(password.as_bytes().to_vec()) }; | ||||
|                     let (key, ..) = key_config.decrypt(&password_fn)?; | ||||
|                     insert_key(key, key_config, true)?; | ||||
|                 } else { | ||||
|                     bail!("media does not contain any encryption key configuration"); | ||||
|                 } | ||||
|  | ||||
|                 Ok(()) | ||||
|             if let Some(key_config) = key_config { | ||||
|                 let password_fn = || Ok(password.as_bytes().to_vec()); | ||||
|                 let (key, ..) = key_config.decrypt(&password_fn)?; | ||||
|                 insert_key(key, key_config, true)?; | ||||
|             } else { | ||||
|                 bail!("media does not contain any encryption key configuration"); | ||||
|             } | ||||
|         ) | ||||
|  | ||||
|             Ok(()) | ||||
|         }) | ||||
|         .await?; | ||||
|     }else if let Some(backupkey) = backupkey { | ||||
|     } else if let Some(key) = key { | ||||
|         let key_config: KeyConfig = | ||||
|                 serde_json::from_str(&backupkey).map_err(|err| format_err!("<errmsg>: {}", err))?; | ||||
|             serde_json::from_str(&key).map_err(|err| format_err!("<errmsg>: {}", err))?; | ||||
|         let password_fn = || Ok(password.as_bytes().to_vec()); | ||||
|         let (key, ..) = key_config.decrypt(&password_fn)?; | ||||
|         insert_key(key, key_config, false)?; | ||||
|  | ||||
| @ -187,9 +187,6 @@ fn change_passphrase( | ||||
|     Ok(()) | ||||
| } | ||||
|  | ||||
| pub const BEGIN_MARKER: &str = "-----BEGIN PROXMOX BACKUP KEY-----"; | ||||
| pub const END_MARKER: &str = "-----END PROXMOX BACKUP KEY-----"; | ||||
|  | ||||
| #[api( | ||||
|     input: { | ||||
|         properties: { | ||||
| @ -197,69 +194,71 @@ pub const END_MARKER: &str = "-----END PROXMOX BACKUP KEY-----"; | ||||
|                 schema: DRIVE_NAME_SCHEMA, | ||||
|                 optional: true, | ||||
|             }, | ||||
|             "backupkey": { | ||||
|                 description: "Importing a previously exported backupkey with either an exported paperkey-file, json-string or a json-file", | ||||
|             key: { | ||||
|                 description: "Import key from json string or an exported paperkey-format.", | ||||
|                 type: String, | ||||
|                 optional: true, | ||||
|             }, | ||||
|             "key-file": { | ||||
|                 description: "Import key from a file with either json or exported paperkey-format.", | ||||
|                 type: String, | ||||
|                 optional: true, | ||||
|             }, | ||||
|         }, | ||||
|     }, | ||||
| )] | ||||
| /// Restore encryption key from tape (read password from stdin) | ||||
| /// Restore encryption key from tape or from a backup file/string (reads password from stdin) | ||||
| async fn restore_key( | ||||
|     mut param: Value, | ||||
|     backupkey: Option<String>, | ||||
|     key: Option<String>, | ||||
|     key_file: Option<String>, | ||||
|     rpcenv: &mut dyn RpcEnvironment, | ||||
| ) -> Result<(), Error> { | ||||
|  | ||||
|     let (config, _digest) = pbs_config::drive::config()?; | ||||
|  | ||||
|     let drive = crate::extract_drive_name(&mut param, &config); | ||||
|  | ||||
|     let drive_passed = param.get("drive").is_some(); | ||||
|     if drive_passed && (key.is_some() || key_file.is_some()) { | ||||
|         bail!("cannot have both 'drive' and 'key(-file)' parameter set!"); | ||||
|     } else if key.is_some() && key_file.is_some() { | ||||
|         bail!("cannot have both 'key' and 'key-file' parameter set!"); | ||||
|     } else if !drive_passed && !key.is_some() && !key_file.is_some() { | ||||
|         bail!("one of either 'drive' or 'key' parameter must be set!"); | ||||
|     } | ||||
|     if !tty::stdin_isatty() { | ||||
|         bail!("no password input mechanism available"); | ||||
|     } | ||||
|  | ||||
|     if (drive.is_err() && backupkey.is_none()) || (drive.is_ok() && backupkey.is_some()) { | ||||
|         param_bail!( | ||||
|             "drive", | ||||
|             format_err!("Please specify either a valid drive name or a backupkey") | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     if drive.is_ok() { | ||||
|         param["drive"] = drive.unwrap().into(); | ||||
|     } | ||||
|  | ||||
|     if let Some(backupkey) = backupkey { | ||||
|         if serde_json::from_str::<KeyConfig>(&backupkey).is_ok() { | ||||
|             // json as Parameter | ||||
|             println!("backupkey to import: {}", backupkey); | ||||
|             param["backupkey"] = backupkey.into(); | ||||
|         } else { | ||||
|             println!("backupkey is not a valid json. Interpreting Parameter as a filename"); | ||||
|             let data = proxmox_sys::fs::file_read_string(backupkey)?; | ||||
|             if serde_json::from_str::<KeyConfig>(&data).is_ok() { | ||||
|                 // standalone json-file | ||||
|                 println!("backupkey to import: {}", data); | ||||
|                 param["backupkey"] = data.into(); | ||||
|             } else { | ||||
|                 // exported paperkey-file | ||||
|                 let start = data | ||||
|                     .find(BEGIN_MARKER) | ||||
|                     .ok_or_else(|| format_err!("cannot find key start marker"))? | ||||
|                     + BEGIN_MARKER.len(); | ||||
|                 let data_remain = &data[start..]; | ||||
|                 let end = data_remain | ||||
|                     .find(END_MARKER) | ||||
|                     .ok_or_else(|| format_err!("cannot find key end marker below start marker"))?; | ||||
|                 let backupkey_extract = &data_remain[..end]; | ||||
|                 println!("backupkey to import: {}", backupkey_extract); | ||||
|                 param["backupkey"] = backupkey_extract.into(); | ||||
|             } | ||||
|     if drive_passed { | ||||
|         let (config, _digest) = pbs_config::drive::config()?; | ||||
|         match crate::extract_drive_name(&mut param, &config) { | ||||
|             Ok(drive) => param["drive"] = drive.into(), | ||||
|             Err(err) => param_bail!("drive", format_err!("invalid drive - {}", err)), | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     let key = match key_file { | ||||
|         Some(key_file) => Some(proxmox_sys::fs::file_read_string(key_file)?), | ||||
|         None => key, | ||||
|     }; | ||||
|     if let Some(data) = key { | ||||
|         let key = if serde_json::from_str::<KeyConfig>(&data).is_ok() { | ||||
|             &data | ||||
|         } else { | ||||
|             const BEGIN_MARKER: &str = "-----BEGIN PROXMOX BACKUP KEY-----"; | ||||
|             const END_MARKER: &str = "-----END PROXMOX BACKUP KEY-----"; | ||||
|             // exported paperkey-file | ||||
|             let start = data | ||||
|                 .find(BEGIN_MARKER) | ||||
|                 .ok_or_else(|| format_err!("cannot find key start marker"))? | ||||
|                 + BEGIN_MARKER.len(); | ||||
|             let data_remain = &data[start..]; | ||||
|             let end = data_remain | ||||
|                 .find(END_MARKER) | ||||
|                 .ok_or_else(|| format_err!("cannot find key end marker below start marker"))?; | ||||
|             &data_remain[..end] | ||||
|         }; | ||||
|         println!("key to import: {}", key); | ||||
|         param["key"] = key.into(); | ||||
|     } | ||||
|  | ||||
|     let password = tty::read_password("Tape Encryption Key Password: ")?; | ||||
|     param["password"] = String::from_utf8(password)?.into(); | ||||
|  | ||||
|  | ||||
		Reference in New Issue
	
	Block a user