553 lines
13 KiB
C
553 lines
13 KiB
C
/*++
|
||
|
||
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 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-1)/sizeof(WCHAR)] != UNICODE_NULL)) {
|
||
return ERROR_INVALID_PARAMETER;
|
||
}
|
||
|
||
if ((lpSubKey) &&
|
||
((!lpSubKey->Length) ||
|
||
(lpSubKey->Length & 1) ||
|
||
(lpSubKey->Buffer[(lpSubKey->Length-1)/sizeof(WCHAR)] != 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 = RtlDosPathNameToNtPathName_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 RtlDosPathNameToNtPathName_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 = *( PUNICODE_STRING ) &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
|
||
);
|
||
|
||
#if DBG
|
||
//OutputDebugString( "WINREG: After RegLoadKey\n" );
|
||
#endif
|
||
|
||
RPC_REVERT_TO_SELF();
|
||
|
||
//
|
||
// Free the buffer allocatted by RtlDosPathNameToNtPathName_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 ) {
|
||
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 RelativeName;
|
||
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) ||
|
||
(lpOldFile == NULL) ||
|
||
(lpOldFile->Buffer == NULL) );
|
||
|
||
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 = RtlDosPathNameToNtPathName_U(
|
||
lpNewFile->Buffer,
|
||
&NewFileName,
|
||
NULL,
|
||
&RelativeName
|
||
);
|
||
|
||
//
|
||
// 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 RtlDosPathNameToNtPathName_U.
|
||
//
|
||
NewFreeBuffer = NewFileName.Buffer;
|
||
|
||
//
|
||
// If a relative name and directory handle will work, use those.
|
||
//
|
||
if ( RelativeName.RelativeName.Length ) {
|
||
|
||
//
|
||
// Replace the full path with the relative path.
|
||
//
|
||
NewFileName = *( PUNICODE_STRING ) &RelativeName.RelativeName;
|
||
|
||
} else {
|
||
|
||
//
|
||
// Using the full path - no containing directory.
|
||
//
|
||
RelativeName.ContainingDirectory = NULL;
|
||
}
|
||
|
||
//
|
||
// Initialize the Obja structure for the new file.
|
||
//
|
||
InitializeObjectAttributes(
|
||
&ObjaNewFile,
|
||
&NewFileName,
|
||
OBJ_CASE_INSENSITIVE,
|
||
RelativeName.ContainingDirectory,
|
||
NULL
|
||
);
|
||
|
||
|
||
//
|
||
// Convert the old DOS path name to a canonical Nt path name.
|
||
//
|
||
ErrorFlag = RtlDosPathNameToNtPathName_U(
|
||
lpOldFile->Buffer,
|
||
&OldFileName,
|
||
NULL,
|
||
&RelativeName
|
||
);
|
||
|
||
//
|
||
// If the name was not succesfully converted assume it was invalid.
|
||
//
|
||
if ( !ErrorFlag ) {
|
||
RtlFreeHeap( RtlProcessHeap( ), 0, NewFreeBuffer );
|
||
NtClose( HiveHandle );
|
||
RPC_REVERT_TO_SELF();
|
||
return ERROR_INVALID_PARAMETER;
|
||
}
|
||
|
||
//
|
||
// Remember the buffer allocatted by RtlDosPathNameToNtPathName_U.
|
||
//
|
||
OldFreeBuffer = OldFileName.Buffer;
|
||
|
||
//
|
||
// If a relative name and directory handle will work, use those.
|
||
//
|
||
if ( RelativeName.RelativeName.Length ) {
|
||
|
||
//
|
||
// Replace the full path with the relative path.
|
||
//
|
||
OldFileName = *( PUNICODE_STRING ) &RelativeName.RelativeName;
|
||
|
||
} else {
|
||
|
||
//
|
||
// Using the full path - no containing directory.
|
||
//
|
||
RelativeName.ContainingDirectory = NULL;
|
||
}
|
||
|
||
//
|
||
// Initialize the Obja structure for the new file.
|
||
//
|
||
InitializeObjectAttributes(
|
||
&ObjaOldFile,
|
||
&OldFileName,
|
||
OBJ_CASE_INSENSITIVE,
|
||
RelativeName.ContainingDirectory,
|
||
NULL
|
||
);
|
||
|
||
|
||
NtStatus = NtReplaceKey(
|
||
&ObjaNewFile,
|
||
HiveHandle,
|
||
&ObjaOldFile
|
||
);
|
||
|
||
//
|
||
// Free the buffers allocatted by RtlDosPathNameToNtPathName_U.
|
||
//
|
||
RtlFreeHeap( RtlProcessHeap( ), 0, NewFreeBuffer );
|
||
RtlFreeHeap( RtlProcessHeap( ), 0, OldFreeBuffer );
|
||
|
||
NtClose( HiveHandle );
|
||
|
||
RPC_REVERT_TO_SELF();
|
||
return (error_status_t)RtlNtStatusToDosError( NtStatus );
|
||
}
|