Fix spelling error in log message
[scpubgit/Object-Remote.git] / lib / Object / Remote / Connector / LocalSudo.pm
CommitLineData
a9fdb55e 1package Object::Remote::Connector::LocalSudo;
2
7efea51f 3use Symbol qw(gensym);
1b315002 4use Module::Runtime qw(use_module);
7efea51f 5use IPC::Open3;
a9fdb55e 6use Moo;
7
8extends 'Object::Remote::Connector::Local';
9
1b315002 10has target_user => (is => 'ro', required => 1);
11
12has password_callback => (is => 'lazy');
13
14sub _build_password_callback {
15 my ($self) = @_;
16 my $pw_prompt = use_module('Object::Remote::Prompt')->can('prompt_pw');
17 my $user = $self->target_user;
18 return sub {
19 $pw_prompt->("sudo password for ${user}", undef, { cache => 1 })
20 }
21}
7efea51f 22
498c4ad5 23has sudo_perl_command => (is => 'lazy');
24
25sub _build_sudo_perl_command {
1b315002 26 my ($self) = @_;
7efea51f 27 return
1b315002 28 'sudo', '-S', '-u', $self->target_user, '-p', "[sudo] password please\n",
7efea51f 29 'perl', '-MPOSIX=dup2',
859f4451 30 '-e', 'print STDERR "GO\n"; exec(@ARGV);',
498c4ad5 31 $self->perl_command;
7efea51f 32}
33
34sub _start_perl {
35 my $self = shift;
7efea51f 36 my $sudo_stderr = gensym;
37 my $pid = open3(
38 my $foreign_stdin,
39 my $foreign_stdout,
40 $sudo_stderr,
498c4ad5 41 @{$self->sudo_perl_command}
7efea51f 42 ) or die "open3 failed: $!";
43 chomp(my $line = <$sudo_stderr>);
44 if ($line eq "GO") {
45 # started already, we're good
46 } elsif ($line =~ /\[sudo\]/) {
47 my $cb = $self->password_callback;
48 die "sudo sent ${line} but we have no password callback"
49 unless $cb;
50 print $foreign_stdin $cb->($line, @_), "\n";
51 chomp($line = <$sudo_stderr>);
aa052874 52 if ($line and $line ne 'GO') {
53 die "sent password and expected newline from sudo, got ${line}";
54 }
55 elsif (not $line) {
56 chomp($line = <$sudo_stderr>);
57 die "sent password but next line was ${line}"
58 unless $line eq "GO";
59 }
7efea51f 60 } else {
61 die "Got inexplicable line ${line} trying to sudo";
62 };
859f4451 63 Object::Remote->current_loop
64 ->watch_io(
65 handle => $sudo_stderr,
66 on_read_ready => sub {
9031635d 67 Dlog_debug { "LocalSudo: Preparing to read data from $_" } $sudo_stderr;
68 if (sysread($sudo_stderr, my $buf, 32768) > 0) {
9d64d2d9 69 log_trace { "LocalSudo: successfully read data, printing it to STDERR" };
859f4451 70 print STDERR $buf;
9d64d2d9 71 log_trace { "LocalSudo: print() to STDERR is done" };
859f4451 72 } else {
9d64d2d9 73 log_debug { "LocalSudo: received EOF or error on file handle, unwatching it" };
859f4451 74 Object::Remote->current_loop
75 ->unwatch_io(
76 handle => $sudo_stderr,
77 on_read_ready => 1
78 );
79 }
80 }
81 );
7efea51f 82 return ($foreign_stdin, $foreign_stdout, $pid);
a9fdb55e 83};
84
7efea51f 85no warnings 'once';
86
a9fdb55e 87push @Object::Remote::Connection::Guess, sub {
88 for ($_[0]) {
89 # username followed by @
90 if (defined and !ref and /^ ([^\@]*?) \@ $/x) {
c824fdf3 91 shift(@_);
92 return __PACKAGE__->new(@_, target_user => $1);
a9fdb55e 93 }
94 }
95 return;
96};
97
981;