I want to use secret-tool and gnome-keyring-daemon from a shell session, to store and retrieve passwords. The shell session might be gnome-terminal under the X console, or independently of whether or not I also have an X login, it might be an ssh session or text login.
I do not want gnome-keyring-daemon prompting to unlock a keyring on some remote X session, I do not want it to prompt unlocking of a keyring at all.
If there is an unlocked keyring (e.g. an X console session) then I want to use that keyring session, but if not, then I don't want to unlock an existing keyring as that could interfere with the available credentials of that X session, instead I want to run a private instance of gnome-keyring-daemon just long enough to get the secret, without interfering with any existing clients of any existing gnome-keyring-daemon (e.g. seahorse, chrome, evolution, ssh-agent -- I don't want suddenly asking for ssh keys because something called gnome-keyring-daemon --replace).
And I want to do it from the command line with without perl and python tools.
Many solutions make use of gnome-keyring-daemon --unlock --replace
which isn't an option as it destroys the relationship of existing clients.
The solution has multiple steps:
Is a keyring already available?
There are various solutions proposed to query whether or not an unlocked keyring is available. Some of this will start gnome-keyring-daemon if it is not running.
The method I settled on is:
There are 4 results:
I process it like this:
If the function returns 3 then there is nothing to be done, if it returns 0 then it is usable, otherwise a private gnome-keyring-daemon is required.
Launching a private keyring
Most of what I've read in all the various answers about launching gnome-keyring-daemon, damage the relationship with existing clients, causing them to fail. Evolution can't connect any more until it is fully restarted (and that takes a bit of doing), seahorse can't change any secrets (although it has cached what it has), ssh-agent doesn't have the passphrase for your keys any more and asks you...
If we want a private unlocked gnome-keyring-daemon we have to use either
--login
or--unlock
and feed the password on stdin, but many people also suggest--replace
which is misleading because without other precautions that aren't mentioned, it closes the existing daemon and ruins all the client sessions.We need to run our private unlocked gnome-keyring-daemon in a private dbus session to avoid other interferences that will happen even if we don't use
--replace
You'd think that
dbus-run-session
orbus-launch --exit-with-session
would work, but you'd be wrong, they fight over the contents of XDG_RUNTIME_DIR where all the control sockets are kept, and whether or not this matters partly depends on whether you've ssh'd in or not and whether or not the keyring is locked.Extensive experiments lead me to conclude that dbus-run-session is ideal provided that XDG_RUNTIME_DIR is also private.
Getting a password using a private gome-keyring-daemon might work something like this:
but it's not enough. You need to
mkdir
andchmod
the temporaryXDG_RUNTIME_DIR
(and cleanup). You also need a lot of flow control so that you can separate your stderr of the different processes.Also you don't want to be doing:
echo -n "$keyring_password"
because in bashset -x
mode you will leak the password to stderr (or${BASH_XTRACEFD}
).I use something like this:
What I'm trying to do here is preserve the original stdin, stdout, stderr of the calling context to the passed command and args in
$@
, while still feeding the password on stdin, and ensuring that stderr of dbus-run-session and stdout of anything in there not taint the process stdout.The missing pieces
You can call
get-secret
andput-secret
with the typical arguments thatsecret-tool
hasexamples
If you run these in a terminal as part of the X console login, they will generally work without a password. If you lock the keyring with seahorse then you will need to provide the password. Or, if you just ssh into a machine that doesn't have a keyring running you will need to provide a password.
When running the tests, check the existence of gnome-keyring-daemon processes before and after. Typically any that were running before should continue undisturbed.
Sometimes when running the tests, if you are on the X console and you locked your keyring with seahorse, you will be spontaneously prompted to unlock it for the benefit of existing keyring clients which are nothing to do with what you are testing here
Tips on passwords in the shell
You don't really want to store passwords in the shell because you'll leak them by having them on as command line parameters of externally invoked processes, accidentally have the in environment variables which will leak to external processes and will be visible if
set -x
is active (and for protection against that, use things liketest ${#password} = 0
instead oftest -z "${password}"
and instead ofecho "$password" |
have<<<"$password"
and instead ofecho -n "$password" |
havetr -d '\n' <<<"$password |
You probably would rather use
dialog
to pipe the password straight into keyring manager:The full script
To make it easy to cut-n-paste the full script is here.