blob: 9b35ac7ae045664afb5b1c4c83ef2e68c49fd14a [file] [log] [blame]
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +05301/*
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 "passwd_mgr.hpp"
18
AppaRao Pulib29b5ab2018-05-17 10:28:48 +053019#include "file.hpp"
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +053020#include "shadowlock.hpp"
21
22#include <openssl/hmac.h>
AppaRao Pulib29b5ab2018-05-17 10:28:48 +053023#include <openssl/rand.h>
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +053024#include <openssl/sha.h>
25#include <string.h>
26#include <sys/stat.h>
AppaRao Pulib29b5ab2018-05-17 10:28:48 +053027#include <unistd.h>
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +053028
George Liu82844ef2024-07-17 17:03:56 +080029#include <phosphor-logging/lg2.hpp>
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -050030
AppaRao Pulib29b5ab2018-05-17 10:28:48 +053031#include <cerrno>
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +053032#include <cstring>
33#include <fstream>
AppaRao Pulib29b5ab2018-05-17 10:28:48 +053034#include <iomanip>
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +053035
36namespace ipmi
37{
38
39static const char* passwdFileName = "/etc/ipmi_pass";
40static const char* encryptKeyFileName = "/etc/key_file";
41static const size_t maxKeySize = 8;
42
Richard Marian Thomaiyar6ba8d312020-04-10 23:52:50 +053043constexpr mode_t modeMask =
44 (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO);
45
AppaRao Pulib29b5ab2018-05-17 10:28:48 +053046#define META_PASSWD_SIG "=OPENBMC="
47
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +053048/*
49 * Meta data struct for encrypted password file
50 */
Richard Marian Thomaiyar48e55582018-12-20 15:58:04 +053051struct MetaPassStruct
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +053052{
53 char signature[10];
54 unsigned char reseved[2];
Tim Lee65a91682022-11-30 17:14:13 +080055 size_t hashSize;
56 size_t ivSize;
57 size_t dataSize;
58 size_t padSize;
59 size_t macSize;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +053060};
61
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +053062PasswdMgr::PasswdMgr()
63{
Richard Marian Thomaiyar6ba8d312020-04-10 23:52:50 +053064 restrictFilesPermission();
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +053065 initPasswordMap();
66}
67
Richard Marian Thomaiyar6ba8d312020-04-10 23:52:50 +053068void PasswdMgr::restrictFilesPermission(void)
69{
70 struct stat st = {};
71 // Restrict file permission to owner read & write
72 if (stat(passwdFileName, &st) == 0)
73 {
74 if ((st.st_mode & modeMask) != (S_IRUSR | S_IWUSR))
75 {
PavanKumarIntel3771f5f2023-11-02 06:26:42 +000076 if (chmod(passwdFileName, S_IRUSR | S_IWUSR) == -1)
77 {
George Liu82844ef2024-07-17 17:03:56 +080078 lg2::debug("Error setting chmod for ipmi_pass file");
PavanKumarIntel3771f5f2023-11-02 06:26:42 +000079 }
Richard Marian Thomaiyar6ba8d312020-04-10 23:52:50 +053080 }
81 }
82
83 if (stat(encryptKeyFileName, &st) == 0)
84 {
85 if ((st.st_mode & modeMask) != (S_IRUSR | S_IWUSR))
86 {
PavanKumarIntel3771f5f2023-11-02 06:26:42 +000087 if (chmod(encryptKeyFileName, S_IRUSR | S_IWUSR) == -1)
88 {
George Liu82844ef2024-07-17 17:03:56 +080089 lg2::debug("Error setting chmod for ipmi_pass file");
PavanKumarIntel3771f5f2023-11-02 06:26:42 +000090 }
Richard Marian Thomaiyar6ba8d312020-04-10 23:52:50 +053091 }
92 }
93}
94
Vernon Mauery1e22a0f2021-07-30 13:36:54 -070095SecureString PasswdMgr::getPasswdByUserName(const std::string& userName)
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +053096{
97 checkAndReload();
98 auto iter = passwdMapList.find(userName);
99 if (iter == passwdMapList.end())
100 {
Vernon Mauery1e22a0f2021-07-30 13:36:54 -0700101 return SecureString();
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530102 }
103 return iter->second;
104}
105
Richard Marian Thomaiyar42bed642018-09-21 12:28:57 +0530106int PasswdMgr::updateUserEntry(const std::string& userName,
107 const std::string& newUserName)
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530108{
109 std::time_t updatedTime = getUpdatedFileTime();
110 // Check file time stamp to know passwdMapList is up-to-date.
111 // If not up-to-date, then updatePasswdSpecialFile will read and
112 // check the user entry existance.
113 if (fileLastUpdatedTime == updatedTime && updatedTime != -EIO)
114 {
115 if (passwdMapList.find(userName) == passwdMapList.end())
116 {
George Liu82844ef2024-07-17 17:03:56 +0800117 lg2::debug("User not found");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530118 return 0;
119 }
120 }
121
122 // Write passwdMap to Encryted file
Richard Marian Thomaiyar42bed642018-09-21 12:28:57 +0530123 if (updatePasswdSpecialFile(userName, newUserName) != 0)
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530124 {
George Liu82844ef2024-07-17 17:03:56 +0800125 lg2::debug("Passwd file update failed");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530126 return -EIO;
127 }
128
George Liu82844ef2024-07-17 17:03:56 +0800129 lg2::debug("Passwd file updated successfully");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530130 return 0;
131}
132
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530133void PasswdMgr::checkAndReload(void)
134{
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530135 std::time_t updatedTime = getUpdatedFileTime();
136 if (fileLastUpdatedTime != updatedTime && updatedTime != -1)
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530137 {
George Liu82844ef2024-07-17 17:03:56 +0800138 lg2::debug("Reloading password map list");
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530139 passwdMapList.clear();
140 initPasswordMap();
141 }
142}
143
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530144int PasswdMgr::encryptDecryptData(bool doEncrypt, const EVP_CIPHER* cipher,
145 uint8_t* key, size_t keyLen, uint8_t* iv,
146 size_t ivLen, uint8_t* inBytes,
147 size_t inBytesLen, uint8_t* mac,
148 size_t* macLen, unsigned char* outBytes,
149 size_t* outBytesLen)
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530150{
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530151 if (cipher == NULL || key == NULL || iv == NULL || inBytes == NULL ||
152 outBytes == NULL || mac == NULL || inBytesLen == 0 ||
153 (size_t)EVP_CIPHER_key_length(cipher) > keyLen ||
154 (size_t)EVP_CIPHER_iv_length(cipher) > ivLen)
155 {
George Liu82844ef2024-07-17 17:03:56 +0800156 lg2::debug("Error Invalid Inputs");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530157 return -EINVAL;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530158 }
159
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530160 if (!doEncrypt)
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530161 {
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530162 // verify MAC before decrypting the data.
163 std::array<uint8_t, EVP_MAX_MD_SIZE> calMac;
164 size_t calMacLen = calMac.size();
165 // calculate MAC for the encrypted message.
166 if (NULL == HMAC(EVP_sha256(), key, keyLen, inBytes, inBytesLen,
167 calMac.data(),
168 reinterpret_cast<unsigned int*>(&calMacLen)))
169 {
George Liu82844ef2024-07-17 17:03:56 +0800170 lg2::debug("Error: Failed to calculate MAC");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530171 return -EIO;
172 }
173 if (!((calMacLen == *macLen) &&
174 (std::memcmp(calMac.data(), mac, calMacLen) == 0)))
175 {
George Liu82844ef2024-07-17 17:03:56 +0800176 lg2::debug("Authenticated message doesn't match");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530177 return -EBADMSG;
178 }
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530179 }
180
181 std::unique_ptr<EVP_CIPHER_CTX, decltype(&::EVP_CIPHER_CTX_free)> ctx(
182 EVP_CIPHER_CTX_new(), ::EVP_CIPHER_CTX_free);
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530183
P Dheeraj Srujan Kumarbf30c8d2021-07-20 04:06:37 +0530184 if (!ctx)
185 {
George Liu82844ef2024-07-17 17:03:56 +0800186 lg2::debug("Error: EVP_CIPHER_CTX is NULL");
P Dheeraj Srujan Kumarbf30c8d2021-07-20 04:06:37 +0530187 return -ENOMEM;
188 }
189
P Dheeraj Srujan Kumara67caed2021-08-25 21:55:09 +0530190 EVP_CIPHER_CTX_set_padding(ctx.get(), 1);
191
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530192 // Set key & IV
193 int retval = EVP_CipherInit_ex(ctx.get(), cipher, NULL, key, iv,
194 static_cast<int>(doEncrypt));
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530195 if (!retval)
196 {
George Liu82844ef2024-07-17 17:03:56 +0800197 lg2::debug("EVP_CipherInit_ex failed: {RET_VAL}", "RET_VAL", retval);
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530198 return -EIO;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530199 }
200
201 int outLen = 0, outEVPLen = 0;
202 if ((retval = EVP_CipherUpdate(ctx.get(), outBytes + outLen, &outEVPLen,
203 inBytes, inBytesLen)))
204 {
205 outLen += outEVPLen;
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500206 if ((retval = EVP_CipherFinal(ctx.get(), outBytes + outLen,
207 &outEVPLen)))
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530208 {
209 outLen += outEVPLen;
210 *outBytesLen = outLen;
211 }
212 else
213 {
George Liu82844ef2024-07-17 17:03:56 +0800214 lg2::debug("EVP_CipherFinal fails: {RET_VAL}", "RET_VAL", retval);
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530215 return -EIO;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530216 }
217 }
218 else
219 {
George Liu82844ef2024-07-17 17:03:56 +0800220 lg2::debug("EVP_CipherUpdate fails: {RET_VAL}", "RET_VAL", retval);
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530221 return -EIO;
222 }
223
224 if (doEncrypt)
225 {
226 // Create MAC for the encrypted message
227 if (NULL == HMAC(EVP_sha256(), key, keyLen, outBytes, *outBytesLen, mac,
228 reinterpret_cast<unsigned int*>(macLen)))
229 {
George Liu82844ef2024-07-17 17:03:56 +0800230 lg2::debug("Failed to create authentication");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530231 return -EIO;
232 }
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530233 }
234 return 0;
235}
236
237void PasswdMgr::initPasswordMap(void)
238{
Andrew Geissler2f0ad742021-05-14 13:39:15 -0500239 // TODO phosphor-host-ipmid#170 phosphor::user::shadow::Lock lock{};
Vernon Mauery1e22a0f2021-07-30 13:36:54 -0700240 SecureString dataBuf;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530241
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530242 if (readPasswdFileData(dataBuf) != 0)
243 {
George Liu82844ef2024-07-17 17:03:56 +0800244 lg2::debug("Error in reading the encrypted pass file");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530245 return;
246 }
247
248 if (dataBuf.size() != 0)
249 {
250 // populate the user list with password
Vernon Mauery1e22a0f2021-07-30 13:36:54 -0700251 char* outPtr = dataBuf.data();
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530252 char* nToken = NULL;
253 char* linePtr = strtok_r(outPtr, "\n", &nToken);
Patrick Venture51d0c402019-08-19 11:19:19 -0700254 size_t lineSize = 0;
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530255 while (linePtr != NULL)
256 {
Patrick Venture51d0c402019-08-19 11:19:19 -0700257 size_t userEPos = 0;
Vernon Mauery1e22a0f2021-07-30 13:36:54 -0700258 SecureString lineStr(linePtr);
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530259 if ((userEPos = lineStr.find(":")) != std::string::npos)
260 {
261 lineSize = lineStr.size();
262 passwdMapList.emplace(
263 lineStr.substr(0, userEPos),
264 lineStr.substr(userEPos + 1, lineSize - (userEPos + 1)));
265 }
266 linePtr = strtok_r(NULL, "\n", &nToken);
267 }
268 }
269
270 // Update the timestamp
271 fileLastUpdatedTime = getUpdatedFileTime();
272 return;
273}
274
Vernon Mauery1e22a0f2021-07-30 13:36:54 -0700275int PasswdMgr::readPasswdFileData(SecureString& outBytes)
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530276{
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530277 std::array<uint8_t, maxKeySize> keyBuff;
278 std::ifstream keyFile(encryptKeyFileName, std::ios::in | std::ios::binary);
279 if (!keyFile.is_open())
280 {
George Liu82844ef2024-07-17 17:03:56 +0800281 lg2::debug("Error in opening encryption key file");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530282 return -EIO;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530283 }
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530284 keyFile.read(reinterpret_cast<char*>(keyBuff.data()), keyBuff.size());
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530285 if (keyFile.fail())
286 {
George Liu82844ef2024-07-17 17:03:56 +0800287 lg2::debug("Error in reading encryption key file");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530288 return -EIO;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530289 }
290
291 std::ifstream passwdFile(passwdFileName, std::ios::in | std::ios::binary);
292 if (!passwdFile.is_open())
293 {
George Liu82844ef2024-07-17 17:03:56 +0800294 lg2::debug("Error in opening ipmi password file");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530295 return -EIO;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530296 }
297
298 // calculate file size and read the data
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530299 passwdFile.seekg(0, std::ios::end);
300 ssize_t fileSize = passwdFile.tellg();
301 passwdFile.seekg(0, std::ios::beg);
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530302 std::vector<uint8_t> input(fileSize);
303 passwdFile.read(reinterpret_cast<char*>(input.data()), fileSize);
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530304 if (passwdFile.fail())
305 {
George Liu82844ef2024-07-17 17:03:56 +0800306 lg2::debug("Error in reading encryption key file");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530307 return -EIO;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530308 }
309
310 // verify the signature first
Richard Marian Thomaiyar48e55582018-12-20 15:58:04 +0530311 MetaPassStruct* metaData = reinterpret_cast<MetaPassStruct*>(input.data());
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530312 if (std::strncmp(metaData->signature, META_PASSWD_SIG,
313 sizeof(metaData->signature)))
314 {
George Liu82844ef2024-07-17 17:03:56 +0800315 lg2::debug("Error signature mismatch in password file");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530316 return -EBADMSG;
317 }
318
319 size_t inBytesLen = metaData->dataSize + metaData->padSize;
320 // If data is empty i.e no password map then return success
321 if (inBytesLen == 0)
322 {
George Liu82844ef2024-07-17 17:03:56 +0800323 lg2::debug("Empty password file");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530324 return 0;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530325 }
326
327 // compute the key needed to decrypt
328 std::array<uint8_t, EVP_MAX_KEY_LENGTH> key;
329 auto keyLen = key.size();
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530330 if (NULL == HMAC(EVP_sha256(), keyBuff.data(), keyBuff.size(),
331 input.data() + sizeof(*metaData), metaData->hashSize,
332 key.data(), reinterpret_cast<unsigned int*>(&keyLen)))
333 {
George Liu82844ef2024-07-17 17:03:56 +0800334 lg2::debug("Failed to create MAC for authentication");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530335 return -EIO;
336 }
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530337
338 // decrypt the data
339 uint8_t* iv = input.data() + sizeof(*metaData) + metaData->hashSize;
340 size_t ivLen = metaData->ivSize;
341 uint8_t* inBytes = iv + ivLen;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530342 uint8_t* mac = inBytes + inBytesLen;
343 size_t macLen = metaData->macSize;
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530344
345 size_t outBytesLen = 0;
346 // Resize to actual data size
Vernon Mauery1e22a0f2021-07-30 13:36:54 -0700347 outBytes.resize(inBytesLen + EVP_MAX_BLOCK_LENGTH, '\0');
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530348 if (encryptDecryptData(false, EVP_aes_128_cbc(), key.data(), keyLen, iv,
349 ivLen, inBytes, inBytesLen, mac, &macLen,
Vernon Mauery1e22a0f2021-07-30 13:36:54 -0700350 reinterpret_cast<unsigned char*>(outBytes.data()),
351 &outBytesLen) != 0)
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530352 {
George Liu82844ef2024-07-17 17:03:56 +0800353 lg2::debug("Error in decryption");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530354 return -EIO;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530355 }
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530356 // Resize the vector to outBytesLen
357 outBytes.resize(outBytesLen);
358
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530359 OPENSSL_cleanse(key.data(), keyLen);
360 OPENSSL_cleanse(iv, ivLen);
361
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530362 return 0;
363}
364
Richard Marian Thomaiyar42bed642018-09-21 12:28:57 +0530365int PasswdMgr::updatePasswdSpecialFile(const std::string& userName,
366 const std::string& newUserName)
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530367{
Andrew Geissler2f0ad742021-05-14 13:39:15 -0500368 // TODO phosphor-host-ipmid#170 phosphor::user::shadow::Lock lock{};
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530369
370 size_t bytesWritten = 0;
371 size_t inBytesLen = 0;
372 size_t isUsrFound = false;
373 const EVP_CIPHER* cipher = EVP_aes_128_cbc();
Vernon Mauery1e22a0f2021-07-30 13:36:54 -0700374 SecureString dataBuf;
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530375
376 // Read the encrypted file and get the file data
377 // Check user existance and return if not exist.
378 if (readPasswdFileData(dataBuf) != 0)
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530379 {
George Liu82844ef2024-07-17 17:03:56 +0800380 lg2::debug("Error in reading the encrypted pass file");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530381 return -EIO;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530382 }
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530383
384 if (dataBuf.size() != 0)
385 {
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500386 inBytesLen = dataBuf.size() + newUserName.size() +
387 EVP_CIPHER_block_size(cipher);
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530388 }
389
Vernon Mauery1e22a0f2021-07-30 13:36:54 -0700390 SecureString inBytes(inBytesLen, '\0');
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530391 if (inBytesLen != 0)
392 {
393 char* outPtr = reinterpret_cast<char*>(dataBuf.data());
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530394 char* nToken = NULL;
395 char* linePtr = strtok_r(outPtr, "\n", &nToken);
396 while (linePtr != NULL)
397 {
Patrick Venture51d0c402019-08-19 11:19:19 -0700398 size_t userEPos = 0;
399
Vernon Mauery1e22a0f2021-07-30 13:36:54 -0700400 SecureString lineStr(linePtr);
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530401 if ((userEPos = lineStr.find(":")) != std::string::npos)
402 {
403 if (userName.compare(lineStr.substr(0, userEPos)) == 0)
404 {
405 isUsrFound = true;
Richard Marian Thomaiyar42bed642018-09-21 12:28:57 +0530406 if (!newUserName.empty())
407 {
408 bytesWritten += std::snprintf(
Vernon Mauery1e22a0f2021-07-30 13:36:54 -0700409 &inBytes[0] + bytesWritten,
Richard Marian Thomaiyar42bed642018-09-21 12:28:57 +0530410 (inBytesLen - bytesWritten), "%s%s\n",
411 newUserName.c_str(),
412 lineStr.substr(userEPos, lineStr.size()).data());
413 }
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530414 }
415 else
416 {
Vernon Mauery1e22a0f2021-07-30 13:36:54 -0700417 bytesWritten += std::snprintf(&inBytes[0] + bytesWritten,
418 (inBytesLen - bytesWritten),
419 "%s\n", lineStr.data());
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530420 }
421 }
422 linePtr = strtok_r(NULL, "\n", &nToken);
423 }
Richard Marian Thomaiyar161f20d2019-01-28 20:33:16 +0530424 inBytesLen = bytesWritten;
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530425 }
426 if (!isUsrFound)
427 {
George Liu82844ef2024-07-17 17:03:56 +0800428 lg2::debug("User doesn't exist");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530429 return 0;
430 }
431
432 // Read the key buff from key file
433 std::array<uint8_t, maxKeySize> keyBuff;
434 std::ifstream keyFile(encryptKeyFileName, std::ios::in | std::ios::binary);
435 if (!keyFile.good())
436 {
George Liu82844ef2024-07-17 17:03:56 +0800437 lg2::debug("Error in opening encryption key file");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530438 return -EIO;
439 }
440 keyFile.read(reinterpret_cast<char*>(keyBuff.data()), keyBuff.size());
441 if (keyFile.fail())
442 {
George Liu82844ef2024-07-17 17:03:56 +0800443 lg2::debug("Error in reading encryption key file");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530444 return -EIO;
445 }
446 keyFile.close();
447
448 // Read the original passwd file mode
449 struct stat st = {};
450 if (stat(passwdFileName, &st) != 0)
451 {
George Liu82844ef2024-07-17 17:03:56 +0800452 lg2::debug("Error in getting password file fstat()");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530453 return -EIO;
454 }
455
456 // Create temporary file for write
457 std::string pwdFile(passwdFileName);
458 std::vector<char> tempFileName(pwdFile.begin(), pwdFile.end());
459 std::vector<char> fileTemplate = {'_', '_', 'X', 'X', 'X',
460 'X', 'X', 'X', '\0'};
461 tempFileName.insert(tempFileName.end(), fileTemplate.begin(),
462 fileTemplate.end());
463 int fd = mkstemp((char*)tempFileName.data());
464 if (fd == -1)
465 {
George Liu82844ef2024-07-17 17:03:56 +0800466 lg2::debug("Error creating temp file");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530467 return -EIO;
468 }
469
470 std::string strTempFileName(tempFileName.data());
471 // Open the temp file for writing from provided fd
472 // By "true", remove it at exit if still there.
473 // This is needed to cleanup the temp file at exception
474 phosphor::user::File temp(fd, strTempFileName, "w", true);
475 if ((temp)() == NULL)
476 {
477 close(fd);
George Liu82844ef2024-07-17 17:03:56 +0800478 lg2::debug("Error creating temp file");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530479 return -EIO;
480 }
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530481
Vernon Maueryb2654552020-04-03 14:28:53 -0700482 // Set the file mode as read-write for owner only
483 if (fchmod(fileno((temp)()), S_IRUSR | S_IWUSR) < 0)
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530484 {
George Liu82844ef2024-07-17 17:03:56 +0800485 lg2::debug("Error setting fchmod for temp file");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530486 return -EIO;
487 }
488
489 const EVP_MD* digest = EVP_sha256();
490 size_t hashLen = EVP_MD_block_size(digest);
491 std::vector<uint8_t> hash(hashLen);
492 size_t ivLen = EVP_CIPHER_iv_length(cipher);
493 std::vector<uint8_t> iv(ivLen);
494 std::array<uint8_t, EVP_MAX_KEY_LENGTH> key;
495 size_t keyLen = key.size();
496 std::array<uint8_t, EVP_MAX_MD_SIZE> mac;
497 size_t macLen = mac.size();
498
499 // Create random hash and generate hash key which will be used for
500 // encryption.
501 if (RAND_bytes(hash.data(), hashLen) != 1)
502 {
George Liu82844ef2024-07-17 17:03:56 +0800503 lg2::debug("Hash genertion failed, bailing out");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530504 return -EIO;
505 }
506 if (NULL == HMAC(digest, keyBuff.data(), keyBuff.size(), hash.data(),
507 hashLen, key.data(),
508 reinterpret_cast<unsigned int*>(&keyLen)))
509 {
George Liu82844ef2024-07-17 17:03:56 +0800510 lg2::debug("Failed to create MAC for authentication");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530511 return -EIO;
512 }
513
514 // Generate IV values
515 if (RAND_bytes(iv.data(), ivLen) != 1)
516 {
George Liu82844ef2024-07-17 17:03:56 +0800517 lg2::debug("UV genertion failed, bailing out");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530518 return -EIO;
519 }
520
521 // Encrypt the input data
522 std::vector<uint8_t> outBytes(inBytesLen + EVP_MAX_BLOCK_LENGTH);
523 size_t outBytesLen = 0;
524 if (inBytesLen != 0)
525 {
Vernon Mauery1e22a0f2021-07-30 13:36:54 -0700526 if (encryptDecryptData(
527 true, EVP_aes_128_cbc(), key.data(), keyLen, iv.data(), ivLen,
528 reinterpret_cast<unsigned char*>(inBytes.data()), inBytesLen,
529 mac.data(), &macLen, outBytes.data(), &outBytesLen) != 0)
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530530 {
George Liu82844ef2024-07-17 17:03:56 +0800531 lg2::debug("Error while encrypting the data");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530532 return -EIO;
533 }
534 outBytes[outBytesLen] = 0;
535 }
536 OPENSSL_cleanse(key.data(), keyLen);
537
538 // Update the meta password structure.
Richard Marian Thomaiyar48e55582018-12-20 15:58:04 +0530539 MetaPassStruct metaData = {META_PASSWD_SIG, {0, 0}, 0, 0, 0, 0, 0};
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530540 metaData.hashSize = hashLen;
541 metaData.ivSize = ivLen;
542 metaData.dataSize = bytesWritten;
543 metaData.padSize = outBytesLen - bytesWritten;
544 metaData.macSize = macLen;
545
546 if (fwrite(&metaData, 1, sizeof(metaData), (temp)()) != sizeof(metaData))
547 {
George Liu82844ef2024-07-17 17:03:56 +0800548 lg2::debug("Error in writing meta data");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530549 return -EIO;
550 }
551
552 if (fwrite(&hash[0], 1, hashLen, (temp)()) != hashLen)
553 {
George Liu82844ef2024-07-17 17:03:56 +0800554 lg2::debug("Error in writing hash data");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530555 return -EIO;
556 }
557
558 if (fwrite(&iv[0], 1, ivLen, (temp)()) != ivLen)
559 {
George Liu82844ef2024-07-17 17:03:56 +0800560 lg2::debug("Error in writing IV data");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530561 return -EIO;
562 }
563
564 if (fwrite(&outBytes[0], 1, outBytesLen, (temp)()) != outBytesLen)
565 {
George Liu82844ef2024-07-17 17:03:56 +0800566 lg2::debug("Error in writing encrypted data");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530567 return -EIO;
568 }
569
570 if (fwrite(&mac[0], 1, macLen, (temp)()) != macLen)
571 {
George Liu82844ef2024-07-17 17:03:56 +0800572 lg2::debug("Error in writing MAC data");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530573 return -EIO;
574 }
575
576 if (fflush((temp)()))
577 {
George Liu82844ef2024-07-17 17:03:56 +0800578 lg2::debug("File fflush error while writing entries to special file");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530579 return -EIO;
580 }
581
582 OPENSSL_cleanse(iv.data(), ivLen);
583
584 // Rename the tmp file to actual file
585 if (std::rename(strTempFileName.data(), passwdFileName) != 0)
586 {
George Liu82844ef2024-07-17 17:03:56 +0800587 lg2::debug("Failed to rename tmp file to ipmi-pass");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530588 return -EIO;
589 }
590
591 return 0;
592}
593
594std::time_t PasswdMgr::getUpdatedFileTime()
595{
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530596 struct stat fileStat = {};
597 if (stat(passwdFileName, &fileStat) != 0)
598 {
George Liu82844ef2024-07-17 17:03:56 +0800599 lg2::debug("Error - Getting passwd file time stamp");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530600 return -EIO;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530601 }
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530602 return fileStat.st_mtime;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530603}
604
605} // namespace ipmi