After trying to figure out how my lowly little perl application could request a Very Important Password from coworkers in a secure manner befitting the importance of said password, a few monks on the CB suggested using a file (mode u=r,go= - aka 0400) or prompting. Obviously insecure methods such as command line parameters and environment variables were not suggested. Then someone suggested encrypting the file and only asking for the password to decrypt it - which is better in the sense that it makes it much less tempting to "accidentally" see a coworker's password on a shared box (since we often have root access for development purposes, nevermind the IT folks who actually administer some of these machines), but worse in that every time the command is run and we need the password we'll need to ask for the encryption password, negating much of the advantage of the file. Then I realised that KDE already has such a beast built in, with further advantages of already being a daemon so that I only need to type in the password once for my entire session no matter how many times I run this app: kwallet. (I know gnome has a similar keyring beast, but I don't run gnome.)

The challenge? While no perl module for kwallet exists yet that I'm aware of, there is Net::DBus. However, the kwallet DBus API is, again as far as I can tell, completely undocumented. So, in case you want to do something similar, here's the basics of what I came up with:

#!/usr/bin/perl use v5.12; use strict; use warnings; use Data::Dump qw(dump); use Net::DBus qw(:typing); my $app_name = "password-extract-in-perl"; my $bus = Net::DBus->find() or die "Can't find DBus"; my $kwallet_service = $bus->get_service('org.kde.kwalletd') or die "Ca +n't get kwallet"; my $KWallet = $kwallet_service->get_object('/modules/kwalletd', 'org.k +de.KWallet') or die "Can't find networkWallet"; my $networkWallet = $KWallet->networkWallet(); say "Network Wallet = $networkWallet"; my $kwallet_handle = $KWallet->open($networkWallet, 0, $app_name); say "Opened = $kwallet_handle"; my $folders = $KWallet->folderList($kwallet_handle,$app_name); say "Folders = ", dump($folders); my $u = $KWallet->readPassword($kwallet_handle, 'MyFolder','Some_Useri +d_Key', $app_name); my $p = $KWallet->readPassword($kwallet_handle, 'MyFolder','Some_Passw +ord_Key', $app_name); say "User ID = ", dump($u); say "Password = ", dump($p);
The last challenge that I had to overcome was that the last parameter to all the $KWallet functions was still $app_name. The only limitation I still am aware of with this is that if you wanted to put the user/password in a map instead of individual password fields, which would make more sense, the data comes back as a "QByteArray" which is the binary representation of a QMap<QString,QString> data type. Extracting this out in Perl will be very fun short of using xs code. Thus my fallback of using a Password field as a user ID. Maybe later I'll look into writing a KDE::KWallet module to encapsulate this, and then learning enough xs to convert between the QMap and Perl hashes.

(I hope this all works with perl 5.8.8 ... since that's what most of my coworkers will have... obviously I'll switch back from say to print, it's Net::DBus which hopefully works there.)

Replies are listed 'Best First'.
Re: Extracting passwords from KWallet
by walto (Pilgrim) on Jan 22, 2011 at 07:31 UTC

    I am using kubuntu 10.10 which uses perl5 (revision 5 version 10 subversion 1). To run the script I had to add

    use feature qw(say);

    to run it using say instead of print.

    I am not sure when say was implemented in perl. To run it on perl versions lower than 5.10. I would recommend to replace say with print.

    Running your script gives me an empty string for User ID and Password when I replace MyFolder with 'Network Management' and User ID and Password with my credentials.

      Actually, we could really change the "use 5.12" to "use 5.10" - I was merely using that line to show everyone what version I was using to develop/test this. Since I also now have the Net::DBUS code working under 5.8.8, then, other than the 'say' lines, this definitely works in earlier-than-5.12 versions of perl.

      Be sure when you're using this that you're looking for Passwords and not Maps. As mentioned originally, this does not work with "Maps" in kwallet (though I've opened a bug against KWallet for their unfortunate maps-to-wire format). That is a definite deficiency, and an Excersise For The Reader(TM).

      Note that in the original script, the userid/password strings are key names, not credentials. The whole point is to fetch credentials, not know them. So, what keys in your "Network Management" folder in KWallet exist under the "Passwords" group? When you open up the folder in KWallet, this should show up:

      [ ] Network Management | +-- Binary Data +-- Maps V-- Passwords | +-- key +-- Unknown
      You have to use "key", not "walto" or "12345" (which, of course, is the password to my luggage).