%PDF- %PDF-
Direktori : /backups/router/usr/local/www/ |
Current File : //backups/router/usr/local/www/diag_backup.php |
<?php /* * Copyright (C) 2015-2023 Franco Fichtner <franco@opnsense.org> * Copyright (C) 2014 Deciso B.V. * Copyright (C) 2004-2009 Scott Ullrich <sullrich@gmail.com> * Copyright (C) 2008 Shrew Soft Inc. <mgrooms@shrew.net> * Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net> * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ require_once("guiconfig.inc"); require_once("interfaces.inc"); require_once("console.inc"); require_once("filter.inc"); require_once("rrd.inc"); require_once("system.inc"); use OPNsense\Backup\Local; /** * restore config section * @param array $section_sets config section sets * @param string $new_contents xml content * @return bool status */ function restore_config_section($section_sets, $new_contents) { global $config; $tmpxml = '/tmp/tmpxml'; $xml = null; try { file_put_contents($tmpxml, $new_contents); $xml = load_config_from_file($tmpxml); } catch (Exception $e) { } @unlink($tmpxml); if (!is_array($xml)) { return false; } $restored = []; $failed = []; foreach ($section_sets as $section_set) { $sections = explode(',', $section_set); $found = []; /* first find the existing sections from the set to be imported */ foreach ($sections as $section) { $new = &$xml; $path = explode('.', $section); $target = array_pop($path); foreach ($path as $node) { if (!isset($new[$node])) { continue 2; } $new = &$new[$node]; } if (isset($new[$target])) { $found[] = $section; } } /* keep current config and skip to next one considering this set (and subsequently the import) failed */ if (!count($found)) { $failed[] = $section_set; continue; } /* secondly delete every old config section to be able to force a migration too */ foreach (array_diff($sections, $found) as $section) { $old = &$config; $path = explode('.', $section); $target = array_pop($path); foreach ($path as $node) { if (!isset($old[$node])) { continue 2; } $old = &$old[$node]; } if (isset($old[$target])) { unset($old[$target]); $restored[] = $section; } } /* thirdly and lastly import the found sections */ foreach ($found as $section) { $old = &$config; $new = &$xml; $path = explode('.', $section); $target = array_pop($path); foreach ($path as $node) { if (!isset($new[$node])) { continue 2; } $new = &$new[$node]; if (!isset($old[$node])) { $old[$node] = []; } $old = &$old[$node]; } if (isset($new[$target])) { $old[$target] = $new[$target]; $restored[] = $section; } } } if (count($restored) && !count($failed)) { /* restored but may not have been modified at all */ write_config(sprintf('Restored sections (%s) of config file', join(',', $restored))); convert_config(); } return $failed; } /* config areas that are not suitable for config sync live here */ $areas = [ 'bridges' => gettext('Bridge Devices'), 'gifs' => gettext('GIF Devices'), 'interfaces' => gettext('Interfaces'), 'laggs' => gettext('LAGG Devices'), 'ppps' => gettext('Point-to-Point Devices'), 'rrddata' => gettext('RRD Data'), 'vlans' => gettext('VLAN Devices'), 'wireless' => gettext('Wireless Devices'), ]; foreach (plugins_xmlrpc_sync() as $area) { if (!empty($area['section'])) { $areas[$area['section']] = $area['description']; } } natcasesort($areas); $backupFactory = new OPNsense\Backup\BackupFactory(); $do_reboot = false; if ($_SERVER['REQUEST_METHOD'] === 'GET') { $pconfig = []; $pconfig['backupcount'] = isset($config['system']['backupcount']) ? $config['system']['backupcount'] : null; $pconfig['rebootafterrestore'] = true; $pconfig['keepconsole'] = true; $pconfig['flush_history'] = true; $pconfig['decrypt'] = false; foreach ($backupFactory->listProviders() as $providerId => $provider) { foreach ($provider['handle']->getConfigurationFields() as $field) { $fieldId = $providerId . "_" .$field['name']; $pconfig[$fieldId] = $field['value']; } } } elseif ($_SERVER['REQUEST_METHOD'] === 'POST') { $input_errors = []; $pconfig = $_POST; $mode = null; foreach (array_keys($backupFactory->listProviders()) as $providerName) { if (!empty($pconfig["setup_{$providerName}"])) { $mode = "setup_{$providerName}"; } } if (empty($mode)) { if (!empty($pconfig['restore'])) { $mode = "restore"; } elseif (!empty($pconfig['download'])) { $mode = "download"; } } if ($mode == "download") { if (!empty($_POST['encrypt']) && (empty($_POST['encrypt_password']) || empty($_POST['encrypt_passconf']))) { $input_errors[] = gettext("You must supply and confirm the password for encryption."); } elseif (!empty($_POST['encrypt']) && $_POST['encrypt_password'] != $_POST['encrypt_passconf']) { $input_errors[] = gettext('The passwords do not match.'); } if (count($input_errors) == 0) { $host = "{$config['system']['hostname']}.{$config['system']['domain']}"; $name = "config-{$host}-".date("YmdHis").".xml"; $data = ""; /* backup entire configuration */ $data = file_get_contents('/conf/config.xml'); /* backup RRD data */ if (empty($_POST['donotbackuprrd'])) { $rrd_data_xml = rrd_export(); $closing_tag = "</opnsense>"; $data = str_replace($closing_tag, $rrd_data_xml . $closing_tag, $data); } if (!empty($_POST['encrypt'])) { $crypter = new Local(); /* XXX this *could* fail, not handled */ $data = $crypter->encrypt($data, $_POST['encrypt_password']); } $size = strlen($data); header("Content-Type: application/octet-stream"); header("Content-Disposition: attachment; filename={$name}"); header("Content-Length: $size"); if (isset($_SERVER['HTTPS'])) { header('Pragma: '); header('Cache-Control: '); } else { header("Pragma: private"); header("Cache-Control: private, must-revalidate"); } echo $data; exit; } } elseif ($mode == "restore") { // unpack data and perform validation $data = null; if (!empty($_POST['decrypt']) && empty($_POST['decrypt_password'])) { $input_errors[] = gettext('You must supply the password for decryption.'); } $user = getUserEntry($_SESSION['Username']); if (userHasPrivilege($user, 'user-config-readonly')) { $input_errors[] = gettext('You do not have the permission to perform this action.'); } /* read the file contents */ if (is_uploaded_file($_FILES['conffile']['tmp_name'])) { $data = file_get_contents($_FILES['conffile']['tmp_name']); if(empty($data)) { $input_errors[] = sprintf(gettext("Warning, could not read file %s"), $_FILES['conffile']['tmp_name']); } } else { $input_errors[] = gettext("The configuration could not be restored (file upload error)."); } if (!empty($_POST['decrypt'])) { $crypter = new Local(); $data = $crypter->decrypt($data, $_POST['decrypt_password']); if (empty($data)) { $input_errors[] = gettext('The uploaded file could not be decrypted.'); } } if (count($input_errors) == 0) { if (!empty($pconfig['restorearea'])) { $ret = restore_config_section($pconfig['restorearea'], $data); if ($ret === false) { $input_errors[] = gettext('The selected config file could not be parsed.'); } elseif (count($ret)) { $descr = []; foreach ($ret as $area) { $descr[] = $areas[$area]; } $input_errors[] = sprintf(gettext('At least one requested restore area could not be found: %s.'), join(', ', $descr)); } else { if (!empty($config['rrddata'])) { /* XXX we should point to the data... */ rrd_import(); unset($config['rrddata']); write_config(); convert_config(); } if (!empty($pconfig['rebootafterrestore'])) { $do_reboot = true; } $savemsg = gettext("The configuration area has been restored."); } } else { /* restore the entire configuration */ $cfieldnames = [ 'usevirtualterminal', 'primaryconsole', 'secondaryconsole', 'serialspeed', 'serialusb', 'disableconsolemenu' ]; $csettings = []; foreach ($cfieldnames as $fieldname) { $csettings[$fieldname] = $config['system'][$fieldname] ?? null; } $filename = $_FILES['conffile']['tmp_name']; file_put_contents($filename, $data); $cnf = OPNsense\Core\Config::getInstance(); if ($cnf->restoreBackup($filename)) { if (!empty($pconfig['rebootafterrestore'])) { $do_reboot = true; } $config = parse_config(); $flush = false; if (!empty($pconfig['keepconsole'])) { // restore existing console settings foreach ($csettings as $fieldname => $fieldcontent) { if ($fieldcontent === null && isset($config[$fieldname])) { unset($config[$fieldname]); } else { $config['system'][$fieldname] = $fieldcontent; } } $flush = true; } if (!empty($config['rrddata'])) { /* XXX we should point to the data... */ rrd_import(); unset($config['rrddata']); $flush = true; } if ($flush) { write_config(); convert_config(); } $savemsg = gettext("The configuration has been restored."); } else { $input_errors[] = gettext("The configuration could not be restored."); } } if (is_interface_mismatch(false)) { $savemsg .= ' ' . sprintf( gettext( "Interfaces do not seem to match, please check the %sassignments%s now for missing devices." ), '<a href="/interfaces_assign.php">', '</a>' ); if ($do_reboot) { $savemsg .= ' ' . gettext('Postponing reboot.'); $do_reboot = false; } } if ($do_reboot) { $savemsg .= ' ' . gettext("The system is rebooting now. This may take one minute."); } if (empty($input_errors) && !empty($pconfig['flush_history'])) { configd_run('system flush config_history'); write_config('System restore flushed local history'); } } } elseif (!empty($mode)){ // setup backup provider, collect provider settings and save/validate $providerId = substr($mode, 6); $provider = $backupFactory->getProvider($providerId); $providerSet = array(); foreach ($provider['handle']->getConfigurationFields() as $field) { $fieldId = $providerId . "_" .$field['name']; if ($field['type'] == 'file') { // extract file to sent to setConfiguration() if (is_uploaded_file($_FILES[$fieldId]['tmp_name'])) { $providerSet[$field['name']] = file_get_contents($_FILES[$fieldId]['tmp_name']); } else { $providerSet[$field['name']] = null; } } else { $providerSet[$field['name']] = $pconfig[$fieldId]; } } $input_errors = $provider['handle']->setConfiguration($providerSet); if (count($input_errors) == 0) { if ($provider['handle']->isEnabled()) { try { $filesInBackup = $provider['handle']->backup(); } catch (Exception $e) { $filesInBackup = array(); $input_errors[] = $e->getMessage(); } if (count($filesInBackup) == 0) { $input_errors[] = gettext('Saved settings, but remote backup failed.'); } else { $input_messages = gettext("Backup successful, current file list:") . "<br>"; foreach ($filesInBackup as $filename) { $input_messages .= "<br>" . $filename; } } } system_cron_configure(); } } elseif (!empty($pconfig['save'])) { if ($pconfig['backupcount'] != null && (!is_numeric($pconfig['backupcount']) || $pconfig['backupcount'] <= 0)) { $input_errors[] = gettext('Backup count must be greater than zero.'); } if (count($input_errors) == 0) { if ($pconfig['backupcount'] != null) { $config['system']['backupcount'] = $pconfig['backupcount']; } elseif (isset($config['system']['backupcount'])) { unset($config['system']['backupcount']); } write_config('Changed backup revision count'); $savemsg = get_std_save_message(); } } } include("head.inc"); legacy_html_escape_form_data($pconfig); ?> <body> <?php include("fbegin.inc"); ?> <script> function show_value(key) { $('#show-' + key + '-btn').html(''); $('#show-' + key + '-val').show(); $("[name='" + key + "']").focus(); } //<![CDATA[ $( document ).ready(function() { // show encryption password $("#encryptconf").change(function(event){ event.preventDefault(); if ($("#encryptconf").prop('checked')) { $("#encrypt_opts").removeClass("hidden"); } else { $("#encrypt_opts").addClass("hidden"); } }); // show decryption password $("#decryptconf").change(function(event){ event.preventDefault(); if ($("#decryptconf").prop('checked')) { $("#decrypt_opts").removeClass("hidden"); } else { $("#decrypt_opts").addClass("hidden"); } }); $("#decryptconf").change(); $('#restorearea').change(function () { $("#flush_history").attr('checked', false); if ($('#restorearea option:selected').text() == '') { $.restorearea_warned = 0; $("#flush_history").attr('checked', true); } else if ($.restorearea_warned != 1) { $.restorearea_warned = 1; BootstrapDialog.confirm({ title: '<?= html_safe(gettext('Warning!')) ?>', message: '<?= html_safe(gettext('Selecting specific restore areas during a configuration import may ' . 'cause loss of configuration integrity due to external references not being restored. It is ' . 'recommended to keep this set to the default unless you know what you are doing.')) ?>', type: BootstrapDialog.TYPE_WARNING, btnOKClass: 'btn-warning', btnOKLabel: '<?= html_safe(gettext('I know what I am doing')) ?>', btnCancelLabel: '<?= html_safe(gettext('Use the default')) ?>', callback: function(result) { if (!result) { $('#restorearea option:selected').prop('selected', false); $('#restorearea').selectpicker('refresh'); $.restorearea_warned = 0; } } }); } }); $.restorearea_warned = $('#restorearea option:selected').length ? 1 : 0; }); //]]> </script> <section class="page-content-main"> <div class="container-fluid"> <div class="row"> <?php if (isset($savemsg)) print_info_box($savemsg); ?> <?php if (isset($input_messages)) print_info_box($input_messages); ?> <?php if (isset($input_errors) && count($input_errors) > 0) print_input_errors($input_errors); ?> <form method="post" enctype="multipart/form-data"> <section class="col-xs-12"> <div class="content-box tab-content table-responsive __mb"> <table class="table table-striped"> <div class="content-box tab-content table-responsive __mb"> <table class="table table-striped"> <tbody> <tr> <td colspan="2"><strong><?= gettext('Backup Count') ?></strong></td> </tr> <tr> <td><input name="backupcount" type="text" size="5" value="<?= html_safe($pconfig['backupcount']) ?>"/></td> <td><?= gettext("Enter the number of older configurations to keep in the local backup cache."); ?></td> </tr> <tr> <td><input name="save" type="submit" class="btn btn-primary" value="<?= html_safe(gettext('Save')) ?>"/></td> <td> <?= gettext('Be aware of how much space is consumed by backups before adjusting this value.'); ?> <?php if (count(OPNsense\Core\Config::getInstance()->getBackups(true)) > 0): ?> <?= gettext('Current space used:') . ' ' . exec("/usr/bin/du -sh /conf/backup | /usr/bin/awk '{print $1;}'") ?> <?php endif ?> </td> </tr> </tbody> </table> </div> </section> <section class="col-xs-12"> <div class="content-box tab-content table-responsive __mb"> <table class="table table-striped"> <tr> <td><strong><?= gettext('Download') ?></strong></td> </tr> <tr> <td> <input name="donotbackuprrd" type="checkbox" id="dotnotbackuprrd" checked="checked" /> <?=gettext("Do not backup RRD data."); ?><br/> <input name="encrypt" type="checkbox" id="encryptconf" /> <?=gettext("Encrypt this configuration file."); ?><br/> <div class="hidden table-responsive __mt" id="encrypt_opts"> <table class="table table-condensed"> <tr> <td><?= gettext('Password') ?></td> <td><input name="encrypt_password" type="password" autocomplete="new-password"/></td> </tr> <tr> <td><?= gettext('Confirmation') ?></td> <td><input name="encrypt_passconf" type="password" autocomplete="new-password"/> </td> </tr> </table> </div> </td> </tr> <tr> <td> <input name="download" type="submit" class="btn btn-primary" value="<?= html_safe(gettext('Download configuration')) ?>" /> </td> </tr> <tr> <td> <?=gettext("Click this button to download the system configuration in XML format."); ?> </td> </tr> </table> </div> <div class="content-box tab-content table-responsive __mb"> <table class="table table-striped"> <tr> <td><strong><?= gettext('Restore') ?></strong></td> </tr> <tr> <td> <?= gettext('Restore areas:') ?> <div> <select name="restorearea[]" id="restorearea" class="selectpicker" multiple="multiple" size="5" title="<?= html_safe(gettext('All (recommended)')) ?>" data-live-search="true" data-size="10"> <?php foreach ($areas as $area => $areaname): ?> <option value="<?= html_safe($area) ?>" <?= in_array($area, $pconfig['restorearea'] ?? []) ? 'selected="selected"' : '' ?>><?= $areaname ?></option> <?php endforeach ?> </select> </div> <br/><input name="conffile" type="file" id="conffile" /><br/> <input name="rebootafterrestore" type="checkbox" id="rebootafterrestore" <?= !empty($pconfig['rebootafterrestore']) ? 'checked="checked"' : '' ?>/> <?=gettext("Reboot after a successful restore."); ?><br/> <input name="keepconsole" type="checkbox" id="keepconsole" <?= !empty($pconfig['keepconsole']) ? 'checked="checked"' : '' ?>/> <?=gettext("Exclude console settings from import."); ?><br/> <input name="flush_history" type="checkbox" id="flush_history" <?= !empty($pconfig['flush_history']) ? 'checked="checked"' : '' ?>/> <?=gettext("Flush (full) local configuration history."); ?><br/> <input name="decrypt" type="checkbox" id="decryptconf" <?= !empty($pconfig['decrypt']) ? 'checked="checked"' : '' ?>/> <?=gettext("Configuration file is encrypted."); ?> <div class="hidden table-responsive __mt" id="decrypt_opts"> <table class="table table-condensed"> <tr> <td><?= gettext('Password') ?></td> <td><input name="decrypt_password" type="password" autocomplete="new-password"/></td> </tr> </table> </div> </td> </tr> <tr> <td> <input name="restore" type="submit" class="btn btn-primary" id="restore" value="<?= html_safe(gettext('Restore configuration')) ?>" /> </td> </tr> <tr> <td> <?=gettext("Open a configuration XML file and click the button below to restore the configuration."); ?><br/> </td> </tr> </table> </div> <?php foreach ($backupFactory->listProviders() as $providerId => $provider):?> <div class="content-box tab-content table-responsive __mb"> <table class="table table-striped opnsense_standard_table_form"> <tr> <td colspan="2"><strong><?= $provider['handle']->getName() ?></strong></td> </tr> <?php foreach ($provider['handle']->getConfigurationFields() as $field): $fieldId = $providerId . "_" .$field['name'];?> <tr> <td style="width:22%"> <?php if (!empty($field['help'])): ?> <a id="help_for_<?=$fieldId;?>" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?php else: ?> <i class="fa fa-info-circle text-muted"></i> <?php endif ?> <?=$field['label'];?> </td> <td style="width:78%"> <?php if ($field['type'] == 'checkbox'): ?> <input name="<?=$fieldId;?>" type="checkbox" <?=!empty($pconfig[$fieldId]) ? "checked" : "";?> > <?php elseif ($field['type'] == 'text'): ?> <input name="<?=$fieldId;?>" value="<?=$pconfig[$fieldId];?>" type="text"> <?php elseif ($field['type'] == 'file'): ?> <input name="<?=$fieldId;?>" type="file"> <?php elseif ($field['type'] == 'password'):?> <input name="<?=$fieldId;?>" type="password" autocomplete="new-password" value="<?=$pconfig[$fieldId];?>" /> <?php elseif ($field['type'] == 'textarea'): ?> <textarea name="<?=$fieldId;?>" rows="10"><?=$pconfig[$fieldId];?></textarea> <?php elseif ($field['type'] == 'passwordarea'): ?> <div id="show-<?=$fieldId;?>-btn"> <button onclick="event.preventDefault();show_value('<?= html_safe($fieldId) ?>');" class="btn btn-default"><?= html_safe(gettext('Click to edit')) ?></button> </div> <div id="show-<?=$fieldId;?>-val" style="display:none"> <textarea name="<?=$fieldId;?>" rows="10"><?=$pconfig[$fieldId];?></textarea> </div> <?php endif ?> <div class="hidden" data-for="help_for_<?=$fieldId;?>"> <?=!empty($field['help']) ? $field['help'] : "";?> </div> </td> </tr> <?php endforeach;?> <tr> <td></td> <td> <button type="submit" name="setup_<?=$providerId;?>" value="yes" class="btn btn-primary"> <?= sprintf(gettext("Setup/Test %s"), $provider['handle']->getName()) ?> </button> </td> </tr> </table> </div> <?php endforeach;?> </section> </form> </div> </div> </section> <?php include("foot.inc"); if ($do_reboot) { configd_run('system reboot', true); }