File: //proc/self/root/scripts.20110531.215904.25158/sshcontrol
#!/usr/bin/perl
# cpanel - sshcontrol Copyright(c) 2010 cPanel, Inc.
# All rights Reserved.
# copyright@cpanel.net http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited
package Script::SSHControl;
BEGIN { unshift @INC, '/usr/local/cpanel'; }
use Cpanel::CleanupStub ();
use strict;
$| = 1;
$ENV{'TERM'} = 'dumb';
my $hasexp = 0;
eval {
require IO::Tty;
require Expect;
$hasexp = 1;
};
if ( !$hasexp ) {
print "Broken Expect.pm, please reinstall the Expect perl module.\n";
die;
}
__PACKAGE__->script(@ARGV) unless caller();
sub script {
my ($class, @argv) = @_;
#%ARGS
#{ctl} = (ssh|scp)
#{host} = (host*)
#{user} = (user*)
#{hash} = (security hash)
#{sumethod} = (usesu)
#{srcfile} = (*)
#{destfile} = (*)
Cpanel::CleanupStub::closefds();
my $sshkey = 'perl -e \'print "\t==sshcontroloutput==\n"\'';
my (%ARGS) = parseargv(@argv);
my $line = <STDIN>;
chomp($line);
my $rpass = $line;
my $upass;
my $rpassforsudo = 0;
if ( $ARGS{'authmethod'} ne 'root' ) {
if ( $ARGS{'escmethod'} eq 'su' ) { $ARGS{sumethod} = 1; }
if ( $ARGS{'escmethod'} eq 'sudo' ) { $ARGS{sudomethod} = 1; }
if ( $ARGS{sumethod} ) {
( $upass, $rpass ) = split( / /, $line );
}
elsif ( $ARGS{sudomethod} ) {
if ( $ARGS{authtype} eq 'publickey' ) {
( $upass, $rpass ) = split( / /, $line );
$rpassforsudo = 1;
}
else {
$upass = $line;
}
}
else {
$upass = $line;
}
}
my ( $prog, $cmdargs ) = ssh_options( \%ARGS );
my $cmd;
if ( $prog eq 'ssh' ) {
$cmd = <STDIN>;
chomp($cmd);
if ( $cmd eq "" ) {
print "Sorry, you cannot execute an empty command!\n";
exit();
}
if ( !$ARGS{sumethod} && !$ARGS{sudomethod} ) {
push( @{$cmdargs}, ${cmd} );
}
}
my $exp = Expect->spawn( $prog, @{$cmdargs} ) or die "Cannot spawn $prog $!\n";
my $pid = $exp->pid();
my $iauth = 1;
if ( $ARGS{sumethod} || $ARGS{sudomethod} ) {
if ( !$upass ) { $iauth = 0; }
}
else {
if ( !$rpass ) { $iauth = 0; }
}
if ($iauth) {
#password auth or public/priv key with a passphrase
my $eof = 0;
$exp->expect(
90,
[ 'eof', sub { $eof = 1; } ],
[ '-re', 'No such file or directory', sub { print "\nsshfileprob\n"; exit(); } ],
[ '-re', 'REMOTE HOST IDENTIFICATION', sub { print "\nsshhostproblem\n"; exit(); } ],
[ '-re', 'Name or service not known', sub { print "\nsshhostnotfound\n"; exit(); } ],
[ '-re', 'Connection timed out', sub { print "\nsshconnecttimeout\n"; exit(); } ],
[ '-re', 'Connection closed', sub { print "\nsshdisconnectproblem\n"; exit(); } ],
[ '-re', 'No route to host', sub { print "\nsshdisconnectproblem\n"; exit(); } ],
[ '-re', 'Connection refused', sub { print "\nsshdisconnectproblem\n"; exit(); } ],
[ '-re', 'timeout', sub { print "\nsshconnectproblem\n"; exit(); } ],
[ '-re', 'Permission denied', sub { print "\nsshcmdpermissiondeny"; exit(); } ],
'-re',
'Enter passphrase',
'-re',
'assword:'
);
if ($eof) {
print "\nsshcmdpermissiondeny";
exit();
}
}
if ( $ARGS{ctl} eq "ssh" ) {
if ( $ARGS{sumethod} || $ARGS{sudomethod} ) {
my $skipp = 0;
$exp->send("$upass\r");
$exp->expect( 30, [ '-re', 'Permission denied', sub { print "\nsshcmdpermissiondeny"; exit(); } ], [ '-re', 'assword:', sub { print "\nsshcmdpermissiondeny"; exit(); } ], [ '-re', 'Enter passphrase', sub { print "\nsshcmdpermissiondeny"; exit(); } ], '-re', '\]$', '-re', '\$$', '-re', '\#$', '-re', '\] ', '-re', '\$ ', '-re', '\# ' );
$exp->send("export LANG=C ; setenv LANG C ; echo \${LANG}_SSH_CLIENT=\${SSH_CLIENT}\r");
my $sshclient = '';
$exp->expect( 15, [ 'C_SSH_CLIENT=\S+', sub { my $self = shift; my $string = $self->exp_match(); $sshclient = $string; } ], [ 'default', sub { $skipp = 1; } ] );
if ( !$skipp ) {
$exp->expect( 10, [ '-re', '\] ', sub { $skipp = 1; } ], [ '-re', '\$ ', sub { $skipp = 1; } ], [ '-re', '\# ', sub { $skipp = 1; } ], [ '-re', '\]$', sub { $skipp = 1; } ], [ '-re', '\$$', sub { $skipp = 1; } ], [ '-re', '\#$', sub { $skipp = 1; } ] );
}
else {
print STDERR "Unable to set C_SSH_CLIENT!\n";
}
my $skippass = 0;
if ( $ARGS{sudomethod} ) {
$exp->send("sudo su\r");
$exp->expect(
30, 'assword:',
[ '-re', 'denied', sub { print "\nsshcmdpermissiondeny\n"; exit(); } ],
[ '-re', 'not in the sudoers', sub { print "\nsshcmdpermissiondeny\n"; exit(); } ],
[ '-re', '\] ', sub { $skippass = 1; } ],
[ '-re', '\$ ', sub { $skippass = 1; } ],
[ '-re', '\# ', sub { $skippass = 1; } ],
[ '-re', '\]$', sub { $skippass = 1; } ],
[ '-re', '\$$', sub { $skippass = 1; } ],
[ '-re', '\#$', sub { $skippass = 1; } ],
);
if ( !$skippass ) {
if ($rpassforsudo) {
$exp->send("$rpass\r");
}
else {
$exp->send("$upass\r");
}
}
if ($skippass) { print STDERR "sudo is cached!\n"; }
}
else {
$exp->send("su\r");
my $waitforprompt = 0;
$exp->expect( 10, '-re', 'assword:', [ 'denied', sub { print "\nsshcmdpermissiondeny\n"; exit(); } ], [ 'timeout', sub { $waitforprompt = 1; } ] );
if ($waitforprompt) {
$exp->expect( 10, '-re', 'assword:', [ '-re', '\] ', sub { $skippass = 1; } ], [ '-re', '\$ ', sub { $skippass = 1; } ], [ '-re', '\# ', sub { $skippass = 1; } ], [ '-re', '\]$', sub { $skippass = 1; } ], [ '-re', '\$$', sub { $skippass = 1; } ], [ '-re', '\#$', sub { $skippass = 1; } ] );
}
$exp->send("$rpass\r");
}
if ($skippass) { print STDERR "su is cached!\n"; }
if ( !$skippass ) {
$exp->expect( 30, [ '-re', 'incorrect', sub { print "\nsshcmdpermissiondeny\n"; exit(); } ], [ '-re', 'Sorry', sub { print "\nsshcmdpermissiondeny\n"; exit(); } ], [ '-re', 'assword:', sub { print "\nsshcmdpermissiondeny\n"; exit(); } ], '-re', '\] ', '-re', '\$ ', '-re', '\# ', '-re', '\]$', '-re', '\$$', '-re', '\#$' );
}
if ( $ARGS{hash} ne "" ) { #alabanz kludge
$exp->send("export DONOTSTEALME=$ARGS{hash}\r");
$exp->expect( 30, '-re', '\] ', '-re', '\$ ', '-re', '\# ', '-re', '\]$', '-re', '\$$', '-re', '\#$' );
}
if ( $sshclient ne '' ) {
chomp($sshclient);
my ( $var, $value ) = split( /=/, $sshclient );
$exp->send("setenv SSH_CLIENT $value ; export SSH_CLIENT=$value\r");
$exp->expect( 30, '-re', '\] ', '-re', '\$ ', '-re', '\# ', '-re', '\]$', '-re', '\$$', '-re', '\#$' );
print STDERR "Carries SSH_CLIENT\n";
}
$exp->send("set TERM dumb ; export TERM=dumb\r");
$exp->expect( 30, '-re', '\] ', '-re', '\$ ', '-re', '\# ', '-re', '\]$', '-re', '\$$', '-re', '\#$' );
$exp->send("stty columns 80\r");
$exp->expect( 30, '-re', '\] ', '-re', '\$ ', '-re', '\# ', '-re', '\]$', '-re', '\$$', '-re', '\#$' );
$exp->send("stty columns 80\r");
$exp->expect( 30, '-re', '\] ', '-re', '\$ ', '-re', '\# ', '-re', '\]$', '-re', '\$$', '-re', '\#$' );
$exp->send( $sshkey . ';' . $cmd . ';echo;' . $sshkey . "\r" );
$exp->expect( 20, "\t==sshcontroloutput==" );
$exp->expect( 15000, "\t==sshcontroloutput==" );
my $dl = 0;
for ( my $i = 0; $i < 6; $i++ ) {
if ( $i % 2 == 0 ) {
$exp->send("exit\r");
}
else {
$exp->send("logout\r");
}
$exp->expect( 10, [ 'eof', sub { $dl = 1; } ], [ '-re', 'closed', sub { $dl = 1; } ], 'default', '-re', "not found", '-re', '\] ', '-re', '\$ ', '-re', '\# ', '-re', '\]$', '-re', '\$$', '-re', '\#$' );
last if ($dl);
}
if ( !$dl ) {
$exp->expect( 15000, 'eof' );
}
$exp->soft_close();
waitpid( $pid, 0 );
}
else {
if ( $rpass eq '' ) {
$exp->send("$upass\r");
}
else {
$exp->send("$rpass\r");
}
print "\t==sshcontroloutput==";
$exp->expect( 15000, [ 'Permission denied', sub { print "\nsshcmdpermissiondeny\n"; } ], [ qr/assword:\s*$/i, sub { print "\nsshcmdpermissiondeny\n"; } ], [ '-re', 'Enter passphrase', sub { print "\nsshcmdpermissiondeny\n"; } ], 'eof' );
$exp->soft_close();
waitpid( $pid, 0 );
print "\t==sshcontroloutput==\n";
}
}
elsif ( $ARGS{ctl} eq "scp" ) {
$exp->send("$rpass\r");
$exp->expect( 15000, [ '/scp: ', sub { print "\nsshscpdisabled\n"; exit(); } ], [ '-re', 'Enter passphrase', sub { print "\nsshcmdpermissiondeny"; exit(); } ], [ 'Permission denied', sub { print "\nsshcmdpermissiondeny\n"; exit(); } ], [ qr/assword:\s*$/i, sub { print "\nsshcmdpermissiondeny\n"; exit(); } ], 'eof' );
$exp->soft_close();
waitpid( $pid, 0 );
}
}
sub parseargv {
my @argv = @_;
my (%args);
while ( $#argv != -1 ) {
$_ = $argv[0];
if (/^\-\-/) {
my $arg = shift(@argv);
$arg =~ s/^\-\-//g;
$arg =~ tr/[A-Z]/[a-z]/;
my $value = shift(@argv);
$args{$arg} = $value;
}
else {
last;
}
}
return (%args);
}
sub ssh_options {
my $args = shift;
my %ARGS = ();
foreach my $key ( %{$args} ) {
$ARGS{$key} = $args->{$key};
}
my (@CMDARGS) = ( "-o", "UserKnownHostsFile /dev/null", "-o", "StrictHostKeyChecking no" );
if ( $ARGS{ctl} eq 'ssh' ) { push( @CMDARGS, "-q" ); }
# using -q hides perm denied errors, but makes this work
#
if ( $ARGS{port} ne "" ) {
if ( $ARGS{ctl} eq "ssh" ) {
push( @CMDARGS, "-p" );
}
else {
push( @CMDARGS, "-P" );
}
push( @CMDARGS, $ARGS{port} );
}
if ( $ARGS{authtype} eq 'publickey' ) {
push( @CMDARGS, "-o", 'PasswordAuthentication no' );
push( @CMDARGS, "-o", 'PubkeyAuthentication yes' );
}
else {
push( @CMDARGS, "-o", 'PasswordAuthentication yes' );
push( @CMDARGS, "-o", 'PubkeyAuthentication no' );
}
if ( $ARGS{authtype} eq 'publickey' && $ARGS{sshkey} ) {
$ARGS{sshkey} =~ s/\.\.//g;
$ARGS{sshkey} =~ s/\///g;
push( @CMDARGS, "-i", ( getpwuid($>) )[7] . "/.ssh/" . $ARGS{sshkey} );
}
if ( $ARGS{authmethod} ne '' ) {
if ( $ARGS{authmethod} eq 'root' ) { $ARGS{user} = 'root'; }
if ( $ARGS{authmethod} eq 'user' ) { $ARGS{user} = $ARGS{authuser}; }
}
if ( $ARGS{user} eq "" ) {
print "Sorry, you must specify a user to login to the remote server as.";
exit();
}
if ( $ARGS{host} eq "" ) {
print "Sorry, you must specify a remote server.";
exit();
}
if ( $ARGS{ctl} eq "ssh" ) {
push( @CMDARGS, $ARGS{user} . '@' . $ARGS{host} );
return ( 'ssh', \@CMDARGS );
}
elsif ( $ARGS{ctl} eq "scp" ) {
if ( $ARGS{srcfile} eq "" ) {
print "Sorry you must specify a source file.\n";
exit();
}
if ( $ARGS{destfile} eq "" ) {
print "Sorry you must specify a destfile file.\n";
exit();
}
if ( $ARGS{direction} eq "" ) {
print "Sorry you must specify a direction file.\n";
exit();
}
if ( $ARGS{direction} eq "download" ) {
push( @CMDARGS, $ARGS{user} . '@' . $ARGS{host} . ':' . $ARGS{srcfile} );
push( @CMDARGS, $ARGS{destfile} );
}
else {
push( @CMDARGS, $ARGS{srcfile} );
push( @CMDARGS, $ARGS{user} . '@' . $ARGS{host} . ':' . $ARGS{destfile} );
}
return ( 'scp', \@CMDARGS );
}
else {
print "Sorry, no app to control was specified!\n";
die;
}
}
1;