From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by lists.proxmox.com (Postfix) with ESMTPS id 48BC661CEE for ; Thu, 10 Feb 2022 15:25:15 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 3F4DF1E22D for ; Thu, 10 Feb 2022 15:24:45 +0100 (CET) Received: from proxmox-new.maurer-it.com (proxmox-new.maurer-it.com [94.136.29.106]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by firstgate.proxmox.com (Proxmox) with ESMTPS id 717251E224 for ; Thu, 10 Feb 2022 15:24:44 +0100 (CET) Received: from proxmox-new.maurer-it.com (localhost.localdomain [127.0.0.1]) by proxmox-new.maurer-it.com (Proxmox) with ESMTP id 488E646DCD for ; Thu, 10 Feb 2022 15:24:44 +0100 (CET) From: Stefan Sterz To: pbs-devel@lists.proxmox.com Date: Thu, 10 Feb 2022 15:23:24 +0100 Message-Id: <20220210142325.2595867-1-s.sterz@proxmox.com> X-Mailer: git-send-email 2.30.2 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL -0.000 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record T_SCC_BODY_TEXT_LINE -0.01 - Subject: [pbs-devel] [PATCH proxmox-backup v2 1/2] fix #3853: api: add force option to tape key change-passphrase X-BeenThere: pbs-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox Backup Server development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 10 Feb 2022 14:25:15 -0000 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 --- v1->v2: check for root privileges moved into the api endpoint, better descriptions and errors strings and incorporated some nitpicks. Thanks for the feedback to Thomas Lamprecht, Dominik Csapak, and Wolfgang Bumiller. src/api2/config/tape_encryption_keys.rs | 41 +++++++++++++++++++++---- 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/src/api2/config/tape_encryption_keys.rs b/src/api2/config/tape_encryption_keys.rs index 1ad99377..25cc6cc0 100644 --- a/src/api2/config/tape_encryption_keys.rs +++ b/src/api2/config/tape_encryption_keys.rs @@ -1,4 +1,4 @@ -use anyhow::{bail, Error}; +use anyhow::{format_err, bail, Error}; use serde_json::Value; use hex::FromHex; @@ -6,12 +6,14 @@ use proxmox_router::{ApiMethod, Router, RpcEnvironment, Permission}; use proxmox_schema::api; use pbs_api_types::{ - Fingerprint, KeyInfo, Kdf, + Authid, Fingerprint, KeyInfo, Kdf, TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA, PROXMOX_CONFIG_DIGEST_SCHEMA, PASSWORD_HINT_SCHEMA, PRIV_TAPE_AUDIT, PRIV_TAPE_MODIFY, }; +use pbs_config::CachedUserInfo; + use pbs_config::key_config::KeyConfig; use pbs_config::open_backup_lockfile; use pbs_config::tape_encryption_keys::{ @@ -70,6 +72,7 @@ pub fn list_keys( password: { description: "The current password.", min_length: 5, + optional: true, }, "new-password": { description: "The new password.", @@ -78,6 +81,12 @@ pub fn list_keys( hint: { 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: { optional: true, schema: PROXMOX_CONFIG_DIGEST_SCHEMA, @@ -91,12 +100,13 @@ pub fn list_keys( /// Change the encryption key's password (and password hint). pub fn change_passphrase( kdf: Option, - password: String, + password: Option, new_password: String, hint: String, + force: bool, fingerprint: Fingerprint, digest: Option, - _rpcenv: &mut dyn RpcEnvironment + rpcenv: &mut dyn RpcEnvironment ) -> Result<(), Error> { let kdf = kdf.unwrap_or_default(); @@ -116,10 +126,29 @@ pub fn change_passphrase( let key_config = match config_map.get(&fingerprint) { 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)?; new_key_config.created = created; // keep original value new_key_config.hint = Some(hint); -- 2.30.2