blob: f712779d0dadde2b4b06f19a8dd2c5ebf0134d9e [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
Patrick Williams1318a5e2024-08-16 15:19:54 -0400144int PasswdMgr::encryptDecryptData(
145 bool doEncrypt, const EVP_CIPHER* cipher, uint8_t* key, size_t keyLen,
146 uint8_t* iv, size_t ivLen, uint8_t* inBytes, size_t inBytesLen,
147 uint8_t* mac, size_t* macLen, unsigned char* outBytes, size_t* outBytesLen)
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530148{
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530149 if (cipher == NULL || key == NULL || iv == NULL || inBytes == NULL ||
150 outBytes == NULL || mac == NULL || inBytesLen == 0 ||
151 (size_t)EVP_CIPHER_key_length(cipher) > keyLen ||
152 (size_t)EVP_CIPHER_iv_length(cipher) > ivLen)
153 {
George Liu82844ef2024-07-17 17:03:56 +0800154 lg2::debug("Error Invalid Inputs");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530155 return -EINVAL;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530156 }
157
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530158 if (!doEncrypt)
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530159 {
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530160 // verify MAC before decrypting the data.
161 std::array<uint8_t, EVP_MAX_MD_SIZE> calMac;
162 size_t calMacLen = calMac.size();
163 // calculate MAC for the encrypted message.
Patrick Williams1318a5e2024-08-16 15:19:54 -0400164 if (NULL ==
165 HMAC(EVP_sha256(), key, keyLen, inBytes, inBytesLen, calMac.data(),
166 reinterpret_cast<unsigned int*>(&calMacLen)))
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530167 {
George Liu82844ef2024-07-17 17:03:56 +0800168 lg2::debug("Error: Failed to calculate MAC");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530169 return -EIO;
170 }
171 if (!((calMacLen == *macLen) &&
172 (std::memcmp(calMac.data(), mac, calMacLen) == 0)))
173 {
George Liu82844ef2024-07-17 17:03:56 +0800174 lg2::debug("Authenticated message doesn't match");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530175 return -EBADMSG;
176 }
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530177 }
178
179 std::unique_ptr<EVP_CIPHER_CTX, decltype(&::EVP_CIPHER_CTX_free)> ctx(
180 EVP_CIPHER_CTX_new(), ::EVP_CIPHER_CTX_free);
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530181
P Dheeraj Srujan Kumarbf30c8d2021-07-20 04:06:37 +0530182 if (!ctx)
183 {
George Liu82844ef2024-07-17 17:03:56 +0800184 lg2::debug("Error: EVP_CIPHER_CTX is NULL");
P Dheeraj Srujan Kumarbf30c8d2021-07-20 04:06:37 +0530185 return -ENOMEM;
186 }
187
P Dheeraj Srujan Kumara67caed2021-08-25 21:55:09 +0530188 EVP_CIPHER_CTX_set_padding(ctx.get(), 1);
189
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530190 // Set key & IV
191 int retval = EVP_CipherInit_ex(ctx.get(), cipher, NULL, key, iv,
192 static_cast<int>(doEncrypt));
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530193 if (!retval)
194 {
George Liu82844ef2024-07-17 17:03:56 +0800195 lg2::debug("EVP_CipherInit_ex failed: {RET_VAL}", "RET_VAL", retval);
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530196 return -EIO;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530197 }
198
199 int outLen = 0, outEVPLen = 0;
200 if ((retval = EVP_CipherUpdate(ctx.get(), outBytes + outLen, &outEVPLen,
201 inBytes, inBytesLen)))
202 {
203 outLen += outEVPLen;
Patrick Williams1318a5e2024-08-16 15:19:54 -0400204 if ((retval =
205 EVP_CipherFinal(ctx.get(), outBytes + outLen, &outEVPLen)))
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530206 {
207 outLen += outEVPLen;
208 *outBytesLen = outLen;
209 }
210 else
211 {
George Liu82844ef2024-07-17 17:03:56 +0800212 lg2::debug("EVP_CipherFinal fails: {RET_VAL}", "RET_VAL", retval);
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530213 return -EIO;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530214 }
215 }
216 else
217 {
George Liu82844ef2024-07-17 17:03:56 +0800218 lg2::debug("EVP_CipherUpdate fails: {RET_VAL}", "RET_VAL", retval);
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530219 return -EIO;
220 }
221
222 if (doEncrypt)
223 {
224 // Create MAC for the encrypted message
225 if (NULL == HMAC(EVP_sha256(), key, keyLen, outBytes, *outBytesLen, mac,
226 reinterpret_cast<unsigned int*>(macLen)))
227 {
George Liu82844ef2024-07-17 17:03:56 +0800228 lg2::debug("Failed to create authentication");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530229 return -EIO;
230 }
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530231 }
232 return 0;
233}
234
235void PasswdMgr::initPasswordMap(void)
236{
Andrew Geissler2f0ad742021-05-14 13:39:15 -0500237 // TODO phosphor-host-ipmid#170 phosphor::user::shadow::Lock lock{};
Vernon Mauery1e22a0f2021-07-30 13:36:54 -0700238 SecureString dataBuf;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530239
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530240 if (readPasswdFileData(dataBuf) != 0)
241 {
George Liu82844ef2024-07-17 17:03:56 +0800242 lg2::debug("Error in reading the encrypted pass file");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530243 return;
244 }
245
246 if (dataBuf.size() != 0)
247 {
248 // populate the user list with password
Vernon Mauery1e22a0f2021-07-30 13:36:54 -0700249 char* outPtr = dataBuf.data();
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530250 char* nToken = NULL;
251 char* linePtr = strtok_r(outPtr, "\n", &nToken);
Patrick Venture51d0c402019-08-19 11:19:19 -0700252 size_t lineSize = 0;
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530253 while (linePtr != NULL)
254 {
Patrick Venture51d0c402019-08-19 11:19:19 -0700255 size_t userEPos = 0;
Vernon Mauery1e22a0f2021-07-30 13:36:54 -0700256 SecureString lineStr(linePtr);
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530257 if ((userEPos = lineStr.find(":")) != std::string::npos)
258 {
259 lineSize = lineStr.size();
260 passwdMapList.emplace(
261 lineStr.substr(0, userEPos),
262 lineStr.substr(userEPos + 1, lineSize - (userEPos + 1)));
263 }
264 linePtr = strtok_r(NULL, "\n", &nToken);
265 }
266 }
267
268 // Update the timestamp
269 fileLastUpdatedTime = getUpdatedFileTime();
270 return;
271}
272
Vernon Mauery1e22a0f2021-07-30 13:36:54 -0700273int PasswdMgr::readPasswdFileData(SecureString& outBytes)
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530274{
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530275 std::array<uint8_t, maxKeySize> keyBuff;
276 std::ifstream keyFile(encryptKeyFileName, std::ios::in | std::ios::binary);
277 if (!keyFile.is_open())
278 {
George Liu82844ef2024-07-17 17:03:56 +0800279 lg2::debug("Error in opening encryption key file");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530280 return -EIO;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530281 }
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530282 keyFile.read(reinterpret_cast<char*>(keyBuff.data()), keyBuff.size());
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530283 if (keyFile.fail())
284 {
George Liu82844ef2024-07-17 17:03:56 +0800285 lg2::debug("Error in reading encryption key file");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530286 return -EIO;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530287 }
288
289 std::ifstream passwdFile(passwdFileName, std::ios::in | std::ios::binary);
290 if (!passwdFile.is_open())
291 {
George Liu82844ef2024-07-17 17:03:56 +0800292 lg2::debug("Error in opening ipmi password file");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530293 return -EIO;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530294 }
295
296 // calculate file size and read the data
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530297 passwdFile.seekg(0, std::ios::end);
298 ssize_t fileSize = passwdFile.tellg();
299 passwdFile.seekg(0, std::ios::beg);
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530300 std::vector<uint8_t> input(fileSize);
301 passwdFile.read(reinterpret_cast<char*>(input.data()), fileSize);
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530302 if (passwdFile.fail())
303 {
George Liu82844ef2024-07-17 17:03:56 +0800304 lg2::debug("Error in reading encryption key file");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530305 return -EIO;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530306 }
307
308 // verify the signature first
Richard Marian Thomaiyar48e55582018-12-20 15:58:04 +0530309 MetaPassStruct* metaData = reinterpret_cast<MetaPassStruct*>(input.data());
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530310 if (std::strncmp(metaData->signature, META_PASSWD_SIG,
311 sizeof(metaData->signature)))
312 {
George Liu82844ef2024-07-17 17:03:56 +0800313 lg2::debug("Error signature mismatch in password file");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530314 return -EBADMSG;
315 }
316
317 size_t inBytesLen = metaData->dataSize + metaData->padSize;
318 // If data is empty i.e no password map then return success
319 if (inBytesLen == 0)
320 {
George Liu82844ef2024-07-17 17:03:56 +0800321 lg2::debug("Empty password file");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530322 return 0;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530323 }
324
325 // compute the key needed to decrypt
326 std::array<uint8_t, EVP_MAX_KEY_LENGTH> key;
327 auto keyLen = key.size();
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530328 if (NULL == HMAC(EVP_sha256(), keyBuff.data(), keyBuff.size(),
329 input.data() + sizeof(*metaData), metaData->hashSize,
330 key.data(), reinterpret_cast<unsigned int*>(&keyLen)))
331 {
George Liu82844ef2024-07-17 17:03:56 +0800332 lg2::debug("Failed to create MAC for authentication");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530333 return -EIO;
334 }
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530335
336 // decrypt the data
337 uint8_t* iv = input.data() + sizeof(*metaData) + metaData->hashSize;
338 size_t ivLen = metaData->ivSize;
339 uint8_t* inBytes = iv + ivLen;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530340 uint8_t* mac = inBytes + inBytesLen;
341 size_t macLen = metaData->macSize;
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530342
343 size_t outBytesLen = 0;
344 // Resize to actual data size
Vernon Mauery1e22a0f2021-07-30 13:36:54 -0700345 outBytes.resize(inBytesLen + EVP_MAX_BLOCK_LENGTH, '\0');
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530346 if (encryptDecryptData(false, EVP_aes_128_cbc(), key.data(), keyLen, iv,
347 ivLen, inBytes, inBytesLen, mac, &macLen,
Vernon Mauery1e22a0f2021-07-30 13:36:54 -0700348 reinterpret_cast<unsigned char*>(outBytes.data()),
349 &outBytesLen) != 0)
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530350 {
George Liu82844ef2024-07-17 17:03:56 +0800351 lg2::debug("Error in decryption");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530352 return -EIO;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530353 }
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530354 // Resize the vector to outBytesLen
355 outBytes.resize(outBytesLen);
356
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530357 OPENSSL_cleanse(key.data(), keyLen);
358 OPENSSL_cleanse(iv, ivLen);
359
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530360 return 0;
361}
362
Richard Marian Thomaiyar42bed642018-09-21 12:28:57 +0530363int PasswdMgr::updatePasswdSpecialFile(const std::string& userName,
364 const std::string& newUserName)
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530365{
Andrew Geissler2f0ad742021-05-14 13:39:15 -0500366 // TODO phosphor-host-ipmid#170 phosphor::user::shadow::Lock lock{};
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530367
368 size_t bytesWritten = 0;
369 size_t inBytesLen = 0;
370 size_t isUsrFound = false;
371 const EVP_CIPHER* cipher = EVP_aes_128_cbc();
Vernon Mauery1e22a0f2021-07-30 13:36:54 -0700372 SecureString dataBuf;
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530373
374 // Read the encrypted file and get the file data
375 // Check user existance and return if not exist.
376 if (readPasswdFileData(dataBuf) != 0)
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530377 {
George Liu82844ef2024-07-17 17:03:56 +0800378 lg2::debug("Error in reading the encrypted pass file");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530379 return -EIO;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530380 }
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530381
382 if (dataBuf.size() != 0)
383 {
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500384 inBytesLen = dataBuf.size() + newUserName.size() +
385 EVP_CIPHER_block_size(cipher);
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530386 }
387
Vernon Mauery1e22a0f2021-07-30 13:36:54 -0700388 SecureString inBytes(inBytesLen, '\0');
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530389 if (inBytesLen != 0)
390 {
391 char* outPtr = reinterpret_cast<char*>(dataBuf.data());
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530392 char* nToken = NULL;
393 char* linePtr = strtok_r(outPtr, "\n", &nToken);
394 while (linePtr != NULL)
395 {
Patrick Venture51d0c402019-08-19 11:19:19 -0700396 size_t userEPos = 0;
397
Vernon Mauery1e22a0f2021-07-30 13:36:54 -0700398 SecureString lineStr(linePtr);
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530399 if ((userEPos = lineStr.find(":")) != std::string::npos)
400 {
401 if (userName.compare(lineStr.substr(0, userEPos)) == 0)
402 {
403 isUsrFound = true;
Richard Marian Thomaiyar42bed642018-09-21 12:28:57 +0530404 if (!newUserName.empty())
405 {
406 bytesWritten += std::snprintf(
Vernon Mauery1e22a0f2021-07-30 13:36:54 -0700407 &inBytes[0] + bytesWritten,
Richard Marian Thomaiyar42bed642018-09-21 12:28:57 +0530408 (inBytesLen - bytesWritten), "%s%s\n",
409 newUserName.c_str(),
410 lineStr.substr(userEPos, lineStr.size()).data());
411 }
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530412 }
413 else
414 {
Vernon Mauery1e22a0f2021-07-30 13:36:54 -0700415 bytesWritten += std::snprintf(&inBytes[0] + bytesWritten,
416 (inBytesLen - bytesWritten),
417 "%s\n", lineStr.data());
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530418 }
419 }
420 linePtr = strtok_r(NULL, "\n", &nToken);
421 }
Richard Marian Thomaiyar161f20d2019-01-28 20:33:16 +0530422 inBytesLen = bytesWritten;
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530423 }
424 if (!isUsrFound)
425 {
George Liu82844ef2024-07-17 17:03:56 +0800426 lg2::debug("User doesn't exist");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530427 return 0;
428 }
429
430 // Read the key buff from key file
431 std::array<uint8_t, maxKeySize> keyBuff;
432 std::ifstream keyFile(encryptKeyFileName, std::ios::in | std::ios::binary);
433 if (!keyFile.good())
434 {
George Liu82844ef2024-07-17 17:03:56 +0800435 lg2::debug("Error in opening encryption key file");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530436 return -EIO;
437 }
438 keyFile.read(reinterpret_cast<char*>(keyBuff.data()), keyBuff.size());
439 if (keyFile.fail())
440 {
George Liu82844ef2024-07-17 17:03:56 +0800441 lg2::debug("Error in reading encryption key file");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530442 return -EIO;
443 }
444 keyFile.close();
445
446 // Read the original passwd file mode
447 struct stat st = {};
448 if (stat(passwdFileName, &st) != 0)
449 {
George Liu82844ef2024-07-17 17:03:56 +0800450 lg2::debug("Error in getting password file fstat()");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530451 return -EIO;
452 }
453
454 // Create temporary file for write
455 std::string pwdFile(passwdFileName);
456 std::vector<char> tempFileName(pwdFile.begin(), pwdFile.end());
457 std::vector<char> fileTemplate = {'_', '_', 'X', 'X', 'X',
458 'X', 'X', 'X', '\0'};
459 tempFileName.insert(tempFileName.end(), fileTemplate.begin(),
460 fileTemplate.end());
461 int fd = mkstemp((char*)tempFileName.data());
462 if (fd == -1)
463 {
George Liu82844ef2024-07-17 17:03:56 +0800464 lg2::debug("Error creating temp file");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530465 return -EIO;
466 }
467
468 std::string strTempFileName(tempFileName.data());
469 // Open the temp file for writing from provided fd
470 // By "true", remove it at exit if still there.
471 // This is needed to cleanup the temp file at exception
472 phosphor::user::File temp(fd, strTempFileName, "w", true);
473 if ((temp)() == NULL)
474 {
475 close(fd);
George Liu82844ef2024-07-17 17:03:56 +0800476 lg2::debug("Error creating temp file");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530477 return -EIO;
478 }
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530479
Vernon Maueryb2654552020-04-03 14:28:53 -0700480 // Set the file mode as read-write for owner only
481 if (fchmod(fileno((temp)()), S_IRUSR | S_IWUSR) < 0)
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530482 {
George Liu82844ef2024-07-17 17:03:56 +0800483 lg2::debug("Error setting fchmod for temp file");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530484 return -EIO;
485 }
486
487 const EVP_MD* digest = EVP_sha256();
488 size_t hashLen = EVP_MD_block_size(digest);
489 std::vector<uint8_t> hash(hashLen);
490 size_t ivLen = EVP_CIPHER_iv_length(cipher);
491 std::vector<uint8_t> iv(ivLen);
492 std::array<uint8_t, EVP_MAX_KEY_LENGTH> key;
493 size_t keyLen = key.size();
494 std::array<uint8_t, EVP_MAX_MD_SIZE> mac;
495 size_t macLen = mac.size();
496
497 // Create random hash and generate hash key which will be used for
498 // encryption.
499 if (RAND_bytes(hash.data(), hashLen) != 1)
500 {
George Liu82844ef2024-07-17 17:03:56 +0800501 lg2::debug("Hash genertion failed, bailing out");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530502 return -EIO;
503 }
Patrick Williams1318a5e2024-08-16 15:19:54 -0400504 if (NULL ==
505 HMAC(digest, keyBuff.data(), keyBuff.size(), hash.data(), hashLen,
506 key.data(), reinterpret_cast<unsigned int*>(&keyLen)))
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530507 {
George Liu82844ef2024-07-17 17:03:56 +0800508 lg2::debug("Failed to create MAC for authentication");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530509 return -EIO;
510 }
511
512 // Generate IV values
513 if (RAND_bytes(iv.data(), ivLen) != 1)
514 {
George Liu82844ef2024-07-17 17:03:56 +0800515 lg2::debug("UV genertion failed, bailing out");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530516 return -EIO;
517 }
518
519 // Encrypt the input data
520 std::vector<uint8_t> outBytes(inBytesLen + EVP_MAX_BLOCK_LENGTH);
521 size_t outBytesLen = 0;
522 if (inBytesLen != 0)
523 {
Vernon Mauery1e22a0f2021-07-30 13:36:54 -0700524 if (encryptDecryptData(
525 true, EVP_aes_128_cbc(), key.data(), keyLen, iv.data(), ivLen,
526 reinterpret_cast<unsigned char*>(inBytes.data()), inBytesLen,
527 mac.data(), &macLen, outBytes.data(), &outBytesLen) != 0)
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530528 {
George Liu82844ef2024-07-17 17:03:56 +0800529 lg2::debug("Error while encrypting the data");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530530 return -EIO;
531 }
532 outBytes[outBytesLen] = 0;
533 }
534 OPENSSL_cleanse(key.data(), keyLen);
535
536 // Update the meta password structure.
Richard Marian Thomaiyar48e55582018-12-20 15:58:04 +0530537 MetaPassStruct metaData = {META_PASSWD_SIG, {0, 0}, 0, 0, 0, 0, 0};
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530538 metaData.hashSize = hashLen;
539 metaData.ivSize = ivLen;
540 metaData.dataSize = bytesWritten;
541 metaData.padSize = outBytesLen - bytesWritten;
542 metaData.macSize = macLen;
543
544 if (fwrite(&metaData, 1, sizeof(metaData), (temp)()) != sizeof(metaData))
545 {
George Liu82844ef2024-07-17 17:03:56 +0800546 lg2::debug("Error in writing meta data");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530547 return -EIO;
548 }
549
550 if (fwrite(&hash[0], 1, hashLen, (temp)()) != hashLen)
551 {
George Liu82844ef2024-07-17 17:03:56 +0800552 lg2::debug("Error in writing hash data");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530553 return -EIO;
554 }
555
556 if (fwrite(&iv[0], 1, ivLen, (temp)()) != ivLen)
557 {
George Liu82844ef2024-07-17 17:03:56 +0800558 lg2::debug("Error in writing IV data");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530559 return -EIO;
560 }
561
562 if (fwrite(&outBytes[0], 1, outBytesLen, (temp)()) != outBytesLen)
563 {
George Liu82844ef2024-07-17 17:03:56 +0800564 lg2::debug("Error in writing encrypted data");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530565 return -EIO;
566 }
567
568 if (fwrite(&mac[0], 1, macLen, (temp)()) != macLen)
569 {
George Liu82844ef2024-07-17 17:03:56 +0800570 lg2::debug("Error in writing MAC data");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530571 return -EIO;
572 }
573
574 if (fflush((temp)()))
575 {
George Liu82844ef2024-07-17 17:03:56 +0800576 lg2::debug("File fflush error while writing entries to special file");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530577 return -EIO;
578 }
579
580 OPENSSL_cleanse(iv.data(), ivLen);
581
582 // Rename the tmp file to actual file
583 if (std::rename(strTempFileName.data(), passwdFileName) != 0)
584 {
George Liu82844ef2024-07-17 17:03:56 +0800585 lg2::debug("Failed to rename tmp file to ipmi-pass");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530586 return -EIO;
587 }
588
589 return 0;
590}
591
592std::time_t PasswdMgr::getUpdatedFileTime()
593{
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530594 struct stat fileStat = {};
595 if (stat(passwdFileName, &fileStat) != 0)
596 {
George Liu82844ef2024-07-17 17:03:56 +0800597 lg2::debug("Error - Getting passwd file time stamp");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530598 return -EIO;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530599 }
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530600 return fileStat.st_mtime;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530601}
602
603} // namespace ipmi