14654d99fSRichard Marian Thomaiyar /*
24654d99fSRichard Marian Thomaiyar // Copyright (c) 2018 Intel Corporation
34654d99fSRichard Marian Thomaiyar //
44654d99fSRichard Marian Thomaiyar // Licensed under the Apache License, Version 2.0 (the "License");
54654d99fSRichard Marian Thomaiyar // you may not use this file except in compliance with the License.
64654d99fSRichard Marian Thomaiyar // You may obtain a copy of the License at
74654d99fSRichard Marian Thomaiyar //
84654d99fSRichard Marian Thomaiyar // http://www.apache.org/licenses/LICENSE-2.0
94654d99fSRichard Marian Thomaiyar //
104654d99fSRichard Marian Thomaiyar // Unless required by applicable law or agreed to in writing, software
114654d99fSRichard Marian Thomaiyar // distributed under the License is distributed on an "AS IS" BASIS,
124654d99fSRichard Marian Thomaiyar // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134654d99fSRichard Marian Thomaiyar // See the License for the specific language governing permissions and
144654d99fSRichard Marian Thomaiyar // limitations under the License.
154654d99fSRichard Marian Thomaiyar */
164654d99fSRichard Marian Thomaiyar
174654d99fSRichard Marian Thomaiyar #include "passwd_mgr.hpp"
184654d99fSRichard Marian Thomaiyar
19b29b5ab3SAppaRao Puli #include "file.hpp"
204654d99fSRichard Marian Thomaiyar #include "shadowlock.hpp"
214654d99fSRichard Marian Thomaiyar
224654d99fSRichard Marian Thomaiyar #include <openssl/hmac.h>
23b29b5ab3SAppaRao Puli #include <openssl/rand.h>
244654d99fSRichard Marian Thomaiyar #include <openssl/sha.h>
254654d99fSRichard Marian Thomaiyar #include <string.h>
264654d99fSRichard Marian Thomaiyar #include <sys/stat.h>
27b29b5ab3SAppaRao Puli #include <unistd.h>
284654d99fSRichard Marian Thomaiyar
2982844ef6SGeorge Liu #include <phosphor-logging/lg2.hpp>
30fbc6c9d7SPatrick Williams
31b29b5ab3SAppaRao Puli #include <cerrno>
324654d99fSRichard Marian Thomaiyar #include <cstring>
334654d99fSRichard Marian Thomaiyar #include <fstream>
34b29b5ab3SAppaRao Puli #include <iomanip>
354654d99fSRichard Marian Thomaiyar
364654d99fSRichard Marian Thomaiyar namespace ipmi
374654d99fSRichard Marian Thomaiyar {
384654d99fSRichard Marian Thomaiyar
394654d99fSRichard Marian Thomaiyar static const char* passwdFileName = "/etc/ipmi_pass";
404654d99fSRichard Marian Thomaiyar static const char* encryptKeyFileName = "/etc/key_file";
414654d99fSRichard Marian Thomaiyar static const size_t maxKeySize = 8;
424654d99fSRichard Marian Thomaiyar
436ba8d315SRichard Marian Thomaiyar constexpr mode_t modeMask =
446ba8d315SRichard Marian Thomaiyar (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO);
456ba8d315SRichard Marian Thomaiyar
46b29b5ab3SAppaRao Puli #define META_PASSWD_SIG "=OPENBMC="
47b29b5ab3SAppaRao Puli
484654d99fSRichard Marian Thomaiyar /*
494654d99fSRichard Marian Thomaiyar * Meta data struct for encrypted password file
504654d99fSRichard Marian Thomaiyar */
5148e55585SRichard Marian Thomaiyar struct MetaPassStruct
524654d99fSRichard Marian Thomaiyar {
534654d99fSRichard Marian Thomaiyar char signature[10];
544654d99fSRichard Marian Thomaiyar unsigned char reseved[2];
5565a9168cSTim Lee size_t hashSize;
5665a9168cSTim Lee size_t ivSize;
5765a9168cSTim Lee size_t dataSize;
5865a9168cSTim Lee size_t padSize;
5965a9168cSTim Lee size_t macSize;
604654d99fSRichard Marian Thomaiyar };
614654d99fSRichard Marian Thomaiyar
PasswdMgr()624654d99fSRichard Marian Thomaiyar PasswdMgr::PasswdMgr()
634654d99fSRichard Marian Thomaiyar {
646ba8d315SRichard Marian Thomaiyar restrictFilesPermission();
654654d99fSRichard Marian Thomaiyar initPasswordMap();
664654d99fSRichard Marian Thomaiyar }
674654d99fSRichard Marian Thomaiyar
restrictFilesPermission(void)686ba8d315SRichard Marian Thomaiyar void PasswdMgr::restrictFilesPermission(void)
696ba8d315SRichard Marian Thomaiyar {
706ba8d315SRichard Marian Thomaiyar struct stat st = {};
716ba8d315SRichard Marian Thomaiyar // Restrict file permission to owner read & write
726ba8d315SRichard Marian Thomaiyar if (stat(passwdFileName, &st) == 0)
736ba8d315SRichard Marian Thomaiyar {
746ba8d315SRichard Marian Thomaiyar if ((st.st_mode & modeMask) != (S_IRUSR | S_IWUSR))
756ba8d315SRichard Marian Thomaiyar {
763771f5f2SPavanKumarIntel if (chmod(passwdFileName, S_IRUSR | S_IWUSR) == -1)
773771f5f2SPavanKumarIntel {
7882844ef6SGeorge Liu lg2::debug("Error setting chmod for ipmi_pass file");
793771f5f2SPavanKumarIntel }
806ba8d315SRichard Marian Thomaiyar }
816ba8d315SRichard Marian Thomaiyar }
826ba8d315SRichard Marian Thomaiyar
836ba8d315SRichard Marian Thomaiyar if (stat(encryptKeyFileName, &st) == 0)
846ba8d315SRichard Marian Thomaiyar {
856ba8d315SRichard Marian Thomaiyar if ((st.st_mode & modeMask) != (S_IRUSR | S_IWUSR))
866ba8d315SRichard Marian Thomaiyar {
873771f5f2SPavanKumarIntel if (chmod(encryptKeyFileName, S_IRUSR | S_IWUSR) == -1)
883771f5f2SPavanKumarIntel {
8982844ef6SGeorge Liu lg2::debug("Error setting chmod for ipmi_pass file");
903771f5f2SPavanKumarIntel }
916ba8d315SRichard Marian Thomaiyar }
926ba8d315SRichard Marian Thomaiyar }
936ba8d315SRichard Marian Thomaiyar }
946ba8d315SRichard Marian Thomaiyar
getPasswdByUserName(const std::string & userName)951e22a0f1SVernon Mauery SecureString PasswdMgr::getPasswdByUserName(const std::string& userName)
964654d99fSRichard Marian Thomaiyar {
974654d99fSRichard Marian Thomaiyar checkAndReload();
984654d99fSRichard Marian Thomaiyar auto iter = passwdMapList.find(userName);
994654d99fSRichard Marian Thomaiyar if (iter == passwdMapList.end())
1004654d99fSRichard Marian Thomaiyar {
1011e22a0f1SVernon Mauery return SecureString();
1024654d99fSRichard Marian Thomaiyar }
1034654d99fSRichard Marian Thomaiyar return iter->second;
1044654d99fSRichard Marian Thomaiyar }
1054654d99fSRichard Marian Thomaiyar
updateUserEntry(const std::string & userName,const std::string & newUserName)10642bed64dSRichard Marian Thomaiyar int PasswdMgr::updateUserEntry(const std::string& userName,
10742bed64dSRichard Marian Thomaiyar const std::string& newUserName)
108b29b5ab3SAppaRao Puli {
109b29b5ab3SAppaRao Puli std::time_t updatedTime = getUpdatedFileTime();
110b29b5ab3SAppaRao Puli // Check file time stamp to know passwdMapList is up-to-date.
111b29b5ab3SAppaRao Puli // If not up-to-date, then updatePasswdSpecialFile will read and
112b29b5ab3SAppaRao Puli // check the user entry existance.
113b29b5ab3SAppaRao Puli if (fileLastUpdatedTime == updatedTime && updatedTime != -EIO)
114b29b5ab3SAppaRao Puli {
115b29b5ab3SAppaRao Puli if (passwdMapList.find(userName) == passwdMapList.end())
116b29b5ab3SAppaRao Puli {
11782844ef6SGeorge Liu lg2::debug("User not found");
118b29b5ab3SAppaRao Puli return 0;
119b29b5ab3SAppaRao Puli }
120b29b5ab3SAppaRao Puli }
121b29b5ab3SAppaRao Puli
122b29b5ab3SAppaRao Puli // Write passwdMap to Encryted file
12342bed64dSRichard Marian Thomaiyar if (updatePasswdSpecialFile(userName, newUserName) != 0)
124b29b5ab3SAppaRao Puli {
12582844ef6SGeorge Liu lg2::debug("Passwd file update failed");
126b29b5ab3SAppaRao Puli return -EIO;
127b29b5ab3SAppaRao Puli }
128b29b5ab3SAppaRao Puli
12982844ef6SGeorge Liu lg2::debug("Passwd file updated successfully");
130b29b5ab3SAppaRao Puli return 0;
131b29b5ab3SAppaRao Puli }
132b29b5ab3SAppaRao Puli
checkAndReload(void)1334654d99fSRichard Marian Thomaiyar void PasswdMgr::checkAndReload(void)
1344654d99fSRichard Marian Thomaiyar {
135b29b5ab3SAppaRao Puli std::time_t updatedTime = getUpdatedFileTime();
136b29b5ab3SAppaRao Puli if (fileLastUpdatedTime != updatedTime && updatedTime != -1)
1374654d99fSRichard Marian Thomaiyar {
13882844ef6SGeorge Liu lg2::debug("Reloading password map list");
1394654d99fSRichard Marian Thomaiyar passwdMapList.clear();
1404654d99fSRichard Marian Thomaiyar initPasswordMap();
1414654d99fSRichard Marian Thomaiyar }
1424654d99fSRichard Marian Thomaiyar }
1434654d99fSRichard Marian Thomaiyar
encryptDecryptData(bool doEncrypt,const EVP_CIPHER * cipher,uint8_t * key,size_t keyLen,uint8_t * iv,size_t ivLen,uint8_t * inBytes,size_t inBytesLen,uint8_t * mac,size_t * macLen,unsigned char * outBytes,size_t * outBytesLen)144*1318a5edSPatrick Williams int PasswdMgr::encryptDecryptData(
145*1318a5edSPatrick Williams bool doEncrypt, const EVP_CIPHER* cipher, uint8_t* key, size_t keyLen,
146*1318a5edSPatrick Williams uint8_t* iv, size_t ivLen, uint8_t* inBytes, size_t inBytesLen,
147*1318a5edSPatrick Williams uint8_t* mac, size_t* macLen, unsigned char* outBytes, size_t* outBytesLen)
1484654d99fSRichard Marian Thomaiyar {
1494654d99fSRichard Marian Thomaiyar if (cipher == NULL || key == NULL || iv == NULL || inBytes == NULL ||
1504654d99fSRichard Marian Thomaiyar outBytes == NULL || mac == NULL || inBytesLen == 0 ||
1514654d99fSRichard Marian Thomaiyar (size_t)EVP_CIPHER_key_length(cipher) > keyLen ||
1524654d99fSRichard Marian Thomaiyar (size_t)EVP_CIPHER_iv_length(cipher) > ivLen)
1534654d99fSRichard Marian Thomaiyar {
15482844ef6SGeorge Liu lg2::debug("Error Invalid Inputs");
155b29b5ab3SAppaRao Puli return -EINVAL;
1564654d99fSRichard Marian Thomaiyar }
1574654d99fSRichard Marian Thomaiyar
158b29b5ab3SAppaRao Puli if (!doEncrypt)
159b29b5ab3SAppaRao Puli {
160b29b5ab3SAppaRao Puli // verify MAC before decrypting the data.
1614654d99fSRichard Marian Thomaiyar std::array<uint8_t, EVP_MAX_MD_SIZE> calMac;
1624654d99fSRichard Marian Thomaiyar size_t calMacLen = calMac.size();
1634654d99fSRichard Marian Thomaiyar // calculate MAC for the encrypted message.
164*1318a5edSPatrick Williams if (NULL ==
165*1318a5edSPatrick Williams HMAC(EVP_sha256(), key, keyLen, inBytes, inBytesLen, calMac.data(),
1664654d99fSRichard Marian Thomaiyar reinterpret_cast<unsigned int*>(&calMacLen)))
1674654d99fSRichard Marian Thomaiyar {
16882844ef6SGeorge Liu lg2::debug("Error: Failed to calculate MAC");
169b29b5ab3SAppaRao Puli return -EIO;
1704654d99fSRichard Marian Thomaiyar }
171b29b5ab3SAppaRao Puli if (!((calMacLen == *macLen) &&
1724654d99fSRichard Marian Thomaiyar (std::memcmp(calMac.data(), mac, calMacLen) == 0)))
1734654d99fSRichard Marian Thomaiyar {
17482844ef6SGeorge Liu lg2::debug("Authenticated message doesn't match");
175b29b5ab3SAppaRao Puli return -EBADMSG;
176b29b5ab3SAppaRao Puli }
1774654d99fSRichard Marian Thomaiyar }
1784654d99fSRichard Marian Thomaiyar
1794654d99fSRichard Marian Thomaiyar std::unique_ptr<EVP_CIPHER_CTX, decltype(&::EVP_CIPHER_CTX_free)> ctx(
1804654d99fSRichard Marian Thomaiyar EVP_CIPHER_CTX_new(), ::EVP_CIPHER_CTX_free);
1814654d99fSRichard Marian Thomaiyar
182bf30c8d3SP Dheeraj Srujan Kumar if (!ctx)
183bf30c8d3SP Dheeraj Srujan Kumar {
18482844ef6SGeorge Liu lg2::debug("Error: EVP_CIPHER_CTX is NULL");
185bf30c8d3SP Dheeraj Srujan Kumar return -ENOMEM;
186bf30c8d3SP Dheeraj Srujan Kumar }
187bf30c8d3SP Dheeraj Srujan Kumar
188a67caed7SP Dheeraj Srujan Kumar EVP_CIPHER_CTX_set_padding(ctx.get(), 1);
189a67caed7SP Dheeraj Srujan Kumar
190b29b5ab3SAppaRao Puli // Set key & IV
191b29b5ab3SAppaRao Puli int retval = EVP_CipherInit_ex(ctx.get(), cipher, NULL, key, iv,
192b29b5ab3SAppaRao Puli static_cast<int>(doEncrypt));
1934654d99fSRichard Marian Thomaiyar if (!retval)
1944654d99fSRichard Marian Thomaiyar {
19582844ef6SGeorge Liu lg2::debug("EVP_CipherInit_ex failed: {RET_VAL}", "RET_VAL", retval);
196b29b5ab3SAppaRao Puli return -EIO;
1974654d99fSRichard Marian Thomaiyar }
1984654d99fSRichard Marian Thomaiyar
1994654d99fSRichard Marian Thomaiyar int outLen = 0, outEVPLen = 0;
2004654d99fSRichard Marian Thomaiyar if ((retval = EVP_CipherUpdate(ctx.get(), outBytes + outLen, &outEVPLen,
2014654d99fSRichard Marian Thomaiyar inBytes, inBytesLen)))
2024654d99fSRichard Marian Thomaiyar {
2034654d99fSRichard Marian Thomaiyar outLen += outEVPLen;
204*1318a5edSPatrick Williams if ((retval =
205*1318a5edSPatrick Williams EVP_CipherFinal(ctx.get(), outBytes + outLen, &outEVPLen)))
2064654d99fSRichard Marian Thomaiyar {
2074654d99fSRichard Marian Thomaiyar outLen += outEVPLen;
2084654d99fSRichard Marian Thomaiyar *outBytesLen = outLen;
2094654d99fSRichard Marian Thomaiyar }
2104654d99fSRichard Marian Thomaiyar else
2114654d99fSRichard Marian Thomaiyar {
21282844ef6SGeorge Liu lg2::debug("EVP_CipherFinal fails: {RET_VAL}", "RET_VAL", retval);
213b29b5ab3SAppaRao Puli return -EIO;
2144654d99fSRichard Marian Thomaiyar }
2154654d99fSRichard Marian Thomaiyar }
2164654d99fSRichard Marian Thomaiyar else
2174654d99fSRichard Marian Thomaiyar {
21882844ef6SGeorge Liu lg2::debug("EVP_CipherUpdate fails: {RET_VAL}", "RET_VAL", retval);
219b29b5ab3SAppaRao Puli return -EIO;
220b29b5ab3SAppaRao Puli }
221b29b5ab3SAppaRao Puli
222b29b5ab3SAppaRao Puli if (doEncrypt)
223b29b5ab3SAppaRao Puli {
224b29b5ab3SAppaRao Puli // Create MAC for the encrypted message
225b29b5ab3SAppaRao Puli if (NULL == HMAC(EVP_sha256(), key, keyLen, outBytes, *outBytesLen, mac,
226b29b5ab3SAppaRao Puli reinterpret_cast<unsigned int*>(macLen)))
227b29b5ab3SAppaRao Puli {
22882844ef6SGeorge Liu lg2::debug("Failed to create authentication");
229b29b5ab3SAppaRao Puli return -EIO;
230b29b5ab3SAppaRao Puli }
2314654d99fSRichard Marian Thomaiyar }
2324654d99fSRichard Marian Thomaiyar return 0;
2334654d99fSRichard Marian Thomaiyar }
2344654d99fSRichard Marian Thomaiyar
initPasswordMap(void)2354654d99fSRichard Marian Thomaiyar void PasswdMgr::initPasswordMap(void)
2364654d99fSRichard Marian Thomaiyar {
2372f0ad74dSAndrew Geissler // TODO phosphor-host-ipmid#170 phosphor::user::shadow::Lock lock{};
2381e22a0f1SVernon Mauery SecureString dataBuf;
2394654d99fSRichard Marian Thomaiyar
240b29b5ab3SAppaRao Puli if (readPasswdFileData(dataBuf) != 0)
2414654d99fSRichard Marian Thomaiyar {
24282844ef6SGeorge Liu lg2::debug("Error in reading the encrypted pass file");
2434654d99fSRichard Marian Thomaiyar return;
2444654d99fSRichard Marian Thomaiyar }
2454654d99fSRichard Marian Thomaiyar
246b29b5ab3SAppaRao Puli if (dataBuf.size() != 0)
2474654d99fSRichard Marian Thomaiyar {
2484654d99fSRichard Marian Thomaiyar // populate the user list with password
2491e22a0f1SVernon Mauery char* outPtr = dataBuf.data();
2504654d99fSRichard Marian Thomaiyar char* nToken = NULL;
2514654d99fSRichard Marian Thomaiyar char* linePtr = strtok_r(outPtr, "\n", &nToken);
25251d0c40aSPatrick Venture size_t lineSize = 0;
2534654d99fSRichard Marian Thomaiyar while (linePtr != NULL)
2544654d99fSRichard Marian Thomaiyar {
25551d0c40aSPatrick Venture size_t userEPos = 0;
2561e22a0f1SVernon Mauery SecureString lineStr(linePtr);
2574654d99fSRichard Marian Thomaiyar if ((userEPos = lineStr.find(":")) != std::string::npos)
2584654d99fSRichard Marian Thomaiyar {
2594654d99fSRichard Marian Thomaiyar lineSize = lineStr.size();
2604654d99fSRichard Marian Thomaiyar passwdMapList.emplace(
2614654d99fSRichard Marian Thomaiyar lineStr.substr(0, userEPos),
2624654d99fSRichard Marian Thomaiyar lineStr.substr(userEPos + 1, lineSize - (userEPos + 1)));
2634654d99fSRichard Marian Thomaiyar }
2644654d99fSRichard Marian Thomaiyar linePtr = strtok_r(NULL, "\n", &nToken);
2654654d99fSRichard Marian Thomaiyar }
266b29b5ab3SAppaRao Puli }
267b29b5ab3SAppaRao Puli
2684654d99fSRichard Marian Thomaiyar // Update the timestamp
269b29b5ab3SAppaRao Puli fileLastUpdatedTime = getUpdatedFileTime();
270b29b5ab3SAppaRao Puli return;
271b29b5ab3SAppaRao Puli }
272b29b5ab3SAppaRao Puli
readPasswdFileData(SecureString & outBytes)2731e22a0f1SVernon Mauery int PasswdMgr::readPasswdFileData(SecureString& outBytes)
274b29b5ab3SAppaRao Puli {
275b29b5ab3SAppaRao Puli std::array<uint8_t, maxKeySize> keyBuff;
276b29b5ab3SAppaRao Puli std::ifstream keyFile(encryptKeyFileName, std::ios::in | std::ios::binary);
277b29b5ab3SAppaRao Puli if (!keyFile.is_open())
278b29b5ab3SAppaRao Puli {
27982844ef6SGeorge Liu lg2::debug("Error in opening encryption key file");
280b29b5ab3SAppaRao Puli return -EIO;
281b29b5ab3SAppaRao Puli }
282b29b5ab3SAppaRao Puli keyFile.read(reinterpret_cast<char*>(keyBuff.data()), keyBuff.size());
283b29b5ab3SAppaRao Puli if (keyFile.fail())
284b29b5ab3SAppaRao Puli {
28582844ef6SGeorge Liu lg2::debug("Error in reading encryption key file");
286b29b5ab3SAppaRao Puli return -EIO;
287b29b5ab3SAppaRao Puli }
288b29b5ab3SAppaRao Puli
289b29b5ab3SAppaRao Puli std::ifstream passwdFile(passwdFileName, std::ios::in | std::ios::binary);
290b29b5ab3SAppaRao Puli if (!passwdFile.is_open())
291b29b5ab3SAppaRao Puli {
29282844ef6SGeorge Liu lg2::debug("Error in opening ipmi password file");
293b29b5ab3SAppaRao Puli return -EIO;
294b29b5ab3SAppaRao Puli }
295b29b5ab3SAppaRao Puli
296b29b5ab3SAppaRao Puli // calculate file size and read the data
297b29b5ab3SAppaRao Puli passwdFile.seekg(0, std::ios::end);
298b29b5ab3SAppaRao Puli ssize_t fileSize = passwdFile.tellg();
299b29b5ab3SAppaRao Puli passwdFile.seekg(0, std::ios::beg);
300b29b5ab3SAppaRao Puli std::vector<uint8_t> input(fileSize);
301b29b5ab3SAppaRao Puli passwdFile.read(reinterpret_cast<char*>(input.data()), fileSize);
302b29b5ab3SAppaRao Puli if (passwdFile.fail())
303b29b5ab3SAppaRao Puli {
30482844ef6SGeorge Liu lg2::debug("Error in reading encryption key file");
305b29b5ab3SAppaRao Puli return -EIO;
306b29b5ab3SAppaRao Puli }
307b29b5ab3SAppaRao Puli
308b29b5ab3SAppaRao Puli // verify the signature first
30948e55585SRichard Marian Thomaiyar MetaPassStruct* metaData = reinterpret_cast<MetaPassStruct*>(input.data());
310b29b5ab3SAppaRao Puli if (std::strncmp(metaData->signature, META_PASSWD_SIG,
311b29b5ab3SAppaRao Puli sizeof(metaData->signature)))
312b29b5ab3SAppaRao Puli {
31382844ef6SGeorge Liu lg2::debug("Error signature mismatch in password file");
314b29b5ab3SAppaRao Puli return -EBADMSG;
315b29b5ab3SAppaRao Puli }
316b29b5ab3SAppaRao Puli
317b29b5ab3SAppaRao Puli size_t inBytesLen = metaData->dataSize + metaData->padSize;
318b29b5ab3SAppaRao Puli // If data is empty i.e no password map then return success
319b29b5ab3SAppaRao Puli if (inBytesLen == 0)
320b29b5ab3SAppaRao Puli {
32182844ef6SGeorge Liu lg2::debug("Empty password file");
322b29b5ab3SAppaRao Puli return 0;
323b29b5ab3SAppaRao Puli }
324b29b5ab3SAppaRao Puli
325b29b5ab3SAppaRao Puli // compute the key needed to decrypt
326b29b5ab3SAppaRao Puli std::array<uint8_t, EVP_MAX_KEY_LENGTH> key;
327b29b5ab3SAppaRao Puli auto keyLen = key.size();
328b29b5ab3SAppaRao Puli if (NULL == HMAC(EVP_sha256(), keyBuff.data(), keyBuff.size(),
329b29b5ab3SAppaRao Puli input.data() + sizeof(*metaData), metaData->hashSize,
330b29b5ab3SAppaRao Puli key.data(), reinterpret_cast<unsigned int*>(&keyLen)))
331b29b5ab3SAppaRao Puli {
33282844ef6SGeorge Liu lg2::debug("Failed to create MAC for authentication");
333b29b5ab3SAppaRao Puli return -EIO;
334b29b5ab3SAppaRao Puli }
335b29b5ab3SAppaRao Puli
336b29b5ab3SAppaRao Puli // decrypt the data
337b29b5ab3SAppaRao Puli uint8_t* iv = input.data() + sizeof(*metaData) + metaData->hashSize;
338b29b5ab3SAppaRao Puli size_t ivLen = metaData->ivSize;
339b29b5ab3SAppaRao Puli uint8_t* inBytes = iv + ivLen;
340b29b5ab3SAppaRao Puli uint8_t* mac = inBytes + inBytesLen;
341b29b5ab3SAppaRao Puli size_t macLen = metaData->macSize;
342b29b5ab3SAppaRao Puli
343b29b5ab3SAppaRao Puli size_t outBytesLen = 0;
344b29b5ab3SAppaRao Puli // Resize to actual data size
3451e22a0f1SVernon Mauery outBytes.resize(inBytesLen + EVP_MAX_BLOCK_LENGTH, '\0');
346b29b5ab3SAppaRao Puli if (encryptDecryptData(false, EVP_aes_128_cbc(), key.data(), keyLen, iv,
347b29b5ab3SAppaRao Puli ivLen, inBytes, inBytesLen, mac, &macLen,
3481e22a0f1SVernon Mauery reinterpret_cast<unsigned char*>(outBytes.data()),
3491e22a0f1SVernon Mauery &outBytesLen) != 0)
350b29b5ab3SAppaRao Puli {
35182844ef6SGeorge Liu lg2::debug("Error in decryption");
352b29b5ab3SAppaRao Puli return -EIO;
353b29b5ab3SAppaRao Puli }
354b29b5ab3SAppaRao Puli // Resize the vector to outBytesLen
355b29b5ab3SAppaRao Puli outBytes.resize(outBytesLen);
356b29b5ab3SAppaRao Puli
357b29b5ab3SAppaRao Puli OPENSSL_cleanse(key.data(), keyLen);
358b29b5ab3SAppaRao Puli OPENSSL_cleanse(iv, ivLen);
359b29b5ab3SAppaRao Puli
360b29b5ab3SAppaRao Puli return 0;
361b29b5ab3SAppaRao Puli }
362b29b5ab3SAppaRao Puli
updatePasswdSpecialFile(const std::string & userName,const std::string & newUserName)36342bed64dSRichard Marian Thomaiyar int PasswdMgr::updatePasswdSpecialFile(const std::string& userName,
36442bed64dSRichard Marian Thomaiyar const std::string& newUserName)
365b29b5ab3SAppaRao Puli {
3662f0ad74dSAndrew Geissler // TODO phosphor-host-ipmid#170 phosphor::user::shadow::Lock lock{};
367b29b5ab3SAppaRao Puli
368b29b5ab3SAppaRao Puli size_t bytesWritten = 0;
369b29b5ab3SAppaRao Puli size_t inBytesLen = 0;
370b29b5ab3SAppaRao Puli size_t isUsrFound = false;
371b29b5ab3SAppaRao Puli const EVP_CIPHER* cipher = EVP_aes_128_cbc();
3721e22a0f1SVernon Mauery SecureString dataBuf;
373b29b5ab3SAppaRao Puli
374b29b5ab3SAppaRao Puli // Read the encrypted file and get the file data
375b29b5ab3SAppaRao Puli // Check user existance and return if not exist.
376b29b5ab3SAppaRao Puli if (readPasswdFileData(dataBuf) != 0)
377b29b5ab3SAppaRao Puli {
37882844ef6SGeorge Liu lg2::debug("Error in reading the encrypted pass file");
379b29b5ab3SAppaRao Puli return -EIO;
380b29b5ab3SAppaRao Puli }
381b29b5ab3SAppaRao Puli
382b29b5ab3SAppaRao Puli if (dataBuf.size() != 0)
383b29b5ab3SAppaRao Puli {
384fbc6c9d7SPatrick Williams inBytesLen = dataBuf.size() + newUserName.size() +
385fbc6c9d7SPatrick Williams EVP_CIPHER_block_size(cipher);
386b29b5ab3SAppaRao Puli }
387b29b5ab3SAppaRao Puli
3881e22a0f1SVernon Mauery SecureString inBytes(inBytesLen, '\0');
389b29b5ab3SAppaRao Puli if (inBytesLen != 0)
390b29b5ab3SAppaRao Puli {
391b29b5ab3SAppaRao Puli char* outPtr = reinterpret_cast<char*>(dataBuf.data());
392b29b5ab3SAppaRao Puli char* nToken = NULL;
393b29b5ab3SAppaRao Puli char* linePtr = strtok_r(outPtr, "\n", &nToken);
394b29b5ab3SAppaRao Puli while (linePtr != NULL)
395b29b5ab3SAppaRao Puli {
39651d0c40aSPatrick Venture size_t userEPos = 0;
39751d0c40aSPatrick Venture
3981e22a0f1SVernon Mauery SecureString lineStr(linePtr);
399b29b5ab3SAppaRao Puli if ((userEPos = lineStr.find(":")) != std::string::npos)
400b29b5ab3SAppaRao Puli {
401b29b5ab3SAppaRao Puli if (userName.compare(lineStr.substr(0, userEPos)) == 0)
402b29b5ab3SAppaRao Puli {
403b29b5ab3SAppaRao Puli isUsrFound = true;
40442bed64dSRichard Marian Thomaiyar if (!newUserName.empty())
40542bed64dSRichard Marian Thomaiyar {
40642bed64dSRichard Marian Thomaiyar bytesWritten += std::snprintf(
4071e22a0f1SVernon Mauery &inBytes[0] + bytesWritten,
40842bed64dSRichard Marian Thomaiyar (inBytesLen - bytesWritten), "%s%s\n",
40942bed64dSRichard Marian Thomaiyar newUserName.c_str(),
41042bed64dSRichard Marian Thomaiyar lineStr.substr(userEPos, lineStr.size()).data());
41142bed64dSRichard Marian Thomaiyar }
412b29b5ab3SAppaRao Puli }
413b29b5ab3SAppaRao Puli else
414b29b5ab3SAppaRao Puli {
4151e22a0f1SVernon Mauery bytesWritten += std::snprintf(&inBytes[0] + bytesWritten,
4161e22a0f1SVernon Mauery (inBytesLen - bytesWritten),
4171e22a0f1SVernon Mauery "%s\n", lineStr.data());
418b29b5ab3SAppaRao Puli }
419b29b5ab3SAppaRao Puli }
420b29b5ab3SAppaRao Puli linePtr = strtok_r(NULL, "\n", &nToken);
421b29b5ab3SAppaRao Puli }
422161f20d5SRichard Marian Thomaiyar inBytesLen = bytesWritten;
423b29b5ab3SAppaRao Puli }
424b29b5ab3SAppaRao Puli if (!isUsrFound)
425b29b5ab3SAppaRao Puli {
42682844ef6SGeorge Liu lg2::debug("User doesn't exist");
427b29b5ab3SAppaRao Puli return 0;
428b29b5ab3SAppaRao Puli }
429b29b5ab3SAppaRao Puli
430b29b5ab3SAppaRao Puli // Read the key buff from key file
431b29b5ab3SAppaRao Puli std::array<uint8_t, maxKeySize> keyBuff;
432b29b5ab3SAppaRao Puli std::ifstream keyFile(encryptKeyFileName, std::ios::in | std::ios::binary);
433b29b5ab3SAppaRao Puli if (!keyFile.good())
434b29b5ab3SAppaRao Puli {
43582844ef6SGeorge Liu lg2::debug("Error in opening encryption key file");
436b29b5ab3SAppaRao Puli return -EIO;
437b29b5ab3SAppaRao Puli }
438b29b5ab3SAppaRao Puli keyFile.read(reinterpret_cast<char*>(keyBuff.data()), keyBuff.size());
439b29b5ab3SAppaRao Puli if (keyFile.fail())
440b29b5ab3SAppaRao Puli {
44182844ef6SGeorge Liu lg2::debug("Error in reading encryption key file");
442b29b5ab3SAppaRao Puli return -EIO;
443b29b5ab3SAppaRao Puli }
444b29b5ab3SAppaRao Puli keyFile.close();
445b29b5ab3SAppaRao Puli
446b29b5ab3SAppaRao Puli // Read the original passwd file mode
447b29b5ab3SAppaRao Puli struct stat st = {};
448b29b5ab3SAppaRao Puli if (stat(passwdFileName, &st) != 0)
449b29b5ab3SAppaRao Puli {
45082844ef6SGeorge Liu lg2::debug("Error in getting password file fstat()");
451b29b5ab3SAppaRao Puli return -EIO;
452b29b5ab3SAppaRao Puli }
453b29b5ab3SAppaRao Puli
454b29b5ab3SAppaRao Puli // Create temporary file for write
455b29b5ab3SAppaRao Puli std::string pwdFile(passwdFileName);
456b29b5ab3SAppaRao Puli std::vector<char> tempFileName(pwdFile.begin(), pwdFile.end());
457b29b5ab3SAppaRao Puli std::vector<char> fileTemplate = {'_', '_', 'X', 'X', 'X',
458b29b5ab3SAppaRao Puli 'X', 'X', 'X', '\0'};
459b29b5ab3SAppaRao Puli tempFileName.insert(tempFileName.end(), fileTemplate.begin(),
460b29b5ab3SAppaRao Puli fileTemplate.end());
461b29b5ab3SAppaRao Puli int fd = mkstemp((char*)tempFileName.data());
462b29b5ab3SAppaRao Puli if (fd == -1)
463b29b5ab3SAppaRao Puli {
46482844ef6SGeorge Liu lg2::debug("Error creating temp file");
465b29b5ab3SAppaRao Puli return -EIO;
466b29b5ab3SAppaRao Puli }
467b29b5ab3SAppaRao Puli
468b29b5ab3SAppaRao Puli std::string strTempFileName(tempFileName.data());
469b29b5ab3SAppaRao Puli // Open the temp file for writing from provided fd
470b29b5ab3SAppaRao Puli // By "true", remove it at exit if still there.
471b29b5ab3SAppaRao Puli // This is needed to cleanup the temp file at exception
472b29b5ab3SAppaRao Puli phosphor::user::File temp(fd, strTempFileName, "w", true);
473b29b5ab3SAppaRao Puli if ((temp)() == NULL)
474b29b5ab3SAppaRao Puli {
475b29b5ab3SAppaRao Puli close(fd);
47682844ef6SGeorge Liu lg2::debug("Error creating temp file");
477b29b5ab3SAppaRao Puli return -EIO;
478b29b5ab3SAppaRao Puli }
479b29b5ab3SAppaRao Puli
480b265455aSVernon Mauery // Set the file mode as read-write for owner only
481b265455aSVernon Mauery if (fchmod(fileno((temp)()), S_IRUSR | S_IWUSR) < 0)
482b29b5ab3SAppaRao Puli {
48382844ef6SGeorge Liu lg2::debug("Error setting fchmod for temp file");
484b29b5ab3SAppaRao Puli return -EIO;
485b29b5ab3SAppaRao Puli }
486b29b5ab3SAppaRao Puli
487b29b5ab3SAppaRao Puli const EVP_MD* digest = EVP_sha256();
488b29b5ab3SAppaRao Puli size_t hashLen = EVP_MD_block_size(digest);
489b29b5ab3SAppaRao Puli std::vector<uint8_t> hash(hashLen);
490b29b5ab3SAppaRao Puli size_t ivLen = EVP_CIPHER_iv_length(cipher);
491b29b5ab3SAppaRao Puli std::vector<uint8_t> iv(ivLen);
492b29b5ab3SAppaRao Puli std::array<uint8_t, EVP_MAX_KEY_LENGTH> key;
493b29b5ab3SAppaRao Puli size_t keyLen = key.size();
494b29b5ab3SAppaRao Puli std::array<uint8_t, EVP_MAX_MD_SIZE> mac;
495b29b5ab3SAppaRao Puli size_t macLen = mac.size();
496b29b5ab3SAppaRao Puli
497b29b5ab3SAppaRao Puli // Create random hash and generate hash key which will be used for
498b29b5ab3SAppaRao Puli // encryption.
499b29b5ab3SAppaRao Puli if (RAND_bytes(hash.data(), hashLen) != 1)
500b29b5ab3SAppaRao Puli {
50182844ef6SGeorge Liu lg2::debug("Hash genertion failed, bailing out");
502b29b5ab3SAppaRao Puli return -EIO;
503b29b5ab3SAppaRao Puli }
504*1318a5edSPatrick Williams if (NULL ==
505*1318a5edSPatrick Williams HMAC(digest, keyBuff.data(), keyBuff.size(), hash.data(), hashLen,
506*1318a5edSPatrick Williams key.data(), reinterpret_cast<unsigned int*>(&keyLen)))
507b29b5ab3SAppaRao Puli {
50882844ef6SGeorge Liu lg2::debug("Failed to create MAC for authentication");
509b29b5ab3SAppaRao Puli return -EIO;
510b29b5ab3SAppaRao Puli }
511b29b5ab3SAppaRao Puli
512b29b5ab3SAppaRao Puli // Generate IV values
513b29b5ab3SAppaRao Puli if (RAND_bytes(iv.data(), ivLen) != 1)
514b29b5ab3SAppaRao Puli {
51582844ef6SGeorge Liu lg2::debug("UV genertion failed, bailing out");
516b29b5ab3SAppaRao Puli return -EIO;
517b29b5ab3SAppaRao Puli }
518b29b5ab3SAppaRao Puli
519b29b5ab3SAppaRao Puli // Encrypt the input data
520b29b5ab3SAppaRao Puli std::vector<uint8_t> outBytes(inBytesLen + EVP_MAX_BLOCK_LENGTH);
521b29b5ab3SAppaRao Puli size_t outBytesLen = 0;
522b29b5ab3SAppaRao Puli if (inBytesLen != 0)
523b29b5ab3SAppaRao Puli {
5241e22a0f1SVernon Mauery if (encryptDecryptData(
5251e22a0f1SVernon Mauery true, EVP_aes_128_cbc(), key.data(), keyLen, iv.data(), ivLen,
5261e22a0f1SVernon Mauery reinterpret_cast<unsigned char*>(inBytes.data()), inBytesLen,
5271e22a0f1SVernon Mauery mac.data(), &macLen, outBytes.data(), &outBytesLen) != 0)
528b29b5ab3SAppaRao Puli {
52982844ef6SGeorge Liu lg2::debug("Error while encrypting the data");
530b29b5ab3SAppaRao Puli return -EIO;
531b29b5ab3SAppaRao Puli }
532b29b5ab3SAppaRao Puli outBytes[outBytesLen] = 0;
533b29b5ab3SAppaRao Puli }
534b29b5ab3SAppaRao Puli OPENSSL_cleanse(key.data(), keyLen);
535b29b5ab3SAppaRao Puli
536b29b5ab3SAppaRao Puli // Update the meta password structure.
53748e55585SRichard Marian Thomaiyar MetaPassStruct metaData = {META_PASSWD_SIG, {0, 0}, 0, 0, 0, 0, 0};
538b29b5ab3SAppaRao Puli metaData.hashSize = hashLen;
539b29b5ab3SAppaRao Puli metaData.ivSize = ivLen;
540b29b5ab3SAppaRao Puli metaData.dataSize = bytesWritten;
541b29b5ab3SAppaRao Puli metaData.padSize = outBytesLen - bytesWritten;
542b29b5ab3SAppaRao Puli metaData.macSize = macLen;
543b29b5ab3SAppaRao Puli
544b29b5ab3SAppaRao Puli if (fwrite(&metaData, 1, sizeof(metaData), (temp)()) != sizeof(metaData))
545b29b5ab3SAppaRao Puli {
54682844ef6SGeorge Liu lg2::debug("Error in writing meta data");
547b29b5ab3SAppaRao Puli return -EIO;
548b29b5ab3SAppaRao Puli }
549b29b5ab3SAppaRao Puli
550b29b5ab3SAppaRao Puli if (fwrite(&hash[0], 1, hashLen, (temp)()) != hashLen)
551b29b5ab3SAppaRao Puli {
55282844ef6SGeorge Liu lg2::debug("Error in writing hash data");
553b29b5ab3SAppaRao Puli return -EIO;
554b29b5ab3SAppaRao Puli }
555b29b5ab3SAppaRao Puli
556b29b5ab3SAppaRao Puli if (fwrite(&iv[0], 1, ivLen, (temp)()) != ivLen)
557b29b5ab3SAppaRao Puli {
55882844ef6SGeorge Liu lg2::debug("Error in writing IV data");
559b29b5ab3SAppaRao Puli return -EIO;
560b29b5ab3SAppaRao Puli }
561b29b5ab3SAppaRao Puli
562b29b5ab3SAppaRao Puli if (fwrite(&outBytes[0], 1, outBytesLen, (temp)()) != outBytesLen)
563b29b5ab3SAppaRao Puli {
56482844ef6SGeorge Liu lg2::debug("Error in writing encrypted data");
565b29b5ab3SAppaRao Puli return -EIO;
566b29b5ab3SAppaRao Puli }
567b29b5ab3SAppaRao Puli
568b29b5ab3SAppaRao Puli if (fwrite(&mac[0], 1, macLen, (temp)()) != macLen)
569b29b5ab3SAppaRao Puli {
57082844ef6SGeorge Liu lg2::debug("Error in writing MAC data");
571b29b5ab3SAppaRao Puli return -EIO;
572b29b5ab3SAppaRao Puli }
573b29b5ab3SAppaRao Puli
574b29b5ab3SAppaRao Puli if (fflush((temp)()))
575b29b5ab3SAppaRao Puli {
57682844ef6SGeorge Liu lg2::debug("File fflush error while writing entries to special file");
577b29b5ab3SAppaRao Puli return -EIO;
578b29b5ab3SAppaRao Puli }
579b29b5ab3SAppaRao Puli
580b29b5ab3SAppaRao Puli OPENSSL_cleanse(iv.data(), ivLen);
581b29b5ab3SAppaRao Puli
582b29b5ab3SAppaRao Puli // Rename the tmp file to actual file
583b29b5ab3SAppaRao Puli if (std::rename(strTempFileName.data(), passwdFileName) != 0)
584b29b5ab3SAppaRao Puli {
58582844ef6SGeorge Liu lg2::debug("Failed to rename tmp file to ipmi-pass");
586b29b5ab3SAppaRao Puli return -EIO;
587b29b5ab3SAppaRao Puli }
588b29b5ab3SAppaRao Puli
589b29b5ab3SAppaRao Puli return 0;
590b29b5ab3SAppaRao Puli }
591b29b5ab3SAppaRao Puli
getUpdatedFileTime()592b29b5ab3SAppaRao Puli std::time_t PasswdMgr::getUpdatedFileTime()
593b29b5ab3SAppaRao Puli {
5944654d99fSRichard Marian Thomaiyar struct stat fileStat = {};
5954654d99fSRichard Marian Thomaiyar if (stat(passwdFileName, &fileStat) != 0)
5964654d99fSRichard Marian Thomaiyar {
59782844ef6SGeorge Liu lg2::debug("Error - Getting passwd file time stamp");
598b29b5ab3SAppaRao Puli return -EIO;
5994654d99fSRichard Marian Thomaiyar }
600b29b5ab3SAppaRao Puli return fileStat.st_mtime;
6014654d99fSRichard Marian Thomaiyar }
6024654d99fSRichard Marian Thomaiyar
6034654d99fSRichard Marian Thomaiyar } // namespace ipmi
604