/*++ Copyright (c) 1996 Microsoft Corporation Module Name: registry.c Abstract: Provides interface for managing cluster registry Author: John Vert (jvert) 19-Jan-1996 Revision History: --*/ #include "clusapip.h" // // Function prototypes for routines local to this module // VOID FreeKey( IN PCKEY Key ); HKEY OpenClusterRelative( IN HCLUSTER hCluster, IN LPCWSTR RelativeName, IN LPCWSTR SpecificName, IN DWORD samDesired ); HKEY WINAPI GetClusterKey( IN HCLUSTER hCluster, IN REGSAM samDesired ) /*++ Routine Description: Opens the the root of the cluster registry subtree for the given cluster. Arguments: hCluster - Supplies a handle to the cluster samDesired - Specifies an access mask that describes the desired security access for the new key. Return Value: A cluster registry key handle to the root of the registry subtree for the given cluster If unsuccessful, NULL is returned and GetLastError() provides the specific error code. --*/ { PCLUSTER Cluster = (PCLUSTER)hCluster; PCKEY Key; error_status_t Status = ERROR_SUCCESS; // // Allocate new CKEY structure and connect to cluster registry. // Key = LocalAlloc(LMEM_FIXED, sizeof(CKEY)); if (Key == NULL) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); return(NULL); } Key->Parent = NULL; Key->RelativeName = NULL; Key->SamDesired = samDesired; Key->Cluster = Cluster; InitializeListHead(&Key->ChildList); InitializeListHead(&Key->NotifyList); WRAP_NULL(Key->RemoteKey, (ApiGetRootKey(Cluster->RpcBinding, samDesired, &Status)), &Status, Cluster); if ((Key->RemoteKey == NULL) || (Status != ERROR_SUCCESS)) { LocalFree(Key); SetLastError(Status); return(NULL); } EnterCriticalSection(&Cluster->Lock); InsertHeadList(&Cluster->KeyList, &Key->ParentList); LeaveCriticalSection(&Cluster->Lock); return((HKEY)Key); } HKEY WINAPI GetClusterNodeKey( IN HNODE hNode, IN REGSAM samDesired ) /*++ Routine Description: Opens the the root of the cluster registry subtree for the given node Arguments: hNode - Supplies a handle to the node samDesired - Specifies an access mask that describes the desired security access for the new key. Return Value: A cluster registry key handle to the root of the registry subtree for the given node If unsuccessful, NULL is returned and GetLastError() provides the specific error code. --*/ { PCNODE Node = (PCNODE)hNode; HCLUSTER Cluster = (HCLUSTER)Node->Cluster; DWORD Status; LPWSTR Guid=NULL; HKEY NodeKey; WRAP(Status, (ApiGetNodeId(Node->hNode, &Guid)), Node->Cluster); if (Status != ERROR_SUCCESS) { SetLastError(Status); return(NULL); } NodeKey = OpenClusterRelative(Cluster, CLUSREG_KEYNAME_NODES, Guid, samDesired); if (NodeKey == NULL) { Status = GetLastError(); } MIDL_user_free(Guid); if (NodeKey == NULL) { SetLastError(Status); } return(NodeKey); } HKEY WINAPI GetClusterGroupKey( IN HGROUP hGroup, IN REGSAM samDesired ) /*++ Routine Description: Opens the the root of the cluster registry subtree for the given group Arguments: hResource - Supplies a handle to the group samDesired - Specifies an access mask that describes the desired security access for the new key. Return Value: A cluster registry key handle to the root of the registry subtree for the given group If unsuccessful, NULL is returned and GetLastError() provides the specific error code. --*/ { PCGROUP Group = (PCGROUP)hGroup; HCLUSTER Cluster = (HCLUSTER)Group->Cluster; DWORD Status; LPWSTR Guid=NULL; HKEY GroupKey; WRAP(Status, (ApiGetGroupId(Group->hGroup, &Guid)), Group->Cluster); if (Status != ERROR_SUCCESS) { SetLastError(Status); return(NULL); } GroupKey = OpenClusterRelative(Cluster, CLUSREG_KEYNAME_GROUPS, Guid, samDesired); if (GroupKey == NULL) { Status = GetLastError(); } MIDL_user_free(Guid); if (GroupKey == NULL) { SetLastError(Status); } return(GroupKey); } HKEY WINAPI GetClusterResourceKey( IN HRESOURCE hResource, IN REGSAM samDesired ) /*++ Routine Description: Opens the the root of the cluster registry subtree for the given resource. Arguments: hResource - Supplies a handle to the resource samDesired - Specifies an access mask that describes the desired security access for the new key. Return Value: A cluster registry key handle to the root of the registry subtree for the given resource If unsuccessful, NULL is returned and GetLastError() provides the specific error code. --*/ { PCRESOURCE Resource = (PCRESOURCE)hResource; HCLUSTER Cluster = (HCLUSTER)Resource->Cluster; DWORD Status; LPWSTR Guid=NULL; HKEY ResKey; WRAP(Status, (ApiGetResourceId(Resource->hResource, &Guid)), Resource->Cluster); if (Status != ERROR_SUCCESS) { SetLastError(Status); return(NULL); } ResKey = OpenClusterRelative(Cluster, CLUSREG_KEYNAME_RESOURCES, Guid, samDesired); if (ResKey == NULL) { Status = GetLastError(); } MIDL_user_free(Guid); if (ResKey == NULL) { SetLastError(Status); } return(ResKey); } HKEY WINAPI GetClusterResourceTypeKey( IN HCLUSTER hCluster, IN LPCWSTR lpszTypeName, IN REGSAM samDesired ) /*++ Routine Description: Opens the the root of the cluster registry subtree for the given resource type. Arguments: hCluster - Supplies the cluster the open is relative to. lpszTypeName - Supplies the resource type name. samDesired - Specifies an access mask that describes the desired security access for the new key. Return Value: A cluster registry key handle to the root of the registry subtree for the given resource type. If unsuccessful, NULL is returned and GetLastError() provides the specific error code. --*/ { return(OpenClusterRelative(hCluster, CLUSREG_KEYNAME_RESOURCE_TYPES, lpszTypeName, samDesired)); } HKEY WINAPI GetClusterNetworkKey( IN HNETWORK hNetwork, IN REGSAM samDesired ) /*++ Routine Description: Opens the the root of the cluster registry subtree for the given network. Arguments: hNetwork - Supplies a handle to the network. samDesired - Specifies an access mask that describes the desired security access for the new key. Return Value: A cluster registry key handle to the root of the registry subtree for the given network. If unsuccessful, NULL is returned and GetLastError() provides the specific error code. --*/ { PCNETWORK Network = (PCNETWORK)hNetwork; HCLUSTER Cluster = (HCLUSTER)Network->Cluster; DWORD Status; LPWSTR Guid=NULL; HKEY NetworkKey; WRAP(Status, (ApiGetNetworkId(Network->hNetwork, &Guid)), Network->Cluster); if (Status != ERROR_SUCCESS) { SetLastError(Status); return(NULL); } NetworkKey = OpenClusterRelative(Cluster, CLUSREG_KEYNAME_NETWORKS, Guid, samDesired); if (NetworkKey == NULL) { Status = GetLastError(); } MIDL_user_free(Guid); if (NetworkKey == NULL) { SetLastError(Status); } return(NetworkKey); } HKEY WINAPI GetClusterNetInterfaceKey( IN HNETINTERFACE hNetInterface, IN REGSAM samDesired ) /*++ Routine Description: Opens the the root of the cluster registry subtree for the given network interface. Arguments: hNetInterface - Supplies a handle to the network interface. samDesired - Specifies an access mask that describes the desired security access for the new key. Return Value: A cluster registry key handle to the root of the registry subtree for the given network interface. If unsuccessful, NULL is returned and GetLastError() provides the specific error code. --*/ { PCNETINTERFACE NetInterface = (PCNETINTERFACE)hNetInterface; HCLUSTER Cluster = (HCLUSTER)NetInterface->Cluster; DWORD Status; LPWSTR Guid=NULL; HKEY NetInterfaceKey; WRAP(Status, (ApiGetNetInterfaceId(NetInterface->hNetInterface, &Guid)), NetInterface->Cluster); if (Status != ERROR_SUCCESS) { SetLastError(Status); return(NULL); } NetInterfaceKey = OpenClusterRelative(Cluster, CLUSREG_KEYNAME_NETINTERFACES, Guid, samDesired); if (NetInterfaceKey == NULL) { Status = GetLastError(); } MIDL_user_free(Guid); if (NetInterfaceKey == NULL) { SetLastError(Status); } return(NetInterfaceKey); } HKEY OpenClusterRelative( IN HCLUSTER Cluster, IN LPCWSTR RelativeName, IN LPCWSTR SpecificName, IN DWORD samDesired ) /*++ Routine Description: Helper routine for the functions that open cluster object keys. (GetCluster*Key) Arguments: Cluster - Supplies the cluster the key should be opened in. RelativeName - Supplies the first part of the relative name (i.e. L"Resources") SpecificName - Supplies the name of the object. Return Value: An open registry key if successful NULL if unsuccessful. LastError will be set to a Win32 error code --*/ { LPWSTR Buff; HKEY ClusterKey; HKEY Key; LONG Status; Buff = LocalAlloc(LMEM_FIXED, (lstrlenW(RelativeName)+lstrlenW(SpecificName)+2)*sizeof(WCHAR)); if ( Buff == NULL ) { return(NULL); } lstrcpyW(Buff, RelativeName); lstrcatW(Buff, L"\\"); lstrcatW(Buff, SpecificName); ClusterKey = GetClusterKey(Cluster, KEY_READ); if (ClusterKey == NULL) { Status = GetLastError(); LocalFree(Buff); SetLastError(Status); return(NULL); } Status = ClusterRegOpenKey(ClusterKey, Buff, samDesired, &Key); LocalFree(Buff); ClusterRegCloseKey(ClusterKey); if (Status == ERROR_SUCCESS) { return(Key); } else { SetLastError(Status); return(NULL); } } LONG WINAPI ClusterRegCreateKey( IN HKEY hKey, IN LPCWSTR lpSubKey, IN DWORD dwOptions, IN REGSAM samDesired, IN LPSECURITY_ATTRIBUTES lpSecurityAttributes, OUT PHKEY phkResult, OUT OPTIONAL LPDWORD lpdwDisposition ) /*++ Routine Description: Creates the specified key in the cluster registry. If the key already exists in the registry, the function opens it. Arguments: hKey - Supplies a currently open key. lpSubKey - Points to a null-terminated string specifying the name of a subkey that this function opens or creates. The subkey specified must be a subkey of the key identified by the hKey parameter. This subkey must not begin with the backslash character ('\'). This parameter cannot be NULL. dwOptions - Specifies special options for this key. Valid options are: REG_OPTION_VOLATILE - This key is volatile; the information is stored in memory and is not preserved when the system is restarted. samDesired - Specifies an access mask that specifies the desired security access for the new key lpSecurityAttributes - The lpSecurityDescriptor member of the structure specifies a security descriptor for the new key. If lpSecurityAttributes is NULL, the key gets a default security descriptor. Since cluster registry handles are not inheritable, the bInheritHandle field of the SECURITY_ATTRIBUTES structure must be FALSE. phkResult - Points to a variable that receives the handle of the opened or created key lpdwDisposition - Points to a variable that receives one of the following disposition values: Value Meaning REG_CREATED_NEW_KEY The key did not exist and was created. REG_OPENED_EXISTING_KEY The key existed and was simply opened without being changed. Return Value: If the function succeeds, the return value is ERROR_SUCCESS. If the function fails, the return value is an error value. --*/ { PCKEY Key; PCKEY ParentKey = (PCKEY)hKey; PCLUSTER Cluster = ParentKey->Cluster; PRPC_SECURITY_ATTRIBUTES pRpcSA; RPC_SECURITY_ATTRIBUTES RpcSA; error_status_t Status = ERROR_SUCCESS; DWORD Disposition; if (lpdwDisposition == NULL) { lpdwDisposition = &Disposition; } // // Allocate new CKEY structure and create cluster registry key // Key = LocalAlloc(LMEM_FIXED, sizeof(CKEY)); if (Key == NULL) { return(ERROR_NOT_ENOUGH_MEMORY); } Key->Parent = ParentKey; Key->RelativeName = LocalAlloc(LMEM_FIXED, (lstrlenW(lpSubKey)+1)*sizeof(WCHAR)); if (Key->RelativeName == NULL) { LocalFree(Key); return(ERROR_NOT_ENOUGH_MEMORY); } lstrcpyW(Key->RelativeName, lpSubKey); Key->SamDesired = samDesired; Key->Cluster = Cluster; InitializeListHead(&Key->ChildList); InitializeListHead(&Key->NotifyList); if( ARGUMENT_PRESENT( lpSecurityAttributes )) { DWORD Error; pRpcSA = &RpcSA; Error = MapSAToRpcSA( lpSecurityAttributes, pRpcSA ); if( Error != ERROR_SUCCESS ) { LocalFree(Key->RelativeName); LocalFree(Key); return Error; } } else { // // No PSECURITY_ATTRIBUTES argument, therefore no mapping was done. // pRpcSA = NULL; } WRAP_NULL(Key->RemoteKey, (ApiCreateKey(ParentKey->RemoteKey, lpSubKey, dwOptions, samDesired, pRpcSA, lpdwDisposition, &Status)), &Status, ParentKey->Cluster); // // Free the RPC_SECURITY_DESCRIPTOR buffer allocated by MapSAToRpcSA. // if ( pRpcSA ) { // // RtlFreeHeap accepts a NULL base address // RtlFreeHeap( RtlProcessHeap(), 0, pRpcSA->RpcSecurityDescriptor.lpSecurityDescriptor ); } if ((Key->RemoteKey == NULL) || (Status != ERROR_SUCCESS)) { *phkResult = NULL; LocalFree(Key->RelativeName); LocalFree(Key); return(Status); } EnterCriticalSection(&Cluster->Lock); InsertHeadList(&ParentKey->ChildList, &Key->ParentList); LeaveCriticalSection(&Cluster->Lock); *phkResult = (HKEY)Key; return(ERROR_SUCCESS); } LONG WINAPI ClusterRegOpenKey( IN HKEY hKey, IN LPCWSTR lpSubKey, IN REGSAM samDesired, OUT PHKEY phkResult ) /*++ Routine Description: Opens the specified key in the cluster registry. Arguments: hKey - Supplies a currently open key. lpSubKey - Points to a null-terminated string specifying the name of a subkey that this function opens or creates. The subkey specified must be a subkey of the key identified by the hKey parameter. This subkey must not begin with the backslash character ('\'). This parameter cannot be NULL. samDesired - Specifies an access mask that specifies the desired security access for the new key phkResult - Points to a variable that receives the handle of the opened or created key. Initialized to NULL on failure. Return Value: If the function succeeds, the return value is ERROR_SUCCESS. If the function fails, the return value is an error value. --*/ { PCKEY Key; PCKEY ParentKey = (PCKEY)hKey; PCLUSTER Cluster = ParentKey->Cluster; error_status_t Status = ERROR_SUCCESS; // // Allocate new CKEY structure and create cluster registry key // Key = LocalAlloc(LMEM_FIXED, sizeof(CKEY)); if (Key == NULL) { return(ERROR_NOT_ENOUGH_MEMORY); } *phkResult = NULL; Key->Parent = ParentKey; Key->RelativeName = LocalAlloc(LMEM_FIXED, (lstrlenW(lpSubKey)+1)*sizeof(WCHAR)); if (Key->RelativeName == NULL) { LocalFree(Key); return(ERROR_NOT_ENOUGH_MEMORY); } lstrcpyW(Key->RelativeName, lpSubKey); Key->SamDesired = samDesired; Key->Cluster = Cluster; InitializeListHead(&Key->ChildList); InitializeListHead(&Key->NotifyList); WRAP_NULL(Key->RemoteKey, (ApiOpenKey(ParentKey->RemoteKey, lpSubKey, samDesired, &Status)), &Status, ParentKey->Cluster); if (Status != ERROR_SUCCESS) { LocalFree(Key->RelativeName); LocalFree(Key); return(Status); } EnterCriticalSection(&Cluster->Lock); InsertHeadList(&ParentKey->ChildList, &Key->ParentList); LeaveCriticalSection(&Cluster->Lock); *phkResult = (HKEY)Key; return(ERROR_SUCCESS); } LONG WINAPI ClusterRegDeleteKey( 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. --*/ { PCKEY Key = (PCKEY)hKey; DWORD Status; WRAP(Status, (ApiDeleteKey(Key->RemoteKey, lpSubKey)), Key->Cluster); return(Status); } LONG WINAPI ClusterRegCloseKey( IN HKEY hKey ) /*++ Routine Description: Closes the handle of the specified cluster registry key Arguments: hKey - Supplies the open key to close Return Value: If the function succeeds, the return value is ERROR_SUCCESS. If the function fails, the return value is an error value. --*/ { PCKEY Key = (PCKEY)hKey; PCLUSTER Cluster = Key->Cluster; // // If any keys have been opened relative to this key, we need to // keep this CKEY around so that we can reconstruct the key names // if we need to reopen the handles. // // If there are no children of this key, all the storage can be // freed. Note that freeing this key may also require us to free // up its parent if the parent has been closed but not freed because // it has children. // EnterCriticalSection(&Cluster->Lock); if (Cluster->Flags & CLUS_DEAD) { if (Key->RemoteKey) RpcSmDestroyClientContext(&Key->RemoteKey); } else { ApiCloseKey(&Key->RemoteKey); } // // Remove any notifications posted against this key. // RundownNotifyEvents(&Key->NotifyList, L""); if (IsListEmpty(&Key->ChildList)) { FreeKey(Key); } LeaveCriticalSection(&Cluster->Lock); // // If this key was the last thing keeping the cluster structure // around, we can clean it up now. // CleanupCluster(Cluster); return(ERROR_SUCCESS); } VOID FreeKey( IN PCKEY Key ) /*++ Routine Description: Frees up the storage for a key and removes it from its parent's ChildList. If this is the last key in its parent's ChildList, this routine calls itself recursively to free the parent storage. Arguments: Key - Supplies the CKEY to be freed. Return Value: None. --*/ { RemoveEntryList(&Key->ParentList); if (Key->Parent != NULL) { // // This is not a root key, so see if we need to free the // parent. // if ((Key->Parent->RemoteKey == NULL) && (IsListEmpty(&Key->Parent->ChildList))) { FreeKey(Key->Parent); } LocalFree(Key->RelativeName); } LocalFree(Key); } LONG WINAPI ClusterRegEnumKey( IN HKEY hKey, IN DWORD dwIndex, OUT LPWSTR lpszName, IN OUT LPDWORD lpcchName, OUT PFILETIME lpftLastWriteTime ) /*++ Routine Description: Enumerates subkeys of the specified open cluster registry key. The function retrieves information about one subkey each time it is called. Arguments: hKey - Supplies a currently open key or NULL. If NULL is specified, the root of the cluster registry is enumerated. dwIndex - Supplies the index of the subkey to retrieve. This parameter should be zero for the first call to the RegEnumKeyEx function and then incremented for subsequent calls. Because subkeys are not ordered, any new subkey will have an arbitrary index. This means that the function may return subkeys in any order. lpszName - Points to a buffer that receives the name of the subkey, including the terminating null character. The function copies only the name of the subkey, not the full key hierarchy, to the buffer. lpcchName - Points to a variable that specifies the size, in characters, of the buffer specified by the lpszName parameter. This size should include the terminating null character. When the function returns, the variable pointed to by lpcchName contains the number of characters stored in the buffer. The count returned does not include the terminating null character. lpftLastWriteTime - Points to a variable that receives the time the enumerated subkey was last written to. Return Value: If the function succeeds, the return value is ERROR_SUCCESS. If the function fails, the return value is an error value. --*/ { PCKEY Key = (PCKEY)hKey; LONG Status; FILETIME LastWriteTime; LPWSTR KeyName=NULL; DWORD dwNameLen; WRAP(Status, (ApiEnumKey(Key->RemoteKey, dwIndex, &KeyName, &LastWriteTime)), Key->Cluster); if (Status != ERROR_SUCCESS) { return(Status); } MylstrcpynW(lpszName, KeyName, *lpcchName); dwNameLen = lstrlenW(KeyName); if (*lpcchName < (dwNameLen + 1)) { if (lpszName != NULL) { Status = ERROR_MORE_DATA; } } *lpcchName = dwNameLen; MIDL_user_free(KeyName); return(Status); } DWORD WINAPI ClusterRegSetValue( IN HKEY hKey, IN LPCWSTR lpszValueName, IN DWORD dwType, IN CONST BYTE* lpData, IN DWORD cbData ) /*++ Routine Description: Sets the named value for the given resource. Arguments: hKey - Supplies the handle of the cluster registry key. lpszValueName - Supplies a pointer to a string containing the name of the value to set. If a value with this name is not already present in the resource, the function adds it to the resource. dwType - Supplies the type of information to be stored as the value's data. This parameter can be one of the following values: Value Meaning REG_BINARY Binary data in any form. REG_DWORD A 32-bit number. REG_EXPAND_SZ A null-terminated Unicode string that contains unexpanded references to environment variables (for example, "%PATH%"). REG_MULTI_SZ An array of null-terminated Unicode strings, terminated by two null characters. REG_NONE No defined value type. REG_SZ A null-terminated Unicode string. lpData - Supplies a pointer to a buffer containing the data to be stored with the specified value name. cbData - Supplies the size, in bytes, of the information pointed to by the lpData parameter. If the data is of type REG_SZ, REG_EXPAND_SZ, or REG_MULTI_SZ, cbData must include the size of the terminating null character. Return value: If the function succeeds, the return value is ERROR_SUCCESS. If the function fails, the return value is an error value. --*/ { PCKEY Key = (PCKEY)hKey; DWORD Status; WRAP(Status, (ApiSetValue(Key->RemoteKey, lpszValueName, dwType, lpData, cbData)), Key->Cluster); return(Status); } DWORD WINAPI ClusterRegDeleteValue( IN HKEY hKey, IN LPCWSTR lpszValueName ) /*++ Routine Description: Removes the specified value from a given registry subkey Arguments: hKey - Supplies the key whose value is to be deleted. lpszValueName - 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. --*/ { PCKEY Key = (PCKEY)hKey; DWORD Status; WRAP(Status, (ApiDeleteValue(Key->RemoteKey, lpszValueName)), Key->Cluster); return(Status); } LONG WINAPI ClusterRegQueryValue( IN HKEY hKey, IN LPCWSTR lpszValueName, OUT LPDWORD lpdwValueType, OUT LPBYTE lpData, IN OUT LPDWORD lpcbData ) /*++ Routine Description: Retrieves the type and data for a specified value name associated with an open cluster registry key. Arguments: hKey - Supplies the handle of the cluster registry key. lpszValueName - Supplies a pointer to a string containing the name of the value to be queried. lpdwValueType - Points to a variable that receives the key's value type. The value returned through this parameter will be one of the following: Value Meaning REG_BINARY Binary data in any form. REG_DWORD A 32-bit number. REG_EXPAND_SZ A null-terminated Unicode string that contains unexpanded references to environment variables (for example, "%PATH%"). REG_MULTI_SZ An array of null-terminated Unicode strings, terminated by two null characters. REG_NONE No defined value type. REG_SZ A null-terminated Unicode string. The lpdwValueType parameter can be NULL if the type is not required lpData - Points to a buffer that receives the value's data. This parameter can be NULL if the data is not required. lpcbData - Points to a variable that specifies the size, in bytes, of the buffer pointed to by the lpData parameter. When the function returns, this variable contains the size of the data copied to lpData. If the buffer specified by lpData parameter is not large enough to hold the data, the function returns the value ERROR_MORE_DATA, and stores the required buffer size, in bytes, into the variable pointed to by lpcbData. If lpData is NULL, and lpcbData is non-NULL, the function returns ERROR_SUCCESS, and stores the size of the data, in bytes, in the variable pointed to by lpcbData. This lets an application determine the best way to allocate a buffer for the value key's data. If the data has the REG_SZ, REG_MULTI_SZ or REG_EXPAND_SZ type, then lpData will also include the size of the terminating null character. The lpcbData parameter can be NULL only if lpData is NULL. Return Value: If the function succeeds, the return value is ERROR_SUCCESS. If the function fails, the return value is an error value. --*/ { DWORD Dummy1; DWORD Dummy2; DWORD Required; PCKEY Key = (PCKEY)hKey; DWORD Status; LPBYTE TempData; DWORD BufferSize; if (lpdwValueType == NULL) { lpdwValueType = &Dummy1; } if (lpData == NULL) { TempData = (LPBYTE)&Dummy2; BufferSize = 0; } else { TempData = lpData; BufferSize = *lpcbData; } WRAP(Status, (ApiQueryValue(Key->RemoteKey, lpszValueName, lpdwValueType, TempData, BufferSize, &Required)), Key->Cluster); if ((Status == ERROR_SUCCESS) || (Status == ERROR_MORE_DATA)) { if ((Status == ERROR_MORE_DATA) && (lpData == NULL)) { // // Map this error to success to match the spec. // Status = ERROR_SUCCESS; } *lpcbData = Required; } return(Status); } DWORD WINAPI ClusterRegEnumValue( IN HKEY hKey, IN DWORD dwIndex, OUT LPWSTR lpszValueName, IN OUT LPDWORD lpcchValueName, IN LPDWORD lpdwType, OUT LPBYTE lpData, IN OUT LPDWORD lpcbData ) /*++ Routine Description: Enumerates the properties of the given resource. Arguments: hKey - Supplies the handle of the key dwIndex - Specifies the index of the value to retrieve. This parameter should be zero for the first call to the EnumClusterResourceValue function and then be incremented for subsequent calls. Because properties are not ordered, any new value will have an arbitrary index. This means that the function may return properties in any order. lpszValueName - Points to a buffer that receives the name of the value, including the terminating null character. lpcchValueName - Points to a variable that specifies the size, in characters, of the buffer pointed to by the lpszValueName parameter. This size should include the terminating null character. When the function returns, the variable pointed to by lpcchValueName contains the number of characters stored in the buffer. The count returned does not include the terminating null character. lpdwType - Points to a variable that receives the type code for the value entry. The type code can be one of the following values: Value Meaning REG_BINARY Binary data in any form. REG_DWORD A 32-bit number. REG_EXPAND_SZ A null-terminated Unicode string that contains unexpanded references to environment variables (for example, "%PATH%"). REG_MULTI_SZ An array of null-terminated Unicode strings, terminated by two null characters. REG_NONE No defined value type. REG_SZ A null-terminated Unicode string. The lpdwType parameter can be NULL if the type code is not required. lpData - Points to a buffer that receives the data for the value entry. This parameter can be NULL if the data is not required. lpcbData - Points to a variable that specifies the size, in bytes, of the buffer pointed to by the lpData parameter. When the function returns, the variable pointed to by the lpcbData parameter contains the number of bytes stored in the buffer. This parameter can be NULL only if lpData is NULL. Return Value: If the function succeeds, the return value is ERROR_SUCCESS. If the function fails, the return value is an error value. --*/ { PCKEY Key = (PCKEY)hKey; LONG Status; LPWSTR ValueName=NULL; DWORD TotalSize; DWORD DummyType; BYTE DummyData; DWORD DummycbData; DWORD dwNameLen; if (lpdwType == NULL) { lpdwType = &DummyType; } if (lpcbData == NULL) { if (lpData != NULL) { return(ERROR_INVALID_PARAMETER); } DummycbData = 0; lpcbData = &DummycbData; } if (lpData == NULL) { lpData = &DummyData; } WRAP(Status, (ApiEnumValue(Key->RemoteKey, dwIndex, &ValueName, lpdwType, lpData, lpcbData, &TotalSize)), Key->Cluster); if ((Status != ERROR_SUCCESS) && (Status != ERROR_MORE_DATA)) { return(Status); } if (Status == ERROR_MORE_DATA) { *lpcbData = TotalSize; if (lpData == &DummyData) { Status = ERROR_SUCCESS; } } MylstrcpynW(lpszValueName, ValueName, *lpcchValueName); dwNameLen = lstrlenW(ValueName); if (*lpcchValueName < (dwNameLen + 1)) { if (lpszValueName != NULL) { Status = ERROR_MORE_DATA; } } *lpcchValueName = dwNameLen; MIDL_user_free(ValueName); return(Status); } LONG WINAPI ClusterRegQueryInfoKey( HKEY hKey, LPDWORD lpcSubKeys, LPDWORD lpcchMaxSubKeyLen, LPDWORD lpcValues, LPDWORD lpcchMaxValueNameLen, LPDWORD lpcbMaxValueLen, LPDWORD lpcbSecurityDescriptor, 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. This parameter can be NULL. lpcchMaxSubKeyLen - 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. This parameter can be NULL. lpcValues - Points to a variable that receives the number of values associated with the key. This parameter can be NULL. lpcchMaxValueNameLen - 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. This parameter can be NULL. lpcbMaxValueLen - Points to a variable that receives the length, in bytes, of the longest data component among the key's values. This parameter can be NULL. lpcbSecurityDescriptor - Points to a variable that receives the length, in bytes, of the key's security descriptor. This parameter can be NULL. lpftLastWriteTime - Pointer to a FILETIME structure. This parameter can be NULL. Return Value: ERROR_SUCCESS if successful Win32 error code otherwise --*/ { DWORD SubKeys; DWORD MaxSubKeyLen; DWORD Values; DWORD MaxValueNameLen; DWORD MaxValueLen; DWORD SecurityDescriptor; DWORD Status; FILETIME LastWriteTime; PCKEY Key = (PCKEY)hKey; WRAP(Status, ApiQueryInfoKey(Key->RemoteKey, &SubKeys, &MaxSubKeyLen, &Values, &MaxValueNameLen, &MaxValueLen, &SecurityDescriptor, &LastWriteTime), Key->Cluster); if (Status == ERROR_SUCCESS) { if (ARGUMENT_PRESENT(lpcSubKeys)) { *lpcSubKeys = SubKeys; } if (ARGUMENT_PRESENT(lpcchMaxSubKeyLen)) { *lpcchMaxSubKeyLen = MaxSubKeyLen; } if (ARGUMENT_PRESENT(lpcValues)) { *lpcValues = Values; } if (ARGUMENT_PRESENT(lpcchMaxValueNameLen)) { *lpcchMaxValueNameLen = MaxValueNameLen; } if (ARGUMENT_PRESENT(lpcbMaxValueLen)) { *lpcbMaxValueLen = MaxValueLen; } if (ARGUMENT_PRESENT(lpcbSecurityDescriptor)) { *lpcbSecurityDescriptor = SecurityDescriptor; } if (ARGUMENT_PRESENT(lpftLastWriteTime)) { *lpftLastWriteTime = LastWriteTime; } } return(Status); } LONG WINAPI ClusterRegGetKeySecurity( HKEY hKey, SECURITY_INFORMATION RequestedInformation, PSECURITY_DESCRIPTOR pSecurityDescriptor, LPDWORD lpcbSecurityDescriptor ) /*++ Routine Description: Retrieves a copy of the security descriptor protecting the specified cluster registry key. Arguments: hKey - Supplies the handle of the key RequestedInformation - Specifies a SECURITY_INFORMATION structure that indicates the requested security information. pSecurityDescriptor - Points to a buffer that receives a copy of the requested security descriptor. lpcbSecurityDescriptor - Points to a variable that specifies the size, in bytes, of the buffer pointed to by the pSecurityDescriptor parameter. When the function returns, the variable contains the number of bytes written to the buffer. Return Value: ERROR_SUCCESS if successful Win32 error code otherwise --*/ { PCKEY Key = (PCKEY)hKey; RPC_SECURITY_DESCRIPTOR RpcSD; DWORD Status; // // Convert the supplied SECURITY_DESCRIPTOR to a RPCable version. // RpcSD.lpSecurityDescriptor = pSecurityDescriptor; RpcSD.cbInSecurityDescriptor = *lpcbSecurityDescriptor; RpcSD.cbOutSecurityDescriptor = 0; WRAP(Status, (ApiGetKeySecurity(Key->RemoteKey, RequestedInformation, &RpcSD)), Key->Cluster); // // Extract the size of the SECURITY_DESCRIPTOR from the RPCable version. // *lpcbSecurityDescriptor = RpcSD.cbOutSecurityDescriptor; return Status; } LONG WINAPI ClusterRegSetKeySecurity( HKEY hKey, SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR pSecurityDescriptor ) /*++ Routine Description: Sets the security of an open cluster registry key. Arguments: hKey - Supplies the cluster registry key SecurityInformation - Specifies a SECURITY_INFORMATION structure that indicates the contents of the supplied security descriptor. pSecurityDescriptor - Points to a SECURITY_DESCRIPTOR structure that specifies the security attributes to set for the specified key. Return Value: ERROR_SUCCESS if successful Win32 error code otherwise --*/ { PCKEY Key = (PCKEY)hKey; RPC_SECURITY_DESCRIPTOR RpcSD; DWORD Status; // // Convert the supplied SECURITY_DESCRIPTOR to a RPCable version. // RpcSD.lpSecurityDescriptor = NULL; Status = MapSDToRpcSD(pSecurityDescriptor,&RpcSD); if (Status != ERROR_SUCCESS) { return(Status); } WRAP(Status, (ApiSetKeySecurity(Key->RemoteKey, SecurityInformation, &RpcSD)), Key->Cluster); // // Free the buffer allocated by MapSDToRpcSD. // LocalFree(RpcSD.lpSecurityDescriptor); return(Status); }