5471 lines
188 KiB
C++
5471 lines
188 KiB
C++
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
metasub.cxx
|
|
|
|
Abstract:
|
|
|
|
IIS MetaBase subroutines to support exported routines
|
|
|
|
Author:
|
|
|
|
Michael W. Thomas 31-May-96
|
|
|
|
Revision History:
|
|
|
|
Notes:
|
|
|
|
Most routines in this file assume that g_rMasterResource is already taken
|
|
for read or write as appropriate.
|
|
--*/
|
|
|
|
#include <locale.h>
|
|
#include <mdcommon.hxx>
|
|
#include <inetsvcs.h>
|
|
#include <malloc.h>
|
|
#include <tuneprefix.h>
|
|
|
|
|
|
#if DBG
|
|
|
|
BOOL g_fShowMetaLocks = FALSE;
|
|
|
|
#endif DBG
|
|
|
|
HRESULT GetObjectFromPath(
|
|
OUT CMDBaseObject *&rpboReturn,
|
|
IN METADATA_HANDLE hHandle,
|
|
IN DWORD dwPermissionNeeded,
|
|
IN OUT LPTSTR &strPath,
|
|
IN BOOL bUnicode)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Finds an object from a path. Updates Path to point past the last
|
|
object found if the whole path is not found. If the entire path
|
|
is not found, the last object found is returned.
|
|
|
|
Arguments:
|
|
|
|
Return - The object found.
|
|
|
|
Handle - The Meta Data handle. METADATA_MASTER_ROOT_HANDLE or a handle
|
|
returned by MDOpenMetaObject with read permission.
|
|
|
|
PermissionNeeded - The read/write permissions needed. Compared with the
|
|
permissions associated with Handle.
|
|
|
|
Path - The path of the object requested, relative to Handle. If the path
|
|
is not found, this is updated to point to the portion of the path
|
|
not found.
|
|
|
|
Return Value:
|
|
|
|
DWORD - ERROR_SUCCESS
|
|
ERROR_ACCESS_DENIED
|
|
ERROR_PATH_NOT_FOUND
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
HRESULT hresReturn = ERROR_SUCCESS;
|
|
CMDBaseObject *pboCurrent, *pboPrevious;
|
|
LPTSTR strCurPath = strPath;
|
|
|
|
CMDHandle *HandleObject = GetHandleObject(hHandle);
|
|
if (HandleObject == NULL) {
|
|
hresReturn = E_HANDLE;
|
|
}
|
|
else if ((((dwPermissionNeeded & METADATA_PERMISSION_WRITE) != 0) && (!HandleObject->IsWriteAllowed())) ||
|
|
(((dwPermissionNeeded & METADATA_PERMISSION_READ) != 0) && (!HandleObject->IsReadAllowed()))) {
|
|
hresReturn = E_ACCESSDENIED;
|
|
}
|
|
else {
|
|
pboCurrent = HandleObject->GetObject();
|
|
MD_ASSERT(pboCurrent != NULL);
|
|
strCurPath = strPath;
|
|
|
|
if (strCurPath != NULL) {
|
|
SkipPathDelimeter(strCurPath, bUnicode);
|
|
while ((pboCurrent != NULL) &&
|
|
(!IsStringTerminator(strCurPath, bUnicode))) {
|
|
pboPrevious = pboCurrent;
|
|
//
|
|
// GetChildObject increments strCurPath on success
|
|
// and returns NULL if child not found
|
|
//
|
|
pboCurrent = pboCurrent->GetChildObject(strCurPath, &hresReturn, bUnicode);
|
|
if (FAILED(hresReturn)) {
|
|
break;
|
|
}
|
|
if (pboCurrent != NULL) {
|
|
SkipPathDelimeter(strCurPath, bUnicode);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hresReturn)) {
|
|
if ((strCurPath == NULL) ||
|
|
IsStringTerminator(strCurPath, bUnicode)) { // Found the whole path
|
|
rpboReturn = pboCurrent;
|
|
hresReturn = ERROR_SUCCESS;
|
|
}
|
|
else { //return last object found and an error code
|
|
rpboReturn = pboPrevious;
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND);
|
|
strPath = strCurPath;
|
|
}
|
|
}
|
|
}
|
|
|
|
return (hresReturn);
|
|
}
|
|
|
|
HRESULT AddObjectToDataBase(
|
|
IN METADATA_HANDLE hHandle,
|
|
IN LPTSTR strPath,
|
|
IN BOOL bUnicode)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates and adds one or more objects to the metabase. Finds the deepest object
|
|
pointed to by Handle/Path and creates any subobject specified by path.
|
|
|
|
Arguments:
|
|
|
|
Handle - The Meta Data handle. METADATA_MASTER_ROOT_HANDLE or a handle
|
|
returned by MDOpenMetaObject with read permission.
|
|
|
|
Path - The path of the object(s) to be created.
|
|
|
|
Return Value:
|
|
|
|
DWORD - ERROR_SUCCESS
|
|
ERROR_ACCESS_DENIED
|
|
ERROR_NOT_ENOUGH_MEMORY
|
|
ERROR_INVALID_NAME
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
HRESULT hresReturn=ERROR_SUCCESS;
|
|
CMDBaseObject *pboParent;
|
|
LPTSTR strTempPath = strPath;
|
|
WCHAR strName[METADATA_MAX_NAME_LEN];
|
|
HRESULT hresExtractRetCode = ERROR_SUCCESS;
|
|
|
|
hresReturn = GetObjectFromPath(pboParent,
|
|
hHandle,
|
|
METADATA_PERMISSION_WRITE,
|
|
strTempPath,
|
|
bUnicode);
|
|
//
|
|
// This should return ERROR_PATH_NOT_FOUND and the parent object,
|
|
// with strPath set to the remainder of the path,
|
|
// which should be the child name, without a preceding delimeter.
|
|
//
|
|
if (hresReturn == RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND)) {
|
|
MD_ASSERT(pboParent != NULL);
|
|
for (hresExtractRetCode = ExtractNameFromPath(strTempPath, (LPSTR)strName, bUnicode);
|
|
SUCCEEDED(hresExtractRetCode);
|
|
hresExtractRetCode = ExtractNameFromPath(strTempPath, (LPSTR)strName, bUnicode)) {
|
|
CMDBaseObject *pboNew;
|
|
if (bUnicode) {
|
|
pboNew = new CMDBaseObject((LPWSTR)strName, NULL);
|
|
}
|
|
else {
|
|
pboNew = new CMDBaseObject((LPSTR)strName, NULL);
|
|
}
|
|
if (pboNew == NULL) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
|
|
break;
|
|
}
|
|
else if (!pboNew->IsValid()) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
|
|
delete (pboNew);
|
|
break;
|
|
}
|
|
else {
|
|
hresReturn = pboParent->InsertChildObject(pboNew);
|
|
if (FAILED(hresReturn)) {
|
|
delete (pboNew);
|
|
break;
|
|
}
|
|
else {
|
|
pboParent = pboNew;
|
|
PREFIX_ASSUME(GetHandleObject(hHandle) != NULL, "GetHandleObject(hHandle) is guaranteed not to return NULL");
|
|
GetHandleObject(hHandle)->SetChangeData(pboNew, MD_CHANGE_TYPE_ADD_OBJECT, 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (SUCCEEDED(hresReturn)) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_ALREADY_EXISTS);
|
|
}
|
|
if (hresExtractRetCode == RETURNCODETOHRESULT(ERROR_INVALID_NAME)) {
|
|
hresReturn = hresExtractRetCode;
|
|
}
|
|
return(hresReturn);
|
|
}
|
|
|
|
HRESULT RemoveObjectFromDataBase(
|
|
IN METADATA_HANDLE hHandle,
|
|
IN LPTSTR strPath,
|
|
IN BOOL bUnicode)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Deletes a metaobject and all subobjects from the database.
|
|
|
|
Arguments:
|
|
|
|
Handle - The Meta Data handle. A handle returned by MDOpenMetaObject with write permission.
|
|
|
|
Path - The path of the object(s) to be created.
|
|
|
|
Return Value:
|
|
|
|
DWORD - ERROR_SUCCESS
|
|
ERROR_ACCESS_DENIED
|
|
ERROR_PATH_NOT_FOUND
|
|
ERROR_INVALID_PARAMETER
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
HRESULT hresReturn;
|
|
CMDBaseObject *pboDelete;
|
|
LPTSTR strTempPath = strPath;
|
|
WCHAR strName[METADATA_MAX_NAME_LEN];
|
|
//
|
|
// Make sure that a valid path was specified
|
|
//
|
|
SkipPathDelimeter(strTempPath, bUnicode);
|
|
hresReturn = ExtractNameFromPath(strTempPath, (LPSTR)strName, bUnicode);
|
|
if (FAILED(hresReturn)) {
|
|
hresReturn = E_INVALIDARG;
|
|
}
|
|
else {
|
|
strTempPath = strPath;
|
|
hresReturn = GetObjectFromPath(pboDelete,
|
|
hHandle,
|
|
METADATA_PERMISSION_WRITE,
|
|
strTempPath,
|
|
bUnicode);
|
|
if (SUCCEEDED(hresReturn)) {
|
|
hresReturn = (pboDelete->GetParent())->RemoveChildObject(pboDelete);
|
|
if (SUCCEEDED(hresReturn)) {
|
|
MD_ASSERT(GetHandleObject(hHandle) != NULL);
|
|
if (GetHandleObject(hHandle)->SetChangeData(pboDelete, MD_CHANGE_TYPE_DELETE_OBJECT, 0)
|
|
!= ERROR_SUCCESS) {
|
|
delete(pboDelete);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return(hresReturn);
|
|
}
|
|
|
|
CMDHandle *GetHandleObject(
|
|
IN METADATA_HANDLE hHandle)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Gets the handle object associated with Handle.
|
|
|
|
Arguments:
|
|
|
|
Handle - The Meta Data handle to get. METADATA_MASTER_ROOT_HANDLE Or a handle
|
|
returned by MDOpenMetaObject.
|
|
|
|
Return Value:
|
|
|
|
CMDHandle * - The handle object, or NULL if not found.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
CMDHandle *hoCurrent;
|
|
for (hoCurrent = g_phHandleHead;
|
|
(hoCurrent != NULL) && (hoCurrent->GetHandleIdentifier() != hHandle);
|
|
hoCurrent = hoCurrent->GetNextPtr()) {
|
|
}
|
|
return (hoCurrent);
|
|
}
|
|
|
|
BOOL
|
|
PermissionsAvailable(
|
|
IN CMDBaseObject *pboTest,
|
|
IN DWORD dwRequestedPermissions,
|
|
IN DWORD dwReadThreshHold
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Checks if the requested handle permissions are available for a meta object.
|
|
|
|
Arguments:
|
|
|
|
Handle - The Meta Data handle to get. METADATA_MASTER_ROOT_HANDLE Or a handle
|
|
returned by MDOpenMetaObject.
|
|
|
|
RequestedPermissions - The permissions requested.
|
|
|
|
ReadThreshHold - The number of reads allows on a write request. Normally 0.
|
|
|
|
Return Value:
|
|
|
|
BOOL - TRUE if the permissions are available.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
BOOL bResults = TRUE;
|
|
CMDBaseObject *pboCurrent;
|
|
MD_ASSERT(pboTest != NULL);
|
|
if (dwRequestedPermissions & METADATA_PERMISSION_WRITE) {
|
|
if ((pboTest->GetReadPathCounter() != 0) ||
|
|
(pboTest->GetWritePathCounter() != 0)) {
|
|
bResults = FALSE;
|
|
}
|
|
if ((pboTest->GetReadCounter() > dwReadThreshHold) || (pboTest->GetWriteCounter() != 0)) {
|
|
bResults = FALSE;
|
|
}
|
|
for (pboCurrent = pboTest->GetParent();bResults && (pboCurrent!=NULL);pboCurrent=pboCurrent->GetParent()) {
|
|
if ((pboCurrent->GetReadCounter() != 0) || (pboCurrent->GetWriteCounter() != 0)) {
|
|
bResults = FALSE;
|
|
}
|
|
}
|
|
}
|
|
else if (dwRequestedPermissions & METADATA_PERMISSION_READ) {
|
|
if (pboTest->GetWritePathCounter() != 0) {
|
|
bResults = FALSE;
|
|
}
|
|
for (pboCurrent = pboTest;bResults && (pboCurrent!=NULL);pboCurrent=pboCurrent->GetParent()) {
|
|
if (pboCurrent->GetWriteCounter() != 0) {
|
|
bResults = FALSE;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
MD_ASSERT(FALSE);
|
|
}
|
|
return (bResults);
|
|
}
|
|
|
|
VOID RemovePermissions(
|
|
IN CMDBaseObject *pboAffected,
|
|
IN DWORD dwRemovePermissions
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Removes the handle permissions from a meta object.
|
|
|
|
Arguments:
|
|
|
|
Affected - The object to remove permissions from.
|
|
|
|
RemovePermissions - The permissions to remove.
|
|
|
|
Return Value:
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
MD_ASSERT(pboAffected != NULL);
|
|
CMDBaseObject *pboCurrent;
|
|
if ((dwRemovePermissions & METADATA_PERMISSION_WRITE) != 0) {
|
|
pboAffected->DecrementWriteCounter();
|
|
for (pboCurrent = pboAffected->GetParent(); pboCurrent != NULL; pboCurrent = pboCurrent->GetParent()) {
|
|
pboCurrent->DecrementWritePathCounter();
|
|
}
|
|
}
|
|
if ((dwRemovePermissions & METADATA_PERMISSION_READ) != 0) {
|
|
pboAffected->DecrementReadCounter();
|
|
for (pboCurrent = pboAffected->GetParent(); pboCurrent != NULL; pboCurrent = pboCurrent->GetParent()) {
|
|
pboCurrent->DecrementReadPathCounter();
|
|
}
|
|
}
|
|
|
|
#if DBG
|
|
char szBuf[1024];
|
|
unsigned long cchSz;
|
|
BUFFER bufName;
|
|
unsigned long cchBuf = 0;
|
|
int wCount;
|
|
|
|
if (g_fShowMetaLocks)
|
|
{
|
|
if ((dwRemovePermissions & (METADATA_PERMISSION_WRITE | METADATA_PERMISSION_READ)) ==
|
|
(METADATA_PERMISSION_WRITE | METADATA_PERMISSION_READ))
|
|
{
|
|
strcpy(szBuf, "Read/Write");
|
|
wCount = pboAffected->GetWriteCounter();
|
|
}
|
|
else if (dwRemovePermissions & (METADATA_PERMISSION_WRITE))
|
|
{
|
|
strcpy(szBuf, "Write");
|
|
wCount = pboAffected->GetWriteCounter();
|
|
}
|
|
else if (dwRemovePermissions & (METADATA_PERMISSION_READ))
|
|
{
|
|
strcpy(szBuf, "Read");
|
|
wCount = pboAffected->GetReadCounter();
|
|
}
|
|
else
|
|
{
|
|
strcpy(szBuf, "No");
|
|
wCount = 0;
|
|
}
|
|
|
|
strcat(szBuf, " perms releasted (%d) on ");
|
|
cchSz = strlen(szBuf);
|
|
|
|
GetObjectPath(pboAffected, &bufName, cchBuf, g_pboMasterRoot, FALSE);
|
|
|
|
cchBuf = (cchBuf + cchSz + 2 > sizeof(szBuf)) ? sizeof(szBuf) - cchSz - 2 : cchBuf;
|
|
memcpy(szBuf + cchSz, bufName.QueryPtr(), cchBuf);
|
|
szBuf[cchSz + cchBuf] = '\n';
|
|
szBuf[cchSz + cchBuf + 1] = '\0';
|
|
|
|
DBGPRINTF((DBG_CONTEXT, szBuf, wCount));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
VOID
|
|
AddPermissions(
|
|
IN CMDBaseObject *pboAffected,
|
|
IN DWORD dwRequestedPermissions
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Adds handle permissions to a meta object.
|
|
|
|
Arguments:
|
|
|
|
Affected - The object to remove permissions from.
|
|
|
|
ReqyestedPermissions - The permissions to add.
|
|
|
|
Return Value:
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
CMDBaseObject *pboCurrent;
|
|
if (((dwRequestedPermissions & METADATA_PERMISSION_WRITE) != 0) &&
|
|
((dwRequestedPermissions & METADATA_PERMISSION_READ) != 0)) {
|
|
pboAffected->IncrementWriteCounter();
|
|
pboAffected->IncrementReadCounter();
|
|
for (pboCurrent = pboAffected->GetParent(); pboCurrent != NULL; pboCurrent = pboCurrent->GetParent()) {
|
|
pboCurrent->IncrementWritePathCounter();
|
|
pboCurrent->IncrementReadPathCounter();
|
|
}
|
|
}
|
|
else if ((dwRequestedPermissions & METADATA_PERMISSION_WRITE) != 0) {
|
|
pboAffected->IncrementWriteCounter();
|
|
for (pboCurrent = pboAffected->GetParent(); pboCurrent != NULL; pboCurrent = pboCurrent->GetParent()) {
|
|
pboCurrent->IncrementWritePathCounter();
|
|
}
|
|
}
|
|
else if ((dwRequestedPermissions & METADATA_PERMISSION_READ) != 0) {
|
|
pboAffected->IncrementReadCounter();
|
|
for (pboCurrent = pboAffected->GetParent(); pboCurrent != NULL; pboCurrent = pboCurrent->GetParent()) {
|
|
pboCurrent->IncrementReadPathCounter();
|
|
}
|
|
}
|
|
|
|
#if DBG
|
|
char szBuf[1024];
|
|
unsigned long cchSz;
|
|
BUFFER bufName;
|
|
unsigned long cchBuf = 0;
|
|
int wCount;
|
|
|
|
if (g_fShowMetaLocks)
|
|
{
|
|
if ((dwRequestedPermissions & (METADATA_PERMISSION_WRITE | METADATA_PERMISSION_READ)) ==
|
|
(METADATA_PERMISSION_WRITE | METADATA_PERMISSION_READ))
|
|
{
|
|
strcpy(szBuf, "Read/Write");
|
|
wCount = pboAffected->GetWriteCounter();
|
|
}
|
|
else if (dwRequestedPermissions & (METADATA_PERMISSION_WRITE))
|
|
{
|
|
strcpy(szBuf, "Write");
|
|
wCount = pboAffected->GetWriteCounter();
|
|
}
|
|
else if (dwRequestedPermissions & (METADATA_PERMISSION_READ))
|
|
{
|
|
strcpy(szBuf, "Read");
|
|
wCount = pboAffected->GetReadCounter();
|
|
}
|
|
else
|
|
{
|
|
strcpy(szBuf, "No");
|
|
wCount = 0;
|
|
}
|
|
|
|
strcat(szBuf, " perms obtained (%d) on ");
|
|
cchSz = strlen(szBuf);
|
|
|
|
GetObjectPath(pboAffected, &bufName, cchBuf, g_pboMasterRoot, FALSE);
|
|
|
|
cchBuf = (cchBuf + cchSz + 2 > sizeof(szBuf)) ? sizeof(szBuf) - cchSz - 2 : cchBuf;
|
|
memcpy(szBuf + cchSz, bufName.QueryPtr(), cchBuf);
|
|
szBuf[cchSz + cchBuf] = '\n';
|
|
szBuf[cchSz + cchBuf + 1] = '\0';
|
|
|
|
DBGPRINTF((DBG_CONTEXT, szBuf, wCount));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
HRESULT
|
|
AddHandle(
|
|
IN CMDBaseObject *pboAssociated,
|
|
IN DWORD dwRequestedPermissions,
|
|
IN METADATA_HANDLE &rmhNew
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates a handle object and adds it to the handle list.
|
|
|
|
Arguments:
|
|
|
|
Handle - The object the handle is associated with.
|
|
|
|
RequestedPermissions - The permissions for the handle.
|
|
|
|
New - The handle id.
|
|
|
|
Return Value:
|
|
DWORD - ERROR_SUCCESS
|
|
ERROR_NOT_ENOUGH_MEMORY
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
HRESULT hresReturn = ERROR_SUCCESS;
|
|
CMDHandle *hoNew = new CMDHandle(pboAssociated,
|
|
dwRequestedPermissions,
|
|
g_dwSystemChangeNumber,
|
|
g_mhHandleIdentifier++);
|
|
if (hoNew == NULL) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
else {
|
|
rmhNew = hoNew->GetHandleIdentifier();
|
|
hoNew->SetNextPtr(g_phHandleHead);
|
|
g_phHandleHead = hoNew;
|
|
AddPermissions(pboAssociated, dwRequestedPermissions);
|
|
}
|
|
return(hresReturn);
|
|
}
|
|
|
|
CMDHandle *
|
|
RemoveHandleObject(
|
|
IN METADATA_HANDLE mhHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Removes a handle object from the handle list.
|
|
|
|
Arguments:
|
|
|
|
Handle - The handle to be removed.
|
|
|
|
Return Value:
|
|
|
|
CMDHandle * - The Handle object removed.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
CMDHandle *hoCurrent;
|
|
CMDHandle *hoReturn;
|
|
|
|
if (g_phHandleHead->GetHandleIdentifier() == mhHandle) {
|
|
hoReturn = g_phHandleHead;
|
|
g_phHandleHead = g_phHandleHead->GetNextPtr();
|
|
}
|
|
else {
|
|
for (hoCurrent = g_phHandleHead;(hoCurrent->GetNextPtr() != NULL) &&
|
|
(hoCurrent->GetNextPtr()->GetHandleIdentifier() != mhHandle);
|
|
hoCurrent = hoCurrent->GetNextPtr()) {
|
|
}
|
|
hoReturn = hoCurrent->GetNextPtr();
|
|
if (hoCurrent->GetNextPtr() != NULL) {
|
|
MD_ASSERT (hoCurrent->GetNextPtr()->GetHandleIdentifier() == mhHandle);
|
|
hoCurrent->SetNextPtr(hoCurrent->GetNextPtr()->GetNextPtr());
|
|
}
|
|
}
|
|
return (hoReturn);
|
|
}
|
|
|
|
HRESULT
|
|
SaveDataObject(HANDLE hFileHandle,
|
|
CMDBaseData *pbdSave,
|
|
PBYTE pbLineBuf,
|
|
DWORD dwWriteBufSize,
|
|
PBYTE pbWriteBuf,
|
|
PBYTE &pbrNextPtr,
|
|
IIS_CRYPTO_STORAGE *pCryptoStorage
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Save a data object.
|
|
|
|
Arguments:
|
|
|
|
FileHandle - File handle for use by WriteLine.
|
|
|
|
Save - The data object to save.
|
|
|
|
LineBuf - The line buffer to write string to.
|
|
|
|
WriteBufSize - Buffer size for use by WriteLine.
|
|
|
|
WriteBuf - Buffer for use by WriteLine.
|
|
|
|
NextPtr - Pointer into WriteBuf for use by WriteLine.
|
|
|
|
CryptoStorage - Used to encrypt secure data.
|
|
|
|
Return Value:
|
|
|
|
DWORD - ERROR_SUCCESS
|
|
Return codes from file system
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
HRESULT hresReturn = ERROR_SUCCESS;
|
|
BOOL bGoodData = TRUE;
|
|
int iStringLen;
|
|
PBYTE pbData;
|
|
DWORD dwTemp;
|
|
|
|
if ((pbdSave->GetAttributes() & METADATA_VOLATILE) == 0) {
|
|
|
|
*pbLineBuf = MD_ID_DATA;
|
|
|
|
hresReturn = WriteLine(hFileHandle,
|
|
dwWriteBufSize,
|
|
pbWriteBuf,
|
|
pbLineBuf,
|
|
pbrNextPtr,
|
|
1,
|
|
FALSE);
|
|
|
|
if (SUCCEEDED(hresReturn)) {
|
|
dwTemp = pbdSave->GetIdentifier();
|
|
hresReturn = WriteLine(hFileHandle,
|
|
dwWriteBufSize,
|
|
pbWriteBuf,
|
|
(PBYTE)&dwTemp,
|
|
pbrNextPtr,
|
|
sizeof(DWORD),
|
|
FALSE);
|
|
}
|
|
if (SUCCEEDED(hresReturn)) {
|
|
dwTemp = pbdSave->GetAttributes();
|
|
hresReturn = WriteLine(hFileHandle,
|
|
dwWriteBufSize,
|
|
pbWriteBuf,
|
|
(PBYTE)&dwTemp,
|
|
pbrNextPtr,
|
|
sizeof(DWORD),
|
|
FALSE);
|
|
}
|
|
if (SUCCEEDED(hresReturn)) {
|
|
dwTemp = pbdSave->GetUserType();
|
|
hresReturn = WriteLine(hFileHandle,
|
|
dwWriteBufSize,
|
|
pbWriteBuf,
|
|
(PBYTE)&dwTemp,
|
|
pbrNextPtr,
|
|
sizeof(DWORD),
|
|
FALSE);
|
|
}
|
|
if (SUCCEEDED(hresReturn)) {
|
|
dwTemp = pbdSave->GetDataType();
|
|
hresReturn = WriteLine(hFileHandle,
|
|
dwWriteBufSize,
|
|
pbWriteBuf,
|
|
(PBYTE)&dwTemp,
|
|
pbrNextPtr,
|
|
sizeof(DWORD),
|
|
FALSE);
|
|
}
|
|
|
|
if (SUCCEEDED(hresReturn)) {
|
|
if (pbdSave->GetData(TRUE) == NULL) {
|
|
//
|
|
// This is to make sure that unicode conversion doesn't cause an error.
|
|
//
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
else {
|
|
if (IsSecureMetadata(pbdSave->GetIdentifier(), pbdSave->GetAttributes())) {
|
|
PIIS_CRYPTO_BLOB blob;
|
|
|
|
//
|
|
// This is a secure data object, so encrypt it before saving it
|
|
// to the file.
|
|
//
|
|
|
|
MD_ASSERT(pCryptoStorage != NULL);
|
|
|
|
hresReturn = pCryptoStorage->EncryptData( &blob,
|
|
pbdSave->GetData(TRUE),
|
|
pbdSave->GetDataLen(TRUE),
|
|
0);
|
|
|
|
if (SUCCEEDED(hresReturn)) {
|
|
hresReturn = WriteLine(hFileHandle,
|
|
dwWriteBufSize,
|
|
pbWriteBuf,
|
|
(PBYTE)blob,
|
|
pbrNextPtr,
|
|
IISCryptoGetBlobLength(blob),
|
|
TRUE);
|
|
|
|
::IISCryptoFreeBlob(blob);
|
|
}
|
|
} else {
|
|
hresReturn = WriteLine(hFileHandle,
|
|
dwWriteBufSize,
|
|
pbWriteBuf,
|
|
(PBYTE)pbdSave->GetData(TRUE),
|
|
pbrNextPtr,
|
|
pbdSave->GetDataLen(TRUE),
|
|
TRUE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return (hresReturn);
|
|
}
|
|
|
|
HRESULT
|
|
SaveMasterRoot(HANDLE hFileHandle,
|
|
PBYTE pbLineBuf,
|
|
DWORD dwWriteBufSize,
|
|
PBYTE pbWriteBuf,
|
|
PBYTE &pbrNextPtr,
|
|
IIS_CRYPTO_STORAGE *pCryptoStorage
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Save the master root object, including its data objects.
|
|
|
|
Arguments:
|
|
|
|
FileHandle - File handle for use by WriteLine.
|
|
|
|
LineBuf - The line buffer to write string to.
|
|
|
|
WriteBufSize - Buffer size for use by WriteLine.
|
|
|
|
WriteBuf - Buffer for use by WriteLine.
|
|
|
|
NextPtr - Pointer into WriteBuf for use by WriteLine.
|
|
|
|
CryptoStorage - Used to encrypt secure data.
|
|
|
|
Return Value:
|
|
|
|
DWORD - ERROR_SUCCESS
|
|
Return codes from file system
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
HRESULT hresReturn = ERROR_SUCCESS;
|
|
CMDBaseData *dataAssociatedData;
|
|
DWORD dwEnumObjectIndex;
|
|
PFILETIME pftTime;
|
|
|
|
pftTime = g_pboMasterRoot->GetLastChangeTime();
|
|
|
|
*pbLineBuf = MD_ID_ROOT_OBJECT;
|
|
|
|
hresReturn = WriteLine(hFileHandle,
|
|
dwWriteBufSize,
|
|
pbWriteBuf,
|
|
pbLineBuf,
|
|
pbrNextPtr,
|
|
1,
|
|
FALSE);
|
|
|
|
if (SUCCEEDED(hresReturn)) {
|
|
hresReturn = WriteLine(hFileHandle,
|
|
dwWriteBufSize,
|
|
pbWriteBuf,
|
|
(PBYTE)pftTime,
|
|
pbrNextPtr,
|
|
sizeof(FILETIME),
|
|
TRUE);
|
|
}
|
|
|
|
for(dwEnumObjectIndex=0,dataAssociatedData=g_pboMasterRoot->EnumDataObject(dwEnumObjectIndex++, 0, ALL_METADATA, ALL_METADATA);
|
|
(SUCCEEDED(hresReturn)) && (dataAssociatedData!=NULL);
|
|
dataAssociatedData=g_pboMasterRoot->EnumDataObject(dwEnumObjectIndex++, 0, ALL_METADATA, ALL_METADATA)) {
|
|
hresReturn = SaveDataObject(hFileHandle,
|
|
dataAssociatedData,
|
|
pbLineBuf,
|
|
dwWriteBufSize,
|
|
pbWriteBuf,
|
|
pbrNextPtr,
|
|
pCryptoStorage
|
|
);
|
|
}
|
|
|
|
return(hresReturn);
|
|
}
|
|
|
|
HRESULT
|
|
SaveTree(
|
|
IN HANDLE hFileHandle,
|
|
IN CMDBaseObject *pboRoot,
|
|
IN PBYTE pbLineBuf,
|
|
IN BUFFER *pbufParentPath,
|
|
IN DWORD dwWriteBufSize,
|
|
IN PBYTE pbWriteBuf,
|
|
IN OUT PBYTE &pbrNextPtr,
|
|
IN IIS_CRYPTO_STORAGE *pCryptoStorage
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Save a tree, recursively saving child objects. This works out as
|
|
a depth first save.
|
|
|
|
Arguments:
|
|
|
|
FileHandle - File handle for use by WriteLine.
|
|
|
|
Root - The root of the tree to save.
|
|
|
|
LineBuf - The line buffer to write string to.
|
|
|
|
WriteBufSize - Buffer size for use by WriteLine.
|
|
|
|
WriteBuf - Buffer for use by WriteLine.
|
|
|
|
NextPtr - Pointer into WriteBuf for use by WriteLine.
|
|
|
|
CryptoStorage - Used to encrypt secure data.
|
|
|
|
Return Value:
|
|
|
|
DWORD - ERROR_SUCCESS
|
|
Return codes from file system
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
HRESULT hresReturn = ERROR_SUCCESS;
|
|
CMDBaseObject *objChildObject;
|
|
CMDBaseData *dataAssociatedData;
|
|
DWORD dwEnumObjectIndex;
|
|
DWORD dwParentPathLen, dwNewParentPathLen;
|
|
DWORD dwNameLen;
|
|
LPWSTR strParentPath;
|
|
PFILETIME pftTime;
|
|
|
|
dwParentPathLen = wcslen((LPWSTR)pbufParentPath->QueryPtr());
|
|
if (pboRoot->GetName(TRUE) == NULL) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
else {
|
|
dwNameLen = wcslen((LPWSTR)pboRoot->GetName(TRUE));
|
|
//
|
|
// include 1 for delimeter and 1 for \0
|
|
//
|
|
dwNewParentPathLen = dwParentPathLen + dwNameLen + 2;
|
|
if (!pbufParentPath->Resize((dwNewParentPathLen) * sizeof(WCHAR))) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
else {
|
|
strParentPath = (LPWSTR)pbufParentPath->QueryPtr();
|
|
wcscat(strParentPath, (LPWSTR)pboRoot->GetName(TRUE));
|
|
strParentPath[dwParentPathLen + dwNameLen] = MD_PATH_DELIMETERW;
|
|
strParentPath[dwNewParentPathLen - 1] = (WCHAR)'\0';
|
|
pftTime = pboRoot->GetLastChangeTime();
|
|
|
|
*pbLineBuf = MD_ID_OBJECT;
|
|
|
|
hresReturn = WriteLine(hFileHandle,
|
|
dwWriteBufSize,
|
|
pbWriteBuf,
|
|
pbLineBuf,
|
|
pbrNextPtr,
|
|
1,
|
|
FALSE);
|
|
|
|
if (SUCCEEDED(hresReturn)) {
|
|
hresReturn = WriteLine(hFileHandle,
|
|
dwWriteBufSize,
|
|
pbWriteBuf,
|
|
(PBYTE)pftTime,
|
|
pbrNextPtr,
|
|
sizeof(FILETIME),
|
|
FALSE);
|
|
}
|
|
|
|
if (SUCCEEDED(hresReturn)) {
|
|
hresReturn = WriteLine(hFileHandle,
|
|
dwWriteBufSize,
|
|
pbWriteBuf,
|
|
(PBYTE) strParentPath,
|
|
pbrNextPtr,
|
|
(dwNewParentPathLen) * sizeof(WCHAR),
|
|
TRUE);
|
|
}
|
|
|
|
if (SUCCEEDED(hresReturn)) {
|
|
|
|
for(dwEnumObjectIndex=0,dataAssociatedData=pboRoot->EnumDataObject(dwEnumObjectIndex++, 0, ALL_METADATA, ALL_METADATA);
|
|
(SUCCEEDED(hresReturn)) && (dataAssociatedData!=NULL);
|
|
dataAssociatedData=pboRoot->EnumDataObject(dwEnumObjectIndex++, 0, ALL_METADATA, ALL_METADATA)) {
|
|
hresReturn = SaveDataObject(hFileHandle,
|
|
dataAssociatedData,
|
|
pbLineBuf,
|
|
dwWriteBufSize,
|
|
pbWriteBuf,
|
|
pbrNextPtr,
|
|
pCryptoStorage
|
|
);
|
|
}
|
|
|
|
for(dwEnumObjectIndex=0,objChildObject=pboRoot->EnumChildObject(dwEnumObjectIndex++);
|
|
(SUCCEEDED(hresReturn)) && (objChildObject!=NULL);
|
|
objChildObject=pboRoot->EnumChildObject(dwEnumObjectIndex++)) {
|
|
hresReturn = SaveTree(hFileHandle,
|
|
objChildObject,
|
|
pbLineBuf,
|
|
pbufParentPath,
|
|
dwWriteBufSize,
|
|
pbWriteBuf,
|
|
pbrNextPtr,
|
|
pCryptoStorage
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Buffer may have changed, so don't use strParentPath
|
|
//
|
|
((LPWSTR)pbufParentPath->QueryPtr())[dwParentPathLen] = (WCHAR)'\0';
|
|
}
|
|
}
|
|
|
|
return(hresReturn);
|
|
}
|
|
|
|
HRESULT
|
|
SaveAllData(
|
|
IN BOOL bSetSaveDisallowed,
|
|
IN IIS_CRYPTO_STORAGE *pCryptoStorage,
|
|
IN PIIS_CRYPTO_BLOB pSessionKeyBlob,
|
|
IN LPSTR pszBackupLocation,
|
|
IN METADATA_HANDLE hHandle,
|
|
IN BOOL bHaveReadSaveSemaphore
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Saves all meta data.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
HRESULT - ERROR_SUCCESS
|
|
ERROR_NOT_ENOUGH_MEMORY
|
|
Return codes from file system
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
HRESULT hresReturn = ERROR_SUCCESS;
|
|
PBYTE pbLineBuf = NULL;
|
|
PBYTE pbWriteBuf = NULL;
|
|
PBYTE pbNextPtr = NULL;
|
|
BUFFER *pbufParentPath = new BUFFER(0);
|
|
DWORD dwWriteBufSize = READWRITE_BUFFER_LENGTH;
|
|
HANDLE hTempFileHandle;
|
|
CMDBaseObject *objChildObject;
|
|
DWORD dwEnumObjectIndex;
|
|
DWORD dwStringLen;
|
|
BOOL bDeleteTemp = TRUE;
|
|
DWORD dwTemp = ERROR_SUCCESS;
|
|
DWORD dwTempLastSaveChangeNumber;
|
|
BOOL bSaveNeeded = FALSE;
|
|
LPTSTR strRealFileName;
|
|
LPTSTR strTempFileName = g_strTempFileName->QueryStr();
|
|
LPTSTR strBackupFileName = g_strBackupFileName->QueryStr();
|
|
|
|
if( !pszBackupLocation )
|
|
{
|
|
strRealFileName = g_strRealFileName->QueryStr();
|
|
}
|
|
else
|
|
{
|
|
strRealFileName = pszBackupLocation;
|
|
}
|
|
|
|
if (!bHaveReadSaveSemaphore) {
|
|
MD_REQUIRE(WaitForSingleObject(g_hReadSaveSemaphore, INFINITE) != WAIT_TIMEOUT);
|
|
}
|
|
if (!g_bSaveDisallowed) {
|
|
g_bSaveDisallowed = bSetSaveDisallowed;
|
|
pbLineBuf = new BYTE[MAX_RECORD_BUFFER];
|
|
for ((pbWriteBuf = new BYTE[dwWriteBufSize]);
|
|
(pbWriteBuf == NULL) && ((dwWriteBufSize/=2) >= MAX_RECORD_BUFFER);
|
|
pbWriteBuf = new BYTE[dwWriteBufSize]) {
|
|
}
|
|
if ((pbWriteBuf == NULL) || (pbLineBuf == NULL)
|
|
|| (pbufParentPath == NULL) || (!pbufParentPath->Resize(MD_MAX_PATH_LEN))) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
else {
|
|
//
|
|
// Write to a temp file first in case there are errors.
|
|
//
|
|
|
|
SECURITY_ATTRIBUTES saStorage;
|
|
PSECURITY_ATTRIBUTES psaStorage = NULL;
|
|
|
|
if (g_psdStorage != NULL) {
|
|
saStorage.nLength = sizeof(SECURITY_ATTRIBUTES);
|
|
saStorage.lpSecurityDescriptor = g_psdStorage;
|
|
saStorage.bInheritHandle = FALSE;
|
|
psaStorage = &saStorage;
|
|
}
|
|
|
|
hTempFileHandle = CreateFile(strTempFileName,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
0,
|
|
psaStorage,
|
|
OPEN_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
|
|
0);
|
|
if (hTempFileHandle == INVALID_HANDLE_VALUE) {
|
|
DWORD dwTemp = GetLastError();
|
|
hresReturn = RETURNCODETOHRESULT(dwTemp);
|
|
}
|
|
else {
|
|
g_rMasterResource->Lock(TSRES_LOCK_READ);
|
|
|
|
//
|
|
// Only Save if changes have been made since the last save.
|
|
//
|
|
|
|
if ( pszBackupLocation || g_dwLastSaveChangeNumber != g_dwSystemChangeNumber )
|
|
{
|
|
bSaveNeeded = TRUE;
|
|
|
|
if (hHandle != METADATA_MASTER_ROOT_HANDLE) {
|
|
CMDHandle *phoHandle;
|
|
phoHandle = GetHandleObject(hHandle);
|
|
if ((phoHandle == NULL) || (phoHandle->GetObject() != g_pboMasterRoot)) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_HANDLE);
|
|
}
|
|
else if ((!phoHandle->IsReadAllowed()) && (!phoHandle->IsWriteAllowed())) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_ACCESS_DENIED);
|
|
}
|
|
}
|
|
if (SUCCEEDED(hresReturn)) {
|
|
*(LPWSTR)pbufParentPath->QueryPtr() = MD_PATH_DELIMETERW;
|
|
((LPWSTR)pbufParentPath->QueryPtr())[1] = (WCHAR)'\0';
|
|
pbNextPtr = pbWriteBuf;
|
|
hresReturn = WriteLine(hTempFileHandle,
|
|
dwWriteBufSize,
|
|
pbWriteBuf,
|
|
(PBYTE) MD_SIGNATURE_STRINGW,
|
|
pbNextPtr,
|
|
sizeof(MD_SIGNATURE_STRINGW),
|
|
TRUE);
|
|
if (SUCCEEDED(hresReturn)) {
|
|
*pbLineBuf = MD_ID_MAJOR_VERSION_NUMBER;
|
|
*((UNALIGNED DWORD *)(pbLineBuf + 1)) = g_dwMajorVersionNumber;
|
|
hresReturn = WriteLine(hTempFileHandle,
|
|
dwWriteBufSize,
|
|
pbWriteBuf,
|
|
pbLineBuf,
|
|
pbNextPtr,
|
|
1 + sizeof(DWORD),
|
|
TRUE);
|
|
}
|
|
if (SUCCEEDED(hresReturn)) {
|
|
*pbLineBuf = MD_ID_MINOR_VERSION_NUMBER;
|
|
*((UNALIGNED DWORD *)(pbLineBuf + 1)) = g_dwMinorVersionNumber;
|
|
hresReturn = WriteLine(hTempFileHandle,
|
|
dwWriteBufSize,
|
|
pbWriteBuf,
|
|
pbLineBuf,
|
|
pbNextPtr,
|
|
1 + sizeof(DWORD),
|
|
TRUE);
|
|
}
|
|
if (SUCCEEDED(hresReturn)) {
|
|
*pbLineBuf = MD_ID_CHANGE_NUMBER;
|
|
*((UNALIGNED DWORD *)(pbLineBuf + 1)) = g_dwSystemChangeNumber;
|
|
hresReturn = WriteLine(hTempFileHandle,
|
|
dwWriteBufSize,
|
|
pbWriteBuf,
|
|
pbLineBuf,
|
|
pbNextPtr,
|
|
1 + sizeof(DWORD),
|
|
TRUE);
|
|
}
|
|
if (SUCCEEDED(hresReturn)) {
|
|
//
|
|
// Write the session key blob to the file.
|
|
//
|
|
*pbLineBuf = MD_ID_SESSION_KEY;
|
|
memcpy((PCHAR)pbLineBuf+1, (PCHAR)pSessionKeyBlob, IISCryptoGetBlobLength(pSessionKeyBlob));
|
|
hresReturn = WriteLine(hTempFileHandle,
|
|
dwWriteBufSize,
|
|
pbWriteBuf,
|
|
pbLineBuf,
|
|
pbNextPtr,
|
|
1 + IISCryptoGetBlobLength(pSessionKeyBlob),
|
|
TRUE);
|
|
}
|
|
if (SUCCEEDED(hresReturn)) {
|
|
|
|
hresReturn = SaveMasterRoot( hTempFileHandle,
|
|
pbLineBuf,
|
|
dwWriteBufSize,
|
|
pbWriteBuf,
|
|
pbNextPtr,
|
|
pCryptoStorage
|
|
);
|
|
|
|
for(dwEnumObjectIndex=0,objChildObject=g_pboMasterRoot->EnumChildObject(dwEnumObjectIndex++);
|
|
(SUCCEEDED(hresReturn)) && (objChildObject!=NULL);
|
|
objChildObject=g_pboMasterRoot->EnumChildObject(dwEnumObjectIndex++)) {
|
|
|
|
hresReturn = SaveTree( hTempFileHandle,
|
|
objChildObject,
|
|
pbLineBuf,
|
|
pbufParentPath,
|
|
dwWriteBufSize,
|
|
pbWriteBuf,
|
|
pbNextPtr,
|
|
pCryptoStorage
|
|
);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// failed to write out session key!
|
|
// pretty serious.
|
|
DBGPRINTF(( DBG_CONTEXT, "SaveAllData:Failed to write out Session Key - error 0x%0x\n", hresReturn));
|
|
}
|
|
}
|
|
|
|
//
|
|
// Must have MasterResource when accessing SystemChangeNumber
|
|
// so save it away here. Only update LastSaveChangeNumber on success.
|
|
//
|
|
|
|
dwTempLastSaveChangeNumber = g_dwSystemChangeNumber;
|
|
|
|
}
|
|
|
|
//
|
|
// Release lock before writing to file.
|
|
//
|
|
|
|
g_rMasterResource->Unlock();
|
|
|
|
if (bSaveNeeded && SUCCEEDED(hresReturn)) {
|
|
|
|
hresReturn = FlushWriteBuf(hTempFileHandle,
|
|
pbWriteBuf,
|
|
pbNextPtr);
|
|
}
|
|
|
|
|
|
//
|
|
// FlushFileBuffers was added trying to solve 390968 when metabase
|
|
// sometimes becomes corrupted during resets. That should ensure that data
|
|
// is already on the disk when doing later MoveFile operations
|
|
//
|
|
|
|
if (!FlushFileBuffers (hTempFileHandle)) {
|
|
hresReturn = GetLastError();
|
|
DBGPRINTF(( DBG_CONTEXT, "Failed FlushFileBuffers - error 0x%0x\n", hresReturn));
|
|
}
|
|
|
|
//
|
|
// Always close the file handle
|
|
//
|
|
|
|
if (!CloseHandle(hTempFileHandle)) {
|
|
hresReturn = GetLastError();
|
|
}
|
|
|
|
}
|
|
if (SUCCEEDED(hresReturn) && bSaveNeeded) {
|
|
//
|
|
// New data file created successfully
|
|
// Backup real file and copy temp
|
|
// to real
|
|
//
|
|
if (!MoveFile(strTempFileName, strRealFileName)) {
|
|
if (GetLastError() != ERROR_ALREADY_EXISTS) {
|
|
dwTemp = GetLastError();
|
|
hresReturn = RETURNCODETOHRESULT(dwTemp);
|
|
}
|
|
//
|
|
// Real File exists, so back it up
|
|
//
|
|
else if (!MoveFile(strRealFileName, strBackupFileName)) {
|
|
//
|
|
// backup failed, check for old backup file
|
|
//
|
|
if (GetLastError() != ERROR_ALREADY_EXISTS) {
|
|
dwTemp = GetLastError();
|
|
}
|
|
else if (!DeleteFile(strBackupFileName)) {
|
|
dwTemp = GetLastError();
|
|
}
|
|
else if (!MoveFile(strRealFileName, strBackupFileName)) {
|
|
dwTemp = GetLastError();
|
|
}
|
|
hresReturn = RETURNCODETOHRESULT(dwTemp);
|
|
}
|
|
if (SUCCEEDED(hresReturn)) {
|
|
BOOL bDeleteBackup = TRUE;
|
|
//
|
|
// Real file is backed up
|
|
// so move in new file
|
|
//
|
|
if (!MoveFile(strTempFileName, strRealFileName)) {
|
|
dwTemp = GetLastError();
|
|
hresReturn = RETURNCODETOHRESULT(dwTemp);
|
|
//
|
|
// Moved real to backup but
|
|
// failed to move temp to real
|
|
// so restore from backup
|
|
//
|
|
if (!MoveFile(strBackupFileName, strRealFileName)) {
|
|
//
|
|
// Unable to write new file
|
|
// or restore original file so don't delete backup
|
|
//
|
|
bDeleteBackup = FALSE;
|
|
}
|
|
}
|
|
if (bDeleteBackup) {
|
|
DeleteFile(strBackupFileName);
|
|
}
|
|
}
|
|
if (FAILED(hresReturn)) {
|
|
//
|
|
// temp file was created ok but a problem
|
|
// occurred while moving it to real
|
|
// so don't delete it
|
|
//
|
|
bDeleteTemp = FALSE;
|
|
}
|
|
else {
|
|
|
|
//
|
|
// Update Change Number
|
|
// Must have ReadSaveSemaphore when accessing this.
|
|
//
|
|
|
|
g_dwLastSaveChangeNumber = dwTempLastSaveChangeNumber;
|
|
}
|
|
}
|
|
}
|
|
if (bDeleteTemp && (hTempFileHandle != INVALID_HANDLE_VALUE)) {
|
|
DeleteFile(strTempFileName);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!bHaveReadSaveSemaphore) {
|
|
MD_REQUIRE(ReleaseSemaphore(g_hReadSaveSemaphore, 1, NULL));
|
|
}
|
|
|
|
if ( pbufParentPath != NULL ) {
|
|
delete(pbufParentPath);
|
|
}
|
|
|
|
if ( pbWriteBuf != NULL ) {
|
|
delete(pbWriteBuf);
|
|
}
|
|
|
|
if ( pbLineBuf != NULL ) {
|
|
delete(pbLineBuf);
|
|
}
|
|
|
|
if ( FAILED( hresReturn )) {
|
|
DBGPRINTF(( DBG_CONTEXT, "Failed to flush metabase - error 0x%08lx\n", hresReturn));
|
|
} else {
|
|
//DBGPRINTF(( DBG_CONTEXT, "Successfully flushed metabase to disk\n" ));
|
|
}
|
|
|
|
return hresReturn;
|
|
}
|
|
|
|
DWORD
|
|
DeleteKeyFromRegistry(HKEY hkeyParent,
|
|
LPTSTR pszCurrent)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Deletes a key and all data and subkeys from the registry.
|
|
|
|
RECURSIVE ROUTINE! DO NOT USE STACK!
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
DWORD - ERROR_SUCCESS
|
|
ERROR_NOT_ENOUGH_MEMORY
|
|
Return codes from file system
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
DWORD dwReturn;
|
|
LPTSTR pszName;
|
|
|
|
MDRegKey *pmdrkCurrent = new MDRegKey(hkeyParent,
|
|
pszCurrent);
|
|
if (pmdrkCurrent == NULL) {
|
|
dwReturn = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
else {
|
|
dwReturn = GetLastError();
|
|
}
|
|
if (dwReturn == ERROR_SUCCESS) {
|
|
MDRegKeyIter *pmdrkiCurrent = new MDRegKeyIter(*pmdrkCurrent);
|
|
if (pmdrkiCurrent == NULL) {
|
|
dwReturn = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
else {
|
|
dwReturn = GetLastError();
|
|
}
|
|
while ((dwReturn == ERROR_SUCCESS) &&
|
|
(dwReturn = pmdrkiCurrent->Next(&pszName, NULL, 0)) == ERROR_SUCCESS) {
|
|
dwReturn = DeleteKeyFromRegistry(*pmdrkCurrent,
|
|
pszName);
|
|
}
|
|
delete (pmdrkiCurrent);
|
|
if (dwReturn == ERROR_NO_MORE_ITEMS) {
|
|
dwReturn = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
delete (pmdrkCurrent);
|
|
|
|
if (dwReturn == ERROR_SUCCESS) {
|
|
dwReturn = RegDeleteKey(hkeyParent,
|
|
pszCurrent);
|
|
}
|
|
return dwReturn;
|
|
}
|
|
|
|
HRESULT
|
|
ReadMetaObject(
|
|
IN CMDBaseObject *&cboRead,
|
|
IN BUFFER *pbufLine,
|
|
IN DWORD dwLineLen,
|
|
IN IIS_CRYPTO_STORAGE *pCryptoStorage,
|
|
IN BOOL bUnicode)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Read a meta object. Given a string with the object info.,
|
|
create the object and add it to the database.
|
|
|
|
Arguments:
|
|
|
|
Read - Place to return the created object.
|
|
|
|
ObjectLine - The object info.
|
|
|
|
CryptoStorage - Used to decrypt secure data.
|
|
|
|
Return Value:
|
|
|
|
DWORD - ERROR_SUCCESS
|
|
ERROR_NOT_ENOUGH_MEMORY
|
|
ERROR_ALREADY_EXISTS
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
HRESULT hresReturn;
|
|
CMDBaseObject *pboParent;
|
|
WCHAR strName[METADATA_MAX_NAME_LEN];
|
|
FILETIME ftTime;
|
|
PFILETIME pftParentTime;
|
|
FILETIME ftParentTime;
|
|
PBYTE pbLine = (PBYTE)pbufLine->QueryPtr();
|
|
LPTSTR strObjectName;
|
|
|
|
if ((dwLineLen <= BASEMETAOBJECTLENGTH) || (*(pbLine + dwLineLen - 1) != '\0')) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_DATA);
|
|
}
|
|
else {
|
|
ftTime = *(UNALIGNED FILETIME *)(pbLine + 1);
|
|
//
|
|
// GetObjectFromPath checks permissions on the handle
|
|
// This only gets called from init so just tell it read.
|
|
//
|
|
strObjectName = (LPTSTR)(pbLine + BASEMETAOBJECTLENGTH);
|
|
|
|
if (bUnicode != FALSE) {
|
|
|
|
PCUWSTR strObjectNameUnaligned;
|
|
PCWSTR strObjectNameAligned;
|
|
|
|
//
|
|
// Generate an aligned copy of the string
|
|
//
|
|
|
|
strObjectNameUnaligned = (PCUWSTR)strObjectName;
|
|
|
|
WSTR_ALIGNED_STACK_COPY(&strObjectNameAligned,
|
|
strObjectNameUnaligned);
|
|
|
|
strObjectName = (LPTSTR)strObjectNameAligned;
|
|
}
|
|
hresReturn = GetObjectFromPath(pboParent,
|
|
METADATA_MASTER_ROOT_HANDLE,
|
|
METADATA_PERMISSION_READ,
|
|
strObjectName,
|
|
bUnicode);
|
|
|
|
//
|
|
// This should return ERROR_PATH_NOT_FOUND and the parent object,
|
|
// with strObjectLine set to the remainder of the path,
|
|
// which should be the child name, without a preceding delimeter.
|
|
//
|
|
|
|
if (hresReturn == RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND)) {
|
|
MD_ASSERT(pboParent != NULL);
|
|
if (bUnicode) {
|
|
hresReturn = ExtractNameFromPath((LPWSTR *)&strObjectName, (LPWSTR)strName);
|
|
}
|
|
else {
|
|
hresReturn = ExtractNameFromPath((LPSTR)strObjectName, (LPSTR)strName);
|
|
}
|
|
if (SUCCEEDED(hresReturn)) {
|
|
CMDBaseObject *pboNew;
|
|
if (bUnicode) {
|
|
pboNew = new CMDBaseObject((LPWSTR)strName, NULL);
|
|
}
|
|
else {
|
|
pboNew = new CMDBaseObject((LPSTR)strName, NULL);
|
|
}
|
|
if (pboNew == NULL) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
else if (!pboNew->IsValid()) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
|
|
delete (pboNew);
|
|
}
|
|
else {
|
|
//
|
|
// InsertChildObject sets the last change time to current time.
|
|
// This isn't really a change, so save and restore time.
|
|
//
|
|
pftParentTime = pboParent->GetLastChangeTime();
|
|
ftParentTime = *pftParentTime;
|
|
hresReturn = pboParent->InsertChildObject(pboNew);
|
|
if (SUCCEEDED(hresReturn)) {
|
|
pboParent->SetLastChangeTime(&ftParentTime);
|
|
pboNew->SetLastChangeTime(&ftTime);
|
|
cboRead = pboNew;
|
|
}
|
|
else {
|
|
delete (pboNew);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (SUCCEEDED(hresReturn)) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_ALREADY_EXISTS);
|
|
}
|
|
}
|
|
return (hresReturn);
|
|
}
|
|
|
|
HRESULT
|
|
ReadDataObject(
|
|
IN CMDBaseObject *cboAssociated,
|
|
IN BUFFER *pbufLine,
|
|
IN DWORD dwLineLen,
|
|
IN IIS_CRYPTO_STORAGE *pCryptoStorage,
|
|
IN BOOL bUnicode
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Read a data object. Given a string with the object info.,
|
|
create the object and add it to the database.
|
|
|
|
Arguments:
|
|
|
|
Associated - The associated meta object.
|
|
|
|
DataLine - The data info.
|
|
|
|
BinaryBuf - Buffer to use in UUDecode.
|
|
|
|
CryptoStorage - Used to decrypt secure data.
|
|
|
|
Return Value:
|
|
|
|
DWORD - ERROR_SUCCESS
|
|
ERROR_NOT_ENOUGH_MEMORY
|
|
ERROR_ALREADY_EXISTS
|
|
ERROR_INVALID_DATA
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
HRESULT hresReturn = ERROR_SUCCESS;
|
|
METADATA_RECORD mdrData;
|
|
PFILETIME pftTime;
|
|
FILETIME ftTime;
|
|
PBYTE pbDataLine = (PBYTE)pbufLine->QueryPtr();
|
|
PBYTE pbDataValue;
|
|
STACK_BUFFER( bufAlignedValue, 256 );
|
|
DWORD dwDataLength;
|
|
PIIS_CRYPTO_BLOB blob = NULL;
|
|
|
|
if (dwLineLen < DATAOBJECTBASESIZE) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_DATA);
|
|
}
|
|
else {
|
|
MD_ASSERT(pbufLine->QuerySize() >= DATAOBJECTBASESIZE);
|
|
mdrData.dwMDIdentifier = *(UNALIGNED DWORD *)(pbDataLine + 1);
|
|
mdrData.dwMDAttributes = *(UNALIGNED DWORD *)(pbDataLine + 1 + sizeof(DWORD));
|
|
mdrData.dwMDUserType = *(UNALIGNED DWORD *)(pbDataLine + 1 + (2 * sizeof(DWORD)));
|
|
mdrData.dwMDDataType = *(UNALIGNED DWORD *)(pbDataLine + 1 + (3 * sizeof(DWORD)));
|
|
|
|
pbDataValue = pbDataLine + DATAOBJECTBASESIZE;
|
|
dwDataLength = dwLineLen - DATAOBJECTBASESIZE;
|
|
|
|
if (IsSecureMetadata(mdrData.dwMDIdentifier, mdrData.dwMDAttributes) &&
|
|
pCryptoStorage != NULL) {
|
|
|
|
//
|
|
// This is a secure data object, we we'll need to decrypt it
|
|
// before proceeding. Note that we must clone the blob before
|
|
// we can actually use it, as the blob data in the line buffer
|
|
// is not DWORD-aligned. (IISCryptoCloneBlobFromRawData() is
|
|
// the only IISCrypto function that can handle unaligned data.)
|
|
//
|
|
|
|
hresReturn = ::IISCryptoCloneBlobFromRawData(
|
|
&blob,
|
|
pbDataValue,
|
|
dwDataLength
|
|
);
|
|
|
|
if (SUCCEEDED(hresReturn)) {
|
|
DWORD dummyRegType;
|
|
|
|
MD_ASSERT(::IISCryptoIsValidBlob(blob));
|
|
|
|
hresReturn = pCryptoStorage->DecryptData(
|
|
(PVOID *)&pbDataValue,
|
|
&dwDataLength,
|
|
&dummyRegType,
|
|
blob
|
|
);
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// The metadata was not secure, so decryption was not required.
|
|
// Nonetheless, it must be copied to an aligned buffer...
|
|
//
|
|
|
|
if( !bufAlignedValue.Resize( dwDataLength ) )
|
|
{
|
|
hresReturn = HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
else
|
|
{
|
|
memcpy( bufAlignedValue.QueryPtr(), pbDataValue, dwDataLength );
|
|
pbDataValue = ( PBYTE )bufAlignedValue.QueryPtr();
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hresReturn)) {
|
|
mdrData.pbMDData = pbDataValue;
|
|
|
|
switch (mdrData.dwMDDataType) {
|
|
case DWORD_METADATA: {
|
|
if (dwDataLength != sizeof(DWORD)) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_DATA);
|
|
}
|
|
break;
|
|
}
|
|
case STRING_METADATA:
|
|
case EXPANDSZ_METADATA:
|
|
{
|
|
if ((LONG)dwDataLength < 1 ||
|
|
(!bUnicode && (pbDataValue[dwDataLength-1] != '\0')) ||
|
|
(bUnicode && *(((LPWSTR)pbDataValue) + ((dwDataLength / sizeof(WCHAR)) -1)) != (WCHAR)'\0')) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_DATA);
|
|
}
|
|
break;
|
|
}
|
|
case BINARY_METADATA:
|
|
{
|
|
mdrData.dwMDDataLen = dwDataLength;
|
|
break;
|
|
}
|
|
case MULTISZ_METADATA:
|
|
{
|
|
if (bUnicode) {
|
|
if (dwDataLength < (2 * sizeof(WCHAR)) ||
|
|
*((LPWSTR)pbDataValue + ((dwDataLength / sizeof(WCHAR))-1)) != (WCHAR)'\0' ||
|
|
*((LPWSTR)pbDataValue + ((dwDataLength / sizeof(WCHAR))-2)) != (WCHAR)'\0') {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_DATA);
|
|
}
|
|
}
|
|
else {
|
|
if (dwDataLength < 2 ||
|
|
pbDataValue[dwDataLength-1] != '\0' ||
|
|
pbDataValue[dwDataLength-2] != '\0') {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_DATA);
|
|
}
|
|
}
|
|
if (SUCCEEDED(hresReturn)) {
|
|
mdrData.dwMDDataLen = dwDataLength;
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_DATA);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hresReturn)) {
|
|
//
|
|
// SetDataObject sets the last change time to current time.
|
|
// This isn't really a change, so save and restore time.
|
|
//
|
|
pftTime = cboAssociated->GetLastChangeTime();
|
|
ftTime = *pftTime;
|
|
hresReturn = cboAssociated->SetDataObject(&mdrData, bUnicode);
|
|
cboAssociated->SetLastChangeTime(&ftTime);
|
|
}
|
|
|
|
if (blob != NULL) {
|
|
::IISCryptoFreeBlob(blob);
|
|
}
|
|
|
|
return(hresReturn);
|
|
}
|
|
|
|
HRESULT
|
|
FlushWriteBuf(HANDLE hWriteFileHandle,
|
|
PBYTE pbWriteBuf,
|
|
PBYTE &pbrNextPtr)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Flush the write buffer to the file.
|
|
|
|
Arguments:
|
|
|
|
FileHandle - File handle to write to.
|
|
|
|
WriteBuf - Buffer to write to file.
|
|
|
|
NextPtr - Pointer past end of buffer.
|
|
|
|
Return Value:
|
|
|
|
DWORD - ERROR_SUCCESS
|
|
Return codes from file system
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
DWORD dwReturn = ERROR_SUCCESS;
|
|
DWORD dwBytesWritten;
|
|
if (pbrNextPtr > pbWriteBuf) {
|
|
if (!WriteFile(hWriteFileHandle,
|
|
pbWriteBuf,
|
|
DIFF((BYTE *)pbrNextPtr - (BYTE *)pbWriteBuf),
|
|
&dwBytesWritten,
|
|
NULL)) {
|
|
dwReturn = GetLastError();
|
|
}
|
|
}
|
|
return (RETURNCODETOHRESULT(dwReturn));
|
|
}
|
|
|
|
BOOL
|
|
CopyLineWithEscapes(PBYTE &pbrFileBuf,
|
|
DWORD &dwrFileBufLen,
|
|
PBYTE &pbrLineBuf,
|
|
DWORD &dwrLineBufLen,
|
|
BOOL &brMidEscape)
|
|
//
|
|
// CopyLineWithExcapes updates parameters.
|
|
// SUCCESS: pbrFileBuf, dwrFileBufLen, brMidEscape
|
|
// FAILURE: pbrLineBuf, dwrLineBufLen, brMidEscape
|
|
// On FAILURE, it fills to the end of the buffer
|
|
//
|
|
{
|
|
BOOL bReturn = TRUE;
|
|
PBYTE pbFileBufEnd = pbrFileBuf + dwrFileBufLen;
|
|
PBYTE pbLineBufEnd = pbrLineBuf + dwrLineBufLen;
|
|
PBYTE pbFileBufIndex = pbrFileBuf;
|
|
PBYTE pbLineBufIndex = pbrLineBuf;
|
|
|
|
brMidEscape = FALSE;
|
|
|
|
while ((pbLineBufIndex < pbLineBufEnd) && (pbFileBufIndex < (pbFileBufEnd - 1))) {
|
|
if (NEEDS_ESCAPE(*pbLineBufIndex)) {
|
|
*pbFileBufIndex++ = MD_ESCAPE_BYTE;
|
|
}
|
|
*pbFileBufIndex++ = *pbLineBufIndex++;
|
|
}
|
|
if ((pbLineBufIndex != pbLineBufEnd) && (pbFileBufIndex < pbFileBufEnd)) {
|
|
MD_ASSERT(pbFileBufIndex == (pbFileBufEnd - 1));
|
|
//
|
|
// file last byte in buffer
|
|
//
|
|
if (NEEDS_ESCAPE(*pbLineBufIndex)) {
|
|
*pbFileBufIndex++ = MD_ESCAPE_BYTE;
|
|
brMidEscape = TRUE;
|
|
}
|
|
else {
|
|
*pbFileBufIndex++ = *pbLineBufIndex++;
|
|
}
|
|
}
|
|
if (pbLineBufIndex != pbLineBufEnd) {
|
|
bReturn = FALSE;
|
|
pbrLineBuf = pbLineBufIndex;
|
|
dwrLineBufLen = DIFF(pbLineBufEnd - pbLineBufIndex);
|
|
}
|
|
else {
|
|
pbrFileBuf = pbFileBufIndex;
|
|
dwrFileBufLen = DIFF(pbFileBufEnd - pbFileBufIndex);
|
|
}
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
WriteLine(HANDLE hWriteFileHandle,
|
|
DWORD dwWriteBufSize,
|
|
PBYTE pbWriteBuf,
|
|
PBYTE pbLineBuf,
|
|
PBYTE &pbNextPtr,
|
|
DWORD dwLineLen,
|
|
BOOL bTerminate)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Write a line. Performs buffered writes to a file. Does not append \n.
|
|
The string does not need to be terminated with \0.
|
|
|
|
Arguments:
|
|
|
|
FileHandle - File to write to.
|
|
|
|
WriteBufSize - Buffer size.
|
|
|
|
WriteBuf - Buffer to store data in.
|
|
|
|
LineBuf - The line buffer with data to write.
|
|
|
|
NextPtr - Pointer to the next unused character in WriteBuf.
|
|
|
|
Len - The number of characters to write.
|
|
|
|
Return Value:
|
|
|
|
DWORD - ERROR_SUCCESS
|
|
Return codes from file system
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
DWORD dwReturn = ERROR_SUCCESS;
|
|
PBYTE pbWriteBufEnd = pbWriteBuf + dwWriteBufSize;
|
|
DWORD dwBufferBytesLeft = DIFF(pbWriteBufEnd - pbNextPtr);
|
|
DWORD dwBytesWritten;
|
|
BOOL bMidEscape;
|
|
|
|
MD_ASSERT(pbLineBuf != NULL);
|
|
MD_ASSERT(pbWriteBuf != NULL);
|
|
MD_ASSERT((pbNextPtr >= pbWriteBuf) && (pbNextPtr <= pbWriteBufEnd));
|
|
|
|
//
|
|
// CopyLineWithExcapes updates parameters.
|
|
// SUCCESS: pbNextPtr, dwBufferBytesLeft
|
|
// FAILURE: pbLineBuf, dwLineLen, bMidEscape
|
|
// On FAILURE, it fills to the end of the buffer
|
|
//
|
|
|
|
while ((dwReturn == ERROR_SUCCESS) &&
|
|
(!CopyLineWithEscapes(pbNextPtr, dwBufferBytesLeft, pbLineBuf, dwLineLen, bMidEscape))) {
|
|
if (!WriteFile(hWriteFileHandle,
|
|
pbWriteBuf,
|
|
dwWriteBufSize,
|
|
&dwBytesWritten,
|
|
NULL)) {
|
|
dwReturn = GetLastError();
|
|
}
|
|
dwBufferBytesLeft = dwWriteBufSize;
|
|
pbNextPtr = pbWriteBuf;
|
|
if (bMidEscape) {
|
|
*pbNextPtr++ = *pbLineBuf++;
|
|
dwBufferBytesLeft--;
|
|
dwLineLen--;
|
|
}
|
|
}
|
|
if (bTerminate && (dwReturn == ERROR_SUCCESS)) {
|
|
if (dwBufferBytesLeft == 0) {
|
|
if (!WriteFile(hWriteFileHandle,
|
|
pbWriteBuf,
|
|
dwWriteBufSize,
|
|
&dwBytesWritten,
|
|
NULL)) {
|
|
dwReturn = GetLastError();
|
|
}
|
|
dwBufferBytesLeft = dwWriteBufSize;
|
|
pbNextPtr = pbWriteBuf;
|
|
}
|
|
*pbNextPtr++ = MD_ESCAPE_BYTE;
|
|
dwBufferBytesLeft--;
|
|
if (dwBufferBytesLeft == 0) {
|
|
if (!WriteFile(hWriteFileHandle,
|
|
pbWriteBuf,
|
|
dwWriteBufSize,
|
|
&dwBytesWritten,
|
|
NULL)) {
|
|
dwReturn = GetLastError();
|
|
}
|
|
dwBufferBytesLeft = dwWriteBufSize;
|
|
pbNextPtr = pbWriteBuf;
|
|
}
|
|
*pbNextPtr++ = MD_TERMINATE_BYTE;
|
|
}
|
|
return (RETURNCODETOHRESULT(dwReturn));
|
|
}
|
|
|
|
PBYTE
|
|
FindEndOfData(PBYTE pbNextPtr,
|
|
PBYTE pbEndReadData,
|
|
BOOL bEscapePending)
|
|
{
|
|
PBYTE pbIndex = pbNextPtr;
|
|
BOOL bEndFound = FALSE;
|
|
|
|
if ((pbEndReadData > pbIndex) && bEscapePending) {
|
|
if (*pbIndex == MD_TERMINATE_BYTE) {
|
|
bEndFound = TRUE;
|
|
}
|
|
pbIndex++;
|
|
}
|
|
while ((pbEndReadData -1 > pbIndex) && !bEndFound) {
|
|
if (*pbIndex == MD_ESCAPE_BYTE) {
|
|
pbIndex++;
|
|
if (*pbIndex == MD_TERMINATE_BYTE) {
|
|
bEndFound = TRUE;
|
|
}
|
|
}
|
|
pbIndex++;
|
|
}
|
|
if (!bEndFound) {
|
|
MD_ASSERT(pbIndex == pbEndReadData - 1);
|
|
pbIndex++;
|
|
}
|
|
return pbIndex;
|
|
}
|
|
|
|
DWORD
|
|
GetLineFromBuffer(PBYTE &pbrNextPtr,
|
|
PBYTE &pbrEndReadData,
|
|
BUFFER *pbufLine,
|
|
DWORD &dwrLineLen,
|
|
BOOL &brEscapePending)
|
|
//
|
|
// GetLineFromBuffer modifies variables!!!!
|
|
// SUCCESS: pbrNextPtr, pbufLine, dwrLineLen
|
|
// FAILURE: pbrNextPtr, pbufLine, dwrLineLen, bEscapePending
|
|
//
|
|
{
|
|
DWORD dwReturn = ERROR_HANDLE_EOF;
|
|
PBYTE pbLineIndex;
|
|
DWORD dwBytesToRead;
|
|
PBYTE pbEndReadLine;
|
|
PBYTE pbReadDataIndex = pbrNextPtr;
|
|
|
|
if (pbrNextPtr != pbrEndReadData) {
|
|
//
|
|
// first find out how many bytes we need to read
|
|
//
|
|
pbEndReadLine = FindEndOfData(pbrNextPtr, pbrEndReadData, brEscapePending);
|
|
MD_ASSERT(pbEndReadLine > pbrNextPtr);
|
|
|
|
//
|
|
// Actual number of bytes needed may be less than the size of the data
|
|
// but never more, so just resize for the max we might need
|
|
//
|
|
if (!pbufLine->Resize(dwrLineLen + DIFF(pbEndReadLine - pbrNextPtr))) {
|
|
dwReturn = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
else {
|
|
pbLineIndex = (PBYTE)pbufLine->QueryPtr() + dwrLineLen;
|
|
if (brEscapePending) {
|
|
brEscapePending = FALSE;
|
|
if (*pbReadDataIndex == MD_ESCAPE_BYTE) {
|
|
*pbLineIndex++ = *pbReadDataIndex++;
|
|
}
|
|
else {
|
|
MD_ASSERT(*pbReadDataIndex == MD_TERMINATE_BYTE);
|
|
dwReturn = ERROR_SUCCESS;
|
|
pbReadDataIndex++;
|
|
}
|
|
}
|
|
while ((dwReturn != ERROR_SUCCESS) && (pbReadDataIndex < pbEndReadLine)) {
|
|
if (*pbReadDataIndex != MD_ESCAPE_BYTE) {
|
|
*pbLineIndex++ = *pbReadDataIndex++;
|
|
}
|
|
else {
|
|
pbReadDataIndex++;
|
|
if (pbReadDataIndex == pbEndReadLine) {
|
|
brEscapePending = TRUE;
|
|
}
|
|
else {
|
|
if (*pbReadDataIndex == MD_ESCAPE_BYTE) {
|
|
*pbLineIndex++ = *pbReadDataIndex++;
|
|
}
|
|
else {
|
|
MD_ASSERT(*pbReadDataIndex == MD_TERMINATE_BYTE);
|
|
pbReadDataIndex++;
|
|
dwReturn = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
dwrLineLen = DIFF(pbLineIndex - (PBYTE)pbufLine->QueryPtr());
|
|
pbrNextPtr = pbReadDataIndex;
|
|
}
|
|
}
|
|
return dwReturn;
|
|
}
|
|
|
|
HRESULT
|
|
GetNextLine(
|
|
IN HANDLE hReadFileHandle,
|
|
IN OUT PBYTE &pbrEndReadData,
|
|
IN BUFFER *pbufRead,
|
|
IN OUT BUFFER *pbufLine,
|
|
IN OUT DWORD &dwrLineLen,
|
|
IN OUT PBYTE &pbrNextPtr)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get the next line. Performs buffered reads from a file. Only pbrCurPtr may be modified between calls.
|
|
Other variables must be set up before the first call and not changed.
|
|
|
|
Arguments:
|
|
|
|
ReadFileHandle - File to write to.
|
|
|
|
EndReadDataPtr - Points past the end of the data in ReadBuf.
|
|
|
|
Read - Buffer for file data.
|
|
|
|
Line - A line buffer which the returned line is stored in.
|
|
|
|
LineLen - The length of the data in line
|
|
|
|
NextPtr - On entry, pointer to the next unread character in ReadBuf.
|
|
On exit, pointer to the new next unread character in ReadBuf.
|
|
|
|
Return Value:
|
|
|
|
DWORD - ERROR_SUCCESS
|
|
ERROR_INVALID_DATA
|
|
Return codes from file system
|
|
|
|
Notes:
|
|
On EOF, returns ERROR_SUCCESS, dwrLineLen = 0.
|
|
|
|
--*/
|
|
{
|
|
DWORD dwReturn = ERROR_SUCCESS;
|
|
DWORD dwBytesRead;
|
|
DWORD dwLineLen = 0;
|
|
BOOL bEscapePending = FALSE;
|
|
DWORD dwGetLineReturn = ERROR_HANDLE_EOF;
|
|
BOOL bEOF = FALSE;
|
|
|
|
//
|
|
// GetLineFromBuffer modifies variables!!!!
|
|
// SUCCESS: pbrNextPtr, pbufLine, dwrLineLen
|
|
// FAILURE: pbrNextPtr, pbufLine, dwrLineLen, bEscapePending
|
|
//
|
|
|
|
while ((dwReturn == ERROR_SUCCESS) && (dwGetLineReturn == ERROR_HANDLE_EOF) && (!bEOF)) {
|
|
|
|
dwGetLineReturn = GetLineFromBuffer(pbrNextPtr,
|
|
pbrEndReadData,
|
|
pbufLine,
|
|
dwLineLen,
|
|
bEscapePending);
|
|
|
|
if (dwGetLineReturn == ERROR_HANDLE_EOF) {
|
|
if (!ReadFile(hReadFileHandle,
|
|
(LPVOID) pbufRead->QueryPtr(),
|
|
pbufRead->QuerySize(),
|
|
&dwBytesRead,
|
|
NULL)) {
|
|
dwReturn = GetLastError();
|
|
}
|
|
else {
|
|
pbrEndReadData = (BYTE *)pbufRead->QueryPtr() + dwBytesRead;
|
|
pbrNextPtr = (PBYTE)pbufRead->QueryPtr();
|
|
if (dwBytesRead == 0) {
|
|
bEOF = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (bEOF) {
|
|
MD_ASSERT(dwGetLineReturn = ERROR_HANDLE_EOF);
|
|
dwLineLen = 0;
|
|
}
|
|
else if (dwGetLineReturn != ERROR_SUCCESS) {
|
|
dwReturn = dwGetLineReturn;
|
|
}
|
|
|
|
dwrLineLen = dwLineLen;
|
|
return RETURNCODETOHRESULT(dwReturn);
|
|
}
|
|
|
|
DWORD
|
|
GetLineID(
|
|
IN OUT LPTSTR &strCurPtr)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determines the ID of a line from the metadata file.
|
|
|
|
Arguments:
|
|
|
|
CurPtr - The line to ID. Updated on successful ID to point past
|
|
the id string.
|
|
|
|
Return Value:
|
|
|
|
DWORD - MD_ID_OBJECT
|
|
MD_ID_DATA
|
|
MD_ID_REFERENCE
|
|
MD_ID_ROOT_OBJECT
|
|
MD_ID_NONE
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
DWORD dwLineID;
|
|
if (MD_STRNICMP(strCurPtr, MD_OBJECT_ID_STRING, ((sizeof(MD_OBJECT_ID_STRING)/sizeof(TCHAR)) - 1)) == 0) {
|
|
dwLineID = MD_ID_OBJECT;
|
|
strCurPtr = (LPTSTR)((BYTE *)strCurPtr + (sizeof(MD_OBJECT_ID_STRING) - sizeof(TCHAR)));
|
|
}
|
|
else if (MD_STRNICMP(strCurPtr, MD_DATA_ID_STRING, ((sizeof(MD_DATA_ID_STRING)/sizeof(TCHAR)) - 1)) == 0) {
|
|
dwLineID = MD_ID_DATA;
|
|
strCurPtr = (LPTSTR)((BYTE *)strCurPtr + (sizeof(MD_DATA_ID_STRING) - sizeof(TCHAR)));
|
|
}
|
|
else if (MD_STRNICMP(strCurPtr, MD_REFERENCE_ID_STRING, ((sizeof(MD_REFERENCE_ID_STRING)/sizeof(TCHAR)) - 1)) == 0) {
|
|
dwLineID = MD_ID_REFERENCE;
|
|
strCurPtr = (LPTSTR)((BYTE *)strCurPtr + (sizeof(MD_REFERENCE_ID_STRING) - sizeof(TCHAR)));
|
|
}
|
|
else if (MD_STRNICMP(strCurPtr, MD_ROOT_OBJECT_ID_STRING, ((sizeof(MD_ROOT_OBJECT_ID_STRING)/sizeof(TCHAR)) - 1)) == 0) {
|
|
dwLineID = MD_ID_ROOT_OBJECT;
|
|
strCurPtr = (LPTSTR)((BYTE *)strCurPtr + (sizeof(MD_ROOT_OBJECT_ID_STRING) - sizeof(TCHAR)));
|
|
}
|
|
else if (MD_STRNICMP(strCurPtr, MD_CHANGE_NUMBER_ID_STRING, ((sizeof(MD_CHANGE_NUMBER_ID_STRING)/sizeof(TCHAR)) - 1)) == 0) {
|
|
dwLineID = MD_ID_CHANGE_NUMBER;
|
|
strCurPtr = (LPTSTR)((BYTE *)strCurPtr + (sizeof(MD_CHANGE_NUMBER_ID_STRING) - sizeof(TCHAR)));
|
|
}
|
|
else if (MD_STRNICMP(strCurPtr, MD_MAJOR_VERSION_NUMBER_ID_STRING, ((sizeof(MD_MAJOR_VERSION_NUMBER_ID_STRING)/sizeof(TCHAR)) - 1)) == 0) {
|
|
dwLineID = MD_ID_MAJOR_VERSION_NUMBER;
|
|
strCurPtr = (LPTSTR)((BYTE *)strCurPtr + (sizeof(MD_MAJOR_VERSION_NUMBER_ID_STRING) - sizeof(TCHAR)));
|
|
}
|
|
else if (MD_STRNICMP(strCurPtr, MD_MINOR_VERSION_NUMBER_ID_STRING, ((sizeof(MD_MINOR_VERSION_NUMBER_ID_STRING)/sizeof(TCHAR)) - 1)) == 0) {
|
|
dwLineID = MD_ID_MINOR_VERSION_NUMBER;
|
|
strCurPtr = (LPTSTR)((BYTE *)strCurPtr + (sizeof(MD_MINOR_VERSION_NUMBER_ID_STRING) - sizeof(TCHAR)));
|
|
}
|
|
else {
|
|
dwLineID = MD_ID_NONE;
|
|
}
|
|
return(dwLineID);
|
|
}
|
|
|
|
HRESULT
|
|
GetWarning(
|
|
IN HRESULT hresWarningCode)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Converts error to warnings.
|
|
|
|
Arguments:
|
|
|
|
WarnignCode - The error code to convert.
|
|
|
|
Return Value:
|
|
|
|
DWORD - MD_WARNING_PATH_NOT_FOUND
|
|
MD_WARNING_DUP_NAME
|
|
MD_WARNING_INVALID_DATA
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
HRESULT hresReturn;
|
|
switch (hresWarningCode) {
|
|
case (RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND)):
|
|
hresReturn = MD_WARNING_PATH_NOT_FOUND;
|
|
break;
|
|
case (RETURNCODETOHRESULT(ERROR_DUP_NAME)):
|
|
hresReturn = MD_WARNING_DUP_NAME;
|
|
break;
|
|
case (RETURNCODETOHRESULT(ERROR_INVALID_DATA)):
|
|
hresReturn = MD_WARNING_INVALID_DATA;
|
|
break;
|
|
case (RETURNCODETOHRESULT(ERROR_ALREADY_EXISTS)):
|
|
hresReturn = MD_WARNING_DUP_NAME;
|
|
break;
|
|
default:
|
|
hresReturn = hresWarningCode;
|
|
}
|
|
return (hresReturn);
|
|
}
|
|
|
|
BOOL CheckDigits(LPTSTR pszString)
|
|
{
|
|
LPTSTR pszTemp;
|
|
BOOL bDigitFound = FALSE;
|
|
BOOL bReturn = FALSE;
|
|
for (pszTemp = pszString;MD_ISDIGIT(*pszTemp); pszTemp++) {
|
|
bDigitFound = TRUE;
|
|
}
|
|
if (bDigitFound && (*pszTemp == (TCHAR)'\0')) {
|
|
bReturn = TRUE;
|
|
}
|
|
return bReturn;
|
|
}
|
|
|
|
HRESULT
|
|
InitStorageHelper(
|
|
PBYTE RawBlob,
|
|
DWORD RawBlobLength,
|
|
IIS_CRYPTO_STORAGE **NewStorage
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Helper routine to create and initialize a new IIS_CRYPTO_STORAGE
|
|
object from an unaligned blob.
|
|
|
|
Arguments:
|
|
|
|
RawBlob - Pointer to the raw unaligned session key blob.
|
|
|
|
RawBlobLength - Length of the raw blob data.
|
|
|
|
NewStorage - Receives a pointer to the new IIS_CRYPTO_STORAGE object
|
|
if successful.
|
|
|
|
Return Value:
|
|
|
|
DWORD - 0 if successful, !0 otherwise.
|
|
|
|
--*/
|
|
{
|
|
|
|
PIIS_CRYPTO_BLOB alignedBlob;
|
|
IIS_CRYPTO_STORAGE *storage = NULL;
|
|
HRESULT hresReturn = NO_ERROR;
|
|
|
|
//
|
|
// Make a copy of the blob. This is necessary, as the incoming
|
|
// raw blob pointer is most likely not DWORD-aligned.
|
|
//
|
|
|
|
hresReturn = ::IISCryptoCloneBlobFromRawData(
|
|
&alignedBlob,
|
|
RawBlob,
|
|
RawBlobLength
|
|
);
|
|
|
|
if (SUCCEEDED(hresReturn)) {
|
|
//
|
|
// Create a new IIS_CRYPTO_STORAGE object and initialize it from
|
|
// the DWORD-aligned blob.
|
|
//
|
|
storage = new IIS_CRYPTO_STORAGE();
|
|
|
|
if (storage == NULL) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
|
|
} else {
|
|
HCRYPTPROV hProv;
|
|
|
|
hresReturn = GetCryptoProvider( &hProv );
|
|
|
|
if (SUCCEEDED(hresReturn)) {
|
|
hresReturn = storage->Initialize(
|
|
alignedBlob,
|
|
TRUE, // fUseMachineKeyset
|
|
hProv
|
|
);
|
|
if (FAILED(hresReturn))
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT,"InitStorageHelper:(IIS_CRYPTO_STORAGE) storage->Initialize() Failed err=0x%x.\n",hresReturn));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT,"InitStorageHelper:GetCryptoProvider Failed err=0x%x. (Crypto problem)\n",hresReturn));
|
|
}
|
|
|
|
if (FAILED(hresReturn)) {
|
|
delete storage;
|
|
storage = NULL;
|
|
}
|
|
}
|
|
|
|
::IISCryptoFreeBlob(alignedBlob);
|
|
}
|
|
else
|
|
{
|
|
// something failed...
|
|
DBGPRINTF(( DBG_CONTEXT,"InitStorageHelper:IISCryptoCloneBlobFromRawData Failed err=0x%x. (Crypto problem).\n",hresReturn));
|
|
}
|
|
|
|
*NewStorage = storage;
|
|
return hresReturn;
|
|
|
|
} // InitStorageHelper
|
|
|
|
HRESULT
|
|
InitStorageHelper2(
|
|
LPSTR pszPasswd,
|
|
PBYTE RawBlob,
|
|
DWORD RawBlobLength,
|
|
IIS_CRYPTO_STORAGE **NewStorage
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Helper routine to create and initialize a new IIS_CRYPTO_STORAGE
|
|
object from an unaligned blob.
|
|
|
|
Arguments:
|
|
|
|
RawBlob - Pointer to the raw unaligned session key blob.
|
|
|
|
RawBlobLength - Length of the raw blob data.
|
|
|
|
NewStorage - Receives a pointer to the new IIS_CRYPTO_STORAGE object
|
|
if successful.
|
|
|
|
Return Value:
|
|
|
|
DWORD - 0 if successful, !0 otherwise.
|
|
|
|
--*/
|
|
{
|
|
|
|
PIIS_CRYPTO_BLOB alignedBlob;
|
|
IIS_CRYPTO_STORAGE2 *storage = NULL;
|
|
HRESULT hresReturn = NO_ERROR;
|
|
|
|
//
|
|
// Make a copy of the blob. This is necessary, as the incoming
|
|
// raw blob pointer is most likely not DWORD-aligned.
|
|
//
|
|
|
|
hresReturn = ::IISCryptoCloneBlobFromRawData2(
|
|
&alignedBlob,
|
|
RawBlob,
|
|
RawBlobLength
|
|
);
|
|
|
|
if (SUCCEEDED(hresReturn)) {
|
|
|
|
if (alignedBlob->BlobSignature != SALT_BLOB_SIGNATURE )
|
|
{
|
|
::IISCryptoFreeBlob2(alignedBlob);
|
|
return InitStorageHelper( RawBlob, RawBlobLength, NewStorage );
|
|
}
|
|
|
|
//
|
|
// Create a new IIS_CRYPTO_STORAGE object and initialize it from
|
|
// the DWORD-aligned blob.
|
|
//
|
|
storage = new IIS_CRYPTO_STORAGE2;
|
|
|
|
if (storage == NULL) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
|
|
} else {
|
|
HCRYPTPROV hProv;
|
|
|
|
hresReturn = GetCryptoProvider2( &hProv );
|
|
|
|
if (SUCCEEDED(hresReturn)) {
|
|
hresReturn = storage->Initialize(
|
|
alignedBlob,
|
|
pszPasswd,
|
|
hProv
|
|
);
|
|
if (FAILED(hresReturn))
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT,"InitStorageHelper:(IIS_CRYPTO_STORAGE) storage->Initialize() Failed err=0x%x.\n",hresReturn));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT,"InitStorageHelper:GetCryptoProvider Failed err=0x%x. (Crypto problem)\n",hresReturn));
|
|
}
|
|
|
|
if (FAILED(hresReturn)) {
|
|
delete storage;
|
|
storage = NULL;
|
|
}
|
|
}
|
|
|
|
::IISCryptoFreeBlob2(alignedBlob);
|
|
}
|
|
else
|
|
{
|
|
// something failed...
|
|
DBGPRINTF(( DBG_CONTEXT,"InitStorageHelper:IISCryptoCloneBlobFromRawData Failed err=0x%x. (Crypto problem).\n",hresReturn));
|
|
}
|
|
|
|
*NewStorage = ( IIS_CRYPTO_STORAGE * )storage;
|
|
return hresReturn;
|
|
|
|
} // InitStorageHelper2
|
|
|
|
|
|
HRESULT
|
|
ReadAllData(LPSTR pszPasswd,
|
|
LPSTR pszBackupLocation,
|
|
BOOL bHaveReadSaveSemaphore
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reads all meta data from a file.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
HRESULT - ERROR_SUCCESS
|
|
ERROR_NOT_ENOUGH_MEMORY
|
|
Return codes from file system
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
HRESULT hresReturn = ERROR_SUCCESS;
|
|
HRESULT hresWarningCode = ERROR_SUCCESS;
|
|
PBYTE pbEndReadData;
|
|
PBYTE pbNextPtr;
|
|
DWORD dwLineLen;
|
|
LPTSTR strReadFileName;
|
|
HANDLE hReadFileHandle;
|
|
BYTE bLineId;
|
|
DWORD dwTemp;
|
|
CMDBaseObject *pboRead;
|
|
FILETIME ftTime;
|
|
IIS_CRYPTO_STORAGE *pStorage = NULL;
|
|
BOOL bUnicode;
|
|
DWORD dwTempLastSaveChangeNumber = 0;
|
|
|
|
BUFFER *pbufRead = new BUFFER(0);
|
|
if( !pbufRead )
|
|
{
|
|
return RETURNCODETOHRESULT( ERROR_NOT_ENOUGH_MEMORY );
|
|
}
|
|
|
|
BUFFER *pbufLine = new BUFFER(0);
|
|
if( !pbufLine )
|
|
{
|
|
delete pbufRead;
|
|
pbufRead = NULL;
|
|
|
|
return RETURNCODETOHRESULT( ERROR_NOT_ENOUGH_MEMORY );
|
|
}
|
|
|
|
if( !pszPasswd )
|
|
{
|
|
strReadFileName = g_strRealFileName->QueryStr();
|
|
}
|
|
else
|
|
{
|
|
strReadFileName = pszBackupLocation;
|
|
}
|
|
|
|
if (!bHaveReadSaveSemaphore) {
|
|
MD_REQUIRE(WaitForSingleObject(g_hReadSaveSemaphore, INFINITE) != WAIT_TIMEOUT);
|
|
}
|
|
//
|
|
// Open the file.
|
|
//
|
|
hReadFileHandle = CreateFile(strReadFileName,
|
|
GENERIC_READ,
|
|
0,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
0);
|
|
|
|
if (hReadFileHandle == INVALID_HANDLE_VALUE) {
|
|
dwTemp = GetLastError();
|
|
hresReturn = RETURNCODETOHRESULT(dwTemp);
|
|
}
|
|
else {
|
|
//
|
|
// Allocate Buffers
|
|
//
|
|
if (!pbufLine->Resize(MAX_RECORD_BUFFER) ||
|
|
!pbufRead->Resize(READWRITE_BUFFER_LENGTH)) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
else {
|
|
pbEndReadData = (PBYTE)pbufRead->QueryPtr();
|
|
//
|
|
// GetNextLine makes sure that the next line is in the buffer and sets strCurPtr to point to it
|
|
// The line is NULL terminated, no new line. The variables passed in must not be modified outside
|
|
// of GetNextLine.
|
|
//
|
|
dwLineLen = 0;
|
|
pbNextPtr = pbEndReadData;
|
|
hresReturn = GetNextLine(hReadFileHandle,
|
|
pbEndReadData,
|
|
pbufRead,
|
|
pbufLine,
|
|
dwLineLen,
|
|
pbNextPtr);
|
|
if (SUCCEEDED(hresReturn)) {
|
|
//
|
|
// See if it's our file
|
|
//
|
|
if (dwLineLen == sizeof(MD_SIGNATURE_STRINGA) &&
|
|
(MD_CMP(MD_SIGNATURE_STRINGA, pbufLine->QueryPtr(), dwLineLen) == 0)) {
|
|
bUnicode = FALSE;
|
|
}
|
|
else if (dwLineLen == sizeof(MD_SIGNATURE_STRINGW) &&
|
|
(MD_CMP(MD_SIGNATURE_STRINGW, pbufLine->QueryPtr(), dwLineLen) == 0)) {
|
|
bUnicode = TRUE;
|
|
}
|
|
else {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_DATA);
|
|
}
|
|
|
|
if (SUCCEEDED(hresReturn)) {
|
|
//
|
|
// The first GetNextLine filled the buffer
|
|
// so we may not need to do any file system stuff
|
|
// with g_rMasterResource locked.
|
|
//
|
|
g_rMasterResource->Lock(TSRES_LOCK_WRITE);
|
|
|
|
while ((SUCCEEDED(hresReturn)) &&
|
|
(SUCCEEDED(hresReturn = GetNextLine(hReadFileHandle,
|
|
pbEndReadData,
|
|
pbufRead,
|
|
pbufLine,
|
|
dwLineLen,
|
|
pbNextPtr))) &&
|
|
(dwLineLen > 0) &&
|
|
(((bLineId = *(BYTE *)(pbufLine->QueryPtr())) == MD_ID_NONE) ||
|
|
(bLineId == MD_ID_MAJOR_VERSION_NUMBER) ||
|
|
(bLineId == MD_ID_MINOR_VERSION_NUMBER) ||
|
|
(bLineId == MD_ID_CHANGE_NUMBER) ||
|
|
(bLineId == MD_ID_SESSION_KEY))) {
|
|
|
|
if (bLineId != MD_ID_NONE) {
|
|
if (bLineId != MD_ID_SESSION_KEY &&
|
|
dwLineLen != (1 + sizeof(DWORD))) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_DATA);
|
|
}
|
|
else {
|
|
dwTemp = *(UNALIGNED DWORD *)FIRSTDATAPTR(pbufLine);
|
|
switch (bLineId) {
|
|
case MD_ID_MAJOR_VERSION_NUMBER:
|
|
g_dwMajorVersionNumber = dwTemp;
|
|
break;
|
|
case MD_ID_MINOR_VERSION_NUMBER:
|
|
g_dwMinorVersionNumber = dwTemp;
|
|
break;
|
|
case MD_ID_CHANGE_NUMBER:
|
|
g_dwSystemChangeNumber = dwTemp;
|
|
break;
|
|
case MD_ID_SESSION_KEY:
|
|
{
|
|
BOOL fSecuredRead = TRUE;
|
|
HKEY hkRegistryKey = NULL;
|
|
DWORD dwRegReturn, dwValue,dwType,dwSize = sizeof(DWORD);
|
|
|
|
dwRegReturn = RegOpenKey(HKEY_LOCAL_MACHINE,
|
|
SETUP_REG_KEY,
|
|
&hkRegistryKey);
|
|
if (dwRegReturn == ERROR_SUCCESS)
|
|
{
|
|
dwSize = MAX_PATH * sizeof(TCHAR);
|
|
dwRegReturn = RegQueryValueEx(hkRegistryKey,
|
|
MD_UNSECUREDREAD_VALUE,
|
|
NULL,
|
|
&dwType,
|
|
(BYTE *)&dwValue,
|
|
&dwSize);
|
|
if ( dwRegReturn == ERROR_SUCCESS &&
|
|
dwType == REG_DWORD &&
|
|
dwValue == 1)
|
|
{
|
|
hresReturn = NO_ERROR;
|
|
pStorage = NULL;
|
|
fSecuredRead = FALSE;
|
|
|
|
DBGPRINTF(( DBG_CONTEXT,
|
|
"Temporary disabling decryption for metabase read\n"));
|
|
|
|
|
|
// special indicator for IIS setup that we passed this point
|
|
dwValue = 2;
|
|
dwRegReturn = RegSetValueEx(hkRegistryKey,
|
|
MD_UNSECUREDREAD_VALUE,
|
|
0,
|
|
REG_DWORD,
|
|
(PBYTE)&dwValue,
|
|
sizeof(dwValue));
|
|
if (dwRegReturn == ERROR_SUCCESS)
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT,"Reanabling decryption after W9z upgrade\n"));
|
|
}
|
|
|
|
}
|
|
MD_REQUIRE( RegCloseKey( hkRegistryKey ) == NO_ERROR );
|
|
}
|
|
|
|
if (fSecuredRead)
|
|
{
|
|
if (IISCryptoIsClearTextSignature((IIS_CRYPTO_BLOB UNALIGNED *) FIRSTDATAPTR(pbufLine)))
|
|
{
|
|
// call special function focibly tell that this machine has no
|
|
// encryption enabled even if it happens to be so
|
|
// that's a special handling for French case with US locale
|
|
IISCryptoInitializeOverride (FALSE);
|
|
}
|
|
|
|
if( !pszPasswd )
|
|
{
|
|
hresReturn = InitStorageHelper(
|
|
FIRSTDATAPTR(pbufLine),
|
|
dwLineLen-1,
|
|
&pStorage
|
|
);
|
|
}
|
|
else
|
|
{
|
|
hresReturn = InitStorageHelper2(
|
|
pszPasswd,
|
|
FIRSTDATAPTR(pbufLine),
|
|
dwLineLen-1,
|
|
&pStorage
|
|
);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
MD_ASSERT(FALSE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (SUCCEEDED(hresReturn)) {
|
|
|
|
//
|
|
// This must be the global master object
|
|
//
|
|
if ((dwLineLen != 1 + sizeof(FILETIME)) || (bLineId != MD_ID_ROOT_OBJECT)) {
|
|
//
|
|
// This file is hosed
|
|
//
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_DATA);
|
|
}
|
|
else {
|
|
//
|
|
// Got the MasterRoot Object.
|
|
//
|
|
|
|
ftTime = *(UNALIGNED FILETIME *)FIRSTDATAPTR(pbufLine);
|
|
g_pboMasterRoot->SetLastChangeTime(&ftTime);
|
|
//
|
|
// Read in MasterRoot Data.
|
|
//
|
|
for (hresReturn = GetNextLine(hReadFileHandle,
|
|
pbEndReadData,
|
|
pbufRead,
|
|
pbufLine,
|
|
dwLineLen,
|
|
pbNextPtr);
|
|
((SUCCEEDED(hresReturn)) && (dwLineLen != 0)
|
|
&& ((bLineId = *(PBYTE)pbufLine->QueryPtr()) != MD_ID_OBJECT));
|
|
hresReturn = GetNextLine(hReadFileHandle,
|
|
pbEndReadData,
|
|
pbufRead,
|
|
pbufLine,
|
|
dwLineLen,
|
|
pbNextPtr)) {
|
|
if (bLineId == MD_ID_DATA) {
|
|
|
|
hresReturn = ReadDataObject( g_pboMasterRoot,
|
|
pbufLine,
|
|
dwLineLen,
|
|
pStorage,
|
|
bUnicode
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// All of the required stuff is read in, and the next line is either
|
|
// NULL or the first normal object.
|
|
// Loop through all normal objects.
|
|
//
|
|
if (SUCCEEDED(hresReturn)) {
|
|
while ((SUCCEEDED(hresReturn)) && (dwLineLen > 0)) {
|
|
MD_ASSERT(bLineId == MD_ID_OBJECT);
|
|
|
|
for (hresReturn = ReadMetaObject(pboRead,
|
|
pbufLine,
|
|
dwLineLen,
|
|
pStorage,
|
|
bUnicode);
|
|
(FAILED(hresReturn));
|
|
hresReturn = ReadMetaObject(pboRead,
|
|
pbufLine,
|
|
dwLineLen,
|
|
pStorage,
|
|
bUnicode)) {
|
|
|
|
//
|
|
// This for loop normally shouldn't be executed.
|
|
// The purpose of the loop is to ignore problems if
|
|
// the object is bad.
|
|
//
|
|
if (hresReturn == RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY)) {
|
|
//
|
|
// Serious error, we're done.
|
|
//
|
|
break;
|
|
}
|
|
else {
|
|
//
|
|
// Just give a warning and go to the next object
|
|
// Ignore everything until we get to the next object
|
|
//
|
|
hresWarningCode = hresReturn;
|
|
|
|
for (hresReturn = GetNextLine(hReadFileHandle,
|
|
pbEndReadData,
|
|
pbufRead,
|
|
pbufLine,
|
|
dwLineLen,
|
|
pbNextPtr);
|
|
((SUCCEEDED(hresReturn)) && (dwLineLen > 0)
|
|
&& ((bLineId = *(PBYTE)pbufLine->QueryPtr()) != MD_ID_OBJECT));
|
|
hresReturn = GetNextLine(hReadFileHandle,
|
|
pbEndReadData,
|
|
pbufRead,
|
|
pbufLine,
|
|
dwLineLen,
|
|
pbNextPtr)) {
|
|
|
|
}
|
|
if (dwLineLen == 0) {
|
|
//
|
|
// EOF, we're done
|
|
//
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if ((SUCCEEDED(hresReturn)) && (dwLineLen > 0)) {
|
|
//
|
|
// Got an object.
|
|
// Read in data.
|
|
//
|
|
for (hresReturn = GetNextLine(hReadFileHandle,
|
|
pbEndReadData,
|
|
pbufRead,
|
|
pbufLine,
|
|
dwLineLen,
|
|
pbNextPtr);
|
|
((SUCCEEDED(hresReturn)) && (dwLineLen > 0)
|
|
//
|
|
// GetLineID increments strCurPtr if a match is found
|
|
//
|
|
&& ((bLineId = *(PBYTE)pbufLine->QueryPtr()) != MD_ID_OBJECT));
|
|
hresReturn = GetNextLine(hReadFileHandle,
|
|
pbEndReadData,
|
|
pbufRead,
|
|
pbufLine,
|
|
dwLineLen,
|
|
pbNextPtr)) {
|
|
if (bLineId == MD_ID_DATA) {
|
|
hresReturn = ReadDataObject( pboRead,
|
|
pbufLine,
|
|
dwLineLen,
|
|
pStorage,
|
|
bUnicode
|
|
);
|
|
|
|
//
|
|
// dwReturn gets blown away by the for loop.
|
|
// Most errors we can just ignore anyway, but
|
|
// save a warning.
|
|
//
|
|
if (FAILED(hresReturn)) {
|
|
if (hresReturn != RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY)) {
|
|
hresWarningCode = hresReturn;
|
|
}
|
|
else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// Must have MasterResource when accessing SystemChangeNumber
|
|
// so save it away here. Only update LastSaveChangeNumber on success.
|
|
//
|
|
|
|
dwTempLastSaveChangeNumber = g_dwSystemChangeNumber;
|
|
g_rMasterResource->Unlock();
|
|
}
|
|
}
|
|
if (!CloseHandle(hReadFileHandle)) {
|
|
dwTemp = GetLastError();
|
|
hresReturn = RETURNCODETOHRESULT(dwTemp);
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// File not found is ok
|
|
// Start with MasterRoot only
|
|
//
|
|
if (hresReturn == RETURNCODETOHRESULT(ERROR_FILE_NOT_FOUND)) {
|
|
hresReturn = ERROR_SUCCESS;
|
|
}
|
|
|
|
if ((SUCCEEDED(hresReturn)) && (hresWarningCode != ERROR_SUCCESS)) {
|
|
hresReturn = GetWarning(hresWarningCode);
|
|
}
|
|
|
|
if (SUCCEEDED(hresReturn)) {
|
|
g_dwLastSaveChangeNumber = dwTempLastSaveChangeNumber;
|
|
}
|
|
|
|
//
|
|
// Cleanup
|
|
//
|
|
if (!bHaveReadSaveSemaphore) {
|
|
MD_REQUIRE(ReleaseSemaphore(g_hReadSaveSemaphore, 1, NULL));
|
|
}
|
|
delete(pbufRead);
|
|
delete(pbufLine);
|
|
delete(pStorage);
|
|
return hresReturn;
|
|
}
|
|
|
|
HRESULT
|
|
InitWorker(
|
|
IN BOOL bHaveReadSaveSemaphore,
|
|
IN LPSTR pszPasswd,
|
|
IN LPSTR pszBackupLocation
|
|
)
|
|
{
|
|
HRESULT hresReturn = ERROR_SUCCESS;
|
|
|
|
g_rMasterResource->Lock(TSRES_LOCK_WRITE);
|
|
if (g_dwInitialized++ > 0) {
|
|
hresReturn = g_hresInitWarning;
|
|
}
|
|
else {
|
|
g_pboMasterRoot = NULL;
|
|
g_phHandleHead = NULL;
|
|
for (int i = 0; i < EVENT_ARRAY_LENGTH; i++) {
|
|
g_phEventHandles[i] = NULL;
|
|
}
|
|
g_mhHandleIdentifier = METADATA_MASTER_ROOT_HANDLE;
|
|
g_pboMasterRoot = new CMDBaseObject(MD_MASTER_ROOT_NAME);
|
|
g_ppbdDataHashTable = NULL;
|
|
g_dwSystemChangeNumber = 0;
|
|
g_strRealFileName = NULL;
|
|
g_strTempFileName = NULL;
|
|
g_strBackupFileName = NULL;
|
|
g_pstrBackupFilePath = NULL;
|
|
|
|
g_psidSystem = NULL;
|
|
g_psidAdmin = NULL;
|
|
g_paclDiscretionary = NULL;
|
|
g_psdStorage = NULL;
|
|
|
|
if ((g_pboMasterRoot == NULL) || (!(g_pboMasterRoot->IsValid()))) {
|
|
|
|
IIS_PRINTF((buff,"Unable to allocate CMDBaseObject\n"));
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
else {
|
|
g_pboMasterRoot->SetParent(NULL);
|
|
g_phHandleHead = new CMDHandle(g_pboMasterRoot,
|
|
METADATA_PERMISSION_READ,
|
|
g_dwSystemChangeNumber,
|
|
g_mhHandleIdentifier++);
|
|
if (g_phHandleHead == NULL) {
|
|
IIS_PRINTF((buff,"Unable to allocate CMDHandle\n"));
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
else {
|
|
g_phHandleHead->SetNextPtr(NULL);
|
|
if( ( g_phEventHandles[EVENT_READ_INDEX] = IIS_CREATE_EVENT(
|
|
"g_phEventHandles[EVENT_READ_INDEX]",
|
|
&g_phEventHandles[EVENT_READ_INDEX],
|
|
TRUE,
|
|
FALSE
|
|
) ) == NULL ) {
|
|
hresReturn = GetLastHResult();
|
|
IIS_PRINTF((buff,"CreateEvent Failed with %x\n",hresReturn));
|
|
}
|
|
else if( ( g_phEventHandles[EVENT_WRITE_INDEX] = IIS_CREATE_EVENT(
|
|
"g_phEventHandles[EVENT_WRITE_INDEX]",
|
|
&g_phEventHandles[EVENT_WRITE_INDEX],
|
|
TRUE,
|
|
FALSE
|
|
) ) == NULL ) {
|
|
hresReturn = GetLastHResult();
|
|
IIS_PRINTF((buff,"CreateEvent Failed with %x\n",hresReturn));
|
|
}
|
|
else if ((g_ppbdDataHashTable = new CMDBaseData *[DATA_HASH_TABLE_LEN]) == NULL) {
|
|
IIS_PRINTF((buff,"Unable to allocate CMDBaseData\n"));
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
else {
|
|
hresReturn = InitBufferPool();
|
|
if (SUCCEEDED(hresReturn)) {
|
|
for (int i =0; i < DATA_HASH_TABLE_LEN; i++) {
|
|
g_ppbdDataHashTable[i] = NULL;
|
|
}
|
|
|
|
//
|
|
// Code Work:
|
|
// There is a conceiveable deadlock if ReadAllData is called with g_rMasterResource Locked,
|
|
// due to the semaphore used to control file access. Would like to release g_rMasterResource,
|
|
// but that could cause duplicate inits.
|
|
//
|
|
|
|
hresReturn = SetStorageSecurityDescriptor();
|
|
if (SUCCEEDED(hresReturn)) {
|
|
hresReturn = SetDataFile();
|
|
if (SUCCEEDED(hresReturn)) {
|
|
hresReturn = ReadAllData(pszPasswd, pszBackupLocation, bHaveReadSaveSemaphore);
|
|
}
|
|
// if ((RetCode = SetRegistryStoreValues()) == ERROR_SUCCESS) {
|
|
// RetCode = ReadAllDataFromRegistry();
|
|
// }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hresReturn)) {
|
|
|
|
// Check if the Major/Minor version needs to get updated...
|
|
// if there is a specified version in the registry (set by iis setup during upgrade)
|
|
// then use that new version, if it's not a dword, then use the default for g_dwMajorVersionNumber.
|
|
CheckForNewMetabaseVersion();
|
|
|
|
if (!CheckVersionNumber()) {
|
|
IIS_PRINTF((buff,"MD: Invalid version number\n"));
|
|
hresReturn = MD_ERROR_INVALID_VERSION;
|
|
}
|
|
}
|
|
|
|
if (FAILED(hresReturn)) {
|
|
g_dwInitialized--;
|
|
delete(g_pboMasterRoot);
|
|
delete(g_phHandleHead);
|
|
delete(g_ppbdDataHashTable);
|
|
DeleteBufferPool();
|
|
for (int i = 0; i < EVENT_ARRAY_LENGTH; i++) {
|
|
if (g_phEventHandles[i] != NULL) {
|
|
CloseHandle(g_phEventHandles[i]);
|
|
}
|
|
}
|
|
ReleaseStorageSecurityDescriptor();
|
|
}
|
|
//
|
|
// Save the return code.
|
|
// Secondary init's repeat warnings.
|
|
// If error, the next init will overwrite this.
|
|
// So don't worry about setting this to errors.
|
|
//
|
|
g_hresInitWarning = hresReturn;
|
|
}
|
|
g_rMasterResource->Unlock();
|
|
return hresReturn;
|
|
}
|
|
|
|
HRESULT
|
|
TerminateWorker1(
|
|
IN BOOL bHaveReadSaveSemaphore
|
|
)
|
|
{
|
|
HRESULT hresReturn;
|
|
IIS_CRYPTO_STORAGE CryptoStorage;
|
|
PIIS_CRYPTO_BLOB pSessionKeyBlob;
|
|
|
|
hresReturn = InitStorageAndSessionKey(
|
|
&CryptoStorage,
|
|
&pSessionKeyBlob
|
|
);
|
|
|
|
if( SUCCEEDED(hresReturn) ) {
|
|
g_rMasterResource->Lock(TSRES_LOCK_WRITE);
|
|
if (g_dwInitialized == 0) {
|
|
hresReturn = MD_ERROR_NOT_INITIALIZED;
|
|
}
|
|
else {
|
|
if (g_dwInitialized == 1) {
|
|
hresReturn = SaveAllData(FALSE,
|
|
&CryptoStorage,
|
|
pSessionKeyBlob,
|
|
NULL,
|
|
METADATA_MASTER_ROOT_HANDLE,
|
|
bHaveReadSaveSemaphore);
|
|
// RetCode = SaveAllDataToRegistry();
|
|
}
|
|
if (SUCCEEDED(hresReturn)) {
|
|
if (--g_dwInitialized == 0)
|
|
TerminateWorker();
|
|
}
|
|
}
|
|
g_rMasterResource->Unlock();
|
|
::IISCryptoFreeBlob(pSessionKeyBlob);
|
|
}
|
|
else
|
|
{
|
|
// pretty serious.
|
|
DBGPRINTF(( DBG_CONTEXT, "TerminateWorker1.InitStorageAndSessionKey:Failed - error 0x%0x\n", hresReturn));
|
|
}
|
|
|
|
return hresReturn;
|
|
}
|
|
|
|
VOID
|
|
TerminateWorker()
|
|
{
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Worker routine for termination.
|
|
|
|
Arguments:
|
|
|
|
SaveData - If true, saves metadata.
|
|
|
|
Return Value:
|
|
|
|
DWORD - ERROR_SUCCESS
|
|
MD_ERROR_NOT_INITIALIZED
|
|
ERROR_NOT_ENOUGH_MEMORY
|
|
Return codes from file system
|
|
|
|
Notes:
|
|
|
|
If SaveData is TRUE and the save fails, the termination code is not executed
|
|
and an error code is returned.
|
|
|
|
--*/
|
|
CMDHandle *CurHandle, *NextHandle;
|
|
for (CurHandle = g_phHandleHead;CurHandle!=NULL;CurHandle=NextHandle) {
|
|
NextHandle = CurHandle->GetNextPtr();
|
|
delete (CurHandle);
|
|
}
|
|
|
|
for (int i = 0; i < EVENT_ARRAY_LENGTH; i++) {
|
|
if (g_phEventHandles[i] != NULL) {
|
|
CloseHandle(g_phEventHandles[i]);
|
|
}
|
|
}
|
|
delete(g_pboMasterRoot);
|
|
|
|
//
|
|
// All data objects should be deleted by
|
|
// deleting the handles and masterroot
|
|
// but it's possible a client failed
|
|
// to release a data by reference so
|
|
// destroy all remaining data objects
|
|
//
|
|
|
|
DeleteAllRemainingDataObjects();
|
|
ReleaseStorageSecurityDescriptor();
|
|
|
|
delete (g_ppbdDataHashTable);
|
|
delete(g_strRealFileName);
|
|
delete(g_strTempFileName);
|
|
delete(g_strBackupFileName);
|
|
delete(g_pstrBackupFilePath);
|
|
DeleteBufferPool();
|
|
}
|
|
|
|
HRESULT
|
|
SetStorageSecurityDescriptor()
|
|
{
|
|
HRESULT hresReturn = ERROR_SUCCESS;
|
|
BOOL status;
|
|
DWORD dwDaclSize;
|
|
SID_IDENTIFIER_AUTHORITY ntAuthority = SECURITY_NT_AUTHORITY;
|
|
PLATFORM_TYPE platformType;
|
|
|
|
//
|
|
// Verify that globals were initialized correctly.
|
|
//
|
|
|
|
|
|
MD_ASSERT(g_psidSystem == NULL);
|
|
MD_ASSERT(g_psidAdmin == NULL);
|
|
MD_ASSERT(g_paclDiscretionary == NULL);
|
|
MD_ASSERT(g_psdStorage == NULL);
|
|
|
|
//
|
|
// Of course, we only need to do this under NT...
|
|
//
|
|
|
|
platformType = IISGetPlatformType();
|
|
|
|
if( (platformType == PtNtWorkstation) || (platformType == PtNtServer ) ) {
|
|
|
|
|
|
g_psdStorage = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
|
|
|
|
if (g_psdStorage == NULL) {
|
|
hresReturn = RETURNCODETOHRESULT(GetLastError());
|
|
goto fatal;
|
|
}
|
|
|
|
//
|
|
// Initialize the security descriptor.
|
|
//
|
|
|
|
status = InitializeSecurityDescriptor(
|
|
g_psdStorage,
|
|
SECURITY_DESCRIPTOR_REVISION
|
|
);
|
|
|
|
if( !status ) {
|
|
hresReturn = RETURNCODETOHRESULT(GetLastError());
|
|
goto fatal;
|
|
}
|
|
|
|
//
|
|
// Create the SIDs for the local system and admin group.
|
|
//
|
|
|
|
status = AllocateAndInitializeSid(
|
|
&ntAuthority,
|
|
1,
|
|
SECURITY_LOCAL_SYSTEM_RID,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
&g_psidSystem
|
|
);
|
|
|
|
if( !status ) {
|
|
hresReturn = RETURNCODETOHRESULT(GetLastError());
|
|
goto fatal;
|
|
}
|
|
status= AllocateAndInitializeSid(
|
|
&ntAuthority,
|
|
2,
|
|
SECURITY_BUILTIN_DOMAIN_RID,
|
|
DOMAIN_ALIAS_RID_ADMINS,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
&g_psidAdmin
|
|
);
|
|
|
|
if( !status ) {
|
|
hresReturn = RETURNCODETOHRESULT(GetLastError());
|
|
goto fatal;
|
|
}
|
|
|
|
//
|
|
// Create the DACL containing an access-allowed ACE
|
|
// for the local system and admin SIDs.
|
|
//
|
|
|
|
dwDaclSize = sizeof(ACL)
|
|
+ sizeof(ACCESS_ALLOWED_ACE)
|
|
+ GetLengthSid(g_psidAdmin)
|
|
+ sizeof(ACCESS_ALLOWED_ACE)
|
|
+ GetLengthSid(g_psidSystem)
|
|
- sizeof(DWORD);
|
|
|
|
g_paclDiscretionary = (PACL)LocalAlloc(LPTR, dwDaclSize );
|
|
|
|
if( g_paclDiscretionary == NULL ) {
|
|
hresReturn = RETURNCODETOHRESULT(GetLastError());
|
|
goto fatal;
|
|
}
|
|
|
|
status = InitializeAcl(
|
|
g_paclDiscretionary,
|
|
dwDaclSize,
|
|
ACL_REVISION
|
|
);
|
|
|
|
if( !status ) {
|
|
hresReturn = RETURNCODETOHRESULT(GetLastError());
|
|
goto fatal;
|
|
}
|
|
|
|
status = AddAccessAllowedAce(
|
|
g_paclDiscretionary,
|
|
ACL_REVISION,
|
|
FILE_ALL_ACCESS,
|
|
g_psidSystem
|
|
);
|
|
|
|
if( !status ) {
|
|
hresReturn = RETURNCODETOHRESULT(GetLastError());
|
|
goto fatal;
|
|
}
|
|
|
|
status = AddAccessAllowedAce(
|
|
g_paclDiscretionary,
|
|
ACL_REVISION,
|
|
FILE_ALL_ACCESS,
|
|
g_psidAdmin
|
|
);
|
|
|
|
if( !status ) {
|
|
hresReturn = RETURNCODETOHRESULT(GetLastError());
|
|
goto fatal;
|
|
|
|
}
|
|
|
|
//
|
|
// Set the DACL into the security descriptor.
|
|
//
|
|
|
|
status = SetSecurityDescriptorDacl(
|
|
g_psdStorage,
|
|
TRUE,
|
|
g_paclDiscretionary,
|
|
FALSE
|
|
);
|
|
|
|
if( !status ) {
|
|
hresReturn = RETURNCODETOHRESULT(GetLastError());
|
|
goto fatal;
|
|
|
|
}
|
|
}
|
|
|
|
fatal:
|
|
|
|
if (FAILED(hresReturn)) {
|
|
ReleaseStorageSecurityDescriptor();
|
|
|
|
}
|
|
|
|
return hresReturn;
|
|
|
|
}
|
|
|
|
VOID
|
|
ReleaseStorageSecurityDescriptor()
|
|
{
|
|
if( g_paclDiscretionary != NULL ) {
|
|
LocalFree( g_paclDiscretionary );
|
|
g_paclDiscretionary = NULL;
|
|
}
|
|
|
|
if( g_psidAdmin != NULL ) {
|
|
FreeSid( g_psidAdmin );
|
|
g_psidAdmin = NULL;
|
|
|
|
}
|
|
|
|
if( g_psidSystem != NULL ) {
|
|
FreeSid( g_psidSystem );
|
|
g_psidSystem = NULL;
|
|
}
|
|
|
|
if( g_psdStorage != NULL ) {
|
|
LocalFree( g_psdStorage );
|
|
g_psdStorage = NULL;
|
|
}
|
|
}
|
|
|
|
HRESULT
|
|
ExtractNameFromPath(
|
|
IN OUT LPSTR &strPath,
|
|
OUT LPSTR strNameBuffer,
|
|
IN BOOL bUnicode)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Finds the next name in a path.
|
|
|
|
Arguments:
|
|
|
|
Path - The path. Updated on success to point past the name.
|
|
|
|
NameBuffer - The buffer to store the name.
|
|
|
|
Return Value:
|
|
|
|
DWORD - ERROR_SUCCESS
|
|
ERROR_PATH_NOT_FOUND
|
|
ERROR_INVALID_NAME
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
LPSTR pszIndex;
|
|
HRESULT hresReturn = RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND);
|
|
|
|
MD_ASSERT(strNameBuffer != NULL);
|
|
if (bUnicode) {
|
|
LPWSTR wstrPath = (LPWSTR)strPath;
|
|
hresReturn = ExtractNameFromPath(&wstrPath, (LPWSTR)strNameBuffer);
|
|
strPath = (LPSTR) wstrPath;
|
|
}
|
|
else {
|
|
if (strPath != NULL) {
|
|
for (pszIndex = strPath;
|
|
((pszIndex - strPath) < METADATA_MAX_NAME_LEN) && (*pszIndex != (TCHAR)'\0') &&
|
|
(*pszIndex != MD_PATH_DELIMETER) && (*pszIndex != MD_ALT_PATH_DELIMETER);
|
|
pszIndex = CharNextExA(CP_ACP,
|
|
pszIndex,
|
|
0)) {
|
|
}
|
|
DWORD dwStrBytes = DIFF(pszIndex - strPath);
|
|
if ((dwStrBytes) >= METADATA_MAX_NAME_LEN) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_NAME);
|
|
}
|
|
else {
|
|
MD_COPY(strNameBuffer, strPath, dwStrBytes);
|
|
strNameBuffer[dwStrBytes] = (TCHAR)'\0';
|
|
strPath = pszIndex;
|
|
if (*strNameBuffer != (TCHAR)'\0') {
|
|
//
|
|
// if a non-null name
|
|
//
|
|
SKIP_PATH_DELIMETERA(strPath);
|
|
hresReturn = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return (hresReturn);
|
|
}
|
|
|
|
HRESULT
|
|
ExtractNameFromPath(
|
|
IN OUT LPWSTR *pstrPath,
|
|
OUT LPWSTR strNameBuffer)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Finds the next name in a path.
|
|
|
|
Arguments:
|
|
|
|
Path - The path. Updated on success to point past the name.
|
|
|
|
NameBuffer - The buffer to store the name.
|
|
|
|
Return Value:
|
|
|
|
DWORD - ERROR_SUCCESS
|
|
ERROR_PATH_NOT_FOUND
|
|
ERROR_INVALID_NAME
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
int i;
|
|
HRESULT hresReturn = RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND);
|
|
|
|
MD_ASSERT(strNameBuffer != NULL);
|
|
if (*pstrPath != NULL) {
|
|
for (i = 0;
|
|
(i < METADATA_MAX_NAME_LEN) && ((*pstrPath)[i] != (WCHAR)'\0') &&
|
|
((*pstrPath)[i] != (WCHAR)MD_PATH_DELIMETER) && ((*pstrPath)[i] != (WCHAR)MD_ALT_PATH_DELIMETER);
|
|
i++) {
|
|
strNameBuffer[i] = (*pstrPath)[i];
|
|
}
|
|
if (i == METADATA_MAX_NAME_LEN) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_NAME);
|
|
}
|
|
else {
|
|
strNameBuffer[i] = (WCHAR)'\0';
|
|
*pstrPath += i;
|
|
if (*strNameBuffer != (WCHAR)'\0') {
|
|
//
|
|
// if a non-null name
|
|
//
|
|
SKIP_PATH_DELIMETERW(*pstrPath);
|
|
hresReturn = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
return (hresReturn);
|
|
}
|
|
|
|
BOOL DataMatch(IN CMDBaseData *pbdExisting,
|
|
IN PMETADATA_RECORD pmdrData,
|
|
OUT PBOOL pbError,
|
|
IN BOOL bUnicode)
|
|
{
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determines if a set of data maches an existing object.
|
|
|
|
Arguments:
|
|
|
|
Existing - The existing data object.
|
|
|
|
Identifier - The Identifier of the data.
|
|
|
|
Attributes - The flags for the data.
|
|
METADATA_INHERIT
|
|
|
|
UserType - The User Type for the data. User Defined.
|
|
|
|
DataType - The Type of the data.
|
|
DWORD_METADATA
|
|
STRING_METADATA
|
|
BINARY_METADATA
|
|
|
|
DataLen - The length of the data. Only used if DataType == BINARY_METADATA.
|
|
Binary data must not exceed METADATA_MAX_BINARY_LEN bytes.
|
|
String data must not exceed METADATA_MAX_STRING_LEN characters,
|
|
include the trailing '\0'.
|
|
|
|
Data - Pointer to the data.
|
|
|
|
|
|
Return Value:
|
|
|
|
BOOL - TRUE if the data matches
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
BOOL bReturn = TRUE;
|
|
BOOL bError = FALSE;
|
|
|
|
if ((pmdrData->dwMDIdentifier != pbdExisting->GetIdentifier()) ||
|
|
(pmdrData->dwMDAttributes != pbdExisting->GetAttributes()) ||
|
|
(pmdrData->dwMDUserType != pbdExisting->GetUserType()) ||
|
|
(pmdrData->dwMDDataType != pbdExisting->GetDataType())) {
|
|
bReturn = FALSE;
|
|
}
|
|
else {
|
|
if (pbdExisting->GetData(bUnicode) == NULL) {
|
|
bError = TRUE;
|
|
}
|
|
else {
|
|
switch(pmdrData->dwMDDataType) {
|
|
case DWORD_METADATA: {
|
|
if (*(DWORD *)(pmdrData->pbMDData) != *(DWORD *)(pbdExisting->GetData())) {
|
|
bReturn = FALSE;
|
|
}
|
|
break;
|
|
}
|
|
case STRING_METADATA:
|
|
case EXPANDSZ_METADATA:
|
|
{
|
|
if (bUnicode) {
|
|
LPWSTR pszStringData = (LPWSTR)(pmdrData->pbMDData);
|
|
if (pszStringData == NULL) {
|
|
pszStringData = L"";
|
|
}
|
|
if (wcscmp(pszStringData, (LPWSTR)(pbdExisting->GetData(bUnicode))) != 0) {
|
|
bReturn = FALSE;
|
|
}
|
|
}
|
|
else {
|
|
LPSTR pszStringData = (LPSTR)(pmdrData->pbMDData);
|
|
if (pszStringData == NULL) {
|
|
pszStringData = "";
|
|
}
|
|
if (MD_STRCMP(pszStringData, (LPSTR)(pbdExisting->GetData(bUnicode))) != 0) {
|
|
bReturn = FALSE;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case BINARY_METADATA:
|
|
case MULTISZ_METADATA:
|
|
{
|
|
if (pmdrData->dwMDDataLen != pbdExisting->GetDataLen(bUnicode)) {
|
|
bReturn = FALSE;
|
|
}
|
|
else {
|
|
if (MD_CMP(pmdrData->pbMDData, pbdExisting->GetData(bUnicode), pmdrData->dwMDDataLen) != 0) {
|
|
bReturn = FALSE;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
bReturn = FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
*pbError = bError;
|
|
return (bReturn);
|
|
}
|
|
|
|
VOID
|
|
DeleteDataObject(
|
|
IN CMDBaseData *pbdDelete)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Decrements the reference count of an object and deletes it if the reference count becomes 0.
|
|
|
|
Arguments:
|
|
|
|
Delete - The data object to delete.
|
|
|
|
Return Value:
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
DWORD dwHash = DATA_HASH(pbdDelete->GetIdentifier());
|
|
CMDBaseData *pdataIndex;
|
|
|
|
MD_ASSERT(pbdDelete != NULL);
|
|
if (pbdDelete->DecrementReferenceCount() == 0) {
|
|
if (g_ppbdDataHashTable[dwHash] == pbdDelete) {
|
|
g_ppbdDataHashTable[dwHash] = pbdDelete->GetNextPtr();
|
|
}
|
|
else {
|
|
for (pdataIndex=g_ppbdDataHashTable[dwHash];
|
|
pdataIndex->GetNextPtr() != pbdDelete;
|
|
pdataIndex = pdataIndex->GetNextPtr()) {
|
|
}
|
|
pdataIndex->SetNextPtr(pbdDelete->GetNextPtr());
|
|
}
|
|
switch (pbdDelete->GetDataType()) {
|
|
case DWORD_METADATA: {
|
|
delete ((CMDDWData *) pbdDelete);
|
|
break;
|
|
}
|
|
case STRING_METADATA: {
|
|
delete ((CMDSTRData *) pbdDelete);
|
|
break;
|
|
}
|
|
case BINARY_METADATA: {
|
|
delete ((CMDBINData *) pbdDelete);
|
|
break;
|
|
}
|
|
case EXPANDSZ_METADATA: {
|
|
delete ((CMDEXSZData *) pbdDelete);
|
|
break;
|
|
}
|
|
case MULTISZ_METADATA: {
|
|
delete ((CMDMLSZData *) pbdDelete);
|
|
break;
|
|
}
|
|
default: {
|
|
MD_ASSERT(FALSE);
|
|
delete (pbdDelete);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID
|
|
DeleteAllRemainingDataObjects()
|
|
{
|
|
DWORD i;
|
|
CMDBaseData *pbdIndex;
|
|
CMDBaseData *pbdSave;
|
|
|
|
for (i = 0; i < DATA_HASH_TABLE_LEN; i++) {
|
|
for (pbdIndex=g_ppbdDataHashTable[i];
|
|
pbdIndex != NULL;
|
|
pbdIndex = pbdSave) {
|
|
pbdSave = pbdIndex->GetNextPtr();
|
|
switch (pbdIndex->GetDataType()) {
|
|
case DWORD_METADATA: {
|
|
delete ((CMDDWData *) pbdIndex);
|
|
break;
|
|
}
|
|
case STRING_METADATA: {
|
|
delete ((CMDSTRData *) pbdIndex);
|
|
break;
|
|
}
|
|
case BINARY_METADATA: {
|
|
delete ((CMDBINData *) pbdIndex);
|
|
break;
|
|
}
|
|
case EXPANDSZ_METADATA: {
|
|
delete ((CMDEXSZData *) pbdIndex);
|
|
break;
|
|
}
|
|
case MULTISZ_METADATA: {
|
|
delete ((CMDMLSZData *) pbdIndex);
|
|
break;
|
|
}
|
|
default: {
|
|
MD_ASSERT(FALSE);
|
|
delete (pbdIndex);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
ValidateData(IN PMETADATA_RECORD pmdrData,
|
|
IN BOOL bUnicode)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Checks data values for new metadata.
|
|
|
|
Arguments:
|
|
|
|
Data - The data structure. All fields must be set.
|
|
|
|
Attributes - The flags for the data.
|
|
METADATA_INHERIT - If set on input, inherited data will be returned.
|
|
If not set on input, inherited data will not be returned.
|
|
|
|
METADATA_PARTIAL_PATH - If set on input, this routine will return ERROR_SUCCESS
|
|
and the inherited data even if the entire path is not present.
|
|
Only valid if METADATA_INHERIT is also set.
|
|
|
|
DataType - The Type of the data.
|
|
DWORD_METADATA
|
|
STRING_METADATA
|
|
BINARY_METADATA
|
|
|
|
Return Value:
|
|
|
|
BOOL - TRUE if the data values are valid.
|
|
|
|
Notes:
|
|
--*/
|
|
{
|
|
BOOL bReturn = TRUE;
|
|
|
|
if (((pmdrData->pbMDData == NULL) &&
|
|
((pmdrData->dwMDDataType == DWORD_METADATA) ||
|
|
(((pmdrData->dwMDDataType == BINARY_METADATA) ||
|
|
(pmdrData->dwMDDataType == MULTISZ_METADATA)) &&
|
|
(pmdrData->dwMDDataLen > 0)))) ||
|
|
(pmdrData->dwMDDataType <= ALL_METADATA) ||
|
|
(pmdrData->dwMDDataType >= INVALID_END_METADATA) ||
|
|
((pmdrData->dwMDAttributes &
|
|
~(METADATA_INHERIT | METADATA_SECURE | METADATA_REFERENCE | METADATA_VOLATILE | METADATA_INSERT_PATH | METADATA_LOCAL_MACHINE_ONLY))!=0) ||
|
|
(((pmdrData->dwMDAttributes & METADATA_REFERENCE) != 0) &&
|
|
((pmdrData->dwMDAttributes & METADATA_INSERT_PATH) != 0)) ||
|
|
(((pmdrData->dwMDAttributes & METADATA_INSERT_PATH) != 0) &&
|
|
((pmdrData->dwMDDataType == DWORD_METADATA) || (pmdrData->dwMDDataType == BINARY_METADATA)))) {
|
|
bReturn = FALSE;
|
|
}
|
|
|
|
if (bReturn && (pmdrData->dwMDDataType == MULTISZ_METADATA)) {
|
|
if (bUnicode) {
|
|
LPWSTR pszData = (LPWSTR) pmdrData->pbMDData;
|
|
DWORD dwDataLen = pmdrData->dwMDDataLen;
|
|
if (dwDataLen > 0) {
|
|
if (((dwDataLen / 2) <= 1) ||
|
|
(pszData[(dwDataLen / 2) - 1] != (WCHAR)'\0') ||
|
|
(pszData[(dwDataLen / 2) - 2] != (WCHAR)'\0')) {
|
|
bReturn = FALSE;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
LPSTR pszData = (LPSTR) pmdrData->pbMDData;
|
|
DWORD dwDataLen = pmdrData->dwMDDataLen;
|
|
if (dwDataLen > 0) {
|
|
if (((dwDataLen) == 1) ||
|
|
(pszData[(dwDataLen) - 1] != '\0') ||
|
|
(pszData[(dwDataLen) - 2] != '\0')) {
|
|
bReturn = FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return (bReturn);
|
|
}
|
|
|
|
CMDBaseData *
|
|
MakeDataObject(IN PMETADATA_RECORD pmdrData,
|
|
IN BOOL bUnicode)
|
|
{
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Looks for a data object matching the parameters.
|
|
If found, increments the reference count. If not found, it
|
|
creates it.
|
|
|
|
Arguments:
|
|
|
|
Data - The data for the new object.
|
|
|
|
Identifier - The Identifier of the data.
|
|
|
|
Attributes - The flags for the data.
|
|
METADATA_INHERIT
|
|
|
|
UserType - The User Type for the data. User Defined.
|
|
|
|
DataType - The Type of the data.
|
|
DWORD_METADATA
|
|
STRING_METADATA
|
|
BINARY_METADATA
|
|
|
|
DataLen - The length of the data. Only used if DataType == BINARY_METADATA.
|
|
|
|
Data - Pointer to the data.
|
|
|
|
Return Value:
|
|
|
|
BOOL - TRUE if the data matches
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
CMDBaseData *pbdIndex;
|
|
CMDBaseData *pbdReturn = NULL;
|
|
CMDBaseData *pbdNew = NULL;
|
|
DWORD dwHash = DATA_HASH(pmdrData->dwMDIdentifier);
|
|
BOOL bDataMatchError = FALSE;
|
|
|
|
for (pbdIndex = g_ppbdDataHashTable[dwHash];
|
|
(pbdIndex != NULL) &&
|
|
!DataMatch(pbdIndex, pmdrData, &bDataMatchError, bUnicode) &&
|
|
!bDataMatchError;
|
|
pbdIndex = pbdIndex->GetNextPtr()) {
|
|
}
|
|
if (!bDataMatchError) {
|
|
if (pbdIndex != NULL) {
|
|
pbdReturn = pbdIndex;
|
|
pbdReturn->IncrementReferenceCount();
|
|
}
|
|
else {
|
|
switch(pmdrData->dwMDDataType) {
|
|
case DWORD_METADATA: {
|
|
pbdNew = new CMDDWData(pmdrData->dwMDIdentifier, pmdrData->dwMDAttributes,
|
|
pmdrData->dwMDUserType, *(DWORD *)(pmdrData->pbMDData));
|
|
break;
|
|
}
|
|
case STRING_METADATA: {
|
|
pbdNew = new CMDSTRData(pmdrData->dwMDIdentifier, pmdrData->dwMDAttributes,
|
|
pmdrData->dwMDUserType, (LPTSTR) (pmdrData->pbMDData), bUnicode);
|
|
break;
|
|
}
|
|
case BINARY_METADATA: {
|
|
pbdNew = new CMDBINData(pmdrData->dwMDIdentifier, pmdrData->dwMDAttributes,
|
|
pmdrData->dwMDUserType, pmdrData->dwMDDataLen, pmdrData->pbMDData);
|
|
break;
|
|
}
|
|
case EXPANDSZ_METADATA: {
|
|
pbdNew = new CMDEXSZData(pmdrData->dwMDIdentifier, pmdrData->dwMDAttributes,
|
|
pmdrData->dwMDUserType, (LPTSTR) (pmdrData->pbMDData), bUnicode);
|
|
break;
|
|
}
|
|
case MULTISZ_METADATA: {
|
|
pbdNew = new CMDMLSZData(pmdrData->dwMDIdentifier,
|
|
pmdrData->dwMDAttributes,
|
|
pmdrData->dwMDUserType,
|
|
pmdrData->dwMDDataLen,
|
|
(LPSTR)pmdrData->pbMDData,
|
|
bUnicode);
|
|
break;
|
|
}
|
|
default: {
|
|
pbdNew = NULL;
|
|
}
|
|
}
|
|
if (pbdNew != NULL) {
|
|
if (!(pbdNew->IsValid())) {
|
|
delete (pbdNew);
|
|
}
|
|
else {
|
|
pbdNew->SetNextPtr(g_ppbdDataHashTable[dwHash]);
|
|
g_ppbdDataHashTable[dwHash] = pbdNew;
|
|
pbdReturn = pbdNew;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return (pbdReturn);
|
|
}
|
|
|
|
HRESULT
|
|
GetHighestVersion(IN OUT STRAU *pstrauBackupLocation,
|
|
OUT DWORD *pdwVersion)
|
|
{
|
|
long lHighestVersion = -1;
|
|
long lVersion;
|
|
HRESULT hresReturn = ERROR_SUCCESS;
|
|
DWORD dwPathBytes = g_pstrBackupFilePath->QueryCB() + 1;
|
|
DWORD dwNameBytes = pstrauBackupLocation->QueryCBA() - dwPathBytes;
|
|
if (!pstrauBackupLocation->Append("*")) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
else {
|
|
if (pstrauBackupLocation->QueryStrA() == NULL) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
else {
|
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
WIN32_FIND_DATA wfdFile;
|
|
hFile = FindFirstFile(pstrauBackupLocation->QueryStrA(),
|
|
&wfdFile);
|
|
if (hFile == INVALID_HANDLE_VALUE) {
|
|
if (GetLastError() != ERROR_FILE_NOT_FOUND) {
|
|
hresReturn = RETURNCODETOHRESULT(GetLastError());
|
|
}
|
|
}
|
|
else {
|
|
//
|
|
// Process the first file
|
|
//
|
|
|
|
//
|
|
// dwNameBytes could be wrong for this assert in MBCS,
|
|
// so call MBCS strlen. Subtract 1 char for appended '*'
|
|
//
|
|
|
|
MD_ASSERT(MD_STRNICMP(pstrauBackupLocation->QueryStrA() + dwPathBytes,
|
|
wfdFile.cFileName,
|
|
MD_STRLEN(pstrauBackupLocation->QueryStrA() + dwPathBytes) - 1) == 0);
|
|
if (CheckDigits(wfdFile.cFileName + (dwNameBytes))) {
|
|
//
|
|
// One of our files
|
|
//
|
|
lVersion = atol(wfdFile.cFileName + dwNameBytes);
|
|
if ((lVersion <= MD_BACKUP_MAX_VERSION) &&
|
|
(lVersion > lHighestVersion)) {
|
|
lHighestVersion = lVersion;
|
|
}
|
|
}
|
|
//
|
|
// Process the remaining files
|
|
//
|
|
while (FindNextFile(hFile, &wfdFile)) {
|
|
MD_ASSERT(MD_STRNICMP(pstrauBackupLocation->QueryStrA() + dwPathBytes,
|
|
wfdFile.cFileName,
|
|
MD_STRLEN(pstrauBackupLocation->QueryStrA() + dwPathBytes) - 1) == 0);
|
|
if (CheckDigits(wfdFile.cFileName + dwNameBytes)) {
|
|
//
|
|
// One of our files
|
|
//
|
|
lVersion = atol(wfdFile.cFileName + dwNameBytes);
|
|
if ((lVersion <= MD_BACKUP_MAX_VERSION) &&
|
|
(lVersion > lHighestVersion)) {
|
|
lHighestVersion = lVersion;
|
|
}
|
|
}
|
|
}
|
|
FindClose(hFile);
|
|
}
|
|
if (SUCCEEDED(hresReturn)) {
|
|
if (lHighestVersion == -1) {
|
|
|
|
//
|
|
// May not be an error, but need to indicate that
|
|
// no backups were found.
|
|
//
|
|
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_FILE_NOT_FOUND);
|
|
}
|
|
else if (lHighestVersion <= MD_BACKUP_MAX_VERSION) {
|
|
*pdwVersion = lHighestVersion;
|
|
}
|
|
else {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_NAME);
|
|
}
|
|
}
|
|
}
|
|
pstrauBackupLocation->SetLen(pstrauBackupLocation->QueryCCH() - 1);
|
|
|
|
}
|
|
|
|
return hresReturn;
|
|
}
|
|
|
|
BOOL
|
|
ValidateBackupLocation(LPSTR pszBackupLocation,
|
|
BOOL bUnicode)
|
|
{
|
|
|
|
//
|
|
// The main purpose of this routine is to make sure the user
|
|
// is not putting in any file system controls, like .., /, etc.
|
|
|
|
//
|
|
// Secondarily, try to eliminate any characters that cannot be
|
|
// used in database names
|
|
//
|
|
|
|
BOOL bReturn = TRUE;
|
|
DWORD dwStringLen;
|
|
|
|
MD_ASSERT(pszBackupLocation != NULL);
|
|
|
|
char *pszLocSave = setlocale(LC_CTYPE, NULL); // Save cur locale
|
|
setlocale(LC_CTYPE, ""); // Set sys locale
|
|
|
|
//
|
|
// strcspn doesn't have an error return, but will return
|
|
// the index of the terminating NULL if the chars are not found
|
|
//
|
|
|
|
if (bUnicode) {
|
|
dwStringLen = wcslen((LPWSTR)pszBackupLocation);
|
|
if ((dwStringLen >= MD_BACKUP_MAX_LEN) ||
|
|
(wcscspn((LPWSTR)pszBackupLocation, MD_BACKUP_INVALID_CHARS_W) !=
|
|
dwStringLen)) {
|
|
bReturn = FALSE;
|
|
}
|
|
else {
|
|
LPWSTR pszIndex;
|
|
for (pszIndex = (LPWSTR)pszBackupLocation;
|
|
(*pszIndex != (WCHAR)'\0') &&
|
|
(iswprint(*pszIndex));
|
|
pszIndex++) {
|
|
}
|
|
if (*pszIndex != (WCHAR)'\0') {
|
|
bReturn = FALSE;
|
|
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
dwStringLen = _mbslen((PBYTE)pszBackupLocation);
|
|
if ((dwStringLen >= MD_BACKUP_MAX_LEN) ||
|
|
(_mbscspn((PBYTE)pszBackupLocation, (PBYTE)MD_BACKUP_INVALID_CHARS_A) !=
|
|
dwStringLen)) {
|
|
bReturn = FALSE;
|
|
}
|
|
else {
|
|
LPSTR pszIndex;
|
|
for (pszIndex = (LPSTR)pszBackupLocation;
|
|
(*pszIndex != (WCHAR)'\0') &&
|
|
(_ismbcprint(*pszIndex));
|
|
pszIndex = CharNextExA(CP_ACP,
|
|
pszIndex,
|
|
0)) {
|
|
}
|
|
if (*pszIndex != '\0') {
|
|
bReturn = FALSE;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
setlocale(LC_CTYPE, pszLocSave);
|
|
return bReturn;
|
|
}
|
|
|
|
DWORD
|
|
GetBackupNameLen(LPSTR pszBackupName)
|
|
|
|
//
|
|
// Get Number of Bytes in name prior to suffix
|
|
//
|
|
|
|
{
|
|
LPSTR pszSubString = NULL;
|
|
LPSTR pszNextSubString;
|
|
MD_REQUIRE((pszNextSubString = (LPSTR)MD_STRCHR(pszBackupName, '.')) != NULL);
|
|
while (pszNextSubString != NULL) {
|
|
|
|
//
|
|
// In case the suffix happens to be part of the name
|
|
//
|
|
|
|
pszSubString = pszNextSubString;
|
|
pszNextSubString = (LPSTR)MD_STRCHR(pszSubString+1, '.');
|
|
}
|
|
|
|
if (pszSubString
|
|
&& (pszSubString[1] != '\0')
|
|
&& (pszSubString[2] != '\0')
|
|
&& !IsDBCSLeadByte(pszSubString[1])
|
|
&& (toupper(pszSubString[1]) == 'M')
|
|
&& (toupper(pszSubString[2]) == 'D')) {
|
|
return DIFF(pszSubString - pszBackupName);
|
|
}
|
|
else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
DWORD
|
|
GetBackupNameLen(LPWSTR pszBackupName)
|
|
|
|
//
|
|
// Get Number of WCHARs in name prior to version Number
|
|
//
|
|
|
|
{
|
|
LPWSTR pszSubString = NULL;
|
|
LPWSTR pszNextSubString;
|
|
MD_REQUIRE((pszNextSubString = wcschr(pszBackupName, L'.')) != NULL);
|
|
while (pszNextSubString != NULL) {
|
|
pszSubString = pszNextSubString;
|
|
pszNextSubString = wcschr(pszSubString+1, L'.');
|
|
}
|
|
if (pszSubString
|
|
&& (pszSubString[1] != L'\0')
|
|
&& (pszSubString[2] != L'\0')
|
|
&& (towupper(pszSubString[1]) == L'M')
|
|
&& (towupper(pszSubString[2]) == L'D')) {
|
|
return DIFF(pszSubString - pszBackupName);
|
|
}
|
|
else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
HRESULT CreateBackupFileName(IN LPSTR pszMDBackupLocation,
|
|
IN DWORD dwMDVersion,
|
|
IN BOOL bUnicode,
|
|
IN OUT STRAU *pstrauBackupLocation)
|
|
{
|
|
HRESULT hresReturn = ERROR_SUCCESS;
|
|
LPSTR pszBackupLocation = pszMDBackupLocation;
|
|
|
|
if (((dwMDVersion > MD_BACKUP_MAX_VERSION) &&
|
|
(dwMDVersion != MD_BACKUP_NEXT_VERSION) &&
|
|
(dwMDVersion != MD_BACKUP_HIGHEST_VERSION)) ||
|
|
((pszBackupLocation != NULL) &&
|
|
!ValidateBackupLocation(pszBackupLocation, bUnicode))) {
|
|
hresReturn = E_INVALIDARG;
|
|
}
|
|
else {
|
|
|
|
if ((pszBackupLocation == NULL) ||
|
|
(bUnicode && ((*(LPWSTR)pszBackupLocation) == (WCHAR)'\0')) ||
|
|
(!bUnicode && ((*(LPSTR)pszBackupLocation) == (CHAR)'\0'))) {
|
|
pszBackupLocation = MD_DEFAULT_BACKUP_LOCATION;
|
|
bUnicode = FALSE;
|
|
}
|
|
|
|
if (!pstrauBackupLocation->Copy(g_pstrBackupFilePath->QueryStr())) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
else if (!pstrauBackupLocation->Append("\\")) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
else {
|
|
if (bUnicode) {
|
|
if (!pstrauBackupLocation->Append((LPWSTR)pszBackupLocation)) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
}
|
|
else {
|
|
if (!pstrauBackupLocation->Append((LPSTR)pszBackupLocation)) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hresReturn)) {
|
|
if (!pstrauBackupLocation->Append(MD_BACKUP_SUFFIX)) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
else {
|
|
DWORD dwVersion = dwMDVersion;
|
|
if (dwVersion == MD_BACKUP_NEXT_VERSION) {
|
|
hresReturn = GetHighestVersion(pstrauBackupLocation, &dwVersion);
|
|
if (SUCCEEDED(hresReturn)) {
|
|
if (dwVersion < MD_BACKUP_MAX_VERSION) {
|
|
dwVersion++;
|
|
}
|
|
else {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_NAME);
|
|
}
|
|
}
|
|
else if (hresReturn == RETURNCODETOHRESULT(ERROR_FILE_NOT_FOUND)) {
|
|
|
|
//
|
|
// Database doesn't exist, so new version is 0
|
|
//
|
|
|
|
dwVersion = 0;
|
|
hresReturn = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
else if (dwVersion == MD_BACKUP_HIGHEST_VERSION) {
|
|
hresReturn = GetHighestVersion(pstrauBackupLocation, &dwVersion);
|
|
}
|
|
if (SUCCEEDED(hresReturn)) {
|
|
CHAR pszBuffer[MD_MAX_DWORD_STRING];
|
|
_ultoa((int)dwVersion, pszBuffer, 10);
|
|
if (!pstrauBackupLocation->Append(pszBuffer)) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hresReturn)) {
|
|
//
|
|
// Make sure the ANSI buffer is valid
|
|
//
|
|
if (pstrauBackupLocation->QueryStrA() == NULL) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
}
|
|
}
|
|
|
|
return hresReturn;
|
|
}
|
|
|
|
HRESULT SetBackupPath(LPSTR pszBackupPath)
|
|
{
|
|
DWORD dwReturn = ERROR_DIRECTORY;
|
|
DWORD dwDirectoryAttributes;
|
|
|
|
dwDirectoryAttributes = GetFileAttributes(pszBackupPath);
|
|
|
|
if (dwDirectoryAttributes == 0xffffffff) {
|
|
//
|
|
// Can't get attributes
|
|
// Path probably doesn't exist
|
|
//
|
|
if (GetLastError() != ERROR_FILE_NOT_FOUND) {
|
|
dwReturn = GetLastError();
|
|
}
|
|
else if (!(CreateDirectory(pszBackupPath,
|
|
NULL))) {
|
|
dwReturn = GetLastError();
|
|
}
|
|
else {
|
|
dwReturn = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
else if ((dwDirectoryAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) {
|
|
//
|
|
// If a directory
|
|
//
|
|
dwReturn = ERROR_SUCCESS;
|
|
}
|
|
if (dwReturn == ERROR_SUCCESS) {
|
|
//
|
|
// Got it! Now set global variable
|
|
//
|
|
MD_ASSERT(g_pstrBackupFilePath == NULL);
|
|
g_pstrBackupFilePath = new STR(pszBackupPath);
|
|
if (g_pstrBackupFilePath == NULL) {
|
|
dwReturn = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
else if (!(g_pstrBackupFilePath->IsValid())) {
|
|
dwReturn = ERROR_NOT_ENOUGH_MEMORY;
|
|
delete g_pstrBackupFilePath;
|
|
g_pstrBackupFilePath = NULL;
|
|
}
|
|
else {
|
|
dwReturn = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
|
|
return RETURNCODETOHRESULT(dwReturn);
|
|
}
|
|
|
|
HRESULT
|
|
SetGlobalDataFileValues(LPTSTR pszFileName)
|
|
{
|
|
DWORD dwReturn = ERROR_SUCCESS;
|
|
HANDLE hFileHandle;
|
|
BOOL bMainFileFound = FALSE;
|
|
|
|
hFileHandle = CreateFile(pszFileName,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
0);
|
|
if (hFileHandle == INVALID_HANDLE_VALUE) {
|
|
if (GetLastError() != ERROR_FILE_NOT_FOUND) {
|
|
dwReturn = GetLastError();
|
|
}
|
|
else {
|
|
hFileHandle = CreateFile(pszFileName,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
CREATE_NEW,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
0);
|
|
if (hFileHandle == INVALID_HANDLE_VALUE) {
|
|
dwReturn = GetLastError();
|
|
}
|
|
else {
|
|
CloseHandle(hFileHandle);
|
|
DeleteFile(pszFileName);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
CloseHandle(hFileHandle);
|
|
bMainFileFound = TRUE;
|
|
}
|
|
if (dwReturn == ERROR_SUCCESS) {
|
|
g_strRealFileName = new STR(pszFileName);
|
|
g_strTempFileName = new STR(pszFileName);
|
|
g_strBackupFileName = new STR(pszFileName);
|
|
if( !g_strRealFileName || !g_strTempFileName || !g_strBackupFileName )
|
|
{
|
|
dwReturn = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
if (g_strTempFileName->IsValid()) {
|
|
g_strTempFileName->Append(MD_TEMP_DATA_FILE_EXT);
|
|
}
|
|
if (g_strBackupFileName->IsValid()) {
|
|
g_strBackupFileName->Append(MD_BACKUP_DATA_FILE_EXT);
|
|
}
|
|
if (!g_strTempFileName->IsValid() || !g_strBackupFileName->IsValid())
|
|
{
|
|
dwReturn = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
else {
|
|
|
|
hFileHandle = CreateFile(g_strTempFileName->QueryStr(),
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
0);
|
|
if (hFileHandle == INVALID_HANDLE_VALUE) {
|
|
if (GetLastError() != ERROR_FILE_NOT_FOUND) {
|
|
dwReturn = GetLastError();
|
|
}
|
|
else {
|
|
hFileHandle = CreateFile(g_strTempFileName->QueryStr(),
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
CREATE_NEW,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
0);
|
|
if (hFileHandle == INVALID_HANDLE_VALUE) {
|
|
dwReturn = GetLastError();
|
|
}
|
|
else {
|
|
CloseHandle(hFileHandle);
|
|
DeleteFile(g_strTempFileName->QueryStr());
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
CloseHandle(hFileHandle);
|
|
}
|
|
|
|
if (dwReturn == ERROR_SUCCESS) {
|
|
hFileHandle = CreateFile(g_strBackupFileName->QueryStr(),
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
0);
|
|
if (hFileHandle == INVALID_HANDLE_VALUE) {
|
|
if (GetLastError() != ERROR_FILE_NOT_FOUND) {
|
|
dwReturn = GetLastError();
|
|
}
|
|
else {
|
|
hFileHandle = CreateFile(g_strBackupFileName->QueryStr(),
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
CREATE_NEW,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
0);
|
|
if (hFileHandle == INVALID_HANDLE_VALUE) {
|
|
dwReturn = GetLastError();
|
|
}
|
|
else {
|
|
CloseHandle(hFileHandle);
|
|
DeleteFile(g_strBackupFileName->QueryStr());
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
CloseHandle(hFileHandle);
|
|
if (!bMainFileFound) {
|
|
if (!MoveFile(g_strBackupFileName->QueryStr(), pszFileName)) {
|
|
dwReturn = GetLastError();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (dwReturn != ERROR_SUCCESS)
|
|
{
|
|
if( g_strRealFileName )
|
|
{
|
|
delete(g_strRealFileName);
|
|
g_strRealFileName = NULL;
|
|
}
|
|
|
|
if( g_strTempFileName )
|
|
{
|
|
delete(g_strTempFileName);
|
|
g_strRealFileName = NULL;
|
|
}
|
|
|
|
if( g_strBackupFileName )
|
|
{
|
|
delete(g_strBackupFileName);
|
|
g_strRealFileName = NULL;
|
|
}
|
|
}
|
|
}
|
|
return RETURNCODETOHRESULT(dwReturn);
|
|
}
|
|
|
|
HRESULT
|
|
SetDataFile()
|
|
{
|
|
HRESULT hresReturn = RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND);
|
|
TCHAR pszBuffer[MAX_PATH];
|
|
HKEY hkRegistryKey = NULL;
|
|
DWORD dwRegReturn;
|
|
DWORD dwType;
|
|
DWORD dwSize = MAX_PATH * sizeof(TCHAR);
|
|
BOOL bAppendSlash = FALSE;
|
|
dwRegReturn = RegOpenKey(HKEY_LOCAL_MACHINE,
|
|
ADMIN_REG_KEY,
|
|
&hkRegistryKey);
|
|
if (dwRegReturn == ERROR_SUCCESS) {
|
|
dwRegReturn = RegQueryValueEx(hkRegistryKey,
|
|
MD_FILE_VALUE,
|
|
NULL,
|
|
&dwType,
|
|
(BYTE *) pszBuffer,
|
|
&dwSize);
|
|
if ((dwRegReturn == ERROR_SUCCESS) && dwType == (REG_SZ)) {
|
|
hresReturn = SetGlobalDataFileValues(pszBuffer);
|
|
}
|
|
|
|
MD_REQUIRE( RegCloseKey( hkRegistryKey ) == NO_ERROR );
|
|
hkRegistryKey = NULL;
|
|
|
|
}
|
|
if (FAILED(hresReturn)) {
|
|
dwRegReturn = RegOpenKey(HKEY_LOCAL_MACHINE,
|
|
SETUP_REG_KEY,
|
|
&hkRegistryKey);
|
|
if (dwRegReturn == ERROR_SUCCESS) {
|
|
dwSize = MAX_PATH * sizeof(TCHAR);
|
|
dwRegReturn = RegQueryValueEx(hkRegistryKey,
|
|
INSTALL_PATH_VALUE,
|
|
NULL,
|
|
&dwType,
|
|
(BYTE *) pszBuffer,
|
|
&dwSize);
|
|
if ((dwRegReturn == ERROR_SUCCESS) && dwType == (REG_SZ)) {
|
|
dwSize /= sizeof(TCHAR);
|
|
if ((pszBuffer[dwSize-2] != (TCHAR)'/') &&
|
|
(pszBuffer[dwSize-2] != (TCHAR)'\\')) {
|
|
bAppendSlash = TRUE;
|
|
}
|
|
if ((dwSize + MD_STRBYTES(MD_DEFAULT_DATA_FILE_NAME) + ((bAppendSlash) ? 1 : 0)) <= MAX_PATH) {
|
|
if (bAppendSlash) {
|
|
pszBuffer[dwSize-1] = (TCHAR)'\\';
|
|
pszBuffer[dwSize] = (TCHAR)'\0';
|
|
}
|
|
MD_STRCAT(pszBuffer, MD_DEFAULT_DATA_FILE_NAME);
|
|
hresReturn = SetGlobalDataFileValues(pszBuffer);
|
|
}
|
|
}
|
|
MD_REQUIRE( RegCloseKey( hkRegistryKey ) == NO_ERROR );
|
|
}
|
|
else {
|
|
hresReturn = RETURNCODETOHRESULT(dwRegReturn);
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hresReturn)) {
|
|
//
|
|
// Now get the backup path.
|
|
//
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND);
|
|
dwRegReturn = RegOpenKey(HKEY_LOCAL_MACHINE,
|
|
METADATA_BACKUP_REG_KEY,
|
|
&hkRegistryKey);
|
|
if (dwRegReturn == ERROR_SUCCESS) {
|
|
dwSize = MAX_PATH * sizeof(TCHAR);
|
|
dwRegReturn = RegQueryValueEx(hkRegistryKey,
|
|
MD_BACKUP_PATH_VALUE,
|
|
NULL,
|
|
&dwType,
|
|
(BYTE *) pszBuffer,
|
|
&dwSize);
|
|
if (dwRegReturn == ERROR_SUCCESS) {
|
|
hresReturn = SetBackupPath(pszBuffer);
|
|
}
|
|
MD_REQUIRE( RegCloseKey( hkRegistryKey ) == NO_ERROR );
|
|
}
|
|
|
|
if (FAILED(hresReturn)) {
|
|
dwRegReturn = RegOpenKey(HKEY_LOCAL_MACHINE,
|
|
SETUP_REG_KEY,
|
|
&hkRegistryKey);
|
|
if (dwRegReturn == ERROR_SUCCESS) {
|
|
dwSize = MAX_PATH * sizeof(TCHAR);
|
|
dwRegReturn = RegQueryValueEx(hkRegistryKey,
|
|
INSTALL_PATH_VALUE,
|
|
NULL,
|
|
&dwType,
|
|
(BYTE *) pszBuffer,
|
|
&dwSize);
|
|
if ((dwRegReturn == ERROR_SUCCESS) && dwType == (REG_SZ)) {
|
|
dwSize /= sizeof(TCHAR);
|
|
if ((pszBuffer[dwSize-2] != (TCHAR)'/') &&
|
|
(pszBuffer[dwSize-2] != (TCHAR)'\\')) {
|
|
bAppendSlash = TRUE;
|
|
}
|
|
if ((dwSize + MD_STRBYTES(MD_DEFAULT_DATA_FILE_NAME) + ((bAppendSlash) ? 1 : 0)) <= MAX_PATH) {
|
|
if (bAppendSlash) {
|
|
pszBuffer[dwSize-1] = (TCHAR)'\\';
|
|
pszBuffer[dwSize] = (TCHAR)'\0';
|
|
}
|
|
MD_STRCAT(pszBuffer, MD_DEFAULT_BACKUP_PATH_NAME);
|
|
hresReturn = SetBackupPath(pszBuffer);
|
|
}
|
|
}
|
|
MD_REQUIRE( RegCloseKey( hkRegistryKey ) == NO_ERROR );
|
|
}
|
|
else {
|
|
hresReturn = RETURNCODETOHRESULT(dwRegReturn);
|
|
}
|
|
}
|
|
}
|
|
|
|
return hresReturn;
|
|
}
|
|
|
|
DWORD GetObjectPath(CMDBaseObject *pboObject,
|
|
BUFFER *pbufPath,
|
|
DWORD &rdwStringLen,
|
|
CMDBaseObject *pboTopObject,
|
|
IN BOOL bUnicode)
|
|
{
|
|
DWORD dwReturn = ERROR_SUCCESS;
|
|
DWORD dwOldStringLen;
|
|
|
|
MD_ASSERT(pboObject != NULL);
|
|
if (pboObject != pboTopObject) {
|
|
dwReturn = GetObjectPath(pboObject->GetParent(),
|
|
pbufPath,
|
|
rdwStringLen,
|
|
pboTopObject,
|
|
bUnicode);
|
|
dwOldStringLen = rdwStringLen;
|
|
if (pboObject->GetName(bUnicode) == NULL) {
|
|
dwReturn = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
else {
|
|
if (bUnicode) {
|
|
rdwStringLen += (1 + wcslen((LPWSTR)pboObject->GetName(bUnicode)));
|
|
if (!pbufPath->Resize((rdwStringLen + 1) * sizeof(WCHAR))) {
|
|
dwReturn = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
else {
|
|
LPWSTR lpzStringEnd = (LPWSTR)(pbufPath->QueryPtr()) + dwOldStringLen;
|
|
*lpzStringEnd = MD_PATH_DELIMETERW;
|
|
wcscpy(lpzStringEnd+1, (LPWSTR)(pboObject->GetName(bUnicode)));
|
|
}
|
|
}
|
|
else {
|
|
rdwStringLen += (1 + MD_STRBYTES(pboObject->GetName(bUnicode)));
|
|
if (!pbufPath->Resize((rdwStringLen + 1) * sizeof(TCHAR))) {
|
|
dwReturn = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
else {
|
|
LPTSTR lpzStringEnd = (LPTSTR)(pbufPath->QueryPtr()) + dwOldStringLen;
|
|
*lpzStringEnd = MD_PATH_DELIMETERA;
|
|
MD_STRCPY(lpzStringEnd+1, pboObject->GetName(bUnicode));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return dwReturn;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
MakeInsertPathData(STRAU *pstrauNewData,
|
|
LPTSTR pszPath,
|
|
LPTSTR pszOldData,
|
|
DWORD *pdwDataLen,
|
|
BOOL bUnicode)
|
|
{
|
|
HRESULT hresReturn = ERROR_SUCCESS;
|
|
if (bUnicode) {
|
|
LPWSTR pszDataIndex, pszNextDataIndex;
|
|
|
|
pstrauNewData->SetLen(0);
|
|
for (pszDataIndex = (LPWSTR)pszOldData;
|
|
SUCCEEDED(hresReturn) && ((pszNextDataIndex = wcsstr(pszDataIndex, MD_INSERT_PATH_STRINGW)) != NULL);
|
|
pszDataIndex = pszNextDataIndex + ((sizeof(MD_INSERT_PATH_STRINGW) / sizeof(WCHAR)) - 1)) {
|
|
// *pszNextDataIndex = (TCHAR)'\0';
|
|
if (!(pstrauNewData->Append(pszDataIndex, DIFF(pszNextDataIndex - pszDataIndex)))) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
if (!(pstrauNewData->Append((LPWSTR)pszPath))) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
}
|
|
if (!(pstrauNewData->Append(pszDataIndex))) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
*pdwDataLen = pstrauNewData->QueryCB(bUnicode) + sizeof(WCHAR);
|
|
}
|
|
else {
|
|
LPTSTR pszDataIndex, pszNextDataIndex;
|
|
|
|
pstrauNewData->SetLen(0);
|
|
for (pszDataIndex = pszOldData;
|
|
SUCCEEDED(hresReturn) && ((pszNextDataIndex = MD_STRSTR(pszDataIndex, MD_INSERT_PATH_STRINGA)) != NULL);
|
|
pszDataIndex = pszNextDataIndex + ((sizeof(MD_INSERT_PATH_STRINGA) - 1))) {
|
|
// *pszNextDataIndex = (TCHAR)'\0';
|
|
if (!(pstrauNewData->Append(pszDataIndex, DIFF(pszNextDataIndex - pszDataIndex)))) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
if (!(pstrauNewData->Append(pszPath))) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
}
|
|
if (!(pstrauNewData->Append(pszDataIndex))) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
*pdwDataLen = pstrauNewData->QueryCB(bUnicode) + sizeof(CHAR);
|
|
}
|
|
return hresReturn;
|
|
}
|
|
|
|
HRESULT
|
|
InsertPathIntoData(BUFFER *pbufNewData,
|
|
STRAU *pstrData,
|
|
PBYTE *ppbNewData,
|
|
DWORD *pdwNewDataLen,
|
|
CMDBaseData *pbdRetrieve,
|
|
METADATA_HANDLE hHandle,
|
|
CMDBaseObject *pboDataMetaObject,
|
|
IN BOOL bUnicode)
|
|
{
|
|
//
|
|
// Need to insert path
|
|
//
|
|
HRESULT hresReturn = ERROR_SUCCESS;
|
|
CMDHandle * phMDHandle;
|
|
DWORD dwPathLen = 0;
|
|
BUFFER bufPath;
|
|
|
|
phMDHandle = GetHandleObject(hHandle);
|
|
if( !phMDHandle )
|
|
{
|
|
return MD_WARNING_PATH_NOT_INSERTED;
|
|
}
|
|
|
|
CMDBaseObject *pboHandleMetaObject = phMDHandle->GetObject();
|
|
|
|
MD_ASSERT((pbdRetrieve->GetDataType() != DWORD_METADATA) &&
|
|
(pbdRetrieve->GetDataType() != BINARY_METADATA));
|
|
|
|
if (pboHandleMetaObject->GetObjectLevel() > pboDataMetaObject->GetObjectLevel()) {
|
|
hresReturn = MD_WARNING_PATH_NOT_INSERTED;
|
|
}
|
|
else {
|
|
DWORD dwReturn;
|
|
if ( (dwReturn = GetObjectPath(pboDataMetaObject,
|
|
&bufPath,
|
|
dwPathLen,
|
|
pboHandleMetaObject,
|
|
bUnicode)) != ERROR_SUCCESS) {
|
|
hresReturn = RETURNCODETOHRESULT(dwReturn);
|
|
}
|
|
else if (!bufPath.Resize((dwPathLen + 2) * ((bUnicode) ? sizeof(WCHAR) : sizeof(CHAR)))) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
else {
|
|
LPTSTR pszPath;
|
|
LPTSTR pszOriginalData;
|
|
DWORD dwDataLen;
|
|
pszPath = (LPTSTR)(bufPath.QueryPtr());
|
|
if (bUnicode) {
|
|
((LPWSTR)pszPath)[dwPathLen] = MD_PATH_DELIMETERW;
|
|
((LPWSTR)pszPath)[dwPathLen + 1] = (WCHAR)'\0';
|
|
}
|
|
else {
|
|
pszPath[dwPathLen] = MD_PATH_DELIMETERA;
|
|
pszPath[dwPathLen + 1] = (TCHAR)'\0';
|
|
}
|
|
//
|
|
// If there was an error in GetData, it would have been
|
|
// caught already.
|
|
//
|
|
MD_ASSERT(pbdRetrieve->GetData(bUnicode) != NULL);
|
|
switch (pbdRetrieve->GetDataType()) {
|
|
case STRING_METADATA:
|
|
case EXPANDSZ_METADATA:
|
|
{
|
|
hresReturn = MakeInsertPathData(pstrData,
|
|
(LPTSTR)bufPath.QueryPtr(),
|
|
(LPTSTR)pbdRetrieve->GetData(bUnicode),
|
|
&dwDataLen,
|
|
bUnicode);
|
|
if (SUCCEEDED(hresReturn)) {
|
|
//
|
|
// QueryStr should not fail in this instance
|
|
// since it was created with the same unicode flag
|
|
//
|
|
MD_ASSERT(pstrData->QueryStr(bUnicode) != NULL);
|
|
*ppbNewData = (PBYTE) pstrData->QueryStr(bUnicode);
|
|
*pdwNewDataLen = dwDataLen;
|
|
}
|
|
}
|
|
break;
|
|
case MULTISZ_METADATA:
|
|
{
|
|
if (bUnicode) {
|
|
LPWSTR pszDataIndex;
|
|
DWORD dwStringBytes;
|
|
dwDataLen = 0;
|
|
//
|
|
// Loop through all strings
|
|
//
|
|
for (pszDataIndex = (LPWSTR)pbdRetrieve->GetData(bUnicode);
|
|
SUCCEEDED(hresReturn) && (*pszDataIndex != (WCHAR)'\0');
|
|
pszDataIndex += (wcslen(pszDataIndex) + 1)) {
|
|
hresReturn = MakeInsertPathData(pstrData,
|
|
(LPSTR)bufPath.QueryPtr(),
|
|
(LPSTR)pszDataIndex,
|
|
&dwStringBytes,
|
|
bUnicode);
|
|
if (SUCCEEDED(hresReturn)) {
|
|
if (!pbufNewData->Resize(dwDataLen + dwStringBytes)) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
else {
|
|
//
|
|
// QueryStr should not fail in this instance
|
|
// since it was created with the same unicode flag
|
|
//
|
|
MD_ASSERT(pstrData->QueryStr(bUnicode) != NULL);
|
|
MD_COPY((PBYTE)(pbufNewData->QueryPtr()) + dwDataLen,
|
|
pstrData->QueryStr(bUnicode),
|
|
dwStringBytes);
|
|
dwDataLen += dwStringBytes;
|
|
}
|
|
}
|
|
}
|
|
if (SUCCEEDED(hresReturn)) {
|
|
dwDataLen += sizeof(WCHAR);
|
|
if (!pbufNewData->Resize(dwDataLen)) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
else {
|
|
*ppbNewData = (PBYTE)(pbufNewData->QueryPtr());
|
|
*(((LPWSTR)(*ppbNewData)) + ((dwDataLen / sizeof(WCHAR)) - 1)) = (WCHAR)'\0';
|
|
*pdwNewDataLen = dwDataLen;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
LPSTR pszDataIndex;
|
|
DWORD dwStringBytes;
|
|
dwDataLen = 0;
|
|
//
|
|
// Loop through all strings
|
|
//
|
|
for (pszDataIndex = (LPTSTR)pbdRetrieve->GetData(bUnicode);
|
|
SUCCEEDED(hresReturn) && (*pszDataIndex != (CHAR)'\0');
|
|
pszDataIndex += (MD_STRBYTES(pszDataIndex) + 1)) {
|
|
hresReturn = MakeInsertPathData(pstrData,
|
|
(LPTSTR)bufPath.QueryPtr(),
|
|
pszDataIndex,
|
|
&dwStringBytes);
|
|
if (SUCCEEDED(hresReturn)) {
|
|
if (!pbufNewData->Resize(dwDataLen + dwStringBytes)) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
else {
|
|
//
|
|
// QueryStr should not fail in this instance
|
|
// since it was created with the same unicode flag
|
|
//
|
|
MD_ASSERT(pstrData->QueryStrA() != NULL);
|
|
MD_COPY((PBYTE)(pbufNewData->QueryPtr()) + dwDataLen, pstrData->QueryStrA(), dwStringBytes);
|
|
dwDataLen += dwStringBytes;
|
|
}
|
|
}
|
|
}
|
|
if (SUCCEEDED(hresReturn)) {
|
|
dwDataLen += sizeof(TCHAR);
|
|
if (!pbufNewData->Resize(dwDataLen)) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
else {
|
|
*ppbNewData = (PBYTE)(pbufNewData->QueryPtr());
|
|
*(*ppbNewData + (dwDataLen-1)) = (CHAR)'\0';
|
|
*pdwNewDataLen = dwDataLen;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
MD_ASSERT(FALSE);
|
|
}
|
|
}
|
|
}
|
|
return hresReturn;
|
|
}
|
|
|
|
HRESULT
|
|
MakeTreeCopyWithPath(CMDBaseObject *pboSource,
|
|
CMDBaseObject *&rpboNew,
|
|
LPSTR pszPath,
|
|
IN BOOL bUnicode)
|
|
{
|
|
WCHAR pszName[METADATA_MAX_NAME_LEN];
|
|
LPSTR pszTempPath = pszPath;
|
|
CMDBaseObject *pboNew = NULL;
|
|
CMDBaseObject *pboParent = NULL;
|
|
CMDBaseObject *pboTree = NULL;
|
|
CMDBaseObject *pboRoot = NULL;
|
|
HRESULT hresReturn = ERROR_SUCCESS;
|
|
HRESULT hresExtractReturn;
|
|
|
|
while ((SUCCEEDED(hresReturn)) &&
|
|
(SUCCEEDED(hresExtractReturn = ExtractNameFromPath(pszTempPath, (LPSTR)pszName, bUnicode)))) {
|
|
|
|
if (bUnicode) {
|
|
pboNew = new CMDBaseObject((LPWSTR)pszName);
|
|
}
|
|
else {
|
|
pboNew = new CMDBaseObject((LPSTR)pszName);
|
|
}
|
|
if (pboNew == NULL) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
else if (!pboNew->IsValid()) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
|
|
delete (pboNew);
|
|
}
|
|
else {
|
|
if (pboParent != NULL) {
|
|
hresReturn = pboParent->InsertChildObject(pboNew);
|
|
if (FAILED(hresReturn)) {
|
|
delete pboNew;
|
|
pboNew = pboParent;
|
|
}
|
|
}
|
|
pboParent = pboNew;
|
|
}
|
|
}
|
|
|
|
if ((SUCCEEDED(hresReturn)) && (hresExtractReturn != (RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND)))) {
|
|
hresReturn = hresExtractReturn;
|
|
}
|
|
|
|
if (SUCCEEDED(hresReturn)) {
|
|
|
|
//
|
|
// Don't really want the leaf object, as MakeTreeCopy will create it.
|
|
//
|
|
|
|
LPWSTR pszTreeName = NULL;
|
|
|
|
if (pboNew != NULL) {
|
|
pszTreeName = (LPWSTR)pboNew->GetName(TRUE);
|
|
pboParent = pboNew->GetParent();
|
|
if (pszTreeName == NULL) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
}
|
|
if (SUCCEEDED(hresReturn)) {
|
|
hresReturn = MakeTreeCopy(pboSource, pboTree, (LPSTR)pszTreeName, TRUE);
|
|
|
|
if (SUCCEEDED(hresReturn)) {
|
|
MD_ASSERT(pboTree != NULL);
|
|
|
|
if (pboParent != NULL) {
|
|
MD_REQUIRE(SUCCEEDED(pboParent->RemoveChildObject(pboNew)));
|
|
hresReturn = pboParent->InsertChildObject(pboTree);
|
|
if (FAILED(hresReturn)) {
|
|
delete(pboTree);
|
|
pboTree = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
delete(pboNew);
|
|
pboNew = NULL;
|
|
}
|
|
|
|
if (FAILED(hresReturn)) {
|
|
if (pboParent != NULL) {
|
|
CMDBaseObject *pboTemp;
|
|
MD_ASSERT(pboNew != NULL);
|
|
for (pboTemp = pboParent; pboTemp->GetParent() != NULL; pboTemp = pboTemp->GetParent()) {
|
|
}
|
|
//
|
|
// destructor recurses through child objects
|
|
//
|
|
delete pboTemp;
|
|
}
|
|
}
|
|
else {
|
|
MD_ASSERT(pboTree != NULL);
|
|
CMDBaseObject *pboTemp;
|
|
for (pboTemp = pboTree; pboTemp->GetParent() != NULL; pboTemp = pboTemp->GetParent()) {
|
|
}
|
|
rpboNew = pboTemp;
|
|
}
|
|
|
|
return hresReturn;
|
|
}
|
|
|
|
HRESULT
|
|
MakeTreeCopy(CMDBaseObject *pboSource,
|
|
CMDBaseObject *&rpboNew,
|
|
LPSTR pszName,
|
|
IN BOOL bUnicode)
|
|
{
|
|
CMDBaseObject *pboTemp = NULL;
|
|
CMDBaseObject *pboOldChild, *pboNewChild;
|
|
DWORD i, dwNumDataObjects;
|
|
PVOID *ppvMainDataBuf;
|
|
CMDBaseData *pbdCurrent;
|
|
HRESULT hresReturn = ERROR_SUCCESS;
|
|
|
|
if (pszName == NULL) {
|
|
if ((pboSource->GetName(TRUE)) != NULL) {
|
|
pboTemp = new CMDBaseObject((LPWSTR)(pboSource->GetName(TRUE)), NULL);
|
|
}
|
|
}
|
|
else {
|
|
if (bUnicode) {
|
|
pboTemp = new CMDBaseObject((LPWSTR)pszName, NULL);
|
|
}
|
|
else {
|
|
pboTemp = new CMDBaseObject((LPSTR)pszName, NULL);
|
|
}
|
|
}
|
|
if (pboTemp == NULL) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
else if (!pboTemp->IsValid()) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
|
|
delete (pboTemp);
|
|
}
|
|
else {
|
|
ppvMainDataBuf = GetMainDataBuffer();
|
|
MD_ASSERT (ppvMainDataBuf != NULL);
|
|
dwNumDataObjects = pboSource->GetAllDataObjects(ppvMainDataBuf, 0, ALL_METADATA, ALL_METADATA, FALSE);
|
|
for (i = 0; (i < dwNumDataObjects) && (SUCCEEDED(hresReturn)) ; i++) {
|
|
pbdCurrent=(CMDBaseData *)GetItemFromDataBuffer(ppvMainDataBuf, i);
|
|
MD_ASSERT(pbdCurrent != NULL);
|
|
hresReturn = pboTemp->SetDataObject(pbdCurrent);
|
|
}
|
|
FreeMainDataBuffer(ppvMainDataBuf);
|
|
}
|
|
if (SUCCEEDED(hresReturn)) {
|
|
i = 0;
|
|
pboOldChild = pboSource->EnumChildObject(i);
|
|
while ((SUCCEEDED(hresReturn)) && (pboOldChild != NULL)) {
|
|
hresReturn = MakeTreeCopy(pboOldChild, pboNewChild, NULL, bUnicode);
|
|
if (SUCCEEDED(hresReturn)) {
|
|
MD_ASSERT (pboNewChild != NULL);
|
|
hresReturn = pboTemp->InsertChildObject(pboNewChild);
|
|
}
|
|
i++;
|
|
pboOldChild = pboSource->EnumChildObject(i);
|
|
}
|
|
}
|
|
if (SUCCEEDED(hresReturn)) {
|
|
rpboNew = pboTemp;
|
|
}
|
|
else {
|
|
rpboNew = NULL;
|
|
delete(pboTemp);
|
|
}
|
|
return (hresReturn);
|
|
}
|
|
|
|
void
|
|
AddNewChangeData(CMDHandle *phoDestHandle,
|
|
CMDBaseObject *pboNew)
|
|
{
|
|
DWORD i, dwNumDataObjects;
|
|
CMDBaseObject *pboChild;
|
|
CMDBaseData *pbdCurrent;
|
|
|
|
MD_ASSERT(pboNew != NULL);
|
|
|
|
phoDestHandle->SetChangeData(pboNew, MD_CHANGE_TYPE_ADD_OBJECT, 0);
|
|
if ((pbdCurrent = pboNew->EnumDataObject(0, 0, ALL_METADATA, ALL_METADATA)) != NULL) {
|
|
phoDestHandle->SetChangeData(pboNew, MD_CHANGE_TYPE_SET_DATA, pbdCurrent->GetIdentifier());
|
|
}
|
|
i = 0;
|
|
pboChild = pboNew->EnumChildObject(i);
|
|
while (pboChild != NULL) {
|
|
AddNewChangeData(phoDestHandle, pboChild);
|
|
i++;
|
|
pboChild = pboNew->EnumChildObject(i);
|
|
}
|
|
}
|
|
|
|
HRESULT
|
|
CopyTree(CMDHandle *phoDestParentHandle,
|
|
CMDBaseObject *pboDest,
|
|
CMDBaseObject *pboSource,
|
|
BOOL &rbChanged)
|
|
|
|
{
|
|
CMDBaseObject *pboOldChild, *pboNewChild;
|
|
DWORD i, dwNumDataObjects;
|
|
PVOID *ppvMainDataBuf;
|
|
CMDBaseData *pbdCurrent;
|
|
LPSTR pszTempName;
|
|
HRESULT hresReturn = ERROR_SUCCESS;
|
|
|
|
MD_ASSERT(pboDest != NULL);
|
|
MD_ASSERT(pboSource != NULL);
|
|
ppvMainDataBuf = GetMainDataBuffer();
|
|
MD_ASSERT (ppvMainDataBuf != NULL);
|
|
dwNumDataObjects = pboSource->GetAllDataObjects(ppvMainDataBuf, 0, ALL_METADATA, ALL_METADATA, FALSE);
|
|
for (i = 0; (i < dwNumDataObjects) && (SUCCEEDED(hresReturn)) ; i++) {
|
|
pbdCurrent=(CMDBaseData *)GetItemFromDataBuffer(ppvMainDataBuf, i);
|
|
MD_ASSERT(pbdCurrent != NULL);
|
|
hresReturn = pboDest->SetDataObject(pbdCurrent);
|
|
if (SUCCEEDED(hresReturn)) {
|
|
rbChanged = TRUE;
|
|
phoDestParentHandle->SetChangeData(pboDest, MD_CHANGE_TYPE_SET_DATA, pbdCurrent->GetIdentifier());
|
|
}
|
|
}
|
|
if (SUCCEEDED(hresReturn)) {
|
|
i = 0;
|
|
pboOldChild = pboSource->EnumChildObject(i);
|
|
while ((SUCCEEDED(hresReturn)) && (pboOldChild != NULL)) {
|
|
pszTempName = (pboOldChild->GetName(TRUE));
|
|
if (pszTempName == NULL) {
|
|
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
else {
|
|
pboNewChild = pboDest->GetChildObject(pszTempName, &hresReturn, TRUE);
|
|
if (SUCCEEDED(hresReturn)) {
|
|
if (pboNewChild != NULL) {
|
|
hresReturn = CopyTree(phoDestParentHandle, pboNewChild, pboOldChild, rbChanged);
|
|
}
|
|
else {
|
|
hresReturn = MakeTreeCopy(pboOldChild, pboNewChild);
|
|
if (SUCCEEDED(hresReturn)) {
|
|
MD_ASSERT (pboNewChild != NULL);
|
|
hresReturn = pboDest->InsertChildObject(pboNewChild);
|
|
if (SUCCEEDED(hresReturn)) {
|
|
rbChanged = TRUE;
|
|
AddNewChangeData(phoDestParentHandle, pboNewChild);
|
|
}
|
|
else {
|
|
delete(pboNewChild);
|
|
}
|
|
}
|
|
}
|
|
i++;
|
|
pboOldChild = pboSource->EnumChildObject(i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
FreeMainDataBuffer(ppvMainDataBuf);
|
|
return (hresReturn);
|
|
}
|
|
|
|
void CheckForNewMetabaseVersion()
|
|
{
|
|
BOOL bValueWasWrongType = FALSE;
|
|
BOOL bSomethingChanged = FALSE;
|
|
HKEY hkRegistryKey = NULL;
|
|
DWORD dwRegReturn,dwValue,dwType,dwSize = sizeof(DWORD);
|
|
|
|
dwRegReturn = RegOpenKey(HKEY_LOCAL_MACHINE,
|
|
SETUP_REG_KEY,
|
|
&hkRegistryKey);
|
|
if (dwRegReturn == ERROR_SUCCESS)
|
|
{
|
|
// Check for update to major version
|
|
|
|
// get the Type of data only first
|
|
// since a string won't fit in &dwValue
|
|
dwValue = 0;
|
|
dwSize = MAX_PATH * sizeof(TCHAR);
|
|
dwRegReturn = RegQueryValueEx(hkRegistryKey,
|
|
MD_SETMAJORVERSION_VALUE,
|
|
NULL,
|
|
&dwType,
|
|
NULL,
|
|
&dwSize);
|
|
if ( dwRegReturn == ERROR_SUCCESS)
|
|
{
|
|
if (dwType == REG_DWORD)
|
|
{
|
|
dwRegReturn = RegQueryValueEx(hkRegistryKey,
|
|
MD_SETMAJORVERSION_VALUE,
|
|
NULL,
|
|
&dwType,
|
|
(BYTE *)&dwValue,
|
|
&dwSize);
|
|
if ( dwRegReturn == ERROR_SUCCESS)
|
|
{
|
|
// default the value with the version that this binary was compiled with
|
|
if (dwType == REG_DWORD)
|
|
{
|
|
if (g_dwMajorVersionNumber != dwValue && dwValue >= 1)
|
|
{
|
|
g_dwMajorVersionNumber = dwValue;
|
|
bSomethingChanged = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bValueWasWrongType = TRUE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bValueWasWrongType = TRUE;
|
|
}
|
|
}
|
|
|
|
if (FALSE == bValueWasWrongType)
|
|
{
|
|
// Check for update to minor version
|
|
|
|
// get the Type of data only first
|
|
// since a string won't fit in &dwValue
|
|
dwValue = 0;
|
|
dwSize = MAX_PATH * sizeof(TCHAR);
|
|
dwRegReturn = RegQueryValueEx(hkRegistryKey,
|
|
MD_SETMINORVERSION_VALUE,
|
|
NULL,
|
|
&dwType,
|
|
NULL,
|
|
&dwSize);
|
|
if ( dwRegReturn == ERROR_SUCCESS)
|
|
{
|
|
if (dwType == REG_DWORD)
|
|
{
|
|
dwRegReturn = RegQueryValueEx(hkRegistryKey,
|
|
MD_SETMINORVERSION_VALUE,
|
|
NULL,
|
|
&dwType,
|
|
(BYTE *)&dwValue,
|
|
&dwSize);
|
|
if ( dwRegReturn == ERROR_SUCCESS)
|
|
{
|
|
if (dwType == REG_DWORD)
|
|
{
|
|
if (g_dwMinorVersionNumber != dwValue)
|
|
{
|
|
g_dwMinorVersionNumber = dwValue;
|
|
bSomethingChanged = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bValueWasWrongType = TRUE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bValueWasWrongType = TRUE;
|
|
}
|
|
}
|
|
}
|
|
MD_REQUIRE( RegCloseKey( hkRegistryKey ) == NO_ERROR );
|
|
}
|
|
|
|
if (TRUE == bValueWasWrongType)
|
|
{
|
|
// default the value with the version that this binary was compiled with
|
|
|
|
if (g_dwMajorVersionNumber != MD_MAJOR_VERSION_NUMBER)
|
|
{
|
|
g_dwMajorVersionNumber = MD_MAJOR_VERSION_NUMBER;
|
|
bSomethingChanged = TRUE;
|
|
}
|
|
|
|
if (g_dwMinorVersionNumber != MD_MINOR_VERSION_NUMBER)
|
|
{
|
|
g_dwMinorVersionNumber = MD_MINOR_VERSION_NUMBER;
|
|
bSomethingChanged = TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
if (TRUE == bSomethingChanged)
|
|
{
|
|
// make sure that we tell the metabase that there was a change made..
|
|
g_dwSystemChangeNumber++;
|
|
IIS_PRINTF((buff,"MD:New Metabase Version:%d.%d\n",g_dwMajorVersionNumber,g_dwMinorVersionNumber));
|
|
}
|
|
return;
|
|
}
|
|
|
|
BOOL
|
|
CheckVersionNumber()
|
|
{
|
|
BOOL bReturn = FALSE;
|
|
|
|
if (g_dwMajorVersionNumber >= 1) {
|
|
// 1 = IIS4
|
|
// we need to be able to open IIS4 in IIS5 during setup upgrade
|
|
// 2 = IIS5
|
|
bReturn = TRUE;
|
|
}
|
|
|
|
// g_dwMinorVersionNumber -- maybe use this for Major service pack releases or something in which
|
|
// Metabase has been changed and we need to know the difference?
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
HRESULT
|
|
InitStorageAndSessionKey(
|
|
IN IIS_CRYPTO_STORAGE *pCryptoStorage,
|
|
OUT PIIS_CRYPTO_BLOB *ppSessionKeyBlob
|
|
)
|
|
{
|
|
HRESULT hresReturn;
|
|
HCRYPTPROV hProv;
|
|
|
|
//
|
|
// Get a handle to the crypto provider, init the storage object,
|
|
// then export the session key blob.
|
|
//
|
|
|
|
hresReturn = GetCryptoProvider( &hProv );
|
|
if( SUCCEEDED(hresReturn) )
|
|
{
|
|
hresReturn = pCryptoStorage->Initialize(
|
|
TRUE, // fUseMachineKeyset
|
|
hProv
|
|
);
|
|
if (FAILED(hresReturn))
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT, "InitStorageAndSessionKey: pCryptoStorage->Initialize Failed - error 0x%0x\n", hresReturn));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT, "InitStorageAndSessionKey: GetCryptoProvider Failed - error 0x%0x\n", hresReturn));
|
|
}
|
|
|
|
if( SUCCEEDED(hresReturn) )
|
|
{
|
|
hresReturn = pCryptoStorage->GetSessionKeyBlob( ppSessionKeyBlob );
|
|
if (FAILED(hresReturn))
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT, "InitStorageAndSessionKey: pCryptoStorage->GetSessionKeyBlob Failed - error 0x%0x\n", hresReturn));
|
|
}
|
|
}
|
|
|
|
return hresReturn;
|
|
|
|
} // InitStorageAndSessionKey
|
|
|
|
HRESULT
|
|
InitStorageAndSessionKey2(
|
|
IN LPSTR pszPasswd,
|
|
IN IIS_CRYPTO_STORAGE *pCryptoStorage,
|
|
OUT PIIS_CRYPTO_BLOB *ppSessionKeyBlob
|
|
)
|
|
{
|
|
HRESULT hresReturn;
|
|
HCRYPTPROV hProv;
|
|
|
|
//
|
|
// Get a handle to the crypto provider, init the storage object,
|
|
// then export the session key blob.
|
|
//
|
|
|
|
hresReturn = GetCryptoProvider2( &hProv );
|
|
if( SUCCEEDED(hresReturn) )
|
|
{
|
|
hresReturn = ((IIS_CRYPTO_STORAGE2*)pCryptoStorage)->Initialize(
|
|
hProv
|
|
);
|
|
if (FAILED(hresReturn))
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT, "InitStorageAndSessionKey: pCryptoStorage->Initialize Failed - error 0x%0x\n", hresReturn));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT, "InitStorageAndSessionKey: GetCryptoProvider2 Failed - error 0x%0x\n", hresReturn));
|
|
}
|
|
|
|
if( SUCCEEDED(hresReturn) )
|
|
{
|
|
hresReturn = ((IIS_CRYPTO_STORAGE2*)pCryptoStorage)->GetSessionKeyBlob( pszPasswd, ppSessionKeyBlob );
|
|
if (FAILED(hresReturn))
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT, "InitStorageAndSessionKey: pCryptoStorage->GetSessionKeyBlob Failed - error 0x%0x\n", hresReturn));
|
|
}
|
|
}
|
|
|
|
return hresReturn;
|
|
|
|
} // InitStorageAndSessionKey2
|
|
|
|
|
|
VOID
|
|
SkipPathDelimeter(IN OUT LPSTR &rpszPath,
|
|
IN BOOL bUnicode)
|
|
{
|
|
if (bUnicode) {
|
|
LPWSTR pszPath = (LPWSTR)rpszPath;
|
|
SKIP_PATH_DELIMETERW(pszPath);
|
|
rpszPath = (LPSTR)pszPath;
|
|
}
|
|
else {
|
|
SKIP_PATH_DELIMETERA(rpszPath);
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
IsStringTerminator(IN LPTSTR pszString,
|
|
IN BOOL bUnicode)
|
|
{
|
|
if (bUnicode) {
|
|
if (*(LPWSTR)pszString == (WCHAR)'\0') {
|
|
return TRUE;
|
|
}
|
|
}
|
|
else {
|
|
if (*(LPSTR)pszString == (CHAR)'\0') {
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
HRESULT
|
|
GetLastHResult() {
|
|
DWORD tmp = GetLastError();
|
|
return RETURNCODETOHRESULT(tmp);
|
|
}
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE BackupCertificates (LPCWSTR backupName,PCHAR lpszToPath,PCHAR lpszFromPath)
|
|
{
|
|
HRESULT hresReturn = ERROR_SUCCESS;
|
|
CHAR *p1,*p2;
|
|
LPSTR searchMask = "*.mp";
|
|
LPSTR backupNameSeparator = ".";
|
|
CHAR strSourcePath[MAX_PATH];
|
|
CHAR strSearchPattern[MAX_PATH];
|
|
CHAR strDestPath[MAX_PATH];
|
|
DWORD dwLenOfBackupName, n1;
|
|
HANDLE hFindFile = INVALID_HANDLE_VALUE;
|
|
WIN32_FIND_DATA FileInfo;
|
|
BOOL fFoundFile = TRUE, fValid;
|
|
STRAU strSrcFileName, strDestFileName;
|
|
|
|
dwLenOfBackupName = wcslen (backupName) * sizeof (WCHAR);
|
|
p1 = strrchr (lpszFromPath,'\\');
|
|
p2 = strrchr (lpszToPath,'\\');
|
|
if (p1 &&p2)
|
|
{
|
|
n1 = min (MAX_PATH-1, DIFF(p1 - lpszFromPath)+1);
|
|
strncpy (strSourcePath,lpszFromPath,n1);
|
|
strSourcePath[n1] = 0;
|
|
strcpy (strSearchPattern,strSourcePath);
|
|
|
|
n1 = min (MAX_PATH-1, DIFF(p2 - lpszToPath)+1);
|
|
strncpy (strDestPath,lpszToPath,n1);
|
|
strDestPath[n1] = 0;
|
|
|
|
if (strlen (strSourcePath) + strlen(searchMask) < MAX_PATH)
|
|
{
|
|
strcat (strSearchPattern,searchMask);
|
|
hFindFile = FindFirstFile( strSearchPattern, &FileInfo);
|
|
|
|
if (hFindFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
// no certificate file found
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
while (fFoundFile)
|
|
{
|
|
if ( strlen (FileInfo.cFileName) + strlen (strDestPath) + dwLenOfBackupName + 1 < MAX_PATH)
|
|
{
|
|
|
|
fValid = strSrcFileName.Copy (strSourcePath);
|
|
fValid = fValid && strSrcFileName.Append (FileInfo.cFileName);
|
|
|
|
fValid = fValid && strDestFileName.Copy (strDestPath);
|
|
fValid = fValid && strDestFileName.Append ((LPWSTR)backupName);
|
|
fValid = fValid && strDestFileName.Append (backupNameSeparator);
|
|
fValid = fValid && strDestFileName.Append (FileInfo.cFileName);
|
|
|
|
if (fValid)
|
|
{
|
|
if (!CopyFileW (strSrcFileName.QueryStrW(),strDestFileName.QueryStrW(),FALSE))
|
|
{
|
|
IIS_PRINTF((buff,"CertificateBackup: CopyFileW error 0x%0X \n",GetLastError()));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
IIS_PRINTF((buff,"CertificateBackup: Failure in STRAU manipulation \n"));
|
|
}
|
|
|
|
}
|
|
|
|
fFoundFile = FindNextFile(hFindFile,&FileInfo);
|
|
}
|
|
fFoundFile = FindClose (hFindFile);
|
|
MD_ASSERT (fFoundFile);
|
|
}
|
|
else
|
|
{
|
|
IIS_PRINTF((buff,"CertificateBackup: strSourcePath filename was too long\n"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
IIS_PRINTF((buff,"CertificateBackup: can't find last back slash in one of these strings %s %s\n",lpszToPath,lpszFromPath));
|
|
}
|
|
return hresReturn;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE RestoreCertificates (LPCWSTR backupName,PCHAR lpszFromPath,PCHAR lpszToPath)
|
|
{
|
|
HRESULT hresReturn = ERROR_SUCCESS;
|
|
DWORD n1;
|
|
CHAR strDestinationPath[MAX_PATH];
|
|
CHAR strSourcePath[MAX_PATH];
|
|
CHAR *p1,*p2;
|
|
HANDLE hFindFile = INVALID_HANDLE_VALUE;
|
|
BOOL fFoundFile = TRUE, fValid;
|
|
STRAU strSearchPatttern, strDestFileName, strSrcFileName;
|
|
WIN32_FIND_DATAW FileInfo;
|
|
LPWSTR pszSearchPattern = NULL;
|
|
|
|
|
|
p1 = strrchr (lpszToPath,'\\');
|
|
p2 = strrchr (lpszFromPath,'\\');
|
|
|
|
|
|
if (p1 &&p2)
|
|
{
|
|
|
|
n1 = min (MAX_PATH-1, DIFF(p1 - lpszToPath)+1);
|
|
strncpy (strDestinationPath,lpszToPath,n1);
|
|
strDestinationPath[n1] = 0;
|
|
|
|
n1 = min (MAX_PATH-1, DIFF(p2 - lpszFromPath)+1);
|
|
strncpy (strSourcePath,lpszFromPath,n1);
|
|
strSourcePath[n1] = 0;
|
|
|
|
|
|
strSearchPatttern.Copy (strSourcePath);
|
|
strSearchPatttern.Append ((LPWSTR)backupName);
|
|
strSearchPatttern.Append ((LPWSTR)L".*.mp");
|
|
|
|
if( !( pszSearchPattern = strSearchPatttern.QueryStrW() ) )
|
|
{
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
hFindFile = FindFirstFileW( pszSearchPattern, &FileInfo);
|
|
|
|
if (hFindFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
// no certificate file found
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
while (fFoundFile)
|
|
{
|
|
fValid = strDestFileName.Copy (strDestinationPath);
|
|
fValid = fValid && strDestFileName.Append ((LPWSTR)(FileInfo.cFileName + wcslen (backupName) +1));
|
|
|
|
fValid = fValid && strSrcFileName.Copy (strSourcePath);
|
|
fValid = fValid && strSrcFileName.Append ((LPWSTR)FileInfo.cFileName);
|
|
|
|
if (fValid)
|
|
{
|
|
if (!CopyFileW (strSrcFileName.QueryStrW(),strDestFileName.QueryStrW(),FALSE))
|
|
{
|
|
IIS_PRINTF((buff,"CertificateBackup: CopyFileW error 0x%0X \n",GetLastError()));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
IIS_PRINTF((buff,"CertificateBackup: Failure in STRAU manipulation \n"));
|
|
}
|
|
|
|
fFoundFile = FindNextFileW(hFindFile,&FileInfo);
|
|
}
|
|
fFoundFile = FindClose (hFindFile);
|
|
MD_ASSERT (fFoundFile);
|
|
}
|
|
else
|
|
{
|
|
IIS_PRINTF((buff,"CertificateRestore: can't find last back slash in one of these strings %s %s\n",lpszToPath,lpszFromPath));
|
|
}
|
|
|
|
return hresReturn;
|
|
|
|
}
|
|
|
|
|