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;
|
||
}
|