#!/usr/bin/env perl
# BEGIN COPYRIGHT BLOCK
# 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; version 2 of the License.
#
# 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.
#
# In addition, as a special exception, Red Hat, Inc. gives You the additional
# right to link the code of this Program with code not covered under the GNU
# General Public License ("Non-GPL Code") and to distribute linked combinations
# including the two, subject to the limitations in this paragraph. Non-GPL Code
# permitted under this exception must only link to the code of this Program
# through those well defined interfaces identified in the file named EXCEPTION
# found in the source code files (the "Approved Interfaces"). The files of
# Non-GPL Code may instantiate templates or use macros or inline functions from
# the Approved Interfaces without causing the resulting work to be covered by
# the GNU General Public License. Only Red Hat, Inc. may make changes or
# additions to the list of Approved Interfaces. You must obey the GNU General
# Public License in all respects for all of the Program code and other code used
# in conjunction with the Program except the Non-GPL Code covered by this
# exception. If you modify this file, you may extend this exception to your
# version of the file, but you are not obligated to do so. If you do not wish to
# provide this exception without modification, you must delete this exception
# statement from your version and license this file solely under the GPL without
# exception.
#
#
# Copyright (C) 2007 Red Hat, Inc.
# All rights reserved.
# END COPYRIGHT BLOCK
#

use lib qw(/usr/lib/x86_64-linux-gnu/dirsrv/perl);

use strict;

use File::Basename;
use Sys::Hostname;

# Admin Setup modules
use AdminUtil;
use AdminServer;

# Directory Setup modules
use Resource;
use Setup;
use SetupLog;
use DialogManager;
use Inf;
use DSUtil;

sub reg_get_passwd
{
    my $setup = shift;
    my $key = shift;
    my $value0 = shift;
    my $value1 = shift;
    my $value2 = shift;

    if ( ! $value2 )
    {
        print("\n==============================================================================\n");
    }
    if ( $value1 )
    {
        $setup->msg(0, $key, $value0, $value1);
    }
    elsif ( $value0 )
    {
        $setup->msg(0, $key, $value0);
    }
    else
    {
        $setup->msg(0, $key);
    }
    system("stty -echo");
    my $answer = <STDIN>;
    system("stty echo");
    print "\n";
    chop($answer);
    return $answer;
}

sub reg_get_response
{
    my $setup = shift;
    my $key = shift;
    my $value = shift;

    print("\n==============================================================================\n");
    $setup->msg(0, $key, $value);
    my $answer = <STDIN>;
    print "\n";
    chop($answer);
    return $answer;
}

#
# Return the bind dn and password for the matching instance (slapd-localhost)
# Used by silent install
#
sub get_cred_from_inst
{
    my $mysetup = shift;
    my $serverid = shift;

    #
    # Check the main config instance first
    #
    my @config_parts = split('::', $mysetup->{inf}->{register}->{configinst});
    if ($#config_parts == 2 && $config_parts[0] eq $serverid){
        return ( $config_parts[1], $config_parts[2] );
    }

    #
    # Check the remaining instances
    #
    my @insts = $mysetup->{inf}->{register}->{instance};
    if ($#insts){
        my $i = 0;
        for (; $i <= $#insts; $i++){
            my @inst_parts = split('::', $insts[$i]);
            if($#inst_parts == 2 && $inst_parts[0] eq $serverid){
                return ( $inst_parts[1], $inst_parts[2] );
            }
        }
    }
    return ("", "");
}

#
# Globals
#
my $silent = "no";
my $remote_host = "";
my $remote_port = "";
my $local_certdir = "";
my $remote_binddn = "";
my $remote_bindpw = "";
my $remote_admindomain = "";
my $localrootdn = "";
my $localrootpw = "";
my $destination = "";  # remote | local
my %instances = ();
my $instconfigdir;
my @instconfigdirs;
my $ans;
my $passwd;
my $rootdn;
my $fqdn = hostname();
my $dialogmgr;
my @dialogs;
my @silent_instances;
my @config_parts;

#
# Continue with the setup...
#

my $res = new Resource("/usr/share/dirsrv/properties/register-ds-admin.res",
                       "/usr/share/dirsrv/properties/setup-ds-admin.res",
                       "/usr/share/dirsrv/properties/setup-ds.res");

#
# Initialize the "setup", check for silent install
#
my $setup = new Setup($res);
if ($setup->{silent}){
    #
    # To be silent we must have "General" & "admin", or just "register" directives
    #
    if ( ($setup->{inf}->{General} && $setup->{inf}->{admin}) || $setup->{inf}->{register} ){
        $silent = "yes";
    } else {
        # Missing required silent install directives
        $setup->msg($FATAL, 'error_silent_install');
        $setup->doExit(1);
    }
}

$instconfigdir = $setup->{configdir};

if ($setup->{inf}->{register}){
    #
    # We have our remote registration silent install info
    #
    # [register]
    # configinst= slapd-INSTANCE::cn=directory manager::myPassword
    # instance= slapd-INSTANCE2::cn=directory manager::myPassword
    # instance= slapd-INSTANCE3::cn=directory manager::myPassword
    # remotehost= remote.server.com
    # remoteport= 389
    # localcertdir= /etc/dirsrv/slapd-INSTANCE
    # remotebinddn= cn=directory manager
    # remotebindpw= password
    # admindn= uid=admin,ou=Administrators,ou=TopologyManagement,o=NetscapeRoot
    # adminpw= password
    # admindomain= server.com
    # destination= local|remote
    #

    # 
    # Validate the silent registration parameters
    #
    if ( !$setup->{inf}->{register}->{configinst} || $setup->{inf}->{register}->{configinst} eq ""){
        $setup->msg($FATAL, 'error_missing_parameter', "configinst");
        $setup->doExit(1);
    }
    if ( !$setup->{inf}->{register}->{remotehost} || $setup->{inf}->{register}->{remotehost} eq ""){
        $setup->msg($FATAL, 'error_missing_parameter', 'remotehost');
        $setup->doExit(1);
    }
    if ( !$setup->{inf}->{register}->{remoteport} ||$setup->{inf}->{register}->{remoteport} eq ""){
        $setup->msg($FATAL, 'error_missing_parameter', 'remoteport');
        $setup->doExit(1);
    }
    if ( !$setup->{inf}->{register}->{remotebinddn} || $setup->{inf}->{register}->{remotebinddn} eq ""){
        $setup->msg($FATAL, 'error_missing_parameter', 'remotebinddn');
        $setup->doExit(1);
    }
    if ( !$setup->{inf}->{register}->{remotebindpw} || $setup->{inf}->{register}->{remotebindpw} eq ""){
        $setup->msg($FATAL, 'error_missing_parameter', 'remotebindpw');
        $setup->doExit(1);
    }
    if ( !$setup->{inf}->{register}->{admindomain} || $setup->{inf}->{register}->{admindomain} eq ""){
        $setup->msg($FATAL, 'error_missing_parameter', 'admindomain');
        $setup->doExit(1);
    }
    if ( !$setup->{inf}->{register}->{admindn} || $setup->{inf}->{register}->{admindn} eq ""){
        $setup->msg($FATAL, 'error_missing_parameter', 'admindn');
        $setup->doExit(1);
    }
    if ( !$setup->{inf}->{register}->{adminpw} || $setup->{inf}->{register}->{adminpw} eq ""){
        $setup->msg($FATAL, 'error_missing_parameter', 'adminpw');
        $setup->doExit(1);
    }
    if ( !$setup->{inf}->{register}->{destination} || $setup->{inf}->{register}->{destination} eq ""){
        $setup->msg($FATAL, 'error_missing_parameter', 'destination');
        $setup->doExit(1);
    }

    #
    # Add the configuration instance to the global instance hash
    #
    @config_parts = split('::', $setup->{inf}->{register}->{configinst});
    if($#config_parts < 2 || $#config_parts > 2){
        $setup->msg($FATAL, 'error_invalid_parameter', " ($#config_parts configinst: $setup->{inf}->{register}->{configinst}");
        $setup->doExit(1);
    }

    if ( -d "$setup->{configdir}/$config_parts[0]"){
        push @{$instances{$setup->{configdir}}}, $config_parts[0];
    } else {
        # config instance not found
        $setup->msg($FATAL, 'error_invalid_parameter', "configinst: $setup->{configdir}/$config_parts[0] does not exist");
        $setup->doExit(1);
    }

    #
    # Add the other instances (if any)
    #
    @silent_instances = $setup->{inf}->{register}->{instance};
    if ($#silent_instances){
        my $i = 0;
        for (; $i <= $#silent_instances; $i++){
            my @inst_parts = split('::', $silent_instances[$i]);
            if($#inst_parts < 2 || $#inst_parts > 2){
                $setup->msg($FATAL, 'error_invalid_parameter', "instance: $silent_instances[$i]");
                $setup->doExit(1);
            }
            push @{$instances{$setup->{configdir}}}, $inst_parts[0];
        }
    }

    #
    # Fill the setup parameters
    #
    $setup->{inf}->{slapd}->{RootDN} = $config_parts[1];
    $setup->{inf}->{slapd}->{RootDNPwd} = $config_parts[2];

    #
    # Set the remote registration parameters
    #
    $remote_host = $setup->{inf}->{register}->{remotehost};
    $remote_port = $setup->{inf}->{register}->{remoteport};
    $remote_binddn = $setup->{inf}->{register}->{remotebinddn};
    $remote_bindpw = $setup->{inf}->{register}->{remotebindpw};
    $local_certdir = $setup->{inf}->{register}->{localcertdir};
    $remote_admindomain = $setup->{inf}->{register}->{admindomain};
    $destination = $setup->{inf}->{register}->{destination};
    $localrootdn = $config_parts[1];
    $localrootpw = $config_parts[2];
}

#
# Get existing instances (interactive mode)
#
$setup->msg('begin_ds_registration');
if($silent eq "no"){
    for my $dir (glob("$setup->{configdir}/slapd-*"))
    {
        if (-d $dir and ($dir !~ /\.removed$/)){
            my $dname = dirname($dir);
            my $bname = basename($dir);
            push @{$instances{$dname}}, $bname;
        }
    }
}

#
# In case Directory Servers are installed at the unexpected location. (interactive mode)
#
if ( $silent eq "no"){
    my $done = 0;
    while ( !$done && ($ans =  reg_get_response($setup, 'subds_conf_prompt', "/etc/dirsrv")) )
    {
        if ( $ans eq "" || !$ans ){
            $done = 1;
        } elsif ( ! -d $ans ){
            ;
        } elsif ( (basename($ans) =~ /^slapd-/) and ($ans !~ /\.removed$/) ){
            my $dname = dirname($ans);
            my $bname = basename($ans);
            if ( exists $instances{$dname} ){
                my $addit = 1;
                foreach my $thisslapd ( @{$instances{$dname}} )
                {
                    if ( $thisslapd eq $bname ){
                        $addit = 0;
                        goto out0;
                    }
                }
out0:
                if ( $addit ){
                    push @{$instances{$dname}}, $bname;
                }
            } else {
                push @{$instances{$dname}}, $bname;
            }
        } else {
            $ans =~ s/^\s+//;
            $ans =~ s/[\/\s]+$//;
            my $rc = opendir(DIR, $ans);
            if ( $rc ){
                my $file = "";
                while ( defined($file = readdir(DIR)) )
                {
                    next if ( !("$file" =~ /^slapd-/) or ($file =~ /\.removed$/) );
                    if ( exists $instances{$ans} ){
                        my $addit = 1;
                        foreach my $thisslapd ( @{$instances{$ans}} )
                        {
                            if ( $thisslapd eq $file ){
                                $addit = 0;
                                goto out1;
                            }
                        }
out1:
                        if ( $addit ){
                            push @{$instances{$ans}}, $file;
                        }
                    } else {
                        push @{$instances{$ans}}, $file;
                    }
                }
                closedir(DIR);
            }
        }
    }
}

@instconfigdirs = keys %instances;
if ( $#instconfigdirs < 0 )
{
    $setup->msg($FATAL, 'error_no_ds');
    $setup->doExit(1);
}

print("\n==============================================================================\n");
$setup->msg('candidate_list_txt');
foreach my $c ( @instconfigdirs )
{
    foreach my $i ( @{$instances{$c}} )
    {
        print "    $c/$i\n";
    }
}

#
# See if there is already a configds
#
my $admConf = AdminUtil::getAdmConf("$instconfigdir/admin-serv");
my @admConfKeys = keys %$admConf;
my $orig_confdsid = "";
my $new_confdsid = "";
my $new_confdir = "";
my $adminuid = "";
my @errs = ();

#
# Check for an existing Admin Server, then set the defaults
#
if ( $#admConfKeys >= 4 ) # admserv.conf, console.conf, httpd.conf, nss.conf
{
    # Admin Server is installed; that is Config DS exists, which may be
    # replaced with a new one in the RegDSDialogs
    $orig_confdsid = getLocalConfigDS("$instconfigdir/admin-serv");
    $setup->{inf}->{slapd}->{ServerIdentifier} = $orig_confdsid;
    $setup->{inf}->{slapd}->{config_dir} = $instconfigdir;
    $setup->{inf}->{slapd}->{Instances} = \%instances;
    $setup->{inf}->{General}->{ConfigDirectoryLdapURL} = $admConf->{ldapurl};
    $setup->{inf}->{General}->{ConfigDirectoryAdminID} = $admConf->{userdn};
    $setup->{inf}->{General}->{AdminDomain} = $admConf->{AdminDomain};
    $setup->{inf}->{General}->{SuiteSpotUserID} = $admConf->{SuiteSpotUserID};
    $setup->{inf}->{General}->{SuiteSpotGroup} = $admConf->{SuiteSpotGroup};
    ($setup->{inf}->{General}->{FullMachineName} = $admConf->{ldapurl}) =~
                                                   s/.*:\/\/(.*):[0-9]*\/.*/\1/;
    $setup->{inf}->{admin}->{SysUser} = $admConf->{sysuser};
    $adminuid = $admConf->{userdn};
    if($silent eq "yes"){
        if($setup->{inf}->{register}->{adminpw}){
            $setup->{inf}->{General}->{ConfigDirectoryAdminPwd} = $setup->{inf}->{register}->{adminpw};
        }
    }
    if (!$setup->{inf}->{admin}->{config_dir}){
        $setup->{inf}->{admin}->{config_dir} = "$instconfigdir/admin-serv";
    }

    #
    # Read additional config from config DS
    #
    my $pset = AdminUtil::getPset($admConf);
    if ($pset && %{$pset}) {
        $setup->{inf}->{admin}->{Port} = $pset->{"configuration.nsserverport"};
        $setup->{asorigport} = $pset->{"configuration.nsserverport"}; # save orig. port
        $setup->{inf}->{admin}->{ServerIpAddress} = $pset->{"configuration.nsserveraddress"};
    }
    my $admpw = AdminUtil::getAdmpw($admConf);
    if ($admpw && %{$admpw}) {
        $setup->{inf}->{admin}->{ServerAdminID} = $admpw->{ServerAdminID};
        $setup->{inf}->{admin}->{ServerAdminPwd} = $admpw->{ServerAdminPwd};
    }

    $setup->{reconfigas} = 1; # allow AS reconfig
    if($silent eq "no"){
        require RegDSDialogs;
        my @dialogs = RegDSDialogs->getDialogs();
        my $dialogmgr = new DialogManager($setup, $res, $TYPICAL);
        $dialogmgr->addDialog(@dialogs);

        my $rc = $dialogmgr->run();
        if ($rc)
        {
            $setup->doExit(1);
        }
    }
    $new_confdsid = $setup->{inf}->{slapd}->{ServerIdentifier};
    $new_confdir = $setup->{inf}->{slapd}->{config_dir};
    my $newinst = "slapd-$new_confdsid";

    my $inf = createInfFromConfig("$instconfigdir/$newinst", $newinst);
    if ( !$inf )
    {
        $setup->msg($FATAL, 'error_create_inf_from_config', "$instconfigdir/$newinst");
        $setup->doExit(1);
    }
    if ( $orig_confdsid ne $new_confdsid )
    {
        #
        # To switch to the new Config DS, unregister the old one
        #
        print("\n==============================================================================\n");
        $setup->msg('unregister_old_confds', $orig_confdsid);
        #
        # If we don't have it, prompt for the Admin password.  Silent install should have set this
        #
        if (!$setup->{inf}->{General}->{ConfigDirectoryAdminPwd} ||
             $setup->{inf}->{General}->{ConfigDirectoryAdminPwd} eq "" )
        {
            $ans = reg_get_passwd($setup, 'input_admin_passwd', $adminuid);
            $setup->{inf}->{General}->{ConfigDirectoryAdminPwd} = $ans;
        }
        while (!unregisterDSWithConfigDS($orig_confdsid, \@errs, $setup->{inf}))
        {
            if($silent eq "yes"){
                # silent install can not recover from this error
                $setup->msg($FATAL, 'error_unregister_ds', $orig_confdsid);
                $setup->doExit(1);
            }
            $setup->msg($FATAL, 'error_unregister_ds', $orig_confdsid);
            $ans = reg_get_passwd($setup, 'input_admin_passwd', $adminuid);
            $setup->{inf}->{General}->{ConfigDirectoryAdminPwd} = $ans;
            @errs = ();
        }
        #
        # Updating the port number
        #
        my $oldport = 0;
        my $newport = $inf->{slapd}->{ServerPort};
        ($oldport = $setup->{inf}->{General}->{ldapurl}) =~ s/.*:([0-9]*)\/.*/\1/;
        $setup->{inf}->{General}->{ldapurl} =~ s/$oldport/$newport/;
        $setup->{inf}->{General}->{ConfigDirectoryLdapURL} = "ldap://" . $fqdn . ":". $newport . "/o=NetscapeRoot";
    }
    #
    # Set the new inf to $setup->{inf}
    #
    $setup->{inf}->{slapd} = $inf->{slapd};
    $setup->{inf}->{slapd}->{config_dir} = $instconfigdir;
    $setup->{inf}->{slapd}->{Instances} = \%instances;
}
elsif($silent eq "no")
{
    #
    # Admin Server is not set up.
    # %instances has more than one instance
    # note: this is orig_confdsid is just a candidate...
    #
    my $orig_confdir = $instconfigdirs[0];
    my @orig_confdsids = @{$instances{$orig_confdir}};
    ($orig_confdsid = $orig_confdsids[0]) =~ s/slapd-(.*)/\1/;

    my $originst = "slapd-$orig_confdsid";
    my $inf = createInfFromConfig("$orig_confdir/$originst", $originst);
    if ( !$inf )
    {
        $setup->msg($FATAL, 'error_create_inf_from_config',
                            "$orig_confdir/$originst");
        $setup->doExit(1);
    }
    $setup->{inf} = $inf;
    $setup->{inf}->{slapd}->{ServerIdentifier} = $orig_confdsid;
    $setup->{inf}->{slapd}->{config_dir} = $orig_confdir;
    $setup->{inf}->{slapd}->{Instances} = \%instances;

    $dialogmgr = new DialogManager($setup, $res, $TYPICAL);
    require RegDSDialogs;
    require SetupDialogs;
    require ConfigDSDialogs;
    require ASDialogs;
    @dialogs = RegDSDialogs->getDialogs();
    $dialogmgr->addDialog(@dialogs);
    my $rc = $dialogmgr->run();
    if ( $rc ){
        $setup->doExit(1);
    }

    $new_confdsid = $setup->{inf}->{slapd}->{ServerIdentifier};
    $new_confdir = $setup->{inf}->{slapd}->{config_dir};
    if ( $orig_confdsid ne $new_confdsid )
    {
        my $newinst = "slapd-$new_confdsid";
        $inf = createInfFromConfig("$instconfigdir/$newinst", $newinst);
        if ( ! $inf )
        {
            $setup->msg($FATAL, 'error_create_inf_from_config', "$instconfigdir/$newinst");
            $setup->doExit(1);
        }
        $setup->{inf}->{slapd} = $inf->{slapd};
        $setup->{inf}->{slapd}->{Instances} = \%instances;
    }
    $setup->{inf}->{General}->{ConfigDirectoryLdapURL} = "ldap://" . $fqdn . ":". 
        $setup->{inf}->{slapd}->{ServerPort} . "/o=NetscapeRoot";

    $dialogmgr->resetDialog();
    @dialogs = SetupDialogs->getRegDialogs();
    push @dialogs, ConfigDSDialogs->getRegDialogs();
    push @dialogs, ASDialogs->getDialogs();
    $dialogmgr->addDialog(@dialogs);
    my $rc = $dialogmgr->run();
    if ( $rc )    {
        $setup->doExit(1);
    }

    $adminuid = $setup->{inf}->{General}->{ConfigDirectoryAdminID};
}
else
{
    #
    # This is a silent install, fill in any remaining missing values
    #
    my $orig_confdir = $new_confdir = $instconfigdirs[0];
    my @orig_confdsids = @{$instances{$orig_confdir}};
    ($new_confdsid = $orig_confdsids[0]) =~ s/slapd-(.*)/\1/;
    my $originst = "slapd-$new_confdsid";
    my $inf = createInfFromConfig("$orig_confdir/$originst", $originst);

    if ( !$inf )
    {
        $setup->msg($FATAL, 'error_create_inf_from_config',
                            "$orig_confdir/$originst");
        $setup->doExit(1);
    }
    $setup->{inf}->{slapd} = $inf->{slapd};
    $setup->{inf}->{slapd}->{Instances} = \%instances;
}

#
# Add "o=netscaperoot" to the config DS
#
print("\n==============================================================================\n");
$setup->msg('register_new_confds', $new_confdsid);

if ($silent eq "no"){
    $setup->{inf}->{slapd}->{RootDNPwd} = reg_get_passwd($setup, 'input_rootdn_passwd', $new_confdsid);
    $localrootpw = $setup->{inf}->{slapd}->{RootDNPwd};
    $localrootdn = $setup->{inf}->{slapd}->{RootDN};
}

if ( ($#admConfKeys >= 0 && ($orig_confdsid ne $new_confdsid)) ||
      $#admConfKeys < 0 )
{
    @errs = ();
    # First, let's register the Configuration Directory itself

    if(!$setup->{inf}->{slapd}->{RootDNPwd}){
        $setup->{inf}->{slapd}->{RootDNPwd} = $localrootpw;
    }
    while (!createConfigDS($setup->{inf}, \@errs))
    {
        foreach my $err (@errs)
        {
            if ( $err eq "suffix_already_exists" || $err eq "error_creating_suffix_backend")
            {
                goto out;
            }
        }
        if(!$setup->{inf}->{slapd}->{RootDNPwd} || $setup->{inf}->{slapd}->{RootDNPwd} eq ""){
            # silent install should have set this
            $setup->{inf}->{slapd}->{RootDNPwd} = reg_get_passwd($setup, 'input_rootdn_passwd', $new_confdsid);
        }
        @errs = ();
    }
out:
}

#
# If we don't have it, prompt for the Admin password
#
if (!$setup->{inf}->{General}->{ConfigDirectoryAdminPwd} ||
     $setup->{inf}->{General}->{ConfigDirectoryAdminPwd} eq "")
{
    # silent install should have set this
    $ans = reg_get_passwd($setup, 'input_admin_passwd', $adminuid);
    $setup->{inf}->{General}->{ConfigDirectoryAdminPwd} = $ans;
}

@errs = ();
while (!registerDSWithConfigDS($new_confdsid, \@errs, $setup->{inf}))
{
    if($silent eq "yes"){
        # silent install can not recover
        $setup->msg($FATAL, 'error_register_configds', $new_confdsid);
        $setup->doExit(1);
    }
    $setup->msg($WARN, 'error_register_configds', $new_confdsid);
    $ans = reg_get_passwd($setup, 'input_admin_passwd', $adminuid);
    $setup->{inf}->{General}->{ConfigDirectoryAdminPwd} = $ans;
    @errs = ();
}

my $hassubinst = 0;

#
# Then, register the rest of the Directory Servers, if any
#
my %subinstances = ();    # hash without the Config DS
%instances = %{$setup->{inf}->{slapd}->{Instances}};
foreach my $subconfdir (keys %instances)
{
    my @subinsts = @{$instances{$subconfdir}};
    foreach my $subinst ( @subinsts )
    {
        if ( ("$subinst" ne "slapd-" . $new_confdsid) ||
             ($subconfdir ne $new_confdir) )
        {
            if ( 0 == $hassubinst){
                $hassubinst = 1;
                print("\n==============================================================================\n");
                $setup->msg('register_subds');
            }
            my $subid = $subinst;
            $subid =~ s/slapd-//;

            if ($silent eq "yes"){
                # Get the password from silent install config
                ($rootdn, $passwd) = get_cred_from_inst($setup, $subinst);
                if($rootdn ne ""){
                    $setup->{inf}->{slapd}->{RootDN} = $rootdn;
                }
            } else {
                $passwd = reg_get_passwd($setup, 'input_rootdn_passwd_sub', $subid, $subid);
            }

            # if the password is not given, we don't register the server
            next if ( "" eq $passwd || !$passwd );

            my $subinf = createInfFromConfig("$subconfdir/$subinst", $subinst);
            if ( !$subinf ){
                $setup->msg($FATAL, 'error_create_inf_from_config', "$subconfdir/$subinst");
            }
            else
            {
                #
                # If we're switching the config DS, we want to force updating the
                # PTA plug-in since it's configured for the old config DS.
                #
                my $force_pta = 0;
                if ( $orig_confdsid ne $new_confdsid ) {
                    $force_pta = 1;
                }

                $setup->{inf}->{slapd} = $subinf->{slapd};
                $setup->{inf}->{slapd}->{RootDNPwd} = $passwd;
                push @{$subinstances{$subconfdir}}, $subinst;
                my $done = 0;
                while ( !$done && !createSubDS($setup->{inf}, \@errs, $force_pta) )
                {
                    $setup->msg($FATAL, @errs);
                    if($silent eq "yes"){
                        # silent install can not recover
                        $setup->doExit(1);
                    }
                    $passwd = reg_get_passwd($setup, 'input_rootdn_passwd_sub',
                                                        $subid, $subid);
                    if ( "" eq $passwd || !$passwd ){
                        $done = 1;
                        pop @{$subinstances{$subconfdir}};
                    } else {
                        $setup->{inf}->{slapd}->{RootDNPwd} = $passwd;
                    }
                }

                if (!$done and !@errs) {
                    $setup->msg('post_create_subds', $subinst, $subinst);
                }

                # add the aci that allows the admin user to administer the server
                @errs = ();
                if (!addConfigACIsToSubDS($setup->{inf}, \@errs)) {
                    $setup->msg(@errs);
                    $setup->doExit(1);
                }
            }
        }
    }
}

my @subkeys = keys %subinstances;
if ( $#subkeys >= 0 ){
    @errs = ();
    if ( !registerScatteredDSWithConfigDS($setup->{inf}, \@errs, \%subinstances) ){
        $setup->msg($FATAL, @errs);
        $setup->doExit(1);
    }
}

#
# Configure and register the admin server instance.
# Generate a new inf for the config DS and override
# the old slapd data from the last instance we registered.
#
print("\n==============================================================================\n");
$new_confdir = $setup->{inf}->{slapd}->{config_dir};
my $newinst = "slapd-$new_confdsid";
my $inf = createInfFromConfig("$instconfigdir/$newinst", $newinst);
if ( !$inf )
{
    $setup->msg($FATAL, 'error_create_inf_from_config', "$instconfigdir/$newinst");
    $setup->doExit(1);
}
$setup->{inf}->{slapd} = $inf->{slapd};

# need to manually set these 2 parameters
$setup->{inf}->{slapd}->{UseExistingMC} = "yes";
$setup->{inf}->{slapd}->{SlapdConfigForMC} = "yes";
if ( !$setup->{reconfigas} )
{
    if ( !createAdminServer($setup) ){
        $setup->msg($FATAL, 'error_create_adminserver');
        $setup->doExit(1);
    }
} else {
    if ( !reconfigAdminServer($setup) ){
        $setup->msg($FATAL, 'error_reconfig_adminserver');
        $setup->doExit(1);
    }
}

#
# Check if we are registering to a remote config, or adding a instance to our local config
#
if ($silent eq "no")
{
    print("\n==============================================================================\n");
    $setup->msg(0, 'remote_register_local_prompt');
    my $answer;
    chomp($answer = <>);
    if ($answer eq "y"){
        $destination = "local";
    } else {
        print("\n==============================================================================\n");
        $setup->msg(0, 'remote_register_remote_prompt');
        chomp($answer = <>);
        if ($answer eq "y")
        {
            $destination = "remote";
        }
    }
    if($destination ne "")
    {
        print "\n";
        $setup->msg(0, 'remote_prompt', "hostname");
        while($remote_host eq ""){
            chomp($remote_host = <>);
        }

        $setup->msg(0, 'remote_prompt', "port");
        while($remote_port eq ""){
            chomp($remote_port = <>);
        }

        $setup->msg(0, 'remote_prompt', "bind DN");
        while($remote_binddn eq ""){
            chomp($remote_binddn = <>);
        }

        $remote_bindpw = reg_get_passwd($setup, 'remote_prompt_bind_password', "", 0, 1);

        $setup->msg(0, 'remote_conn_use_ssl');
        chomp($local_certdir = <>);

        $setup->msg(0, 'remote_prompt', "admin domain[$setup->{inf}->{General}->{AdminDomain}]");
        chomp($remote_admindomain = <>);
        if ($remote_admindomain eq ""){
            $remote_admindomain = $setup->{inf}->{General}->{AdminDomain};
        }
    }
}

#
# We are registering with a remote server(locally or remotely)
#
# So we search the origin o=netscaperoot (admin domain), and simply add
# those entries to the destination config server.
#
if($remote_host)
{
    #
    # Open connections to remote and local servers
    #
    my $connRemote = new Mozilla::LDAP::Conn($remote_host,
                                             $remote_port,
                                             $remote_binddn,
                                             $remote_bindpw,
                                             $local_certdir);
    my $errstr = "Success";
    if ($connRemote) {
        $errstr = $connRemote->getErrorString();
    }
    if (!$connRemote or ($errstr ne "Success")) {
        # error
        if ($errstr eq "Success"){
            $errstr = "";
        }
        $setup->msg($FATAL, 'error_connection', $remote_host, $errstr);
        $setup->msg($FATAL, 'remote_register_error');
        $setup->doExit(1);
    }

    #
    # Open a connection to the local server
    #
    my $connLocal = new Mozilla::LDAP::Conn($fqdn, $inf->{slapd}->{ServerPort}, $localrootdn, $localrootpw);
    if ($connLocal) {
        $errstr = $connLocal->getErrorString();
    }
    if (!$connLocal or ($errstr ne "Success")) {
        # error
        if ($errstr eq "Success"){
            $errstr = "";
        }
        $setup->msg($FATAL, 'error_connection', $fqdn, $errstr);
        $setup->msg($FATAL, 'remote_register_error');
        $setup->doExit(1);
    }

    if ($destination eq "local"){
        #
        # Register a remote server with our local configuration server
        #
        print "Searching local configuration server...\n";
        my $entry = $connRemote->search("ou=$remote_admindomain,o=netscaperoot", "sub", "(objectclass=*)");
        if (!$entry){
            $setup->msg($FATAL, 'error_operation', "searching" ,"ou=$remote_admindomain,o=netscaperoot", $connLocal->getErrorString());
            $connLocal->close();
            $connRemote->close();
            $setup->doExit(1);
        } else {
            print "Adding remote configuration entries to local configuration server...\n";
            while ($entry){
                $connLocal->add($entry);
                if($connLocal->getErrorCode() != 0 && $connLocal->getErrorCode() != 68){
                    $setup->msg($FATAL, 'error_operation', 'adding', $entry->getDN(), $connLocal->getErrorString());
                    $setup->msg($FATAL, 'remote_register_error');
                    $connLocal->close();
                    $connRemote->close();
                    $setup->doExit(1);
                }
                $entry = $connRemote->nextEntry();
            }
        }
        $setup->msg(0, 'remote_register_completed', $remote_host, $fqdn );
    } else {
        #
        # Register our local server with a remote configuration server
        #
        print "Searching remote configuration server...\n";
        my $entry = $connLocal->search("ou=$setup->{inf}->{General}->{AdminDomain},o=netscaperoot", "sub", "(objectclass=*)");
        if (!$entry){
            $setup->msg($FATAL, 'error_operation', "searching", $entry->getDN(), $connLocal->getErrorString());
            $setup->msg($FATAL, 'remote_register_error');
            $connLocal->close();
            $connRemote->close();
            $setup->doExit(1);
        } else {
            print "Adding local configuration entries to remote configuration server...\n";
            while ($entry){
                $connRemote->add($entry);
                if($connRemote->getErrorCode() != 0 && $connRemote->getErrorCode() != 68){
                    $setup->msg($FATAL, 'error_connection', 'adding', $entry->getDN(), $connRemote->getErrorString());
                    $setup->msg($FATAL, 'remote_register_error');
                    $connLocal->close();
                    $connRemote->close();
                    $setup->doExit(1);
                }
                $entry = $connLocal->nextEntry();
            }
        }
        $setup->msg(0, 'remote_register_completed', $setup->{inf}->{General}->{FullMachineName}, $remote_host );
    }

    # Close up our connections
    $connLocal->close();
    $connRemote->close();
}

print("\n==============================================================================\n");
$setup->msg('end_ds_registration');
$setup->doExit(0);

