i commented out the Kerberos part of this, but you got the basic idea. if you have a valid ticket you can connect to the server and the server can check you against its list of valid users. the server then sends the encrypted hash (with the __password and __cipher preset) back to the client to use as desired. the Kerberos parts are much uglier. i'll need to poke around them some more before posting.
package Keystore;
use strict;
use warnings;
use Tie::EncryptedHash;
use Term::ReadKey;
use Data::Dumper;
my $default_keyfile = "$ENV{HOME}/.Q/keystore";
my $default_secret = 'notverysecret';
my $default_cipher = 'Blowfish';
sub _get_secret {
my $prompt = shift;
my $secret;
print STDERR "$prompt: ";
ReadMode 'noecho';
$secret = ReadLine 0;
chomp $secret;
ReadMode 'normal';
print STDERR "\n";
return $secret;
}
sub pw {
my ($self,$password,$newval) = @_;
my $keystore = $self->{keystore};
return undef unless (defined($password) and length $password);
my $encpass = "_$password"; # Tie::Encrypted uses _ for the
+encrypted keys
if (exists($keystore->{$encpass})) {
return $keystore->{$encpass} || '';
} elsif (defined($newval) and length $newval) {
$keystore->{$encpass} = $newval;
return $keystore->{$encpass} || '';
} else {
$keystore->{$encpass} = _get_secret($password);
return $keystore->{$encpass} || '';
}
return undef;
}
sub new {
my ($c,%param) = @_;
=begin comment
# this was the Kerberos part, instead of reading from a file i
+t
# would connect to a Kerberos server (using your credentials).
# if all went well it would recieve the encrypted hash from th
+e
# server and would leave the keyfile 'undef' so it wouldn't be
# saved on DESTROY. if the server chat failed it failed to the
# file based method below.
my $kks = KKS::keystore;
if (ref $kks) {
my $self = { keystore => $kks, keyfile => undef };
return bless $self, $c;
}
=cut
$param{keyfile} ||= $default_keyfile;
if (-f $param{keyfile} && !-r _) { $param{secret} = $default_s
+ecret; }
$param{secret} ||= _get_secret('secret');
my (%s,%sold);
if (-f _ && -r _) {
open(F,"<$param{keyfile}") or warn "open\n";
my ($cfgstr,$passwords);
{local $/ = undef; $cfgstr = <F>; }
eval "$cfgstr"; # ewwww!! would not do this this
+way now...
%sold = (%$passwords);
}
tie %s, 'Tie::EncryptedHash';
%s = (%sold);
$s{__password} = $param{secret};
$s{__cipher} = $param{cipher} || $default_cipher;
my $self = { keystore => \%s, keyfile => $param{keyfile} };
return bless $self, $c;
}
sub DESTROY {
my ($s) = @_;
my ($k,$f) = ($s->{keystore}, $s->{keyfile});
{
local $^W = 0;
no warnings;
delete $k->{__password};
}
return unless defined $f;
open(F,">$f") or return;
print F Data::Dumper->Dump([$k],['passwords']);
close(F);
}
1;
=head1 NAME
Keystore - Perl extension for a password keystore.
=head1 SYNOPSIS
use Keystore;
$ks = new Keystore;
$passwd = $ks->pw('cisco_console');
$passwd2 = $ks->pw('cisco_enable');
# do something
query_rtr('rtr-foo',$passwd,$passwd2);
# clean up if you're paranoid
$passwd = $passwd2 = undef;
=head1 DESCRIPTION
Try it:
$ mkdir $HOME/.Q
# type the following on a single line so you can up-arrow and do it a
+gain.
$ perl -e 'use Keystore;$ks=new Keystore; \
for(qw( testpass anotherpass foopass)) { \
print $ks->pw($_),"\n";}'
# type a secret, it will be used to encrypt your passwords.
# since it doesn't know these passwords, it will ask.
secret:
testpass:
foo
anotherpass:
lala
foopass:
zig
# do it again, type the same secret as before.
# it knows them now, doesn't need to ask.
secret:
foo
lala
zig
$ cat $HOME/.Q/keystore
$passwords = {
'_testpass' => 'Blowfish rL0Y20zC+Fzt72VPzMSk2A 52616e646f6d4956fde
+2cd4cc69fb
4ab6888532e6b2aac86',
'_foopass' => 'Blowfish I4uNgfsODwP+rVYTtSNLdA 52616e646f6d49567073
+d91467ce68
e7d45d91ad73b75cc7',
'_anotherpass' => 'Blowfish LjgXKT/CddvudL1xzm6wVg 52616e646f6d4956
+2070a13f37
a38f8dcd55403f697a6661'
};
To delete a password, just delete the line. To completely disable the
+ encrypted
saving of passwords: chmod -rw $HOME/.Q/keystore If it can't read the
+ file
it will prompt for passwords when needed (but still only once per sess
+ion).
If it can't write the file they won't get saved.
=head2 EXPORT
None by default.
=head1 AUTHOR
=head1 SEE ALSO
L<Tie::EncryptedHash>.
=cut
|