blob: 3b45db8553c4dce517bdb18c6127967bd8457b8b [file] [log] [blame]
Vernon Mauery783dc072018-10-08 12:05:20 -07001#include <algorithm>
2#include <array>
3#include <ipmid/api.hpp>
4#include <ipmid/registration.hpp>
5#include <ipmiwhitelist.hpp>
6#include <phosphor-logging/elog-errors.hpp>
7#include <phosphor-logging/log.hpp>
8#include <settings.hpp>
Vernon Mauery64a350d2019-03-06 09:24:55 -08009#include <utils.hpp>
Vernon Mauery783dc072018-10-08 12:05:20 -070010#include <xyz/openbmc_project/Control/Security/RestrictionMode/server.hpp>
11
12using namespace phosphor::logging;
13using namespace sdbusplus::xyz::openbmc_project::Common::Error;
14
15namespace ipmi
16{
17
18// put the filter provider in an unnamed namespace
19namespace
20{
21
22/** @class WhitelistFilter
23 *
24 * Class that implements an IPMI message filter based
25 * on incoming interface and a restriction mode setting
26 */
27class WhitelistFilter
28{
29 public:
30 WhitelistFilter();
31 ~WhitelistFilter() = default;
32 WhitelistFilter(WhitelistFilter const&) = delete;
33 WhitelistFilter(WhitelistFilter&&) = delete;
34 WhitelistFilter& operator=(WhitelistFilter const&) = delete;
35 WhitelistFilter& operator=(WhitelistFilter&&) = delete;
36
37 private:
38 void postInit();
39 void cacheRestrictedMode();
40 void handleRestrictedModeChange(sdbusplus::message::message& m);
41 ipmi::Cc filterMessage(ipmi::message::Request::ptr request);
42
43 bool restrictedMode = true;
44 std::shared_ptr<sdbusplus::asio::connection> bus;
45 std::unique_ptr<settings::Objects> objects;
46 std::unique_ptr<sdbusplus::bus::match::match> modeChangeMatch;
47
48 static constexpr const char restrictionModeIntf[] =
49 "xyz.openbmc_project.Control.Security.RestrictionMode";
50};
51
52WhitelistFilter::WhitelistFilter()
53{
54 bus = getSdBus();
55
56 log<level::INFO>("Loading whitelist filter");
57
58 ipmi::registerFilter(ipmi::prioOpenBmcBase,
59 [this](ipmi::message::Request::ptr request) {
60 return filterMessage(request);
61 });
62
63 // wait until io->run is going to fetch RestrictionMode
64 post_work([this]() { postInit(); });
65}
66
67void WhitelistFilter::cacheRestrictedMode()
68{
69 using namespace sdbusplus::xyz::openbmc_project::Control::Security::server;
70 std::string restrictionModeSetting;
71 std::string restrictionModeService;
72 try
73 {
74 restrictionModeSetting = objects->map.at(restrictionModeIntf).at(0);
75 restrictionModeService =
76 objects->service(restrictionModeSetting, restrictionModeIntf);
77 }
78 catch (const std::out_of_range& e)
79 {
80 log<level::ERR>(
81 "Could not look up restriction mode interface from cache");
82 return;
83 }
84 bus->async_method_call(
Vernon Mauery64a350d2019-03-06 09:24:55 -080085 [this](boost::system::error_code ec, ipmi::Value v) {
Vernon Mauery783dc072018-10-08 12:05:20 -070086 if (ec)
87 {
88 log<level::ERR>("Error in RestrictionMode Get");
89 // Fail-safe to true.
90 restrictedMode = true;
91 return;
92 }
Vernon Mauery64a350d2019-03-06 09:24:55 -080093 auto mode = std::get<std::string>(v);
Vernon Mauery783dc072018-10-08 12:05:20 -070094 auto restrictionMode =
95 RestrictionMode::convertModesFromString(mode);
96 restrictedMode =
97 (restrictionMode == RestrictionMode::Modes::Whitelist);
98 log<level::INFO>((restrictedMode ? "Set restrictedMode = true"
99 : "Set restrictedMode = false"));
100 },
Vernon Mauery64a350d2019-03-06 09:24:55 -0800101 restrictionModeService, restrictionModeSetting,
102 "org.freedesktop.DBus.Properties", "Get", restrictionModeIntf,
103 "RestrictionMode");
Vernon Mauery783dc072018-10-08 12:05:20 -0700104}
105
106void WhitelistFilter::handleRestrictedModeChange(sdbusplus::message::message& m)
107{
108 using namespace sdbusplus::xyz::openbmc_project::Control::Security::server;
109 std::string mode;
110 m.read(mode);
111 RestrictionMode::Modes restrictionMode =
112 RestrictionMode::convertModesFromString(mode);
113 restrictedMode = (restrictionMode == RestrictionMode::Modes::Whitelist);
114 log<level::INFO>((restrictedMode ? "Updated restrictedMode = true"
115 : "Updated restrictedMode = false"));
116}
117
118void WhitelistFilter::postInit()
119{
120 objects = std::make_unique<settings::Objects>(
121 *bus, std::vector<settings::Interface>({restrictionModeIntf}));
122 if (!objects)
123 {
124 log<level::ERR>(
125 "Failed to create settings object; defaulting to restricted mode");
126 return;
127 }
128
129 // Initialize restricted mode
130 cacheRestrictedMode();
131 // Wait for changes on Restricted mode
132 std::string filterStr;
133 try
134 {
135 filterStr = sdbusplus::bus::match::rules::propertiesChanged(
136 objects->map.at(restrictionModeIntf).at(0), restrictionModeIntf);
137 }
138 catch (const std::out_of_range& e)
139 {
140 log<level::ERR>("Failed to determine restriction mode filter string");
141 return;
142 }
143 modeChangeMatch = std::make_unique<sdbusplus::bus::match::match>(
144 *bus, filterStr, [this](sdbusplus::message::message& m) {
145 handleRestrictedModeChange(m);
146 });
147}
148
149ipmi::Cc WhitelistFilter::filterMessage(ipmi::message::Request::ptr request)
150{
151 if (request->ctx->channel == ipmi::channelSystemIface && restrictedMode)
152 {
153 if (!std::binary_search(
154 whitelist.cbegin(), whitelist.cend(),
155 std::make_pair(request->ctx->netFn, request->ctx->cmd)))
156 {
157 log<level::ERR>("Net function not whitelisted",
158 entry("NETFN=0x%X", int(request->ctx->netFn)),
159 entry("CMD=0x%X", int(request->ctx->cmd)));
160 return ipmi::ccInsufficientPrivilege;
161 }
162 }
163 return ipmi::ccSuccess;
164}
165
166// instantiate the WhitelistFilter when this shared object is loaded
167WhitelistFilter whitelistFilter;
168
169} // namespace
170
171} // namespace ipmi