blob: 5f50c8682270caa3026d3e5c1f9c0ecc62a5bee1 [file] [log] [blame]
Sumanth Bhate4e633e2019-05-14 12:13:57 +00001/*
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#include "cipher_mgmt.hpp"
17
18#include <fcntl.h>
19#include <sys/stat.h>
20#include <sys/types.h>
21#include <unistd.h>
22
23#include <filesystem>
24#include <fstream>
Sumanth Bhate4e633e2019-05-14 12:13:57 +000025#include <phosphor-logging/log.hpp>
26
27namespace ipmi
28{
29
30using namespace phosphor::logging;
31using Json = nlohmann::json;
32namespace fs = std::filesystem;
33
34CipherConfig& getCipherConfigObject(const std::string& csFileName,
35 const std::string& csDefaultFileName)
36{
37 static CipherConfig cipherConfig(csFileName, csDefaultFileName);
38 return cipherConfig;
39}
40
41CipherConfig::CipherConfig(const std::string& csFileName,
42 const std::string& csDefaultFileName) :
43 cipherSuitePrivFileName(csFileName),
44 cipherSuiteDefaultPrivFileName(csDefaultFileName)
45{
46 loadCSPrivilegesToMap();
47}
48
49void CipherConfig::loadCSPrivilegesToMap()
50{
51 if (!fs::exists(cipherSuiteDefaultPrivFileName))
52 {
53 log<level::ERR>("CS privilege levels default file does not exist...");
54 }
55 else
56 {
57 // read default privileges
58 Json data = readCSPrivilegeLevels(cipherSuiteDefaultPrivFileName);
59
60 // load default privileges
61 updateCSPrivilegesMap(data);
62
63 // check for user-saved privileges
64 if (fs::exists(cipherSuitePrivFileName))
65 {
66 data = readCSPrivilegeLevels(cipherSuitePrivFileName);
67 if (data != nullptr)
68 {
69 // update map with user-saved privileges by merging (overriding)
70 // values from the defaults
71 updateCSPrivilegesMap(data);
72 }
73 }
74 }
75}
76
77void CipherConfig::updateCSPrivilegesMap(const Json& jsonData)
78{
79 for (uint8_t chNum = 0; chNum < ipmi::maxIpmiChannels; chNum++)
80 {
81 std::string chKey = "Channel" + std::to_string(chNum);
82 for (uint8_t csNum = 0; csNum < maxCSRecords; csNum++)
83 {
84 auto csKey = "CipherID" + std::to_string(csNum);
85
86 if (jsonData.find(chKey) != jsonData.end())
87 {
88 csPrivilegeMap[{chNum, csNum}] = convertToPrivLimitIndex(
89 static_cast<std::string>(jsonData[chKey][csKey]));
90 }
91 }
92 }
93}
94
95Json CipherConfig::readCSPrivilegeLevels(const std::string& csFileName)
96{
97 std::ifstream jsonFile(csFileName);
98 if (!jsonFile.good())
99 {
100 log<level::ERR>("JSON file not found");
101 return nullptr;
102 }
103
104 Json data = nullptr;
105 try
106 {
107 data = Json::parse(jsonFile, nullptr, false);
108 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500109 catch (const Json::parse_error& e)
Sumanth Bhate4e633e2019-05-14 12:13:57 +0000110 {
111 log<level::ERR>("Corrupted cipher suite privilege levels config file.",
112 entry("MSG: %s", e.what()));
113 }
114
115 return data;
116}
117
118int CipherConfig::writeCSPrivilegeLevels(const Json& jsonData)
119{
120 std::string tmpFile =
121 static_cast<std::string>(cipherSuitePrivFileName) + "_tmpXXXXXX";
122
Willy Tu11d68892022-01-20 10:37:34 -0800123 std::vector<char> tmpRandomFile(tmpFile.length() + 1);
124 strncpy(tmpRandomFile.data(), tmpFile.c_str(), tmpFile.length() + 1);
Sumanth Bhate4e633e2019-05-14 12:13:57 +0000125
Willy Tu11d68892022-01-20 10:37:34 -0800126 int fd = mkstemp(tmpRandomFile.data());
Sumanth Bhate4e633e2019-05-14 12:13:57 +0000127 fchmod(fd, 0644);
128
129 if (fd < 0)
130 {
131 log<level::ERR>("Error opening CS privilege level config file",
132 entry("FILE_NAME=%s", tmpFile.c_str()));
133 return -EIO;
134 }
135 const auto& writeData = jsonData.dump();
136 if (write(fd, writeData.c_str(), writeData.size()) !=
137 static_cast<ssize_t>(writeData.size()))
138 {
139 close(fd);
140 log<level::ERR>("Error writing CS privilege level config file",
141 entry("FILE_NAME=%s", tmpFile.c_str()));
Willy Tu11d68892022-01-20 10:37:34 -0800142 unlink(tmpRandomFile.data());
Sumanth Bhate4e633e2019-05-14 12:13:57 +0000143 return -EIO;
144 }
145 close(fd);
146
Willy Tu11d68892022-01-20 10:37:34 -0800147 if (std::rename(tmpRandomFile.data(), cipherSuitePrivFileName.c_str()))
Sumanth Bhate4e633e2019-05-14 12:13:57 +0000148 {
149 log<level::ERR>("Error renaming CS privilege level config file",
150 entry("FILE_NAME=%s", tmpFile.c_str()));
Willy Tu11d68892022-01-20 10:37:34 -0800151 unlink(tmpRandomFile.data());
Sumanth Bhate4e633e2019-05-14 12:13:57 +0000152 return -EIO;
153 }
154
155 return 0;
156}
157
158uint4_t CipherConfig::convertToPrivLimitIndex(const std::string& value)
159{
160 auto iter = std::find(ipmi::privList.begin(), ipmi::privList.end(), value);
161 if (iter == privList.end())
162 {
163 log<level::ERR>("Invalid privilege.",
164 entry("PRIV_STR=%s", value.c_str()));
165 return ccUnspecifiedError;
166 }
167
168 return static_cast<uint4_t>(std::distance(ipmi::privList.begin(), iter));
169}
170
171std::string CipherConfig::convertToPrivLimitString(const uint4_t& value)
172{
173 return ipmi::privList.at(static_cast<size_t>(value));
174}
175
jayaprakash Mutyalab741b992019-12-02 17:29:09 +0000176ipmi::Cc CipherConfig::getCSPrivilegeLevels(
177 uint8_t chNum, std::array<uint4_t, maxCSRecords>& csPrivilegeLevels)
178{
179 if (!isValidChannel(chNum))
180 {
181 log<level::ERR>("Invalid channel number", entry("CHANNEL=%u", chNum));
182 return ccInvalidFieldRequest;
183 }
184
185 for (size_t csNum = 0; csNum < maxCSRecords; ++csNum)
186 {
187 csPrivilegeLevels[csNum] = csPrivilegeMap[{chNum, csNum}];
188 }
189 return ccSuccess;
190}
191
192ipmi::Cc CipherConfig::setCSPrivilegeLevels(
193 uint8_t chNum, const std::array<uint4_t, maxCSRecords>& requestData)
194{
195 if (!isValidChannel(chNum))
196 {
197 log<level::ERR>("Invalid channel number", entry("CHANNEL=%u", chNum));
198 return ccInvalidFieldRequest;
199 }
200
201 Json jsonData;
202 if (!fs::exists(cipherSuitePrivFileName))
203 {
204 log<level::INFO>("CS privilege levels user settings file does not "
205 "exist. Creating...");
206 }
207 else
208 {
209 jsonData = readCSPrivilegeLevels(cipherSuitePrivFileName);
210 if (jsonData == nullptr)
211 {
212 return ccUnspecifiedError;
213 }
214 }
215
216 Json privData;
217 std::string csKey;
218 constexpr auto privMaxValue = static_cast<uint8_t>(ipmi::Privilege::Oem);
219 for (size_t csNum = 0; csNum < maxCSRecords; ++csNum)
220 {
221 csKey = "CipherID" + std::to_string(csNum);
222 auto priv = static_cast<uint8_t>(requestData[csNum]);
223
224 if (priv > privMaxValue)
225 {
226 return ccInvalidFieldRequest;
227 }
228 privData[csKey] = convertToPrivLimitString(priv);
229 }
230
231 std::string chKey = "Channel" + std::to_string(chNum);
232 jsonData[chKey] = privData;
233
234 if (writeCSPrivilegeLevels(jsonData))
235 {
236 log<level::ERR>("Error in setting CS Privilege Levels.");
237 return ccUnspecifiedError;
238 }
239
240 updateCSPrivilegesMap(jsonData);
241 return ccSuccess;
242}
243
Sumanth Bhate4e633e2019-05-14 12:13:57 +0000244} // namespace ipmi