#!/usr/bin/perl -U
#
$version = "2.6"; # written by Herb Rubin herbr@pfinders.com 09/04/2014
# www.pfinders.com
#
# Purpose:
#----------
# Securely send (upload) a file using sftp (over ssh)
#
# It works with a password or preshared keys.
# If password is blank then it assumes preshared keys.
#
# Use it like this: sftppush -f /path/to/file
# Requires: /usr/bin/expect to be installed
#
$progname = $0;
use Getopt::Std;
#
# Begin User Defined Section
#----------------------------
my $tempscript = "/tmp/sftp_script";
my $host = "ftp.domain.com";
my $port = "22";
my $user = "bob";
my $password = "flaDfld3d"; # if blank then assume preshared keys
my $remote = ""; # remote directory to upload to, blank is ok
# End User Defined Section
#----------------------------

$pid = $$;
$progname = $1 if ($progname =~ /\/(\w+)$/);
$ENV{'PATH'} = '/usr/bin:/usr/bin/X11:/sbin:.';
&getopts("ahf:u:p:s:r:vo:",\%Options);
if (! -e "/usr/bin/expect") {
  print "Error: The requisite /usr/bin/expect not found\n";
  exit;
}
&usage if ($Options{'h'});

if ($Options{'u'} ne "") {
  $user = "$Options{'u'}";
}
if ($user eq "") {
  print "$progname: User id missing, try -u user\n";
}
if ($Options{'p'} ne "") {
  $password = "$Options{'p'}";
}
if ($Options{'o'} ne "") {
  $port = "$Options{'o'}";
}
if ($Options{'s'} ne "") {
  $host = "$Options{'s'}";
}
if (host eq "") {
  print "$progname: FTP Server missing, try -s server\n";
}
if ($Options{'r'} ne "") {
  $remote = "$Options{'r'}";
}
$filename = "$Options{'f'}";

if (-e "$filename") {
############################################
# There is some data to upload, so send it #
############################################
  $results = &send_file;
  print $results if ($Options{'v'});
} else {
  if ($filename eq "") {
    print "filename to push was not provided, use -f file\n";
  } else {
    print "$progname: $filename does not exist, nothing uploaded via FTP\n";
  }
}
exit;

sub usage {
    print <<EOF;
$progname usage:

   $progname [-hvV] -s ftp.server.com -u user -p password -f /path/to/file

   Upload a file to an sftp server (ssh)

   Where:

     -f filename            file to upload
     -s ftp.server.name     hostname of ftp server
     -u userid              login with userid to ftp server
     -p password            login with password not preshared keys
     -o port                sftp port, default 22
     -a                     send in ascii mode, defaults to binary
     -r remotedirectory     change to this directory on ftp server
     -v                     verbose mode
     -V                     show version (currently $version)

   If password is not specified then it requires preshared keys
     ssh-keygen -t dsa
     on remote machine:
     cat identity.pub >> ~/.ssh/authorized_keys

   Note: If password is specified on the command line and includes symbols, 
   surround it with single quotes.

   Examples:
   $progname -f /tmp/data.txt
   $progname -p 2222 -f /tmp/data.txt

EOF
  exit;
}

sub send_file {
  my $cmd;
  my $sftpscript = "/tmp/sftpscript$pid";
  my $tempscript = "/tmp/tempscript$pid";
  if ($host eq "") {
      print "$progname: remote hostname missing, nothing sent\n";
      return;
  }
  if ($user eq "") {
      print "$progname: user missing, nothing sent\n";
      return;
  }
  print "Connecting to sftp site $host\n" if ($Options{'v'});
  if (open PFILE, ">$sftpscript") {
    if ($remote ne "") {
        print PFILE "cd $remote\n";
    }
    print PFILE "put $filename\n";
    print PFILE "quit\n";
    close PFILE;
  } else {
    print "$progname: failed to create sftp script $sftpscript\n";
  }
  chmod 0660, $sftpscript;
  if ($port ne "22") {
      $cmd = "sftp -o batchmode=no -o Port=$port -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -b $sftpscript $user\@$host";
  } else {
      $cmd = "sftp -o batchmode=no -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -b $sftpscript $user\@$host";
  }
  my $results = "";
  if ($password ne "") {
      ###############################################
      # use expect to force feed a password to sftp #
      ###############################################
      if (open PFILE, ">$tempscript") {
        print PFILE <<EOF;
#!/usr/bin/expect
spawn $cmd
for {} 1 {} {
  expect {
    assword: { sleep 1; set send_human {.1 .3 1 .07 .1 .3 .1} ; send -h \"$password\\r\" }
    failed: { exit }
    eof exit
  }
}
EOF
        close PFILE;
        chmod 0700, $tempscript;
        $results = `$tempscript`;
        $results =~ s/\r//g; # remove CRs
        unlink $tempscript unless ($Options{'v'});
        unlink $sftpscript unless ($Options{'v'});
      } else {
        print "$progname: Cannot write to $tempscript, sftp session aborted\n";
      }
  } else {
      $results = `$cmd`;
      unlink $sftpscript unless ($Options{'v'});
  }

  if ($results =~ /closed by remote host/) {
    print "$progname: failed to login to $host, firewall issue?\n";
  }
  if ($results =~ /Host not found/) {
    print "$progname: failed to login to $host, DNS failure?\n";
  }
  if ($results =~ /ermission denied/) {
    print "$progname: failed to login to $host, password incorrect?\n";
  }
  return $results;
}