From 548355125e554b099f7181fa0627b9dfe9f3830c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stelmach?= Date: Thu, 20 Sep 2018 13:32:34 +0200 Subject: [PATCH] read a passphrase from a file descriptor Read a passpharase from a file descriptor specified in the BORG_PASSPHRASE_FD environment variable. --- docs/usage_general.rst.inc | 7 +++++++ src/borg/crypto/key.py | 15 ++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/docs/usage_general.rst.inc b/docs/usage_general.rst.inc index aaefb23c4..eff2dedda 100644 --- a/docs/usage_general.rst.inc +++ b/docs/usage_general.rst.inc @@ -174,6 +174,13 @@ General: passphrase should be initially set when initializing an encrypted repo. If BORG_PASSPHRASE is also set, it takes precedence. See also BORG_NEW_PASSPHRASE. + BORG_PASSPHRASE_FD + When set, specifies a file descriptor to read a passphrase + from. Programs starting borg may choose to open an anonymous pipe + and use it to pass a passphrase. This is safer than passing via + BORG_PASSPHRASE, because on some systems (e.g. Linux) environment + can be examined by other processes. + If BORG_PASSPHRASE or BORG_PASSCOMMAND are also set, they take precedence. BORG_NEW_PASSPHRASE When set, use the value to answer the passphrase question when a **new** passphrase is asked for. This variable is checked first. If it is not set, BORG_PASSPHRASE and BORG_PASSCOMMAND will also diff --git a/src/borg/crypto/key.py b/src/borg/crypto/key.py index 498eb142f..7bc87fbd1 100644 --- a/src/borg/crypto/key.py +++ b/src/borg/crypto/key.py @@ -36,7 +36,7 @@ class NoPassphraseFailure(Error): class PassphraseWrong(Error): - """passphrase supplied in BORG_PASSPHRASE or by BORG_PASSCOMMAND is incorrect.""" + """passphrase supplied in BORG_PASSPHRASE, by BORG_PASSCOMMAND or via BORG_PASSPHRASE_FD is incorrect.""" class PasscommandFailure(Error): @@ -429,6 +429,9 @@ class Passphrase(str): passphrase = cls.env_passcommand() if passphrase is not None: return passphrase + passphrase = cls.fd_passphrase() + if passphrase is not None: + return passphrase @classmethod def env_passcommand(cls, default=None): @@ -442,6 +445,16 @@ class Passphrase(str): raise PasscommandFailure(e) return cls(passphrase.rstrip('\n')) + @classmethod + def fd_passphrase(cls): + try: + fd = int(os.environ.get('BORG_PASSPHRASE_FD')) + except (ValueError, TypeError): + return None + with os.fdopen(fd, mode='r') as f: + passphrase = f.read() + return cls(passphrase.rstrip('\n')) + @classmethod def env_new_passphrase(cls, default=None): return cls._env_passphrase('BORG_NEW_PASSPHRASE', default)