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.
 
 
 
 
 
 

797 lines
18 KiB

/**********************************************************************/
/** Microsoft Passport **/
/** Copyright(c) Microsoft Corporation, 1999 - 2001 **/
/**********************************************************************/
/*
PassportCrypt.cpp
FILE HISTORY:
*/
// PassportCrypt.cpp : Implementation of CCrypt
#include "stdafx.h"
#include "Passport.h"
#include "PassportCrypt.h"
#include <time.h>
/* moved into passport.idl -- so consumer of the COM API can see it
// max blocks + 10 should be multiples of 3 for simplicity
#define ENC_MAX_SIZE 2045
// I don't trust the compiler... (((2045+10)*4)/3)+9 = 2749 * sizeof(wchar)
#define DEC_MAX_SIZE 5498
*/
//===========================================================================
//
// CCrypt
//
CCrypt::CCrypt() : m_crypt(NULL), m_szSiteName(NULL), m_szHostName(NULL)
{
m_pUnkMarshaler = NULL;
m_keyVersion = 0;
CRegistryConfig* crc = g_config->checkoutRegistryConfig();
if( crc )
{
m_keyVersion = crc->getCurrentCryptVersion();
crc->getCrypt(m_keyVersion, &m_validUntil);
crc->Release();
}
}
/////////////////////////////////////////////////////////////////////////////
// CCrypt
//===========================================================================
//
// InterfaceSupportsErrorInfo
//
STDMETHODIMP CCrypt::InterfaceSupportsErrorInfo(REFIID riid)
{
static const IID* arr[] =
{
&IID_IPassportCrypt,
};
for (int i=0;i<sizeof(arr)/sizeof(arr[0]);i++)
{
if (InlineIsEqualGUID(*arr[i],riid))
return S_OK;
}
return S_FALSE;
}
//===========================================================================
//
// OnStartPage
//
STDMETHODIMP CCrypt::OnStartPage(IUnknown* piUnk)
{
BOOL bHasPort;
DWORD dwServerNameLen;
HRESULT hr = S_OK;
BOOL bVariantInited = FALSE;
// param needs to cleanup
IRequestPtr piRequest ;
IRequestDictionaryPtr piServerVariables ;
_variant_t vtItemName;
_variant_t vtServerName;
_variant_t vtServerPort;
_variant_t vtHTTPS;
// WCHAR szServerName = NULL;
// CHAR* szServerName_A = NULL;
CRegistryConfig* crc = NULL;
if(!piUnk)
{
hr = E_POINTER;
goto exit;
}
if (!g_config->isValid()) // Guarantees config is non-null
{
AtlReportError(CLSID_Manager, PP_E_NOT_CONFIGUREDSTR,
IID_IPassportManager, PP_E_NOT_CONFIGURED);
hr = PP_E_NOT_CONFIGURED;
}
try
{
// Get Request Object Pointer
piRequest = ((IScriptingContextPtr)piUnk)->Request;
//
// Use the request object to get the server name being requested
// so we can get the correct registry config. But only do this
// if we have some configured sites.
//
if(g_config->HasSites())
{
piRequest->get_ServerVariables(&piServerVariables);
vtItemName.vt = VT_BSTR;
vtItemName.bstrVal = SysAllocString(L"SERVER_NAME");
if (NULL == vtItemName.bstrVal)
{
hr = E_OUTOFMEMORY;
goto exit;
}
piServerVariables->get_Item(vtItemName, &vtServerName);
if(vtServerName.vt != VT_BSTR)
VariantChangeType(&vtServerName, &vtServerName, 0, VT_BSTR);
VariantClear(&vtItemName);
vtItemName.vt = VT_BSTR;
vtItemName.bstrVal = SysAllocString(L"SERVER_PORT");
if (NULL == vtItemName.bstrVal)
{
hr = E_OUTOFMEMORY;
goto exit;
}
piServerVariables->get_Item(vtItemName, &vtServerPort);
if(vtServerPort.vt != VT_BSTR)
VariantChangeType(&vtServerPort, &vtServerPort, 0, VT_BSTR);
VariantClear(&vtItemName);
vtItemName.vt = VT_BSTR;
vtItemName.bstrVal = SysAllocString(L"HTTPS");
if (NULL == vtItemName.bstrVal)
{
hr = E_OUTOFMEMORY;
goto exit;
}
hr = piServerVariables->get_Item(vtItemName, &vtHTTPS);
if(vtHTTPS.vt != VT_BSTR)
VariantChangeType(&vtHTTPS, &vtHTTPS, 0, VT_BSTR);
// If not default port, append ":port" to server name.
bHasPort = (lstrcmpiW(L"off", vtHTTPS.bstrVal) == 0 &&
lstrcmpW(L"80", vtServerPort.bstrVal) != 0) ||
(lstrcmpiW(L"on", vtHTTPS.bstrVal) == 0 &&
lstrcmpW(L"443", vtServerPort.bstrVal) != 0);
dwServerNameLen = bHasPort ?
lstrlenW(vtServerName.bstrVal) + lstrlenW(vtServerPort.bstrVal) + 2 :
lstrlenW(vtServerName.bstrVal) + 1;
m_szHostName = new CHAR[dwServerNameLen];
if( !m_szHostName )
{
hr = E_OUTOFMEMORY;
goto exit;
}
WideCharToMultiByte(CP_ACP, 0, vtServerName.bstrVal, -1,
m_szHostName, dwServerNameLen,
NULL,
NULL);
if(bHasPort)
{
USES_CONVERSION;
lstrcatA(m_szHostName, ":");
lstrcatA(m_szHostName, W2A(vtServerPort.bstrVal));
}
crc = g_config->checkoutRegistryConfig(m_szHostName);
}
else
{
crc = g_config->checkoutRegistryConfig();
}
m_keyVersion = 0;
if (crc)
{
m_keyVersion = crc->getCurrentCryptVersion();
crc->getCrypt(m_keyVersion,&m_validUntil);
}
}
catch(...)
{
hr = S_OK;
}
exit:
if( crc )
crc->Release();
return hr;
}
//===========================================================================
//
// Encrypt
//
STDMETHODIMP CCrypt::Encrypt(BSTR rawData, BSTR *pEncrypted)
{
if (!rawData)
return E_INVALIDARG;
if (SysStringLen(rawData) > ENC_MAX_SIZE)
{
AtlReportError(CLSID_Crypt, L"Passport.Crypt: Data too large",
IID_IPassportCrypt, E_FAIL);
return E_FAIL;
}
if (m_crypt)
{
if (!m_crypt->Encrypt(m_keyVersion, (LPSTR)rawData, SysStringByteLen(rawData), pEncrypted))
{
AtlReportError(CLSID_Crypt,
L"Encryption failed", IID_IPassportCrypt, E_FAIL);
return E_FAIL;
}
}
else
{
CRegistryConfig* crc = ObtainCRC();
if (!crc)
{
AtlReportError(CLSID_Crypt,
L"Passport misconfigured", IID_IPassportCrypt, E_FAIL);
return E_FAIL;
}
CCoCrypt *cr = crc->getCrypt(m_keyVersion,&m_validUntil);
if (!cr)
{
AtlReportError(CLSID_Crypt,
L"No such key version", IID_IPassportCrypt, E_FAIL);
crc->Release();
return E_FAIL;
}
if (!cr->Encrypt(m_keyVersion,(LPSTR)rawData,SysStringByteLen(rawData),pEncrypted))
{
AtlReportError(CLSID_Crypt,
L"Encryption failed", IID_IPassportCrypt, E_FAIL);
crc->Release();
return E_FAIL;
}
crc->Release();
}
return S_OK;
}
//===========================================================================
//
// Decrypt
//
STDMETHODIMP CCrypt::Decrypt(BSTR rawData, BSTR *pUnencrypted)
{
if (rawData == NULL)
{
*pUnencrypted = NULL;
return S_OK;
}
if (SysStringLen(rawData) > DEC_MAX_SIZE)
{
AtlReportError(CLSID_Crypt, L"Passport.Crypt: Data too large",
IID_IPassportCrypt, E_FAIL);
return E_FAIL;
}
if (m_crypt) // Just do our job, no questions
{
if (m_crypt->Decrypt(rawData, SysStringByteLen(rawData), pUnencrypted))
{
return S_OK;
}
if(g_pAlert)
g_pAlert->report(PassportAlertInterface::WARNING_TYPE, PM_FAILED_DECRYPT);
*pUnencrypted = NULL;
return S_OK;
}
// First find the key version
int kv = CCoCrypt::getKeyVersion(rawData);
time_t vU, now;
CRegistryConfig* crc = ObtainCRC();
if (!crc)
{
AtlReportError(CLSID_Crypt,
L"Passport misconfigured", IID_IPassportCrypt, PP_E_NOT_CONFIGURED);
return PP_E_NOT_CONFIGURED;
}
CCoCrypt *cr = crc->getCrypt(kv, &vU);
time(&now);
if ((vU != 0 && now > vU) || cr == NULL)
{
*pUnencrypted = NULL;
if(g_pAlert)
g_pAlert->report(PassportAlertInterface::WARNING_TYPE, PM_FAILED_DECRYPT);
crc->Release();
return S_OK;
}
if (cr->Decrypt(rawData, SysStringByteLen(rawData), pUnencrypted))
{
crc->Release();
return S_OK;
}
if(g_pAlert)
g_pAlert->report(PassportAlertInterface::WARNING_TYPE, PM_FAILED_DECRYPT);
crc->Release();
*pUnencrypted = NULL;
return S_OK;
}
//===========================================================================
//
// get_keyVersion
//
STDMETHODIMP CCrypt::get_keyVersion(int *pVal)
{
*pVal = m_keyVersion;
return S_OK;
}
//===========================================================================
//
// put_keyVersion
//
STDMETHODIMP CCrypt::put_keyVersion(int newVal)
{
m_keyVersion = newVal;
if (m_crypt)
{
delete m_crypt;
m_crypt = NULL;
}
return S_OK;
}
//===========================================================================
//
// vget_IsValid
//
STDMETHODIMP CCrypt::get_IsValid(VARIANT_BOOL *pVal)
{
// fix 6695 PassportCrypt.IsValid is inconsistent to end users.
// *pVal = (m_crypt != NULL) ? VARIANT_TRUE : VARIANT_FALSE;
*pVal = (g_config->isValid()) ? VARIANT_TRUE : VARIANT_FALSE;
return S_OK;
}
//===========================================================================
//
// put_keyMaterial
//
STDMETHODIMP CCrypt::put_keyMaterial(BSTR newVal)
{
CCoCrypt *pcccTemp = new CCoCrypt();
if (pcccTemp == NULL)
{
return E_OUTOFMEMORY;
}
if (m_crypt)
{
delete m_crypt;
}
m_crypt = pcccTemp;
m_crypt->setKeyMaterial(newVal);
return S_OK;
}
//===========================================================================
//
// Compress
//
STDMETHODIMP CCrypt::Compress(
BSTR bstrIn,
BSTR* pbstrCompressed
)
{
HRESULT hr;
UINT nInLen;
//
// Check inputs.
//
if(bstrIn == NULL ||
pbstrCompressed == NULL)
{
hr = E_POINTER;
goto Cleanup;
}
//
// nInLen does not include the terminating NULL.
//
nInLen = SysStringLen(bstrIn);
//
// Always want to allocate an even number of bytes
// so that the corresponding decompress does not
// lose characters.
//
if(nInLen & 0x1)
nInLen++;
//
// Allocate a BSTR of the correct length.
//
*pbstrCompressed = SysAllocStringByteLen(NULL, nInLen);
if(*pbstrCompressed == NULL)
{
hr = E_OUTOFMEMORY;
goto Cleanup;
}
//
// We allocated a total of nInLen + 2 bytes. Zero it out.
//
memset(*pbstrCompressed, 0, nInLen + sizeof(OLECHAR));
//
// Convert to multibyte.
//
if (0 == WideCharToMultiByte(CP_ACP, 0, bstrIn, nInLen, (LPSTR)*pbstrCompressed,
nInLen + 1, // this is how many bytes were allocated by
// SysAllocStringByteLen
NULL, NULL))
{
hr = E_FAIL;
}
else
{
hr = S_OK;
}
Cleanup:
return hr;
}
//===========================================================================
//
// Decompress
//
STDMETHODIMP CCrypt::Decompress(
BSTR bstrIn,
BSTR* pbstrDecompressed
)
{
HRESULT hr;
CHAR *pch;
UINT nInLen;
if(bstrIn == NULL ||
pbstrDecompressed == NULL)
{
hr = E_POINTER;
goto Cleanup;
}
//
// nInLen is number of mbc's, and does not include the terminating NULL.
//
nInLen = SysStringByteLen(bstrIn);
//
// 13386: return NULL if 0 length
//
if (nInLen == 0)
{
*pbstrDecompressed = NULL;
hr = S_OK;
goto Cleanup;
}
pch = (CHAR*)bstrIn;
if ('\0' == pch[nInLen - 1])
{
nInLen--;
}
//
// Allocate a BSTR of the correct length.
//
*pbstrDecompressed = SysAllocStringLen(NULL, nInLen);
if(*pbstrDecompressed == NULL)
{
hr = E_OUTOFMEMORY;
goto Cleanup;
}
//
// We allocated a total of (nOutLen+1) * sizeof(OLECHAR) bytes, since
// SysAllocStringLen allocs an extra character. Zero it all out.
//
memset(*pbstrDecompressed, 0, (nInLen + 1) * sizeof(OLECHAR));
//
// Convert to wide.
//
if (0 == MultiByteToWideChar(CP_ACP, 0, (LPCSTR)bstrIn, -1, *pbstrDecompressed, nInLen + 1))
{
hr = E_FAIL;
}
else
{
hr = S_OK;
}
Cleanup:
return hr;
}
//===========================================================================
//
// put_site
//
STDMETHODIMP
CCrypt::put_site(
BSTR bstrSiteName
)
{
HRESULT hr;
int nLen;
LPSTR szNewSiteName;
CRegistryConfig* crc;
if(!bstrSiteName)
{
if(m_szSiteName)
delete [] m_szSiteName;
m_szSiteName = NULL;
}
else
{
nLen = SysStringLen(bstrSiteName) + 1;
szNewSiteName = new CHAR[nLen];
if(!szNewSiteName)
{
hr = E_OUTOFMEMORY;
goto Cleanup;
}
WideCharToMultiByte(CP_ACP, 0, bstrSiteName, -1,
szNewSiteName, nLen,
NULL,
NULL);
Cleanup();
m_szSiteName = szNewSiteName;
}
crc = ObtainCRC();
if (!crc)
{
m_keyVersion = 0;
}
else
{
m_keyVersion = crc->getCurrentCryptVersion();
crc->getCrypt(m_keyVersion,&m_validUntil);
crc->Release();
}
hr = S_OK;
Cleanup:
return hr;
}
//===========================================================================
//
// put_host
//
STDMETHODIMP
CCrypt::put_host(
BSTR bstrHostName
)
{
HRESULT hr;
int nLen;
LPSTR szNewHostName;
CRegistryConfig* crc;
if(!bstrHostName)
{
if(m_szHostName)
delete [] m_szHostName;
m_szHostName = NULL;
}
else
{
nLen = SysStringLen(bstrHostName) + 1;
szNewHostName = new CHAR[nLen];
if(!szNewHostName)
{
hr = E_OUTOFMEMORY;
goto Cleanup;
}
WideCharToMultiByte(CP_ACP, 0, bstrHostName, -1,
szNewHostName, nLen,
NULL,
NULL);
Cleanup();
m_szHostName = szNewHostName;
crc = ObtainCRC();
if (!crc)
{
m_keyVersion = 0;
}
else
{
m_keyVersion = crc->getCurrentCryptVersion();
crc->getCrypt(m_keyVersion,&m_validUntil);
crc->Release();
}
}
hr = S_OK;
Cleanup:
return hr;
}
//===========================================================================
//
// Cleanup
//
void CCrypt::Cleanup()
{
if( m_szSiteName )
{
delete [] m_szSiteName;
m_szSiteName = NULL;
}
if( m_szHostName )
{
delete [] m_szHostName;
m_szHostName = NULL;
}
}
//===========================================================================
//
// ObtainCRC
//
CRegistryConfig* CCrypt::ObtainCRC()
{
CRegistryConfig* crc = NULL;
if( m_szHostName && m_szSiteName )
{
// we are in bad state now
Cleanup();
goto exit;
}
if( m_szHostName )
crc = g_config->checkoutRegistryConfig(m_szHostName);
if( m_szSiteName )
crc = g_config->checkoutRegistryConfigBySite(m_szSiteName);
// if we still can't get crc at this moment, try the default one
if( !crc )
crc = g_config->checkoutRegistryConfig();
exit:
return crc;
}
/////////////////////////////////////////////////////////////////////////////
// IPassportService implementation
//===========================================================================
//
// Initialize
//
STDMETHODIMP CCrypt::Initialize(BSTR configfile, IServiceProvider* p)
{
HRESULT hr;
// Initialize.
if (!g_config->isValid())
{
AtlReportError(CLSID_Crypt, PP_E_NOT_CONFIGUREDSTR,
IID_IPassportService, PP_E_NOT_CONFIGURED);
hr = PP_E_NOT_CONFIGURED;
goto Cleanup;
}
hr = S_OK;
Cleanup:
return hr;
}
//===========================================================================
//
// Shutdown
//
STDMETHODIMP CCrypt::Shutdown()
{
return S_OK;
}
//===========================================================================
//
// ReloadState
//
STDMETHODIMP CCrypt::ReloadState(IServiceProvider*)
{
return S_OK;
}
//===========================================================================
//
// CommitState
//
STDMETHODIMP CCrypt::CommitState(IServiceProvider*)
{
return S_OK;
}
//===========================================================================
//
// DumpState
//
STDMETHODIMP CCrypt::DumpState(BSTR* pbstrState)
{
ATLASSERT( *pbstrState != NULL &&
"CCrypt:DumpState - "
"Are you sure you want to hand me a non-null BSTR?" );
HRESULT hr = S_OK;
return hr;
}