Net-VNC
view release on metacpan or search on metacpan
lib/Net/VNC.pm view on Meta::CPAN
package Net::VNC;
use strict;
use warnings;
use base qw(Class::Accessor::Fast);
use Crypt::DES;
use Image::Imlib2;
use IO::Socket::INET;
use bytes;
__PACKAGE__->mk_accessors(
qw(hostname port username password socket name width height depth save_bandwidth
hide_cursor server_endian
_pixinfo _colourmap _framebuffer _cursordata _rfb_version
_bpp _true_colour _big_endian _image_format
)
);
our $VERSION = '0.40';
my $MAX_PROTOCOL_VERSION = 'RFB 003.008' . chr(0x0a); # Max version supported
# Precompute booleans for specific Image::Imlib2 features
my $CAN_CREATE_RAW_IMAGE = Image::Imlib2->can('new_using_data');
my $CAN_CHANGE_BLEND = Image::Imlib2->can('will_blend');
# This line comes from perlport.pod
my $AM_BIG_ENDIAN = unpack( 'h*', pack( 's', 1 ) ) =~ /01/ ? 1 : 0;
# The numbers in the hashes below were acquired from the VNC source code
my %supported_depths = (
'24' => {
bpp => 32,
true_colour => 1,
red_max => 255,
green_max => 255,
blue_max => 255,
red_shift => 16,
green_shift => 8,
blue_shift => 0,
},
'16' => {
bpp => 16,
true_colour => 1,
red_max => 31,
green_max => 31,
blue_max => 31,
red_shift => 10,
green_shift => 5,
blue_shift => 0,
},
'8' => {
bpp => 8,
true_colour => 0,
red_max => 255,
green_max => 255,
blue_max => 255,
red_shift => 16,
green_shift => 8,
blue_shift => 0,
},
# Unused right now, but supportable
'8t' => {
bpp => 8,
true_colour => 1, #!!!
red_max => 7,
green_max => 7,
lib/Net/VNC.pm view on Meta::CPAN
if ( $number_of_security_types == 0 ) {
die 'Error authenticating';
}
my @security_types;
foreach ( 1 .. $number_of_security_types ) {
$socket->read( my $security_type, 1 )
|| die 'unexpected end of data';
$security_type = unpack( 'C', $security_type );
# warn "sec: $security_type";
push @security_types, $security_type;
}
my @pref_types = ( 1, 2 );
@pref_types = ( 30, 1, 2 ) if $self->username;
for my $preferred_type (@pref_types) {
if ( 0 < grep { $_ == $preferred_type } @security_types ) {
$security_type = $preferred_type;
last;
}
}
} else {
# In RFB 3.3, the server dictates the security type
$socket->read( $security_type, 4 ) || die 'unexpected end of data';
$security_type = unpack( 'N', $security_type );
}
if ( !$security_type ) {
die 'Connection failed';
} elsif ( $security_type == 2 ) {
# DES-encrypted challenge/response
if ( $self->_rfb_version ge '003.007' ) {
$socket->print( pack( 'C', 2 ) );
}
$socket->read( my $challenge, 16 ) || die 'unexpected end of data';
# warn "chal: " . unpack('h*', $challenge) . "\n";
# the RFB protocol only uses the first 8 characters of a password
my $key = substr( $self->password, 0, 8 );
$key = '' if ( !defined $key );
$key .= pack( 'C', 0 ) until ( length($key) % 8 ) == 0;
my $realkey;
# warn unpack('b*', $key);
foreach my $byte ( split //, $key ) {
$realkey .= pack( 'b8', scalar reverse unpack( 'b8', $byte ) );
}
# warn unpack('b*', $realkey);
my $cipher = Crypt::DES->new($realkey);
my $response;
my $i = 0;
while ( $i < 16 ) {
my $word = substr( $challenge, $i, 8 );
# warn "$i: " . length($word);
$response .= $cipher->encrypt($word);
$i += 8;
}
# warn "resp: " . unpack('h*', $response) . "\n";
$socket->print($response);
} elsif ( $security_type == 1 ) {
# No authorization needed!
if ( $self->_rfb_version ge '003.007' ) {
$socket->print( pack( 'C', 1 ) );
}
} elsif ( $security_type == 30 ) {
require Crypt::GCrypt::MPI;
require Crypt::Random;
# ARD - Apple Remote Desktop - authentication
$socket->print( pack( 'C', 30 ) ); # use ARD
$socket->read( my $gen, 2 ) || die 'unexpected end of data';
$socket->read( my $len, 2 ) || die 'unexpected end of data';
my $keylen = $self->_bin_int($len);
$socket->read( my $mod, $keylen ) || die 'unexpected end of data';
$socket->read( my $resp, $keylen ) || die 'unexpected end of data';
my $genmpi = Crypt::GCrypt::MPI::new(
secure => 0,
value => $self->_bin_int($gen),
format => Crypt::GCrypt::MPI::FMT_USG()
);
my $modmpi = Crypt::GCrypt::MPI::new(
secure => 0,
value => $mod,
format => Crypt::GCrypt::MPI::FMT_USG()
);
my $respmpi = Crypt::GCrypt::MPI::new(
secure => 0,
value => $resp,
format => Crypt::GCrypt::MPI::FMT_USG()
);
my $privmpi = $self->_mpi_randomize($keylen);
my $pubmpi = $genmpi->copy()->powm( $privmpi, $modmpi );
my $keympi = $respmpi->copy()->powm( $privmpi, $modmpi );
my $pub = $self->_mpi_2_bytes( $pubmpi, $keylen );
my $key = $self->_mpi_2_bytes( $keympi, $keylen );
my $md5 = Crypt::GCrypt->new( type => 'digest', algorithm => 'md5' );
$md5->write($key);
my $shared = $md5->read();
my $passlen = length( $self->password ) + 1;
my $userlen = length( $self->username ) + 1;
( run in 4.488 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )