http://www.perlmonks.org?node_id=712535
Category: Utility scripts
Author/Contact Info jacques
Description: I wrote this cvs wrapper because we were using cvs over ssh and I didn't want to keep logging in each time I invoked cvs. If you are doing the same thing, you might find it useful. One thing to note is that if someone has root, it is possible for them to get your password, since ssh-agent keeps it unencrypted in memory.
# Add the next 2 lines to bash_profile/bashrc file: 
#
#  eval `ssh-agent` > /dev/null
#  alias cvs='/path/to/cvs_wrapper.pl'
#
#!/usr/bin/perl

use strict;
use warnings;
use Expect;
#$Expect::Exp_Internal = 1;
#$Expect::Debug = 3;

my $testcommand = Expect->spawn("ssh-add -l");
$testcommand->log_stdout(0);

if ($testcommand->expect(1, '-re' => 'agent has')) {

    $testcommand->soft_close();

    print "CVS Wrapper\n===========\n\n";

    GET_PASSWD: {

        use Term::ReadKey;

        ReadMode 2;

        print "Enter cvs passwd:";

        my $passwd = <STDIN>;
        chomp $passwd;

        ReadMode 0;
        unless (length $passwd > 4) {
              print "\nBad password\n";
             redo GET_PASSWD;
        }

        my $user = $ENV{'USER'};
        my $home = $ENV{'HOME'};
        my $remoteserv = 'server.name.here';
        my $login = "$user" . '@' . "$remoteserv";

        unless (-e "$home/.ssh/id_dsa.pub") {
        # Set up private keys
        my $command = Expect->spawn("ssh-keygen -t dsa");
        $command->log_stdout(0);
        if ($command->expect(2, '-re' => 'Enter')) {
            print $command "\r"; 
        }
        if ($command->expect(2, '-re' => 'passphrase')) {
            print $command "$passwd\r"; 
        }

        if ($command->expect(2, '-re' => 'same')) {
            print $command "$passwd\r"; 
        }
        $command->soft_close();

        my $copy_command = Expect->spawn("scp ~/.ssh/id_dsa.pub $remot
+eserv:.ssh/authorized_keys2");
        $copy_command->log_stdout(0);
        if ($copy_command->expect(2, "password")) {
            print $copy_command "$passwd\r";
        }
        if ($copy_command->expect(3, '-re' => 'denied')) {
            $copy_command->hard_close();
            print "\nBad password\n";
            unlink "$home/.ssh/id_dsa.pub", "$home/.ssh/id_dsa";
            redo GET_PASSWD;
        }
        $copy_command->soft_close();

        }

        my $ssha_command = Expect->spawn("ssh-add");
        $ssha_command->log_stdout(0);
        if ($ssha_command->expect(2, "passphrase")) {
            print $ssha_command "$passwd\r";
        }
        if ($ssha_command->expect(1,'-re' =>'Bad')) {
            $ssha_command->hard_close();
            print "\nBad password\n";
            redo GET_PASSWD;
        }
        $ssha_command->soft_close();

        print "\nLogin successful\n";
    } #end GET_PASSWD
} else { $testcommand->soft_close(); }

open DATA, "/usr/bin/cvs @ARGV |" or die "Couldn't execute program: $!
+";
    while ( defined( my $line = <DATA> ) ) {
        chomp($line);
        print "$line\n";
    }
close DATA;
Replies are listed 'Best First'.
Re: cvs wrapper with ssh-agent
by blazar (Canon) on Sep 19, 2008 at 18:06 UTC
    open DATA, "/usr/bin/cvs @ARGV |" or die "Couldn't execute program: $! +";

    I personally believe that even if probably it doesn't do any harm here, you should avoid naming your filheandle DATA since it's a predefined perl one. Of course, had you used a lexical instead, there would have been no problem a priori.

    while ( defined( my $line = <DATA> ) ) {

    As a side note: perhaps you know (and perhaps you don't know) that defined is pleonastic there since perl will dwimmily assume it implicitly for you.

    chomp($line); print "$line\n"; } close DATA;

    Sorry, but I'm very tired and I may be missing something obvious. Anyway: why are you doing this? Line ending conversion? Since it's the very last part of your script, you may even be thinking -for once- of using exec instead, couldn't you?

    --
    If you can't understand the incipit, then please check the IPB Campaign.
      Originally I had did not have the open() there and had the last line as:
      print `/usr/bin/cvs @ARGV`;
      But this failed when there were double quotes in the @ARGV. For example if @ARGV contained: commit -m "message goes here" filename_to_commit

      So I used open() instead.

        I personally believe

        If you use open or exec (or system) you can "bypass" the shell by passing a list with more than one element, e.g.:

        open my $data, '-|', '/usr/bin/cvs' => @ARGV or die horribly;
        --
        If you can't understand the incipit, then please check the IPB Campaign.