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.
 
 
 
 
 
 

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);
}