blob: 2729cbb379d14881950e24caafd1e3ef6dc6c13e [file] [log] [blame]
Patrick Venture0b02be92018-08-31 11:55:55 -07001#include "ipmid.hpp"
2
Patrick Venture46470a32018-09-07 19:26:25 -07003#include "host-cmd-manager.hpp"
4#include "ipmiwhitelist.hpp"
5#include "sensorhandler.hpp"
Patrick Venture0b02be92018-08-31 11:55:55 -07006#include "settings.hpp"
7
vishwabmcba0bd5f2015-09-30 16:50:23 +05308#include <assert.h>
9#include <dirent.h>
Patrick Venture0b02be92018-08-31 11:55:55 -070010#include <dlfcn.h>
11#include <errno.h>
12#include <mapper.h>
Patrick Venture0b02be92018-08-31 11:55:55 -070013#include <sys/time.h>
14#include <systemd/sd-bus.h>
15#include <unistd.h>
16
17#include <algorithm>
Patrick Ventureb51bf9c2018-09-10 15:53:14 -070018#include <cstring>
Patrick Venture0b02be92018-08-31 11:55:55 -070019#include <host-ipmid/ipmid-host-cmd.hpp>
Patrick Venture46470a32018-09-07 19:26:25 -070020#include <host-ipmid/oemrouter.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -070021#include <iostream>
Patrick Venture0b02be92018-08-31 11:55:55 -070022#include <iterator>
vishwabmcba0bd5f2015-09-30 16:50:23 +053023#include <map>
Deepak Kodihalli84b3a082017-07-21 23:44:44 -050024#include <memory>
Andrew Geissler93c679b2017-04-02 10:06:43 -050025#include <phosphor-logging/log.hpp>
Deepak Kodihalli84b3a082017-07-21 23:44:44 -050026#include <sdbusplus/bus.hpp>
27#include <sdbusplus/bus/match.hpp>
William A. Kennington III4c008022018-10-12 17:18:14 -070028#include <sdbusplus/message/types.hpp>
Vernon Mauery1181af72018-10-08 12:05:00 -070029#include <sdbusplus/timer.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -070030#include <vector>
31#include <xyz/openbmc_project/Control/Security/RestrictionMode/server.hpp>
32
Andrew Geissler93c679b2017-04-02 10:06:43 -050033using namespace phosphor::logging;
Deepak Kodihalli84b3a082017-07-21 23:44:44 -050034namespace sdbusRule = sdbusplus::bus::match::rules;
William A. Kennington III4c008022018-10-12 17:18:14 -070035namespace variant_ns = sdbusplus::message::variant_ns;
Andrew Geissler93c679b2017-04-02 10:06:43 -050036
Patrick Venture0b02be92018-08-31 11:55:55 -070037sd_bus* bus = NULL;
38sd_bus_slot* ipmid_slot = NULL;
39sd_event* events = nullptr;
Chris Austen30195fa2015-11-13 14:39:19 -060040
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +053041// Need this to use new sdbusplus compatible interfaces
42sdbusPtr sdbusp;
43
44// Global Host Bound Command manager
45using cmdManagerPtr = std::unique_ptr<phosphor::host::command::Manager>;
46cmdManagerPtr cmdManager;
47
Ratan Gupta7a7f0122018-03-07 12:31:05 +053048// Global timer for network changes
Vernon Mauery1181af72018-10-08 12:05:00 -070049std::unique_ptr<phosphor::Timer> networkTimer = nullptr;
Ratan Gupta7a7f0122018-03-07 12:31:05 +053050
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +053051// Command and handler tuple. Used when clients ask the command to be put
52// into host message queue
53using CommandHandler = phosphor::host::command::CommandHandler;
54
Tom Joseph9a61b4f2016-07-11 06:56:11 -050055// Initialise restricted mode to true
56bool restricted_mode = true;
57
Chris Austen41a4b312015-10-25 03:45:42 -050058FILE *ipmiio, *ipmidbus, *ipmicmddetails;
vishwabmcba0bd5f2015-09-30 16:50:23 +053059
Patrick Venture0b02be92018-08-31 11:55:55 -070060void print_usage(void)
61{
Patrick Ventureb51bf9c2018-09-10 15:53:14 -070062 std::fprintf(stderr, "Options: [-d mask]\n");
63 std::fprintf(stderr, " mask : 0x01 - Print ipmi packets\n");
64 std::fprintf(stderr, " mask : 0x02 - Print DBUS operations\n");
65 std::fprintf(stderr, " mask : 0x04 - Print ipmi command details\n");
66 std::fprintf(stderr, " mask : 0xFF - Print all trace\n");
Chris Austen99497312015-10-22 13:00:16 -050067}
68
Patrick Venture0b02be92018-08-31 11:55:55 -070069const char* DBUS_INTF = "org.openbmc.HostIpmi";
vishwabmcba0bd5f2015-09-30 16:50:23 +053070
Patrick Venture0b02be92018-08-31 11:55:55 -070071const char* FILTER =
72 "type='signal',interface='org.openbmc.HostIpmi',member='ReceivedMessage'";
Chris Austen0ba649e2015-10-13 12:28:13 -050073
vishwabmcba0bd5f2015-09-30 16:50:23 +053074typedef std::pair<ipmi_netfn_t, ipmi_cmd_t> ipmi_fn_cmd_t;
75typedef std::pair<ipmid_callback_t, ipmi_context_t> ipmi_fn_context_t;
76
77// Global data structure that contains the IPMI command handler's registrations.
78std::map<ipmi_fn_cmd_t, ipmi_fn_context_t> g_ipmid_router_map;
79
Nan Li36c0cb62016-03-31 11:16:08 +080080// IPMI Spec, shared Reservation ID.
Jason M. Bills13e67c82018-09-10 14:12:16 -070081static unsigned short selReservationID = 0xFFFF;
82static bool selReservationValid = false;
Nan Li36c0cb62016-03-31 11:16:08 +080083
Jason M. Bills13e67c82018-09-10 14:12:16 -070084unsigned short reserveSel(void)
Nan Li36c0cb62016-03-31 11:16:08 +080085{
Jason M. Bills13e67c82018-09-10 14:12:16 -070086 // IPMI spec, Reservation ID, the value simply increases against each
87 // execution of the Reserve SEL command.
88 if (++selReservationID == 0)
89 {
90 selReservationID = 1;
91 }
92 selReservationValid = true;
93 return selReservationID;
94}
95
96bool checkSELReservation(unsigned short id)
97{
98 return (selReservationValid && selReservationID == id);
99}
100
101void cancelSELReservation(void)
102{
103 selReservationValid = false;
Nan Li36c0cb62016-03-31 11:16:08 +0800104}
Chris Austen0ba649e2015-10-13 12:28:13 -0500105
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500106namespace internal
107{
108
109constexpr auto restrictionModeIntf =
110 "xyz.openbmc_project.Control.Security.RestrictionMode";
111
112namespace cache
113{
114
115std::unique_ptr<settings::Objects> objects = nullptr;
116
117} // namespace cache
118} // namespace internal
119
Chris Austen0ba649e2015-10-13 12:28:13 -0500120#ifndef HEXDUMP_COLS
121#define HEXDUMP_COLS 16
122#endif
123
Patrick Venture0b02be92018-08-31 11:55:55 -0700124void hexdump(FILE* s, void* mem, size_t len)
Chris Austen0ba649e2015-10-13 12:28:13 -0500125{
Patrick Venture0b02be92018-08-31 11:55:55 -0700126 unsigned int i, j;
Chris Austen120f7322015-10-14 23:27:31 -0500127
Patrick Venture0b02be92018-08-31 11:55:55 -0700128 for (i = 0;
129 i <
130 len + ((len % HEXDUMP_COLS) ? (HEXDUMP_COLS - len % HEXDUMP_COLS) : 0);
131 i++)
132 {
133 /* print offset */
134 if (i % HEXDUMP_COLS == 0)
Chris Austen0ba649e2015-10-13 12:28:13 -0500135 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700136 std::fprintf(s, "0x%06x: ", i);
Chris Austen0ba649e2015-10-13 12:28:13 -0500137 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700138
139 /* print hex data */
140 if (i < len)
141 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700142 std::fprintf(s, "%02x ", 0xFF & ((char*)mem)[i]);
Patrick Venture0b02be92018-08-31 11:55:55 -0700143 }
144 else /* end of block, just aligning for ASCII dump */
145 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700146 std::fprintf(s, " ");
Patrick Venture0b02be92018-08-31 11:55:55 -0700147 }
148
149 /* print ASCII dump */
150 if (i % HEXDUMP_COLS == (HEXDUMP_COLS - 1))
151 {
152 for (j = i - (HEXDUMP_COLS - 1); j <= i; j++)
153 {
154 if (j >= len) /* end of block, not really printing */
155 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700156 std::fputc(' ', s);
Patrick Venture0b02be92018-08-31 11:55:55 -0700157 }
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700158 else if (std::isprint(((char*)mem)[j])) /* printable char */
Patrick Venture0b02be92018-08-31 11:55:55 -0700159 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700160 std::fputc(0xFF & ((char*)mem)[j], s);
Patrick Venture0b02be92018-08-31 11:55:55 -0700161 }
162 else /* other char */
163 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700164 std::fputc('.', s);
Patrick Venture0b02be92018-08-31 11:55:55 -0700165 }
166 }
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700167 std::fputc('\n', s);
Patrick Venture0b02be92018-08-31 11:55:55 -0700168 }
169 }
Chris Austen0ba649e2015-10-13 12:28:13 -0500170}
171
Patrick Venture0b02be92018-08-31 11:55:55 -0700172// Method that gets called by shared libraries to get their command handlers
173// registered
174void ipmi_register_callback(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
175 ipmi_context_t context, ipmid_callback_t handler,
176 ipmi_cmd_privilege_t priv)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530177{
178 // Pack NetFn and Command in one.
179 auto netfn_and_cmd = std::make_pair(netfn, cmd);
180
181 // Pack Function handler and Data in another.
182 auto handler_and_context = std::make_pair(handler, context);
183
184 // Check if the registration has already been made..
185 auto iter = g_ipmid_router_map.find(netfn_and_cmd);
Patrick Venture0b02be92018-08-31 11:55:55 -0700186 if (iter != g_ipmid_router_map.end())
vishwabmcba0bd5f2015-09-30 16:50:23 +0530187 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700188 log<level::ERR>("Duplicate registration", entry("NETFN=0x%X", netfn),
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530189 entry("CMD=0x%X", cmd));
vishwabmcba0bd5f2015-09-30 16:50:23 +0530190 }
191 else
192 {
193 // This is a fresh registration.. Add it to the map.
194 g_ipmid_router_map.emplace(netfn_and_cmd, handler_and_context);
195 }
196
197 return;
198}
199
200// Looks at the map and calls corresponding handler functions.
Patrick Venture0b02be92018-08-31 11:55:55 -0700201ipmi_ret_t ipmi_netfn_router(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
202 ipmi_request_t request, ipmi_response_t response,
203 ipmi_data_len_t data_len)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530204{
205 // return from the Command handlers.
206 ipmi_ret_t rc = IPMI_CC_INVALID;
207
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500208 // If restricted mode is true and command is not whitelisted, don't
209 // execute the command
Patrick Venture0b02be92018-08-31 11:55:55 -0700210 if (restricted_mode)
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500211 {
212 if (!std::binary_search(whitelist.cbegin(), whitelist.cend(),
Patrick Venture0b02be92018-08-31 11:55:55 -0700213 std::make_pair(netfn, cmd)))
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500214 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530215 log<level::ERR>("Net function not whitelisted",
Patrick Venture0b02be92018-08-31 11:55:55 -0700216 entry("NETFN=0x%X", netfn), entry("CMD=0x%X", cmd));
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500217 rc = IPMI_CC_INSUFFICIENT_PRIVILEGE;
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700218 std::memcpy(response, &rc, IPMI_CC_LEN);
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500219 *data_len = IPMI_CC_LEN;
220 return rc;
221 }
222 }
223
vishwabmcba0bd5f2015-09-30 16:50:23 +0530224 // Walk the map that has the registered handlers and invoke the approprite
225 // handlers for matching commands.
226 auto iter = g_ipmid_router_map.find(std::make_pair(netfn, cmd));
Patrick Venture0b02be92018-08-31 11:55:55 -0700227 if (iter == g_ipmid_router_map.end())
vishwabmcba0bd5f2015-09-30 16:50:23 +0530228 {
Patrick Venture03f84ba2017-09-20 09:15:33 -0700229 /* By default should only print on failure to find wildcard command. */
230#ifdef __IPMI_DEBUG__
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530231 log<level::ERR>(
Patrick Venture0b02be92018-08-31 11:55:55 -0700232 "No registered handlers for NetFn, trying Wilcard implementation",
233 entry("NET_FUN=0x%X", netfn) entry("CMD=0x%X", IPMI_CMD_WILDCARD));
Patrick Venture03f84ba2017-09-20 09:15:33 -0700234#endif
vishwabmcba0bd5f2015-09-30 16:50:23 +0530235
236 // Now that we did not find any specific [NetFn,Cmd], tuple, check for
237 // NetFn, WildCard command present.
Patrick Venture0b02be92018-08-31 11:55:55 -0700238 iter =
239 g_ipmid_router_map.find(std::make_pair(netfn, IPMI_CMD_WILDCARD));
240 if (iter == g_ipmid_router_map.end())
vishwabmcba0bd5f2015-09-30 16:50:23 +0530241 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530242 log<level::ERR>("No Registered handlers for NetFn",
243 entry("NET_FUN=0x%X", netfn),
244 entry("CMD=0x%X", IPMI_CMD_WILDCARD));
vishwabmcba0bd5f2015-09-30 16:50:23 +0530245
246 // Respond with a 0xC1
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700247 std::memcpy(response, &rc, IPMI_CC_LEN);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530248 *data_len = IPMI_CC_LEN;
249 return rc;
250 }
251 }
252
253#ifdef __IPMI_DEBUG__
254 // We have either a perfect match -OR- a wild card atleast,
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530255 log<level::ERR>("Calling Net function",
Patrick Venture0b02be92018-08-31 11:55:55 -0700256 entry("NET_FUN=0x%X", netfn) entry("CMD=0x%X", cmd));
vishwabmcba0bd5f2015-09-30 16:50:23 +0530257#endif
258
259 // Extract the map data onto appropriate containers
260 auto handler_and_context = iter->second;
261
262 // Creating a pointer type casted to char* to make sure we advance 1 byte
263 // when we advance pointer to next's address. advancing void * would not
264 // make sense.
Patrick Venture0b02be92018-08-31 11:55:55 -0700265 char* respo = &((char*)response)[IPMI_CC_LEN];
vishwabmcba0bd5f2015-09-30 16:50:23 +0530266
Richard Marian Thomaiyarebc886f2018-06-06 14:33:59 +0530267 try
268 {
269 // Response message from the plugin goes into a byte post the base
270 // response
Patrick Venture0b02be92018-08-31 11:55:55 -0700271 rc = (handler_and_context.first)(netfn, cmd, request, respo, data_len,
272 handler_and_context.second);
Richard Marian Thomaiyarebc886f2018-06-06 14:33:59 +0530273 }
274 // IPMI command handlers can throw unhandled exceptions, catch those
275 // and return sane error code.
Patrick Venture0b02be92018-08-31 11:55:55 -0700276 catch (const std::exception& e)
Richard Marian Thomaiyarebc886f2018-06-06 14:33:59 +0530277 {
278 log<level::ERR>(e.what(), entry("NET_FUN=0x%X", netfn),
279 entry("CMD=0x%X", cmd));
280 rc = IPMI_CC_UNSPECIFIED_ERROR;
281 *data_len = 0;
282 // fall through
283 }
vishwabmcba0bd5f2015-09-30 16:50:23 +0530284 // Now copy the return code that we got from handler and pack it in first
285 // byte.
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700286 std::memcpy(response, &rc, IPMI_CC_LEN);
Chris Austen120f7322015-10-14 23:27:31 -0500287
vishwabmcba0bd5f2015-09-30 16:50:23 +0530288 // Data length is now actual data + completion code.
289 *data_len = *data_len + IPMI_CC_LEN;
290
291 return rc;
292}
293
Patrick Venture0b02be92018-08-31 11:55:55 -0700294static int send_ipmi_message(sd_bus_message* req, unsigned char seq,
295 unsigned char netfn, unsigned char lun,
296 unsigned char cmd, unsigned char cc,
297 unsigned char* buf, unsigned char len)
298{
vishwabmcba0bd5f2015-09-30 16:50:23 +0530299
Chris Austen0ba649e2015-10-13 12:28:13 -0500300 sd_bus_error error = SD_BUS_ERROR_NULL;
Patrick Venture0b02be92018-08-31 11:55:55 -0700301 sd_bus_message *reply = NULL, *m = NULL;
Jeremy Kerre41081f2015-10-27 12:11:36 +0800302 const char *dest, *path;
Chris Austen0ba649e2015-10-13 12:28:13 -0500303 int r, pty;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530304
Jeremy Kerre41081f2015-10-27 12:11:36 +0800305 dest = sd_bus_message_get_sender(req);
306 path = sd_bus_message_get_path(req);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530307
Patrick Venture0b02be92018-08-31 11:55:55 -0700308 r = sd_bus_message_new_method_call(bus, &m, dest, path, DBUS_INTF,
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530309 "sendMessage");
Patrick Venture0b02be92018-08-31 11:55:55 -0700310 if (r < 0)
311 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530312 log<level::ERR>("Failed to add the method object",
313 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500314 return -1;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530315 }
316
Chris Austenabfb5e82015-10-13 12:29:24 -0500317 // Responses in IPMI require a bit set. So there ya go...
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800318 netfn |= 0x01;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530319
Chris Austen0ba649e2015-10-13 12:28:13 -0500320 // Add the bytes needed for the methods to be called
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800321 r = sd_bus_message_append(m, "yyyyy", seq, netfn, lun, cmd, cc);
Patrick Venture0b02be92018-08-31 11:55:55 -0700322 if (r < 0)
323 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530324 log<level::ERR>("Failed add the netfn and others",
325 entry("ERRNO=0x%X", -r));
Chris Austen169395e2015-12-02 20:56:15 -0600326 goto final;
Chris Austen0ba649e2015-10-13 12:28:13 -0500327 }
Chris Austen120f7322015-10-14 23:27:31 -0500328
Chris Austen0ba649e2015-10-13 12:28:13 -0500329 r = sd_bus_message_append_array(m, 'y', buf, len);
Patrick Venture0b02be92018-08-31 11:55:55 -0700330 if (r < 0)
331 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530332 log<level::ERR>("Failed to add the string of response bytes",
333 entry("ERRNO=0x%X", -r));
Chris Austen169395e2015-12-02 20:56:15 -0600334 goto final;
Chris Austen0ba649e2015-10-13 12:28:13 -0500335 }
336
Chris Austen0ba649e2015-10-13 12:28:13 -0500337 // Call the IPMI responder on the bus so the message can be sent to the CEC
338 r = sd_bus_call(bus, m, 0, &error, &reply);
Patrick Venture0b02be92018-08-31 11:55:55 -0700339 if (r < 0)
340 {
341 log<level::ERR>("Failed to call the method", entry("DEST=%s", dest),
342 entry("PATH=%s", path), entry("ERRNO=0x%X", -r));
Chris Austen169395e2015-12-02 20:56:15 -0600343 goto final;
Chris Austen0ba649e2015-10-13 12:28:13 -0500344 }
345
346 r = sd_bus_message_read(reply, "x", &pty);
Patrick Venture0b02be92018-08-31 11:55:55 -0700347 if (r < 0)
348 {
349 log<level::ERR>("Failed to get a reply from the method",
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530350 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500351 }
352
Chris Austen169395e2015-12-02 20:56:15 -0600353final:
Chris Austen0ba649e2015-10-13 12:28:13 -0500354 sd_bus_error_free(&error);
vishwa1eaea4f2016-02-26 11:57:40 -0600355 m = sd_bus_message_unref(m);
356 reply = sd_bus_message_unref(reply);
Chris Austen0ba649e2015-10-13 12:28:13 -0500357
Chris Austen0ba649e2015-10-13 12:28:13 -0500358 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
Chris Austen0ba649e2015-10-13 12:28:13 -0500359}
360
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500361void cache_restricted_mode()
362{
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500363 restricted_mode = false;
364 using namespace sdbusplus::xyz::openbmc_project::Control::Security::server;
365 using namespace internal;
366 using namespace internal::cache;
367 sdbusplus::bus::bus dbus(ipmid_get_sd_bus_connection());
368 const auto& restrictionModeSetting =
Deepak Kodihallie6027092017-08-27 08:13:37 -0500369 objects->map.at(restrictionModeIntf).front();
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500370 auto method = dbus.new_method_call(
Patrick Venture0b02be92018-08-31 11:55:55 -0700371 objects->service(restrictionModeSetting, restrictionModeIntf).c_str(),
372 restrictionModeSetting.c_str(), "org.freedesktop.DBus.Properties",
373 "Get");
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500374 method.append(restrictionModeIntf, "RestrictionMode");
375 auto resp = dbus.call(method);
376 if (resp.is_method_error())
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500377 {
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500378 log<level::ERR>("Error in RestrictionMode Get");
379 // Fail-safe to true.
380 restricted_mode = true;
381 return;
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500382 }
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500383 sdbusplus::message::variant<std::string> result;
384 resp.read(result);
William A. Kennington III4c008022018-10-12 17:18:14 -0700385 auto restrictionMode = RestrictionMode::convertModesFromString(
386 variant_ns::get<std::string>(result));
Patrick Venture0b02be92018-08-31 11:55:55 -0700387 if (RestrictionMode::Modes::Whitelist == restrictionMode)
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500388 {
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500389 restricted_mode = true;
390 }
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500391}
392
Patrick Venture0b02be92018-08-31 11:55:55 -0700393static int handle_restricted_mode_change(sd_bus_message* m, void* user_data,
394 sd_bus_error* ret_error)
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500395{
396 cache_restricted_mode();
397 return 0;
398}
399
Patrick Venture0b02be92018-08-31 11:55:55 -0700400static int handle_ipmi_command(sd_bus_message* m, void* user_data,
401 sd_bus_error* ret_error)
402{
Chris Austen0ba649e2015-10-13 12:28:13 -0500403 int r = 0;
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800404 unsigned char sequence, netfn, lun, cmd;
Patrick Venture0b02be92018-08-31 11:55:55 -0700405 const void* request;
Chris Austen0ba649e2015-10-13 12:28:13 -0500406 size_t sz;
Patrick Venture0b02be92018-08-31 11:55:55 -0700407 size_t resplen = MAX_IPMI_BUFFER;
Chris Austen0ba649e2015-10-13 12:28:13 -0500408 unsigned char response[MAX_IPMI_BUFFER];
409
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700410 std::memset(response, 0, MAX_IPMI_BUFFER);
Chris Austen0ba649e2015-10-13 12:28:13 -0500411
Patrick Venture0b02be92018-08-31 11:55:55 -0700412 r = sd_bus_message_read(m, "yyyy", &sequence, &netfn, &lun, &cmd);
413 if (r < 0)
414 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530415 log<level::ERR>("Failed to parse signal message",
416 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500417 return -1;
418 }
419
Patrick Venture0b02be92018-08-31 11:55:55 -0700420 r = sd_bus_message_read_array(m, 'y', &request, &sz);
421 if (r < 0)
422 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530423 log<level::ERR>("Failed to parse signal message",
424 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500425 return -1;
426 }
427
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700428 std::fprintf(ipmiio,
429 "IPMI Incoming: Seq 0x%02x, NetFn 0x%02x, CMD: 0x%02x \n",
430 sequence, netfn, cmd);
Chris Austen99497312015-10-22 13:00:16 -0500431 hexdump(ipmiio, (void*)request, sz);
Chris Austen0ba649e2015-10-13 12:28:13 -0500432
Chris Austen120f7322015-10-14 23:27:31 -0500433 // Allow the length field to be used for both input and output of the
Chris Austen0ba649e2015-10-13 12:28:13 -0500434 // ipmi call
435 resplen = sz;
436
Chris Austen120f7322015-10-14 23:27:31 -0500437 // Now that we have parsed the entire byte array from the caller
vishwabmcba0bd5f2015-09-30 16:50:23 +0530438 // we can call the ipmi router to do the work...
Patrick Venture0b02be92018-08-31 11:55:55 -0700439 r = ipmi_netfn_router(netfn, cmd, (void*)request, (void*)response,
440 &resplen);
441 if (r != 0)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530442 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530443#ifdef __IPMI_DEBUG__
Patrick Venture0b02be92018-08-31 11:55:55 -0700444 log<level::ERR>("ERROR in handling NetFn", entry("ERRNO=0x%X", -r),
445 entry("NET_FUN=0x%X", netfn), entry("CMD=0x%X", cmd));
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530446#endif
Ratan Guptae0cc8552018-01-22 14:23:04 +0530447 resplen = 0;
448 }
449 else
450 {
451 resplen = resplen - 1; // first byte is for return code.
vishwabmcba0bd5f2015-09-30 16:50:23 +0530452 }
453
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700454 std::fprintf(ipmiio, "IPMI Response:\n");
Patrick Venture0b02be92018-08-31 11:55:55 -0700455 hexdump(ipmiio, (void*)response, resplen);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530456
Chris Austen0ba649e2015-10-13 12:28:13 -0500457 // Send the response buffer from the ipmi command
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800458 r = send_ipmi_message(m, sequence, netfn, lun, cmd, response[0],
Patrick Venture0b02be92018-08-31 11:55:55 -0700459 ((unsigned char*)response) + 1, resplen);
460 if (r < 0)
461 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530462 log<level::ERR>("Failed to send the response message");
Chris Austen0ba649e2015-10-13 12:28:13 -0500463 return -1;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530464 }
465
Chris Austen0ba649e2015-10-13 12:28:13 -0500466 return 0;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530467}
468
469//----------------------------------------------------------------------
470// handler_select
471// Select all the files ending with with .so. in the given diretcory
472// @d: dirent structure containing the file name
473//----------------------------------------------------------------------
Patrick Venture0b02be92018-08-31 11:55:55 -0700474int handler_select(const struct dirent* entry)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530475{
476 // To hold ".so" from entry->d_name;
477 char dname_copy[4] = {0};
478
479 // We want to avoid checking for everything and isolate to the ones having
Adriana Kobylak87e080b2016-07-10 13:16:53 -0500480 // .so.* or .so in them.
481 // Check for versioned libraries .so.*
Patrick Venture0b02be92018-08-31 11:55:55 -0700482 if (strstr(entry->d_name, IPMI_PLUGIN_SONAME_EXTN))
Adriana Kobylak87e080b2016-07-10 13:16:53 -0500483 {
484 return 1;
485 }
486 // Check for non versioned libraries .so
Patrick Venture0b02be92018-08-31 11:55:55 -0700487 else if (strstr(entry->d_name, IPMI_PLUGIN_EXTN))
vishwabmcba0bd5f2015-09-30 16:50:23 +0530488 {
489 // It is possible that .so could be anywhere in the string but unlikely
Chris Austen120f7322015-10-14 23:27:31 -0500490 // But being careful here. Get the base address of the string, move
vishwabmcba0bd5f2015-09-30 16:50:23 +0530491 // until end and come back 3 steps and that gets what we need.
Patrick Venture0b02be92018-08-31 11:55:55 -0700492 strcpy(dname_copy, (entry->d_name + strlen(entry->d_name) -
493 strlen(IPMI_PLUGIN_EXTN)));
494 if (strcmp(dname_copy, IPMI_PLUGIN_EXTN) == 0)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530495 {
496 return 1;
497 }
498 }
499 return 0;
500}
501
Patrick Venture0b02be92018-08-31 11:55:55 -0700502// This will do a dlopen of every .so in ipmi_lib_path and will dlopen
503// everything so that they will register a callback handler
vishwabmcba0bd5f2015-09-30 16:50:23 +0530504void ipmi_register_callback_handlers(const char* ipmi_lib_path)
505{
506 // For walking the ipmi_lib_path
Patrick Venture0b02be92018-08-31 11:55:55 -0700507 struct dirent** handler_list;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530508
509 // This is used to check and abort if someone tries to register a bad one.
Patrick Venture0b02be92018-08-31 11:55:55 -0700510 void* lib_handler = NULL;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530511
Patrick Venture0b02be92018-08-31 11:55:55 -0700512 if (ipmi_lib_path == NULL)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530513 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530514 log<level::ERR>("No handlers to be registered for ipmi.. Aborting");
vishwabmcba0bd5f2015-09-30 16:50:23 +0530515 assert(0);
516 }
517 else
518 {
519 // 1: Open ipmi_lib_path. Its usually "/usr/lib/phosphor-host-ipmid"
520 // 2: Scan the directory for the files that end with .so
Chris Austen120f7322015-10-14 23:27:31 -0500521 // 3: For each one of them, just do a 'dlopen' so that they register
vishwabmcba0bd5f2015-09-30 16:50:23 +0530522 // the handlers for callback routines.
523
524 std::string handler_fqdn = ipmi_lib_path;
Chris Austen120f7322015-10-14 23:27:31 -0500525
vishwabmcba0bd5f2015-09-30 16:50:23 +0530526 // Append a "/" since we need to add the name of the .so. If there is
527 // already a .so, adding one more is not any harm.
528 handler_fqdn += "/";
529
Patrick Venture4491a462018-10-13 13:00:42 -0700530 int num_handlers =
Patrick Venture0b02be92018-08-31 11:55:55 -0700531 scandir(ipmi_lib_path, &handler_list, handler_select, alphasort);
Nan Li36c0cb62016-03-31 11:16:08 +0800532 if (num_handlers < 0)
533 return;
Jeremy Kerr5e8f85e2015-10-27 13:43:54 +0800534
Patrick Venture0b02be92018-08-31 11:55:55 -0700535 while (num_handlers--)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530536 {
Chris Austen54030262015-10-13 12:30:46 -0500537 handler_fqdn = ipmi_lib_path;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530538 handler_fqdn += handler_list[num_handlers]->d_name;
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530539#ifdef __IPMI_DEBUG__
540 log<level::DEBUG>("Registering handler",
541 entry("HANDLER=%s", handler_fqdn.c_str()));
542#endif
Chris Austen54030262015-10-13 12:30:46 -0500543
vishwabmcba0bd5f2015-09-30 16:50:23 +0530544 lib_handler = dlopen(handler_fqdn.c_str(), RTLD_NOW);
Nan Li36c0cb62016-03-31 11:16:08 +0800545
Patrick Venture0b02be92018-08-31 11:55:55 -0700546 if (lib_handler == NULL)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530547 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530548 log<level::ERR>("ERROR opening",
549 entry("HANDLER=%s", handler_fqdn.c_str()),
550 entry("ERROR=%s", dlerror()));
vishwabmcba0bd5f2015-09-30 16:50:23 +0530551 }
552 // Wipe the memory allocated for this particular entry.
553 free(handler_list[num_handlers]);
554 }
Nan Li36c0cb62016-03-31 11:16:08 +0800555
vishwabmcba0bd5f2015-09-30 16:50:23 +0530556 // Done with all registration.
557 free(handler_list);
558 }
559
560 // TODO : What to be done on the memory that is given by dlopen ?.
561 return;
562}
563
Patrick Venture0b02be92018-08-31 11:55:55 -0700564sd_bus* ipmid_get_sd_bus_connection(void)
565{
Chris Austen30195fa2015-11-13 14:39:19 -0600566 return bus;
567}
568
Patrick Venture0b02be92018-08-31 11:55:55 -0700569sd_event* ipmid_get_sd_event_connection(void)
570{
Andrew Geissler93c679b2017-04-02 10:06:43 -0500571 return events;
572}
573
Patrick Venture0b02be92018-08-31 11:55:55 -0700574sd_bus_slot* ipmid_get_sd_bus_slot(void)
575{
vishwab9f559a2016-01-13 01:53:08 -0600576 return ipmid_slot;
577}
578
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530579// Calls host command manager to do the right thing for the command
Patrick Venture0b02be92018-08-31 11:55:55 -0700580void ipmid_send_cmd_to_host(CommandHandler&& cmd)
581{
582 return cmdManager->execute(std::move(cmd));
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530583}
584
Patrick Venture0b02be92018-08-31 11:55:55 -0700585cmdManagerPtr& ipmid_get_host_cmd_manager()
586{
587 return cmdManager;
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530588}
589
Patrick Venture0b02be92018-08-31 11:55:55 -0700590sdbusPtr& ipmid_get_sdbus_plus_handler()
591{
592 return sdbusp;
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530593}
594
Patrick Venture0b02be92018-08-31 11:55:55 -0700595int main(int argc, char* argv[])
vishwabmcba0bd5f2015-09-30 16:50:23 +0530596{
Chris Austen0ba649e2015-10-13 12:28:13 -0500597 int r;
Chris Austen99497312015-10-22 13:00:16 -0500598 unsigned long tvalue;
599 int c;
600
Chris Austen99497312015-10-22 13:00:16 -0500601 // This file and subsequient switch is for turning on levels
602 // of trace
Patrick Venture0b02be92018-08-31 11:55:55 -0700603 ipmicmddetails = ipmiio = ipmidbus = fopen("/dev/null", "w");
Chris Austen99497312015-10-22 13:00:16 -0500604
Patrick Venture0b02be92018-08-31 11:55:55 -0700605 while ((c = getopt(argc, argv, "h:d:")) != -1)
606 switch (c)
607 {
Chris Austen99497312015-10-22 13:00:16 -0500608 case 'd':
Patrick Venture0b02be92018-08-31 11:55:55 -0700609 tvalue = strtoul(optarg, NULL, 16);
610 if (1 & tvalue)
611 {
Chris Austen99497312015-10-22 13:00:16 -0500612 ipmiio = stdout;
613 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700614 if (2 & tvalue)
615 {
Chris Austen99497312015-10-22 13:00:16 -0500616 ipmidbus = stdout;
617 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700618 if (4 & tvalue)
619 {
Chris Austen99497312015-10-22 13:00:16 -0500620 ipmicmddetails = stdout;
621 }
622 break;
Patrick Venture0b02be92018-08-31 11:55:55 -0700623 case 'h':
624 case '?':
Chris Austen99497312015-10-22 13:00:16 -0500625 print_usage();
626 return 1;
627 }
Chris Austen0ba649e2015-10-13 12:28:13 -0500628
Chris Austen0ba649e2015-10-13 12:28:13 -0500629 /* Connect to system bus */
630 r = sd_bus_open_system(&bus);
Patrick Venture0b02be92018-08-31 11:55:55 -0700631 if (r < 0)
632 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530633 log<level::ERR>("Failed to connect to system bus",
634 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500635 goto finish;
636 }
vishwabmcba0bd5f2015-09-30 16:50:23 +0530637
Andrew Geissler93c679b2017-04-02 10:06:43 -0500638 /* Get an sd event handler */
639 r = sd_event_default(&events);
640 if (r < 0)
641 {
642 log<level::ERR>("Failure to create sd_event handler",
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530643 entry("ERRNO=0x%X", -r));
Andrew Geissler93c679b2017-04-02 10:06:43 -0500644 goto finish;
645 }
646
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530647 // Now create the Host Bound Command manager. Need sdbusplus
648 // to use the generated bindings
649 sdbusp = std::make_unique<sdbusplus::bus::bus>(bus);
James Feist331f5d52018-11-01 11:03:40 -0700650 sdbusp->request_name("xyz.openbmc_project.Ipmi.Host");
651
Patrick Venture0b02be92018-08-31 11:55:55 -0700652 cmdManager =
653 std::make_unique<phosphor::host::command::Manager>(*sdbusp, events);
Andrew Geissler93c679b2017-04-02 10:06:43 -0500654
Peter Hanson4a589852017-06-07 17:40:45 -0700655 // Activate OemRouter.
656 oem::mutableRouter()->activate();
657
Chris Austen30195fa2015-11-13 14:39:19 -0600658 // Register all the handlers that provider implementation to IPMI commands.
659 ipmi_register_callback_handlers(HOST_IPMI_LIB_PATH);
660
Patrick Venture0b02be92018-08-31 11:55:55 -0700661 // Watch for BT messages
vishwab9f559a2016-01-13 01:53:08 -0600662 r = sd_bus_add_match(bus, &ipmid_slot, FILTER, handle_ipmi_command, NULL);
Patrick Venture0b02be92018-08-31 11:55:55 -0700663 if (r < 0)
664 {
665 log<level::ERR>("Failed: sd_bus_add_match", entry("FILTER=%s", FILTER),
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530666 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500667 goto finish;
668 }
vishwabmcba0bd5f2015-09-30 16:50:23 +0530669
Andrew Geissler93c679b2017-04-02 10:06:43 -0500670 // Attach the bus to sd_event to service user requests
671 sd_bus_attach_event(bus, events, SD_EVENT_PRIORITY_NORMAL);
672
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500673 {
674 using namespace internal;
675 using namespace internal::cache;
676 sdbusplus::bus::bus dbus{bus};
677 objects = std::make_unique<settings::Objects>(
Patrick Venture0b02be92018-08-31 11:55:55 -0700678 dbus, std::vector<settings::Interface>({restrictionModeIntf}));
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500679 // Initialize restricted mode
680 cache_restricted_mode();
681 // Wait for changes on Restricted mode
682 sdbusplus::bus::match_t restrictedModeMatch(
683 dbus,
684 sdbusRule::propertiesChanged(
Deepak Kodihallie6027092017-08-27 08:13:37 -0500685 objects->map.at(restrictionModeIntf).front(),
686 restrictionModeIntf),
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500687 handle_restricted_mode_change);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530688
Patrick Venture0b02be92018-08-31 11:55:55 -0700689 for (;;)
690 {
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500691 /* Process requests */
692 r = sd_event_run(events, (uint64_t)-1);
693 if (r < 0)
694 {
695 log<level::ERR>("Failure in processing request",
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530696 entry("ERRNO=0x%X", -r));
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500697 goto finish;
698 }
Chris Austen0ba649e2015-10-13 12:28:13 -0500699 }
700 }
701
702finish:
Andrew Geissler93c679b2017-04-02 10:06:43 -0500703 sd_event_unref(events);
704 sd_bus_detach_event(bus);
vishwab9f559a2016-01-13 01:53:08 -0600705 sd_bus_slot_unref(ipmid_slot);
Chris Austen0ba649e2015-10-13 12:28:13 -0500706 sd_bus_unref(bus);
707 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530708}