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.
1048 lines
29 KiB
1048 lines
29 KiB
/*++
|
|
|
|
Copyright (c) 1996-1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
cluster.c
|
|
|
|
Abstract:
|
|
|
|
Server side support for Cluster APIs dealing with the whole
|
|
cluster.
|
|
|
|
Author:
|
|
|
|
John Vert (jvert) 9-Feb-1996
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
#include "apip.h"
|
|
#include "clusverp.h"
|
|
#include "clusudef.h"
|
|
#include <ntlsa.h>
|
|
#include <ntmsv1_0.h>
|
|
|
|
|
|
|
|
HCLUSTER_RPC
|
|
s_ApiOpenCluster(
|
|
IN handle_t IDL_handle,
|
|
OUT error_status_t *Status
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Opens a handle to the cluster. This context handle is
|
|
currently used only to handle cluster notify additions
|
|
and deletions correctly.
|
|
|
|
Added call to ApipConnectCallback which checks that connecting
|
|
users have rights to open cluster.
|
|
|
|
Rod Sharper 03/27/97
|
|
|
|
Arguments:
|
|
|
|
IDL_handle - RPC binding handle, not used.
|
|
|
|
Status - Returns any error that may occur.
|
|
|
|
Return Value:
|
|
|
|
A context handle to a cluster object if successful
|
|
|
|
NULL otherwise.
|
|
|
|
History:
|
|
RodSh 27-Mar-1997 Modified to support secured user connections.
|
|
|
|
--*/
|
|
|
|
{
|
|
PAPI_HANDLE Handle;
|
|
|
|
Handle = LocalAlloc(LMEM_FIXED, sizeof(API_HANDLE));
|
|
|
|
if (Handle == NULL) {
|
|
*Status = ERROR_NOT_ENOUGH_MEMORY;
|
|
return(NULL);
|
|
}
|
|
|
|
*Status = ERROR_SUCCESS;
|
|
Handle->Type = API_CLUSTER_HANDLE;
|
|
Handle->Flags = 0;
|
|
Handle->Cluster = NULL;
|
|
InitializeListHead(&Handle->NotifyList);
|
|
|
|
return(Handle);
|
|
}
|
|
|
|
|
|
error_status_t
|
|
s_ApiCloseCluster(
|
|
IN OUT HCLUSTER_RPC *phCluster
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Closes an open cluster context handle.
|
|
|
|
Arguments:
|
|
|
|
phCluster - Supplies a pointer to the HCLUSTER_RPC to be closed.
|
|
Returns NULL
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PAPI_HANDLE Handle;
|
|
|
|
Handle = (PAPI_HANDLE)*phCluster;
|
|
if ((Handle == NULL) || (Handle->Type != API_CLUSTER_HANDLE)) {
|
|
return(ERROR_INVALID_HANDLE);
|
|
}
|
|
ApipRundownNotify(Handle);
|
|
|
|
LocalFree(*phCluster);
|
|
*phCluster = NULL;
|
|
|
|
return(ERROR_SUCCESS);
|
|
}
|
|
|
|
|
|
VOID
|
|
HCLUSTER_RPC_rundown(
|
|
IN HCLUSTER_RPC Cluster
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
RPC rundown procedure for a HCLUSTER_RPC. Just closes the handle.
|
|
|
|
Arguments:
|
|
|
|
Cluster - Supplies the HCLUSTER_RPC that is to be rundown.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
s_ApiCloseCluster(&Cluster);
|
|
}
|
|
|
|
|
|
error_status_t
|
|
s_ApiSetClusterName(
|
|
IN handle_t IDL_handle,
|
|
IN LPCWSTR NewClusterName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Changes the current cluster's name.
|
|
|
|
Arguments:
|
|
|
|
IDL_handle - RPC binding handle, not used
|
|
|
|
NewClusterName - Supplies the new name of the cluster.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful
|
|
|
|
Win32 error code otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD Status = ERROR_SUCCESS;
|
|
DWORD dwSize;
|
|
LPWSTR pszClusterName = NULL;
|
|
|
|
API_CHECK_INIT();
|
|
|
|
//
|
|
// Get the cluster name, which is kept in the root of the
|
|
// cluster registry under the "ClusterName" value, call the
|
|
// FM only if the new name is different
|
|
//
|
|
|
|
dwSize = (MAX_COMPUTERNAME_LENGTH+1)*sizeof(WCHAR);
|
|
retry:
|
|
pszClusterName = (LPWSTR)LocalAlloc(LMEM_FIXED, dwSize);
|
|
if (pszClusterName == NULL) {
|
|
Status = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto FnExit;
|
|
}
|
|
|
|
Status = DmQueryValue(DmClusterParametersKey,
|
|
CLUSREG_NAME_CLUS_NAME,
|
|
NULL,
|
|
(LPBYTE)pszClusterName,
|
|
&dwSize);
|
|
|
|
if (Status == ERROR_MORE_DATA) {
|
|
//
|
|
// Try again with a bigger buffer.
|
|
//
|
|
LocalFree(pszClusterName);
|
|
goto retry;
|
|
}
|
|
|
|
if ( Status == ERROR_SUCCESS ) {
|
|
LPWSTR pszNewNameUpperCase = NULL;
|
|
|
|
pszNewNameUpperCase = (LPWSTR) LocalAlloc(
|
|
LMEM_FIXED,
|
|
(lstrlenW(NewClusterName) + 1) *
|
|
sizeof(*NewClusterName)
|
|
);
|
|
|
|
if (pszNewNameUpperCase != NULL) {
|
|
lstrcpyW( pszNewNameUpperCase, NewClusterName );
|
|
_wcsupr( pszNewNameUpperCase );
|
|
|
|
Status = FmChangeClusterName(pszNewNameUpperCase, pszClusterName);
|
|
|
|
LocalFree( pszNewNameUpperCase );
|
|
}
|
|
else {
|
|
Status = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
}
|
|
|
|
FnExit:
|
|
if ( pszClusterName ) LocalFree( pszClusterName );
|
|
return(Status);
|
|
|
|
}
|
|
|
|
|
|
error_status_t
|
|
s_ApiGetClusterName(
|
|
IN handle_t IDL_handle,
|
|
OUT LPWSTR *ClusterName,
|
|
OUT LPWSTR *NodeName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns the current cluster name and the name of the
|
|
node this RPC connection is to.
|
|
|
|
Arguments:
|
|
|
|
IDL_handle - RPC binding handle, not used
|
|
|
|
ClusterName - Returns a pointer to the cluster name.
|
|
This memory must be freed by the client side.
|
|
|
|
NodeName - Returns a pointer to the node name.
|
|
This memory must be freed by the client side.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful
|
|
|
|
Win32 error code otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD Size;
|
|
DWORD Status=ERROR_SUCCESS;
|
|
|
|
//
|
|
// Get the current node name
|
|
//
|
|
*ClusterName = NULL;
|
|
Size = MAX_COMPUTERNAME_LENGTH+1;
|
|
*NodeName = MIDL_user_allocate(Size*sizeof(WCHAR));
|
|
if (*NodeName == NULL) {
|
|
Status = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto FnExit;
|
|
}
|
|
GetComputerNameW(*NodeName, &Size);
|
|
|
|
|
|
//
|
|
// Get the cluster name, which is kept in the root of the
|
|
// cluster registry under the "ClusterName" value.
|
|
//
|
|
|
|
Status = ERROR_SUCCESS;
|
|
Size = (MAX_COMPUTERNAME_LENGTH+1)*sizeof(WCHAR);
|
|
retry:
|
|
*ClusterName = MIDL_user_allocate(Size);
|
|
if (*ClusterName == NULL) {
|
|
Status = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto FnExit;
|
|
}
|
|
|
|
Status = DmQueryValue(DmClusterParametersKey,
|
|
CLUSREG_NAME_CLUS_NAME,
|
|
NULL,
|
|
(LPBYTE)*ClusterName,
|
|
&Size);
|
|
if (Status == ERROR_MORE_DATA) {
|
|
//
|
|
// Try again with a bigger buffer.
|
|
//
|
|
MIDL_user_free(*ClusterName);
|
|
goto retry;
|
|
}
|
|
|
|
|
|
FnExit:
|
|
if (Status == ERROR_SUCCESS) {
|
|
return(ERROR_SUCCESS);
|
|
}
|
|
|
|
if (*NodeName) MIDL_user_free(*NodeName);
|
|
if (*ClusterName) MIDL_user_free(*ClusterName);
|
|
*NodeName = NULL;
|
|
*ClusterName = NULL;
|
|
return(Status);
|
|
}
|
|
|
|
|
|
error_status_t
|
|
s_ApiGetClusterVersion(
|
|
IN handle_t IDL_handle,
|
|
OUT LPWORD lpwMajorVersion,
|
|
OUT LPWORD lpwMinorVersion,
|
|
OUT LPWORD lpwBuildNumber,
|
|
OUT LPWSTR *lpszVendorId,
|
|
OUT LPWSTR *lpszCSDVersion
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns the current cluster version information.
|
|
|
|
Arguments:
|
|
|
|
IDL_handle - RPC binding handle, not used
|
|
|
|
lpdwMajorVersion - Returns the major version number of the cluster software
|
|
|
|
lpdwMinorVersion - Returns the minor version number of the cluster software
|
|
|
|
lpszVendorId - Returns a pointer to the vendor name. This memory must be
|
|
freed by the client side.
|
|
|
|
lpszCSDVersion - Returns a pointer to the current CSD description. This memory
|
|
must be freed by the client side.
|
|
N.B. The CSD Version of a cluster is currently the same as the CSD
|
|
Version of the base operating system.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful
|
|
|
|
Win32 error code otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
LPWSTR VendorString = NULL;
|
|
LPWSTR CsdString = NULL;
|
|
DWORD Length;
|
|
OSVERSIONINFO OsVersionInfo;
|
|
DWORD dwStatus = ERROR_SUCCESS;
|
|
|
|
Length = lstrlenA(VER_CLUSTER_PRODUCTNAME_STR)+1;
|
|
VendorString = MIDL_user_allocate(Length*sizeof(WCHAR));
|
|
if (VendorString == NULL)
|
|
{
|
|
dwStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto FnExit;
|
|
}
|
|
mbstowcs(VendorString, VER_CLUSTER_PRODUCTNAME_STR, Length);
|
|
|
|
OsVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
GetVersionExW(&OsVersionInfo);
|
|
Length = lstrlenW(OsVersionInfo.szCSDVersion)+1;
|
|
CsdString = MIDL_user_allocate(Length*sizeof(WCHAR));
|
|
if (CsdString == NULL) {
|
|
dwStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto FnExit;
|
|
}
|
|
lstrcpyW(CsdString, OsVersionInfo.szCSDVersion);
|
|
|
|
*lpszCSDVersion = CsdString;
|
|
*lpszVendorId = VendorString;
|
|
*lpwMajorVersion = VER_PRODUCTVERSION_W >> 8;
|
|
*lpwMinorVersion = VER_PRODUCTVERSION_W & 0xff;
|
|
*lpwBuildNumber = (WORD)(CLUSTER_GET_MINOR_VERSION(CsMyHighestVersion));
|
|
|
|
|
|
FnExit:
|
|
if (dwStatus != ERROR_SUCCESS)
|
|
{
|
|
if (VendorString)
|
|
MIDL_user_free(VendorString);
|
|
if (CsdString)
|
|
MIDL_user_free(CsdString);
|
|
|
|
}
|
|
return(dwStatus);
|
|
}
|
|
|
|
|
|
error_status_t
|
|
s_ApiGetClusterVersion2(
|
|
IN handle_t IDL_handle,
|
|
OUT LPWORD lpwMajorVersion,
|
|
OUT LPWORD lpwMinorVersion,
|
|
OUT LPWORD lpwBuildNumber,
|
|
OUT LPWSTR *lpszVendorId,
|
|
OUT LPWSTR *lpszCSDVersion,
|
|
OUT PCLUSTER_OPERATIONAL_VERSION_INFO *ppClusterOpVerInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns the current cluster version information.
|
|
|
|
Arguments:
|
|
|
|
IDL_handle - RPC binding handle, not used
|
|
|
|
lpdwMajorVersion - Returns the major version number of the cluster software
|
|
|
|
lpdwMinorVersion - Returns the minor version number of the cluster software
|
|
|
|
lpszVendorId - Returns a pointer to the vendor name. This memory must be
|
|
freed by the client side.
|
|
|
|
lpszCSDVersion - Returns a pointer to the current CSD description. This memory
|
|
must be freed by the client side.
|
|
N.B. The CSD Version of a cluster is currently the same as the CSD
|
|
Version of the base operating system.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful
|
|
|
|
Win32 error code otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
LPWSTR VendorString = NULL;
|
|
LPWSTR CsdString = NULL;
|
|
DWORD Length;
|
|
OSVERSIONINFO OsVersionInfo;
|
|
DWORD dwStatus;
|
|
PCLUSTER_OPERATIONAL_VERSION_INFO pClusterOpVerInfo=NULL;
|
|
|
|
|
|
*lpszVendorId = NULL;
|
|
*lpszCSDVersion = NULL;
|
|
*ppClusterOpVerInfo = NULL;
|
|
|
|
Length = lstrlenA(VER_CLUSTER_PRODUCTNAME_STR)+1;
|
|
VendorString = MIDL_user_allocate(Length*sizeof(WCHAR));
|
|
if (VendorString == NULL) {
|
|
dwStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto FnExit;
|
|
}
|
|
mbstowcs(VendorString, VER_CLUSTER_PRODUCTNAME_STR, Length);
|
|
|
|
OsVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
GetVersionExW(&OsVersionInfo);
|
|
Length = lstrlenW(OsVersionInfo.szCSDVersion)+1;
|
|
CsdString = MIDL_user_allocate(Length*sizeof(WCHAR));
|
|
if (CsdString == NULL) {
|
|
dwStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto FnExit;
|
|
}
|
|
lstrcpyW(CsdString, OsVersionInfo.szCSDVersion);
|
|
|
|
|
|
pClusterOpVerInfo = MIDL_user_allocate(sizeof(CLUSTER_OPERATIONAL_VERSION_INFO));
|
|
if (pClusterOpVerInfo == NULL) {
|
|
dwStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto FnExit;
|
|
}
|
|
pClusterOpVerInfo->dwSize = sizeof(CLUSTER_OPERATIONAL_VERSION_INFO);
|
|
pClusterOpVerInfo->dwReserved = 0;
|
|
|
|
dwStatus = NmGetClusterOperationalVersion(&(pClusterOpVerInfo->dwClusterHighestVersion),
|
|
&(pClusterOpVerInfo->dwClusterLowestVersion),
|
|
&(pClusterOpVerInfo->dwFlags));
|
|
|
|
*lpszCSDVersion = CsdString;
|
|
*lpszVendorId = VendorString;
|
|
*ppClusterOpVerInfo = pClusterOpVerInfo;
|
|
*lpwMajorVersion = VER_PRODUCTVERSION_W >> 8;
|
|
*lpwMinorVersion = VER_PRODUCTVERSION_W & 0xff;
|
|
*lpwBuildNumber = (WORD)CLUSTER_GET_MINOR_VERSION(CsMyHighestVersion);
|
|
|
|
FnExit:
|
|
if (dwStatus != ERROR_SUCCESS)
|
|
{
|
|
// free the strings
|
|
if (VendorString) MIDL_user_free(VendorString);
|
|
if (CsdString) MIDL_user_free(CsdString);
|
|
if (pClusterOpVerInfo) MIDL_user_free(pClusterOpVerInfo);
|
|
}
|
|
|
|
return(ERROR_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
error_status_t
|
|
s_ApiGetQuorumResource(
|
|
IN handle_t IDL_handle,
|
|
OUT LPWSTR *ppszResourceName,
|
|
OUT LPWSTR *ppszClusFileRootPath,
|
|
OUT DWORD *pdwMaxQuorumLogSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Gets the current cluster quorum resource.
|
|
|
|
Arguments:
|
|
|
|
IDL_handle - RPC binding handle, not used.
|
|
|
|
*ppszResourceName - Returns a pointer to the current quorum resource name. This
|
|
memory must be freed by the client side.
|
|
|
|
*ppszClusFileRootPath - Returns the root path where the permanent cluster files are
|
|
stored.
|
|
|
|
*pdwMaxQuorumLogSize - Returns the size at which the quorum log path is set.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful
|
|
|
|
Win32 error code otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD Status;
|
|
LPWSTR quorumId = NULL;
|
|
DWORD idMaxSize = 0;
|
|
DWORD idSize = 0;
|
|
PFM_RESOURCE pResource=NULL;
|
|
LPWSTR pszResourceName=NULL;
|
|
LPWSTR pszClusFileRootPath=NULL;
|
|
LPWSTR pszLogPath=NULL;
|
|
|
|
API_CHECK_INIT();
|
|
//
|
|
// Get the quorum resource value.
|
|
//
|
|
Status = DmQuerySz( DmQuorumKey,
|
|
CLUSREG_NAME_QUORUM_RESOURCE,
|
|
(LPWSTR*)&quorumId,
|
|
&idMaxSize,
|
|
&idSize);
|
|
if (Status != ERROR_SUCCESS) {
|
|
ClRtlLogPrint(LOG_ERROR,
|
|
"[API] s_ApiGetQuorumResource Failed to get quorum resource, error %1!u!.\n",
|
|
Status);
|
|
goto FnExit;
|
|
}
|
|
|
|
//
|
|
// Reference the specified resource ID.
|
|
//
|
|
pResource = OmReferenceObjectById( ObjectTypeResource, quorumId );
|
|
if (pResource == NULL) {
|
|
Status = ERROR_RESOURCE_NOT_FOUND;
|
|
ClRtlLogPrint(LOG_ERROR,
|
|
"[API] s_ApiGetQuorumResource Failed to find quorum resource object, error %1!u!\n",
|
|
Status);
|
|
goto FnExit;
|
|
}
|
|
|
|
//
|
|
// Allocate buffer for returning the resource name.
|
|
//
|
|
pszResourceName = MIDL_user_allocate((lstrlenW(OmObjectName(pResource))+1)*sizeof(WCHAR));
|
|
if (pszResourceName == NULL) {
|
|
|
|
Status = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto FnExit;
|
|
}
|
|
lstrcpyW(pszResourceName, OmObjectName(pResource));
|
|
|
|
//
|
|
// Get the root path for cluster temporary files
|
|
//
|
|
idMaxSize = 0;
|
|
idSize = 0;
|
|
|
|
Status = DmQuerySz( DmQuorumKey,
|
|
cszPath,
|
|
(LPWSTR*)&pszLogPath,
|
|
&idMaxSize,
|
|
&idSize);
|
|
if (Status != ERROR_SUCCESS) {
|
|
ClRtlLogPrint(LOG_ERROR,
|
|
"[API] s_ApiGetQuorumResource Failed to get the log path, error %1!u!.\n",
|
|
Status);
|
|
goto FnExit;
|
|
}
|
|
|
|
//
|
|
// Allocate buffer for returning the resource name.
|
|
//
|
|
pszClusFileRootPath = MIDL_user_allocate((lstrlenW(pszLogPath)+1)*sizeof(WCHAR));
|
|
if (pszClusFileRootPath == NULL) {
|
|
|
|
Status = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto FnExit;
|
|
}
|
|
lstrcpyW(pszClusFileRootPath, pszLogPath);
|
|
|
|
*ppszResourceName = pszResourceName;
|
|
*ppszClusFileRootPath = pszClusFileRootPath;
|
|
|
|
DmGetQuorumLogMaxSize(pdwMaxQuorumLogSize);
|
|
|
|
FnExit:
|
|
if (pResource) OmDereferenceObject(pResource);
|
|
if (pszLogPath) LocalFree(pszLogPath);
|
|
if (quorumId) LocalFree(quorumId);
|
|
if (Status != ERROR_SUCCESS)
|
|
{
|
|
if (pszResourceName) MIDL_user_free(pszResourceName);
|
|
if (pszClusFileRootPath) MIDL_user_free(pszClusFileRootPath);
|
|
}
|
|
return(Status);
|
|
}
|
|
|
|
|
|
error_status_t
|
|
s_ApiSetQuorumResource(
|
|
IN HRES_RPC hResource,
|
|
IN LPCWSTR lpszClusFileRootPath,
|
|
IN DWORD dwMaxQuorumLogSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sets the current cluster quorum resource.
|
|
|
|
Arguments:
|
|
|
|
hResource - Supplies a handle to the resource that should be the cluster
|
|
quorum resource.
|
|
|
|
lpszClusFileRootPath - The root path for storing
|
|
permananent cluster maintenace files.
|
|
|
|
dwMaxQuorumLogSize - The maximum size of the quorum logs before they are
|
|
reset by checkpointing. If 0, the default is used.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful
|
|
|
|
Win32 error code otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD Status;
|
|
PFM_RESOURCE Resource;
|
|
LPCWSTR lpszPathName = NULL;
|
|
|
|
API_CHECK_INIT();
|
|
VALIDATE_RESOURCE_EXISTS(Resource, hResource);
|
|
|
|
//
|
|
// Chittur Subbaraman (chitturs) - 1/6/99
|
|
//
|
|
// Check whether the user is passing in a pointer to a NULL character
|
|
// as the second parameter. If not, pass the parameter passed by the
|
|
// user
|
|
//
|
|
if ( ( ARGUMENT_PRESENT( lpszClusFileRootPath ) ) &&
|
|
( *lpszClusFileRootPath != L'\0' ) )
|
|
{
|
|
lpszPathName = lpszClusFileRootPath;
|
|
}
|
|
|
|
//
|
|
// Let FM decide if this operation can be completed.
|
|
//
|
|
Status = FmSetQuorumResource(Resource, lpszPathName, dwMaxQuorumLogSize );
|
|
if ( Status != ERROR_SUCCESS ) {
|
|
return(Status);
|
|
}
|
|
|
|
//Update the path
|
|
return(Status);
|
|
}
|
|
|
|
|
|
|
|
error_status_t
|
|
s_ApiSetNetworkPriorityOrder(
|
|
IN handle_t IDL_handle,
|
|
IN DWORD NetworkCount,
|
|
IN LPWSTR *NetworkIdList
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sets the priority order for internal (intracluster) networks.
|
|
|
|
Arguments:
|
|
|
|
IDL_handle - RPC binding handle, not used
|
|
|
|
NetworkCount - The count of networks in the NetworkList
|
|
|
|
NetworkList - An array of pointers to network IDs.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful
|
|
|
|
Win32 error code otherwise.
|
|
|
|
--*/
|
|
{
|
|
API_CHECK_INIT();
|
|
|
|
return(
|
|
NmSetNetworkPriorityOrder(
|
|
NetworkCount,
|
|
NetworkIdList
|
|
)
|
|
);
|
|
|
|
}
|
|
|
|
error_status_t
|
|
s_ApiBackupClusterDatabase(
|
|
IN handle_t IDL_handle,
|
|
IN LPCWSTR lpszPathName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Requests for backup of the quorum log file and the checkpoint file.
|
|
|
|
Argument:
|
|
|
|
IDL_handle - RPC binding handle, not used
|
|
|
|
lpszPathName - The directory path name where the files have to be
|
|
backed up. This path must be visible to the node
|
|
on which the quorum resource is online.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful
|
|
|
|
Win32 error code otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
API_CHECK_INIT();
|
|
|
|
//
|
|
// Let FM decide if this operation can be completed.
|
|
//
|
|
return( FmBackupClusterDatabase( lpszPathName ) );
|
|
}
|
|
|
|
|
|
|
|
// #define SetServiceAccountPasswordDebug 1
|
|
|
|
error_status_t
|
|
s_ApiSetServiceAccountPassword(
|
|
IN handle_t IDL_handle,
|
|
IN LPWSTR lpszNewPassword,
|
|
IN DWORD dwFlags,
|
|
OUT IDL_CLUSTER_SET_PASSWORD_STATUS *ReturnStatusBufferPtr,
|
|
IN DWORD ReturnStatusBufferSize,
|
|
OUT DWORD *SizeReturned,
|
|
OUT DWORD *ExpectedBufferSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Change cluster service account password on Service Control Manager
|
|
Database and LSA password cache on every node of cluster.
|
|
Return execution status on each node.
|
|
|
|
Argument:
|
|
|
|
IDL_handle - Input parameter, RPC binding handle.
|
|
lpszNewPassword - Input parameter, new password for cluster service account.
|
|
|
|
dwFlags - Describing how the password update should be made to
|
|
the cluster. The dwFlags parameter is optional. If set, the
|
|
following value is valid:
|
|
|
|
CLUSTER_SET_PASSWORD_IGNORE_DOWN_NODES
|
|
Apply the update even if some nodes are not
|
|
actively participating in the cluster (i.e. not
|
|
ClusterNodeStateUp or ClusterNodeStatePaused).
|
|
By default, the update is only applied if all
|
|
nodes are up.
|
|
|
|
ReturnStatusBufferPtr - Output parameter, pointer to return status buffer.
|
|
ReturnStatusBufferSize - Input paramter, the length of return status
|
|
buffer, in number of elements.
|
|
SizeReturned - Output parameter, the number of elements written to return
|
|
status buffer.
|
|
ExpectedBufferSize - Output parameter, expected return status buffer size
|
|
(in number of entries) when ReturnStatusBuffer is
|
|
too small.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful
|
|
Win32 error code otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD Status=ERROR_SUCCESS;
|
|
RPC_AUTHZ_HANDLE AuthzHandle = NULL;
|
|
unsigned long AuthnLevel = 0;
|
|
HANDLE TokenHandle = NULL;
|
|
TOKEN_STATISTICS TokenSta;
|
|
DWORD ReturnSize = 0;
|
|
PSECURITY_LOGON_SESSION_DATA SecLogSesData = NULL;
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
|
|
#ifdef SetServiceAccountPasswordDebug
|
|
// test
|
|
WCHAR ComputerName[100];
|
|
DWORD ComputerNameSize=100;
|
|
static int once=0;
|
|
// test
|
|
#endif
|
|
|
|
API_CHECK_INIT();
|
|
|
|
ClRtlLogPrint(LOG_NOISE,
|
|
"s_ApiSetServiceAccountPassword(): Changing account password.\n"
|
|
);
|
|
|
|
#ifdef SetServiceAccountPasswordDebug
|
|
ClRtlLogPrint(LOG_NOISE,
|
|
"s_ApiSetServiceAccountPassword(): NewPassword = %1!ws!.\n",
|
|
lpszNewPassword
|
|
);
|
|
ClRtlLogPrint(LOG_NOISE,
|
|
"s_ApiSetServiceAccountPassword(): ReturnStatusBufferSize = %1!u!.\n",
|
|
ReturnStatusBufferSize
|
|
);
|
|
// test
|
|
#endif
|
|
|
|
// check privilege attributes of the authenticated client that made the remote procedure call.
|
|
Status = RpcBindingInqAuthClient(IDL_handle, // The client binding handle of the client that made
|
|
// the remote procedure call.
|
|
&AuthzHandle, // Returns a pointer to a handle to the privileged information
|
|
// for the client application that made the remote procedure
|
|
// call
|
|
NULL,
|
|
&AuthnLevel, // Returns a pointer to the level of authentication requested
|
|
// by the client application that made the remote procedure call
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
|
|
if (Status == RPC_S_OK)
|
|
{
|
|
#ifdef SetServiceAccountPasswordDebug
|
|
ClRtlLogPrint(LOG_NOISE,
|
|
"s_ApiSetServiceAccountPassword()/RpcBindingInqAuthClient() succeeded. AuthnLevel = %1!u!.\n",
|
|
AuthnLevel
|
|
);
|
|
#endif
|
|
if (AuthnLevel < RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
|
|
{
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"s_ApiSetServiceAccountPassword()/RpcBindingInqAuthClient(): AuthnLevel (%1!u!) < RPC_C_AUTHN_LEVEL_PKT_PRIVACY.\n",
|
|
AuthnLevel
|
|
);
|
|
Status = ERROR_ACCESS_DENIED;
|
|
goto ErrorExit;
|
|
}
|
|
else
|
|
{
|
|
#ifdef SetServiceAccountPasswordDebug
|
|
ClRtlLogPrint(LOG_NOISE,
|
|
"s_ApiSetServiceAccountPassword()/RpcBindingInqAuthClient(): AuthnLevel (%1!u!) fine.\n",
|
|
AuthnLevel
|
|
);
|
|
#endif
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"s_ApiSetServiceAccountPassword()/RpcBindingInqAuthClient() failed. Error code = %1!u!.\n",
|
|
Status
|
|
);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
|
|
// Get domain name and account name
|
|
if (!OpenProcessToken(GetCurrentProcess(), // Handle to the process whose access token is opened.
|
|
TOKEN_QUERY, // Access mask
|
|
&TokenHandle // Pointer to a handle identifying the newly-opened access token
|
|
// when the function returns.
|
|
))
|
|
{
|
|
Status=GetLastError();
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"s_ApiSetServiceAccountPassword()/OpenProcessToken() failed. Error code = %1!u!.\n",
|
|
Status);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
Status = GetTokenInformation(TokenHandle, // Handle to an access token from which information is retrieved.
|
|
TokenStatistics,
|
|
&TokenSta, // The buffer receives a TOKEN_STATISTICS structure containing
|
|
// various token statistics.
|
|
sizeof(TokenSta),
|
|
&ReturnSize
|
|
);
|
|
if ( (Status==0) || (ReturnSize > sizeof(TokenSta)) )
|
|
{
|
|
Status=GetLastError();
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"s_ApiSetServiceAccountPassword()/GetTokenInformation() failed. Error code = %1!u!.\n",
|
|
Status);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
NtStatus = LsaGetLogonSessionData(&(TokenSta.AuthenticationId), // Specifies a pointer to a LUID that
|
|
// identifies the logon session whose
|
|
// information will be retrieved.
|
|
&SecLogSesData // Address of a pointer to a SECURITY_LOGON_SESSION_DATA
|
|
// structure containing information on the logon session
|
|
);
|
|
if (NtStatus != STATUS_SUCCESS)
|
|
{
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"s_ApiSetServiceAccountPassword()/LsaGetLogonSessionData() failed. Error code = %1!u!.\n",
|
|
LsaNtStatusToWinError(NtStatus));
|
|
Status=LsaNtStatusToWinError(NtStatus);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
#ifdef SetServiceAccountPasswordDebug
|
|
// test
|
|
ClRtlLogPrint(LOG_NOISE,
|
|
"s_ApiSetServiceAccountPassword()/DomainName = %1!ws!\n",
|
|
SecLogSesData->LogonDomain.Buffer);
|
|
ClRtlLogPrint(LOG_NOISE,
|
|
"s_ApiSetServiceAccountPassword()/AccountName = %1!ws!\n",
|
|
SecLogSesData->UserName.Buffer);
|
|
ClRtlLogPrint(LOG_NOISE,
|
|
"s_ApiSetServiceAccountPassword()/AuthenticationPackage = %1!ws!\n",
|
|
SecLogSesData->AuthenticationPackage.Buffer);
|
|
ClRtlLogPrint(LOG_NOISE,
|
|
"s_ApiSetServiceAccountPassword()/LogonType = %1!u!\n",
|
|
SecLogSesData->LogonType);
|
|
|
|
// test
|
|
#endif
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
// Call NmSetServiceAccountPassword()
|
|
|
|
Status = NmSetServiceAccountPassword(
|
|
SecLogSesData->LogonDomain.Buffer,
|
|
SecLogSesData->UserName.Buffer,
|
|
lpszNewPassword,
|
|
dwFlags,
|
|
(PCLUSTER_SET_PASSWORD_STATUS) ReturnStatusBufferPtr,
|
|
ReturnStatusBufferSize,
|
|
SizeReturned,
|
|
ExpectedBufferSize
|
|
);
|
|
|
|
RtlSecureZeroMemory(lpszNewPassword, (wcslen(lpszNewPassword)+1)*sizeof(WCHAR));
|
|
|
|
ErrorExit:
|
|
if (TokenHandle!=NULL)
|
|
{
|
|
if (!CloseHandle(TokenHandle))
|
|
ClRtlLogPrint(LOG_ERROR,
|
|
"s_ApiSetServiceAccountPassword(): CloseHandle() FAILED. Error code=%1!u!\n",
|
|
GetLastError()
|
|
);
|
|
}
|
|
|
|
if (SecLogSesData!=NULL)
|
|
{
|
|
NtStatus = LsaFreeReturnBuffer(SecLogSesData);
|
|
if (NtStatus!=STATUS_SUCCESS)
|
|
ClRtlLogPrint(LOG_ERROR,
|
|
"s_ApiSetServiceAccountPassword(): LsaFreeReturnBuffer() FAILED. Error code=%1!u!\n",
|
|
LsaNtStatusToWinError(NtStatus)
|
|
);
|
|
}
|
|
|
|
// Return status can not be ERROR_INVALID_HANDLE, since this will trigger the
|
|
// re-try logic at the RPC client. So ERROR_INVALID_HANDLE is converted to some
|
|
// value, which no Win32 function will ever set its return status to, before
|
|
// it is sent back to RPC client.
|
|
|
|
// Error codes are 32-bit values (bit 31 is the most significant bit). Bit 29
|
|
// is reserved for application-defined error codes; no system error code has
|
|
// this bit set. If you are defining an error code for your application, set this
|
|
// bit to one. That indicates that the error code has been defined by an application,
|
|
// and ensures that your error code does not conflict with any error codes defined
|
|
// by the system.
|
|
if ( Status == ERROR_INVALID_HANDLE ) {
|
|
Status |= 0x20000000; // Bit 29 set.
|
|
}
|
|
|
|
return (Status);
|
|
|
|
} // s_ApiSetServiceAccountPassword()
|