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