#!/usr/bin/env perl IO::Socket::SSL::set_ctx_defaults( SSL_verify_mode => Net::SSLeay::VERIFY_NONE() ); package INF::ILO2; use HTTP::Daemon::SSL; use HTTP::Server::Brick; use HTTP::Status; use IO::Socket::SSL qw(); use HTML::TreeBuilder; use HTTP::Request::Common; use LWP::UserAgent; use URI::Escape; use File::Temp qw/ tempfile tempdir /; use XML::Simple; use Data::Dumper; use JSON::PP; use MIME::Base64 qw( encode_base64 ); sub b64($) { my $ret = shift; $ret = encode_base64($ret); $ret =~ s/[\n\s\r]//g; return $ret; } sub read_file($) { my ($name) = @_; my $fh = new IO::File "<" . $name; local $/; my $guts = $fh->getline; $fh->close; undef $fh; return $guts; } sub setup_port_proxy($$$$) { my ( $self, $local_port, $remote_host, $remote_port ) = @_; my $child = fork(); my $cmd = [ "balance", "-d", "-f", "-b", "127.0.0.1", $local_port, $remote_host . ":" . $remote_port ]; print STDERR "PROXY CMD: " . join( ' ', @$cmd ) . "\n"; if ( $child == 0 ) { if ( defined $self->{proxy_host} ) { my $tmp = File::Temp->new( UNLINK => 0, SUFFIX => '.cnf' ); select( ( select($tmp), $| = 1 )[0] ); print $tmp "server = 127.0.0.1\n"; print $tmp "server_port = " . $self->{proxy_port} . "\n"; print $tmp "local = 127.0.0.0/255.0.0.0\n"; $ENV{'LD_PRELOAD'} = 'libtsocks.so'; $ENV{'TSOCKS_CONF_FILE'} = $tmp->filename; print "Filename is $tmp->filename\n"; } exec(@$cmd); print STDERR "failed to start port proxy"; sleep(10000); } sleep(4); print "Setup proxy $local_port -> $remote_host:$remote_port\n"; return $child; } sub proxy($$$) { my ( $self, $req, $res ) = @_; if ( $req->uri->as_string =~ /^\/html\/java_irc.html/ ) { $res->header( 'Content-type' => 'text/html' ); $res->add_content( $self->{java_html} ); $res->code(200); return; } if ( $req->uri->as_string =~ /^\/html\/rc.*\.jar/ ) { $res->header( 'Content-type' => 'application/x-ms-application' ); $res->add_content( read_file('/usr/local/share/inf/ilo/rc175p08.jar') ); $res->code(200); return; } if ( $req->uri->as_string =~ /^\/html\/vtd.*\.jar/ ) { $res->header( 'Content-type' => 'application/x-ms-application' ); $res->add_content( read_file('/usr/local/share/inf/ilo/vtd191p06.jar') ); $res->code(200); return; } print "Another url..." . $req->uri->as_string . "\n"; die "meh"; } sub logout($) { my $self = shift; return unless defined $self->{stoken}; my $get = GET( $self->{ilo_url} . '/logout.htm' ); $get->header( 'cookie' => $self->{stoken} ); my $res = $self->{ua}->request($get); unless ( $res->is_success ) { print STDERR "failed to logout"; return -1; } print STDERR "Logged out of ILO2\n"; $self->{stoken} = undef; } sub login($) { my $self = shift; $self->{stoken} = undef; $self->{skey} = undef; $self->{sindex} = undef; my $get = GET( $self->{ilo_url} . '/login.htm' ); my $res = $self->{ua}->request($get); unless ( $res->is_success ) { print STDERR "Get nonce failed - did not get 200\n"; print Dumper($res); return -1; } my $content = $res->content; return -1 unless $content =~ /sessionkey="([A-Z0-9]+)"/; $self->{skey} = $1; #print "skey=" . $self->{skey} . "\n"; return -1 unless $content =~ /sessionindex="([0-9]+)"/; $self->{sindex} = $1; #print "sindex=" . $self->{sindex} . "\n"; $self->{slogin} = "hp-iLO-Login=" . $self->{sindex} . ":" . b64( $self->{user} ) . ":" . b64( $self->{password} ) . ":" . $self->{skey}; #print "Session login " . $self->{slogin} . "\n"; $get = GET( $self->{ilo_url} . '/index.htm' ); $get->header( 'cookie' => $self->{slogin} ); $get->header( 'Referer' => $self->{ilo_url} . '/login.htm' ); $res = $self->{ua}->request($get); unless ( $res->is_success ) { print STDERR "Get nonce failed - did not get 200\n"; print Dumper($res); return -1; } my $content = $res->content; unless ( $content =~ /ie_index.htm/ ) { print STDERR "Unhappy with reply from login\n"; return -1; } $self->{stoken} = 'hp-iLO-Session=' . $self->{sindex} . ':::' . $self->{skey} . ';' . $self->{slogin}; #print "ILO Session token " . $self->{stoken} . "\n"; # print "ILO2 login successful\n"; return 0; } sub view($) { my $self = shift; $self->login() unless defined $self->{stoken}; my $get = GET( $self->{ilo_url} . '/drc2fram.htm?restart=0' ); $get->header( 'cookie' => $self->{stoken} ); my $res = $self->{ua}->request($get); unless ( $res->is_success ) { print STDERR "drc2fram frequest failed - did not get 200\n"; return -1; } my $content = $res->content; unless ( $content =~ /com.hp.ilo2.remcons.remcons.class/ ) { print STDERR "returned html doesn't look right\n"; print Dumper($content); return -1; } my $things = {}; for my $thing ( qw( consoleWidth consoleHeight info1 info2 info3 info4 info5 info6 infomp infoscp info7 info8 slot_number info0 irc_fullscreen rcseize_timeout infoa infob infoc infod infom infomm infok infosc infocc infoae infomu infoms infon infoo infoscp infopriv) ) { return -1 unless $content =~ /${thing}=([^;]*);/; $things->{$thing} = $1; $things->{$thing} =~ s/[\\"']//g; } my $local_port = int( rand(30000) ) + 30000; push @{ $self->{to_kill} }, $self->setup_port_proxy( $local_port, $self->{host}, $things->{info6} ); $things->{info6} = $local_port; $things->{consoleWidth} = 1024; $things->{consoleHeight} = 768; my $document = '' . "\n"; $document .= '' . "\n"; $document .= '' . "\n"; $document .= '' . "\n"; $document .= '' . "\n"; $document .= '' . "\n"; $document .= '' . "\n"; $document .= '' . "\n"; $document .= '' . "\n"; $document .= '' . "\n"; $document .= '' . "\n"; $document .= '' . "\n"; $document .= '' . "\n"; $document .= '' . "\n"; $document .= '' . "\n"; $document .= '' . "\n"; $document .= ''; $document = "" . $document . ""; print Dumper($document); $self->{java_html} = $document; my $webserver_pid = fork(); if ( $webserver_pid == 0 ) { $SIG{INT} = sub { kill 'KILL', ( @{ $self->{to_kill} } ); die; }; $SIG{TERM} = sub { kill 'KILL', ( @{ $self->{to_kill} } ); die; }; $self->{server}->start; print STDERR "failed to web server"; sleep(100000); } push @{ $self->{to_kill} }, $webserver_pid; $SIG{INT} = sub { kill 'INT', ( @{ $self->{to_kill} } ); die; }; $SIG{TERM} = sub { kill 'TERM', ( @{ $self->{to_kill} } ); die; }; system( "appletviewer", "-J-Djava.security.manager", "-J-Djava.security.policy=/usr/local/share/inf/ilo/mypolicy", "-J-Djavax.net.ssl.trustStore=/usr/local/share/inf/ilo/server.jks", $self->{proxy_url} . "/html/java_irc.html" ); kill 'TERM', ( @{ $self->{to_kill} } ); } sub media($) { my $self = shift; $self->login() unless defined $self->{stoken}; my $get = GET( $self->{ilo_url} . '/vtd028.htm' ); $get->header( 'cookie' => $self->{stoken} ); my $res = $self->{ua}->request($get); unless ( $res->is_success ) { print STDERR "vtd frequest failed - did not get 200\n"; return -1; } my $content = $res->content; unless ( $content =~ /com.hp.ilo2.virtdevs.virtdevs.class/ ) { print STDERR "returned html doesn't look right\n"; print Dumper($content); return -1; } my $things = {}; for my $thing (qw( info0v info1v usbcfg serverName dp)) { return -1 unless $content =~ /${thing}=([^;]*);/; $things->{$thing} = $1; $things->{$thing} =~ s/[\\"']//g; } my $local_port = int( rand(30000) ) + 30000; push @{ $self->{to_kill} }, $self->setup_port_proxy( $local_port, $self->{host}, $things->{info1v} ); $things->{info1v} = $local_port; my $document = '' . "\n"; $document .= '' . "\n"; $document .= '' . "\n"; $document .= '' . "\n"; $document .= '' . "\n"; $document .= '' . "\n"; $document .= '' . "\n" if $things->{dp} != 0; $document .= ''; $document = "" . $document . ""; print Dumper($document); $self->{java_html} = $document; my $webserver_pid = fork(); if ( $webserver_pid == 0 ) { $SIG{INT} = sub { kill 'KILL', ( @{ $self->{to_kill} } ); die; }; $SIG{TERM} = sub { kill 'KILL', ( @{ $self->{to_kill} } ); die; }; $self->{server}->start; print STDERR "failed to web server"; sleep(100000); } push @{ $self->{to_kill} }, $webserver_pid; $SIG{INT} = sub { kill 'INT', ( @{ $self->{to_kill} } ); die; }; $SIG{TERM} = sub { kill 'TERM', ( @{ $self->{to_kill} } ); die; }; system( # "strace","-f","-o","t2","-s","8192", # "/bin/appletviewer", "appletviewer", "-J-Djava.security.manager", "-J-Djava.security.policy=/usr/local/share/inf/ilo/myvtdpolicy", "-J-Djavax.net.ssl.trustStore=/usr/local/share/inf/ilo/server.jks", $self->{proxy_url} . "/html/java_irc.html" ); kill 'TERM', ( @{ $self->{to_kill} } ); } sub get_host_power($) { my ($self) = @_; $self->login() unless defined $self->{stoken}; my $get = GET( $self->{ilo_url} . '/dvirtpwr.htm' ); $get->header( 'cookie' => $self->{stoken} ); my $res = $self->{ua}->request($get); unless ( $res->is_success ) { print STDERR " $what - did not get 200\n"; return 0; } my $content = $res->content; return 0 unless $content =~ /serverPower="([A-Z0-9]+)"/; my $state = $1; $state = "OFF" if $state eq 'STANDBY'; print "Server Power is $state\n"; return $state; } sub set_host_power($$$) { my ( $self, $thing, $other_thing ) = @_; $self->login() unless defined $self->{stoken}; my $get = GET( $self->{ilo_url} . '/dvirtpwr.htm' ); $get->header( 'cookie' => $self->{stoken} ); my $res = $self->{ua}->request($get); unless ( $res->is_success ) { print STDERR " $what - did not get 200\n"; return 0; } #cold Cold+Boot #warn Reset #hold Press+and+Hold #press Momentary+Press my $content = $res->content; return -1 unless $content =~ /signature="([A-Z0-9]+)"/; $self->{signature} = $1; my $form_content = 'signature=' . $self->{signature} . '&' . $thing . '=' . $other_thing; print "form_content=$form_content\n"; my $post = POST( $self->{ilo_url} . '/virtpwrpress.cgi' ); $post->header( 'Content-Type' => 'application/x-www-form-urlencoded' ); $post->header( 'Content-Length' => length($form_content) ); $post->content($form_content); $post->header( 'cookie' => $self->{stoken} ); my $res = $self->{ua}->request($post); unless ( $res->is_success ) { print STDERR " $what - did not get 200\n"; return 0; } return 1; } sub cold_boot($) { my $self = shift; return $self->set_host_power( 'cold', 'Cold+Boot' ); } sub reset($) { my $self = shift; return $self->set_host_power( 'warm', 'Reset' ); } sub off($) { my $self = shift; if ( $self->get_host_power =~ /ON/i ) { return $self->set_host_power( 'hold', 'Press+and+Hold' ); } return 1; } sub on($) { my $self = shift; if ( $self->get_host_power =~ /OFF/i ) { return $self->set_host_power( 'press', 'Momentary+Press' ); } return 1; } sub port_on($$) { my $self = shift; return $self->on(); } sub port_off($$) { my $self = shift; return $self->off(); } sub port_cycle($$) { my $self = shift; return $self->cold_boot(); } sub port_state_get_no_cache($$) { my $self = shift; return $self->get_host_power(); } sub port_state_get($$) { my $self = shift; return $self->get_host_power(); } sub port_name_get($$) { my $self = shift; return $self->{name}; } sub name_get($) { my $self = shift; return $self->{name}; } sub pdu_load_get($) { return "N/A"; } sub psu_status($) { return "N/A"; } sub port_count($) { return 1; } sub port_id_get_by_number($$) { return "K0"; } sub new ($;$) { my ( $class, $parm ) = @_; my $self; $self->{ua} = my $ua = LWP::UserAgent->new; $self->{host} = $parm->{host} || "127.0.0.1"; print "ILO2 instansiated for host " . $self->{host} . "\n"; $self->{user} = $parm->{user} || "Administrator"; $self->{password} = $parm->{password} || ""; $self->{name} = $parm->{name} || $self->{host}; $self->{ilo_url} = $parm->{ilo_url} || 'https://' . $self->{host}; $self->{userid} = undef; $self->{ua}->ssl_opts( SSL_verify_mode => Net::SSLeay::VERIFY_NONE(), verify_hostname => 0, ); if ( defined $parm->{proxy_host} ) { $self->{ua}->proxy( [qw(http https)] => "socks://" . $parm->{proxy_host} . ":" . $parm->{proxy_port} ); $self->{proxy_host} = $parm->{proxy_host}; $self->{proxy_port} = $parm->{proxy_port}; } my $local_port = int( rand(30000) ) + 30000; $self->{proxy_url} = 'https://127.0.0.1:' . $local_port; $self->{server} = HTTP::Server::Brick->new( port => $local_port, daemon_class => 'HTTP::Daemon::SSL', daemon_args => [ LocalAddr => '127.0.0.1', SSL_key_file => '/usr/local/share/inf/ilo/server.key', SSL_cert_file => '/usr/local/share/inf/ilo/server.crt', SSL_verify_mode => Net::SSLeay::VERIFY_NONE(), ], ); $self->{server}->mount( '/' => { handler => sub { my ( $req, $res ) = @_; $self->proxy( $req, $res ); 1; }, wildcard => 1, } ); $self->{stoken} = undef; $self->{to_kill} = []; return bless $self, $class; } 1;