IPMI password entry cleanup

Whenever user is removed from the system, password map in IPMI
database has to be cleaned up. Similarly password entry must
be updated when user rename happens. This commit add's API
changes for the same

Change-Id: I304c721b31fc7fbad019c85d8ca2ecc60ca398d8
Signed-off-by: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com>
diff --git a/user_channel/passwd_mgr.cpp b/user_channel/passwd_mgr.cpp
index 15e6e34..c47bc6d 100644
--- a/user_channel/passwd_mgr.cpp
+++ b/user_channel/passwd_mgr.cpp
@@ -78,7 +78,8 @@
     return iter->second;
 }
 
-int PasswdMgr::clearUserEntry(const std::string& userName)
+int PasswdMgr::updateUserEntry(const std::string& userName,
+                               const std::string& newUserName)
 {
     std::time_t updatedTime = getUpdatedFileTime();
     // Check file time stamp to know passwdMapList is up-to-date.
@@ -94,7 +95,7 @@
     }
 
     // Write passwdMap to Encryted file
-    if (updatePasswdSpecialFile(userName) != 0)
+    if (updatePasswdSpecialFile(userName, newUserName) != 0)
     {
         log<level::DEBUG>("Passwd file update failed");
         return -EIO;
@@ -330,7 +331,8 @@
     return 0;
 }
 
-int PasswdMgr::updatePasswdSpecialFile(const std::string& userName)
+int PasswdMgr::updatePasswdSpecialFile(const std::string& userName,
+                                       const std::string& newUserName)
 {
     phosphor::user::shadow::Lock lock();
 
@@ -350,7 +352,8 @@
 
     if (dataBuf.size() != 0)
     {
-        inBytesLen = dataBuf.size() + EVP_CIPHER_block_size(cipher);
+        inBytesLen =
+            dataBuf.size() + newUserName.size() + EVP_CIPHER_block_size(cipher);
     }
 
     std::vector<uint8_t> inBytes(inBytesLen);
@@ -368,12 +371,20 @@
                 if (userName.compare(lineStr.substr(0, userEPos)) == 0)
                 {
                     isUsrFound = true;
+                    if (!newUserName.empty())
+                    {
+                        bytesWritten += std::snprintf(
+                            reinterpret_cast<char*>(&inBytes[0]) + bytesWritten,
+                            (inBytesLen - bytesWritten), "%s%s\n",
+                            newUserName.c_str(),
+                            lineStr.substr(userEPos, lineStr.size()).data());
+                    }
                 }
                 else
                 {
                     bytesWritten += std::snprintf(
                         reinterpret_cast<char*>(&inBytes[0]) + bytesWritten,
-                        inBytesLen, "%s\n", lineStr.data());
+                        (inBytesLen - bytesWritten), "%s\n", lineStr.data());
                 }
             }
             linePtr = strtok_r(NULL, "\n", &nToken);
diff --git a/user_channel/passwd_mgr.hpp b/user_channel/passwd_mgr.hpp
index e5625bc..a444522 100644
--- a/user_channel/passwd_mgr.hpp
+++ b/user_channel/passwd_mgr.hpp
@@ -46,13 +46,17 @@
      */
     std::string getPasswdByUserName(const std::string& userName);
 
-    /** @brief Clear username and password entry for the specified user
+    /** @brief Update / clear  username and password entry for the specified
+     * user
      *
-     *  @param[in] userName - username
+     *  @param[in] userName - user name that has to be renamed / deleted
+     *  @param[in] newUserName - new user name. If empty, userName will be
+     *   deleted.
      *
      * @return error response
      */
-    int clearUserEntry(const std::string& userName);
+    int updateUserEntry(const std::string& userName,
+                        const std::string& newUserName);
 
   private:
     using UserName = std::string;
@@ -81,11 +85,14 @@
     /** @brief  Updates special password file by clearing the password entry
      *  for the user specified.
      *
-     *  @param[in] userName - user name entry that has to be removed.
+     *  @param[in] userName - user name that has to be renamed / deleted
+     *  @param[in] newUserName - new user name. If empty, userName will be
+     *   deleted.
      *
      * @return error response
      */
-    int updatePasswdSpecialFile(const std::string& userName);
+    int updatePasswdSpecialFile(const std::string& userName,
+                                const std::string& newUserName);
     /** @brief encrypts or decrypt the data provided
      *
      *  @param[in] doEncrypt - do encrypt if set to true, else do decrypt.
diff --git a/user_channel/user_layer.cpp b/user_channel/user_layer.cpp
index ed99137..06cdd68 100644
--- a/user_channel/user_layer.cpp
+++ b/user_channel/user_layer.cpp
@@ -29,9 +29,22 @@
     return passwdMgr.getPasswdByUserName(userName);
 }
 
-ipmi_ret_t ipmiUserClearPassword(const std::string& userName)
+ipmi_ret_t ipmiClearUserEntryPassword(const std::string& userName)
 {
-    passwdMgr.clearUserEntry(userName);
+    if (passwdMgr.updateUserEntry(userName, "") != 0)
+    {
+        return IPMI_CC_UNSPECIFIED_ERROR;
+    }
+    return IPMI_CC_OK;
+}
+
+ipmi_ret_t ipmiRenameUserEntryPassword(const std::string& userName,
+                                       const std::string& newUserName)
+{
+    if (passwdMgr.updateUserEntry(userName, newUserName) != 0)
+    {
+        return IPMI_CC_UNSPECIFIED_ERROR;
+    }
     return IPMI_CC_OK;
 }
 
diff --git a/user_channel/user_layer.hpp b/user_channel/user_layer.hpp
index 4040102..a946e4c 100644
--- a/user_channel/user_layer.hpp
+++ b/user_channel/user_layer.hpp
@@ -35,7 +35,18 @@
  *
  *  @return 0 on success, non-zero otherwise.
  */
-ipmi_ret_t ipmiUserClearPassword(const std::string& userName);
+ipmi_ret_t ipmiClearUserEntryPassword(const std::string& userName);
+
+/** @brief The IPMI call to reuse password entry for the renamed user
+ *  to another one
+ *
+ *  @param[in] userName
+ *  @param[in] newUserName
+ *
+ *  @return 0 on success, non-zero otherwise.
+ */
+ipmi_ret_t ipmiRenameUserEntryPassword(const std::string& userName,
+                                       const std::string& newUserName);
 
 // TODO: Define required user layer API Call's which user layer shared library
 // must implement.