This is a simple Python 3 script that reads, from stdin
, the first line of
input as a passphrase that is then passed to gpg-connect-agent
to unlock one
or more keys. By design, gpg-connect-agent
will start gpg-agent
if
necessary. This script is intended primarily to be called from the
pam_exec.so
module, but may be used from a shell. Any trailing carriage
return or newline is stripped from the password.
gpg_unlock [KEYLIST ...]
Read the given KEYLIST
files for lists of GPG keygrips and, if at least one
keygrip is found, read a passphrase from stdin. If and only if no KEYLIST
files are specified, $HOME/.gnupg/autounlock
will be checked by default.
KEYLIST
files may be commented; comments begin with a #
(either at the
start of the line or after some whitespace) and continue to the end of the line
on which they appear. Lines that are empty or consist of all whitespace after
comments are removed will be ignored. Any files that cannot be read will cause
an error message to be emitted to stderr
, but processing of other files will
continue.
For the purposes of unlocking, a keygrip is any whole word in a KEYLIST
file.
More than one keygrip may be specified per file, with one or more per line.
Valid keygrips may be identified by running
gpg2 --list-secret-keys --with-keygrip
(For some distributions, gpg
may be needed in place of gpg2
.)
No attempt is made to validate keygrips before gpg-connect-agent
is invoked
to unlock keys; gpg-agent
should simply refuse to accept invalid keys.
gpg_unlock
may be invoked from PAM by adding
auth optional pam_exec.so expose_authtok /path/to/gpg_unlock
in the relevant PAM service files. The line must appear AFTER the module
responsible for authenticating users (commonly pam_unix.so
) for the
authentication token to be passed on stdin
via the expose_authtok
mechanism. On Void Linux, adding the line to /etc/pam.d/system-local-login
after the line
auth include system-login
will perform the unlock only on local console logins.
To use gpg_unlock
outside of PAM, invoke
stty -echo && gpg_unlock
from a shell and enter a passphrase, followed by <Enter>
.
gpg_unlock
will forward any stdout
or stderr
output from
gpg-connect-agent
to its own stdout
and stderr
, respectively.
gpg_unlock
also prints some error conditions (not all of which are fatal) to
stderr
. Generally, gpg-connect-agent
writes command responses to stdout
;
the pam_exec
module will ignore stdout
by default. There is currently no
way to suppress or reconfigure output in gpg_unlock
except to edit the
script.
When invoked from a PAM module, gpg_unlock
may be run as the superuser rather
than as the user being authenticated. When gpg_unlock
finds a value in
PAM_USER
(which is set by pam_exec.so
to the user being authenticated), it
will immediately attempt to adopt the UID and primary GID of $PAM_USER
and
relinquish any other group privileges. If these attemps fail, gpg_unlock
will
exit with a unit return code before attempting further action.
As a special case, if $PAM_USER
has the same value as os.getuid()
prior to
dropping privileges, gpg_unlock
will not attempt to alter group privileges.