From 9bf5440826f060d4349fc4348e50dc4e3b57fbbf Mon Sep 17 00:00:00 2001 From: UBiqube-ydu Date: Mon, 26 Jan 2026 14:24:16 +0100 Subject: [PATCH] OPSLAB-245: Fix restore for Stormshield --- adapters/stormshield/conf/device.properties | 2 +- adapters/stormshield/connect_cli.php | 4 +- adapters/stormshield/do_get_archive_conf.php | 2 +- adapters/stormshield/do_restore_conf.php | 173 ++++++++++++++++--- 4 files changed, 157 insertions(+), 24 deletions(-) diff --git a/adapters/stormshield/conf/device.properties b/adapters/stormshield/conf/device.properties index f1c81550..5b99fe68 100644 --- a/adapters/stormshield/conf/device.properties +++ b/adapters/stormshield/conf/device.properties @@ -3,5 +3,5 @@ model.name = Generic manufacturer.id = 16010401 manufacturer.name = Stormshield manufacturer.category = Security -feature.restore = false +feature.restore = true obsolete = false diff --git a/adapters/stormshield/connect_cli.php b/adapters/stormshield/connect_cli.php index d1f8fcfd..0b93a5ae 100644 --- a/adapters/stormshield/connect_cli.php +++ b/adapters/stormshield/connect_cli.php @@ -42,8 +42,8 @@ public function do_connect() { } public function do_disconnect() { - $this->sendexpectone(__FILE__.':'.__LINE__, "quit", '>'); - $this->sendCmd(__FILE__.':'.__LINE__, 'exit'); + //$this->sendexpectone(__FILE__.':'.__LINE__, "quit", '>'); + //$this->sendCmd(__FILE__.':'.__LINE__, 'exit'); parent::disconnect(); } diff --git a/adapters/stormshield/do_get_archive_conf.php b/adapters/stormshield/do_get_archive_conf.php index 4af490e7..bf55f911 100644 --- a/adapters/stormshield/do_get_archive_conf.php +++ b/adapters/stormshield/do_get_archive_conf.php @@ -55,7 +55,7 @@ echo "/opt/sms/bin/sms_scp_transfer -r -s $local_backup -d $target_file -a $sd->SD_IP_CONFIG -l $sd->SD_LOGIN_ENTRY -p '$sd->SD_PASSWD_ENTRY' -P $sd->SD_MANAGEMENT_PORT\n"; -$ret_scp = exec_local(__FILE__.':'.__LINE__, "/opt/sms/bin/sms_scp_transfer -r -s $local_backup -d $target_file -a $sd->SD_IP_CONFIG -l $sd->SD_LOGIN_ENTRY -p '$sd->SD_PASSWD_ENTRY' -P $sd->SD_MANAGEMENT_PORT", $output); +exec_local(__FILE__.':'.__LINE__, "/opt/sms/bin/sms_scp_transfer -r -s $local_backup -d $target_file -a $sd->SD_IP_CONFIG -l $sd->SD_LOGIN_ENTRY -p '$sd->SD_PASSWD_ENTRY' -P $sd->SD_MANAGEMENT_PORT", $output); // remove the backup on the ME connect(); diff --git a/adapters/stormshield/do_restore_conf.php b/adapters/stormshield/do_restore_conf.php index d5448ddd..037f374c 100644 --- a/adapters/stormshield/do_restore_conf.php +++ b/adapters/stormshield/do_restore_conf.php @@ -16,11 +16,136 @@ */ // Restore configuration from archive file -// TODO require_once 'smsd/sms_common.php'; -require_once load_once('stormshield', 'netasq_configuration.php'); +require_once load_once('stormshield', 'connect_cli.php'); +require_once load_once('stormshield', 'nsrpc.php'); + +function get_old_revision($restore_conf_file, $revision_id) +{ + global $sdid; + + echo("restore_from_old_revision revision_id: $revision_id\n"); + + $get_saved_conf_cmd = "/opt/sms/script/get_saved_conf --getfile {$sdid} file {$restore_conf_file} r{$revision_id}"; + + $ret = exec_local(__FILE__ . ':' . __LINE__, $get_saved_conf_cmd, $output); + if ($ret !== SMS_OK) + { + echo("no running conf found\n"); + unlink($restore_conf_file); + return $ret; + } + + if (!file_exists($restore_conf_file)) + { + echo("no running conf found\n"); + return ERR_CONFIG_EMPTY; + } + + return SMS_OK; +} + +function copy_restore_file_to_me($sd, $src, $dst) +{ + global $sms_sd_ctx; + + $ret = SMS_OK; + + echo "/opt/sms/bin/sms_scp_transfer -s $src -d $dst -a $sd->SD_IP_CONFIG -l $sd->SD_LOGIN_ENTRY -p '$sd->SD_PASSWD_ENTRY' -P $sd->SD_MANAGEMENT_PORT\n"; + + exec_local(__FILE__.':'.__LINE__, "/opt/sms/bin/sms_scp_transfer -s $src -d $dst -a $sd->SD_IP_CONFIG -l $sd->SD_LOGIN_ENTRY -p '$sd->SD_PASSWD_ENTRY' -P $sd->SD_MANAGEMENT_PORT", $output); + // no check ot the outcome, will check the presence of the file on the ME later on + + // remove the backup on the MSA + unlink($src); + + // check file on ME + connect(); + + sendexpectone(__FILE__.':'.__LINE__, $sms_sd_ctx, "quit", '>'); + $result = sendexpectone(__FILE__.':'.__LINE__, $sms_sd_ctx, "test -f $dst; echo $?", '>'); + if (strpos($result, "\n0") === false) + { + $err = __FILE__ . ':' . __LINE__ . ": Impossible to copy restore file from $src to $dst\n"; + sms_log_error("$err\n"); + $ret = ERR_SD_CMDFAILED; + } + + disconnect(); + + return $ret; +} + +function restore_conf($sd, $restore_conf_file) +{ + global $sms_sd_ctx; + + connect(); + + sendexpectone(__FILE__.':'.__LINE__, $sms_sd_ctx, "modify on force"); + + $ret = sendexpectone(__FILE__.':'.__LINE__, $sms_sd_ctx, "config restore list=\"all\" refresh=1 < $restore_conf_file"); + + sendexpectone(__FILE__.':'.__LINE__, $sms_sd_ctx, "quit", '>'); + sendexpectone(__FILE__.':'.__LINE__, $sms_sd_ctx, "rm $restore_conf_file", '>'); + + if (is_error($ret)) + { + $err = __FILE__ . ':' . __LINE__ . ": Error config restore list=\"all\" refresh=1 < $restore_conf_file returns\n$ret"; + sms_log_error("$err\n"); + disconnect(); + return ERR_SD_CMDFAILED; + } + + // reboot + sendexpectone(__FILE__.':'.__LINE__, $sms_sd_ctx, 'cli', 'assword'); + sendexpectone(__FILE__.':'.__LINE__, $sms_sd_ctx, $sd->SD_PASSWD_ENTRY); + sendexpectone(__FILE__.':'.__LINE__, $sms_sd_ctx, "system reboot", '>'); + + disconnect(); + + return SMS_OK; +} + +function wait_until_device_is_up($sd, $nb_loop = 60, $initial_sec_to_wait = 30) +{ + // wait the device become up after reboot + $ret = wait_for_device_up($sd->SD_IP_CONFIG, $nb_loop, $initial_sec_to_wait); + if ($ret != SMS_OK) + { + return $ret; + } + + sms_sleep($initial_sec_to_wait); // Wait for the ssh service + $done = $nb_loop; + do + { + echo "waiting for the device (SSH), $done\n"; + sleep(5); + try + { + connect(); + break; + } + catch (Exception | Error $e) + { + $done--; + } + } while ($done > 0); + + if ($done === 0) + { + sms_log_error(__FILE__ . ':' . __LINE__ . ": The device stay DOWN\n"); + return ERR_SD_CMDTMOUT; + } + + disconnect(); + + return SMS_OK; +} + $ret = sms_sd_lock($sms_csp, $sms_sd_info); if ($ret !== 0) @@ -37,39 +162,47 @@ // Asynchronous mode, the user socket is now closed, the results are written in database +$network = get_network_profile(); +$sd = &$network->SD; + try { - netasq_connect(); - - $conf = new netasq_configuration($sdid); + $restore_conf_file = "{$sdid}_r{$revision_id}.conf"; + $msa_restore_conf_file = "/opt/sms/spool/tmp/{$restore_conf_file}"; - // Should be connected before calling restore_from_old_revision - // After restore_from_old_revision is called, we are disconnected - $ret = $conf->restore_from_old_revision($revision_id); + $ret = get_old_revision($msa_restore_conf_file, $revision_id); if ($ret !== SMS_OK) { - sms_set_update_status($sms_csp, $sdid, $ret, 'RESTORE', 'FAILED', "Restoring revision $revision_id failed"); + sms_set_update_status($sms_csp, $sdid, $ret, 'RESTORE', 'FAILED', "Getting revision $revision_id failed"); sms_sd_unlock($sms_csp, $sms_sd_info); return SMS_OK; } - sms_set_update_status($sms_csp, $sdid, SMS_OK, 'RESTORE', 'WORKING', "Waiting the device (restore revision: $revision_id)"); - $ret = $conf->wait_until_device_is_up(60, 0); - if ($ret !== SMS_OK) + $me_restore_conf_file = "/tmp/{$restore_conf_file}"; + + $ret = copy_restore_file_to_me($sd, $msa_restore_conf_file, $me_restore_conf_file); + if ($ret != SMS_OK) { - sms_set_update_status($sms_csp, $sdid, $ret, 'RESTORE', 'FAILED', "The device is unreachable after restoring the configuration (restore revision: $revision_id)"); + sms_set_update_status($sms_csp, $sdid, $ret, 'RESTORE', 'FAILED', "Copying revision $revision_id failed"); sms_sd_unlock($sms_csp, $sms_sd_info); return SMS_OK; } - if ($conf->sd->SD_HSRP_TYPE !== 0) + $ret = restore_conf($sd, $me_restore_conf_file); + if ($ret != SMS_OK) { - netasq_connect(); - - sms_set_update_status($sms_csp, $sdid, SMS_OK, 'RESTORE', 'WORKING', "Synchronize the configuration on the passive node (restore revision: $revision_id)"); - $ret = $conf->ha_sync(); + sms_set_update_status($sms_csp, $sdid, $ret, 'RESTORE', 'FAILED', "Restoring revision $revision_id failed"); + sms_sd_unlock($sms_csp, $sms_sd_info); + return SMS_OK; + } - netasq_disconnect(); + sms_set_update_status($sms_csp, $sdid, SMS_OK, 'RESTORE', 'WORKING', "Waiting the device (restore revision: $revision_id)"); + $ret = wait_until_device_is_up($sd); + if ($ret !== SMS_OK) + { + sms_set_update_status($sms_csp, $sdid, $ret, 'RESTORE', 'FAILED', "The device is unreachable after restoring the configuration (restore revision: $revision_id)"); + sms_sd_unlock($sms_csp, $sms_sd_info); + return SMS_OK; } sms_set_update_status($sms_csp, $sdid, SMS_OK, 'RESTORE', 'WORKING', "Backup of the restored configuration (restore revision: $revision_id)"); @@ -80,7 +213,7 @@ } catch (Exception | Error $e) { - netasq_disconnect(); + disconnect(); sms_set_update_status($sms_csp, $sdid, $e->getCode(), 'RESTORE', 'FAILED', "Restore failure (restore revision: $revision_id)"); sms_sd_unlock($sms_csp, $sms_sd_info); return SMS_OK;