Move commands from ipmi-providers
Many commands were in ipmi-providers and need to be moved into the
active development library (intel-ipmi-oem). This copies wholesale
those commands, even though many need to be rewritten to use the new
ipmi providers API.
Tested-by: build and see that the commands are still present even when
the ipmi-providers library is removed
Change-Id: If326f5d7844adeed7da2d3b7a2f1d3eeeea43b29
Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com>
diff --git a/src/bmccontrolservices.cpp b/src/bmccontrolservices.cpp
new file mode 100644
index 0000000..2bebab5
--- /dev/null
+++ b/src/bmccontrolservices.cpp
@@ -0,0 +1,153 @@
+/*
+// Copyright (c) 2018 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include "oemcommands.hpp"
+
+#include <openssl/hmac.h>
+
+#include <ipmid/api.hpp>
+#include <ipmid/utils.hpp>
+#include <phosphor-logging/log.hpp>
+#include <sdbusplus/bus.hpp>
+
+void register_netfn_bmc_control_functions() __attribute__((constructor));
+
+enum ipmi_bmc_control_services_return_codes
+{
+ ipmiCCBmcControlInvalidBitMask = 0xCC,
+ ipmiCCBmcControlPasswdInvalid = 0xCD,
+ ipmiCCBmcControlInvalidChannel = 0xD4,
+};
+
+// TODO: Add other services, once they are supported
+static const std::unordered_map<uint8_t, std::string> bmcServices = {
+ {3, "netipmid"},
+ {5, "web"},
+ {6, "ssh"},
+};
+
+static constexpr const char* objectManagerIntf =
+ "org.freedesktop.DBus.ObjectManager";
+static constexpr const char* serviceConfigBasePath =
+ "/xyz/openbmc_project/control/service";
+static constexpr const char* serviceConfigAttrIntf =
+ "xyz.openbmc_project.Control.Service.Attributes";
+static constexpr const char* serviceStateProperty = "State";
+static std::string disableServiceValue = "disabled";
+
+static ipmi_ret_t disableBmcServices(const std::string& objName)
+{
+ std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
+ static std::string serviceCfgMgr{};
+ if (serviceCfgMgr.empty())
+ {
+ try
+ {
+ serviceCfgMgr = ipmi::getService(*dbus, objectManagerIntf,
+ serviceConfigBasePath);
+ }
+ catch (const sdbusplus::exception::SdBusError& e)
+ {
+ serviceCfgMgr.clear();
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Error: In fetching disabling service manager name");
+ return IPMI_CC_UNSPECIFIED_ERROR;
+ }
+ }
+ auto path = std::string(serviceConfigBasePath) + "/" + objName;
+ try
+ {
+ ipmi::setDbusProperty(*dbus, serviceCfgMgr, path, serviceConfigAttrIntf,
+ serviceStateProperty,
+ ipmi::Value(disableServiceValue));
+ phosphor::logging::log<phosphor::logging::level::INFO>(
+ "Disabling service",
+ phosphor::logging::entry("PATH=%s", path.c_str()),
+ phosphor::logging::entry("MGR_NAME=%s", serviceCfgMgr.c_str()));
+ return IPMI_CC_OK;
+ }
+ catch (const sdbusplus::exception_t&)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Error: Disabling service",
+ phosphor::logging::entry("PATH=%s", path.c_str()),
+ phosphor::logging::entry("MGR_NAME=%s", serviceCfgMgr.c_str()));
+ return IPMI_CC_UNSPECIFIED_ERROR;
+ }
+}
+
+static constexpr size_t controlPasswdSize = 32;
+
+ipmi::RspType<> bmcIntelControlServices(
+ ipmi::Context::ptr ctx,
+ const std::array<uint8_t, controlPasswdSize>& passwd, uint8_t stdServices,
+ uint8_t oemServices)
+{
+ // Execute this command only in KCS interface
+ if (ctx->channel != interfaceKCS)
+ {
+ return ipmi::response(ipmiCCBmcControlInvalidChannel);
+ }
+
+ static std::string hashData("Intel 0penBMC");
+ static std::vector<uint8_t> hashedValue = {
+ 0x89, 0x6A, 0xAB, 0x7D, 0xB0, 0x5A, 0x2D, 0x92, 0x41, 0xAD, 0x92,
+ 0xEE, 0xD4, 0x82, 0xDE, 0x62, 0x66, 0x16, 0xC1, 0x08, 0xFD, 0x23,
+ 0xC6, 0xD8, 0x75, 0xB3, 0x52, 0x53, 0x31, 0x3C, 0x7F, 0x69};
+ std::vector<uint8_t> hashedOutput(EVP_MAX_MD_SIZE, 0);
+ unsigned int outputLen = 0;
+ HMAC(EVP_sha256(), passwd.data(), passwd.size(),
+ reinterpret_cast<const uint8_t*>(hashData.c_str()), hashData.length(),
+ &hashedOutput[0], &outputLen);
+ hashedOutput.resize(outputLen);
+
+ if (hashedOutput != hashedValue)
+ {
+ return ipmi::response(ipmiCCBmcControlPasswdInvalid);
+ }
+
+ if (stdServices == 0 && oemServices == 0)
+ {
+ return ipmi::response(ipmiCCBmcControlInvalidBitMask);
+ }
+
+ ipmi_ret_t retVal = IPMI_CC_OK;
+ for (size_t bitIndex = 0; bitIndex < 8; ++bitIndex)
+ {
+ if (stdServices & (1 << bitIndex))
+ {
+ auto it = bmcServices.find(bitIndex);
+ if (it == bmcServices.end())
+ {
+ return ipmi::response(ipmiCCBmcControlInvalidBitMask);
+ }
+ retVal = disableBmcServices(it->second);
+ if (retVal != IPMI_CC_OK)
+ {
+ return ipmi::response(retVal);
+ }
+ }
+ }
+ return ipmi::responseSuccess();
+}
+
+void register_netfn_bmc_control_functions()
+{
+ ipmi::registerHandler(ipmi::prioOpenBmcBase, netfnIntcOEMGeneral,
+ static_cast<ipmi_cmd_t>(
+ IPMINetFnIntelOemGeneralCmds::BmcControlServices),
+ ipmi::Privilege::User, bmcIntelControlServices);
+}