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.
564 lines
14 KiB
564 lines
14 KiB
/*++
|
|
|
|
Copyright (c) 1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
Reglukey.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the server side Win32 Registry
|
|
APIs to load, unload and replace keys. That is:
|
|
|
|
- BaseRegLoadKeyA
|
|
- BaseRegLoadKeyW
|
|
- BaseRegUnLoadKeyA
|
|
- BaseRegUnLoadKeyW
|
|
- BaseRegReplaceKeyA
|
|
- BaseRegReplaceKeyW
|
|
|
|
Author:
|
|
|
|
|
|
Ramon J. San Andres (ramonsa) 16-Apr-1992
|
|
|
|
|
|
|
|
--*/
|
|
|
|
#include <rpc.h>
|
|
#include "regrpc.h"
|
|
#include "localreg.h"
|
|
|
|
error_status_t
|
|
BaseRegLoadKey(
|
|
IN HKEY hKey,
|
|
IN PUNICODE_STRING lpSubKey OPTIONAL,
|
|
IN PUNICODE_STRING lpFile
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Load the tree in the supplied file into the key referenced by the
|
|
supplied key handle and sub-key. The loaded tree will overwrite all
|
|
of the contents of the supplied sub-key except for its name.
|
|
Pictorially, if the file contains:
|
|
|
|
A
|
|
/ \
|
|
/ \
|
|
B C
|
|
|
|
and the supplied key refers to a key name X, the resultant tree would
|
|
look like:
|
|
|
|
X
|
|
/ \
|
|
/ \
|
|
B C
|
|
|
|
Arguments:
|
|
|
|
hKey - Supplies the predefined handle HKEY_USERS or HKEY_LOCAL_MACHINE.
|
|
lpSubKey is relative to this handle.
|
|
|
|
lpSubKey - Supplies a path name to a new (i.e. non-existant) key
|
|
where the supplied file will be loaded.
|
|
|
|
lpFile - Supplies a pointer to an existing file name whose contents was
|
|
created with RegSaveKey. The file name may not have an extension.
|
|
|
|
Return Value:
|
|
|
|
Returns ERROR_SUCCESS (0) for success; error-code for failure.
|
|
|
|
Notes:
|
|
|
|
The difference between RegRestoreKey and RegLoadKey is that in the
|
|
latter case the supplied file is used as the actual backing store
|
|
whereas in the former case the information in the file is copied into
|
|
the Registry.
|
|
|
|
RegLoadKey requires SeRestorePrivilege.
|
|
|
|
--*/
|
|
|
|
{
|
|
OBJECT_ATTRIBUTES ObjaKey;
|
|
OBJECT_ATTRIBUTES ObjaFile;
|
|
BOOLEAN ErrorFlag;
|
|
UNICODE_STRING FileName;
|
|
RTL_RELATIVE_NAME_U RelativeName;
|
|
PVOID FreeBuffer;
|
|
NTSTATUS NtStatus;
|
|
PUNICODE_STRING SubKey;
|
|
|
|
#if DBG
|
|
//OutputDebugString( "WINREG: Entering BaseRegLoadKey\n" );
|
|
#endif
|
|
|
|
|
|
ASSERT( (hKey != NULL) && (lpFile != NULL) && (lpFile->Buffer != NULL));
|
|
if ( (hKey == NULL) || (lpFile == NULL) || (lpFile->Buffer == NULL) ) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// check for oddly formed UNICODE_STRINGs passed by malicious clients
|
|
// check also for zero-length strings
|
|
//
|
|
if ((!lpFile->Length) ||
|
|
(lpFile->Length & 1) ||
|
|
(lpFile->Buffer[lpFile->Length/sizeof(WCHAR) - 1] != UNICODE_NULL)) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ((lpSubKey) &&
|
|
((!lpSubKey->Length) ||
|
|
(lpSubKey->Length & 1) ||
|
|
(lpSubKey->Buffer && (lpSubKey->Buffer[lpSubKey->Length/sizeof(WCHAR) - 1] != UNICODE_NULL)))) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
RPC_IMPERSONATE_CLIENT( NULL );
|
|
|
|
|
|
//
|
|
// Remove terminating NULLs from Length counts. These were added
|
|
// on the client side so that RPC would transmit the whole thing.
|
|
//
|
|
if ( lpSubKey && lpSubKey->Length > 0 ) {
|
|
lpSubKey->Length -= sizeof( UNICODE_NULL );
|
|
SubKey = lpSubKey;
|
|
} else {
|
|
SubKey = NULL;
|
|
}
|
|
|
|
if ( lpFile->Length > 0 ) {
|
|
lpFile->Length -= sizeof( UNICODE_NULL );
|
|
}
|
|
|
|
|
|
InitializeObjectAttributes(
|
|
&ObjaKey,
|
|
SubKey,
|
|
OBJ_CASE_INSENSITIVE,
|
|
hKey,
|
|
NULL
|
|
);
|
|
|
|
//
|
|
// Convert the DOS path name to a canonical Nt path name.
|
|
//
|
|
ErrorFlag = RtlDosPathNameToRelativeNtPathName_U(
|
|
lpFile->Buffer,
|
|
&FileName,
|
|
NULL,
|
|
&RelativeName
|
|
);
|
|
|
|
//
|
|
// If the name was not succesfully converted assume it was invalid.
|
|
//
|
|
if ( !ErrorFlag ) {
|
|
RPC_REVERT_TO_SELF();
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Remember the buffer allocatted by RtlDosPathNameToRelativeNtPathName_U.
|
|
//
|
|
FreeBuffer = FileName.Buffer;
|
|
|
|
//
|
|
// If a relative name and directory handle will work, use those.
|
|
//
|
|
if ( RelativeName.RelativeName.Length ) {
|
|
|
|
//
|
|
// Replace the full path with the relative path.
|
|
//
|
|
FileName = RelativeName.RelativeName;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Using the full path - no containing directory.
|
|
//
|
|
RelativeName.ContainingDirectory = NULL;
|
|
}
|
|
|
|
//
|
|
// Initialize the Obja structure for the file.
|
|
//
|
|
InitializeObjectAttributes(
|
|
&ObjaFile,
|
|
&FileName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
RelativeName.ContainingDirectory,
|
|
NULL
|
|
);
|
|
|
|
#if DBG
|
|
//OutputDebugString( "WINREG: Before NtLoadKey\n" );
|
|
#endif
|
|
|
|
|
|
NtStatus = NtLoadKey(
|
|
&ObjaKey,
|
|
&ObjaFile
|
|
);
|
|
|
|
RtlReleaseRelativeName(&RelativeName);
|
|
|
|
#if DBG
|
|
//OutputDebugString( "WINREG: After RegLoadKey\n" );
|
|
#endif
|
|
|
|
RPC_REVERT_TO_SELF();
|
|
|
|
//
|
|
// Free the buffer allocatted by RtlDosPathNameToRelativeNtPathName_U.
|
|
//
|
|
RtlFreeHeap( RtlProcessHeap( ), 0, FreeBuffer );
|
|
|
|
#if DBG
|
|
//OutputDebugString( "WINREG: Leaving BaseRegLoadKey\n" );
|
|
#endif
|
|
|
|
return (error_status_t)RtlNtStatusToDosError( NtStatus );
|
|
}
|
|
|
|
|
|
|
|
|
|
error_status_t
|
|
BaseRegUnLoadKey(
|
|
IN HKEY hKey,
|
|
IN PUNICODE_STRING lpSubKey OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Unload the specified tree (hive) from the Registry.
|
|
|
|
Arguments:
|
|
|
|
hKey - Supplies a handle to an open key. lpSubKey is relative to this
|
|
handle.
|
|
|
|
lpSubKey - Supplies a path name to the key that is to be unloaded.
|
|
The combination of hKey and lpSubKey must refer to a hive in the
|
|
Registry created with RegRestoreKey or RegLoadKey. This parameter may
|
|
be NULL.
|
|
|
|
Return Value:
|
|
|
|
Returns ERROR_SUCCESS (0) for success; error-code for failure.
|
|
|
|
RegUnLoadKey requires SeRestorePrivilege.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
OBJECT_ATTRIBUTES ObjaKey;
|
|
NTSTATUS NtStatus;
|
|
|
|
|
|
ASSERT( hKey != NULL );
|
|
if ( (hKey == NULL) ||
|
|
(lpSubKey && (lpSubKey->Length &1)) ) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
|
|
RPC_IMPERSONATE_CLIENT( NULL );
|
|
|
|
//
|
|
// Remove terminating NULLs from Length counts. These were added
|
|
// on the client side so that RPC would transmit the whole thing.
|
|
//
|
|
if ( lpSubKey && lpSubKey->Length > 0 ) {
|
|
lpSubKey->Length -= sizeof( UNICODE_NULL );
|
|
}
|
|
|
|
|
|
InitializeObjectAttributes(
|
|
&ObjaKey,
|
|
lpSubKey,
|
|
OBJ_CASE_INSENSITIVE,
|
|
hKey,
|
|
NULL
|
|
);
|
|
|
|
NtStatus = NtUnloadKey( &ObjaKey );
|
|
|
|
RPC_REVERT_TO_SELF();
|
|
return (error_status_t)RtlNtStatusToDosError( NtStatus );
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
error_status_t
|
|
BaseRegReplaceKey(
|
|
HKEY hKey,
|
|
PUNICODE_STRING lpSubKey,
|
|
PUNICODE_STRING lpNewFile,
|
|
PUNICODE_STRING lpOldFile
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Replace an existing tree (hive) in the Registry. The new tree will
|
|
take effect the next time the system is rebooted.
|
|
|
|
Arguments:
|
|
|
|
hKey - Supplies a handle to an open key. lpSubKey is relative to this
|
|
handle.
|
|
|
|
lpSubKey - Supplies a path name to the key that is to be replaced.
|
|
The combination of hKey and lpSubKey must refer to a hive in the
|
|
Registry. This parameter may be NULL.
|
|
|
|
lpNewFile - Supplies a file name for the new hive file.
|
|
|
|
lpOldFile - Supplies a backup file name for the old (existing) hive file.
|
|
|
|
Return Value:
|
|
|
|
Returns ERROR_SUCCESS (0) for success; error-code for failure.
|
|
|
|
Notes:
|
|
|
|
lpNewFile will remain open until after the system is rebooted.
|
|
|
|
RegUnLoadKey requires SeRestorePrivilege.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
UNICODE_STRING NewFileName;
|
|
UNICODE_STRING OldFileName;
|
|
RTL_RELATIVE_NAME_U NewRelativeName;
|
|
RTL_RELATIVE_NAME_U OldRelativeName;
|
|
PVOID NewFreeBuffer;
|
|
PVOID OldFreeBuffer;
|
|
HANDLE HiveHandle;
|
|
OBJECT_ATTRIBUTES ObjaKey;
|
|
OBJECT_ATTRIBUTES ObjaNewFile;
|
|
OBJECT_ATTRIBUTES ObjaOldFile;
|
|
BOOLEAN ErrorFlag;
|
|
NTSTATUS NtStatus;
|
|
|
|
|
|
ErrorFlag = (BOOLEAN)( (hKey == NULL) ||
|
|
(lpNewFile == NULL) ||
|
|
(lpNewFile->Buffer == NULL) ||
|
|
(lpNewFile->Length & 1) ||
|
|
(lpOldFile == NULL) ||
|
|
(lpOldFile->Buffer == NULL) ||
|
|
(lpOldFile->Length & 1) ||
|
|
(lpSubKey && (lpSubKey->Length & 1))
|
|
);
|
|
|
|
ASSERT( !ErrorFlag );
|
|
|
|
if ( ErrorFlag ) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
|
|
RPC_IMPERSONATE_CLIENT( NULL );
|
|
|
|
//
|
|
// Remove terminating NULLs from Length counts. These were added
|
|
// on the client side so that RPC would transmit the whole thing.
|
|
//
|
|
if ( lpSubKey && lpSubKey->Length > 0 ) {
|
|
lpSubKey->Length -= sizeof( UNICODE_NULL );
|
|
}
|
|
|
|
if ( lpNewFile->Length > 0 ) {
|
|
lpNewFile->Length -= sizeof( UNICODE_NULL );
|
|
}
|
|
|
|
if ( lpOldFile->Length > 0 ) {
|
|
lpOldFile->Length -= sizeof( UNICODE_NULL );
|
|
}
|
|
|
|
|
|
InitializeObjectAttributes(
|
|
&ObjaKey,
|
|
lpSubKey,
|
|
OBJ_CASE_INSENSITIVE,
|
|
hKey,
|
|
NULL
|
|
);
|
|
|
|
//
|
|
// Get a handle to the hive root
|
|
//
|
|
NtStatus = NtCreateKey(
|
|
&HiveHandle,
|
|
MAXIMUM_ALLOWED,
|
|
&ObjaKey,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_BACKUP_RESTORE,
|
|
NULL
|
|
);
|
|
|
|
|
|
if ( !NT_SUCCESS( NtStatus ) ) {
|
|
RPC_REVERT_TO_SELF();
|
|
return (error_status_t)RtlNtStatusToDosError( NtStatus );
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Convert the new DOS path name to a canonical Nt path name.
|
|
//
|
|
ErrorFlag = RtlDosPathNameToRelativeNtPathName_U(
|
|
lpNewFile->Buffer,
|
|
&NewFileName,
|
|
NULL,
|
|
&NewRelativeName
|
|
);
|
|
|
|
//
|
|
// If the name was not succesfully converted assume it was invalid.
|
|
//
|
|
if ( !ErrorFlag ) {
|
|
NtClose( HiveHandle );
|
|
RPC_REVERT_TO_SELF();
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Remember the buffer allocatted by RtlDosPathNameToRelativeNtPathName_U.
|
|
//
|
|
NewFreeBuffer = NewFileName.Buffer;
|
|
|
|
//
|
|
// If a relative name and directory handle will work, use those.
|
|
//
|
|
if ( NewRelativeName.RelativeName.Length ) {
|
|
|
|
//
|
|
// Replace the full path with the relative path.
|
|
//
|
|
NewFileName = NewRelativeName.RelativeName;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Using the full path - no containing directory.
|
|
//
|
|
NewRelativeName.ContainingDirectory = NULL;
|
|
}
|
|
|
|
//
|
|
// Initialize the Obja structure for the new file.
|
|
//
|
|
InitializeObjectAttributes(
|
|
&ObjaNewFile,
|
|
&NewFileName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NewRelativeName.ContainingDirectory,
|
|
NULL
|
|
);
|
|
|
|
|
|
//
|
|
// Convert the old DOS path name to a canonical Nt path name.
|
|
//
|
|
ErrorFlag = RtlDosPathNameToRelativeNtPathName_U(
|
|
lpOldFile->Buffer,
|
|
&OldFileName,
|
|
NULL,
|
|
&OldRelativeName
|
|
);
|
|
|
|
//
|
|
// If the name was not succesfully converted assume it was invalid.
|
|
//
|
|
if ( !ErrorFlag ) {
|
|
RtlReleaseRelativeName(&NewRelativeName);
|
|
RtlFreeHeap( RtlProcessHeap( ), 0, NewFreeBuffer );
|
|
NtClose( HiveHandle );
|
|
RPC_REVERT_TO_SELF();
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Remember the buffer allocatted by RtlDosPathNameToRelativeNtPathName_U.
|
|
//
|
|
OldFreeBuffer = OldFileName.Buffer;
|
|
|
|
//
|
|
// If a relative name and directory handle will work, use those.
|
|
//
|
|
if ( OldRelativeName.RelativeName.Length ) {
|
|
|
|
//
|
|
// Replace the full path with the relative path.
|
|
//
|
|
OldFileName = OldRelativeName.RelativeName;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Using the full path - no containing directory.
|
|
//
|
|
OldRelativeName.ContainingDirectory = NULL;
|
|
}
|
|
|
|
//
|
|
// Initialize the Obja structure for the new file.
|
|
//
|
|
InitializeObjectAttributes(
|
|
&ObjaOldFile,
|
|
&OldFileName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
OldRelativeName.ContainingDirectory,
|
|
NULL
|
|
);
|
|
|
|
|
|
NtStatus = NtReplaceKey(
|
|
&ObjaNewFile,
|
|
HiveHandle,
|
|
&ObjaOldFile
|
|
);
|
|
|
|
RtlReleaseRelativeName(&NewRelativeName);
|
|
RtlReleaseRelativeName(&OldRelativeName);
|
|
|
|
//
|
|
// Free the buffers allocatted by RtlDosPathNameToRelativeNtPathName_U.
|
|
//
|
|
RtlFreeHeap( RtlProcessHeap( ), 0, NewFreeBuffer );
|
|
RtlFreeHeap( RtlProcessHeap( ), 0, OldFreeBuffer );
|
|
|
|
NtClose( HiveHandle );
|
|
|
|
RPC_REVERT_TO_SELF();
|
|
return (error_status_t)RtlNtStatusToDosError( NtStatus );
|
|
}
|