xref: /openbmc/phosphor-host-ipmid/user_channel/passwd_mgr.cpp (revision 42bed64d8e34d55bae9ab8fb395a00ce412dcd8e)
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 
29b29b5ab3SAppaRao Puli #include <cerrno>
304654d99fSRichard Marian Thomaiyar #include <cstring>
314654d99fSRichard Marian Thomaiyar #include <fstream>
32b29b5ab3SAppaRao Puli #include <iomanip>
334654d99fSRichard Marian Thomaiyar #include <phosphor-logging/log.hpp>
344654d99fSRichard Marian Thomaiyar 
354654d99fSRichard Marian Thomaiyar namespace ipmi
364654d99fSRichard Marian Thomaiyar {
374654d99fSRichard Marian Thomaiyar 
384654d99fSRichard Marian Thomaiyar static const char* passwdFileName = "/etc/ipmi_pass";
394654d99fSRichard Marian Thomaiyar static const char* encryptKeyFileName = "/etc/key_file";
404654d99fSRichard Marian Thomaiyar static const size_t maxKeySize = 8;
414654d99fSRichard Marian Thomaiyar 
42b29b5ab3SAppaRao Puli #define META_PASSWD_SIG "=OPENBMC="
43b29b5ab3SAppaRao Puli 
44b29b5ab3SAppaRao Puli static inline size_t blockRound(size_t odd, size_t blk)
45b29b5ab3SAppaRao Puli {
46b29b5ab3SAppaRao Puli     return ((odd) + (((blk) - ((odd) & ((blk)-1))) & ((blk)-1)));
47b29b5ab3SAppaRao Puli }
484654d99fSRichard Marian Thomaiyar 
494654d99fSRichard Marian Thomaiyar /*
504654d99fSRichard Marian Thomaiyar  * Meta data struct for encrypted password file
514654d99fSRichard Marian Thomaiyar  */
524654d99fSRichard Marian Thomaiyar struct metaPassStruct
534654d99fSRichard Marian Thomaiyar {
544654d99fSRichard Marian Thomaiyar     char signature[10];
554654d99fSRichard Marian Thomaiyar     unsigned char reseved[2];
564654d99fSRichard Marian Thomaiyar     size_t hashSize;
574654d99fSRichard Marian Thomaiyar     size_t ivSize;
584654d99fSRichard Marian Thomaiyar     size_t dataSize;
594654d99fSRichard Marian Thomaiyar     size_t padSize;
604654d99fSRichard Marian Thomaiyar     size_t macSize;
614654d99fSRichard Marian Thomaiyar };
624654d99fSRichard Marian Thomaiyar 
634654d99fSRichard Marian Thomaiyar using namespace phosphor::logging;
644654d99fSRichard Marian Thomaiyar 
654654d99fSRichard Marian Thomaiyar PasswdMgr::PasswdMgr()
664654d99fSRichard Marian Thomaiyar {
674654d99fSRichard Marian Thomaiyar     initPasswordMap();
684654d99fSRichard Marian Thomaiyar }
694654d99fSRichard Marian Thomaiyar 
704654d99fSRichard Marian Thomaiyar std::string PasswdMgr::getPasswdByUserName(const std::string& userName)
714654d99fSRichard Marian Thomaiyar {
724654d99fSRichard Marian Thomaiyar     checkAndReload();
734654d99fSRichard Marian Thomaiyar     auto iter = passwdMapList.find(userName);
744654d99fSRichard Marian Thomaiyar     if (iter == passwdMapList.end())
754654d99fSRichard Marian Thomaiyar     {
764654d99fSRichard Marian Thomaiyar         return std::string();
774654d99fSRichard Marian Thomaiyar     }
784654d99fSRichard Marian Thomaiyar     return iter->second;
794654d99fSRichard Marian Thomaiyar }
804654d99fSRichard Marian Thomaiyar 
81*42bed64dSRichard Marian Thomaiyar int PasswdMgr::updateUserEntry(const std::string& userName,
82*42bed64dSRichard Marian Thomaiyar                                const std::string& newUserName)
83b29b5ab3SAppaRao Puli {
84b29b5ab3SAppaRao Puli     std::time_t updatedTime = getUpdatedFileTime();
85b29b5ab3SAppaRao Puli     // Check file time stamp to know passwdMapList is up-to-date.
86b29b5ab3SAppaRao Puli     // If not up-to-date, then updatePasswdSpecialFile will read and
87b29b5ab3SAppaRao Puli     // check the user entry existance.
88b29b5ab3SAppaRao Puli     if (fileLastUpdatedTime == updatedTime && updatedTime != -EIO)
89b29b5ab3SAppaRao Puli     {
90b29b5ab3SAppaRao Puli         if (passwdMapList.find(userName) == passwdMapList.end())
91b29b5ab3SAppaRao Puli         {
92b29b5ab3SAppaRao Puli             log<level::DEBUG>("User not found");
93b29b5ab3SAppaRao Puli             return 0;
94b29b5ab3SAppaRao Puli         }
95b29b5ab3SAppaRao Puli     }
96b29b5ab3SAppaRao Puli 
97b29b5ab3SAppaRao Puli     // Write passwdMap to Encryted file
98*42bed64dSRichard Marian Thomaiyar     if (updatePasswdSpecialFile(userName, newUserName) != 0)
99b29b5ab3SAppaRao Puli     {
100b29b5ab3SAppaRao Puli         log<level::DEBUG>("Passwd file update failed");
101b29b5ab3SAppaRao Puli         return -EIO;
102b29b5ab3SAppaRao Puli     }
103b29b5ab3SAppaRao Puli 
104b29b5ab3SAppaRao Puli     log<level::DEBUG>("Passwd file updated successfully");
105b29b5ab3SAppaRao Puli     return 0;
106b29b5ab3SAppaRao Puli }
107b29b5ab3SAppaRao Puli 
1084654d99fSRichard Marian Thomaiyar void PasswdMgr::checkAndReload(void)
1094654d99fSRichard Marian Thomaiyar {
110b29b5ab3SAppaRao Puli     std::time_t updatedTime = getUpdatedFileTime();
111b29b5ab3SAppaRao Puli     if (fileLastUpdatedTime != updatedTime && updatedTime != -1)
1124654d99fSRichard Marian Thomaiyar     {
1134654d99fSRichard Marian Thomaiyar         log<level::DEBUG>("Reloading password map list");
1144654d99fSRichard Marian Thomaiyar         passwdMapList.clear();
1154654d99fSRichard Marian Thomaiyar         initPasswordMap();
1164654d99fSRichard Marian Thomaiyar     }
1174654d99fSRichard Marian Thomaiyar }
1184654d99fSRichard Marian Thomaiyar 
119b29b5ab3SAppaRao Puli int PasswdMgr::encryptDecryptData(bool doEncrypt, const EVP_CIPHER* cipher,
120b29b5ab3SAppaRao Puli                                   uint8_t* key, size_t keyLen, uint8_t* iv,
121b29b5ab3SAppaRao Puli                                   size_t ivLen, uint8_t* inBytes,
122b29b5ab3SAppaRao Puli                                   size_t inBytesLen, uint8_t* mac,
123b29b5ab3SAppaRao Puli                                   size_t* macLen, unsigned char* outBytes,
124b29b5ab3SAppaRao Puli                                   size_t* outBytesLen)
1254654d99fSRichard Marian Thomaiyar {
1264654d99fSRichard Marian Thomaiyar     if (cipher == NULL || key == NULL || iv == NULL || inBytes == NULL ||
1274654d99fSRichard Marian Thomaiyar         outBytes == NULL || mac == NULL || inBytesLen == 0 ||
1284654d99fSRichard Marian Thomaiyar         (size_t)EVP_CIPHER_key_length(cipher) > keyLen ||
1294654d99fSRichard Marian Thomaiyar         (size_t)EVP_CIPHER_iv_length(cipher) > ivLen)
1304654d99fSRichard Marian Thomaiyar     {
1314654d99fSRichard Marian Thomaiyar         log<level::DEBUG>("Error Invalid Inputs");
132b29b5ab3SAppaRao Puli         return -EINVAL;
1334654d99fSRichard Marian Thomaiyar     }
1344654d99fSRichard Marian Thomaiyar 
135b29b5ab3SAppaRao Puli     if (!doEncrypt)
136b29b5ab3SAppaRao Puli     {
137b29b5ab3SAppaRao Puli         // verify MAC before decrypting the data.
1384654d99fSRichard Marian Thomaiyar         std::array<uint8_t, EVP_MAX_MD_SIZE> calMac;
1394654d99fSRichard Marian Thomaiyar         size_t calMacLen = calMac.size();
1404654d99fSRichard Marian Thomaiyar         // calculate MAC for the encrypted message.
1414654d99fSRichard Marian Thomaiyar         if (NULL == HMAC(EVP_sha256(), key, keyLen, inBytes, inBytesLen,
1424654d99fSRichard Marian Thomaiyar                          calMac.data(),
1434654d99fSRichard Marian Thomaiyar                          reinterpret_cast<unsigned int*>(&calMacLen)))
1444654d99fSRichard Marian Thomaiyar         {
1454654d99fSRichard Marian Thomaiyar             log<level::DEBUG>("Error: Failed to calculate MAC");
146b29b5ab3SAppaRao Puli             return -EIO;
1474654d99fSRichard Marian Thomaiyar         }
148b29b5ab3SAppaRao Puli         if (!((calMacLen == *macLen) &&
1494654d99fSRichard Marian Thomaiyar               (std::memcmp(calMac.data(), mac, calMacLen) == 0)))
1504654d99fSRichard Marian Thomaiyar         {
1514654d99fSRichard Marian Thomaiyar             log<level::DEBUG>("Authenticated message doesn't match");
152b29b5ab3SAppaRao Puli             return -EBADMSG;
153b29b5ab3SAppaRao Puli         }
1544654d99fSRichard Marian Thomaiyar     }
1554654d99fSRichard Marian Thomaiyar 
1564654d99fSRichard Marian Thomaiyar     std::unique_ptr<EVP_CIPHER_CTX, decltype(&::EVP_CIPHER_CTX_free)> ctx(
1574654d99fSRichard Marian Thomaiyar         EVP_CIPHER_CTX_new(), ::EVP_CIPHER_CTX_free);
1584654d99fSRichard Marian Thomaiyar     EVP_CIPHER_CTX_set_padding(ctx.get(), 1);
1594654d99fSRichard Marian Thomaiyar 
160b29b5ab3SAppaRao Puli     // Set key & IV
161b29b5ab3SAppaRao Puli     int retval = EVP_CipherInit_ex(ctx.get(), cipher, NULL, key, iv,
162b29b5ab3SAppaRao Puli                                    static_cast<int>(doEncrypt));
1634654d99fSRichard Marian Thomaiyar     if (!retval)
1644654d99fSRichard Marian Thomaiyar     {
1654654d99fSRichard Marian Thomaiyar         log<level::DEBUG>("EVP_CipherInit_ex failed",
1664654d99fSRichard Marian Thomaiyar                           entry("RET_VAL=%d", retval));
167b29b5ab3SAppaRao Puli         return -EIO;
1684654d99fSRichard Marian Thomaiyar     }
1694654d99fSRichard Marian Thomaiyar 
1704654d99fSRichard Marian Thomaiyar     int outLen = 0, outEVPLen = 0;
1714654d99fSRichard Marian Thomaiyar     if ((retval = EVP_CipherUpdate(ctx.get(), outBytes + outLen, &outEVPLen,
1724654d99fSRichard Marian Thomaiyar                                    inBytes, inBytesLen)))
1734654d99fSRichard Marian Thomaiyar     {
1744654d99fSRichard Marian Thomaiyar         outLen += outEVPLen;
1754654d99fSRichard Marian Thomaiyar         if ((retval =
1764654d99fSRichard Marian Thomaiyar                  EVP_CipherFinal(ctx.get(), outBytes + outLen, &outEVPLen)))
1774654d99fSRichard Marian Thomaiyar         {
1784654d99fSRichard Marian Thomaiyar             outLen += outEVPLen;
1794654d99fSRichard Marian Thomaiyar             *outBytesLen = outLen;
1804654d99fSRichard Marian Thomaiyar         }
1814654d99fSRichard Marian Thomaiyar         else
1824654d99fSRichard Marian Thomaiyar         {
1834654d99fSRichard Marian Thomaiyar             log<level::DEBUG>("EVP_CipherFinal fails",
1844654d99fSRichard Marian Thomaiyar                               entry("RET_VAL=%d", retval));
185b29b5ab3SAppaRao Puli             return -EIO;
1864654d99fSRichard Marian Thomaiyar         }
1874654d99fSRichard Marian Thomaiyar     }
1884654d99fSRichard Marian Thomaiyar     else
1894654d99fSRichard Marian Thomaiyar     {
1904654d99fSRichard Marian Thomaiyar         log<level::DEBUG>("EVP_CipherUpdate fails",
1914654d99fSRichard Marian Thomaiyar                           entry("RET_VAL=%d", retval));
192b29b5ab3SAppaRao Puli         return -EIO;
193b29b5ab3SAppaRao Puli     }
194b29b5ab3SAppaRao Puli 
195b29b5ab3SAppaRao Puli     if (doEncrypt)
196b29b5ab3SAppaRao Puli     {
197b29b5ab3SAppaRao Puli         // Create MAC for the encrypted message
198b29b5ab3SAppaRao Puli         if (NULL == HMAC(EVP_sha256(), key, keyLen, outBytes, *outBytesLen, mac,
199b29b5ab3SAppaRao Puli                          reinterpret_cast<unsigned int*>(macLen)))
200b29b5ab3SAppaRao Puli         {
201b29b5ab3SAppaRao Puli             log<level::DEBUG>("Failed to create authentication");
202b29b5ab3SAppaRao Puli             return -EIO;
203b29b5ab3SAppaRao Puli         }
2044654d99fSRichard Marian Thomaiyar     }
2054654d99fSRichard Marian Thomaiyar     return 0;
2064654d99fSRichard Marian Thomaiyar }
2074654d99fSRichard Marian Thomaiyar 
2084654d99fSRichard Marian Thomaiyar void PasswdMgr::initPasswordMap(void)
2094654d99fSRichard Marian Thomaiyar {
2104654d99fSRichard Marian Thomaiyar     phosphor::user::shadow::Lock lock();
211b29b5ab3SAppaRao Puli     std::vector<uint8_t> dataBuf;
2124654d99fSRichard Marian Thomaiyar 
213b29b5ab3SAppaRao Puli     if (readPasswdFileData(dataBuf) != 0)
2144654d99fSRichard Marian Thomaiyar     {
215b29b5ab3SAppaRao Puli         log<level::DEBUG>("Error in reading the encrypted pass file");
2164654d99fSRichard Marian Thomaiyar         return;
2174654d99fSRichard Marian Thomaiyar     }
2184654d99fSRichard Marian Thomaiyar 
219b29b5ab3SAppaRao Puli     if (dataBuf.size() != 0)
2204654d99fSRichard Marian Thomaiyar     {
2214654d99fSRichard Marian Thomaiyar         // populate the user list with password
222b29b5ab3SAppaRao Puli         char* outPtr = reinterpret_cast<char*>(dataBuf.data());
2234654d99fSRichard Marian Thomaiyar         char* nToken = NULL;
2244654d99fSRichard Marian Thomaiyar         char* linePtr = strtok_r(outPtr, "\n", &nToken);
2254654d99fSRichard Marian Thomaiyar         size_t userEPos = 0, lineSize = 0;
2264654d99fSRichard Marian Thomaiyar         while (linePtr != NULL)
2274654d99fSRichard Marian Thomaiyar         {
2284654d99fSRichard Marian Thomaiyar             std::string lineStr(linePtr);
2294654d99fSRichard Marian Thomaiyar             if ((userEPos = lineStr.find(":")) != std::string::npos)
2304654d99fSRichard Marian Thomaiyar             {
2314654d99fSRichard Marian Thomaiyar                 lineSize = lineStr.size();
2324654d99fSRichard Marian Thomaiyar                 passwdMapList.emplace(
2334654d99fSRichard Marian Thomaiyar                     lineStr.substr(0, userEPos),
2344654d99fSRichard Marian Thomaiyar                     lineStr.substr(userEPos + 1, lineSize - (userEPos + 1)));
2354654d99fSRichard Marian Thomaiyar             }
2364654d99fSRichard Marian Thomaiyar             linePtr = strtok_r(NULL, "\n", &nToken);
2374654d99fSRichard Marian Thomaiyar         }
238b29b5ab3SAppaRao Puli     }
239b29b5ab3SAppaRao Puli 
2404654d99fSRichard Marian Thomaiyar     // Update the timestamp
241b29b5ab3SAppaRao Puli     fileLastUpdatedTime = getUpdatedFileTime();
242b29b5ab3SAppaRao Puli     return;
243b29b5ab3SAppaRao Puli }
244b29b5ab3SAppaRao Puli 
245b29b5ab3SAppaRao Puli int PasswdMgr::readPasswdFileData(std::vector<uint8_t>& outBytes)
246b29b5ab3SAppaRao Puli {
247b29b5ab3SAppaRao Puli     std::array<uint8_t, maxKeySize> keyBuff;
248b29b5ab3SAppaRao Puli     std::ifstream keyFile(encryptKeyFileName, std::ios::in | std::ios::binary);
249b29b5ab3SAppaRao Puli     if (!keyFile.is_open())
250b29b5ab3SAppaRao Puli     {
251b29b5ab3SAppaRao Puli         log<level::DEBUG>("Error in opening encryption key file");
252b29b5ab3SAppaRao Puli         return -EIO;
253b29b5ab3SAppaRao Puli     }
254b29b5ab3SAppaRao Puli     keyFile.read(reinterpret_cast<char*>(keyBuff.data()), keyBuff.size());
255b29b5ab3SAppaRao Puli     if (keyFile.fail())
256b29b5ab3SAppaRao Puli     {
257b29b5ab3SAppaRao Puli         log<level::DEBUG>("Error in reading encryption key file");
258b29b5ab3SAppaRao Puli         return -EIO;
259b29b5ab3SAppaRao Puli     }
260b29b5ab3SAppaRao Puli 
261b29b5ab3SAppaRao Puli     std::ifstream passwdFile(passwdFileName, std::ios::in | std::ios::binary);
262b29b5ab3SAppaRao Puli     if (!passwdFile.is_open())
263b29b5ab3SAppaRao Puli     {
264b29b5ab3SAppaRao Puli         log<level::DEBUG>("Error in opening ipmi password file");
265b29b5ab3SAppaRao Puli         return -EIO;
266b29b5ab3SAppaRao Puli     }
267b29b5ab3SAppaRao Puli 
268b29b5ab3SAppaRao Puli     // calculate file size and read the data
269b29b5ab3SAppaRao Puli     passwdFile.seekg(0, std::ios::end);
270b29b5ab3SAppaRao Puli     ssize_t fileSize = passwdFile.tellg();
271b29b5ab3SAppaRao Puli     passwdFile.seekg(0, std::ios::beg);
272b29b5ab3SAppaRao Puli     std::vector<uint8_t> input(fileSize);
273b29b5ab3SAppaRao Puli     passwdFile.read(reinterpret_cast<char*>(input.data()), fileSize);
274b29b5ab3SAppaRao Puli     if (passwdFile.fail())
275b29b5ab3SAppaRao Puli     {
276b29b5ab3SAppaRao Puli         log<level::DEBUG>("Error in reading encryption key file");
277b29b5ab3SAppaRao Puli         return -EIO;
278b29b5ab3SAppaRao Puli     }
279b29b5ab3SAppaRao Puli 
280b29b5ab3SAppaRao Puli     // verify the signature first
281b29b5ab3SAppaRao Puli     metaPassStruct* metaData = reinterpret_cast<metaPassStruct*>(input.data());
282b29b5ab3SAppaRao Puli     if (std::strncmp(metaData->signature, META_PASSWD_SIG,
283b29b5ab3SAppaRao Puli                      sizeof(metaData->signature)))
284b29b5ab3SAppaRao Puli     {
285b29b5ab3SAppaRao Puli         log<level::DEBUG>("Error signature mismatch in password file");
286b29b5ab3SAppaRao Puli         return -EBADMSG;
287b29b5ab3SAppaRao Puli     }
288b29b5ab3SAppaRao Puli 
289b29b5ab3SAppaRao Puli     size_t inBytesLen = metaData->dataSize + metaData->padSize;
290b29b5ab3SAppaRao Puli     // If data is empty i.e no password map then return success
291b29b5ab3SAppaRao Puli     if (inBytesLen == 0)
292b29b5ab3SAppaRao Puli     {
293b29b5ab3SAppaRao Puli         log<level::DEBUG>("Empty password file");
294b29b5ab3SAppaRao Puli         return 0;
295b29b5ab3SAppaRao Puli     }
296b29b5ab3SAppaRao Puli 
297b29b5ab3SAppaRao Puli     // compute the key needed to decrypt
298b29b5ab3SAppaRao Puli     std::array<uint8_t, EVP_MAX_KEY_LENGTH> key;
299b29b5ab3SAppaRao Puli     auto keyLen = key.size();
300b29b5ab3SAppaRao Puli     if (NULL == HMAC(EVP_sha256(), keyBuff.data(), keyBuff.size(),
301b29b5ab3SAppaRao Puli                      input.data() + sizeof(*metaData), metaData->hashSize,
302b29b5ab3SAppaRao Puli                      key.data(), reinterpret_cast<unsigned int*>(&keyLen)))
303b29b5ab3SAppaRao Puli     {
304b29b5ab3SAppaRao Puli         log<level::DEBUG>("Failed to create MAC for authentication");
305b29b5ab3SAppaRao Puli         return -EIO;
306b29b5ab3SAppaRao Puli     }
307b29b5ab3SAppaRao Puli 
308b29b5ab3SAppaRao Puli     // decrypt the data
309b29b5ab3SAppaRao Puli     uint8_t* iv = input.data() + sizeof(*metaData) + metaData->hashSize;
310b29b5ab3SAppaRao Puli     size_t ivLen = metaData->ivSize;
311b29b5ab3SAppaRao Puli     uint8_t* inBytes = iv + ivLen;
312b29b5ab3SAppaRao Puli     uint8_t* mac = inBytes + inBytesLen;
313b29b5ab3SAppaRao Puli     size_t macLen = metaData->macSize;
314b29b5ab3SAppaRao Puli 
315b29b5ab3SAppaRao Puli     size_t outBytesLen = 0;
316b29b5ab3SAppaRao Puli     // Resize to actual data size
317b29b5ab3SAppaRao Puli     outBytes.resize(inBytesLen + EVP_MAX_BLOCK_LENGTH);
318b29b5ab3SAppaRao Puli     if (encryptDecryptData(false, EVP_aes_128_cbc(), key.data(), keyLen, iv,
319b29b5ab3SAppaRao Puli                            ivLen, inBytes, inBytesLen, mac, &macLen,
320b29b5ab3SAppaRao Puli                            outBytes.data(), &outBytesLen) != 0)
321b29b5ab3SAppaRao Puli     {
322b29b5ab3SAppaRao Puli         log<level::DEBUG>("Error in decryption");
323b29b5ab3SAppaRao Puli         return -EIO;
324b29b5ab3SAppaRao Puli     }
325b29b5ab3SAppaRao Puli     // Resize the vector to outBytesLen
326b29b5ab3SAppaRao Puli     outBytes.resize(outBytesLen);
327b29b5ab3SAppaRao Puli 
328b29b5ab3SAppaRao Puli     OPENSSL_cleanse(key.data(), keyLen);
329b29b5ab3SAppaRao Puli     OPENSSL_cleanse(iv, ivLen);
330b29b5ab3SAppaRao Puli 
331b29b5ab3SAppaRao Puli     return 0;
332b29b5ab3SAppaRao Puli }
333b29b5ab3SAppaRao Puli 
334*42bed64dSRichard Marian Thomaiyar int PasswdMgr::updatePasswdSpecialFile(const std::string& userName,
335*42bed64dSRichard Marian Thomaiyar                                        const std::string& newUserName)
336b29b5ab3SAppaRao Puli {
337b29b5ab3SAppaRao Puli     phosphor::user::shadow::Lock lock();
338b29b5ab3SAppaRao Puli 
339b29b5ab3SAppaRao Puli     size_t bytesWritten = 0;
340b29b5ab3SAppaRao Puli     size_t inBytesLen = 0;
341b29b5ab3SAppaRao Puli     size_t isUsrFound = false;
342b29b5ab3SAppaRao Puli     const EVP_CIPHER* cipher = EVP_aes_128_cbc();
343b29b5ab3SAppaRao Puli     std::vector<uint8_t> dataBuf;
344b29b5ab3SAppaRao Puli 
345b29b5ab3SAppaRao Puli     // Read the encrypted file and get the file data
346b29b5ab3SAppaRao Puli     // Check user existance and return if not exist.
347b29b5ab3SAppaRao Puli     if (readPasswdFileData(dataBuf) != 0)
348b29b5ab3SAppaRao Puli     {
349b29b5ab3SAppaRao Puli         log<level::DEBUG>("Error in reading the encrypted pass file");
350b29b5ab3SAppaRao Puli         return -EIO;
351b29b5ab3SAppaRao Puli     }
352b29b5ab3SAppaRao Puli 
353b29b5ab3SAppaRao Puli     if (dataBuf.size() != 0)
354b29b5ab3SAppaRao Puli     {
355*42bed64dSRichard Marian Thomaiyar         inBytesLen =
356*42bed64dSRichard Marian Thomaiyar             dataBuf.size() + newUserName.size() + EVP_CIPHER_block_size(cipher);
357b29b5ab3SAppaRao Puli     }
358b29b5ab3SAppaRao Puli 
359b29b5ab3SAppaRao Puli     std::vector<uint8_t> inBytes(inBytesLen);
360b29b5ab3SAppaRao Puli     if (inBytesLen != 0)
361b29b5ab3SAppaRao Puli     {
362b29b5ab3SAppaRao Puli         char* outPtr = reinterpret_cast<char*>(dataBuf.data());
363b29b5ab3SAppaRao Puli         size_t userEPos = 0;
364b29b5ab3SAppaRao Puli         char* nToken = NULL;
365b29b5ab3SAppaRao Puli         char* linePtr = strtok_r(outPtr, "\n", &nToken);
366b29b5ab3SAppaRao Puli         while (linePtr != NULL)
367b29b5ab3SAppaRao Puli         {
368b29b5ab3SAppaRao Puli             std::string lineStr(linePtr);
369b29b5ab3SAppaRao Puli             if ((userEPos = lineStr.find(":")) != std::string::npos)
370b29b5ab3SAppaRao Puli             {
371b29b5ab3SAppaRao Puli                 if (userName.compare(lineStr.substr(0, userEPos)) == 0)
372b29b5ab3SAppaRao Puli                 {
373b29b5ab3SAppaRao Puli                     isUsrFound = true;
374*42bed64dSRichard Marian Thomaiyar                     if (!newUserName.empty())
375*42bed64dSRichard Marian Thomaiyar                     {
376*42bed64dSRichard Marian Thomaiyar                         bytesWritten += std::snprintf(
377*42bed64dSRichard Marian Thomaiyar                             reinterpret_cast<char*>(&inBytes[0]) + bytesWritten,
378*42bed64dSRichard Marian Thomaiyar                             (inBytesLen - bytesWritten), "%s%s\n",
379*42bed64dSRichard Marian Thomaiyar                             newUserName.c_str(),
380*42bed64dSRichard Marian Thomaiyar                             lineStr.substr(userEPos, lineStr.size()).data());
381*42bed64dSRichard Marian Thomaiyar                     }
382b29b5ab3SAppaRao Puli                 }
383b29b5ab3SAppaRao Puli                 else
384b29b5ab3SAppaRao Puli                 {
385b29b5ab3SAppaRao Puli                     bytesWritten += std::snprintf(
386b29b5ab3SAppaRao Puli                         reinterpret_cast<char*>(&inBytes[0]) + bytesWritten,
387*42bed64dSRichard Marian Thomaiyar                         (inBytesLen - bytesWritten), "%s\n", lineStr.data());
388b29b5ab3SAppaRao Puli                 }
389b29b5ab3SAppaRao Puli             }
390b29b5ab3SAppaRao Puli             linePtr = strtok_r(NULL, "\n", &nToken);
391b29b5ab3SAppaRao Puli         }
392b29b5ab3SAppaRao Puli 
393b29b5ab3SAppaRao Puli         // Round of to block size and padding remaing bytes with zero.
394b29b5ab3SAppaRao Puli         inBytesLen = blockRound(bytesWritten, EVP_CIPHER_block_size(cipher));
395b29b5ab3SAppaRao Puli         std::memset(&inBytes[0] + bytesWritten, 0, inBytesLen - bytesWritten);
396b29b5ab3SAppaRao Puli     }
397b29b5ab3SAppaRao Puli     if (!isUsrFound)
398b29b5ab3SAppaRao Puli     {
399b29b5ab3SAppaRao Puli         log<level::DEBUG>("User doesn't exist");
400b29b5ab3SAppaRao Puli         return 0;
401b29b5ab3SAppaRao Puli     }
402b29b5ab3SAppaRao Puli 
403b29b5ab3SAppaRao Puli     // Read the key buff from key file
404b29b5ab3SAppaRao Puli     std::array<uint8_t, maxKeySize> keyBuff;
405b29b5ab3SAppaRao Puli     std::ifstream keyFile(encryptKeyFileName, std::ios::in | std::ios::binary);
406b29b5ab3SAppaRao Puli     if (!keyFile.good())
407b29b5ab3SAppaRao Puli     {
408b29b5ab3SAppaRao Puli         log<level::DEBUG>("Error in opening encryption key file");
409b29b5ab3SAppaRao Puli         return -EIO;
410b29b5ab3SAppaRao Puli     }
411b29b5ab3SAppaRao Puli     keyFile.read(reinterpret_cast<char*>(keyBuff.data()), keyBuff.size());
412b29b5ab3SAppaRao Puli     if (keyFile.fail())
413b29b5ab3SAppaRao Puli     {
414b29b5ab3SAppaRao Puli         log<level::DEBUG>("Error in reading encryption key file");
415b29b5ab3SAppaRao Puli         return -EIO;
416b29b5ab3SAppaRao Puli     }
417b29b5ab3SAppaRao Puli     keyFile.close();
418b29b5ab3SAppaRao Puli 
419b29b5ab3SAppaRao Puli     // Read the original passwd file mode
420b29b5ab3SAppaRao Puli     struct stat st = {};
421b29b5ab3SAppaRao Puli     if (stat(passwdFileName, &st) != 0)
422b29b5ab3SAppaRao Puli     {
423b29b5ab3SAppaRao Puli         log<level::DEBUG>("Error in getting password file fstat()");
424b29b5ab3SAppaRao Puli         return -EIO;
425b29b5ab3SAppaRao Puli     }
426b29b5ab3SAppaRao Puli 
427b29b5ab3SAppaRao Puli     // Create temporary file for write
428b29b5ab3SAppaRao Puli     std::string pwdFile(passwdFileName);
429b29b5ab3SAppaRao Puli     std::vector<char> tempFileName(pwdFile.begin(), pwdFile.end());
430b29b5ab3SAppaRao Puli     std::vector<char> fileTemplate = {'_', '_', 'X', 'X', 'X',
431b29b5ab3SAppaRao Puli                                       'X', 'X', 'X', '\0'};
432b29b5ab3SAppaRao Puli     tempFileName.insert(tempFileName.end(), fileTemplate.begin(),
433b29b5ab3SAppaRao Puli                         fileTemplate.end());
434b29b5ab3SAppaRao Puli     int fd = mkstemp((char*)tempFileName.data());
435b29b5ab3SAppaRao Puli     if (fd == -1)
436b29b5ab3SAppaRao Puli     {
437b29b5ab3SAppaRao Puli         log<level::DEBUG>("Error creating temp file");
438b29b5ab3SAppaRao Puli         return -EIO;
439b29b5ab3SAppaRao Puli     }
440b29b5ab3SAppaRao Puli 
441b29b5ab3SAppaRao Puli     std::string strTempFileName(tempFileName.data());
442b29b5ab3SAppaRao Puli     // Open the temp file for writing from provided fd
443b29b5ab3SAppaRao Puli     // By "true", remove it at exit if still there.
444b29b5ab3SAppaRao Puli     // This is needed to cleanup the temp file at exception
445b29b5ab3SAppaRao Puli     phosphor::user::File temp(fd, strTempFileName, "w", true);
446b29b5ab3SAppaRao Puli     if ((temp)() == NULL)
447b29b5ab3SAppaRao Puli     {
448b29b5ab3SAppaRao Puli         close(fd);
449b29b5ab3SAppaRao Puli         log<level::DEBUG>("Error creating temp file");
450b29b5ab3SAppaRao Puli         return -EIO;
451b29b5ab3SAppaRao Puli     }
452b29b5ab3SAppaRao Puli     fd = -1; // don't use fd anymore, as the File object owns it
453b29b5ab3SAppaRao Puli 
454b29b5ab3SAppaRao Puli     // Set the file mode as of actual ipmi-pass file.
455b29b5ab3SAppaRao Puli     if (fchmod(fileno((temp)()), st.st_mode) < 0)
456b29b5ab3SAppaRao Puli     {
457b29b5ab3SAppaRao Puli         log<level::DEBUG>("Error setting fchmod for temp file");
458b29b5ab3SAppaRao Puli         return -EIO;
459b29b5ab3SAppaRao Puli     }
460b29b5ab3SAppaRao Puli 
461b29b5ab3SAppaRao Puli     const EVP_MD* digest = EVP_sha256();
462b29b5ab3SAppaRao Puli     size_t hashLen = EVP_MD_block_size(digest);
463b29b5ab3SAppaRao Puli     std::vector<uint8_t> hash(hashLen);
464b29b5ab3SAppaRao Puli     size_t ivLen = EVP_CIPHER_iv_length(cipher);
465b29b5ab3SAppaRao Puli     std::vector<uint8_t> iv(ivLen);
466b29b5ab3SAppaRao Puli     std::array<uint8_t, EVP_MAX_KEY_LENGTH> key;
467b29b5ab3SAppaRao Puli     size_t keyLen = key.size();
468b29b5ab3SAppaRao Puli     std::array<uint8_t, EVP_MAX_MD_SIZE> mac;
469b29b5ab3SAppaRao Puli     size_t macLen = mac.size();
470b29b5ab3SAppaRao Puli 
471b29b5ab3SAppaRao Puli     // Create random hash and generate hash key which will be used for
472b29b5ab3SAppaRao Puli     // encryption.
473b29b5ab3SAppaRao Puli     if (RAND_bytes(hash.data(), hashLen) != 1)
474b29b5ab3SAppaRao Puli     {
475b29b5ab3SAppaRao Puli         log<level::DEBUG>("Hash genertion failed, bailing out");
476b29b5ab3SAppaRao Puli         return -EIO;
477b29b5ab3SAppaRao Puli     }
478b29b5ab3SAppaRao Puli     if (NULL == HMAC(digest, keyBuff.data(), keyBuff.size(), hash.data(),
479b29b5ab3SAppaRao Puli                      hashLen, key.data(),
480b29b5ab3SAppaRao Puli                      reinterpret_cast<unsigned int*>(&keyLen)))
481b29b5ab3SAppaRao Puli     {
482b29b5ab3SAppaRao Puli         log<level::DEBUG>("Failed to create MAC for authentication");
483b29b5ab3SAppaRao Puli         return -EIO;
484b29b5ab3SAppaRao Puli     }
485b29b5ab3SAppaRao Puli 
486b29b5ab3SAppaRao Puli     // Generate IV values
487b29b5ab3SAppaRao Puli     if (RAND_bytes(iv.data(), ivLen) != 1)
488b29b5ab3SAppaRao Puli     {
489b29b5ab3SAppaRao Puli         log<level::DEBUG>("UV genertion failed, bailing out");
490b29b5ab3SAppaRao Puli         return -EIO;
491b29b5ab3SAppaRao Puli     }
492b29b5ab3SAppaRao Puli 
493b29b5ab3SAppaRao Puli     // Encrypt the input data
494b29b5ab3SAppaRao Puli     std::vector<uint8_t> outBytes(inBytesLen + EVP_MAX_BLOCK_LENGTH);
495b29b5ab3SAppaRao Puli     size_t outBytesLen = 0;
496b29b5ab3SAppaRao Puli     if (inBytesLen != 0)
497b29b5ab3SAppaRao Puli     {
498b29b5ab3SAppaRao Puli         if (encryptDecryptData(true, EVP_aes_128_cbc(), key.data(), keyLen,
499b29b5ab3SAppaRao Puli                                iv.data(), ivLen, inBytes.data(), inBytesLen,
500b29b5ab3SAppaRao Puli                                mac.data(), &macLen, outBytes.data(),
501b29b5ab3SAppaRao Puli                                &outBytesLen) != 0)
502b29b5ab3SAppaRao Puli         {
503b29b5ab3SAppaRao Puli             log<level::DEBUG>("Error while encrypting the data");
504b29b5ab3SAppaRao Puli             return -EIO;
505b29b5ab3SAppaRao Puli         }
506b29b5ab3SAppaRao Puli         outBytes[outBytesLen] = 0;
507b29b5ab3SAppaRao Puli     }
508b29b5ab3SAppaRao Puli     OPENSSL_cleanse(key.data(), keyLen);
509b29b5ab3SAppaRao Puli 
510b29b5ab3SAppaRao Puli     // Update the meta password structure.
511b29b5ab3SAppaRao Puli     metaPassStruct metaData = {META_PASSWD_SIG, {0, 0}, 0, 0, 0, 0, 0};
512b29b5ab3SAppaRao Puli     metaData.hashSize = hashLen;
513b29b5ab3SAppaRao Puli     metaData.ivSize = ivLen;
514b29b5ab3SAppaRao Puli     metaData.dataSize = bytesWritten;
515b29b5ab3SAppaRao Puli     metaData.padSize = outBytesLen - bytesWritten;
516b29b5ab3SAppaRao Puli     metaData.macSize = macLen;
517b29b5ab3SAppaRao Puli 
518b29b5ab3SAppaRao Puli     if (fwrite(&metaData, 1, sizeof(metaData), (temp)()) != sizeof(metaData))
519b29b5ab3SAppaRao Puli     {
520b29b5ab3SAppaRao Puli         log<level::DEBUG>("Error in writing meta data");
521b29b5ab3SAppaRao Puli         return -EIO;
522b29b5ab3SAppaRao Puli     }
523b29b5ab3SAppaRao Puli 
524b29b5ab3SAppaRao Puli     if (fwrite(&hash[0], 1, hashLen, (temp)()) != hashLen)
525b29b5ab3SAppaRao Puli     {
526b29b5ab3SAppaRao Puli         log<level::DEBUG>("Error in writing hash data");
527b29b5ab3SAppaRao Puli         return -EIO;
528b29b5ab3SAppaRao Puli     }
529b29b5ab3SAppaRao Puli 
530b29b5ab3SAppaRao Puli     if (fwrite(&iv[0], 1, ivLen, (temp)()) != ivLen)
531b29b5ab3SAppaRao Puli     {
532b29b5ab3SAppaRao Puli         log<level::DEBUG>("Error in writing IV data");
533b29b5ab3SAppaRao Puli         return -EIO;
534b29b5ab3SAppaRao Puli     }
535b29b5ab3SAppaRao Puli 
536b29b5ab3SAppaRao Puli     if (fwrite(&outBytes[0], 1, outBytesLen, (temp)()) != outBytesLen)
537b29b5ab3SAppaRao Puli     {
538b29b5ab3SAppaRao Puli         log<level::DEBUG>("Error in writing encrypted data");
539b29b5ab3SAppaRao Puli         return -EIO;
540b29b5ab3SAppaRao Puli     }
541b29b5ab3SAppaRao Puli 
542b29b5ab3SAppaRao Puli     if (fwrite(&mac[0], 1, macLen, (temp)()) != macLen)
543b29b5ab3SAppaRao Puli     {
544b29b5ab3SAppaRao Puli         log<level::DEBUG>("Error in writing MAC data");
545b29b5ab3SAppaRao Puli         return -EIO;
546b29b5ab3SAppaRao Puli     }
547b29b5ab3SAppaRao Puli 
548b29b5ab3SAppaRao Puli     if (fflush((temp)()))
549b29b5ab3SAppaRao Puli     {
550b29b5ab3SAppaRao Puli         log<level::DEBUG>(
551b29b5ab3SAppaRao Puli             "File fflush error while writing entries to special file");
552b29b5ab3SAppaRao Puli         return -EIO;
553b29b5ab3SAppaRao Puli     }
554b29b5ab3SAppaRao Puli 
555b29b5ab3SAppaRao Puli     OPENSSL_cleanse(iv.data(), ivLen);
556b29b5ab3SAppaRao Puli 
557b29b5ab3SAppaRao Puli     // Rename the tmp  file to actual file
558b29b5ab3SAppaRao Puli     if (std::rename(strTempFileName.data(), passwdFileName) != 0)
559b29b5ab3SAppaRao Puli     {
560b29b5ab3SAppaRao Puli         log<level::DEBUG>("Failed to rename tmp file to ipmi-pass");
561b29b5ab3SAppaRao Puli         return -EIO;
562b29b5ab3SAppaRao Puli     }
563b29b5ab3SAppaRao Puli 
564b29b5ab3SAppaRao Puli     return 0;
565b29b5ab3SAppaRao Puli }
566b29b5ab3SAppaRao Puli 
567b29b5ab3SAppaRao Puli std::time_t PasswdMgr::getUpdatedFileTime()
568b29b5ab3SAppaRao Puli {
5694654d99fSRichard Marian Thomaiyar     struct stat fileStat = {};
5704654d99fSRichard Marian Thomaiyar     if (stat(passwdFileName, &fileStat) != 0)
5714654d99fSRichard Marian Thomaiyar     {
572b29b5ab3SAppaRao Puli         log<level::DEBUG>("Error - Getting passwd file time stamp");
573b29b5ab3SAppaRao Puli         return -EIO;
5744654d99fSRichard Marian Thomaiyar     }
575b29b5ab3SAppaRao Puli     return fileStat.st_mtime;
5764654d99fSRichard Marian Thomaiyar }
5774654d99fSRichard Marian Thomaiyar 
5784654d99fSRichard Marian Thomaiyar } // namespace ipmi
579