#!/usr/bin/perl

use strict;

use EBox;
use EBox::Global;
use EBox::SambaLdapUser;
use EBox::Ldap;
use Error qw(:try);
use EBox::Sudo qw( :all );
use Crypt::SmbHash qw(nthash ntlmgen);


use constant DEFAULTDOMAINNAME => 'EBOX';
use constant TMP_ROOT	=> 'ebox-samba-admin';
use constant TMP_UNIX_ID_POOL => 'tmpIdPool';

# LDAP Domain stuff
use constant DomainGroups => 
		( 
			{ 
				name => 'Domain Admins',
				gid  => 512,
				gtype => 2,
			},
			{
				name => 'Domain Users',
				gid => 513,
				gtype => 2,
			},
			{
				name => 'Domain Guests',
				gid  => 514,
				gtype => 2,
			},
			{
				name => 'Domain Computers',
				gid => 544,
				gtype => 2,
			},
			{
				name => 'Administrators',
				gid => 544,
				gtype => 5,
				sid => 'S-1-5-32-544',
			},
			{
				name => 'Account Operators',
				gid => 548,
				gtype => 5,
				sid => 'S-1-5-32-548'
			},
			{
				name => 'Print Operators',
				gid => 550,
				gtype => 5,
				sid => 'S-1-5-32-550'
			}, 
			{
				name => 'Backup Operators',
				gid => 551,
				gtype => 5,
				sid => 'S-1-5-32-551'

			},
			{
				name => 'Replicators',
				gid => 552,
				gtype => 5,
				sid => 'S-1-5-32-552'

			}
		);
	


EBox::init();

my $global = EBox::Global->getInstance();
my $users  = $global->modInstance('users');


sub populateLdap
{
        my $ldap = EBox::Ldap->instance();
	my $sambaLdap = new EBox::SambaLdapUser;

	my $sid = $sambaLdap->alwaysGetSID();
	defined $sid or die 'Cannot get domain SID';

	# Mandatory groups
	foreach my $group (DomainGroups) {
		my ($name, $gid, $gtype) = ($group->{'name'}, 
					    $group->{'gid'}, $group->{'gtype'});
		my %attrs = ( 
				base => 'ou=Groups,dc=ebox',
				filter => "&(objectclass=*)(cn=$name)",
				scope => 'one'
			    );
		next if ($ldap->search(\%attrs)->count() > 0);

		my $gsid;
		if ($group->{'sid'}) {
			$gsid = $group->{'sid'};
		} else {
			$gsid = "$sid-$gid";
		}

		my %args = (
			    attr => [
				      'cn'		=> $name,
				      'gidNumber'	=> $gid,
				      'sambaSID'	=> $gsid, 
				      'sambaGroupType'  => $gtype,
				      'displayName'	=> $name, 
				      'objectclass'	=> ['posixGroup',
				      			   'sambaGroupMapping', 
							   'eboxGroup']
				    ]
			    );

		my $dn = "cn=$name,ou=Groups,dc=ebox";
		$ldap->add($dn, \%args);

	}
	
	# Computers
        my %args = (base => "dc=ebox", filter => "&(ou=Computers)", 
			scope => 'one');
	unless ($ldap->search(\%args)->pop_entry()) {
		%args = (
		    attr => [
			      'ou'		=> 'Computers',
			      'objectclass'	=> ['organizationalUnit']
			    ]
		        );

		my $dn = "ou=Computers,dc=ebox";
		$ldap->add($dn, \%args);
	}

	# Idmap 
	%args = (base => "dc=ebox", filter => "&(ou=Idmap)", 
			scope => 'one');

	unless ($ldap->search(\%args)->pop_entry()) {
		%args = (
		    attr => [
			      'ou'		=> 'Idmap',
			      'objectclass'	=> ['organizationalUnit']
			    ]
		    );

		my $dn = "ou=Idmap,dc=ebox";
		$ldap->add($dn, \%args);
	}

}

sub _addPDCStuff 
{
	# add unixIdPool attributes to newly created domains
	_addSambaUnixIdPool();
}


sub _addSambaUnixIdPool
{
	my $users = EBox::Global->modInstance('users');	
	my $lastUid = $users->lastUid;
	my $lastGid = $users->lastGid;

	my $ldap = EBox::Ldap->instance();
	my %searchParams = (
				base => $ldap->dn,
				filter => "objectClass=sambaDomain",
				scope => "sub"
		    );


	my @sambaDomains = $ldap->search(\%searchParams)->entries();
	foreach my $entry (@sambaDomains) {
	  my $dn = $entry->dn;	

	  if (not $ldap->isObjectClass($dn, 'sambaUnixIdPool')) {
	    $ldap->modify($dn, 
			  { add => {  
				    objectClass => 'sambaUnixIdPool',
				    uidNumber => $lastUid + 1,
				    gidNumber => $lastGid + 1,
				   }
			  }
			  
			 );
	  }

	}
}


sub clean 
{
	my $smb  = new EBox::SambaLdapUser;
	my $ldap = EBox::Ldap->instance();

	
	# clean users
	foreach my $user ($users->users){
		my $username = $user->{'username'};
		my $dn = "uid=$username," .  $users->usersDn;
		$ldap->delObjectclass($dn, 'sambaSamAccount');
		
	}

	# clean groups
	foreach my $group ($users->groups){
		my $groupname = $group->{'account'};
		my $dn = "cn=$groupname," .  $users->groupsDn;
		$ldap->delObjectclass($dn, 'eboxGroup');
		$ldap->delObjectclass($dn, 'sambaGroupMapping');
	}
	
	# remove groups
	foreach my $group (DomainGroups) {
		my $name = $group->{'name'}; 
		my $dn = "cn=$name,ou=Groups,dc=ebox";
		my %attrs = (
				base => 'ou=Groups,dc=ebox',
				filter => "&(objectclass=*)(cn=$name)",
				scope => 'one'
			    );
		next unless ($ldap->search(\%attrs)->count() > 0);
		$ldap->delete($dn);
	}

	# Idmap 
	my %args = (base => "dc=ebox", filter => "&(ou=Idmap)", 
			scope => 'one');

	if ($ldap->search(\%args)->pop_entry()) {
		$ldap->delete ('ou=Idmap,dc=ebox');
	}


	# SambaDomainName
	%args = (
                        base => "dc=ebox",
                        filter => "(sambaDomainName=*)",
			attrs => ['sambaDomainName'],
                        scope => "sub"
                    );
	
	foreach my $entry ($ldap->search(\%args)->entries()) {
		my $dn = 'sambaDomainName=' . 
			$entry->get_value('sambaDomainName') . ',dc=ebox';
		$ldap->delete($dn);
	}

	# Computers
	%args = (base => "dc=ebox", filter => "&(ou=Computers)", 
			scope => 'sub');
	if ($ldap->search(\%args)->pop_entry()) {
		%args = (
			base => "ou=Computers,dc=ebox",
			filter => 'objectclass=*',
			scope => "one",
			attrs => ['cn']
			
		    );
		
		for my $entry ($ldap->search(\%args)->entries()) {
			my $cn = $entry->get_value('cn');
			$ldap->delete("uid=$cn,ou=Computers,dc=ebox");
		}
	}
	
}

sub updateUsers
{
	my $smb  = new EBox::SambaLdapUser;
	$smb->migrateUsers();
}

sub gen_config
{
	my $samba = EBox::Global->modInstance('samba');
	$samba->_regenConfig;
}


sub fixSIDs
{
	my $samba = EBox::Global->modInstance('samba');
	$samba->fixSIDs();
}

sub usage
{
	print "Usage: $0 populate-ldap update-users | update-pdc | clean | genconfig | fix-sids\n";
	exit 1;
}

#main 

unless ($#ARGV == 0) {
	usage();
}

if ($ARGV[0] eq 'populate-ldap') {
	populateLdap();
}
elsif ($ARGV[0] eq 'update-users') {
	updateUsers();
} elsif ($ARGV[0] eq 'update-pdc') {
	_addPDCStuff();
} elsif ($ARGV[0] eq 'fix-sids') {
	fixSIDs();
} elsif ($ARGV[0] eq 'genconfig') {
	gen_config();
} elsif ($ARGV[0] eq 'clean') {
	clean();
} else {
	usage();
}
