#!/usr/bin/perl -I. -I.. -I/opt/novell/xad/lib64/perl -I/opt/novell/xad/lib/perl
#################################################################################
## Domain Services for Windows Server Deletion Tool
##
## See the file LICENSE for redistribution information.
##
## Copyright (c) 2010-2012
##   Novell, Inc.  All rights reserved.
#################################################################################
#
#
use strict;
use warnings;
use Getopt::Std;
use helpers::remoteStatus;
use helpers::utility;
use helpers::containerCheck;
use helpers::ndsServerHealthCheck;
use XAD::registry;
use helpers::utility;
use Term::ReadKey;
use File::Temp;
use File::Copy;
use Logger qw(:DEFAULT);

#Global variables
my ($partial, $frd, $nm_frd, $adc, $nm_adc, $child, $nm_child, $debug_info, $forest_name, $provisoned);
my ($dcadminname, $dcadminpasswd,$adminnamends, $dcfullname, $ridmanagerfullname);
my ($object_removal_passed, $all_objects_removal_passed, $ndsconfig_passed);
my ($configurationldapname, $defaultcontainer, $configurationndsname, $schemandsname, $schemaldapname, $treename, $servername, $serverobjlocation);
my @got_status=();

#Global files, commands and constants
my $LDAPSEARCH="/opt/novell/eDirectory/bin/ldapsearch";
my $LDAPMODIFY="/opt/novell/eDirectory/bin/ldapmodify";
my $LDAPDELETE="/opt/novell/eDirectory/bin/ldapdelete";
my $LDAPCONFIG="/opt/novell/eDirectory/bin/ldapconfig";
my $NDSSTAT="/opt/novell/eDirectory/bin/ndsstat";
my $NDSCONFIG="/opt/novell/eDirectory/bin/ndsconfig";
my $NDSLOGIN="/opt/novell/eDirectory/bin/ndslogin";
#my $LOG="/var/opt/novell/xad/log/ndsdcrm.log";
my $LOG="/var/log/ndsdcrm.log";
my $SMBCONF="/etc/samba/smb.conf";
my $SMBCONF_BKP="/var/opt/novell/xad/ds/backup/smb.conf.org";
my $KEYTAB_FILE="/var/opt/novell/xad/ds/krb5kdc/krb5.keytab";
my $KRB5_FILE_DEFAULT="/etc/krb5.conf";
my $KRB5_FILE="/etc/opt/novell/xad/krb5.conf";
my $GETCERT_COMMAND="/opt/novell/oes-install/util/getSSCert";
my $LDAP_PORT=389;
my $LDAPS_PORT=636;
my $SERVER_CERT="/etc/opt/novell/certs/SSCert.der";

# Initialize the log handler to the log file
sub initLog{
	my $dirn=`dirname $LOG`;
	chomp($dirn);
	if(! -d $dirn){
		print "$dirn doesn't exist\n";
	}
	Logger::set_filename($LOG);
}

# Writes message only to the log file
sub writeLog
{
        #added for password mask
	my @msg=@_;
	$msg[0] =~ s/ -w\s*\S+/ -w *****/;
	$msg[0] =~ s/-x\s+[^-]\S+/-x *****/;
	$msg[0] =~ s/ADM_PASSWD\s*=\s*\S+/ ADM_PASSWD = *****/;
	Logger::unset_mask(2);
	Log(@msg);
	Logger::set_mask(2);
}

# Writes message to the log file and screen
sub writeScreenAndLog
{
        #added for password mask
	my @msg=@_;
	$msg[0] =~ s/ -w\s*\S+/ -w *****/;
        $msg[0] =~ s/-x\s+[^-]\S+/-x ****/;
	$msg[0] =~ s/ADM_PASSWD\s*=\s*\S+/ ADM_PASSWD = *****/;
	Log(@msg);
}

# Display the command status after execution
sub displayCommandStatus($$){
	my $st = shift;
	my $er = shift;

	if($st == -1){
		writeLog "Failed with error : $er";
	}
	elsif($st & 127){
		writeLog "Failed with signal ".($st & 127)." ".(($st & 128) ? 'with' : 'without')." coredump";
	}
	else{
		writeLog "Exit with value ".($st>>8);
	}
}

#Execution Command Routine
sub EXEC_COMMAND{
	my %args = @_;
	my $output_file  = $args{file} || $LOG;
	my $cmd  = $args{cmd} || die("No command is provided");
	my $redirect = $args{redir} || 0;
	my $stdout_to_log = $args{otol} || 0;
	my ($result, $status, $error);
	my @caller_info=caller;

	#Append stdout to log
	if($stdout_to_log){
		writeLog "__$caller_info[2]__ Executing... ".$cmd." 2>>$output_file";
		$result = `$cmd 2>>$output_file`;
	}
	else{
		if(!$redirect){
			writeLog "__$caller_info[2]__ Executing... ".$cmd." 2>&1";
			$result = `$cmd 2>&1`;
		}
		else{
			writeLog "__$caller_info[2]__ Executing... ".$cmd." >>$output_file 2>&1";
			$result = `$cmd >>$output_file 2>&1`;
		}
	}
	$status = $?;
	$error = $status>>8;

	displayCommandStatus($status, $error);

	return ($status, $error, $result);
}

# Provides information about a particular user
# Input:
# n - name
# p - password
# u - uid
# g - gid
# q - quota
# c - comment
# k - real name
# d - home directory
# s - shell
# Return:
# None :  option is invalid
# Otherwise the value as per the request
sub getUserInfo{
	my %detail=('n'=>0, 'p'=>1, 'u'=>2, 'g'=>3, 'q'=>4, 'c'=>5, 'k'=>6, 'd'=>7, 's'=>8, 'x'=>9);
	my $opt= shift || 'n';
	my @user_info=getpwnam(getlogin());
	return $user_info[$detail{$opt}] if(defined($user_info[$detail{$opt}]));
	return "None";
}

# Checks for xad.ini file, locates the DNS server and starts
# ndsd if it is not up and running.
sub checkForServer
{
	my $installedMac=registry::getReg("Install_DCName");
	my $dnsRoot=registry::getReg("DNS Root");
	my $user_confirmation;

	eval{
		if( ! -e "/etc/opt/novell/xad/xad.ini"){
			writeScreenAndLog "No domain is configured on this machine.";
			exit(1);
		}

		# Start ndsd, if it is not running.
		@got_status=EXEC_COMMAND(cmd=>"$NDSSTAT --config-file /etc/opt/novell/eDirectory/conf/nds.conf");
		if($got_status[0] != 0){
			writeScreenAndLog ">>> Starting eDirectory in order to deconfigure the Domain Services for Windows server.";
			EXEC_COMMAND(cmd=>"/etc/init.d/ndsd start");
		}

		@got_status=EXEC_COMMAND(cmd=>"/opt/novell/xad/sbin/provision -q -m $installedMac -l 10 --locate-dc $dnsRoot");
		my $provision_ret=$got_status[0];

		if($provision_ret != 0 and $partial != 1){
			writeScreenAndLog ">>> The Domain Services for Windows server seems to have a problem. Make sure all the necessary services on all DCs of $dnsRoot are up and running.";
			writeScreenAndLog "    Correct the following command's error and retry \n\t\t/opt/novell/xad/sbin/provision -q -m $installedMac -l 10 --locate-dc $dnsRoot";
			writeScreenAndLog "    If its an improper installation for some reason, use \'-f\' option for forced removal";
			exit(-1);
		}
		elsif($provision_ret != 0 and $partial == 1){
			until(defined($user_confirmation)){
				writeScreenAndLog ">>> The Domain Services for Windows server may not be configured properly. Do you wish to remove a partially installed server? [y/n] ";
				$user_confirmation=<STDIN>;
				chomp($user_confirmation);
			}

			if("$user_confirmation" eq "y" or "$user_confirmation" eq "Y"){

				$partial=1;
			}
			elsif("$user_confirmation" eq "n" or "$user_confirmation" eq "N"){
				# Aborting on user input
				exit(-1);
			}
			else{
				writeScreenAndLog ">>> Invalid user input. Exiting.";
				exit(-1);
			}
		}
	};

	if ($@) {
		Log(ERR, $@);
	}
}

# Display the --help option contents
sub printUsage
{
	print "Usage:\nndsdcrm [-f] [-p <IP Address>] [-a <administrator's fully distinguished name>] [-w <password>][-h]\n\n";
	print "For primary domain controller of forest root domain (name-mapped) server.\n\t-p\tSpecifies the IP address of the existing eDirectory server\n\t-a\tSpecifies the tree root admin name (FDN) of the existing eDirectory server. For example: cn=admin,o=novell\n\t-w\tSpecifies the tree root administrator password of the existing eDirectory server\n\n";
	print "For primary domain controller of forest root domain (non-name mapped) server.\n\t-p\tSpecifies the IP address of the same DSfW server\n\t-w\tSpecifies the forest root domain administrator's password\n\n";
	print "For all other installation (except primary domain controller of forest root domain).\n\t-p\tSpecifies the IP address of the server hosting the immediate parent domain\n\t-w\tSpecifies the forest root domain administrator's password\n\n";
	print "Incase of removing an improper installation use \'-f\' option to force the removal. This applies to all installations\n";
	exit(1);
}

# Provides the values for the input parameters to the
# /opt/novell/xad/share/dcinit/printConfigKey.pl file.
sub printConfigFileOption{
	my $opt = shift || die("No option provided");
	return `/opt/novell/xad/share/dcinit/printConfigKey.pl '$opt'`;
}

# Determines the server is a FRD/CHILD
sub analyzeScenario
{
	if(registry::getReg("Forest NC") eq registry::getReg("Domain NC")){
		if(registry::getReg("Domain NC") eq registry::getReg("Mapped Domain NC")){
			$frd=1;
		}
		else{
			$nm_frd=1;
		}
	}
	else{
		if(registry::getReg("Domain NC") eq registry::getReg("Mapped Domain NC")){
			$child=1;
		}
		else{
			$nm_child=1;
		}
	}
}

# It computes few global variables further
# used in the scripfurther used in the script
sub ComputeVariables
{
	my $treeroot_ip = shift;
	my $admin_name = shift;
	my $admin_passwd = shift;
	my $forestroot=registry::getReg("Forest Root");
	eval{
		@got_status=EXEC_COMMAND(cmd=>"/opt/novell/xad/share/dcinit/provisionTools.sh get-default-container");
		if($got_status[0] != 0){
			writeScreenAndLog "Failed to obtained default container. The Error was $got_status[1]";
			exit(-1);
		}
		$defaultcontainer=$got_status[2];
		chomp($defaultcontainer);
		@got_status=EXEC_COMMAND(cmd=>"ADM_PASSWD='$admin_passwd' /opt/novell/xad/share/dcinit/ndsConfigServerContext.sh --add-dc \"$forestroot\" \"$admin_name\" \"$treeroot_ip\"", otol=>1);
		if($got_status[0] != 0){
			writeScreenAndLog "Failed to obtain forestndsnc. The Error was $got_status[1]";
			exit(-1);
		}
		my $forestndsnc=$got_status[2];
		chomp($forestndsnc);
		$forestndsnc=~s/$defaultcontainer\.//g;
		$configurationndsname="CN=Configuration.".$forestndsnc;
		($configurationldapname=$configurationndsname)=~s/\./,/g;
		$schemandsname="CN=Schema.".$configurationndsname;
		($schemaldapname=$schemandsname)=~s/\./,/g;
		my $configurationndsfullname=".$configurationndsname."."T=$treename";
		my $schemandsfullname=".$schemandsname."."T=$treename.";

		if($debug_info == 1){
			writeScreenAndLog "configurationldapname = $configurationldapname";
			writeScreenAndLog "schemaldapname = $schemaldapname";
			writeScreenAndLog "configurationndsname = $configurationndsname";
			writeScreenAndLog "schemandsname = $schemandsname";
			writeScreenAndLog "configurationndsfullname = $configurationndsfullname";
			writeScreenAndLog "schemandsfullname = $schemandsfullname";
		}

		$servername=lc(`uname -n`);
		chomp($servername);
		$serverobjlocation="$servername,$defaultcontainer,".registry::getReg("Mapped Domain NC");
		$dcfullname="OU=Domain Controllers,".lc(registry::getReg("Mapped Domain NC"));
		$all_objects_removal_passed=1;
		$ridmanagerfullname="CN=RID Manager\$,CN=System,".registry::getReg("Mapped Domain NC");
		$forest_name=registry::getReg("Forest Root");
	};

	if ($@) {
		Log(ERR, $@);
	}
}

# Validates 3 major properties associated to replica ring
# Status of the replica : UP or DOWN
# State of the replica : ON or OFF
# Time Sync : Yes or No
# If any of the property is improper, displays the status
# and aborts the operation.
sub validateReplica
{
	my $admin_passwd = shift;
	my $ndscheck_log="/tmp/ndscheck.log";
	my $ndsrepair_log="/tmp/ndsrepair.log";
	my $para="";

	eval{
		$ENV{"ADM_PASSWD"}=$admin_passwd;
		EXEC_COMMAND(cmd=>"> $ndscheck_log");
		EXEC_COMMAND(cmd=>"> $ndsrepair_log");
		EXEC_COMMAND(cmd=>"/opt/novell/eDirectory/bin/ndscheck -q -a $adminnamends -w $ENV{\"ADM_PASSWD\"} -F $ndscheck_log");
		EXEC_COMMAND(cmd=>"/opt/novell/eDirectory/bin/ndsrepair -T | grep -A 1 \"Processing server\" > $ndsrepair_log");
		open(FH, $ndscheck_log) or die("Could not open file $ndscheck_log");
		foreach my $line (grep(/^.CN=/, <FH>)){
			chomp($line);
			$line=~s/\s+$//g;
			if((split(/\s+/, $line))[1] ne 'UP' and grep(/STATUS\//, $para)==0){
				$para.="STATUS/";
			}

			if((split(/\s+/, $line))[6] ne 'ON' and grep(/REPLICA STATE\//, $para)==0){
				$para.="REPLICA STATE/";
			}
		}
		close(FH);

		open(FH, $ndsrepair_log) or die("Could not open file $ndsrepair_log");
		foreach my $line (grep(!/Processing server/, <FH>)){
			chomp($line);
			$line=~s/\s+$//g;
			if((split(/\s+/, $line))[4] ne 'Yes' and grep(/TIME SYNCH/, $para)==0){
				$para.="TIME SYNCH";
			}

		}
		close(FH);

		if($para ne "" and $partial != 1){
			writeScreenAndLog ">>> One or more replicas are unstable in terms of $para. Please remove this inconsistency by using ndsrepair tool or/and synchronizing the server's time.";
			writeLog ">>> Partition Status & Replica State Information of all Servers";
			EXEC_COMMAND(cmd=>"grep -E \"(Status of partition|Server Name|^.CN=)\" $ndscheck_log");
			writeLog ">>> Time Synchronization Information of all Servers";
			EXEC_COMMAND(cmd=>"cat $ndsrepair_log");
			unlink($ndscheck_log);
			unlink($ndsrepair_log);
			writeScreenAndLog ">>> Exiting here.";
			exit(4);
		}
		else{
			unlink($ndscheck_log);
			unlink($ndsrepair_log);
		}
	};

	if ($@) {
		Log(ERR, $@);
	}
}

# It does a ndslogin to the Forest Root Domain and
# validate the credentials.
# If the ndslogin fails, it areports the error message
# and aborts the operation further.
sub validateInputs
{
	my $treeroot_ip = shift;
	my $admin_name = shift;
	my $admin_passwd = shift;
	my $tmp_admin;
	# Doing ndslogin in FRD to validate the credentials
	my $ndslogin_output=mktemp("/tmp/ndstmplg.XXXXXXXX");

	eval{
		@got_status=EXEC_COMMAND(cmd=>"$NDSLOGIN -h $treeroot_ip $adminnamends -p $admin_passwd > $ndslogin_output");
		my $ndslogin_ret=$got_status[0];
		if($ndslogin_ret == 1 and $frd == 1 and $partial == 1){
			$tmp_admin="cn=xad_provisioning_user,".registry::getReg("Domain NC");
			$tmp_admin=~s/,/\./g;
			$adminnamends=$tmp_admin;
			($admin_name=$tmp_admin)=~s/\./,/g;
			@got_status=EXEC_COMMAND(cmd=>"$NDSLOGIN -h $treeroot_ip $tmp_admin -p $admin_passwd > $ndslogin_output");
			$ndslogin_ret=$got_status[0];
		}
		else{
			@got_status=EXEC_COMMAND(cmd=>"$LDAPSEARCH -D $admin_name -w $admin_passwd -b \"\" -s base -e $SERVER_CERT");
			my $output=$got_status[2];
			chomp($output);
			if(grep(/Invalid DN Syntax/, $output)){
				writeScreenAndLog ">>> Invalid Administrator FQDN. Exiting.";
				exit(3);
			}
		}

		if($ndslogin_ret == 1){
			# Invalid Password or User Name
			open FH, ">$ndslogin_output" or die("Could not open $ndslogin_output");
			# if 669 or 601 found in ndslogin output
			if(grep(/669/, <FH>) || (seek(FH, 0, 0) && grep(/601/, <FH>))){
				writeScreenAndLog ">>> Invalid credentials. Exiting.";
				close(FH);
				exit(3);
			}

			if((seek(FH, 0, 0) && grep(/login cannot be done/, <FH>))){
				writeScreenAndLog ">>> Cannot log in to eDirectory. Check whether Novell eDirectory server is running on the machine $treeroot_ip. Exiting.";
				close(FH);
				exit(3);
			}
			close(FH);
		}

		unlink($ndslogin_output);
	};

	if ($@) {
		Log(ERR, $@);
	}
}

# Takes input as server name and object dn
# and search in the server to find the
# object dn. If the object dn is not present
# on the server then returns 0 else 1.
sub checkIfObjectPresent
{
	my $machine=shift || return 2;
	my $object_dn=shift || return 2;
	writeLog "checkIfObjectPresent: object=\"$object_dn\" from Machine=$machine";
	my $object_returned="";
	my $object_expected=lc($object_dn);
	my $retVal=0;	#Return Value default set to Successful

	eval{
		@got_status=EXEC_COMMAND(cmd=>"$LDAPSEARCH -LLL -x -h \"$machine\" -s base -b \"$object_dn\" dn 2>/dev/null | sed ' /^ / {; H; d; }; /^ /! {; x; s/\\n //; }; ' | grep \"dn:\" 2>/dev/null | awk -F\"dn: \" '{print \$2}' | tr \"[:upper:]\" \"[:lower:]\"");
		$object_returned=$got_status[2];
		chomp($object_returned);

		writeLog "checkIfObjectPresent: object_expected=$object_expected and object_returned=$object_returned";

		if("$object_returned" eq "$object_expected"){
			$retVal=0;
		}
		else{
			$retVal=1;
		}
	};

	if ($@) {
		Log(ERR, $@);
	}

	return $retVal;
}

# Deletes a particular object dn from the server
# Input:
# Server Admin Name
# Server Admin Password
# Server IP
# object dn to delete
sub deleteIfObjectPresent
{
	my $admin_name = shift;
	my $admin_passwd = shift;
	my $machine=shift || return 2;
	my $object_dn=shift || return 2;
	my $deleteAttempt=0;
	my $object_present=0; # Default assumption is that the object is present.

	writeLog "deleteIfObjectPresent: object=\"$object_dn\" from Machine=$machine";

	eval{
		while($deleteAttempt< 5){
			writeLog "Delete attempt=$deleteAttempt";
			$object_present=checkIfObjectPresent("$machine", "$object_dn");
			if($object_present == 0){
				EXEC_COMMAND(cmd=>"$LDAPDELETE -h \"$machine\" -D \"$admin_name\" -w $admin_passwd -e $SERVER_CERT -r \"$object_dn\"");
				sleep(1);
			}
			else{
				$object_removal_passed=1;
				last;
			}

			$deleteAttempt++;
		}

		if($object_present == 0){
			$object_removal_passed=0;
			$all_objects_removal_passed=0;
		}

		writeLog "Removal of $object_dn passed=$object_removal_passed";
	};

	if ($@) {
		Log(ERR, $@);
	}
}

# Removes the Domain object present under Servers and Domain Controllers
# section
sub removeDCObjects
{
	my $admin_name=shift;
	my $admin_passwd=shift;
	my $installedMac=registry::getReg("Install_DCName");
	my $mapped_domain_nc=registry::getReg("Mapped Domain NC");

	deleteIfObjectPresent($admin_name, $admin_passwd, "localhost", "CN=$installedMac,cn=Servers,cn=Default-First-Site-Name,cn=Sites,$configurationldapname");
	deleteIfObjectPresent($admin_name, $admin_passwd, "localhost", "CN=$installedMac,OU=Domain Controllers,$mapped_domain_nc");
}

# Subroutine checks the preferred dns server passed is a DSfW server or not.
# If it is not a DNS server it finds the DNS server from the /etc/r4esolv.conf.
# Finds the location of the DNS Zone objects, computes both Forward Zone name
# and FDN along with Reverse Zone name and FDN.
# Deletion of Forward Zone and Reverse Zone along with the objects beneath
# them takes place as per the configuration of the DSfW server as an adc or
# child.
sub removeDNSObjects
{
	my $treeroot_ip = shift;
	my $admin_name = shift;
	my $admin_passwd = shift;
	my $preferred_dns = shift;
	my $nonfrd_dns=0;
	my $dns_server_ip="";
	my $ipaddress=registry::getReg("IP Address");
	my $library_path = "LD_LIBRARY_PATH=\"/opt/novell/eDirectory/lib:/opt/novell/eDirectory/lib/nds-modules:".(defined $ENV{'LD_LIBRARY_PATH'}? $ENV{'LD_LIBRARY_PATH'} : "")."\"";
	my $rc=0;
	my $dns_rev_soa_serial_ldif="";
	my $dns_fwd_soa_serial_ldif="";

	eval{
		# Check if the preferred DNS server passed is a DSfW server or not
		# if not, then fall back on /etc/resolv.conf method
		@got_status=EXEC_COMMAND(cmd=>"/usr/bin/ldapsearch -h \"$preferred_dns\" -b \"\" -s base supportedCapabilities -x -LLL | grep '^supportedCapabilities: ' | grep '2.16.840.1.113719.1.513.7.1' >/dev/null");
		if( $got_status[0] == 0){
			# this is the DSfW server to talk to for DNS related transations
			$dns_server_ip=$preferred_dns;
			# Make sure incase if the domain we are deleting has the DNS configured.. If so we mark it as preferred DNS
			if($preferred_dns ne  $ipaddress){
				if(registry::getReg("DNS Master") eq "TRUE"){
					# this is the DSfW server to talk to for DNS related transations
					$dns_server_ip="$ipaddress";
					$preferred_dns="$ipaddress";
					$nonfrd_dns=1;
				}
			}
		}
		else{
			# the server passed as the preferred DNS server is not a DSfW server
			# hence we must look for DNS servers from /etc/resolv.conf, query for
			# the domain name, check if it contains domain name as $FOREST_NAME
			# if so, that $ip_address would point to the correct DSfW server hosting
			# the DNS server.

			# calculate the number of nameserver entries
			open(FH, "/etc/resolv.conf") or die("Could not open /etc/resolv.conf");
			my @ip_list=grep(/nameserver/, <FH>);
			my $ns_entries=$#ip_list+1;
			close(FH);
			if($ns_entries >= 1){
				# get each NS entry's IP address and do a nslookp. Look
				# for the FOREST_NAME in the output, if found this is our
				# designated server, keep the hostname and the domain name,
				# and the IP address as well
				my $match_found=0;
				foreach my $ip_address (@ip_list){
					$ip_address=(split(/nameserver\s+/, $ip_address))[1];
					chomp($ip_address);
					if($match_found == 1 ){
						# match found for the FOREST_NAME, break the loop
						last;

					}
					@got_status=EXEC_COMMAND(cmd=>"/usr/bin/nslookup \"$ip_address\" | grep \"$forest_name\"");
					my $value=$got_status[2];
					chomp($value);
					if(defined($value)){
						$match_found=1;
						$dns_server_ip=$ip_address;
						last;
					}
				}
			}
		}
		# Get the NCP server context of the designated DNS server
		@got_status=EXEC_COMMAND(cmd=>"ndsstat -h $dns_server_ip");
		my $ncpserverfdn=(split(/.T=/, (split(/Server Name:\s+\./, (grep(/Server Name:\s+/, $got_status[2]))[0]))[1]))[0];
		chomp($ncpserverfdn);
		if(!defined($ncpserverfdn)){
			writeScreenAndLog ">>> Error enocuntered while computing the NCP server context for the DNS server $dns_server_ip. exiting.. The ERROR returned is $got_status[1]";
			exit(1);
		}

		# Get the ndstempcontainer or the location of the DNS zone objects
		@got_status=EXEC_COMMAND(cmd=>"nslookup $dns_server_ip");
		if(grep(/\*\* server can't find/, $got_status[2])){
			writeScreenAndLog ">>> Error enocuntered while executing the nslookup for the DNS server $dns_server_ip. exiting..";
			exit(1);
		}

		my $dnsserverhostname=(split(/\./, (split(/name = /, (grep(/name\s+=/, $got_status[2]))[0]))[1]))[0];
		chomp($dnsserverhostname);
		if(!defined($dnsserverhostname)){
			writeScreenAndLog ">>> Error enocuntered while computing the DNS Server Hostname for the DNS server $dns_server_ip. exiting..";
			exit(1);
		}

		my $ndstempcontainer=(split(/cn=$dnsserverhostname\./, lc($ncpserverfdn), 2))[1];
		$ndstempcontainer=~s/\./,/g;
		$ENV{"LDAPTEMPCONTAINER"}=$ndstempcontainer;
		my $hostname=lc(`/bin/hostname`);
		chomp($hostname);

		# Compute the DNS Forward zone name and FDN
		my $dnshostname=registry::getReg("DNS Host Name");
		my $dnsforwardzonerdn;
		($dnsforwardzonerdn=$dnshostname)=~s/$hostname\.//;
		$dnsforwardzonerdn=~s/\./_/g;
		my $dnsforwardzonefdn="cn=$dnsforwardzonerdn,".$ENV{"LDAPTEMPCONTAINER"};

		# Compute the DNS reverse zone name and FDN
		@got_status=EXEC_COMMAND(cmd=>"/opt/novell/xad/share/dcinit/printConfigKey.pl 'IP_ADDRESS_UNDERSCORE_FORM'");
		my $ip_address_underscore_form=$got_status[2];
		chomp($ip_address_underscore_form);
		my $dnsreversezonerdn="cn=$ip_address_underscore_form";
		my $dnsreversezonefdn="$dnsreversezonerdn,".$ENV{"LDAPTEMPCONTAINER"};

		writeLog "dnsforwardzonefdn : $dnsforwardzonefdn";
		writeLog "dnsreversezonefdn : $dnsreversezonefdn";
		writeLog "LDAPTEMPCONTAINER : ".$ENV{"LDAPTEMPCONTAINER"};

		# In case its a child domain, Remove both the forward and reverse
		# DNS zones and the objects beneath them, talk to the preferred DNS
		# server as Tree admin (as the parent might not be configured as the
		# preferred DNS server, do a check for the two IPs entered), using tree
		# certs
		writeLog "$frd:$nm_frd:$child:$nm_child:$adc:$nm_adc:$nonfrd_dns";
		if(($nm_frd == 1 ) or ( ($child == 1 or $nm_child == 1) and $nonfrd_dns == 1 )){
			# delete the forward and reverse zone objects along with all
			# subordinate objects
			deleteIfObjectPresent($admin_name, $admin_passwd, $dns_server_ip, "$dnsforwardzonefdn");
			deleteIfObjectPresent($admin_name, $admin_passwd, $dns_server_ip, "$dnsreversezonefdn");
		}

		# In case its an ADC or CHILD not configured with DNS, we need to
		# delete the reverse DNS zone and objects beneath it but in case
		# of forward DNS zone, only the entries specific to DC are to be
		# reomved (as they occur as Multi valued atribute DNIPRR, in SRV
		# records)
		if( ($child == 1 or $nm_child == 1) and $nonfrd_dns != 1){
			deleteIfObjectPresent($admin_name, $admin_passwd, $dns_server_ip, "$dnsforwardzonefdn");

			@got_status=EXEC_COMMAND(cmd=>"ADM_PASSWD=\"$admin_passwd\" /opt/novell/xad/share/dcinit/provisionTools.sh soa-query -p $dns_server_ip -a \"$admin_name\" -c \"$dnsreversezonefdn\"");
			if($got_status[0] != 0){
				writeScreenAndLog "Failed to obtained soa_serial from the dns Server. The Error was $got_status[1]";
				exit(-1);
			}
			my $soa_serial = $got_status[2];
			chomp($soa_serial);
			$dns_rev_soa_serial_ldif = mktemp ("/tmp/tmp.XXXXXXXX");
			open FILE, ">$dns_rev_soa_serial_ldif" or die ("failed to open the file $dns_rev_soa_serial_ldif");
			print FILE "dn: $dnsreversezonefdn\nchangetype: modify\nreplace: dNIPSOASerial\ndNIPSOASerial: $soa_serial";
			close(FILE);

			# Delete the DNS reverse zone along with the subordinate objects
			my $last_octet=(split(/\./, $ipaddress))[3];
			$dnsreversezonefdn="cn=$last_octet,".$dnsreversezonefdn;
			deleteIfObjectPresent($admin_name, $admin_passwd, $dns_server_ip, "$dnsreversezonefdn");

			EXEC_COMMAND(cmd=>"$LDAPMODIFY -h $treeroot_ip -D $admin_name -w $admin_passwd -e $SERVER_CERT -f $dns_rev_soa_serial_ldif");
			unlink($dns_rev_soa_serial_ldif);

			# Modify the SOA serial for Forward Zone
			@got_status=EXEC_COMMAND(cmd=>"ADM_PASSWD=\"$admin_passwd\" /opt/novell/xad/share/dcinit/provisionTools.sh soa-query -p $dns_server_ip -a \"$admin_name\" -c \"$dnsforwardzonefdn\"");
			if($got_status[0] != 0){
				writeScreenAndLog "Failed to obtained soa_serial from the DNS Server. The Error was $got_status[1]";
				exit(-1);
			}
			$soa_serial = $got_status[2];
			chomp($soa_serial);
			$dns_fwd_soa_serial_ldif = mktemp ("/tmp/tmp.XXXXXXXX");
			open FILE, ">$dns_fwd_soa_serial_ldif" or die ("failed to open the file $dns_fwd_soa_serial_ldif");
			print FILE "dn: $dnsforwardzonefdn\nchangetype: modify\nreplace: dNIPSOASerial\ndNIPSOASerial: $soa_serial";
			close(FILE);

			EXEC_COMMAND(cmd=>"$LDAPMODIFY -h $treeroot_ip -D $admin_name -w $admin_passwd -e $SERVER_CERT -f $dns_fwd_soa_serial_ldif");
			unlink($dns_fwd_soa_serial_ldif);
		}

		if($adc == 1 or $nm_adc == 1){
			# generate the ldif to delete the Forward zone records
			# check if the forward zone file for ADC is present or not, if not create it
			my $dnsRoot=registry::getReg("DNS Root");
			if(! -f "/var/opt/novell/xad/ds/dns/RR/DC_$dnsRoot.zone"){
				if($adc == 1 or $nm_adc == 1){
					@got_status=EXEC_COMMAND(cmd=>"/opt/novell/xad/share/dcinit/regSubstitute.pl < /opt/novell/xad/share/dcinit/templates/additional-dc.zone > /var/opt/novell/xad/ds/dns/RR/DC_$dnsRoot.zone");
				}
				else{
					@got_status=EXEC_COMMAND(cmd=>"/opt/novell/xad/share/dcinit/regSubstitute.pl < /opt/novell/xad/share/dcinit/templates/dns.zone > /var/opt/novell/xad/ds/dns/RR/DC_$dnsRoot.zone");
				}
			}
			# delete the already existing files
			@got_status=EXEC_COMMAND(cmd=>"ls /var/opt/novell/xad/ds/dns/RR/Delete_*.ldif");
			if($got_status[0] == 0){
				foreach my $exst_file (split('\n', $got_status[2])){
					chomp($exst_file);
					unlink($exst_file);
				}
			}

			# Create the ldif files for deleting the individual record #DHIRAJ's Find
		        if( -e "/var/opt/novell/xad/ds/dns/RR/DC_$dnsRoot.zone"){
				@got_status=EXEC_COMMAND(cmd=>"/opt/novell/xad/share/dcinit/GenerateRRLdifs.pl /var/opt/novell/xad/ds/dns/RR/DC_$dnsRoot.zone $ENV{\"LDAPTEMPCONTAINER\"} TRUE delete");
				if($got_status[0] != 0){
					writeScreenAndLog ">>> Failed while generating the ADC DNS record removal ldifs. Exiting..";
					exit(-1);
				}
			}
			unlink("/var/opt/novell/xad/ds/dns/final_dns_records_delete.ldif") if -e "/var/opt/novell/xad/ds/dns/final_dns_records_delete.ldif";
			EXEC_COMMAND(cmd=>"touch /var/opt/novell/xad/ds/dns/final_dns_records_delete.ldif");
			@got_status=EXEC_COMMAND(cmd=>"ls /var/opt/novell/xad/ds/dns/RR/Delete_*.ldif");
			foreach my $i (split('\n', $got_status[2])){
				chomp($i);
				EXEC_COMMAND(cmd=>"cat $i >> /var/opt/novell/xad/ds/dns/final_dns_records_delete.ldif");
				EXEC_COMMAND(cmd=>"echo \"\" >> /var/opt/novell/xad/ds/dns/final_dns_records_delete.ldif");
			}
			# Check for cert
			if(! -f "/etc/opt/novell/certs/SSCert.der"){
				EXEC_COMMAND(cmd=>"$library_path \"$GETCERT_COMMAND\" -a $ipaddress -t $treename -u \"$adminnamends\" -x \"$admin_passwd\"");
			}

			if(! -f "/etc/opt/novell/certs/SSCert.der"){
				writeScreenAndLog ">>> Unable to retrieve CA certificates. Exiting..";
				exit(-1);
			}
			# Delete the DNS forward zone records for ADC
			$rc=checkIfObjectPresent("$dns_server_ip", "$dnsforwardzonefdn");
			if($rc == 0){
				@got_status=EXEC_COMMAND(cmd=>"/opt/novell/eDirectory/bin/ldapmodify -c -h $dns_server_ip -x -D $admin_name -e $SERVER_CERT -p 636 -w $admin_passwd -f /var/opt/novell/xad/ds/dns/final_dns_records_delete.ldif");
				if($got_status[0] != 0){
					$object_removal_passed=0;
				}
				writeLog "Removal of RR records under $dnsforwardzonefdn passed=$object_removal_passed";
			}

			@got_status=EXEC_COMMAND(cmd=>"ADM_PASSWD=\"$admin_passwd\" /opt/novell/xad/share/dcinit/provisionTools.sh soa-query -p $dns_server_ip -a \"$admin_name\" -c \"$dnsreversezonefdn\"");
			my $soa_serial=$got_status[2];
			chomp($soa_serial);
			$dns_rev_soa_serial_ldif = mktemp ("/tmp/tmp.XXXXXXXX");
			open FILE, ">$dns_rev_soa_serial_ldif" or die ("failed to open the file $dns_rev_soa_serial_ldif");
			print FILE "dn: $dnsreversezonefdn\nchangetype: modify\nreplace: dNIPSOASerial\ndNIPSOASerial: $soa_serial";
			close(FILE);

			# Delete the reverse zone IP under zone object and update the SOA
			my $last_octet=(split(/\./, $ipaddress))[3];
			$dnsreversezonefdn="cn=$last_octet,".$dnsreversezonefdn;
			deleteIfObjectPresent($admin_name, $admin_passwd, $dns_server_ip, "$dnsreversezonefdn");
			deleteIfObjectPresent($admin_name, $admin_passwd, $dns_server_ip, "cn=DNS_$serverobjlocation");

			EXEC_COMMAND(cmd=>"$LDAPMODIFY -h $treeroot_ip -D $admin_name -w $admin_passwd -e $SERVER_CERT -f $dns_rev_soa_serial_ldif");
			unlink($dns_rev_soa_serial_ldif);

			# Modify the SOA serial for Forward Zone
			@got_status=EXEC_COMMAND(cmd=>"ADM_PASSWD=\"$admin_passwd\" /opt/novell/xad/share/dcinit/provisionTools.sh soa-query -p $dns_server_ip -a \"$admin_name\" -c \"$dnsforwardzonefdn\"");
			$soa_serial = $got_status[2];
			chomp($soa_serial);
			$dns_fwd_soa_serial_ldif = mktemp ("/tmp/tmp.XXXXXXXX");
			open FILE, ">$dns_fwd_soa_serial_ldif" or die ("failed to open the file $dns_fwd_soa_serial_ldif");
			print FILE "dn: $dnsforwardzonefdn\nchangetype: modify\nreplace: dNIPSOASerial\ndNIPSOASerial: $soa_serial";
			close(FILE);

			EXEC_COMMAND(cmd=>"$LDAPMODIFY -h $treeroot_ip -D $admin_name -w $admin_passwd -e $SERVER_CERT -f $dns_fwd_soa_serial_ldif");
			unlink($dns_fwd_soa_serial_ldif);
		}
	};

	if ($@) {
		Log(ERR, $@);
	}
}

# Clean all the DSfW server security objects
sub cleanSecurityObjects
{
	my $admin_name = shift;
	my $admin_passwd = shift;
	my $ipaddress=registry::getReg("IP Address");
	my $domainfullname=registry::getReg("DNS Root");

	deleteIfObjectPresent($admin_name, $admin_passwd, "localhost", "cn=SAS Service - ".$serverobjlocation);
	deleteIfObjectPresent($admin_name, $admin_passwd, "localhost", "cn=SSL CertificateDNS - ".$serverobjlocation);
	deleteIfObjectPresent($admin_name, $admin_passwd, "localhost", "cn=SSL CertificateIP - ".$serverobjlocation);
	deleteIfObjectPresent($admin_name, $admin_passwd, "localhost", "cn=IP AG ".$ipaddress." - ".$serverobjlocation);
	deleteIfObjectPresent($admin_name, $admin_passwd, "localhost", "cn=DNS AG ".$servername.".$domainfullname - ".$serverobjlocation);
}

# Stop all the services up and running under DSfW server
sub StopServices{
	writeScreenAndLog ">>> Stopping Services";
	my @stop_services = qw(smb winbind nmb xadsd xad-kpasswdd xad-krb5kdc rpcd novell-named);

	eval{
		foreach my $serv (@stop_services){
			if( -f "/etc/init.d/$serv"){
				writeScreenAndLog ">>> Stopping $serv";
				EXEC_COMMAND(cmd=>"/etc/init.d/$serv stop");
			}
		}
	};

	if ($@) {
		Log(ERR, $@);
	}
}

# Subroutine removes the eDirectory with the help of command
# "ndsconfig rm".
sub removeeDirectory
{
	my $retVal=0;	#Return Value default set to Successful
	eval{
		unlink("/var/opt/novell/eDirectory/data/ndsconfig.err");
		writeScreenAndLog ">>> Executing ndsconfig rm";
		@got_status=EXEC_COMMAND(cmd=>"$NDSCONFIG rm -a $adminnamends -c");
		my $ndsconfig_ret_val=$got_status[0];
		if($ndsconfig_ret_val == 0){
			writeLog "ndsconfig rm passed.";
			$retVal=0;
		}

		my $ndsconfigRetryAttempt=1;
		if($ndsconfig_ret_val != 0){
			writeLog "ndsconfig rm failed with return value $ndsconfig_ret_val.";
			while(1){
				@got_status=EXEC_COMMAND(cmd=>"cat /var/opt/novell/eDirectory/data/ndsconfig.err");
				my $ndsconfig_ret_code = $got_status[2];
				chomp($ndsconfig_ret_code);
				writeLog "ndsconfig return code from ndsconfig.err=$ndsconfig_ret_code.";
				if("$ndsconfig_ret_code" eq "-658" and $ndsconfigRetryAttempt < 6){
					$ndsconfigRetryAttempt++;
					writeLog "ndsconfig retry attempt=$ndsconfigRetryAttempt.";
					sleep(20);
					@got_status=EXEC_COMMAND(cmd=>"$NDSCONFIG rm -a $adminnamends -c");
					$ndsconfig_ret_val=$got_status[0];
					if($ndsconfig_ret_val == 0){
						writeLog "ndsconfig rm passed.";
						$retVal=0;
					}
				}
				else {
					if("$ndsconfig_ret_code" eq "-658"){
						writeScreenAndLog ">>> ndsconfig rm failed. Could not proceed with the removal of the domain controller.";
						exit(2);
					}
					else{
						$retVal=2;
						return $retVal;
					}
				}
			}
		}
	};

	if ($@) {
		Log(ERR, $@);
	}
	return $retVal;
}

# Before removing a particular domain we need few confirmations
# from the administrator and we get it with the help of this
# subroutine.
sub promptUser
{
	my ($user_confirmation, $user_strong_confirmation);
	eval{
		until(defined($user_confirmation)){
			writeScreenAndLog ">>> ndsconfig failed to remove the eDirectory server properly. Do you want to continue? [y/n] ";
			$user_confirmation=<STDIN>;
			chomp($user_confirmation);
		}

		if("$user_confirmation" eq "y" or "$user_confirmation" eq "Y"){
			writeScreenAndLog "ERROR: eDirectory server is not properly removed. Use iManager to clean the tree.";
			until(defined($user_strong_confirmation)){
				writeScreenAndLog ">>> ndsconfig failed. This failure can cause inconsistency in the tree. Do you really want to continue[y/n] ";
				$user_strong_confirmation=<STDIN>;
				chomp($user_strong_confirmation);
			}
			if("$user_strong_confirmation" eq "y" or "$user_strong_confirmation" eq "Y"){
			}
			elsif("$user_strong_confirmation" eq "n" or "$user_strong_confirmation" eq "N"){
				writeScreenAndLog "ERROR: Use 'ndsconfig rm' to remove the eDirectory server. After removing the eDirectory server, use ndsdcrm to remove Domain Services for Windows server. ";
				# Aborting on user input
				exit(-1);
			}
			else{
				writeScreenAndLog ">>> Invalid user input. Exiting.";
				exit(-1);
			}
		}
		elsif("$user_confirmation" eq "n" or "$user_confirmation" eq "N"){
			writeScreenAndLog "ERROR: Use 'ndsconfig rm' to remove the eDirectory server. After removing the eDirectory server, use ndsdcrm to remove Domain Services for Windows server.";
			# Aborting on user input
			exit(-1);
		}
		else{
			writeScreenAndLog ">>> Invalid user input. Exiting.";
			exit(-1);
		}
	};

	if ($@) {
		Log(ERR, $@);
	}
}

# Revert the config files ndsmodules.conf, krb5.conf, xad.ini,
# smb.conf, krb5.keytab and provisioning.xml to retain the state
# of the server as a non-configured server.
sub revertConfigFiles
{
	eval{
		writeScreenAndLog ">>> Taking the back up of configuration files";
		my $modules_conf_tmp=mktemp("/tmp/tmp.XXXXXXXX");
		EXEC_COMMAND(cmd=>"cat /etc/opt/novell/eDirectory/conf/ndsmodules.conf |grep -v samspm > $modules_conf_tmp");
		EXEC_COMMAND(cmd=>"cat $modules_conf_tmp > /etc/opt/novell/eDirectory/conf/ndsmodules.conf");
		unlink($modules_conf_tmp);
		if(-f "/etc/opt/novell/xad/xad.ini"){
			if("$ndsconfig_passed" eq "true"){
				move("/etc/opt/novell/xad/xad.ini", "/etc/opt/novell/xad/xad.ini.old");
			}
		}
		copy($SMBCONF_BKP, $SMBCONF);
		unlink($KEYTAB_FILE);
		EXEC_COMMAND(cmd=>"/opt/novell/xad/bin/kdestroy");
		unlink($KRB5_FILE_DEFAULT);
		unlink($KRB5_FILE);
		unlink("/etc/opt/novell/xad/provisioning.xml");

		open FH, ">$KRB5_FILE" or die("Could not open $KRB5_FILE");
		print FH "[libdefaults]
		default_realm = EXAMPLE.COM

		[realms]
		EXAMPLE.COM = {
		kdc = kerberos.example.com
		admin_server = kerberos.example.com
		}

		[logging]
		kdc = FILE:/var/log/krb5/krb5kdc.log
		admin_server = FILE:/var/log/krb5/kadmind.log
		default = SYSLOG:NOTICE:DAEMON\n";
		close(FH);
	};

	if ($@) {
		Log(ERR, $@);
	}
}

# Remove all the partitions associated with the DSfW server
sub removeExternalPartitions
{
	my $admin_name = shift;
	my $admin_passwd = shift;
	my $mapped_domain_nc=registry::getReg("Mapped Domain NC");
	my ($kinitpasswd, $kinitadmin);
	my $domainfullname=registry::getReg("DNS Root");
	my $netbiosname=registry::getReg("Netbios Name");
	writeScreenAndLog ">>> Cleaning external partitions added through custom provisioning, if any";

	eval{
		if($nm_child == 1 or $child == 1 or $nm_frd == 1){
			$kinitadmin=(split(/\,/,(split(/=/, lc($dcadminname), 2))[1],2))[0];
			$kinitpasswd="$dcadminpasswd";
		}
		else{
			$kinitadmin=(split(/\,/,(split(/=/, lc($admin_name), 2))[1],2))[0];
			$kinitpasswd="$admin_passwd";
		}

		EXEC_COMMAND(cmd=>"ADM_PASSWD=$kinitpasswd /opt/novell/xad/bin/kinit -E $kinitadmin");
		@got_status=EXEC_COMMAND(cmd=>"$LDAPSEARCH -D $admin_name -w $admin_passwd -b \"cn=$netbiosname,cn=Partitions,$configurationldapname\" -s sub 'domainPartitionList'  -e $SERVER_CERT 3>/dev/null | sed ' /^ / {; H; d; }; /^ /! {; x; s/\\n //; }; ' | grep -i \"domainPartitionList:\" |tr \"[:upper:]\" \"[:lower:]\" | awk -F \"domainPartitionList\" '{print \$2}'| grep -v -i \": $mapped_domain_nc\"");
		my @collected_ext_partitions = split('\n', $got_status[2]);
		foreach my $externalPartitions (@collected_ext_partitions){
			chomp($externalPartitions);
			my $Other_Partition=(split(/:\s+/, $externalPartitions))[1];
			if(defined($Other_Partition)){
				writeScreenAndLog ">>> This external partition '$Other_Partition' is currently part of the domain $domainfullname.";
				writeScreenAndLog "	Removing using 'domaincntrl' remove option before proceeding..";
				EXEC_COMMAND(cmd=>"echo '1' | /opt/novell/xad/sbin/domaincntrl --remove", otol=>1);
				sleep(10);
			}
		}
	};

	if ($@) {
		Log(ERR, $@);
	}
}

# Clean all the attributes in the domain container
sub cleanDomainContainerAttributes
{
	my $mapped_domain_nc=registry::getReg("Mapped Domain NC");
	writeScreenAndLog ">>> Removing Domain Services specific attributes from the domain container";

	eval{
		EXEC_COMMAND(cmd=>"/opt/novell/xad/share/dcinit/genLdif.pl /opt/novell/xad/share/dcinit/templates/domain-object-modify-delete-attributes.ini --defaultrootdomainobject > /tmp/temp.ldif");
		EXEC_COMMAND(cmd=>"sed -e \"s/^-/\\ndn: $mapped_domain_nc\\nchangetype: modify/g\" /tmp/temp.ldif > /tmp/domain-object-modify-delete-attributes.ldif");
		EXEC_COMMAND(cmd=>"/usr/bin/ldapmodify -H ldapi://%2fvar%2fopt%2fnovell%2fxad%2frun%2fldapi -Y EXTERNAL -c -f /tmp/domain-object-modify-delete-attributes.ldif");;
		unlink("/tmp/temp.ldif");
		unlink("/tmp/domain-object-modify-delete-attributes.ldif");
	};

	if ($@) {
		Log(ERR, $@);
	}
}

# Delete all objects under configuration partition
sub deleteConfigurationObjects
{
	my $admin_name = shift;
	my $admin_passwd = shift;

	writeScreenAndLog ">>> Cleaning Domain Services objects under configuration partition";
	eval{
		if($child != 1){
			my $conf_objects=mktemp("/tmp/temp.XXXXXXXX");
			open(FH, ">$conf_objects") or die("Couldn't open file $conf_objects in write mode");
			print FH "cn=Sites\ncn=Services\ncn=Deleted Objects\ncn=DisplaySpecifiers\ncn=Extended-Rights\ncn=ForestUpdates\ncn=LostAndFoundConfig\ncn=NTDS Quotas\ncn=Partitions\ncn=Physical Locations\ncn=WellKnown Security Principals\ncn=Schema";
			close(FH);
			open(FH, "<$conf_objects") or die("Couldn't open file $conf_objects in read mode");
			while(my $ConfContainer=<FH>){
				chomp($ConfContainer);
				my $ConfContainerDN=$ConfContainer.",$configurationldapname";
				deleteIfObjectPresent($admin_name, $admin_passwd, "localhost", "$ConfContainerDN");
			}
			close(FH);
			unlink($conf_objects);
		}
	};

	if ($@) {
		Log(ERR, $@);
	}
}

#
sub checkIfObjectIsPartitionRoot
{
        my $machine=shift || return 2;
        my $object_dn=shift || return 2;

        writeLog "checkIfObjectIsPartitionRoot: object=\"$object_dn\" from Machine=$machine" ;

        #Default assumption is that the object is at partition root
        my $object_is_partition_root=0;

	eval{
		@got_status=EXEC_COMMAND(cmd=>"$LDAPSEARCH -LLL -x -h \"$machine\" -s base -b \"$object_dn\" objectClass 2>/dev/null | sed ' /^ / {; H; d; }; /^ /! {; x; s/\\n //; }; ' | grep -i \"objectClass: Partition\" >/dev/null");

		$object_is_partition_root=$got_status[0];

		writeLog "checkIfObjectIsPartitionRoot: object_is_partition_root=$object_is_partition_root";
	};

	if ($@) {
		Log(ERR, $@);
	}

	# 0 indicates true and 1 indicates false
	return $object_is_partition_root;
}

# Merge all the partitions like schema, configuration etc.
# Before merging it deletes all the objects under that
# particular partion. Merging and deletion of object is
# specific to the type of server(frd/child etc.).
sub mergePartitions
{
	my $admin_name = shift;
	my $admin_passwd = shift;
	my $mapped_domain_nc=registry::getReg("Mapped Domain NC");
	my $rc=0;

	eval{
		EXEC_COMMAND(cmd=>"$LDAPCONFIG set \"Require TLS for Simple Binds with Password=no\" --config-file /etc/opt/novell/eDirectory/nds.conf -t \"$treename\" -a \"$adminnamends\" -w \"$admin_passwd\"");
		sleep(10);
		$ENV{"ADM_PASSWD"}=$admin_passwd;
		my $ncpserverobj="cn=$servername,$defaultcontainer,".$mapped_domain_nc;
		if($child == 1){
			# Deleting a domain Administrator before merging the partition
			deleteIfObjectPresent($admin_name, $admin_passwd, "localhost", "cn=Administrator,cn=Users,$mapped_domain_nc");

			# merging domain partition
			writeScreenAndLog ">>> Merging domain partition";
			$rc=checkIfObjectPresent("localhost", "$mapped_domain_nc");
			if($? == 0){
				$rc=checkIfObjectIsPartitionRoot("localhost", "$mapped_domain_nc");
				if($rc == 0){
					EXEC_COMMAND(cmd=>"/opt/novell/xad/sbin/replops -p 389  -s $ncpserverobj -n \"$mapped_domain_nc\" -D \"$admin_name\" -w $ENV{\"ADM_PASSWD\"} --merge-partition");
					sleep(10);
				}
			}
		}
		elsif($nm_frd == 1){
			# merging schema partition
			# recursively delete the objects under schema partition
			my $schemacontainerdn="$schemaldapname";
			# wait for 60 seconds before merging the schema partition
			sleep(60);
			writeScreenAndLog ">>> Merging schema partition";
			$rc=checkIfObjectPresent("localhost", "$schemaldapname");
			if($rc == 0){
				$rc=checkIfObjectIsPartitionRoot("localhost", "$schemaldapname");
				if($rc == 0){
					EXEC_COMMAND(cmd=>"/opt/novell/xad/sbin/replops -p 389 -s $ncpserverobj -n \"$schemaldapname\" -D \"$admin_name\" -w $ENV{\"ADM_PASSWD\"} --merge-partition");
					sleep(60);
				}
			}

			# merging configuration partition
			# delete all the objects in the Configuration partition prior to merging
			deleteConfigurationObjects($admin_name, $admin_passwd);

			# wait ofr 60 seconds before merging configuration partition
			sleep(60);
			writeScreenAndLog ">>> Merging configuration partition";
			$rc=checkIfObjectPresent("localhost", "$configurationldapname");
			if($rc==0){
				$rc=checkIfObjectIsPartitionRoot("localhost", "$configurationldapname");
				if($rc==0){
					EXEC_COMMAND(cmd=>"/opt/novell/xad/sbin/replops -p 389  -s $ncpserverobj -n \"$configurationldapname\" -D \"$admin_name\" -w $ENV{\"ADM_PASSWD\"} --merge-partition");
					sleep(10);
				}
			}
		}
		delete $ENV{"ADM_PASSWD"};
	};

	if ($@) {
		Log(ERR, $@);
	}
}

# Clean all the Trusted Domain Objects present inside domain server
sub removeTDO
{
	my $admin_name = shift;
	my $admin_passwd = shift;
	my $forestnc=registry::getReg("Forest NC");
	my $domainfullname=registry::getReg("DNS Root");

	writeScreenAndLog ">>> Cleaning Trusted Domain Objects";
	eval{
		@got_status=EXEC_COMMAND(cmd=>"$LDAPSEARCH  -D $admin_name -w $admin_passwd -e $SERVER_CERT -CC -b $forestnc -s sub  objectclass=trustedDomain dn 2> /dev/null |sed ' /^ / {; H; d; }; /^ /! {; x; s/\\n //; }; '");
		foreach my $tdoobject (split('\n', $got_status[2])){
			chomp($tdoobject);
			if(grep(/dn:/, $tdoobject)){
				my $rdn_tdoobject=lc((split(/=/,(split(/,/,(split(/dn:\s+/, $tdoobject))[1]))[0]))[1]);
				my $dn_tdoobject=(split(/\s+/, $tdoobject))[1];
				my $domain_tdo_obj=(split(/System,/, $dn_tdoobject))[1];
				$domain_tdo_obj=~s/dc=//g;
				$domain_tdo_obj=~s/,/\./g;
				@got_status=EXEC_COMMAND(cmd=>"/opt/novell/xad/sbin/provision -q -l 10 --locate-dc $domain_tdo_obj");
				my $dc_tdo_obj_tmp=(grep(/DC:/, ($got_status[2])))[0];
				chomp($dc_tdo_obj_tmp);
				$dc_tdo_obj_tmp=~s/\s+//g;
				my $dc_tdo_obj=(split(/\\\\/, $dc_tdo_obj_tmp))[1];
				$dc_tdo_obj =~s/Address://g;
				if($domainfullname eq $rdn_tdoobject ){
					deleteIfObjectPresent($admin_name, $admin_passwd, $dc_tdo_obj, "$dn_tdoobject");
				}
			}
		}
	};

	if ($@) {
		Log(ERR, $@);
	}
}

# This subroutine get called specific for the child domain.
# It removes all objetcs present inside a child domain.
sub removeChildObjects
{
	my $admin_name = shift;
	my $admin_passwd = shift;
	my $installedMac=registry::getReg("Install_DCName");
	my $forestnc=registry::getReg("Forest NC");
	my $netbiosname=registry::getReg("Netbios Name");
	my $forest_nc_domain;
	eval{
		($forest_nc_domain=lc($forestnc))=~s/dc=//g;
		$forest_nc_domain=~s/,/\./g;
		@got_status=EXEC_COMMAND(cmd=>"/opt/novell/xad/sbin/provision -q -l 10 --locate-dc $forest_nc_domain");
		my $forestnc_dc_tmp=(grep(/DC:/, ($got_status[2])))[0];
		chomp($forestnc_dc_tmp);
		$forestnc_dc_tmp=~s/\s+//g;
		my $forestnc_dc=(split(/\\\\/, $forestnc_dc_tmp))[1];
		$forestnc_dc=~s/Address://g;
		deleteIfObjectPresent($admin_name, $admin_passwd, "$forestnc_dc", "cn=$netbiosname,cn=Partitions,$configurationldapname");
		deleteIfObjectPresent($admin_name, $admin_passwd, "$forestnc_dc", "CN=$installedMac,cn=Servers,cn=Default-First-Site-Name,cn=Sites,$configurationldapname");
	};

	if ($@) {
		Log(ERR, $@);
	}
}

# Clears all the domain service objects
sub deleteADObjects
{
	my $treeroot_ip = shift;
	my $admin_name = shift;
	my $admin_passwd = shift;
	my $mapped_domain_nc=registry::getReg("Mapped Domain NC");
	my $domainnc=registry::getReg("Domain NC");
	writeScreenAndLog ">>> Cleaning Domain Services objects";
	eval{
		if($child == 1){
			writeScreenAndLog ">>> Refreshing LDAP server";
			EXEC_COMMAND(cmd=>"$LDAPCONFIG -R -p $treeroot_ip --config-file /etc/opt/novell/eDirectory/nds.conf -t \"$treename\" -a \"$adminnamends\" -w \"$admin_passwd\"");
			sleep(30);
			deleteIfObjectPresent($admin_name, $admin_passwd, "$treeroot_ip", "$domainnc");
		}
		else{
			my $ad_objects=mktemp("/tmp/tmp.XXXXXXXX");
			open FH, ">$ad_objects" or die("Couldn't open file $ad_objects");
			print FH "cn=Builtin\ncn=Computers\ncn=Users\nou=Domain Controllers\ncn=DefaultMigrationContainer\ncn=Deleted Objects\ncn=ForeignSecurityPrincipals\ncn=Infrastructure\ncn=LostAndFound\ncn=Program Data\ncn=NTDS Quotas\ncn=Configuration\ncn=System\nou=OESSystemObjects";
			close(FH);

			open FH, "<$ad_objects" or die("Couldn't open file $ad_objects");
			while(my $adcontainer=<FH>){
				chomp($adcontainer);
				my $adcontainerdn="$adcontainer,$mapped_domain_nc";
				deleteIfObjectPresent($admin_name, $admin_passwd, "$treeroot_ip", "$adcontainerdn");
			}
			close(FH);
			unlink($ad_objects);
		}
	};

	if ($@) {
		Log(ERR, $@);
	}
}

# Clean all the domain's DNS entries
sub removeDomainDnsEntry
{
	my $treeroot_ip = shift;
	my $admin_name = shift;
	my $admin_passwd = shift;
	my $mapped_domain_nc=registry::getReg("Mapped Domain NC");
	eval{
		my $nds_domain_del_ldif=mktemp("/tmp/tmp.XXXXXXXX");
		open FH, ">$nds_domain_del_ldif" or die("Could not open $nds_domain_del_ldif");
		print FH "dn: $mapped_domain_nc \nchangetype: modify\ndelete: objectClass\nobjectClass: domainDNS";
		close(FH);
		EXEC_COMMAND(cmd=>"$LDAPMODIFY -h $treeroot_ip -D $admin_name -w $admin_passwd -e $SERVER_CERT -f $nds_domain_del_ldif");
		unlink($nds_domain_del_ldif );
	};

	if ($@) {
		Log(ERR, $@);
	}
}

# Cleaning a domain is specific to Name-Mapped and Non-Name-Mapped
# configuration. Further it get's divided into type of the server
# (frd/adc/child).
# It follows a sequence of activites to remove the complete domain.
# . Collect the credentials
# . Merge partiions and remove the objects
# . Remove the partion
# . Remove the DNS objects
# . Clean security objects
# . Stop all services of DSfW server
# . Validate the replica status for state, time sync etc.
# . Remove the eDirectory
# . Revert all the configuration files to original state
# . Delete all the left over objects related to DNS and DSfW
sub removeDomain
{
	my $treeroot_ip = shift;
	my $admin_name = shift;
	my $admin_passwd = shift;
	my $preferred_dns = shift;
	my $user_confirmation;
	my $mapped_domain_nc=registry::getReg("Mapped Domain NC");
	my $domainnc=registry::getReg("Domain NC");

	eval{
		# check if the domain being removed is a non-name mapped FRD
		until(defined($user_confirmation)){
			if( $frd == 1){
				# warn the users that all the containers/objects under domain would be deleted
				writeScreenAndLog ">>> WARNING: All objects present in the domain will be deleted. Do you wish to continue?[y/n]: ";
			}
			else{
				# warn user about the deletion of all users under cn=User container
				writeScreenAndLog ">>> WARNING: All objects present in the cn=Users,$domainnc (cn=Users,$mapped_domain_nc) container will be deleted. Do you wish to continue? [y/n]: ";
			}
			$user_confirmation=<STDIN>;
			chomp($user_confirmation);
		}

		if("$user_confirmation" eq "n" or  "$user_confirmation" eq "N"){
			# Aborting on user input
			exit(-1);
		}
		elsif("$user_confirmation" eq "y" or "$user_confirmation" eq "Y"){
		}
		else{
			# Invalid user input
			writeScreenAndLog ">>> Invalid user input. Exiting.";
			exit(-1);
		}

		if($nm_frd == 1 or $nm_child == 1 or $frd == 1 or $child == 1){
			removeExternalPartitions($admin_name, $admin_passwd);
		}

		if($nm_frd == 1 or $nm_child == 1){
			cleanDomainContainerAttributes();
		}

		if($frd != 1){
			if($nm_child != 1){
				mergePartitions($admin_name, $admin_passwd);
			}
			if($nm_child == 1 or $child == 1){
				removeTDO($admin_name, $admin_passwd);
				removeChildObjects($admin_name, $admin_passwd);
			}
			removeDNSObjects($treeroot_ip, $admin_name, $admin_passwd, $preferred_dns);
		}

		if($partial == 1){
			cleanSecurityObjects($admin_name, $admin_passwd);
		}

		$ENV{"ADM_PASSWD"}=$admin_passwd;
		StopServices();
		$ndsconfig_passed="true"; # Default value
		# Check the replica ring for its consistency before removing the eDirectory
		validateReplica($admin_passwd);
		my $rc=removeeDirectory();
		if($rc != 0){
			$ndsconfig_passed="false";
			promptUser();
		}
		delete $ENV{"ADM_PASSWD"};
		revertConfigFiles();
		# wait for 60 seconds before removing the left-over DSfW specific objects
		sleep(60);
		if($frd != 1){
			deleteADObjects($treeroot_ip, $admin_name, $admin_passwd);
		}

		if($nm_frd == 1 or $nm_child == 1){
			removeDomainDnsEntry($treeroot_ip, $admin_name, $admin_passwd);
		}
	};

	if ($@) {
		Log(ERR, $@);
	}
}

sub promptForDomainRemoval
{
	my $treeroot_ip = shift;
	my $admin_name = shift;
	my $admin_passwd = shift;
	my $preferred_dns = shift;
	my $user_confirmation;
	my $domainfullname=registry::getReg("DNS Root");
	# Child Domains do not exist

	eval{
		until(defined($user_confirmation)){
			writeScreenAndLog ">>> The server '$servername' is the only domain controller residing in '$domainfullname'. Removing this server will remove the domain '$domainfullname'. Are you sure you want to remove it? [y/n] ";
			$user_confirmation=<STDIN>;
			chomp($user_confirmation);
		}

		if("$user_confirmation" eq "y" or "$user_confirmation" eq "Y"){
			removeDomain($treeroot_ip, $admin_name, $admin_passwd, $preferred_dns);
		}
		elsif("$user_confirmation" eq "n" or  "$user_confirmation" eq "N"){
			# Aborting on user input
			exit(-1);
		}
		else{
			writeScreenAndLog ">>> Invalid user input. Exiting.";
			exit(-1);
		}
	};

	if ($@) {
		Log(ERR, $@);
	}
}

# Removes ADC in a Domain
sub removeADC
{
	my $treeroot_ip = shift;
	my $admin_name = shift;
	my $admin_passwd = shift;
	my $preferred_dns = shift;

	eval{
		removeDCObjects($admin_name, $admin_passwd);
		removeDNSObjects($treeroot_ip, $admin_name, $admin_passwd, $preferred_dns);
		cleanSecurityObjects($admin_name, $admin_passwd);
		$ENV{"ADM_PASSWD"}=$admin_passwd;
		StopServices();
		$ndsconfig_passed="true"; # Default value
		# Check the replica ring for its consistency before removing the eDirectory
		validateReplica($admin_passwd);
		my $rc=removeeDirectory();
		if($rc != 0){
			$ndsconfig_passed="false";
			promptUser();
		}
		delete $ENV{'ADM_PASSWD'};
		revertConfigFiles();
		@got_status = EXEC_COMMAND(cmd=>"/bin/hostname");
		my $hostname=lc($got_status[2]);
		chomp($hostname);
		deleteIfObjectPresent($admin_name, $admin_passwd, "$treeroot_ip", "cn=OESCommonproxy_$hostname,".$ENV{"LDAPTEMPCONTAINER"});
	};

	if ($@) {
		Log(ERR, $@);
	}
}

#Check whether the DC is a DNS master or not, also checks
#for the ADPH Master role player. if this server is a ADPH
#Master role player suggest to tarnsfer the role to another
#DC before removing this server.
sub dcrmCheck
{
	my $treeroot_ip = shift;
	my $admin_name = shift;
	my $admin_passwd = shift;
	my $preferred_dns = shift;
	my $dnsRoot=registry::getReg("DNS Root");
	my $domainfullname=registry::getReg("DNS Root");
	my $user_confirmation;
	my $domainnc=registry::getReg("Domain NC");
	my $defaultrootdomain=lc(registry::getReg("Mapped Domain NC"));

	eval{
		# Checking for other Domain Controllers in the Domain
		@got_status=EXEC_COMMAND(cmd=>"$LDAPSEARCH -D $admin_name -w $admin_passwd -b \"$dcfullname\" -s one cn  -e $SERVER_CERT 2>/dev/null | sed ' /^ / {; H; d; }; /^ /! {; x; s/\\n //; }; ' | grep -i \"cn: \" | awk -F \": \" '{print \$2}' | grep -v -x -i \"$servername\" >/dev/null");
		if($got_status[0] == 0){
			if($partial != 1){
				@got_status=EXEC_COMMAND(cmd=>"$LDAPSEARCH -D $admin_name -w $admin_passwd -b \"$domainnc\" -s sub \"(ObjectClass=DNIPDNSServer)\" dn -e $SERVER_CERT -LLL 2>/dev/null | sed ' /^ / {; H; d; }; /^ /! {; x; s/\\n //; }; ' | awk -F \": \" '{print \$2}'| grep -v -i \"$servername\"");
				my $dnsmaster_other=$got_status[2];
				chomp($dnsmaster_other);
				if($? != 0){
					writeScreenAndLog ">>> This server, '$servername', is the only DNS master for this Domain. Before removing $servername.$dnsRoot, add another DNS Server for the proper functioning of this Domain. If you intend to remove whole domain, remove ADCs first.";
					exit(-1);
				}
				@got_status=EXEC_COMMAND(cmd=>"$LDAPSEARCH -D $admin_name -w $admin_passwd -e $SERVER_CERT  -b \"$ridmanagerfullname\" 2>/dev/null | sed ' /^ / {; H; d; }; /^ /! {; x; s/\\n //; }; ' | grep -i \"fSMORoleOwner: \" | awk -F \": \" '{print \$2}' | awk -F \",\" '{print \$2}' | awk -F \"cn=\" '{print \$2}' | tr \"[:upper:]\" \"[:lower:]\"");
				my $adphmaster=$got_status[2];
				chomp($adphmaster);
				if($debug_info == 1 ){
					writeScreenAndLog "adphmaster=$adphmaster";
					writeScreenAndLog "servername=$servername";
				}

				if("$adphmaster" eq "$servername"){
					# This server plays the role of ADPH master. This Domain Controller should not be removed
					writeScreenAndLog ">>> The server '$servername' has the ADPH master role. Transfer the ADPH master role to any other domain controller in the domain before removing the server.";
					exit(-1);
				}

				# This Domain Controller is not playing ADPH Master role
				# Checking for Configuration/Schema partition's replica
				my $dclist=mktemp("/tmp/dclist.XXXXXXXX");
				my $config_nc=0;
				EXEC_COMMAND(cmd=>"$LDAPSEARCH -D $admin_name -w $admin_passwd -e $SERVER_CERT -s one -b \"ou=Domain Controllers,$defaultrootdomain\" dn -LLL | sed ' /^ / {; H; d; }; /^ /! {; x; s/\\n //; }; ' >$dclist");
				open(FH, "<$dclist") || die "Could not open $dclist";
				while((my $dcObject=<FH>)){
					chomp($dcObject);
					if(grep(/dn:/, $dcObject)){
						my $dcName=lc((split(/=/,(split(/,/,(split(/dn:\s+/, $dcObject))[1]))[0]))[1]);
						if($dcName ne $servername){
							@got_status=EXEC_COMMAND(cmd=>"$NDSSTAT -n -p \".$configurationndsname.T=$treename.\" --config-file /etc/opt/novell/eDirectory/conf/nds.conf | grep -i \"\.CN=$dcName\.\" >/dev/null");
							if($got_status[0] == 0){
								@got_status=EXEC_COMMAND(cmd=>"ndsstat -p \".$configurationndsname.T=$treename.\" --config-file /etc/opt/novell/eDirectory/conf/nds.conf");
								my $replicaType=(split(/\s+/, (grep(/.CN=$dcName./i, $got_status[2]))[0]))[1];
								chomp($replicaType);
								if($replicaType eq "Subordinate" ){
									next;
								}
								$config_nc=1;
							}
						}
					}
				}
				close(FH);

				if($config_nc == 0){
					writeScreenAndLog ">>> The server '$servername' holds the only replica of configuration partition. Relocate the replica to any other domain controller before removing the server.";
					exit(-1);
				}
				my $schema_nc=0;
				open(FH, "<$dclist") || die "Could not open $dclist";
				while(my $dcObject=<FH>){
					chomp($dcObject);
					if(grep(/dn:/, $dcObject)){
						my $dcName=lc((split(/=/,(split(/,/,(split(/dn:\s+/, $dcObject))[1]))[0]))[1]);
						if($dcName ne $servername){
							@got_status=EXEC_COMMAND(cmd=>"$NDSSTAT -n -p \".$schemandsname.T=$treename.\"  --config-file /etc/opt/novell/eDirectory/conf/nds.conf |grep -i \"\.CN=$dcName\.\" > /dev/null");
							if( $got_status[0] == 0 ){
								@got_status=EXEC_COMMAND(cmd=>"ndsstat -p \".$configurationndsname.T=$treename.\" --config-file /etc/opt/novell/eDirectory/conf/nds.conf");
								my $replicaType=(split(/\s+/, (grep(/.CN=$dcName./i, $got_status[2]))[0]))[1];
								chomp($replicaType);
								if($replicaType eq "Subordinate" ){
									next;
								}
								$schema_nc=1;
							}
						}
					}
				}
				close(FH);
				unlink($dclist);

				if($schema_nc == 0){
					writeScreenAndLog ">>> The server '$servername' holds the only replica of schema partition. Relocate the replica to any other domain controller before removing the server.";
					exit(-1);
				}

				until(defined($user_confirmation)){
					writeScreenAndLog ">>> The server '$servername' is a domain controller hosting '$domainfullname'. Are you sure you want to remove it? [y/n] ";
					$user_confirmation=<STDIN>;
					chomp($user_confirmation);
				}
				if("$user_confirmation" eq "y" || "$user_confirmation" eq "Y"){
					removeADC($treeroot_ip, $admin_name, $admin_passwd, $preferred_dns);
				}
				elsif("$user_confirmation" eq "n" || "$user_confirmation" eq "N"){
					# Aborting on user input
					exit(-1);
				}
				else{
					writeScreenAndLog ">>> Invalid user input. Exiting.";
					exit(-1);
				}
			}
			else{
				removeADC($treeroot_ip, $admin_name, $admin_passwd, $preferred_dns);
			}
		}
		else{
			# This is the last Domain Controller in the domain, so lets check the trust existence, if any.
			# Ignoring the trust to the parent domain in search.
			my @got_status=EXEC_COMMAND(cmd=>"$LDAPSEARCH -D $admin_name -w $admin_passwd -e $SERVER_CERT -b \"$defaultrootdomain\" '(&(objectClass=trustedDomain)(!(trustAttributes:1.2.840.113556.1.4.803:=4194304)))' dn 2>/dev/null | sed ' /^ / {; H; d; }; /^ /! {; x; s/\\n //; }; ' | grep  \"dn: \" | cut -d \" \" -f2");
			my $tdo_obj_dn_list=$got_status[2];
			chomp($tdo_obj_dn_list);
			if($got_status[0] == 0){
				@got_status=EXEC_COMMAND(cmd=>"echo $tdo_obj_dn_list | grep -ic \"$domainfullname\"");
				if($got_status[2] != 0 ){
					# List down the Trust Partners of following trust types
					# Parent-Child Trust with Child Domains.
					writeScreenAndLog ">>> The domain has following Child Domain/s. Remove them before removing this server.";
					@got_status=EXEC_COMMAND(cmd=>"echo \"$tdo_obj_dn_list\" | grep -i \"$domainfullname\"");
					writeScreenAndLog "$got_status[2]";
					exit(-1);
				}
				# List down the Trust Partners of following trust types
				# Cross Forest Trust OR External Trust OR Shortcut Trust.
				if($tdo_obj_dn_list ne ""){
					writeScreenAndLog ">>> The domain has a trust relationship with following domain/s. Remove the trust/s before removing this server.";
					writeScreenAndLog "$tdo_obj_dn_list";
					until(defined($user_confirmation)){
						writeScreenAndLog ">>> Do you still wish to continue? [y/n] ";
						$user_confirmation=<STDIN>;
						chomp($user_confirmation);
					}
					if($user_confirmation eq "y" || $user_confirmation eq "Y"){
						writeScreenAndLog ">>> WARNING: This domain is trusted by one or more domains. To avoid inconsistency, the administrator of those domains must remove all trusts with this domain, using the Microsoft Management Console (MMC).";
						promptForDomainRemoval($treeroot_ip, $admin_name, $admin_passwd, $preferred_dns);
					}
					# Aborting on user input
					elsif($user_confirmation eq "n" || "$user_confirmation" eq "N"){
						exit(-1);
					}
					# Invalid User Input. Exiting.
					else{
						writeScreenAndLog ">>> Invalid user input. Exiting.";
						exit(-1);
					}
				}
				# Warn for the Trust Partners of following trust types
				# Parent-Child Trust with Parent Domain.
				if($frd != 1 || $nm_frd != 1){
					writeScreenAndLog ">>> WARNING: The domain has parent-child trust with its parent domain. The administrator of parent domain must remove this trust using the Microsoft Management Console (MMC).";
				}
				promptForDomainRemoval($treeroot_ip, $admin_name, $admin_passwd, $preferred_dns);
			}
		}
	};

	if ($@) {
		Log(ERR, $@);
	}
}

# Collects the creadentials specific to the server
# , if not provided at the command line.
sub promptForAdminCredentials
{
	my $treeroot_ip = shift;
	my $admin_name = shift;
	my $admin_passwd = shift;
	my $preferred_dns = shift;
	my $error;
	my $ipaddress=registry::getReg("IP Address");
	my $domainfullname=registry::getReg("DNS Root");
	my $library_path = "LD_LIBRARY_PATH=\"/opt/novell/eDirectory/lib:/opt/novell/eDirectory/lib/nds-modules:".(defined $ENV{'LD_LIBRARY_PATH'}? $ENV{'LD_LIBRARY_PATH'} : "")."\"";
	my $retVal=0; #Return Value default set to Successful

	eval{
		if(!defined(${$treeroot_ip})){
			if($nm_frd == 1 || $nm_adc == 1){
				until(defined(${$treeroot_ip})){
					print STDERR "\n>>> Enter existing eDirectory server's IP address: ";
					${$treeroot_ip}=<STDIN>;
					chomp(${$treeroot_ip});
				}
			}
			elsif($frd == 1){
				until(defined(${$treeroot_ip})){
					print STDERR "\n>>> Enter IP address of the domain controller of forest root domain: ";
					${$treeroot_ip}=<STDIN>;
					chomp(${$treeroot_ip});
				}
			}
			elsif($adc == 1){
				until(defined(${$treeroot_ip})){
					print STDERR "\n>>> Enter IP address of another domain controller for the domain '$domainfullname': ";
					${$treeroot_ip}=<STDIN>;
					chomp(${$treeroot_ip});
				}
			}
			else{
				until(defined(${$treeroot_ip})){
					print STDERR "\n>>> Enter IP address of the domain controller of the immediate parent domain: ";
					${$treeroot_ip}=<STDIN>;
					chomp(${$treeroot_ip});
				}
			}
		}

		$error = helpers::validateIP(${$treeroot_ip});
		if ($error) {
			helpers::logWrite(1, "The IP Address supplied is not proper. [${$treeroot_ip}]. <$error>");
			$retVal=90;
		}

		if(!defined(${$treeroot_ip})){
			writeScreenAndLog ">>> IP address must be specified.";
			exit(3);
		}

		if(!defined(${$admin_name})){
			if($nm_child == 1 || $nm_frd == 1 || $nm_adc == 1 ){
				until(defined(${$admin_name})){
					print STDERR "\n>>> Enter existing tree administrator's typed FDN [cn=admin,o=foo]: ";
					${$admin_name}=<STDIN>;
					chomp(${$admin_name});
				}
			}
			else{
				until(defined(${$admin_name})){
					print STDERR "\n>>> Enter forest root domain administrator's typed FDN [cn=administrator,cn=users,dc=example,dc=com]: ";
					${$admin_name}=<STDIN>;
					chomp(${$admin_name});
				}
			}
		}

		if(!defined(${$admin_name})){
			writeScreenAndLog ">>> Existing administrator name must be specified.";
			exit(3);
		}

		if(!defined(${$admin_passwd})){
			if($nm_child == 1 || $nm_frd == 1 || $nm_adc == 1){
				until(defined(${$admin_passwd})){
					print STDERR "\n>>> Enter existing tree administrator password: ";
					ReadMode 'noecho';
					${$admin_passwd}=<STDIN>;
					chomp(${$admin_passwd});
					ReadMode 'normal';
				}
			}
			else{
				until(defined(${$admin_passwd})){
					print STDERR "\n>>> Enter forest root domain administrator's password: ";
					ReadMode 'noecho';
					${$admin_passwd}=<STDIN>;
					chomp(${$admin_passwd});
					ReadMode 'normal';
				}
			}
		}

		if(!defined(${$admin_passwd})){
			writeScreenAndLog ">>> Existing administrator password must be specified.";
			exit(3);
		}

		if (!defined($dcadminname) || !defined($dcadminpasswd) && ( $nm_adc != 1 and $adc != 1 )){
			if(defined($provisoned) and $provisoned eq 'YES'){
				if(!defined($dcadminname)){
					@got_status = EXEC_COMMAND(cmd=>"/opt/novell/xad/share/dcinit/provisionTools.sh get-admin-name");
					$dcadminname = $got_status[2];
					chomp($dcadminname);
				}
			}
			until(defined($dcadminname)){
				print STDERR "\n>>> Enter this domain administrator's typed FDN [cn=administrator,cn=users,dc=example,dc=com]: ";
				$dcadminname=<STDIN>;
				chomp($dcadminname);
			}

			until(defined($dcadminpasswd)){
				print STDERR "\n>>> Enter ${dcadminname}'s password: ";
				ReadMode 'noecho';
				$dcadminpasswd=<STDIN>;
				chomp($dcadminpasswd);
				ReadMode 'normal';
			}

			if(!defined($dcadminname) || !defined($dcadminpasswd)){
				writeScreenAndLog ">>> Existing administrator name and password must be specified.";
				exit(3);
			}
		}
		print "\n";

		if(!defined(${$preferred_dns})){
			until(defined(${$preferred_dns})){
				print STDERR "\n>>> Enter the IP address of the preferred DNS server: ";
				${$preferred_dns}=<STDIN>;
				chomp(${$preferred_dns});
			}
		}

		if(!defined(${$preferred_dns})){
			writeScreenAndLog ">>>IP address of preferred DNS server must be specified.";
			exit(3);
		}

		($adminnamends=${$admin_name})=~s/,/\./g;

		EXEC_COMMAND(cmd=>"$library_path \"$GETCERT_COMMAND\" -a $ipaddress -t $treename -u \"$adminnamends\" -x \"${$admin_passwd}\"");
		if(! -f "$SERVER_CERT"){
			writeScreenAndLog ">>> Unable to retrieve CA certificate. Exiting.";
			exit(-1);
		}
	};

	if ($@) {
		Log(ERR, $@);
	}

	return $retVal;
}

# Removes configuration files associated with DSfW server
sub removeFiles{
	my $file;
	my $nds_conf_file = "/etc/opt/novell/eDirectory/conf/nds.conf";
	my $resolv_conf = "/etc/resolv.conf";
	my $proxy_users = "/etc/opt/novell/proxymgmt/proxy_users.conf";
	my $host_ip = `hostname -i`;

	chomp($host_ip);

	eval{
		my @remove_files=("/var/opt/novell/xad/run/rpcdep.dat",
			"/opt/novell/oes-install/xad_provisioned",
			"/etc/xdg/autostart/start-xad-provisioning.desktop",
			"/etc/opt/novell/xad/gss/mech",
			"/etc/opt/novell/certs/SSCert.pem",
			"/etc/opt/novell/certs/SSCert.der");

		if(-e $proxy_users) {
			EXEC_COMMAND(cmd=>"sed -in '/.*OESCommonProxy*/d' $proxy_users");
		}
		if(-e $nds_conf_file) {
			EXEC_COMMAND(cmd=>"sed -in '/.*n4u.server.log-file=.*/d' $nds_conf_file");
		}

		if(-e $resolv_conf){
			open(FH, "<$resolv_conf") or die("Could not open file $resolv_conf");
			my @output=<FH>;
			close(FH);

			if(grep(/$host_ip/, @output)){
				EXEC_COMMAND(cmd=>"sed -in '/.*nameserver.*$host_ip.*/d' $resolv_conf");
			}
		}

		# Cleaning up files
		foreach $file (@remove_files){
			if(-f $file){
				unlink($file);
			}
		}

		my @modify_files=("/etc/sysconfig/novell/xad_oes11_sp1",
			"/etc/sysconfig/novell/xad2_oes11",
			"/etc/sysconfig/novell/xad2_sp3",
			"/etc/sysconfig/novell/xad2_sp2",
			"/etc/sysconfig/novell/NvlDns_oes11_sp1",
			"/etc/sysconfig/novell/NvlDns2_oes11",
			"/etc/sysconfig/novell/NvlDns2_sp3",
			"/etc/sysconfig/novell/NvlDns2_sp2");

		foreach $file (@modify_files){
			if(-f $file and grep(/_sp2/, $file)){
				my $temp_file=mktemp("/tmp/temp.XXXXXXXX");
				EXEC_COMMAND(cmd=>"sed -e 's/^SERVICE_CONFIGURED=\"yes\"/SERVICE_CONFIGURED=\"no\"/g' $file > $temp_file");
				move($temp_file, $file);
				unlink($temp_file);
			}
			elsif(-f $file){
				EXEC_COMMAND(cmd=>"sed -ie 's/^SERVICE_CONFIGURED=\"yes\"/SERVICE_CONFIGURED=\"no\"/g' $file");
			}
		}

		if( -f "/etc/sysconfig/novell/oes-ldap"){
			EXEC_COMMAND(cmd=>"sed 's/^CONFIG_LDAP_ADMIN_CONTEXT=.*/CONFIG_LDAP_ADMIN_CONTEXT=\"\"/g' /etc/sysconfig/novell/oes-ldap > /tmp/temp");
			EXEC_COMMAND(cmd=>"sed 's/^XAD_TREE_ADMIN_CONTEXT=.*/XAD_TREE_ADMIN_CONTEXT=\"\"/g' /tmp/temp > /etc/sysconfig/novell/oes-ldap");
		}

		my @directories_to_remove=(registry::getReg("STAGEDIR"),
			registry::getReg("LIVE_LOCALSTATEDIR"),
			"/etc/opt/novell/xad/openldap");
		#May be possible that partial install did not cleanup the staging dirs
		foreach $file (@directories_to_remove){
			if(-e $file){
				EXEC_COMMAND(cmd=>"rm -rf $file");
			}
		}

		#Create The krbcore directory in /etc/opt/novell/xad/
		my @directories_to_add=("/var/opt/novell/xad/krbcore/kpasswdd",
			"/var/opt/novell/xad/krbcore/krb5kdc");
		foreach $file (@directories_to_add){
			if(! -e $file){
				EXEC_COMMAND(cmd=>"mkdir -p $file");
			}
		}

		my @modify_edir_files=("/etc/sysconfig/novell/edir_oes11_sp1",
			"/etc/sysconfig/novell/edir2_oes11",
			"/etc/sysconfig/novell/edir2_sp3",
			"/etc/sysconfig/novell/edir2_sp2");
		if($ndsconfig_passed eq "true" and $all_objects_removal_passed == 1){
			foreach $file (@modify_edir_files){
				if(-f $file){
					my $temp_file=mktemp("/tmp/temp.XXXXXXXX");
					EXEC_COMMAND(cmd=>"sed -e 's/^SERVICE_CONFIGURED=\"yes\"/SERVICE_CONFIGURED=\"no\"/g' $file > $temp_file");
					move($temp_file, $file);
					unlink($temp_file);
				}
			}
			writeScreenAndLog ">>> Domain Services for Windows server removed successfully";
		}
		else{
			writeScreenAndLog ">>> Domain Services for Windows server removal failed";
			exit(1);
		}
	};

	if ($@) {
		Log(ERR, $@);
	}
}

# Main subroutine accepts input arguments like tree root
# ip, admin name, admin password, preferred DNS etc. at
# command line and passes the arguments to different
# subroutines to complete the removal of DC.
sub main{
	my %options=();
	my ($treeroot_ip,$admin_name, $admin_passwd, $preferred_dns);

	initLog();
	writeLog "Starting ndsdcrm";
	if(!defined(getUserInfo('u'))){
		exit(1);
	}

	getopts("p:a:w:o:hfd", \%options) or croak("Unexpected arguments");
	$treeroot_ip = $options{p} if defined $options{p};
	$admin_name = $options{a} if defined $options{a};
	$admin_passwd = $options{w} if defined $options{w};
	$preferred_dns = $options{o} if defined $options{o};
	$partial = defined $options{f}? 1:0;
	$debug_info = defined $options{d}? 1:0;
	printUsage() if defined($options{h}); # Un expected arguments

	#Input options are treeroot, tree admin, tree admin passwd and partial
	writeScreenAndLog "-----------------------------------------------------------------";
	writeScreenAndLog "Deconfiguration utility for Domain Services for Windows 2.0";
	writeScreenAndLog "Supports OES2SP3, OES11 and OES11 SP1";
	writeScreenAndLog "-----------------------------------------------------------------";
	#Default values
	$frd=$child=$adc=$nm_frd=$nm_child=$nm_adc=0;
	$object_removal_passed=1;

	checkForServer();

	if (registry::getReg("IS_REPLICA") ne "TRUE"){
		analyzeScenario();
	}
	else{
		if(registry::getReg("Domain NC") eq registry::getReg("Mapped Domain NC")){
			$adc=1;
		}
		else{
			$nm_adc=1;
		}

	}

	writeLog "DC server : $frd:$nm_frd:$child:$nm_child:$adc:$nm_adc";

	if($partial == 1){
		writeScreenAndLog "Forcing the removal";
	}
	@got_status=EXEC_COMMAND(cmd=>"/opt/novell/xad/share/dcinit/ndsConfigGet.sh \"n4u.base.tree-name\"");
	$treename=$got_status[2];
	chomp($treename);

	@got_status=EXEC_COMMAND(cmd=>"/opt/novell/xad/share/dcinit/printConfigKey.pl \"PROVISIONED\"");
	$provisoned=$got_status[2];
	chomp($provisoned);
	if(defined($provisoned) and $provisoned eq 'YES'){
		if(!defined($admin_name)){
			@got_status = EXEC_COMMAND(cmd=>"/opt/novell/xad/share/dcinit/printConfigKey.pl \"NDSEXISTINGADMINNAME\"");
			$admin_name = $got_status[2];
			$admin_name =~ s/\./,/g;
			chomp($admin_name);
		}

		if(!defined($preferred_dns)){
			@got_status = EXEC_COMMAND(cmd=>"/opt/novell/xad/share/dcinit/printConfigKey.pl \"DNS_SERVER_IP\"");
			$preferred_dns = $got_status[2];
			chomp($preferred_dns);
		}

	}

	promptForAdminCredentials(\$treeroot_ip, \$admin_name, \$admin_passwd, \$preferred_dns);
	ComputeVariables($treeroot_ip, $admin_name, $admin_passwd);
	validateReplica($admin_passwd);
	validateInputs($treeroot_ip, $admin_name, $admin_passwd);
	dcrmCheck($treeroot_ip, $admin_name, $admin_passwd, $preferred_dns);
	removeFiles();
}

main;
