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 @
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]': $!";