X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FObject%2FRemote%2FConnector%2FLocalSudo.pm;h=aa19ced3fbcbc1dcef95ba9c093af24235cb68f1;hb=aa052874c2efdb5837fd42ae2f924d6f05b49c71;hp=c23f2e984e929a8c3ec33e97e3e684db7906d680;hpb=a9fdb55e205b30cfca1cee5f61ab0f1107f750d1;p=scpubgit%2FObject-Remote.git diff --git a/lib/Object/Remote/Connector/LocalSudo.pm b/lib/Object/Remote/Connector/LocalSudo.pm index c23f2e9..aa19ced 100644 --- a/lib/Object/Remote/Connector/LocalSudo.pm +++ b/lib/Object/Remote/Connector/LocalSudo.pm @@ -1,14 +1,71 @@ 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, $target_user) = @_; + return + 'sudo', '-S', '-u', $target_user, '-p', "[sudo] password please\n", + 'perl', '-MPOSIX=dup2', + '-e', 'print STDERR "GO\n"; exec(@ARGV);', + $self->_perl_command($target_user); +} + +sub _start_perl { + my $self = shift; + my $sudo_stderr = gensym; + my $pid = open3( + my $foreign_stdin, + my $foreign_stdout, + $sudo_stderr, + $self->_sudo_perl_command(@_) + ) 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>); + if ($line and $line ne 'GO') { + die "sent password and expected newline from sudo, got ${line}"; + } + elsif (not $line) { + 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"; + }; + Object::Remote->current_loop + ->watch_io( + handle => $sudo_stderr, + on_read_ready => sub { + if (sysread($sudo_stderr, my $buf, 1024) > 0) { + print STDERR $buf; + } else { + Object::Remote->current_loop + ->unwatch_io( + handle => $sudo_stderr, + on_read_ready => 1 + ); + } + } + ); + return ($foreign_stdin, $foreign_stdout, $pid); }; +no warnings 'once'; + push @Object::Remote::Connection::Guess, sub { for ($_[0]) { # username followed by @