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