text: /* Editor Settings: expandtabs and use 4 spaces for indentation
   * ex: set softtabstop=4 tabstop=8 expandtab shiftwidth=4: *
   * -*- mode: c, c-basic-offset: 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:
   *
   *        status.c
   *
   * Abstract:
   *
   *        BeyondTrust Security and Authentication Subsystem (LSASS)
   * 
   *        Status (Server)
   *
   * Authors: Krishna Ganugapati (krishnag@likewisesoftware.com)
   *          Sriram Nambakam (snambakam@likewisesoftware.com)
   */
  
  #include "api.h"
  
  DWORD
  LsaSrvGetStatus(
      HANDLE hServer,
      PCSTR pszTargetProvider,
      PLSASTATUS* ppLsaStatus
      )
  {
      DWORD dwError = 0;
      BOOLEAN bInLock = FALSE;
      PLSA_AUTH_PROVIDER pProvider = NULL;
      DWORD dwProviderCount = 0;
      DWORD iCount = 0;
      DWORD dwStatusIndex = 0;
      HANDLE hProvider = (HANDLE)NULL;
      PLSASTATUS pLsaStatus = NULL;
      PLSA_AUTH_PROVIDER_STATUS pProviderOwnedStatus = NULL;
      BOOLEAN bFoundProvider = FALSE;
      PSTR pszTargetProviderName = NULL;
      PSTR pszTargetInstance = NULL;
  
      BAIL_ON_INVALID_POINTER(ppLsaStatus);
  
      dwError = LwAllocateMemory(
                    sizeof(LSASTATUS),
                    (PVOID*)&pLsaStatus);
      BAIL_ON_LSA_ERROR(dwError);
  
      pLsaStatus->dwUptime = (DWORD)difftime(time(NULL), gServerStartTime);
      
      dwError = LsaSrvGetLsassVersion(
                      &pLsaStatus->lsassVersion);
      BAIL_ON_LSA_ERROR(dwError);
  
      dwError = LsaReadVersionFile(
                      &pLsaStatus->productVersion);
      BAIL_ON_LSA_ERROR(dwError);
  
      if (pszTargetProvider)
      {
          dwError = LsaSrvGetTargetElements(
                        pszTargetProvider,
                        &pszTargetProviderName,
                        &pszTargetInstance);
          BAIL_ON_LSA_ERROR(dwError);
      }
  
      ENTER_AUTH_PROVIDER_LIST_READER_LOCK(bInLock);
  
      if (pszTargetProviderName)
      {
          dwProviderCount = 1;
      }
      else
      {
          dwProviderCount = LsaGetNumberOfProviders_inlock();
      }
      
      if (!dwProviderCount)
      {
          goto done;
      }
      
      dwError = LwAllocateMemory(
                      dwProviderCount * sizeof(LSA_AUTH_PROVIDER_STATUS),
                      (PVOID*)&pLsaStatus->pAuthProviderStatusList);
      BAIL_ON_LSA_ERROR(dwError);
      
      pLsaStatus->dwCount = dwProviderCount;
          
      dwError = LW_ERROR_NOT_HANDLED;
      
      for (pProvider = gpAuthProviderList, iCount = 0, dwStatusIndex = 0;
           pProvider;
           pProvider = pProvider->pNext, iCount++)
      {
          PLSA_AUTH_PROVIDER_STATUS pAuthProviderStatus = NULL;
  
          if (pszTargetProviderName)
          {
              if (!strcmp(pszTargetProviderName, pProvider->pszName))
              {
                  bFoundProvider = TRUE;
              }
              else
              {
                  continue;
              }
          }
          
          dwError = LsaSrvOpenProvider(
                        hServer,
                        pProvider,
                        pszTargetInstance,
                        &hProvider);
          BAIL_ON_LSA_ERROR(dwError);
  
         pAuthProviderStatus = &pLsaStatus->pAuthProviderStatusList[dwStatusIndex++];
          
          dwError = LwAllocateString(
                          pProvider->pszName,
                          &pAuthProviderStatus->pszId);
          BAIL_ON_LSA_ERROR(dwError);
          
          dwError = pProvider->pFnTable->pfnGetStatus(
                                              hProvider,
                                              &pProviderOwnedStatus);
          if (dwError == LW_ERROR_NOT_HANDLED)
          {
              dwError = 0;
          }
          else
          {
              BAIL_ON_LSA_ERROR(dwError);
              
              dwError = LsaSrvCopyProviderStatus(
                              pProviderOwnedStatus,
                              pAuthProviderStatus);
              BAIL_ON_LSA_ERROR(dwError);
              
              pProvider->pFnTable->pfnFreeStatus(
                              pProviderOwnedStatus);
              
              pProviderOwnedStatus = NULL;
          }
  
          LsaSrvCloseProvider(pProvider, hProvider);
          hProvider = (HANDLE)NULL;
      }
  
      if (pszTargetProviderName && !bFoundProvider)
      {
          dwError = LW_ERROR_INVALID_AUTH_PROVIDER;
          BAIL_ON_LSA_ERROR(dwError);
      }
  
  done:
  
      *ppLsaStatus = pLsaStatus;
  
  cleanup:
  
      LW_SAFE_FREE_STRING(pszTargetProviderName);
      LW_SAFE_FREE_STRING(pszTargetInstance);
  
      if (pProvider != NULL && pProviderOwnedStatus)
      {
          pProvider->pFnTable->pfnFreeStatus(
                          pProviderOwnedStatus);
      }
          
      if (hProvider != NULL)
      {
          LsaSrvCloseProvider(pProvider, hProvider);
      }
      
      LEAVE_AUTH_PROVIDER_LIST_READER_LOCK(bInLock);
  
      return dwError;
  
  error:
      LSA_LOG_ERROR_API_FAILED(hServer, dwError, "get lsass status");
  
      if (ppLsaStatus)
      {
          *ppLsaStatus = NULL;
      }
      
      if (pLsaStatus)
      {
          LsaFreeStatus(pLsaStatus);
      }
  
     goto cleanup;
  }
  
  DWORD
  LsaSrvCopyProviderStatus(
      PLSA_AUTH_PROVIDER_STATUS pProviderOwnedStatus,
      PLSA_AUTH_PROVIDER_STATUS pTargetStatus
      )
  {
      DWORD dwError = 0;
      
      pTargetStatus->mode = pProviderOwnedStatus->mode;
      
      LW_SAFE_FREE_STRING(pTargetStatus->pszCell);
      
      if (!LW_IS_NULL_OR_EMPTY_STR(pProviderOwnedStatus->pszCell))
      {
          dwError = LwAllocateString(
                          pProviderOwnedStatus->pszCell,
                          &pTargetStatus->pszCell);
          BAIL_ON_LSA_ERROR(dwError);
      }
      
      LW_SAFE_FREE_STRING(pTargetStatus->pszDomain);
      
      if (!LW_IS_NULL_OR_EMPTY_STR(pProviderOwnedStatus->pszDomain))
      {
          dwError = LwAllocateString(
                          pProviderOwnedStatus->pszDomain,
                          &pTargetStatus->pszDomain);
          BAIL_ON_LSA_ERROR(dwError);
      }
  
      LW_SAFE_FREE_STRING(pTargetStatus->pszDomainSid);
      
      if (!LW_IS_NULL_OR_EMPTY_STR(pProviderOwnedStatus->pszDomainSid))
      {
          dwError = LwAllocateString(
                          pProviderOwnedStatus->pszDomainSid,
                          &pTargetStatus->pszDomainSid);
          BAIL_ON_LSA_ERROR(dwError);
      }
      
      LW_SAFE_FREE_STRING(pTargetStatus->pszForest);
      
      if (!LW_IS_NULL_OR_EMPTY_STR(pProviderOwnedStatus->pszForest))
      {
          dwError = LwAllocateString(
                          pProviderOwnedStatus->pszForest,
                          &pTargetStatus->pszForest);
          BAIL_ON_LSA_ERROR(dwError);
      }
      
      LW_SAFE_FREE_STRING(pTargetStatus->pszId);
      
      if (!LW_IS_NULL_OR_EMPTY_STR(pProviderOwnedStatus->pszId))
      {
          dwError = LwAllocateString(
                      pProviderOwnedStatus->pszId,
                      &pTargetStatus->pszId);
          BAIL_ON_LSA_ERROR(dwError);
      }
      
      LW_SAFE_FREE_STRING(pTargetStatus->pszSite);
      
      if (!LW_IS_NULL_OR_EMPTY_STR(pProviderOwnedStatus->pszSite))
      {
          dwError = LwAllocateString(
                      pProviderOwnedStatus->pszSite,
                      &pTargetStatus->pszSite);
          BAIL_ON_LSA_ERROR(dwError);
      }
      
      pTargetStatus->status = pProviderOwnedStatus->status;
      pTargetStatus->subMode = pProviderOwnedStatus->subMode;
      pTargetStatus->dwNetworkCheckInterval = pProviderOwnedStatus->dwNetworkCheckInterval;
      
      if (pProviderOwnedStatus->pTrustedDomainInfoArray)
      {
          dwError = LsaSrvCopyTrustedDomainInfoArray(
                          pProviderOwnedStatus->dwNumTrustedDomains,
                          pProviderOwnedStatus->pTrustedDomainInfoArray,
                          &pTargetStatus->pTrustedDomainInfoArray);
          BAIL_ON_LSA_ERROR(dwError);
          
          pTargetStatus->dwNumTrustedDomains = pProviderOwnedStatus->dwNumTrustedDomains;
      }
      
  cleanup:
  
      return dwError;
      
  error:
  
      goto cleanup;
  }
  
  DWORD
  LsaSrvCopyTrustedDomainInfoArray(
      DWORD                     dwNumDomains,
      PLSA_TRUSTED_DOMAIN_INFO  pSrcDomainInfoArray,
      PLSA_TRUSTED_DOMAIN_INFO* ppDomainInfoArray
      )
  {
      DWORD dwError = 0;
      PLSA_TRUSTED_DOMAIN_INFO pDomainInfoArray = NULL;
      DWORD iDomain = 0;
      
      dwError = LwAllocateMemory(
                      dwNumDomains * sizeof(LSA_TRUSTED_DOMAIN_INFO),
                      (PVOID*)&pDomainInfoArray);
      BAIL_ON_LSA_ERROR(dwError);
      
      for (; iDomain < dwNumDomains; iDomain++)
      {
          PLSA_TRUSTED_DOMAIN_INFO pSrcDomainInfo =
              &pSrcDomainInfoArray[iDomain];
          PLSA_TRUSTED_DOMAIN_INFO pDestDomainInfo =
              &pDomainInfoArray[iDomain];
          
          dwError = LwStrDupOrNull(
                          pSrcDomainInfo->pszDnsDomain,
                          &pDestDomainInfo->pszDnsDomain);
          BAIL_ON_LSA_ERROR(dwError);
          
          dwError = LwStrDupOrNull(
                          pSrcDomainInfo->pszNetbiosDomain,
                          &pDestDomainInfo->pszNetbiosDomain);
          BAIL_ON_LSA_ERROR(dwError);
          
          dwError = LwStrDupOrNull(
                          pSrcDomainInfo->pszDomainSID,
                          &pDestDomainInfo->pszDomainSID);
          BAIL_ON_LSA_ERROR(dwError);
          
          dwError = LwStrDupOrNull(
                          pSrcDomainInfo->pszDomainGUID,
                          &pDestDomainInfo->pszDomainGUID);
          BAIL_ON_LSA_ERROR(dwError);
          
          dwError = LwStrDupOrNull(
                          pSrcDomainInfo->pszTrusteeDnsDomain,
                          &pDestDomainInfo->pszTrusteeDnsDomain);
          BAIL_ON_LSA_ERROR(dwError);
          
          pDestDomainInfo->dwTrustFlags = pSrcDomainInfo->dwTrustFlags;
          pDestDomainInfo->dwTrustType = pSrcDomainInfo->dwTrustType;
          pDestDomainInfo->dwTrustAttributes = pSrcDomainInfo->dwTrustAttributes;
          pDestDomainInfo->dwTrustDirection = pSrcDomainInfo->dwTrustDirection;
          pDestDomainInfo->dwTrustMode = pSrcDomainInfo->dwTrustMode;
          
          dwError = LwStrDupOrNull(
                          pSrcDomainInfo->pszForestName,
                          &pDestDomainInfo->pszForestName);
          BAIL_ON_LSA_ERROR(dwError);
          
          dwError = LwStrDupOrNull(
                          pSrcDomainInfo->pszClientSiteName,
                          &pDestDomainInfo->pszClientSiteName);
          BAIL_ON_LSA_ERROR(dwError);
          
          pDestDomainInfo->dwDomainFlags = pSrcDomainInfo->dwDomainFlags;
          
          if (pSrcDomainInfo->pDCInfo)
          {
              dwError = LsaSrvCopyDCInfo(
                              pSrcDomainInfo->pDCInfo,
                              &pDestDomainInfo->pDCInfo);
              BAIL_ON_LSA_ERROR(dwError);
          }
          
          if (pSrcDomainInfo->pGCInfo)
          {
              dwError = LsaSrvCopyDCInfo(
                              pSrcDomainInfo->pGCInfo,
                              &pDestDomainInfo->pGCInfo);
              BAIL_ON_LSA_ERROR(dwError);
          }
      }
      
      *ppDomainInfoArray = pDomainInfoArray;
      
  cleanup:
  
      return dwError;
      
  error:
  
      *ppDomainInfoArray = NULL;
      
      if (pDomainInfoArray)
      {
          LsaFreeDomainInfoArray(dwNumDomains, pDomainInfoArray);
      }
  
      goto cleanup;
  }
  
  DWORD
  LsaSrvCopyDCInfo(
      PLSA_DC_INFO  pSrcInfo,
      PLSA_DC_INFO* ppDCInfo
      )
  {
      DWORD dwError = 0;
      PLSA_DC_INFO pDCInfo = NULL;
      
      dwError = LwAllocateMemory(
                      sizeof(LSA_DC_INFO),
                      (PVOID*)&pDCInfo);
      BAIL_ON_LSA_ERROR(dwError);
      
      dwError = LwStrDupOrNull(
                      pSrcInfo->pszName,
                      &pDCInfo->pszName);
      BAIL_ON_LSA_ERROR(dwError);
      
      dwError = LwStrDupOrNull(
                      pSrcInfo->pszAddress,
                      &pDCInfo->pszAddress);
      BAIL_ON_LSA_ERROR(dwError);
      
      dwError = LwStrDupOrNull(
                      pSrcInfo->pszSiteName,
                      &pDCInfo->pszSiteName);
      BAIL_ON_LSA_ERROR(dwError);
      
      pDCInfo->dwFlags = pSrcInfo->dwFlags;
      
      *ppDCInfo = pDCInfo;
      
  cleanup:
  
      return dwError;
      
  error:
  
      *ppDCInfo = NULL;
      
      if (pDCInfo)
      {
          LsaFreeDCInfo(pDCInfo);
      }
      goto cleanup;
  }
  
  DWORD
  LsaSrvGetLsassVersion(
      PLSA_VERSION pVersion
      )
  {  
      DWORD dwError = 0;
      PSTR pszVersion = NULL;
      DWORD iVerComp = 0;
      PSTR  pszToken = NULL;
      PSTR  pszTokenState = NULL;
      DWORD dwMajor = 0;
      DWORD dwMinor = 0;
      DWORD dwBuild = 0;
      DWORD dwRevision = 0;
      
      if (LW_IS_NULL_OR_EMPTY_STR(COMPONENT_VERSION))
      {
          dwError = LW_ERROR_INVALID_AGENT_VERSION;
          BAIL_ON_LSA_ERROR(dwError);
      }
      
      dwError = LwAllocateString(
                      COMPONENT_VERSION,
                      &pszVersion);
      BAIL_ON_LSA_ERROR(dwError);
      
      pszToken = strtok_r(pszVersion, ".",  &pszTokenState);
      
      while (!LW_IS_NULL_OR_EMPTY_STR(pszVersion) && (iVerComp < 4))
      {
          int i = 0;
          
          for (; i < strlen(pszVersion); i++)
          {
              if (!isdigit((int)pszVersion[i]))
              {
                  dwError = LW_ERROR_INVALID_AGENT_VERSION;
                  BAIL_ON_LSA_ERROR(dwError);
              }
          }
          
          switch (iVerComp++)
          {
              case 0:
                  
                  dwMajor = atoi(pszToken);
                  break;
                  
              case 1:
                  
                  dwMinor = atoi(pszToken);
                  break;
                  
              case 2:
                  
                  dwBuild = atoi(pszToken);
                  break;
  
              case 3:
                  
                  errno = 0;
                  dwRevision = strtoul(pszToken, NULL, 10);
                  dwError = LwMapErrnoToLwError(errno);
                  if (dwError != 0)
                  {
                      LSA_LOG_DEBUG("Unable to parse revision due to error %u", dwError);
                      dwRevision = 0;
                      dwError = 0;
                  }
                  break;
                  
              default:
                  
                  dwError = LW_ERROR_INTERNAL;
                  BAIL_ON_LSA_ERROR(dwError);
          }
          
          pszToken = strtok_r(NULL, ".", &pszTokenState);
      }
      
      if (iVerComp < 4)
      {
          dwError = LW_ERROR_INVALID_AGENT_VERSION;
          BAIL_ON_LSA_ERROR(dwError);
      }
      
      pVersion->dwMajor = dwMajor;
      pVersion->dwMinor = dwMinor;
      pVersion->dwBuild = dwBuild;
      pVersion->dwRevision = dwRevision;
      
  cleanup:
  
      LW_SAFE_FREE_MEMORY(pszVersion);
  
      return dwError;
      
  error:
  
      memset(pVersion, 0, sizeof(*pVersion));
      
      goto cleanup;
  }
  