* [PATCH backup v4 1/4] fix #7054: client: remove trailing newlines from credentials
2026-07-06 8:02 [PATCH backup v4 0/4] fix #7054: client: remove trailing newlines from credentials Maximiliano Sandoval
@ 2026-07-06 8:02 ` Maximiliano Sandoval
2026-07-06 8:02 ` [PATCH backup v4 2/4] docs: client: document further password constrains Maximiliano Sandoval
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Maximiliano Sandoval @ 2026-07-06 8:02 UTC (permalink / raw)
To: pbs-devel
Some tools, like systemd-ask-password can add a trailing new line to the file.
In order to improve usability we strip trailing newlines.
For repositories and fingerprints we simply strip trailing whitespaces. For
passwords, we refer to the password regex at proxmox-schema: `^[[:^cntrl:]]*$`,
we can only strip trailing control characters without potentially breaking
existing passwords. For the sake of avoiding to strip more than necessary we
only strip trailing newlines.
The encryption password is just a blob of bytes handled locally by the client,
we cannot remove trailing whitespace here without potential breakage. Creation
of such passwords (via proxmox_sys::tty::read_and_verify_password) only verifies
valid utf-8 and len >= 5 and thus the password might contain newlines.
Signed-off-by: Maximiliano Sandoval <m.sandoval@proxmox.com>
---
pbs-client/src/tools/mod.rs | 3 +++
1 file changed, 3 insertions(+)
diff --git a/pbs-client/src/tools/mod.rs b/pbs-client/src/tools/mod.rs
index 700436f8c..ca64b239e 100644
--- a/pbs-client/src/tools/mod.rs
+++ b/pbs-client/src/tools/mod.rs
@@ -189,6 +189,7 @@ fn get_secret_impl(env_variable: &str, credential_name: &str) -> Result<Option<S
/// [credential]: https://systemd.io/CREDENTIALS/
pub fn get_password() -> Result<Option<String>, Error> {
get_secret_impl(ENV_VAR_PBS_PASSWORD, CRED_PBS_PASSWORD)
+ .map(|opt| opt.map(|s| s.trim_end_matches('\n').to_string()))
}
/// Gets an encryption password.
@@ -214,6 +215,7 @@ pub fn get_default_repository() -> Option<String> {
.inspect_err(|err| {
proxmox_log::error!("could not read default repository: {err:#}");
})
+ .map(|opt| opt.map(|s| s.trim_end().to_string()))
.unwrap_or_default()
}
@@ -232,6 +234,7 @@ pub fn get_fingerprint() -> Option<String> {
.inspect_err(|err| {
proxmox_log::error!("could not read fingerprint: {err:#}");
})
+ .map(|opt| opt.map(|s| s.trim_end().to_string()))
.unwrap_or_default()
}
--
2.47.3
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH backup v4 2/4] docs: client: document further password constrains
2026-07-06 8:02 [PATCH backup v4 0/4] fix #7054: client: remove trailing newlines from credentials Maximiliano Sandoval
2026-07-06 8:02 ` [PATCH backup v4 1/4] " Maximiliano Sandoval
@ 2026-07-06 8:02 ` Maximiliano Sandoval
2026-07-06 8:02 ` [PATCH backup v4 3/4] client: rename password to blob Maximiliano Sandoval
2026-07-06 8:02 ` [PATCH backup v4 4/4] client: Rename get_secret_impl method Maximiliano Sandoval
3 siblings, 0 replies; 5+ messages in thread
From: Maximiliano Sandoval @ 2026-07-06 8:02 UTC (permalink / raw)
To: pbs-devel
Even though newlines are control characters, we keep them explicitly for ease of
understanding.
Signed-off-by: Maximiliano Sandoval <m.sandoval@proxmox.com>
---
docs/backup-client.rst | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/docs/backup-client.rst b/docs/backup-client.rst
index e2a05d4fc..cd7488287 100644
--- a/docs/backup-client.rst
+++ b/docs/backup-client.rst
@@ -168,9 +168,10 @@ Environment Variables
wireguard, instead of using an HTTP proxy.
-.. Note:: Passwords must be valid UTF-8 and may not contain newlines. For your
- convenience, Proxmox Backup Server only uses the first line as password, so
- you can add arbitrary comments after the first newline.
+.. Note:: Passwords must be valid UTF-8 and may not contain newlines or any
+ control character. For your convenience, Proxmox Backup Server only uses the
+ first line as password, so you can add arbitrary comments after the first
+ newline.
System and Service Credentials
--
2.47.3
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH backup v4 3/4] client: rename password to blob
2026-07-06 8:02 [PATCH backup v4 0/4] fix #7054: client: remove trailing newlines from credentials Maximiliano Sandoval
2026-07-06 8:02 ` [PATCH backup v4 1/4] " Maximiliano Sandoval
2026-07-06 8:02 ` [PATCH backup v4 2/4] docs: client: document further password constrains Maximiliano Sandoval
@ 2026-07-06 8:02 ` Maximiliano Sandoval
2026-07-06 8:02 ` [PATCH backup v4 4/4] client: Rename get_secret_impl method Maximiliano Sandoval
3 siblings, 0 replies; 5+ messages in thread
From: Maximiliano Sandoval @ 2026-07-06 8:02 UTC (permalink / raw)
To: pbs-devel
This is a Vec<u8> and not yet the password in its unicode form.
Signed-off-by: Maximiliano Sandoval <m.sandoval@proxmox.com>
---
pbs-client/src/tools/mod.rs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pbs-client/src/tools/mod.rs b/pbs-client/src/tools/mod.rs
index ca64b239e..d99215c44 100644
--- a/pbs-client/src/tools/mod.rs
+++ b/pbs-client/src/tools/mod.rs
@@ -169,8 +169,8 @@ fn get_secret_from_env(base_name: &str) -> Result<Option<String>, Error> {
fn get_secret_impl(env_variable: &str, credential_name: &str) -> Result<Option<String>, Error> {
if let Some(password) = get_secret_from_env(env_variable)? {
Ok(Some(password))
- } else if let Some(password) = get_credential(credential_name)? {
- String::from_utf8(password)
+ } else if let Some(blob) = get_credential(credential_name)? {
+ String::from_utf8(blob)
.map(Option::Some)
.map_err(|_err| format_err!("credential {credential_name} is not utf8 encoded"))
} else {
--
2.47.3
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH backup v4 4/4] client: Rename get_secret_impl method
2026-07-06 8:02 [PATCH backup v4 0/4] fix #7054: client: remove trailing newlines from credentials Maximiliano Sandoval
` (2 preceding siblings ...)
2026-07-06 8:02 ` [PATCH backup v4 3/4] client: rename password to blob Maximiliano Sandoval
@ 2026-07-06 8:02 ` Maximiliano Sandoval
3 siblings, 0 replies; 5+ messages in thread
From: Maximiliano Sandoval @ 2026-07-06 8:02 UTC (permalink / raw)
To: pbs-devel
To get_secret_string to reflect this is a unicode string.
Signed-off-by: Maximiliano Sandoval <m.sandoval@proxmox.com>
---
pbs-client/src/tools/mod.rs | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/pbs-client/src/tools/mod.rs b/pbs-client/src/tools/mod.rs
index d99215c44..778c301c6 100644
--- a/pbs-client/src/tools/mod.rs
+++ b/pbs-client/src/tools/mod.rs
@@ -166,7 +166,7 @@ fn get_secret_from_env(base_name: &str) -> Result<Option<String>, Error> {
/// is UTF-8 encoded.
///
/// [credential]: https://systemd.io/CREDENTIALS/
-fn get_secret_impl(env_variable: &str, credential_name: &str) -> Result<Option<String>, Error> {
+fn get_secret_string(env_variable: &str, credential_name: &str) -> Result<Option<String>, Error> {
if let Some(password) = get_secret_from_env(env_variable)? {
Ok(Some(password))
} else if let Some(blob) = get_credential(credential_name)? {
@@ -188,7 +188,7 @@ fn get_secret_impl(env_variable: &str, credential_name: &str) -> Result<Option<S
///
/// [credential]: https://systemd.io/CREDENTIALS/
pub fn get_password() -> Result<Option<String>, Error> {
- get_secret_impl(ENV_VAR_PBS_PASSWORD, CRED_PBS_PASSWORD)
+ get_secret_string(ENV_VAR_PBS_PASSWORD, CRED_PBS_PASSWORD)
.map(|opt| opt.map(|s| s.trim_end_matches('\n').to_string()))
}
@@ -204,14 +204,14 @@ pub fn get_password() -> Result<Option<String>, Error> {
///
/// [credential]: https://systemd.io/CREDENTIALS/
pub fn get_encryption_password() -> Result<Option<String>, Error> {
- get_secret_impl(
+ get_secret_string(
ENV_VAR_PBS_ENCRYPTION_PASSWORD,
CRED_PBS_ENCRYPTION_PASSWORD,
)
}
pub fn get_default_repository() -> Option<String> {
- get_secret_impl(ENV_VAR_PBS_REPOSITORY, CRED_PBS_REPOSITORY)
+ get_secret_string(ENV_VAR_PBS_REPOSITORY, CRED_PBS_REPOSITORY)
.inspect_err(|err| {
proxmox_log::error!("could not read default repository: {err:#}");
})
@@ -230,7 +230,7 @@ pub fn get_default_repository() -> Option<String> {
///
/// [credential]: https://systemd.io/CREDENTIALS/
pub fn get_fingerprint() -> Option<String> {
- get_secret_impl(ENV_VAR_PBS_FINGERPRINT, CRED_PBS_FINGERPRINT)
+ get_secret_string(ENV_VAR_PBS_FINGERPRINT, CRED_PBS_FINGERPRINT)
.inspect_err(|err| {
proxmox_log::error!("could not read fingerprint: {err:#}");
})
--
2.47.3
^ permalink raw reply related [flat|nested] 5+ messages in thread