some functional changes in gotty

This commit is contained in:
alejandro.campos@artica.es 2023-10-02 13:57:11 +02:00
parent 85598d5012
commit 12fbd1e522
3 changed files with 207 additions and 84 deletions

View File

@ -31,6 +31,7 @@ global $config;
require_once $config['homedir'].'/include/functions_agents.php';
require_once $config['homedir'].'/godmode/wizards/Wizard.main.php';
require_once $config['homedir'].'/include/functions_cron_task.php';
/**
@ -78,9 +79,28 @@ function quickShell()
return;
}
$method = get_parameter('method', null);
$setup_anchor = html_print_anchor(
[
'href' => 'index.php?sec=gsetup&sec2=godmode/setup/setup&section=quickshell',
'content' => __('GoTTY setup'),
],
true
);
if ($method === 'ssh' && (bool) $config['gotty_ssh_enabled'] === false) {
ui_print_error_message(__('Please, enable SSH in %s', $setup_anchor));
return;
}
if ($method === 'telnet' && (bool) $config['gotty_telnet_enabled'] === false) {
ui_print_error_message(__('Please, enable Telnet in %s', $setup_anchor));
return;
}
$agent_id = get_parameter('id_agente', 0);
$username = get_parameter('username', null);
$method = get_parameter('method', null);
$method_port = get_parameter('port', null);
// Retrieve main IP Address.
@ -89,10 +109,10 @@ function quickShell()
ui_require_css_file('wizard');
ui_require_css_file('discovery');
// Initialize Gotty Client.
// Build URL args.
if ($method === 'ssh') {
// SSH.
$args = '?arg='.$username.'@'.$agent_address;
$args .= '?arg='.$username.'@'.$agent_address;
//$args = '?arg='.$username.'@172.16.0.1';
$args .= '&arg=-p%20'.$method_port;
} else if ($method == 'telnet') {
@ -103,20 +123,15 @@ function quickShell()
$args .= '&arg='.$method_port.'&arg=-E';
}
$method_addr = ($method === 'ssh') ? $config['gotty_ssh_addr'] : $config['gotty_telnet_addr'];
$address = (empty($method_addr) === true) ? $_SERVER['SERVER_ADDR'] : $method_addr;
$use_ssl = ($method === 'ssh') ? $config['gotty_ssh_use_ssl'] : $config['gotty_telnet_use_ssl'];
$protocol = ((bool) $use_ssl === true) ? 'https://' : 'http://';
$port = ($method === 'ssh') ? $config['gotty_ssh_port'] : $config['gotty_telnet_port'];
$connection_hash = ($method === 'ssh') ? $config['gotty_ssh_connection_hash'] : $config['gotty_telnet_connection_hash'];
$gotty_addr = $protocol.$address.':'.$port.'/'.$connection_hash.'/'.$args;
$connectionURL = buildConnectionURL($method);
//$basic_auth_hdr = $config['gotty_ssh_user'].':'.$config['gotty_ssh_pass'].'@';
$gotty_addr = $connectionURL.$args;
// Username. Retrieve from form.
if (empty($username) === true) {
// No username provided, ask for it.
$wiz = new Wizard();
$wiz->printForm(
[
'form' => [
@ -192,13 +207,70 @@ function quickShell()
}
</style>
<div id="terminal"><iframe id="gotty-iframe" src="<?php echo $gotty_addr; ?>"></iframe></div>
<div id="terminal"><iframe id="gotty-iframe" src="<?php echo $gotty_addr; ?>"></iframe></div>
<?php
/*
<script>
// Capture error sent from iframe.
window.addEventListener("message", function(event) {
var received_data = event.data;
if (received_data.error_code) {
// Send error code to the server.
var new_url = window.location.href + "?error_code=" + received_data.error_code;
window.location.href = new_url;
}
});
var iframe = document.getElementById('gotty-iframe');
console.log(iframe );
iframe.addEventListener("error", function (event) {
console.log("erorrrrrrr");
// If an error occurs while loading the iframe content.
if (event.target.contentWindow) {
var status = event.target.contentWindow.document;
if (status && status.location) {
var status_code = status.location.href.match(/(\d{3})\.html/)[1];
if (status_code >= "400" && status_code < "600") {
// Post the error data to the parent window.
window.parent.postMessage(status_code, window.location.origin);
}
}
}
});
</script>*/
?>
<?php
}
/**
* Build Connection URL based on provided connection method.
*
* @param string $method Connection method (SSH/Telnet).
*
* @return string
*/
function buildConnectionURL($method)
{
global $config;
$method_addr = ($method === 'ssh') ? $config['gotty_ssh_addr'] : $config['gotty_telnet_addr'];
$address = (empty($method_addr) === true) ? $_SERVER['SERVER_ADDR'] : $method_addr;
$use_ssl = ($method === 'ssh') ? $config['gotty_ssh_use_ssl'] : $config['gotty_telnet_use_ssl'];
$protocol = ((bool) $use_ssl === true) ? 'https://' : 'http://';
$port = ($method === 'ssh') ? $config['gotty_ssh_port'] : $config['gotty_telnet_port'];
$connection_hash = ($method === 'ssh') ? $config['gotty_ssh_connection_hash'] : $config['gotty_telnet_connection_hash'];
//$basic_auth_hdr = $config['gotty_ssh_user'].':'.$config['gotty_ssh_pass'].'@';
return $protocol.$address.':'.$port.'/'.$connection_hash;
}
/**
* Provide an interface where configure all settings.
*
@ -212,6 +284,15 @@ function quickShellSettings()
ui_require_css_file('discovery');
// Gotty settings. Internal communication (WS).
if (isset($config['gotty_ssh_enabled']) === false) {
config_update_value('gotty_ssh_enabled', 0);
}
if (isset($config['gotty_telnet_enabled']) === false) {
config_update_value('gotty_telnet_enabled', 0);
}
if (isset($config['gotty_host']) === false) {
config_update_value('gotty_host', '127.0.0.1');
}
@ -245,6 +326,16 @@ function quickShellSettings()
// Parser.
if (get_parameter('update_config', false) !== false) {
$gotty_ssh_enabled = get_parameter(
'gotty_ssh_enabled',
0
);
$gotty_telnet_enabled = get_parameter(
'gotty_telnet_enabled',
0
);
$gotty_ssh_addr = get_parameter(
'gotty_ssh_addr',
''
@ -296,6 +387,14 @@ function quickShellSettings()
'Pandor4!'
);
if ($config['gotty_ssh_enabled'] != $gotty_ssh_enabled) {
config_update_value('gotty_ssh_enabled', $gotty_ssh_enabled);
}
if ($config['gotty_telnet_enabled'] != $gotty_telnet_enabled) {
config_update_value('gotty_telnet_enabled', $gotty_telnet_enabled);
}
$gotty_telnet_pass = io_input_password($gotty_telnet_pass);
if ($config['gotty_ssh_addr'] != $gotty_ssh_addr) {
@ -353,6 +452,8 @@ function quickShellSettings()
$gotty_telnet_pass = io_input_password($gotty_telnet_pass);
config_update_value('gotty_telnet_pass', $gotty_telnet_pass);
}
cron_task_start_gotty();
}
echo '<fieldset class="margin-bottom-10">';
@ -370,6 +471,16 @@ function quickShellSettings()
$ssh_table->style[0] = 'width: 50%;';
$ssh_table->data[0][] = html_print_label_input_block(
__('Enable SSH GoTTY'),
html_print_checkbox_switch(
'gotty_ssh_enabled',
1,
$config['gotty_ssh_enabled'],
true
)
);
$ssh_table->data[1][] = html_print_label_input_block(
__('Gotty address'),
html_print_input_text(
'gotty_ssh_addr',
@ -381,7 +492,7 @@ function quickShellSettings()
)
);
$ssh_table->data[0][] = html_print_label_input_block(
$ssh_table->data[1][] = html_print_label_input_block(
__('Gotty port'),
html_print_input_text(
'gotty_ssh_port',
@ -393,7 +504,7 @@ function quickShellSettings()
)
);
$ssh_table->data[1][] = html_print_label_input_block(
$ssh_table->data[2][] = html_print_label_input_block(
__('Gotty user'),
html_print_input_text(
'gotty_ssh_user',
@ -405,7 +516,7 @@ function quickShellSettings()
)
);
$ssh_table->data[1][] = html_print_label_input_block(
$ssh_table->data[2][] = html_print_label_input_block(
__('Gotty password'),
html_print_input_password(
'gotty_ssh_pass',
@ -417,7 +528,7 @@ function quickShellSettings()
)
);
$ssh_table->data[2][] = html_print_label_input_block(
$ssh_table->data[3][] = html_print_label_input_block(
__('Use SSL'),
html_print_checkbox_switch(
'gotty_ssh_use_ssl',
@ -433,7 +544,12 @@ function quickShellSettings()
$test_start = '<span id="test-gotty-spinner-ssh" class="invisible">&nbsp;'.html_print_image('images/spinner.gif', true).'</span>';
$test_start .= '&nbsp;<span id="test-gotty-message-ssh" class="invisible"></span>';
$ssh_table->data[2][] = html_print_button(
/*$tip = ui_print_help_tip(
__('Save configuration before performing test to check if GoTTY process was started successfully'),
true
);*/
$ssh_table->data[3][] = html_print_button(
__('Test'),
'test-gotty-ssh',
false,
@ -462,6 +578,16 @@ function quickShellSettings()
$telnet_table->style[0] = 'width: 50%;';
$telnet_table->data[0][] = html_print_label_input_block(
__('Enable Telnet GoTTY'),
html_print_checkbox_switch(
'gotty_telnet_enabled',
1,
$config['gotty_telnet_enabled'],
true
)
);
$telnet_table->data[1][] = html_print_label_input_block(
__('Gotty address'),
html_print_input_text(
'gotty_telnet_addr',
@ -473,7 +599,7 @@ function quickShellSettings()
)
);
$telnet_table->data[0][] = html_print_label_input_block(
$telnet_table->data[1][] = html_print_label_input_block(
__('Gotty port'),
html_print_input_text(
'gotty_telnet_port',
@ -485,7 +611,7 @@ function quickShellSettings()
)
);
$telnet_table->data[1][] = html_print_label_input_block(
$telnet_table->data[2][] = html_print_label_input_block(
__('Gotty user'),
html_print_input_text(
'gotty_telnet_user',
@ -497,7 +623,7 @@ function quickShellSettings()
)
);
$telnet_table->data[1][] = html_print_label_input_block(
$telnet_table->data[2][] = html_print_label_input_block(
__('Gotty password'),
html_print_input_password(
'gotty_telnet_pass',
@ -509,7 +635,7 @@ function quickShellSettings()
)
);
$telnet_table->data[2][] = html_print_label_input_block(
$telnet_table->data[3][] = html_print_label_input_block(
__('Use SSL'),
html_print_checkbox_switch(
'gotty_telnet_use_ssl',
@ -524,7 +650,7 @@ function quickShellSettings()
$test_start = '<span id="test-gotty-spinner-telnet" class="invisible">&nbsp;'.html_print_image('images/spinner.gif', true).'</span>';
$test_start .= '&nbsp;<span id="test-gotty-message-telnet" class="invisible"></span>';
$telnet_table->data[2][] = html_print_button(
$telnet_table->data[3][] = html_print_button(
__('Test'),
'test-gotty-telnet',
false,
@ -545,9 +671,10 @@ function quickShellSettings()
if (is_ajax() === true) {
$address = get_parameter('address');
$method = (string) get_parameter('method', '');
if (isset($address) === true) {
if (empty($method) === false) {
$address = buildConnectionURL($method);
$ch = curl_init($address);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
@ -571,6 +698,9 @@ if (is_ajax() === true) {
echo json_encode($result);
return;
}
$result = ['status' => 'error'];
return;
}
// This extension is useful only if the agent has associated IP.
@ -599,13 +729,14 @@ if (empty($agent_id) === false
}
echo '<script>';
echo 'var server_addr = "'.$_SERVER['SERVER_ADDR'].'";';
echo "function checkAddressReachability(address, callback) {
echo "function checkAddressReachability(method, callback) {
$.ajax({
url: 'ajax.php',
data: {
page: 'extensions/quick_shell',
address
method
},
type: 'GET',
async: false,
@ -663,7 +794,7 @@ $handle_test_telnet = "var handleTestTelnet = function (event) {
hideMessage();
showLoadingImage();
checkAddressReachability(url, function(isReachable) {
checkAddressReachability('telnet', function(isReachable) {
if (isReachable) {
showSuccessImage();
hideMessage();
@ -717,7 +848,7 @@ $handle_test_ssh = "var handleTestSSH = function (event) {
hideMessage();
showLoadingImage();
checkAddressReachability(url, function(isReachable) {
checkAddressReachability('ssh', function(isReachable) {
if (isReachable) {
showSuccessImage();
hideMessage();

View File

@ -161,30 +161,37 @@ class DiscoveryConsoleTask
}
}
// Maintenance task: schedule task 'cron_task_start_gotty' if not defined yet.
// Maintenance task: schedule daily task to manage GoTTY processes if not defined yet.
// Must do at every Cron execution.
if ((bool) $config['enterprise_installed'] === false) {
$call_func_user_task_id = db_get_value_sql('SELECT id FROM `tuser_task` WHERE `function_name` = "cron_task_call_user_function"');
if ($call_func_user_task_id === false) {
db_process_sql("INSERT INTO `tuser_task` (`function_name`, `parameters`, `name`) VALUES ('cron_task_call_user_function','a:1:{i:0;a:2:{s:11:\"description\";s:13:\"Function name\";s:4:\"type\";s:4:\"text\";}}','Call PHP function')");
$gotty_ssh_enabled = (bool) $config['gotty_ssh_enabled'];
$gotty_telnet_enabled = (bool) $config['gotty_telnet_enabled'];
if ($gotty_ssh_enabled === true || $gotty_telnet_enabled === true) {
// Create necessary data in task tables when some method of GoTTY is enabled in setup.
if ((bool) $config['enterprise_installed'] === false) {
$call_func_user_task_id = db_get_value_sql('SELECT id FROM `tuser_task` WHERE `function_name` = "cron_task_call_user_function"');
if ($call_func_user_task_id === false) {
db_process_sql("INSERT INTO `tuser_task` (`function_name`, `parameters`, `name`) VALUES ('cron_task_call_user_function','a:1:{i:0;a:2:{s:11:\"description\";s:13:\"Function name\";s:4:\"type\";s:4:\"text\";}}','Call PHP function')");
}
}
}
$user_function_task_id = db_get_value_sql('SELECT id FROM `tuser_task_scheduled` WHERE `args` LIKE "%cron_task_start_gotty%"');
$user_function_task_id = db_get_value_sql('SELECT id FROM `tuser_task_scheduled` WHERE `args` LIKE "%cron_task_start_gotty%"');
if ($user_function_task_id === false) {
$this->schedule(
'cron_task_call_user_function',
[
0 => 'cron_task_start_gotty',
'function_name' => 'cron_task_start_gotty',
'internal' => 1,
],
'daily',
0,
0,
strtotime('tomorrow')
);
if ($user_function_task_id === false) {
// Schedule task to manage GoTTY processes daily if it is not scheduled yet.
$this->schedule(
'cron_task_call_user_function',
[
0 => 'cron_task_start_gotty',
'function_name' => 'cron_task_start_gotty',
'internal' => 1,
],
'daily',
0,
0,
strtotime('tomorrow')
);
}
}
// Maintenance task: check whether start GoTTY SSH and Telnet processes are running and start otherwise.

View File

@ -449,15 +449,12 @@ function cron_task_start_gotty(bool $restart_mode=true)
{
global $config;
if (empty($config['gotty_ssh_addr']) === true
&& empty($config['gotty_telnet_addr']) === true
) {
return;
}
include_once $config['homedir'].'/include/functions_config.php';
// Check prev SSH process running and kill it.
$gotty_ssh_enabled = (bool) $config['gotty_ssh_enabled'];
$gotty_telnet_enabled = (bool) $config['gotty_telnet_enabled'];
// Check prev SSH process running and kill it (before changing config parameters).
if (empty($config['restart_gotty_ssh_next_cron_port']) === false) {
config_update_value('restart_gotty_ssh_next_cron_port', '');
@ -468,7 +465,7 @@ function cron_task_start_gotty(bool $restart_mode=true)
}
}
// Check if prev Telnet process running and kill it.
// Check if prev Telnet process running and kill it (before changing config parameters).
if (empty($config['restart_gotty_telnet_next_cron_port']) === false) {
config_update_value('restart_gotty_telnet_next_cron_port', '');
@ -486,49 +483,38 @@ function cron_task_start_gotty(bool $restart_mode=true)
$start_ssh_proc = true;
$start_telnet_proc = true;
if (empty($config['gotty_ssh_addr']) === true) {
if ($gotty_ssh_enabled === false) {
$start_ssh_proc = false;
}
if (empty($config['gotty_telnet_addr']) === true) {
if ($gotty_telnet_enabled === false) {
$start_telnet_proc = false;
}
if (!empty($processRunningSSH)) {
// Process is running.
if ($restart_mode === true || $start_ssh_proc === false) {
// Stop the process for restarting.
// Stop the process for restarting or in case GoTTY method is disabled in this iteration.
shell_exec("pkill -f 'pandora_gotty.*-p ".$config['gotty_ssh_port']."'");
} else {
// Prevent starting if already running and must not be restarted.
// Prevent starting if already running and must not be restarted or terminated.
$start_ssh_proc = false;
}
}
if (!empty($processRunningTelnet)) {
// Process is running.
if ($restart_mode === true
|| empty($config['restart_gotty_telnet_next_cron_port']) === false
|| $start_telnet_proc === false
) {
// Restart GoTTY if it is intended to be restarted specifically, port has changed, or address was changed to an empty value.
if (empty($config['restart_gotty_telnet_next_cron_port']) === false) {
$telnet_port_kill = $config['restart_gotty_telnet_next_cron_port'];
config_update_value('restart_gotty_telnet_next_cron_port', '');
} else {
$telnet_port_kill = $config['gotty_telnet_port'];
}
// Stop the process for restarting.
shell_exec("pkill -f 'pandora_gotty.*-p ".$telnet_port_kill."'");
if ($restart_mode === true || $start_telnet_proc === false) {
// Stop the process for restarting or in case GoTTY method is disabled in this iteration.
shell_exec("pkill -f 'pandora_gotty.*-p ".$config['gotty_telnet_port']."'");
} else {
// Prevent starting if already running and must not be restarted.
// Prevent starting if already running and must not be restarted or terminated.
$start_telnet_proc = false;
}
}
if ($start_ssh_proc === false && $start_telnet_proc === false) {
// Nothing to do.
// Nothing to start.
return;
}
@ -537,7 +523,7 @@ function cron_task_start_gotty(bool $restart_mode=true)
shell_exec('touch '.$logFilePathSSH);
// Start pandora_gotty and capture the output.
$command_ssh = '/usr/bin/nohup /usr/bin/pandora_gotty --config /etc/pandora_gotty/pandora_gotty.conf -p '.$config['gotty_ssh_port'].' ssh > '.$logFilePathSSH.' 2>&1 &';
$command_ssh = '/usr/bin/nohup /usr/bin/pandora_gotty --config /etc/pandora_gotty/pandora_gotty.conf --ws-origin ".*" -p '.$config['gotty_ssh_port'].' ssh > '.$logFilePathSSH.' 2>&1 &';
shell_exec($command_ssh);
}
@ -546,15 +532,15 @@ function cron_task_start_gotty(bool $restart_mode=true)
shell_exec('touch '.$logFilePathTelnet);
// Start pandora_gotty and capture the output.
$command_telnet = '/usr/bin/nohup /usr/bin/pandora_gotty --config /etc/pandora_gotty/pandora_gotty.conf -p '.$config['gotty_telnet_port'].' telnet > '.$logFilePathTelnet.' 2>&1 &';
$command_telnet = '/usr/bin/nohup /usr/bin/pandora_gotty --config /etc/pandora_gotty/pandora_gotty.conf --ws-origin ".*" -p '.$config['gotty_telnet_port'].' telnet > '.$logFilePathTelnet.' 2>&1 &';
shell_exec($command_telnet);
}
$ssh_hash_read = false;
$telnet_hash_read = false;
// Maximum wait time (seconds).
$maxWaitTime = 2;
// Maximum wait time to read asynchronously the output of the executed commands (seconds).
$maxWaitTime = 10;
// Wait for content to appear in the log file.
$startTime = time();
@ -579,11 +565,10 @@ function cron_task_start_gotty(bool $restart_mode=true)
$hash = array_slice($parts, -2, 1)[0];
config_update_value('gotty_ssh_connection_hash', $hash);
$ssh_hash_read = true;
}
unlink($logFilePathSSH);
$ssh_hash_read = true;
}
if ($start_telnet_proc === true) {
@ -604,16 +589,16 @@ function cron_task_start_gotty(bool $restart_mode=true)
$hash = array_slice($parts, -2, 1)[0];
config_update_value('gotty_telnet_connection_hash', $hash);
$telnet_hash_read = true;
}
unlink($logFilePathTelnet);
$telnet_hash_read = true;
}
if (($start_ssh_proc === false || $ssh_hash_read === true)
&& ($start_telnet_proc === false || $telnet_hash_read === true)
) {
// As soon as the reads have completed, the timing loop will terminate.
break;
}