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