<?php /* Copyright (C) 2015-2016 Deciso B.V. Copyright (C) 2009, 2010 Scott Ullrich Copyright (C) 2005 Colin Smith 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. */ /** * request functions which may be registered by the xmlrpc system * @return array */ function xmlrpc_publishable_legacy() { $publish = array('filter_configure_xmlrpc','restore_config_section_xmlrpc','firmware_version_xmlrpc'); return $publish; } /* * does_vip_exist($vip): return true or false if a vip is * configured. */ function does_vip_exist($vip) { global $config; if(!$vip) { return false; } switch ($vip['mode']) { case "carp": case "ipalias": /* XXX: Make proper checks? */ $realif = get_real_interface($vip['interface']); if (!does_interface_exist($realif)) { return false; } break; case "proxyarp": /* XXX: Implement this */ default: return false; } $ifacedata = pfSense_getall_interface_addresses($realif); foreach ($ifacedata as $vipips) { if ($vipips == "{$vip['subnet']}/{$vip['subnet_bits']}") { return true; } } return false; } /** * merge attributes from source array to destination * updates leaves and overwrites sequenced arrays (container types). * @param array $cnf_source source data * @param array $cnf_dest target */ function merge_config_attributes(&$cnf_source, &$cnf_dest) { foreach ($cnf_source as $cnf_key => &$cnf_value) { if (is_array($cnf_value)) { if (!isset($cnf_dest[$cnf_key]) || !is_array($cnf_dest[$cnf_key]) || // new (count($cnf_dest[$cnf_key]) > 0 && isset($cnf_dest[$cnf_key][0])) || // sequenced item (count($cnf_dest[$cnf_key]) > 0 && isset($cnf_dest[$cnf_key]['@attributes']['uuid'])) // mvc array ) { // (re)set destination array when new or containing a sequenced list of items $cnf_dest[$cnf_key] = array(); } merge_config_attributes($cnf_value, $cnf_dest[$cnf_key]); } else { $cnf_dest[$cnf_key] = $cnf_value; } } } /** * retrieve firmware version * @return mixed */ function firmware_version_xmlrpc() { require_once("pfsense-utils.inc"); return host_firmware_version(); } /** * filter reconfigure * @return mixed */ function filter_configure_xmlrpc() { global $config; require_once("filter.inc"); require_once("system.inc"); require_once("interfaces.inc"); require_once("vslb.inc"); require_once("openvpn.inc"); require_once("services.inc"); require_once("rrd.inc"); require_once('pfsense-utils.inc'); filter_configure(); system_routing_configure(); setup_gateways_monitor(); relayd_configure(); openvpn_resync_all(); if (isset($config['dnsmasq']['enable'])) { services_dnsmasq_configure(); } elseif (isset($config['unbound']['enable'])) { services_unbound_configure(); } else { # Both calls above run services_dhcpd_configure(), then we just # need to call it when them are not called to avoid restart dhcpd # twice, as described on ticket #3797 services_dhcpd_configure(); } system_hosts_generate(); local_sync_accounts(); return true; } /** * restore config section * @param $new_config * @return bool */ function restore_config_section_xmlrpc($new_config) { global $config; require_once("interfaces.inc"); require_once("filter.inc"); require_once("ipsec.inc"); // save old config $old_config = $config; // Some sections should just be copied and not merged, namely if there's a risk of attributes being removed // without being seen by the remote remote (backup) side. // (ipsec, openvpn, nat can probably moved out later by specifying a better path to the attribute) $sync_full = array('ipsec', 'wol', 'dnsmasq', 'load_balancer', 'openvpn', 'nat', 'dhcpd', 'dhcpv6'); $sync_full_done = array(); foreach ($sync_full as $syncfull) { if (isset($new_config[$syncfull])) { $config[$syncfull] = $new_config[$syncfull]; unset($new_config[$syncfull]); $sync_full_done[] = $syncfull; } } $vipbackup = array(); $oldvips = array(); if (isset($new_config['virtualip']['vip']) && isset($config['virtualip']['vip'])) { foreach ($config['virtualip']['vip'] as $vipindex => $vip) { if ($vip['mode'] == "carp") { // rc.filter_synchronize only sends carp vips, keep the rest like it was $oldvips["{$vip['interface']}_vip{$vip['vhid']}"] = $vip ; } else { $vipbackup[] = $vip; } } } // merge config attributes. merge_config_attributes($new_config, $config); if (count($vipbackup) > 0) { // if $new_config contained VIPS and the old config contained non carp vips, prepend original vips foreach ($vipbackup as $vip) { array_unshift($config['virtualip']['vip'], $vip); } } /* Log what happened */ $mergedkeys = implode(",", array_merge(array_keys($new_config), $sync_full_done)); write_config(sprintf(gettext("Merged in config (%s sections) from XMLRPC client."), $mergedkeys)); /* * Handle virtual ips */ if (isset($new_config['virtualip']['vip'])) { $carp_setuped = false; $anyproxyarp = false; if (isset($config['virtualip']['vip'])) { foreach ($config['virtualip']['vip'] as $vip) { if ($vip['mode'] == "carp" && isset($oldvips["{$vip['interface']}_vip{$vip['vhid']}"])) { $is_changed = false; foreach (array('password', 'advskew', 'subnet', 'subnet_bits', 'advbase') as $chk_key) { if ($oldvips["{$vip['interface']}_vip{$vip['vhid']}"][$chk_key] != $vip[$chk_key]) { $is_changed = true; break; } } if (!$is_changed) { unset($oldvips["{$vip['interface']}_vip{$vip['vhid']}"]); if (does_vip_exist($vip)) { continue; // Skip reconfiguring this vips since nothing has changed. } } } switch ($vip['mode']) { case "proxyarp": $anyproxyarp = true; break; case "ipalias": interface_ipalias_configure($vip); break; case "carp": $carp_setuped = true; interface_carp_configure($vip); break; } } } // remove old (carp) virtual ip's foreach ($oldvips as $oldvip) { interface_vip_bring_down($oldvip); } if ($carp_setuped) { interfaces_carp_setup(); } if ($anyproxyarp) { interface_proxyarp_configure(); } } if (isset($old_config['ipsec']['enable']) !== isset($config['ipsec']['enable'])) { ipsec_configure(); } unset($old_config); return true; }