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

4497 lines
122 KiB

/*++
Copyright (c) 1997-2001 Microsoft Corporation
Module Name:
resutils.c
Abstract:
Common utility routines for clusters resources
Author:
John Vert (jvert) 12/15/1996
Revision History:
--*/
#pragma warning( push )
#pragma warning( disable : 4115 ) // Clusrtl - struct def in parentheses
#pragma warning( disable : 4201 ) // SDK - nameless struct/union
#include "clusres.h"
#include "clusrtl.h"
#include "winbase.h"
#include <windows.h>
#include "userenv.h"
#include <strsafe.h>
#pragma warning( push )
#pragma warning( disable: 4214 )
#include <windns.h>
#pragma warning( pop )
#pragma warning( pop )
//
// For some reason this doesn't get pulled in from winnt.h.
//
#ifndef RTL_NUMBER_OF
#define RTL_NUMBER_OF(A) (sizeof(A)/sizeof((A)[0]))
#endif
//#define DBG_PRINT printf
#define DBG_PRINT
typedef struct _WORK_CONTEXT {
PCLUS_WORKER Worker;
PVOID lpParameter;
PWORKER_START_ROUTINE lpStartRoutine;
} WORK_CONTEXT, *PWORK_CONTEXT;
//
// Local Data
//
CRITICAL_SECTION ResUtilWorkerLock;
BOOLEAN
WINAPI
ResUtilDllEntry(
IN HINSTANCE DllHandle,
IN DWORD Reason,
IN LPVOID Reserved
)
/*++
Routine Description:
Main DLL entry for resource utility helper module.
Arguments:
DllHandle - Supplies the DLL Handle.
Reason - Supplies the call reason.
Return Value:
TRUE if successful
FALSE if unsuccessful
--*/
{
BOOLEAN fSuccess = TRUE;
UNREFERENCED_PARAMETER( Reserved );
if ( Reason == DLL_PROCESS_ATTACH )
{
fSuccess = (BOOLEAN) ( InitializeCriticalSectionAndSpinCount(&ResUtilWorkerLock,1000) != 0 ) ? TRUE : FALSE;
DisableThreadLibraryCalls(DllHandle);
}
if ( Reason == DLL_PROCESS_DETACH )
{
DeleteCriticalSection(&ResUtilWorkerLock);
}
return fSuccess;
} // ResUtilDllEntry
DWORD
WINAPI
ResUtilStartResourceService(
IN LPCWSTR pszServiceName,
OUT LPSC_HANDLE phServiceHandle
)
/*++
Routine Description:
Start a service.
Arguments:
pszServiceName - The name of the service to start.
phServiceHandle - Pointer to a handle to receive the service handle
for this service.
Return Value:
ERROR_SUCCESS if successful.
A Win32 error code on failure.
--*/
{
SC_HANDLE serviceHandle;
SC_HANDLE scManagerHandle;
DWORD status = ERROR_SUCCESS;
SERVICE_STATUS serviceStatus;
scManagerHandle = OpenSCManager( NULL, // local machine
NULL, // ServicesActive database
SC_MANAGER_ALL_ACCESS ); // all access
if ( scManagerHandle == NULL ) {
status = GetLastError();
DBG_PRINT( "ResUtilStartResourceService: Cannot access service controller! Error: %u.\n",
status );
return(status);
}
serviceHandle = OpenService( scManagerHandle,
pszServiceName,
SERVICE_ALL_ACCESS );
if ( serviceHandle == NULL ) {
status = GetLastError();
DBG_PRINT( "ResUtilStartResourceService: Cannot open service %ws. Error: %u.\n",
pszServiceName,
status );
CloseServiceHandle( scManagerHandle );
return(status);
}
CloseServiceHandle( scManagerHandle );
if ( !StartService( serviceHandle,
0,
NULL) ) {
status = GetLastError();
if ( status == ERROR_SERVICE_ALREADY_RUNNING ) {
status = ERROR_SUCCESS;
} else {
DBG_PRINT( "ResUtilStartResourceService: Failed to start %ws service. Error: %u.\n",
pszServiceName,
status );
}
} else {
//
// Wait for the service to start.
//
for (;;)
{
status = ERROR_SUCCESS;
if ( !QueryServiceStatus(serviceHandle, &serviceStatus) ) {
status = GetLastError();
DBG_PRINT("ResUtilStartResourceService: Failed to query status of %ws service. Error: %u.\n",
pszServiceName,
status);
break;
}
if ( serviceStatus.dwCurrentState == SERVICE_RUNNING ) {
break;
} else if ( serviceStatus.dwCurrentState != SERVICE_START_PENDING ) {
status = ERROR_SERVICE_NEVER_STARTED;
DBG_PRINT("ResUtilStartResourceService: Failed to start %ws service. CurrentState: %u.\n",
pszServiceName,
serviceStatus.dwCurrentState);
break;
}
Sleep(200); // Try again in a little bit
} // for: ever
} // else:
if ( (status == ERROR_SUCCESS) &&
ARGUMENT_PRESENT(phServiceHandle) ) {
*phServiceHandle = serviceHandle;
} else {
CloseServiceHandle( serviceHandle );
}
return(status);
} // ResUtilStartResourceService
DWORD
WINAPI
ResUtilStopResourceService(
IN LPCWSTR pszServiceName
)
/*++
Routine Description:
Stop a service.
Arguments:
pszServiceName - The name of the service to stop.
Return Value:
ERROR_SUCCESS - Service stopped successfully.
Win32 error code - Error stopping service.
--*/
{
SC_HANDLE serviceHandle = NULL;
SC_HANDLE scManagerHandle = NULL;
DWORD sc = ERROR_SUCCESS;
int retryTime = 30*1000; // wait 30 secs for shutdown
int retryTick = 300; // 300 msec at a time
BOOL didStop = FALSE;
SERVICE_STATUS serviceStatus;
scManagerHandle = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
if ( scManagerHandle == NULL )
{
sc = GetLastError();
DBG_PRINT( "ResUtilStartResourceService: Cannot access service controller! Error: %u.\n", sc );
goto Cleanup;
}
serviceHandle = OpenService( scManagerHandle, pszServiceName, SERVICE_ALL_ACCESS );
if ( serviceHandle == NULL )
{
sc = GetLastError();
DBG_PRINT( "ResUtilStartResourceService: Cannot open service %ws. Error: %u.\n", pszServiceName, sc );
CloseServiceHandle(scManagerHandle);
goto Cleanup;
}
CloseServiceHandle(scManagerHandle);
for (;;)
{
sc = ERROR_SUCCESS;
if ( !ControlService(serviceHandle,
(didStop ? SERVICE_CONTROL_INTERROGATE : SERVICE_CONTROL_STOP),
&serviceStatus) ) {
sc = GetLastError();
if ( sc == ERROR_SUCCESS )
{
didStop = TRUE;
if ( serviceStatus.dwCurrentState == SERVICE_STOPPED )
{
DBG_PRINT( "ResUtilStartResourceService: service %ws successfully stopped.\n", pszServiceName );
goto Cleanup;
}
}
}
if ( (sc == ERROR_EXCEPTION_IN_SERVICE) ||
(sc == ERROR_PROCESS_ABORTED) ||
(sc == ERROR_SERVICE_NOT_ACTIVE) )
{
DBG_PRINT( "ResUtilStartResourceService: service %ws stopped or died; sc = %u.\n", pszServiceName, sc );
sc = ERROR_SUCCESS;
goto Cleanup;
}
if ( (retryTime -= retryTick) <= 0 )
{
DBG_PRINT( "ResUtilStartResourceService: service %ws did not stop; giving up.\n", pszServiceName, sc );
sc = ERROR_TIMEOUT;
goto Cleanup;
}
DBG_PRINT("ResUtilStartResourceService: StopResourceService retrying...\n");
Sleep(retryTick);
} // for: ever
Cleanup:
CloseServiceHandle( scManagerHandle );
CloseServiceHandle( serviceHandle );
return sc;
} // ResUtilStopResourceService
DWORD
WINAPI
ResUtilVerifyResourceService(
IN LPCWSTR pszServiceName
)
/*++
Routine Description:
Verify that a service is alive.
Arguments:
pszServiceName - The name of the service to verify.
Return Value:
ERROR_SUCCESS - Service is alive.
Win32 error code - Error verifying service, or service is not alive.
--*/
{
BOOL success;
SC_HANDLE serviceHandle;
SC_HANDLE scManagerHandle;
DWORD status = ERROR_SUCCESS;
SERVICE_STATUS serviceStatus;
scManagerHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if ( scManagerHandle == NULL ) {
status = GetLastError();
DBG_PRINT("ResUtilStartResourceService: Cannot access service controller! Error: %u.\n",
status);
return(status);
}
serviceHandle = OpenService( scManagerHandle,
pszServiceName,
SERVICE_QUERY_STATUS );
if ( serviceHandle == NULL ) {
status = GetLastError();
DBG_PRINT("ResUtilStartResourceService: Cannot open service %ws. Error: %u.\n",
pszServiceName,
status);
CloseServiceHandle(scManagerHandle);
return(status);
}
CloseServiceHandle(scManagerHandle);
success = QueryServiceStatus( serviceHandle,
&serviceStatus );
status = GetLastError();
CloseServiceHandle(serviceHandle);
if ( !success ) {
DBG_PRINT("ResUtilStartResourceService: Cannot query service %ws. Error: %u.\n",
pszServiceName,
status);
return(status);
}
if ( (serviceStatus.dwCurrentState != SERVICE_RUNNING) &&
(serviceStatus.dwCurrentState != SERVICE_START_PENDING) ) {
DBG_PRINT("ResUtilStartResourceService: Service %ws is not alive: dwCurrentState: %u.\n",
pszServiceName,
serviceStatus.dwCurrentState);
return(ERROR_SERVICE_NOT_ACTIVE);
}
return(ERROR_SUCCESS);
} // ResUtilVerifyResourceService
DWORD
WINAPI
ResUtilStopService(
IN SC_HANDLE hServiceHandle
)
/*++
Routine Description:
Stop a service.
Arguments:
hServiceHandle - The handle of the service to stop.
Return Value:
ERROR_SUCCESS - Service stopped successfully.
Win32 error code - Error stopping service.
Notes:
The hServiceHandle is closed as a side effect of this routine.
--*/
{
DWORD status = ERROR_SUCCESS;
DWORD retryTime = 30*1000; // wait 30 secs for shutdown
DWORD retryTick = 300; // 300 msec at a time
BOOL didStop = FALSE;
SERVICE_STATUS serviceStatus;
for (;;)
{
status = ERROR_SUCCESS;
if ( !ControlService(hServiceHandle,
(didStop ? SERVICE_CONTROL_INTERROGATE : SERVICE_CONTROL_STOP),
&serviceStatus) ) {
status = GetLastError();
if ( status == ERROR_SUCCESS ) {
didStop = TRUE;
if ( serviceStatus.dwCurrentState == SERVICE_STOPPED ) {
DBG_PRINT("ResUtilStartResourceService: service successfully stopped.\n" );
break;
}
}
}
if ( (status == ERROR_EXCEPTION_IN_SERVICE) ||
(status == ERROR_PROCESS_ABORTED) ||
(status == ERROR_SERVICE_NOT_ACTIVE) ) {
DBG_PRINT("ResUtilStartResourceService: service stopped or died; status = %u.\n",
status);
status = ERROR_SUCCESS;
break;
}
if ( (retryTime -= retryTick) <= 0 ) {
DBG_PRINT("ResUtilStartResourceService: service did not stop; giving up.\n",
status);
status = ERROR_TIMEOUT;
break;
}
DBG_PRINT("ResUtilStartResourceService: StopResourceService retrying...\n");
Sleep(retryTick);
} // for: ever
CloseServiceHandle(hServiceHandle);
return(status);
} // ResUtilStopResourceService
DWORD
WINAPI
ResUtilVerifyService(
IN SC_HANDLE hServiceHandle
)
/*++
Routine Description:
Verify that a service is alive.
Arguments:
hServiceHandle - The handle of the service to verify.
Return Value:
ERROR_SUCCESS - Service is alive.
Win32 error code - Error verifying service, or service is not alive.
--*/
{
BOOL success;
DWORD status = ERROR_SUCCESS;
SERVICE_STATUS serviceStatus;
success = QueryServiceStatus( hServiceHandle,
&serviceStatus );
if ( !success ) {
status = GetLastError();
DBG_PRINT("ResUtilStartResourceService: Cannot query service. Error: %u.\n",
status);
return(status);
}
if ( (serviceStatus.dwCurrentState != SERVICE_RUNNING) &&
(serviceStatus.dwCurrentState != SERVICE_START_PENDING) ) {
DBG_PRINT("ResUtilStartResourceService: Service is not alive: dwCurrentState: %u.\n",
serviceStatus.dwCurrentState);
return(ERROR_SERVICE_NOT_ACTIVE);
}
return(ERROR_SUCCESS);
} // ResUtilVerifyService
/////////////////////////////////////////////////////////////////////////////
//++
//
// ResUtilTerminateServiceProcessFromResDll
//
// Description:
// Attempt to terminate a service process from a resource DLL.
//
// Arguments:
// dwServicePid [IN]
// The process ID of the service process to terminate.
//
// bOffline [IN]
// TRUE = called from the offline thread.
//
// pdwResourceState [OUT]
// State of the resource. Optional.
//
// pfnLogEvent [IN]
// Pointer to a routine that handles the reporting of events from
// the resource DLL.
//
// hResourceHandle [IN]
// Handle for logging.
//
// Return Value:
// ERROR_SUCCESS
// The function completed successfully.
//
// Win32 error code
// The function failed.
//
//--
/////////////////////////////////////////////////////////////////////////////
DWORD
WINAPI
ResUtilTerminateServiceProcessFromResDll(
IN DWORD dwServicePid,
IN BOOL bOffline,
OUT PDWORD pdwResourceState,
IN PLOG_EVENT_ROUTINE pfnLogEvent,
IN RESOURCE_HANDLE hResourceHandle
)
{
DWORD sc = ERROR_SUCCESS;
HANDLE hSvcProcess = NULL;
BOOLEAN bWasEnabled;
DWORD dwResourceState = ClusterResourceFailed;
(pfnLogEvent)(
hResourceHandle,
LOG_INFORMATION,
L"ResUtilTerminateServiceProcessFromResDll: Process with id=%1!u! might be terminated...\n",
dwServicePid
);
//
// Adjust the privilege to allow debug. This is to allow termination
// of a service process which runs in a local system account from a
// different service process which runs in a domain user account.
//
sc = ClRtlEnableThreadPrivilege(
SE_DEBUG_PRIVILEGE,
&bWasEnabled
);
if ( sc != ERROR_SUCCESS )
{
(pfnLogEvent)(
hResourceHandle,
LOG_ERROR,
L"ResUtilTerminateServiceProcessFromResDll: Unable to set debug privilege for process with id=%1!u!, status=%2!u!...\n",
dwServicePid,
sc
);
goto Cleanup;
} // if: error enabling thread privilege
//
// Open the process so we can terminate it.
//
hSvcProcess = OpenProcess(
PROCESS_TERMINATE,
FALSE,
dwServicePid
);
if ( hSvcProcess == NULL )
{
//
// Did this happen because the process terminated
// too quickly after we sent out one control request ?
//
sc = GetLastError();
(pfnLogEvent)(
hResourceHandle,
LOG_INFORMATION,
L"ResUtilTerminateServiceProcessFromResDll: Unable to open pid=%1!u! for termination, status=%2!u!...\n",
dwServicePid,
sc
);
} // if: error opening the process
else
{
if ( ! bOffline )
{
(pfnLogEvent)(
hResourceHandle,
LOG_INFORMATION,
L"ResUtilTerminateServiceProcessFromResDll: Pid=%1!u! will be terminated by brute force...\n",
dwServicePid
);
} // if: called from Terminate
else
{
//
// Wait 3 seconds for the process to shutdown gracefully.
//
if ( WaitForSingleObject( hSvcProcess, 3000 )
== WAIT_OBJECT_0 )
{
(pfnLogEvent)(
hResourceHandle,
LOG_INFORMATION,
L"ResUtilTerminateServiceProcessFromResDll: Process with id=%1!u! shutdown gracefully...\n",
dwServicePid
);
dwResourceState = ClusterResourceOffline;
sc = ERROR_SUCCESS;
goto RestoreAndCleanup;
} // if: process exited on its own
} // else: called from Offline
if ( ! TerminateProcess( hSvcProcess, 0 ) )
{
sc = GetLastError();
(pfnLogEvent)(
hResourceHandle,
LOG_ERROR,
L"ResUtilTerminateServiceProcessFromResDll: Unable to terminate process with id=%1!u!, status=%2!u!...\n",
dwServicePid,
sc
);
} // if: error terminating the process
else
{
(pfnLogEvent)(
hResourceHandle,
LOG_INFORMATION,
L"ResUtilTerminateServiceProcessFromResDll: Process with id=%1!u! was terminated...\n",
dwServicePid
);
dwResourceState = ClusterResourceOffline;
} // else: process terminated successfully
} // else: process opened successfully
RestoreAndCleanup:
ClRtlRestoreThreadPrivilege(
SE_DEBUG_PRIVILEGE,
bWasEnabled
);
Cleanup:
if ( hSvcProcess != NULL )
{
CloseHandle( hSvcProcess );
} // if: process was opened successfully
if ( pdwResourceState != NULL )
{
*pdwResourceState = dwResourceState;
} // if: caller wants the resource state
(pfnLogEvent)(
hResourceHandle,
LOG_INFORMATION,
L"ResUtilTerminateServiceProcessFromResDll: Process id=%1!u!, status=%2!u!, state=%3!u!.\n",
dwServicePid,
sc,
dwResourceState
);
return sc;
} //*** ResUtilTerminateServiceProcessFromResDll()
LPWSTR
WINAPI
ResUtilDupString(
IN LPCWSTR pszInString
)
/*++
Routine Description:
Duplicates a string.
Arguments:
pszInString - Supplies the string to be duplicated.
Return Value:
A pointer to a buffer containing the duplicate if successful.
NULL if unsuccessful. Call GetLastError() to get more details.
--*/
{
PWSTR pszNewString = NULL;
size_t cbString;
DWORD sc = ERROR_SUCCESS;
HRESULT hr;
//
// Get the size of the parameter so we know how much to allocate.
//
cbString = (wcslen( pszInString ) + 1) * sizeof(WCHAR);
//
// Allocate a buffer to copy the string into.
//
pszNewString = (PWSTR) LocalAlloc( LMEM_FIXED, cbString );
if ( pszNewString == NULL )
{
sc = ERROR_NOT_ENOUGH_MEMORY;
goto Cleanup;
}
//
// Copy the in string to the new string.
//
hr = StringCbCopyW( pszNewString, cbString, pszInString );
if ( FAILED( hr ) )
{
sc = HRESULT_CODE( hr );
goto Cleanup;
}
Cleanup:
if ( sc != ERROR_SUCCESS )
{
LocalFree( pszNewString );
pszNewString = NULL;
}
SetLastError( sc );
return pszNewString;
} // ResUtilDupString
DWORD
WINAPI
ResUtilGetBinaryValue(
IN HKEY hkeyClusterKey,
IN LPCWSTR pszValueName,
OUT LPBYTE * ppbOutValue,
OUT LPDWORD pcbOutValueSize
)
/*++
Routine Description:
Queries a REG_BINARY or REG_MULTI_SZ value out of the cluster
database and allocates the necessary storage for it.
Arguments:
hkeyClusterKey - Supplies the cluster key where the value is stored
pszValueName - Supplies the name of the value.
ppbOutValue - Supplies the address of a pointer in which to return the value.
pcbOutValueSize - Supplies the address of a DWORD in which to return the
size of the value.
Return Value:
ERROR_SUCCESS - The value was read successfully.
ERROR_NOT_ENOUGH_MEMORY - Error allocating memory for the value.
Win32 error code - The operation failed.
--*/
{
LPBYTE value;
DWORD valueSize;
DWORD valueType;
DWORD status;
//
// Initialize the output parameters.
//
*ppbOutValue = NULL;
*pcbOutValueSize = 0;
//
// Get the size of the value so we know how much to allocate.
//
valueSize = 0;
status = ClusterRegQueryValue( hkeyClusterKey,
pszValueName,
&valueType,
NULL,
&valueSize );
if ( (status != ERROR_SUCCESS) &&
(status != ERROR_MORE_DATA) ) {
return(status);
}
//
// Allocate a buffer to read the value into.
//
value = LocalAlloc( LMEM_FIXED, valueSize );
if ( value == NULL ) {
return(ERROR_NOT_ENOUGH_MEMORY);
}
//
// Read the value from the cluster database.
//
status = ClusterRegQueryValue( hkeyClusterKey,
pszValueName,
&valueType,
(LPBYTE)value,
&valueSize );
if ( status != ERROR_SUCCESS ) {
LocalFree( value );
} else {
*ppbOutValue = value;
*pcbOutValueSize = valueSize;
}
return(status);
} // ResUtilGetBinaryValue
PWSTR
WINAPI
ResUtilGetSzValue(
IN HKEY hkeyClusterKey,
IN LPCWSTR pszValueName
)
/*++
Routine Description:
Queries a REG_SZ or REG_EXPAND_SZ value out of the cluster database
and allocates the necessary storage for it.
Arguments:
hkeyClusterKey - Supplies the cluster key where the value is stored
pszValueName - Supplies the name of the value.
Return Value:
A pointer to a buffer containing the value if successful.
NULL if unsuccessful. Call GetLastError() to get more details.
--*/
{
PWSTR value;
DWORD valueSize;
DWORD valueType;
DWORD status;
//
// Get the size of the value so we know how much to allocate.
//
valueSize = 0;
status = ClusterRegQueryValue( hkeyClusterKey,
pszValueName,
&valueType,
NULL,
&valueSize );
if ( (status != ERROR_SUCCESS) &&
(status != ERROR_MORE_DATA) ) {
SetLastError( status );
return(NULL);
}
//
// Add on the size of the null terminator.
//
valueSize += sizeof(UNICODE_NULL);
//
// Allocate a buffer to read the string into.
//
value = LocalAlloc( LMEM_FIXED, valueSize );
if ( value == NULL ) {
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
return(NULL);
}
//
// Read the value from the cluster database.
//
status = ClusterRegQueryValue( hkeyClusterKey,
pszValueName,
&valueType,
(LPBYTE)value,
&valueSize );
if ( status != ERROR_SUCCESS ) {
LocalFree( value );
value = NULL;
} else if ( (valueType != REG_SZ) &&
(valueType != REG_EXPAND_SZ) &&
(valueType != REG_MULTI_SZ) ) {
status = ERROR_INVALID_PARAMETER;
LocalFree( value );
value = NULL;
}
return(value);
} // ResUtilGetSzValue
PWSTR
WINAPI
ResUtilGetExpandSzValue(
IN HKEY hkeyClusterKey,
IN LPCWSTR pszValueName,
IN BOOL bExpand
)
/*++
Routine Description:
Queries a REG_EXPAND_SZ value out of the cluster database and allocates
the necessary storage for it, optionally expanding it.
Arguments:
hkeyClusterKey - Supplies the cluster key where the value is stored
pszValueName - Supplies the name of the value.
bExpand - TRUE = return the expanded string.
Return Value:
A pointer to a buffer containing the value if successful.
NULL if unsuccessful. Call GetLastError() to get more details.
--*/
{
PWSTR value;
PWSTR pwszExpanded = NULL;
DWORD valueSize;
DWORD valueType;
size_t cchExpanded;
size_t cchExpandedReturned;
DWORD sc;
//
// Get the size of the value so we know how much to allocate.
//
valueSize = 0;
sc = ClusterRegQueryValue( hkeyClusterKey,
pszValueName,
&valueType,
NULL,
&valueSize );
if ( (sc != ERROR_SUCCESS) &&
(sc != ERROR_MORE_DATA) )
{
SetLastError( sc );
return(NULL);
}
//
// Add on the size of the null terminator.
//
valueSize += sizeof(UNICODE_NULL);
//
// Allocate a buffer to read the string into.
//
value = LocalAlloc( LMEM_FIXED, valueSize );
if ( value == NULL )
{
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
return(NULL);
}
//
// Read the value from the cluster database.
//
sc = ClusterRegQueryValue( hkeyClusterKey,
pszValueName,
&valueType,
(LPBYTE)value,
&valueSize );
if ( sc != ERROR_SUCCESS )
{
LocalFree( value );
value = NULL;
}
else if ( ( valueType != REG_EXPAND_SZ ) &&
( valueType != REG_SZ ) )
{
sc = ERROR_INVALID_PARAMETER;
LocalFree( value );
value = NULL;
}
else if ( bExpand )
{
//
// Expand the environment variable strings in the
// value that was just read.
//
cchExpanded = valueSize / sizeof( WCHAR );
for (;;)
{
//
// Allocate the buffer for the expansion string. This will
// get double each time we are told it is too small.
//
pwszExpanded = LocalAlloc( LMEM_FIXED, cchExpanded * sizeof( WCHAR ) );
if ( pwszExpanded == NULL )
{
sc = ERROR_NOT_ENOUGH_MEMORY;
break;
}
else
{
//
// Expand the environment variables in the value.
// If the buffer isn't big enough, we will loop up to
// the top of the loop and allocate a bigger buffer.
//
cchExpandedReturned = ExpandEnvironmentStringsW(
value,
pwszExpanded,
(DWORD)cchExpanded );
if ( cchExpandedReturned == 0 )
{
sc = GetLastError();
break;
}
else if ( cchExpandedReturned > cchExpanded )
{
cchExpanded *= 2;
LocalFree( pwszExpanded );
pwszExpanded = NULL;
continue;
}
else
{
sc = ERROR_SUCCESS;
break;
}
}
} // for: ever
//
// If any errors occurred, cleanup.
// Otherwise, return expanded string.
//
if ( sc != ERROR_SUCCESS )
{
LocalFree( pwszExpanded );
LocalFree( value );
value = NULL;
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
}
else
{
LocalFree( value );
value = pwszExpanded;
}
} // else: expand
return(value);
} // ResUtilGetExpandSzValue
DWORD
WINAPI
ResUtilGetDwordValue(
IN HKEY hkeyClusterKey,
IN LPCWSTR pszValueName,
OUT LPDWORD pdwOutValue,
IN DWORD dwDefaultValue
)
/*++
Routine Description:
Queries a REG_DWORD value out of the cluster database.
Arguments:
hkeyClusterKey - Supplies the cluster key where the value is stored
pszValueName - Supplies the name of the value.
pdwOutValue - Supplies the address of a DWORD in which to return the value.
dwDefaultValue - Value to return if the parameter is not found.
Return Value:
ERROR_SUCCESS - The value was read successfully.
Win32 error code - The operation failed.
--*/
{
DWORD value;
DWORD valueSize;
DWORD valueType;
DWORD status;
//
// Initialize the output value.
//
*pdwOutValue = 0;
//
// Read the value from the cluster database.
//
valueSize = sizeof(DWORD);
status = ClusterRegQueryValue( hkeyClusterKey,
pszValueName,
&valueType,
(LPBYTE)&value,
&valueSize );
if ( status == ERROR_SUCCESS ) {
if ( valueType != REG_DWORD ) {
status = ERROR_INVALID_PARAMETER;
} else {
*pdwOutValue = value;
}
} else if ( status == ERROR_FILE_NOT_FOUND ) {
*pdwOutValue = dwDefaultValue;
status = ERROR_SUCCESS;
}
return(status);
} // ResUtilGetDwordValue
DWORD
WINAPI
ResUtilSetBinaryValue(
IN HKEY hkeyClusterKey,
IN LPCWSTR pszValueName,
IN const LPBYTE pbNewValue,
IN DWORD cbNewValueSize,
IN OUT LPBYTE * ppbOutValue,
IN OUT LPDWORD pcbOutValueSize
)
/*++
Routine Description:
Sets a REG_BINARY value in a pointer, deallocating a previous value
if necessary, and sets the value in the cluster database.
Arguments:
hkeyClusterKey - Supplies the cluster key where the value is stored.
pszValueName - Supplies the name of the value.
pbNewValue - Supplies the new binary value.
cbNewValueSize - Supplies the size of the new value.
ppbOutValue - Supplies pointer to the binary pointer in which to set
the value.
pcbOutValueSize - Supplies a pointer to a size DWORD in which to set
the size of the value.
Return Value:
ERROR_SUCCESS - The operation completed successfully.
ERROR_NOT_ENOUGH_MEMORY - An error occurred attempting to allocate memory.
Win32 error code - The operation failed.
--*/
{
DWORD status;
LPBYTE allocedValue = NULL;
if ( ppbOutValue != NULL )
{
//
// Allocate memory for the new value.
//
allocedValue = LocalAlloc( LMEM_FIXED, cbNewValueSize );
if ( allocedValue == NULL ) {
return(ERROR_NOT_ENOUGH_MEMORY);
}
}
//
// Set the value in the cluster database.
//
// _ASSERTE( hkeyClusterKey != NULL );
// _ASSERTE( pszValueName != NULL );
status = ClusterRegSetValue( hkeyClusterKey,
pszValueName,
REG_BINARY,
pbNewValue,
cbNewValueSize );
if ( status != ERROR_SUCCESS ) {
LocalFree( allocedValue );
return(status);
}
if ( ppbOutValue != NULL )
{
//
// Copy the new value to the output buffer.
//
CopyMemory( allocedValue, pbNewValue, cbNewValueSize );
// Set the new value in the output pointer.
if ( *ppbOutValue != NULL ) {
LocalFree( *ppbOutValue );
}
*ppbOutValue = allocedValue;
*pcbOutValueSize = cbNewValueSize;
}
return(ERROR_SUCCESS);
} // ResUtilSetBinaryValue
DWORD
WINAPI
ResUtilSetSzValue(
IN HKEY hkeyClusterKey,
IN LPCWSTR pszValueName,
IN LPCWSTR pszNewValue,
IN OUT LPWSTR * ppszOutValue
)
/*++
Routine Description:
Sets a REG_SZ value in a pointer, deallocating a previous value
if necessary, and sets the value in the cluster database.
Arguments:
hkeyClusterKey - Supplies the cluster key where the value is stored.
pszValueName - Supplies the name of the value.
pszNewValue - Supplies the new string value.
ppszOutValue - Supplies pointer to the string pointer in which to set
the value.
Return Value:
ERROR_SUCCESS - The operation completed successfully.
ERROR_NOT_ENOUGH_MEMORY - An error occurred attempting to allocate memory.
Win32 error code - The operation failed.
--*/
{
DWORD sc = ERROR_SUCCESS;
size_t cbData;
LPWSTR pwszAllocedValue = NULL;
HRESULT hr;
cbData = (wcslen( pszNewValue ) + 1) * sizeof(WCHAR);
if ( ppszOutValue != NULL )
{
//
// Allocate memory for the new value string.
//
pwszAllocedValue = LocalAlloc( LMEM_FIXED, cbData );
if ( pwszAllocedValue == NULL )
{
sc = ERROR_NOT_ENOUGH_MEMORY;
goto Cleanup;
}
}
//
// Set the value in the cluster database.
//
// _ASSERTE( hkeyClusterKey != NULL );
// _ASSERTE( pszValueName != NULL );
sc = ClusterRegSetValue( hkeyClusterKey,
pszValueName,
REG_SZ,
(CONST BYTE*)pszNewValue,
(DWORD)cbData );
if ( sc != ERROR_SUCCESS )
{
goto Cleanup;
}
if ( ppszOutValue != NULL )
{
//
// Copy the new value to the output buffer.
//
hr = StringCbCopyW( pwszAllocedValue, cbData, pszNewValue );
if ( FAILED( hr ) )
{
sc = HRESULT_CODE( hr );
goto Cleanup;
}
// Set the new value in the output string pointer.
if ( *ppszOutValue != NULL )
{
LocalFree( *ppszOutValue );
}
*ppszOutValue = pwszAllocedValue;
pwszAllocedValue = NULL;
}
sc = ERROR_SUCCESS;
Cleanup:
LocalFree( pwszAllocedValue );
return sc;
} // ResUtilSetSzValue
DWORD
WINAPI
ResUtilSetExpandSzValue(
IN HKEY hkeyClusterKey,
IN LPCWSTR pszValueName,
IN LPCWSTR pszNewValue,
IN OUT LPWSTR * ppszOutValue
)
/*++
Routine Description:
Sets a REG_EXPAND_SZ value in a pointer, deallocating a previous value
if necessary, and sets the value in the cluster database.
Arguments:
hkeyClusterKey - Supplies the cluster key where the value is stored.
pszValueName - Supplies the name of the value.
pszNewValue - Supplies the new string value.
ppszOutValue - Supplies pointer to the string pointer in which to set
the value.
Return Value:
ERROR_SUCCESS - The operation completed successfully.
ERROR_NOT_ENOUGH_MEMORY - An error occurred attempting to allocate memory.
Win32 error code - The operation failed.
--*/
{
DWORD sc;
DWORD dataSize;
PWSTR allocedValue = NULL;
HRESULT hr;
dataSize = ((DWORD) wcslen( pszNewValue ) + 1) * sizeof(WCHAR);
if ( ppszOutValue != NULL ) {
//
// Allocate memory for the new value string.
//
allocedValue = LocalAlloc( LMEM_FIXED, dataSize );
if ( allocedValue == NULL )
{
sc = ERROR_NOT_ENOUGH_MEMORY;
goto Cleanup;
}
}
//
// Set the value in the cluster database.
//
// _ASSERTE( hkeyClusterKey != NULL );
// _ASSERTE( pszValueName != NULL );
sc = ClusterRegSetValue( hkeyClusterKey,
pszValueName,
REG_EXPAND_SZ,
(CONST BYTE*)pszNewValue,
dataSize );
if ( sc != ERROR_SUCCESS )
{
goto Cleanup;
}
if ( ppszOutValue != NULL )
{
//
// Copy the new value to the output buffer.
//
hr = StringCbCopyW( allocedValue, dataSize, pszNewValue );
if ( FAILED( hr ) )
{
sc = HRESULT_CODE( hr );
goto Cleanup;
}
// Set the new value in the output string pointer.
if ( *ppszOutValue != NULL )
{
LocalFree( *ppszOutValue );
}
*ppszOutValue = allocedValue;
allocedValue = NULL;
}
sc = ERROR_SUCCESS;
Cleanup:
LocalFree( allocedValue );
return sc;
} // ResUtilSetSzValue
DWORD
WINAPI
ResUtilSetMultiSzValue(
IN HKEY hkeyClusterKey,
IN LPCWSTR pszValueName,
IN LPCWSTR pszNewValue,
IN DWORD cbNewValueSize,
IN OUT LPWSTR * ppszOutValue,
IN OUT LPDWORD pcbOutValueSize
)
/*++
Routine Description:
Sets a REG_MULTI_SZ value in a pointer, deallocating a previous value
if necessary, and sets the value in the cluster database.
Arguments:
hkeyClusterKey - Supplies the cluster key where the ValueName is stored.
pszValueName - Supplies the name of the value.
pszNewValue - Supplies the new MULTI_SZ value.
cbNewValueSize - Supplies the size of the new value.
ppszOutValue - Supplies a pointer to the string pointer in which to set
the value.
pcbOutValueSize - Supplies a pointer to a size DWORD in which to set
the size of the value.
Return Value:
ERROR_SUCCESS - The operation completed successfully.
ERROR_NOT_ENOUGH_MEMORY - An error occurred attempting to allocate memory.
Win32 error code - The operation failed.
--*/
{
DWORD status;
LPWSTR allocedValue = NULL;
if ( ppszOutValue != NULL )
{
//
// Allocate memory for the new value.
//
allocedValue = LocalAlloc( LMEM_FIXED, cbNewValueSize );
if ( allocedValue == NULL ) {
return(ERROR_NOT_ENOUGH_MEMORY);
}
}
//
// Set the value in the cluster database.
//
// _ASSERTE( hkeyClusterKey != NULL );
// _ASSERTE( pszValueName != NULL );
status = ClusterRegSetValue( hkeyClusterKey,
pszValueName,
REG_MULTI_SZ,
(CONST BYTE*)pszNewValue,
cbNewValueSize );
if ( status != ERROR_SUCCESS ) {
LocalFree(allocedValue);
return(status);
}
if ( ppszOutValue != NULL )
{
//
// Copy the new value to the output buffer.
//
CopyMemory( allocedValue, pszNewValue, cbNewValueSize );
// Set the new value in the output pointer.
if ( *ppszOutValue != NULL ) {
LocalFree( *ppszOutValue );
}
*ppszOutValue = allocedValue;
*pcbOutValueSize = cbNewValueSize;
}
return(ERROR_SUCCESS);
} // ResUtilSetMultiSzValue
DWORD
WINAPI
ResUtilSetDwordValue(
IN HKEY hkeyClusterKey,
IN LPCWSTR pszValueName,
IN DWORD dwNewValue,
IN OUT LPDWORD pdwOutValue
)
/*++
Routine Description:
Sets a REG_DWORD value in a pointer and sets the value in the
cluster database.
Arguments:
hkeyClusterKey - Supplies the cluster key where the property is stored.
pszValueName - Supplies the name of the value.
dwNewValue - Supplies the new DWORD value.
pdwOutValue - Supplies pointer to the DWORD pointer in which to set
the value.
Return Value:
ERROR_SUCCESS - The operation completed successfully.
Win32 error code - The operation failed.
--*/
{
DWORD status;
//
// Set the value in the cluster database.
//
// _ASSERTE( hkeyClusterKey != NULL );
// _ASSERTE( pszValueName != NULL );
status = ClusterRegSetValue( hkeyClusterKey,
pszValueName,
REG_DWORD,
(CONST BYTE*)&dwNewValue,
sizeof(DWORD) );
if ( status != ERROR_SUCCESS ) {
return(status);
}
if ( pdwOutValue != NULL )
{
//
// Copy the new value to the output buffer.
//
*pdwOutValue = dwNewValue;
}
return(ERROR_SUCCESS);
} // ResUtilSetDwordValue
DWORD
WINAPI
ResUtilGetBinaryProperty(
OUT LPBYTE * ppbOutValue,
OUT LPDWORD pcbOutValueSize,
IN const PCLUSPROP_BINARY pValueStruct,
IN const LPBYTE pbOldValue,
IN DWORD cbOldValueSize,
OUT LPBYTE * ppPropertyList,
OUT LPDWORD pcbPropertyListSize
)
/*++
Routine Description:
Gets a binary property from a property list and advances the pointers.
Arguments:
ppbOutValue - Supplies the address of a pointer in which to return a
pointer to the binary value in the property list.
pcbOutValueSize - Supplies the address of the output value size.
pValueStruct - Supplies the binary value from the property list.
pbOldValue - Supplies the previous value for this property.
cbOldValueSize - Supplies the previous value's size.
ppPropertyList - Supplies the address of the pointer to the property list
buffer which will be advanced to the beginning of the next property.
pcbPropertyListSize - Supplies a pointer to the buffer size which will be
decremented to account for this property.
Return Value:
ERROR_SUCCESS - The operation completed successfully.
ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
Win32 error code - The operation failed.
--*/
{
BOOL propChanged = FALSE;
DWORD arrayIndex;
DWORD dataSize;
//
// Make sure the buffer is big enough and
// the value is formatted correctly.
//
dataSize = sizeof(*pValueStruct) + ALIGN_CLUSPROP( pValueStruct->cbLength );
if ( (*pcbPropertyListSize < dataSize) ||
(pValueStruct->Syntax.wFormat != CLUSPROP_FORMAT_BINARY) ) {
return(ERROR_INVALID_PARAMETER);
}
//
// If the value changed, point to the new value.
//
if ( (pbOldValue == NULL) ||
(cbOldValueSize != pValueStruct->cbLength) ) {
propChanged = TRUE;
} else {
for ( arrayIndex = 0 ; arrayIndex < cbOldValueSize ; arrayIndex++ ) {
if ( pValueStruct->rgb[arrayIndex] != pbOldValue[arrayIndex] ) {
propChanged = TRUE;
break;
}
}
}
if ( propChanged ) {
*ppbOutValue = pValueStruct->rgb;
*pcbOutValueSize = pValueStruct->cbLength;
}
//
// Decrement remaining buffer size and move to the next property.
//
*pcbPropertyListSize -= dataSize;
*ppPropertyList += dataSize;
return(ERROR_SUCCESS);
} // ResUtilGetBinaryProperty
DWORD
WINAPI
ResUtilGetSzProperty(
OUT LPWSTR * ppszOutValue,
IN const PCLUSPROP_SZ pValueStruct,
IN LPCWSTR pszOldValue,
OUT LPBYTE * ppPropertyList,
OUT LPDWORD pcbPropertyListSize
)
/*++
Routine Description:
Gets a string property from a property list and advances the pointers.
Arguments:
ppszOutValue - Supplies the address of a pointer in which to return a
pointer to the string in the property list.
pValueStruct - Supplies the string value from the property list.
pszOldValue - Supplies the previous value for this property.
ppPropertyList - Supplies the address of the pointer to the property list
buffer which will be advanced to the beginning of the next property.
pcbPropertyListSize - Supplies a pointer to the buffer size which will be
decremented to account for this property.
Return Value:
ERROR_SUCCESS - The operation completed successfully.
ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
Win32 error code - The operation failed.
--*/
{
DWORD dataSize;
DWORD sc = ERROR_SUCCESS;
//
// Make sure the buffer is big enough and
// the value is formatted correctly.
//
dataSize = sizeof(*pValueStruct) + ALIGN_CLUSPROP( pValueStruct->cbLength );
if ( (*pcbPropertyListSize < dataSize) ||
(pValueStruct->Syntax.wFormat != CLUSPROP_FORMAT_SZ) ||
(pValueStruct->Syntax.wFormat != CLUSPROP_FORMAT_EXPAND_SZ) )
{
sc = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
//
// If the value changed, point to the new value.
// Do this even if only the case of the value changed.
//
if ( (pszOldValue == NULL) ||
(wcsncmp( pValueStruct->sz, pszOldValue, pValueStruct->cbLength / sizeof( WCHAR ) ) != 0)
)
{
*ppszOutValue = pValueStruct->sz;
}
//
// Decrement remaining buffer size and move to the next property.
//
*pcbPropertyListSize -= dataSize;
*ppPropertyList += dataSize;
Cleanup:
return sc;
} // ResUtilGetSzProperty
DWORD
WINAPI
ResUtilGetMultiSzProperty(
OUT LPWSTR * ppszOutValue,
OUT LPDWORD pcbOutValueSize,
IN const PCLUSPROP_SZ pValueStruct,
IN LPCWSTR pszOldValue,
IN DWORD cbOldValueSize,
OUT LPBYTE * ppPropertyList,
OUT LPDWORD pcbPropertyListSize
)
/*++
Routine Description:
Gets a binary property from a property list and advances the pointers.
Arguments:
ppszOutValue - Supplies the address of a pointer in which to return a
pointer to the binary value in the property list.
pcbOutValueSize - Supplies the address of the output value size.
pValueStruct - Supplies the string value from the property list.
pszOldValue - Supplies the previous value for this property.
cbOldValueSize - Supplies the previous value's size.
ppPropertyList - Supplies the address of the pointer to the property list
buffer which will be advanced to the beginning of the next property.
pcbPropertyListSize - Supplies a pointer to the buffer size which will be
decremented to account for this property.
Return Value:
ERROR_SUCCESS - The operation completed successfully.
ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
Win32 error code - The operation failed.
--*/
{
BOOL propChanged = FALSE;
DWORD dataSize;
//
// Make sure the buffer is big enough and
// the value is formatted correctly.
//
dataSize = sizeof(*pValueStruct) + ALIGN_CLUSPROP( pValueStruct->cbLength );
if ( (*pcbPropertyListSize < dataSize) ||
(pValueStruct->Syntax.wFormat != CLUSPROP_FORMAT_MULTI_SZ) ) {
return(ERROR_INVALID_PARAMETER);
}
//
// If the value changed, point to the new value.
//
if ( (pszOldValue == NULL) ||
(cbOldValueSize != pValueStruct->cbLength) ) {
propChanged = TRUE;
} else if ( memcmp( pValueStruct->sz, pszOldValue, cbOldValueSize ) != 0 ) {
propChanged = TRUE;
}
if ( propChanged ) {
*ppszOutValue = pValueStruct->sz;
*pcbOutValueSize = pValueStruct->cbLength;
}
//
// Decrement remaining buffer size and move to the next property.
//
*pcbPropertyListSize -= dataSize;
*ppPropertyList += dataSize;
return(ERROR_SUCCESS);
} // ResUtilGetMultiSzProperty
DWORD
WINAPI
ResUtilGetDwordProperty(
OUT LPDWORD pdwOutValue,
IN const PCLUSPROP_DWORD pValueStruct,
IN DWORD dwOldValue,
IN DWORD dwMinimum,
IN DWORD dwMaximum,
OUT LPBYTE * ppPropertyList,
OUT LPDWORD pcbPropertyListSize
)
/*++
Routine Description:
Gets a DWORD property from a property list and advances the pointers.
Arguments:
pdwOutValue - Supplies the address of a pointer in which to return a
pointer to the string in the property list.
pValueStruct - Supplies the DWORD value from the property list.
dwOldValue - Supplies the previous value for this property.
dwMinimum - Minimum value the value can have. If both Minimum and Maximum
are 0, no range check will be done.
dwMaximum - Maximum value the value can have.
ppPropertyList - Supplies the address of the pointer to the property list
buffer which will be advanced to the beginning of the next property.
pcbPropertyListSize - Supplies a pointer to the buffer size which will be
decremented to account for this property.
Return Value:
ERROR_SUCCESS - The operation completed successfully.
ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
Win32 error code - The operation failed.
--*/
{
size_t cbData;
DWORD sc = ERROR_SUCCESS;
UNREFERENCED_PARAMETER( dwOldValue );
//
// Make sure the buffer is big enough and
// the value is formatted correctly.
//
cbData = sizeof(*pValueStruct);
if ( (*pcbPropertyListSize < cbData) ||
(pValueStruct->Syntax.wFormat != CLUSPROP_FORMAT_DWORD) ||
(pValueStruct->cbLength != sizeof(DWORD)) )
{
sc = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
//
// Make sure the value is in range.
//
if ( (dwMinimum != 0) && (dwMaximum != 0) )
{
if ( (pValueStruct->dw < dwMinimum) ||
(pValueStruct->dw > dwMaximum) )
{
sc = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
}
//
// Set to the new value.
//
*pdwOutValue = pValueStruct->dw;
//
// Decrement remaining buffer size and move to the next property.
//
*pcbPropertyListSize -= (DWORD) cbData;
*ppPropertyList += cbData;
Cleanup:
return sc;
} // ResUtilGetDwordProperty
static DWORD
ScBuildNetNameEnvironment(
IN LPWSTR pszNetworkName,
IN DWORD cchNetworkNameBufferSize,
IN OUT LPVOID * ppvEnvironment OPTIONAL
)
{
UNICODE_STRING usValueName;
UNICODE_STRING usValue;
DWORD sc = ERROR_SUCCESS;
NTSTATUS ntStatus;
DWORD cchDomain;
DWORD cchNetworkName = (DWORD)wcslen( pszNetworkName );
PVOID pvEnvBlock = NULL;
//
// validate parameters
//
if ( cchNetworkName == 0 ||
cchNetworkNameBufferSize == 0 ||
pszNetworkName == NULL ||
*pszNetworkName == UNICODE_NULL
)
{
return ERROR_INVALID_PARAMETER;
}
//
// if no env. block was passed in, create one since the RTL routines will
// modify the current process' environment if NULL is passed into
// RtlSetEnvironmentVariable
//
if ( *ppvEnvironment == NULL )
{
ntStatus = RtlCreateEnvironment( FALSE, // don't clone current environment
&pvEnvBlock );
if ( ! NT_SUCCESS( ntStatus ))
{
sc = RtlNtStatusToDosError( ntStatus );
goto Error;
}
}
else
{
pvEnvBlock = *ppvEnvironment;
}
//
// Add the virtual netname to the cloned environment
//
RtlInitUnicodeString( &usValueName, L"_CLUSTER_NETWORK_NAME_" );
RtlInitUnicodeString( &usValue, pszNetworkName );
ntStatus = RtlSetEnvironmentVariable(
&pvEnvBlock,
&usValueName,
&usValue
);
if ( ! NT_SUCCESS( ntStatus ) )
{
sc = RtlNtStatusToDosError( ntStatus );
goto Error;
}
//
// add the netname as the DNS hostname
//
RtlInitUnicodeString( &usValueName, L"_CLUSTER_NETWORK_HOSTNAME_" );
ntStatus = RtlSetEnvironmentVariable(
&pvEnvBlock,
&usValueName,
&usValue
);
if ( ! NT_SUCCESS( ntStatus ) )
{
sc = RtlNtStatusToDosError( ntStatus );
goto Error;
}
//
// Change the COMPUTERNAME environment variable to match.
//
RtlInitUnicodeString( &usValueName, L"COMPUTERNAME" );
ntStatus = RtlSetEnvironmentVariable(
&pvEnvBlock,
&usValueName,
&usValue
);
if ( ! NT_SUCCESS( ntStatus ) )
{
sc = RtlNtStatusToDosError( ntStatus );
goto Error;
}
//
// Now generate the string for the FQDN
//
RtlInitUnicodeString( &usValueName, L"_CLUSTER_NETWORK_FQDN_" );
pszNetworkName[ cchNetworkName ] = L'.';
cchDomain = cchNetworkNameBufferSize - cchNetworkName - 1;
if ( GetComputerNameExW(
ComputerNameDnsDomain,
&pszNetworkName[ cchNetworkName + 1 ],
&cchDomain )
)
{
if ( cchDomain == 0 )
{
pszNetworkName[ cchNetworkName ] = L'\0';
}
}
else
{
//
// Error from trying to get the DNS Domain name.
// Just don't set the DnsDomain name!
//
goto Error;
}
RtlInitUnicodeString( &usValue, pszNetworkName );
//
// Add in the FQDN name
//
ntStatus = RtlSetEnvironmentVariable(
&pvEnvBlock,
&usValueName,
&usValue
);
if ( ! NT_SUCCESS( ntStatus ) )
{
sc = RtlNtStatusToDosError( ntStatus );
goto Error;
}
Exit:
*ppvEnvironment = pvEnvBlock;
return sc;
Error:
if ( pvEnvBlock != NULL )
{
RtlDestroyEnvironment( pvEnvBlock );
pvEnvBlock = NULL;
}
goto Exit;
} // ScBuildNetNameEnvironment
static DWORD
ScGetNameFromNetnameResource(
HRESOURCE hNetNameResource,
LPWSTR * ppszNetworkName
)
{
DWORD sc = ERROR_SUCCESS;
BOOL fSuccess = FALSE;
LPWSTR pszNetworkName = NULL;
DWORD cchNetworkName = 0;
DWORD cchAllocSize = 0;
//
// First find out the network name
//
cchNetworkName = DNS_MAX_NAME_BUFFER_LENGTH;
cchAllocSize = cchNetworkName;
pszNetworkName = LocalAlloc( LMEM_FIXED, cchAllocSize * sizeof( pszNetworkName[ 0 ] ) );
if ( pszNetworkName == NULL )
{
sc = ERROR_NOT_ENOUGH_MEMORY;
goto Cleanup;
}
fSuccess = GetClusterResourceNetworkName(
hNetNameResource
, pszNetworkName
, &cchNetworkName
);
if ( ! fSuccess )
{
sc = GetLastError();
if ( sc == ERROR_MORE_DATA )
{
LocalFree( pszNetworkName );
cchNetworkName++;
cchNetworkName *= 2;
cchAllocSize = cchNetworkName;
pszNetworkName = LocalAlloc( LMEM_FIXED, cchAllocSize * sizeof( pszNetworkName[ 0 ] ) );
if ( pszNetworkName == NULL )
{
sc = ERROR_NOT_ENOUGH_MEMORY;
goto Cleanup;
} // if:
fSuccess = GetClusterResourceNetworkName(
hNetNameResource
, pszNetworkName
, &cchNetworkName
);
}
if ( ! fSuccess )
{
sc = GetLastError();
goto Cleanup;
}
} // if: !fSuccess
Cleanup:
if ( sc != ERROR_SUCCESS )
{
LocalFree( pszNetworkName );
pszNetworkName = NULL;
SetLastError( sc );
}
*ppszNetworkName = pszNetworkName;
return cchAllocSize;
} // ScGetNameFromNetnameResource
LPVOID
WINAPI
ResUtilGetEnvironmentWithNetName(
IN HRESOURCE hResource
)
/*++
Routine Description:
Creates an environment block based on the current thread or process
token's environment block, but with the addition of a
_CLUSTER_NETWORK_NAME=xxx environment value. xxx in this case represents
the network name of the supplied resource. This environment block is
suitable for passing to CreateProcess to create an environment that will
cause GetComputerName to lie to the application.
THIS API SHOULDN'T BE USED TO CREATE A SERVICE'S ENVIRONMENT unless the
service runs in the same user account context as that of the caller. The
service will end up with the caller's environment instead of the account
associated with the service. Use ResUtilSetResourceServiceEnvironment for
this purpose.
_CLUSTER_NETWORK_FQDN_ will be set to the fully qualified DNS name using
the primary DNS suffix for this node.
Arguments:
hResource - Supplies the resource
Return Value:
pointer to the environment block if successful.
NULL otherwise
--*/
{
PVOID pvEnvironment = NULL;
DWORD sc = ERROR_SUCCESS;
NTSTATUS ntStatus;
BOOL fSuccess;
LPWSTR pszNetworkName = NULL;
DWORD cchNetworkNameBufferSize;
HANDLE hToken = NULL;
//
// get the Name property of the netname represented by hResource
//
cchNetworkNameBufferSize = ScGetNameFromNetnameResource( hResource, &pszNetworkName );
if ( pszNetworkName == NULL )
{
sc = GetLastError();
goto Cleanup;
}
//
// see if the calling thread has a token. If so, we'll use that token's
// identity for getting the environment. If not, get the current process
// token. If that fails, we revert to using just the system environment
// area.
//
fSuccess = OpenThreadToken(GetCurrentThread(),
TOKEN_IMPERSONATE | TOKEN_QUERY,
TRUE,
&hToken);
if ( !fSuccess )
{
OpenProcessToken(GetCurrentProcess(),
TOKEN_IMPERSONATE | TOKEN_QUERY,
&hToken );
}
//
// Clone the current environment, picking up any changes that might have
// been made after resmon started
//
fSuccess = CreateEnvironmentBlock( &pvEnvironment, hToken, FALSE );
if ( ! fSuccess )
{
sc = GetLastError();
goto Cleanup;
}
ntStatus = ScBuildNetNameEnvironment( pszNetworkName, cchNetworkNameBufferSize, &pvEnvironment );
if ( ! NT_SUCCESS( ntStatus ) )
{
sc = RtlNtStatusToDosError( ntStatus );
goto Error;
}
Cleanup:
CloseHandle( hToken );
LocalFree( pszNetworkName );
SetLastError( sc );
return pvEnvironment;
Error:
if ( pvEnvironment != NULL )
{
RtlDestroyEnvironment( pvEnvironment );
pvEnvironment = NULL;
}
goto Cleanup;
} // ResUtilGetEnvironmentWithNetName
//***************************************************************************
//
// Worker thread routines
//
//***************************************************************************
DWORD
WINAPI
ClusWorkerStart(
IN PWORK_CONTEXT pContext
)
/*++
Routine Description:
Wrapper routine for cluster resource worker startup
Arguments:
Context - Supplies the context block. This will be freed.
Return Value:
ERROR_SUCCESS
--*/
{
DWORD Status;
WORK_CONTEXT Context;
//
// Capture our parameters and free the work context.
//
Context = *pContext;
LocalFree(pContext);
//
// Call the worker routine
//
Status = (Context.lpStartRoutine)(Context.Worker, Context.lpParameter);
//
// Synchronize and clean up properly.
//
EnterCriticalSection(&ResUtilWorkerLock);
if (!Context.Worker->Terminate) {
CloseHandle(Context.Worker->hThread);
Context.Worker->hThread = NULL;
}
Context.Worker->Terminate = TRUE;
LeaveCriticalSection(&ResUtilWorkerLock);
return(Status);
} // ClusWorkerStart
DWORD
WINAPI
ClusWorkerCreate(
OUT PCLUS_WORKER lpWorker,
IN PWORKER_START_ROUTINE lpStartAddress,
IN PVOID lpParameter
)
/*++
Routine Description:
Common wrapper for resource DLL worker threads. Provides
"clean" terminate semantics
Arguments:
lpWorker - Returns an initialized worker structure
lpStartAddress - Supplies the worker thread routine
lpParameter - Supplies the parameter to be passed to the
worker thread routine
Return Value:
ERROR_SUCCESS if successful
Win32 error code otherwise
--*/
{
PWORK_CONTEXT Context;
DWORD ThreadId;
DWORD Status;
Context = LocalAlloc(LMEM_FIXED, sizeof(WORK_CONTEXT));
if (Context == NULL) {
return(ERROR_NOT_ENOUGH_MEMORY);
}
Context->Worker = lpWorker;
Context->lpParameter = lpParameter;
Context->lpStartRoutine = lpStartAddress;
lpWorker->Terminate = FALSE;
lpWorker->hThread = CreateThread(NULL,
0,
ClusWorkerStart,
Context,
0,
&ThreadId);
if (lpWorker->hThread == NULL) {
Status = GetLastError();
LocalFree(Context);
return(Status);
}
return(ERROR_SUCCESS);
} // ClusWorkerCreate
BOOL
WINAPI
ClusWorkerCheckTerminate(
IN PCLUS_WORKER lpWorker
)
/*++
Routine Description:
Checks to see if the specified Worker thread should exit ASAP.
Arguments:
lpWorker - Supplies the worker
Return Value:
TRUE if the thread should exit.
FALSE otherwise
--*/
{
return(lpWorker->Terminate);
} // ClusWorkerCheckTerminate
VOID
WINAPI
ClusWorkerTerminate(
IN PCLUS_WORKER lpWorker
)
/*++
Routine Description:
Checks to see if the specified Worker thread should exit ASAP.
Arguments:
lpWorker - Supplies the worker
Return Value:
None.
--*/
{
//
// N.B. There is a race condition here if multiple threads
// call this routine on the same worker. The first one
// through will set Terminate. The second one will see
// that Terminate is set and return immediately without
// waiting for the Worker to exit. Not really any nice
// way to fix this without adding another synchronization
// object.
//
if ((lpWorker->hThread == NULL) ||
(lpWorker->Terminate)) {
return;
}
EnterCriticalSection(&ResUtilWorkerLock);
if (!lpWorker->Terminate) {
lpWorker->Terminate = TRUE;
LeaveCriticalSection(&ResUtilWorkerLock);
WaitForSingleObject(lpWorker->hThread, INFINITE);
CloseHandle(lpWorker->hThread);
lpWorker->hThread = NULL;
} else {
LeaveCriticalSection(&ResUtilWorkerLock);
}
return;
} // ClusWorkerTerminate
DWORD
WINAPI
ResUtilCreateDirectoryTree(
IN LPCWSTR pszPath
)
/*++
Routine Description:
Creates all the directories in the specified path.
ERROR_ALREADY_EXISTS will never be returned by this routine.
Arguments:
pszPath - String containing a path.
Return Value:
ERROR_SUCCESS - The operation completed successfully
Win32 error code - The operation failed.
--*/
{
return( ClRtlCreateDirectory( pszPath ) );
} // ResUtilCreateDirectoryTree
BOOL
WINAPI
ResUtilIsPathValid(
IN LPCWSTR pszPath
)
/*++
Routine Description:
Returns true if the given path looks syntactically valid.
This call is NOT network-aware.
Arguments:
pszPath - String containing a path.
Return Value:
TRUE if the path looks valid, otherwise FALSE.
--*/
{
return( ClRtlIsPathValid( pszPath ) );
} // ResUtilIsPathValid
DWORD
WINAPI
ResUtilFreeEnvironment(
IN LPVOID lpEnvironment
)
/*++
Routine Description:
Destroys an environment variable block.
Arguments:
Environment - the environment variable block to destroy.
Return Value:
A Win32 error code.
--*/
{
NTSTATUS ntStatus;
ntStatus = RtlDestroyEnvironment( lpEnvironment );
return( RtlNtStatusToDosError(ntStatus) );
} // ResUtilFreeEnvironment
LPWSTR
WINAPI
ResUtilExpandEnvironmentStrings(
IN LPCWSTR pszSrc
)
/*++
Routine Description:
Expands environment strings and returns an allocated buffer containing
the result.
Arguments:
pszSrc - Source string to expand.
Return Value:
A pointer to a buffer containing the value if successful.
NULL if unsuccessful. Call GetLastError() to get more details.
--*/
{
return( ClRtlExpandEnvironmentStrings( pszSrc ) );
} // ResUtilExpandEnvironmentStrings
/////////////////////////////////////////////////////////////////////////////
//++
//
// ResUtilSetResourceServiceEnvironment
//
// Description:
// Write an additional netname based environment for the specified
// service. SCM will add these vars to the target service's environment
// such that the hostname APIs (GetComputerName, et. al.) will provide
// the netname as the hostname instead of the normal hostname.
//
// Arguments:
// pszServiceName [IN]
// Name of service whose environment is to be augmented.
//
// hResource [IN]
// Handle to resource that is dependent on a netname resource.
//
// pfnLogEvent [IN]
// Pointer to a routine that handles the reporting of events from
// the resource DLL.
//
// hResourceHandle [IN]
// Handle of hResource for logging.
//
// Return Value:
// ERROR_SUCCESS
// The function completed successfully.
//
// Win32 error code
// The function failed.
//
//--
/////////////////////////////////////////////////////////////////////////////
DWORD WINAPI ResUtilSetResourceServiceEnvironment(
IN LPCWSTR pszServiceName,
IN HRESOURCE hResource,
IN PLOG_EVENT_ROUTINE pfnLogEvent,
IN RESOURCE_HANDLE hResourceHandle
)
{
DWORD sc = ERROR_SUCCESS;
DWORD cbEnvironment = 0;
PVOID pvEnvironment = NULL;
LPWSTR pszEnvString = NULL;
HKEY hkeyServicesKey = NULL;
HKEY hkeyServiceName = NULL;
LPWSTR pszNetworkName = NULL;
DWORD cchNetworkNameBufferSize = 0;
//
// get the Name property from the netname resource represented by
// hResource
//
cchNetworkNameBufferSize = ScGetNameFromNetnameResource( hResource, &pszNetworkName );
if ( pszNetworkName == NULL )
{
sc = GetLastError();
(pfnLogEvent)(
hResourceHandle,
LOG_ERROR,
L"ResUtilSetResourceServiceEnvironment: Failed to get the Name property "
L"of this resource, error = %1!u!.\n",
sc
);
goto Cleanup;
}
//
// now get only the env. vars that cause the hostname APIs to report the
// netname as the hostname
//
sc = ScBuildNetNameEnvironment( pszNetworkName, cchNetworkNameBufferSize, &pvEnvironment );
if ( sc != ERROR_SUCCESS )
{
(pfnLogEvent)(
hResourceHandle,
LOG_ERROR,
L"ResUtilSetResourceServiceEnvironment: Failed to build the target service's "
L"environment for this resource, error = %1!u!.\n",
sc
);
goto Cleanup;
}
//
// Compute the size of the environment. We are looking for
// the double NULL terminator that ends the environment block.
//
pszEnvString = (LPWSTR) pvEnvironment;
while ( *pszEnvString != L'\0' )
{
while ( *pszEnvString++ != L'\0')
{
} // while: more characters in this environment string
} // while: more environment strings
cbEnvironment = (DWORD)((PUCHAR)pszEnvString - (PUCHAR)pvEnvironment) + sizeof( WCHAR );
//
// Open the Services key in the registry.
//
sc = RegOpenKeyExW(
HKEY_LOCAL_MACHINE,
L"System\\CurrentControlSet\\Services",
0,
KEY_READ,
&hkeyServicesKey
);
if ( sc != ERROR_SUCCESS )
{
(pfnLogEvent)(
hResourceHandle,
LOG_ERROR,
L"ResUtilSetResourceServiceEnvironment: Failed to open services key, error = %1!u!.\n",
sc
);
goto Cleanup;
} // if: error opening the Services key in the registry
//
// Open the service name key in the registry
//
sc = RegOpenKeyExW(
hkeyServicesKey,
pszServiceName,
0,
KEY_READ | KEY_WRITE,
&hkeyServiceName
);
RegCloseKey( hkeyServicesKey );
if ( sc != ERROR_SUCCESS )
{
(pfnLogEvent)(
hResourceHandle,
LOG_ERROR,
L"ResUtilSetResourceServiceEnvironment: Failed to open service key, error = %1!u!.\n",
sc
);
goto Cleanup;
} // if: error opening the service name key in the registry
//
// Set the environment value in the service's registry key.
//
sc = RegSetValueExW(
hkeyServiceName,
L"Environment",
0,
REG_MULTI_SZ,
(const BYTE *) pvEnvironment,
cbEnvironment
);
RegCloseKey( hkeyServiceName );
if ( sc != ERROR_SUCCESS )
{
(pfnLogEvent)(
hResourceHandle,
LOG_ERROR,
L"ResUtilSetResourceServiceEnvironment: Failed to set service environment value, error = %1!u!.\n",
sc
);
goto Cleanup;
} // if: error setting the Environment value in the registry
Cleanup:
LocalFree( pszNetworkName );
if ( pvEnvironment != NULL )
{
ResUtilFreeEnvironment( pvEnvironment );
} // if: environment block allocated
return sc;
} //*** ResUtilSetResourceServiceEnvironment()
/////////////////////////////////////////////////////////////////////////////
//++
//
// ResUtilRemoveResourceServiceEnvironment
//
// Description:
// Remove the "netname" environment variables for the specified service.
//
// Arguments:
// pszServiceName [IN]
// Name of service whose environment is to be set.
//
// pfnLogEvent [IN]
// Pointer to a routine that handles the reporting of events from
// the resource DLL.
//
// hResourceHandle [IN]
// Handle for logging.
//
// Return Value:
// ERROR_SUCCESS
// The function completed successfully.
//
// Win32 error code
// The function failed.
//
//--
/////////////////////////////////////////////////////////////////////////////
DWORD WINAPI ResUtilRemoveResourceServiceEnvironment(
IN LPCWSTR pszServiceName,
IN PLOG_EVENT_ROUTINE pfnLogEvent,
IN RESOURCE_HANDLE hResourceHandle
)
{
DWORD sc;
HKEY hkeyServicesKey;
HKEY hkeyServiceName;
//
// Open the Services key in the registry.
//
sc = RegOpenKeyExW(
HKEY_LOCAL_MACHINE,
L"System\\CurrentControlSet\\Services",
0,
KEY_READ,
&hkeyServicesKey
);
if ( sc != ERROR_SUCCESS )
{
(pfnLogEvent)(
hResourceHandle,
LOG_ERROR,
L"ResUtilRemoveResourceServiceEnvironment: Failed to open Services key, error = %1!u!.\n",
sc
);
goto Cleanup;
} // if: error opening the Services key in the registry
//
// Open the service name key in the registry
//
sc = RegOpenKeyExW(
hkeyServicesKey,
pszServiceName,
0,
KEY_READ | KEY_WRITE,
&hkeyServiceName
);
RegCloseKey( hkeyServicesKey );
if ( sc != ERROR_SUCCESS )
{
(pfnLogEvent)(
hResourceHandle,
LOG_ERROR,
L"ResUtilRemoveResourceServiceEnvironment: Failed to open %1!ws! key, error = %2!u!.\n",
pszServiceName,
sc
);
goto Cleanup;
} // if: error opening the service name key in the registry
//
// Delete the environment value in the service's registry key.
//
sc = RegDeleteValueW(
hkeyServiceName,
L"Environment"
);
RegCloseKey( hkeyServiceName );
if ( sc != ERROR_SUCCESS )
{
(pfnLogEvent)(
hResourceHandle,
LOG_WARNING,
L"ResUtilRemoveResourceServiceEnvironment: Failed to remove environment "
L"value from service %1!ws!, error = %1!u!.\n",
pszServiceName,
sc
);
goto Cleanup;
} // if: error setting the Environment value in the registry
Cleanup:
return sc;
} //*** ResUtilRemoveResourceServiceEnvironment()
/////////////////////////////////////////////////////////////////////////////
//++
//
// ResUtilSetResourceServiceStartParameters
//
// Description:
// Set the start parameters for the specified service.
//
// Arguments:
// pszServiceName [IN]
// Name of service whose start parameters are to be set.
//
// schSCMHandle [IN]
// Handle to the Service Control Manager. Can be specified as NULL.
//
// phService [OUT]
// Service handle.
//
// pfnLogEvent [IN]
// Pointer to a routine that handles the reporting of events from
// the resource DLL.
//
// hResourceHandle [IN]
// Handle for logging.
//
// Return Value:
// ERROR_SUCCESS
// The function completed successfully.
//
// Win32 error code
// The function failed.
//
//--
/////////////////////////////////////////////////////////////////////////////
DWORD WINAPI ResUtilSetResourceServiceStartParameters(
IN LPCWSTR pszServiceName,
IN SC_HANDLE schSCMHandle,
IN OUT LPSC_HANDLE phService,
IN PLOG_EVENT_ROUTINE pfnLogEvent,
IN RESOURCE_HANDLE hResourceHandle
)
{
DWORD sc;
DWORD cbBytesNeeded;
DWORD cbQueryServiceConfig;
DWORD idx;
BOOL bWeOpenedSCM = FALSE;
LPQUERY_SERVICE_CONFIG pQueryServiceConfig = NULL;
LPSERVICE_FAILURE_ACTIONS pSvcFailureActions = NULL;
//
// Open the Service Control Manager if necessary.
//
if ( schSCMHandle == NULL )
{
schSCMHandle = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
if ( schSCMHandle == NULL )
{
sc = GetLastError();
(pfnLogEvent)(
hResourceHandle,
LOG_ERROR,
L"ResUtilSetResourceServiceStartParameters: Failed to open Service Control Manager. Error: %1!u!.\n",
sc
);
goto Cleanup;
} // if: error opening the Service Control Manager
bWeOpenedSCM = TRUE;
} // if: Service Control Manager not open yet
//
// Open the service.
//
*phService = OpenService(
schSCMHandle,
pszServiceName,
SERVICE_ALL_ACCESS
);
if ( *phService == NULL )
{
sc = GetLastError();
// TODO: Log event to the event log.
(pfnLogEvent)(
hResourceHandle,
LOG_ERROR,
L"ResUtilSetResourceServiceStartParameters: Failed to open the '%1' service. Error: %2!u!.\n",
pszServiceName,
sc
);
goto Cleanup;
} // if: error opening the service
//
// Query the service to make sure it is not disabled.
//
cbQueryServiceConfig = sizeof( QUERY_SERVICE_CONFIG );
do
{
//
// Allocate memory for the config info structure.
//
pQueryServiceConfig = (LPQUERY_SERVICE_CONFIG) LocalAlloc( LMEM_FIXED, cbQueryServiceConfig );
if ( pQueryServiceConfig == NULL )
{
sc = GetLastError();
(pfnLogEvent)(
hResourceHandle,
LOG_ERROR,
L"ResUtilSetResourceServiceStartParameters: Failed to allocate memory for query_service_config. Error: %1!u!.\n",
sc
);
break;
} // if: error allocating memory
//
// Query for the config info. If it fails because the buffer
// is too small, reallocate and try again.
//
if ( ! QueryServiceConfig(
*phService,
pQueryServiceConfig,
cbQueryServiceConfig,
&cbBytesNeeded
) )
{
sc = GetLastError();
if ( sc != ERROR_INSUFFICIENT_BUFFER )
{
(pfnLogEvent)(
hResourceHandle,
LOG_ERROR,
L"ResUtilSetResourceServiceStartParameters: Failed to query service configuration for the '%1' service. Error: %2!u!.\n",
pszServiceName,
sc
);
break;
}
sc = ERROR_SUCCESS;
LocalFree( pQueryServiceConfig );
pQueryServiceConfig = NULL;
cbQueryServiceConfig = cbBytesNeeded;
continue;
} // if: error querying for service config info
else
{
sc = ERROR_SUCCESS;
cbBytesNeeded = 0;
} // else: query was successful
//
// Check to see if the service is disabled or not.
//
if ( pQueryServiceConfig->dwStartType == SERVICE_DISABLED )
{
(pfnLogEvent)(
hResourceHandle,
LOG_ERROR,
L"ResUtilSetResourceServiceStartParameters: The service '%1' is DISABLED.\n",
pszServiceName
);
sc = ERROR_SERVICE_DISABLED;
break;
} // if: service is disabled
} while ( cbBytesNeeded != 0 );
if ( sc != ERROR_SUCCESS )
{
goto Cleanup;
} // if: error occurred checking to see if service is disabled
//
// Set the service to manual start.
//
if ( ! ChangeServiceConfig(
*phService,
SERVICE_NO_CHANGE,
SERVICE_DEMAND_START, // Manual start
SERVICE_NO_CHANGE,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL
) )
{
sc = GetLastError();
(pfnLogEvent)(
hResourceHandle,
LOG_ERROR,
L"ResUtilSetResourceServiceStartParameters: Failed to set service '%1' to manual start. Error: %2!u!.\n",
pszServiceName,
sc
);
goto Cleanup;
} // if: error setting service to manual start
//
// Query for the size of the service failure actions array.
// Use sc as the dummy buffer since the QueryServiceConfig2 API
// is not that friendly.
//
if ( ! QueryServiceConfig2(
*phService,
SERVICE_CONFIG_FAILURE_ACTIONS,
(LPBYTE) &sc,
sizeof( DWORD ),
&cbBytesNeeded
) )
{
sc = GetLastError();
if ( sc == ERROR_INSUFFICIENT_BUFFER )
{
sc = ERROR_SUCCESS;
} // if: expected "buffer too small" error occurred
else
{
(pfnLogEvent)(
hResourceHandle,
LOG_ERROR,
L"ResUtilSetResourceServiceStartParameters: Failed to query service configuration for size for the '%1' service. Error: %2!u!.\n",
pszServiceName,
sc
);
goto Cleanup;
} // else: an unexpected error occurred
} // if: error querying for service failure actions buffer size
//
// Allocate memory for the service failure actions array.
//
pSvcFailureActions = (LPSERVICE_FAILURE_ACTIONS) LocalAlloc( LMEM_FIXED, cbBytesNeeded );
if ( pSvcFailureActions == NULL )
{
sc = GetLastError();
(pfnLogEvent)(
hResourceHandle,
LOG_ERROR,
L"ResUtilSetResourceServiceStartParameters: Failed to allocate memory of size %1!u!. Error: %2!u!.\n",
cbBytesNeeded,
sc
);
goto Cleanup;
} // if: error allocating memory for the service failure actions array
//
// Query for the service failure actions array.
//
if ( ! QueryServiceConfig2(
*phService,
SERVICE_CONFIG_FAILURE_ACTIONS,
(LPBYTE) pSvcFailureActions,
cbBytesNeeded,
&cbBytesNeeded
) )
{
sc = GetLastError();
(pfnLogEvent)(
hResourceHandle,
LOG_ERROR,
L"ResUtilSetResourceServiceStartParameters: Failed to query service configuration for the '%1' service. Error: %2!u!.\n",
pszServiceName,
sc
);
goto Cleanup;
} // if: error querying for service failure actions
//
// If any of the service action is set to service restart,
// set it to none.
//
for ( idx = 0 ; idx < pSvcFailureActions->cActions ; idx++ )
{
if ( pSvcFailureActions->lpsaActions[ idx ].Type == SC_ACTION_RESTART )
{
pSvcFailureActions->lpsaActions[ idx ].Type = SC_ACTION_NONE;
} // if: action set to restart
} // for: each service failure action array entry
//
// Set the changes to the service failure actions array.
//
if ( ! ChangeServiceConfig2(
*phService,
SERVICE_CONFIG_FAILURE_ACTIONS,
pSvcFailureActions
) )
{
sc = GetLastError();
(pfnLogEvent)(
hResourceHandle,
LOG_ERROR,
L"ResUtilSetResourceServiceStartParameters: Failed to set service failure actions for the '%1' service. Error: %2!u!.\n",
pszServiceName,
sc
);
goto Cleanup;
} // if: error saving service failure actions
Cleanup:
//
// Cleanup.
//
LocalFree( pQueryServiceConfig );
LocalFree( pSvcFailureActions );
if ( bWeOpenedSCM )
{
CloseServiceHandle( schSCMHandle );
} // if: we opened the Server Control Manager
if ( ( sc != ERROR_SUCCESS ) && ( *phService != NULL ) )
{
CloseServiceHandle( *phService );
*phService = NULL;
} // if: error occurred after opening service
return sc;
} //*** ResUtilSetResourceServiceStartParameters()
/////////////////////////////////////////////////////////////////////////////
//++
//
// ResUtilGetResourceDependentIPAddressProps
//
// Description:
// Get the properties from the first IP Address resource on which the
// specified resource is dependent.
//
// Arguments:
// hResource [IN]
// Handle to the resource to query.
//
// pszAddress [OUT]
// Output buffer for returning the address.
//
// pcchAddress [IN OUT]
// On input contains the size in characters of the pszAddress buffer.
// On output contains the size in characters, including the terminating
// NULL, of the string for the Address property. If pszAddress is
// specified as NULL and this is not specified as NULL, ERROR_SUCCESS
// be returned. Otherwise, ERROR_MORE_DATA will be returned.
//
// pszSubnetMask [OUT]
// Output buffer for returning the subnet mask.
//
// pcchSubnetMask [IN OUT]
// On input contains the size in characters of the pszSubnetMask buffer.
// On output contains the size in characters, including the terminating
// NULL, of the string for the SubnetMask property. If pszSubnetMask is
// specified as NULL and this is not specified as NULL, ERROR_SUCCESS
// be returned. Otherwise, ERROR_MORE_DATA will be returned.
//
// pszNetwork [OUT]
// Output buffer for returning the network.
//
// pcchNetwork [IN OUT]
// On input contains the size in characters of the pszNetwork buffer.
// On output contains the size in characters, including the terminating
// NULL, of the string for the Network property. If pszNetwork is
// specified as NULL and this is not specified as NULL, ERROR_SUCCESS
// be returned. Otherwise, ERROR_MORE_DATA will be returned.
//
// Return Value:
// ERROR_SUCCESS
// The function completed successfully.
//
// ERROR_MORE_DATA
// The size of one of the buffers was too small.
//
// Win32 error code
// The function failed.
//
//--
/////////////////////////////////////////////////////////////////////////////
DWORD WINAPI ResUtilGetResourceDependentIPAddressProps(
IN HRESOURCE hResource,
OUT LPWSTR pszAddress,
IN OUT DWORD * pcchAddress,
OUT LPWSTR pszSubnetMask,
IN OUT DWORD * pcchSubnetMask,
OUT LPWSTR pszNetwork,
IN OUT DWORD * pcchNetwork
)
{
DWORD sc = ERROR_SUCCESS;
HRESENUM hresenum = NULL;
HRESOURCE hresDep = NULL;
DWORD idx;
DWORD nType;
DWORD cchmacName;
DWORD cchName;
LPWSTR pszName = NULL;
DWORD cbProps;
PBYTE pbProps = NULL;
LPWSTR pszProp;
DWORD cchProp;
HCLUSTER hCluster;
HRESULT hr;
//
// Enumerate dependent resources.
//
hresenum = ClusterResourceOpenEnum( hResource, CLUSTER_RESOURCE_ENUM_DEPENDS );
if ( hresenum == NULL )
{
sc = GetLastError();
goto Cleanup;
} // if: error opening the enumeration
//
// Allocate the initial name buffer.
//
cchmacName = 256;
cchName = cchmacName;
pszName = (LPWSTR) LocalAlloc( LMEM_FIXED, cchName * sizeof( pszName[ 0 ] ) );
if ( pszName == NULL )
{
sc = GetLastError();
goto Cleanup;
} // if: error allocating resource name buffer
for ( idx = 0 ; ; idx++ )
{
//
// Get the first entry in the enumeration.
//
sc = ClusterResourceEnum(
hresenum,
idx,
&nType,
pszName,
&cchName
);
if ( sc == ERROR_MORE_DATA )
{
LocalFree( pszName );
cchName++;
cchmacName = cchName;
pszName = (LPWSTR) LocalAlloc( LMEM_FIXED, cchName * sizeof( pszName[ 0 ] ) );
if ( pszName == NULL )
{
sc = GetLastError();
break;
} // if: error allocating resource name buffer
sc = ClusterResourceEnum(
hresenum,
idx,
&nType,
pszName,
&cchName
);
} // if: buffer is too small
if ( sc != ERROR_SUCCESS )
{
break;
} // if: error getting the dependent resource name
//
// Open the resource.
//
hCluster = GetClusterFromResource( hResource );
if ( hCluster == NULL ) {
sc = GetLastError();
break;
}
hresDep = OpenClusterResource( hCluster, pszName );
if ( hresDep == NULL )
{
sc = GetLastError();
break;
} // if: error opening the dependent resource
//
// Get the resource type name.
//
cchName = cchmacName;
sc = ClusterResourceControl(
hresDep,
NULL,
CLUSCTL_RESOURCE_GET_RESOURCE_TYPE,
NULL,
0,
pszName,
cchmacName,
&cchName
);
if ( sc == ERROR_MORE_DATA )
{
LocalFree( pszName );
cchName++;
cchmacName = cchName;
pszName = (LPWSTR) LocalAlloc( LMEM_FIXED, cchName * sizeof( pszName[ 0 ] ) );
if ( pszName == NULL )
{
sc = GetLastError();
break;
} // if: error allocating resource type name buffer
sc = ClusterResourceControl(
hresDep,
NULL,
CLUSCTL_RESOURCE_GET_RESOURCE_TYPE,
NULL,
0,
pszName,
cchmacName,
&cchName
);
} // if: buffer was too small
if ( sc != ERROR_SUCCESS )
{
break;
} // if: error getting resource type name
if ( ClRtlStrNICmp( pszName, CLUS_RESTYPE_NAME_IPADDR, RTL_NUMBER_OF( CLUS_RESTYPE_NAME_IPADDR ) ) == 0 )
{
//
// Get the private properties of the dependent resource.
//
cbProps = 1024;
pbProps = (PBYTE) LocalAlloc( LMEM_FIXED, cbProps );
if ( pbProps == NULL )
{
sc = GetLastError();
break;
} // if: error allocating buffer for properties
sc = ClusterResourceControl(
hresDep,
NULL,
CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES,
NULL,
0,
pbProps,
cbProps,
&cbProps
);
if ( sc == ERROR_MORE_DATA )
{
LocalFree( pbProps );
pbProps = (PBYTE) LocalAlloc( LMEM_FIXED, cbProps );
if ( pbProps == NULL )
{
sc = GetLastError();
break;
} // if: error allocating buffer for properties
sc = ClusterResourceControl(
hresDep,
NULL,
CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES,
NULL,
0,
pbProps,
cbProps,
&cbProps
);
} // if: properties buffer too small
if ( sc != ERROR_SUCCESS )
{
break;
} // if: error getting private properties
//
// Return the address.
//
if ( ( pszAddress != NULL )
|| ( pcchAddress != NULL )
)
{
sc = ResUtilFindSzProperty(
pbProps,
cbProps,
L"Address",
&pszProp
);
if ( sc != ERROR_SUCCESS )
{
break;
} // if: error finding the property
cchProp = (DWORD) wcslen( pszProp ) + 1;
if ( cchProp > *pcchAddress )
{
if ( pszAddress == NULL )
{
sc = ERROR_SUCCESS;
} // if: no buffer was specified
else
{
sc = ERROR_MORE_DATA;
} // else: buffer was specified but was too small
*pcchAddress = cchProp;
break;
} // if: buffer is too small
hr = StringCchCopy( pszAddress, *pcchAddress, pszProp );
if ( FAILED( hr ) )
{
sc = HRESULT_CODE( hr );
break;
}
*pcchAddress = cchProp;
} // if: address requested by caller
//
// Return the subnet mask.
//
if ( ( pszSubnetMask != NULL )
|| ( pcchSubnetMask != NULL )
)
{
sc = ResUtilFindSzProperty(
pbProps,
cbProps,
L"SubnetMask",
&pszProp
);
if ( sc != ERROR_SUCCESS )
{
break;
} // if: error finding the property
cchProp = (DWORD) wcslen( pszProp ) + 1;
if ( cchProp > *pcchSubnetMask )
{
if ( pszSubnetMask == NULL )
{
sc = ERROR_SUCCESS;
} // if: no buffer was specified
else
{
sc = ERROR_MORE_DATA;
} // else: buffer was specified but was too small
*pcchSubnetMask = cchProp;
break;
} // if: buffer is too small
hr = StringCchCopy( pszSubnetMask, *pcchSubnetMask, pszProp );
if ( FAILED( hr ) )
{
sc = HRESULT_CODE( hr );
break;
}
*pcchSubnetMask = cchProp;
} // if: subnet mask requested by caller
//
// Return the network.
//
if ( ( pszNetwork != NULL )
|| ( pcchNetwork != NULL )
)
{
sc = ResUtilFindSzProperty(
pbProps,
cbProps,
L"Network",
&pszProp
);
if ( sc != ERROR_SUCCESS )
{
break;
} // if: error finding the property
cchProp = (DWORD) wcslen( pszProp ) + 1;
if ( cchProp > *pcchNetwork )
{
if ( pszNetwork == NULL )
{
sc = ERROR_SUCCESS;
} // if: no buffer was specified
else
{
sc = ERROR_MORE_DATA;
} // else: buffer was specified but was too small
*pcchNetwork = cchProp;
break;
} // if: buffer is too small
hr = StringCchCopy( pszNetwork, *pcchNetwork, pszProp );
if ( FAILED( hr ) )
{
sc = HRESULT_CODE( hr );
break;
}
*pcchNetwork = cchProp;
} // if: network requested by caller
//
// Exit the loop since we found a match.
//
break;
} // if: IP Address resource found
//
// Close the dependent resource.
//
CloseClusterResource( hresDep );
hresDep = NULL;
} // for: each dependency
Cleanup:
//
// Cleanup.
//
LocalFree( pszName );
LocalFree( pbProps );
if ( hresenum != NULL )
{
ClusterResourceCloseEnum( hresenum );
} // if: we opened the enumerator
if ( hresDep != NULL )
{
CloseClusterResource( hresDep );
} // if: opened dependent resource
return sc;
} //*** ResUtilGetResourceDependentIPAddressProps()
/////////////////////////////////////////////////////////////////////////////
//++
//
// ResUtilFindDependentDiskResourceDriveLetter
//
// Description:
// Finds a disk resource in the dependent resources and retrieves the
// the drive letter associated with it.
//
// Arguments:
// hCluster [IN]
// Handle to the cluster.
//
// hResource [IN]
// Handle to the resource to query for dependencies.
//
// pszDriveLetter [IN/RETVAL]
// The drive letter of a dependent disk resource that was found.
// If a resource is not found, this value is untouched.
//
// pcchDriverLetter [IN/OUT]
// [IN] The number of characters that pszDriverLetter points to.
// [OUT] The number of characters written to the buffer
// (including NULL). If ERROR_MORE_DATA is returned, this value
// is the size of the buffer required to store the value.
//
// Return Value:
// ERROR_SUCCESS
// The function completed successfully and the drive letter was
// set.
//
// ERROR_NO_MORE_ITEMS
// ERROR_RESOURCE_NOT_PRESENT
// A dependent disk resource was not found or the resource is
// not dependent on a disk resource.
//
// ERROR_MORE_DATA
// The buffer passed in is too small. pcchDriveLetter will
// contain the size of the buffer (WCHARs) needed to fulfill
// the request.
//
// Win32 error code
// Other possible failures.
//
// SPECIAL NOTE:
// Do _NOT_ call this from a Resource DLL. It will cause a deadlock.
// You should have your Resource Extension call this function and
// write the results out as a private property that your Resource
// DLL can then read.
//
//--
/////////////////////////////////////////////////////////////////////////////
DWORD WINAPI ResUtilFindDependentDiskResourceDriveLetter(
IN HCLUSTER hCluster, // handle to cluster
IN HRESOURCE hResource, // handle to resource to query for dependencies
IN LPWSTR pszDriveLetter, // buffer to store drive letter (ex. "X:")
IN OUT DWORD * pcchDriveLetter // IN size of the pszDriveLetter buffer, OUT size of buffer required
)
{
BOOL fFoundDriveLetter = FALSE;
DWORD status = ERROR_SUCCESS;
HRESENUM hresenum = NULL;
HRESOURCE hRes = NULL;
DWORD cchName;
DWORD dwRetType;
WCHAR szName[ MAX_PATH ];
INT iCount;
HRESULT hr;
PBYTE pDiskInfo = NULL;
// validate arguments
if ( !pszDriveLetter || !pcchDriveLetter )
{
status = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
hresenum = ClusterResourceOpenEnum( hResource, CLUSTER_RESOURCE_ENUM_DEPENDS );
if ( hresenum != NULL )
{
// Scan the dependencies until we find a disk resource or we hit
// the end of the dependency list.
for( iCount = 0 ; ! fFoundDriveLetter && ( status == ERROR_SUCCESS ) ; iCount++ )
{
cchName = RTL_NUMBER_OF( szName );
status = ClusterResourceEnum( hresenum, iCount, &dwRetType, szName, &cchName );
if ( status == ERROR_SUCCESS )
{
// Interrogate the resource to see if it is a disk resource.
hRes = OpenClusterResource( hCluster, szName );
if ( hRes != NULL )
{
DWORD cbDiskInfo = sizeof(CLUSPROP_DWORD)
+ sizeof(CLUSPROP_SCSI_ADDRESS)
+ sizeof(CLUSPROP_DISK_NUMBER)
+ sizeof(CLUSPROP_PARTITION_INFO)
+ sizeof(CLUSPROP_SYNTAX);
pDiskInfo = (PBYTE) LocalAlloc( LMEM_FIXED, cbDiskInfo );
if ( !pDiskInfo )
{
status = ERROR_OUTOFMEMORY;
goto Cleanup;
} // if: !pDiskInfo
status = ClusterResourceControl( hRes,
NULL,
CLUSCTL_RESOURCE_STORAGE_GET_DISK_INFO,
NULL,
0,
pDiskInfo,
cbDiskInfo,
&cbDiskInfo
);
if ( status == ERROR_MORE_DATA )
{
LocalFree( pDiskInfo );
// get a bigger block
pDiskInfo = (PBYTE) LocalAlloc( LMEM_FIXED, cbDiskInfo );
if ( !pDiskInfo )
{
status = ERROR_OUTOFMEMORY;
goto Cleanup;
} // if: !pDiskInfo
status = ClusterResourceControl( hRes,
NULL,
CLUSCTL_RESOURCE_STORAGE_GET_DISK_INFO,
NULL,
0,
pDiskInfo,
cbDiskInfo,
&cbDiskInfo
);
} // if: more data
if ( status == ERROR_SUCCESS )
{
DWORD dwValueSize;
CLUSPROP_BUFFER_HELPER props;
PCLUSPROP_PARTITION_INFO pPartitionInfo;
props.pb = pDiskInfo;
// Loop through each property.
while ( ! fFoundDriveLetter
&& ( status == ERROR_SUCCESS )
&& ( cbDiskInfo > sizeof(CLUSPROP_SYNTAX ) )
&& ( props.pSyntax->dw != CLUSPROP_SYNTAX_ENDMARK) )
{
// Get the size of this value and verify there is enough buffer left.
dwValueSize = sizeof(*props.pValue) + ALIGN_CLUSPROP( props.pValue->cbLength );
if ( dwValueSize > cbDiskInfo )
{
goto Cleanup;
} // if: data is not valid
if ( props.pSyntax->dw == CLUSPROP_SYNTAX_PARTITION_INFO )
{
// Validate the data. There must be a device name.
pPartitionInfo = props.pPartitionInfoValue;
if ( ( dwValueSize != sizeof(*pPartitionInfo) )
|| ( pPartitionInfo->szDeviceName[0] == L'\0' ) )
{
goto Cleanup;
} // if: data is not valid
// Make sure it fits
if ( wcslen( pPartitionInfo->szDeviceName ) < *pcchDriveLetter )
{
hr = StringCchCopy( pszDriveLetter, *pcchDriveLetter, pPartitionInfo->szDeviceName );
if ( FAILED( hr ) )
{
status = HRESULT_CODE( hr );
goto Cleanup;
}
fFoundDriveLetter = TRUE;
} // if: drive letter fits into buffer
else
{
status = ERROR_MORE_DATA;
} // else: does not fit into buffer
// set the size written and/or size needed
*pcchDriveLetter = (DWORD) wcslen( pPartitionInfo->szDeviceName ) + 1;
} // if props.pSyntax->dw
cbDiskInfo -= dwValueSize;
props.pb += dwValueSize;
} // while
} // if status
else if ( status == ERROR_INVALID_FUNCTION )
{
// Ignore resources that don't support the control
// code. Only storage-class resources will support
// the control code.
status = ERROR_SUCCESS;
} // else if: resource doesn't support the control code
LocalFree( pDiskInfo );
pDiskInfo = NULL;
CloseClusterResource( hRes );
hRes = NULL;
} // if hRes
} // if status
else if ( status == ERROR_NO_MORE_ITEMS )
{
goto Cleanup;
} // if status
} // for ( i )
ClusterResourceCloseEnum( hresenum );
hresenum = NULL;
} // if: opened hresenum
else
{
status = GetLastError( );
} // else: failed to open hresenum
Cleanup:
// Make sure if we did not find a disk resource that we don't
// return ERROR_SUCCESS or ERROR_NO_MORE_ITEMS.
if ( ! fFoundDriveLetter
&& ( ( status == ERROR_SUCCESS )
|| ( status == ERROR_NO_MORE_ITEMS ) ) )
{
status = ERROR_RESOURCE_NOT_PRESENT;
} // if: sanity check
LocalFree( pDiskInfo );
if ( hRes != NULL )
{
CloseClusterResource( hRes );
}
if ( hresenum != NULL )
{
ClusterResourceCloseEnum( hresenum );
}
return status;
} //*** ResUtilFindDependentDiskResourceDriveLetter()
//////////////////////////////////////////////////////////////////////////////
//++
//
// ScIsResourceOfType()
//
// Description:
// Is the resource of the type passed in?
//
// Arguments:
//
//
// Return Value:
// S_OK
// The resource is of the type requested.
//
// S_FALSE
// The resource is not of the type requested.
//
// Other HRESULT
// Win32 error as HRESULT.
//
// Remarks:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
static DWORD
ScIsResourceOfType(
HRESOURCE hResIn
, const WCHAR * pszResourceTypeIn
, BOOL * pbIsResourceOfTypeOut
)
{
DWORD sc = ERROR_SUCCESS;
WCHAR * psz = NULL;
DWORD cbpsz = 33 * sizeof( WCHAR );
DWORD cb;
int idx;
if ( pbIsResourceOfTypeOut == NULL )
{
sc = ERROR_INVALID_PARAMETER;
goto Cleanup;
} // else
for ( idx = 0; idx < 2; idx++ )
{
psz = (WCHAR *) LocalAlloc( LPTR, cbpsz );
if ( psz == NULL )
{
sc = ERROR_NOT_ENOUGH_MEMORY;
goto Cleanup;
} // if:
sc = ClusterResourceControl( hResIn, NULL, CLUSCTL_RESOURCE_GET_RESOURCE_TYPE, NULL, 0, psz, cbpsz, &cb );
if ( sc == ERROR_MORE_DATA )
{
LocalFree( psz );
psz = NULL;
cbpsz = cb + 1;
continue;
} // if:
if ( sc != ERROR_SUCCESS )
{
goto Cleanup;
} // if:
break;
} // for:
*pbIsResourceOfTypeOut = ( ClRtlStrNICmp( psz, pszResourceTypeIn, (cbpsz / sizeof( WCHAR )) ) == 0 );
Cleanup:
LocalFree( psz );
return sc;
} //*** ScIsResourceOfType()
//////////////////////////////////////////////////////////////////////////////
//++
//
// ScIsCoreResource()
//
// Description:
// Is the passed in resource a core resource?
//
// Arguments:
//
//
// Return Value:
// ERROR_SUCCESS
// The operation succeeded.
//
// Other Win32 error
//
// Remarks:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
static DWORD
ScIsCoreResource(
HRESOURCE hResIn
, BOOL * pfIsCoreResourceOut
)
{
DWORD sc;
DWORD dwFlags = 0;
DWORD cb;
BOOL fIsCoreResource = FALSE;
sc = ClusterResourceControl( hResIn, NULL, CLUSCTL_RESOURCE_GET_FLAGS, NULL, 0, &dwFlags, sizeof( dwFlags ), &cb );
if ( sc != ERROR_SUCCESS )
{
goto Cleanup;
} // if:
fIsCoreResource = ( dwFlags & CLUS_FLAG_CORE );
if ( pfIsCoreResourceOut != NULL )
{
*pfIsCoreResourceOut = fIsCoreResource;
} // if:
else
{
sc = ERROR_INVALID_PARAMETER;
} // else
Cleanup:
return sc;
} //*** ScIsCoreResource()
//////////////////////////////////////////////////////////////////////////////
//++
//
// ScIsQuorumCapableResource()
//
// Description:
// Is the passed in resource quorum capable?
//
// Arguments:
// hResIn
// The resource to check for quorum capability.
//
// pfIsQuorumCapableResource
// True if the resource is quorum capable, false if it is not.
//
// Return Value:
// ERROR_SUCCESS
// The operation succeeded.
//
// Other Win32 error
//
// Remarks:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
static DWORD
ScIsQuorumCapableResource(
HRESOURCE hResIn
, BOOL * pfIsQuorumCapableResource
)
{
DWORD sc;
DWORD cb;
DWORD dwFlags = 0;
if ( hResIn == NULL )
{
sc = ERROR_INVALID_PARAMETER;
goto Cleanup;
} // if:
if ( pfIsQuorumCapableResource == NULL )
{
sc = ERROR_INVALID_PARAMETER;
goto Cleanup;
} // if:
sc = ClusterResourceControl( hResIn, NULL, CLUSCTL_RESOURCE_GET_CHARACTERISTICS, NULL, 0, &dwFlags, sizeof( dwFlags ), &cb );
if ( sc != ERROR_SUCCESS )
{
goto Cleanup;
} // if:
*pfIsQuorumCapableResource = ( dwFlags & CLUS_CHAR_QUORUM );
Cleanup:
return sc;
} //*** ScIsQuorumCapableResource()
static WCHAR * g_pszCoreResourceTypes[] =
{
CLUS_RESTYPE_NAME_NETNAME,
CLUS_RESTYPE_NAME_IPADDR,
L"\0"
};
#define CLUSTER_NAME 0
#define CLUSTER_IP_ADDRESS 1
//////////////////////////////////////////////////////////////////////////////
//++
//
// ResUtilGetCoreClusterResources()
//
// Description:
// Find the core cluster resources.
//
// Arguments:
// hClusterIn
// The cluster whose core resource are sought.
//
// phClusterNameResourceOut
// The resource handle of the cluster name resource.
//
// phClusterIPAddressResourceOut
// The resource handle of the cluster IP address resource.
//
// phClusterQuorumResourceOut
// The resource handle of the cluster quorum resource.
//
// Return Value:
// ERROR_SUCCESS or other Win32 error.
//
// Remarks:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
DWORD
WINAPI
ResUtilGetCoreClusterResources(
HCLUSTER hClusterIn
, HRESOURCE * phClusterNameResourceOut
, HRESOURCE * phClusterIPAddressResourceOut
, HRESOURCE * phClusterQuorumResourceOut
)
{
DWORD sc;
HCLUSENUM hEnum = NULL;
DWORD idxResource;
DWORD idx;
DWORD dwType;
WCHAR * psz = NULL;
DWORD cchpsz = 33;
DWORD cch;
HRESOURCE hRes = NULL;
BOOL fIsCoreResource = FALSE;
BOOL fIsResourceOfType = FALSE;
BOOL fCloseResource = FALSE;
BOOL fIsQuorumCapableResource = FALSE;
if ( hClusterIn == NULL )
{
sc = ERROR_INVALID_PARAMETER;
goto Cleanup;
} // if:
hEnum = ClusterOpenEnum( hClusterIn, CLUSTER_ENUM_RESOURCE );
if ( hEnum == NULL )
{
sc = GetLastError();
goto Cleanup;
} // if:
psz = (WCHAR *) LocalAlloc( LPTR, cchpsz * sizeof( WCHAR ) );
if ( psz == NULL )
{
sc = ERROR_NOT_ENOUGH_MEMORY;
goto Cleanup;
} // if:
//
// KB: 10-JUL-2002 GalenB
//
// Using cch in the ClusterEnum() call below because using cchpsz causes extra allocations.
// ClusterEnum() changes cch when the buffer is big enough to hold the data and returns
// ERROR_SUCCESS to be the size of the data that was just copied into the buffer. Now
// cch no longer reflects the amount of memory allocated to psz...
//
for ( idxResource = 0; ; )
{
//
// Reset cch to the real size of the buffer to avoid extra allocations...
//
cch = cchpsz;
sc = ClusterEnum( hEnum, idxResource, &dwType, psz, &cch );
if ( sc == ERROR_MORE_DATA )
{
LocalFree( psz );
psz = NULL;
cch++; // need space for the NULL...
cchpsz = cch;
psz = (WCHAR *) LocalAlloc( LPTR, cchpsz * sizeof( WCHAR ) );
if ( psz == NULL )
{
sc = ERROR_NOT_ENOUGH_MEMORY;
goto Cleanup;
} // if:
sc = ClusterEnum( hEnum, idxResource, &dwType, psz, &cch );
} // if: sc == ERROR_MORE_DATA
if ( sc == ERROR_SUCCESS )
{
hRes = OpenClusterResource( hClusterIn, psz );
if ( hRes == NULL )
{
sc = GetLastError();
goto Cleanup;
} // if:
fCloseResource = TRUE;
sc = ScIsCoreResource( hRes, &fIsCoreResource );
if ( sc != ERROR_SUCCESS )
{
goto Cleanup;
} // if:
//
// If the resource is not a core resource then close it and go around again.
//
if ( !fIsCoreResource )
{
CloseClusterResource( hRes );
hRes = NULL;
idxResource++;
continue;
} // if:
sc = ScIsQuorumCapableResource( hRes, &fIsQuorumCapableResource );
if ( sc != ERROR_SUCCESS )
{
goto Cleanup;
} // if:
//
// If this core resource is a quorum capable resource then it must be the quorom. If the caller
// has asked for the quorom resource then pass it back and leave the resource open, other wise
// close the resource and go around again.
//
if ( fIsQuorumCapableResource )
{
if ( phClusterQuorumResourceOut != NULL)
{
*phClusterQuorumResourceOut = hRes;
} // if:
else
{
CloseClusterResource( hRes );
} // else:
hRes = NULL;
idxResource++;
continue;
} // if:
//
// Since this core resource is not a quorum capable resource it is either the cluster
// name or the cluster IP address resource.
//
for ( idx = 0; *( g_pszCoreResourceTypes[ idx ] ) != '\0'; idx++ )
{
sc = ScIsResourceOfType( hRes, g_pszCoreResourceTypes[ idx ], &fIsResourceOfType );
if ( sc != ERROR_SUCCESS )
{
goto Cleanup;
} // if:
if ( !fIsResourceOfType )
{
continue;
} // if:
switch ( idx )
{
case CLUSTER_NAME :
if ( phClusterNameResourceOut != NULL )
{
*phClusterNameResourceOut = hRes;
fCloseResource = FALSE;
} // if:
break;
case CLUSTER_IP_ADDRESS :
if ( phClusterIPAddressResourceOut != NULL )
{
*phClusterIPAddressResourceOut = hRes;
fCloseResource = FALSE;
} // if:
break;
default:
goto Cleanup;
} // switch:
//
// If we get here then we broke from the switch above and we want out of
// this loop.
//
break;
} // for:
if ( fCloseResource )
{
CloseClusterResource( hRes );
} // if:
hRes = NULL;
idxResource++;
continue;
} // if: sc == ERROR_SUCCESS
else if ( sc == ERROR_NO_MORE_ITEMS )
{
sc = ERROR_SUCCESS;
break;
} // else if: sc == ERROR_NO_MORE_ITEMS
else
{
goto Cleanup;
} // else: sc has some other error...
break;
} // for:
Cleanup:
LocalFree( psz );
if ( hRes != NULL )
{
CloseClusterResource( hRes );
} // if:
if ( hEnum != NULL )
{
ClusterCloseEnum( hEnum );
} // if:
return sc;
} //*** ResUtilGetCoreClusterResources
//////////////////////////////////////////////////////////////////////////////
//++
//
// ResUtilGetResourceName()
//
// Description:
// Get the name of the resource that is passed in.
//
// Arguments:
// hResourceIn
// The resource whose name is sought.
//
// pszResourceNameOut
// Buffer to hold the resource's name.
//
// pcchResourceNameInOut
// The size of the buffer on input and the size required on output.
//
//
// Return Value:
// ERROR_SUCCESS
// ERROR_MORE_DATA
//
// Remarks:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
DWORD
WINAPI
ResUtilGetResourceName(
HRESOURCE hResourceIn
, WCHAR * pszResourceNameOut
, DWORD * pcchResourceNameInOut
)
{
DWORD sc = ERROR_INVALID_PARAMETER;
WCHAR * psz = NULL;
DWORD cb;
HRESULT hr;
if ( hResourceIn == NULL )
{
goto Cleanup;
} // if:
if ( ( pszResourceNameOut == NULL ) || ( pcchResourceNameInOut == NULL ) )
{
goto Cleanup;
} // if:
psz = (WCHAR *) LocalAlloc( LPTR, (*pcchResourceNameInOut) * sizeof( WCHAR ) );
if ( psz == NULL )
{
sc = ERROR_NOT_ENOUGH_MEMORY;
goto Cleanup;
} // if:
sc = ClusterResourceControl(
hResourceIn
, NULL
, CLUSCTL_RESOURCE_GET_NAME
, NULL
, 0
, psz
, (*pcchResourceNameInOut) * sizeof( WCHAR )
, &cb
);
if ( sc == ERROR_MORE_DATA )
{
*pcchResourceNameInOut = ( cb / sizeof( WCHAR ) ) + 1;
goto Cleanup;
} // if:
if ( sc != ERROR_SUCCESS )
{
goto Cleanup;
} // if:
hr = StringCchCopy( pszResourceNameOut, *pcchResourceNameInOut, psz );
if ( FAILED( hr ) )
{
sc = HRESULT_CODE( hr );
goto Cleanup;
}
Cleanup:
LocalFree( psz );
return sc;
} //*** ResUtilGetResourceName