Rex-LibSSH

 view release on metacpan or  search on metacpan

t/lib/TestSSHD.pm  view on Meta::CPAN

package TestSSHD;

use strict;
use warnings;

use File::Temp qw(tempdir);
use IO::Socket::INET;
use POSIX qw(SIGTERM);

my $SFTP_SERVER = do {
    my @candidates = qw(
        /usr/lib/openssh/sftp-server
        /usr/libexec/openssh/sftp-server
        /usr/libexec/sftp-server
    );
    my ($found) = grep { -x $_ } @candidates;
    $found // '';
};

sub start {
    my ($class) = @_;

    my $sshd = do {
        my ($found) = grep { -x $_ } qw(/usr/sbin/sshd /usr/bin/sshd);
        $found // return undef;
    };

    -x '/usr/bin/ssh-keygen' or return undef;

    my $dir = tempdir(CLEANUP => 1);

    system('ssh-keygen', '-t', 'ed25519', '-N', '', '-f', "$dir/host_key", '-q') == 0
        or return undef;

    system('ssh-keygen', '-t', 'ed25519', '-N', '', '-f', "$dir/client_key", '-q') == 0
        or return undef;

    system('cp', "$dir/client_key.pub", "$dir/authorized_keys") == 0
        or return undef;
    chmod 0600, "$dir/authorized_keys";

    my $port = _free_port() or return undef;
    my $user = getpwuid($<);

    my $cfg = "$dir/sshd_config";
    open my $fh, '>', $cfg or return undef;
    print $fh <<"CONFIG";
Port $port
HostKey $dir/host_key
AuthorizedKeysFile $dir/authorized_keys
PidFile $dir/sshd.pid
LogLevel ERROR
StrictModes no
UsePAM no
AllowUsers $user
CONFIG
    print $fh "Subsystem sftp $SFTP_SERVER\n" if $SFTP_SERVER;
    close $fh;

    my $pid = fork();
    return undef unless defined $pid;

    if ($pid == 0) {
        open STDOUT, '>', '/dev/null';
        open STDERR, '>', '/dev/null';
        exec $sshd, '-D', '-f', $cfg;
        exit 1;
    }

    # Wait until the port is open (up to 5s)
    my $started;
    for (1..50) {
        if (IO::Socket::INET->new(PeerAddr => "127.0.0.1:$port", Timeout => 0.1)) {
            $started = 1;
            last;
        }
        select undef, undef, undef, 0.1;
    }

    unless ($started) {
        kill SIGTERM, $pid;
        waitpid $pid, 0;
        return undef;
    }

    return bless {
        dir        => $dir,
        pid        => $pid,
        port       => $port,
        host       => '127.0.0.1',
        client_key => "$dir/client_key",
        has_sftp   => $SFTP_SERVER ? 1 : 0,
    }, $class;
}

sub port       { $_[0]->{port}       }
sub host       { $_[0]->{host}       }
sub client_key { $_[0]->{client_key} }
sub has_sftp   { $_[0]->{has_sftp}   }

sub DESTROY {
    my ($self) = @_;
    if ($self->{pid}) {



( run in 2.767 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )