#!/usr/bin/perl

use strict;
use warnings;
use LATMOS::Accounts;
use Getopt::Long;
use Pod::Usage;
use Term::ReadKey;

=head1 NAME

    la-passwd - set user password                                          
                                                                            
=head1 SYNOPSIS                                                            
                                                                             
    la-passwd [options] userid                                             

=head1 OPTIONS

=over 4

=item -c|--config configdir

Use this configuration directory instead of the default one.

=item -b|--base basename

Query this specific base instead of the default one.

=item -s|--sync syncname

Use this synchronisation

=item -t|--test

Don't change the password but check its validity using CrackLib.

=item -f|--force

Change the even it is weak (has no effect with --crypt)

=item --crypt

The given password is crypt using standard unix method and will be injected
as is inside the base. Works only for base supporting this, and some form of
password may not be updated.

=item --input FILENAME

Read login/password from a file in form

    username:password

or
    username:password:...

Everything after the second colon is ignored

If C<FILENAME> is C<->, standard input is used

=back

=cut

GetOptions(
    'c|config=s' => \my $config,
    'b|base=s'   => \my $base,
    't|test'     => \my $test,
    's|sync=s'   => \my $sync,
    'f|force'    => \my $force,
    'crypt'      => \my $crypt,
    'i|input=s'  => \my $input,
    'help'       => sub { pod2usage(0) },
) or pod2usage();

my $LA = LATMOS::Accounts->new($config, noacl => 1);
my $labase = $base ? $LA->base($base) : $LA->sync_access($sync);
$labase && $labase->load or die "Cannot load base";

$labase->wexported(1);

sub set_passwd {
    my ($obj, $password) = @_;
    my $res = $obj->check_password($password);

    if ($res !~ /^ok$/) {
        print "Password quality: " . $res . "\n";
        print "Cannot set bad password, use --force to bypass security\n" unless($force);
        return 0;
    }

    return 1  if($test);

    if ($obj->set_password($password)) {
        print "Password succefully changed\n";
        $labase->commit;
        return 1;
    } else {
        warn "Error when trying to change password\n";
        return 0;
    }
}

if (!$ARGV[0] && !$input) {warn "You must specify 'userid', aborting\n"; pod2usage(); }

my ($username, $password) = @ARGV;

my $otype = 'user';


if ($input) {
    my $handle;
    if ($input eq '-') {
        $input = \*STDIN;
    } else {
        open($handle, '<', $input) or die "Cannot open $input: $!\n";
    }

    while (<$handle>) {
        my ($username, $password) = split(/:/);
        $username or next;
        $password or next;

        my $obj = $labase->get_object($otype, $username) or do {
            warn "Object $otype $ARGV[0] not found\n";
            next;
        };

        print "Updating user $username\n";
        if ($crypt) {
            if ($obj->InjectCryptPasswd($password)) {
                $labase->commit;
            }
        } else {
            set_passwd($obj, $password);
        }
    }

} else {
    my $obj = $labase->get_object($otype, $username) or do {
        die "Object $otype $ARGV[0] not found\n";
    };

    unless($password) {
        ReadMode('noecho');
        print "Enter password: ";
        $password = ReadLine(0);
        ReadMode 0;
        print "\n";
        chomp($password);
    }

    if ($crypt) {
        if ($obj->InjectCryptPasswd($password)) {
            $labase->commit;
            exit(0);
        }
    } else {
        exit (!set_passwd($obj, $password));
    } 
};

