Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

902 lines
21 KiB

////////////////////////////////////////////////////////////////////////
//
// Module : Dynamic/Nshcertmgmt.cpp
//
// Purpose : Smartdefaults implementation.
//
// Developers Name : Bharat/Radhika
//
// History :
//
// Date Author Comments
// 10-13-2001 Bharat Initial Version. V1.0
//
////////////////////////////////////////////////////////////////////////
#ifndef UNICODE
#define UNICODE
#endif
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <ntlsa.h>
#include <ntmsv1_0.h>
#include <tchar.h>
#include <stdlib.h>
#include <string.h>
#include <rpc.h>
#include <windows.h>
#include <wincrypt.h>
#include <stdio.h>
#include <winipsec.h>
#include <ipsecshr.h>
#include "memory.h"
#include "nshcertmgmt.h"
///////////////////////////////////////////////////////////////////////////////////////////
//
// Function : fIsCertStoreEmpty
//
// Date of Creation : 10-10-2001
//
// Parameters : IN HCERTSTORE hCertStore
// Return : BOOL
//
// Description : Check if certificate store is empty.
//
// Revision History :
//
// Date Author Comments
//
////////////////////////////////////////////////////////////////////////////////////////////
BOOL
fIsCertStoreEmpty(
IN HCERTSTORE hCertStore
)
{
PCCERT_CONTEXT pCertContext = NULL;
BOOL fResult = FALSE;
pCertContext = CertEnumCertificatesInStore(hCertStore, NULL);
if(NULL == pCertContext)
{
fResult = TRUE;
}
else
{
CertFreeCertificateContext(pCertContext);
}
return fResult;
}
///////////////////////////////////////////////////////////////////////////////////////////
//
// Function : ListCertsInStore
//
// Date of Creation: 10-10-2001
//
// Parameters : IN HCERTSTORE hCertStore,
// OUT INT_IPSEC_MM_AUTH_INFO ** ppAuthInfo,
// OUT PDWORD pdwNumCertificates
// Return : DWORD
//
// Description : Lists Certificates InStore hCertStore and fills in ppAuth.
//
// Revision History:
//
// Date Author Comments
//
//////////////////////////////////////////////////////////////////////////////////////////
DWORD
ListCertsInStore(
IN HCERTSTORE hCertStore,
OUT INT_IPSEC_MM_AUTH_INFO ** ppAuthInfo,
OUT PDWORD pdwNumCertificates
)
{
PCCERT_CONTEXT pPrevCertContext = NULL;
PCCERT_CONTEXT pCertContext = NULL;
CERT_NAME_BLOB NameBlob;
PCERT_ENHKEY_USAGE pUsage = NULL;
PCERT_NODE pCertificateList = NULL;
PCERT_NODE pTemp = NULL;
INT_IPSEC_MM_AUTH_INFO * pAuthInfo = NULL;
INT_IPSEC_MM_AUTH_INFO * pCurrentAuth = NULL;
LPWSTR pszSubjectName = NULL;
DWORD i = 0;
DWORD dwNumCertificates = 0;
DWORD dwError = 0;
DWORD Usage = 0;
BOOL bValid = FALSE;
while(TRUE)
{
pCertContext = CertEnumCertificatesInStore(hCertStore, pPrevCertContext);
if (!pCertContext)
{
break;
}
pUsage = NULL;
Usage = 0;
bValid = FALSE;
dwError = CertGetEnhancedKeyUsage(pCertContext, 0, NULL, &Usage);
if(Usage)
{
pUsage = (PCERT_ENHKEY_USAGE)LocalAlloc(LPTR, Usage);
if(!pUsage)
{
dwError = ERROR_OUTOFMEMORY;
BAIL_ON_WIN32ERROR(dwError)
}
CertGetEnhancedKeyUsage(pCertContext, 0, pUsage, &Usage);
for (Usage = 0; Usage < pUsage->cUsageIdentifier; Usage++)
{
if(!strcmp(pUsage->rgpszUsageIdentifier[Usage],szOID_PKIX_KP_SERVER_AUTH))
{
bValid = TRUE;
}
else if(!strcmp(pUsage->rgpszUsageIdentifier[Usage],szOID_PKIX_KP_CLIENT_AUTH))
{
bValid = TRUE;
}
else if(!strcmp(pUsage->rgpszUsageIdentifier[Usage],szOID_ANY_CERT_POLICY))
{
bValid = TRUE;
}
}
if(pUsage)
{
LocalFree(pUsage);
pUsage = NULL;
}
}
else
{
dwError = ERROR_SUCCESS;
}
if(bValid)
{
NameBlob = pCertContext->pCertInfo->Issuer;
dwError = GetCertificateName(&NameBlob, &pszSubjectName);
if (dwError)
{
if(NULL != pPrevCertContext)
{
CertFreeCertificateContext(pCertContext);
}
break;
}
if (!FindCertificateInList(pCertificateList, pszSubjectName))
{
//
// Append this CA to the list of CAs
//
pCertificateList = AppendCertificateNode(pCertificateList, pszSubjectName);
dwNumCertificates++;
}
else
{
FreeADsStr(pszSubjectName);
}
}
pPrevCertContext = pCertContext;
}
pAuthInfo = (INT_IPSEC_MM_AUTH_INFO *)AllocADsMem( sizeof(INT_IPSEC_MM_AUTH_INFO)*dwNumCertificates );
if (!pAuthInfo)
{
dwError = ERROR_OUTOFMEMORY;
BAIL_ON_WIN32ERROR(dwError)
}
pTemp = pCertificateList;
for (i = 0; i < dwNumCertificates; i++)
{
pCurrentAuth = pAuthInfo + i;
dwError = CopyCertificateNode(pCurrentAuth, pTemp);
BAIL_ON_WIN32ERROR(dwError)
pTemp = pTemp->pNext;
}
if (pCertificateList)
{
FreeCertificateList(pCertificateList);
}
*ppAuthInfo = pAuthInfo;
*pdwNumCertificates = dwNumCertificates;
return(dwError);
error:
if (pCertificateList)
{
FreeCertificateList(pCertificateList);
}
if(NULL != pAuthInfo)
{
FreeADsMem(pAuthInfo);
}
*ppAuthInfo = NULL;
*pdwNumCertificates = 0;
return(dwError);
}
///////////////////////////////////////////////////////////////////////////////////////////
//
// Function : CopyCertificateNode
//
// Date of Creation : 10-10-2001
//
// Parameters : OUT PINT_IPSEC_MM_AUTH_INFO pCurrentAuth,
// IN PCERT_NODE pTemp
// Return : DWORD
//
// Description : This function copies certificate from node to authentication.
//
// Revision History :
//
// Date Author Comments
//
//////////////////////////////////////////////////////////////////////////////////////////
DWORD
CopyCertificateNode(
OUT PINT_IPSEC_MM_AUTH_INFO pCurrentAuth,
IN PCERT_NODE pTemp
)
{
DWORD dwError = ERROR_SUCCESS;
LPWSTR pszSubjectName = NULL;
pCurrentAuth->AuthMethod = IKE_RSA_SIGNATURE; //value is 3
pszSubjectName = AllocADsStr(pTemp->pszSubjectName);
if (!pszSubjectName)
{
dwError = ERROR_OUTOFMEMORY;
BAIL_ON_WIN32ERROR(dwError)
}
pCurrentAuth->pAuthInfo = (LPBYTE) pszSubjectName;
//
// The AuthInfoSize is in number of characters -1 the leading character
// see oakley\isadb.c
//
pCurrentAuth->dwAuthInfoSize = wcslen(pTemp->pszSubjectName)*sizeof(WCHAR);
error:
return dwError;
}
///////////////////////////////////////////////////////////////////////////////////////////
//
// Function : AppendCertificateNode
//
// Date of Creation: 10-10-2001
//
// Parameters : OUT PCERT_NODE pCertificateList,
// IN LPWSTR pszSubjectName
// Return : PCERT_NODE
//
// Description : Add node and allocates memory.
//
// Revision History:
//
// Date Author Comments
//
//////////////////////////////////////////////////////////////////////////////////////////
PCERT_NODE
AppendCertificateNode(
OUT PCERT_NODE pCertificateList,
IN LPWSTR pszSubjectName
)
{
PCERT_NODE pCertificateNode = NULL;
pCertificateNode = (PCERT_NODE)AllocADsMem(sizeof(CERT_NODE));
if (!pCertificateNode)
{
pCertificateNode = pCertificateList;
BAILOUT;
}
pCertificateNode->pszSubjectName = pszSubjectName;
pCertificateNode->pNext = pCertificateList;
error:
return(pCertificateNode);
}
///////////////////////////////////////////////////////////////////////////////////////////
//
// Function : FreeCertificateList
//
// Date of Creation: 10-10-2001
//
// Parameters : IN PCERT_NODE pCertificateList
// Return : VOID
//
// Description : Frees node
//
// Revision History:
//
// Date Author Comments
//
//////////////////////////////////////////////////////////////////////////////////////////
VOID
FreeCertificateList(
IN PCERT_NODE pCertificateList
)
{
PCERT_NODE pTemp = NULL;
pTemp = pCertificateList;
while (pCertificateList)
{
pTemp = pCertificateList;
pCertificateList = pCertificateList->pNext;
if (pTemp)
{
FreeADsStr(pTemp->pszSubjectName);
FreeADsMem(pTemp);
}
}
return;
}
///////////////////////////////////////////////////////////////////////////////////////////
//
// Function : GetCertificateName
//
// Date of Creation : 10-10-2001
//
// Parameters : IN CERT_NAME_BLOB * pCertNameBlob,
// IN LPWSTR * ppszSubjectName
// Return : DWORD
//
// Description : Gets certificate
//
// Revision History :
//
// Date Author Comments
//
//////////////////////////////////////////////////////////////////////////////////////////
DWORD
GetCertificateName(
IN CERT_NAME_BLOB * pCertNameBlob,
IN LPWSTR * ppszSubjectName
)
{
DWORD dwSize = 0;
DWORD dwError = 0;
LPWSTR pszSubjectName = NULL;
*ppszSubjectName = NULL;
dwSize = CertNameToStrW(MY_ENCODING_TYPE_CERT, pCertNameBlob, CERT_X500_NAME_STR, NULL, dwSize );
if (dwSize <= 1)
{
dwError = ERROR_OUTOFMEMORY;
BAIL_ON_WIN32ERROR(dwError)
}
pszSubjectName = (LPWSTR)AllocADsMem((dwSize + 1)*sizeof(WCHAR));
if (!pszSubjectName)
{
dwError = ERROR_OUTOFMEMORY;
BAIL_ON_WIN32ERROR(dwError)
}
dwSize = CertNameToStrW(MY_ENCODING_TYPE_CERT, pCertNameBlob, CERT_X500_NAME_STR, pszSubjectName, dwSize );
if(dwSize <= 1)
{
FreeADsMem(pszSubjectName);
dwError = ERROR_OUTOFMEMORY;
BAIL_ON_WIN32ERROR(dwError)
}
*ppszSubjectName = pszSubjectName;
error:
return(dwError);
}
///////////////////////////////////////////////////////////////////////////////////////////
//
// Function : FreeCertificatesList
//
// Date of Creation : 10-10-2001
//
// Parameters : IN INT_IPSEC_MM_AUTH_INFO * pAuthInfo,
// IN DWORD dwNumCertificates
// Return : VOID
//
// Description : Frees list of certificates from pAuth
//
// Revision History :
//
// Date Author Comments
//
//////////////////////////////////////////////////////////////////////////////////////////
VOID
FreeCertificatesList(
IN INT_IPSEC_MM_AUTH_INFO * pAuthInfo,
IN DWORD dwNumCertificates
)
{
DWORD i = 0;
INT_IPSEC_MM_AUTH_INFO * pThisAuthInfo = NULL;
if (!pAuthInfo)
{
BAILOUT;
}
for (i = 0; i < dwNumCertificates; i++)
{
pThisAuthInfo = pAuthInfo + i;
if (pThisAuthInfo->pAuthInfo)
{
FreeADsMem(pThisAuthInfo->pAuthInfo);
pThisAuthInfo->pAuthInfo = NULL;
}
}
FreeADsMem(pAuthInfo);
error:
return;
}
///////////////////////////////////////////////////////////////////////////////////////////
//
// Function : FindCertificateInList
//
// Date of Creation : 10-10-2001
//
// Parameters : IN PCERT_NODE pCertificateList,
// IN LPWSTR pszSubjectName
// Return : BOOL
//
// Description : Finds certificate in List
//
// Revision History :
//
// Date Author Comments
//
//////////////////////////////////////////////////////////////////////////////////////////
BOOL
FindCertificateInList(
IN PCERT_NODE pCertificateList,
IN LPWSTR pszSubjectName
)
{
BOOL bReturn = FALSE;
while (pCertificateList) {
if (!_wcsicmp(pCertificateList->pszSubjectName, pszSubjectName)) {
bReturn = TRUE;
BAILOUT;
}
pCertificateList = pCertificateList->pNext;
}
error:
return bReturn;
}
///////////////////////////////////////////////////////////////////////////////////////////
//
// Function : ListCertChainsInStore
//
// Date of Creation: 10-10-2001
//
// Parameters : IN HCERTSTORE hCertStore,
// OUT INT_IPSEC_MM_AUTH_INFO ** ppAuthInfo,
// IN PDWORD pdwNumCertificates,
// IN LPCSTR pszUsageIdentifier
//
// Return : DWORD
//
// Description : Lists certificate in store
//
// Revision History:
//
// Date Author Comments
//
//////////////////////////////////////////////////////////////////////////////////////////
DWORD
ListCertChainsInStore(
IN HCERTSTORE hCertStore,
OUT INT_IPSEC_MM_AUTH_INFO ** ppAuthInfo,
IN PDWORD pdwNumCertificates,
IN LPCSTR pszUsageIdentifier
)
{
PCCERT_CHAIN_CONTEXT pPrevChain=NULL;
PCCERT_CHAIN_CONTEXT pCertChain = NULL;
DWORD dwError = 0;
CERT_CHAIN_FIND_BY_ISSUER_PARA FindPara;
CERT_NAME_BLOB *NameArray=NULL;
DWORD ArraySize=0;
PCERT_SIMPLE_CHAIN pSimpChain = NULL;
PCERT_CHAIN_ELEMENT pRoot = NULL;
DWORD dwRootIndex = 0;
LPWSTR pszSubjectName = NULL;
PCERT_NODE pCertificateList = NULL;
PCERT_NODE pTemp = NULL;
INT_IPSEC_MM_AUTH_INFO * pAuthInfo = NULL;
INT_IPSEC_MM_AUTH_INFO * pCurrentAuth = NULL;
DWORD i = 0;
DWORD dwNumCertificates = 0;
FindPara.pszUsageIdentifier = pszUsageIdentifier;
FindPara.cbSize = sizeof(FindPara);
FindPara.dwKeySpec = 0;
FindPara.cIssuer = ArraySize;
FindPara.rgIssuer = NameArray;
FindPara.pfnFindCallback = NULL;
FindPara.pvFindArg = NULL;
while (TRUE)
{
pCertChain=CertFindChainInStore(hCertStore, X509_ASN_ENCODING,
CERT_CHAIN_FIND_BY_ISSUER_COMPARE_KEY_FLAG |
CERT_CHAIN_FIND_BY_ISSUER_LOCAL_MACHINE_FLAG |
CERT_CHAIN_FIND_BY_ISSUER_CACHE_ONLY_URL_FLAG |
CERT_CHAIN_FIND_BY_ISSUER_NO_KEY_FLAG,
CERT_CHAIN_FIND_BY_ISSUER,
&FindPara,
pPrevChain
);
if (!pCertChain)
{
break;
}
pSimpChain=*(pCertChain->rgpChain);
dwRootIndex=pSimpChain->cElement-1;
pRoot=pSimpChain->rgpElement[dwRootIndex];
dwError = GetCertificateName(
&(pRoot->pCertContext->pCertInfo->Issuer),
&pszSubjectName
);
BAIL_ON_WIN32ERROR(dwError)
if (!FindCertificateInList(pCertificateList, pszSubjectName))
{
//
// Append this CA to the list of CAs
//
pCertificateList = AppendCertificateNode( pCertificateList, pszSubjectName );
dwNumCertificates++;
}
else
{
//
// This is a duplicate - certificate payloads will not accept dupes.
//
FreeADsStr(pszSubjectName);
}
pPrevChain = pCertChain;
}
if (!dwNumCertificates)
{
dwError = ERROR_NO_MORE_ITEMS;
BAIL_ON_WIN32ERROR(dwError);
}
//
// Allocate one more authinfo for pre-sharedkey.
//
pAuthInfo = (INT_IPSEC_MM_AUTH_INFO *)AllocADsMem(sizeof(INT_IPSEC_MM_AUTH_INFO) * (1 + dwNumCertificates));
if (!pAuthInfo)
{
dwError = ERROR_OUTOFMEMORY;
BAIL_ON_WIN32ERROR(dwError);
}
pTemp = pCertificateList;
for (i = 0; i < dwNumCertificates; i++)
{
pCurrentAuth = pAuthInfo + i;
dwError = CopyCertificateNode( pCurrentAuth, pTemp);
BAIL_ON_WIN32ERROR(dwError);
pTemp = pTemp->pNext;
}
*ppAuthInfo = pAuthInfo;
*pdwNumCertificates = dwNumCertificates;
error:
if (pCertificateList)
{
FreeCertificateList(pCertificateList);
}
if(dwError != 0)
{
*ppAuthInfo = NULL;
*pdwNumCertificates = 0;
}
return(dwError);
}
///////////////////////////////////////////////////////////////////////////////////////////
//
// Function : CopyCertificate
//
// Date of Creation: 10-10-2001
//
// Parameters : IN PINT_IPSEC_MM_AUTH_INFO pCurrentAuth,
// IN PINT_IPSEC_MM_AUTH_INFO pCurrentAuthFrom
// Return : DWORD
//
// Description : Copies certificate
//
// Revision History:
//
// Date Author Comments
//
//////////////////////////////////////////////////////////////////////////////////////////
DWORD
CopyCertificate(
IN PINT_IPSEC_MM_AUTH_INFO pCurrentAuth,
IN PINT_IPSEC_MM_AUTH_INFO pCurrentAuthFrom
)
{
DWORD dwReturn = ERROR_SUCCESS;
pCurrentAuth->AuthMethod = pCurrentAuthFrom->AuthMethod;
dwReturn = EncodeCertificateName ((LPTSTR)pCurrentAuthFrom->pAuthInfo,
&pCurrentAuth->pAuthInfo,
&pCurrentAuth->dwAuthInfoSize);
return dwReturn;
}
///////////////////////////////////////////////////////////////////////////////////////////
//
// Function : IsDomainMember
//
// Date of Creation: 10-10-2001
//
// Parameters : IN LPTSTR pszMachine
//
// Return : BOOL
//
// Description : Checks for member of a domain(2k) or not of pszMachine.
//
// Revision History:
//
// Date Author Comments
//
//////////////////////////////////////////////////////////////////////////////////////////
BOOL
IsDomainMember(
IN LPTSTR pszMachine
)
{
BOOL bIsDomainMember = FALSE;
do
{
NTSTATUS lStatus;
LSA_HANDLE hLsa;
LSA_OBJECT_ATTRIBUTES ObjectAttributes;
LSA_UNICODE_STRING LsaString;
// Initialize the object attributes to all zeroes.
ZeroMemory( &ObjectAttributes, sizeof( ObjectAttributes ) );
if ((pszMachine == NULL) || !wcscmp(pszMachine, L"\0"))
{
LsaString.Buffer = NULL;
LsaString.Length = 0;
LsaString.MaximumLength = 0;
}
else
{
LsaString.Buffer = pszMachine;
LsaString.Length = (USHORT) (wcslen(pszMachine)* sizeof(WCHAR));
LsaString.MaximumLength = (USHORT) (wcslen(pszMachine) + 1) * sizeof(WCHAR);
}
// Attempt to open the policy.
lStatus = LsaOpenPolicy( &LsaString, &ObjectAttributes,
GENERIC_READ | POLICY_VIEW_LOCAL_INFORMATION, &hLsa );
// Exit on error.
if (lStatus)
{
break;
}
// Query domain information
PPOLICY_PRIMARY_DOMAIN_INFO ppdiDomainInfo;
lStatus = LsaQueryInformationPolicy( hLsa, PolicyPrimaryDomainInformation,
(PVOID*)&ppdiDomainInfo );
// Exit on error.
if (lStatus)
{
break;
}
//
// Check the Sid pointer, if it is null, the workstation is either a
// stand-alone computer or a member of a workgroup.
//
if( ppdiDomainInfo->Sid )
{
bIsDomainMember = TRUE;
}
//
// Clean up
//
if (NULL != ppdiDomainInfo)
LsaFreeMemory( ppdiDomainInfo );
} while (0);
return bIsDomainMember;
}
///////////////////////////////////////////////////////////////////////////////////////////
//
// Function : SmartDefaults
//
// Date of Creation: 10-10-2001
//
// Parameters : IN PINT_IPSEC_MM_AUTH_INFO pAuthInfo,
// IN LPTSTRT pszMachine,
// IN DWORD * pdwNumberOfAuth,
// IN BOOL bIsDomainPolicy
//
// Return : DWORD
//
// Description : Loads smart defaults of pszMachine in pAuthinfo.
//
// Revision History:
//
// Date Author Comments
//
//////////////////////////////////////////////////////////////////////////////////////////
DWORD
SmartDefaults(
IN PINT_IPSEC_MM_AUTH_INFO *ppAuthInfo,
IN LPTSTR pszMachine,
IN DWORD * pdwNumberOfAuth,
IN BOOL bIsDomainPolicy
)
{
HCERTSTORE hCertStore = NULL;
INT_IPSEC_MM_AUTH_INFO * pAuthInfoIKE = NULL, * pAuthInfoOthers = NULL;
PINT_IPSEC_MM_AUTH_INFO pAuthInfo = NULL;
DWORD dwReturn = ERROR_SUCCESS, i=0;
DWORD dwNumCertificatesIKE = 0, dwNumCertificatesOthers = 0;
_TCHAR szMachine[MACHINE_NAME] = {0};
if((pszMachine == NULL) || (!wcscmp(pszMachine, L"\0")))
{
wcscpy(szMachine, L"MY\0");
}
else
{
wcscpy(szMachine, pszMachine);
wcscat(szMachine, L"\\MY\0");
}
if (bIsDomainPolicy || IsDomainMember(pszMachine))
{
hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG | CERT_SYSTEM_STORE_LOCAL_MACHINE,
szMachine);
if(hCertStore)
{
//
// First fill IKE intermediate
//
dwReturn = ListCertChainsInStore( hCertStore, &pAuthInfoIKE,
&dwNumCertificatesIKE, szOID_IPSEC_KP_IKE_INTERMEDIATE );
if(dwNumCertificatesIKE == 0)
{
dwReturn = ERROR_SUCCESS;
}
if(dwReturn == ERROR_SUCCESS)
{
dwReturn = ListCertsInStore( hCertStore, &pAuthInfoOthers, &dwNumCertificatesOthers);
}
if(dwNumCertificatesOthers == 0)
{
dwReturn = ERROR_SUCCESS;
}
}
else
{
dwReturn = GetLastError();
BAIL_ON_WIN32ERROR(dwReturn)
}
}
*pdwNumberOfAuth = dwNumCertificatesIKE + dwNumCertificatesOthers + 1;
pAuthInfo = new INT_IPSEC_MM_AUTH_INFO[(*pdwNumberOfAuth)];
if(pAuthInfo == NULL)
{
dwReturn = ERROR_OUTOFMEMORY;
BAIL_ON_WIN32ERROR(dwReturn)
}
ZeroMemory(pAuthInfo, sizeof(INT_IPSEC_MM_AUTH_INFO) * (*pdwNumberOfAuth));
if(dwReturn == ERROR_SUCCESS)
{
for( i=0; i< dwNumCertificatesIKE; i++)
{
CopyCertificate( &pAuthInfo[i], &pAuthInfoIKE[i]);
}
for( i=0; i< dwNumCertificatesOthers; i++)
{
CopyCertificate( &pAuthInfo[i+dwNumCertificatesIKE], &pAuthInfoOthers[i]);
}
pAuthInfo[(*pdwNumberOfAuth)-1].AuthMethod = IKE_SSPI;
pAuthInfo[(*pdwNumberOfAuth)-1].dwAuthInfoSize = 0;
pAuthInfo[(*pdwNumberOfAuth)-1].pAuthInfo = (LPBYTE)new _TCHAR[1];
if(pAuthInfo[(*pdwNumberOfAuth)-1].pAuthInfo != NULL)
{
pAuthInfo[(*pdwNumberOfAuth)-1].pAuthInfo[0] = UNICODE_NULL;
}
else
{
dwReturn = ERROR_OUTOFMEMORY;
BAIL_ON_WIN32ERROR(dwReturn)
}
}
error:
*ppAuthInfo = pAuthInfo;
if(pAuthInfoIKE)
FreeADsMem(pAuthInfoIKE);
if(pAuthInfoOthers)
FreeADsMem(pAuthInfoOthers);
return dwReturn;
}