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