maybe::start
[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 {
859f4451 12 my ($self, $target_user) = @_;
7efea51f 13 return
14 'sudo', '-S', '-u', $target_user, '-p', "[sudo] password please\n",
15 'perl', '-MPOSIX=dup2',
859f4451 16 '-e', 'print STDERR "GO\n"; exec(@ARGV);',
17 $self->_perl_command($target_user);
7efea51f 18}
19
20sub _start_perl {
21 my $self = shift;
7efea51f 22 my $sudo_stderr = gensym;
23 my $pid = open3(
24 my $foreign_stdin,
25 my $foreign_stdout,
26 $sudo_stderr,
859f4451 27 $self->_sudo_perl_command(@_)
7efea51f 28 ) or die "open3 failed: $!";
29 chomp(my $line = <$sudo_stderr>);
30 if ($line eq "GO") {
31 # started already, we're good
32 } elsif ($line =~ /\[sudo\]/) {
33 my $cb = $self->password_callback;
34 die "sudo sent ${line} but we have no password callback"
35 unless $cb;
36 print $foreign_stdin $cb->($line, @_), "\n";
37 chomp($line = <$sudo_stderr>);
aa052874 38 if ($line and $line ne 'GO') {
39 die "sent password and expected newline from sudo, got ${line}";
40 }
41 elsif (not $line) {
42 chomp($line = <$sudo_stderr>);
43 die "sent password but next line was ${line}"
44 unless $line eq "GO";
45 }
7efea51f 46 } else {
47 die "Got inexplicable line ${line} trying to sudo";
48 };
859f4451 49 Object::Remote->current_loop
50 ->watch_io(
51 handle => $sudo_stderr,
52 on_read_ready => sub {
53 if (sysread($sudo_stderr, my $buf, 1024) > 0) {
54 print STDERR $buf;
55 } else {
56 Object::Remote->current_loop
57 ->unwatch_io(
58 handle => $sudo_stderr,
59 on_read_ready => 1
60 );
61 }
62 }
63 );
7efea51f 64 return ($foreign_stdin, $foreign_stdout, $pid);
a9fdb55e 65};
66
7efea51f 67no warnings 'once';
68
a9fdb55e 69push @Object::Remote::Connection::Guess, sub {
70 for ($_[0]) {
71 # username followed by @
72 if (defined and !ref and /^ ([^\@]*?) \@ $/x) {
73 return __PACKAGE__->new->connect($1);
74 }
75 }
76 return;
77};
78
791;