From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [IPv6:2a01:7e0:0:424::9]) by lore.proxmox.com (Postfix) with ESMTPS id AE4E21FF136 for ; Mon, 20 Apr 2026 18:16:41 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 8DF648E43; Mon, 20 Apr 2026 18:16:26 +0200 (CEST) From: Christian Ebner To: pbs-devel@lists.proxmox.com Subject: [PATCH proxmox-backup v4 12/30] api: config: check sync owner has access to en-/decryption keys Date: Mon, 20 Apr 2026 18:15:15 +0200 Message-ID: <20260420161533.1055484-13-c.ebner@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260420161533.1055484-1-c.ebner@proxmox.com> References: <20260420161533.1055484-1-c.ebner@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1776701665367 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.070 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy 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 Message-ID-Hash: 7DMMIK3W4IQXMO4RK62RBXFKCE36ZIMN X-Message-ID-Hash: 7DMMIK3W4IQXMO4RK62RBXFKCE36ZIMN X-MailFrom: c.ebner@proxmox.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox Backup Server development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: So a sync job can not be configured with a non existing or non accessible key for given sync owner/local-user. Key access is checked by loading the key from the keyfile. When setting the active encryption key for push sync jobs it is further assured that the key is not archived yet. Signed-off-by: Christian Ebner --- src/api2/config/sync.rs | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/api2/config/sync.rs b/src/api2/config/sync.rs index 67fa3182c..75b99c2a7 100644 --- a/src/api2/config/sync.rs +++ b/src/api2/config/sync.rs @@ -62,6 +62,22 @@ fn is_correct_owner(auth_id: &Authid, job: &SyncJobConfig) -> bool { } } +// Check access and test key loading works as expected for sync job owner/user. +fn sync_user_can_access_optional_key( + key_id: Option<&str>, + owner: &Authid, + fail_on_archived: bool, +) -> Result<(), Error> { + if let Some(key_id) = key_id { + if crate::server::sync::check_privs_and_load_key_config(key_id, owner, fail_on_archived) + .is_err() + { + bail!("no such key or cannot access key '{key_id}'"); + } + } + Ok(()) +} + /// checks whether user can run the corresponding sync job, depending on sync direction /// /// namespace creation/deletion ACL and backup group ownership checks happen in the pull/push code @@ -251,6 +267,19 @@ pub fn create_sync_job( } } + let owner = config + .owner + .as_ref() + .unwrap_or_else(|| Authid::root_auth_id()); + + if sync_direction == SyncDirection::Push { + sync_user_can_access_optional_key(config.active_encryption_key.as_deref(), owner, true)?; + } else { + for key in config.associated_key.as_deref().unwrap_or(&[]) { + sync_user_can_access_optional_key(Some(key), owner, false)?; + } + } + let (mut section_config, _digest) = sync::config()?; if section_config.sections.contains_key(&config.id) { -- 2.47.3