#!/usr/bin/perl -w
###################################################################
# (C) Copyright 2012-2015 Hewlett-Packard Enterprise Development, L.P.
# @(#) Serviceguard password-less ssh setup utility for
# @(#) Continentalclusters.
# @(#) Product Name    : HP Serviceguard
# @(#) Product Version : A.12.10.00
# @(#) Patch Name      : 
#
# *** Note: This file MUST NOT be edited. *****"
#
# Any changes made to it will be overwritten when you upgrade to the
# next release of HP Serviceguard.
#
# Changing this file may lead to failure in setting up
# password less ssh for Continentalcluster.
#
###################################################################

use strict;
use warnings;
use Getopt::Long qw(GetOptions HelpMessage :config bundling no_ignore_case);
use Pod::Usage;
use Sys::Hostname;
use File::Path;
use File::Basename;
use File::Copy;
use Socket;  			


=head1 NAME

      cmsshsetup - Simplifies configuring the Secure Shell public-key user
      authentication between systems. This establishes a security domain for
      the cluster.

# arguments
# {-f hostfile| -n hostname1 ...} [-v] [-k dsa] [-h/-help] [-t] [-l logfile]
# example :
# cmsshsetup -f hostfile -k dsa
# cmsshsetup -f hostfile -t
# cmsshsetup -n node1 -n node2 -k dsa -v
# cmsshsetup -k dsa -t -n node1

=head1 SYNOPSIS

cmsshsetup
S<{-f hostfile | -n node_name...} >
S<[-h/-help] [-v] [-t] [-k type] [-l logfile]>

=head1 OPTIONS

=over 4

=item B<-f hostfile>

      Reads a list of remote hosts specified in the hostfile, one
      host per line.

      If the remote host is in a different domain than the local
      host, you must specify the full domain name.

      If a hostname is supplied instead of a hostfile name,
      cmsshsetup reads host names from standard input, typically
      the command line.

=item B<-n hostname>

      Hostname Specifies the name of a remote host with which to
      exchange keys. Using this option (-n) multiple remote host
      can be specified with which to exchange keys.

=item B<-k type>

      Specifies the type of key to create. Possible values are
      rsa or dsa for ssh protocol version 2. The default key type
      is rsa.

=item B<-t>

      Test the password less ssh connection among list of remote hosts
      specified in the hostfile.

=item B<-l logfile>

      Dump all detailed log information into a logfile.

=item B<-h/help>

      Displays help

=item B<-v>

      Displays verbose output.

=back

=head1 DESCRIPTION

      The cmsshsetup command simplifies the task of setting up ssh public-key
      authentication trust relationships for a set of managed systems.  The
      cmsshsetup command employs the round-robin key-exchange feature that
      must be used in a Serviceguard cluster to establish an "any-member-
      to-any-member"ssh trust relationship.

=cut

# Global file related variables
my $gprivkeyfile = undef;
my $gpubkeyfile  = undef;
my $gauthkeyfile = undef;

# Global host related variables
my $lhost         = undef;
my $HOME          = undef;
my $luser         = undef;
my $hostcount     = 0;
my $localhostonly = "false";
my @tmp_hostlist  = ();
my @goodhostlist  = ();
my @hostlist      = ();
my @hostfqn       = ();
my $tag           = "cmsshsetup"; # variable $tag will be used 
                                    # to identify keys inserted by
                                    # cmsshsetup script while 
                                    # cleanup.

# Global option related variables
my $key          = undef;
my $log          = undef;
my $file         = undef;
my $verbose      = 0;
my $help         = 0;
my $testonly     = 0;
my $delete_key   = 0;
my $global_switch_log = "true";

# General use commands (the path for ping, cp and cat is not 		
# the same on hpux and linux). 		
my @systemcommand=("cat", "echo", "logger", "mkdir", 
                   "ssh", "ssh-keygen", "unlink", "ssh-copy-id"); 		
my $CAT       = undef; 		
my $ECHO      = undef; 		
my $LOGGER    = undef; 		
my $MKDIR     = undef; 		
my $SSH       = undef; 		
my $SSHKEYGEN = undef; 		
my $UNLINK    = undef;
my $SSH_COPY_ID = undef;

# General status.
my $SUCCESS=0;
my $FAILURE=1;

# ssh client options
my $quiet="-q";
my $batchyes=" -o BatchMode=yes";

# Create ssh variables to simplify usage.
my $sshstrictyes = undef;;
my $sshstrictno  = undef;
my $sshctout     = "-o ConnectTimeout=5 -o ServerAliveCountMax=3 ".
                   "-o ServerAliveInterval=15";

# Key specific; default key type is rsa.
my $gkeytype    = "rsa";
my $gdfbase     = ".ssh/id_rsa";
my $gdfauthbase = ".ssh/authorized_keys";

exit(1) if (parse_args());

exit(1) if (validate_and_setup_args());

exit (1) if (main());

exit(0);

# SUBROUTINES
#------------------------------------------------------------------------------
#
# Subroutine    : non_dash_arg()
# Calls         : -
# Called by     : parse_args()
# Globals       : 
# Input Params  : name of option, value of opt, and target(array or scalar variable)
# Return Value  : -
#
# This function populated the inputs passed to the script into appropriate
# variables.
#
#------------------------------------------------------------------------------
sub non_dash_arg {
    my ($name, $val, $target) = @_;
    if ($val =~ /^-/) {
        pod2usage("ERROR: Option $name requires an argument.\n");
    } else {
        if (ref($target) eq "ARRAY") {
            push @{$target}, $val;
            if ($name eq "n") {
                $hostcount++;
            }
        } elsif (ref($target) eq "SCALAR") {
            # a scalar target generally indicates an option that should not be
            # used more than once, so check for that.
            if (${$target}) {
                pod2usage("ERROR: Option $name should not be supplied more than once.\n");
            }
            ${$target} = $val;
        }
    }
}

#------------------------------------------------------------------------------
#
# Subroutine    : runandCaptureCommand()
# Calls         : open system call
# Called by     : all functions
# Globals       : -
# Input Params  : The command to be executed
# Return Value  : returns the exitcode and output of command execution.
#
# This function opens the ommand in a pipe and returns the output and
# exit code of the command to the calling function.
#
#------------------------------------------------------------------------------

sub runandCaptureCommand {
    my ($myCmd) = @_;
    my @lines  = ();
    my @output = ();
    my $temp   = undef;

    open(CMD, "$myCmd 2>/dev/null |") or return (1 , @output);
    while ($temp=<CMD>) {
        push(@output, $temp);
        last if eof(CMD);
    }
    close(CMD);
    my $exitcode = ($? >> 8);
    return($exitcode, @output);
}

#------------------------------------------------------------------------------
#
# Subroutine    : parse_args()
# Calls         : non_dash_arg, printPhaseTag
# Called by     : -
# Globals       : -
# Input Params  : -
# Return Value  : -
#
# parse arguments passed to cmsshsetup. Set appropriate
# global varibles and return success or failure.
#
#------------------------------------------------------------------------------
sub parse_args {
    GetOptions(
        "n=s"     => sub { non_dash_arg(@_, \@hostlist) },
        "k=s"     => sub { non_dash_arg(@_, \$key) },
        "f=s"     => sub { non_dash_arg(@_, \$file) },
        "v"       => sub { non_dash_arg(@_, \$verbose) },
        "t"       => sub { non_dash_arg(@_, \$testonly) },
        "--delete"=> sub { non_dash_arg(@_, \$delete_key) },
        "l=s"     => sub { non_dash_arg(@_, \$log) },
        "help|h|?"=> sub { pod2usage(-verbose => 1)},
         ) || pod2usage("Invalid argument");

    if ($hostcount == 0) {
        if (!($file)) {
            pod2usage("Error:  Atleast one hostname or a hostfile ".
                      "which contains hostnames is required to run ".
                      "the script\n");
        }
    } else {
        if (($file)) {
            pod2usage("Error:  Either atleast one remote host".
                      "names or a hostfile which contains hostnames ".
                      "is required to run the script\n");
        }
    }

    if ($log) { 
        my $full_path_of_log_file = "$log";
        my $directory_of_log_file = dirname $full_path_of_log_file;
        my $log_file = basename $full_path_of_log_file;
        my ($ret) = runandCaptureCommand("mkdir -p $directory_of_log_file");
        if ($ret ne $SUCCESS) {
            print "Warning:  Unable to access log file's directory ".
                  "[$directory_of_log_file], logging will be disabled\n";
            $global_switch_log="false"
        }
    }
    print_message("V", "Begin cmsshsetup");
    return $SUCCESS;
}

#------------------------------------------------------------------------------
#
# Subroutine    : writeLog()
# Calls         :
# Called by     : print_message
# Globals       : -
# Input Params  : message and type of tag (msg and type)
# Return Value  : -
#
# Write into log file.
#
#------------------------------------------------------------------------------
sub writeLog {
    my ($msg, $type) = @_;
    my $current_time = undef;
        open (LOGFILE, ">>$log");
        if (-e $log) {
            $current_time = scalar(localtime);
            if (defined($current_time) && ($current_time)) {
                print LOGFILE "[$current_time] $type ".$msg."\n";
            } else {
                print LOGFILE "[Local Time Not Found] $type ".$msg."\n";
            }
        } else {
            print "Warning:  Unable to access log file [$log],".
                  "logging will be disabled\n";
            $global_switch_log = "false";
        }
        close LOGFILE;
}

#------------------------------------------------------------------------------
#
# Subroutine    : print_message()
# Calls         : writeLog
# Called by     : All functions 
# Globals       : verbose
# Input Params  : msg and type
# Return Value  : -
#
# Print a message with tag.
#
#------------------------------------------------------------------------------
sub print_message {
    my ($type,$msg) = @_;
    my $full_name_type = undef;

    if ($type eq "V") {
        if ($verbose) {
            $full_name_type = " Verbose: ";
        } else {
            $full_name_type = "";
        }
    } 
    elsif ($type eq "E") { $full_name_type = " Error  : "; }
    elsif ($type eq "F") { $full_name_type = " Failure: "; }
    elsif ($type eq "S") { $full_name_type = " Success: "; }
    elsif ($type eq "M") { $full_name_type = ""; }
    
    # Do logging of messages, if -l option is used.
    if (defined($log) && $global_switch_log eq "true") {
        if ($verbose) {
             if ($msg =~ m/cmsshsetup/) {
                 $full_name_type = " Verbose: "; 
             }
             writeLog($msg, $full_name_type);
        } else {
            if ($type ne "V") {
                writeLog($msg, $full_name_type);
            }
        }
    }

    # Do print of message on console, 
    if ($verbose) {
         if (defined($log) && $global_switch_log eq "true") {
            if ($type ne "V") {
                print "$full_name_type $msg\n";
            }
         } else {
                print "$full_name_type $msg\n";
         }
    } else {
         if ($type ne "V") {
             print "$full_name_type $msg\n";
         }
    }

}

#------------------------------------------------------------------------------
#
# Subroutine    : validate_and_setup_args()
# Calls         : printPhaseTag, print_message
# Called by     : - 
# Globals       : file, key, gdfbase, gdfauthbase, log
# Input Params  : -
# Return Value  : return 1 if there is any failure othewise return 0
#
# Validate and set basic path for private/public and
# auth file with respect to key type ("dsa"/"rsa")
#
#------------------------------------------------------------------------------
sub validate_and_setup_args {
    print_message("V", "Initalization");
    if (defined($file)) {
        if (!-f $file) {
            print_message("E", "Hostfile path $file does not exist");
            return $FAILURE;
        } else {
            print_message("V", "Host file: $file");
        }
    }
    if (!defined($key)) {
        $key="rsa";
    } else {
        if ($key eq "dsa") {
            $gdfbase=".ssh/id_dsa";
            $gdfauthbase=".ssh/authorized_keys";
        }
    }
    print_message("V", "Key Type: $key");
    print_message("V", "Private key file: $gdfbase");
    print_message("V", "Public key file: ".
                  "$gdfbase.pub");
    print_message("V", "Authorized keys file: ".
                  "$gdfauthbase");
    if (defined($log)) {
        print_message("V", "Log file: ".
                      "$log");
    }
    if ($delete_key) {
        print_message("V", "Delete Key option is specified");
    }
    return $SUCCESS;
}

# Find correct path for all required system command used by
# cmsshsetup tool.
sub findBasicCommandPath { 		
    my (@commandArray) = (); 		
    my $cmd=undef; 		
    my $ret = undef;
    my $cmd_full_path = undef;
    my @output = ();
    foreach(@systemcommand) { 		
        $cmd=$_; 		
        ($ret, @output) = runandCaptureCommand("command -v $cmd");
        if ( $ret eq $SUCCESS) { 		
            $cmd_full_path = "@output";
            chomp($cmd_full_path);
            push(@commandArray, $cmd_full_path); 		
        } else { 		
            print_message("E", "cmsshsetup tool requires system command ". 		
                          "$cmd, which does not exist on system"); 		
            return; 		
        } 		
    } 		
    return @commandArray; 		
}

#  Set basic system command required for cmsshsetup tool 		
sub setBasicCommandPath { 		
    my @cmd = findBasicCommandPath(); 		
    my $fn="setBasicCommandPath "; 		
    if (scalar(@cmd) == 0 ) { 		
       exit $FAILURE; 		
    } 		
    return (@cmd); 		
}

#------------------------------------------------------------------------------
#
# Subroutine    : getLocalUserHome()
# Calls         : print_message
# Called by     : main
# Globals       : -
# Input Params  : luser
# Return Value  : It will return local user home or exit from program with ret-
#                 urn 1.
#
# Returns local host user name.
#
#------------------------------------------------------------------------------
sub getLocalUserHome {
    my ($luser) = @_;
    my $yourfile = "/etc/passwd";
    my @lines = ();
    my $ret   = $FAILURE;
    if ( -r $yourfile) {
       ($ret, @lines) = runandCaptureCommand("$CAT $yourfile");
       if ($ret ne $SUCCESS) {
          print_message("E", "Unable to get local user [$luser] home".
                        " from file [$yourfile]");
          exit $FAILURE
       }
       my @f = grep { chomp($_) == m/^$luser/ } @lines;
       if (scalar(@f) != 0) {
          my @values = split(':', "@f");
          print_message("V", "Local user [$luser] home: ".$values[5]);
          return $values[5];
       } else {
          print_message("E", "Unable to get local user [$luser] home".
                        " from file [$yourfile]");
          exit $FAILURE
       }
    } else {
       print_message("E", "Unable to access [$yourfile] and get local user ".
                     "[$luser] home");
       exit $FAILURE
    }
}

#------------------------------------------------------------------------------
#
# Subroutine    : definePubPrivAuthFileNames()
# Calls         : -
# Called by     : main
# Globals       : gdfbase and gdfauthbase
# Input Params  : -
# Return Value  : - 
#
# Pass in the names of variables to be defined,
# e.g. define file names prv pub auth files as
# global variables.
#
#------------------------------------------------------------------------------
sub definePubPrivAuthFileNames {
    my ($dfprv, $dfpub, $dfauth) = @_;

    # Define the private filename.
    if (!defined($dfprv)) {
        $gprivkeyfile=$gdfbase;
    }

    # Define the public filename.
    if (!defined($dfpub)) {
        $gpubkeyfile=$gdfbase.".pub";
    }

    # Define the authorized_keys file.
    if (!defined($dfauth)) {
        $gauthkeyfile=$gdfauthbase;
    }
    return;
}


#------------------------------------------------------------------------------
#
# Subroutine    : buildHashTableFromFile()
# Calls         : runandCaptureCommand
# Called by     : findKeyPresenceInAuthFile
# Globals       : -
# Input Params  : filename
# Return Value  : It will return hash map from each line of command.
#
# Build hash table with each line from any file
# and return hash table and first line as data
#
#------------------------------------------------------------------------------
sub buildHashTableFromFile  {
    my ($fileName) = @_;
    my(%hash_table);
    my $line_counter = 0;
    my $data = undef;
    my $ret = $FAILURE;
    my @temp = ();
    #some code to build hash table: "%hash_table" for e.g
    ($ret, @temp) = runandCaptureCommand("$CAT $fileName");
    $line_counter = 0;
    foreach(@temp) {
        chomp ($_); #-only if you want to get rid of 'endl' sign
        $line_counter++;
        if (!($_ =~ m/^\s*$/)) {
            $data=$_;
            $hash_table{$_}=$line_counter;
        }
    }
    return (\%hash_table, $data, $ret);
}

#------------------------------------------------------------------------------
#
# Subroutine    : appendPublicKeyToAuthFile()
# Calls         : -
# Called by     : setLocalHostKeys, pullPubKeyFromRemoteToLocal
# Globals       : -
# Input Params  : publicKeyFile and authFile
# Return Value  : It will return 0 on successfully copy of contains from one to
#                 other file othersie return 1 if any of file is unable to access.
#
# Append public keys from public key file to auth file.
#
#------------------------------------------------------------------------------
sub appendPublicKeyToAuthFile {
    my ($publicKeyFile, $authFile) = @_;
    if ( !-r $publicKeyFile) {
       print_message("V", "Unable to read public key file [$publicKeyFile]");
       return $FAILURE; 
    }
    open my $in,  '<',  $publicKeyFile;
    open my $out, '>>', $authFile;
    if ( !-e $authFile) {
       print_message("V", "Unable to access authorized key file [$authFile]");
       return $FAILURE; 
    }
    while( <$in> ) {
        print $out $_;
    }
    close $out;
    close $in;
    return $SUCCESS;
}

#------------------------------------------------------------------------------
#
# Subroutine    : findKeyPresenceInAuthFile()
# Calls         : buildHashTableFromFile
# Called by     : setLocalHostKeys, pullPubKeyFromRemoteToLocal
# Globals       : -
# Input Params  : publicKeyFile and authFile
# Return Value  : It will return 0 on if key found in auth file
#                 otherwise return 1 if key not found
#
# Check for public key presentence auth file for
# local host
#
#------------------------------------------------------------------------------
sub findKeyPresenceInAuthFile {
    my ($pubkey_file, $auth_file) = @_;
    my %file_1_hash;
    my $line_counter = 0;
    my $foundKey = "false";
    my $ref  = undef;
    my $ret  = $FAILURE;
    my $data = undef;
    my $temp = undef;

    ($ref, $data, $ret) = &buildHashTableFromFile("$auth_file");

    if ($ret eq $SUCCESS) {
        #read and compare auth key file with public key file to search for key
        if ( !-r $pubkey_file ) {
            print_message("V", "Unable to read public key file [$pubkey_file]");
            return $FAILURE;
        }
        open (FILE2,"<$pubkey_file");
        $line_counter = 0;
        while ($temp=<FILE2>) {
            $line_counter++;
            chomp ($temp);
            if (defined ${$ref}{$temp}) {
                $foundKey="true";
                last;
            }
        }
        close (FILE2);
    }

    if ($foundKey eq "true") {
        return $SUCCESS;
    } else {
        return $FAILURE;
    }
}

#------------------------------------------------------------------------------
#
# Subroutine    : setLocalHostKeys()
# Calls         : findKeyPresenceInAuthFile, appendPublicKeyToAuthFile,
#                 print_message
# Called by     : main
# Globals       : gprivkeyfile, gpubkeyfile, gauthkeyfile
# Input Params  : lhost
# Return Value  : It will return 0 public key of local host has been successfully
#                 added to auth file on local host otherwise return 1 for any
#                 failure.
#
# Generate key pair and sets up access to local
# host.
#
#------------------------------------------------------------------------------
sub setLocalHostKeys {
    my ($lhost) = @_;
    definePubPrivAuthFileNames();
    my $prvf  = $gprivkeyfile;
    my $pubf  = $gpubkeyfile;
    my $authf = $gauthkeyfile;
    my $privKeyNotFound = $FAILURE;
    my $pubKeyNotFound  = $FAILURE;
    my $cmd   = undef;
    my $ret   = $FAILURE;
    my $logit = undef;

    # Syslog entry.
    $logit="logger -i -t $luser added an entry to $HOME/$authf ".
           "for $lhost";
    # Generate keys on local if needed.
    if ((!-f "$HOME/$prvf") || (-z "$HOME/$prvf")) {
        print_message("V", "Unable to find key pair file, there is no private ".
                      "key file [$HOME/$prvf] or file size is zero for ".
                      "corresponding public key file ".
                      "[$HOME/$pubf] key pair on local host [$lhost]");
        $privKeyNotFound = $SUCCESS;
    }
    if ((!-r "$HOME/$pubf") || (-z "$HOME/$pubf")) {
        print_message("V", "Unable to access key pair file, there is no public ".
                      "key file [$HOME/$pubf] or file size is zero for ".
                      "corresponding private key file ".
                      "[$HOME/$prvf] key pair on local host [$lhost]");
        $pubKeyNotFound = $SUCCESS;
    }
    if (($privKeyNotFound eq $SUCCESS) || ($pubKeyNotFound eq $SUCCESS)) {
        runandCaptureCommand("$UNLINK $HOME/$pubf");
        runandCaptureCommand("$UNLINK $HOME/$prvf");
        $ret = $FAILURE; # To reset variable
        $cmd = "$SSHKEYGEN $quiet"." -P "."\"\""." -f "."$HOME/".
               $prvf." -t $key";
        ($ret) = runandCaptureCommand($cmd);
        if ($ret eq $SUCCESS) {
            print_message("V", "Generated public-private ".
                           "key pair at local host [$lhost]");
        } else {
            print_message("V", "Unable to generate key pair on local ".
                          "host [$lhost]");
            return $FAILURE
        }
    }

    # Add the local public key to the auth file.
    if (!-w "$HOME/$authf") {
        if (-r "$HOME/$pubf") {
            copy("$HOME/$pubf", "$HOME/$authf");
            ($ret) = runandCaptureCommand($logit);
            if ($ret ne $SUCCESS) {
                print_message("M", "Warning: Unable to log message ".
                              "via logger command that Successfully ".
                              "appended public key of local host [$lhost] ". 
                              "to authorized keys file [$HOME/$authf] ".
                              "at local host [$lhost].");
            }
            $cmd = "$ECHO \"$tag\" >> $HOME/$authf";
            runandCaptureCommand($cmd);
        } else {
            print_message("V", "Failed to append public key of local ".
                          "host [$lhost] in authorized keys file ".
                          "[$HOME/$authf] at local host [$lhost]");
            return $FAILURE
        }
    } else {
        if (findKeyPresenceInAuthFile("$HOME/$pubf", "$HOME/$authf")
            ne $SUCCESS) {
            if (appendPublicKeyToAuthFile("$HOME/$pubf", "$HOME/$authf")
                ne $SUCCESS) {
                print_message("V", "Failed to append public key of local ".
                              "host [$lhost] in authorized keys file ".
                              "[$HOME/$authf] at local host [$lhost]");
                return $FAILURE;
            } else {
                $cmd = "$ECHO \"$tag\" >> $HOME/$authf";
                runandCaptureCommand($cmd);
                print_message("V", "Appended public key of local host ".
                              "[$lhost] in authorized keys file [$HOME/$authf] at ".
                              "local host [$lhost]");
            }
        } else {
            print_message("V", "Found public key of local host [$lhost] ".
                          "in authorized keys file [$HOME/$authf] at ".
                          "local host [$lhost]");
        }
    }
    return $SUCCESS;
}


#------------------------------------------------------------------------------
#
# Subroutine    : exchangePubKeyBwLocalAndRemote()
# Calls         : pushPubKeyFromLocalToRemote, pullPubKeyFromRemoteToLocal
#                 print_message
# Called by     : main
# Globals       :
# Input Params  : lhost, $other
# Return Value  : It will return 0 if exchange of public key between local host 
#                 and remote node has been done successfully otherwise return 1
#                 for any failure.
#
# Exchange public keys bewteen local host and all remote hosts.
#
#------------------------------------------------------------------------------
sub exchangePubKeyBwLocalAndRemote {
    my ($lhost, $other)=@_;
    # Push the local public key to the other system
    # This allows us to access the other node
    if (pushPubKeyFromLocalToRemote($lhost,$other) ne $SUCCESS) {
        print_message("E", "Unable to push public key from ".
                      "local host [$lhost] to remote host [$other]");
        return $FAILURE;
    }

    # Pull other system public key to the local host
    if (pullPubKeyFromRemoteToLocal($lhost,$other) ne $SUCCESS) {
        print_message("E", "Unable to pull public key from ".
                      "remote host [$other] to local host [$lhost]");
        return $FAILURE;
    }
    return $SUCCESS;
}

#------------------------------------------------------------------------------
#
# Subroutine    : pushPubKeyFromLocalToRemote()
# Calls         : runandCaptureCommand, buildHashTableFromFile, print_message, 
#                 testAccessOfHost, definePubPrivAuthFileNames
# Called by     : exchangePubKeyBwLocalAndRemote
# Globals       : gpubkeyfile, gprivkeyfile, gauthkeyfile
# Input Params  : lhost, $other
# Return Value  : It will return 0 if public key of local host has been 
#                 has been appended to auth file of remote node otherwise 
#                 return 1 for any failure.
#
# Push the local public key to the remote host to
# setup access for local
#
#------------------------------------------------------------------------------
sub pushPubKeyFromLocalToRemote {
    my ($lhost, $other)=@_;
    # Get the name of the pubfile (short form).
    definePubPrivAuthFileNames();
    my $prvf     = $gprivkeyfile;
    my $pubf     = $gpubkeyfile;
    my $authf    = $gauthkeyfile;
    my $data          = undef;
    my $ref           = undef;
    my $logit         = undef;
    my $line_counter  = undef;
    my $temp_command  = undef;
    my $ret           = $FAILURE;
    my $foundKey      = "false";
    my $accessFailure = "false";
    my @node          = ();
    my @temp          = ();
    my @tempData      = ();
    my $cmd           = undef;


    # We must have access to the remote system.
    # If not we must always ask.
    print_message("M", "If asked, enter password and/or add ".
                  "fingerprint for $luser\@$other");

    # Make the directory and append local key to other's
    # authorization file. Write to syslog if we add an
    # entry to the auth file.
    $logit = "logger"." "."-i -t $luser added an entry to ".
             "$HOME/$authf for $lhost";

    if ( -r "$HOME/$pubf") {
        ($ref, $data, $ret) = &buildHashTableFromFile("$HOME/$pubf");
        if ($ret eq $SUCCESS) {
            @tempData = split(' ', $data);
        } else {
            $accessFailure = "true";
        }
    } else {
        $accessFailure = "true";
    }

    if ($accessFailure eq "true") {
        print_message("V", "Unable to access public key file".
                      "[$HOME/$pubf] at local host [$lhost]"); 
        print_message("V", "Unable to setup ssh connection for remote ".
                      "host [$other] from local host [$lhost]");
        return $FAILURE;
    }

    $cmd = "$SSH_COPY_ID -i $HOME/$pubf $other";

    ($ret) = runandCaptureCommand($cmd);

    if ($ret eq $SUCCESS) {
        $cmd = "$SSH $sshctout $quiet $other $logit";
        ($ret) = runandCaptureCommand($cmd);
        if ($ret ne $SUCCESS) {
             print_message("M", "Warning: Unable to log message via logger command ".
                           "that Successfully appended public key of local host ".
                           "[$lhost] to authorized keys file [$HOME/$authf] ".
                           "at remote host [$other]");
        }
        $cmd = "$SSH $sshctout $quiet $other \"sh -c '$ECHO \"$tag\" >> $HOME/$authf'\"";
        runandCaptureCommand($cmd);
        print_message("V", "Appended public key of local host [$lhost] in ".
                      "authorized keys file [$HOME/$authf] at remote host [$other]");
    } else {
        print_message("V", "Unable to add public key of local host [$lhost] to ". 
                      "authorized keys file [$HOME/$authf] at remote host [$other]");
        print_message("V", "Unable to setup ssh connection for remote ".
                      "host [$other] from local host [$lhost]");
        return $FAILURE;
    }

    # Check access, we might not have it.
    if ( testAccessOfHost($lhost, $lhost, $other, "no", "yes") ne $SUCCESS) {
        print_message("V", "Failed to do ssh connection from local host [$lhost] ".
                      "to remote host [$other]");
        return $FAILURE;
    }
    return $SUCCESS;
}


#------------------------------------------------------------------------------
#
# Subroutine    : pullPubKeyFromLocalToRemote()
# Calls         : definePubPrivAuthFileNames, runandCaptureCommand, 
#                 findKeyPresenceInAuthFile, appendPublicKeyToAuthFile
#                 print_message
# Called by     : exchangePubKeyBwLocalAndRemote
# Globals       : gpubkeyfile, gprivkeyfile, gauthkeyfile
# Input Params  : lhost, $other
# Return Value  : It will return 0 if public key of remote host has been
#                 has been appended to auth file of local node otherwise
#                 return 1 for any failure.
#
# Add public key of "other" (remote host) to local host authorized_keys and 
# Generate keys (if needed) on the "other" node.
#
#------------------------------------------------------------------------------
sub pullPubKeyFromRemoteToLocal {
    my ($lhost, $other)=@_;
    my $logit        = undef;
    my $newf         = undef;
    my $keygencmd    = undef;
    my @temp_cmd     = ();
    my @temp         = ();
    my $ret          = $FAILURE;
    my $failureInKeygen = "false";
    my $pubFileFound    = "false";
    my $privFileFound   = "false";
    definePubPrivAuthFileNames();
    my $prvf=$gprivkeyfile;
    my $pubf=$gpubkeyfile;
    my $authf=$gauthkeyfile;
    my $cmd          = undef;

    $keygencmd = "$SSHKEYGEN $quiet"." -P "."\"\""." -f ".
                 "$HOME/".$prvf." -t $key";

    # Syslog entry.
    $logit="logger -i -t $luser added an entry to $HOME/$authf ".
           "for $other";

    # Now set up the other node, if needed.
    $temp_cmd[0] = "$SSH $sshctout $quiet $other ".
                   "'$CAT $HOME/$prvf'";
    $temp_cmd[1] = "$SSH $sshctout $quiet $other ".
                   "'$UNLINK $HOME/$prvf'";
    $temp_cmd[2] = "$SSH $sshctout $quiet $other ".
                   "'$UNLINK $HOME/$pubf'";

    ($ret, @temp) = runandCaptureCommand($temp_cmd[0]);
    if ($ret eq $SUCCESS) {
        if (scalar(@temp) == 0) {
            # To make sure keygen command will pass, we need to remove
            # private key file of zero size.
            ($ret) = runandCaptureCommand($temp_cmd[1]);
            if ($ret ne $SUCCESS) {
                $failureInKeygen = "true";
            }
        } else {
            $privFileFound = "true";
        }
    }

    $temp_cmd[0] = "$SSH $sshctout $quiet $other ".
                   "'$CAT $HOME/$pubf'";
    @temp = ();
    $ret  = $FAILURE;
    ($ret, @temp) = runandCaptureCommand($temp_cmd[0]);
    if ($ret eq $SUCCESS) {
        if (scalar(@temp) == 0) {
            # To make sure keygen command will pass, we need to remove
            # private key file of zero size.
            ($ret) = runandCaptureCommand($temp_cmd[0]);
            if ($ret ne $SUCCESS) {
                $failureInKeygen = "true";
            }
        } else {
            $pubFileFound = "true";
        }
    }

    if ( "$failureInKeygen" eq "true") {
        print_message("V", "Unable to generate key pair at ".
                      "remote host [$other]");
        return $FAILURE;
    } 

    if (($pubFileFound ne "true") || ($privFileFound ne "true")) { 
        runandCaptureCommand($temp_cmd[1]);
        runandCaptureCommand($temp_cmd[2]);
        ($ret) = runandCaptureCommand("$sshstrictno $other '$keygencmd'");
        if ($ret eq $SUCCESS) {
            print_message("V", "Generated public-private key ".
                          "pair at remote host [$other]");
        } else {
            print_message("V", "Unable to generate key pair at ".
                          "remote host [$other]");
            return $FAILURE;
        }
    }

    $newf = getNewPubName($other);
    my $temp_newfile="$HOME/$newf";

    $temp_cmd[0] = "$SSH $sshctout $other ".
                   "'$CAT $HOME/$pubf' > $temp_newfile";
    ($ret) = runandCaptureCommand($temp_cmd[0]);
    if ($ret ne $SUCCESS) {
        print_message("V", "Unable to access file [$temp_newfile] at".
                      " remote host [$other]");
        return $FAILURE;
    } 

    # Add the local public key to the auth file.
    if (findKeyPresenceInAuthFile("$HOME/$newf", "$HOME/$authf") ne $SUCCESS) {
        if (appendPublicKeyToAuthFile( "$HOME/$newf", "$HOME/$authf") ne $SUCCESS) {
            print_message("V", "Failed to append key in $HOME/$authf");
            return $FAILURE;
        }
        ($ret) = runandCaptureCommand($logit);
        if ($ret ne $SUCCESS) {
             print_message("M", "Warning: Unable to log message via logger ".
                           "command that Successfully appended public key of ".
                           "remote host [$other] ".
                           "to authorized keys file [$HOME/$authf] ".
                           "at local host [$lhost]");
        }
        $cmd = "$ECHO $tag >> $HOME/$authf";
        runandCaptureCommand($cmd);
        print_message("V", "Appended public key of remote host [$other] ".
                      "to authorized keys file [$HOME/$authf] at local ".
                      "host [$lhost]");
    } else {
        print_message("V", "Found public key of remote host [$other] ".
                      "in authorized keys file ".
                      "[$HOME/$authf] at local host [$lhost]");
    }
    return $SUCCESS;
}

#------------------------------------------------------------------------------
#
# Subroutine    : getNewPubName()
# Calls         : definePubPrivAuthFileNames
# Called by     : distributeKeyBwHosts
# Globals       : gpubkeyfile
# Input Params  : data (host name)
# Return Value  : It will return pubic key file name with appended name of
#                 host.
#
# Gets a public key from passed host name and store
# as a temporary public key of a given host.
#
#------------------------------------------------------------------------------
sub getNewPubName {
    my ($data)=@_;
    @_ = split(/\./, $data);
    my $host = shift(@_);
    my $pubf=undef;
    my $gnname=undef;
    definePubPrivAuthFileNames();
    $pubf=$gpubkeyfile;
    # Set the output variable.
    $gnname="$pubf"."_"."$host";
    return $gnname;
}

#------------------------------------------------------------------------------
#
# Subroutine    : distributeKeyBwHosts()
# Calls         : runandCaptureCommand, definePubPrivAuthFileNames
#                 getNewPubName, buildHashTableFromFile, print_message
# Called by     : distributeKeyToAll
# Globals       : gpubkeyfile, gprivkeyfile, gauthkeyfile
# Input Params  : lhost, $other
# Return Value  : It will return 0 if exchange between public keys b/w remote hosts 
#                 has been done successfully otherwise return 1 for any failure.
#
# Push/pull public key between two hosts to setup access.
#
#------------------------------------------------------------------------------
sub distributeKeyBwHosts {
    my ($lhost,$owner,$other)=@_;
    # Get the name of the pubfile (short form).
    definePubPrivAuthFileNames();
    my $prvf  = $gprivkeyfile;
    my $pubf  = $gpubkeyfile;
    my $authf = $gauthkeyfile;
    my $logit = undef;
    my $line  = undef;
    my $data  = undef;
    my $ref   = undef;
    my $temp_cmd      = undef;
    my $line_counter  = undef;
    my $ret           = $FAILURE;
    my $foundKey      = "false";
    my @temp_response = ();
    my $cmd   = undef;

    my $newf=getNewPubName($owner);

    # We do not need to setup this combination,
    # already done by setLocalHostKeys.
    if (($lhost eq $owner) || ($lhost eq $other)) {
         return $SUCCESS;
    }

    # Make the directory and append local key to other's
    # authorization file. Write to syslog if we add an entry
    # to the auth file.
    $logit="logger"." "."-i -t $luser added an entry to $HOME/$authf ".
           "for $owner";

    if (-f "$HOME/$newf") {
        ($ref, $data, $ret) = &buildHashTableFromFile("$HOME/$newf");
        if ($ret ne $SUCCESS) {
            print_message("V", "Unable to access file [$HOME/$newf] at ".
                          "remote host [$owner]");
            print_message("V", "Unable to setup ssh connection for remote ".
                          "host [$other] from remote host [$owner]");
            return $FAILURE;
        }
    } else {
        print_message("V", "Unable to access file [$HOME/$newf] at ".
                      "remote host [$owner]");
        print_message("V", "Unable to setup ssh connection for remote ".
                      "host [$other] from remote host [$owner]");
        return $FAILURE;
    }

    $temp_cmd = "$sshstrictyes $other '$CAT $HOME/$authf'";
    ($ret, @temp_response) = runandCaptureCommand($temp_cmd);
    if ($ret eq $SUCCESS) {
        $line_counter = 0;
        foreach(@temp_response) {
            $line_counter++;
            chomp ($_);
            if (defined ${$ref}{$_}) {
                 $foundKey="true";
                 last;
            }
        }
    }

    if ("$foundKey" eq "true") {
        print_message("V", "Found public key of remote host [$owner] ".
                      "in authorized keys file [$HOME/$authf] at ".
                      "remote host [$other]");
    } else {
        $temp_cmd = "$sshstrictyes $other '$ECHO $data >> $HOME/$authf'|";
        $ret = $FAILURE;     # Reset variable
        @temp_response = (); # Reset variable
        ($ret, @temp_response) = runandCaptureCommand($temp_cmd);
        if ($ret eq $SUCCESS) {
              $cmd = "$sshstrictyes $other"." ".$logit;
              ($ret) = runandCaptureCommand($cmd);
              if ($ret ne $SUCCESS) {
                  print_message("M", "Warning: Unable to log message ".
                                "via logger command that Successfully ".
                                "added public key of remote host [$owner] ".
                                "to authorized keys file [$HOME/$authf] ".
                                "at remote host [$other]");
              }
              $cmd = "$SSH $sshctout $quiet $other \"sh -c '$ECHO \"$tag\" >> $HOME/$authf'\"";
              runandCaptureCommand($cmd);
              print_message("V", "Added public key of remote host [$owner] ".
                            "to authorized keys file [$HOME/$authf] ".
                            "at remote host [$other]");
        } else {
            print_message("V", "Failed to add public key of remote host ".
                          "[$owner] to authorized keys file [$HOME/$authf] ".
                          "at remote host [$other]");
            print_message("V", "Unable to setup ssh connection for remote ".
                          "host [$other] from remote host [$owner]");

            return $FAILURE;
        }
    }
    return $SUCCESS;
}

#------------------------------------------------------------------------------
#
# Subroutine    : distributeKeyToAll()
# Calls         : distributeKeyBwHosts, print_message
# Called by     : main 
# Globals       : @goodhostlist
# Input Params  : lhost, owner
# Return Value  : It will return 0 if exchange between public keys amongs all 
#                 remote hosts has been done successfully otherwise return 1 
#                 for any failure.
#
# Push/pull public key among all hosts. The public key is to be distributed from 
# owner to all systems in hostlist.
#
#------------------------------------------------------------------------------
sub distributeKeyToAll {
    my ($lhost,$owner)=@_;
    my $other=undef;
    # Assume we can ssh to owner from here.
    # From there, copy the public file to each of the
    # other hosts.
    foreach(@goodhostlist) {
       $other=$_;
       if (distributeKeyBwHosts($lhost,$owner,$other) ne $SUCCESS) {
           print_message("V", 
                         "Unable to exchange keys between [$owner] and [$other]");
       }
    }
    return $SUCCESS;
}

#------------------------------------------------------------------------------
#
# Subroutine    : checkForValidIpAddress()
# Calls         : -
# Called by     : main
# Globals       : -
# Input Params  : str 
# Return Value  : SUCESSS [0] -> Passed string is a IP address.
#                 FAILURE [1] -> Passed string is not a IP address.
#
# This function validates passed string is a IP address or normal string then 
# send back response as SUCESSS or FAILURE that will be used while convert any
# string into full qualifiied name.
# 
#
#------------------------------------------------------------------------------
sub checkForValidIpAddress {
    my ($str) = @_;
    chomp($str);
    my $return_value = $FAILURE;
    my $x = "2[0-4]";
    my $y = "25[0-5]";
    my $w = "[01]";
    if ($str =~
        m/^($w?\d\d?|$x\d|$y)\.($w?\d\d?|$x\d|$y)\.($w?\d\d?|$x\d|$y)\.($w?\d\d?|$x\d|$y)$/) {
        $return_value = $SUCCESS;
    }
    return $return_value;
}

#------------------------------------------------------------------------------
#
# Subroutine    : getFQHN()
# Calls         : print_message
# Called by     : main
# Globals       : -
# Input Params  : mylhostmylhost and is_ip_address
# Return Value  : It will return full_hostname if passed otherwise program
#                 will exit with value 1;
#
# Get full host name with domain from IP address or short name.
#
#------------------------------------------------------------------------------
sub getFQHN {
    my ($mylhost, $is_ip_address) = @_;
    chomp($mylhost);
    my $temp_lhost = undef;
    my $full_hostname = undef;

    if ($is_ip_address eq "true") {
        $temp_lhost = inet_aton($mylhost);
        if ( defined($temp_lhost)) {
            ($full_hostname) = gethostbyaddr($temp_lhost, AF_INET);
        }
    } else {
        ($full_hostname) = gethostbyname($mylhost);
    }
 
    if (! (defined($full_hostname) && ($full_hostname))) {
        # Just say we could not determine the domain,
        # but no hard failure
        print_message("E", "Unable to determine the ".
                      "fully qualified name ".
                      "for host [$mylhost]");
        exit $FAILURE;
    }

    return $full_hostname;
}

#------------------------------------------------------------------------------
#
# Subroutine    : testAccessOfHost()
# Calls         : print_message
# Called by     : testAccessOfAllHost
# Globals       : goodlist
# Input Params  : local, otehr, result_phase and silent_test
# Return Value  : Return 0 for success and 1 for failure
#
# This quietly tests access between two hosts
#
#------------------------------------------------------------------------------
sub testAccessOfHost {
    my ($local, $owner, $other, $result_phase, $silent_test) = @_;
    my $first_hop ="";
    my $first_hop1="";
    my $cmd;
    my $stat;
    my @temp = ();
    my $localname = undef;
    my $ownername = undef;
    my $othername = undef;
    if (!defined($silent_test)) {$silent_test = "no";}

    @temp = split(/\./, $local);
    $localname = shift(@temp);
    @temp = split(/\./, $owner);
    $ownername = shift(@temp);
    @temp = split(/\./, $other);
    $othername = shift(@temp);

    if ($localname ne $ownername) {
        $first_hop="$sshstrictno $batchyes $owner ";
        $first_hop1="$sshstrictno $batchyes $ownername ";
    }

    # Add the shortname hostname to the known_hosts file.
    $cmd="$first_hop1"." $sshstrictno $batchyes $othername hostname";
    ($stat) = runandCaptureCommand($cmd);
    if ($stat != $SUCCESS) {
        if (($result_phase eq "no")) {
        print_message("E", "Unable to add the host shortname ".
                      "[$othername] to known_hosts at host ".
                      "[$ownername]");
        }
        return $FAILURE
    } else {
        if (($result_phase eq "no") && ($silent_test eq "no")) {
            print_message("V", "Added host shortname ".
                          "[$othername] to known_hosts at host [$ownername]");
        }
    }

    $cmd="$first_hop"." $sshstrictno $batchyes $other hostname";
    if (($result_phase eq "no") && ($silent_test eq "no")) {
        print_message("V", "Test start from [$othername] to [$ownername]");
        ($stat) = runandCaptureCommand($cmd);
        print_message("V", "Test status : [$stat]");
        print_message("V", "Test stop from [$othername] to [$ownername]");
    }
    return $stat;
}
#------------------------------------------------------------------------------
#
# Subroutine    : testAccessOfAllHost()
# Calls         : print_message, testAccessOfHost
# Called by     : main
# Globals       : goodlist
# Input Params  : local, result_phase
# Return Value  : -
#
# Test ssh setup among all hosts
#
#------------------------------------------------------------------------------
sub testAccessOfAllHost {
    my ($result_phase, $lhost, @host_list) = @_;
    my $i=0;
    my $j=0;
    #@host_list = @goodhostlist;
    foreach $i (@host_list) {
        foreach $j (@host_list) {
            if (testAccessOfHost($lhost, $i, $j, $result_phase)
                eq $SUCCESS) {
                if ($result_phase eq "yes") {
                    print_message("S","$i -> $j");
                }
            } else {
                if ($result_phase eq "yes") {
                    print_message("F", "$i -> $j");
                }
            }
        }
    }
}

#------------------------------------------------------------------------------
#
# Subroutine    : cleanupTempKeyFiles()
# Calls         : unlink system call, getNewPubName, print_message
# Called by     : main
# Globals       : -
# Input Params  : rhost and lhost
# Return Value  : It will return success if all temp file has been deleted 
#                 
# Remove temporary files
#
#------------------------------------------------------------------------------
sub cleanupTempKeyFiles {
    my ($rhost,$lhost)=@_;
    my $newf=getNewPubName($rhost);
    # Remove keys stored in temporary files.
    if ( $rhost ne $lhost )  {
       if ( -f "$HOME/$newf") {
           my ($ret) = runandCaptureCommand("$UNLINK $HOME/$newf");
           if ($ret eq $SUCCESS) {
               print_message("V", "Removed temp file [$HOME/$newf] ".
                             "at local host [$lhost]")
           } else {
               print_message("M", "Warning:  Unable to remove temp file ".
                             "[$HOME/$newf] at local host [$lhost]");
           }
       } else {
           print_message("V", "Not found temp file [$HOME/$newf] ".
                         "at local host [$lhost]")
       }
    }
   return $SUCCESS;
}

#------------------------------------------------------------------------------
#
# Subroutine    : cleanupKeysFromAuthfile()
# Calls         : print_message, runandCaptureCommand
# Called by     : main
# Globals       : goodlist
# Input Params  : local, host_list
# Return Value  : Success if it clears the keys 
#                 Failure if it fails to clean keys or no Auth file.
#
#  Removes the ssh keys added by cmsshsetup from authorized_keys file of all
#  hosts.
#
#------------------------------------------------------------------------------
sub cleanupKeysFromAuthfile{
    my (@host_list) = @_;
    my $i=0;
    my $ret;
    my $authf=$gauthkeyfile;
    my $clean_cmd = "\"sed -n -i '/cmsshsetup/{s/.*//;x;d;};x;p;\\\${x;p;}' $authf && sed -i '\/^\$\/d' $authf\"";

    print_message("V", "Key Removal Phase");

    foreach $i (@host_list) {
        if ( -f "$HOME/$gdfauthbase") {
            my $cmd = "$SSH $sshctout $quiet $i $clean_cmd";
            $ret = runandCaptureCommand($cmd);
            if ($ret eq $SUCCESS) {
                print_message("V", "Cleanup done on $i node, Removed ssh key from $HOME/$authf file.");
            } else {
                print_message("V", "Unable to cleanup the ssh key on node $i from $HOME/$authf file.");
                return $FAILURE;
            }
        } else {
            print_message("V", "Not found $gdfauthbase at host [$i]");
            return $FAILURE;
        }
    }
    return $SUCCESS;
}

#------------------------------------------------------------------------------
#
# Subroutine    : trim()
# Calls         : -
# Called by     : main
# Globals       : -
# Input Params  : str 
# Return Value  : It will return trimmed string
#
# Remove all tailing and front white spaces
# from variables and return updated variable.
#
#------------------------------------------------------------------------------
sub trim {
    my ($str) = @_;
    $str =~ s/^\s+//;
    $str =~ s/\s+$//;
    return $str;
}

#------------------------------------------------------------------------------
#
# Subroutine    : main()
# Calls         : getLocalUserHome, checkForValidIpAddress, trim,
#                 runandCaptureCommand, getFQHN, exchangePubKeyBwLocalAndRemote
#                 setLocalHostKeys, distributeKeyToAll, cleanupTempKeyFiles
#                 testAccessOfAllHost, print_message
# Called by     : -
# Globals       : @goodhostlist, @hostlist
# Input Params  : -
# Return Value  : It will exit with 0 for successful and exit with 1 for any
#                 failure.
#
# This is main function which is called by cmsshsetup script.
#
#------------------------------------------------------------------------------
sub main {
    my @lines          = ();
    my $ret            = $FAILURE;
    my $shortlhost     = undef;
    my $index          = 0;
    my $tmpother       = undef;
    my $temp_variable  = undef;
    my $tmpfqn         = undef;
    my $is_ip_addr     = "false";
    my @cmd            = ();

    # Set basic system command path used by cmsshsetup tool 
    @cmd = setBasicCommandPath(); 
    $CAT         = shift(@cmd); 
    $ECHO        = shift(@cmd); 
    $LOGGER      = shift(@cmd); 
    $MKDIR       = shift(@cmd); 
    $SSH         = shift(@cmd); 
    $SSHKEYGEN   = shift(@cmd); 
    $UNLINK      = shift(@cmd);
    $SSH_COPY_ID = shift(@cmd);

    # Get local user.
    ($ret, $luser) = runandCaptureCommand("/usr/bin/whoami");
    if ($ret eq $SUCCESS) {
        chomp($luser);
    } else {
        print_message("E", "Unable to get local user via command ".
                      "[`/usr/bin/whoami`]");
        exit $FAILURE
    }

    # Get local user's home
    ($HOME)= getLocalUserHome($luser);

    # Setup the ssh command options.
    $sshstrictyes="$SSH -l"." ".$luser." ".$quiet." ".$sshctout.
                  " -o StrictHostKeyChecking=yes";
    $sshstrictno="$SSH -l"." ".$luser." ".$quiet." ".$sshctout.
                  " -o StrictHostKeyChecking=no";

    $ret = $FAILURE; # Reset variable 
    ($ret, $shortlhost) = runandCaptureCommand("hostname");

    if ($ret eq $SUCCESS) {
        chomp($shortlhost);
    } else {
        print_message("E", "Unable to get local host name via command ".
                      "[`hostname`]");
        exit $FAILURE
    }

    # Get the fully-qualified name of the host on which we're 
    # running on.
    $lhost = getFQHN($shortlhost, $is_ip_addr);

    # Reset the flag so it can be reuse in below code.
    $is_ip_addr = "false";

    # Prepare hostlist. Strip out the commented lines or
    # add the single host to the list.
    if ($file) {
        ($ret, @lines) = runandCaptureCommand("$CAT $file");
        if ($ret eq $SUCCESS) {
            foreach(@lines) {
                if (chomp($_) != /^#/) {
                    # If file contains line with heading and
                    # tailing whitespaces so that must be
                    # removed and adding updated string as
                    # valid element or host name in hostlist.
                    $_ = trim($_);
                    # If file contains line with black or only
                    # white spaces. Avoid adding as a vaild
                    # element or host name in hostlist.
                    unless($_ =~ /^\s*$/) {
                        push(@hostlist, $_);
                    }
                }
            }
        } else {
            print_message("E", "Unable to get host names from Hostfile ".
                          "$file does not exist");
            exit $FAILURE;
        }
    }

    print_message("V", "Host list: ");
    foreach(@hostlist) {
        print_message("V", "\tHost [$index]: $_");
        $index++;
    }
    print_message("V", "Verification Phase");
    # Handle the cases where hostlist contains only one host name
    # convert host name into fully qualified domain name and
    # add it into a list called @hostfqn
    #
    # Case 1: Single host name is local host then set variable
    #         "localhostonly" as true.
    #
    # Case 2: Single host name is a remote node then set variable
    #         "localhostonly" as false.
    if (scalar(@hostlist) == 1) {
        if (checkForValidIpAddress($hostlist[0]) eq $SUCCESS) {
            $is_ip_addr = "true";
        }
        $tmpfqn =
            getFQHN($hostlist[0], $is_ip_addr);
        if ($tmpfqn eq $lhost) {
            $localhostonly="true";
        } else {
            push(@hostfqn, $lhost);
        }
        push(@hostfqn, $tmpfqn);
    }
    # Get the fully qualified domain name for each element in hostlist
    # and add them in a list called @hostfqn.
    # If hostlist file contains host IP address or host's short name
    # instead of fully qualified domain name then convert them into
    # fully qualified domain name via function "getFQHN"
    else {
        foreach $temp_variable (@hostlist) {
            if (checkForValidIpAddress($temp_variable) eq $SUCCESS) {
                $is_ip_addr = "true";
            }
            $tmpfqn =
                getFQHN($temp_variable, $is_ip_addr);
            # Reset the flag so it can be reuse for each element in list @hostlist.
            $is_ip_addr = "false";
            if (defined($tmpfqn) &&
                $tmpfqn ne $lhost) {
                push(@hostfqn, $tmpfqn);
            }
        }
        # To find local host is part of valid hostlist,
        # if not add it to hostlist
        my %params = map { $_ => 1 } @hostfqn;
        if (!exists($params{$lhost})) {
            push(@hostfqn, $lhost);
        }
    }

    print_message("V", "Host list after conversion into fully qualified name: ");
    $index=0;
    foreach $temp_variable (@hostfqn) {
        chomp($temp_variable);
        print_message("V", "\tHost [$index]: [$temp_variable] is a valid host");
        $index++;
    }

    if ($testonly) {
        print_message("V", "Result Phase");
        print_message("M", "cmsshsetup result");
        testAccessOfAllHost("yes", $lhost, @hostfqn);
        print_message("V", "End cmsshsetup");
        exit $SUCCESS;
    }

    # Set up the keys on the local system.
    print_message("V", "SSH Setup Phase");
    if (setLocalHostKeys($lhost) ne $SUCCESS) {
        print_message("E", "Unable to setup ssh for local system [$lhost]");
        exit $FAILURE;
    }

    if ($localhostonly eq "true") {
        @lines = (); #To reset value
        $ret = 1;    #To reset value
        $temp_variable = "$SSH $sshctout $lhost $ECHO ".
                         "'Success: local host [ $lhost ] setup'";
        ($ret, @lines) = runandCaptureCommand($temp_variable);
        if (( $ret eq $SUCCESS) && ("@lines" =~ /Success:/)) {
            chomp(@lines);
            push(@goodhostlist, $lhost);
            print_message("V", "Connection Test Phase");
            testAccessOfAllHost("no", $lhost, @goodhostlist);
            print_message("V", "Result Phase");
            print_message("M", "cmsshsetup result");
            testAccessOfAllHost("yes", $lhost, @goodhostlist);
            if ($delete_key) {
                print_message("V", "Delete key option specified, hence".
                             " added ssh keys will be removed from auth file.");
                  $ret = cleanupKeysFromAuthfile(@goodhostlist);
                  if ($ret eq $SUCCESS) {
                      print_message("V", "Key Removal Success"); 
                  } else {
                      print_message("V", "Key Removal Failed"); 
                  }       
            }
            print_message("V", "End cmsshsetup");
            exit $SUCCESS
        } else {
            print_message("E", "Unable to setup ssh for local host ".
                          "[$lhost]");
            exit $FAILURE
        }
    }

    @hostfqn =
        grep { $_ ne $lhost } @hostfqn;
    my $temp=undef;
    foreach $temp (@hostfqn) {
        if (exchangePubKeyBwLocalAndRemote($lhost, $temp) ne
            $SUCCESS) {
            push(@tmp_hostlist, $temp);
        } else {
            push(@goodhostlist, $temp);
        }
    }

    if ( scalar(@tmp_hostlist) != 0 ) {
        foreach(@tmp_hostlist) {
            print_message("E", "Unable to exchange keys with $_");
        }
    }

    if ( scalar(@goodhostlist) == 0 ) {
         print_message("E", "Unable to exchange keys with ".
                       "any remote hosts");
         @goodhostlist = @hostfqn;
         push(@goodhostlist, $lhost);
    } else {
        # To find local host is part of valid hostlist,
        # if not add it to hostlist
        push(@goodhostlist, $lhost);
    }

    foreach(@goodhostlist) {
            distributeKeyToAll($lhost,$_);
    }

    print_message("V", "Connection Test Phase");
    push @hostfqn, $lhost;
    testAccessOfAllHost("no", $lhost, @hostfqn);
    print_message("V", "Cleanup Phase");
    # We are done here, clean up keys stored in temp files.
    foreach (@goodhostlist) {
        cleanupTempKeyFiles($_, $lhost);
    }
    print_message("V", "Result Phase");
    print_message("M", "cmsshsetup result");
    testAccessOfAllHost("yes", $lhost, @hostfqn);
    if ($delete_key) {
        print_message("V", "Delete key option specified, hence added".
                        " ssh keys will be removed from auth file.");
        $ret = cleanupKeysFromAuthfile(@goodhostlist);
        if ($ret eq $SUCCESS) {
            print_message("V", "Key Removal Success");
        } else {
            print_message("V", "Key Removal Failed");
       }
    }
    print_message("V", "End cmsshsetup");

    exit $SUCCESS;
}
