fix #3853: api: add force option to tape key change-passphrase
When force is used, the current passphrase is not required. Instead it will be read from the file pointed to by TAPE_KEYS_FILENAME and the old key configuration will be overwritten using the new passphrase. Requires super user privileges. Signed-off-by: Stefan Sterz <s.sterz@proxmox.com>
This commit is contained in:
parent
5b93835744
commit
77d6d7a22c
@ -1,4 +1,4 @@
|
|||||||
use anyhow::{bail, Error};
|
use anyhow::{format_err, bail, Error};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use hex::FromHex;
|
use hex::FromHex;
|
||||||
|
|
||||||
@ -6,12 +6,14 @@ use proxmox_router::{ApiMethod, Router, RpcEnvironment, Permission};
|
|||||||
use proxmox_schema::api;
|
use proxmox_schema::api;
|
||||||
|
|
||||||
use pbs_api_types::{
|
use pbs_api_types::{
|
||||||
Fingerprint, KeyInfo, Kdf,
|
Authid, Fingerprint, KeyInfo, Kdf,
|
||||||
TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA,
|
TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA,
|
||||||
PROXMOX_CONFIG_DIGEST_SCHEMA, PASSWORD_HINT_SCHEMA,
|
PROXMOX_CONFIG_DIGEST_SCHEMA, PASSWORD_HINT_SCHEMA,
|
||||||
PRIV_TAPE_AUDIT, PRIV_TAPE_MODIFY,
|
PRIV_TAPE_AUDIT, PRIV_TAPE_MODIFY,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use pbs_config::CachedUserInfo;
|
||||||
|
|
||||||
use pbs_config::key_config::KeyConfig;
|
use pbs_config::key_config::KeyConfig;
|
||||||
use pbs_config::open_backup_lockfile;
|
use pbs_config::open_backup_lockfile;
|
||||||
use pbs_config::tape_encryption_keys::{
|
use pbs_config::tape_encryption_keys::{
|
||||||
@ -70,6 +72,7 @@ pub fn list_keys(
|
|||||||
password: {
|
password: {
|
||||||
description: "The current password.",
|
description: "The current password.",
|
||||||
min_length: 5,
|
min_length: 5,
|
||||||
|
optional: true,
|
||||||
},
|
},
|
||||||
"new-password": {
|
"new-password": {
|
||||||
description: "The new password.",
|
description: "The new password.",
|
||||||
@ -78,6 +81,12 @@ pub fn list_keys(
|
|||||||
hint: {
|
hint: {
|
||||||
schema: PASSWORD_HINT_SCHEMA,
|
schema: PASSWORD_HINT_SCHEMA,
|
||||||
},
|
},
|
||||||
|
force: {
|
||||||
|
optional: true,
|
||||||
|
type: bool,
|
||||||
|
description: "Reset the passphrase for a tape key, using the root-only accessible copy.",
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
digest: {
|
digest: {
|
||||||
optional: true,
|
optional: true,
|
||||||
schema: PROXMOX_CONFIG_DIGEST_SCHEMA,
|
schema: PROXMOX_CONFIG_DIGEST_SCHEMA,
|
||||||
@ -91,12 +100,13 @@ pub fn list_keys(
|
|||||||
/// Change the encryption key's password (and password hint).
|
/// Change the encryption key's password (and password hint).
|
||||||
pub fn change_passphrase(
|
pub fn change_passphrase(
|
||||||
kdf: Option<Kdf>,
|
kdf: Option<Kdf>,
|
||||||
password: String,
|
password: Option<String>,
|
||||||
new_password: String,
|
new_password: String,
|
||||||
hint: String,
|
hint: String,
|
||||||
|
force: bool,
|
||||||
fingerprint: Fingerprint,
|
fingerprint: Fingerprint,
|
||||||
digest: Option<String>,
|
digest: Option<String>,
|
||||||
_rpcenv: &mut dyn RpcEnvironment
|
rpcenv: &mut dyn RpcEnvironment
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
|
|
||||||
let kdf = kdf.unwrap_or_default();
|
let kdf = kdf.unwrap_or_default();
|
||||||
@ -116,10 +126,29 @@ pub fn change_passphrase(
|
|||||||
|
|
||||||
let key_config = match config_map.get(&fingerprint) {
|
let key_config = match config_map.get(&fingerprint) {
|
||||||
Some(key_config) => key_config,
|
Some(key_config) => key_config,
|
||||||
None => bail!("tape encryption key '{}' does not exist.", fingerprint),
|
None => bail!("tape encryption key configuration '{}' does not exist.", fingerprint),
|
||||||
|
};
|
||||||
|
|
||||||
|
let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
|
||||||
|
let user_info = CachedUserInfo::new()?;
|
||||||
|
|
||||||
|
if force && !user_info.is_superuser(&auth_id) {
|
||||||
|
bail!("resetting the key's passphrase requires root privileges")
|
||||||
|
}
|
||||||
|
|
||||||
|
let (key, created, fingerprint) = match (force, &password) {
|
||||||
|
(true, Some(_)) => bail!("password is not allowed when using force"),
|
||||||
|
(false, None) => bail!("missing parameter: password"),
|
||||||
|
(false, Some(pass)) => key_config.decrypt(&|| Ok(pass.as_bytes().to_vec()))?,
|
||||||
|
(true, None) => {
|
||||||
|
let key = load_keys()?.0.get(&fingerprint).ok_or_else(|| {
|
||||||
|
format_err!("failed to reset passphrase, could not find key '{}'", fingerprint)
|
||||||
|
})?.key;
|
||||||
|
|
||||||
|
(key, key_config.created, fingerprint)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let (key, created, fingerprint) = key_config.decrypt(&|| Ok(password.as_bytes().to_vec()))?;
|
|
||||||
let mut new_key_config = KeyConfig::with_key(&key, new_password.as_bytes(), kdf)?;
|
let mut new_key_config = KeyConfig::with_key(&key, new_password.as_bytes(), kdf)?;
|
||||||
new_key_config.created = created; // keep original value
|
new_key_config.created = created; // keep original value
|
||||||
new_key_config.hint = Some(hint);
|
new_key_config.hint = Some(hint);
|
||||||
|
Loading…
Reference in New Issue
Block a user