blob: 345f3cc0ad345df7aa82829277a6bccdd07ab0af [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
AppaRao Pulib29b5ab2018-05-17 10:28:48 +053029#include <cerrno>
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +053030#include <cstring>
31#include <fstream>
AppaRao Pulib29b5ab2018-05-17 10:28:48 +053032#include <iomanip>
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +053033#include <phosphor-logging/log.hpp>
34
35namespace ipmi
36{
37
38static const char* passwdFileName = "/etc/ipmi_pass";
39static const char* encryptKeyFileName = "/etc/key_file";
40static const size_t maxKeySize = 8;
41
Richard Marian Thomaiyar6ba8d312020-04-10 23:52:50 +053042constexpr mode_t modeMask =
43 (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO);
44
AppaRao Pulib29b5ab2018-05-17 10:28:48 +053045#define META_PASSWD_SIG "=OPENBMC="
46
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +053047/*
48 * Meta data struct for encrypted password file
49 */
Richard Marian Thomaiyar48e55582018-12-20 15:58:04 +053050struct MetaPassStruct
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +053051{
52 char signature[10];
53 unsigned char reseved[2];
54 size_t hashSize;
55 size_t ivSize;
56 size_t dataSize;
57 size_t padSize;
58 size_t macSize;
59};
60
61using namespace phosphor::logging;
62
63PasswdMgr::PasswdMgr()
64{
Richard Marian Thomaiyar6ba8d312020-04-10 23:52:50 +053065 restrictFilesPermission();
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +053066 initPasswordMap();
67}
68
Richard Marian Thomaiyar6ba8d312020-04-10 23:52:50 +053069void PasswdMgr::restrictFilesPermission(void)
70{
71 struct stat st = {};
72 // Restrict file permission to owner read & write
73 if (stat(passwdFileName, &st) == 0)
74 {
75 if ((st.st_mode & modeMask) != (S_IRUSR | S_IWUSR))
76 {
77 chmod(passwdFileName, S_IRUSR | S_IWUSR);
78 }
79 }
80
81 if (stat(encryptKeyFileName, &st) == 0)
82 {
83 if ((st.st_mode & modeMask) != (S_IRUSR | S_IWUSR))
84 {
85 chmod(encryptKeyFileName, S_IRUSR | S_IWUSR);
86 }
87 }
88}
89
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +053090std::string PasswdMgr::getPasswdByUserName(const std::string& userName)
91{
92 checkAndReload();
93 auto iter = passwdMapList.find(userName);
94 if (iter == passwdMapList.end())
95 {
96 return std::string();
97 }
98 return iter->second;
99}
100
Richard Marian Thomaiyar42bed642018-09-21 12:28:57 +0530101int PasswdMgr::updateUserEntry(const std::string& userName,
102 const std::string& newUserName)
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530103{
104 std::time_t updatedTime = getUpdatedFileTime();
105 // Check file time stamp to know passwdMapList is up-to-date.
106 // If not up-to-date, then updatePasswdSpecialFile will read and
107 // check the user entry existance.
108 if (fileLastUpdatedTime == updatedTime && updatedTime != -EIO)
109 {
110 if (passwdMapList.find(userName) == passwdMapList.end())
111 {
112 log<level::DEBUG>("User not found");
113 return 0;
114 }
115 }
116
117 // Write passwdMap to Encryted file
Richard Marian Thomaiyar42bed642018-09-21 12:28:57 +0530118 if (updatePasswdSpecialFile(userName, newUserName) != 0)
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530119 {
120 log<level::DEBUG>("Passwd file update failed");
121 return -EIO;
122 }
123
124 log<level::DEBUG>("Passwd file updated successfully");
125 return 0;
126}
127
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530128void PasswdMgr::checkAndReload(void)
129{
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530130 std::time_t updatedTime = getUpdatedFileTime();
131 if (fileLastUpdatedTime != updatedTime && updatedTime != -1)
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530132 {
133 log<level::DEBUG>("Reloading password map list");
134 passwdMapList.clear();
135 initPasswordMap();
136 }
137}
138
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530139int PasswdMgr::encryptDecryptData(bool doEncrypt, const EVP_CIPHER* cipher,
140 uint8_t* key, size_t keyLen, uint8_t* iv,
141 size_t ivLen, uint8_t* inBytes,
142 size_t inBytesLen, uint8_t* mac,
143 size_t* macLen, unsigned char* outBytes,
144 size_t* outBytesLen)
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530145{
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530146 if (cipher == NULL || key == NULL || iv == NULL || inBytes == NULL ||
147 outBytes == NULL || mac == NULL || inBytesLen == 0 ||
148 (size_t)EVP_CIPHER_key_length(cipher) > keyLen ||
149 (size_t)EVP_CIPHER_iv_length(cipher) > ivLen)
150 {
151 log<level::DEBUG>("Error Invalid Inputs");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530152 return -EINVAL;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530153 }
154
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530155 if (!doEncrypt)
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530156 {
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530157 // verify MAC before decrypting the data.
158 std::array<uint8_t, EVP_MAX_MD_SIZE> calMac;
159 size_t calMacLen = calMac.size();
160 // calculate MAC for the encrypted message.
161 if (NULL == HMAC(EVP_sha256(), key, keyLen, inBytes, inBytesLen,
162 calMac.data(),
163 reinterpret_cast<unsigned int*>(&calMacLen)))
164 {
165 log<level::DEBUG>("Error: Failed to calculate MAC");
166 return -EIO;
167 }
168 if (!((calMacLen == *macLen) &&
169 (std::memcmp(calMac.data(), mac, calMacLen) == 0)))
170 {
171 log<level::DEBUG>("Authenticated message doesn't match");
172 return -EBADMSG;
173 }
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530174 }
175
176 std::unique_ptr<EVP_CIPHER_CTX, decltype(&::EVP_CIPHER_CTX_free)> ctx(
177 EVP_CIPHER_CTX_new(), ::EVP_CIPHER_CTX_free);
178 EVP_CIPHER_CTX_set_padding(ctx.get(), 1);
179
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530180 // Set key & IV
181 int retval = EVP_CipherInit_ex(ctx.get(), cipher, NULL, key, iv,
182 static_cast<int>(doEncrypt));
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530183 if (!retval)
184 {
185 log<level::DEBUG>("EVP_CipherInit_ex failed",
186 entry("RET_VAL=%d", retval));
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530187 return -EIO;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530188 }
189
190 int outLen = 0, outEVPLen = 0;
191 if ((retval = EVP_CipherUpdate(ctx.get(), outBytes + outLen, &outEVPLen,
192 inBytes, inBytesLen)))
193 {
194 outLen += outEVPLen;
195 if ((retval =
196 EVP_CipherFinal(ctx.get(), outBytes + outLen, &outEVPLen)))
197 {
198 outLen += outEVPLen;
199 *outBytesLen = outLen;
200 }
201 else
202 {
203 log<level::DEBUG>("EVP_CipherFinal fails",
204 entry("RET_VAL=%d", retval));
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530205 return -EIO;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530206 }
207 }
208 else
209 {
210 log<level::DEBUG>("EVP_CipherUpdate fails",
211 entry("RET_VAL=%d", retval));
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530212 return -EIO;
213 }
214
215 if (doEncrypt)
216 {
217 // Create MAC for the encrypted message
218 if (NULL == HMAC(EVP_sha256(), key, keyLen, outBytes, *outBytesLen, mac,
219 reinterpret_cast<unsigned int*>(macLen)))
220 {
221 log<level::DEBUG>("Failed to create authentication");
222 return -EIO;
223 }
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530224 }
225 return 0;
226}
227
228void PasswdMgr::initPasswordMap(void)
229{
Andrew Geissler2f0ad742021-05-14 13:39:15 -0500230 // TODO phosphor-host-ipmid#170 phosphor::user::shadow::Lock lock{};
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530231 std::vector<uint8_t> dataBuf;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530232
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530233 if (readPasswdFileData(dataBuf) != 0)
234 {
235 log<level::DEBUG>("Error in reading the encrypted pass file");
236 return;
237 }
238
239 if (dataBuf.size() != 0)
240 {
241 // populate the user list with password
242 char* outPtr = reinterpret_cast<char*>(dataBuf.data());
243 char* nToken = NULL;
244 char* linePtr = strtok_r(outPtr, "\n", &nToken);
Patrick Venture51d0c402019-08-19 11:19:19 -0700245 size_t lineSize = 0;
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530246 while (linePtr != NULL)
247 {
Patrick Venture51d0c402019-08-19 11:19:19 -0700248 size_t userEPos = 0;
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530249 std::string lineStr(linePtr);
250 if ((userEPos = lineStr.find(":")) != std::string::npos)
251 {
252 lineSize = lineStr.size();
253 passwdMapList.emplace(
254 lineStr.substr(0, userEPos),
255 lineStr.substr(userEPos + 1, lineSize - (userEPos + 1)));
256 }
257 linePtr = strtok_r(NULL, "\n", &nToken);
258 }
259 }
260
261 // Update the timestamp
262 fileLastUpdatedTime = getUpdatedFileTime();
Jayaprakash Mutyala70bd0632020-10-23 06:24:55 +0000263 // Clear sensitive data
264 OPENSSL_cleanse(dataBuf.data(), dataBuf.size());
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530265 return;
266}
267
268int PasswdMgr::readPasswdFileData(std::vector<uint8_t>& outBytes)
269{
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530270 std::array<uint8_t, maxKeySize> keyBuff;
271 std::ifstream keyFile(encryptKeyFileName, std::ios::in | std::ios::binary);
272 if (!keyFile.is_open())
273 {
274 log<level::DEBUG>("Error in opening encryption key file");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530275 return -EIO;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530276 }
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530277 keyFile.read(reinterpret_cast<char*>(keyBuff.data()), keyBuff.size());
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530278 if (keyFile.fail())
279 {
280 log<level::DEBUG>("Error in reading encryption key file");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530281 return -EIO;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530282 }
283
284 std::ifstream passwdFile(passwdFileName, std::ios::in | std::ios::binary);
285 if (!passwdFile.is_open())
286 {
287 log<level::DEBUG>("Error in opening ipmi password file");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530288 return -EIO;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530289 }
290
291 // calculate file size and read the data
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530292 passwdFile.seekg(0, std::ios::end);
293 ssize_t fileSize = passwdFile.tellg();
294 passwdFile.seekg(0, std::ios::beg);
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530295 std::vector<uint8_t> input(fileSize);
296 passwdFile.read(reinterpret_cast<char*>(input.data()), fileSize);
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530297 if (passwdFile.fail())
298 {
299 log<level::DEBUG>("Error in reading encryption key file");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530300 return -EIO;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530301 }
302
303 // verify the signature first
Richard Marian Thomaiyar48e55582018-12-20 15:58:04 +0530304 MetaPassStruct* metaData = reinterpret_cast<MetaPassStruct*>(input.data());
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530305 if (std::strncmp(metaData->signature, META_PASSWD_SIG,
306 sizeof(metaData->signature)))
307 {
308 log<level::DEBUG>("Error signature mismatch in password file");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530309 return -EBADMSG;
310 }
311
312 size_t inBytesLen = metaData->dataSize + metaData->padSize;
313 // If data is empty i.e no password map then return success
314 if (inBytesLen == 0)
315 {
316 log<level::DEBUG>("Empty password file");
317 return 0;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530318 }
319
320 // compute the key needed to decrypt
321 std::array<uint8_t, EVP_MAX_KEY_LENGTH> key;
322 auto keyLen = key.size();
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530323 if (NULL == HMAC(EVP_sha256(), keyBuff.data(), keyBuff.size(),
324 input.data() + sizeof(*metaData), metaData->hashSize,
325 key.data(), reinterpret_cast<unsigned int*>(&keyLen)))
326 {
327 log<level::DEBUG>("Failed to create MAC for authentication");
328 return -EIO;
329 }
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530330
331 // decrypt the data
332 uint8_t* iv = input.data() + sizeof(*metaData) + metaData->hashSize;
333 size_t ivLen = metaData->ivSize;
334 uint8_t* inBytes = iv + ivLen;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530335 uint8_t* mac = inBytes + inBytesLen;
336 size_t macLen = metaData->macSize;
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530337
338 size_t outBytesLen = 0;
339 // Resize to actual data size
340 outBytes.resize(inBytesLen + EVP_MAX_BLOCK_LENGTH);
341 if (encryptDecryptData(false, EVP_aes_128_cbc(), key.data(), keyLen, iv,
342 ivLen, inBytes, inBytesLen, mac, &macLen,
343 outBytes.data(), &outBytesLen) != 0)
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530344 {
345 log<level::DEBUG>("Error in decryption");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530346 return -EIO;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530347 }
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530348 // Resize the vector to outBytesLen
349 outBytes.resize(outBytesLen);
350
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530351 OPENSSL_cleanse(key.data(), keyLen);
352 OPENSSL_cleanse(iv, ivLen);
353
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530354 return 0;
355}
356
Richard Marian Thomaiyar42bed642018-09-21 12:28:57 +0530357int PasswdMgr::updatePasswdSpecialFile(const std::string& userName,
358 const std::string& newUserName)
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530359{
Andrew Geissler2f0ad742021-05-14 13:39:15 -0500360 // TODO phosphor-host-ipmid#170 phosphor::user::shadow::Lock lock{};
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530361
362 size_t bytesWritten = 0;
363 size_t inBytesLen = 0;
364 size_t isUsrFound = false;
365 const EVP_CIPHER* cipher = EVP_aes_128_cbc();
366 std::vector<uint8_t> dataBuf;
367
368 // Read the encrypted file and get the file data
369 // Check user existance and return if not exist.
370 if (readPasswdFileData(dataBuf) != 0)
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530371 {
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530372 log<level::DEBUG>("Error in reading the encrypted pass file");
373 return -EIO;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530374 }
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530375
376 if (dataBuf.size() != 0)
377 {
Richard Marian Thomaiyar42bed642018-09-21 12:28:57 +0530378 inBytesLen =
379 dataBuf.size() + newUserName.size() + EVP_CIPHER_block_size(cipher);
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530380 }
381
382 std::vector<uint8_t> inBytes(inBytesLen);
383 if (inBytesLen != 0)
384 {
385 char* outPtr = reinterpret_cast<char*>(dataBuf.data());
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530386 char* nToken = NULL;
387 char* linePtr = strtok_r(outPtr, "\n", &nToken);
388 while (linePtr != NULL)
389 {
Patrick Venture51d0c402019-08-19 11:19:19 -0700390 size_t userEPos = 0;
391
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530392 std::string lineStr(linePtr);
393 if ((userEPos = lineStr.find(":")) != std::string::npos)
394 {
395 if (userName.compare(lineStr.substr(0, userEPos)) == 0)
396 {
397 isUsrFound = true;
Richard Marian Thomaiyar42bed642018-09-21 12:28:57 +0530398 if (!newUserName.empty())
399 {
400 bytesWritten += std::snprintf(
401 reinterpret_cast<char*>(&inBytes[0]) + bytesWritten,
402 (inBytesLen - bytesWritten), "%s%s\n",
403 newUserName.c_str(),
404 lineStr.substr(userEPos, lineStr.size()).data());
405 }
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530406 }
407 else
408 {
409 bytesWritten += std::snprintf(
410 reinterpret_cast<char*>(&inBytes[0]) + bytesWritten,
Richard Marian Thomaiyar42bed642018-09-21 12:28:57 +0530411 (inBytesLen - bytesWritten), "%s\n", lineStr.data());
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530412 }
413 }
414 linePtr = strtok_r(NULL, "\n", &nToken);
415 }
Richard Marian Thomaiyar161f20d2019-01-28 20:33:16 +0530416 inBytesLen = bytesWritten;
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530417 }
418 if (!isUsrFound)
419 {
420 log<level::DEBUG>("User doesn't exist");
421 return 0;
422 }
423
424 // Read the key buff from key file
425 std::array<uint8_t, maxKeySize> keyBuff;
426 std::ifstream keyFile(encryptKeyFileName, std::ios::in | std::ios::binary);
427 if (!keyFile.good())
428 {
429 log<level::DEBUG>("Error in opening encryption key file");
430 return -EIO;
431 }
432 keyFile.read(reinterpret_cast<char*>(keyBuff.data()), keyBuff.size());
433 if (keyFile.fail())
434 {
435 log<level::DEBUG>("Error in reading encryption key file");
436 return -EIO;
437 }
438 keyFile.close();
439
440 // Read the original passwd file mode
441 struct stat st = {};
442 if (stat(passwdFileName, &st) != 0)
443 {
444 log<level::DEBUG>("Error in getting password file fstat()");
445 return -EIO;
446 }
447
448 // Create temporary file for write
449 std::string pwdFile(passwdFileName);
450 std::vector<char> tempFileName(pwdFile.begin(), pwdFile.end());
451 std::vector<char> fileTemplate = {'_', '_', 'X', 'X', 'X',
452 'X', 'X', 'X', '\0'};
453 tempFileName.insert(tempFileName.end(), fileTemplate.begin(),
454 fileTemplate.end());
455 int fd = mkstemp((char*)tempFileName.data());
456 if (fd == -1)
457 {
458 log<level::DEBUG>("Error creating temp file");
459 return -EIO;
460 }
461
462 std::string strTempFileName(tempFileName.data());
463 // Open the temp file for writing from provided fd
464 // By "true", remove it at exit if still there.
465 // This is needed to cleanup the temp file at exception
466 phosphor::user::File temp(fd, strTempFileName, "w", true);
467 if ((temp)() == NULL)
468 {
469 close(fd);
470 log<level::DEBUG>("Error creating temp file");
471 return -EIO;
472 }
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530473
Vernon Maueryb2654552020-04-03 14:28:53 -0700474 // Set the file mode as read-write for owner only
475 if (fchmod(fileno((temp)()), S_IRUSR | S_IWUSR) < 0)
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530476 {
477 log<level::DEBUG>("Error setting fchmod for temp file");
478 return -EIO;
479 }
480
481 const EVP_MD* digest = EVP_sha256();
482 size_t hashLen = EVP_MD_block_size(digest);
483 std::vector<uint8_t> hash(hashLen);
484 size_t ivLen = EVP_CIPHER_iv_length(cipher);
485 std::vector<uint8_t> iv(ivLen);
486 std::array<uint8_t, EVP_MAX_KEY_LENGTH> key;
487 size_t keyLen = key.size();
488 std::array<uint8_t, EVP_MAX_MD_SIZE> mac;
489 size_t macLen = mac.size();
490
491 // Create random hash and generate hash key which will be used for
492 // encryption.
493 if (RAND_bytes(hash.data(), hashLen) != 1)
494 {
495 log<level::DEBUG>("Hash genertion failed, bailing out");
496 return -EIO;
497 }
498 if (NULL == HMAC(digest, keyBuff.data(), keyBuff.size(), hash.data(),
499 hashLen, key.data(),
500 reinterpret_cast<unsigned int*>(&keyLen)))
501 {
502 log<level::DEBUG>("Failed to create MAC for authentication");
503 return -EIO;
504 }
505
506 // Generate IV values
507 if (RAND_bytes(iv.data(), ivLen) != 1)
508 {
509 log<level::DEBUG>("UV genertion failed, bailing out");
510 return -EIO;
511 }
512
513 // Encrypt the input data
514 std::vector<uint8_t> outBytes(inBytesLen + EVP_MAX_BLOCK_LENGTH);
515 size_t outBytesLen = 0;
516 if (inBytesLen != 0)
517 {
518 if (encryptDecryptData(true, EVP_aes_128_cbc(), key.data(), keyLen,
519 iv.data(), ivLen, inBytes.data(), inBytesLen,
520 mac.data(), &macLen, outBytes.data(),
521 &outBytesLen) != 0)
522 {
523 log<level::DEBUG>("Error while encrypting the data");
524 return -EIO;
525 }
526 outBytes[outBytesLen] = 0;
527 }
528 OPENSSL_cleanse(key.data(), keyLen);
529
530 // Update the meta password structure.
Richard Marian Thomaiyar48e55582018-12-20 15:58:04 +0530531 MetaPassStruct metaData = {META_PASSWD_SIG, {0, 0}, 0, 0, 0, 0, 0};
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530532 metaData.hashSize = hashLen;
533 metaData.ivSize = ivLen;
534 metaData.dataSize = bytesWritten;
535 metaData.padSize = outBytesLen - bytesWritten;
536 metaData.macSize = macLen;
537
538 if (fwrite(&metaData, 1, sizeof(metaData), (temp)()) != sizeof(metaData))
539 {
540 log<level::DEBUG>("Error in writing meta data");
541 return -EIO;
542 }
543
544 if (fwrite(&hash[0], 1, hashLen, (temp)()) != hashLen)
545 {
546 log<level::DEBUG>("Error in writing hash data");
547 return -EIO;
548 }
549
550 if (fwrite(&iv[0], 1, ivLen, (temp)()) != ivLen)
551 {
552 log<level::DEBUG>("Error in writing IV data");
553 return -EIO;
554 }
555
556 if (fwrite(&outBytes[0], 1, outBytesLen, (temp)()) != outBytesLen)
557 {
558 log<level::DEBUG>("Error in writing encrypted data");
559 return -EIO;
560 }
561
562 if (fwrite(&mac[0], 1, macLen, (temp)()) != macLen)
563 {
564 log<level::DEBUG>("Error in writing MAC data");
565 return -EIO;
566 }
567
568 if (fflush((temp)()))
569 {
570 log<level::DEBUG>(
571 "File fflush error while writing entries to special file");
572 return -EIO;
573 }
574
575 OPENSSL_cleanse(iv.data(), ivLen);
576
577 // Rename the tmp file to actual file
578 if (std::rename(strTempFileName.data(), passwdFileName) != 0)
579 {
580 log<level::DEBUG>("Failed to rename tmp file to ipmi-pass");
581 return -EIO;
582 }
583
584 return 0;
585}
586
587std::time_t PasswdMgr::getUpdatedFileTime()
588{
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530589 struct stat fileStat = {};
590 if (stat(passwdFileName, &fileStat) != 0)
591 {
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530592 log<level::DEBUG>("Error - Getting passwd file time stamp");
593 return -EIO;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530594 }
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530595 return fileStat.st_mtime;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530596}
597
598} // namespace ipmi