# # Copyright 2021 Centreon (http://www.centreon.com/) # # Centreon is a full-fledged industry-strength solution that meets # the needs in IT infrastructure and application monitoring for # service performance. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # package centreon::plugins::backend::ssh::libssh; use strict; use warnings; sub new { my ($class, %options) = @_; my $self = {}; bless $self, $class; if (!defined($options{noptions}) || $options{noptions} != 1) { $options{options}->add_options(arguments => { 'libssh-strict-connect' => { name => 'libssh_strict_connect' } }); $options{options}->add_help(package => __PACKAGE__, sections => 'BACKEND LIBSSH OPTIONS', once => 1); } $self->{connected} = 0; $self->{output} = $options{output}; return $self; } sub check_options { my ($self, %options) = @_; centreon::plugins::misc::mymodule_load( output => $self->{output}, module => 'Libssh::Session', error_msg => "Cannot load module 'Libssh::Session'." ); centreon::plugins::misc::mymodule_load( output => $self->{output}, module => 'centreon::plugins::backend::ssh::libsshconstants', error_msg => "Cannot load module 'centreon::plugins::backend::ssh::libsshconstants'." ); $self->{constant_cb} = \¢reon::plugins::backend::ssh::libsshconstants::get_constant_value; if (!defined($self->{ssh})) { $self->{ssh} = Libssh::Session->new(); } $self->{ssh_port} = defined($options{option_results}->{ssh_port}) && $options{option_results}->{ssh_port} =~ /(\d+)/ ? $1 : 22; $self->{ssh}->options(port => $self->{ssh_port}); $self->{ssh_username} = $options{option_results}->{ssh_username}; $self->{ssh_password} = $options{option_results}->{ssh_password}; $self->{ssh}->options(identity => $options{option_results}->{ssh_priv_key}) if (defined($options{option_results}->{ssh_priv_key}) && $options{option_results}->{ssh_priv_key} ne ''); $self->{ssh}->options(user => $options{option_results}->{ssh_username}) if (defined($options{option_results}->{ssh_username}) && $options{option_results}->{ssh_username} ne ''); $self->{ssh_strict_connect} = defined($options{option_results}->{libssh_strict_connect}) ? 0 : 1; } sub connect { my ($self, %options) = @_; return if ($self->{connected} == 1); $self->{ssh}->options(host => $options{hostname}); if ($self->{ssh}->connect(SkipKeyProblem => $self->{ssh_strict_connect}) != $self->{constant_cb}->(name => 'SSH_OK')) { $self->{output}->add_option_msg(short_msg => 'connect issue: ' . $self->{ssh}->error()); $self->{output}->option_exit(); } if ($self->{ssh}->auth_publickey_auto() != $self->{constant_cb}->(name => 'SSH_AUTH_SUCCESS')) { if (defined($self->{ssh_username}) && $self->{ssh_username} ne '' && defined($self->{ssh_password}) && $self->{ssh_password} ne '' && $self->{ssh}->auth_password(password => $self->{ssh_password}) == $self->{constant_cb}->(name => 'SSH_AUTH_SUCCESS')) { $self->{connected} = 1; return ; } my $msg_error = $self->{ssh}->error(GetErrorSession => 1); $self->{output}->add_option_msg(short_msg => sprintf("auth issue: %s", defined($msg_error) && $msg_error ne '' ? $msg_error : 'pubkey issue')); $self->{output}->option_exit(); } $self->{connected} = 1; } sub execute { my ($self, %options) = @_; if (defined($options{timeout}) && $options{timeout} =~ /(\d+)/) { $self->{ssh}->options(timeout => $options{timeout}); } $self->connect(hostname => $options{hostname}); my $cmd = ''; $cmd = 'sudo ' if (defined($options{sudo})); $cmd .= $options{command_path} . '/' if (defined($options{command_path})); $cmd .= $options{command} . ' ' if (defined($options{command})); $cmd .= $options{command_options} if (defined($options{command_options})); my $ret; if (!defined($options{ssh_pipe}) || $options{ssh_pipe} == 0) { $ret = $self->{ssh}->execute_simple( cmd => $cmd, timeout => $options{timeout}, timeout_nodata => $options{timeout} ); } else { $ret = $self->{ssh}->execute_simple( input_data => $cmd, timeout => $options{timeout}, timeout_nodata => $options{timeout} ); } $self->{output}->output_add(long_msg => $ret->{stdout}, debug => 1) if (defined($ret->{stdout})); $self->{output}->output_add(long_msg => $ret->{stderr}, debug => 1) if (defined($ret->{stderr})); my ($content, $exit_code); if ($ret->{exit} == $self->{constant_cb}->(name => 'SSH_OK')) { $content = $ret->{stdout}; $exit_code = $ret->{exit_code}; } elsif ($ret->{exit} == $self->{constant_cb}->(name => 'SSH_AGAIN')) { # AGAIN means timeout $self->{output}->add_option_msg(short_msg => sprintf('command execution timeout')); $self->{output}->option_exit(); } else { $self->{output}->add_option_msg(short_msg => sprintf( 'command execution error: %s', $self->{ssh}->error(GetErrorSession => 1) ) ); $self->{output}->option_exit(); } if (defined($options{ssh_pipe}) && $options{ssh_pipe} == 1) { # Last failed login: Tue Feb 25 09:30:20 EST 2020 from 10.40.1.160 on ssh:notty # There was 1 failed login attempt since the last successful login. $content =~ s/^(?:Last failed login:|There was.*?failed login).*?\n//msg; } if ($exit_code != 0 && (!defined($options{no_quit}) || $options{no_quit} != 1)) { $self->{output}->add_option_msg(short_msg => sprintf('command execution error [exit code: %s]', $exit_code)); $self->{output}->option_exit(); } return ($content, $exit_code); } 1; __END__ =head1 NAME libssh backend. =head1 SYNOPSIS libssh backend. =head1 BACKEND LIBSSH OPTIONS =over 8 =item B<--libssh-strict-connect> Connection won't be OK even if there is a problem (server known changed or server found other) with the ssh server. =back =head1 DESCRIPTION B. =cut