text: /* Editor Settings: expandtabs and use 4 spaces for indentation
   * ex: set softtabstop=4 tabstop=8 expandtab shiftwidth=4: *
   */
  
  /*
   * Copyright © BeyondTrust Software 2004 - 2019
   * All rights reserved.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *        http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   *
   * BEYONDTRUST MAKES THIS SOFTWARE AVAILABLE UNDER OTHER LICENSING TERMS AS
   * WELL. IF YOU HAVE ENTERED INTO A SEPARATE LICENSE AGREEMENT WITH
   * BEYONDTRUST, THEN YOU MAY ELECT TO USE THE SOFTWARE UNDER THE TERMS OF THAT
   * SOFTWARE LICENSE AGREEMENT INSTEAD OF THE TERMS OF THE APACHE LICENSE,
   * NOTWITHSTANDING THE ABOVE NOTICE.  IF YOU HAVE QUESTIONS, OR WISH TO REQUEST
   * A COPY OF THE ALTERNATE LICENSING TERMS OFFERED BY BEYONDTRUST, PLEASE CONTACT
   * BEYONDTRUST AT beyondtrust.com/contact
   */
  
  /*
   * Copyright (C) BeyondTrust Software. All rights reserved.
   *
   * Module Name:
   *
   *        pam-passwd.c
   *
   * Abstract:
   *
   *        BeyondTrust Security and Authentication Subsystem (LSASS)
   *
   *        Pluggable Authentication Module
   *
   *        Password API
   *
   * Authors: Krishna Ganugapati (krishnag@likewisesoftware.com)
   *          Sriram Nambakam (snambakam@likewisesoftware.com)
   */
  #include "pam-lsass.h"
  
  #ifndef PAM_BAD_ITEM
  #define PAM_BAD_ITEM PAM_SERVICE_ERR
  #endif
  
  int
  pam_sm_chauthtok(
      pam_handle_t* pamh,
      int           flags,
      int           argc,
      const char**  argv
      )
  {
      DWORD dwError = 0;
      PSTR pszPassword = NULL;
      PPAMCONTEXT pPamContext = NULL;
      PLSA_PAM_CONFIG pConfig = NULL;
      PSTR pszLoginId = NULL;
      int iPamError = 0;
  
      LSA_LOG_PAM_DEBUG("pam_sm_chauthtok::begin");
  
      dwError = LsaPamGetContext(
                      pamh,
                      flags,
                      argc,
                      argv,
                      &pPamContext);
      BAIL_ON_LSA_ERROR(dwError);
  
      dwError = LsaPamGetLoginId(
              pamh,
              pPamContext,
              &pszLoginId,
              TRUE);
      BAIL_ON_LSA_ERROR(dwError);
  
      if (LsaShouldIgnoreUser(pszLoginId))
      {
          dwError = LW_ERROR_IGNORE_THIS_USER;
          BAIL_ON_LSA_ERROR(dwError);
      }
  
      dwError = LsaPamGetConfig(&pConfig);
      BAIL_ON_LSA_ERROR(dwError);
  
      LsaPamSetLogLevel(pConfig->dwLogLevel);
  
      if (!(flags & PAM_UPDATE_AUTHTOK) &&
          !(flags & PAM_PRELIM_CHECK))
      {
          dwError = LsaPamUnmapErrorCode(PAM_AUTHTOK_ERR);
          BAIL_ON_LSA_ERROR(dwError);
      }
  
      dwError = LsaPamGetContext(
                      pamh,
                      flags,
                      argc,
                      argv,
                      &pPamContext);
      BAIL_ON_LSA_ERROR(dwError);
  
      if (flags & PAM_PRELIM_CHECK)
      {
          dwError = LsaPamCheckCurrentPassword(
                              pamh,
                              pPamContext);
          if ( dwError == LW_ERROR_PASSWORD_EXPIRED )
          {
              /*
               * We must return success, so that PAM will
               * prompt us for the next stage where the password
               * is actually changed
               */
              dwError = 0;
          }
      }
      else if (flags & PAM_UPDATE_AUTHTOK)
      {
  
          pPamContext->pamOptions.bUseFirstPass = TRUE;
  
          dwError = LsaPamUpdatePassword(
                          pamh,
                          pPamContext);
      }
      BAIL_ON_LSA_ERROR(dwError);
  
  cleanup:
  
      LW_SECURE_FREE_STRING(pszPassword);
      LW_SAFE_FREE_STRING(pszLoginId);
  
      if (pConfig)
      {
          LsaPamFreeConfig(pConfig);
      }
  
      LSA_LOG_PAM_DEBUG("pam_sm_chauthtok::end");
  
  #ifdef __LWI_AIX__
       /* If PAM_SUCCESS is returned on AIX 5.3 TL4, AIX will not call back
          with PAM_UPDATE_AUTHTOK; AIX will think the password change has
          finished and was successful. It seems like any error code other
          than PAM_SUCCESS will convince AIX to call back.
  
          On AIX 5.3 TL6, PAM_SUCCESS can be returned, however most other
          error codes (including PAM_NEW_AUTHTOK_REQD) will cause AIX to
          think an unrecoverable error occurred.
  
          PAM_IGNORE is the magic error code that works on both AIX 5.3
          TL4 and AIX 5.3 TL6.
        */
      if ( !dwError && (flags & PAM_PRELIM_CHECK) )
      {
          iPamError = PAM_IGNORE;
      }
      else
      {
          iPamError = LsaPamOpenPamFilterChauthtok(
                                      LsaPamMapErrorCode(dwError, pPamContext));
      }
  #else
      iPamError = LsaPamOpenPamFilterChauthtok(
                                  LsaPamMapErrorCode(dwError, pPamContext));
  #endif
  
      LSA_LOG_PAM_DEBUG("pam_sm_chauthtok::returning pam error code %d", iPamError);
      return iPamError;
  
  error:
  
      if (dwError ==  LW_ERROR_NO_SUCH_USER)
      {
          LSA_LOG_PAM_DEBUG("pam_sm_chauthtok failed since the user could not be found [error code: %u]", dwError);
      }
      else if (dwError == LW_ERROR_IGNORE_THIS_USER)
      {
          LSA_LOG_PAM_WARNING("pam_sm_chauthtok bypassing lsass for ignore user %s", pszLoginId);
      }
      else
      {
          LSA_LOG_PAM_ERROR("pam_sm_chauthtok failed [error code: %u]", dwError);
      }
  
      goto cleanup;
  }
  
  DWORD
  LsaPamCheckCurrentPassword(
      pam_handle_t* pamh,
      PPAMCONTEXT pPamContext
      )
  {
      DWORD   dwError = 0;
      HANDLE  hLsaConnection = (HANDLE)NULL;
      BOOLEAN bCheckOldPassword = TRUE;
      PSTR    pszOldPassword = NULL;
      PSTR    pszLoginId = NULL;
      PSTR pszMessage = NULL;
  
      LSA_LOG_PAM_DEBUG("LsaPamCheckCurrentPassword::begin");
  
      dwError = LsaPamGetLoginId(
                      pamh,
                      pPamContext,
                      &pszLoginId,
                      TRUE);
      BAIL_ON_LSA_ERROR(dwError);
  
      dwError = LsaOpenServer(&hLsaConnection);
      BAIL_ON_LSA_ERROR(dwError);
  
      dwError = LsaPamMustCheckCurrentPassword(
                       hLsaConnection,
                       pszLoginId,
                       &bCheckOldPassword);
      BAIL_ON_LSA_ERROR(dwError);
  
      if (bCheckOldPassword)
      {
          dwError = LsaPamGetOldPassword(
                            pamh,
                            pPamContext,
                            &pszOldPassword);
          BAIL_ON_LSA_ERROR(dwError);
  
          dwError = LsaAuthenticateUser(
                            hLsaConnection,
                            pszLoginId,
                            pszOldPassword,
                            &pszMessage);
          if (pszMessage)
          {
              LsaPamConverse(pamh,
                             pszMessage,
                             PAM_TEXT_INFO,
                             NULL);
          }
          BAIL_ON_LSA_ERROR(dwError);
       }
  
  cleanup:
  
      if (hLsaConnection != (HANDLE)NULL)
      {
          LsaCloseServer(hLsaConnection);
      }
  
      LW_SAFE_FREE_STRING(pszLoginId);
      LW_SECURE_FREE_STRING(pszOldPassword);
      LW_SAFE_FREE_STRING(pszMessage);
  
      LSA_LOG_PAM_DEBUG("LsaPamCheckCurrentPassword::end");
  
      return dwError;
  
  error:
  
      LSA_LOG_PAM_ERROR("LsaPamCheckCurrentPassword failed [login:%s][error code: %u]",
                        LSA_SAFE_LOG_STRING(pszLoginId),
                        dwError);
  
      goto cleanup;
  }
  
  DWORD
  LsaPamMustCheckCurrentPassword(
      HANDLE   hLsaConnection,
      PCSTR    pszLoginId,
      PBOOLEAN pbCheckOldPassword)
  {
      DWORD dwError = 0;
      PVOID pUserInfo = NULL;
      DWORD dwUserInfoLevel = 1;
      BOOLEAN bCheckOldPassword = FALSE;
  
      LSA_LOG_PAM_DEBUG("LsaPamMustCheckCurrentPassword::begin");
  
      dwError = LsaFindUserByName(
                       hLsaConnection,
                       pszLoginId,
                       dwUserInfoLevel,
                       &pUserInfo);
      BAIL_ON_LSA_ERROR(dwError);
  
      if (((PLSA_USER_INFO_1)pUserInfo)->bIsLocalUser)
      {
          // Local root user does not have to
          // provide a user's old password.
          bCheckOldPassword = (getuid() != 0);
      }
      else
      {
          // TODO: Handle domain admins
          // For now, prompt for old password of AD Users
          bCheckOldPassword = TRUE;
      }
  
      *pbCheckOldPassword = bCheckOldPassword;
  
  cleanup:
  
      if (pUserInfo) {
          LsaFreeUserInfo(dwUserInfoLevel, pUserInfo);
      }
  
      LSA_LOG_PAM_DEBUG("LsaPamMustCheckCurrentPassword::end");
  
      return dwError;
  
  error:
  
      *pbCheckOldPassword = TRUE;
  
      if (dwError == LW_ERROR_NO_SUCH_USER)
      {
          LSA_LOG_PAM_DEBUG("LsaPamMustCheckCurrentPassword failed since the user could not be found [login:%s][error code: %u]",
                            LSA_SAFE_LOG_STRING(pszLoginId),
                            dwError);
      }
      else
      {
          LSA_LOG_PAM_ERROR("LsaPamMustCheckCurrentPassword failed [login:%s][error code: %u]",
                            LSA_SAFE_LOG_STRING(pszLoginId),
                            dwError);
      }
  
      goto cleanup;
  }
  
  DWORD
  LsaPamUpdatePassword(
      pam_handle_t* pamh,
      PPAMCONTEXT   pPamContext
      )
  {
      DWORD  dwError = 0;
      PSTR   pszOldPassword = NULL;
      PSTR   pszPassword = NULL;
      PSTR   pszLoginId = NULL;
      PCSTR  pszConstLoginId = NULL;
      HANDLE hLsaConnection = (HANDLE)NULL;
      LSA_QUERY_LIST query = { NULL };
      PLSA_SECURITY_OBJECT* ppUser = NULL;
  
      LSA_LOG_PAM_DEBUG("LsaPamUpdatePassword::begin");
  
      if (pPamContext->bPasswordChangeFailed)
      {
          LSA_LOG_PAM_DEBUG("Password change already failed");
          dwError = LW_ERROR_USER_CANNOT_CHANGE_PASSWD;
          BAIL_ON_LSA_ERROR(dwError);
      }
      if (pPamContext->bPasswordChangeSuceeded)
      {
          LSA_LOG_PAM_DEBUG("Password change already succeeded");
          goto cleanup;
      }
  
      dwError = LsaPamGetLoginId(
                      pamh,
                      pPamContext,
                      &pszLoginId,
                      TRUE);
      BAIL_ON_LSA_ERROR(dwError);
  
      dwError = LsaOpenServer(&hLsaConnection);
      BAIL_ON_LSA_ERROR(dwError);
  
      // Verify the user is known to lsass
      pszConstLoginId = pszLoginId;
      query.ppszStrings = &pszConstLoginId;
      dwError = LsaFindObjects(
                      hLsaConnection,
                      NULL,
                      0,
                      LSA_OBJECT_TYPE_USER,
                      LSA_QUERY_TYPE_BY_NAME,
                      1,
                      query,
                      &ppUser);
      BAIL_ON_LSA_ERROR(dwError);
  
      if (!ppUser[0])
      {
          dwError = LW_ERROR_NO_SUCH_USER;
          BAIL_ON_LSA_ERROR(dwError);
      }
  
      dwError = LsaPamGetOldPassword(
                     pamh,
                     pPamContext,
                     &pszOldPassword);
      BAIL_ON_LSA_ERROR(dwError);
  
      dwError = LsaPamGetNewPassword(
                     pamh,
                     pPamContext,
                     &pszPassword);
      BAIL_ON_LSA_ERROR(dwError);
  
      dwError = LsaChangePassword(
                     hLsaConnection,
                     pszLoginId,
                     pszPassword,
                     pszOldPassword);
      BAIL_ON_LSA_ERROR(dwError);
  
  cleanup:
  
      LW_SECURE_FREE_STRING(pszPassword);
      LW_SECURE_FREE_STRING(pszOldPassword);
      LW_SAFE_FREE_STRING(pszLoginId);
      if (ppUser)
      {
          LsaFreeSecurityObjectList(
              1,
              ppUser);
      }
  
      if (hLsaConnection != (HANDLE)NULL)
      {
          LsaCloseServer(hLsaConnection);
      }
  
      if (pPamContext->pamOptions.bRememberChPass)
      {
          if (dwError == LW_ERROR_SUCCESS)
          {
              pPamContext->bPasswordChangeSuceeded = TRUE;
          }
          else
          {
              pPamContext->bPasswordChangeFailed = TRUE;
          }
      }
  
      LSA_LOG_PAM_DEBUG("LsaPamUpdatePassword::end");
  
      return dwError;
  
  error:
  
      if ( dwError == LW_ERROR_INVALID_PASSWORD && ppUser && ppUser[0])
      {
          if (getuid() == 0 && ppUser[0]->bIsLocal) {
              LsaPamConverse(
                  pamh,
                  "Ignoring root password change for BeyondTrust AD Bridge AD user. Please use '/opt/pbis/bin/adtool' to manage AD user account passwords.",
                  PAM_ERROR_MSG,
                  NULL);
  
              dwError = LW_ERROR_SUCCESS;
          }
      }
  
      if ( dwError == LW_ERROR_PASSWORD_RESTRICTION )
      {
          LsaPamConverse(
              pamh,
              "Password does not meet requirements",
              PAM_ERROR_MSG,
              NULL);
      }
  
      if (dwError == LW_ERROR_NO_SUCH_USER)
      {
          LSA_LOG_PAM_DEBUG("LsaPamUpdatePassword failed since the user could not be found [login:%s][error code: %u]",
                            LSA_SAFE_LOG_STRING(pszLoginId),
                            dwError);
      }
      else
      {
          LSA_LOG_PAM_ERROR("LsaPamUpdatePassword failed [login:%s][error code: %u]",
                            LSA_SAFE_LOG_STRING(pszLoginId),
                            dwError);
      }
  
      goto cleanup;
  }
  
  DWORD
  LsaPamGetCurrentPassword(
      pam_handle_t* pamh,
      PPAMCONTEXT   pPamContext,
      PCSTR pcszPasswordPrompt,
      PSTR*         ppszPassword
      )
  {
      DWORD dwError = 0;
      PSTR pszPassword = NULL;
      BOOLEAN bPrompt = TRUE;
      PPAMOPTIONS pPamOptions = &pPamContext->pamOptions;
      int iPamError = 0;
  
      LSA_LOG_PAM_DEBUG("LsaPamGetCurrentPassword::begin");
  
      if (pPamOptions->bTryFirstPass ||
          pPamOptions->bUseFirstPass) {
          PCSTR pszItem = NULL;
  
          iPamError = pam_get_item(
                          pamh,
                          PAM_AUTHTOK,
                          (PAM_GET_ITEM_TYPE)&pszItem);
          dwError = LsaPamUnmapErrorCode(iPamError);
          if (dwError)
          {
              if (dwError == LsaPamUnmapErrorCode(PAM_BAD_ITEM))
              {
                  if (pPamOptions->bUseFirstPass)
                  {
                      BAIL_ON_LSA_ERROR(dwError);
                  }
                  else
                  {
                      dwError = 0;
                  }
              }
              else
              {
                 BAIL_ON_LSA_ERROR(dwError);
              }
  
          }
          else if (!LW_IS_NULL_OR_EMPTY_STR(pszItem))
          {
              dwError = LwAllocateString(pszItem, &pszPassword);
              BAIL_ON_LSA_ERROR(dwError);
              bPrompt = FALSE;
          }
          else if (pPamOptions->bUseFirstPass)
          {
              dwError = LsaPamUnmapErrorCode(PAM_BAD_ITEM);
              BAIL_ON_LSA_ERROR(dwError);
          }
      }
  
      if (bPrompt) {
  
         dwError = LsaPamConverse(
                          pamh,
                          strcmp(pcszPasswordPrompt, "") == 0 ? "Password:" : pcszPasswordPrompt,
                          PAM_PROMPT_ECHO_OFF,
                          &pszPassword);
         BAIL_ON_LSA_ERROR(dwError);
  
         iPamError = pam_set_item(
                         pamh,
                         PAM_AUTHTOK,
                         (const void*) pszPassword);
         dwError = LsaPamUnmapErrorCode(iPamError);
         BAIL_ON_LSA_ERROR(dwError);
  
      }
  
      *ppszPassword = pszPassword;
  
  cleanup:
  
      LSA_LOG_PAM_DEBUG("LsaPamGetCurrentPassword::end");
  
      return dwError;
  
  error:
  
      LW_SECURE_FREE_STRING(pszPassword);
  
      *ppszPassword = NULL;
  
      LSA_LOG_PAM_ERROR("LsaPamGetCurrentPassword failed [error code: %u]", dwError);
  
      goto cleanup;
  }
  
  DWORD
  LsaPamGetOldPassword(
      pam_handle_t* pamh,
      PPAMCONTEXT pPamContext,
      PSTR* ppszPassword
      )
  {
      DWORD dwError = 0;
      PSTR pszPassword = NULL;
      BOOLEAN bPrompt = TRUE;
      PPAMOPTIONS pPamOptions = &pPamContext->pamOptions;
      int iPamError = 0;
  
      LSA_LOG_PAM_DEBUG("LsaPamGetOldPassword::begin");
  
      if (pPamOptions->bTryFirstPass ||
          pPamOptions->bUseFirstPass)
      {
          PCSTR pszItem = NULL;
  
  #if defined(__LWI_SOLARIS__) || defined(__LWI_HP_UX__)
          /* Solaris doesn't use PAM_OLDAUTHTOK, but we previously saved
             the password as PAM_LSASS_OLDAUTHTOK during pam_sm_authenticate,
             so we'll grab it from there */
  
          /* HP-UX likes to clear PAM_OLDAUTHTOK between the two phases
             of chauthtok, so we also grab our saved version in this case */
          iPamError = pam_get_data(
              pamh,
              PAM_LSASS_OLDAUTHTOK,
              (PAM_GET_DATA_TYPE)&pszItem);
          dwError = LsaPamUnmapErrorCode(iPamError);
  #else
          iPamError = pam_get_item(
              pamh,
              PAM_OLDAUTHTOK,
              (PAM_GET_ITEM_TYPE)&pszItem);
          dwError = LsaPamUnmapErrorCode(iPamError);
  #endif
          if (dwError == LsaPamUnmapErrorCode(PAM_BAD_ITEM) ||
              pszItem == NULL)
          {
              if (pPamOptions->bUseFirstPass)
              {
                  bPrompt = FALSE;
                  dwError = LW_ERROR_INVALID_PASSWORD;
                  BAIL_ON_LSA_ERROR(dwError);
              }
              else if (pPamOptions->bTryFirstPass)
              {
                  dwError = 0;
              }
          }
          else if (dwError)
          {
             BAIL_ON_LSA_ERROR(dwError);
          }
          else
          {
              dwError = LwAllocateString(pszItem, &pszPassword);
              BAIL_ON_LSA_ERROR(dwError);
  
              bPrompt = FALSE;
          }
      }
  
      if (bPrompt) {
  
          LSA_LOG_PAM_DEBUG("LsaPamGetOldPassword::prompting for current password");
         dwError = LsaPamConverse(
                              pamh,
                              "Current password: ",
                              PAM_PROMPT_ECHO_OFF,
                              &pszPassword);
         BAIL_ON_LSA_ERROR(dwError);
  
         iPamError = pam_set_item(
                         pamh,
                         PAM_OLDAUTHTOK,
                         (const void*) pszPassword);
         dwError = LsaPamUnmapErrorCode(iPamError);
         BAIL_ON_LSA_ERROR(dwError);
  
  #if defined(__LWI_SOLARIS__) || defined(__LWI_HP_UX__)
         /* HP-UX clears PAM_OLDAUTHTOK between the two phases of chauthtok, so
            save a copy of the old password where we can find it later */
  
         /* For Solaris, we read PAM_LSASS_OLDAUTHTOK instead of
            PAM_OLDAUTHTOK. */
         dwError = LsaPamSetDataString(pamh, PAM_LSASS_OLDAUTHTOK, pszPassword);
         BAIL_ON_LSA_ERROR(dwError);
  #endif
      }
  
      *ppszPassword = pszPassword;
  
  cleanup:
  
      LSA_LOG_PAM_DEBUG("LsaPamGetOldPassword::end");
  
      return dwError;
  
  error:
  
      LW_SECURE_FREE_STRING(pszPassword);
  
      *ppszPassword = NULL;
  
      LSA_LOG_PAM_ERROR("LsaPamGetOldPassword failed [error code: %u]", dwError);
  
      goto cleanup;
  }
  
  DWORD
  LsaPamGetNewPassword(
      pam_handle_t* pamh,
      PPAMCONTEXT   pPamContext,
      PSTR*         ppszPassword
      )
  {
      DWORD dwError = 0;
      PSTR pszPassword_1 = NULL;
      PSTR pszPassword_2 = NULL;
      DWORD dwLen_1 = 0;
      DWORD dwLen_2 = 0;
      BOOLEAN bPrompt = TRUE;
      PPAMOPTIONS pPamOptions = &pPamContext->pamOptions;
      int iPamError = 0;
  
      LSA_LOG_PAM_DEBUG("LsaPamGetNewPassword::begin");
  
      if (pPamOptions->bUseAuthTok) {
  
          PCSTR pszItem = NULL;
  
          iPamError = pam_get_item(
                      pamh,
                      PAM_AUTHTOK,
                      (PAM_GET_ITEM_TYPE)&pszItem);
          dwError = LsaPamUnmapErrorCode(iPamError);
          BAIL_ON_LSA_ERROR(dwError);
  
          if (!LW_IS_NULL_OR_EMPTY_STR(pszItem)) {
              dwError = LwAllocateString(pszItem, &pszPassword_1);
              BAIL_ON_LSA_ERROR(dwError);
  
              bPrompt = FALSE;
          }
      }
  
      while (bPrompt)
      {
          LSA_LOG_PAM_DEBUG("LsaPamGetOldPassword::prompting for new password");
         dwError = LsaPamConverse(
                  pamh,
                  "New password: ",
                  PAM_PROMPT_ECHO_OFF,
                  &pszPassword_1);
         BAIL_ON_LSA_ERROR(dwError);
  
          LSA_LOG_PAM_DEBUG("LsaPamGetOldPassword::prompting for re-enter password");
         dwError = LsaPamConverse(
                  pamh,
                  "Re-enter password: ",
                  PAM_PROMPT_ECHO_OFF,
                  &pszPassword_2);
         BAIL_ON_LSA_ERROR(dwError);
  
         // Will never get NULL on success.
         // It could be an empty string though.
         dwLen_1 = strlen(pszPassword_1);
         dwLen_2 = strlen(pszPassword_2);
  
         if ((dwLen_1 != dwLen_2) ||
             (strcmp(pszPassword_1, pszPassword_2) != 0))
         {
             LsaPamConverse(pamh, "Passwords do not match", PAM_ERROR_MSG, NULL);
             dwError = 0;
  
             LW_SECURE_FREE_STRING(pszPassword_1);
             LW_SECURE_FREE_STRING(pszPassword_2);
  
         }
         else
         {
             iPamError = pam_set_item(
                         pamh,
                         PAM_AUTHTOK,
                         (const void*) pszPassword_1);
             dwError = LsaPamUnmapErrorCode(iPamError);
             BAIL_ON_LSA_ERROR(dwError);
  
             bPrompt = FALSE;
         }
      }
  
      *ppszPassword = pszPassword_1;
  
  cleanup:
  
      LW_SECURE_FREE_STRING(pszPassword_2);
  
      LSA_LOG_PAM_DEBUG("LsaPamGetNewPassword::end");
  
      return dwError;
  
  error:
  
      LW_SECURE_FREE_STRING(pszPassword_1);
  
      *ppszPassword = NULL;
  
      LSA_LOG_PAM_ERROR("LsaPamGetNewPassword failed [error code: %u]", dwError);
  
      goto cleanup;
  }
  
  
  /*
  local variables:
  mode: c
  c-basic-offset: 4
  indent-tabs-mode: nil
  tab-width: 4
  end:
  */
  