From: Matt S Trout Date: Sat, 2 Jun 2012 16:30:41 +0000 (+0000) Subject: successfully wrapping sudo X-Git-Tag: v0.001001~36 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=7efea51f193cf42822232047403138ef98abcc32;p=scpubgit%2FObject-Remote.git successfully wrapping sudo --- diff --git a/lib/Object/Remote/Connector/Local.pm b/lib/Object/Remote/Connector/Local.pm index ce96d9a..bfe6639 100644 --- a/lib/Object/Remote/Connector/Local.pm +++ b/lib/Object/Remote/Connector/Local.pm @@ -4,6 +4,8 @@ use Moo; with 'Object::Remote::Role::Connector::PerlInterpreter'; +no warnings 'once'; + push @Object::Remote::Connection::Guess, sub { if (($_[0]||'') eq '-') { __PACKAGE__->new->connect } }; diff --git a/lib/Object/Remote/Connector/LocalSudo.pm b/lib/Object/Remote/Connector/LocalSudo.pm index c23f2e9..c6bad11 100644 --- a/lib/Object/Remote/Connector/LocalSudo.pm +++ b/lib/Object/Remote/Connector/LocalSudo.pm @@ -1,14 +1,51 @@ package Object::Remote::Connector::LocalSudo; +use Symbol qw(gensym); +use IPC::Open3; use Moo; extends 'Object::Remote::Connector::Local'; -around _perl_command => sub { - my ($orig, $self, $target_user) = @_; - return 'sudo', '-u', $target_user, $self->$orig($target_user); +has password_callback => (is => 'ro'); + +sub _sudo_perl_command { + my ($self, $stderr_fdno, $target_user) = @_; + return + 'sudo', '-S', '-u', $target_user, '-p', "[sudo] password please\n", + 'perl', '-MPOSIX=dup2', + '-e', 'print STDERR "GO\n"; dup2(shift(@ARGV), 2); exec(@ARGV);', + $stderr_fdno, $self->_perl_command($target_user); +} + +sub _start_perl { + my $self = shift; + open my $stderr_dup, '>&', \*STDERR or die "Couldn't dup STDERR: $!"; + my $sudo_stderr = gensym; + my $pid = open3( + my $foreign_stdin, + my $foreign_stdout, + $sudo_stderr, + $self->_sudo_perl_command(fileno($stderr_dup), @_) + ) or die "open3 failed: $!"; + chomp(my $line = <$sudo_stderr>); + if ($line eq "GO") { + # started already, we're good + } elsif ($line =~ /\[sudo\]/) { + my $cb = $self->password_callback; + die "sudo sent ${line} but we have no password callback" + unless $cb; + print $foreign_stdin $cb->($line, @_), "\n"; + chomp($line = <$sudo_stderr>); + die "sent password but next line was ${line}" + unless $line eq "GO"; + } else { + die "Got inexplicable line ${line} trying to sudo"; + }; + return ($foreign_stdin, $foreign_stdout, $pid); }; +no warnings 'once'; + push @Object::Remote::Connection::Guess, sub { for ($_[0]) { # username followed by @ diff --git a/lib/Object/Remote/Connector/SSH.pm b/lib/Object/Remote/Connector/SSH.pm index 3d89564..a90270f 100644 --- a/lib/Object/Remote/Connector/SSH.pm +++ b/lib/Object/Remote/Connector/SSH.pm @@ -11,6 +11,8 @@ around _perl_command => sub { return 'ssh', $target, $self->$orig($target); }; +no warnings 'once'; + push @Object::Remote::Connection::Guess, sub { for ($_[0]) { # 0-9 a-z _ - first char, those or . subsequent - hostnamish diff --git a/lib/Object/Remote/Role/Connector/PerlInterpreter.pm b/lib/Object/Remote/Role/Connector/PerlInterpreter.pm index 62d0153..5a9f64e 100644 --- a/lib/Object/Remote/Role/Connector/PerlInterpreter.pm +++ b/lib/Object/Remote/Role/Connector/PerlInterpreter.pm @@ -30,13 +30,19 @@ around connect => sub { sub _perl_command { 'perl', '-' } -sub _open2_for { +sub _start_perl { my $self = shift; my $pid = open2( my $foreign_stdout, my $foreign_stdin, $self->_perl_command(@_), ) or die "Failed to run perl at '$_[0]': $!"; + return ($foreign_stdin, $foreign_stdout, $pid); +} + +sub _open2_for { + my $self = shift; + my ($foreign_stdin, $foreign_stdout, $pid) = $self->_start_perl(@_); require Object::Remote::FatNode; print $foreign_stdin $Object::Remote::FatNode::DATA, "__END__\n" or die "Failed to send fatpacked data to new node on '$_[0]': $!"; diff --git a/xt/local-sudo.t b/xt/local-sudo.t index cd0af39..b1a7fa6 100644 --- a/xt/local-sudo.t +++ b/xt/local-sudo.t @@ -1,8 +1,6 @@ use strictures 1; use Test::More; -use FindBin; - -use lib "$FindBin::Bin/lib"; +use lib 'xt/lib'; use Object::Remote;