513 lines
14 KiB
C
513 lines
14 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1992 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
Regqkey.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module contains the client side wrappers for the Win32 Registry
|
|||
|
query key APIs. That is:
|
|||
|
|
|||
|
- RegQueryInfoKeyA
|
|||
|
- RegQueryInfoKeyW
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
David J. Gilman (davegi) 18-Mar-1992
|
|||
|
|
|||
|
Notes:
|
|||
|
|
|||
|
See the notes in server\regqkey.c.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include <rpc.h>
|
|||
|
#include "regrpc.h"
|
|||
|
#include "client.h"
|
|||
|
|
|||
|
LONG
|
|||
|
RegQueryInfoKeyA (
|
|||
|
HKEY hKey,
|
|||
|
LPSTR lpClass,
|
|||
|
LPDWORD lpcbClass,
|
|||
|
LPDWORD lpReserved,
|
|||
|
LPDWORD lpcSubKeys,
|
|||
|
LPDWORD lpcbMaxSubKeyLen,
|
|||
|
LPDWORD lpcbMaxClassLen,
|
|||
|
LPDWORD lpcValues,
|
|||
|
LPDWORD lpcbMaxValueNameLen,
|
|||
|
LPDWORD lpcbMaxValueLen,
|
|||
|
LPDWORD lpcbSecurityDescriptor,
|
|||
|
PFILETIME lpftLastWriteTime
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Win32 ANSI RPC wrapper for querying information about a previously
|
|||
|
opened key.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PUNICODE_STRING Class;
|
|||
|
UNICODE_STRING UnicodeString;
|
|||
|
ANSI_STRING AnsiString;
|
|||
|
NTSTATUS Status;
|
|||
|
LONG Error;
|
|||
|
DWORD cSubKeys;
|
|||
|
DWORD cbMaxSubKeyLen;
|
|||
|
DWORD cValues;
|
|||
|
DWORD cbMaxValueNameLen;
|
|||
|
DWORD cbMaxValueLen;
|
|||
|
FILETIME ftLastWriteTime;
|
|||
|
HKEY TempHandle = NULL;
|
|||
|
DWORD cbMaxClassLen;
|
|||
|
DWORD cbSecurityDescriptor;
|
|||
|
PDWORD pCbMaxClassLen = NULL;
|
|||
|
PDWORD pCbSecurityDescriptor = NULL;
|
|||
|
|
|||
|
|
|||
|
#if DBG
|
|||
|
if ( BreakPointOnEntry ) {
|
|||
|
DbgBreakPoint();
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
if( ARGUMENT_PRESENT( lpReserved ) ||
|
|||
|
(ARGUMENT_PRESENT( lpClass ) && ( ! ARGUMENT_PRESENT( lpcbClass )))) {
|
|||
|
return ERROR_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
hKey = MapPredefinedHandle( hKey, &TempHandle );
|
|||
|
if( hKey == NULL ) {
|
|||
|
Error = ERROR_INVALID_HANDLE;
|
|||
|
goto ExitCleanup;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Make sure that the buffer size for lpClass is zero if lpClass is NULL
|
|||
|
//
|
|||
|
if( !ARGUMENT_PRESENT( lpClass ) && ARGUMENT_PRESENT( lpcbClass ) ) {
|
|||
|
*lpcbClass = 0;
|
|||
|
}
|
|||
|
|
|||
|
if( ARGUMENT_PRESENT( lpcbMaxClassLen ) ) {
|
|||
|
pCbMaxClassLen = &cbMaxClassLen;
|
|||
|
}
|
|||
|
|
|||
|
if( ARGUMENT_PRESENT( lpcbSecurityDescriptor ) ) {
|
|||
|
pCbSecurityDescriptor = &cbSecurityDescriptor;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If the count of bytes in the class is 0, pass a NULL pointer
|
|||
|
// instead of what was supplied. This ensures that RPC won't
|
|||
|
// attempt to copy data to a bogus pointer. Note that in this
|
|||
|
// case we use the unicode string allocated on the stack, because
|
|||
|
// we must not change the Buffer or MaximumLength fields of the
|
|||
|
// static unicode string in the TEB.
|
|||
|
//
|
|||
|
if ( !ARGUMENT_PRESENT( lpClass ) || *lpcbClass == 0 ) {
|
|||
|
|
|||
|
Class = &UnicodeString;
|
|||
|
Class->Length = 0;
|
|||
|
Class->MaximumLength = 0;
|
|||
|
Class->Buffer = NULL;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Use the static Unicode string in the TEB as a temporary for the
|
|||
|
// key's class.
|
|||
|
//
|
|||
|
Class = &NtCurrentTeb( )->StaticUnicodeString;
|
|||
|
ASSERT( Class != NULL );
|
|||
|
Class->Length = 0;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Call the Base API passing it a pointer to a counted Unicode string
|
|||
|
// for the class string.
|
|||
|
//
|
|||
|
|
|||
|
if( IsLocalHandle( hKey )) {
|
|||
|
|
|||
|
Error = (LONG)LocalBaseRegQueryInfoKey(
|
|||
|
hKey,
|
|||
|
Class,
|
|||
|
&cSubKeys,
|
|||
|
&cbMaxSubKeyLen,
|
|||
|
pCbMaxClassLen,
|
|||
|
&cValues,
|
|||
|
&cbMaxValueNameLen,
|
|||
|
&cbMaxValueLen,
|
|||
|
pCbSecurityDescriptor,
|
|||
|
&ftLastWriteTime
|
|||
|
);
|
|||
|
} else {
|
|||
|
//
|
|||
|
// on RPC always send valid pointers!!!
|
|||
|
//
|
|||
|
pCbMaxClassLen = &cbMaxClassLen;
|
|||
|
pCbSecurityDescriptor = &cbSecurityDescriptor;
|
|||
|
|
|||
|
Error = (LONG)BaseRegQueryInfoKey(
|
|||
|
DereferenceRemoteHandle( hKey ),
|
|||
|
Class,
|
|||
|
&cSubKeys,
|
|||
|
&cbMaxSubKeyLen,
|
|||
|
pCbMaxClassLen,
|
|||
|
&cValues,
|
|||
|
&cbMaxValueNameLen,
|
|||
|
&cbMaxValueLen,
|
|||
|
pCbSecurityDescriptor,
|
|||
|
&ftLastWriteTime
|
|||
|
);
|
|||
|
if (Error == ERROR_SUCCESS) {
|
|||
|
DWORD dwVersion;
|
|||
|
|
|||
|
//
|
|||
|
// Check for a downlevel Win95 server, which requires
|
|||
|
// us to work around their BaseRegQueryInfoKey bugs.
|
|||
|
// They do not account for Unicode correctly.
|
|||
|
//
|
|||
|
if (IsWin95Server(DereferenceRemoteHandle(hKey),dwVersion)) {
|
|||
|
//
|
|||
|
// This is a Win95 server.
|
|||
|
// Double the maximum value name length and
|
|||
|
// maximum value data length to account for
|
|||
|
// the Unicode translation that Win95 forgot
|
|||
|
// to account for.
|
|||
|
//
|
|||
|
cbMaxValueNameLen *= sizeof(WCHAR);
|
|||
|
cbMaxValueLen *= sizeof(WCHAR);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// MaxSubKeyLen, MaxClassLen, and MaxValueNameLen should be in
|
|||
|
// number of characters, without counting the NULL.
|
|||
|
// Note that the server side will return the number of bytes,
|
|||
|
// without counting the NUL
|
|||
|
//
|
|||
|
|
|||
|
cbMaxSubKeyLen /= sizeof( WCHAR );
|
|||
|
if( pCbMaxClassLen != NULL ) {
|
|||
|
cbMaxClassLen /= sizeof( WCHAR );
|
|||
|
ASSERT( *pCbMaxClassLen == cbMaxClassLen );
|
|||
|
}
|
|||
|
cbMaxValueNameLen /= sizeof( WCHAR );
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Subtract the NULL from the Length. This was added on
|
|||
|
// the server side so that RPC would transmit it.
|
|||
|
//
|
|||
|
if ( Class->Length > 0 ) {
|
|||
|
Class->Length -= sizeof( UNICODE_NULL );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If all the information was succesfully queried from the key
|
|||
|
// convert the class name to ANSI and update the class length value.
|
|||
|
//
|
|||
|
|
|||
|
if( ( Error == ERROR_SUCCESS ) &&
|
|||
|
ARGUMENT_PRESENT( lpClass ) && ( *lpcbClass != 0 ) ) {
|
|||
|
|
|||
|
if (*lpcbClass > (DWORD)0xFFFF) {
|
|||
|
AnsiString.MaximumLength = ( USHORT ) 0xFFFF;
|
|||
|
} else {
|
|||
|
AnsiString.MaximumLength = ( USHORT ) *lpcbClass;
|
|||
|
}
|
|||
|
|
|||
|
AnsiString.Buffer = lpClass;
|
|||
|
|
|||
|
Status = RtlUnicodeStringToAnsiString(
|
|||
|
&AnsiString,
|
|||
|
Class,
|
|||
|
FALSE
|
|||
|
);
|
|||
|
ASSERTMSG( "Unicode->ANSI conversion of Class ",
|
|||
|
NT_SUCCESS( Status ));
|
|||
|
|
|||
|
//
|
|||
|
// Update the class length return parameter.
|
|||
|
//
|
|||
|
|
|||
|
*lpcbClass = AnsiString.Length;
|
|||
|
|
|||
|
Error = RtlNtStatusToDosError( Status );
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Not all of the information was succesfully queried, or Class
|
|||
|
// doesn't have to be converted from UNICODE to ANSI
|
|||
|
//
|
|||
|
|
|||
|
if( ARGUMENT_PRESENT( lpcbClass ) ) {
|
|||
|
if( Class->Length == 0 ) {
|
|||
|
|
|||
|
*lpcbClass = 0;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
*lpcbClass = ( Class->Length >> 1 );
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if( ARGUMENT_PRESENT( lpcSubKeys ) ) {
|
|||
|
*lpcSubKeys = cSubKeys;
|
|||
|
}
|
|||
|
if( ARGUMENT_PRESENT( lpcbMaxSubKeyLen ) ) {
|
|||
|
*lpcbMaxSubKeyLen = cbMaxSubKeyLen;
|
|||
|
}
|
|||
|
if( ARGUMENT_PRESENT( lpcbMaxClassLen ) ) {
|
|||
|
*lpcbMaxClassLen = cbMaxClassLen;
|
|||
|
ASSERT( *pCbMaxClassLen == cbMaxClassLen );
|
|||
|
}
|
|||
|
if( ARGUMENT_PRESENT( lpcValues ) ) {
|
|||
|
*lpcValues = cValues;
|
|||
|
}
|
|||
|
if( ARGUMENT_PRESENT( lpcbMaxValueNameLen ) ) {
|
|||
|
*lpcbMaxValueNameLen = cbMaxValueNameLen;
|
|||
|
}
|
|||
|
if( ARGUMENT_PRESENT( lpcbMaxValueLen ) ) {
|
|||
|
*lpcbMaxValueLen = cbMaxValueLen;
|
|||
|
}
|
|||
|
if( ARGUMENT_PRESENT( lpcbSecurityDescriptor ) ) {
|
|||
|
*lpcbSecurityDescriptor = cbSecurityDescriptor;
|
|||
|
ASSERT( *pCbSecurityDescriptor == cbSecurityDescriptor );
|
|||
|
}
|
|||
|
if( ARGUMENT_PRESENT( lpftLastWriteTime ) ) {
|
|||
|
*lpftLastWriteTime = ftLastWriteTime;
|
|||
|
}
|
|||
|
|
|||
|
ExitCleanup:
|
|||
|
|
|||
|
CLOSE_LOCAL_HANDLE(TempHandle);
|
|||
|
return Error;
|
|||
|
}
|
|||
|
|
|||
|
LONG
|
|||
|
RegQueryInfoKeyW (
|
|||
|
HKEY hKey,
|
|||
|
LPWSTR lpClass,
|
|||
|
LPDWORD lpcbClass,
|
|||
|
LPDWORD lpReserved,
|
|||
|
LPDWORD lpcSubKeys,
|
|||
|
LPDWORD lpcbMaxSubKeyLen,
|
|||
|
LPDWORD lpcbMaxClassLen,
|
|||
|
LPDWORD lpcValues,
|
|||
|
LPDWORD lpcbMaxValueNameLen,
|
|||
|
LPDWORD lpcbMaxValueLen,
|
|||
|
LPDWORD lpcbSecurityDescriptor,
|
|||
|
PFILETIME lpftLastWriteTime
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Win32 Unicode RPC wrapper for querying information about a previously
|
|||
|
opened key.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
UNICODE_STRING Class;
|
|||
|
LONG Error;
|
|||
|
|
|||
|
DWORD cbClass;
|
|||
|
DWORD cSubKeys;
|
|||
|
DWORD cbMaxSubKeyLen;
|
|||
|
DWORD cValues;
|
|||
|
DWORD cbMaxValueNameLen;
|
|||
|
DWORD cbMaxValueLen;
|
|||
|
FILETIME ftLastWriteTime;
|
|||
|
HKEY TempHandle = NULL;
|
|||
|
DWORD cbMaxClassLen;
|
|||
|
DWORD cbSecurityDescriptor;
|
|||
|
PDWORD pCbMaxClassLen = NULL;
|
|||
|
PDWORD pCbSecurityDescriptor = NULL;
|
|||
|
|
|||
|
|
|||
|
#if DBG
|
|||
|
if ( BreakPointOnEntry ) {
|
|||
|
DbgBreakPoint();
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
if( ARGUMENT_PRESENT( lpReserved ) ||
|
|||
|
(ARGUMENT_PRESENT( lpClass ) && ( ! ARGUMENT_PRESENT( lpcbClass )))) {
|
|||
|
return ERROR_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
hKey = MapPredefinedHandle( hKey, &TempHandle );
|
|||
|
if( hKey == NULL ) {
|
|||
|
Error = ERROR_INVALID_HANDLE;
|
|||
|
goto ExitCleanup;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Make sure that the buffer size for lpClass is zero if lpClass is NULL
|
|||
|
//
|
|||
|
if( !ARGUMENT_PRESENT( lpClass ) && ARGUMENT_PRESENT( lpcbClass ) ) {
|
|||
|
*lpcbClass = 0;
|
|||
|
}
|
|||
|
|
|||
|
if( ARGUMENT_PRESENT( lpcbMaxClassLen ) ) {
|
|||
|
pCbMaxClassLen = &cbMaxClassLen;
|
|||
|
}
|
|||
|
|
|||
|
if( ARGUMENT_PRESENT( lpcbSecurityDescriptor ) ) {
|
|||
|
pCbSecurityDescriptor = &cbSecurityDescriptor;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Use the supplied class Class buffer as the buffer in a counted
|
|||
|
// Unicode Class.
|
|||
|
//
|
|||
|
Class.Length = 0;
|
|||
|
if( ARGUMENT_PRESENT( lpcbClass ) && ( *lpcbClass != 0 ) ) {
|
|||
|
|
|||
|
Class.MaximumLength = ( USHORT )( *lpcbClass << 1 );
|
|||
|
Class.Buffer = lpClass;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// If the count of bytes in the class is 0, pass a NULL pointer
|
|||
|
// instead of what was supplied. This ensures that RPC won't
|
|||
|
// attempt to copy data to a bogus pointer.
|
|||
|
//
|
|||
|
Class.MaximumLength = 0;
|
|||
|
Class.Buffer = NULL;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Call the Base API.
|
|||
|
//
|
|||
|
|
|||
|
if( IsLocalHandle( hKey )) {
|
|||
|
|
|||
|
Error = (LONG)LocalBaseRegQueryInfoKey(
|
|||
|
hKey,
|
|||
|
&Class,
|
|||
|
&cSubKeys,
|
|||
|
&cbMaxSubKeyLen,
|
|||
|
pCbMaxClassLen,
|
|||
|
&cValues,
|
|||
|
&cbMaxValueNameLen,
|
|||
|
&cbMaxValueLen,
|
|||
|
pCbSecurityDescriptor,
|
|||
|
&ftLastWriteTime
|
|||
|
);
|
|||
|
} else {
|
|||
|
//
|
|||
|
// on RPC always send valid pointers!!!
|
|||
|
//
|
|||
|
pCbMaxClassLen = &cbMaxClassLen;
|
|||
|
pCbSecurityDescriptor = &cbSecurityDescriptor;
|
|||
|
|
|||
|
Error = (LONG)BaseRegQueryInfoKey(
|
|||
|
DereferenceRemoteHandle( hKey ),
|
|||
|
&Class,
|
|||
|
&cSubKeys,
|
|||
|
&cbMaxSubKeyLen,
|
|||
|
pCbMaxClassLen,
|
|||
|
&cValues,
|
|||
|
&cbMaxValueNameLen,
|
|||
|
&cbMaxValueLen,
|
|||
|
pCbSecurityDescriptor,
|
|||
|
&ftLastWriteTime
|
|||
|
);
|
|||
|
if (Error == ERROR_SUCCESS) {
|
|||
|
DWORD dwVersion;
|
|||
|
//
|
|||
|
// Check for a downlevel Win95 server, which requires
|
|||
|
// us to work around their BaseRegQueryInfoKey bugs.
|
|||
|
// They do not account for Unicode correctly.
|
|||
|
//
|
|||
|
if (IsWin95Server(DereferenceRemoteHandle(hKey),dwVersion)) {
|
|||
|
//
|
|||
|
// This is a Win95 server.
|
|||
|
// Double the maximum value name length and
|
|||
|
// maximum value data length to account for
|
|||
|
// the Unicode translation that Win95 forgot
|
|||
|
// to account for.
|
|||
|
//
|
|||
|
cbMaxValueNameLen *= sizeof(WCHAR);
|
|||
|
cbMaxValueLen *= sizeof(WCHAR);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// MaxSubKeyLen, MaxClassLen, and MaxValueNameLen should be in
|
|||
|
// number of characters, without counting the NULL.
|
|||
|
// Note that the server side will return the number of bytes,
|
|||
|
// without counting the NUL
|
|||
|
//
|
|||
|
|
|||
|
cbMaxSubKeyLen /= sizeof( WCHAR );
|
|||
|
if( pCbMaxClassLen != NULL ) {
|
|||
|
cbMaxClassLen /= sizeof( WCHAR );
|
|||
|
ASSERT( *pCbMaxClassLen == cbMaxClassLen );
|
|||
|
}
|
|||
|
cbMaxValueNameLen /= sizeof( WCHAR );
|
|||
|
|
|||
|
|
|||
|
if( ARGUMENT_PRESENT( lpcbClass ) ) {
|
|||
|
if( Class.Length == 0 ) {
|
|||
|
*lpcbClass = 0;
|
|||
|
} else {
|
|||
|
*lpcbClass = ( Class.Length >> 1 ) - 1;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if( ARGUMENT_PRESENT( lpcSubKeys ) ) {
|
|||
|
*lpcSubKeys = cSubKeys;
|
|||
|
}
|
|||
|
if( ARGUMENT_PRESENT( lpcbMaxSubKeyLen ) ) {
|
|||
|
*lpcbMaxSubKeyLen = cbMaxSubKeyLen;
|
|||
|
}
|
|||
|
if( ARGUMENT_PRESENT( lpcbMaxClassLen ) ) {
|
|||
|
*lpcbMaxClassLen = cbMaxClassLen;
|
|||
|
ASSERT( *pCbMaxClassLen == cbMaxClassLen );
|
|||
|
}
|
|||
|
if( ARGUMENT_PRESENT( lpcValues ) ) {
|
|||
|
*lpcValues = cValues;
|
|||
|
}
|
|||
|
if( ARGUMENT_PRESENT( lpcbMaxValueNameLen ) ) {
|
|||
|
*lpcbMaxValueNameLen = cbMaxValueNameLen;
|
|||
|
}
|
|||
|
if( ARGUMENT_PRESENT( lpcbMaxValueLen ) ) {
|
|||
|
*lpcbMaxValueLen = cbMaxValueLen;
|
|||
|
}
|
|||
|
if( ARGUMENT_PRESENT( lpcbSecurityDescriptor ) ) {
|
|||
|
*lpcbSecurityDescriptor = cbSecurityDescriptor;
|
|||
|
ASSERT( *pCbSecurityDescriptor == cbSecurityDescriptor );
|
|||
|
}
|
|||
|
if( ARGUMENT_PRESENT( lpftLastWriteTime ) ) {
|
|||
|
*lpftLastWriteTime = ftLastWriteTime;
|
|||
|
}
|
|||
|
|
|||
|
ExitCleanup:
|
|||
|
|
|||
|
CLOSE_LOCAL_HANDLE(TempHandle);
|
|||
|
return Error;
|
|||
|
}
|