From 6c7923deafa8f4b046dbedc77181df7cbe7a42d3 Mon Sep 17 00:00:00 2001 From: Ad Schellevis <ad@opnsense.org> Date: Fri, 14 Aug 2015 10:48:42 +0200 Subject: [PATCH] (acl) add hotplug support for ACL's --- .../mvc/app/models/OPNsense/Core/ACL.php | 111 ++++++++++++++---- 1 file changed, 86 insertions(+), 25 deletions(-) diff --git a/src/opnsense/mvc/app/models/OPNsense/Core/ACL.php b/src/opnsense/mvc/app/models/OPNsense/Core/ACL.php index 60f6566be..e36f11a00 100644 --- a/src/opnsense/mvc/app/models/OPNsense/Core/ACL.php +++ b/src/opnsense/mvc/app/models/OPNsense/Core/ACL.php @@ -47,46 +47,107 @@ class ACL private $legacyGroupPrivs = array(); /** - * @var array old page mapping structure + * @var array page/endpoint mapping structure */ - private $legacyACL = array(); + private $ACLtags = array(); /** - * temporary hack to support the old pfSense priv to page mapping and metadata. + * ACL to page/endpoint mapping method. + * Processes all acl tags containing patterns and generates a key/value store acl/pattern. * @return array */ - private function loadLegacyPageMap() + private function loadPageMap() { - $legacyPageMap = array(); + $pageMap = array(); - foreach ($this->legacyACL as $aclKey => $aclItem) { - if (property_exists($aclItem, "match")) { - // check if acl item already exists and add match expressions - if (!array_key_exists($aclKey, $legacyPageMap)) { - $legacyPageMap[$aclKey] = array(); + foreach ($this->ACLtags as $aclKey => $aclItem) { + // check if acl item already exists if there's acl content for it + if (!array_key_exists($aclKey, $pageMap) && (isset($aclItem["match"]) || isset($aclItem["pattern"]))) { + $pageMap[$aclKey] = array(); + } + if (isset($aclItem["match"])) { + foreach ($aclItem['match'] as $matchexpr) { + $pageMap[$aclKey][] = trim($matchexpr); } - foreach ($aclItem->match as $matchexpr) { - $legacyPageMap[$aclKey][] = trim($matchexpr); + } + } + return $pageMap; + } + + /** + * merge legacy acl's from json file into $this->ACLtags + */ + private function mergeLegacyACL() + { + // load legacy acl from json file + $this->ACLtags = array_merge_recursive( + $this->ACLtags, + json_decode(file_get_contents(__DIR__."/ACL_Legacy_Page_Map.json"), true) + ); + } + + /** + * merge pluggable ACL xml's into $this->ACLtags + * @throws \Exception + */ + private function mergePluggableACLs() + { + // crawl all vendors and modules and add acl definitions + foreach (glob(__DIR__.'/../../*') as $vendor) { + foreach (glob($vendor.'/*') as $module) { + $acl_cfg_xml = $module.'/ACL/ACL.xml'; + if (file_exists($acl_cfg_xml)) { + // load ACL xml file and perform some basic validation + $ACLxml = simplexml_load_file($acl_cfg_xml); + if ($ACLxml === false) { + throw new \Exception('ACL xml '.$acl_cfg_xml.' not valid') ; + } + if ($ACLxml->getName() != "acl") { + throw new \Exception('ACL xml '.$acl_cfg_xml.' seems to be of wrong type') ; + } + + // when acl was correctly loaded, let's parse data into private $this->ACLtags + foreach ($ACLxml as $aclID => $ACLnode) { + // an acl should minimal have a name, without one skip processing. + if (isset($ACLnode->name)) { + $aclPayload = array(); + $aclPayload['name'] = (string)$ACLnode->name; + if (isset($ACLnode->desc)) { + $aclPayload['desc'] = (string)$ACLnode->desc; + } + if (isset($ACLnode->patterns->pattern)) { + // rename pattern to match for internal usage, old code did use match and + // to avoid duplicate conversion let's do this only on input. + $aclPayload['match'] = array(); + foreach ($ACLnode->patterns->pattern as $pattern) { + $aclPayload['match'][] = (string)$pattern; + } + } + + $this->ACLtags[$aclID] = $aclPayload; + } + + } } } } - return $legacyPageMap; } /** * init legacy ACL features */ - private function initLegacy() + private function init() { - // load legacy acl from json file - $this->legacyACL = json_decode(file_get_contents(__DIR__."/ACL_Legacy_Page_Map.json")); + // add acl payload + $this->mergeLegacyACL(); + $this->mergePluggableACLs(); + + $pageMap = $this->loadPageMap(); // create privilege mappings $this->legacyUsers = array(); $this->legacyGroupPrivs = array(); - $legacyPageMap = $this->loadLegacyPageMap(); - $groupmap = array(); // gather user / group data from config.xml @@ -99,9 +160,9 @@ class ACL $this->legacyUsers[$node->name->__toString()]['priv'] = array(); foreach ($node->priv as $priv) { if (substr($priv, 0, 5) == 'page-') { - if (array_key_exists($priv->__toString(), $legacyPageMap)) { + if (array_key_exists($priv->__toString(), $pageMap)) { $this->legacyUsers[$node->name->__toString()]['priv'][] = - $legacyPageMap[$priv->__toString()]; + $pageMap[$priv->__toString()]; } } } @@ -121,8 +182,8 @@ class ACL } } } elseif ($node->getName() == "priv" && substr($node->__toString(), 0, 5) == "page-") { - if (array_key_exists($node->__toString(), $legacyPageMap)) { - $this->legacyGroupPrivs[$groupkey][] = $legacyPageMap[$node->__toString()]; + if (array_key_exists($node->__toString(), $pageMap)) { + $this->legacyGroupPrivs[$groupkey][] = $pageMap[$node->__toString()]; } } } @@ -151,7 +212,7 @@ class ACL */ public function __construct() { - $this->initLegacy(); + $this->init(); } /** @@ -189,14 +250,14 @@ class ACL } /** - * return privilege list as array (sorted) + * return privilege list as array (sorted), only for backward compatibility * @return array */ public function getLegacyPrivList() { // convert json priv map to array $priv_list = array(); - foreach ($this->legacyACL as $aclKey => $aclItem) { + foreach ($this->ACLtags as $aclKey => $aclItem) { $priv_list[$aclKey] = array(); foreach ($aclItem as $propName => $propValue) { if ($propName == 'name' || $propName == 'descr') { -- 2.21.0