From 59e335b09903e84f72263b5713f8509f755f8e7e Mon Sep 17 00:00:00 2001
From: Mark Reynolds <mreynolds@redhat.com>
Date: Tue, 25 Oct 2016 20:45:34 -0400
Subject: [PATCH] Ticket 49015 - register-ds-admin.pl - silent install does not
     register local instances

Bug Description:  There is no way to specify how to register local instances with
                  a local configuration server when using silent install.

Fix Description:  Revise the [register] directive section to allow "local instances".
                  Improved config file validation, and fixed other minor bugs.

                  Also updated the man page with INF parameter changes.

https://fedorahosted.org/389/ticket/49015

Reviewed by: ?
---
 admserv/newinst/src/register-ds-admin.pl.in  | 176 +++++++++++++++++----------
 admserv/newinst/src/register-ds-admin.res.in |   4 +-
 man/man8/register-ds-admin.pl.8              | 132 ++++++++++++++------
 3 files changed, 207 insertions(+), 105 deletions(-)

diff --git a/admserv/newinst/src/register-ds-admin.pl.in b/admserv/newinst/src/register-ds-admin.pl.in
index dd100d9..f8cc6c0 100644
--- a/admserv/newinst/src/register-ds-admin.pl.in
+++ b/admserv/newinst/src/register-ds-admin.pl.in
@@ -122,8 +122,8 @@ sub get_cred_from_inst
     #
     # Check the remaining instances
     #
-    my @insts = $mysetup->{inf}->{register}->{instance};
-    if ($#insts){
+    my @insts = $mysetup->{inf}->{register}->{localinst};
+    if ($#insts >= 0 && $insts[0] ne ""){
         my $i = 0;
         for (; $i <= $#insts; $i++){
             my @inst_parts = split('::', $insts[$i]);
@@ -159,6 +159,7 @@ my $dialogmgr;
 my @dialogs;
 my @silent_instances;
 my @config_parts;
+my $remote_reg = 0;
 
 #
 # Continue with the setup...
@@ -174,9 +175,11 @@ my $res = new Resource("@propertydir@/register-ds-admin.res",
 my $setup = new Setup($res);
 if ($setup->{silent}){
     #
-    # To be silent we must have "General" & "admin", or just "register" directives
+    # To be silent we must have "General" & "register".  If 'register" does not have
+    # a localinst/remotehost parameter, then there must be an 'admin' directive in the INF file
     #
-    if ( ($setup->{inf}->{General} && $setup->{inf}->{admin}) || $setup->{inf}->{register} ){
+    if ( ($setup->{inf}->{General} && $setup->{inf}->{register}) &&
+         ($setup->{inf}->{register}->{localinst} || $setup->{inf}->{admin} || $setup->{inf}->{register}->{remotehost})){
         $silent = "yes";
     } else {
         # Missing required silent install directives
@@ -193,11 +196,11 @@ if ($setup->{inf}->{register}){
     #
     # [register]
     # configinst= slapd-INSTANCE::cn=directory manager::myPassword
-    # instance= slapd-INSTANCE2::cn=directory manager::myPassword
-    # instance= slapd-INSTANCE3::cn=directory manager::myPassword
+    # localinst= slapd-INSTANCE2::cn=directory manager::myPassword
+    # localinst= slapd-INSTANCE3::cn=directory manager::myPassword
+    # localcertdir= /etc/dirsrv/slapd-INSTANCE
     # 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
@@ -206,44 +209,88 @@ if ($setup->{inf}->{register}){
     # 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);
+
+    #
+    # If 'remotehost' is set, then we are registering with a remote admin/config server.
+    # Otherwise, we are just registering local instances.
+    #
+    if ( $setup->{inf}->{register}->{remotehost} && $setup->{inf}->{register}->{remotehost} ne ""){
+        $remote_reg = 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);
+        }
+    } elsif (!$setup->{inf}->{register}->{localinst} || $setup->{inf}->{register}->{localinst} eq ""){
+        if (!$setup->{inf}->{admin}){
+            # We expected a local instance to register since weare not providing
+            $setup->msg($FATAL, 'error_missing_parameter', 'localinst');
+            $setup->doExit(1);
+        }
+    } else {
+        #
+        # If we got here we assume this is a local registration, but we need to make sure
+        # that other remote parameters were not supplied. In that case we really don't know
+        # what the end user is trying to do - invalid config.
+        #
+        if ( $setup->{inf}->{register}->{remoteport} ){
+            $setup->msg($FATAL, 'error_unexpected_parameter', 'remoteport');
+            $setup->doExit(1);
+        }
+        if ( $setup->{inf}->{register}->{remotebinddn} ) {
+            $setup->msg($FATAL, 'error_unexpected_parameter', 'remotebinddn');
+            $setup->doExit(1);
+        }
+        if ( $setup->{inf}->{register}->{remotebindpw} ){
+            $setup->msg($FATAL, 'error_unexpected_parameter', 'remotebindpw');
+            $setup->doExit(1);
+        }
+        if ( $setup->{inf}->{register}->{admindomain} ){
+            $setup->msg($FATAL, 'error_unexpected_parameter', 'admindomain');
+            $setup->doExit(1);
+        }
+        if ( $setup->{inf}->{register}->{admindn} ){
+            $setup->msg($FATAL, 'error_unexpected_parameter', 'admindn');
+            $setup->doExit(1);
+        }
+        if ( $setup->{inf}->{register}->{adminpw} ){
+            $setup->msg($FATAL, 'error_unexpected_parameter', 'adminpw');
+            $setup->doExit(1);
+        }
+        if ( $setup->{inf}->{register}->{destination} ){
+            $setup->msg($FATAL, 'error_unexpected_parameter', 'destination');
+            $setup->doExit(1);
+        }
     }
 
     #
@@ -266,8 +313,8 @@ if ($setup->{inf}->{register}){
     #
     # Add the other instances (if any)
     #
-    @silent_instances = $setup->{inf}->{register}->{instance};
-    if ($#silent_instances){
+    @silent_instances = $setup->{inf}->{register}->{localinst};
+    if ($#silent_instances >= 0 && $silent_instances[0] ne ""){
         my $i = 0;
         for (; $i <= $#silent_instances; $i++){
             my @inst_parts = split('::', $silent_instances[$i]);
@@ -285,16 +332,18 @@ if ($setup->{inf}->{register}){
     $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};
+    if ($remote_reg){
+        #
+        # 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];
 }
@@ -432,7 +481,6 @@ if ( $#admConfKeys >= 4 ) # admserv.conf, console.conf, httpd.conf, nss.conf
     if (!$setup->{inf}->{admin}->{config_dir}){
         $setup->{inf}->{admin}->{config_dir} = "$instconfigdir/admin-serv";
     }
-
     #
     # Read additional config from config DS
     #
@@ -611,32 +659,32 @@ 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};
+} else {
+    # silent install always contains the proper root password from (configinst/localinst)
+    $setup->{inf}->{slapd}->{RootDNPwd} = $localrootpw;
 }
-
-if ( ($#admConfKeys >= 0 && ($orig_confdsid ne $new_confdsid)) ||
-      $#admConfKeys < 0 )
+if ( ($#admConfKeys >= 0 && $orig_confdsid ne $new_confdsid) ||
+     $#admConfKeys < 0 )
 {
+    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 = ();
     # 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")
+            if ( $err eq "suffix_already_exists" || $err eq "error_creating_suffix_backend" ||
+                 $err eq "error_connection_failed")
             {
                 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:
 }
 
diff --git a/admserv/newinst/src/register-ds-admin.res.in b/admserv/newinst/src/register-ds-admin.res.in
index f7c0e67..1f5f62f 100644
--- a/admserv/newinst/src/register-ds-admin.res.in
+++ b/admserv/newinst/src/register-ds-admin.res.in
@@ -46,11 +46,13 @@ error_missing_parameter = Silent install file missing required parameter '%s'\n
 
 error_invalid_parameter = Silent install parameter '%s' is invalid\n
 
+error_unexpected_parameter = Unexpected install parameter '%s' - config is invalid\n
+
 error_connection = Error connecting to host '%s' - %s\n
 
 error_operation = Error while %s entry '%s' - %s\n
 
-error_silent_install = Silent setup misconfiguration.  Must have 'General' and 'admin', or 'register' directives\n
+error_silent_install = Silent setup misconfiguration.  Please see the man page for using a silent install file'\n
 
 remote_register_error = The remote registration process failed!\n
 
diff --git a/man/man8/register-ds-admin.pl.8 b/man/man8/register-ds-admin.pl.8
index eb85bba..29337c8 100644
--- a/man/man8/register-ds-admin.pl.8
+++ b/man/man8/register-ds-admin.pl.8
@@ -21,12 +21,15 @@ register\-ds\-admin.pl \- Registers Directory Server instances with an Admin Ser
 .B register-ds-admin.pl
 [\fI--options\fR] \fI-- \fR[\fIargs\fR]
 .SH DESCRIPTION
-Registers existing Directory Server instances with an existing Admin Server. 
-This command does the set up necessary for the use of the Console to manage 
-the Directory Server instances you are registering.  You can register remote 
-Directory Server instances to a local Admin Server, as well as register local 
-Directory Server instances with a remote Admin Server - this allows a single 
-console/Admin Server to manage all your Directory Servers on your network.
+Registers existing Directory Server instances with an existing Admin Server.
+This command does the set up necessary for the use of the Console to manage
+the Directory Server instances you are registering.  You can register local
+Directory Server instances with a local Configuration Directory Server/Admin
+Server.  You can also create an Admin Server and register standalone instances
+with it. You can register remote Directory Server instances to the local
+Admin Server, as well as register local Directory Server instances with a
+remote Admin Server - this allows a single Console/Admin Server to manage all
+the Directory Servers in your network.
 
 Use this command with the \fB--update\fR option after an upgrade to refresh
  the server information (version, build number, etc.) in the Console.
@@ -68,8 +71,8 @@ Update an existing installation (e.g. after upgrading packages)
 .B \fB\-\-continue
 (update only) keep going despite errors (also --force)
 .PP
-For all options, you can also use the short name e.g. \fB\-h\fR, \fB\-d\fR, etc.  
-For the \fB\-d\fR argument, specifying it more than once will increase the debug 
+For all options, you can also use the short name e.g. \fB\-h\fR, \fB\-d\fR, etc.
+For the \fB\-d\fR argument, specifying it more than once will increase the debug
 level e.g. \fB\-ddddd\fR
 .PP
 args:
@@ -85,20 +88,25 @@ or
 .IP
 "slapd.Suffix=dc=example,dc=com"
 .PP
-Values passed in this manner will override values in an .inf file given with 
+Values passed in this manner will override values in an .inf file given with
 the \fB\-f\fR argument.
 
 .SH Silent Mode (.inf file)
 .PP
-Here is an example of an .inf file that registers a local Directory Server instance with a remote server over SSL:
+The .inf file use three directives depending on what you want to do:  [General], [admin], and [register].
+The [admin] section is only needed if an Admin Server needs to be installed on the local system.
+.br
+
+Here is an example of creating an Admin Server, and turning a standalone Directory Server instance into
+a configuration instance.  In this case we need the [General], [admin], and [register] directives
 .IP
 [General]
 .br
 FullMachineName= localhost.localdomain
 .br
-SuiteSpotUserID= nobody
+SuiteSpotUserID= dirsrv
 .br
-SuiteSpotGroup= nobody
+SuiteSpotGroup= dirsrv
 .br
 AdminDomain= redhat.com
 .br
@@ -126,7 +134,69 @@ ServerAdminPwd= password
 .br
 configinst= slapd-localhost::cn=directory manager::password
 .br
-instance= slapd-replica::cn=directory manager::password
+
+.PP
+Here is an example of an .inf file that registers two local Directory Server
+instances (slapi-replica, slapd-instance2) with the local Configuration
+Directory Server (slapd-localhost).
+.IP
+[General]
+.br
+FullMachineName= localhost.localdomain
+.br
+SuiteSpotUserID= dirsrv
+.br
+SuiteSpotGroup= dirsrv
+.br
+AdminDomain= redhat.com
+.br
+ConfigDirectoryAdminID= admin
+.br
+ConfigDirectoryAdminPwd= admin
+.br
+ConfigDirectoryLdapURL= ldap://localhost.localdomain:389/o=NetscapeRoot
+.br
+
+.br
+[register]
+.br
+configinst= slapd-localhost::cn=directory manager::password
+.br
+localinst= slapd-instance2::cn=directory manager::password
+.br
+localinst= slapd-replica::cn=directory manager::password
+.br
+
+.PP
+This example will add the slapd-replica instance to the local configuration server.  Then this
+server's configuration to added to the remote configuration server on ldap.redhat.com
+.IP
+.br
+[General]
+.br
+FullMachineName= localhost.localdomain
+.br
+SuiteSpotUserID= dirsrv
+.br
+SuiteSpotGroup= dirsrv
+.br
+AdminDomain= redhat.com
+.br
+ConfigDirectoryAdminID= admin
+.br
+ConfigDirectoryAdminPwd= admin
+.br
+ConfigDirectoryLdapURL= ldap://localhost.localdomain:389/o=NetscapeRoot
+.br
+
+.br
+[register]
+.br
+configinst= slapd-localhost::cn=directory manager::password
+.br
+localinst= slapd-replica::cn=directory manager::password
+.br
+localcertdir= /etc/dirsrv/slapd-localhost
 .br
 remotehost= ldap.redhat.com
 .br
@@ -136,8 +206,6 @@ remotebinddn= cn=directory manager
 .br
 remotebindpw= password
 .br
-localcertdir= /etc/dirsrv/slapd-localhost
-.br
 admindomain= redhat.com
 .br
 admindn= uid=admin,ou=Administrators,ou=TopologyManagement,o=NetscapeRoot
@@ -146,54 +214,38 @@ adminpw= password
 .br
 destination= remote
 .br
-
-.br
-The above .inf will install a local admin server and then store its configuration (o=netscaperoot) 
-in the "config" instance.  The second local Directory Server instance, slapd-replica, is also 
-added the configuration server.  Then this server's configuration to added to the 
-remote configuration server on ldap.redhat.com
 .PP
 The \fB[register]\fR directive parameter descriptions:
 .TP
 .B configinst\fR = INSTANCE::BIND_DN::PASSWORD\fR
 .br
 .IP
-.I INSTANCE\fR = The server where the existing configuration exists, or the server where you want 
+.I INSTANCE\fR = The server where the existing configuration exists, or the server where you want
 to add the configuration to. The value takes the form of slapd-INSTANCE.
 .br
 .I BIND_DN\fR = The root DN, usually \*(lqcn=directory manager\*(rq, for the local configuration server.
 .br
 .I PASSWORD\fR = the root DN password.
 .TP
-.B instance\fR = INSTANCE::BIND_DN::PASSWORD\fR
-.br
-.IP
-.I INSTANCE\fR = Additional local Directory Server instance that should be added to the 
-configuration server. The value takes the form of slapd-INSTANCE.
-.br
-.I BIND_DN\fR = The root DN, usually \*(lqcn=directory manager\*(rq, for the local server.
+.B localinst\fR = INSTANCE::BIND_DN::PASSWORD\fR
 .br
-.I PASSWORD\fR = the root DN password.
+.IP 
+The parameters are the same as 'configinst'.  This argument is required for local registerations.
 .br
-
-This is an optional parameter for specifying other local Directory Server instances to register with the
-configuration server.
-.br 
 .TP
-.B remotehost\fR = The FQDN of the remote server.  This is either the rmeote server we 
-registering with, or the remote server that is being registered with the local configuration 
+.B remotehost\fR = The FQDN of the remote server.  This is either the rmeote server we
+registering with, or the remote server that is being registered with the local configuration
 server.
 .TP
 .B remoteport\fR = The port of the remote server.
 .TP
+.B localcertdir\fR = The directory of the certificate database files (e.g. cert8.db, key3.db). This optional parameter is only used if connecting to the remote server over SSL.
+.TP
 .B remotebinddn\fR = The bind DN, preferrably the root DN, to connect to the remote server.
 .TP
 .B remotebinddn\fR = The password for the remotebinddn entry.
 .TP
-.B localcertdir\fR = The directory of the certificate database files (e.g. cert8.db, key3.db). This 
-optional parameter is only used if connecting to the remote server over SSL.
-.TP
-.B admindomain\fR = The admin domain of the remote configuration server.
+.B admindomain\fR = This is the Admin Domain for the server that is being registered. If registering the local server to the remote server, it would be the domain from the local server. If registering a remote server to the local configuration server, it would be the Admin Domain from the remote server.
 .TP
 .B admindn\fR = The local administrator DN for o=netscaperoot
 .TP 
-- 
2.7.4

