#!/usr/bin/perl use strict; use warnings; use LATMOS::Accounts; use Getopt::Long; use Pod::Usage; use Term::ReadKey; use Crypt::RSA; =head1 NAME la-crypt-passwd - Tools to managed rsa crypted password in LATMOS Account system =head1 SYNOPSIS la-crypt-passwd [options] [--genkey|--regen] [--set BASE] =cut GetOptions( 'c|config=s' => \my $config, 'help' => sub { pod2usage(0) }, 'genkey' => \my $genkey, 'regen' => \my $regen, 'delkey' => \my $delkey, 'set=s' => \my $set, 'base=s' => \my $base, 'u|user=s' => \my @users, ) or pod2usage(); =head1 OPTIONS =over 4 =item -c|--config configdir Use this configuration directory instead of the default one. =item --genkey Generate a RSA key and store it into database If one is already present, use regen to force generation of a new one =item --regen Like --genkey but a new key will replace the current one if already present. Stored password will be read and encrypted again using the new key. =item --delkey Delete the current peer key and all encrypted password stored. =item --base base Work on this specific base instead default one =item --set BASE Read password from database, decrypt it and then set it in BASE given as argument. =item -u|--user USER Set password only for this user (can be set multiple times). =back =cut my $LA = LATMOS::Accounts->new($config, noacl => 1); my $labase = $LA->base($base); $labase && $labase->load or die "Cannot load base"; $labase->wexported(1); my $clear; sub get_clear_password { my @users_to_decode = @_; $clear and return $clear; my %encpasswd = $labase->get_rsa_password; scalar(keys %encpasswd) or return {}; ReadMode('noecho'); print "Enter password for current passphrase: "; my $password = ReadLine(0); ReadMode 0; print "\n"; my $private_key = $labase->private_key($password) or die "Cannot get private key\n"; my $rsa = new Crypt::RSA ES => 'PKCS1v15'; my %clear_passwd; if (!@users_to_decode) { @users_to_decode = sort keys %encpasswd; } printf "Trying to get current stored password (%d)\n", scalar(@users_to_decode); foreach (@users_to_decode) { my $clearp = $rsa->decrypt ( Cyphertext => $encpasswd{$_}, Key => $private_key, Armour => 1, ); if (defined $clearp) { $clear_passwd{$_} = $clearp; } else { die "Cannot get password for $_, crypt module said :" . $rsa->errstr() . "Was the password correct ?\n"; } } return \%clear_passwd; } if ($set) { if (!$labase->get_global_value('rsa_private_key')) { warn "No rsa key found in database\n"; } my $destbase = $LA->base($set) or die "Cannot get base $set\n"; my $clearpasswd = get_clear_password(@users); my @userstoset = @users ? @users : keys %$clearpasswd; foreach (@userstoset) { $clearpasswd->{$_} or next; my $obj = $destbase->get_object('user', $_) or do { warn "Cannot find user $_ in destination base, need sync ?\n"; next; }; $obj->set_password($clearpasswd->{$_}) and print "Password set for $_\n"; } $destbase->commit; } elsif ($regen || $genkey) { if ($labase->get_global_value('rsa_private_key') && !$regen) { die <generate_rsa_key($password); $labase->store_rsa_key($public, $private); foreach (keys %$clearpasswd) { my $obj = $labase->get_object('user', $_); $obj->setCryptPassword($clearpasswd->{$_}); } $labase->commit; } elsif ($delkey) { if (! $labase->get_global_value('rsa_public_key')) { die "There is no key in this base, not deleting nothing\n"; } my %encpasswd = $labase->get_rsa_password; print "Deleting password...\n"; foreach my $user (keys %encpasswd) { my $ouser = $labase->get_object('user', $user) or next; $ouser->set_c_fields('encryptedPassword' => undef) or die "Cannot delete encryptedPassword attribute for $user\n"; } $labase->set_global_value('rsa_public_key', undef); $labase->set_global_value('rsa_private_key', undef); $labase->commit; } else { if ($labase->get_global_value('rsa_private_key')) { my $clearpasswd = get_clear_password(); foreach (keys %$clearpasswd) { printf("%s: %s\n", $_, $clearpasswd->{$_}); } } else { warn "No rsa key found in database\n"; } }