Fix password update

There is a regression issue found with this commit in password update
https://gerrit.openbmc.org/c/openbmc/bmcweb/+/73605
This commit fixes PAM conversation for password update

Tested by:
PATCH https://${bmc}/redfish/v1/AccountService/Accounts/root -d
'{"Password":"0penBmc1"}'

Change-Id: Ifcede67364c35ced899a3f726f67253cdb51002e
Signed-off-by: Ed Tanous <etanous@nvidia.com>
Signed-off-by: Ravi Teja <raviteja28031990@gmail.com>
diff --git a/include/pam_authenticate.hpp b/include/pam_authenticate.hpp
index 36d307e..fbb3f61 100644
--- a/include/pam_authenticate.hpp
+++ b/include/pam_authenticate.hpp
@@ -134,13 +134,77 @@
     return pam_end(localAuthHandle, PAM_SUCCESS);
 }
 
+inline int pamUpdatePasswordFunctionConversation(
+    int numMsg, const struct pam_message** msgs, struct pam_response** resp,
+    void* appdataPtr)
+{
+    if ((appdataPtr == nullptr) || (msgs == nullptr) || (resp == nullptr))
+    {
+        return PAM_CONV_ERR;
+    }
+
+    if (numMsg <= 0 || numMsg >= PAM_MAX_NUM_MSG)
+    {
+        return PAM_CONV_ERR;
+    }
+    auto msgCount = static_cast<size_t>(numMsg);
+
+    // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays)
+    auto responseArrPtr = std::make_unique<pam_response[]>(msgCount);
+    auto responses = std::span(responseArrPtr.get(), msgCount);
+    auto messagePtrs = std::span(msgs, msgCount);
+    for (size_t i = 0; i < msgCount; ++i)
+    {
+        const pam_message& msg = *(messagePtrs[i]);
+
+        pam_response& response = responses[i];
+        response.resp_retcode = 0;
+        response.resp = nullptr;
+
+        switch (msg.msg_style)
+        {
+            case PAM_PROMPT_ECHO_ON:
+                break;
+            case PAM_PROMPT_ECHO_OFF:
+            {
+                // Assume PAM is only prompting for the password as hidden input
+                // Allocate memory only when PAM_PROMPT_ECHO_OFF is encounterred
+                char* appPass = static_cast<char*>(appdataPtr);
+                size_t appPassSize = std::strlen(appPass);
+
+                if ((appPassSize + 1) > PAM_MAX_RESP_SIZE)
+                {
+                    return PAM_CONV_ERR;
+                }
+                // Create an array for pam to own
+                // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays)
+                auto passPtr = std::make_unique<char[]>(appPassSize + 1);
+                std::strncpy(passPtr.get(), appPass, appPassSize + 1);
+
+                responses[i].resp = passPtr.release();
+            }
+            break;
+            case PAM_ERROR_MSG:
+                BMCWEB_LOG_ERROR("Pam error {}", msg.msg);
+                break;
+            case PAM_TEXT_INFO:
+                BMCWEB_LOG_ERROR("Pam info {}", msg.msg);
+                break;
+            default:
+                return PAM_CONV_ERR;
+        }
+    }
+    *resp = responseArrPtr.release();
+    return PAM_SUCCESS;
+}
+
 inline int pamUpdatePassword(const std::string& username,
                              const std::string& password)
 {
     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
     char* passStrNoConst = const_cast<char*>(password.c_str());
-    const struct pam_conv localConversation = {pamFunctionConversation,
-                                               passStrNoConst};
+    const struct pam_conv localConversation = {
+        pamUpdatePasswordFunctionConversation, passStrNoConst};
     pam_handle_t* localAuthHandle = nullptr; // this gets set by pam_start
 
     int retval = pam_start("webserver", username.c_str(), &localConversation,