|
|
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
registry.c
Abstract:
Server side support for Cluster registry database APIs
Author:
John Vert (jvert) 8-Mar-1996
Revision History:
--*/ #include "apip.h"
PAPI_HANDLE ApipMakeKeyHandle( IN HDMKEY Key ) /*++
Routine Description:
Allocates and initializes an API_HANDLE structure for the specified HDMKEY.
Arguments:
Key - Supplies the HDMKEY.
Return Value:
A pointer to the initialized API_HANDLE structure on success.
NULL on memory allocation failure.
--*/
{ PAPI_HANDLE Handle;
Handle = LocalAlloc(LMEM_FIXED, sizeof(API_HANDLE)); if (Handle == NULL) { return(NULL); } Handle->Type = API_KEY_HANDLE; Handle->Flags = 0; Handle->Key = Key; InitializeListHead(&Handle->NotifyList); return(Handle);
}
HKEY_RPC s_ApiGetRootKey( IN handle_t IDL_handle, IN DWORD samDesired, OUT error_status_t *Status )
/*++
Routine Description:
Opens the registry key at the root of the cluster registry database
Arguments:
IDL_handle - Supplies RPC binding handle, not used.
samDesired - Supplies requested security access
Status - Returns error code, if any.
Return Value:
A handle to the opened registry key.
--*/
{ DWORD Error; HDMKEY Key; PAPI_HANDLE Handle=NULL;
*Status = RpcImpersonateClient(NULL); if (*Status != RPC_S_OK) { goto FnExit; } Key = DmGetRootKey(samDesired); RpcRevertToSelf(); if (Key == NULL) { *Status = GetLastError(); } else { Handle = ApipMakeKeyHandle(Key); if (Handle == NULL) { DmCloseKey(Key); *Status = ERROR_NOT_ENOUGH_MEMORY; } else { *Status = ERROR_SUCCESS; } } FnExit: return(Handle); }
HKEY_RPC s_ApiCreateKey( IN HKEY_RPC hKey, IN LPCWSTR lpSubKey, IN DWORD dwOptions, IN DWORD samDesired, IN PRPC_SECURITY_ATTRIBUTES lpSecurityAttributes, OUT LPDWORD lpdwDisposition, OUT error_status_t *Status )
/*++
Routine Description:
Creates a key in the cluster registry. If the key exists, it is opened. If it does not exist, it is created on all nodes in the cluster.
Arguments:
hKey - Supplies the key that the create is relative to.
lpSubKey - Supplies the key name relative to hKey
dwOptions - Supplies any registry option flags. The only currently supported option is REG_OPTION_VOLATILE
samDesired - Supplies desired security access mask
lpSecurityAttributes - Supplies security for the newly created key.
Disposition - Returns whether the key was opened (REG_OPENED_EXISTING_KEY) or created (REG_CREATED_NEW_KEY)
Status - Returns the error code if the function is unsuccessful.
Return Value:
A handle to the specified key if successful
NULL otherwise.
--*/
{ HDMKEY NewKey; PAPI_HANDLE Handle = NULL; PAPI_HANDLE RootHandle = NULL;
if (hKey != NULL) { RootHandle = (PAPI_HANDLE)hKey; if (RootHandle->Type != API_KEY_HANDLE) { *Status = ERROR_INVALID_HANDLE; return(NULL); } } else { *Status = ERROR_INVALID_HANDLE; return(NULL); }
if (ApiState != ApiStateOnline) { *Status = ERROR_SHARING_PAUSED; return(NULL); }
*Status = RpcImpersonateClient(NULL); if (*Status != RPC_S_OK) { return(NULL); }
if ( ARGUMENT_PRESENT( lpSecurityAttributes ) && (lpSecurityAttributes->RpcSecurityDescriptor.lpSecurityDescriptor != NULL) && !RtlValidRelativeSecurityDescriptor( lpSecurityAttributes->RpcSecurityDescriptor.lpSecurityDescriptor, lpSecurityAttributes->RpcSecurityDescriptor.cbInSecurityDescriptor, 0 ) ) { *Status = ERROR_INVALID_SECURITY_DESCR; goto FnExit; }
NewKey = DmCreateKey(RootHandle->Key, lpSubKey, dwOptions, samDesired, ARGUMENT_PRESENT(lpSecurityAttributes) ? lpSecurityAttributes->RpcSecurityDescriptor.lpSecurityDescriptor : NULL, lpdwDisposition); if (NewKey == NULL) { *Status = GetLastError(); } else { Handle = ApipMakeKeyHandle(NewKey); if (Handle == NULL) { DmCloseKey(NewKey); *Status = ERROR_NOT_ENOUGH_MEMORY; } else { *Status = ERROR_SUCCESS; } }
FnExit: RpcRevertToSelf(); return(Handle); }
HKEY_RPC s_ApiOpenKey( IN HKEY_RPC hKey, IN LPCWSTR lpSubKey, IN DWORD samDesired, OUT error_status_t *Status )
/*++
Routine Description:
Opens a key in the cluster registry. If the key exists, it is opened. If it does not exist, the call fails.
Arguments:
hKey - Supplies the key that the open is relative to.
lpSubKey - Supplies the key name relative to hKey
samDesired - Supplies desired security access mask
Status - Returns the error code if the function is unsuccessful.
Return Value:
A handle to the specified key if successful
NULL otherwise.
--*/
{ HDMKEY NewKey; PAPI_HANDLE Handle=NULL; PAPI_HANDLE RootHandle;
if (hKey != NULL) { RootHandle = (PAPI_HANDLE)hKey; if (RootHandle->Type != API_KEY_HANDLE) { *Status = ERROR_INVALID_HANDLE; return(NULL); } } else { *Status = ERROR_INVALID_HANDLE; return(NULL); }
*Status = RpcImpersonateClient(NULL); if (*Status != RPC_S_OK) { goto FnExit; }
NewKey = DmOpenKey(RootHandle->Key, lpSubKey, samDesired); if (NewKey == NULL) { *Status = GetLastError(); } else { Handle = ApipMakeKeyHandle(NewKey); if (Handle == NULL) { DmCloseKey(NewKey); *Status = ERROR_NOT_ENOUGH_MEMORY; } else { *Status = ERROR_SUCCESS; } } RpcRevertToSelf(); FnExit: return(Handle); }
error_status_t s_ApiEnumKey( IN HKEY_RPC hKey, IN DWORD dwIndex, OUT LPWSTR *KeyName, OUT PFILETIME lpftLastWriteTime )
/*++
Routine Description:
Enumerates the subkeys of a cluster registry key.
Arguments:
hKey - Supplies the registry key for which the subkeys should be enumerated.
dwIndex - Supplies the index to be enumerated.
KeyName - Returns the name of the dwIndex subkey. The memory allocated for this buffer must be freed by the client.
lpftLastWriteTime - Returns the last write time.
Return Value:
ERROR_SUCCESS if successful
Win32 error code otherwise
--*/
{ LONG Status; DWORD NameLength; HDMKEY DmKey;
VALIDATE_KEY(DmKey, hKey);
Status = DmQueryInfoKey(DmKey, NULL, &NameLength, NULL, NULL, NULL, NULL, NULL); if (Status != ERROR_SUCCESS) { return(Status); }
NameLength += 1;
*KeyName = MIDL_user_allocate(NameLength*sizeof(WCHAR)); if (*KeyName == NULL) { return(ERROR_NOT_ENOUGH_MEMORY); } Status = DmEnumKey(DmKey, dwIndex, *KeyName, &NameLength, lpftLastWriteTime); if (Status != ERROR_SUCCESS) { MIDL_user_free(*KeyName); *KeyName = NULL; } return(Status); }
DWORD s_ApiSetValue( IN HKEY_RPC hKey, IN LPCWSTR lpValueName, IN DWORD dwType, IN CONST UCHAR *lpData, IN DWORD cbData )
/*++
Routine Description:
This routine sets the named value for the specified cluster registry key.
Arguments:
hKey - Supplies the cluster registry subkey whose value is to be set
lpValueName - Supplies the name of the value to be set.
dwType - Supplies the value data type
lpData - Supplies a pointer to the value data
cbData - Supplies the length of the value data.
Return Value:
ERROR_SUCCESS if successful
Win32 error code otherwise
--*/
{ HDMKEY DmKey;
VALIDATE_KEY(DmKey, hKey); API_CHECK_INIT();
return(DmSetValue(DmKey, lpValueName, dwType, lpData, cbData)); }
DWORD s_ApiDeleteValue( IN HKEY_RPC hKey, IN LPCWSTR lpValueName )
/*++
Routine Description:
Removes the specified value from a given registry subkey
Arguments:
hKey - Supplies the key whose value is to be deleted.
lpValueName - Supplies the name of the value to be removed.
Return Value:
If the function succeeds, the return value is ERROR_SUCCESS.
If the function fails, the return value is an error value.
--*/
{ HDMKEY DmKey;
VALIDATE_KEY(DmKey, hKey); API_CHECK_INIT(); return(DmDeleteValue(DmKey, lpValueName)); }
error_status_t s_ApiQueryValue( IN HKEY_RPC hKey, IN LPCWSTR lpValueName, OUT LPDWORD lpValueType, OUT PUCHAR lpData, IN DWORD cbData, OUT LPDWORD lpcbRequired )
/*++
Routine Description:
Queries a named value for the specified cluster registry subkey
Arguments:
hKey - Supplies the subkey whose value should be queried
lpValueName - Supplies the named value to be queried
lpValueType - Returns the type of the value's data
lpData - Returns the value's data
cbData - Supplies the size (in bytes) of the lpData buffer Returns the number of bytes copied into the lpData buffer If lpData==NULL, cbData is set to the required buffer size and the function returns ERROR_SUCCESS
Return Value:
ERROR_SUCCESS if successful
Win32 error code otherwise
--*/
{ DWORD Status; DWORD BuffSize; HDMKEY DmKey;
VALIDATE_KEY(DmKey, hKey);
BuffSize = cbData; Status = DmQueryValue(DmKey, lpValueName, lpValueType, lpData, &BuffSize); if ((Status == ERROR_SUCCESS) || (Status == ERROR_MORE_DATA)) { *lpcbRequired = BuffSize; }
return(Status); }
DWORD s_ApiDeleteKey( IN HKEY hKey, IN LPCWSTR lpSubKey )
/*++
Routine Description:
Deletes the specified key. A key that has subkeys cannot be deleted.
Arguments:
hKey - Supplies a handle to a currently open key.
lpSubKey - Points to a null-terminated string specifying the name of the key to delete. This parameter cannot be NULL, and the specified key must not have subkeys.
Return Value:
If the function succeeds, the return value is ERROR_SUCCESS.
If the function fails, the return value is an error value.
--*/
{ HDMKEY DmKey;
VALIDATE_KEY(DmKey, hKey); API_CHECK_INIT(); return(DmDeleteKey(DmKey, lpSubKey)); }
error_status_t s_ApiEnumValue( IN HKEY_RPC hKey, IN DWORD dwIndex, OUT LPWSTR *lpValueName, OUT LPDWORD lpType, OUT UCHAR *lpData, IN OUT LPDWORD lpcbData, OUT LPDWORD TotalSize )
/*++
Routine Description:
Enumerates the specified value of a registry subkey
Arguments:
hKey - Supplies the registry key handle
dwIndex - Supplies the index of the value to be enumerated
lpValueName - Returns the name of the dwIndex'th value. The memory for this name is allocated on the server and must be freed by the client side.
lpType - Returns the value data type
lpData - Returns the value data
lpcbData - Returns the number of bytes written to the lpData buffer.
TotalSize - Returns the size of the data
Return Value:
ERROR_SUCCESS if successful
Win32 error code otherwise
--*/
{ LONG Status; DWORD OriginalNameLength; DWORD NameLength; DWORD DataLength; HDMKEY DmKey;
VALIDATE_KEY(DmKey, hKey);
Status = DmQueryInfoKey(DmKey, NULL, NULL, NULL, &NameLength, NULL, NULL, NULL); if (Status != ERROR_SUCCESS) { return(Status); } NameLength += 1;
*lpValueName = MIDL_user_allocate(NameLength * sizeof(WCHAR)); if (*lpValueName == NULL) { return(ERROR_NOT_ENOUGH_MEMORY); }
*TotalSize = *lpcbData;
//
// Chittur Subbaraman (chitturs) - 3/13/2001
//
// First of all, at the beginning of this function, a big enough buffer for lpValueName
// is allocated. This means that ERROR_SUCCESS or ERROR_MORE_DATA will be returned by
// DmEnumValue depending ONLY on the size of the lpData buffer. This info is used by
// by the clusapi layer when it makes a decision based on the return code from this
// function.
//
// Note that *TotalSize is initialized to *lpcbData just above. The TotalSize OUT variable
// allows the required lpData size to be returned without touching lpcbData. This is
// important since lpcbData is declared as the sizeof lpData in the IDL file and that is
// what RPC will consider the lpData buffer size as. So, it is important that if the lpData
// buffer is not big enough, this function does not change the value of *lpcbData from what
// it was originally at IN time.
//
// Strange behavior of RegEnumValue: If you supply a big enough buffer for lpValueName and
// a smaller than required buffer for lpData, then RegEnumValue won't bother to fill in
// lpValueName and will return ERROR_MORE_DATA. This irregular behavior is handled by
// DmEnumValue.
//
// For reference pointers, RPC won't allow a client to pass in NULL pointers. That is why
// clusapi layer uses dummy variables in case some of the parameters passed in by the
// client caller is NULL.
//
//
// Behavior of RegEnumValue (assuming lpValueName buffer is big enough):
// (1) If lpData = NULL and lpcbData = NULL, then returns ERROR_SUCCESS.
// (2) If lpData = NULL and lpcbData != NULL, then returns ERROR_SUCCESS and sets
// *lpcbData to total buffer size required.
// (3) If lpData != NULL and lpcbData != NULL, but the data buffer size is smaller than
// required size, then returns ERROR_MORE_DATA and sets *lpcbData to the size required.
// (4) If lpData != NULL and lpcbData != NULL and the buffer is big enough, then returns
// ERROR_SUCCESS and sets *lpcbData to the size of the data copied into lpData.
//
// OUR GOAL: ClusterRegEnumValue == RegEnumValue.
//
//
// The following cases are handled by this function and the clusapi layer. Note that in this
// analysis, we assume that the client has called into clusapi with a big enough lpValueName
// buffer size. (If this is not true, then clusapi layer handles that, check ClusterRegEnumValue.)
//
// Case 1: Client passes in lpData=NULL, lpcbData=NULL to ClusterRegEnumValue.
//
// In this case, the clusapi layer will point both lpData and lpcbData to local dummy
// variables and initialize *lpcbData to 0. Thus, s_ApiEnumValue will see
// both lpData and lpcbData as valid pointers. If the data value is bigger than the size of
// *lpcbData, then DmEnumValue will return ERROR_MORE_DATA. In this case, *TotalSize will
// contain the required buffer size and *lpcbData will be untouched. The client detects this
// error code and sets the return status to ERROR_SUCCESS and *lpcbData to *TotalSize. Note
// that the 2nd action has less relevance since lpcbData is pointing to a local dummy variable.
// If the data value is of zero size, DmEnumValue will return ERROR_SUCCESS.
// In such a case, *lpcbData will be set to *TotalSize before returning by this function.
// Note that since the data size is 0, DmEnumValue would set *TotalSize to 0 and hence
// *lpcbData will also be set to 0. Thus, in this case, when ApiEnumValue returns to the
// clusapi layer, lpValueName will be filled in, *lpData will not be changed and *lpcbData
// will be set to 0.
//
// Case 2: Client passes in lpData=NULL, lpcbData!=NULL and *lpcbData=0 to ClusterRegEnumValue.
//
// In this case, lpData alone will be pointing to a dummy clusapi buffer when ApiEnumValue
// is invoked. Thus, s_ApiEnumValue will get both lpData and lpcbData as valid pointers.
// If the data size is non-zero, then DmEnumValue will return ERROR_MORE_DATA and
// *TotalSize will contain the size of the required buffer. When this function returns,
// *lpcbData will remain untouched. As in case 1, the clusapi layer will set status
// to ERROR_SUCCESS and *lpcbData to *TotalSize. Thus, the client will see the required
// buffer size in *lpcbData. If the data size is zero, then it is handled as in case 1.
//
// Case 3: Client passes in lpData!=NULL, lpcbData!=NULL, but the data buffer size is smaller than
// required.
//
// In this case, both lpData and lpcbData will be pointing to client buffers (or RPC buffers
// representing them) at the entry to s_ApiEnumValue. DmEnumValue will return ERROR_MORE_DATA
// and this function will return the size required in *TotalSize. *lpcbData will not be
// touched. At the clusapi layer, *lpcbData will be set to *TotalSize and ERROR_MORE_DATA
// will be returned to the client.
//
// Case 4: Client passes in lpData!=NULL, lpcbData!=NULL and the data buffer size is big enough.
//
// In this case, as in case 3, s_ApiEnumValue will have lpData and lpcbData pointing to
// client buffers. DmEnumValue will return ERROR_SUCCESS, data copied to lpData and
// *lpcbData will be set to *TotalSize (which is the size of the data copied into the
// lpData buffer), before returning. The clusapi layer will return these values to the client.
//
Status = DmEnumValue(DmKey, dwIndex, *lpValueName, &NameLength, lpType, lpData, TotalSize);
if (Status == ERROR_MORE_DATA) { return(Status); } else if (Status != ERROR_SUCCESS) { MIDL_user_free(*lpValueName); *lpValueName = NULL; *lpcbData = 0; } else { // This tells RPC how big the lpData buffer
// is so it can copy the buffer to the client.
*lpcbData = *TotalSize; } return(Status); }
error_status_t s_ApiQueryInfoKey( IN HKEY_RPC hKey, OUT LPDWORD lpcSubKeys, OUT LPDWORD lpcbMaxSubKeyLen, OUT LPDWORD lpcValues, OUT LPDWORD lpcbMaxValueNameLen, OUT LPDWORD lpcbMaxValueLen, OUT LPDWORD lpcbSecurityDescriptor, OUT PFILETIME lpftLastWriteTime ) /*++
Routine Description:
Retrieves information about a specified cluster registry key.
Arguments:
hKey - Supplies the handle of the key.
lpcSubKeys - Points to a variable that receives the number of subkeys contained by the specified key.
lpcbMaxSubKeyLen - Points to a variable that receives the length, in characters, of the key's subkey with the longest name. The count returned does not include the terminating null character.
lpcValues - Points to a variable that receives the number of values associated with the key.
lpcbMaxValueNameLen - Points to a variable that receives the length, in characters, of the key's longest value name. The count returned does not include the terminating null character.
lpcbMaxValueLen - Points to a variable that receives the length, in bytes, of the longest data component among the key's values.
lpcbSecurityDescriptor - Points to a variable that receives the length, in bytes, of the key's security descriptor.
lpftLastWriteTime - Pointer to a FILETIME structure.
Return Value:
ERROR_SUCCESS if successful
Win32 error code otherwise
--*/
{ HDMKEY DmKey; DWORD Status;
VALIDATE_KEY(DmKey, hKey);
Status = DmQueryInfoKey(DmKey, lpcSubKeys, lpcbMaxSubKeyLen, lpcValues, lpcbMaxValueNameLen, lpcbMaxValueLen, lpcbSecurityDescriptor, lpftLastWriteTime); return(Status); }
error_status_t s_ApiCloseKey( IN OUT HKEY_RPC *pKey )
/*++
Routine Description:
Closes a cluster registry key
Arguments:
pKey - Supplies the key to be closed Returns NULL
Return Value:
None.
--*/
{ HDMKEY DmKey; DWORD Status;
VALIDATE_KEY(DmKey, *pKey);
Status = RpcImpersonateClient(NULL); if (Status != ERROR_SUCCESS) { return(Status); } Status = DmCloseKey(DmKey); RpcRevertToSelf();
LocalFree(*pKey); *pKey = NULL;
return(Status); }
void HKEY_RPC_rundown( IN HKEY_RPC Key )
/*++
Routine Description:
RPC rundown routine for cluster registry keys
Arguments:
Key - Supplies the handle to be rundown
Return Value:
None.
--*/
{ HDMKEY DmKey;
//this should not call impersonate client
if ((Key != NULL) && (((PAPI_HANDLE)(Key))->Type == API_KEY_HANDLE)) { DmKey = ((PAPI_HANDLE)(Key))->Key; DmCloseKey(DmKey); LocalFree(Key); } }
DWORD s_ApiSetKeySecurity( IN HKEY hKey, IN DWORD SecurityInformation, IN PRPC_SECURITY_DESCRIPTOR pRpcSecurityDescriptor )
/*++
Routine Description:
Sets the security on the specified registry key.
Arguments:
hKey - Supplies a handle to a currently open key.
SecurityInformation - Supplies the type of security information to be set.
pRpcSecurityDescriptor - Supplies the security information
Return Value:
If the function succeeds, the return value is ERROR_SUCCESS.
If the function fails, the return value is an error value.
--*/
{ HDMKEY DmKey; DWORD Status; PSECURITY_DESCRIPTOR pSecurityDescriptor;
VALIDATE_KEY(DmKey, hKey); API_CHECK_INIT();
pSecurityDescriptor = pRpcSecurityDescriptor->lpSecurityDescriptor; if (!RtlValidRelativeSecurityDescriptor( pSecurityDescriptor, pRpcSecurityDescriptor->cbInSecurityDescriptor,0)){ return(ERROR_INVALID_PARAMETER); } Status = RpcImpersonateClient(NULL); if (Status != ERROR_SUCCESS) { return(Status); } Status = DmSetKeySecurity(DmKey, SecurityInformation, pSecurityDescriptor); RpcRevertToSelf(); return(Status); }
DWORD s_ApiGetKeySecurity( IN HKEY hKey, IN DWORD SecurityInformation, IN OUT PRPC_SECURITY_DESCRIPTOR pRpcSecurityDescriptor )
/*++
Routine Description:
Gets the security from the specified registry key.
Arguments:
hKey - Supplies a handle to a currently open key.
SecurityInformation - Supplies the type of security information to be retrieved.
pRpcSecurityDescriptor - Returns the security information
Return Value:
If the function succeeds, the return value is ERROR_SUCCESS.
If the function fails, the return value is an error value.
--*/
{ HDMKEY DmKey; DWORD cbLength; DWORD Status; PSECURITY_DESCRIPTOR lpSD;
VALIDATE_KEY(DmKey, hKey); API_CHECK_INIT();
cbLength = pRpcSecurityDescriptor->cbInSecurityDescriptor; lpSD = LocalAlloc(LMEM_FIXED, cbLength); if (lpSD == NULL) { return(ERROR_NOT_ENOUGH_MEMORY); }
Status = RpcImpersonateClient(NULL); if (Status != ERROR_SUCCESS) { LocalFree(lpSD); return(Status); } Status = DmGetKeySecurity(DmKey, SecurityInformation, lpSD, &cbLength); RpcRevertToSelf(); if (Status == ERROR_SUCCESS) { Status = MapSDToRpcSD(lpSD, pRpcSecurityDescriptor); } if (Status != ERROR_SUCCESS) { pRpcSecurityDescriptor->cbInSecurityDescriptor = cbLength; pRpcSecurityDescriptor->cbOutSecurityDescriptor = 0; }
LocalFree(lpSD); return(Status); }
|