mirror of https://github.com/tongzx/nt5src
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.
2395 lines
57 KiB
2395 lines
57 KiB
/*++
|
|
|
|
Copyright (c) 1992-1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
iisutil.c
|
|
|
|
Abstract:
|
|
|
|
IIS Resource utility routine DLL
|
|
|
|
Author:
|
|
|
|
Pete Benoit (v-pbenoi) 12-SEP-1996
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "iisutil.h"
|
|
#if defined(_DEBUG_SUPPORT)
|
|
#include <time.h>
|
|
#endif
|
|
#include <pudebug.h>
|
|
|
|
|
|
IMSAdminBase* CMetaData::g_pMBCom;
|
|
CRITICAL_SECTION CMetaData::g_cs;
|
|
|
|
VOID
|
|
FreeIISResource(
|
|
IN LPIIS_RESOURCE ResourceEntry
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Free all the storage for a IIS_RESOURCE
|
|
|
|
Arguments:
|
|
|
|
vr - virtual root to free
|
|
|
|
Return Value:
|
|
|
|
NONE
|
|
|
|
--*/
|
|
|
|
{
|
|
if (ResourceEntry != NULL)
|
|
{
|
|
if ( ResourceEntry->ResourceName != NULL )
|
|
{
|
|
LocalFree( ResourceEntry->ResourceName );
|
|
ResourceEntry->ResourceName = NULL;
|
|
}
|
|
#if 0
|
|
if ( ResourceEntry->ResourceHandle != NULL )
|
|
{
|
|
CloseClusterResource( ResourceEntry->ResourceHandle );
|
|
}
|
|
#endif
|
|
if ( ResourceEntry->ParametersKey != NULL )
|
|
{
|
|
ClusterRegCloseKey( ResourceEntry->ParametersKey );
|
|
ResourceEntry->ParametersKey = NULL;
|
|
}
|
|
|
|
if ( ResourceEntry->Params.ServiceName != NULL )
|
|
{
|
|
LocalFree( ResourceEntry->Params.ServiceName);
|
|
ResourceEntry->Params.ServiceName = NULL;
|
|
}
|
|
|
|
if ( ResourceEntry->Params.InstanceId != NULL )
|
|
{
|
|
LocalFree( ResourceEntry->Params.InstanceId);
|
|
ResourceEntry->Params.InstanceId = NULL;
|
|
}
|
|
|
|
if ( ResourceEntry->Params.MDPath != NULL )
|
|
{
|
|
LocalFree( ResourceEntry->Params.MDPath);
|
|
ResourceEntry->Params.MDPath = NULL;
|
|
}
|
|
|
|
} // ResourceEntry != NULL
|
|
|
|
} // FreeIISResource
|
|
|
|
|
|
|
|
|
|
VOID
|
|
DestructIISResource(
|
|
IN LPIIS_RESOURCE ResourceEntry
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Free all the storage for a ResourceEntry and the ResourceEntry
|
|
|
|
Arguments:
|
|
|
|
vr - virtual root to free
|
|
|
|
Return Value:
|
|
|
|
NONE
|
|
|
|
--*/
|
|
{
|
|
if (ResourceEntry != NULL)
|
|
{
|
|
FreeIISResource(ResourceEntry);
|
|
LocalFree(ResourceEntry);
|
|
} // ResourceEntry != NULL
|
|
|
|
} // DestructIISResource
|
|
|
|
DWORD
|
|
GetServerBindings(
|
|
LPWSTR MDPath,
|
|
DWORD dwServiceType,
|
|
SOCKADDR* psaServer,
|
|
LPDWORD pdwPort
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Read the first ip address and port number form the ServerBindings property for a particlar branch of the metabase
|
|
|
|
Arguments:
|
|
|
|
MDPath : the particular branch of the metabase to read the information from (ex. /LM/W3SVC/1)
|
|
dwServiceType : the service type id
|
|
pszServer : the structure to save the ip address
|
|
pdwPort : the returned port number
|
|
|
|
Return Value:
|
|
|
|
sucess : ERROR_SUCCESS
|
|
failure : the win32 error code of the failure
|
|
|
|
--*/
|
|
{
|
|
DWORD dwStatus = ERROR_SUCCESS;
|
|
DWORD dwR = 0;
|
|
DWORD dwW = 0;
|
|
TCHAR * achBindings = NULL;
|
|
INT cBindingsSize = sizeof(TCHAR)*1024;
|
|
TCHAR * pB = NULL;
|
|
TCHAR * pP = NULL;
|
|
DWORD cL = 0;
|
|
BOOL bGetBindingsStatus = FALSE ;
|
|
|
|
//
|
|
// allocate space for the server bindings string
|
|
//
|
|
if( !(achBindings = (TCHAR*)LocalAlloc(LMEM_FIXED, cBindingsSize)) )
|
|
{
|
|
dwStatus = GetLastError();
|
|
TR( (DEBUG_BUFFER,"[GetServerBindings] Can't allocate memory for server bindings info. (%d)\n",dwStatus) );
|
|
}
|
|
|
|
if ( achBindings )
|
|
{
|
|
//
|
|
// Get binding info from metabase
|
|
//
|
|
|
|
CMetaData MD;
|
|
|
|
if ( MD.Open( MDPath ) )
|
|
{
|
|
dwR = cBindingsSize;
|
|
|
|
if( !(bGetBindingsStatus = MD.GetMultisz( L"",
|
|
MD_SERVER_BINDINGS,
|
|
IIS_MD_UT_SERVER,
|
|
achBindings,
|
|
&dwR )) )
|
|
{
|
|
dwStatus = GetLastError();
|
|
|
|
if ( ERROR_INSUFFICIENT_BUFFER == dwStatus )
|
|
{
|
|
TR( (DEBUG_BUFFER,"[GetServerBindings] Buffer too small, reallocating\n") );
|
|
|
|
//
|
|
// (# 296798) If the original binding's buffer size is too small so realloc memory to the required size
|
|
//
|
|
TCHAR* achBindingsNew = (TCHAR*)LocalReAlloc(achBindings, dwR, 0);
|
|
if( !achBindingsNew )
|
|
{
|
|
dwStatus = GetLastError();
|
|
|
|
LocalFree (achBindings);
|
|
achBindings = NULL;
|
|
}
|
|
else
|
|
{
|
|
achBindings = achBindingsNew;
|
|
bGetBindingsStatus = MD.GetMultisz( L"",
|
|
MD_SERVER_BINDINGS,
|
|
IIS_MD_UT_SERVER,
|
|
achBindings,
|
|
&dwR );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// error getting server bindings information from the metabase
|
|
//
|
|
TR( (DEBUG_BUFFER,"[GetServerBindings] error getting server bindings information (%d)\n", dwStatus) );
|
|
}
|
|
}
|
|
|
|
MD.Close();
|
|
}
|
|
else
|
|
{
|
|
dwStatus = GetLastError();
|
|
TR( (DEBUG_BUFFER,"[GetServerBindings] failed to open MD, error %08x\n", dwStatus) );
|
|
}
|
|
}
|
|
|
|
//
|
|
// not getting server bindings information is a serious error
|
|
//
|
|
if ( !bGetBindingsStatus )
|
|
{
|
|
TR( (DEBUG_BUFFER,"[GetServerBindings] error getting server bindings infomation (%d) \n", dwStatus ) );
|
|
}
|
|
else
|
|
{
|
|
TR( (DEBUG_BUFFER,"[GetServerBindings] got server bindings string (%S) \n", achBindings ) );
|
|
|
|
(*pdwPort) = DEFAULT_PORT[dwServiceType];
|
|
|
|
ZeroMemory( psaServer, sizeof(SOCKADDR) );
|
|
((SOCKADDR_IN*)psaServer)->sin_family = AF_INET;
|
|
((SOCKADDR_IN*)psaServer)->sin_addr.s_net = 127;
|
|
((SOCKADDR_IN*)psaServer)->sin_addr.s_impno = 1;
|
|
|
|
//
|
|
// Each binding is of the form "addr:port:hostname"
|
|
// we look only at addr & port
|
|
//
|
|
// use the 1st valid binding ( i.e. contains ':' )
|
|
//
|
|
|
|
dwR /= sizeof(WCHAR);
|
|
|
|
for ( pB = achBindings ; *pB && dwR ; )
|
|
{
|
|
if ( (cL = wcslen( pB ) + 1 ) > dwR )
|
|
{
|
|
break;
|
|
}
|
|
|
|
if ( (pP = wcschr( pB, L':' )) )
|
|
{
|
|
SOCKADDR sa;
|
|
INT cL = sizeof(sa);
|
|
|
|
pP[0] = '\0';
|
|
if ( achBindings[0] &&
|
|
WSAStringToAddress( achBindings,
|
|
AF_INET,
|
|
NULL,
|
|
&sa,
|
|
&cL ) == 0 )
|
|
{
|
|
memcpy( psaServer, &sa, cL );
|
|
}
|
|
else
|
|
{
|
|
TR( (DEBUG_BUFFER,"[GetServerBindings] WSAStringToAddress failed converting string (%S) \n", achBindings ) );
|
|
}
|
|
|
|
if ( iswdigit(pP[1]) )
|
|
{
|
|
(*pdwPort) = wcstoul( pP + 1, NULL, 0 );
|
|
}
|
|
|
|
TR( (DEBUG_BUFFER,"[GetServerBindings] found binding addr %S %u.%u.%u.%u port %u\n",
|
|
achBindings,
|
|
((SOCKADDR_IN*)psaServer)->sin_addr.s_net,
|
|
((SOCKADDR_IN*)psaServer)->sin_addr.s_host,
|
|
((SOCKADDR_IN*)psaServer)->sin_addr.s_lh,
|
|
((SOCKADDR_IN*)psaServer)->sin_addr.s_impno,
|
|
(*pdwPort) ) );
|
|
|
|
goto found_bindings;
|
|
}
|
|
|
|
pB += cL;
|
|
dwR -= cL;
|
|
}
|
|
|
|
}
|
|
|
|
found_bindings:
|
|
if( achBindings )
|
|
{
|
|
LocalFree(achBindings);
|
|
achBindings = NULL;
|
|
}
|
|
|
|
return dwStatus ;
|
|
|
|
} // GetServerBindings
|
|
|
|
|
|
|
|
CHAR IsAliveRequest[]="TRACK / HTTP/1.1\r\nHost: CLUSIIS\r\nConnection: close\r\nContent-length: 0\r\n\r\n"; // # 292727
|
|
|
|
|
|
DWORD
|
|
VerifyIISService(
|
|
IN LPWSTR MDPath,
|
|
IN DWORD ServiceType,
|
|
IN DWORD dwPort,
|
|
IN SOCKADDR saServer,
|
|
IN PLOG_EVENT_ROUTINE LogEvent
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Verify that the IIS service is running and that it has virtual roots
|
|
contained in the resource
|
|
Steps:
|
|
1. get server instance binding info
|
|
2. connect to server, send HTTP request & wait for response
|
|
|
|
Arguments:
|
|
|
|
Resource - supplies the resource id
|
|
|
|
IsAliveFlag - says this is an IsAlive call
|
|
|
|
Return Value:
|
|
|
|
TRUE - if service is running and service contains resources virtual roots
|
|
|
|
FALSE - service is in any other state
|
|
|
|
--*/
|
|
{
|
|
DWORD status = ERROR_SUCCESS;
|
|
DWORD dwR;
|
|
DWORD dwW;
|
|
SOCKET s;
|
|
CHAR IsAliveResponse[1024];
|
|
|
|
TR( (DEBUG_BUFFER,"[IISVerify] Enter\n") );
|
|
|
|
TR( (DEBUG_BUFFER,"[IISVerify] checking address %S : %u.%u.%u.%u port %u\n",
|
|
MDPath,
|
|
((SOCKADDR_IN*)&saServer)->sin_addr.s_net,
|
|
((SOCKADDR_IN*)&saServer)->sin_addr.s_host,
|
|
((SOCKADDR_IN*)&saServer)->sin_addr.s_lh,
|
|
((SOCKADDR_IN*)&saServer)->sin_addr.s_impno,
|
|
dwPort ) );
|
|
|
|
if ( (s = TcpSockConnectToHost( &saServer,
|
|
dwPort,
|
|
CHECK_IS_ALIVE_CONNECT_TIMEOUT )) != NULL )
|
|
{
|
|
if ( ServiceType == IIS_SERVICE_TYPE_W3 )
|
|
{
|
|
//
|
|
// If this is W3 then attempt to send a request and get response from server.
|
|
//
|
|
if ( TcpSockSend( s,
|
|
IsAliveRequest,
|
|
sizeof(IsAliveRequest),
|
|
&dwW,
|
|
CHECK_IS_ALIVE_SEND_TIMEOUT ) &&
|
|
TcpSockRecv( s,
|
|
IsAliveResponse,
|
|
sizeof(IsAliveResponse),
|
|
&dwR,
|
|
CHECK_IS_ALIVE_SEND_TIMEOUT ) &&
|
|
dwR > 5 )
|
|
{
|
|
status = ERROR_SUCCESS;
|
|
TcpSockClose( s );
|
|
goto finished_check;
|
|
}
|
|
else
|
|
{
|
|
TR( (DEBUG_BUFFER,"[IISVerify] failed HTTP request\n") );
|
|
status = ERROR_SERVICE_NOT_ACTIVE;
|
|
}
|
|
}
|
|
else if ( ServiceType == IIS_SERVICE_TYPE_SMTP )
|
|
{
|
|
//
|
|
// If this is SMTP then check the reply code.
|
|
// (220: service ready)
|
|
//
|
|
if ( TcpSockRecv( s,
|
|
IsAliveResponse,
|
|
sizeof(IsAliveResponse),
|
|
&dwR,
|
|
CHECK_IS_ALIVE_SEND_TIMEOUT ) &&
|
|
strncmp( IsAliveResponse, "220", 3 ) == 0 )
|
|
{
|
|
status = ERROR_SUCCESS;
|
|
TcpSockClose( s );
|
|
goto finished_check;
|
|
}
|
|
else
|
|
{
|
|
TR( (DEBUG_BUFFER,"[IISVerify] failed SMTP request, response:%S\n", IsAliveResponse) );
|
|
status = ERROR_SERVICE_NOT_ACTIVE;
|
|
}
|
|
}
|
|
else if ( ServiceType == IIS_SERVICE_TYPE_NNTP )
|
|
{
|
|
//
|
|
// If this is NNTP then check the reply code.
|
|
// (200: service ready - posting allowed) or
|
|
// (201: service ready - no posting allowed)
|
|
//
|
|
if ( TcpSockRecv( s,
|
|
IsAliveResponse,
|
|
sizeof(IsAliveResponse),
|
|
&dwR,
|
|
CHECK_IS_ALIVE_SEND_TIMEOUT ) &&
|
|
( strncmp( IsAliveResponse, "200", 3 ) == 0 ||
|
|
strncmp( IsAliveResponse, "201", 3 ) == 0 ) )
|
|
{
|
|
status = ERROR_SUCCESS;
|
|
TcpSockClose( s );
|
|
goto finished_check;
|
|
}
|
|
else
|
|
{
|
|
TR( (DEBUG_BUFFER,"[IISVerify] failed NNTP request, response:%S\n", IsAliveResponse) );
|
|
status = ERROR_SERVICE_NOT_ACTIVE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
status = ERROR_SUCCESS;
|
|
TcpSockClose( s );
|
|
goto finished_check;
|
|
}
|
|
|
|
TcpSockClose( s );
|
|
}
|
|
else
|
|
{
|
|
TR( (DEBUG_BUFFER,"[IISVerify] failed to connect port %d\n", dwPort) );
|
|
status = ERROR_SERVICE_NOT_ACTIVE;
|
|
}
|
|
|
|
finished_check:
|
|
|
|
//
|
|
// Check to see if there was an error
|
|
//
|
|
|
|
if ( status != ERROR_SUCCESS )
|
|
{
|
|
TR( (DEBUG_BUFFER,"[IISVerify] FALSE (%d), Leave\n", status) );
|
|
|
|
#if defined(DBG_CANT_VERIFY)
|
|
g_fDbgCantVerify = TRUE;
|
|
#endif
|
|
|
|
}
|
|
else
|
|
{
|
|
TR( (DEBUG_BUFFER,"[IISVerify] TRUE, Leave\n") );
|
|
}
|
|
|
|
return status;
|
|
|
|
} // VerifyIISService
|
|
|
|
|
|
|
|
LPWSTR
|
|
GetClusterResourceType(
|
|
HRESOURCE hResource,
|
|
LPIIS_RESOURCE ResourceEntry,
|
|
IN PLOG_EVENT_ROUTINE LogEvent
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns the resource type for the resource
|
|
|
|
Arguments:
|
|
|
|
hResource - handle to a resource
|
|
|
|
Return Value:
|
|
|
|
TRUE - if service is running and service contains resources virtual roots
|
|
|
|
FALSE - service is in any other state
|
|
|
|
--*/
|
|
{
|
|
DWORD dwType = 0;
|
|
DWORD dwSize = MAX_DEFAULT_WSTRING_SIZE;
|
|
WCHAR lpzTypeName[MAX_DEFAULT_WSTRING_SIZE];
|
|
LPWSTR TypeName = NULL;
|
|
HKEY hKey = NULL;
|
|
LONG status;
|
|
|
|
(LogEvent)(
|
|
ResourceEntry->ResourceHandle,
|
|
LOG_ERROR,
|
|
L"[GetClusterResourceType] entry\n");
|
|
//
|
|
// Valid resource now open the reg and get it's type
|
|
//
|
|
|
|
hKey = GetClusterResourceKey(hResource,KEY_READ);
|
|
if (hKey == NULL)
|
|
{
|
|
(LogEvent)(
|
|
ResourceEntry->ResourceHandle,
|
|
LOG_ERROR,
|
|
L"[GetClusterResourceType] Unable to open resource key = %1!u!\n",GetLastError());
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
//
|
|
// Got a valid key now get the type
|
|
//
|
|
|
|
status = ClusterRegQueryValue(hKey,L"Type",&dwType,(LPBYTE)lpzTypeName,&dwSize);
|
|
|
|
if (status == ERROR_SUCCESS)
|
|
{
|
|
TypeName = (WCHAR*)LocalAlloc(LMEM_FIXED,(dwSize+16)*sizeof(WCHAR));
|
|
if (TypeName != NULL)
|
|
{
|
|
wcscpy(TypeName,lpzTypeName);
|
|
} // TypeName != NULL
|
|
}
|
|
else
|
|
{
|
|
(LogEvent)(
|
|
ResourceEntry->ResourceHandle,
|
|
LOG_ERROR,
|
|
L"[GetClusterResourceType] Unable to Query Value = %1!u!\n",status);
|
|
}
|
|
|
|
ClusterRegCloseKey(hKey);
|
|
|
|
(LogEvent)(
|
|
ResourceEntry->ResourceHandle,
|
|
LOG_ERROR,
|
|
L"[GetClusterResourceType] TypeName = %1!ws!\n",TypeName);
|
|
|
|
return TypeName;
|
|
|
|
}// end GetClusterResourceType
|
|
|
|
|
|
HRESOURCE
|
|
ClusterGetResourceDependency(
|
|
IN LPCWSTR ResourceName,
|
|
IN LPCWSTR ResourceType,
|
|
IN LPIIS_RESOURCE ResourceEntry,
|
|
IN PLOG_EVENT_ROUTINE LogEvent
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns a dependent resource
|
|
|
|
Arguments:
|
|
|
|
ResourceName - the resource
|
|
|
|
ResourceType - the type of resource that it depends on
|
|
|
|
Return Value:
|
|
|
|
NULL - error (use GetLastError() to get further info)
|
|
|
|
NON-NULL - Handle to a resource of type ResourceType
|
|
|
|
--*/
|
|
{
|
|
HCLUSTER hCluster = NULL;
|
|
HRESOURCE hResource = NULL;
|
|
HRESOURCE hResDepends = NULL;
|
|
HRESENUM hResEnum = NULL;
|
|
DWORD dwType = 0;
|
|
DWORD dwIndex = 0;
|
|
DWORD dwSize = MAX_DEFAULT_WSTRING_SIZE;
|
|
WCHAR lpszName[MAX_DEFAULT_WSTRING_SIZE];
|
|
LPWSTR ResTypeName = NULL;
|
|
DWORD status;
|
|
|
|
//
|
|
// Open the cluster
|
|
//
|
|
hCluster = OpenCluster(NULL);
|
|
if (hCluster == NULL)
|
|
{
|
|
(LogEvent)(
|
|
ResourceEntry->ResourceHandle,
|
|
LOG_ERROR,
|
|
L"[ClusterGetResourceDependency] Unable to OpenCluster status = %1!u!\n",GetLastError());
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
//
|
|
// Open the resource
|
|
//
|
|
|
|
hResource = OpenClusterResource(hCluster,ResourceName);
|
|
if (hResource == NULL)
|
|
{
|
|
(LogEvent)(
|
|
ResourceEntry->ResourceHandle,
|
|
LOG_ERROR,
|
|
L"[ClusterGetResourceDependency] Unable to OpenClusterResource status = %1!u!\n",GetLastError());
|
|
|
|
goto error_exit;
|
|
}
|
|
|
|
//
|
|
// Open the depends on enum
|
|
//
|
|
|
|
hResEnum = ClusterResourceOpenEnum(hResource,CLUSTER_RESOURCE_ENUM_DEPENDS);
|
|
if (hResEnum == NULL)
|
|
{
|
|
(LogEvent)(
|
|
ResourceEntry->ResourceHandle,
|
|
LOG_ERROR,
|
|
L"[ClusterGetResourceDependency] Unsuccessful ClusterResourceOpenEnum status = %1!u!\n",GetLastError());
|
|
|
|
goto error_exit;
|
|
}
|
|
|
|
//
|
|
// Enumerate all the depends on keys
|
|
//
|
|
|
|
do {
|
|
dwSize = MAX_DEFAULT_WSTRING_SIZE;
|
|
status = ClusterResourceEnum(hResEnum,dwIndex++,&dwType,lpszName,&dwSize);
|
|
if ((status != ERROR_SUCCESS) && (status != ERROR_MORE_DATA))
|
|
{
|
|
//
|
|
// This checks to see if NO dependencies were found
|
|
//
|
|
if ((status == ERROR_NO_MORE_ITEMS) && (dwIndex == 1))
|
|
{
|
|
SetLastError( ERROR_NO_DATA );
|
|
}
|
|
else
|
|
{
|
|
SetLastError( status );
|
|
}
|
|
goto error_exit;
|
|
}
|
|
|
|
//
|
|
// Determine the type of resource found
|
|
//
|
|
|
|
hResDepends = OpenClusterResource(hCluster,lpszName);
|
|
if (hResDepends == NULL)
|
|
{
|
|
(LogEvent)(
|
|
ResourceEntry->ResourceHandle,
|
|
LOG_ERROR,
|
|
L"[ClusterGetResourceDependency] Unsuccessful OpenClusterResource status = %1!u!\n",GetLastError());
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Valid resource now open the reg and get it's type
|
|
//
|
|
ResTypeName = GetClusterResourceType(hResDepends,ResourceEntry,LogEvent);
|
|
if (ResTypeName == NULL)
|
|
{
|
|
(LogEvent)(
|
|
ResourceEntry->ResourceHandle,
|
|
LOG_ERROR,
|
|
L"[ClusterGetResourceDependency] Unsuccessful GetClusterResourceType status = %1!u!\n",GetLastError());
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Compare the types and look for a match
|
|
//
|
|
if ( (_wcsicmp(ResTypeName,ResourceType)) == 0)
|
|
{
|
|
//
|
|
//Found a match
|
|
//
|
|
|
|
goto success_exit;
|
|
|
|
} // END _wcsicmp(ResTypeName,ResourceType)
|
|
|
|
} // END if ResourceTypeName != NULL
|
|
|
|
} // END if hResDepends != NULL
|
|
//
|
|
// Close all handles, key's
|
|
//
|
|
if (hResDepends != NULL)
|
|
{
|
|
CloseClusterResource(hResDepends);
|
|
hResDepends = NULL;
|
|
}
|
|
} while ((status == ERROR_SUCCESS) || (status == ERROR_MORE_DATA));
|
|
|
|
|
|
if (hResDepends == NULL)
|
|
{
|
|
(LogEvent)(
|
|
ResourceEntry->ResourceHandle,
|
|
LOG_ERROR,
|
|
L"[ClusterGetResourceDependency] Unsuccessful resource enum status = %1!u! %2!x! last error = %3!u!\n",status,status,GetLastError());
|
|
}
|
|
success_exit:
|
|
error_exit:
|
|
//
|
|
// At this point hResDepends is NULL if no match or non-null (success)
|
|
//
|
|
if (hCluster != NULL)
|
|
{
|
|
CloseCluster(hCluster);
|
|
}
|
|
if (hResource != NULL)
|
|
{
|
|
CloseClusterResource(hResource);
|
|
}
|
|
if (hResEnum != NULL)
|
|
{
|
|
ClusterResourceCloseEnum(hResEnum);
|
|
}
|
|
|
|
return hResDepends;
|
|
} // ClusterGetResourceDependency
|
|
|
|
|
|
DWORD
|
|
SetInstanceState(
|
|
IN PCLUS_WORKER pWorker,
|
|
IN LPIIS_RESOURCE ResourceEntry,
|
|
IN RESOURCE_STATUS* presourceStatus,
|
|
IN CLUSTER_RESOURCE_STATE TargetState,
|
|
IN LPWSTR TargetStateString,
|
|
IN DWORD dwMdPropControl,
|
|
IN DWORD dwMdPropTarget
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set the server instance to te requested state ( start / stop )
|
|
|
|
Arguments:
|
|
|
|
pWorker - thread context to monitor for cancel request
|
|
ResourceEntry - ptr to IIS server instance resource ctx
|
|
presourceStatus - ptr to struct to be updated with new status
|
|
TargetState - cluster API target state
|
|
dwMdPropControl - IIS metabase property value for request to server
|
|
dwMdPropTarget - IIS metabase property value for target state
|
|
|
|
Return Value:
|
|
|
|
Win32 error code, ERROR_SUCCESS if success
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD status = ERROR_SERVICE_NOT_ACTIVE;
|
|
int retry;
|
|
DWORD dwS;
|
|
DWORD dwEnabled;
|
|
|
|
CMetaData MD;
|
|
|
|
TR( (DEBUG_BUFFER,"[SetInstanceState] Enter\n") );
|
|
|
|
if ( MD.Open( ResourceEntry->Params.MDPath,
|
|
TRUE,
|
|
METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE ) )
|
|
{
|
|
|
|
//
|
|
// Reenable clustering. If we are receiving this notification we know
|
|
// enabled should be set to true.
|
|
//
|
|
if ( !MD.GetDword( L"", MD_CLUSTER_ENABLED, IIS_MD_UT_SERVER, &dwEnabled, 0 ) ||
|
|
dwEnabled == 0 )
|
|
{
|
|
TR( (DEBUG_BUFFER,"[SetInstanceState] cluster not enabled\n") );
|
|
|
|
if ( !MD.SetDword( L"", MD_CLUSTER_ENABLED, IIS_MD_UT_SERVER, 1, 0 ) )
|
|
{
|
|
TR( (DEBUG_BUFFER,"[SetInstanceState] failed to re-enable cluster\n") );
|
|
}
|
|
}
|
|
|
|
if ( MD.GetDword( L"", MD_SERVER_STATE, IIS_MD_UT_SERVER, &dwS, 0 ) )
|
|
{
|
|
TR( (DEBUG_BUFFER,"[SetInstanceState] state prob is %d\n",dwS) );
|
|
}
|
|
else
|
|
{
|
|
TR( (DEBUG_BUFFER,"[SetInstanceState] failed to probe server state\n") );
|
|
dwS = 0xffffffff;
|
|
}
|
|
|
|
if ( dwS != dwMdPropTarget )
|
|
{
|
|
if ( MD.SetDword( L"", MD_CLUSTER_SERVER_COMMAND, IIS_MD_UT_SERVER, dwMdPropControl, 0 ) )
|
|
{
|
|
MD.Close();
|
|
TR( (DEBUG_BUFFER,"[SetInstanceState] command set to %d\n",dwMdPropControl) );
|
|
|
|
for ( retry = (TargetState == ClusterResourceOnline) ? IISCLUS_ONLINE_TIMEOUT :IISCLUS_OFFLINE_TIMEOUT ;
|
|
retry-- ; )
|
|
{
|
|
if ( ClusWorkerCheckTerminate(pWorker) )
|
|
{
|
|
status = ERROR_OPERATION_ABORTED;
|
|
break;
|
|
}
|
|
|
|
if ( MD.GetDword( ResourceEntry->Params.MDPath, MD_SERVER_STATE, IIS_MD_UT_SERVER, &dwS, 0 ) )
|
|
{
|
|
if ( dwS == dwMdPropTarget )
|
|
{
|
|
status = ERROR_SUCCESS;
|
|
break;
|
|
}
|
|
TR( (DEBUG_BUFFER,"[SetInstanceState] state is %d, waiting for %d\n",dwS,dwMdPropTarget) );
|
|
}
|
|
else
|
|
{
|
|
TR( (DEBUG_BUFFER,"[SetInstanceState] failed to get server state\n") );
|
|
break;
|
|
}
|
|
|
|
Sleep(SERVER_START_DELAY);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
TR( (DEBUG_BUFFER,"[SetInstanceState] failed to set server command to %d\n",dwMdPropControl) );
|
|
MD.Close();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
status = ERROR_SUCCESS;
|
|
MD.Close();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( g_hEventLog && TargetState == ClusterResourceOnline )
|
|
{
|
|
LPCTSTR aErrStr[3];
|
|
WCHAR aErrCode[32];
|
|
|
|
_ultow( GetLastError(), aErrCode, 10 );
|
|
|
|
aErrStr[0] = ResourceEntry->Params.ServiceName;
|
|
aErrStr[1] = ResourceEntry->Params.InstanceId;
|
|
aErrStr[2] = aErrCode;
|
|
|
|
ReportEvent( g_hEventLog,
|
|
EVENTLOG_ERROR_TYPE,
|
|
0,
|
|
IISCL_EVENT_CANT_OPEN_METABASE,
|
|
NULL,
|
|
sizeof(aErrStr) / sizeof(LPCTSTR),
|
|
0,
|
|
aErrStr,
|
|
NULL );
|
|
}
|
|
|
|
TR( (DEBUG_BUFFER,"[SetInstanceState] failed to open %S, error %08x\n",ResourceEntry->Params.MDPath, GetLastError()) );
|
|
}
|
|
|
|
if ( status != ERROR_SUCCESS )
|
|
{
|
|
//
|
|
// Error
|
|
//
|
|
(g_IISLogEvent)(
|
|
ResourceEntry->ResourceHandle,
|
|
LOG_ERROR,
|
|
L"Error %1!u! cannot bring resource %2!ws! %3!ws!.\n",
|
|
status,
|
|
ResourceEntry->ResourceName,
|
|
TargetStateString );
|
|
|
|
presourceStatus->ResourceState = ClusterResourceFailed;
|
|
ResourceEntry->State = ClusterResourceFailed;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Success, update state, log message
|
|
//
|
|
presourceStatus->ResourceState = TargetState;
|
|
ResourceEntry->State = TargetState;
|
|
|
|
TR( (DEBUG_BUFFER,"[SetInstanceState] Setting Metadata Path:%S ResourceEntry->State:%d\n", ResourceEntry->Params.MDPath, TargetState) );
|
|
|
|
(g_IISLogEvent)(
|
|
ResourceEntry->ResourceHandle,
|
|
LOG_INFORMATION,
|
|
L"Success bringing resource %1!ws! %2!ws!.\n",
|
|
ResourceEntry->ResourceName,
|
|
TargetStateString );
|
|
}
|
|
|
|
TR( (DEBUG_BUFFER,"[SetInstanceState] status = %d, Leave\n",status) );
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
DWORD
|
|
InstanceEnableCluster(
|
|
LPWSTR pwszServiceName,
|
|
LPWSTR pwszInstanceId
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Ensure server instance in state consistent with cluster membership.
|
|
If not already part of a cluster, stop instance & flag it as cluster enabled
|
|
|
|
Arguments:
|
|
|
|
pwszServiceName - IIS service name ( e.g. W3SVC )
|
|
pwszInstanceId - IIS serverr instance ID
|
|
|
|
Return Value:
|
|
|
|
win32 error code or ERROR_SUCCESS if success
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD status = ERROR_SERVICE_NOT_ACTIVE;
|
|
int retry;
|
|
DWORD dwS;
|
|
TCHAR achMDPath[80];
|
|
DWORD dwL;
|
|
|
|
dwL = wsprintf( achMDPath, L"/LM/%s/%s", pwszServiceName, pwszInstanceId );
|
|
|
|
CMetaData MD;
|
|
|
|
TR( (DEBUG_BUFFER,"[InstanceEnableCluster] for %S, Enter\n", achMDPath ) );
|
|
|
|
if ( MD.Open( achMDPath,
|
|
TRUE,
|
|
METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE ) )
|
|
{
|
|
//
|
|
// ensure instance is marked as cluster enabled
|
|
//
|
|
|
|
if ( !MD.GetDword( L"", MD_CLUSTER_ENABLED, IIS_MD_UT_SERVER, &dwS, 0 ) ||
|
|
dwS == 0 )
|
|
{
|
|
if ( MD.SetDword( L"", MD_CLUSTER_ENABLED, IIS_MD_UT_SERVER, 1, 0 ) )
|
|
{
|
|
if ( MD.GetDword( L"", MD_SERVER_STATE, IIS_MD_UT_SERVER, &dwS, 0 ) )
|
|
{
|
|
TR( (DEBUG_BUFFER,"[InstanceEnableCluster] state prob is %d\n",dwS) );
|
|
}
|
|
else
|
|
{
|
|
TR( (DEBUG_BUFFER,"[InstanceEnableCluster] failed to probe server state\n") );
|
|
dwS = 0xffffffff;
|
|
}
|
|
|
|
MD.Close();
|
|
|
|
if ( dwS != MD_SERVER_STATE_STOPPED )
|
|
{
|
|
if ( MD.Open( achMDPath,
|
|
TRUE,
|
|
METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE ) &&
|
|
MD.SetDword( L"",
|
|
MD_CLUSTER_SERVER_COMMAND,
|
|
IIS_MD_UT_SERVER,
|
|
MD_SERVER_COMMAND_STOP,
|
|
0 ) )
|
|
{
|
|
|
|
TR( (DEBUG_BUFFER,"[InstanceEnableCluster] command set to %d\n",MD_SERVER_COMMAND_STOP) );
|
|
|
|
for ( retry = 30 ; retry-- ; )
|
|
{
|
|
if ( MD.GetDword( L"", MD_SERVER_STATE, IIS_MD_UT_SERVER, &dwS, 0 ) )
|
|
{
|
|
if ( dwS == MD_SERVER_STATE_STOPPED )
|
|
{
|
|
status = ERROR_SUCCESS;
|
|
break;
|
|
}
|
|
TR( (DEBUG_BUFFER,"[InstanceEnableCluster] state is %d, waiting for %d\n",dwS,MD_SERVER_STATE_STOPPED) );
|
|
}
|
|
else
|
|
{
|
|
TR( (DEBUG_BUFFER,"[InstanceEnableCluster] failed to get server state\n") );
|
|
break;
|
|
}
|
|
|
|
Sleep(SERVER_START_DELAY);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TR( (DEBUG_BUFFER,"[InstanceEnableCluster] failed to set server command to %d\n",MD_SERVER_COMMAND_STOP) );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
status = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TR( (DEBUG_BUFFER,"[InstanceEnableCluster] failed to set cluster enabled\n") );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TR( (DEBUG_BUFFER,"[InstanceEnableCluster] failed to open %S, error %08x\n",achMDPath, GetLastError()) );
|
|
}
|
|
|
|
TR( (DEBUG_BUFFER,"[InstanceEnableCluster] status = %d, Leave\n",status) );
|
|
|
|
MD.Close();
|
|
return status;
|
|
}
|
|
|
|
DWORD
|
|
InstanceDisableCluster(
|
|
LPWSTR pwszServiceName,
|
|
LPWSTR pwszInstanceId
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Ensure server instance in state consistent with cluster membership.
|
|
If already part of a cluster, stop instance & remove its cluster enabled flag.
|
|
|
|
Arguments:
|
|
|
|
pwszServiceName - IIS service name ( e.g. W3SVC )
|
|
pwszInstanceId - IIS serverr instance ID
|
|
|
|
Return Value:
|
|
|
|
win32 error code or ERROR_SUCCESS if success
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD status = ERROR_SERVICE_NOT_ACTIVE;
|
|
int retry;
|
|
DWORD dwS;
|
|
TCHAR achMDPath[80];
|
|
DWORD dwL;
|
|
|
|
dwL = wsprintf( achMDPath, L"/LM/%s/%s", pwszServiceName, pwszInstanceId );
|
|
|
|
CMetaData MD;
|
|
|
|
TR( (DEBUG_BUFFER,"[InstanceDisableCluster] for %S, Enter\n", achMDPath ) );
|
|
|
|
if ( MD.Open( achMDPath,
|
|
TRUE,
|
|
METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE ) )
|
|
{
|
|
//
|
|
// ensure instance is marked as cluster enabled
|
|
//
|
|
|
|
if ( !MD.GetDword( L"", MD_CLUSTER_ENABLED, IIS_MD_UT_SERVER, &dwS, 0 ) ||
|
|
( dwS == 0) )
|
|
{
|
|
MD.Close();
|
|
return status;
|
|
}
|
|
|
|
if ( MD.SetDword( L"", MD_CLUSTER_ENABLED, IIS_MD_UT_SERVER, 0, 0 ) )
|
|
{
|
|
if ( MD.GetDword( L"", MD_SERVER_STATE, IIS_MD_UT_SERVER, &dwS, 0 ) )
|
|
{
|
|
TR( (DEBUG_BUFFER,"[InstanceDisableCluster] state prob is %d\n",dwS) );
|
|
}
|
|
else
|
|
{
|
|
TR( (DEBUG_BUFFER,"[InstanceDisableCluster] failed to probe server state\n") );
|
|
dwS = 0xffffffff;
|
|
}
|
|
|
|
MD.Close();
|
|
|
|
if ( dwS != MD_SERVER_STATE_STOPPED )
|
|
{
|
|
if ( MD.Open( achMDPath,
|
|
TRUE,
|
|
METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE ) &&
|
|
MD.SetDword( L"",
|
|
MD_SERVER_COMMAND,
|
|
IIS_MD_UT_SERVER,
|
|
MD_SERVER_COMMAND_STOP,
|
|
0 ))
|
|
{
|
|
|
|
TR( (DEBUG_BUFFER,"[InstanceDisableCluster] command set to %d\n",MD_SERVER_COMMAND_STOP) );
|
|
|
|
for ( retry = 30 ; retry-- ; )
|
|
{
|
|
if ( MD.GetDword( L"", MD_SERVER_STATE, IIS_MD_UT_SERVER, &dwS, 0 ) )
|
|
{
|
|
if ( dwS == MD_SERVER_STATE_STOPPED )
|
|
{
|
|
break;
|
|
}
|
|
TR( (DEBUG_BUFFER,"[InstanceDisableCluster] state is %d, waiting for %d\n",dwS,MD_SERVER_STATE_STOPPED) );
|
|
}
|
|
else
|
|
{
|
|
TR( (DEBUG_BUFFER,"[InstanceDisableCluster] failed to get server state\n") );
|
|
break;
|
|
}
|
|
|
|
Sleep(SERVER_START_DELAY);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TR( (DEBUG_BUFFER,"[InstanceDisableCluster] failed to set server command to %d\n",MD_SERVER_COMMAND_STOP) );
|
|
}
|
|
|
|
MD.Close();
|
|
|
|
//
|
|
// restart the server
|
|
//
|
|
|
|
if ( MD.Open( achMDPath,
|
|
TRUE,
|
|
METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE ) &&
|
|
MD.SetDword( L"",
|
|
MD_SERVER_COMMAND,
|
|
IIS_MD_UT_SERVER,
|
|
MD_SERVER_COMMAND_START,
|
|
0 ))
|
|
{
|
|
TR( (DEBUG_BUFFER,"[InstanceDisableCluster] set server command to %d\n",MD_SERVER_COMMAND_START) );
|
|
}
|
|
else
|
|
{
|
|
TR( (DEBUG_BUFFER,"[InstanceDisableCluster] failed to set server command to %d\n",MD_SERVER_COMMAND_START) );
|
|
}
|
|
|
|
status = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TR( (DEBUG_BUFFER,"[InstanceDisableCluster] failed to set cluster disbled\n") );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TR( (DEBUG_BUFFER,"[InstanceDisableCluster] failed to open %S, error %08x\n",achMDPath, GetLastError()) );
|
|
}
|
|
|
|
MD.Close();
|
|
|
|
TR( (DEBUG_BUFFER,"[InstanceDisableCluster] status = %d, Leave\n",status) );
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CMetaData::Open(
|
|
LPWSTR pszPath,
|
|
BOOL fReconnect,
|
|
DWORD dwFlags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Opens the metabase
|
|
|
|
Arguments:
|
|
|
|
pszPath - Path to open
|
|
dwFlags - Open flags
|
|
|
|
Return:
|
|
|
|
TRUE if success, FALSE on error, (call GetLastError())
|
|
|
|
--*/
|
|
{
|
|
HRESULT hRes;
|
|
|
|
TR( (DEBUG_BUFFER,"[MDOpen] %S\n",pszPath) );
|
|
|
|
if ( !GetCoInit() )
|
|
{
|
|
TR( (DEBUG_BUFFER,"[MDOpen] calling CoInit\n") );
|
|
hRes = CoInitializeEx(NULL, COINIT_MULTITHREADED);
|
|
if ( FAILED(hRes) )
|
|
{
|
|
TR( (DEBUG_BUFFER,"[MD:GetMD::CoInitializeEx] error %08x\n",HRESULTTOWIN32( hRes )) );
|
|
SetLastError( HRESULTTOWIN32( hRes ) );
|
|
return FALSE;
|
|
}
|
|
SetCoInit( TRUE );
|
|
}
|
|
|
|
EnterCriticalSection( &g_cs );
|
|
|
|
for ( int retry = 2 ; retry-- ; )
|
|
{
|
|
if ( !GetMD() )
|
|
{
|
|
LeaveCriticalSection( &g_cs );
|
|
TR( (DEBUG_BUFFER,"[MDOpen] can't get MD interface\n") );
|
|
return FALSE;
|
|
}
|
|
|
|
TR( (DEBUG_BUFFER,"[MDOpen] before OpenKey\n") );
|
|
|
|
hRes = g_pMBCom->OpenKey( METADATA_MASTER_ROOT_HANDLE,
|
|
pszPath,
|
|
dwFlags,
|
|
MB_TIMEOUT,
|
|
&m_hMB );
|
|
|
|
if ( SUCCEEDED( hRes ) )
|
|
{
|
|
LeaveCriticalSection( &g_cs );
|
|
TR( (DEBUG_BUFFER,"[MDOpen] OK, leave\n") );
|
|
return TRUE;
|
|
}
|
|
|
|
if ( !fReconnect )
|
|
{
|
|
break;
|
|
}
|
|
|
|
TR( (DEBUG_BUFFER,"[MDOpen] error %d, fReconnect=%d\n",HRESULTTOWIN32( hRes ),fReconnect) );
|
|
if ( HRESULTTOWIN32( hRes ) == RPC_S_SERVER_UNAVAILABLE ||
|
|
HRESULTTOWIN32( hRes ) == RPC_S_CALL_FAILED_DNE )
|
|
{
|
|
ReleaseMD();
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
SetLastError( HRESULTTOWIN32( hRes ) );
|
|
|
|
LeaveCriticalSection( &g_cs );
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CMetaData::Close(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Close opened handle to metadata
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
TRUE if success, otherwise FALSE
|
|
|
|
--*/
|
|
|
|
{
|
|
if ( m_hMB )
|
|
{
|
|
g_pMBCom->CloseKey( m_hMB );
|
|
m_hMB = NULL;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CMetaData::SetData(
|
|
LPWSTR pszPath,
|
|
DWORD dwPropID,
|
|
DWORD dwUserType,
|
|
DWORD dwDataType,
|
|
VOID * pvData,
|
|
DWORD cbData,
|
|
DWORD dwFlags
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sets a metadata property on an openned metabase
|
|
|
|
Arguments:
|
|
|
|
pszPath - Path to set data on
|
|
dwPropID - Metabase property ID
|
|
dwUserType - User type for this property
|
|
dwDataType - Type of data being set (dword, string etc)
|
|
pvData - Pointer to data
|
|
cbData - Size of data
|
|
dwFlags - Inheritance flags
|
|
|
|
Return:
|
|
|
|
TRUE if success, FALSE on error, (call GetLastError())
|
|
|
|
--*/
|
|
|
|
{
|
|
METADATA_RECORD mdRecord;
|
|
HRESULT hRes;
|
|
|
|
mdRecord.dwMDIdentifier = dwPropID;
|
|
mdRecord.dwMDAttributes = dwFlags;
|
|
mdRecord.dwMDUserType = dwUserType;
|
|
mdRecord.dwMDDataType = dwDataType;
|
|
mdRecord.dwMDDataLen = cbData;
|
|
mdRecord.pbMDData = (PBYTE) pvData;
|
|
|
|
EnterCriticalSection( &g_cs );
|
|
|
|
if ( !GetMD() )
|
|
{
|
|
LeaveCriticalSection( &g_cs );
|
|
return FALSE;
|
|
}
|
|
|
|
hRes = g_pMBCom->SetData( m_hMB,
|
|
pszPath,
|
|
&mdRecord );
|
|
|
|
if ( SUCCEEDED( hRes ))
|
|
{
|
|
LeaveCriticalSection( &g_cs );
|
|
return TRUE;
|
|
}
|
|
|
|
SetLastError( HRESULTTOWIN32( hRes ) );
|
|
|
|
LeaveCriticalSection( &g_cs );
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CMetaData::GetData(
|
|
LPWSTR pszPath,
|
|
DWORD dwPropID,
|
|
DWORD dwUserType,
|
|
DWORD dwDataType,
|
|
VOID * pvData,
|
|
DWORD * pcbData,
|
|
DWORD dwFlags
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Retrieves a metadata property on an openned metabase
|
|
|
|
Arguments:
|
|
|
|
pszPath - Path to set data on
|
|
dwPropID - Metabase property ID
|
|
dwUserType - User type for this property
|
|
dwDataType - Type of data being set (dword, string etc)
|
|
pvData - Pointer to data
|
|
pcbData - Size of pvData, receives size of object
|
|
dwFlags - Inheritance flags
|
|
|
|
Return:
|
|
|
|
TRUE if success, FALSE on error, (call GetLastError())
|
|
|
|
--*/
|
|
|
|
{
|
|
METADATA_RECORD mdRecord;
|
|
HRESULT hRes;
|
|
DWORD dwRequiredLen;
|
|
BOOL fConvert;
|
|
|
|
mdRecord.pbMDData = (PBYTE) pvData;
|
|
mdRecord.dwMDDataLen = *pcbData;
|
|
mdRecord.dwMDIdentifier = dwPropID;
|
|
mdRecord.dwMDAttributes = dwFlags;
|
|
mdRecord.dwMDUserType = dwUserType;
|
|
mdRecord.dwMDDataType = dwDataType;
|
|
|
|
EnterCriticalSection( &g_cs );
|
|
|
|
if ( !GetMD() )
|
|
{
|
|
LeaveCriticalSection( &g_cs );
|
|
return FALSE;
|
|
}
|
|
|
|
hRes = g_pMBCom->GetData( m_hMB,
|
|
pszPath,
|
|
&mdRecord,
|
|
&dwRequiredLen );
|
|
|
|
if ( SUCCEEDED( hRes ))
|
|
{
|
|
LeaveCriticalSection( &g_cs );
|
|
|
|
*pcbData = mdRecord.dwMDDataLen;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
LeaveCriticalSection( &g_cs );
|
|
|
|
*pcbData = dwRequiredLen;
|
|
|
|
SetLastError( HRESULTTOWIN32( hRes ) );
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CMetaData::Init(
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize access to metadata
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
TRUE if success, otherwise FALSE
|
|
|
|
--*/
|
|
|
|
{
|
|
INITIALIZE_CRITICAL_SECTION( &g_cs );
|
|
g_pMBCom = NULL;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CMetaData::Terminate(
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Terminate access to metadata
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
TRUE if success, otherwise FALSE
|
|
|
|
--*/
|
|
|
|
{
|
|
DeleteCriticalSection( &g_cs );
|
|
if ( g_pMBCom )
|
|
{
|
|
if (FAILED(CoInitializeEx(NULL, COINIT_MULTITHREADED)))
|
|
{
|
|
return FALSE;
|
|
}
|
|
g_pMBCom->Release();
|
|
g_pMBCom = NULL;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CMetaData::GetMD(
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize interface pointer to DCOM metabase object
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
TRUE if success, otherwise FALSE
|
|
|
|
--*/
|
|
|
|
{
|
|
if ( g_pMBCom == NULL )
|
|
{
|
|
HRESULT hRes;
|
|
hRes = CoCreateInstance(CLSID_MSAdminBase, NULL,
|
|
CLSCTX_SERVER, IID_IMSAdminBase, (void**) &g_pMBCom);
|
|
|
|
TR( (DEBUG_BUFFER,"[MD:GetMD] called cocreate\n") );
|
|
if ( hRes == CO_E_NOTINITIALIZED )
|
|
{
|
|
TR( (DEBUG_BUFFER,"[MD:GetMD] call coinit\n") );
|
|
hRes = CoInitializeEx(NULL, COINIT_MULTITHREADED);
|
|
if ( FAILED(hRes) )
|
|
{
|
|
TR( (DEBUG_BUFFER,"[MD:GetMD::CoInitializeEx] error %08x\n",HRESULTTOWIN32( hRes )) );
|
|
SetLastError( HRESULTTOWIN32( hRes ) );
|
|
return FALSE;
|
|
}
|
|
hRes = CoCreateInstance(CLSID_MSAdminBase, NULL,
|
|
CLSCTX_SERVER, IID_IMSAdminBase, (void**) &g_pMBCom);
|
|
}
|
|
|
|
if ( FAILED(hRes) )
|
|
{
|
|
TR( (DEBUG_BUFFER,"[MD:GetMD] error %08x\n",HRESULTTOWIN32( hRes )) );
|
|
SetLastError( HRESULTTOWIN32( hRes ) );
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CMetaData::ReleaseMD(
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Release interface pointer to DCOM metabase object
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
TRUE if success, otherwise FALSE
|
|
|
|
--*/
|
|
|
|
{
|
|
if ( g_pMBCom )
|
|
{
|
|
g_pMBCom->Release();
|
|
g_pMBCom = NULL;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
SOCKET
|
|
TcpSockConnectToHost(
|
|
SOCKADDR* psaServer,
|
|
DWORD dwPort,
|
|
DWORD dwTimeOut
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create a TCP connection to specified port on specified machine
|
|
|
|
Arguments:
|
|
|
|
psaServer - target address
|
|
dwPort - target port to connect to
|
|
dwTimeOut - time out for connection ( in seconds )
|
|
|
|
Return Value:
|
|
|
|
socket or NULL if error
|
|
|
|
--*/
|
|
|
|
{
|
|
SOCKET sNew;
|
|
BOOL fWrite = FALSE;
|
|
INT serr = 0;
|
|
SOCKADDR_IN inAddr;
|
|
PSOCKADDR addr;
|
|
INT addrLength;
|
|
|
|
|
|
sNew = WSASocket(
|
|
AF_INET,
|
|
SOCK_STREAM,
|
|
0,
|
|
NULL, // protocol info
|
|
0, // Group ID = 0 => no constraints
|
|
WSA_FLAG_OVERLAPPED // completion port notifications
|
|
);
|
|
|
|
if ( sNew == INVALID_SOCKET )
|
|
{
|
|
TR( (DEBUG_BUFFER,"[TcpSockConnectToLocalHost] failed WSASocket, error %08x\n",GetLastError()) );
|
|
return NULL;
|
|
}
|
|
|
|
addrLength = sizeof(inAddr);
|
|
|
|
ZeroMemory(&inAddr, addrLength);
|
|
inAddr.sin_family = AF_INET;
|
|
inAddr.sin_port = 0;
|
|
|
|
((PSOCKADDR_IN)psaServer)->sin_port = (unsigned short)htons((unsigned short)dwPort );
|
|
|
|
//
|
|
// Bind an address to socket
|
|
//
|
|
|
|
if ( bind( sNew,
|
|
(PSOCKADDR)&inAddr,
|
|
addrLength ) == 0 &&
|
|
WSAConnect( sNew,
|
|
(PSOCKADDR)psaServer,
|
|
addrLength,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL ) == 0 &&
|
|
WaitForSocketWorker(
|
|
INVALID_SOCKET,
|
|
sNew,
|
|
NULL,
|
|
&fWrite,
|
|
dwTimeOut ) == 0 )
|
|
{
|
|
return sNew;
|
|
}
|
|
|
|
TR( (DEBUG_BUFFER,"[TcpSockConnectToLocalHost] failed connect, error %08x\n",GetLastError()) );
|
|
closesocket( sNew );
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
VOID
|
|
TcpSockClose(
|
|
SOCKET hSocket
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Close a socket opened by TcpSockConnectToLocalHost
|
|
|
|
Arguments:
|
|
|
|
hSocket - socket opened by TcpSockConnectToLocalHost
|
|
|
|
Return Value:
|
|
|
|
Nothing
|
|
|
|
--*/
|
|
|
|
{
|
|
closesocket( hSocket );
|
|
}
|
|
|
|
|
|
BOOL
|
|
TcpSockSend(
|
|
IN SOCKET sock,
|
|
IN LPVOID pBuffer,
|
|
IN DWORD cbBuffer,
|
|
OUT PDWORD pcbTotalSent,
|
|
IN DWORD nTimeout
|
|
)
|
|
|
|
/*++
|
|
|
|
Description:
|
|
Do async socket send
|
|
|
|
Arguments:
|
|
sock - socket
|
|
pBuffer - buffer to send
|
|
cbBuffer - size of buffer
|
|
pcbTotalSent - bytes sent
|
|
nTimeout - timeout in seconds to use
|
|
|
|
Returns:
|
|
FALSE if there is any error.
|
|
TRUE otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
INT serr = 0;
|
|
INT cbSent;
|
|
DWORD dwBytesSent = 0;
|
|
ULONG one;
|
|
|
|
//
|
|
// Loop until there's no more data to send.
|
|
//
|
|
|
|
while( cbBuffer > 0 )
|
|
{
|
|
//
|
|
// Wait for the socket to become writeable.
|
|
//
|
|
BOOL fWrite = FALSE;
|
|
|
|
serr = WaitForSocketWorker(
|
|
INVALID_SOCKET,
|
|
sock,
|
|
NULL,
|
|
&fWrite,
|
|
nTimeout
|
|
);
|
|
|
|
if( serr == 0 )
|
|
{
|
|
//
|
|
// Write a block to the socket.
|
|
//
|
|
|
|
cbSent = send( sock, (CHAR *)pBuffer, (INT)cbBuffer, 0 );
|
|
|
|
if( cbSent < 0 )
|
|
{
|
|
//
|
|
// Socket error.
|
|
//
|
|
|
|
serr = WSAGetLastError();
|
|
}
|
|
else
|
|
{
|
|
dwBytesSent += (DWORD)cbSent;
|
|
}
|
|
}
|
|
|
|
if( serr != 0 )
|
|
{
|
|
TR( (DEBUG_BUFFER,"[TcpSockSend] failed send, error %08x\n",serr) );
|
|
break;
|
|
}
|
|
|
|
pBuffer = (LPVOID)( (LPBYTE)pBuffer + cbSent );
|
|
cbBuffer -= (DWORD)cbSent;
|
|
}
|
|
|
|
if(pcbTotalSent)
|
|
{
|
|
*pcbTotalSent = dwBytesSent;
|
|
}
|
|
|
|
return (serr == 0);
|
|
|
|
} // SockSend
|
|
|
|
|
|
|
|
BOOL
|
|
TcpSockRecv(
|
|
IN SOCKET sock,
|
|
IN LPVOID pBuffer,
|
|
IN DWORD cbBuffer,
|
|
OUT LPDWORD pbReceived,
|
|
IN DWORD nTimeout
|
|
)
|
|
|
|
/*++
|
|
|
|
Description:
|
|
Do async socket recv
|
|
|
|
Arguments:
|
|
sock - The target socket.
|
|
pBuffer - Will receive the data.
|
|
cbBuffer - The size (in bytes) of the buffer.
|
|
pbReceived - Will receive the actual number of bytes
|
|
nTimeout - timeout in seconds
|
|
|
|
Returns:
|
|
TRUE, if successful
|
|
|
|
--*/
|
|
|
|
{
|
|
INT serr = 0;
|
|
DWORD cbTotal = 0;
|
|
INT cbReceived;
|
|
DWORD dwBytesRecv = 0;
|
|
|
|
ULONG one;
|
|
BOOL fRead = FALSE;
|
|
|
|
//
|
|
// Wait for the socket to become readable.
|
|
//
|
|
|
|
serr = WaitForSocketWorker(
|
|
sock,
|
|
INVALID_SOCKET,
|
|
&fRead,
|
|
NULL,
|
|
nTimeout
|
|
);
|
|
|
|
if( serr == 0 )
|
|
{
|
|
//
|
|
// Read a block from the socket.
|
|
//
|
|
cbReceived = recv( sock, (CHAR *)pBuffer, (INT)cbBuffer, 0 );
|
|
|
|
if( cbReceived < 0 )
|
|
{
|
|
//
|
|
// Socket error.
|
|
//
|
|
|
|
serr = WSAGetLastError();
|
|
}
|
|
else
|
|
{
|
|
cbTotal = cbReceived;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TR( (DEBUG_BUFFER,"[TcpSockRecv] failed send, error %08x\n",serr) );
|
|
}
|
|
|
|
if( serr == 0 )
|
|
{
|
|
//
|
|
// Return total byte count to caller.
|
|
//
|
|
|
|
*pbReceived = cbTotal;
|
|
}
|
|
|
|
return (serr == 0);
|
|
|
|
} // SockRecv
|
|
|
|
|
|
INT
|
|
WaitForSocketWorker(
|
|
IN SOCKET sockRead,
|
|
IN SOCKET sockWrite,
|
|
IN LPBOOL pfRead,
|
|
IN LPBOOL pfWrite,
|
|
IN DWORD nTimeout
|
|
)
|
|
|
|
/*++
|
|
|
|
Description:
|
|
Wait routine
|
|
NOTES: Any (but not all) sockets may be INVALID_SOCKET. For
|
|
each socket that is INVALID_SOCKET, the corresponding
|
|
pf* parameter may be NULL.
|
|
|
|
Arguments:
|
|
sockRead - The socket to check for readability.
|
|
sockWrite - The socket to check for writeability.
|
|
pfRead - Will receive TRUE if sockRead is readable.
|
|
pfWrite - Will receive TRUE if sockWrite is writeable.
|
|
nTimeout - timeout in seconds
|
|
|
|
Returns:
|
|
SOCKERR - 0 if successful, !0 if not. Will return
|
|
WSAETIMEDOUT if the timeout period expired.
|
|
|
|
--*/
|
|
|
|
{
|
|
INT serr = 0;
|
|
TIMEVAL timeout;
|
|
LPTIMEVAL ptimeout;
|
|
fd_set fdsRead;
|
|
fd_set fdsWrite;
|
|
INT res;
|
|
|
|
//
|
|
// Ensure we got valid parameters.
|
|
//
|
|
|
|
if( ( sockRead == INVALID_SOCKET ) &&
|
|
( sockWrite == INVALID_SOCKET ) )
|
|
{
|
|
|
|
return WSAENOTSOCK;
|
|
}
|
|
|
|
timeout.tv_sec = (LONG )nTimeout;
|
|
|
|
if( timeout.tv_sec == 0 )
|
|
{
|
|
|
|
//
|
|
// If the connection timeout == 0, then we have no timeout.
|
|
// So, we block and wait for the specified conditions.
|
|
//
|
|
|
|
ptimeout = NULL;
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
//
|
|
// The connectio timeout is > 0, so setup the timeout structure.
|
|
//
|
|
|
|
timeout.tv_usec = 0;
|
|
|
|
ptimeout = &timeout;
|
|
}
|
|
|
|
for( ; ; )
|
|
{
|
|
|
|
//
|
|
// Setup our socket sets.
|
|
//
|
|
|
|
FD_ZERO( &fdsRead );
|
|
FD_ZERO( &fdsWrite );
|
|
|
|
if( sockRead != INVALID_SOCKET )
|
|
{
|
|
|
|
FD_SET( sockRead, &fdsRead );
|
|
*pfRead = FALSE;
|
|
}
|
|
|
|
if( sockWrite != INVALID_SOCKET )
|
|
{
|
|
|
|
FD_SET( sockWrite, &fdsWrite );
|
|
*pfWrite = FALSE;
|
|
}
|
|
|
|
//
|
|
// Wait for one of the conditions to be met.
|
|
//
|
|
|
|
res = select( 0, &fdsRead, &fdsWrite, NULL, ptimeout );
|
|
|
|
if( res == 0 )
|
|
{
|
|
|
|
//
|
|
// Timeout.
|
|
//
|
|
|
|
serr = WSAETIMEDOUT;
|
|
break;
|
|
|
|
}
|
|
else if( res == SOCKET_ERROR )
|
|
{
|
|
|
|
//
|
|
// Bad news.
|
|
//
|
|
|
|
serr = WSAGetLastError();
|
|
TR( (DEBUG_BUFFER,"[WaitForSocketWorker] failed send, error %08x\n",serr) );
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
BOOL fSomethingWasSet = FALSE;
|
|
|
|
if( pfRead != NULL )
|
|
{
|
|
|
|
*pfRead = FD_ISSET( sockRead, &fdsRead );
|
|
fSomethingWasSet = TRUE;
|
|
}
|
|
|
|
if( pfWrite != NULL )
|
|
{
|
|
*pfWrite = FD_ISSET( sockWrite, &fdsWrite );
|
|
fSomethingWasSet = TRUE;
|
|
}
|
|
|
|
if( fSomethingWasSet )
|
|
{
|
|
|
|
//
|
|
// Success.
|
|
//
|
|
|
|
serr = 0;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// select() returned with neither a timeout, nor
|
|
// an error, nor any bits set. This feels bad...
|
|
//
|
|
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
return serr;
|
|
|
|
} // WaitForSocketWorker()
|
|
|
|
|
|
#if defined(_DEBUG_SUPPORT)
|
|
|
|
void
|
|
TimeStamp(
|
|
FILE* f
|
|
)
|
|
{
|
|
time_t t = time( NULL );
|
|
struct tm *pTm;
|
|
|
|
if ( pTm = localtime( &t ) )
|
|
{
|
|
fprintf( f,
|
|
"%02d:%02d:%02d> ",
|
|
pTm->tm_hour,
|
|
pTm->tm_min,
|
|
pTm->tm_sec );
|
|
}
|
|
}
|
|
|
|
void
|
|
InitDebug(
|
|
)
|
|
{
|
|
char achPath[MAX_PATH];
|
|
HKEY hKey;
|
|
DWORD dwValue;
|
|
DWORD dwType;
|
|
DWORD dwLen;
|
|
BOOL fDoDebug = FALSE;
|
|
BOOL fAppend = TRUE;
|
|
INT cL = 0;
|
|
LPSTR pTmp;
|
|
|
|
//
|
|
// get debug flag from registry
|
|
//
|
|
|
|
if ( RegOpenKey( HKEY_LOCAL_MACHINE,
|
|
L"SYSTEM\\CurrentControlSet\\Services\\W3SVC\\Parameters",
|
|
&hKey )
|
|
== ERROR_SUCCESS )
|
|
{
|
|
TR( (DEBUG_BUFFER,"[InitDebug] opened key\n") );
|
|
dwLen = sizeof( dwValue );
|
|
if ( RegQueryValueEx( hKey,
|
|
L"ClusterDebugMode",
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE)&dwValue,
|
|
&dwLen ) == ERROR_SUCCESS &&
|
|
dwType == REG_DWORD )
|
|
{
|
|
fDoDebug = !!dwValue;
|
|
}
|
|
|
|
dwLen = sizeof( dwValue );
|
|
if ( RegQueryValueEx( hKey,
|
|
L"ClusterDebugAppendToFile",
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE)&dwValue,
|
|
&dwLen ) == ERROR_SUCCESS &&
|
|
dwType == REG_DWORD )
|
|
{
|
|
fAppend = !!dwValue;
|
|
}
|
|
|
|
dwLen = sizeof( achPath );
|
|
if ( RegQueryValueExA( hKey,
|
|
"ClusterDebugPath",
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE)achPath,
|
|
&dwLen ) == ERROR_SUCCESS &&
|
|
dwType == REG_SZ )
|
|
{
|
|
if ( dwLen )
|
|
{
|
|
cL = dwLen - 1;
|
|
if ( cL && achPath[cL-1] != '\\' )
|
|
{
|
|
achPath[cL++] = '\\';
|
|
}
|
|
}
|
|
}
|
|
|
|
RegCloseKey( hKey );
|
|
}
|
|
|
|
if ( fDoDebug && cL )
|
|
{
|
|
memcpy( achPath + cL, "iisclus.trc", sizeof("iisclus.trc") );
|
|
debug_file = fopen(achPath, fAppend ? "a" : "w" );
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
DWORD
|
|
WINAPI
|
|
ResUtilReadProperties(
|
|
IN HKEY RegistryKey,
|
|
IN const PRESUTIL_PROPERTY_ITEM PropertyTable,
|
|
IN OUT LPBYTE OutParams,
|
|
IN RESOURCE_HANDLE ResourceHandle,
|
|
IN PLOG_EVENT_ROUTINE LogEvent
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Read properties based on a property table.
|
|
|
|
Arguments:
|
|
|
|
RegistryKey - Supplies the cluster key where the properties are stored.
|
|
|
|
PropertyTable - Pointer to the property table to process.
|
|
|
|
OutParams - Parameter block to read into.
|
|
|
|
ResourceHandle - Handle for the resource fo which properties are being read.
|
|
|
|
LogEvent - Function to call to log events to the cluster log.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS - Properties read successfully.
|
|
|
|
ERROR_INVALID_DATA - Required property not present.
|
|
|
|
--*/
|
|
|
|
{
|
|
PRESUTIL_PROPERTY_ITEM propertyItem = PropertyTable;
|
|
HKEY key;
|
|
DWORD status = ERROR_SUCCESS;
|
|
LPWSTR pszInValue;
|
|
LPBYTE pbInValue;
|
|
DWORD dwInValue;
|
|
LPWSTR * ppszOutValue;
|
|
LPBYTE * ppbOutValue;
|
|
LPDWORD pdwOutValue;
|
|
|
|
while ( propertyItem->Name != NULL ) {
|
|
//
|
|
// If the value resides at a different location, create the key.
|
|
//
|
|
if ( propertyItem->KeyName != NULL ) {
|
|
|
|
DWORD disposition;
|
|
|
|
status = ClusterRegCreateKey( RegistryKey,
|
|
propertyItem->KeyName,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
&key,
|
|
&disposition );
|
|
if ( status != ERROR_SUCCESS ) {
|
|
return(status);
|
|
}
|
|
} else {
|
|
key = RegistryKey;
|
|
}
|
|
|
|
switch ( propertyItem->Format ) {
|
|
case CLUSPROP_FORMAT_DWORD:
|
|
pdwOutValue = (LPDWORD) &OutParams[propertyItem->Offset];
|
|
status = ResUtilGetDwordValue( RegistryKey,
|
|
propertyItem->Name,
|
|
pdwOutValue,
|
|
propertyItem->Default );
|
|
if ( (status == ERROR_FILE_NOT_FOUND) &&
|
|
!(propertyItem->Flags & RESUTIL_PROPITEM_REQUIRED) ) {
|
|
*pdwOutValue = propertyItem->Default;
|
|
}
|
|
break;
|
|
|
|
case CLUSPROP_FORMAT_SZ:
|
|
case CLUSPROP_FORMAT_EXPAND_SZ:
|
|
ppszOutValue = (LPWSTR*) &OutParams[propertyItem->Offset];
|
|
pszInValue = ResUtilGetSzValue( RegistryKey,
|
|
propertyItem->Name );
|
|
if ( pszInValue == NULL ) {
|
|
status = GetLastError();
|
|
if ( (status == ERROR_FILE_NOT_FOUND) &&
|
|
!(propertyItem->Flags & RESUTIL_PROPITEM_REQUIRED) ) {
|
|
if ( *ppszOutValue != NULL ) {
|
|
LocalFree( *ppszOutValue );
|
|
*ppszOutValue = NULL;
|
|
}
|
|
|
|
// If a default is specified, copy it.
|
|
if ( propertyItem->lpDefault != NULL ) {
|
|
*ppszOutValue = (LPWSTR)LocalAlloc( LMEM_FIXED, (lstrlenW( (LPCWSTR) propertyItem->lpDefault ) + 1) * sizeof(WCHAR) );
|
|
if ( *ppszOutValue == NULL ) {
|
|
status = GetLastError();
|
|
} else {
|
|
lstrcpyW( *ppszOutValue, (LPCWSTR) propertyItem->lpDefault );
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if ( *ppszOutValue != NULL ) {
|
|
LocalFree( *ppszOutValue );
|
|
}
|
|
*ppszOutValue = pszInValue;
|
|
}
|
|
break;
|
|
|
|
case CLUSPROP_FORMAT_MULTI_SZ:
|
|
case CLUSPROP_FORMAT_BINARY:
|
|
ppbOutValue = (LPBYTE*) &OutParams[propertyItem->Offset];
|
|
pdwOutValue = (PDWORD) &OutParams[propertyItem->Offset+sizeof(LPBYTE*)];
|
|
status = ResUtilGetBinaryValue( RegistryKey,
|
|
propertyItem->Name,
|
|
&pbInValue,
|
|
&dwInValue );
|
|
if ( status == ERROR_SUCCESS ) {
|
|
if ( *ppbOutValue != NULL ) {
|
|
LocalFree( *ppbOutValue );
|
|
}
|
|
*ppbOutValue = pbInValue;
|
|
*pdwOutValue = dwInValue;
|
|
} else if ( (status == ERROR_FILE_NOT_FOUND) &&
|
|
!(propertyItem->Flags & RESUTIL_PROPITEM_REQUIRED) ) {
|
|
if ( *ppbOutValue != NULL ) {
|
|
LocalFree( *ppbOutValue );
|
|
*ppbOutValue = NULL;
|
|
*pdwOutValue = 0;
|
|
}
|
|
|
|
// If a default is specified, copy it.
|
|
if ( propertyItem->lpDefault != NULL ) {
|
|
*ppbOutValue = (LPBYTE)LocalAlloc( LMEM_FIXED, propertyItem->Minimum );
|
|
if ( *ppbOutValue == NULL ) {
|
|
status = GetLastError();
|
|
} else {
|
|
memcpy( *ppbOutValue, propertyItem->lpDefault, propertyItem->Minimum );
|
|
*pdwOutValue = propertyItem->Minimum;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Close the key if we opened it.
|
|
//
|
|
if ( (propertyItem->KeyName != NULL) &&
|
|
(key != NULL) ) {
|
|
ClusterRegCloseKey( key );
|
|
}
|
|
|
|
//
|
|
// Handle any errors that occurred.
|
|
//
|
|
if ( status != ERROR_SUCCESS ) {
|
|
(LogEvent)(
|
|
ResourceHandle,
|
|
LOG_ERROR,
|
|
L"Unable to read the '%1' property. Error: %2!u!.\n",
|
|
propertyItem->Name,
|
|
status );
|
|
if ( propertyItem->Flags & RESUTIL_PROPITEM_REQUIRED ) {
|
|
if ( status == ERROR_FILE_NOT_FOUND ) {
|
|
status = ERROR_INVALID_DATA;
|
|
}
|
|
break;
|
|
} else {
|
|
status = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Advance to the next property.
|
|
//
|
|
propertyItem++;
|
|
}
|
|
|
|
return(status);
|
|
|
|
} // ResUtilReadProperties
|
|
|