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.
 
 
 
 
 
 

1547 lines
36 KiB

//+-------------------------------------------------------------------------
//
// Microsoft Windows NT
//
// Copyright (C) Microsoft Corporation, 1995 - 1998
//
// File: mscep.cpp
//
// Contents: Cisco enrollment protocal implementation
//
//--------------------------------------------------------------------------
#include "global.hxx"
#include <dbgdef.h>
CRITICAL_SECTION CriticalSec;
CRITICAL_SECTION PasswordCriticalSec;
static BOOL g_fInit=FALSE;
static BOOL g_fRelease=FALSE;
HCERTSTORE g_HCACertStore=NULL;
CEP_RA_INFO g_RAInfo;
CEP_CA_INFO g_CAInfo={NULL, NULL, NULL, NULL, NULL, FALSE, NULL};
HCRYPTASN1MODULE ICM_hAsn1Module=NULL;
HMODULE g_hMSCEPModule=NULL;
HANDLE g_hEventSource = NULL;
ULARGE_INTEGER g_ftRAExpiration;
ULARGE_INTEGER g_ftRACloseToExpire;
ULARGE_INTEGER g_ftRAWarn;
LPWSTR g_pwszComputerName=NULL;
//-----------------------------------------------------------------------------------
//
// DllMain
//
//------------------------------------------------------------------------------------
BOOL WINAPI DllMain(
HMODULE hInstDLL,
DWORD fdwReason,
LPVOID lpvReserved
)
{
BOOL fResult = TRUE;
//we use the try{}except here to prevent malicous requests
__try
{
switch(fdwReason)
{
case DLL_PROCESS_ATTACH:
g_hMSCEPModule=hInstDLL;
InitializeCriticalSection(&CriticalSec);
InitializeCriticalSection(&PasswordCriticalSec);
CEPASN_Module_Startup();
if (0 == (ICM_hAsn1Module = I_CryptInstallAsn1Module(
CEPASN_Module, 0, NULL)))
fResult = FALSE;
g_hEventSource = RegisterEventSourceW(NULL, MSCEP_EVENT_LOG);
break;
case DLL_PROCESS_DETACH:
if (g_hEventSource)
DeregisterEventSource(g_hEventSource);
I_CryptUninstallAsn1Module(ICM_hAsn1Module);
CEPASN_Module_Cleanup();
DeleteCriticalSection(&PasswordCriticalSec);
DeleteCriticalSection(&CriticalSec);
break;
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
// return failure
fResult = FALSE;
}
return(fResult);
}
//-----------------------------------------------------------------------------------
//
// DllRegisterServer
//
//------------------------------------------------------------------------------------
STDAPI DllRegisterServer()
{
HRESULT hr = S_OK;
return hr;
}
//-----------------------------------------------------------------------------------
//
// DllUnregisterServer
//
//------------------------------------------------------------------------------------
STDAPI DllUnregisterServer()
{
HRESULT hr = S_OK;
return hr;
}
//-----------------------------------------------------------------------------------
//
// DecodeIssuerAndSerialNumber
//
// Decoding routine to decode a IssuerAndSerialNumber blob and return the
// SerialNumber
//
//------------------------------------------------------------------------------------
BOOL WINAPI GetSerialNumberFromBlob(BYTE *pbEncoded,
DWORD cbEncoded,
CRYPT_INTEGER_BLOB *pSerialNumber)
{
BOOL fResult = FALSE;
ASN1error_e Asn1Err;
ASN1decoding_t pDec;
IssuerAndSerialNumber *pisn=NULL;
if((!pSerialNumber) || (!pbEncoded))
goto InvalidArgErr;
pDec = I_CryptGetAsn1Decoder(ICM_hAsn1Module);
if (0 != (Asn1Err = PkiAsn1Decode(
pDec,
(void **)&pisn,
IssuerAndSerialNumber_PDU,
pbEncoded,
cbEncoded)))
goto DecodeIssuerAndSerialNumberError;
//we now reverse the byte
PkiAsn1ReverseBytes(pisn->serialNumber.value,
pisn->serialNumber.length);
pSerialNumber->cbData=pisn->serialNumber.length;
if(!(pSerialNumber->pbData = (BYTE *)malloc(pSerialNumber->cbData)))
goto MemoryErr;
memcpy(pSerialNumber->pbData, pisn->serialNumber.value, pSerialNumber->cbData);
fResult = TRUE;
CommonReturn:
if(pisn)
PkiAsn1FreeInfo(pDec, IssuerAndSerialNumber_PDU, pisn);
return fResult;
ErrorReturn:
fResult=FALSE;
goto CommonReturn;
SET_ERROR(InvalidArgErr, E_INVALIDARG);
SET_ERROR_VAR(DecodeIssuerAndSerialNumberError, PkiAsn1ErrToHr(Asn1Err))
SET_ERROR(MemoryErr, E_OUTOFMEMORY);
}
//-----------------------------------------------------------------------------------
//
// GetExtensionVersion
//
// IIS initialization code
//
//------------------------------------------------------------------------------------
BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO *pVer)
{
BOOL fResult = FALSE;
HRESULT hr = S_OK;
BOOL fOleInit=FALSE;
DWORD dwSize=0;
//copy the version/description
pVer->dwExtensionVersion = MAKELONG( HSE_VERSION_MINOR,
HSE_VERSION_MAJOR );
lstrcpyn( pVer->lpszExtensionDesc,
"This is the implementation of cisco enrollment protocol",
HSE_MAX_EXT_DLL_NAME_LEN);
if(g_fInit)
{
LogSCEPEvent(0, FALSE, S_OK, EVENT_MSCEP_LOADED, 0);
return TRUE;
}
EnterCriticalSection(&CriticalSec);
//retest in the case of lock: the second thread has passed the 1st test
//and was waiting for the criticcal section
if(g_fInit)
{
LogSCEPEvent(0, FALSE, S_OK, EVENT_MSCEP_LOADED, 0);
LeaveCriticalSection(&CriticalSec);
return TRUE;
}
memset(&g_ftRAExpiration, 0, sizeof(ULARGE_INTEGER));
memset(&g_ftRACloseToExpire, 0, sizeof(ULARGE_INTEGER));
memset(&g_ftRAWarn, 0, sizeof(ULARGE_INTEGER));
//get the computer name
dwSize=0;
GetComputerNameExW(ComputerNamePhysicalDnsHostname,
NULL,
&dwSize);
g_pwszComputerName=(LPWSTR)malloc(dwSize * sizeof(WCHAR));
if(NULL==g_pwszComputerName)
goto InitErr;
if(!GetComputerNameExW(ComputerNamePhysicalDnsHostname,
g_pwszComputerName,
&dwSize))
goto InitErr;
//initialize the state information
if(FAILED(hr=CoInitialize(NULL)))
goto OleErr;
fOleInit=TRUE;
if(!InitCAInformation(&g_CAInfo))
{
LogSCEPEvent(0, TRUE, HRESULT_FROM_WIN32(GetLastError()), EVENT_MSCEP_FAILED_CA_INFO, 1, g_pwszComputerName);
goto InitErr;
}
if(!GetCACertFromInfo(&g_CAInfo, &g_HCACertStore))
{
LogSCEPEvent(0, TRUE, HRESULT_FROM_WIN32(GetLastError()), EVENT_MSCEP_FAILED_CA_CERT, 1, g_pwszComputerName);
goto InitErr;
}
if(!GetRAInfo(&g_RAInfo))
{
LogSCEPEvent(0, TRUE, HRESULT_FROM_WIN32(GetLastError()), EVENT_MSCEP_FAILED_RA_CERT, 1, g_pwszComputerName);
goto InitErr;
}
//we add the RA and CA cert to the g_hCACertStore
if(!CertAddCertificateContextToStore(g_HCACertStore,
g_RAInfo.pRACert,
CERT_STORE_ADD_NEW,
NULL))
goto InitErr;
if(!CertAddCertificateContextToStore(g_HCACertStore,
g_RAInfo.pRASign,
CERT_STORE_ADD_NEW,
NULL))
goto InitErr;
if(!InitHashTable())
goto InitErr;
if(!InitPasswordTable())
goto InitErr;
if(!InitRequestTable())
goto InitErr;
//copy the time when the RAs will expire
if( 1 == CompareFileTime(&((g_RAInfo.pRACert->pCertInfo)->NotAfter), &((g_RAInfo.pRASign->pCertInfo)->NotAfter)))
{
g_ftRAExpiration.QuadPart=((ULARGE_INTEGER UNALIGNED *)&((g_RAInfo.pRASign->pCertInfo)->NotAfter))->QuadPart;
}
else
g_ftRAExpiration.QuadPart=((ULARGE_INTEGER UNALIGNED *)&((g_RAInfo.pRACert->pCertInfo)->NotAfter))->QuadPart;
//start to give out warnings two weeks before the RA Certificates expire
g_ftRACloseToExpire.QuadPart=g_ftRAExpiration.QuadPart-Int32x32To64(FILETIME_TICKS_PER_SECOND, OVERLAP_TWO_WEEKS);
fResult=TRUE;
CommonReturn:
g_fInit=fResult;
if(fResult)
{
LogSCEPEvent(0, FALSE, S_OK, EVENT_MSCEP_LOADED, 0);
}
else
{
LogSCEPEvent(0, TRUE, HRESULT_FROM_WIN32(GetLastError()), EVENT_MSCEP_FAILED_TO_LOAD, 0);
}
LeaveCriticalSection(&CriticalSec);
return fResult;
ErrorReturn:
//clean up the global data.
if(g_HCACertStore)
{
CertCloseStore(g_HCACertStore, 0);
g_HCACertStore=NULL;
}
FreeRAInformation(&g_RAInfo);
FreeCAInformation(&g_CAInfo);
if(fOleInit)
CoUninitialize();
fResult=FALSE;
goto CommonReturn;
TRACE_ERROR(InitErr);
SET_ERROR_VAR(OleErr, hr);
}
//--------------------------------------------------------------------
//
// Verify if the user is a member of the BUILTIN\Administrators group
//
//--------------------------------------------------------------------
BOOL WINAPI IsUserInLocalAdminGroup()
{
BOOL bIsMember=FALSE;
SID_IDENTIFIER_AUTHORITY siaNtAuthority=SECURITY_NT_AUTHORITY;
HANDLE hThread=NULL; //no need to close
SID * psidLocalAdmins=NULL;
HANDLE hToken=NULL;
hThread=GetCurrentThread();
if(NULL == hThread)
goto error;
//we want to check with the impersonation token
if(!OpenThreadToken(hThread,
TOKEN_IMPERSONATE | TOKEN_QUERY,
FALSE,
&hToken))
goto error;
// get the well-known SID
if (!AllocateAndInitializeSid(&siaNtAuthority, 2,
SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0, (void **)&psidLocalAdmins))
goto error;
// check for membership
if (!CheckTokenMembership(hToken, psidLocalAdmins, &bIsMember))
{
bIsMember=FALSE;
goto error;
}
error:
if(hToken)
{
CloseHandle(hToken);
}
if (NULL!=psidLocalAdmins)
{
FreeSid(psidLocalAdmins);
}
return bIsMember;
}
//-----------------------------------------------------------------------------------
//
// CEPPasswordAllowALL
//
// Detect if the registry to allow password to everyone is enabled for
// standalone CA ONLY.
//
//------------------------------------------------------------------------------------
BOOL WINAPI CEPPasswordAllowALL()
{
BOOL fAllowALL=FALSE;
DWORD cbData=0;
DWORD dwData=0;
DWORD dwType=0;
HKEY hKey=NULL;
if(ERROR_SUCCESS == RegOpenKeyExU(
HKEY_LOCAL_MACHINE,
MSCEP_LOCATION,
0,
KEY_READ,
&hKey))
{
cbData=sizeof(dwData);
if(ERROR_SUCCESS == RegQueryValueExU(
hKey,
MSCEP_KEY_ALLOW_ALL,
NULL,
&dwType,
(BYTE *)&dwData,
&cbData))
{
if (REG_DWORD == dwType)
{
if(0 != dwData)
{
fAllowALL=TRUE;
}
}
}
}
if(hKey)
RegCloseKey(hKey);
return fAllowALL;
}
//-----------------------------------------------------------------------------------
//
// GetExtensionVersion.
//
// IIS load/initialization code.
//
//------------------------------------------------------------------------------------
DWORD WINAPI HttpExtensionProc(EXTENSION_CONTROL_BLOCK *pECB)
{
DWORD dwHttp = HSE_STATUS_ERROR;
LPSTR pszTagValue=NULL;
LPSTR pszMsgValue=NULL;
DWORD dwOpType = 0;
DWORD cbData=0;
DWORD cbFree=0;
CHAR szBuff[1024];
DWORD cbBuff;
LPSTR pszContentType=NULL;
DWORD dwException=0;
BOOL f401Response=FALSE;
ULARGE_INTEGER ftTime;
HANDLE hThread=NULL; //no need to close
BYTE *pbData=NULL;
HANDLE hToken=NULL;
//we use the try{}except here to prevent malicous requests
__try {
EnterCriticalSection(&CriticalSec);
if(NULL==pECB)
goto InvalidArgErr;
if(NULL==(pECB->lpszQueryString))
goto InvalidArgErr;
//user are asking for the CEP information/password
if(0 == strlen(pECB->lpszQueryString))
{
pszContentType=CONTENT_TYPE_HTML;
if(g_RAInfo.fPassword)
{
if(IsAnonymousAccess(pECB))
{
//LogSCEPEvent(0, FALSE, S_OK, EVENT_MSCEP_NO_PASSWORD_ANONYMOUS, 1, g_pwszComputerName);
f401Response=TRUE;
}
else
{
if(g_CAInfo.fEnterpriseCA)
{
//we want to check with the impersonation token
if(S_OK != CheckACLOnCertTemplate(TRUE, g_CAInfo.bstrDSName, wszCERTTYPE_IPSEC_INTERMEDIATE_OFFLINE))
{
LogSCEPEvent(0, FALSE, S_OK, EVENT_MSCEP_NO_PASSWORD_TEMPLATE, 1, g_pwszComputerName);
//return HTML error messages
if(!OperationDisplayAccessHTML(&pbData, &cbData))
goto OperationErr;
if(NULL == pbData)
goto OperationErr;
}
}
else
{
if(!CEPPasswordAllowALL())
{
if(FALSE == IsUserInLocalAdminGroup())
{
LogSCEPEvent(0, FALSE, S_OK, EVENT_MSCEP_NO_PASSWORD_STANDALONE, 1, g_pwszComputerName);
//return HTML error messages
if(!OperationDisplayAccessHTML(&pbData, &cbData))
goto OperationErr;
if(NULL == pbData)
goto OperationErr;
}
}
}
}
}
if((FALSE==f401Response) && (NULL==pbData))
{
if(!OperationGetDisplayInfoForCEP(g_CAInfo.pwszCAHash,
g_CAInfo.hProv,
g_RAInfo.fPassword,
&pbData,
&cbData))
goto OperationErr;
}
}
else
{
hThread=GetCurrentThread();
if(NULL != hThread)
{
if(OpenThreadToken(hThread,
TOKEN_IMPERSONATE | TOKEN_QUERY,
FALSE,
&hToken))
{
if(hToken)
{
//no need to check for return here. If this failed, just go on
RevertToSelf();
}
}
}
//get the operation
if(NULL==(pszTagValue=GetTagValue(pECB->lpszQueryString, GET_TAG_OP)))
{
LogSCEPEvent(0, FALSE, S_OK, EVENT_MSCEP_NO_OPERATION, 1, g_pwszComputerName);
goto InvalidArgErr;
}
if(strlen(pszTagValue) > strlen(GET_OP_CA))
{
if(0==_strnicmp(pszTagValue, GET_OP_CA, strlen(GET_OP_CA)))
{
dwOpType = OPERATION_GET_CACERT;
pszTagValue += strlen(GET_OP_CA);
}
}
if( 0 == dwOpType)
{
if(strlen(pszTagValue) > strlen(GET_OP_PKI))
{
if(0==_strnicmp(pszTagValue, GET_OP_PKI, strlen(GET_OP_PKI)))
{
dwOpType = OPERATION_GET_PKI;
pszTagValue += strlen(GET_OP_PKI);
}
}
}
if(0 == dwOpType)
{
LogSCEPEvent(0, FALSE, S_OK, EVENT_MSCEP_NO_OPERATION, 1, g_pwszComputerName);
goto InvalidArgErr;
}
//get the message value
if(NULL==(pszMsgValue=GetTagValue(pszTagValue, GET_TAG_MSG)))
{
LogSCEPEvent(0, FALSE, S_OK, EVENT_MSCEP_NO_MESSAGE, 1, g_pwszComputerName);
goto InvalidArgErr;
}
//check if the RA certificates are close to expire
GetSystemTimeAsFileTime((LPFILETIME)&ftTime);
if(ftTime.QuadPart >= g_ftRAExpiration.QuadPart)
{
//RA Certificate has expired
LogSCEPEvent(0, FALSE, S_OK, EVENT_SCEP_RA_EXPIRE, 1, g_pwszComputerName);
}
else
{
if(ftTime.QuadPart >= g_ftRACloseToExpire.QuadPart)
{
if( (0 == g_ftRAWarn.QuadPart) || (ftTime.QuadPart >= g_ftRAWarn.QuadPart))
{
//RA Certificate is close to expire
LogSCEPEvent(0, FALSE, S_OK, EVENT_SCEP_RA_CLOSE_TO_EXPIRE, 1, g_pwszComputerName);
//only give out an warning once an hour
g_ftRAWarn.QuadPart = ftTime.QuadPart + Int32x32To64(FILETIME_TICKS_PER_SECOND, OVERLAP_ONE_HOUR);
}
}
}
//get the return blob
switch(dwOpType)
{
case OPERATION_GET_CACERT:
if(!OperationGetCACert(g_HCACertStore,
pszMsgValue,
&pbData,
&cbData))
{
LogSCEPEvent(0, TRUE, HRESULT_FROM_WIN32(GetLastError()), EVENT_MSCEP_GET_CA_CERT_FAILED, 1, g_pwszComputerName);
goto OperationErr;
}
pszContentType = CONTENT_TYPE_CA_RA;
break;
case OPERATION_GET_PKI:
if(!OperationGetPKI(
&g_RAInfo,
&g_CAInfo,
pszMsgValue,
&pbData,
&cbData))
goto OperationErr;
pszContentType = CONTENT_TYPE_PKI;
break;
default:
goto InvalidArgErr;
break;
}
}
if(f401Response)
{
if(!(pECB->ServerSupportFunction(pECB->ConnID,HSE_REQ_SEND_RESPONSE_HEADER,
ACCESS_MESSAGE,
NULL,
NULL)))
{
LogSCEPEvent(0, TRUE, HRESULT_FROM_WIN32(GetLastError()), EVENT_SCEP_SERVER_SUPPORT, 1, g_pwszComputerName);
goto WriteErr;
}
dwHttp = HSE_STATUS_ERROR;
}
else
{
//write the header and the real data
pECB->dwHttpStatusCode = 200;
// write headers
sprintf(szBuff, "Content-Length: %d\r\nContent-Type: %hs\r\n\r\n", cbData, pszContentType);
cbBuff = strlen(szBuff);
if(!(pECB->ServerSupportFunction(pECB->ConnID, HSE_REQ_SEND_RESPONSE_HEADER, NULL, &cbBuff, (LPDWORD)szBuff)))
{
LogSCEPEvent(0, TRUE, HRESULT_FROM_WIN32(GetLastError()), EVENT_SCEP_SERVER_SUPPORT, 1, g_pwszComputerName);
goto WriteErr;
}
// write users data
cbFree=cbData;
if(!(pECB->WriteClient(pECB->ConnID, pbData, &cbData, HSE_IO_SYNC)))
{
LogSCEPEvent(0, TRUE, HRESULT_FROM_WIN32(GetLastError()), EVENT_SCEP_WRITE_DATA, 1, g_pwszComputerName);
goto WriteErr;
}
dwHttp = HSE_STATUS_SUCCESS;
}
} __except(EXCEPTION_EXECUTE_HANDLER)
{
dwException = GetExceptionCode();
goto ExceptionErr;
}
CommonReturn:
if(pbData)
{
if(cbFree)
{
SecureZeroMemory(pbData, cbFree);
}
free(pbData);
}
if(hToken)
{
SetThreadToken(&hThread, hToken);
CloseHandle(hToken);
}
LeaveCriticalSection(&CriticalSec);
return dwHttp;
ErrorReturn:
dwHttp = HSE_STATUS_ERROR;
goto CommonReturn;
SET_ERROR(InvalidArgErr, E_INVALIDARG);
TRACE_ERROR(OperationErr);
TRACE_ERROR(WriteErr);
SET_ERROR_VAR(ExceptionErr, dwException);
}
//-----------------------------------------------------------------------------------
//
// TerminateExtension.
//
// IIS unload/cleanup code
//
//------------------------------------------------------------------------------------
BOOL WINAPI TerminateExtension(DWORD dwFlags)
{
if(g_fRelease)
{
LogSCEPEvent(0, FALSE, S_OK, EVENT_MSCEP_UNLOADED, 0);
return TRUE;
}
EnterCriticalSection(&CriticalSec);
//retest in the case of lock: the second thread has passed the 1st test
//and was waiting for the criticcal section
if(g_fRelease)
{
LogSCEPEvent(0, FALSE, S_OK, EVENT_MSCEP_UNLOADED, 0);
LeaveCriticalSection(&CriticalSec);
return TRUE;
}
if(g_pwszComputerName)
{
free(g_pwszComputerName);
g_pwszComputerName=NULL;
}
ReleaseRequestTable();
ReleasePasswordTable();
ReleaseHashTable();
if(g_HCACertStore)
{
CertCloseStore(g_HCACertStore, 0);
g_HCACertStore=NULL;
}
FreeRAInformation(&g_RAInfo);
FreeCAInformation(&g_CAInfo);
//only if fInit is TRUE, that we have an outstanding CoInitialize() call
if(g_fInit)
CoUninitialize();
g_fRelease=TRUE;
LogSCEPEvent(0, FALSE, S_OK, EVENT_MSCEP_UNLOADED, 0);
LeaveCriticalSection(&CriticalSec);
//we always allow unload
return TRUE;
}
//***********************************************************************************
//
// Helper functions for the password table
//
//***********************************************************************************
//-----------------------------------------------------------------------------------
//
// CEPObtainPassword
//
//------------------------------------------------------------------------------------
BOOL WINAPI CEPObtainPassword(HCRYPTPROV hProv,
LPWSTR *ppwszPassword)
{
BYTE pbData[CEP_PASSWORD_LENGTH];
BOOL fResult=FALSE;
memset(pbData, 0, CEP_PASSWORD_LENGTH);
if(!CryptGenRandom(hProv, CEP_PASSWORD_LENGTH, pbData))
return FALSE;
fResult=ConvertByteToWstr(pbData, CEP_PASSWORD_LENGTH, ppwszPassword, FALSE);
SecureZeroMemory(pbData, CEP_PASSWORD_LENGTH);
return fResult;
}
//***********************************************************************************
//
// Helper functions for ISAPI dll entry points
//
//***********************************************************************************
//-----------------------------------------------------------------------------------
//
// IsAnonymousAccess
//
//------------------------------------------------------------------------------------
BOOL WINAPI IsAnonymousAccess(EXTENSION_CONTROL_BLOCK *pECB)
{
BOOL fAccess=TRUE;
DWORD dwSize=0;
BYTE *pbData=NULL;
pECB->GetServerVariable(pECB->ConnID,
"REMOTE_USER",
NULL,
&dwSize);
if(0==dwSize)
goto CLEANUP;
pbData=(BYTE *)malloc(dwSize);
if(NULL==pbData)
goto CLEANUP;
if(!(pECB->GetServerVariable(pECB->ConnID,
"REMOTE_USER",
pbData,
&dwSize)))
goto CLEANUP;
if(0 == strlen((LPSTR)pbData))
goto CLEANUP;
fAccess=FALSE;
CLEANUP:
if(pbData)
free(pbData);
return fAccess;
}
//-----------------------------------------------------------------------------------
//
// CheckACLOnCertTemplate
//
//------------------------------------------------------------------------------------
HRESULT WINAPI CheckACLOnCertTemplate(BOOL fSelf, LPWSTR pwszCAName, LPWSTR pwszCertType)
{
HRESULT hr=S_OK;
HANDLE hThread=NULL; //no need to close
DWORD dwIndex=0;
HCAINFO hCAInfo=NULL;
LPWSTR *ppwszList=NULL;
HCERTTYPE hCertType=NULL;
HANDLE hToken=NULL;
if((NULL == pwszCAName) || (NULL == pwszCertType))
return E_INVALIDARG;
//first of all, we need to revert to ourselves if
//we are under impersonation and delegation is not
//supported by default, thus we can not access the DS.
//we are ganranteed to have a thread token under impersonation
hThread=GetCurrentThread();
if(NULL == hThread)
return HRESULT_FROM_WIN32(GetLastError());
if(OpenThreadToken(hThread,
TOKEN_IMPERSONATE | TOKEN_QUERY,
FALSE,
&hToken))
{
if(hToken)
{
RevertToSelf();
}
}
if(S_OK != (hr=CAFindCertTypeByName(pwszCertType,
NULL,
CT_ENUM_MACHINE_TYPES | CT_FLAG_NO_CACHE_LOOKUP | CT_FIND_LOCAL_SYSTEM,
&hCertType)))
goto error;
//fSelf means we want to check with the impersonation token
if(TRUE == fSelf)
{
if(S_OK != (hr=CACertTypeAccessCheck(hCertType, hToken)))
goto error;
}
else
{
if(S_OK != (hr=CACertTypeAccessCheck(hCertType, NULL)))
goto error;
}
if(S_OK != (hr=CAFindByName(
pwszCAName,
NULL,
CA_FIND_LOCAL_SYSTEM,
&hCAInfo)))
goto error;
if(S_OK != (hr= CAGetCAProperty(
hCAInfo,
CA_PROP_CERT_TYPES,
&ppwszList)))
goto error;
if((NULL == ppwszList) || (NULL == ppwszList[0]))
{
hr=E_FAIL;
goto error;
}
while(ppwszList[dwIndex])
{
if(0 == _wcsicmp(pwszCertType, ppwszList[dwIndex]))
{
break;
}
dwIndex++;
}
if(NULL == ppwszList[dwIndex])
{
hr=E_FAIL;
goto error;
}
hr=S_OK;
error:
if(ppwszList)
CAFreeCAProperty(hCAInfo, ppwszList);
if(hCAInfo)
CACloseCA(hCAInfo);
if(hCertType)
CACloseCertType(hCertType);
if(hToken)
{
SetThreadToken(&hThread, hToken);
CloseHandle(hToken);
}
return hr;
}
//-----------------------------------------------------------------------------------
//
// OperationDisplayAccessHTML
//
//------------------------------------------------------------------------------------
BOOL WINAPI OperationDisplayAccessHTML(BYTE **ppbData, DWORD *pcbData)
{
return LoadIDToTemplate(IDS_ACCESS_DENIED,
ppbData,
pcbData);
}
//-----------------------------------------------------------------------------------
//
// OperationGetDisplayInfoForCEP
//
//------------------------------------------------------------------------------------
BOOL WINAPI OperationGetDisplayInfoForCEP(LPWSTR pwszCAHash,
HCRYPTPROV hProv,
BOOL fPassword,
BYTE **ppbData,
DWORD *pcbData)
{
BOOL fResult=FALSE;
HRESULT hr=E_FAIL;
UINT idsMsg=IDS_TOO_MANY_PASSWORD;
LPWSTR pwszPassword=NULL;
LPWSTR pwszText=NULL;
if(fPassword)
{
if(!CEPObtainPassword(hProv, &pwszPassword))
{
idsMsg=IDS_FAIL_TO_GET_PASSWORD;
goto InfoWithLastErrorReturn;
}
if(!CEPAddPasswordToTable(pwszPassword))
{
if(CRYPT_E_NO_MATCH == GetLastError())
{
idsMsg=IDS_TOO_MANY_PASSWORD;
goto InfoWithIDReturn;
}
else
{
idsMsg=IDS_FAIL_TO_ADD_PASSWORD;
goto InfoWithLastErrorReturn;
}
}
if(!FormatMessageUnicode(&pwszText, IDS_CEP_INFO_WITH_PASSWORD, pwszCAHash,
pwszPassword, g_dwPasswordValidity))
goto TraceErr;
}
else
{
if(!FormatMessageUnicode(&pwszText, IDS_CEP_INFO_NO_PASSWORD, pwszCAHash))
goto TraceErr;
}
fResult=LoadWZToTemplate(pwszText, ppbData, pcbData);
CommonReturn:
if(pwszText)
{
SecureZeroMemory(pwszText, sizeof(WCHAR) * wcslen(pwszText));
LocalFree((HLOCAL)pwszText);
}
if(pwszPassword)
{
SecureZeroMemory(pwszPassword, sizeof(WCHAR) * wcslen(pwszPassword));
free(pwszPassword);
}
return fResult;
InfoWithIDReturn:
fResult=LoadIDToTemplate(idsMsg, ppbData, pcbData);
goto CommonReturn;
InfoWithLastErrorReturn:
hr=HRESULT_FROM_WIN32(GetLastError());
fResult=LoadIDAndHRToTempalte(idsMsg, hr, ppbData, pcbData);
goto CommonReturn;
ErrorReturn:
fResult=FALSE;
goto CommonReturn;
TRACE_ERROR(TraceErr);
}
//-----------------------------------------------------------------------------------
//
// LoadIDToTemplate
//
//------------------------------------------------------------------------------------
BOOL WINAPI LoadIDToTemplate(UINT idsMsg,
BYTE **ppbData,
DWORD *pcbData)
{
BOOL fResult=FALSE;
WCHAR wsz[MAX_STRING_SIZE];
if(!LoadStringU(g_hMSCEPModule, idsMsg, wsz, MAX_STRING_SIZE))
return FALSE;
return LoadWZToTemplate(wsz, ppbData, pcbData);
}
//-----------------------------------------------------------------------------------
//
// LoadIDToTemplate
//
//------------------------------------------------------------------------------------
BOOL WINAPI LoadIDAndHRToTempalte(UINT idsMsg,
HRESULT hr,
BYTE **ppbData,
DWORD *pcbData)
{
BOOL fResult=FALSE;
WCHAR wszUnknownError[50];
LPWSTR pwszErrorMsg=NULL;
LPWSTR pwszText=NULL;
if(!FAILED(hr))
hr=E_FAIL;
//using W version because this is a NT5 only function call
if(FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
hr,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPWSTR) &pwszErrorMsg,
0,
NULL))
{
if(!FormatMessageUnicode(&pwszText, idsMsg, pwszErrorMsg))
goto TraceErr;
}
else
{
if(!LoadStringU(g_hMSCEPModule, IDS_ERROR_UNKONWN, wszUnknownError, 50))
goto TraceErr;
if(!FormatMessageUnicode(&pwszText, idsMsg, wszUnknownError))
goto TraceErr;
}
fResult=LoadWZToTemplate(pwszText, ppbData, pcbData);
CommonReturn:
if(pwszText)
LocalFree((HLOCAL)pwszText);
if(pwszErrorMsg)
LocalFree((HLOCAL)pwszErrorMsg);
return fResult;
ErrorReturn:
fResult=FALSE;
goto CommonReturn;
TRACE_ERROR(TraceErr);
}
//-----------------------------------------------------------------------------------
//
// LoadWZToTemplate
//
//------------------------------------------------------------------------------------
BOOL WINAPI LoadWZToTemplate(LPWSTR pwsz,
BYTE **ppbData,
DWORD *pcbData)
{
BOOL fResult=FALSE;
LPWSTR pwszHTML=NULL;
if(!FormatMessageUnicode(&pwszHTML, IDS_HTML_TEMPLATE, pwsz))
goto TraceErr;
fResult=CopyWZToBuffer(pwszHTML, ppbData, pcbData);
CommonReturn:
if(pwszHTML)
LocalFree((HLOCAL)pwszHTML);
return fResult;
ErrorReturn:
fResult=FALSE;
goto CommonReturn;
TRACE_ERROR(TraceErr);
}
//-----------------------------------------------------------------------------------
//
// CopyWZToBuffer
//
//------------------------------------------------------------------------------------
BOOL WINAPI CopyWZToBuffer( LPWSTR pwszData,
BYTE **ppbData,
DWORD *pcbData)
{
BOOL fResult=FALSE;
DWORD dwSize=0;
*ppbData=NULL;
*pcbData=0;
dwSize=sizeof(WCHAR) * (wcslen(pwszData) + 1);
*ppbData=(BYTE *)malloc(dwSize);
if(NULL==ppbData)
goto MemoryErr;
memcpy(*ppbData, pwszData, dwSize);
*pcbData=dwSize;
fResult=TRUE;
CommonReturn:
return fResult;
ErrorReturn:
fResult=FALSE;
goto CommonReturn;
SET_ERROR(MemoryErr, E_OUTOFMEMORY);
}
//------------------------------------------------------------------------
// Convert the byte to its Hex presentation.
//
// Precondition: byte is less than 15
//
//------------------------------------------------------------------------
ULONG ByteToHex(BYTE byte, LPWSTR wszZero, LPWSTR wszA)
{
ULONG uValue=0;
if(((ULONG)byte)<=9)
{
uValue=((ULONG)byte)+ULONG(*wszZero);
}
else
{
uValue=(ULONG)byte-10+ULONG(*wszA);
}
return uValue;
}
//--------------------------------------------------------------------------
//
// ConvertByteToWstr
//
// If fSpace is TRUE, we add a space every 2 bytes.
//--------------------------------------------------------------------------
BOOL WINAPI ConvertByteToWstr(BYTE *pbData,
DWORD cbData,
LPWSTR *ppwsz,
BOOL fSpace)
{
BOOL fResult=FALSE;
DWORD dwBufferSize=0;
DWORD dwBufferIndex=0;
DWORD dwEncodedIndex=0;
LPWSTR pwszSpace=L" ";
LPWSTR pwszZero=L"0";
LPWSTR pwszA=L"A";
if(!pbData || !ppwsz)
goto InvalidArgErr;
//calculate the memory needed, in bytes
//we need 3 wchars per byte, along with the NULL terminator
dwBufferSize=sizeof(WCHAR)*(cbData*3+1);
*ppwsz=(LPWSTR)malloc(dwBufferSize);
if(NULL==(*ppwsz))
goto MemoryErr;
dwBufferIndex=0;
//format the wchar buffer one byte at a time
for(dwEncodedIndex=0; dwEncodedIndex<cbData; dwEncodedIndex++)
{
//copy the space between every four bytes. Skip for the 1st byte
if(fSpace)
{
if((0!=dwEncodedIndex) && (0==(dwEncodedIndex % 4 )))
{
(*ppwsz)[dwBufferIndex]=pwszSpace[0];
dwBufferIndex++;
}
}
//format the higher 4 bits
(*ppwsz)[dwBufferIndex]=(WCHAR)ByteToHex(
(pbData[dwEncodedIndex]&UPPER_BITS)>>4,
pwszZero, pwszA);
dwBufferIndex++;
//format the lower 4 bits
(*ppwsz)[dwBufferIndex]=(WCHAR)ByteToHex(
pbData[dwEncodedIndex]&LOWER_BITS,
pwszZero, pwszA);
dwBufferIndex++;
}
//add the NULL terminator to the string
(*ppwsz)[dwBufferIndex]=L'\0';
fResult=TRUE;
CommonReturn:
return fResult;
ErrorReturn:
fResult=FALSE;
goto CommonReturn;
SET_ERROR(MemoryErr, E_OUTOFMEMORY);
SET_ERROR(InvalidArgErr, E_INVALIDARG);
}
//--------------------------------------------------------------------------
//
// FormatMessageUnicode
//
//--------------------------------------------------------------------------
BOOL WINAPI FormatMessageUnicode(LPWSTR *ppwszFormat,UINT ids,...)
{
// get format string from resources
WCHAR wszFormat[1000];
va_list argList;
DWORD cbMsg=0;
BOOL fResult=FALSE;
HRESULT hr=S_OK;
if(NULL == ppwszFormat)
goto InvalidArgErr;
if(!LoadStringU(g_hMSCEPModule, ids, wszFormat, 1000))
goto LoadStringError;
// format message into requested buffer
va_start(argList, ids);
cbMsg = FormatMessageU(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
wszFormat,
0, // dwMessageId
0, // dwLanguageId
(LPWSTR) (ppwszFormat),
0, // minimum size to allocate
&argList);
va_end(argList);
if(!cbMsg)
goto FormatMessageError;
fResult=TRUE;
CommonReturn:
return fResult;
ErrorReturn:
fResult=FALSE;
goto CommonReturn;
TRACE_ERROR(LoadStringError);
TRACE_ERROR(FormatMessageError);
SET_ERROR(InvalidArgErr, E_INVALIDARG);
}
//--------------------------------------------------------------------------
// Name: LogSCEPEvent
//
// Description: This function registers an event in the event log of the
// local machine. Takes an optional argument list.
//
//--------------------------------------------------------------------------
void WINAPI LogSCEPEvent(IN DWORD dwLogLevel,
IN BOOL fError,
IN HRESULT hr,
IN DWORD dwEventId,
IN DWORD dwParamCount,
...
)
{
WORD dwEventType = 0;
LPWSTR awszStrings[PENDING_ALLOC_SIZE + 2];
WORD cStrings = 0;
LPWSTR wszString = NULL;
WCHAR wszMsg[MAX_STRING_SIZE];
DWORD dwIndex=0;
LPWSTR wszHR=NULL;
va_list ArgList;
if(NULL == g_hEventSource)
return;
//copy the variable strings if present
va_start(ArgList, dwParamCount);
for(dwIndex=0; dwIndex < dwParamCount; dwIndex++)
{
wszString = va_arg(ArgList, LPWSTR);
if(wszString)
awszStrings[cStrings++] = wszString;
if(cStrings >= PENDING_ALLOC_SIZE)
{
break;
}
}
va_end(ArgList);
//copy the hr error code
if(fError)
{
if(S_OK == hr)
hr=E_FAIL;
wsprintfW(wszMsg, L"0x%lx", hr);
awszStrings[cStrings++] = wszMsg;
if(0 != FormatMessageW(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
hr,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(WCHAR *)&wszHR,
0,
NULL))
{
if(wszHR)
{
awszStrings[cStrings++] = wszHR;
}
else
{
awszStrings[cStrings++]=L" ";
}
}
else
{
awszStrings[cStrings++]=L" ";
}
}
switch(dwEventId >> 30)
{
case 0:
dwEventType = EVENTLOG_SUCCESS;
break;
case 1:
dwEventType = EVENTLOG_INFORMATION_TYPE;
break;
case 2:
dwEventType = EVENTLOG_WARNING_TYPE;
break;
case 3:
dwEventType = EVENTLOG_ERROR_TYPE;
break;
}
ReportEventW(g_hEventSource, // handle of event source
dwEventType, // event type
0, // event category
dwEventId, // event ID
NULL, // current user's SID
cStrings, // strings in lpszStrings
0, // no bytes of raw data
(LPCWSTR*)awszStrings, // array of error strings
NULL // no raw data
);
if(wszHR)
LocalFree(wszHR);
return;
}