18b7c156eSVernon Mauery #include <ipmi-allowlist.hpp>
28b7c156eSVernon Mauery #include <ipmid/api.hpp>
38b7c156eSVernon Mauery #include <ipmid/utils.hpp>
48b7c156eSVernon Mauery #include <phosphor-logging/elog-errors.hpp>
58b7c156eSVernon Mauery #include <phosphor-logging/log.hpp>
68b7c156eSVernon Mauery #include <xyz/openbmc_project/Control/Security/RestrictionMode/server.hpp>
78b7c156eSVernon Mauery 
88b7c156eSVernon Mauery #include <algorithm>
98b7c156eSVernon Mauery #include <array>
108b7c156eSVernon Mauery 
118b7c156eSVernon Mauery using namespace phosphor::logging;
128b7c156eSVernon Mauery using namespace sdbusplus::xyz::openbmc_project::Common::Error;
138b7c156eSVernon Mauery using namespace sdbusplus::xyz::openbmc_project::Control::Security::server;
148b7c156eSVernon Mauery 
158b7c156eSVernon Mauery namespace ipmi
168b7c156eSVernon Mauery {
178b7c156eSVernon Mauery 
188b7c156eSVernon Mauery // put the filter provider in an unnamed namespace
198b7c156eSVernon Mauery namespace
208b7c156eSVernon Mauery {
218b7c156eSVernon Mauery 
228b7c156eSVernon Mauery /** @class AllowlistFilter
238b7c156eSVernon Mauery  *
248b7c156eSVernon Mauery  * Class that implements an IPMI message filter based
258b7c156eSVernon Mauery  * on incoming interface and a restriction mode setting
268b7c156eSVernon Mauery  */
278b7c156eSVernon Mauery class AllowlistFilter
288b7c156eSVernon Mauery {
298b7c156eSVernon Mauery 
308b7c156eSVernon Mauery   public:
318b7c156eSVernon Mauery     AllowlistFilter();
328b7c156eSVernon Mauery     ~AllowlistFilter() = default;
338b7c156eSVernon Mauery     AllowlistFilter(AllowlistFilter const&) = delete;
348b7c156eSVernon Mauery     AllowlistFilter(AllowlistFilter&&) = delete;
358b7c156eSVernon Mauery     AllowlistFilter& operator=(AllowlistFilter const&) = delete;
368b7c156eSVernon Mauery     AllowlistFilter& operator=(AllowlistFilter&&) = delete;
378b7c156eSVernon Mauery 
388b7c156eSVernon Mauery   private:
398b7c156eSVernon Mauery     void postInit();
408b7c156eSVernon Mauery     void cacheRestrictedAndPostCompleteMode();
418b7c156eSVernon Mauery     void handleRestrictedModeChange(sdbusplus::message_t& m);
428b7c156eSVernon Mauery     void handlePostCompleteChange(sdbusplus::message_t& m);
438b7c156eSVernon Mauery     void updatePostComplete(const std::string& value);
448b7c156eSVernon Mauery     void updateRestrictionMode(const std::string& value);
458b7c156eSVernon Mauery     ipmi::Cc filterMessage(ipmi::message::Request::ptr request);
468b7c156eSVernon Mauery     void handleCoreBiosDoneChange(sdbusplus::message_t& m);
478b7c156eSVernon Mauery     void cacheCoreBiosDone();
488b7c156eSVernon Mauery 
498b7c156eSVernon Mauery     // the BMC KCS Policy Control Modes document uses different names
508b7c156eSVernon Mauery     // than the RestrictionModes D-Bus interface; use aliases
518b7c156eSVernon Mauery     static constexpr RestrictionMode::Modes restrictionModeAllowAll =
528b7c156eSVernon Mauery         RestrictionMode::Modes::Provisioning;
538b7c156eSVernon Mauery     static constexpr RestrictionMode::Modes restrictionModeRestricted =
548b7c156eSVernon Mauery         RestrictionMode::Modes::ProvisionedHostWhitelist;
558b7c156eSVernon Mauery     static constexpr RestrictionMode::Modes restrictionModeDenyAll =
568b7c156eSVernon Mauery         RestrictionMode::Modes::ProvisionedHostDisabled;
578b7c156eSVernon Mauery 
588b7c156eSVernon Mauery     RestrictionMode::Modes restrictionMode = restrictionModeRestricted;
598b7c156eSVernon Mauery     bool postCompleted = true;
608b7c156eSVernon Mauery     bool coreBIOSDone = true;
618b7c156eSVernon Mauery     int channelSMM = -1;
628b7c156eSVernon Mauery     std::shared_ptr<sdbusplus::asio::connection> bus;
638b7c156eSVernon Mauery     std::unique_ptr<sdbusplus::bus::match_t> modeChangeMatch;
648b7c156eSVernon Mauery     std::unique_ptr<sdbusplus::bus::match_t> modeIntfAddedMatch;
658b7c156eSVernon Mauery     std::unique_ptr<sdbusplus::bus::match_t> postCompleteMatch;
668b7c156eSVernon Mauery     std::unique_ptr<sdbusplus::bus::match_t> postCompleteIntfAddedMatch;
678b7c156eSVernon Mauery     std::unique_ptr<sdbusplus::bus::match_t> platStateChangeMatch;
688b7c156eSVernon Mauery     std::unique_ptr<sdbusplus::bus::match_t> platStateIntfAddedMatch;
698b7c156eSVernon Mauery 
708b7c156eSVernon Mauery     static constexpr const char restrictionModeIntf[] =
718b7c156eSVernon Mauery         "xyz.openbmc_project.Control.Security.RestrictionMode";
728b7c156eSVernon Mauery     static constexpr const char* systemOsStatusIntf =
738b7c156eSVernon Mauery         "xyz.openbmc_project.State.OperatingSystem.Status";
748b7c156eSVernon Mauery     static constexpr const char* hostMiscIntf =
758b7c156eSVernon Mauery         "xyz.openbmc_project.State.Host.Misc";
768b7c156eSVernon Mauery     static constexpr const char* restrictionModePath =
778b7c156eSVernon Mauery         "/xyz/openbmc_project/control/security/restriction_mode";
788b7c156eSVernon Mauery     static constexpr const char* systemOsStatusPath =
798b7c156eSVernon Mauery         "/xyz/openbmc_project/state/os";
808b7c156eSVernon Mauery };
818b7c156eSVernon Mauery 
828b7c156eSVernon Mauery static inline uint8_t getSMMChannel()
838b7c156eSVernon Mauery {
848b7c156eSVernon Mauery     ipmi::ChannelInfo chInfo;
858b7c156eSVernon Mauery 
868b7c156eSVernon Mauery     for (int channel = 0; channel < ipmi::maxIpmiChannels; channel++)
878b7c156eSVernon Mauery     {
888b7c156eSVernon Mauery         if (ipmi::getChannelInfo(channel, chInfo) != ipmi::ccSuccess)
898b7c156eSVernon Mauery         {
908b7c156eSVernon Mauery             continue;
918b7c156eSVernon Mauery         }
928b7c156eSVernon Mauery 
938b7c156eSVernon Mauery         if (static_cast<ipmi::EChannelMediumType>(chInfo.mediumType) ==
948b7c156eSVernon Mauery                 ipmi::EChannelMediumType::systemInterface &&
958b7c156eSVernon Mauery             channel != ipmi::channelSystemIface)
968b7c156eSVernon Mauery         {
978b7c156eSVernon Mauery             log<level::INFO>("SMM channel number",
988b7c156eSVernon Mauery                              entry("CHANNEL=%d", channel));
998b7c156eSVernon Mauery             return channel;
1008b7c156eSVernon Mauery         }
1018b7c156eSVernon Mauery     }
1028b7c156eSVernon Mauery     log<level::ERR>("Unable to find SMM Channel Info");
1038b7c156eSVernon Mauery     return -1;
1048b7c156eSVernon Mauery }
1058b7c156eSVernon Mauery 
1068b7c156eSVernon Mauery AllowlistFilter::AllowlistFilter()
1078b7c156eSVernon Mauery {
1088b7c156eSVernon Mauery     bus = getSdBus();
1098b7c156eSVernon Mauery 
1108b7c156eSVernon Mauery     log<level::INFO>("Loading Allowlist filter");
1118b7c156eSVernon Mauery 
1128b7c156eSVernon Mauery     ipmi::registerFilter(ipmi::prioOpenBmcBase,
1138b7c156eSVernon Mauery                          [this](ipmi::message::Request::ptr request) {
1148b7c156eSVernon Mauery                              return filterMessage(request);
1158b7c156eSVernon Mauery                          });
1168b7c156eSVernon Mauery 
1178b7c156eSVernon Mauery     channelSMM = getSMMChannel();
1188b7c156eSVernon Mauery     // wait until io->run is going to fetch RestrictionMode
1198b7c156eSVernon Mauery     post_work([this]() { postInit(); });
1208b7c156eSVernon Mauery }
1218b7c156eSVernon Mauery 
1228b7c156eSVernon Mauery void AllowlistFilter::cacheRestrictedAndPostCompleteMode()
1238b7c156eSVernon Mauery {
1248b7c156eSVernon Mauery     try
1258b7c156eSVernon Mauery     {
1268b7c156eSVernon Mauery         auto service =
1278b7c156eSVernon Mauery             ipmi::getService(*bus, restrictionModeIntf, restrictionModePath);
1288b7c156eSVernon Mauery         ipmi::Value v =
1298b7c156eSVernon Mauery             ipmi::getDbusProperty(*bus, service, restrictionModePath,
1308b7c156eSVernon Mauery                                   restrictionModeIntf, "RestrictionMode");
1318b7c156eSVernon Mauery         auto& mode = std::get<std::string>(v);
1328b7c156eSVernon Mauery         restrictionMode = RestrictionMode::convertModesFromString(mode);
1338b7c156eSVernon Mauery         log<level::INFO>("Read restriction mode",
1348b7c156eSVernon Mauery                          entry("VALUE=%d", static_cast<int>(restrictionMode)));
1358b7c156eSVernon Mauery     }
1368b7c156eSVernon Mauery     catch (const std::exception&)
1378b7c156eSVernon Mauery     {
1388b7c156eSVernon Mauery         log<level::ERR>("Could not initialize provisioning mode, "
1398b7c156eSVernon Mauery                         "defaulting to restricted",
1408b7c156eSVernon Mauery                         entry("VALUE=%d", static_cast<int>(restrictionMode)));
1418b7c156eSVernon Mauery     }
1428b7c156eSVernon Mauery 
1438b7c156eSVernon Mauery     try
1448b7c156eSVernon Mauery     {
1458b7c156eSVernon Mauery         auto service =
1468b7c156eSVernon Mauery             ipmi::getService(*bus, systemOsStatusIntf, systemOsStatusPath);
1478b7c156eSVernon Mauery         ipmi::Value v =
1488b7c156eSVernon Mauery             ipmi::getDbusProperty(*bus, service, systemOsStatusPath,
1498b7c156eSVernon Mauery                                   systemOsStatusIntf, "OperatingSystemState");
1508b7c156eSVernon Mauery         auto& value = std::get<std::string>(v);
1518b7c156eSVernon Mauery         updatePostComplete(value);
1528b7c156eSVernon Mauery         log<level::INFO>("Read POST complete value",
1538b7c156eSVernon Mauery                          entry("VALUE=%d", postCompleted));
1548b7c156eSVernon Mauery     }
1558b7c156eSVernon Mauery     catch (const std::exception&)
1568b7c156eSVernon Mauery     {
1578b7c156eSVernon Mauery         log<level::ERR>("Error in OperatingSystemState Get");
1588b7c156eSVernon Mauery         postCompleted = true;
1598b7c156eSVernon Mauery     }
1608b7c156eSVernon Mauery }
1618b7c156eSVernon Mauery 
1628b7c156eSVernon Mauery void AllowlistFilter::updateRestrictionMode(const std::string& value)
1638b7c156eSVernon Mauery {
1648b7c156eSVernon Mauery     restrictionMode = RestrictionMode::convertModesFromString(value);
1658b7c156eSVernon Mauery     log<level::INFO>("Updated restriction mode",
1668b7c156eSVernon Mauery                      entry("VALUE=%d", static_cast<int>(restrictionMode)));
1678b7c156eSVernon Mauery }
1688b7c156eSVernon Mauery 
1698b7c156eSVernon Mauery void AllowlistFilter::handleRestrictedModeChange(sdbusplus::message_t& m)
1708b7c156eSVernon Mauery {
1718b7c156eSVernon Mauery     std::string signal = m.get_member();
1728b7c156eSVernon Mauery     if (signal == "PropertiesChanged")
1738b7c156eSVernon Mauery     {
1748b7c156eSVernon Mauery         std::string intf;
1758b7c156eSVernon Mauery         std::vector<std::pair<std::string, ipmi::Value>> propertyList;
1768b7c156eSVernon Mauery         m.read(intf, propertyList);
1778b7c156eSVernon Mauery         for (const auto& property : propertyList)
1788b7c156eSVernon Mauery         {
1798b7c156eSVernon Mauery             if (property.first == "RestrictionMode")
1808b7c156eSVernon Mauery             {
1818b7c156eSVernon Mauery                 updateRestrictionMode(std::get<std::string>(property.second));
1828b7c156eSVernon Mauery             }
1838b7c156eSVernon Mauery         }
1848b7c156eSVernon Mauery     }
1858b7c156eSVernon Mauery     else if (signal == "InterfacesAdded")
1868b7c156eSVernon Mauery     {
1878b7c156eSVernon Mauery         sdbusplus::message::object_path path;
1888b7c156eSVernon Mauery         DbusInterfaceMap restModeObj;
1898b7c156eSVernon Mauery         m.read(path, restModeObj);
1908b7c156eSVernon Mauery         auto intfItr = restModeObj.find(restrictionModeIntf);
1918b7c156eSVernon Mauery         if (intfItr == restModeObj.end())
1928b7c156eSVernon Mauery         {
1938b7c156eSVernon Mauery             return;
1948b7c156eSVernon Mauery         }
1958b7c156eSVernon Mauery         PropertyMap& propertyList = intfItr->second;
1968b7c156eSVernon Mauery         auto itr = propertyList.find("RestrictionMode");
1978b7c156eSVernon Mauery         if (itr == propertyList.end())
1988b7c156eSVernon Mauery         {
1998b7c156eSVernon Mauery             return;
2008b7c156eSVernon Mauery         }
2018b7c156eSVernon Mauery         updateRestrictionMode(std::get<std::string>(itr->second));
2028b7c156eSVernon Mauery     }
2038b7c156eSVernon Mauery }
2048b7c156eSVernon Mauery 
2058b7c156eSVernon Mauery void AllowlistFilter::updatePostComplete(const std::string& value)
2068b7c156eSVernon Mauery {
2078b7c156eSVernon Mauery     // The short string "Standby" is deprecated in favor of the full enum string
2088b7c156eSVernon Mauery     // Support for the short string will be removed in the future.
2098b7c156eSVernon Mauery     postCompleted = (value == "Standby") ||
2108b7c156eSVernon Mauery                     (value == "xyz.openbmc_project.State.OperatingSystem."
2118b7c156eSVernon Mauery                               "Status.OSStatus.Standby");
2128b7c156eSVernon Mauery     log<level::INFO>(postCompleted ? "Updated to POST Complete"
2138b7c156eSVernon Mauery                                    : "Updated to !POST Complete");
2148b7c156eSVernon Mauery }
2158b7c156eSVernon Mauery 
2168b7c156eSVernon Mauery void AllowlistFilter::handlePostCompleteChange(sdbusplus::message_t& m)
2178b7c156eSVernon Mauery {
2188b7c156eSVernon Mauery     std::string signal = m.get_member();
2198b7c156eSVernon Mauery     if (signal == "PropertiesChanged")
2208b7c156eSVernon Mauery     {
2218b7c156eSVernon Mauery         std::string intf;
2228b7c156eSVernon Mauery         std::vector<std::pair<std::string, ipmi::Value>> propertyList;
2238b7c156eSVernon Mauery         m.read(intf, propertyList);
2248b7c156eSVernon Mauery         for (const auto& property : propertyList)
2258b7c156eSVernon Mauery         {
2268b7c156eSVernon Mauery             if (property.first == "OperatingSystemState")
2278b7c156eSVernon Mauery             {
2288b7c156eSVernon Mauery                 updatePostComplete(std::get<std::string>(property.second));
2298b7c156eSVernon Mauery             }
2308b7c156eSVernon Mauery         }
2318b7c156eSVernon Mauery     }
2328b7c156eSVernon Mauery     else if (signal == "InterfacesAdded")
2338b7c156eSVernon Mauery     {
2348b7c156eSVernon Mauery         sdbusplus::message::object_path path;
2358b7c156eSVernon Mauery         DbusInterfaceMap postCompleteObj;
2368b7c156eSVernon Mauery         m.read(path, postCompleteObj);
2378b7c156eSVernon Mauery         auto intfItr = postCompleteObj.find(systemOsStatusIntf);
2388b7c156eSVernon Mauery         if (intfItr == postCompleteObj.end())
2398b7c156eSVernon Mauery         {
2408b7c156eSVernon Mauery             return;
2418b7c156eSVernon Mauery         }
2428b7c156eSVernon Mauery         PropertyMap& propertyList = intfItr->second;
2438b7c156eSVernon Mauery         auto itr = propertyList.find("OperatingSystemState");
2448b7c156eSVernon Mauery         if (itr == propertyList.end())
2458b7c156eSVernon Mauery         {
2468b7c156eSVernon Mauery             return;
2478b7c156eSVernon Mauery         }
2488b7c156eSVernon Mauery         updatePostComplete(std::get<std::string>(itr->second));
2498b7c156eSVernon Mauery     }
2508b7c156eSVernon Mauery }
2518b7c156eSVernon Mauery 
2528b7c156eSVernon Mauery void AllowlistFilter::cacheCoreBiosDone()
2538b7c156eSVernon Mauery {
2548b7c156eSVernon Mauery     std::string coreBiosDonePath;
2558b7c156eSVernon Mauery     std::string coreBiosDoneService;
2568b7c156eSVernon Mauery     try
2578b7c156eSVernon Mauery     {
2588b7c156eSVernon Mauery         ipmi::DbusObjectInfo coreBiosDoneObj =
2598b7c156eSVernon Mauery             ipmi::getDbusObject(*bus, hostMiscIntf);
2608b7c156eSVernon Mauery 
2618b7c156eSVernon Mauery         coreBiosDonePath = coreBiosDoneObj.first;
2628b7c156eSVernon Mauery         coreBiosDoneService = coreBiosDoneObj.second;
2638b7c156eSVernon Mauery     }
2648b7c156eSVernon Mauery     catch (const std::exception&)
2658b7c156eSVernon Mauery     {
2668b7c156eSVernon Mauery         log<level::ERR>("Could not initialize CoreBiosDone, "
2678b7c156eSVernon Mauery                         "coreBIOSDone asserted as default");
2688b7c156eSVernon Mauery         return;
2698b7c156eSVernon Mauery     }
2708b7c156eSVernon Mauery 
2718b7c156eSVernon Mauery     bus->async_method_call(
2728b7c156eSVernon Mauery         [this](boost::system::error_code ec, const ipmi::Value& v) {
2738b7c156eSVernon Mauery             if (ec)
2748b7c156eSVernon Mauery             {
2758b7c156eSVernon Mauery                 log<level::ERR>(
2768b7c156eSVernon Mauery                     "async call failed, coreBIOSDone asserted as default");
2778b7c156eSVernon Mauery                 return;
2788b7c156eSVernon Mauery             }
2798b7c156eSVernon Mauery             coreBIOSDone = std::get<bool>(v);
2808b7c156eSVernon Mauery             log<level::INFO>("Read CoreBiosDone",
2818b7c156eSVernon Mauery                              entry("VALUE=%d", static_cast<int>(coreBIOSDone)));
2828b7c156eSVernon Mauery         },
2838b7c156eSVernon Mauery         coreBiosDoneService, coreBiosDonePath,
2848b7c156eSVernon Mauery         "org.freedesktop.DBus.Properties", "Get", hostMiscIntf, "CoreBiosDone");
2858b7c156eSVernon Mauery }
2868b7c156eSVernon Mauery 
2878b7c156eSVernon Mauery void AllowlistFilter::handleCoreBiosDoneChange(sdbusplus::message_t& msg)
2888b7c156eSVernon Mauery {
2898b7c156eSVernon Mauery     std::string signal = msg.get_member();
2908b7c156eSVernon Mauery     if (signal == "PropertiesChanged")
2918b7c156eSVernon Mauery     {
2928b7c156eSVernon Mauery         std::string intf;
2938b7c156eSVernon Mauery         std::vector<std::pair<std::string, ipmi::Value>> propertyList;
2948b7c156eSVernon Mauery         msg.read(intf, propertyList);
2958b7c156eSVernon Mauery         auto it =
2968b7c156eSVernon Mauery             std::find_if(propertyList.begin(), propertyList.end(),
2978b7c156eSVernon Mauery                          [](const std::pair<std::string, ipmi::Value>& prop) {
2988b7c156eSVernon Mauery                              return prop.first == "CoreBiosDone";
2998b7c156eSVernon Mauery                          });
3008b7c156eSVernon Mauery 
3018b7c156eSVernon Mauery         if (it != propertyList.end())
3028b7c156eSVernon Mauery         {
3038b7c156eSVernon Mauery             coreBIOSDone = std::get<bool>(it->second);
3048b7c156eSVernon Mauery             log<level::INFO>(coreBIOSDone ? "coreBIOSDone asserted"
3058b7c156eSVernon Mauery                                           : "coreBIOSDone not asserted");
3068b7c156eSVernon Mauery         }
3078b7c156eSVernon Mauery     }
3088b7c156eSVernon Mauery     else if (signal == "InterfacesAdded")
3098b7c156eSVernon Mauery     {
3108b7c156eSVernon Mauery         sdbusplus::message::object_path path;
3118b7c156eSVernon Mauery         DbusInterfaceMap eSpiresetObj;
3128b7c156eSVernon Mauery         msg.read(path, eSpiresetObj);
3138b7c156eSVernon Mauery         auto intfItr = eSpiresetObj.find(hostMiscIntf);
3148b7c156eSVernon Mauery         if (intfItr == eSpiresetObj.end())
3158b7c156eSVernon Mauery         {
3168b7c156eSVernon Mauery             return;
3178b7c156eSVernon Mauery         }
3188b7c156eSVernon Mauery         PropertyMap& propertyList = intfItr->second;
3198b7c156eSVernon Mauery         auto itr = propertyList.find("CoreBiosDone");
3208b7c156eSVernon Mauery         if (itr == propertyList.end())
3218b7c156eSVernon Mauery         {
3228b7c156eSVernon Mauery             return;
3238b7c156eSVernon Mauery         }
3248b7c156eSVernon Mauery         coreBIOSDone = std::get<bool>(itr->second);
3258b7c156eSVernon Mauery         log<level::INFO>(coreBIOSDone ? "coreBIOSDone asserted"
3268b7c156eSVernon Mauery                                       : "coreBIOSDone not asserted");
3278b7c156eSVernon Mauery     }
3288b7c156eSVernon Mauery }
3298b7c156eSVernon Mauery 
3308b7c156eSVernon Mauery void AllowlistFilter::postInit()
3318b7c156eSVernon Mauery {
3328b7c156eSVernon Mauery     // Wait for changes on Restricted mode
3338b7c156eSVernon Mauery     namespace rules = sdbusplus::bus::match::rules;
3348b7c156eSVernon Mauery     const std::string filterStrModeChange =
3358b7c156eSVernon Mauery         rules::type::signal() + rules::member("PropertiesChanged") +
3368b7c156eSVernon Mauery         rules::interface("org.freedesktop.DBus.Properties") +
3378b7c156eSVernon Mauery         rules::argN(0, restrictionModeIntf);
3388b7c156eSVernon Mauery 
3398b7c156eSVernon Mauery     const std::string filterStrModeIntfAdd =
3408b7c156eSVernon Mauery         rules::interfacesAdded() +
3418b7c156eSVernon Mauery         rules::argNpath(
3428b7c156eSVernon Mauery             0, "/xyz/openbmc_project/control/security/restriction_mode");
3438b7c156eSVernon Mauery 
3448b7c156eSVernon Mauery     const std::string filterStrPostComplete =
3458b7c156eSVernon Mauery         rules::type::signal() + rules::member("PropertiesChanged") +
3468b7c156eSVernon Mauery         rules::interface("org.freedesktop.DBus.Properties") +
3478b7c156eSVernon Mauery         rules::argN(0, systemOsStatusIntf);
3488b7c156eSVernon Mauery 
3498b7c156eSVernon Mauery     const std::string filterStrPostIntfAdd =
3508b7c156eSVernon Mauery         rules::interfacesAdded() +
3518b7c156eSVernon Mauery         rules::argNpath(0, "/xyz/openbmc_project/state/os");
3528b7c156eSVernon Mauery 
3538b7c156eSVernon Mauery     const std::string filterStrPlatStateChange =
3548b7c156eSVernon Mauery         rules::type::signal() + rules::member("PropertiesChanged") +
3558b7c156eSVernon Mauery         rules::interface("org.freedesktop.DBus.Properties") +
3568b7c156eSVernon Mauery         rules::argN(0, hostMiscIntf);
3578b7c156eSVernon Mauery 
3588b7c156eSVernon Mauery     const std::string filterStrPlatStateIntfAdd =
3598b7c156eSVernon Mauery         rules::interfacesAdded() +
3608b7c156eSVernon Mauery         rules::argNpath(0, "/xyz/openbmc_project/misc/platform_state");
3618b7c156eSVernon Mauery 
3628b7c156eSVernon Mauery     modeChangeMatch = std::make_unique<sdbusplus::bus::match_t>(
3638b7c156eSVernon Mauery         *bus, filterStrModeChange,
3648b7c156eSVernon Mauery         [this](sdbusplus::message_t& m) { handleRestrictedModeChange(m); });
3658b7c156eSVernon Mauery     modeIntfAddedMatch = std::make_unique<sdbusplus::bus::match_t>(
3668b7c156eSVernon Mauery         *bus, filterStrModeIntfAdd,
3678b7c156eSVernon Mauery         [this](sdbusplus::message_t& m) { handleRestrictedModeChange(m); });
3688b7c156eSVernon Mauery 
3698b7c156eSVernon Mauery     postCompleteMatch = std::make_unique<sdbusplus::bus::match_t>(
3708b7c156eSVernon Mauery         *bus, filterStrPostComplete,
3718b7c156eSVernon Mauery         [this](sdbusplus::message_t& m) { handlePostCompleteChange(m); });
3728b7c156eSVernon Mauery 
3738b7c156eSVernon Mauery     postCompleteIntfAddedMatch = std::make_unique<sdbusplus::bus::match_t>(
3748b7c156eSVernon Mauery         *bus, filterStrPostIntfAdd,
3758b7c156eSVernon Mauery         [this](sdbusplus::message_t& m) { handlePostCompleteChange(m); });
3768b7c156eSVernon Mauery 
3778b7c156eSVernon Mauery     platStateChangeMatch = std::make_unique<sdbusplus::bus::match_t>(
3788b7c156eSVernon Mauery         *bus, filterStrPlatStateChange,
3798b7c156eSVernon Mauery         [this](sdbusplus::message_t& m) { handleCoreBiosDoneChange(m); });
3808b7c156eSVernon Mauery 
3818b7c156eSVernon Mauery     platStateIntfAddedMatch = std::make_unique<sdbusplus::bus::match_t>(
3828b7c156eSVernon Mauery         *bus, filterStrPlatStateIntfAdd,
3838b7c156eSVernon Mauery         [this](sdbusplus::message_t& m) { handleCoreBiosDoneChange(m); });
3848b7c156eSVernon Mauery 
3858b7c156eSVernon Mauery     // Initialize restricted mode
3868b7c156eSVernon Mauery     cacheRestrictedAndPostCompleteMode();
3878b7c156eSVernon Mauery     // Initialize CoreBiosDone
3888b7c156eSVernon Mauery     cacheCoreBiosDone();
3898b7c156eSVernon Mauery }
3908b7c156eSVernon Mauery 
3918b7c156eSVernon Mauery ipmi::Cc AllowlistFilter::filterMessage(ipmi::message::Request::ptr request)
3928b7c156eSVernon Mauery {
3938b7c156eSVernon Mauery     auto channelMask = static_cast<unsigned short>(1 << request->ctx->channel);
3948b7c156eSVernon Mauery     bool Allowlisted = std::binary_search(
3958b7c156eSVernon Mauery         allowlist.cbegin(), allowlist.cend(),
3968b7c156eSVernon Mauery         std::make_tuple(request->ctx->netFn, request->ctx->cmd, channelMask),
3978b7c156eSVernon Mauery         [](const netfncmd_tuple& first, const netfncmd_tuple& value) {
3988b7c156eSVernon Mauery             return (std::get<2>(first) & std::get<2>(value))
3998b7c156eSVernon Mauery                        ? first < std::make_tuple(std::get<0>(value),
4008b7c156eSVernon Mauery                                                  std::get<1>(value),
4018b7c156eSVernon Mauery                                                  std::get<2>(first))
4028b7c156eSVernon Mauery                        : first < value;
4038b7c156eSVernon Mauery         });
4048b7c156eSVernon Mauery 
4058b7c156eSVernon Mauery     // no special handling for non-system-interface channels
4068b7c156eSVernon Mauery     if (!(request->ctx->channel == ipmi::channelSystemIface ||
4078b7c156eSVernon Mauery           request->ctx->channel == channelSMM))
4088b7c156eSVernon Mauery     {
4098b7c156eSVernon Mauery         if (!Allowlisted)
4108b7c156eSVernon Mauery         {
4118b7c156eSVernon Mauery             log<level::INFO>("Channel/NetFn/Cmd not Allowlisted",
4128b7c156eSVernon Mauery                              entry("CHANNEL=0x%X", request->ctx->channel),
4138b7c156eSVernon Mauery                              entry("NETFN=0x%X", int(request->ctx->netFn)),
4148b7c156eSVernon Mauery                              entry("CMD=0x%X", int(request->ctx->cmd)));
4158b7c156eSVernon Mauery             return ipmi::ccInsufficientPrivilege;
4168b7c156eSVernon Mauery         }
4178b7c156eSVernon Mauery         return ipmi::ccSuccess;
4188b7c156eSVernon Mauery     }
4198b7c156eSVernon Mauery 
4208b7c156eSVernon Mauery     // for system interface, filtering is done as follows:
4218b7c156eSVernon Mauery     // Allow All:  preboot ? ccSuccess : ccSuccess
4228b7c156eSVernon Mauery     // Restricted: preboot ? ccSuccess :
4238b7c156eSVernon Mauery     //                  ( Allowlist ? ccSuccess : ccInsufficientPrivilege )
4248b7c156eSVernon Mauery     // Deny All:   preboot ? ccSuccess : ccInsufficientPrivilege
4258b7c156eSVernon Mauery 
4268b7c156eSVernon Mauery     if (!(postCompleted || coreBIOSDone))
4278b7c156eSVernon Mauery     {
4288b7c156eSVernon Mauery         // Allow all commands, till POST or CoreBiosDone is completed
4298b7c156eSVernon Mauery         return ipmi::ccSuccess;
4308b7c156eSVernon Mauery     }
4318b7c156eSVernon Mauery 
4328b7c156eSVernon Mauery     switch (restrictionMode)
4338b7c156eSVernon Mauery     {
4348b7c156eSVernon Mauery         case RestrictionMode::Modes::None:
4358b7c156eSVernon Mauery         case restrictionModeAllowAll:
4368b7c156eSVernon Mauery         {
4378b7c156eSVernon Mauery             // Allow All
4388b7c156eSVernon Mauery             return ipmi::ccSuccess;
4398b7c156eSVernon Mauery             break;
4408b7c156eSVernon Mauery         }
4418b7c156eSVernon Mauery         case restrictionModeRestricted:
4428b7c156eSVernon Mauery         {
4438b7c156eSVernon Mauery             // Restricted - follow Allowlist
4448b7c156eSVernon Mauery             break;
4458b7c156eSVernon Mauery         }
4468b7c156eSVernon Mauery         case restrictionModeDenyAll:
4478b7c156eSVernon Mauery         {
4488b7c156eSVernon Mauery             // Deny All
4498b7c156eSVernon Mauery             Allowlisted = false;
4508b7c156eSVernon Mauery             break;
4518b7c156eSVernon Mauery         }
452*80d4d5f9SMatt Simmering         default: // for Allowlist and Blocklist
4538b7c156eSVernon Mauery             return ipmi::ccInsufficientPrivilege;
4548b7c156eSVernon Mauery     }
4558b7c156eSVernon Mauery 
4568b7c156eSVernon Mauery     if (!Allowlisted)
4578b7c156eSVernon Mauery     {
4588b7c156eSVernon Mauery         log<level::INFO>("Channel/NetFn/Cmd not allowlisted",
4598b7c156eSVernon Mauery                          entry("CHANNEL=0x%X", request->ctx->channel),
4608b7c156eSVernon Mauery                          entry("NETFN=0x%X", int(request->ctx->netFn)),
4618b7c156eSVernon Mauery                          entry("CMD=0x%X", int(request->ctx->cmd)));
4628b7c156eSVernon Mauery         return ipmi::ccInsufficientPrivilege;
4638b7c156eSVernon Mauery     }
4648b7c156eSVernon Mauery     return ipmi::ccSuccess;
4658b7c156eSVernon Mauery } // namespace
4668b7c156eSVernon Mauery 
4678b7c156eSVernon Mauery // instantiate the AllowlistFilter when this shared object is loaded
4688b7c156eSVernon Mauery AllowlistFilter allowlistFilter;
4698b7c156eSVernon Mauery 
4708b7c156eSVernon Mauery } // namespace
4718b7c156eSVernon Mauery 
4728b7c156eSVernon Mauery } // namespace ipmi
473