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 444654d99fSRichard Marian Thomaiyar /* 454654d99fSRichard Marian Thomaiyar * Meta data struct for encrypted password file 464654d99fSRichard Marian Thomaiyar */ 4748e55585SRichard Marian Thomaiyar struct MetaPassStruct 484654d99fSRichard Marian Thomaiyar { 494654d99fSRichard Marian Thomaiyar char signature[10]; 504654d99fSRichard Marian Thomaiyar unsigned char reseved[2]; 514654d99fSRichard Marian Thomaiyar size_t hashSize; 524654d99fSRichard Marian Thomaiyar size_t ivSize; 534654d99fSRichard Marian Thomaiyar size_t dataSize; 544654d99fSRichard Marian Thomaiyar size_t padSize; 554654d99fSRichard Marian Thomaiyar size_t macSize; 564654d99fSRichard Marian Thomaiyar }; 574654d99fSRichard Marian Thomaiyar 584654d99fSRichard Marian Thomaiyar using namespace phosphor::logging; 594654d99fSRichard Marian Thomaiyar 604654d99fSRichard Marian Thomaiyar PasswdMgr::PasswdMgr() 614654d99fSRichard Marian Thomaiyar { 624654d99fSRichard Marian Thomaiyar initPasswordMap(); 634654d99fSRichard Marian Thomaiyar } 644654d99fSRichard Marian Thomaiyar 654654d99fSRichard Marian Thomaiyar std::string PasswdMgr::getPasswdByUserName(const std::string& userName) 664654d99fSRichard Marian Thomaiyar { 674654d99fSRichard Marian Thomaiyar checkAndReload(); 684654d99fSRichard Marian Thomaiyar auto iter = passwdMapList.find(userName); 694654d99fSRichard Marian Thomaiyar if (iter == passwdMapList.end()) 704654d99fSRichard Marian Thomaiyar { 714654d99fSRichard Marian Thomaiyar return std::string(); 724654d99fSRichard Marian Thomaiyar } 734654d99fSRichard Marian Thomaiyar return iter->second; 744654d99fSRichard Marian Thomaiyar } 754654d99fSRichard Marian Thomaiyar 7642bed64dSRichard Marian Thomaiyar int PasswdMgr::updateUserEntry(const std::string& userName, 7742bed64dSRichard Marian Thomaiyar const std::string& newUserName) 78b29b5ab3SAppaRao Puli { 79b29b5ab3SAppaRao Puli std::time_t updatedTime = getUpdatedFileTime(); 80b29b5ab3SAppaRao Puli // Check file time stamp to know passwdMapList is up-to-date. 81b29b5ab3SAppaRao Puli // If not up-to-date, then updatePasswdSpecialFile will read and 82b29b5ab3SAppaRao Puli // check the user entry existance. 83b29b5ab3SAppaRao Puli if (fileLastUpdatedTime == updatedTime && updatedTime != -EIO) 84b29b5ab3SAppaRao Puli { 85b29b5ab3SAppaRao Puli if (passwdMapList.find(userName) == passwdMapList.end()) 86b29b5ab3SAppaRao Puli { 87b29b5ab3SAppaRao Puli log<level::DEBUG>("User not found"); 88b29b5ab3SAppaRao Puli return 0; 89b29b5ab3SAppaRao Puli } 90b29b5ab3SAppaRao Puli } 91b29b5ab3SAppaRao Puli 92b29b5ab3SAppaRao Puli // Write passwdMap to Encryted file 9342bed64dSRichard Marian Thomaiyar if (updatePasswdSpecialFile(userName, newUserName) != 0) 94b29b5ab3SAppaRao Puli { 95b29b5ab3SAppaRao Puli log<level::DEBUG>("Passwd file update failed"); 96b29b5ab3SAppaRao Puli return -EIO; 97b29b5ab3SAppaRao Puli } 98b29b5ab3SAppaRao Puli 99b29b5ab3SAppaRao Puli log<level::DEBUG>("Passwd file updated successfully"); 100b29b5ab3SAppaRao Puli return 0; 101b29b5ab3SAppaRao Puli } 102b29b5ab3SAppaRao Puli 1034654d99fSRichard Marian Thomaiyar void PasswdMgr::checkAndReload(void) 1044654d99fSRichard Marian Thomaiyar { 105b29b5ab3SAppaRao Puli std::time_t updatedTime = getUpdatedFileTime(); 106b29b5ab3SAppaRao Puli if (fileLastUpdatedTime != updatedTime && updatedTime != -1) 1074654d99fSRichard Marian Thomaiyar { 1084654d99fSRichard Marian Thomaiyar log<level::DEBUG>("Reloading password map list"); 1094654d99fSRichard Marian Thomaiyar passwdMapList.clear(); 1104654d99fSRichard Marian Thomaiyar initPasswordMap(); 1114654d99fSRichard Marian Thomaiyar } 1124654d99fSRichard Marian Thomaiyar } 1134654d99fSRichard Marian Thomaiyar 114b29b5ab3SAppaRao Puli int PasswdMgr::encryptDecryptData(bool doEncrypt, const EVP_CIPHER* cipher, 115b29b5ab3SAppaRao Puli uint8_t* key, size_t keyLen, uint8_t* iv, 116b29b5ab3SAppaRao Puli size_t ivLen, uint8_t* inBytes, 117b29b5ab3SAppaRao Puli size_t inBytesLen, uint8_t* mac, 118b29b5ab3SAppaRao Puli size_t* macLen, unsigned char* outBytes, 119b29b5ab3SAppaRao Puli size_t* outBytesLen) 1204654d99fSRichard Marian Thomaiyar { 1214654d99fSRichard Marian Thomaiyar if (cipher == NULL || key == NULL || iv == NULL || inBytes == NULL || 1224654d99fSRichard Marian Thomaiyar outBytes == NULL || mac == NULL || inBytesLen == 0 || 1234654d99fSRichard Marian Thomaiyar (size_t)EVP_CIPHER_key_length(cipher) > keyLen || 1244654d99fSRichard Marian Thomaiyar (size_t)EVP_CIPHER_iv_length(cipher) > ivLen) 1254654d99fSRichard Marian Thomaiyar { 1264654d99fSRichard Marian Thomaiyar log<level::DEBUG>("Error Invalid Inputs"); 127b29b5ab3SAppaRao Puli return -EINVAL; 1284654d99fSRichard Marian Thomaiyar } 1294654d99fSRichard Marian Thomaiyar 130b29b5ab3SAppaRao Puli if (!doEncrypt) 131b29b5ab3SAppaRao Puli { 132b29b5ab3SAppaRao Puli // verify MAC before decrypting the data. 1334654d99fSRichard Marian Thomaiyar std::array<uint8_t, EVP_MAX_MD_SIZE> calMac; 1344654d99fSRichard Marian Thomaiyar size_t calMacLen = calMac.size(); 1354654d99fSRichard Marian Thomaiyar // calculate MAC for the encrypted message. 1364654d99fSRichard Marian Thomaiyar if (NULL == HMAC(EVP_sha256(), key, keyLen, inBytes, inBytesLen, 1374654d99fSRichard Marian Thomaiyar calMac.data(), 1384654d99fSRichard Marian Thomaiyar reinterpret_cast<unsigned int*>(&calMacLen))) 1394654d99fSRichard Marian Thomaiyar { 1404654d99fSRichard Marian Thomaiyar log<level::DEBUG>("Error: Failed to calculate MAC"); 141b29b5ab3SAppaRao Puli return -EIO; 1424654d99fSRichard Marian Thomaiyar } 143b29b5ab3SAppaRao Puli if (!((calMacLen == *macLen) && 1444654d99fSRichard Marian Thomaiyar (std::memcmp(calMac.data(), mac, calMacLen) == 0))) 1454654d99fSRichard Marian Thomaiyar { 1464654d99fSRichard Marian Thomaiyar log<level::DEBUG>("Authenticated message doesn't match"); 147b29b5ab3SAppaRao Puli return -EBADMSG; 148b29b5ab3SAppaRao Puli } 1494654d99fSRichard Marian Thomaiyar } 1504654d99fSRichard Marian Thomaiyar 1514654d99fSRichard Marian Thomaiyar std::unique_ptr<EVP_CIPHER_CTX, decltype(&::EVP_CIPHER_CTX_free)> ctx( 1524654d99fSRichard Marian Thomaiyar EVP_CIPHER_CTX_new(), ::EVP_CIPHER_CTX_free); 1534654d99fSRichard Marian Thomaiyar EVP_CIPHER_CTX_set_padding(ctx.get(), 1); 1544654d99fSRichard Marian Thomaiyar 155b29b5ab3SAppaRao Puli // Set key & IV 156b29b5ab3SAppaRao Puli int retval = EVP_CipherInit_ex(ctx.get(), cipher, NULL, key, iv, 157b29b5ab3SAppaRao Puli static_cast<int>(doEncrypt)); 1584654d99fSRichard Marian Thomaiyar if (!retval) 1594654d99fSRichard Marian Thomaiyar { 1604654d99fSRichard Marian Thomaiyar log<level::DEBUG>("EVP_CipherInit_ex failed", 1614654d99fSRichard Marian Thomaiyar entry("RET_VAL=%d", retval)); 162b29b5ab3SAppaRao Puli return -EIO; 1634654d99fSRichard Marian Thomaiyar } 1644654d99fSRichard Marian Thomaiyar 1654654d99fSRichard Marian Thomaiyar int outLen = 0, outEVPLen = 0; 1664654d99fSRichard Marian Thomaiyar if ((retval = EVP_CipherUpdate(ctx.get(), outBytes + outLen, &outEVPLen, 1674654d99fSRichard Marian Thomaiyar inBytes, inBytesLen))) 1684654d99fSRichard Marian Thomaiyar { 1694654d99fSRichard Marian Thomaiyar outLen += outEVPLen; 1704654d99fSRichard Marian Thomaiyar if ((retval = 1714654d99fSRichard Marian Thomaiyar EVP_CipherFinal(ctx.get(), outBytes + outLen, &outEVPLen))) 1724654d99fSRichard Marian Thomaiyar { 1734654d99fSRichard Marian Thomaiyar outLen += outEVPLen; 1744654d99fSRichard Marian Thomaiyar *outBytesLen = outLen; 1754654d99fSRichard Marian Thomaiyar } 1764654d99fSRichard Marian Thomaiyar else 1774654d99fSRichard Marian Thomaiyar { 1784654d99fSRichard Marian Thomaiyar log<level::DEBUG>("EVP_CipherFinal fails", 1794654d99fSRichard Marian Thomaiyar entry("RET_VAL=%d", retval)); 180b29b5ab3SAppaRao Puli return -EIO; 1814654d99fSRichard Marian Thomaiyar } 1824654d99fSRichard Marian Thomaiyar } 1834654d99fSRichard Marian Thomaiyar else 1844654d99fSRichard Marian Thomaiyar { 1854654d99fSRichard Marian Thomaiyar log<level::DEBUG>("EVP_CipherUpdate fails", 1864654d99fSRichard Marian Thomaiyar entry("RET_VAL=%d", retval)); 187b29b5ab3SAppaRao Puli return -EIO; 188b29b5ab3SAppaRao Puli } 189b29b5ab3SAppaRao Puli 190b29b5ab3SAppaRao Puli if (doEncrypt) 191b29b5ab3SAppaRao Puli { 192b29b5ab3SAppaRao Puli // Create MAC for the encrypted message 193b29b5ab3SAppaRao Puli if (NULL == HMAC(EVP_sha256(), key, keyLen, outBytes, *outBytesLen, mac, 194b29b5ab3SAppaRao Puli reinterpret_cast<unsigned int*>(macLen))) 195b29b5ab3SAppaRao Puli { 196b29b5ab3SAppaRao Puli log<level::DEBUG>("Failed to create authentication"); 197b29b5ab3SAppaRao Puli return -EIO; 198b29b5ab3SAppaRao Puli } 1994654d99fSRichard Marian Thomaiyar } 2004654d99fSRichard Marian Thomaiyar return 0; 2014654d99fSRichard Marian Thomaiyar } 2024654d99fSRichard Marian Thomaiyar 2034654d99fSRichard Marian Thomaiyar void PasswdMgr::initPasswordMap(void) 2044654d99fSRichard Marian Thomaiyar { 2054654d99fSRichard Marian Thomaiyar phosphor::user::shadow::Lock lock(); 206b29b5ab3SAppaRao Puli std::vector<uint8_t> dataBuf; 2074654d99fSRichard Marian Thomaiyar 208b29b5ab3SAppaRao Puli if (readPasswdFileData(dataBuf) != 0) 2094654d99fSRichard Marian Thomaiyar { 210b29b5ab3SAppaRao Puli log<level::DEBUG>("Error in reading the encrypted pass file"); 2114654d99fSRichard Marian Thomaiyar return; 2124654d99fSRichard Marian Thomaiyar } 2134654d99fSRichard Marian Thomaiyar 214b29b5ab3SAppaRao Puli if (dataBuf.size() != 0) 2154654d99fSRichard Marian Thomaiyar { 2164654d99fSRichard Marian Thomaiyar // populate the user list with password 217b29b5ab3SAppaRao Puli char* outPtr = reinterpret_cast<char*>(dataBuf.data()); 2184654d99fSRichard Marian Thomaiyar char* nToken = NULL; 2194654d99fSRichard Marian Thomaiyar char* linePtr = strtok_r(outPtr, "\n", &nToken); 220*51d0c40aSPatrick Venture size_t lineSize = 0; 2214654d99fSRichard Marian Thomaiyar while (linePtr != NULL) 2224654d99fSRichard Marian Thomaiyar { 223*51d0c40aSPatrick Venture size_t userEPos = 0; 2244654d99fSRichard Marian Thomaiyar std::string lineStr(linePtr); 2254654d99fSRichard Marian Thomaiyar if ((userEPos = lineStr.find(":")) != std::string::npos) 2264654d99fSRichard Marian Thomaiyar { 2274654d99fSRichard Marian Thomaiyar lineSize = lineStr.size(); 2284654d99fSRichard Marian Thomaiyar passwdMapList.emplace( 2294654d99fSRichard Marian Thomaiyar lineStr.substr(0, userEPos), 2304654d99fSRichard Marian Thomaiyar lineStr.substr(userEPos + 1, lineSize - (userEPos + 1))); 2314654d99fSRichard Marian Thomaiyar } 2324654d99fSRichard Marian Thomaiyar linePtr = strtok_r(NULL, "\n", &nToken); 2334654d99fSRichard Marian Thomaiyar } 234b29b5ab3SAppaRao Puli } 235b29b5ab3SAppaRao Puli 2364654d99fSRichard Marian Thomaiyar // Update the timestamp 237b29b5ab3SAppaRao Puli fileLastUpdatedTime = getUpdatedFileTime(); 238b29b5ab3SAppaRao Puli return; 239b29b5ab3SAppaRao Puli } 240b29b5ab3SAppaRao Puli 241b29b5ab3SAppaRao Puli int PasswdMgr::readPasswdFileData(std::vector<uint8_t>& outBytes) 242b29b5ab3SAppaRao Puli { 243b29b5ab3SAppaRao Puli std::array<uint8_t, maxKeySize> keyBuff; 244b29b5ab3SAppaRao Puli std::ifstream keyFile(encryptKeyFileName, std::ios::in | std::ios::binary); 245b29b5ab3SAppaRao Puli if (!keyFile.is_open()) 246b29b5ab3SAppaRao Puli { 247b29b5ab3SAppaRao Puli log<level::DEBUG>("Error in opening encryption key file"); 248b29b5ab3SAppaRao Puli return -EIO; 249b29b5ab3SAppaRao Puli } 250b29b5ab3SAppaRao Puli keyFile.read(reinterpret_cast<char*>(keyBuff.data()), keyBuff.size()); 251b29b5ab3SAppaRao Puli if (keyFile.fail()) 252b29b5ab3SAppaRao Puli { 253b29b5ab3SAppaRao Puli log<level::DEBUG>("Error in reading encryption key file"); 254b29b5ab3SAppaRao Puli return -EIO; 255b29b5ab3SAppaRao Puli } 256b29b5ab3SAppaRao Puli 257b29b5ab3SAppaRao Puli std::ifstream passwdFile(passwdFileName, std::ios::in | std::ios::binary); 258b29b5ab3SAppaRao Puli if (!passwdFile.is_open()) 259b29b5ab3SAppaRao Puli { 260b29b5ab3SAppaRao Puli log<level::DEBUG>("Error in opening ipmi password file"); 261b29b5ab3SAppaRao Puli return -EIO; 262b29b5ab3SAppaRao Puli } 263b29b5ab3SAppaRao Puli 264b29b5ab3SAppaRao Puli // calculate file size and read the data 265b29b5ab3SAppaRao Puli passwdFile.seekg(0, std::ios::end); 266b29b5ab3SAppaRao Puli ssize_t fileSize = passwdFile.tellg(); 267b29b5ab3SAppaRao Puli passwdFile.seekg(0, std::ios::beg); 268b29b5ab3SAppaRao Puli std::vector<uint8_t> input(fileSize); 269b29b5ab3SAppaRao Puli passwdFile.read(reinterpret_cast<char*>(input.data()), fileSize); 270b29b5ab3SAppaRao Puli if (passwdFile.fail()) 271b29b5ab3SAppaRao Puli { 272b29b5ab3SAppaRao Puli log<level::DEBUG>("Error in reading encryption key file"); 273b29b5ab3SAppaRao Puli return -EIO; 274b29b5ab3SAppaRao Puli } 275b29b5ab3SAppaRao Puli 276b29b5ab3SAppaRao Puli // verify the signature first 27748e55585SRichard Marian Thomaiyar MetaPassStruct* metaData = reinterpret_cast<MetaPassStruct*>(input.data()); 278b29b5ab3SAppaRao Puli if (std::strncmp(metaData->signature, META_PASSWD_SIG, 279b29b5ab3SAppaRao Puli sizeof(metaData->signature))) 280b29b5ab3SAppaRao Puli { 281b29b5ab3SAppaRao Puli log<level::DEBUG>("Error signature mismatch in password file"); 282b29b5ab3SAppaRao Puli return -EBADMSG; 283b29b5ab3SAppaRao Puli } 284b29b5ab3SAppaRao Puli 285b29b5ab3SAppaRao Puli size_t inBytesLen = metaData->dataSize + metaData->padSize; 286b29b5ab3SAppaRao Puli // If data is empty i.e no password map then return success 287b29b5ab3SAppaRao Puli if (inBytesLen == 0) 288b29b5ab3SAppaRao Puli { 289b29b5ab3SAppaRao Puli log<level::DEBUG>("Empty password file"); 290b29b5ab3SAppaRao Puli return 0; 291b29b5ab3SAppaRao Puli } 292b29b5ab3SAppaRao Puli 293b29b5ab3SAppaRao Puli // compute the key needed to decrypt 294b29b5ab3SAppaRao Puli std::array<uint8_t, EVP_MAX_KEY_LENGTH> key; 295b29b5ab3SAppaRao Puli auto keyLen = key.size(); 296b29b5ab3SAppaRao Puli if (NULL == HMAC(EVP_sha256(), keyBuff.data(), keyBuff.size(), 297b29b5ab3SAppaRao Puli input.data() + sizeof(*metaData), metaData->hashSize, 298b29b5ab3SAppaRao Puli key.data(), reinterpret_cast<unsigned int*>(&keyLen))) 299b29b5ab3SAppaRao Puli { 300b29b5ab3SAppaRao Puli log<level::DEBUG>("Failed to create MAC for authentication"); 301b29b5ab3SAppaRao Puli return -EIO; 302b29b5ab3SAppaRao Puli } 303b29b5ab3SAppaRao Puli 304b29b5ab3SAppaRao Puli // decrypt the data 305b29b5ab3SAppaRao Puli uint8_t* iv = input.data() + sizeof(*metaData) + metaData->hashSize; 306b29b5ab3SAppaRao Puli size_t ivLen = metaData->ivSize; 307b29b5ab3SAppaRao Puli uint8_t* inBytes = iv + ivLen; 308b29b5ab3SAppaRao Puli uint8_t* mac = inBytes + inBytesLen; 309b29b5ab3SAppaRao Puli size_t macLen = metaData->macSize; 310b29b5ab3SAppaRao Puli 311b29b5ab3SAppaRao Puli size_t outBytesLen = 0; 312b29b5ab3SAppaRao Puli // Resize to actual data size 313b29b5ab3SAppaRao Puli outBytes.resize(inBytesLen + EVP_MAX_BLOCK_LENGTH); 314b29b5ab3SAppaRao Puli if (encryptDecryptData(false, EVP_aes_128_cbc(), key.data(), keyLen, iv, 315b29b5ab3SAppaRao Puli ivLen, inBytes, inBytesLen, mac, &macLen, 316b29b5ab3SAppaRao Puli outBytes.data(), &outBytesLen) != 0) 317b29b5ab3SAppaRao Puli { 318b29b5ab3SAppaRao Puli log<level::DEBUG>("Error in decryption"); 319b29b5ab3SAppaRao Puli return -EIO; 320b29b5ab3SAppaRao Puli } 321b29b5ab3SAppaRao Puli // Resize the vector to outBytesLen 322b29b5ab3SAppaRao Puli outBytes.resize(outBytesLen); 323b29b5ab3SAppaRao Puli 324b29b5ab3SAppaRao Puli OPENSSL_cleanse(key.data(), keyLen); 325b29b5ab3SAppaRao Puli OPENSSL_cleanse(iv, ivLen); 326b29b5ab3SAppaRao Puli 327b29b5ab3SAppaRao Puli return 0; 328b29b5ab3SAppaRao Puli } 329b29b5ab3SAppaRao Puli 33042bed64dSRichard Marian Thomaiyar int PasswdMgr::updatePasswdSpecialFile(const std::string& userName, 33142bed64dSRichard Marian Thomaiyar const std::string& newUserName) 332b29b5ab3SAppaRao Puli { 333b29b5ab3SAppaRao Puli phosphor::user::shadow::Lock lock(); 334b29b5ab3SAppaRao Puli 335b29b5ab3SAppaRao Puli size_t bytesWritten = 0; 336b29b5ab3SAppaRao Puli size_t inBytesLen = 0; 337b29b5ab3SAppaRao Puli size_t isUsrFound = false; 338b29b5ab3SAppaRao Puli const EVP_CIPHER* cipher = EVP_aes_128_cbc(); 339b29b5ab3SAppaRao Puli std::vector<uint8_t> dataBuf; 340b29b5ab3SAppaRao Puli 341b29b5ab3SAppaRao Puli // Read the encrypted file and get the file data 342b29b5ab3SAppaRao Puli // Check user existance and return if not exist. 343b29b5ab3SAppaRao Puli if (readPasswdFileData(dataBuf) != 0) 344b29b5ab3SAppaRao Puli { 345b29b5ab3SAppaRao Puli log<level::DEBUG>("Error in reading the encrypted pass file"); 346b29b5ab3SAppaRao Puli return -EIO; 347b29b5ab3SAppaRao Puli } 348b29b5ab3SAppaRao Puli 349b29b5ab3SAppaRao Puli if (dataBuf.size() != 0) 350b29b5ab3SAppaRao Puli { 35142bed64dSRichard Marian Thomaiyar inBytesLen = 35242bed64dSRichard Marian Thomaiyar dataBuf.size() + newUserName.size() + EVP_CIPHER_block_size(cipher); 353b29b5ab3SAppaRao Puli } 354b29b5ab3SAppaRao Puli 355b29b5ab3SAppaRao Puli std::vector<uint8_t> inBytes(inBytesLen); 356b29b5ab3SAppaRao Puli if (inBytesLen != 0) 357b29b5ab3SAppaRao Puli { 358b29b5ab3SAppaRao Puli char* outPtr = reinterpret_cast<char*>(dataBuf.data()); 359b29b5ab3SAppaRao Puli char* nToken = NULL; 360b29b5ab3SAppaRao Puli char* linePtr = strtok_r(outPtr, "\n", &nToken); 361b29b5ab3SAppaRao Puli while (linePtr != NULL) 362b29b5ab3SAppaRao Puli { 363*51d0c40aSPatrick Venture size_t userEPos = 0; 364*51d0c40aSPatrick Venture 365b29b5ab3SAppaRao Puli std::string lineStr(linePtr); 366b29b5ab3SAppaRao Puli if ((userEPos = lineStr.find(":")) != std::string::npos) 367b29b5ab3SAppaRao Puli { 368b29b5ab3SAppaRao Puli if (userName.compare(lineStr.substr(0, userEPos)) == 0) 369b29b5ab3SAppaRao Puli { 370b29b5ab3SAppaRao Puli isUsrFound = true; 37142bed64dSRichard Marian Thomaiyar if (!newUserName.empty()) 37242bed64dSRichard Marian Thomaiyar { 37342bed64dSRichard Marian Thomaiyar bytesWritten += std::snprintf( 37442bed64dSRichard Marian Thomaiyar reinterpret_cast<char*>(&inBytes[0]) + bytesWritten, 37542bed64dSRichard Marian Thomaiyar (inBytesLen - bytesWritten), "%s%s\n", 37642bed64dSRichard Marian Thomaiyar newUserName.c_str(), 37742bed64dSRichard Marian Thomaiyar lineStr.substr(userEPos, lineStr.size()).data()); 37842bed64dSRichard Marian Thomaiyar } 379b29b5ab3SAppaRao Puli } 380b29b5ab3SAppaRao Puli else 381b29b5ab3SAppaRao Puli { 382b29b5ab3SAppaRao Puli bytesWritten += std::snprintf( 383b29b5ab3SAppaRao Puli reinterpret_cast<char*>(&inBytes[0]) + bytesWritten, 38442bed64dSRichard Marian Thomaiyar (inBytesLen - bytesWritten), "%s\n", lineStr.data()); 385b29b5ab3SAppaRao Puli } 386b29b5ab3SAppaRao Puli } 387b29b5ab3SAppaRao Puli linePtr = strtok_r(NULL, "\n", &nToken); 388b29b5ab3SAppaRao Puli } 389161f20d5SRichard Marian Thomaiyar inBytesLen = bytesWritten; 390b29b5ab3SAppaRao Puli } 391b29b5ab3SAppaRao Puli if (!isUsrFound) 392b29b5ab3SAppaRao Puli { 393b29b5ab3SAppaRao Puli log<level::DEBUG>("User doesn't exist"); 394b29b5ab3SAppaRao Puli return 0; 395b29b5ab3SAppaRao Puli } 396b29b5ab3SAppaRao Puli 397b29b5ab3SAppaRao Puli // Read the key buff from key file 398b29b5ab3SAppaRao Puli std::array<uint8_t, maxKeySize> keyBuff; 399b29b5ab3SAppaRao Puli std::ifstream keyFile(encryptKeyFileName, std::ios::in | std::ios::binary); 400b29b5ab3SAppaRao Puli if (!keyFile.good()) 401b29b5ab3SAppaRao Puli { 402b29b5ab3SAppaRao Puli log<level::DEBUG>("Error in opening encryption key file"); 403b29b5ab3SAppaRao Puli return -EIO; 404b29b5ab3SAppaRao Puli } 405b29b5ab3SAppaRao Puli keyFile.read(reinterpret_cast<char*>(keyBuff.data()), keyBuff.size()); 406b29b5ab3SAppaRao Puli if (keyFile.fail()) 407b29b5ab3SAppaRao Puli { 408b29b5ab3SAppaRao Puli log<level::DEBUG>("Error in reading encryption key file"); 409b29b5ab3SAppaRao Puli return -EIO; 410b29b5ab3SAppaRao Puli } 411b29b5ab3SAppaRao Puli keyFile.close(); 412b29b5ab3SAppaRao Puli 413b29b5ab3SAppaRao Puli // Read the original passwd file mode 414b29b5ab3SAppaRao Puli struct stat st = {}; 415b29b5ab3SAppaRao Puli if (stat(passwdFileName, &st) != 0) 416b29b5ab3SAppaRao Puli { 417b29b5ab3SAppaRao Puli log<level::DEBUG>("Error in getting password file fstat()"); 418b29b5ab3SAppaRao Puli return -EIO; 419b29b5ab3SAppaRao Puli } 420b29b5ab3SAppaRao Puli 421b29b5ab3SAppaRao Puli // Create temporary file for write 422b29b5ab3SAppaRao Puli std::string pwdFile(passwdFileName); 423b29b5ab3SAppaRao Puli std::vector<char> tempFileName(pwdFile.begin(), pwdFile.end()); 424b29b5ab3SAppaRao Puli std::vector<char> fileTemplate = {'_', '_', 'X', 'X', 'X', 425b29b5ab3SAppaRao Puli 'X', 'X', 'X', '\0'}; 426b29b5ab3SAppaRao Puli tempFileName.insert(tempFileName.end(), fileTemplate.begin(), 427b29b5ab3SAppaRao Puli fileTemplate.end()); 428b29b5ab3SAppaRao Puli int fd = mkstemp((char*)tempFileName.data()); 429b29b5ab3SAppaRao Puli if (fd == -1) 430b29b5ab3SAppaRao Puli { 431b29b5ab3SAppaRao Puli log<level::DEBUG>("Error creating temp file"); 432b29b5ab3SAppaRao Puli return -EIO; 433b29b5ab3SAppaRao Puli } 434b29b5ab3SAppaRao Puli 435b29b5ab3SAppaRao Puli std::string strTempFileName(tempFileName.data()); 436b29b5ab3SAppaRao Puli // Open the temp file for writing from provided fd 437b29b5ab3SAppaRao Puli // By "true", remove it at exit if still there. 438b29b5ab3SAppaRao Puli // This is needed to cleanup the temp file at exception 439b29b5ab3SAppaRao Puli phosphor::user::File temp(fd, strTempFileName, "w", true); 440b29b5ab3SAppaRao Puli if ((temp)() == NULL) 441b29b5ab3SAppaRao Puli { 442b29b5ab3SAppaRao Puli close(fd); 443b29b5ab3SAppaRao Puli log<level::DEBUG>("Error creating temp file"); 444b29b5ab3SAppaRao Puli return -EIO; 445b29b5ab3SAppaRao Puli } 446b29b5ab3SAppaRao Puli 447b29b5ab3SAppaRao Puli // Set the file mode as of actual ipmi-pass file. 448b29b5ab3SAppaRao Puli if (fchmod(fileno((temp)()), st.st_mode) < 0) 449b29b5ab3SAppaRao Puli { 450b29b5ab3SAppaRao Puli log<level::DEBUG>("Error setting fchmod for temp file"); 451b29b5ab3SAppaRao Puli return -EIO; 452b29b5ab3SAppaRao Puli } 453b29b5ab3SAppaRao Puli 454b29b5ab3SAppaRao Puli const EVP_MD* digest = EVP_sha256(); 455b29b5ab3SAppaRao Puli size_t hashLen = EVP_MD_block_size(digest); 456b29b5ab3SAppaRao Puli std::vector<uint8_t> hash(hashLen); 457b29b5ab3SAppaRao Puli size_t ivLen = EVP_CIPHER_iv_length(cipher); 458b29b5ab3SAppaRao Puli std::vector<uint8_t> iv(ivLen); 459b29b5ab3SAppaRao Puli std::array<uint8_t, EVP_MAX_KEY_LENGTH> key; 460b29b5ab3SAppaRao Puli size_t keyLen = key.size(); 461b29b5ab3SAppaRao Puli std::array<uint8_t, EVP_MAX_MD_SIZE> mac; 462b29b5ab3SAppaRao Puli size_t macLen = mac.size(); 463b29b5ab3SAppaRao Puli 464b29b5ab3SAppaRao Puli // Create random hash and generate hash key which will be used for 465b29b5ab3SAppaRao Puli // encryption. 466b29b5ab3SAppaRao Puli if (RAND_bytes(hash.data(), hashLen) != 1) 467b29b5ab3SAppaRao Puli { 468b29b5ab3SAppaRao Puli log<level::DEBUG>("Hash genertion failed, bailing out"); 469b29b5ab3SAppaRao Puli return -EIO; 470b29b5ab3SAppaRao Puli } 471b29b5ab3SAppaRao Puli if (NULL == HMAC(digest, keyBuff.data(), keyBuff.size(), hash.data(), 472b29b5ab3SAppaRao Puli hashLen, key.data(), 473b29b5ab3SAppaRao Puli reinterpret_cast<unsigned int*>(&keyLen))) 474b29b5ab3SAppaRao Puli { 475b29b5ab3SAppaRao Puli log<level::DEBUG>("Failed to create MAC for authentication"); 476b29b5ab3SAppaRao Puli return -EIO; 477b29b5ab3SAppaRao Puli } 478b29b5ab3SAppaRao Puli 479b29b5ab3SAppaRao Puli // Generate IV values 480b29b5ab3SAppaRao Puli if (RAND_bytes(iv.data(), ivLen) != 1) 481b29b5ab3SAppaRao Puli { 482b29b5ab3SAppaRao Puli log<level::DEBUG>("UV genertion failed, bailing out"); 483b29b5ab3SAppaRao Puli return -EIO; 484b29b5ab3SAppaRao Puli } 485b29b5ab3SAppaRao Puli 486b29b5ab3SAppaRao Puli // Encrypt the input data 487b29b5ab3SAppaRao Puli std::vector<uint8_t> outBytes(inBytesLen + EVP_MAX_BLOCK_LENGTH); 488b29b5ab3SAppaRao Puli size_t outBytesLen = 0; 489b29b5ab3SAppaRao Puli if (inBytesLen != 0) 490b29b5ab3SAppaRao Puli { 491b29b5ab3SAppaRao Puli if (encryptDecryptData(true, EVP_aes_128_cbc(), key.data(), keyLen, 492b29b5ab3SAppaRao Puli iv.data(), ivLen, inBytes.data(), inBytesLen, 493b29b5ab3SAppaRao Puli mac.data(), &macLen, outBytes.data(), 494b29b5ab3SAppaRao Puli &outBytesLen) != 0) 495b29b5ab3SAppaRao Puli { 496b29b5ab3SAppaRao Puli log<level::DEBUG>("Error while encrypting the data"); 497b29b5ab3SAppaRao Puli return -EIO; 498b29b5ab3SAppaRao Puli } 499b29b5ab3SAppaRao Puli outBytes[outBytesLen] = 0; 500b29b5ab3SAppaRao Puli } 501b29b5ab3SAppaRao Puli OPENSSL_cleanse(key.data(), keyLen); 502b29b5ab3SAppaRao Puli 503b29b5ab3SAppaRao Puli // Update the meta password structure. 50448e55585SRichard Marian Thomaiyar MetaPassStruct metaData = {META_PASSWD_SIG, {0, 0}, 0, 0, 0, 0, 0}; 505b29b5ab3SAppaRao Puli metaData.hashSize = hashLen; 506b29b5ab3SAppaRao Puli metaData.ivSize = ivLen; 507b29b5ab3SAppaRao Puli metaData.dataSize = bytesWritten; 508b29b5ab3SAppaRao Puli metaData.padSize = outBytesLen - bytesWritten; 509b29b5ab3SAppaRao Puli metaData.macSize = macLen; 510b29b5ab3SAppaRao Puli 511b29b5ab3SAppaRao Puli if (fwrite(&metaData, 1, sizeof(metaData), (temp)()) != sizeof(metaData)) 512b29b5ab3SAppaRao Puli { 513b29b5ab3SAppaRao Puli log<level::DEBUG>("Error in writing meta data"); 514b29b5ab3SAppaRao Puli return -EIO; 515b29b5ab3SAppaRao Puli } 516b29b5ab3SAppaRao Puli 517b29b5ab3SAppaRao Puli if (fwrite(&hash[0], 1, hashLen, (temp)()) != hashLen) 518b29b5ab3SAppaRao Puli { 519b29b5ab3SAppaRao Puli log<level::DEBUG>("Error in writing hash data"); 520b29b5ab3SAppaRao Puli return -EIO; 521b29b5ab3SAppaRao Puli } 522b29b5ab3SAppaRao Puli 523b29b5ab3SAppaRao Puli if (fwrite(&iv[0], 1, ivLen, (temp)()) != ivLen) 524b29b5ab3SAppaRao Puli { 525b29b5ab3SAppaRao Puli log<level::DEBUG>("Error in writing IV data"); 526b29b5ab3SAppaRao Puli return -EIO; 527b29b5ab3SAppaRao Puli } 528b29b5ab3SAppaRao Puli 529b29b5ab3SAppaRao Puli if (fwrite(&outBytes[0], 1, outBytesLen, (temp)()) != outBytesLen) 530b29b5ab3SAppaRao Puli { 531b29b5ab3SAppaRao Puli log<level::DEBUG>("Error in writing encrypted data"); 532b29b5ab3SAppaRao Puli return -EIO; 533b29b5ab3SAppaRao Puli } 534b29b5ab3SAppaRao Puli 535b29b5ab3SAppaRao Puli if (fwrite(&mac[0], 1, macLen, (temp)()) != macLen) 536b29b5ab3SAppaRao Puli { 537b29b5ab3SAppaRao Puli log<level::DEBUG>("Error in writing MAC data"); 538b29b5ab3SAppaRao Puli return -EIO; 539b29b5ab3SAppaRao Puli } 540b29b5ab3SAppaRao Puli 541b29b5ab3SAppaRao Puli if (fflush((temp)())) 542b29b5ab3SAppaRao Puli { 543b29b5ab3SAppaRao Puli log<level::DEBUG>( 544b29b5ab3SAppaRao Puli "File fflush error while writing entries to special file"); 545b29b5ab3SAppaRao Puli return -EIO; 546b29b5ab3SAppaRao Puli } 547b29b5ab3SAppaRao Puli 548b29b5ab3SAppaRao Puli OPENSSL_cleanse(iv.data(), ivLen); 549b29b5ab3SAppaRao Puli 550b29b5ab3SAppaRao Puli // Rename the tmp file to actual file 551b29b5ab3SAppaRao Puli if (std::rename(strTempFileName.data(), passwdFileName) != 0) 552b29b5ab3SAppaRao Puli { 553b29b5ab3SAppaRao Puli log<level::DEBUG>("Failed to rename tmp file to ipmi-pass"); 554b29b5ab3SAppaRao Puli return -EIO; 555b29b5ab3SAppaRao Puli } 556b29b5ab3SAppaRao Puli 557b29b5ab3SAppaRao Puli return 0; 558b29b5ab3SAppaRao Puli } 559b29b5ab3SAppaRao Puli 560b29b5ab3SAppaRao Puli std::time_t PasswdMgr::getUpdatedFileTime() 561b29b5ab3SAppaRao Puli { 5624654d99fSRichard Marian Thomaiyar struct stat fileStat = {}; 5634654d99fSRichard Marian Thomaiyar if (stat(passwdFileName, &fileStat) != 0) 5644654d99fSRichard Marian Thomaiyar { 565b29b5ab3SAppaRao Puli log<level::DEBUG>("Error - Getting passwd file time stamp"); 566b29b5ab3SAppaRao Puli return -EIO; 5674654d99fSRichard Marian Thomaiyar } 568b29b5ab3SAppaRao Puli return fileStat.st_mtime; 5694654d99fSRichard Marian Thomaiyar } 5704654d99fSRichard Marian Thomaiyar 5714654d99fSRichard Marian Thomaiyar } // namespace ipmi 572