Newer
Older
#!/usr/bin/perl
# awit-ssh - SSH initiator which searches LDAP for host details
# Copyright (c) 2016, AllWorldIT
#
# 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, either version 3 of the License, or
# (at your option) any later version.
#
# 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, see <http://www.gnu.org/licenses/>.
use strict;
use warnings;
# Check Config::IniFiles
if (!eval {require Config::IniFiles; 1;}) {
print STDERR "You're missing Config::IniFiles, try 'apt-get install libconfig-inifiles-perl'\n";
exit 1;
}
# Check IO::Socket::INET6
if (!eval {require IO::Socket::INET6; 1;}) {
print STDERR "You're missing IO::Socket::INET6, try 'apt-get install libio-socket-inet6-perl'\n";
exit 1;
}
# Check Net::LDAP
if (!eval {require Net::LDAP; 1;}) {
print STDERR "You're missing Net::LDAP, try 'apt-get install libnet-ldap-perl'\n";
exit 1;
}
# Check IO::Prompt
if (!eval {require IO::Prompt; 1;}) {
print STDERR "You're missing IO::Prompt, try 'apt-get install libio-prompt-perl'\n";
## no critic (BuiltinFunctions::ProhibitStringyEval)
eval qq(
use IO::Prompt qw(prompt);
);
## use critic
print(STDERR "$NAME v$VERSION - Copyright (c) 2016, AllWorldIT\n\n");
# Grab options
my %optctl = ();
GetOptions(\%optctl,
"help|?",
"version",
# TODO: debug is not implemented, make sure displayHelp is updated
# TODO: Improve globbing before adding it to displayHelp
"globbing",
) or exit 1;
# Check for help
if (defined($optctl{'help'})) {
displayHelp();
exit 0;
}
# Check for version
if (defined($optctl{'version'})) {
displayVersion();
exit 0;
}
my @rsyncParams;
if (defined(my $rsyncHost = $optctl{'rsync'})) {
$useRsync = $rsyncHost;
}
# Check if we using libvirt vnc instead of SSH
my $libvirtVNC;
if (defined(my $vmName = $optctl{'libvirt-vnc'})) {
if (! -x '/usr/bin/ssvncviewer') {
logger('ERROR',color('magenta')."To use --libvirt-vnc you need to install ssvncviewer. Hint: apt-get install ssvnc".
color('reset'));
exit 1;
}
$libvirtVNC = $vmName;
}
# Check if we should be doing port knocking
my ($knockHost,$knockPort);
if (defined(my $knock = $optctl{'knock'})) {
# If so, split off the host and the port
($knockHost,$knockPort) = split(':',$knock);
if (!defined($knockPort)) {
logger('ERROR',color('magenta')."Port knock specifications should be in the format of HOST:PORT".color('reset'));
exit 1;
}
}
# Check for option combinations
if (defined($useRsync) && defined($libvirtVNC)) {
logger('ERROR',color('magenta')."Options --rsync and --libvirt-monitor cannot be used together".color('reset'));
exit 1;
}
# Variables we may set below
my $loginUsername;
# Pull in hostname
foreach my $param (@ARGV) {
# Look for the remote:// param
if ($param =~ /remote:\/\//) {
# Remove it and set the hostSpec
my $removedTag = substr($param,9);
# Assing hostSpec to the first part of the tag
($hostSpec) = split(/[\/:]/,$removedTag);
# Change first / to a :/
$removedTag =~ s,/,:/,;
push(@rsyncParams,$removedTag);
# Else just add it
} else {
push(@rsyncParams,$param);
}
}
# Make sure we got a hostSpec
if (!defined($hostSpec)) {
logger('ERROR',color('magenta')."awit-ssh --rsync needs a remote://SERVER.... to be specified on the command line".
color('reset'));
exit 1;
}
} else {
$hostSpec = shift(@ARGV) // "";
}
my ($loginHost,$loginPort) = split(':',$hostSpec);
if (defined($loginHost)) {
# Suck in username if specified
if (defined($hostBit)) {
$loginUsername = $userBit;
$loginHost = $hostBit;
}
} else {
logger('ERROR',color('magenta')."No hostname provided".color('reset'));
exit 1;
}
# Make sure we save the hostname
my $realLoginHost = $loginHost;
my ($forwardHost,$forwardPort,$forwardUsername,@forwardPortExtra);
# Check for config and read
my $configFile = $ENV{"HOME"}.'/.awit-ssh.conf';
if (! -f $configFile) {
print STDERR "No configuration file found. Please answer the questions below to generate it.\n\n";
tie %iniSetup, 'Config::IniFiles';
$iniSetup{server} = {};
$iniSetup{server}{uri} = prompt("Your LDAP URI : ");
$iniSetup{server}{uri} =~ s/^uri=//;
$iniSetup{server}{base} = prompt("Your LDAP Base : ");
$iniSetup{server}{base} =~ s/^base=//;
tied(%iniSetup)->WriteConfig($configFile) or die "Could not write settings to new configuration file.";
untie %iniSetup;
} else {
# Flag, so we don't echo the same output lower down immediately after a setup.
$iniSetup{server} = 'installed';
}
my $config = Config::IniFiles->new(-file => $configFile);
my $ldapURI = $config->val("server","uri");
if (!defined($ldapURI) || $ldapURI eq "") {
logger('ERROR',color('magenta')."Server URI not defined in config file".color('reset'));
exit 1;
}
my $ldapBase = $config->val("server","base");
if (!defined($ldapBase) || $ldapBase eq "") {
logger('ERROR',color('magenta')."Server base DN not defined in config file".color('reset'));
my $pkcsProvider = $config->val("pkcs11","provider");
if (defined($pkcsProvider) && $pkcsProvider ne "") {
if (! -f $pkcsProvider) {
logger('ERROR',color('magenta')."PKCS11 provider '$pkcsProvider' does not exist".color('reset'));
exit 1;
}
}
if (%iniSetup) {
print STDERR "LDAP server URI : $ldapURI\n";
print STDERR "LDAP server base : $ldapBase\n";
}
# Try get name automatically
my $pwent = getpwnam($ENV{'USER'});
(my $username) = split(/,/,$pwent->gecos);
if (!defined($username) || $username eq "") {
print STDERR "WARNING: Cannot determine your name, set your gecos field.\n\n";
print STDERR "Your LDAP CN : $username (passwd->gecos)\n";
# Sort out LDAP password
my $password;
# Lets try kwallet
my ($kwalletObject,$kwalletHandle);
# IF removed, lets rather run this in its own scope...
{
my $dbus = Net::DBus->find();
# Grab the kwallet service off DBus
my $kwalletService = $dbus->get_service('org.kde.kwalletd');
if (!defined($kwalletService)) {
logger('WARNING',color('magenta')."Kwallet not found on DBus".color('reset'));
goto KWALLET_END;
}
$kwalletObject = $kwalletService->get_object('/modules/kwalletd','org.kde.KWallet');
# Grab a handle to the network wallet
my $networkWalletName = $kwalletObject->networkWallet();
$kwalletHandle = $kwalletObject->open($networkWalletName,0,$NAME);
$password = $kwalletObject->readPassword($kwalletHandle,"ldap","password",$NAME);
# If kwallet returned nothing, try read from terminal
$password = prompt("Your LDAP Password: ", '-echo' => "*");
my $ldap = Net::LDAP->new($ldapURI,
logger('ERROR',color('magenta')."Failed to setup LDAP object '%s'".color('reset'),$@);
my $mesg = $ldap->bind("cn=$username,ou=Users,$ldapBase",password => $password);
base => "ou=Servers,$ldapBase",
filter => "(|(cn=$loginHost)(awitLoginHostAlias=$loginHost))",
if (my $mesgCode = $mesg->code()) {
if ($mesgCode eq "No such object") {
logger('ERROR',color('magenta')."LDAP returned '%s', this more than likely means a Username/Password error or your BaseDN is wrong.".color('reset'),$mesgCode);
logger('ERROR',color('magenta')."LDAP returned '%s'".color('reset'),$mesgCode);

Nigel Kukard
committed
# Some flags we may need
my $needDSS;
# If no matches
my @ldapResults = $mesg->entries();
my $ldapNumResults = @ldapResults;
my $ldapEntry;
if ($ldapNumResults < 1) {
logger('NOTICE',color('bold red')."No LDAP results, using the hostname provided on the commandline".color('reset'));
} elsif ($ldapNumResults == 1) {
$ldapEntry = $ldapResults[0];
} elsif ($ldapNumResults > 1) {
logger('WARNING',color('red')."Found multiple entries!".color('reset'));
print STDERR "\n";
foreach my $key (sort(keys %{$mesg->as_struct()})) {
logger('MENU '.$counter," ".color('red')."%s".color('reset'),$key);
$counter++;
my $menuSelection = prompt("Your selection [1-$ldapNumResults,q]: ",
'-onechar',
'-require' => {
"Invalid Value - Your selection [1-$ldapNumResults,q]: " => sub {
my $val = $_;
return (
# Check if is numeric and its within range
$val =~ /^\d$/ &&
$val > 0 &&
$val <= $ldapNumResults
) || (
# Else our only other option we accept is 'q'
$val eq "q"
);
}
}
);
if ($menuSelection eq "q") {
$menuSelection = $menuSelection->{'value'} - 1;
$ldapEntry = $ldapResults[$menuSelection];
}
print STDERR "\n";
# Check if we got a result and modify our connection details
if ($ldapEntry) {
my $ldapEntryName = $ldapEntry->get_value('cn');
logger('INFO',"Found server entry '".color('green')."$ldapEntryName".color('reset')."'");
# TODO: Ability to select between mulitple awitLoginHost's separated by ,'s
# Check if we need to set the port knocking host & port
if (my $ldapLoginKnockHost = $ldapEntry->get_value('awitLoginKnockHost')) {
logger('INFO'," - Knock host ".color('green')."%s".color('reset')." (awitLoginKnockHost)",$ldapLoginKnockHost);
$knockHost //= $ldapLoginKnockHost;
}
if (my $ldapLoginKnockPort = $ldapEntry->get_value('awitLoginKnockPort')) {
logger('INFO'," - Knock port ".color('green')."%s".color('reset')." (awitLoginKnockPort)",$ldapLoginKnockPort);
$knockPort //= $ldapLoginKnockPort;
}
# Check if we need to set the port forwarding info
if (my $ldapLoginForwardHost = $ldapEntry->get_value('awitLoginForwardHost')) {
logger('INFO'," - Forward host ".color('green')."%s".color('reset')." (awitLoginForwardHost)",$ldapLoginForwardHost);
$forwardHost //= $ldapLoginForwardHost;
}
if (my $ldapLoginForwardPort = $ldapEntry->get_value('awitLoginForwardPort')) {
logger('INFO'," - Forward port ".color('green')."%s".color('reset')." (awitLoginForwardPort)",$ldapLoginForwardPort);
$forwardPort = $ldapLoginForwardPort;
}
if (my $ldapLoginForwardUsername = $ldapEntry->get_value('awitLoginForwardUsername')) {
logger('INFO'," - Forward user ".color('green')."%s".color('reset')." (awitLoginForwardUsername)",$ldapLoginForwardUsername);
$forwardUsername //= $ldapLoginForwardUsername;
}
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
if (my $ldapLoginForwardPortExtra = $ldapEntry->get_value('awitLoginForwardPortExtra')) {
my @tmpList = ();
# Check if this is an array ref or not
if (ref($ldapLoginForwardPortExtra) eq "ARRAY") {
@tmpList = @{$ldapLoginForwardPortExtra};
} else {
@tmpList = ($ldapLoginForwardPortExtra);
}
# Output all the port forwards
foreach my $item (@tmpList) {
my ($localPort,$destHost,$destPort) = split(/:/,$item);
# Check localPort
if (!defined($localPort) || $localPort < 8000) {
logger('WARNING'," - Forward port extra ".color('red')."%s".color('reset').
" (awitLoginForwardPortExtra) is INVALID, localPort check failed",$item);
goto PFEC1;
}
# Check destHost
if (!defined($destHost)) {
logger('WARNING'," - Forward port extra ".color('red')."%s".color('reset').
" (awitLoginForwardPortExtra) is INVALID, destHost check failed",$item);
goto PFEC1;
}
# Check destPort
if (!defined($destPort) || $destPort < 1) {
logger('WARNING'," - Forward port extra ".color('red')."%s".color('reset').
" (awitLoginForwardPortExtra) is INVALID, destPort check failed",$item);
goto PFEC1;
}
# Add port forwarding to our list
push(@forwardPortExtra,{'localPort' => $localPort, 'destHost' => $destHost, 'destPort' => $destPort});
logger('INFO'," - Forward port extra ".color('green')."%s".color('reset')." (awitLoginForwardPortExtra)",$item);
PFEC1:
}
}
if (defined($optctl{'globbing'})) {
$loginHost = $ldapEntryName;
}
if (my $ldapLoginHost = $ldapEntry->get_value('awitLoginHost')) {
logger('INFO'," - Host ".color('green')."%s".color('reset')." (awitLoginHost)",$ldapLoginHost);
}
# Check if we need to set the port
if (my $ldapLoginPort = $ldapEntry->get_value('awitLoginPort')) {
logger('INFO'," - Port ".color('green')."%s".color('reset')." (awitLoginPort)",$ldapLoginPort);
# Check if we need to set the username
if (my $ldapLoginUsername = $ldapEntry->get_value('awitLoginUsername')) {
logger('INFO'," - User ".color('green')."%s".color('reset')." (awitLoginUsername)",$ldapLoginUsername);
# Check if we have a description
if (my $ldapDescription = $ldapEntry->get_value('description')) {
logger('INFO',"Description");
foreach my $line (split(/\n/,$ldapDescription)) {
logger('INFO'," ".color('green')."%s".color('reset'),$line);

Nigel Kukard
committed
# Hack'ish ... look if the description mentions dss is required...
if ($ldapDescription =~ /needs ssh-dss/i) {
$needDSS = 1;
}
}
# Check if we have a wiki page
if (my $ldapLoginWikiPage = $ldapEntry->get_value('awitLoginWikiPage')) {
logger('INFO'," ".color('green')."%s".color('reset'),$ldapLoginWikiPage);
# If we have kwalletObject and kwalletHandle defined, store the password as we've given awit-ssh-client permission to access
# kwallet
if (defined($kwalletObject) && defined($kwalletHandle)) {
$kwalletObject->writePassword($kwalletHandle,"ldap","password",$password,$NAME);
}
# Check if we need to do port knocking
if (defined($knockHost)) {
# Make sure we have a port knocking port
if (!defined($knockPort)) {
logger('ERROR',color('bold red')."No port knocking port defined!".color('reset'));
logger('NOTICE',"Port knocking '".color('green')."%s".color('reset')."' on port '".color('green')."%s".color('reset')."'...",
$knockHost,$knockPort);
# Do the port knock
my $sock = IO::Socket::INET6->new(
PeerAddr => $knockHost,
PeerPort => $knockPort,
Proto => 'tcp',
Timeout => 3
);
# We should get a failure of "Connection refused", if not ERR
if (defined($sock) || $! ne "Connection refused") {
logger('ERROR',color('bold red')."Port knocking failed!".color('reset'));
if (defined($pkcsProvider) && $pkcsProvider ne "") {
logger('NOTICE',color('blue')."Enabling smartcard/token authentication.".color('reset'));
# Only push the config file override to SSH if the config file exists in the users homedir\
if (-f (my $sshConfigFile = $ENV{"HOME"}.'/.ssh/config')) {
push(@sshArgs,'-F',$sshConfigFile);
}

Nigel Kukard
committed
# If the server is ancient, we need to enable DSS
if (defined($needDSS)) {
logger('WARNING',color('red')."Host needs ssh-dss".color('reset'));

Nigel Kukard
committed
push(@sshArgs,'-o','PubkeyAcceptedKeyTypes=+ssh-dss');
push(@sshArgs,'-o','HostbasedKeyTypes=+ssh-dss');
push(@sshArgs,'-o','HostKeyAlgorithms=+ssh-dss');
}
# Try our key only, we should never need to fall back to password
push(@sshArgs,'-o','PreferredAuthentications=publickey');
push(@sshArgs,'-o','StrictHostKeyChecking=ask');
# Use TCP keepalive
push(@sshArgs,'-o','TCPKeepAlive=yes');
push(@sshArgs,'-o','ServerAliveInterval=5');
push(@sshArgs,'-o','ServerAliveCountMax=24'); # 120s
# Timeout for our connect
push(@sshArgs,'-o','ConnectTimeout=30');
# Fail if we cannot forward ports
push(@sshArgs,'-o','ExitOnForwardFailure=yes');
# Check if we're doing port forwarding...
foreach my $item (@forwardPortExtra) {
push(@sshArgsPortForwards,'-L',sprintf('%s:%s:%s',$item->{'localPort'},$item->{'destHost'},$item->{'destPort'}));
logger('NOTICE',color('magenta')."Forwarding port '".color('reset').$item->{'localPort'}.color('magenta').
"' on localhost to '".color('reset').$item->{'destHost'}.color('magenta')."' port '" .color('reset').
$item->{'destPort'}.color('magenta')."'\n");
}
# Fixup environment before we start to run SSH
local $ENV{'LANG'} = "en_US.UTF-8";
delete($ENV{'LC_ALL'});
delete($ENV{'LC_TIME'});
delete($ENV{'LC_CTYPE'});
# Setup TMPDIR, we prefer XDG_RUNTIME_DIR as its protected in /run/user/$UID/
my $TMPDIR = $ENV{'XDG_RUNTIME_DIR'} // $ENV{'TMPDIR'} // '/tmp';
our $libvirtSocket;
# Children PID's we may create
# Check if we're forwarding, we need to work a few things out...
if (defined($forwardHost)) {
logger('NOTICE',"Forwarding '".color('green').$realLoginHost.color('reset')."' via host '".color('green').$loginHost.
color('reset')."'" .(defined($loginPort) ? " on port '".color('green')."$loginPort".color('reset')."'" : "") .
"...\n\n\n");
# Default to port 22 if the login port is not defined
my $destPort = $forwardPort // 22;
# Add forward socket name
$forwardSocket = "$TMPDIR/awit-ssh-forward-".sha1_hex("$forwardHost:$destPort $$").".sock";
# Build up our forwarding process args into this...
my @forwardArgs = ();
# TODO: Allow the use of multiple forwarded ports by separating them with ,'s
# The first port will be assumed as the SSH port, all other ports will be forwarded via TCP/IP and reported in terminal
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
# Add on port we're forwarding
push(@forwardArgs,'-L',"$forwardSocket:$forwardHost:$forwardPort");
# Check if we have a port defined, if so specify it
if (defined($loginPort)) {
push(@forwardArgs,'-p',$loginPort);
}
# Check if we have a different username defined to login as
if (defined($loginUsername)) {
push(@forwardArgs,'-l',$loginUsername);
}
# Explicitly disable control master for the main forwarding process
push(@forwardArgs,'-o','ControlMaster=no');
# Fork off child to establish the main connection
$forwardChild = fork();
if (!$forwardChild) {
# Exec ssh
if (!exec('/usr/bin/ssh',
@sshArgs,
@forwardArgs,
# Use basic compression
'-o','Compression=yes',
'-o','CompressionLevel=1',
# All we're doing here is forwarding the port...
'-N',
$loginHost
)) {
logger('ERROR',color('magenta')."Forwarding SSH process failed to start".color('reset'));
exit 1;
}
}
};
# Install signal handlers to cleanup if we get a TERM or INT
local $SIG{TERM} = local $SIG{INT} = \&cleanup;
# Check if we're forwarding to a socket...
if (defined($forwardSocket)) {
# Loop waiting for the socket to be created
my $delay = 30;
while (! -e $forwardSocket && $delay > 0) {
$delay--;
sleep 1;
}
if ($delay) {
# Check if we need to specify the username
push(@sshArgs,'-l',$forwardUsername) if (defined($forwardUsername));
logger('NOTICE',"Connecting to host '".color('green')."$forwardHost".color('reset')."'" .
(defined($forwardPort) ? " on port '".color('green')."$forwardPort".color('reset')."'" : "") . "...\n\n\n");
# Build SSH command
my $sshCmd = join(' ','/usr/bin/ssh',
@sshArgs,
# Override where we connecting to
'-o',"ProxyCommand='nc -U $forwardSocket'",
# Explicitly disable control master
'-o','ControlMaster=no',
);
# Run rsync
system('/usr/bin/rsync',
'-e',$sshCmd,
@rsyncParams
);
} else {
# Fire up SSH
system('/usr/bin/ssh',
@sshArgs,
# Override where we connecting to
'-o',"ProxyCommand=nc -U $forwardSocket",
# Explicitly disable control master
'-o','ControlMaster=no',
$realLoginHost
);
}
# Unlink socket and unset it to designate we exited normally
unlink($forwardSocket);
undef($forwardSocket);
} else {
logger('ERROR',color('magenta')."Forward socket not connected, aborting!".color('reset'));
}
# Normal SSH connection
} else {
logger('NOTICE',"Connecting to host '".color('green')."$loginHost".color('reset')."'" .
(defined($loginPort) ? " on port '".color('green')."$loginPort".color('reset')."'" : "") . "...\n\n\n");
# Make sure we get asked for control master connections...
push(@sshArgs,'-o','ControlMaster=autoask');
push(@sshArgs,'-o',"ControlPath=$TMPDIR/awit-ssh-master-%C");
# Check if we have a different username defined to login as
if (defined($loginUsername)) {
push(@sshArgs,'-l',$loginUsername);
}
# Check if we have a port defined, if so specify it
if (defined($loginPort)) {
push(@sshArgs,'-p',$loginPort);
}
# Check if we're doing rsync...
if (defined($useRsync)) {
# Build SSH command
my $sshCmd = join(' ','/usr/bin/ssh',
@sshArgs,
# Use basic compression
'-o','Compression=yes',
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
# Check if we're doing libvirt monitor port forwarding...
} elsif (defined($libvirtVNC)) {
# Split off host and port
my ($vncHost,$vncDisplay) = split(':',$libvirtVNC);
if (!defined($vncHost) || $vncHost ne "127.0.0.1" || !defined($vncDisplay)) {
logger('ERROR',color('magenta')."Libvirt VNC socket looks invalid '%s'".color('reset'),$libvirtVNC);
exit 1;
}
# VNC port is the display plus 5900
my $vncPort = 5900 + $vncDisplay;
# Add forward socket name
$libvirtSocket = "$TMPDIR/awit-ssh-vnc-".sha1_hex("$loginHost:$loginPort:$libvirtVNC $$").".sock";
my @libvirtArgs = ();
# Add on port we're forwarding
push(@libvirtArgs,'-L',"$libvirtSocket:$vncHost:$vncPort");
# Fork off child to establish the main connection
$libvirtChild = fork();
if (!$libvirtChild) {
# Don't use signals for this child
undef($SIG{'TERM'});
undef($SIG{'INT'});
# Exec ssh
if (!exec('/usr/bin/ssh',
@sshArgs,
'-o','ControlMaster=no',
@libvirtArgs,
# Use basic compression
'-o','Compression=yes',
'-o','CompressionLevel=7',
# All we're doing here is forwarding the port...
'-N',
$loginHost
)) {
logger('ERROR',color('magenta')."Libvirt VNC unix forwarding SSH process failed to start".color('reset'));
exit 1;
}
}
# Loop waiting for the socket to be created
my $delay = 30;
while (! -e $libvirtSocket && $delay > 0) {
$delay--;
sleep 1;
}
# If we still have timeout ticks left, then we connected, hopefully successfully
if ($delay) {
system('/usr/bin/ssvncviewer',
# '-encodings','copyrect tight hextile zlib corre rre raw',
# '-encodings','tight hextile zlib corre rre raw',
# '-quality','7',
$libvirtSocket);
} else {
logger('ERROR',color('magenta')."Libvirt socket not connected, aborting!".color('reset'));
}
# Normal SSH
} else {
system('/usr/bin/ssh',
@sshArgs,
# Use basic compression
'-o','Compression=yes',
'-o','CompressionLevel=1',
$loginHost
);
}
exit 0;
#
# Internal Functions
#
if ($forwardChild && kill(0,$forwardChild)) {
kill('TERM',$forwardChild);
# Wait for it to die
waitpid($forwardChild,-1);
}
if ($libvirtChild && kill(0,$libvirtChild)) {
kill('TERM',$libvirtChild);
# Wait for it to die
waitpid($libvirtChild,-1);
}
if ($forwardSocket) {
unlink($forwardSocket);
}
if ($libvirtSocket) {
unlink($libvirtSocket);
}
# Check if we exiting abnormally...
if ($forwardSocket || $libvirtSocket) {
print STDERR "\nExiting...\n";
exit 1;
}
exit 0;
}
# Log something
sub logger
{
my ($level,$arg1,@args) = @_;
printf(STDERR '%-7s: '.$arg1.color('reset')."\n",$level,@args);
}
# Display version
sub displayVersion
{
print("Version: $VERSION\n");
}
# Display usage
sub displayHelp
{
print(STDERR<<EOF);
$0 <options> --rsync -- <rsync options> remote://[USER@]HOST/file.name /tmp
General Options:
--help What you're seeing now.
--version Display version.
Port Knocking:
--knock HOST:PORT Port knock a host to get access.
--rsync ... Run rsync instead of ssh, passing all
command line parameters after the host
to it. HOST is used for searching
LDAP.
Libvirt:
--libvirt-vnc ... Connect to the qemu machines VNC.