blob: e5860d0c02ef9f392dc1b41a38816732215216a2 [file] [log] [blame]
Patrick Venture15e95f22018-11-14 19:25:08 -08001#include "config.h"
2
Patrick Venture0b02be92018-08-31 11:55:55 -07003#include "ipmid.hpp"
4
Patrick Venture46470a32018-09-07 19:26:25 -07005#include "host-cmd-manager.hpp"
6#include "ipmiwhitelist.hpp"
7#include "sensorhandler.hpp"
Patrick Venture0b02be92018-08-31 11:55:55 -07008#include "settings.hpp"
9
vishwabmcba0bd5f2015-09-30 16:50:23 +053010#include <assert.h>
11#include <dirent.h>
Patrick Venture0b02be92018-08-31 11:55:55 -070012#include <dlfcn.h>
13#include <errno.h>
Patrick Venture0b02be92018-08-31 11:55:55 -070014#include <sys/time.h>
15#include <systemd/sd-bus.h>
16#include <unistd.h>
17
18#include <algorithm>
Patrick Ventureb51bf9c2018-09-10 15:53:14 -070019#include <cstring>
Patrick Venture0b02be92018-08-31 11:55:55 -070020#include <iostream>
William A. Kennington III194375f2018-12-14 02:14:33 -080021#include <ipmid-host/cmd.hpp>
22#include <ipmid/oemrouter.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -070023#include <iterator>
vishwabmcba0bd5f2015-09-30 16:50:23 +053024#include <map>
Deepak Kodihalli84b3a082017-07-21 23:44:44 -050025#include <memory>
Andrew Geissler93c679b2017-04-02 10:06:43 -050026#include <phosphor-logging/log.hpp>
Deepak Kodihalli84b3a082017-07-21 23:44:44 -050027#include <sdbusplus/bus.hpp>
28#include <sdbusplus/bus/match.hpp>
William A. Kennington III4c008022018-10-12 17:18:14 -070029#include <sdbusplus/message/types.hpp>
Vernon Mauery1181af72018-10-08 12:05:00 -070030#include <sdbusplus/timer.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -070031#include <vector>
32#include <xyz/openbmc_project/Control/Security/RestrictionMode/server.hpp>
33
Andrew Geissler93c679b2017-04-02 10:06:43 -050034using namespace phosphor::logging;
Deepak Kodihalli84b3a082017-07-21 23:44:44 -050035namespace sdbusRule = sdbusplus::bus::match::rules;
William A. Kennington III4c008022018-10-12 17:18:14 -070036namespace variant_ns = sdbusplus::message::variant_ns;
Andrew Geissler93c679b2017-04-02 10:06:43 -050037
Patrick Venture0b02be92018-08-31 11:55:55 -070038sd_bus* bus = NULL;
39sd_bus_slot* ipmid_slot = NULL;
40sd_event* events = nullptr;
Chris Austen30195fa2015-11-13 14:39:19 -060041
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +053042// Need this to use new sdbusplus compatible interfaces
43sdbusPtr sdbusp;
44
45// Global Host Bound Command manager
46using cmdManagerPtr = std::unique_ptr<phosphor::host::command::Manager>;
47cmdManagerPtr cmdManager;
48
Ratan Gupta7a7f0122018-03-07 12:31:05 +053049// Global timer for network changes
Vernon Mauery1181af72018-10-08 12:05:00 -070050std::unique_ptr<phosphor::Timer> networkTimer = nullptr;
Ratan Gupta7a7f0122018-03-07 12:31:05 +053051
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +053052// Command and handler tuple. Used when clients ask the command to be put
53// into host message queue
54using CommandHandler = phosphor::host::command::CommandHandler;
55
Tom Joseph9a61b4f2016-07-11 06:56:11 -050056// Initialise restricted mode to true
57bool restricted_mode = true;
58
Chris Austen41a4b312015-10-25 03:45:42 -050059FILE *ipmiio, *ipmidbus, *ipmicmddetails;
vishwabmcba0bd5f2015-09-30 16:50:23 +053060
Patrick Venture0b02be92018-08-31 11:55:55 -070061void print_usage(void)
62{
Patrick Ventureb51bf9c2018-09-10 15:53:14 -070063 std::fprintf(stderr, "Options: [-d mask]\n");
64 std::fprintf(stderr, " mask : 0x01 - Print ipmi packets\n");
65 std::fprintf(stderr, " mask : 0x02 - Print DBUS operations\n");
66 std::fprintf(stderr, " mask : 0x04 - Print ipmi command details\n");
67 std::fprintf(stderr, " mask : 0xFF - Print all trace\n");
Chris Austen99497312015-10-22 13:00:16 -050068}
69
Patrick Venture0b02be92018-08-31 11:55:55 -070070const char* DBUS_INTF = "org.openbmc.HostIpmi";
vishwabmcba0bd5f2015-09-30 16:50:23 +053071
Patrick Venture0b02be92018-08-31 11:55:55 -070072const char* FILTER =
73 "type='signal',interface='org.openbmc.HostIpmi',member='ReceivedMessage'";
Chris Austen0ba649e2015-10-13 12:28:13 -050074
vishwabmcba0bd5f2015-09-30 16:50:23 +053075typedef std::pair<ipmi_netfn_t, ipmi_cmd_t> ipmi_fn_cmd_t;
76typedef std::pair<ipmid_callback_t, ipmi_context_t> ipmi_fn_context_t;
77
78// Global data structure that contains the IPMI command handler's registrations.
79std::map<ipmi_fn_cmd_t, ipmi_fn_context_t> g_ipmid_router_map;
80
Nan Li36c0cb62016-03-31 11:16:08 +080081// IPMI Spec, shared Reservation ID.
Jason M. Bills13e67c82018-09-10 14:12:16 -070082static unsigned short selReservationID = 0xFFFF;
83static bool selReservationValid = false;
Nan Li36c0cb62016-03-31 11:16:08 +080084
Jason M. Bills13e67c82018-09-10 14:12:16 -070085unsigned short reserveSel(void)
Nan Li36c0cb62016-03-31 11:16:08 +080086{
Jason M. Bills13e67c82018-09-10 14:12:16 -070087 // IPMI spec, Reservation ID, the value simply increases against each
88 // execution of the Reserve SEL command.
89 if (++selReservationID == 0)
90 {
91 selReservationID = 1;
92 }
93 selReservationValid = true;
94 return selReservationID;
95}
96
97bool checkSELReservation(unsigned short id)
98{
99 return (selReservationValid && selReservationID == id);
100}
101
102void cancelSELReservation(void)
103{
104 selReservationValid = false;
Nan Li36c0cb62016-03-31 11:16:08 +0800105}
Chris Austen0ba649e2015-10-13 12:28:13 -0500106
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500107namespace internal
108{
109
110constexpr auto restrictionModeIntf =
111 "xyz.openbmc_project.Control.Security.RestrictionMode";
112
113namespace cache
114{
115
116std::unique_ptr<settings::Objects> objects = nullptr;
117
118} // namespace cache
119} // namespace internal
120
Chris Austen0ba649e2015-10-13 12:28:13 -0500121#ifndef HEXDUMP_COLS
122#define HEXDUMP_COLS 16
123#endif
124
Patrick Venture0b02be92018-08-31 11:55:55 -0700125void hexdump(FILE* s, void* mem, size_t len)
Chris Austen0ba649e2015-10-13 12:28:13 -0500126{
Patrick Venture0b02be92018-08-31 11:55:55 -0700127 unsigned int i, j;
Chris Austen120f7322015-10-14 23:27:31 -0500128
Patrick Venture0b02be92018-08-31 11:55:55 -0700129 for (i = 0;
130 i <
131 len + ((len % HEXDUMP_COLS) ? (HEXDUMP_COLS - len % HEXDUMP_COLS) : 0);
132 i++)
133 {
134 /* print offset */
135 if (i % HEXDUMP_COLS == 0)
Chris Austen0ba649e2015-10-13 12:28:13 -0500136 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700137 std::fprintf(s, "0x%06x: ", i);
Chris Austen0ba649e2015-10-13 12:28:13 -0500138 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700139
140 /* print hex data */
141 if (i < len)
142 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700143 std::fprintf(s, "%02x ", 0xFF & ((char*)mem)[i]);
Patrick Venture0b02be92018-08-31 11:55:55 -0700144 }
145 else /* end of block, just aligning for ASCII dump */
146 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700147 std::fprintf(s, " ");
Patrick Venture0b02be92018-08-31 11:55:55 -0700148 }
149
150 /* print ASCII dump */
151 if (i % HEXDUMP_COLS == (HEXDUMP_COLS - 1))
152 {
153 for (j = i - (HEXDUMP_COLS - 1); j <= i; j++)
154 {
155 if (j >= len) /* end of block, not really printing */
156 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700157 std::fputc(' ', s);
Patrick Venture0b02be92018-08-31 11:55:55 -0700158 }
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700159 else if (std::isprint(((char*)mem)[j])) /* printable char */
Patrick Venture0b02be92018-08-31 11:55:55 -0700160 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700161 std::fputc(0xFF & ((char*)mem)[j], s);
Patrick Venture0b02be92018-08-31 11:55:55 -0700162 }
163 else /* other char */
164 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700165 std::fputc('.', s);
Patrick Venture0b02be92018-08-31 11:55:55 -0700166 }
167 }
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700168 std::fputc('\n', s);
Patrick Venture0b02be92018-08-31 11:55:55 -0700169 }
170 }
Chris Austen0ba649e2015-10-13 12:28:13 -0500171}
172
Patrick Venture0b02be92018-08-31 11:55:55 -0700173// Method that gets called by shared libraries to get their command handlers
174// registered
175void ipmi_register_callback(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
176 ipmi_context_t context, ipmid_callback_t handler,
177 ipmi_cmd_privilege_t priv)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530178{
179 // Pack NetFn and Command in one.
180 auto netfn_and_cmd = std::make_pair(netfn, cmd);
181
182 // Pack Function handler and Data in another.
183 auto handler_and_context = std::make_pair(handler, context);
184
185 // Check if the registration has already been made..
186 auto iter = g_ipmid_router_map.find(netfn_and_cmd);
Patrick Venture0b02be92018-08-31 11:55:55 -0700187 if (iter != g_ipmid_router_map.end())
vishwabmcba0bd5f2015-09-30 16:50:23 +0530188 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700189 log<level::ERR>("Duplicate registration", entry("NETFN=0x%X", netfn),
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530190 entry("CMD=0x%X", cmd));
vishwabmcba0bd5f2015-09-30 16:50:23 +0530191 }
192 else
193 {
194 // This is a fresh registration.. Add it to the map.
195 g_ipmid_router_map.emplace(netfn_and_cmd, handler_and_context);
196 }
197
198 return;
199}
200
201// Looks at the map and calls corresponding handler functions.
Patrick Venture0b02be92018-08-31 11:55:55 -0700202ipmi_ret_t ipmi_netfn_router(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
203 ipmi_request_t request, ipmi_response_t response,
204 ipmi_data_len_t data_len)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530205{
206 // return from the Command handlers.
207 ipmi_ret_t rc = IPMI_CC_INVALID;
208
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500209 // If restricted mode is true and command is not whitelisted, don't
210 // execute the command
Patrick Venture0b02be92018-08-31 11:55:55 -0700211 if (restricted_mode)
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500212 {
213 if (!std::binary_search(whitelist.cbegin(), whitelist.cend(),
Patrick Venture0b02be92018-08-31 11:55:55 -0700214 std::make_pair(netfn, cmd)))
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500215 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530216 log<level::ERR>("Net function not whitelisted",
Patrick Venture0b02be92018-08-31 11:55:55 -0700217 entry("NETFN=0x%X", netfn), entry("CMD=0x%X", cmd));
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500218 rc = IPMI_CC_INSUFFICIENT_PRIVILEGE;
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700219 std::memcpy(response, &rc, IPMI_CC_LEN);
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500220 *data_len = IPMI_CC_LEN;
221 return rc;
222 }
223 }
224
vishwabmcba0bd5f2015-09-30 16:50:23 +0530225 // Walk the map that has the registered handlers and invoke the approprite
226 // handlers for matching commands.
227 auto iter = g_ipmid_router_map.find(std::make_pair(netfn, cmd));
Patrick Venture0b02be92018-08-31 11:55:55 -0700228 if (iter == g_ipmid_router_map.end())
vishwabmcba0bd5f2015-09-30 16:50:23 +0530229 {
Patrick Venture03f84ba2017-09-20 09:15:33 -0700230 /* By default should only print on failure to find wildcard command. */
231#ifdef __IPMI_DEBUG__
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530232 log<level::ERR>(
Patrick Venture0b02be92018-08-31 11:55:55 -0700233 "No registered handlers for NetFn, trying Wilcard implementation",
234 entry("NET_FUN=0x%X", netfn) entry("CMD=0x%X", IPMI_CMD_WILDCARD));
Patrick Venture03f84ba2017-09-20 09:15:33 -0700235#endif
vishwabmcba0bd5f2015-09-30 16:50:23 +0530236
237 // Now that we did not find any specific [NetFn,Cmd], tuple, check for
238 // NetFn, WildCard command present.
Patrick Venture0b02be92018-08-31 11:55:55 -0700239 iter =
240 g_ipmid_router_map.find(std::make_pair(netfn, IPMI_CMD_WILDCARD));
241 if (iter == g_ipmid_router_map.end())
vishwabmcba0bd5f2015-09-30 16:50:23 +0530242 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530243 log<level::ERR>("No Registered handlers for NetFn",
244 entry("NET_FUN=0x%X", netfn),
245 entry("CMD=0x%X", IPMI_CMD_WILDCARD));
vishwabmcba0bd5f2015-09-30 16:50:23 +0530246
247 // Respond with a 0xC1
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700248 std::memcpy(response, &rc, IPMI_CC_LEN);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530249 *data_len = IPMI_CC_LEN;
250 return rc;
251 }
252 }
253
254#ifdef __IPMI_DEBUG__
255 // We have either a perfect match -OR- a wild card atleast,
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530256 log<level::ERR>("Calling Net function",
Patrick Venture0b02be92018-08-31 11:55:55 -0700257 entry("NET_FUN=0x%X", netfn) entry("CMD=0x%X", cmd));
vishwabmcba0bd5f2015-09-30 16:50:23 +0530258#endif
259
260 // Extract the map data onto appropriate containers
261 auto handler_and_context = iter->second;
262
263 // Creating a pointer type casted to char* to make sure we advance 1 byte
264 // when we advance pointer to next's address. advancing void * would not
265 // make sense.
Patrick Venture0b02be92018-08-31 11:55:55 -0700266 char* respo = &((char*)response)[IPMI_CC_LEN];
vishwabmcba0bd5f2015-09-30 16:50:23 +0530267
Richard Marian Thomaiyarebc886f2018-06-06 14:33:59 +0530268 try
269 {
270 // Response message from the plugin goes into a byte post the base
271 // response
Patrick Venture0b02be92018-08-31 11:55:55 -0700272 rc = (handler_and_context.first)(netfn, cmd, request, respo, data_len,
273 handler_and_context.second);
Richard Marian Thomaiyarebc886f2018-06-06 14:33:59 +0530274 }
275 // IPMI command handlers can throw unhandled exceptions, catch those
276 // and return sane error code.
Patrick Venture0b02be92018-08-31 11:55:55 -0700277 catch (const std::exception& e)
Richard Marian Thomaiyarebc886f2018-06-06 14:33:59 +0530278 {
279 log<level::ERR>(e.what(), entry("NET_FUN=0x%X", netfn),
280 entry("CMD=0x%X", cmd));
281 rc = IPMI_CC_UNSPECIFIED_ERROR;
282 *data_len = 0;
283 // fall through
284 }
vishwabmcba0bd5f2015-09-30 16:50:23 +0530285 // Now copy the return code that we got from handler and pack it in first
286 // byte.
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700287 std::memcpy(response, &rc, IPMI_CC_LEN);
Chris Austen120f7322015-10-14 23:27:31 -0500288
vishwabmcba0bd5f2015-09-30 16:50:23 +0530289 // Data length is now actual data + completion code.
290 *data_len = *data_len + IPMI_CC_LEN;
291
292 return rc;
293}
294
Patrick Venture0b02be92018-08-31 11:55:55 -0700295static int send_ipmi_message(sd_bus_message* req, unsigned char seq,
296 unsigned char netfn, unsigned char lun,
297 unsigned char cmd, unsigned char cc,
298 unsigned char* buf, unsigned char len)
299{
vishwabmcba0bd5f2015-09-30 16:50:23 +0530300
Chris Austen0ba649e2015-10-13 12:28:13 -0500301 sd_bus_error error = SD_BUS_ERROR_NULL;
Patrick Venture0b02be92018-08-31 11:55:55 -0700302 sd_bus_message *reply = NULL, *m = NULL;
Jeremy Kerre41081f2015-10-27 12:11:36 +0800303 const char *dest, *path;
Chris Austen0ba649e2015-10-13 12:28:13 -0500304 int r, pty;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530305
Jeremy Kerre41081f2015-10-27 12:11:36 +0800306 dest = sd_bus_message_get_sender(req);
307 path = sd_bus_message_get_path(req);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530308
Patrick Venture0b02be92018-08-31 11:55:55 -0700309 r = sd_bus_message_new_method_call(bus, &m, dest, path, DBUS_INTF,
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530310 "sendMessage");
Patrick Venture0b02be92018-08-31 11:55:55 -0700311 if (r < 0)
312 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530313 log<level::ERR>("Failed to add the method object",
314 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500315 return -1;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530316 }
317
Chris Austenabfb5e82015-10-13 12:29:24 -0500318 // Responses in IPMI require a bit set. So there ya go...
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800319 netfn |= 0x01;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530320
Chris Austen0ba649e2015-10-13 12:28:13 -0500321 // Add the bytes needed for the methods to be called
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800322 r = sd_bus_message_append(m, "yyyyy", seq, netfn, lun, cmd, cc);
Patrick Venture0b02be92018-08-31 11:55:55 -0700323 if (r < 0)
324 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530325 log<level::ERR>("Failed add the netfn and others",
326 entry("ERRNO=0x%X", -r));
Chris Austen169395e2015-12-02 20:56:15 -0600327 goto final;
Chris Austen0ba649e2015-10-13 12:28:13 -0500328 }
Chris Austen120f7322015-10-14 23:27:31 -0500329
Chris Austen0ba649e2015-10-13 12:28:13 -0500330 r = sd_bus_message_append_array(m, 'y', buf, len);
Patrick Venture0b02be92018-08-31 11:55:55 -0700331 if (r < 0)
332 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530333 log<level::ERR>("Failed to add the string of response bytes",
334 entry("ERRNO=0x%X", -r));
Chris Austen169395e2015-12-02 20:56:15 -0600335 goto final;
Chris Austen0ba649e2015-10-13 12:28:13 -0500336 }
337
Chris Austen0ba649e2015-10-13 12:28:13 -0500338 // Call the IPMI responder on the bus so the message can be sent to the CEC
339 r = sd_bus_call(bus, m, 0, &error, &reply);
Patrick Venture0b02be92018-08-31 11:55:55 -0700340 if (r < 0)
341 {
342 log<level::ERR>("Failed to call the method", entry("DEST=%s", dest),
343 entry("PATH=%s", path), entry("ERRNO=0x%X", -r));
Chris Austen169395e2015-12-02 20:56:15 -0600344 goto final;
Chris Austen0ba649e2015-10-13 12:28:13 -0500345 }
346
347 r = sd_bus_message_read(reply, "x", &pty);
Patrick Venture0b02be92018-08-31 11:55:55 -0700348 if (r < 0)
349 {
350 log<level::ERR>("Failed to get a reply from the method",
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530351 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500352 }
353
Chris Austen169395e2015-12-02 20:56:15 -0600354final:
Chris Austen0ba649e2015-10-13 12:28:13 -0500355 sd_bus_error_free(&error);
vishwa1eaea4f2016-02-26 11:57:40 -0600356 m = sd_bus_message_unref(m);
357 reply = sd_bus_message_unref(reply);
Chris Austen0ba649e2015-10-13 12:28:13 -0500358
Chris Austen0ba649e2015-10-13 12:28:13 -0500359 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
Chris Austen0ba649e2015-10-13 12:28:13 -0500360}
361
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500362void cache_restricted_mode()
363{
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500364 restricted_mode = false;
365 using namespace sdbusplus::xyz::openbmc_project::Control::Security::server;
366 using namespace internal;
367 using namespace internal::cache;
368 sdbusplus::bus::bus dbus(ipmid_get_sd_bus_connection());
369 const auto& restrictionModeSetting =
Deepak Kodihallie6027092017-08-27 08:13:37 -0500370 objects->map.at(restrictionModeIntf).front();
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500371 auto method = dbus.new_method_call(
Patrick Venture0b02be92018-08-31 11:55:55 -0700372 objects->service(restrictionModeSetting, restrictionModeIntf).c_str(),
373 restrictionModeSetting.c_str(), "org.freedesktop.DBus.Properties",
374 "Get");
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500375 method.append(restrictionModeIntf, "RestrictionMode");
376 auto resp = dbus.call(method);
377 if (resp.is_method_error())
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500378 {
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500379 log<level::ERR>("Error in RestrictionMode Get");
380 // Fail-safe to true.
381 restricted_mode = true;
382 return;
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500383 }
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500384 sdbusplus::message::variant<std::string> result;
385 resp.read(result);
William A. Kennington III4c008022018-10-12 17:18:14 -0700386 auto restrictionMode = RestrictionMode::convertModesFromString(
387 variant_ns::get<std::string>(result));
Patrick Venture0b02be92018-08-31 11:55:55 -0700388 if (RestrictionMode::Modes::Whitelist == restrictionMode)
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500389 {
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500390 restricted_mode = true;
391 }
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500392}
393
Patrick Venture0b02be92018-08-31 11:55:55 -0700394static int handle_restricted_mode_change(sd_bus_message* m, void* user_data,
395 sd_bus_error* ret_error)
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500396{
397 cache_restricted_mode();
398 return 0;
399}
400
Patrick Venture0b02be92018-08-31 11:55:55 -0700401static int handle_ipmi_command(sd_bus_message* m, void* user_data,
402 sd_bus_error* ret_error)
403{
Chris Austen0ba649e2015-10-13 12:28:13 -0500404 int r = 0;
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800405 unsigned char sequence, netfn, lun, cmd;
Patrick Venture0b02be92018-08-31 11:55:55 -0700406 const void* request;
Chris Austen0ba649e2015-10-13 12:28:13 -0500407 size_t sz;
Patrick Venture0b02be92018-08-31 11:55:55 -0700408 size_t resplen = MAX_IPMI_BUFFER;
Chris Austen0ba649e2015-10-13 12:28:13 -0500409 unsigned char response[MAX_IPMI_BUFFER];
410
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700411 std::memset(response, 0, MAX_IPMI_BUFFER);
Chris Austen0ba649e2015-10-13 12:28:13 -0500412
Patrick Venture0b02be92018-08-31 11:55:55 -0700413 r = sd_bus_message_read(m, "yyyy", &sequence, &netfn, &lun, &cmd);
414 if (r < 0)
415 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530416 log<level::ERR>("Failed to parse signal message",
417 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500418 return -1;
419 }
420
Patrick Venture0b02be92018-08-31 11:55:55 -0700421 r = sd_bus_message_read_array(m, 'y', &request, &sz);
422 if (r < 0)
423 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530424 log<level::ERR>("Failed to parse signal message",
425 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500426 return -1;
427 }
428
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700429 std::fprintf(ipmiio,
430 "IPMI Incoming: Seq 0x%02x, NetFn 0x%02x, CMD: 0x%02x \n",
431 sequence, netfn, cmd);
Chris Austen99497312015-10-22 13:00:16 -0500432 hexdump(ipmiio, (void*)request, sz);
Chris Austen0ba649e2015-10-13 12:28:13 -0500433
Chris Austen120f7322015-10-14 23:27:31 -0500434 // Allow the length field to be used for both input and output of the
Chris Austen0ba649e2015-10-13 12:28:13 -0500435 // ipmi call
436 resplen = sz;
437
Chris Austen120f7322015-10-14 23:27:31 -0500438 // Now that we have parsed the entire byte array from the caller
vishwabmcba0bd5f2015-09-30 16:50:23 +0530439 // we can call the ipmi router to do the work...
Patrick Venture0b02be92018-08-31 11:55:55 -0700440 r = ipmi_netfn_router(netfn, cmd, (void*)request, (void*)response,
441 &resplen);
442 if (r != 0)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530443 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530444#ifdef __IPMI_DEBUG__
Patrick Venture0b02be92018-08-31 11:55:55 -0700445 log<level::ERR>("ERROR in handling NetFn", entry("ERRNO=0x%X", -r),
446 entry("NET_FUN=0x%X", netfn), entry("CMD=0x%X", cmd));
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530447#endif
Ratan Guptae0cc8552018-01-22 14:23:04 +0530448 resplen = 0;
449 }
450 else
451 {
452 resplen = resplen - 1; // first byte is for return code.
vishwabmcba0bd5f2015-09-30 16:50:23 +0530453 }
454
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700455 std::fprintf(ipmiio, "IPMI Response:\n");
Patrick Venture0b02be92018-08-31 11:55:55 -0700456 hexdump(ipmiio, (void*)response, resplen);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530457
Chris Austen0ba649e2015-10-13 12:28:13 -0500458 // Send the response buffer from the ipmi command
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800459 r = send_ipmi_message(m, sequence, netfn, lun, cmd, response[0],
Patrick Venture0b02be92018-08-31 11:55:55 -0700460 ((unsigned char*)response) + 1, resplen);
461 if (r < 0)
462 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530463 log<level::ERR>("Failed to send the response message");
Chris Austen0ba649e2015-10-13 12:28:13 -0500464 return -1;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530465 }
466
Chris Austen0ba649e2015-10-13 12:28:13 -0500467 return 0;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530468}
469
470//----------------------------------------------------------------------
471// handler_select
472// Select all the files ending with with .so. in the given diretcory
473// @d: dirent structure containing the file name
474//----------------------------------------------------------------------
Patrick Venture0b02be92018-08-31 11:55:55 -0700475int handler_select(const struct dirent* entry)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530476{
477 // To hold ".so" from entry->d_name;
478 char dname_copy[4] = {0};
479
480 // We want to avoid checking for everything and isolate to the ones having
Adriana Kobylak87e080b2016-07-10 13:16:53 -0500481 // .so.* or .so in them.
482 // Check for versioned libraries .so.*
Patrick Venture0b02be92018-08-31 11:55:55 -0700483 if (strstr(entry->d_name, IPMI_PLUGIN_SONAME_EXTN))
Adriana Kobylak87e080b2016-07-10 13:16:53 -0500484 {
485 return 1;
486 }
487 // Check for non versioned libraries .so
Patrick Venture0b02be92018-08-31 11:55:55 -0700488 else if (strstr(entry->d_name, IPMI_PLUGIN_EXTN))
vishwabmcba0bd5f2015-09-30 16:50:23 +0530489 {
490 // It is possible that .so could be anywhere in the string but unlikely
Chris Austen120f7322015-10-14 23:27:31 -0500491 // But being careful here. Get the base address of the string, move
vishwabmcba0bd5f2015-09-30 16:50:23 +0530492 // until end and come back 3 steps and that gets what we need.
Patrick Venture0b02be92018-08-31 11:55:55 -0700493 strcpy(dname_copy, (entry->d_name + strlen(entry->d_name) -
494 strlen(IPMI_PLUGIN_EXTN)));
495 if (strcmp(dname_copy, IPMI_PLUGIN_EXTN) == 0)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530496 {
497 return 1;
498 }
499 }
500 return 0;
501}
502
Patrick Venture0b02be92018-08-31 11:55:55 -0700503// This will do a dlopen of every .so in ipmi_lib_path and will dlopen
504// everything so that they will register a callback handler
vishwabmcba0bd5f2015-09-30 16:50:23 +0530505void ipmi_register_callback_handlers(const char* ipmi_lib_path)
506{
507 // For walking the ipmi_lib_path
Patrick Venture0b02be92018-08-31 11:55:55 -0700508 struct dirent** handler_list;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530509
510 // This is used to check and abort if someone tries to register a bad one.
Patrick Venture0b02be92018-08-31 11:55:55 -0700511 void* lib_handler = NULL;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530512
Patrick Venture0b02be92018-08-31 11:55:55 -0700513 if (ipmi_lib_path == NULL)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530514 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530515 log<level::ERR>("No handlers to be registered for ipmi.. Aborting");
vishwabmcba0bd5f2015-09-30 16:50:23 +0530516 assert(0);
517 }
518 else
519 {
520 // 1: Open ipmi_lib_path. Its usually "/usr/lib/phosphor-host-ipmid"
521 // 2: Scan the directory for the files that end with .so
Chris Austen120f7322015-10-14 23:27:31 -0500522 // 3: For each one of them, just do a 'dlopen' so that they register
vishwabmcba0bd5f2015-09-30 16:50:23 +0530523 // the handlers for callback routines.
524
525 std::string handler_fqdn = ipmi_lib_path;
Chris Austen120f7322015-10-14 23:27:31 -0500526
vishwabmcba0bd5f2015-09-30 16:50:23 +0530527 // Append a "/" since we need to add the name of the .so. If there is
528 // already a .so, adding one more is not any harm.
529 handler_fqdn += "/";
530
Patrick Venture4491a462018-10-13 13:00:42 -0700531 int num_handlers =
Patrick Venture0b02be92018-08-31 11:55:55 -0700532 scandir(ipmi_lib_path, &handler_list, handler_select, alphasort);
Nan Li36c0cb62016-03-31 11:16:08 +0800533 if (num_handlers < 0)
534 return;
Jeremy Kerr5e8f85e2015-10-27 13:43:54 +0800535
Patrick Venture0b02be92018-08-31 11:55:55 -0700536 while (num_handlers--)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530537 {
Chris Austen54030262015-10-13 12:30:46 -0500538 handler_fqdn = ipmi_lib_path;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530539 handler_fqdn += handler_list[num_handlers]->d_name;
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530540#ifdef __IPMI_DEBUG__
541 log<level::DEBUG>("Registering handler",
542 entry("HANDLER=%s", handler_fqdn.c_str()));
543#endif
Chris Austen54030262015-10-13 12:30:46 -0500544
vishwabmcba0bd5f2015-09-30 16:50:23 +0530545 lib_handler = dlopen(handler_fqdn.c_str(), RTLD_NOW);
Nan Li36c0cb62016-03-31 11:16:08 +0800546
Patrick Venture0b02be92018-08-31 11:55:55 -0700547 if (lib_handler == NULL)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530548 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530549 log<level::ERR>("ERROR opening",
550 entry("HANDLER=%s", handler_fqdn.c_str()),
551 entry("ERROR=%s", dlerror()));
vishwabmcba0bd5f2015-09-30 16:50:23 +0530552 }
553 // Wipe the memory allocated for this particular entry.
554 free(handler_list[num_handlers]);
555 }
Nan Li36c0cb62016-03-31 11:16:08 +0800556
vishwabmcba0bd5f2015-09-30 16:50:23 +0530557 // Done with all registration.
558 free(handler_list);
559 }
560
561 // TODO : What to be done on the memory that is given by dlopen ?.
562 return;
563}
564
Patrick Venture0b02be92018-08-31 11:55:55 -0700565sd_bus* ipmid_get_sd_bus_connection(void)
566{
Chris Austen30195fa2015-11-13 14:39:19 -0600567 return bus;
568}
569
Patrick Venture0b02be92018-08-31 11:55:55 -0700570sd_event* ipmid_get_sd_event_connection(void)
571{
Andrew Geissler93c679b2017-04-02 10:06:43 -0500572 return events;
573}
574
Patrick Venture0b02be92018-08-31 11:55:55 -0700575sd_bus_slot* ipmid_get_sd_bus_slot(void)
576{
vishwab9f559a2016-01-13 01:53:08 -0600577 return ipmid_slot;
578}
579
ssekarb8491102018-08-16 17:31:43 +0530580EInterfaceIndex getInterfaceIndex(void)
581{
582 return interfaceKCS;
583}
584
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530585// Calls host command manager to do the right thing for the command
Patrick Venture0b02be92018-08-31 11:55:55 -0700586void ipmid_send_cmd_to_host(CommandHandler&& cmd)
587{
588 return cmdManager->execute(std::move(cmd));
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530589}
590
Patrick Venture0b02be92018-08-31 11:55:55 -0700591cmdManagerPtr& ipmid_get_host_cmd_manager()
592{
593 return cmdManager;
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530594}
595
Patrick Venture0b02be92018-08-31 11:55:55 -0700596sdbusPtr& ipmid_get_sdbus_plus_handler()
597{
598 return sdbusp;
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530599}
600
Patrick Venture0b02be92018-08-31 11:55:55 -0700601int main(int argc, char* argv[])
vishwabmcba0bd5f2015-09-30 16:50:23 +0530602{
Chris Austen0ba649e2015-10-13 12:28:13 -0500603 int r;
Chris Austen99497312015-10-22 13:00:16 -0500604 unsigned long tvalue;
605 int c;
606
Chris Austen99497312015-10-22 13:00:16 -0500607 // This file and subsequient switch is for turning on levels
608 // of trace
Patrick Venture0b02be92018-08-31 11:55:55 -0700609 ipmicmddetails = ipmiio = ipmidbus = fopen("/dev/null", "w");
Chris Austen99497312015-10-22 13:00:16 -0500610
Patrick Venture0b02be92018-08-31 11:55:55 -0700611 while ((c = getopt(argc, argv, "h:d:")) != -1)
612 switch (c)
613 {
Chris Austen99497312015-10-22 13:00:16 -0500614 case 'd':
Patrick Venture0b02be92018-08-31 11:55:55 -0700615 tvalue = strtoul(optarg, NULL, 16);
616 if (1 & tvalue)
617 {
Chris Austen99497312015-10-22 13:00:16 -0500618 ipmiio = stdout;
619 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700620 if (2 & tvalue)
621 {
Chris Austen99497312015-10-22 13:00:16 -0500622 ipmidbus = stdout;
623 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700624 if (4 & tvalue)
625 {
Chris Austen99497312015-10-22 13:00:16 -0500626 ipmicmddetails = stdout;
627 }
628 break;
Patrick Venture0b02be92018-08-31 11:55:55 -0700629 case 'h':
630 case '?':
Chris Austen99497312015-10-22 13:00:16 -0500631 print_usage();
632 return 1;
633 }
Chris Austen0ba649e2015-10-13 12:28:13 -0500634
Chris Austen0ba649e2015-10-13 12:28:13 -0500635 /* Connect to system bus */
Vernon Mauery46590a32018-11-08 15:29:56 -0800636 r = sd_bus_default_system(&bus);
Patrick Venture0b02be92018-08-31 11:55:55 -0700637 if (r < 0)
638 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530639 log<level::ERR>("Failed to connect to system bus",
640 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500641 goto finish;
642 }
vishwabmcba0bd5f2015-09-30 16:50:23 +0530643
Andrew Geissler93c679b2017-04-02 10:06:43 -0500644 /* Get an sd event handler */
645 r = sd_event_default(&events);
646 if (r < 0)
647 {
648 log<level::ERR>("Failure to create sd_event handler",
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530649 entry("ERRNO=0x%X", -r));
Andrew Geissler93c679b2017-04-02 10:06:43 -0500650 goto finish;
651 }
652
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530653 // Now create the Host Bound Command manager. Need sdbusplus
654 // to use the generated bindings
655 sdbusp = std::make_unique<sdbusplus::bus::bus>(bus);
James Feist331f5d52018-11-01 11:03:40 -0700656 sdbusp->request_name("xyz.openbmc_project.Ipmi.Host");
657
Vernon Mauery316f23d2018-10-29 13:34:26 -0700658 cmdManager = std::make_unique<phosphor::host::command::Manager>(*sdbusp);
Andrew Geissler93c679b2017-04-02 10:06:43 -0500659
Peter Hanson4a589852017-06-07 17:40:45 -0700660 // Activate OemRouter.
661 oem::mutableRouter()->activate();
662
Chris Austen30195fa2015-11-13 14:39:19 -0600663 // Register all the handlers that provider implementation to IPMI commands.
664 ipmi_register_callback_handlers(HOST_IPMI_LIB_PATH);
665
Patrick Venture0b02be92018-08-31 11:55:55 -0700666 // Watch for BT messages
vishwab9f559a2016-01-13 01:53:08 -0600667 r = sd_bus_add_match(bus, &ipmid_slot, FILTER, handle_ipmi_command, NULL);
Patrick Venture0b02be92018-08-31 11:55:55 -0700668 if (r < 0)
669 {
670 log<level::ERR>("Failed: sd_bus_add_match", entry("FILTER=%s", FILTER),
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530671 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500672 goto finish;
673 }
vishwabmcba0bd5f2015-09-30 16:50:23 +0530674
Andrew Geissler93c679b2017-04-02 10:06:43 -0500675 // Attach the bus to sd_event to service user requests
676 sd_bus_attach_event(bus, events, SD_EVENT_PRIORITY_NORMAL);
677
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500678 {
679 using namespace internal;
680 using namespace internal::cache;
681 sdbusplus::bus::bus dbus{bus};
682 objects = std::make_unique<settings::Objects>(
Patrick Venture0b02be92018-08-31 11:55:55 -0700683 dbus, std::vector<settings::Interface>({restrictionModeIntf}));
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500684 // Initialize restricted mode
685 cache_restricted_mode();
686 // Wait for changes on Restricted mode
687 sdbusplus::bus::match_t restrictedModeMatch(
688 dbus,
689 sdbusRule::propertiesChanged(
Deepak Kodihallie6027092017-08-27 08:13:37 -0500690 objects->map.at(restrictionModeIntf).front(),
691 restrictionModeIntf),
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500692 handle_restricted_mode_change);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530693
Andrew Jefferyb975c402018-11-23 15:28:58 +1100694 r = sd_event_loop(events);
Chris Austen0ba649e2015-10-13 12:28:13 -0500695 }
696
697finish:
Andrew Geissler93c679b2017-04-02 10:06:43 -0500698 sd_event_unref(events);
699 sd_bus_detach_event(bus);
vishwab9f559a2016-01-13 01:53:08 -0600700 sd_bus_slot_unref(ipmid_slot);
Chris Austen0ba649e2015-10-13 12:28:13 -0500701 sd_bus_unref(bus);
702 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530703}