password callback working
[scpubgit/Object-Remote.git] / lib / Object / Remote / Connector / LocalSudo.pm
CommitLineData
a9fdb55e 1package Object::Remote::Connector::LocalSudo;
2
7efea51f 3use Symbol qw(gensym);
4use IPC::Open3;
a9fdb55e 5use Moo;
6
7extends 'Object::Remote::Connector::Local';
8
7efea51f 9has password_callback => (is => 'ro');
10
11sub _sudo_perl_command {
12 my ($self, $stderr_fdno, $target_user) = @_;
13 return
14 'sudo', '-S', '-u', $target_user, '-p', "[sudo] password please\n",
15 'perl', '-MPOSIX=dup2',
16 '-e', 'print STDERR "GO\n"; dup2(shift(@ARGV), 2); exec(@ARGV);',
17 $stderr_fdno, $self->_perl_command($target_user);
18}
19
20sub _start_perl {
21 my $self = shift;
22 open my $stderr_dup, '>&', \*STDERR or die "Couldn't dup STDERR: $!";
23 my $sudo_stderr = gensym;
24 my $pid = open3(
25 my $foreign_stdin,
26 my $foreign_stdout,
27 $sudo_stderr,
28 $self->_sudo_perl_command(fileno($stderr_dup), @_)
29 ) or die "open3 failed: $!";
30 chomp(my $line = <$sudo_stderr>);
31 if ($line eq "GO") {
32 # started already, we're good
33 } elsif ($line =~ /\[sudo\]/) {
34 my $cb = $self->password_callback;
35 die "sudo sent ${line} but we have no password callback"
36 unless $cb;
37 print $foreign_stdin $cb->($line, @_), "\n";
38 chomp($line = <$sudo_stderr>);
dac97b35 39 die "sent password and expected newline from sudo, got ${line}"
40 if $line;
41 chomp($line = <$sudo_stderr>);
7efea51f 42 die "sent password but next line was ${line}"
43 unless $line eq "GO";
44 } else {
45 die "Got inexplicable line ${line} trying to sudo";
46 };
47 return ($foreign_stdin, $foreign_stdout, $pid);
a9fdb55e 48};
49
7efea51f 50no warnings 'once';
51
a9fdb55e 52push @Object::Remote::Connection::Guess, sub {
53 for ($_[0]) {
54 # username followed by @
55 if (defined and !ref and /^ ([^\@]*?) \@ $/x) {
56 return __PACKAGE__->new->connect($1);
57 }
58 }
59 return;
60};
61
621;