#!/usr/bin/perl
#
# Migrate the relevant parts of the Debian Edu LDAP database from
# Squeeze to Wheezy.
#
# Extract users and groups from the slapcad output to insert with
# slapadd.  It must be run just after installation of the main server.

sub usage {
    my $exitcode = shift;
    print <<'EOF';
Usage: $0

Migrate LDAP information from a Debian Edu Squeeze main server to a
Wheezy main server.

How to use it:

  # Get a copy of the Squeeze LDAP database
  ssh root@squeeze-tjener "service slapd stop"
  ssh root@squeeze-tjener "slapcat" > squeeze-tjener.ldif
  ssh root@squeeze-tjener "service slapd start"

  # Get a copy of the current Wheezy LDAP database
  service slapd stop
  slapcat > wheezy-tjener.dif

  ldap-migrate-squeeze-wheezy       # Merge the two databases
  slapadd < newtjener-slapadd.ldif  # Load the new/changed entries into LDAP
  service slapd start               # Restart local LDAP server

  # Copy home directories from old to new main-server
  rsync -av root@squeeze-tjener:/skole/tjener/home0/. /skole/tjener/home0/.

WARNING: This code is experimental!
EOF
    exit($exitcore) if $exitcode;
}

use strict;
use warnings;

use Getopt::Std;
use Net::LDAP::LDIF;
use Data::Dumper;

my $debug = 0;
my %opts;
getopts("d", \%opts) || usage(1);
$debug = 1 if $opts{d};

my $oldldiffile = "squeeze-tjener.ldif";
my $curldiffile = "wheezy-tjener.ldif";
my $newldiffile = "newtjener-slapadd.ldif";

my $oldldif = Net::LDAP::LDIF->new( $oldldiffile, "r", onerror => 'undef' );
my $curldif = Net::LDAP::LDIF->new( $curldiffile, "r", onerror => 'undef' );
my $newldif = Net::LDAP::LDIF->new( $newldiffile, "w", onerror => 'undef',
                                    change => 1 );

my %curuser;
my %curgroup;
while (not $curldif->eof() ) {
    my $entry = $curldif->read_entry ( );
    if ( ! $curldif->error() ) {
        my %cls;
        map { $cls{$_} = 1 } $entry->get_value('objectClass');
        if ( exists $cls{'posixAccount'} && exists $cls{'person'}
             && ! exists $cls{'gosaUserTemplate'}) {
            $curuser{$entry->get_value('uid')} = 1;
        } elsif (exists $cls{'posixGroup'} ) {
            $curgroup{$entry->get_value('cn')} = $entry;
        }
    }
}
print Dumper(\%curuser);
#print Dumper(\%curgroup);

# Extract every user and group LDAP object not already in the LDAP
# database.
while (not $oldldif->eof ( ) ) {
    my $entry = $oldldif->read_entry ( );
    if ( $oldldif->error ( ) ) {
        print "Error msg: ", $oldldif->error ( ), "\n";
        print "Error lines:\n", $oldldif->error_lines ( ), "\n";
    } else {
        #foreach my $attr ( $entry->attribute ) {
        #}
        my %cls;
        map { $cls{$_} = 1 } $entry->get_value('objectClass');
        if (exists $cls{'posixAccount'} && exists $cls{'person'}
            && ! exists $cls{'gosaUserTemplate'}) {
            my $uid = $entry->get_value('uid');
            if (!exists ($curuser{$uid})) {
                $newldif->write_entry($entry);
            }
        } elsif (exists $cls{'posixGroup'} ) {
            my $cn = $entry->get_value('cn');
            if (exists ($curgroup{$cn})) {
                # check membership of both, figure out how to create
                # change records.
                print "G: $cn\n";
                my $curentry = $curgroup{$cn};
                my @oldmembers = sort $entry->get_value('memberUid');
                my @curmembers = sort $curentry->get_value('memberUid');
                print "Cur: ", Dumper(\@curmembers), "\n";
                print "Old: ", Dumper(\@oldmembers), "\n";
                my %curmemhash;
                map { $curmemhash{$_} = 1 } @curmembers;
                my $newentry;
                my @newmembers;
                for my $oldmember (@oldmembers) {
                    if (!exists $curmemhash{$oldmember}) {
                        print "Adding $oldmember to group $cn\n";
                        if (! defined $newentry) {
                            $newentry = $entry->clone();
                            $newentry->changetype('modify');
                        }
                        push(@newmembers, $oldmember);
                    }
                }
                if (@newmembers) {
                    $newentry->replace('memberUid' =>
                                       [@curmembers, @newmembers]);
                    $newldif->write_entry($newentry);
                }
            } else {
                # Missing entry, just add it
                $newldif->write_entry($entry);
            }
        }
#            print Dumper($entry);
    }
}

$newldif->done();
$curldif->done();
$oldldif->done();
