#!/usr/bin/perl

# $Id: smbldap-migrate-groups,v 1.5 2005/01/08 12:04:45 jtournier Exp $
#
#  This code was developped by IDEALX (http://IDEALX.org/) and
#  contributors (their names can be found in the CONTRIBUTORS file).
#
#                 Copyright (C) 2002 IDEALX
#
#  This program is free software; you can redistribute it and/or
#  modify it under the terms of the GNU General Public License
#  as published by the Free Software Foundation; either version 2
#  of the License, or (at your option) any later version.
#
#  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.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
#  USA.

# Purpose of smbldap-migrate-groups : to parse a Windows
# group dump and populate Unix groups
# Reads group dump on stdin


use strict;
use FindBin;
use FindBin qw($RealBin);
use lib "$RealBin/";
use smbldap_tools;
use Getopt::Std;

sub process_rec_group
  {
    my ($group, $mb) = @_;
    my @members;
    
    if (!(@members = group_get_members($group))) {
      return 0;
    }

    foreach my $m (@members) {
      if ( !($m =~ m/^\*/) ) {
	push @{$mb}, $m;
      } else {
	my $gname = $m;
	$gname =~ s/^.//;
	if (!process_rec_group($gname, $mb)) {
	  print "recursive group not added : $gname\n";
	}
      }
    }
  }


# given a group dn and a list of members, update the group
sub modify_group
  {
    my ($group, $dn_line, @members, $recgroup) = @_;
    my $m;
    my @new_mb;

    foreach $m (@members) {
      if ( ($m =~ m/^\*/) ) {
	my $gname = $m;
	$gname =~ s/^.//;
	if (!$recgroup) {
	  print "recursive group not added : $gname\n";
	} else {
	  if (!process_rec_group($gname, \@new_mb)) {
	    print "recursive group not added : $gname\n";
	  }
	}
      } else {
	push @new_mb, $m;
      }
    }

    # new_mb contains flat members from group dump
    # now append them to existing members
    push @new_mb, group_get_members($group);
    # uniq them
    my %saw;
    @saw{@new_mb} = ();
    @new_mb = keys %saw;

    my $nmb = $#new_mb + 1;
    print STDERR "Group $group now has $nmb member(s)\n"; 
    
    my $mbs;
    foreach $m (@new_mb) {
      $mbs .= "memberUid: $m\n";
    }

    my $mods="$dn_line
changetype: modify
replace: memberUid
$mbs
";

    #print "$mods\n";
    my $tmpldif =
      "$mods
";

    die "$0: error while modifying group $group\n"
      unless (do_ldapmodify($tmpldif) == 0);
    undef $tmpldif;
  }

sub display_group
  {
    my ($group, @members) = @_;

    print "Group name $group\n";
    print "Members\n";
    my $m;
    my $i = 0;
    foreach $m (@members) {
      print "$m ";
      if ($i % 5 == 0) {
	print "\n";
      }
      $i++;
    }
  }

sub process_group
  {
    my ($group, @members, $nocreate, $noupdate, $recgroup) = @_;

    my $dn_line;
    if (!defined($dn_line = get_group_dn($group))) {
      # group not found, create it ?
      if (!$nocreate) {
	system "/usr/local/sbin/smbldap-groupadd \"$group\"; sleep 5";
	if (!defined($dn_line = get_group_dn($group))) {
	  return 1;
	}
	modify_group($group, $dn_line, @members, $recgroup);
      } else {
	# don't create
	print "not created:\n";
	display_group($group, @members);
      }
    } else {
      # group found, update it ?
      if (!$noupdate) {
	modify_group($group, $dn_line, @members, $recgroup);
      } else {
	# don't update
	print "not updated:\n";
	display_group($group, @members);    
      }
    }
  }

###################################################

my %Options;

my $ok = getopts('CUr?', \%Options);
if ( (!$ok) || ($Options{'?'}) ) {
  print "Usage: $0 [-CUr?] < group_dump\n";
  print "  -C	    don't create group if it doesn't exist\n";
  print "  -U	    don't update group if it exists\n";
  print "  -r	    recursively process groups\n";
  exit(1);
}

my $group_name;
my $group_desc;
my $has_members = 0;
my @members = ();

while (<>) {
  my $line = $_;
  chomp($line);
  next if ( $line =~ m/^\s*$/ );

  if ($group_name eq "") {
    if ( $line =~ m/^Group name\s+(.+).$/ ) {
      $group_name = $1;
      next;
    }
  }
  if ($group_desc eq "") {
    if ( $line =~ m/^Comment\s+(.*)$/ ) {
      $group_desc = $1;
      next;
    }
  }
  next if ( $line =~ m/^-+.$/ );
  if (!$has_members) {
    if ( $line =~ m/^Members/ ) {
      $has_members = 1;
      next;
    }
  } else {
    if ( $line =~ m/^The command completed successfully/ ) {
      last;
    } else {
      push(@members, split(/\s+/, $line));
      next;
    }
  }

  #print;
}

if ( $#members > -1) {
  process_group($group_name, @members, $Options{'C'}, $Options{'U'}, $Options{'r'});
}

#print "gn=$group_name\n";
#print "gd=$group_desc\n";
#my $m;
#foreach $m (@members)
#{
#    print "$m ";
#}
#print "\n";
