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