1*a3702c1fSVernon Mauery /* 2*a3702c1fSVernon Mauery // Copyright (c) 2018 Intel Corporation 3*a3702c1fSVernon Mauery // 4*a3702c1fSVernon Mauery // Licensed under the Apache License, Version 2.0 (the "License"); 5*a3702c1fSVernon Mauery // you may not use this file except in compliance with the License. 6*a3702c1fSVernon Mauery // You may obtain a copy of the License at 7*a3702c1fSVernon Mauery // 8*a3702c1fSVernon Mauery // http://www.apache.org/licenses/LICENSE-2.0 9*a3702c1fSVernon Mauery // 10*a3702c1fSVernon Mauery // Unless required by applicable law or agreed to in writing, software 11*a3702c1fSVernon Mauery // distributed under the License is distributed on an "AS IS" BASIS, 12*a3702c1fSVernon Mauery // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*a3702c1fSVernon Mauery // See the License for the specific language governing permissions and 14*a3702c1fSVernon Mauery // limitations under the License. 15*a3702c1fSVernon Mauery */ 16*a3702c1fSVernon Mauery 17*a3702c1fSVernon Mauery #include "oemcommands.hpp" 18*a3702c1fSVernon Mauery 19*a3702c1fSVernon Mauery #include <openssl/hmac.h> 20*a3702c1fSVernon Mauery 21*a3702c1fSVernon Mauery #include <ipmid/api.hpp> 22*a3702c1fSVernon Mauery #include <ipmid/utils.hpp> 23*a3702c1fSVernon Mauery #include <phosphor-logging/log.hpp> 24*a3702c1fSVernon Mauery #include <sdbusplus/bus.hpp> 25*a3702c1fSVernon Mauery 26*a3702c1fSVernon Mauery void register_netfn_bmc_control_functions() __attribute__((constructor)); 27*a3702c1fSVernon Mauery 28*a3702c1fSVernon Mauery enum ipmi_bmc_control_services_return_codes 29*a3702c1fSVernon Mauery { 30*a3702c1fSVernon Mauery ipmiCCBmcControlInvalidBitMask = 0xCC, 31*a3702c1fSVernon Mauery ipmiCCBmcControlPasswdInvalid = 0xCD, 32*a3702c1fSVernon Mauery ipmiCCBmcControlInvalidChannel = 0xD4, 33*a3702c1fSVernon Mauery }; 34*a3702c1fSVernon Mauery 35*a3702c1fSVernon Mauery // TODO: Add other services, once they are supported 36*a3702c1fSVernon Mauery static const std::unordered_map<uint8_t, std::string> bmcServices = { 37*a3702c1fSVernon Mauery {3, "netipmid"}, 38*a3702c1fSVernon Mauery {5, "web"}, 39*a3702c1fSVernon Mauery {6, "ssh"}, 40*a3702c1fSVernon Mauery }; 41*a3702c1fSVernon Mauery 42*a3702c1fSVernon Mauery static constexpr const char* objectManagerIntf = 43*a3702c1fSVernon Mauery "org.freedesktop.DBus.ObjectManager"; 44*a3702c1fSVernon Mauery static constexpr const char* serviceConfigBasePath = 45*a3702c1fSVernon Mauery "/xyz/openbmc_project/control/service"; 46*a3702c1fSVernon Mauery static constexpr const char* serviceConfigAttrIntf = 47*a3702c1fSVernon Mauery "xyz.openbmc_project.Control.Service.Attributes"; 48*a3702c1fSVernon Mauery static constexpr const char* serviceStateProperty = "State"; 49*a3702c1fSVernon Mauery static std::string disableServiceValue = "disabled"; 50*a3702c1fSVernon Mauery 51*a3702c1fSVernon Mauery static ipmi_ret_t disableBmcServices(const std::string& objName) 52*a3702c1fSVernon Mauery { 53*a3702c1fSVernon Mauery std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 54*a3702c1fSVernon Mauery static std::string serviceCfgMgr{}; 55*a3702c1fSVernon Mauery if (serviceCfgMgr.empty()) 56*a3702c1fSVernon Mauery { 57*a3702c1fSVernon Mauery try 58*a3702c1fSVernon Mauery { 59*a3702c1fSVernon Mauery serviceCfgMgr = ipmi::getService(*dbus, objectManagerIntf, 60*a3702c1fSVernon Mauery serviceConfigBasePath); 61*a3702c1fSVernon Mauery } 62*a3702c1fSVernon Mauery catch (const sdbusplus::exception::SdBusError& e) 63*a3702c1fSVernon Mauery { 64*a3702c1fSVernon Mauery serviceCfgMgr.clear(); 65*a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::ERR>( 66*a3702c1fSVernon Mauery "Error: In fetching disabling service manager name"); 67*a3702c1fSVernon Mauery return IPMI_CC_UNSPECIFIED_ERROR; 68*a3702c1fSVernon Mauery } 69*a3702c1fSVernon Mauery } 70*a3702c1fSVernon Mauery auto path = std::string(serviceConfigBasePath) + "/" + objName; 71*a3702c1fSVernon Mauery try 72*a3702c1fSVernon Mauery { 73*a3702c1fSVernon Mauery ipmi::setDbusProperty(*dbus, serviceCfgMgr, path, serviceConfigAttrIntf, 74*a3702c1fSVernon Mauery serviceStateProperty, 75*a3702c1fSVernon Mauery ipmi::Value(disableServiceValue)); 76*a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::INFO>( 77*a3702c1fSVernon Mauery "Disabling service", 78*a3702c1fSVernon Mauery phosphor::logging::entry("PATH=%s", path.c_str()), 79*a3702c1fSVernon Mauery phosphor::logging::entry("MGR_NAME=%s", serviceCfgMgr.c_str())); 80*a3702c1fSVernon Mauery return IPMI_CC_OK; 81*a3702c1fSVernon Mauery } 82*a3702c1fSVernon Mauery catch (const sdbusplus::exception_t&) 83*a3702c1fSVernon Mauery { 84*a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::ERR>( 85*a3702c1fSVernon Mauery "Error: Disabling service", 86*a3702c1fSVernon Mauery phosphor::logging::entry("PATH=%s", path.c_str()), 87*a3702c1fSVernon Mauery phosphor::logging::entry("MGR_NAME=%s", serviceCfgMgr.c_str())); 88*a3702c1fSVernon Mauery return IPMI_CC_UNSPECIFIED_ERROR; 89*a3702c1fSVernon Mauery } 90*a3702c1fSVernon Mauery } 91*a3702c1fSVernon Mauery 92*a3702c1fSVernon Mauery static constexpr size_t controlPasswdSize = 32; 93*a3702c1fSVernon Mauery 94*a3702c1fSVernon Mauery ipmi::RspType<> bmcIntelControlServices( 95*a3702c1fSVernon Mauery ipmi::Context::ptr ctx, 96*a3702c1fSVernon Mauery const std::array<uint8_t, controlPasswdSize>& passwd, uint8_t stdServices, 97*a3702c1fSVernon Mauery uint8_t oemServices) 98*a3702c1fSVernon Mauery { 99*a3702c1fSVernon Mauery // Execute this command only in KCS interface 100*a3702c1fSVernon Mauery if (ctx->channel != interfaceKCS) 101*a3702c1fSVernon Mauery { 102*a3702c1fSVernon Mauery return ipmi::response(ipmiCCBmcControlInvalidChannel); 103*a3702c1fSVernon Mauery } 104*a3702c1fSVernon Mauery 105*a3702c1fSVernon Mauery static std::string hashData("Intel 0penBMC"); 106*a3702c1fSVernon Mauery static std::vector<uint8_t> hashedValue = { 107*a3702c1fSVernon Mauery 0x89, 0x6A, 0xAB, 0x7D, 0xB0, 0x5A, 0x2D, 0x92, 0x41, 0xAD, 0x92, 108*a3702c1fSVernon Mauery 0xEE, 0xD4, 0x82, 0xDE, 0x62, 0x66, 0x16, 0xC1, 0x08, 0xFD, 0x23, 109*a3702c1fSVernon Mauery 0xC6, 0xD8, 0x75, 0xB3, 0x52, 0x53, 0x31, 0x3C, 0x7F, 0x69}; 110*a3702c1fSVernon Mauery std::vector<uint8_t> hashedOutput(EVP_MAX_MD_SIZE, 0); 111*a3702c1fSVernon Mauery unsigned int outputLen = 0; 112*a3702c1fSVernon Mauery HMAC(EVP_sha256(), passwd.data(), passwd.size(), 113*a3702c1fSVernon Mauery reinterpret_cast<const uint8_t*>(hashData.c_str()), hashData.length(), 114*a3702c1fSVernon Mauery &hashedOutput[0], &outputLen); 115*a3702c1fSVernon Mauery hashedOutput.resize(outputLen); 116*a3702c1fSVernon Mauery 117*a3702c1fSVernon Mauery if (hashedOutput != hashedValue) 118*a3702c1fSVernon Mauery { 119*a3702c1fSVernon Mauery return ipmi::response(ipmiCCBmcControlPasswdInvalid); 120*a3702c1fSVernon Mauery } 121*a3702c1fSVernon Mauery 122*a3702c1fSVernon Mauery if (stdServices == 0 && oemServices == 0) 123*a3702c1fSVernon Mauery { 124*a3702c1fSVernon Mauery return ipmi::response(ipmiCCBmcControlInvalidBitMask); 125*a3702c1fSVernon Mauery } 126*a3702c1fSVernon Mauery 127*a3702c1fSVernon Mauery ipmi_ret_t retVal = IPMI_CC_OK; 128*a3702c1fSVernon Mauery for (size_t bitIndex = 0; bitIndex < 8; ++bitIndex) 129*a3702c1fSVernon Mauery { 130*a3702c1fSVernon Mauery if (stdServices & (1 << bitIndex)) 131*a3702c1fSVernon Mauery { 132*a3702c1fSVernon Mauery auto it = bmcServices.find(bitIndex); 133*a3702c1fSVernon Mauery if (it == bmcServices.end()) 134*a3702c1fSVernon Mauery { 135*a3702c1fSVernon Mauery return ipmi::response(ipmiCCBmcControlInvalidBitMask); 136*a3702c1fSVernon Mauery } 137*a3702c1fSVernon Mauery retVal = disableBmcServices(it->second); 138*a3702c1fSVernon Mauery if (retVal != IPMI_CC_OK) 139*a3702c1fSVernon Mauery { 140*a3702c1fSVernon Mauery return ipmi::response(retVal); 141*a3702c1fSVernon Mauery } 142*a3702c1fSVernon Mauery } 143*a3702c1fSVernon Mauery } 144*a3702c1fSVernon Mauery return ipmi::responseSuccess(); 145*a3702c1fSVernon Mauery } 146*a3702c1fSVernon Mauery 147*a3702c1fSVernon Mauery void register_netfn_bmc_control_functions() 148*a3702c1fSVernon Mauery { 149*a3702c1fSVernon Mauery ipmi::registerHandler(ipmi::prioOpenBmcBase, netfnIntcOEMGeneral, 150*a3702c1fSVernon Mauery static_cast<ipmi_cmd_t>( 151*a3702c1fSVernon Mauery IPMINetFnIntelOemGeneralCmds::BmcControlServices), 152*a3702c1fSVernon Mauery ipmi::Privilege::User, bmcIntelControlServices); 153*a3702c1fSVernon Mauery } 154