1 /*
2 // Copyright (c) 2018 Intel Corporation
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 */
16 
17 #include "passwd_mgr.hpp"
18 
19 #include "file.hpp"
20 #include "shadowlock.hpp"
21 
22 #include <openssl/hmac.h>
23 #include <openssl/rand.h>
24 #include <openssl/sha.h>
25 #include <string.h>
26 #include <sys/stat.h>
27 #include <unistd.h>
28 
29 #include <cerrno>
30 #include <cstring>
31 #include <fstream>
32 #include <iomanip>
33 #include <phosphor-logging/log.hpp>
34 
35 namespace ipmi
36 {
37 
38 static const char* passwdFileName = "/etc/ipmi_pass";
39 static const char* encryptKeyFileName = "/etc/key_file";
40 static const size_t maxKeySize = 8;
41 
42 #define META_PASSWD_SIG "=OPENBMC="
43 
44 /*
45  * Meta data struct for encrypted password file
46  */
47 struct MetaPassStruct
48 {
49     char signature[10];
50     unsigned char reseved[2];
51     size_t hashSize;
52     size_t ivSize;
53     size_t dataSize;
54     size_t padSize;
55     size_t macSize;
56 };
57 
58 using namespace phosphor::logging;
59 
60 PasswdMgr::PasswdMgr()
61 {
62     initPasswordMap();
63 }
64 
65 std::string PasswdMgr::getPasswdByUserName(const std::string& userName)
66 {
67     checkAndReload();
68     auto iter = passwdMapList.find(userName);
69     if (iter == passwdMapList.end())
70     {
71         return std::string();
72     }
73     return iter->second;
74 }
75 
76 int PasswdMgr::updateUserEntry(const std::string& userName,
77                                const std::string& newUserName)
78 {
79     std::time_t updatedTime = getUpdatedFileTime();
80     // Check file time stamp to know passwdMapList is up-to-date.
81     // If not up-to-date, then updatePasswdSpecialFile will read and
82     // check the user entry existance.
83     if (fileLastUpdatedTime == updatedTime && updatedTime != -EIO)
84     {
85         if (passwdMapList.find(userName) == passwdMapList.end())
86         {
87             log<level::DEBUG>("User not found");
88             return 0;
89         }
90     }
91 
92     // Write passwdMap to Encryted file
93     if (updatePasswdSpecialFile(userName, newUserName) != 0)
94     {
95         log<level::DEBUG>("Passwd file update failed");
96         return -EIO;
97     }
98 
99     log<level::DEBUG>("Passwd file updated successfully");
100     return 0;
101 }
102 
103 void PasswdMgr::checkAndReload(void)
104 {
105     std::time_t updatedTime = getUpdatedFileTime();
106     if (fileLastUpdatedTime != updatedTime && updatedTime != -1)
107     {
108         log<level::DEBUG>("Reloading password map list");
109         passwdMapList.clear();
110         initPasswordMap();
111     }
112 }
113 
114 int PasswdMgr::encryptDecryptData(bool doEncrypt, const EVP_CIPHER* cipher,
115                                   uint8_t* key, size_t keyLen, uint8_t* iv,
116                                   size_t ivLen, uint8_t* inBytes,
117                                   size_t inBytesLen, uint8_t* mac,
118                                   size_t* macLen, unsigned char* outBytes,
119                                   size_t* outBytesLen)
120 {
121     if (cipher == NULL || key == NULL || iv == NULL || inBytes == NULL ||
122         outBytes == NULL || mac == NULL || inBytesLen == 0 ||
123         (size_t)EVP_CIPHER_key_length(cipher) > keyLen ||
124         (size_t)EVP_CIPHER_iv_length(cipher) > ivLen)
125     {
126         log<level::DEBUG>("Error Invalid Inputs");
127         return -EINVAL;
128     }
129 
130     if (!doEncrypt)
131     {
132         // verify MAC before decrypting the data.
133         std::array<uint8_t, EVP_MAX_MD_SIZE> calMac;
134         size_t calMacLen = calMac.size();
135         // calculate MAC for the encrypted message.
136         if (NULL == HMAC(EVP_sha256(), key, keyLen, inBytes, inBytesLen,
137                          calMac.data(),
138                          reinterpret_cast<unsigned int*>(&calMacLen)))
139         {
140             log<level::DEBUG>("Error: Failed to calculate MAC");
141             return -EIO;
142         }
143         if (!((calMacLen == *macLen) &&
144               (std::memcmp(calMac.data(), mac, calMacLen) == 0)))
145         {
146             log<level::DEBUG>("Authenticated message doesn't match");
147             return -EBADMSG;
148         }
149     }
150 
151     std::unique_ptr<EVP_CIPHER_CTX, decltype(&::EVP_CIPHER_CTX_free)> ctx(
152         EVP_CIPHER_CTX_new(), ::EVP_CIPHER_CTX_free);
153     EVP_CIPHER_CTX_set_padding(ctx.get(), 1);
154 
155     // Set key & IV
156     int retval = EVP_CipherInit_ex(ctx.get(), cipher, NULL, key, iv,
157                                    static_cast<int>(doEncrypt));
158     if (!retval)
159     {
160         log<level::DEBUG>("EVP_CipherInit_ex failed",
161                           entry("RET_VAL=%d", retval));
162         return -EIO;
163     }
164 
165     int outLen = 0, outEVPLen = 0;
166     if ((retval = EVP_CipherUpdate(ctx.get(), outBytes + outLen, &outEVPLen,
167                                    inBytes, inBytesLen)))
168     {
169         outLen += outEVPLen;
170         if ((retval =
171                  EVP_CipherFinal(ctx.get(), outBytes + outLen, &outEVPLen)))
172         {
173             outLen += outEVPLen;
174             *outBytesLen = outLen;
175         }
176         else
177         {
178             log<level::DEBUG>("EVP_CipherFinal fails",
179                               entry("RET_VAL=%d", retval));
180             return -EIO;
181         }
182     }
183     else
184     {
185         log<level::DEBUG>("EVP_CipherUpdate fails",
186                           entry("RET_VAL=%d", retval));
187         return -EIO;
188     }
189 
190     if (doEncrypt)
191     {
192         // Create MAC for the encrypted message
193         if (NULL == HMAC(EVP_sha256(), key, keyLen, outBytes, *outBytesLen, mac,
194                          reinterpret_cast<unsigned int*>(macLen)))
195         {
196             log<level::DEBUG>("Failed to create authentication");
197             return -EIO;
198         }
199     }
200     return 0;
201 }
202 
203 void PasswdMgr::initPasswordMap(void)
204 {
205     phosphor::user::shadow::Lock lock();
206     std::vector<uint8_t> dataBuf;
207 
208     if (readPasswdFileData(dataBuf) != 0)
209     {
210         log<level::DEBUG>("Error in reading the encrypted pass file");
211         return;
212     }
213 
214     if (dataBuf.size() != 0)
215     {
216         // populate the user list with password
217         char* outPtr = reinterpret_cast<char*>(dataBuf.data());
218         char* nToken = NULL;
219         char* linePtr = strtok_r(outPtr, "\n", &nToken);
220         size_t userEPos = 0, lineSize = 0;
221         while (linePtr != NULL)
222         {
223             std::string lineStr(linePtr);
224             if ((userEPos = lineStr.find(":")) != std::string::npos)
225             {
226                 lineSize = lineStr.size();
227                 passwdMapList.emplace(
228                     lineStr.substr(0, userEPos),
229                     lineStr.substr(userEPos + 1, lineSize - (userEPos + 1)));
230             }
231             linePtr = strtok_r(NULL, "\n", &nToken);
232         }
233     }
234 
235     // Update the timestamp
236     fileLastUpdatedTime = getUpdatedFileTime();
237     return;
238 }
239 
240 int PasswdMgr::readPasswdFileData(std::vector<uint8_t>& outBytes)
241 {
242     std::array<uint8_t, maxKeySize> keyBuff;
243     std::ifstream keyFile(encryptKeyFileName, std::ios::in | std::ios::binary);
244     if (!keyFile.is_open())
245     {
246         log<level::DEBUG>("Error in opening encryption key file");
247         return -EIO;
248     }
249     keyFile.read(reinterpret_cast<char*>(keyBuff.data()), keyBuff.size());
250     if (keyFile.fail())
251     {
252         log<level::DEBUG>("Error in reading encryption key file");
253         return -EIO;
254     }
255 
256     std::ifstream passwdFile(passwdFileName, std::ios::in | std::ios::binary);
257     if (!passwdFile.is_open())
258     {
259         log<level::DEBUG>("Error in opening ipmi password file");
260         return -EIO;
261     }
262 
263     // calculate file size and read the data
264     passwdFile.seekg(0, std::ios::end);
265     ssize_t fileSize = passwdFile.tellg();
266     passwdFile.seekg(0, std::ios::beg);
267     std::vector<uint8_t> input(fileSize);
268     passwdFile.read(reinterpret_cast<char*>(input.data()), fileSize);
269     if (passwdFile.fail())
270     {
271         log<level::DEBUG>("Error in reading encryption key file");
272         return -EIO;
273     }
274 
275     // verify the signature first
276     MetaPassStruct* metaData = reinterpret_cast<MetaPassStruct*>(input.data());
277     if (std::strncmp(metaData->signature, META_PASSWD_SIG,
278                      sizeof(metaData->signature)))
279     {
280         log<level::DEBUG>("Error signature mismatch in password file");
281         return -EBADMSG;
282     }
283 
284     size_t inBytesLen = metaData->dataSize + metaData->padSize;
285     // If data is empty i.e no password map then return success
286     if (inBytesLen == 0)
287     {
288         log<level::DEBUG>("Empty password file");
289         return 0;
290     }
291 
292     // compute the key needed to decrypt
293     std::array<uint8_t, EVP_MAX_KEY_LENGTH> key;
294     auto keyLen = key.size();
295     if (NULL == HMAC(EVP_sha256(), keyBuff.data(), keyBuff.size(),
296                      input.data() + sizeof(*metaData), metaData->hashSize,
297                      key.data(), reinterpret_cast<unsigned int*>(&keyLen)))
298     {
299         log<level::DEBUG>("Failed to create MAC for authentication");
300         return -EIO;
301     }
302 
303     // decrypt the data
304     uint8_t* iv = input.data() + sizeof(*metaData) + metaData->hashSize;
305     size_t ivLen = metaData->ivSize;
306     uint8_t* inBytes = iv + ivLen;
307     uint8_t* mac = inBytes + inBytesLen;
308     size_t macLen = metaData->macSize;
309 
310     size_t outBytesLen = 0;
311     // Resize to actual data size
312     outBytes.resize(inBytesLen + EVP_MAX_BLOCK_LENGTH);
313     if (encryptDecryptData(false, EVP_aes_128_cbc(), key.data(), keyLen, iv,
314                            ivLen, inBytes, inBytesLen, mac, &macLen,
315                            outBytes.data(), &outBytesLen) != 0)
316     {
317         log<level::DEBUG>("Error in decryption");
318         return -EIO;
319     }
320     // Resize the vector to outBytesLen
321     outBytes.resize(outBytesLen);
322 
323     OPENSSL_cleanse(key.data(), keyLen);
324     OPENSSL_cleanse(iv, ivLen);
325 
326     return 0;
327 }
328 
329 int PasswdMgr::updatePasswdSpecialFile(const std::string& userName,
330                                        const std::string& newUserName)
331 {
332     phosphor::user::shadow::Lock lock();
333 
334     size_t bytesWritten = 0;
335     size_t inBytesLen = 0;
336     size_t isUsrFound = false;
337     const EVP_CIPHER* cipher = EVP_aes_128_cbc();
338     std::vector<uint8_t> dataBuf;
339 
340     // Read the encrypted file and get the file data
341     // Check user existance and return if not exist.
342     if (readPasswdFileData(dataBuf) != 0)
343     {
344         log<level::DEBUG>("Error in reading the encrypted pass file");
345         return -EIO;
346     }
347 
348     if (dataBuf.size() != 0)
349     {
350         inBytesLen =
351             dataBuf.size() + newUserName.size() + EVP_CIPHER_block_size(cipher);
352     }
353 
354     std::vector<uint8_t> inBytes(inBytesLen);
355     if (inBytesLen != 0)
356     {
357         char* outPtr = reinterpret_cast<char*>(dataBuf.data());
358         size_t userEPos = 0;
359         char* nToken = NULL;
360         char* linePtr = strtok_r(outPtr, "\n", &nToken);
361         while (linePtr != NULL)
362         {
363             std::string lineStr(linePtr);
364             if ((userEPos = lineStr.find(":")) != std::string::npos)
365             {
366                 if (userName.compare(lineStr.substr(0, userEPos)) == 0)
367                 {
368                     isUsrFound = true;
369                     if (!newUserName.empty())
370                     {
371                         bytesWritten += std::snprintf(
372                             reinterpret_cast<char*>(&inBytes[0]) + bytesWritten,
373                             (inBytesLen - bytesWritten), "%s%s\n",
374                             newUserName.c_str(),
375                             lineStr.substr(userEPos, lineStr.size()).data());
376                     }
377                 }
378                 else
379                 {
380                     bytesWritten += std::snprintf(
381                         reinterpret_cast<char*>(&inBytes[0]) + bytesWritten,
382                         (inBytesLen - bytesWritten), "%s\n", lineStr.data());
383                 }
384             }
385             linePtr = strtok_r(NULL, "\n", &nToken);
386         }
387         inBytesLen = bytesWritten;
388     }
389     if (!isUsrFound)
390     {
391         log<level::DEBUG>("User doesn't exist");
392         return 0;
393     }
394 
395     // Read the key buff from key file
396     std::array<uint8_t, maxKeySize> keyBuff;
397     std::ifstream keyFile(encryptKeyFileName, std::ios::in | std::ios::binary);
398     if (!keyFile.good())
399     {
400         log<level::DEBUG>("Error in opening encryption key file");
401         return -EIO;
402     }
403     keyFile.read(reinterpret_cast<char*>(keyBuff.data()), keyBuff.size());
404     if (keyFile.fail())
405     {
406         log<level::DEBUG>("Error in reading encryption key file");
407         return -EIO;
408     }
409     keyFile.close();
410 
411     // Read the original passwd file mode
412     struct stat st = {};
413     if (stat(passwdFileName, &st) != 0)
414     {
415         log<level::DEBUG>("Error in getting password file fstat()");
416         return -EIO;
417     }
418 
419     // Create temporary file for write
420     std::string pwdFile(passwdFileName);
421     std::vector<char> tempFileName(pwdFile.begin(), pwdFile.end());
422     std::vector<char> fileTemplate = {'_', '_', 'X', 'X', 'X',
423                                       'X', 'X', 'X', '\0'};
424     tempFileName.insert(tempFileName.end(), fileTemplate.begin(),
425                         fileTemplate.end());
426     int fd = mkstemp((char*)tempFileName.data());
427     if (fd == -1)
428     {
429         log<level::DEBUG>("Error creating temp file");
430         return -EIO;
431     }
432 
433     std::string strTempFileName(tempFileName.data());
434     // Open the temp file for writing from provided fd
435     // By "true", remove it at exit if still there.
436     // This is needed to cleanup the temp file at exception
437     phosphor::user::File temp(fd, strTempFileName, "w", true);
438     if ((temp)() == NULL)
439     {
440         close(fd);
441         log<level::DEBUG>("Error creating temp file");
442         return -EIO;
443     }
444     fd = -1; // don't use fd anymore, as the File object owns it
445 
446     // Set the file mode as of actual ipmi-pass file.
447     if (fchmod(fileno((temp)()), st.st_mode) < 0)
448     {
449         log<level::DEBUG>("Error setting fchmod for temp file");
450         return -EIO;
451     }
452 
453     const EVP_MD* digest = EVP_sha256();
454     size_t hashLen = EVP_MD_block_size(digest);
455     std::vector<uint8_t> hash(hashLen);
456     size_t ivLen = EVP_CIPHER_iv_length(cipher);
457     std::vector<uint8_t> iv(ivLen);
458     std::array<uint8_t, EVP_MAX_KEY_LENGTH> key;
459     size_t keyLen = key.size();
460     std::array<uint8_t, EVP_MAX_MD_SIZE> mac;
461     size_t macLen = mac.size();
462 
463     // Create random hash and generate hash key which will be used for
464     // encryption.
465     if (RAND_bytes(hash.data(), hashLen) != 1)
466     {
467         log<level::DEBUG>("Hash genertion failed, bailing out");
468         return -EIO;
469     }
470     if (NULL == HMAC(digest, keyBuff.data(), keyBuff.size(), hash.data(),
471                      hashLen, key.data(),
472                      reinterpret_cast<unsigned int*>(&keyLen)))
473     {
474         log<level::DEBUG>("Failed to create MAC for authentication");
475         return -EIO;
476     }
477 
478     // Generate IV values
479     if (RAND_bytes(iv.data(), ivLen) != 1)
480     {
481         log<level::DEBUG>("UV genertion failed, bailing out");
482         return -EIO;
483     }
484 
485     // Encrypt the input data
486     std::vector<uint8_t> outBytes(inBytesLen + EVP_MAX_BLOCK_LENGTH);
487     size_t outBytesLen = 0;
488     if (inBytesLen != 0)
489     {
490         if (encryptDecryptData(true, EVP_aes_128_cbc(), key.data(), keyLen,
491                                iv.data(), ivLen, inBytes.data(), inBytesLen,
492                                mac.data(), &macLen, outBytes.data(),
493                                &outBytesLen) != 0)
494         {
495             log<level::DEBUG>("Error while encrypting the data");
496             return -EIO;
497         }
498         outBytes[outBytesLen] = 0;
499     }
500     OPENSSL_cleanse(key.data(), keyLen);
501 
502     // Update the meta password structure.
503     MetaPassStruct metaData = {META_PASSWD_SIG, {0, 0}, 0, 0, 0, 0, 0};
504     metaData.hashSize = hashLen;
505     metaData.ivSize = ivLen;
506     metaData.dataSize = bytesWritten;
507     metaData.padSize = outBytesLen - bytesWritten;
508     metaData.macSize = macLen;
509 
510     if (fwrite(&metaData, 1, sizeof(metaData), (temp)()) != sizeof(metaData))
511     {
512         log<level::DEBUG>("Error in writing meta data");
513         return -EIO;
514     }
515 
516     if (fwrite(&hash[0], 1, hashLen, (temp)()) != hashLen)
517     {
518         log<level::DEBUG>("Error in writing hash data");
519         return -EIO;
520     }
521 
522     if (fwrite(&iv[0], 1, ivLen, (temp)()) != ivLen)
523     {
524         log<level::DEBUG>("Error in writing IV data");
525         return -EIO;
526     }
527 
528     if (fwrite(&outBytes[0], 1, outBytesLen, (temp)()) != outBytesLen)
529     {
530         log<level::DEBUG>("Error in writing encrypted data");
531         return -EIO;
532     }
533 
534     if (fwrite(&mac[0], 1, macLen, (temp)()) != macLen)
535     {
536         log<level::DEBUG>("Error in writing MAC data");
537         return -EIO;
538     }
539 
540     if (fflush((temp)()))
541     {
542         log<level::DEBUG>(
543             "File fflush error while writing entries to special file");
544         return -EIO;
545     }
546 
547     OPENSSL_cleanse(iv.data(), ivLen);
548 
549     // Rename the tmp  file to actual file
550     if (std::rename(strTempFileName.data(), passwdFileName) != 0)
551     {
552         log<level::DEBUG>("Failed to rename tmp file to ipmi-pass");
553         return -EIO;
554     }
555 
556     return 0;
557 }
558 
559 std::time_t PasswdMgr::getUpdatedFileTime()
560 {
561     struct stat fileStat = {};
562     if (stat(passwdFileName, &fileStat) != 0)
563     {
564         log<level::DEBUG>("Error - Getting passwd file time stamp");
565         return -EIO;
566     }
567     return fileStat.st_mtime;
568 }
569 
570 } // namespace ipmi
571