#include #include #include #include #include #include #include #include #include using namespace phosphor::logging; using namespace sdbusplus::xyz::openbmc_project::Common::Error; namespace ipmi { // put the filter provider in an unnamed namespace namespace { /** @class WhitelistFilter * * Class that implements an IPMI message filter based * on incoming interface and a restriction mode setting */ class WhitelistFilter { public: WhitelistFilter(); ~WhitelistFilter() = default; WhitelistFilter(WhitelistFilter const&) = delete; WhitelistFilter(WhitelistFilter&&) = delete; WhitelistFilter& operator=(WhitelistFilter const&) = delete; WhitelistFilter& operator=(WhitelistFilter&&) = delete; private: void postInit(); void cacheRestrictedMode(); void handleRestrictedModeChange(sdbusplus::message::message& m); ipmi::Cc filterMessage(ipmi::message::Request::ptr request); bool restrictedMode = true; std::shared_ptr bus; std::unique_ptr objects; std::unique_ptr modeChangeMatch; static constexpr const char restrictionModeIntf[] = "xyz.openbmc_project.Control.Security.RestrictionMode"; }; WhitelistFilter::WhitelistFilter() { bus = getSdBus(); log("Loading whitelist filter"); ipmi::registerFilter(ipmi::prioOpenBmcBase, [this](ipmi::message::Request::ptr request) { return filterMessage(request); }); // wait until io->run is going to fetch RestrictionMode post_work([this]() { postInit(); }); } void WhitelistFilter::cacheRestrictedMode() { using namespace sdbusplus::xyz::openbmc_project::Control::Security::server; std::string restrictionModeSetting; std::string restrictionModeService; try { restrictionModeSetting = objects->map.at(restrictionModeIntf).at(0); restrictionModeService = objects->service(restrictionModeSetting, restrictionModeIntf); } catch (const std::out_of_range& e) { log( "Could not look up restriction mode interface from cache"); return; } bus->async_method_call( [this](boost::system::error_code ec, ipmi::Value v) { if (ec) { log("Error in RestrictionMode Get"); // Fail-safe to true. restrictedMode = true; return; } auto mode = std::get(v); auto restrictionMode = RestrictionMode::convertModesFromString(mode); restrictedMode = (restrictionMode == RestrictionMode::Modes::Whitelist); log((restrictedMode ? "Set restrictedMode = true" : "Set restrictedMode = false")); }, restrictionModeService, restrictionModeSetting, "org.freedesktop.DBus.Properties", "Get", restrictionModeIntf, "RestrictionMode"); } void WhitelistFilter::handleRestrictedModeChange(sdbusplus::message::message& m) { using namespace sdbusplus::xyz::openbmc_project::Control::Security::server; std::string mode; m.read(mode); RestrictionMode::Modes restrictionMode = RestrictionMode::convertModesFromString(mode); restrictedMode = (restrictionMode == RestrictionMode::Modes::Whitelist); log((restrictedMode ? "Updated restrictedMode = true" : "Updated restrictedMode = false")); } void WhitelistFilter::postInit() { objects = std::make_unique( *bus, std::vector({restrictionModeIntf})); if (!objects) { log( "Failed to create settings object; defaulting to restricted mode"); return; } // Initialize restricted mode cacheRestrictedMode(); // Wait for changes on Restricted mode std::string filterStr; try { filterStr = sdbusplus::bus::match::rules::propertiesChanged( objects->map.at(restrictionModeIntf).at(0), restrictionModeIntf); } catch (const std::out_of_range& e) { log("Failed to determine restriction mode filter string"); return; } modeChangeMatch = std::make_unique( *bus, filterStr, [this](sdbusplus::message::message& m) { handleRestrictedModeChange(m); }); } ipmi::Cc WhitelistFilter::filterMessage(ipmi::message::Request::ptr request) { if (request->ctx->channel == ipmi::channelSystemIface && restrictedMode) { if (!std::binary_search( whitelist.cbegin(), whitelist.cend(), std::make_pair(request->ctx->netFn, request->ctx->cmd))) { log("Net function not whitelisted", entry("NETFN=0x%X", int(request->ctx->netFn)), entry("CMD=0x%X", int(request->ctx->cmd))); return ipmi::ccInsufficientPrivilege; } } return ipmi::ccSuccess; } // instantiate the WhitelistFilter when this shared object is loaded WhitelistFilter whitelistFilter; } // namespace } // namespace ipmi