CUFP
Tanktalus
<p>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.)</p>
<p>The challenge? While no perl module for kwallet exists yet that I'm aware of, there is [mod://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:<c>
#!/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 "Can't get kwallet";
my $KWallet = $kwallet_service->get_object('/modules/kwalletd', 'org.kde.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_Userid_Key', $app_name);
my $p = $KWallet->readPassword($kwallet_handle, 'MyFolder','Some_Password_Key', $app_name);
say "User ID = ", dump($u);
say "Password = ", dump($p);
</c>
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 <c>QMap<QString,QString></c> 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.</p>
<p>(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.)</p>