#!/usr/bin/perl -w

###########################################################################
#
# Baracus build and boot management framework
#
# Copyright (C) 2010 Novell, Inc, 404 Wyman Street, Waltham, MA 02451, USA.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the Artistic License 2.0, as published
# by the Perl Foundation, or the GNU General Public License 2.0
# as published by the Free Software Foundation; your choice.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  Both the Artistic
# Licesnse and the GPL License referenced have clauses with more details.
#
# You should have received a copy of the licenses mentioned
# along with this program; if not, write to:
#
# FSF, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110, USA.
# The Perl Foundation, 6832 Mulderstraat, Grand Ledge, MI 48837, USA.
#
###########################################################################

use strict;
use warnings;

use Getopt::Long qw( :config pass_through );
use Pod::Usage;

use lib "/usr/share/baracus/perl";

use SqlFS;

use BaracusDB;
use BaracusCore qw( :subs  );
use BaracusConfig qw( :vars :subs );

use BaracusAuth qw( :vars :subs :const );

=pod

=head1 NAME

B<bauser> - Baracus "user" account management for access to barcus

=head1 SYNOPSIS

B<bauser> E<lt>commandE<gt> [options and arguments]

Where E<lt>commandE<gt> is

    add       <...>  Add a username and password for new user definition
    update    <...>  Modify definition of a username entry
    remove    <...>  Remove username and thereby deny user access to baracus
    list      <...>  List usernames
    detail    <...>  Show all information about a particular user

    help    This 'Usage' summary message.
    man     Detailed man page.

Use 'man' or 'help <command>' for more details.

=head1 DESCRIPTION

This tool is for baracus user management.

=head1 OPTIONS

=over 4

=item -v --verbose  Be verbose with output

=back

=cut

my $man      = 0;
my $help     = 0;

my $cmds =
{
 'add'      => \&add,
 'update'   => \&update,
 'remove'   => \&remove,
 'list'     => \&list,
 'detail'   => \&detail,

 'help'     => \&help,
 'man'      => \&man,
 };

my $opts =
{
 verbose    => 0,
 quiet      => 0,
# all        => 0,
# nolabels   => 0,
 debug      => 0,
 execname   => "",
 LASTERROR  => "",
 htpasswd   => "/usr/bin/htpasswd2 -n ",
 };

# Build command line for help, historical reference and point-in-time rebuilding
$opts->{execname} = $0;
$opts->{execname} = $1 if ( $0 =~ m|^.*/([^/].+)| );
my $cmdline = join '::', $opts->{execname}, @ARGV;

GetOptions(
           'verbose'   => \$opts->{verbose},
           'quiet'     => \$opts->{quiet},
#           'all'       => \$opts->{all},
#           'nolabels'  => \$opts->{nolabels},
           'debug+'    => \$opts->{debug},
           'man'       => \$man,
           'help|?'    => \$help,
           );

&man()  if $man;
&help( $opts, $cmds ) if $help;
&help( $opts, $cmds ) unless ( scalar @ARGV );
if ($ARGV[0] eq "man"  ) { &man(); }
if ($ARGV[0] eq "help" ) { shift @ARGV; &help( $opts, $cmds, @ARGV ); }

my $dbname = "baracus";
my $dbrole = $dbname;

print "setting uid to $dbrole\n" if ($opts->{debug} > 2);

my $uid = BaracusDB::su_user( $dbrole );
die BaracusDB::errstr unless ( defined $uid );

my $dbh = BaracusDB::connect_db( $dbname, $dbrole );
die BaracusDB::errstr unless( $dbh );

my $status = &main( $opts, $cmds, @ARGV );

die BaracusDB::errstr unless BaracusDB::disconnect_db( $dbh );

print $opts->{LASTERROR} if $status;

exit $status;

die "DOES NOT EXECUTE";


###############################################################################
##
## commands
##

=head1 COMMANDS

=head2 add <options and args>

Where <options and args> are

    --username <name>      Required unique id.
    --enable | --disable   Set user access status. [default enable]
    --password <passwd>    WARN: *clear text on command-line* [ default prompt ]
    --encryption <type>    md5, crypt, sha1, plaintext [ default sha1 ]

                     Note: generated line should be stored in a file in
                           users \$HOME and named .baracuspw
                           file owner should be set to user <name> and
                           perms to readonly for user/owner alone.

                           vi ~<name>/.baracuspw  # paste output
                           chown <name> ~<name>/.baracuspw
                           chmod 400 ~<name>/.baracuspw


=cut

sub add
{
    my $command = "add";

    my %entry =
        (
         'username'     => "",
         'password'     => "",
         'encryption'   => "sha1",
         'status'       => 1,
         'realm'        => "baracus_su",
         );

    @ARGV = @_;
    GetOptions
        (
         'username=s'     => \$entry{'username'},
         'password=s'     => \$entry{'password'},
         'encryption=s'   => \$entry{'encryption'},
         'enable!'        => \$entry{'status'},
         'disable'        => sub { $entry{'status'} = 0 },
         );

    if ( scalar @ARGV ) {
        $opts->{LASTERROR} = sprintf "\nUnknown arg(s): %s\n", join(" ", @ARGV);
        return 1;
    }

    &help( $opts, $cmds, $command ) unless ( $entry{username} );

    my $chkref;

    # check for pre-exsisting id
    $chkref = &get_db_user( $dbh, $entry{username} );
    if ( defined $chkref ) {
        $opts->{LASTERROR} = "user: $entry{username} already exists.\n";
        return 1;
    }

    if ( &check_encryption( $opts, $entry{encryption} ) ) {
        # lasterror already set
        return 1;
    } else {
        if ( $entry{encryption} eq "plaintext" ) {
            $opts->{LASTERROR} = "Storing passwords in plaintext is forbidden.\n";
            return 1;
        }
        $opts->{htpasswd} .= $encrypt2cmdopt{ $entry{encryption} };
        $entry{encryption} = $baAuth{ $entry{encryption} };
    }
    if ( $entry{password} ) {
        $opts->{htpasswd} .= " -b $entry{username} $entry{password}";
    } else {
        $opts->{htpasswd} .= " $entry{username}";
    }

    open (CMD, "$opts->{htpasswd}|") || die "unable to run $opts->{htpasswd}\n$?";
    my $cmdout = <CMD>; chomp $cmdout;
    close CMD;

    my ($cmduser, $cmdhash) = split(':', $cmdout, 2);
    print "result $cmdout - user $cmduser hash $cmdhash\n";
    exit 0;

    # done with all checking

    &add_db_user( $dbh, \%entry );

    if ( $opts->{verbose} )
    {
        printf "user: $entry{username} added\n";
    }

    return 0;
}


=head2 remove 

=cut

sub remove
{
    my $command = "remove";
}

=head2 list


=cut

sub list
{
    my $command = "list";
}

=head2 detail

Show details for specified network storage device

=cut

sub detail
{
    my $command = "detail";
}

sub check_encryption
{
    my $opts    = shift;
    my $encrypt = shift;

    my $encrypts = join ', ', @baAuths;
    unless ( defined $baAuth{ $encrypt } ) {
        $opts->{LASTERROR} = "Invalid <type> '$encrypt'\nPlease use: $encrypts\n";
        return 1;
    }
    return 0;
}


die "ABSOLUTELY DOES NOT EXECUTE";

__END__
