Leaked source code of windows server 2003
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.
 
 
 
 
 
 

2147 lines
58 KiB

/*++
Copyright (c) 2000-2001 Microsoft Corporation
Module Name:
registry.c
Abstract:
Domain Name System (DNS) API
Registry management routines.
Author:
Jim Gilroy (jamesg) March, 2000
Revision History:
--*/
#include "local.h"
#include "registry.h"
//
// Globals
//
// DWORD globals blob
//
// g_IsRegReady protects needs init and protects (requires)
// global init.
//
// See registry.h for discussion of how these globals are
// exposed both internal to the DLL and external.
//
DNS_GLOBALS_BLOB DnsGlobals;
BOOL g_IsRegReady = FALSE;
PWSTR g_pwsRemoteResolver = NULL;
//
// Property table
//
//
// WARNING: table must be in sync with DNS_REGID definitions
//
// For simplicity I did not provide a separate index field and
// a lookup function (or alternatively a function that returned
// all the properties or a property pointer).
//
// The DNS_REGID values ARE the INDEXES!
// Hence the table MUST be in sync or the whole deal blows up
// If you make a change to either -- you must change the other!
//
REG_PROPERTY RegPropertyTable[] =
{
// Basic
HOST_NAME ,
0 , // Default FALSE
0 , // No policy
1 , // Client
1 , // TcpIp
0 , // No Cache
DOMAIN_NAME ,
0 , // Default FALSE
1 , // Policy
0 , // No Client
1 , // TcpIp
0 , // No Cache
DHCP_DOMAIN_NAME ,
0 , // Default FALSE
1 , // Policy
0 , // No Client
1 , // TcpIp
0 , // No Cache
ADAPTER_DOMAIN_NAME ,
0 , // Default FALSE
1 , // Policy
1 , // Client
0 , // No TcpIp
0 , // No Cache
PRIMARY_DOMAIN_NAME ,
0 , // Default FALSE
1 , // Policy
1 , // Client
0 , // No TcpIp
0 , // No Cache
PRIMARY_SUFFIX ,
0 , // Default FALSE
1 , // Policy
1 , // Client
1 , // TcpIp
0 , // No Cache
ALTERNATE_NAMES ,
0 , // Default NULL
0 , // No Policy
0 , // No Client
0 , // No TcpIp
1 , // Cache
DNS_SERVERS ,
0 , // Default FALSE
0 , // Policy
0 , // Client
0 , // TcpIp
0 , // No Cache
SEARCH_LIST_KEY ,
0 , // Default FALSE
1 , // Policy
1 , // Client
1 , // TcpIp
0 , // No Cache
// not in use
UPDATE_ZONE_EXCLUSIONS ,
0 , // Default
1 , // Policy
1 , // Client
0 , // No TcpIp
1 , // Cache
// Query
QUERY_ADAPTER_NAME ,
1 , // Default TRUE
1 , // Policy
1 , // Client
0 , // No TcpIp
1 , // Cache
USE_DOMAIN_NAME_DEVOLUTION ,
1 , // Default TRUE
1 , // Policy
1 , // Client
1 , // TcpIp
1 , // Cache
PRIORITIZE_RECORD_DATA ,
1 , // Default TRUE
1 , // Policy
1 , // Client
1 , // TcpIp
1 , // Cache
ALLOW_UNQUALIFIED_QUERY ,
0 , // Default FALSE
1 , // Policy
1 , // Client
1 , // TcpIp
1 , // Cache
APPEND_TO_MULTI_LABEL_NAME ,
1 , // Default TRUE
1 , // Policy
1 , // Client
0 , // No TcpIp
1 , // Cache
SCREEN_BAD_TLDS ,
DNS_TLD_SCREEN_DEFAULT , // Default
1 , // Policy
1 , // Client
0 , // No TcpIp
1 , // Cache
SCREEN_UNREACHABLE_SERVERS ,
1 , // Default TRUE
1 , // Policy
1 , // Client
0 , // No TcpIp
1 , // Cache
FILTER_CLUSTER_IP ,
0 , // Default FALSE
1 , // Policy
1 , // Client
0 , // No TcpIp
1 , // Cache
WAIT_FOR_NAME_ERROR_ON_ALL ,
1 , // Default TRUE
1 , // Policy
1 , // Client
0 , // No TcpIp
1 , // Cache
USE_EDNS ,
//REG_EDNS_TRY , // Default TRY EDNS
0 , // Default FALSE
1 , // Policy
1 , // Client
0 , // No TcpIp
1 , // Cache
QUERY_IP_MATCHING ,
1 , // Default TRUE
1 , // Policy
1 , // Client
1 , // TcpIp (in Win2k)
1 , // Cache
// Update
REGISTRATION_ENABLED ,
1 , // Default TRUE
1 , // Policy
1 , // Client
0 , // No TcpIp
1 , // Cache
REGISTER_PRIMARY_NAME ,
1 , // Default TRUE
1 , // Policy
1 , // Client
0 , // No TcpIp
1 , // Cache
REGISTER_ADAPTER_NAME ,
1 , // Default TRUE
1 , // Policy
1 , // Client
0 , // No TcpIp
1 , // Cache
REGISTER_REVERSE_LOOKUP ,
1 , // Default TRUE
1 , // Policy
1 , // Client
0 , // No TcpIp
1 , // Cache
REGISTER_WAN_ADAPTERS ,
1 , // Default TRUE
1 , // Policy
1 , // Client
0 , // No TcpIp
1 , // Cache
REGISTRATION_TTL ,
REGDEF_REGISTRATION_TTL ,
1 , // Policy
1 , // Client
0 , // No TcpIp
1 , // Cache
REGISTRATION_REFRESH_INTERVAL ,
REGDEF_REGISTRATION_REFRESH_INTERVAL ,
1 , // Policy
1 , // Client
0 , // No TcpIp
1 , // Cache
REGISTRATION_MAX_ADDRESS_COUNT ,
1 , // Default register 1 address
1 , // Policy
1 , // Client
0 , // No TcpIp
1 , // Cache
UPDATE_SECURITY_LEVEL ,
DNS_UPDATE_SECURITY_USE_DEFAULT ,
1 , // Policy
1 , // Client
1 , // TcpIp
1 , // Cache
// not in use
UPDATE_ZONE_EXCLUDE_FILE ,
0 , // Default OFF
1 , // Policy
1 , // Client
0 , // No TcpIp
1 , // Cache
UPDATE_TOP_LEVEL_DOMAINS ,
0 , // Default OFF
1 , // Policy
1 , // Client
0 , // No TcpIp
1 , // Cache
//
// Backcompat
//
// DCR: once policy fixed, policy should be OFF on all backcompat
//
DISABLE_ADAPTER_DOMAIN_NAME ,
0 , // Default FALSE
0 , // Policy
0 , // Client
1 , // TcpIp
0 , // No Cache
DISABLE_DYNAMIC_UPDATE ,
0 , // Default FALSE
0 , // Policy
0 , // Client
1 , // TcpIp
0 , // No Cache
ENABLE_ADAPTER_DOMAIN_NAME_REGISTRATION ,
0 , // Default TRUE
0 , // Policy
0 , // Client
1 , // TcpIp
0 , // No Cache
DISABLE_REVERSE_ADDRESS_REGISTRATIONS ,
0 , // Default FALSE
0 , // Policy
0 , // Client
1 , // TcpIp
0 , // No Cache
DISABLE_WAN_DYNAMIC_UPDATE ,
0 , // Default FALSE
0 , // Policy OFF
0 , // Client
1 , // TcpIp
0 , // No Cache
ENABLE_WAN_UPDATE_EVENT_LOG ,
0 , // Default FALSE
0 , // Policy OFF
0 , // Client
1 , // TcpIp
0 , // No Cache
DEFAULT_REGISTRATION_TTL ,
REGDEF_REGISTRATION_TTL ,
0 , // Policy OFF
0 , // Client
1 , // TcpIp
0 , // No Cache
DEFAULT_REGISTRATION_REFRESH_INTERVAL ,
REGDEF_REGISTRATION_REFRESH_INTERVAL ,
0 , // Policy
0 , // Client
1 , // TcpIp
0 , // No Cache
MAX_NUMBER_OF_ADDRESSES_TO_REGISTER ,
1 , // Default register 1 address
0 , // Policy
0 , // Client
1 , // TcpIp
0 , // No Cache
// Micellaneous
NT_SETUP_MODE ,
0 , // Default FALSE
0 , // No policy
0 , // Client
0 , // No TcpIp
0 , // No Cache
DNS_TEST_MODE ,
0 , // Default FALSE
0 , // No policy
0 , // No Client
0 , // No TcpIp
1 , // In Cache
REMOTE_DNS_RESOLVER ,
0 , // Default FALSE
1 , // Policy
1 , // Client
0 , // No TcpIp
1 , // In Cache
// Resolver
MAX_CACHE_SIZE ,
1000 , // Default 1000 record sets
1 , // Policy
1 , // Client
0 , // No TcpIp
1 , // Cache
MAX_CACHE_TTL ,
86400 , // Default 1 day
1 , // Policy
1 , // Client
0 , // No TcpIp
1 , // Cache
MAX_NEGATIVE_CACHE_TTL ,
900 , // Default 15 minutes
1 , // Policy
1 , // Client
0 , // No TcpIp
1 , // Cache
ADAPTER_TIMEOUT_LIMIT ,
600 , // Default 10 minutes
1 , // Policy
1 , // Client
0 , // No TcpIp
1 , // Cache
SERVER_PRIORITY_TIME_LIMIT ,
300 , // Default 5 minutes
1 , // Policy
1 , // Client
0 , // No TcpIp
1 , // Cache
MAX_CACHED_SOCKETS ,
10 , // Default 10
1 , // Policy
1 , // Client
0 , // No TcpIp
1 , // Cache
// Multicast
MULTICAST_LISTEN_LEVEL ,
MCAST_LISTEN_FULL_IP6_ONLY , // Default IP6 only
1 , // Policy
0 , // No Client
0 , // No TcpIp
1 , // Cache
MULTICAST_SEND_LEVEL ,
MCAST_SEND_FULL_IP6_ONLY , // Default IP6 only
1 , // Policy
0 , // No Client
0 , // No TcpIp
1 , // Cache
//
// DHCP registration regkeys
//
// note, these are not part of the normal DNS client\resolver
// registry settings; they are only here to provide the
// regid to regname mapping so they can be read and written
// with the standard registry functions
//
DHCP_REGISTERED_DOMAIN_NAME ,
0 , // No Default
0 , // No Policy
0 , // No Client
0 , // No TcpIp
0 , // No Cache
DHCP_SENT_UPDATE_TO_IP ,
0 , // No Default
0 , // No Policy
0 , // No Client
0 , // No TcpIp
0 , // No Cache
DHCP_SENT_PRI_UPDATE_TO_IP ,
0 , // No Default
0 , // No Policy
0 , // No Client
0 , // No TcpIp
0 , // No Cache
DHCP_REGISTERED_TTL ,
0 , // No Default
0 , // No Policy
0 , // No Client
0 , // No TcpIp
0 , // No Cache
DHCP_REGISTERED_FLAGS ,
0 , // No Default
0 , // No Policy
0 , // No Client
0 , // No TcpIp
0 , // No Cache
DHCP_REGISTERED_SINCE_BOOT ,
0 , // No Default
0 , // No Policy
0 , // No Client
0 , // No TcpIp
0 , // No Cache
DHCP_DNS_SERVER_ADDRS ,
0 , // No Default
0 , // No Policy
0 , // No Client
0 , // No TcpIp
0 , // No Cache
DHCP_DNS_SERVER_ADDRS_COUNT ,
0 , // No Default
0 , // No Policy
0 , // No Client
0 , // No TcpIp
0 , // No Cache
DHCP_REGISTERED_ADDRS ,
0 , // No Default
0 , // No Policy
0 , // No Client
0 , // No TcpIp
0 , // No Cache
DHCP_REGISTERED_ADDRS_COUNT ,
0 , // No Default
0 , // No Policy
0 , // No Client
0 , // No TcpIp
0 , // No Cache
// Termination
NULL, 0, 0, 0, 0, 0
};
//
// Backward compatibility list
//
// Maps new reg id to old reg id.
// Flag fReverse indicates need to reverse (!) the value.
//
#define NO_BACK_VALUE ((DWORD)(0xffffffff))
typedef struct _Backpat
{
DWORD NewId;
DWORD OldId;
BOOL fReverse;
}
BACKPAT;
BACKPAT BackpatArray[] =
{
RegIdQueryAdapterName,
RegIdDisableAdapterDomainName,
TRUE,
RegIdRegistrationEnabled,
RegIdDisableDynamicUpdate,
TRUE,
RegIdRegisterAdapterName,
RegIdEnableAdapterDomainNameRegistration,
FALSE,
RegIdRegisterReverseLookup,
RegIdDisableReverseAddressRegistrations,
TRUE,
RegIdRegisterWanAdapters,
RegIdDisableWanDynamicUpdate,
TRUE,
RegIdRegistrationTtl,
RegIdDefaultRegistrationTTL,
FALSE,
RegIdRegistrationRefreshInterval,
RegIdDefaultRegistrationRefreshInterval,
FALSE,
RegIdRegistrationMaxAddressCount,
RegIdMaxNumberOfAddressesToRegister,
FALSE,
NO_BACK_VALUE, 0, 0
};
VOID
Reg_Init(
VOID
)
/*++
Routine Description:
Init DNS registry stuff.
Essentially this means get system version info.
Arguments:
None.
Globals:
Sets the system info globals above:
g_IsWorkstation
g_IsServer
g_IsDomainController
g_IsRegReady
Return Value:
None.
--*/
{
OSVERSIONINFOEX osvi;
BOOL bversionInfoEx;
//
// do this just once
//
if ( g_IsRegReady )
{
return;
}
//
// code validity check
// property table should have entry for every reg value plus an
// extra one for the terminator
//
DNS_ASSERT( (RegIdMax+2)*sizeof(REG_PROPERTY) ==
sizeof(RegPropertyTable) );
//
// clear globals blob
//
// DCR: warning clearing DnsGlobals but don't read them all
// this is protected by read-once deal but still kind of
//
RtlZeroMemory(
& DnsGlobals,
sizeof(DnsGlobals) );
//
// get version info
//
g_IsWin2000 = TRUE;
ZeroMemory( &osvi, sizeof(OSVERSIONINFOEX) );
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
bversionInfoEx = GetVersionEx( (OSVERSIONINFO*) &osvi );
if ( !bversionInfoEx)
{
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if ( ! GetVersionEx( (OSVERSIONINFO *) &osvi ) )
{
DNS_ASSERT( FALSE );
return;
}
}
//
// get system type -- workstation, server, DC
//
if ( bversionInfoEx )
{
if ( osvi.wProductType == VER_NT_WORKSTATION )
{
g_IsWorkstation = TRUE;
}
else if ( osvi.wProductType == VER_NT_SERVER )
{
g_IsServer = TRUE;
}
else if ( osvi.wProductType == VER_NT_DOMAIN_CONTROLLER )
{
g_IsServer = TRUE;
g_IsDomainController = TRUE;
}
ELSE_ASSERT( FALSE );
}
g_IsRegReady = TRUE;
DNSDBG( REGISTRY, (
"DNS registry init:\n"
"\tWorksta = %d\n"
"\tServer = %d\n"
"\tDC = %d\n",
g_IsWorkstation,
g_IsServer,
g_IsDomainController ));
}
//
// Registry table routines
//
PWSTR
regValueNameForId(
IN DWORD RegId
)
/*++
Routine Description:
Return registry value name for reg ID
Arguments:
RegId -- ID for value
Return Value:
Ptr to reg value name.
NULL on error.
--*/
{
DNSDBG( REGISTRY, (
"regValueNameForId( id=%d )\n",
RegId ));
//
// validate ID
//
if ( RegId > RegIdMax )
{
return( NULL );
}
//
// index into table
//
return( REGPROP_NAME(RegId) );
}
DWORD
checkBackCompat(
IN DWORD NewId,
OUT PBOOL pfReverse
)
/*++
Routine Description:
Check if have backward compatible regkey.
Arguments:
NewId -- id to check for old backward compatible id
pfReverse -- addr to receive reverse flag
Return Value:
Reg Id of old backward compatible value.
NO_BACK_VALUE if no old value.
--*/
{
DWORD i = 0;
DWORD id;
//
// loop through backcompat list looking for value
//
while ( 1 )
{
id = BackpatArray[i].NewId;
if ( id == NO_BACK_VALUE )
{
return( NO_BACK_VALUE );
}
if ( id != NewId )
{
i++;
continue;
}
// found value in backcompat array
break;
}
*pfReverse = BackpatArray[i].fReverse;
return BackpatArray[i].OldId;
}
//
// Registry session handle
//
DNS_STATUS
WINAPI
Reg_OpenSession(
OUT PREG_SESSION pRegSession,
IN DWORD Level,
IN DWORD RegId
)
/*++
Routine Description:
Open registry for DNS client info.
Arguments:
pRegSession -- ptr to unitialize reg session blob
Level -- level of access to get
RegId -- ID of value we're interested in
Return Value:
None.
--*/
{
DWORD status = NO_ERROR;
HKEY hkey = NULL;
DWORD disposition;
// auto init
Reg_Init();
//
// clear handles
//
RtlZeroMemory(
pRegSession,
sizeof( REG_SESSION ) );
//
// DCR: handle multiple access levels
//
// For know assume that if getting access to "standard"
// section we'll need both policy and regular.
//
//
// NT
// - Win2000
// - open TCPIP
// note, always open TCPIP as may not be any policy
// for some or all of our desired reg values, even
// if policy key is available
// - open policy (only if standard successful)
//
status = RegCreateKeyExW(
HKEY_LOCAL_MACHINE,
TCPIP_PARAMETERS_KEY,
0,
L"Class",
REG_OPTION_NON_VOLATILE,
KEY_READ,
NULL,
&hkey,
&disposition );
if ( status != ERROR_SUCCESS )
{
goto Done;
}
#ifdef DNSCLIENTKEY
// open DNS client key
//
// DCR: currently no DNSClient regkey
RegOpenKeyExW(
HKEY_LOCAL_MACHINE,
DNS_CLIENT_KEY,
0,
KEY_READ,
& pRegSession->hClient );
#endif
// open DNS cache key
RegOpenKeyExW(
HKEY_LOCAL_MACHINE,
DNS_CACHE_KEY,
0,
KEY_READ,
& pRegSession->hCache );
// open DNS policy key
RegOpenKeyExW(
HKEY_LOCAL_MACHINE,
DNS_POLICY_KEY,
0,
KEY_READ,
& pRegSession->hPolicy );
Done:
//
// all OS versions return TCP/IP key
//
if ( status == ERROR_SUCCESS )
{
pRegSession->hTcpip = hkey;
}
else
{
Reg_CloseSession( pRegSession );
}
DNSDBG( TRACE, (
"Leave: Reg_OpenSession( s=%d, t=%p, p=%p, c=%p )\n",
status,
pRegSession->hTcpip,
pRegSession->hPolicy,
pRegSession->hClient ));
return( status );
}
VOID
WINAPI
Reg_CloseSession(
IN OUT PREG_SESSION pRegSession
)
/*++
Routine Description:
Close registry session handle.
This means close underlying regkeys.
Arguments:
pSessionHandle -- ptr to registry session handle
Return Value:
None.
--*/
{
//
// allow sloppy cleanup
//
if ( !pRegSession )
{
return;
}
//
// close any non-NULL handles
//
if ( pRegSession->hPolicy )
{
RegCloseKey( pRegSession->hPolicy );
}
if ( pRegSession->hTcpip )
{
RegCloseKey( pRegSession->hTcpip );
}
#ifdef DNSCLIENTKEY
if ( pRegSession->hClient )
{
RegCloseKey( pRegSession->hClient );
}
#endif
if ( pRegSession->hCache )
{
RegCloseKey( pRegSession->hCache );
}
//
// clear handles (just for safety)
//
RtlZeroMemory(
pRegSession,
sizeof(REG_SESSION) );
}
//
// Registry reading routines
//
DNS_STATUS
Reg_GetDword(
IN PREG_SESSION pRegSession, OPTIONAL
IN HKEY hRegKey, OPTIONAL
IN PWSTR pwsKeyName, OPTIONAL
IN DWORD RegId,
OUT PDWORD pResult
)
/*++
Routine Description:
Read REG_DWORD value from registry.
//
// DCR: do we need to expose location result?
// (explicit, policy, defaulted)
//
Arguments:
pRegSession -- ptr to reg session already opened (OPTIONAL)
hRegKey -- explicit regkey
pwsKeyName -- key name OR dummy key
RegId -- ID for value
pResult -- addr of DWORD to recv result
pfRead -- addr to recv result of how value read
0 -- defaulted
1 -- read
Currently just use ERROR_SUCCESS to mean read rather
than defaulted.
Return Value:
ERROR_SUCCESS on success.
ErrorCode on failure -- value is then defaulted.
--*/
{
DNS_STATUS status;
REG_SESSION session;
PREG_SESSION psession = pRegSession;
PWSTR pname;
DWORD regType = REG_DWORD;
DWORD dataLength = sizeof(DWORD);
HKEY hkey;
HKEY hlocalKey = NULL;
DNSDBG( REGISTRY, (
"Reg_GetDword( s=%p, k=%p, a=%p, id=%d )\n",
pRegSession,
hRegKey,
pwsKeyName,
RegId ));
// auto init
Reg_Init();
//
// clear result for error case
//
*pResult = 0;
//
// get proper regval name
// - wide for NT
// - narrow for 9X
//
pname = regValueNameForId( RegId );
if ( !pname )
{
DNS_ASSERT( FALSE );
return( ERROR_INVALID_PARAMETER );
}
//
// DCR: can use function pointers for wide narrow
//
//
// three paradigms
//
// 1) specific key (adapter or something else)
// => use it
//
// 2) specific key name (adapter or dummy key location)
// => open key
// => use it
// => close
//
// 3) session -- passed in or created (default)
// => use pRegSession or open new
// => try policy first then TCPIP parameters
// => close if open
//
if ( hRegKey )
{
hkey = hRegKey;
}
else if ( pwsKeyName )
{
hkey = Reg_CreateKey(
pwsKeyName,
FALSE // read access
);
if ( !hkey )
{
status = GetLastError();
goto Done;
}
hlocalKey = hkey;
}
else
{
// open reg handle if not open
if ( !psession )
{
status = Reg_OpenSession(
&session,
0, // standard level
RegId // target key
);
if ( status != ERROR_SUCCESS )
{
goto Done;
}
psession = &session;
}
// try policy section -- if available
hkey = psession->hPolicy;
if ( hkey && REGPROP_POLICY(RegId) )
{
status = RegQueryValueExW(
hkey,
pname,
0,
& regType,
(PBYTE) pResult,
& dataLength
);
if ( status == ERROR_SUCCESS )
{
goto DoneSuccess;
}
}
// unsuccessful -- try DnsClient
#ifdef DNSCLIENTKEY
hkey = psession->hClient;
if ( hkey && REGPROP_CLIENT(RegId) )
{
status = RegQueryValueExW(
hkey,
pname,
0,
& regType,
(PBYTE) pResult,
& dataLength
);
if ( status == ERROR_SUCCESS )
{
goto DoneSuccess;
}
}
#endif
// unsuccessful -- try DnsCache
hkey = psession->hCache;
if ( hkey && REGPROP_CACHE(RegId) )
{
status = RegQueryValueExW(
hkey,
pname,
0,
& regType,
(PBYTE) pResult,
& dataLength
);
if ( status == ERROR_SUCCESS )
{
goto DoneSuccess;
}
}
// unsuccessful -- try TCPIP key
// - if have open session it MUST include TCPIP key
hkey = psession->hTcpip;
if ( hkey && REGPROP_TCPIP(RegId) )
{
status = RegQueryValueExW(
hkey,
pname,
0,
& regType,
(PBYTE) pResult,
& dataLength
);
if ( status == ERROR_SUCCESS )
{
goto DoneSuccess;
}
}
status = ERROR_FILE_NOT_FOUND;
goto Done;
}
//
// explict key (passed in or from name)
//
if ( hkey )
{
status = RegQueryValueExW(
hkey,
pname,
0,
& regType,
(PBYTE) pResult,
& dataLength
);
}
ELSE_ASSERT_FALSE;
Done:
//
// if value not found, check for backward compatibility value
//
if ( status != ERROR_SUCCESS )
{
DWORD oldId;
BOOL freverse;
oldId = checkBackCompat( RegId, &freverse );
if ( oldId != NO_BACK_VALUE )
{
DWORD backValue;
status = Reg_GetDword(
psession,
( psession ) ? NULL : hkey,
( psession ) ? NULL : pwsKeyName,
oldId,
& backValue );
if ( status == ERROR_SUCCESS )
{
if ( freverse )
{
backValue = !backValue;
}
*pResult = backValue;
}
}
}
// default the value if read failed
if ( status != ERROR_SUCCESS )
{
*pResult = REGPROP_DEFAULT( RegId );
}
DoneSuccess:
// cleanup any regkey's opened
if ( psession == &session )
{
Reg_CloseSession( psession );
}
else if ( hlocalKey )
{
RegCloseKey( hlocalKey );
}
return( status );
}
//
// Reg utilities
//
DNS_STATUS
privateRegReadValue(
IN HKEY hKey,
IN DWORD RegId,
IN DWORD Flag,
OUT PBYTE * ppBuffer,
OUT PDWORD pBufferLength
)
/*++
Routine Description:
Main registry reading routine.
Handles sizing, allocations and conversions as necessary.
Arguments:
hKey -- handle of the key whose value field is retrieved.
RegId -- reg value ID, assumed to be validated (in table)
Flag -- reg flags
DNSREG_FLAG_DUMP_EMPTY
DNSREG_FLAG_GET_UTF8
ppBuffer -- ptr to address to receive buffer ptr
pBufferLength -- addr to receive buffer length
Return Value:
ERROR_SUCCESS if successful.
ErrorCode on failure.
--*/
{
DWORD status;
PWSTR pname;
DWORD valueType = 0; // prefix
DWORD valueSize = 0; // prefix
PBYTE pdataBuffer;
PBYTE pallocBuffer = NULL;
//
// query for buffer size
//
pname = REGPROP_NAME( RegId );
status = RegQueryValueExW(
hKey,
pname,
0,
&valueType,
NULL,
&valueSize );
if ( status != ERROR_SUCCESS )
{
return( status );
}
//
// setup result buffer
//
switch( valueType )
{
case REG_DWORD:
pdataBuffer = (PBYTE) ppBuffer;
break;
case REG_SZ:
case REG_MULTI_SZ:
case REG_EXPAND_SZ:
case REG_BINARY:
// if size is zero, still allocate empty string
// - min alloc DWORD
// - can't possibly alloc smaller
// - good clean init to zero includes MULTISZ zero
// - need at least WCHAR string zero init
// and much catch small regbinary (1,2,3)
if ( valueSize <= sizeof(DWORD) )
{
valueSize = sizeof(DWORD);
}
pallocBuffer = pdataBuffer = ALLOCATE_HEAP( valueSize );
if ( !pdataBuffer )
{
return( DNS_ERROR_NO_MEMORY );
}
*(PDWORD)pdataBuffer = 0;
break;
default:
return( ERROR_INVALID_PARAMETER );
}
//
// query for data
//
status = RegQueryValueExW(
hKey,
pname,
0,
&valueType,
pdataBuffer,
&valueSize );
if ( status != ERROR_SUCCESS )
{
goto Cleanup;
}
//
// setup return buffer
//
switch( valueType )
{
case REG_DWORD:
case REG_BINARY:
break;
case REG_SZ:
case REG_EXPAND_SZ:
case REG_MULTI_SZ:
//
// dump empty strings?
//
// note: we always allocate at least a DWORD and
// set it NULL, so rather than a complex test for
// different reg types and char sets, can just test
// if that DWORD is still NULL
//
// DCR: do we want to screen whitespace-empty strings
// - example blank string
//
if ( Flag & DNSREG_FLAG_DUMP_EMPTY )
{
if ( valueSize==0 ||
*(PDWORD)pdataBuffer == 0 )
{
status = ERROR_INVALID_DATA;
goto Cleanup;
}
}
//
// force NULL termination
// - during security push, someone raised the question of whether
// the registry guarantees NULL termination on corrupted data
//
if ( valueSize == 0 )
{
*(PDWORD)pdataBuffer = 0;
}
else
{
INT lastChar = valueSize/sizeof(WCHAR) - 1;
if ( lastChar >= 0 )
{
((PWSTR)pdataBuffer)[ lastChar ] = 0;
}
}
//
// by default we return strings as unicode
//
// if flagged, return in UTF8
//
if ( Flag & DNSREG_FLAG_GET_UTF8 )
{
PBYTE putf8Buffer = ALLOCATE_HEAP( valueSize * 2 );
if ( !putf8Buffer )
{
status = DNS_ERROR_NO_MEMORY;
goto Cleanup;
}
if ( !Dns_UnicodeToUtf8(
(PWSTR) pdataBuffer,
valueSize / sizeof(WCHAR),
putf8Buffer,
valueSize * 2 ) )
{
FREE_HEAP( putf8Buffer );
status = ERROR_INVALID_DATA;
goto Cleanup;
}
FREE_HEAP( pallocBuffer );
pallocBuffer = NULL;
pdataBuffer = putf8Buffer;
}
break;
default:
break;
}
Cleanup:
//
// set return
// - REG_DWORD writes DWORD to ppBuffer directly
// - otherwise ppBuffer set to allocated buffer ptr
// or cleanup
// - on failure dump allocated buffer
//
if ( status == ERROR_SUCCESS )
{
if ( valueType != REG_DWORD )
{
*ppBuffer = pdataBuffer;
}
*pBufferLength = valueSize;
}
else
{
if ( valueType != REG_DWORD )
{
*ppBuffer = NULL;
}
else
{
*(PDWORD)ppBuffer = 0;
}
*pBufferLength = 0;
FREE_HEAP( pallocBuffer );
}
return( status );
}
DNS_STATUS
Reg_GetValueEx(
IN PREG_SESSION pRegSession, OPTIONAL
IN HKEY hRegKey, OPTIONAL
IN PWSTR pwsAdapter, OPTIONAL
IN DWORD RegId,
IN DWORD ValueType,
IN DWORD Flag,
OUT PBYTE * ppBuffer
)
/*++
Routine Description:
Arguments:
pRegSession -- ptr to registry session, OPTIONAL
hRegKey -- handle to open regkey OPTIONAL
pwsAdapter -- name of adapter to query under OPTIONAL
RegId -- value ID
ValueType -- reg type of value
Flag -- flags with tweaks to lookup
ppBuffer -- addr to receive buffer ptr
Note, for REG_DWORD, DWORD data is written directly to this
location instead of a buffer being allocated and it's ptr
being written.
Return Value:
ERROR_SUCCESS if successful.
Registry error code on failure.
--*/
{
DNS_STATUS status = ERROR_FILE_NOT_FOUND;
REG_SESSION session;
PREG_SESSION psession = pRegSession;
PWSTR pname;
DWORD regType = REG_DWORD;
DWORD dataLength;
HKEY hkey;
HKEY hadapterKey = NULL;
DNSDBG( REGISTRY, (
"Reg_GetValueEx( s=%p, k=%p, id=%d )\n",
pRegSession,
hRegKey,
RegId ));
ASSERT( !pwsAdapter );
// auto init
Reg_Init();
//
// get regval name
//
pname = regValueNameForId( RegId );
if ( !pname )
{
DNS_ASSERT( FALSE );
status = ERROR_INVALID_PARAMETER;
goto FailedDone;
}
//
// two paradigms
//
// 1) specific key (adapter or something else)
// => use it
// => open adapter subkey if necessary
//
// 2) standard
// => try policy first, then DNSCache, then TCPIP
// => use pRegSession or open it
//
if ( hRegKey )
{
hkey = hRegKey;
// need to open adapter subkey
if ( pwsAdapter )
{
status = RegOpenKeyExW(
hkey,
pwsAdapter,
0,
KEY_QUERY_VALUE,
& hadapterKey );
if ( status != ERROR_SUCCESS )
{
goto FailedDone;
}
hkey = hadapterKey;
}
}
else
{
// open reg handle if not open
if ( !pRegSession )
{
status = Reg_OpenSession(
&session,
0, // standard level
RegId // target key
);
if ( status != ERROR_SUCCESS )
{
goto FailedDone;
}
psession = &session;
}
// try policy section -- if available
hkey = psession->hPolicy;
if ( hkey && REGPROP_POLICY(RegId) )
{
status = privateRegReadValue(
hkey,
RegId,
Flag,
ppBuffer,
& dataLength
);
if ( status == ERROR_SUCCESS )
{
goto Done;
}
}
// try DNS cache -- if available
hkey = psession->hCache;
if ( hkey && REGPROP_CACHE(RegId) )
{
status = privateRegReadValue(
hkey,
RegId,
Flag,
ppBuffer,
& dataLength
);
if ( status == ERROR_SUCCESS )
{
goto Done;
}
}
// unsuccessful -- use TCPIP key
hkey = psession->hTcpip;
if ( !hkey )
{
goto Done;
}
}
//
// explict key OR standard key case
//
status = privateRegReadValue(
hkey,
RegId,
Flag,
ppBuffer,
& dataLength
);
if ( status == ERROR_SUCCESS )
{
goto Done;
}
FailedDone:
//
// if failed
// - for REG_DWORD, default the value
// - for strings, ensure NULL return buffer
// this takes care of cases where privateRegReadValue()
// never got called
//
if ( status != ERROR_SUCCESS )
{
if ( ValueType == REG_DWORD )
{
*(PDWORD) ppBuffer = REGPROP_DEFAULT( RegId );
}
else
{
*ppBuffer = NULL;
}
}
Done:
// cleanup any regkey's opened
if ( psession == &session )
{
Reg_CloseSession( psession );
}
if ( hadapterKey )
{
RegCloseKey( hadapterKey );
}
return( status );
}
DNS_STATUS
Reg_GetIpArray(
IN PREG_SESSION pRegSession, OPTIONAL
IN HKEY hRegKey, OPTIONAL
IN PWSTR pwsAdapter, OPTIONAL
IN DWORD RegId,
IN DWORD ValueType,
OUT PIP4_ARRAY * ppIpArray
)
/*++
Routine Description:
Arguments:
pRegSession -- ptr to registry session, OPTIONAL
hRegKey -- handle to open regkey OPTIONAL
pwsAdapter -- name of adapter to query under OPTIONAL
RegId -- value ID
ValueType -- currently ignored, but could later use
to distinguish REG_SZ from REG_MULTI_SZ
processing
ppIpArray -- addr to receive IP array ptr
- array is allocated with Dns_Alloc(),
caller must free with Dns_Free()
Return Value:
ERROR_SUCCESS if successful.
Registry error code on failure.
--*/
{
DNS_STATUS status;
PSTR pstring = NULL;
DNSDBG( REGISTRY, (
"Reg_GetIpArray( s=%p, k=%p, id=%d )\n",
pRegSession,
hRegKey,
RegId ));
//
// make call to get IP array as string
//
status = Reg_GetValueEx(
pRegSession,
hRegKey,
pwsAdapter,
RegId,
REG_SZ, // only supported type is REG_SZ
DNSREG_FLAG_GET_UTF8, // get as narrow
& pstring );
if ( status != ERROR_SUCCESS )
{
ASSERT( pstring == NULL );
return( status );
}
//
// convert from string to IP array
//
// note: this call is limited to a parsing limit
// but it is a large number suitable for stuff
// like DNS server lists
//
// DCR: use IP array builder for local IP address
// then need Dns_CreateIpArrayFromMultiIpString()
// to use count\alloc method when buffer overflows
//
status = Dns_CreateIpArrayFromMultiIpString(
pstring,
ppIpArray );
// cleanup
if ( pstring )
{
FREE_HEAP( pstring );
}
return( status );
}
//
// Registry writing routines
//
HKEY
WINAPI
Reg_CreateKey(
IN PWSTR pwsKeyName,
IN BOOL bWrite
)
/*++
Routine Description:
Open registry key.
The purpose of this routine is simply to functionalize
opening with\without an adapter name.
So caller can pass through adapter name argument instead
of building key name or doing two opens for adapter
present\absent.
This is NT only.
Arguments:
pwsKeyName -- key "name"
this is one of the REGKEY_X from registry.h
OR
adapter name
bWrite -- TRUE for write access, FALSE for read
Return Value:
New opened key.
--*/
{
HKEY hkey = NULL;
DWORD disposition;
DWORD status;
PWSTR pnameKey;
WCHAR nameBuffer[ MAX_PATH+1 ];
//
// determine key name
//
// this is either DNSKEY_X dummy pointer from registry.h
// OR
// is an adapter name;
//
// - if adapter given, open under it
// adapters are under TCPIP\Interfaces
// - any other specific key
// - default is TCPIP params key
//
// note: if if grows too big, turn into table
//
if ( pwsKeyName <= REGKEY_DNS_MAX )
{
if ( pwsKeyName == REGKEY_TCPIP_PARAMETERS )
{
pnameKey = TCPIP_PARAMETERS_KEY;
}
else if ( pwsKeyName == REGKEY_DNS_CACHE )
{
pnameKey = DNS_CACHE_KEY;
}
else if ( pwsKeyName == REGKEY_DNS_POLICY )
{
pnameKey = DNS_POLICY_KEY;
}
else if ( pwsKeyName == REGKEY_SETUP_MODE_LOCATION )
{
pnameKey = NT_SETUP_MODE_KEY;
}
else
{
pnameKey = TCPIP_PARAMETERS_KEY;
}
}
else // adapter name
{
_snwprintf(
nameBuffer,
MAX_PATH,
L"%s%s",
TCPIP_INTERFACES_KEY,
pwsKeyName );
pnameKey = nameBuffer;
}
//
// create\open key
//
if ( bWrite )
{
status = RegCreateKeyExW(
HKEY_LOCAL_MACHINE,
pnameKey,
0,
L"Class",
REG_OPTION_NON_VOLATILE,
KEY_WRITE,
NULL,
& hkey,
& disposition );
}
else
{
status = RegOpenKeyExW(
HKEY_LOCAL_MACHINE,
pnameKey,
0,
KEY_QUERY_VALUE,
& hkey );
}
if ( status != ERROR_SUCCESS )
{
SetLastError( status );
}
ELSE_ASSERT( hkey != NULL );
return( hkey );
}
DNS_STATUS
WINAPI
Reg_SetDwordValueByName(
IN PVOID pReserved,
IN HKEY hRegKey,
IN PWSTR pwsNameKey, OPTIONAL
IN PWSTR pwsNameValue, OPTIONAL
IN DWORD dwValue
)
/*++
Routine Description:
Set DWORD regkey.
Arguments:
pReserved -- reserved (may become session)
hRegKey -- existing key to set under OPTIONAL
pwsNameKey -- name of key or adapter to set under
pwsNameValue -- name of reg value to set
dwValue -- value to set
Return Value:
ERROR_SUCCESS if successful.
ErrorCode on failure.
--*/
{
HKEY hkey;
DNS_STATUS status;
//
// open key, if not provided
// - if adapter given, open under it
// - otherwise TCPIP params key
//
hkey = hRegKey;
if ( !hkey )
{
hkey = Reg_CreateKey(
pwsNameKey,
TRUE // open for write
);
if ( !hkey )
{
return( GetLastError() );
}
}
//
// write back value
//
status = RegSetValueExW(
hkey,
pwsNameValue,
0,
REG_DWORD,
(LPBYTE) &dwValue,
sizeof(DWORD) );
if ( !hRegKey )
{
RegCloseKey( hkey );
}
return status;
}
DNS_STATUS
WINAPI
Reg_SetDwordValue(
IN PVOID pReserved,
IN HKEY hRegKey,
IN PWSTR pwsNameKey, OPTIONAL
IN DWORD RegId,
IN DWORD dwValue
)
/*++
Routine Description:
Set DWORD regkey.
Arguments:
pReserved -- reserved (may become session)
hRegKey -- existing key to set under OPTIONAL
pwsNameKey -- name of key or adapter to set under
RegId -- id of value to set
dwValue -- value to set
Return Value:
ERROR_SUCCESS if successful.
ErrorCode on failure.
--*/
{
//
// write back value using name of id
//
return Reg_SetDwordValueByName(
pReserved,
hRegKey,
pwsNameKey,
REGPROP_NAME( RegId ),
dwValue );
}
//
// End registry.c
//