#include "precomp.h"

extern LPWSTR PolicyDNAttributes[];

DWORD
ValidateISAKMPData(
    PIPSEC_ISAKMP_DATA pIpsecISAKMPData
    )
{
    DWORD dwError = 0;


    if (!pIpsecISAKMPData) {
        dwError = ERROR_INVALID_PARAMETER;
        BAIL_ON_WIN32_ERROR(dwError);
    }

    if (!(pIpsecISAKMPData->pSecurityMethods) ||
        !(pIpsecISAKMPData->dwNumISAKMPSecurityMethods)) {
        dwError = ERROR_INVALID_PARAMETER;
        BAIL_ON_WIN32_ERROR(dwError);
    }

error:

    return (dwError);
}


DWORD
ValidateNegPolData(
    PIPSEC_NEGPOL_DATA pIpsecNegPolData
    )
{
    DWORD dwError = 0;


    if (!pIpsecNegPolData) {
        dwError = ERROR_INVALID_PARAMETER;
        BAIL_ON_WIN32_ERROR(dwError);
    }

    if (!IsClearOnly(pIpsecNegPolData->NegPolAction) &&
        !IsBlocking(pIpsecNegPolData->NegPolAction)) {

        if (!(pIpsecNegPolData->pIpsecSecurityMethods) ||
            !(pIpsecNegPolData->dwSecurityMethodCount)) {
            dwError = ERROR_INVALID_PARAMETER;
            BAIL_ON_WIN32_ERROR(dwError);
        }

    }

error:

    return (dwError);
}


BOOL
IsClearOnly(
    GUID gNegPolAction
    )
{
    if (!memcmp(
            &gNegPolAction,
            &(GUID_NEGOTIATION_ACTION_NO_IPSEC),
            sizeof(GUID))) {
        return (TRUE);
    }
    else {
        return (FALSE);
    }
}


BOOL
IsBlocking(
    GUID gNegPolAction
    )
{
    if (!memcmp(
            &gNegPolAction,
            &(GUID_NEGOTIATION_ACTION_BLOCK),
            sizeof(GUID))) {
        return (TRUE);
    }
    else {
        return (FALSE);
    }
}


DWORD
ValidateISAKMPDataDeletion(
    HANDLE hPolicyStore,
    GUID ISAKMPIdentifier
    )
{
    DWORD dwError = 0;
    PIPSEC_POLICY_STORE pPolicyStore = NULL;
    LPWSTR pszIpsecISAKMPReference = NULL;
    DWORD dwRootPathLen = 0;
    LPWSTR pszRelativeName = NULL;
    LPWSTR * ppszIpsecPolicyReferences = NULL;
    DWORD dwNumReferences = 0;


    pPolicyStore = (PIPSEC_POLICY_STORE) hPolicyStore;

    switch (pPolicyStore->dwProvider) {

    case IPSEC_REGISTRY_PROVIDER:

        dwError = ConvertGuidToISAKMPString(
                      ISAKMPIdentifier,
                      pPolicyStore->pszIpsecRootContainer,
                      &pszIpsecISAKMPReference
                      );
        BAIL_ON_WIN32_ERROR(dwError);

        dwRootPathLen =  wcslen(pPolicyStore->pszIpsecRootContainer);
        pszRelativeName = pszIpsecISAKMPReference + dwRootPathLen + 1;

        dwError = RegGetPolicyReferencesForISAKMP(
                      pPolicyStore->hRegistryKey,
                      pPolicyStore->pszIpsecRootContainer,
                      pszRelativeName,
                      &ppszIpsecPolicyReferences,
                      &dwNumReferences
                      );
        break;

    case IPSEC_DIRECTORY_PROVIDER:

        dwError = DirGetPolicyReferencesForISAKMP(
                      pPolicyStore->hLdapBindHandle,
                      pPolicyStore->pszIpsecRootContainer,
                      ISAKMPIdentifier,
                      &ppszIpsecPolicyReferences,
                      &dwNumReferences
                      );
        break;

    default:

        dwError = ERROR_INVALID_PARAMETER;
        return (dwError);
        break;

    }

    if (!dwNumReferences) {
        dwError = ERROR_SUCCESS;
    }
    else {
        dwError = ERROR_INVALID_DATA;
    }

error:

    if (pszIpsecISAKMPReference) {
        FreePolStr(pszIpsecISAKMPReference);
    }

    if (ppszIpsecPolicyReferences) {
        FreeNFAReferences(
            ppszIpsecPolicyReferences,
            dwNumReferences
            );
    }

    return (dwError);
}


DWORD
ValidateNegPolDataDeletion(
    HANDLE hPolicyStore,
    GUID NegPolIdentifier
    )
{
    DWORD dwError = 0;
    PIPSEC_POLICY_STORE pPolicyStore = NULL;
    LPWSTR pszIpsecNegPolReference = NULL;
    DWORD dwRootPathLen = 0;
    LPWSTR pszRelativeName = NULL;
    LPWSTR * ppszIpsecNFAReferences = NULL;
    DWORD dwNumReferences = 0;


    pPolicyStore = (PIPSEC_POLICY_STORE) hPolicyStore;

    switch (pPolicyStore->dwProvider) {

    case IPSEC_REGISTRY_PROVIDER:

        dwError = ConvertGuidToNegPolString(
                      NegPolIdentifier,
                      pPolicyStore->pszIpsecRootContainer,
                      &pszIpsecNegPolReference
                      );
        BAIL_ON_WIN32_ERROR(dwError);

        dwRootPathLen =  wcslen(pPolicyStore->pszIpsecRootContainer);
        pszRelativeName = pszIpsecNegPolReference + dwRootPathLen + 1;

        dwError = RegGetNFAReferencesForNegPol(
                      pPolicyStore->hRegistryKey,
                      pPolicyStore->pszIpsecRootContainer,
                      pszRelativeName,
                      &ppszIpsecNFAReferences,
                      &dwNumReferences
                      );
        break;

    case IPSEC_DIRECTORY_PROVIDER:

        dwError = DirGetNFAReferencesForNegPol(
                      pPolicyStore->hLdapBindHandle,
                      pPolicyStore->pszIpsecRootContainer,
                      NegPolIdentifier,
                      &ppszIpsecNFAReferences,
                      &dwNumReferences
                      );
        break;

    default:

        dwError = ERROR_INVALID_PARAMETER;
        return (dwError);
        break;

    }

    if (!dwNumReferences) {
        dwError = ERROR_SUCCESS;
    }
    else {
        dwError = ERROR_INVALID_DATA;
    }

error:

    if (pszIpsecNegPolReference) {
        FreePolStr(pszIpsecNegPolReference);
    }

    if (ppszIpsecNFAReferences) {
        FreeNFAReferences(
            ppszIpsecNFAReferences,
            dwNumReferences
            );
    }

    return (dwError);
}


DWORD
ValidateFilterDataDeletion(
    HANDLE hPolicyStore,
    GUID FilterIdentifier
    )
{
    DWORD dwError = 0;
    PIPSEC_POLICY_STORE pPolicyStore = NULL;
    LPWSTR pszIpsecFilterReference = NULL;
    DWORD dwRootPathLen = 0;
    LPWSTR pszRelativeName = NULL;
    LPWSTR * ppszIpsecNFAReferences = NULL;
    DWORD dwNumReferences = 0;


    pPolicyStore = (PIPSEC_POLICY_STORE) hPolicyStore;

    switch (pPolicyStore->dwProvider) {

    case IPSEC_REGISTRY_PROVIDER:

        dwError = ConvertGuidToFilterString(
                      FilterIdentifier,
                      pPolicyStore->pszIpsecRootContainer,
                      &pszIpsecFilterReference
                      );
        BAIL_ON_WIN32_ERROR(dwError);

        dwRootPathLen =  wcslen(pPolicyStore->pszIpsecRootContainer);
        pszRelativeName = pszIpsecFilterReference + dwRootPathLen + 1;

        dwError = RegGetNFAReferencesForFilter(
                      pPolicyStore->hRegistryKey,
                      pPolicyStore->pszIpsecRootContainer,
                      pszRelativeName,
                      &ppszIpsecNFAReferences,
                      &dwNumReferences
                      );
        break;

    case IPSEC_DIRECTORY_PROVIDER:

        dwError = DirGetNFAReferencesForFilter(
                      pPolicyStore->hLdapBindHandle,
                      pPolicyStore->pszIpsecRootContainer,
                      FilterIdentifier,
                      &ppszIpsecNFAReferences,
                      &dwNumReferences
                      );
        break;

    default:

        dwError = ERROR_INVALID_PARAMETER;
        return (dwError);
        break;

    }

    if (!dwNumReferences) {
        dwError = ERROR_SUCCESS;
    }
    else {
        dwError = ERROR_INVALID_DATA;
    }

error:

    if (pszIpsecFilterReference) {
        FreePolStr(pszIpsecFilterReference);
    }

    if (ppszIpsecNFAReferences) {
        FreeNFAReferences(
            ppszIpsecNFAReferences,
            dwNumReferences
            );
    }

    return (dwError);
}


DWORD
ValidatePolicyDataDeletion(
    HANDLE hPolicyStore,
    PIPSEC_POLICY_DATA pIpsecPolicyData
    )
{
    DWORD dwError = 0;
    PIPSEC_POLICY_STORE pPolicyStore = NULL;
    LPWSTR pszIpsecPolicyReference = NULL;
    DWORD dwRootPathLen = 0;
    LPWSTR pszRelativeName = NULL;
    LPWSTR * ppszIpsecNFAReferences = NULL;
    DWORD dwNumReferences = 0;


    pPolicyStore = (PIPSEC_POLICY_STORE) hPolicyStore;

    switch (pPolicyStore->dwProvider) {

    case IPSEC_REGISTRY_PROVIDER:

        dwError = ConvertGuidToPolicyString(
                      pIpsecPolicyData->PolicyIdentifier,
                      pPolicyStore->pszIpsecRootContainer,
                      &pszIpsecPolicyReference
                      );
        BAIL_ON_WIN32_ERROR(dwError);

        dwRootPathLen =  wcslen(pPolicyStore->pszIpsecRootContainer);
        pszRelativeName = pszIpsecPolicyReference + dwRootPathLen + 1;

        dwError = RegGetNFAReferencesForPolicy(
                      pPolicyStore->hRegistryKey,
                      pPolicyStore->pszIpsecRootContainer,
                      pszRelativeName,
                      &ppszIpsecNFAReferences,
                      &dwNumReferences
                      );
        break;

    case IPSEC_DIRECTORY_PROVIDER:

        dwError = GenerateSpecificPolicyQuery(
                      pIpsecPolicyData->PolicyIdentifier,
                      &pszIpsecPolicyReference
                      );
        BAIL_ON_WIN32_ERROR(dwError);

        dwError = DirGetNFADNsForPolicy(
                      pPolicyStore->hLdapBindHandle,
                      pPolicyStore->pszIpsecRootContainer,
                      pszIpsecPolicyReference,
                      &ppszIpsecNFAReferences,
                      &dwNumReferences
                      );
        break;

    default:

        dwError = ERROR_INVALID_PARAMETER;
        return (dwError);
        break;

    }

    if (!dwNumReferences) {
        dwError = ERROR_SUCCESS;
    }
    else {
        dwError = ERROR_INVALID_DATA;
    }

error:

    if (pszIpsecPolicyReference) {
        FreePolStr(pszIpsecPolicyReference);
    }

    if (ppszIpsecNFAReferences) {
        FreeNFAReferences(
            ppszIpsecNFAReferences,
            dwNumReferences
            );
    }

    return (dwError);
}


DWORD
ValidatePolicyData(
    HANDLE hPolicyStore,
    PIPSEC_POLICY_DATA pIpsecPolicyData
    )
{
    DWORD dwError = 0;
    PIPSEC_ISAKMP_DATA pIpsecISAKMPData = NULL;


    dwError = IPSecGetISAKMPData(
                  hPolicyStore,
                  pIpsecPolicyData->ISAKMPIdentifier,
                  &pIpsecISAKMPData
                  );
    BAIL_ON_WIN32_ERROR(dwError);

error:

    if (pIpsecISAKMPData) {
        FreeIpsecISAKMPData(
            pIpsecISAKMPData
            );
    }

    return (dwError);
}


DWORD
ValidateNFAData(
    HANDLE hPolicyStore,
    GUID PolicyIdentifier,
    PIPSEC_NFA_DATA pIpsecNFAData
    )
{
    DWORD dwError = 0;
    PIPSEC_FILTER_DATA pIpsecFilterData = NULL;
    PIPSEC_NEGPOL_DATA pIpsecNegPolData = NULL;
    GUID gZeroGUID;


    memset(&gZeroGUID, 0, sizeof(GUID));

    if (memcmp(
            &gZeroGUID,
            &pIpsecNFAData->FilterIdentifier,
            sizeof(GUID))) {
        dwError = IPSecGetFilterData(
                      hPolicyStore,
                      pIpsecNFAData->FilterIdentifier, 
                      &pIpsecFilterData
                      );
        BAIL_ON_WIN32_ERROR(dwError);
    }

    dwError = IPSecGetNegPolData(
                  hPolicyStore,
                  pIpsecNFAData->NegPolIdentifier, 
                  &pIpsecNegPolData
                  );
    BAIL_ON_WIN32_ERROR(dwError);

    dwError = VerifyPolicyDataExistence(
                  hPolicyStore,
                  PolicyIdentifier
                  );
    BAIL_ON_WIN32_ERROR(dwError);

error:

    if (pIpsecFilterData) {
        FreeIpsecFilterData(
            pIpsecFilterData
            );
    }

    if (pIpsecNegPolData) {
        FreeIpsecNegPolData(
            pIpsecNegPolData
            );
    }

    return (dwError);
}


DWORD
VerifyPolicyDataExistence(
    HANDLE hPolicyStore,
    GUID PolicyIdentifier
    )
{
    DWORD dwError = 0;
    PIPSEC_POLICY_STORE pPolicyStore = NULL;


    pPolicyStore = (PIPSEC_POLICY_STORE) hPolicyStore;

    switch (pPolicyStore->dwProvider) {

        case IPSEC_REGISTRY_PROVIDER:
            dwError = RegVerifyPolicyDataExistence(
                          pPolicyStore->hRegistryKey,
                          pPolicyStore->pszIpsecRootContainer,
                          PolicyIdentifier
                          );
            break;

        case IPSEC_DIRECTORY_PROVIDER:
            dwError = DirVerifyPolicyDataExistence(
                          pPolicyStore->hLdapBindHandle,
                          pPolicyStore->pszIpsecRootContainer,
                          PolicyIdentifier
                          );
            break;

        default:
            dwError = ERROR_INVALID_PARAMETER;
            break;

    }

    return (dwError);
}


DWORD
RegGetNFAReferencesForPolicy(
    HKEY hRegistryKey,
    LPWSTR pszIpsecRootContainer,
    LPWSTR pszIpsecRelPolicyName,
    LPWSTR ** pppszIpsecNFANames,
    PDWORD pdwNumNFANames
    )
{
    DWORD dwError = 0;
    HKEY hRegKey = 0;
    LPWSTR pszIpsecNFAReference = NULL;
    DWORD dwSize = 0;
    LPWSTR pszTemp = NULL;
    DWORD dwCount = 0;
    LPWSTR * ppszIpsecNFANames = NULL;
    LPWSTR pszString = NULL;
    DWORD i = 0;


    dwError = RegOpenKeyExW(
                    hRegistryKey,
                    pszIpsecRelPolicyName,
                    0,
                    KEY_ALL_ACCESS,
                    &hRegKey
                    );
    BAIL_ON_WIN32_ERROR(dwError);

    dwError = RegstoreQueryValue(
                    hRegKey,
                    L"ipsecNFAReference",
                    REG_MULTI_SZ,
                    (LPBYTE *)&pszIpsecNFAReference,
                    &dwSize
                    );
    BAIL_ON_WIN32_ERROR(dwError);

    pszTemp = pszIpsecNFAReference;
    while (*pszTemp != L'\0') {

        pszTemp += wcslen(pszTemp) + 1;
        dwCount++;

    }

    if (!dwCount) {
        dwError = ERROR_NO_DATA;
        BAIL_ON_WIN32_ERROR(dwError);
    }

    ppszIpsecNFANames =  (LPWSTR *)AllocPolMem(
                                sizeof(LPWSTR)*dwCount
                                );
    if (!ppszIpsecNFANames) {
        dwError = ERROR_OUTOFMEMORY;
        BAIL_ON_WIN32_ERROR(dwError);
    }

    pszTemp = pszIpsecNFAReference;
    for (i = 0; i < dwCount; i++) {

        pszString = AllocPolStr(pszTemp);
        if (!pszString) {
            dwError = ERROR_OUTOFMEMORY;
            BAIL_ON_WIN32_ERROR(dwError);
        }

        *(ppszIpsecNFANames + i) = pszString;

        pszTemp += wcslen(pszTemp) + 1; //for the null terminator;

    }

    *pppszIpsecNFANames = ppszIpsecNFANames;
    *pdwNumNFANames = dwCount;

    dwError = ERROR_SUCCESS;

cleanup:

    if (hRegKey) {
        RegCloseKey(hRegKey);
    }

    if (pszIpsecNFAReference) {
        FreePolStr(pszIpsecNFAReference);
    }

    return(dwError);

error:

    if (ppszIpsecNFANames) {
        FreeNFAReferences(
            ppszIpsecNFANames,
            dwCount
            );
    }

    *pppszIpsecNFANames = NULL;
    *pdwNumNFANames = 0;

    goto cleanup;
}


DWORD
RegVerifyPolicyDataExistence(
    HKEY hRegistryKey,
    LPWSTR pszIpsecRootContainer,
    GUID PolicyGUID
    )
{
    DWORD dwError = 0;
    WCHAR szIpsecPolicyName[MAX_PATH];
    LPWSTR pszPolicyName = NULL;
    HKEY hRegKey = NULL;


    szIpsecPolicyName[0] = L'\0';
    wcscpy(szIpsecPolicyName, L"ipsecPolicy");

    dwError = UuidToString(&PolicyGUID, &pszPolicyName);
    BAIL_ON_WIN32_ERROR(dwError);

    wcscat(szIpsecPolicyName, L"{");
    wcscat(szIpsecPolicyName, pszPolicyName);
    wcscat(szIpsecPolicyName, L"}");

    dwError = RegOpenKeyExW(
                  hRegistryKey,
                  szIpsecPolicyName,
                  0,
                  KEY_ALL_ACCESS,
                  &hRegKey
                  );
    BAIL_ON_WIN32_ERROR(dwError);

error:

    if (pszPolicyName) {
        RpcStringFree(&pszPolicyName);
    }

    if (hRegKey) {
        RegCloseKey(hRegKey);
    }

    return (dwError);
}


DWORD
DirVerifyPolicyDataExistence(
    HLDAP hLdapBindHandle,
    LPWSTR pszIpsecRootContainer,
    GUID PolicyGUID
    )
{
    DWORD dwError = 0;
    LPWSTR pszPolicyString = NULL;
    LDAPMessage * res = NULL;
    DWORD dwCount = 0;


    dwError = GenerateSpecificPolicyQuery(
                  PolicyGUID,
                  &pszPolicyString
                  );
    BAIL_ON_WIN32_ERROR(dwError);

    dwError = LdapSearchST(
                  hLdapBindHandle,
                  pszIpsecRootContainer,
                  LDAP_SCOPE_ONELEVEL,
                  pszPolicyString,
                  PolicyDNAttributes,
                  0,
                  NULL,
                  &res
                  );
    BAIL_ON_WIN32_ERROR(dwError);

    dwCount = LdapCountEntries(
                  hLdapBindHandle,
                  res
                  );
    if (!dwCount) {
        dwError = ERROR_DS_NO_ATTRIBUTE_OR_VALUE;
        BAIL_ON_WIN32_ERROR(dwError);
    }

error:

    if (pszPolicyString) {
        FreePolStr(pszPolicyString);
    }

    if (res) {
        LdapMsgFree(res);
    }

    return (dwError);
}