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.
673 lines
12 KiB
673 lines
12 KiB
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
group.c
|
|
|
|
Abstract:
|
|
|
|
Server side support for Cluster APIs dealing with groups
|
|
|
|
Author:
|
|
|
|
John Vert (jvert) 7-Mar-1996
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
#include "apip.h"
|
|
|
|
HGROUP_RPC
|
|
s_ApiOpenGroup(
|
|
IN handle_t IDL_handle,
|
|
IN LPCWSTR lpszGroupName,
|
|
OUT error_status_t *Status
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Opens a handle to an existing group object.
|
|
|
|
Arguments:
|
|
|
|
IDL_handle - RPC binding handle, not used.
|
|
|
|
lpszGroupName - Supplies the name of the group to open.
|
|
|
|
Status - Returns any error that may occur.
|
|
|
|
Return Value:
|
|
|
|
A context handle to a group object if successful
|
|
|
|
NULL otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
PAPI_HANDLE Handle;
|
|
HGROUP_RPC Group;
|
|
|
|
if (ApiState != ApiStateOnline) {
|
|
*Status = ERROR_SHARING_PAUSED;
|
|
return(NULL);
|
|
}
|
|
Handle = LocalAlloc(LMEM_FIXED, sizeof(API_HANDLE));
|
|
if (Handle == NULL) {
|
|
*Status = ERROR_NOT_ENOUGH_MEMORY;
|
|
return(NULL);
|
|
}
|
|
|
|
Group = OmReferenceObjectByName(ObjectTypeGroup, lpszGroupName);
|
|
if (Group == NULL) {
|
|
LocalFree(Handle);
|
|
*Status = ERROR_GROUP_NOT_FOUND;
|
|
return(NULL);
|
|
}
|
|
|
|
Handle->Type = API_GROUP_HANDLE;
|
|
Handle->Flags = 0;
|
|
Handle->Group = Group;
|
|
InitializeListHead(&Handle->NotifyList);
|
|
*Status = ERROR_SUCCESS;
|
|
return(Handle);
|
|
}
|
|
|
|
HGROUP_RPC
|
|
s_ApiCreateGroup(
|
|
IN handle_t IDL_handle,
|
|
IN LPCWSTR lpszGroupName,
|
|
OUT error_status_t *pStatus
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates a new group object.
|
|
|
|
Arguments:
|
|
|
|
IDL_handle - RPC binding handle, not used.
|
|
|
|
lpszGroupName - Supplies the name of the group to create.
|
|
|
|
Status - Returns any error that may occur.
|
|
|
|
Return Value:
|
|
|
|
A context handle to a group object if successful
|
|
|
|
NULL otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
HGROUP_RPC Group=NULL;
|
|
UUID Guid;
|
|
DWORD Status = ERROR_SUCCESS;
|
|
WCHAR *KeyName=NULL;
|
|
PAPI_HANDLE Handle;
|
|
DWORD dwDisposition;
|
|
HDMKEY hKey = NULL;
|
|
|
|
if (ApiState != ApiStateOnline) {
|
|
*pStatus = ERROR_SHARING_PAUSED;
|
|
return(NULL);
|
|
}
|
|
|
|
Handle = LocalAlloc(LMEM_FIXED, sizeof(API_HANDLE));
|
|
if (Handle == NULL) {
|
|
*pStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|
return(NULL);
|
|
}
|
|
retry:
|
|
//
|
|
//
|
|
// Create a GUID for this group.
|
|
//
|
|
Status = UuidCreate(&Guid);
|
|
if (Status != RPC_S_OK) {
|
|
goto error_exit;
|
|
}
|
|
Status = UuidToString(&Guid, &KeyName);
|
|
if (Status != RPC_S_OK) {
|
|
goto error_exit;
|
|
}
|
|
|
|
//
|
|
// Create this group in the FM. This will also trigger the notification.
|
|
//
|
|
Group = FmCreateGroup(KeyName, lpszGroupName);
|
|
|
|
if (Group == NULL) {
|
|
Status = GetLastError();
|
|
if (Status == ERROR_ALREADY_EXISTS) {
|
|
RpcStringFree(&KeyName);
|
|
goto retry;
|
|
}
|
|
}
|
|
|
|
error_exit:
|
|
if (KeyName != NULL) {
|
|
RpcStringFree(&KeyName);
|
|
}
|
|
|
|
*pStatus = Status;
|
|
|
|
if (Status == ERROR_SUCCESS) {
|
|
CL_ASSERT(Group != NULL);
|
|
Handle->Type = API_GROUP_HANDLE;
|
|
Handle->Group = Group;
|
|
Handle->Flags = 0;
|
|
InitializeListHead(&Handle->NotifyList);
|
|
return(Handle);
|
|
} else {
|
|
LocalFree(Handle);
|
|
return(NULL);
|
|
}
|
|
}
|
|
|
|
|
|
error_status_t
|
|
s_ApiDeleteGroup(
|
|
IN HGROUP_RPC hGroup
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Deletes a cluster group. The group must contain no resources.
|
|
|
|
Arguments:
|
|
|
|
hGroup - Supplies the group to delete.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful.
|
|
|
|
Win32 error code otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD Status;
|
|
PFM_GROUP Group;
|
|
HDMKEY Key;
|
|
|
|
API_ASSERT_INIT();
|
|
|
|
VALIDATE_GROUP_EXISTS(Group, hGroup);
|
|
|
|
Status = FmDeleteGroup(Group);
|
|
if (Status == ERROR_SUCCESS) {
|
|
DmDeleteTree(DmGroupsKey,OmObjectId(Group));
|
|
}
|
|
return(Status);
|
|
}
|
|
|
|
|
|
error_status_t
|
|
s_ApiCloseGroup(
|
|
IN OUT HGROUP_RPC *phGroup
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Closes an open group context handle.
|
|
|
|
Arguments:
|
|
|
|
Group - Supplies a pointer to the HGROUP_RPC to be closed.
|
|
Returns NULL
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PFM_GROUP Group;
|
|
PAPI_HANDLE Handle;
|
|
|
|
API_ASSERT_INIT();
|
|
|
|
VALIDATE_GROUP(Group, *phGroup);
|
|
|
|
Handle = (PAPI_HANDLE)*phGroup;
|
|
ApipRundownNotify(Handle);
|
|
|
|
OmDereferenceObject(Group);
|
|
|
|
LocalFree(Handle);
|
|
*phGroup = NULL;
|
|
|
|
return(ERROR_SUCCESS);
|
|
}
|
|
|
|
|
|
VOID
|
|
HGROUP_RPC_rundown(
|
|
IN HGROUP_RPC Group
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
RPC rundown procedure for a HGROUP_RPC. Just closes the handle.
|
|
|
|
Arguments:
|
|
|
|
Group - Supplies the HGROUP_RPC that is to be rundown.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
API_ASSERT_INIT();
|
|
|
|
s_ApiCloseGroup(&Group);
|
|
}
|
|
|
|
|
|
error_status_t
|
|
s_ApiGetGroupState(
|
|
IN HGROUP_RPC hGroup,
|
|
OUT DWORD *lpState,
|
|
OUT LPWSTR *lpNodeName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns the current state of the specified group.
|
|
|
|
Arguments:
|
|
|
|
hGroup - Supplies the group whose state is to be returned.
|
|
|
|
lpState - Returns the current state of the group
|
|
|
|
lpNodeName - Returns the name of the node where the group is currently online
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful
|
|
|
|
Win32 error code otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
PFM_GROUP Group;
|
|
LPWSTR NodeName;
|
|
DWORD NameLength;
|
|
|
|
API_ASSERT_INIT();
|
|
|
|
VALIDATE_GROUP_EXISTS(Group, hGroup);
|
|
NameLength = MAX_COMPUTERNAME_LENGTH+1;
|
|
NodeName = MIDL_user_allocate(NameLength*sizeof(WCHAR));
|
|
if (NodeName == NULL) {
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
*lpState = FmGetGroupState( Group,
|
|
NodeName,
|
|
&NameLength);
|
|
if ( *lpState == ClusterGroupStateUnknown ) {
|
|
MIDL_user_free(NodeName);
|
|
return(GetLastError());
|
|
}
|
|
*lpNodeName = NodeName;
|
|
|
|
return( ERROR_SUCCESS );
|
|
}
|
|
|
|
|
|
error_status_t
|
|
s_ApiSetGroupName(
|
|
IN HGROUP_RPC hGroup,
|
|
IN LPCWSTR lpszGroupName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sets the new friendly name of a group.
|
|
|
|
Arguments:
|
|
|
|
hGroup - Supplies the group whose name is to be set.
|
|
|
|
lpszGroupName - Supplies the new name of hGroup
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful
|
|
|
|
Win32 error code otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
PFM_GROUP Group;
|
|
HDMKEY GroupKey;
|
|
DWORD Status;
|
|
|
|
API_ASSERT_INIT();
|
|
|
|
VALIDATE_GROUP_EXISTS(Group, hGroup);
|
|
|
|
//
|
|
// Tell the FM about the new name. If it is OK with the
|
|
// FM, go ahead and update the registry.
|
|
//
|
|
Status = FmSetGroupName(Group,
|
|
lpszGroupName);
|
|
if (Status == ERROR_SUCCESS) {
|
|
GroupKey = DmOpenKey(DmGroupsKey,
|
|
OmObjectId(Group),
|
|
KEY_SET_VALUE);
|
|
if (GroupKey == NULL) {
|
|
return(GetLastError());
|
|
}
|
|
|
|
Status = DmSetValue(GroupKey,
|
|
CLUSREG_NAME_GRP_NAME,
|
|
REG_SZ,
|
|
(CONST BYTE *)lpszGroupName,
|
|
(lstrlenW(lpszGroupName)+1)*sizeof(WCHAR));
|
|
DmCloseKey(GroupKey);
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
error_status_t
|
|
s_ApiGetGroupId(
|
|
IN HGROUP_RPC hGroup,
|
|
OUT LPWSTR *pGuid
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns the unique identifier (GUID) for a group.
|
|
|
|
Arguments:
|
|
|
|
hGroup - Supplies the group whose identifer is to be returned
|
|
|
|
pGuid - Returns the unique identifier. This memory must be freed on the
|
|
client side.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful
|
|
|
|
Win32 error code otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
PFM_GROUP Group;
|
|
DWORD IdLen;
|
|
LPCWSTR Id;
|
|
|
|
API_ASSERT_INIT();
|
|
|
|
VALIDATE_GROUP_EXISTS(Group, hGroup);
|
|
|
|
Id = OmObjectId(Group);
|
|
|
|
IdLen = (lstrlenW(Id)+1)*sizeof(WCHAR);
|
|
*pGuid = MIDL_user_allocate(IdLen);
|
|
if (*pGuid == NULL) {
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
CopyMemory(*pGuid, Id, IdLen);
|
|
return(ERROR_SUCCESS);
|
|
}
|
|
|
|
|
|
DWORD
|
|
s_ApiOnlineGroup(
|
|
IN HGROUP_RPC hGroup
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Brings a group and all its dependencies online
|
|
|
|
Arguments:
|
|
|
|
hGroup - Supplies the group to be brought online
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful
|
|
|
|
Win32 error code otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
PFM_GROUP Group;
|
|
|
|
API_ASSERT_INIT();
|
|
|
|
VALIDATE_GROUP_EXISTS(Group, hGroup);
|
|
|
|
return(FmOnlineGroup(Group));
|
|
|
|
}
|
|
|
|
|
|
DWORD
|
|
s_ApiOfflineGroup(
|
|
IN HGROUP_RPC hGroup
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Brings a group and all its dependents offline
|
|
|
|
Arguments:
|
|
|
|
hGroup - Supplies the group to be brought offline
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful
|
|
|
|
Win32 error code otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
PFM_GROUP Group;
|
|
|
|
API_ASSERT_INIT();
|
|
|
|
VALIDATE_GROUP_EXISTS(Group, hGroup);
|
|
|
|
return(FmOfflineGroup(Group));
|
|
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
s_ApiMoveGroup(
|
|
IN HGROUP_RPC hGroup
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Moves a group and all its dependents to another system.
|
|
|
|
Arguments:
|
|
|
|
hGroup - Supplies the group to be moved
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful
|
|
|
|
Win32 error code otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
PFM_GROUP Group;
|
|
|
|
API_ASSERT_INIT();
|
|
|
|
VALIDATE_GROUP_EXISTS(Group, hGroup);
|
|
|
|
return(FmMoveGroup(Group, NULL));
|
|
|
|
}
|
|
|
|
|
|
DWORD
|
|
s_ApiMoveGroupToNode(
|
|
IN HGROUP_RPC hGroup,
|
|
IN HNODE_RPC hNode
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Moves a group and all its dependents to another system.
|
|
|
|
Arguments:
|
|
|
|
hGroup - Supplies the group to be moved
|
|
|
|
hNode - Supplies the node to move the group to
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful
|
|
|
|
Win32 error code otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
PFM_GROUP Group;
|
|
PNM_NODE Node;
|
|
|
|
API_ASSERT_INIT();
|
|
|
|
VALIDATE_GROUP_EXISTS(Group, hGroup);
|
|
VALIDATE_NODE(Node, hNode);
|
|
|
|
return(FmMoveGroup(Group, Node));
|
|
|
|
}
|
|
|
|
|
|
|
|
error_status_t
|
|
s_ApiSetGroupNodeList(
|
|
IN HGROUP_RPC hGroup,
|
|
IN UCHAR *lpNodeList,
|
|
IN DWORD cbListSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sets the list of preferred nodes for a group.
|
|
|
|
Arguments:
|
|
|
|
hGroup - Supplies the group to set the preferred nodes.
|
|
|
|
lpNodeList - Supplies the list of preferred owners, as a REG_MULTI_SZ.
|
|
|
|
cbListSize - Supplies the size in bytes of the preferred owners list.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful
|
|
|
|
Win32 error code otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
PFM_GROUP Group;
|
|
HDMKEY GroupKey;
|
|
DWORD Status;
|
|
LPWSTR lpszTemp = ( LPWSTR ) lpNodeList;
|
|
DWORD cchListSize = cbListSize / sizeof ( WCHAR );
|
|
|
|
API_ASSERT_INIT();
|
|
|
|
//
|
|
// Make sure the node list is formatted as a MULTI_SZ (and if it is empty it should
|
|
// have at least a single NULL). Don't rely on clusapi.dll doing this since a hacker may be able to
|
|
// bypass clusapi.dll (even though we make that hard with security callback). Also, since
|
|
// lpNodeList is declared as a byte buffer in the IDL file, RPC won't help you with
|
|
// anything (except make sure cbListSize is allocated.)
|
|
//
|
|
if ( ( lpNodeList == NULL ) ||
|
|
( cbListSize % sizeof ( WCHAR ) != 0 ) || // User passed in a size not a multiple of WCHAR
|
|
( cchListSize < 1 ) || // List is of zero length
|
|
( lpszTemp[ cchListSize - 1 ] != UNICODE_NULL ) || // Last char is not NULL
|
|
( ( cchListSize > 1 ) && // List has at least 2 elements and last but one is not NULL
|
|
( lpszTemp[ cchListSize - 2 ] != UNICODE_NULL ) ) )
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
VALIDATE_GROUP_EXISTS(Group, hGroup);
|
|
|
|
//
|
|
// Set the registry with the REG_MULTI_SZ. Let the FM pick it up from
|
|
// there.
|
|
//
|
|
GroupKey = DmOpenKey(DmGroupsKey,
|
|
OmObjectId(Group),
|
|
KEY_SET_VALUE);
|
|
if (GroupKey == NULL) {
|
|
return(GetLastError());
|
|
}
|
|
|
|
Status = DmSetValue(GroupKey,
|
|
CLUSREG_NAME_GRP_PREFERRED_OWNERS,
|
|
REG_MULTI_SZ,
|
|
(CONST BYTE *)lpNodeList,
|
|
cbListSize);
|
|
|
|
DmCloseKey(GroupKey);
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|