#!/usr/bin/perl -w
#
# convert from linux passwd/shadow to master.passwd
#
use strict;
use Class::Date qw(:errors date now);
use Data::Dumper;


sub read_file {
    my ($f, $data, $fields) = @_;

    open(FH, '<', $f) || die "can't open $f";
    while (<FH>) {
	chomp;
	my @list = split(':');

	for (my $i = 0; $i < scalar(@$fields); $i++) {
	    $data->{$list[0]}->{$fields->[$i]} = $list[$i];
	}
    }
    close(FH);
}

sub write_file {
    my ($fh, $data, $fields) = @_;

    foreach my $key (keys(%$data)) {
	print $fh join(':', map { my $x = $data->{$key}->{$_}; die $_ unless(defined($x)); $x } @$fields), "\n";
    }
}

sub read_passwd {
    my ($f, $users) = @_;
    &read_file($f, $users, 
	    ['login', 'pw', 'uid', 'gid', 'gecos', 'home', 'shell']);
}

sub read_shadow {
    my ($f, $users) = @_;
    &read_file($f, $users, 
	    ['login', 'pw', 'last_changed', 'may_change', 'must_change', 'expire_warn', 'disable', 'disabled_since', 'reserved']);
}

sub write_bsd {
    my ($users) = @_;
    &write_file(\*STDOUT, $users, 
    	[ 'login', 'pw', 'uid', 'gid', 'class', 'change', 'expire', 'gecos', 'home', 'shell' ]);
}

sub days_to_epoch_seconds {
    my ($days) = @_;
    my $from = now;
    my $rel = new Class::Date::Rel { day => $days };
    my $r = $from+$rel;
    return $r->epoch;
}

sub conv_class {
    my ($u, $d) = @_;
    $d->{'class'} = '';
}

sub conv_change {
    my ($u, $d) = @_;
    my $f = $d->{'must_change'};

    if (defined($f) && $f > 0) {
    	$d->{'change'} = &days_to_epoch_seconds($f);
    } elsif ($f == '-1') {
    	$d->{'change'} = -1;
    } else {
    	$d->{'change'} = '';
    }
}

sub conv_expire {
    my ($u, $d) = @_;
    $d->{'expire'} = '';
}

sub conv_fields {
    my ($data) = @_;

    while (my ($user, $data) = each(%$data)) {
	&conv_class($user, $data);
	&conv_change($user, $data);
	&conv_expire($user, $data);
    }
}

sub usage {
	print STDERR "Usage: $0 <passwd> <shadow>\n";
	exit 1;
}

sub main {
    &usage() if (scalar(@ARGV) != 2);
    my %users;

    &read_passwd($ARGV[0], \%users);
    &read_shadow($ARGV[1], \%users);
    &conv_fields(\%users);
    &write_bsd(\%users);
}

&main;

# all done!
