/*++ Copyright (c) 1999-2001 Microsoft Corporation Module Name: regfig.c Abstract: Domain Name System (DNS) API Configuration routines. Author: Jim Gilroy (jamesg) September 1999 Revision History: --*/ #include "local.h" // // Table for quick lookup of DWORD\BOOL reg values // // DCR: read directly to config BLOB with regID indexes // you can't screw that up // #define DWORD_PTR_ARRAY_END ((PDWORD) (DWORD_PTR)(-1)) PDWORD RegDwordPtrArray[] = { // basic -- not DWORDs NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // query (PDWORD) &g_QueryAdapterName, (PDWORD) &g_UseNameDevolution, (PDWORD) &g_PrioritizeRecordData, (PDWORD) &g_AllowUnqualifiedQuery, (PDWORD) &g_AppendToMultiLabelName, (PDWORD) &g_ScreenBadTlds, (PDWORD) &g_ScreenUnreachableServers, (PDWORD) &g_FilterClusterIp, (PDWORD) &g_WaitForNameErrorOnAll, (PDWORD) &g_UseEdns, (PDWORD) &g_QueryIpMatching, // update (PDWORD) &g_RegistrationEnabled, (PDWORD) &g_RegisterPrimaryName, (PDWORD) &g_RegisterAdapterName, (PDWORD) &g_RegisterReverseLookup, (PDWORD) &g_RegisterWanAdapters, (PDWORD) &g_RegistrationTtl, (PDWORD) &g_RegistrationRefreshInterval, (PDWORD) &g_RegistrationMaxAddressCount, (PDWORD) &g_UpdateSecurityLevel, (PDWORD) &g_UpdateZoneExcludeFile, (PDWORD) &g_UpdateTopLevelDomains, // backcompat NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // micellaneous NULL, //g_InNTSetupMode, // not in standard location (PDWORD) &g_DnsTestMode, NULL, // remote resolver not a DWORD // resolver (PDWORD) &g_MaxCacheSize, (PDWORD) &g_MaxCacheTtl, (PDWORD) &g_MaxNegativeCacheTtl, (PDWORD) &g_AdapterTimeoutLimit, (PDWORD) &g_ServerPriorityTimeLimit, (PDWORD) &g_MaxCachedSockets, // multicast resolver (PDWORD) &g_MulticastListenLevel, (PDWORD) &g_MulticastSendLevel, // termination DWORD_PTR_ARRAY_END }; // // Array indicating which registry values // were read versus defaulted // DWORD RegValueWasReadArray[ RegIdValueCount ]; // // Check for empty reg value (string) // // DCR: consider more detailed white space check // #define IS_EMPTY_STRING(psz) (*(psz)==0) // // General registry\config utils // VOID PrintConfigGlobals( IN PSTR pszHeader ) /*++ Routine Description: Print config globals. Arguments: pszHeader -- header to print with Return Value: ERROR_SUCCESS if successful. ErrorCode on failure. --*/ { DWORD propId; // // print each property // DnsDbg_Lock(); DnsDbg_Printf( "%s\n", pszHeader ? pszHeader : "Registry Globals:" ); propId = 0; for( propId=0; propId<=RegIdValueGlobalMax; propId++ ) { PDWORD pdword = RegDwordPtrArray[propId]; // separators if ( propId == RegIdQueryAdapterName ) { DnsDbg_Printf( "\t-- Query:\n" ); } else if ( propId == RegIdRegistrationEnabled ) { DnsDbg_Printf( "\t-- Update:\n" ); } else if ( propId == RegIdSetupMode ) { DnsDbg_Printf( "\t-- Miscellaneous:\n" ); } else if ( propId == RegIdMaxCacheSize ) { DnsDbg_Printf( "\t-- Resolver\n" ); } // NULL indicates not DWORD or not standard if ( !pdword ) { continue; } // terminate on bogus ptr if ( pdword == DWORD_PTR_ARRAY_END ) { ASSERT( FALSE ); break; } DnsDbg_Printf( "\t%-36S= %8d (read=%d)\n", REGPROP_NAME( propId ), * pdword, RegValueWasReadArray[ propId ] ); } DnsDbg_Printf( "\t-- Random:\n" "\tIsDnsServer = %d\n" "\tInNTSetupMode = %d\n" "\tDnsTestMode = %08x\n\n", g_IsDnsServer, g_InNTSetupMode, g_DnsTestMode ); DnsDbg_Unlock(); } DNS_STATUS Reg_ReadGlobalsEx( IN DWORD dwFlag, IN PVOID pRegSession OPTIONAL ) /*++ Routine Description: Read globals from registry. Arguments: dwFlag -- flag indicating read level // // DCR: reg read flag unimplemented // // note: should have option to NOT read some registry // values for case when cache off, then could // skip useless cache info when building local // networkinfo blob // pRegSession -- ptr to existing registry session Return Value: ERROR_SUCCESS if successful. ErrorCode on failure. --*/ { DWORD propId; REG_SESSION regSession; PREG_SESSION psession; DNS_STATUS status; DNSDBG( TRACE, ( "Reg_ReadGlobalsEx( %08x, %p )\n", dwFlag, pRegSession )); // // basic registry init // - includes system global // Reg_Init(); // // code validity check // property table should have entry for every reg value plus an // extra one for the terminator // #if DBG DNS_ASSERT( (RegIdValueCount+1)*sizeof(PDWORD) == sizeof(RegDwordPtrArray) ); #endif // // open registry session -- if not passed in // psession = (PREG_SESSION) pRegSession; if ( !psession ) { psession = ®Session; status = Reg_OpenSession( psession, 0, 0 ); if ( status != ERROR_SUCCESS ) { return( status ); } } // // clear "value was read" array // RtlZeroMemory( RegValueWasReadArray, sizeof( RegValueWasReadArray ) ); // // MS DNS? // g_IsDnsServer = Reg_IsMicrosoftDnsServer(); // // remote resolver? // - not currently enabled // //g_pwsRemoteResolver = DnsGetResolverAddress(); g_pwsRemoteResolver = NULL; // // read\set each DWORD\BOOL registry value // propId = 0; for( propId=0; propId<=RegIdValueGlobalMax; propId++ ) { PDWORD pdword = RegDwordPtrArray[propId]; // NULL indicates not DWORD or not standard if ( !pdword ) { continue; } // terminate on bogus ptr if ( pdword == DWORD_PTR_ARRAY_END ) { ASSERT( FALSE ); break; } status = Reg_GetDword( psession, // reg session NULL, // no key NULL, // standard location propId, // index is property id pdword ); // set fRead flag if value found in registry if ( status == ERROR_SUCCESS ) { RegValueWasReadArray[propId] = TRUE; } } // // registration refresh defaults are different for DC // if ( !RegValueWasReadArray[ RegIdRegistrationRefreshInterval ] ) { if ( g_IsDomainController ) { g_RegistrationRefreshInterval = REGDEF_REGISTRATION_REFRESH_INTERVAL_DC; } ELSE_ASSERT( g_RegistrationRefreshInterval == REGDEF_REGISTRATION_REFRESH_INTERVAL ); } // // non-standard registry values // - setup mode // Reg_GetDword( psession, NULL, // no key REGKEY_SETUP_MODE_LOCATION, RegIdSetupMode, (PDWORD) &g_InNTSetupMode ); // // DCR: flip in policy globals and do single read here // or since they are only relevant to adapter // list and registration, keep separate // // fundamentally the question is how separate is the // adapter list read from other globals? // // close local session registry handles if ( psession == ®Session ) { Reg_CloseSession( psession ); } IF_DNSDBG( INIT ) { PrintConfigGlobals( "Read Registry Globals" ); } return( ERROR_SUCCESS ); } DNS_STATUS Reg_RefreshUpdateConfig( VOID ) /*++ Routine Description: Read\refresh update config. This routine encapsulates getting all update config info current before any update operation. Arguments: None Return Value: ERROR_SUCCESS if successful. Error code on failure. --*/ { // // read all global DWORDs if haven't been read "recently" // // note: adapter specific stuff is read building network config; // here were are just insuring that we have top level globals // current; specifically test was blocked because the // update TLD flag was not being reread // // DCR: when have change\notify this should just tie into // global config read // return Reg_ReadGlobalsEx( 0, NULL ); } // // Special DNS property routines // DNS_STATUS Reg_ReadPrimaryDomainName( IN PREG_SESSION pRegSession, OPTIONAL IN HKEY hRegKey, OPTIONAL OUT PWSTR * ppPrimaryDomainName ) /*++ Routine Description: Read primary domain name. Arguments: pRegSession -- ptr to registry session, OPTIONAL hRegKey -- handle to open regkey OPTIONAL (currently unimplemented) ppPrimaryDomainName -- addr to recv ptr to PDN Return Value: ERROR_SUCCESS if successful. Error code on failure. --*/ { DNS_STATUS status; REG_SESSION session; PREG_SESSION psession = NULL; PWSTR pdomainName = NULL; HKEY holdPolicyKey = NULL; HKEY hkeyPolicy; DNSDBG( TRACE, ( "Reg_ReadPrimaryDomainName()\n" )); ASSERT( !hRegKey ); // // open reg handle if not open // // note: worth doing here, because if we default the open // in the calls below, we will make unnecessary reg calls // -- won't be able to screen for policy existence // so policy PDN name will be looked for in TCPIP // -- the second call for the TCPIP domain name, will also // check in the policy area (if exists) // psession = pRegSession; if ( !psession ) { psession = &session; status = Reg_OpenSession( psession, 0, // standard level 0 // no specific value, open both ); if ( status != ERROR_SUCCESS ) { goto Done; } } // // try policy // - no policy pickup for DCs // - first try new WindowsNT policy // - if not found, try policy used in Win2K // hkeyPolicy = psession->hPolicy; if ( hkeyPolicy ) { status = Reg_GetValue( NULL, // don't send whole session hkeyPolicy, // use explicit policy key RegIdPrimaryDomainName, REGTYPE_DNS_NAME, (PBYTE *) &pdomainName ); if ( pdomainName ) { goto Found; } } // // not found in new, open old policy // status = RegOpenKeyExW( HKEY_LOCAL_MACHINE, DNS_POLICY_WIN2K_KEY, 0, KEY_QUERY_VALUE, & holdPolicyKey ); if ( holdPolicyKey ) { status = Reg_GetValue( NULL, // don't send whole session holdPolicyKey, // use explicit policy key RegIdPrimaryDnsSuffix, REGTYPE_DNS_NAME, (PBYTE *) &pdomainName ); RegCloseKey( holdPolicyKey ); if ( pdomainName ) { goto Found; } } // // no policy name // - try DNS client // - try standard TCPIP location // note under TCPIP it's "Domain" // #ifdef DNSCLIENTKEY if ( psession->hClient ) { status = Reg_GetValue( NULL, // don't send whole session psession->hClient, // send client key explicitly RegIdPrimaryDomainName, REGTYPE_DNS_NAME, (PBYTE *) &pdomainName ); if ( pdomainName ) { goto Found; } } #endif status = Reg_GetValue( NULL, // don't send whole session psession->hTcpip, // send TCPIP key explicitly RegIdDomainName, REGTYPE_DNS_NAME, (PBYTE *) &pdomainName ); Found: // dump name if empty\useless if ( pdomainName && ( wcslen( pdomainName ) == 0 ) ) { FREE_HEAP( pdomainName ); pdomainName = NULL; } Done: DNSDBG( TRACE, ( "Read PDN = %S\n", pdomainName )); // set domain name OUT param *ppPrimaryDomainName = pdomainName; // cleanup any regkey's opened if ( psession == &session ) { Reg_CloseSession( psession ); } return( status ); } BOOL Reg_IsMicrosoftDnsServer( VOID ) /*++ Routine Description: Read registry to determine if MS DNS server. Arguments: None Return Value: ERROR_SUCCESS if successful. Error code on failure. --*/ { DWORD status = NO_ERROR; HKEY hkey = NULL; // // open services key to determine whether the DNS server is installed. // // DCR: read DNS server only once // - however need some sort of callback so we can pick this up // after install // status = RegOpenKeyExW( HKEY_LOCAL_MACHINE, DNS_SERVER_KEY, 0, KEY_QUERY_VALUE, &hkey ); if ( status != ERROR_SUCCESS ) { return FALSE; } RegCloseKey( hkey ); return TRUE; } // // Reg info read. // These are read routines for info beyond flat globals. // // Three types of info: // - global // - adapter specific // - update // DNS_STATUS Reg_ReadGlobalInfo( IN PREG_SESSION pRegSession, OUT PREG_GLOBAL_INFO pRegInfo ) /*++ Routine Description: Read DNS registry info, not read in flat read. This covers all the allocated stuff, plus policy stuff for adapter info. -- primary domain name -- adapter policy - domain name - DNS servers - flag overrides Arguments: pRegSession -- registry session pRegInfo -- blob to hold reg info Return Value: ERROR_SUCCESS if successful. Error code on failure. --*/ { DNS_STATUS status; REG_SESSION regSession; PREG_SESSION pregSession = pRegSession; HKEY hkeyPolicy = NULL; DNSDBG( TRACE, ( "Reg_ReadGlobalInfo( %p, %p )\n", pRegSession, pRegInfo )); // // clear reg info blob // RtlZeroMemory( pRegInfo, sizeof( *pRegInfo ) ); // // open the registry // if ( !pregSession ) { pregSession = ®Session; status = Reg_OpenSession( pregSession, 0, 0 ); if ( status != ERROR_SUCCESS ) { return( status ); } } // // if not read force registry read // status = Reg_ReadGlobalsEx( 0, // no flag, read it all pregSession ); // // primary domain name // Reg_ReadPrimaryDomainName( pregSession, NULL, // no specific key & pRegInfo->pszPrimaryDomainName ); // // host name // Reg_GetValue( pregSession, NULL, // no key RegIdHostName, REGTYPE_DNS_NAME, (PBYTE *) &pRegInfo->pszHostName ); // // pick up required registry values from globals // pRegInfo->fUseNameDevolution = g_UseNameDevolution; // // policy overrides for adapter info // - enable adapter registration // - DNS servers // - domain name // // note, we need both value and found\not-found flag // as value overrides only when it exists // hkeyPolicy = pregSession->hPolicy; if ( !hkeyPolicy ) { goto Done; } // // policy for register adapter name? // status = Reg_GetDword( NULL, // no session hkeyPolicy, // policy NULL, // no adapter RegIdRegisterAdapterName, & pRegInfo->fRegisterAdapterName ); if ( status == ERROR_SUCCESS ) { pRegInfo->fPolicyRegisterAdapterName = TRUE; } // // policy for adapter domain name? // status = Reg_GetValue( NULL, // no session hkeyPolicy, RegIdAdapterDomainName, REGTYPE_DNS_NAME, (PBYTE *) &pRegInfo->pszAdapterDomainName ); // // policy for adapter DNS server lists // status = Reg_GetIpArray( NULL, // no session hkeyPolicy, NULL, // no adapter RegIdDnsServers, REG_SZ, &pRegInfo->pDnsServerArray ); Done: // if opened session -- close if ( pregSession && !pRegSession ) { Reg_CloseSession( pregSession ); } DNSDBG( TRACE, ( "Leave Reg_ReadGlobalInfo()\n" "\tPDN = %S\n" "\tPolicy:\n" "\t\tRegister Adapter = %d\n" "\t\tAdapterName = %S\n" "\t\tDNS servers = %p\n", pRegInfo->pszPrimaryDomainName, pRegInfo->fRegisterAdapterName, pRegInfo->pszAdapterDomainName, pRegInfo->pDnsServerArray )); return ERROR_SUCCESS; } VOID Reg_FreeGlobalInfo( IN OUT PREG_GLOBAL_INFO pRegInfo, IN BOOL fFreeBlob ) /*++ Routine Description: Free registry adapter policy info blob. Arguments: pRegInfo -- adapter policy blob to free fFreeBlob -- flag to free blob itself FALSE -- just free allocated data fields TRUE -- also free blob itself Return Value: ERROR_SUCCESS if successful. Error code on failure. --*/ { DNSDBG( TRACE, ( "Reg_FreeGlobalInfo( %p )\n", pRegInfo )); // allow sloppy cleanup if ( !pRegInfo ) { return; } // // free data // - primary DNS name // - policy adapter name // - policy DNS server list // if ( pRegInfo->pszPrimaryDomainName ) { FREE_HEAP( pRegInfo->pszPrimaryDomainName ); } if ( pRegInfo->pszHostName ) { FREE_HEAP( pRegInfo->pszHostName ); } if ( pRegInfo->pszAdapterDomainName ) { FREE_HEAP( pRegInfo->pszAdapterDomainName ); } if ( pRegInfo->pDnsServerArray ) { FREE_HEAP( pRegInfo->pDnsServerArray ); } // free blob itself if ( fFreeBlob ) { FREE_HEAP( pRegInfo ); } } DNS_STATUS Reg_ReadAdapterInfo( IN PWSTR pszAdapterName, IN PREG_SESSION pRegSession, IN PREG_GLOBAL_INFO pRegInfo, OUT PREG_ADAPTER_INFO pBlob ) /*++ Routine Description: Read adapter registry info. Arguments: pszAdapterName -- adapter name (registry name) pRegSession -- registry session pRegInfo -- registry global info pBlob -- adapter info blob to fill in Return Value: ERROR_SUCCESS if successful. Error code on failure. --*/ { DNS_STATUS status; HKEY hkeyAdapter = NULL; PWSTR padapterDomainName = NULL; WCHAR adapterParamKey[ MAX_PATH+1 ]; DNSDBG( TRACE, ( "ReadRegAdapterInfo( %S, %p, %p, %p )\n", pszAdapterName, pRegSession, pRegInfo, pBlob )); // // clear adapter blob // RtlZeroMemory( pBlob, sizeof(*pBlob) ); // // bail if no adapter // // note: this check\bail is only in place to allow call to // Reg_ReadUpdateInfo() to be made in asyncreg.c without // specifying an adapter; this allows us to make the call // before the adapter check and therefore skip a separate // registry op to get current g_IsDnsServer global; // no actual use will be made of REG_ADAPTER_INFO blob if ( !pszAdapterName ) { return ERROR_SUCCESS; } // // open adapter key for read // // DCR: fail on adapter key name overflow // DCR: this may be backwards -- ie need %s%s // _snwprintf( adapterParamKey, MAX_PATH, L"%s%s", TCPIP_INTERFACES_KEY, pszAdapterName ); adapterParamKey[ MAX_PATH ] = 0; status = RegOpenKeyExW( HKEY_LOCAL_MACHINE, adapterParamKey, 0, KEY_READ, &hkeyAdapter ); if ( status != NO_ERROR ) { DNSDBG( ANY, ( "Failed open of adapter key %S!\n", adapterParamKey )); return( status ); } // // query with adapter name // - OFF global overrides // pBlob->fQueryAdapterName = g_QueryAdapterName; if ( g_QueryAdapterName ) { Reg_GetDword( NULL, // no session, hkeyAdapter, // explicit key NULL, // no adapter name RegIdQueryAdapterName, & pBlob->fQueryAdapterName ); } // // check if adapter IPs get registered // - OFF global overrides // pBlob->fRegistrationEnabled = g_RegistrationEnabled; if ( g_RegistrationEnabled ) { Reg_GetDword( NULL, // no session, hkeyAdapter, // explicit key NULL, // no adapter name RegIdRegistrationEnabled, & pBlob->fRegistrationEnabled ); } // // adapter name registration // - policy may override // - OFF global overrides // - then adapter // if ( pRegInfo->fPolicyRegisterAdapterName ) { pBlob->fRegisterAdapterName = pRegInfo->fRegisterAdapterName; } else { pBlob->fRegisterAdapterName = g_RegisterAdapterName; if ( g_RegisterAdapterName ) { Reg_GetDword( NULL, // no open session, hkeyAdapter, // open key NULL, // no adapter name RegIdRegisterAdapterName, & pBlob->fRegisterAdapterName ); } } // // max addresses to register // // DCR: RegistrationAddrCount -- adapter or global sets high\low? // if ( pBlob->fRegistrationEnabled ) { Reg_GetDword( NULL, // no session, hkeyAdapter, // explicit key NULL, // no adapter name RegIdRegistrationMaxAddressCount, & pBlob->RegistrationMaxAddressCount ); #if 0 if ( g_RegistrationMaxAddressCount > pBlob->RegistrationMaxAddressCount ) { pBlob->RegistrationMaxAddressCount = g_RegistrationMaxAddressCount; } #endif } // // get adapter name // - policy may override AND // allow policy to override with NULL string to kill domain name // padapterDomainName = pRegInfo->pszAdapterDomainName; if ( padapterDomainName ) { if ( IS_EMPTY_STRING( padapterDomainName ) ) { padapterDomainName = NULL; } else { padapterDomainName = Dns_CreateStringCopy_W( padapterDomainName ); } } else { // // static domain name set on adapter? // status = Reg_GetValueEx( NULL, // no session hkeyAdapter, NULL, // no adapter name RegIdStaticDomainName, REGTYPE_DNS_NAME, DNSREG_FLAG_DUMP_EMPTY, // dump empty string (PBYTE *) &padapterDomainName ); if ( status != ERROR_SUCCESS ) { DNS_ASSERT( padapterDomainName == NULL ); padapterDomainName = NULL; } // // if no static name, use DHCP name // if ( ! padapterDomainName ) { status = Reg_GetValueEx( NULL, // no session hkeyAdapter, NULL, // no adapter RegIdDhcpDomainName, REGTYPE_DNS_NAME, DNSREG_FLAG_DUMP_EMPTY, // dump if empty string (PBYTE *) &padapterDomainName ); if ( status != ERROR_SUCCESS ) { DNS_ASSERT( padapterDomainName == NULL ); padapterDomainName = NULL; } } } // // set adapter name in info blob // pBlob->pszAdapterDomainName = padapterDomainName; // // cleanup // if ( hkeyAdapter ) { RegCloseKey( hkeyAdapter ); } DNSDBG( TRACE, ( "Leave Reg_ReadAdapterInfo()\n" "\tDomainName = %S\n" "\tQueryAdapterName = %d\n" "\tRegistrationEnabled = %d\n" "\tRegisterAdapterName = %d\n" "\tRegisterAddrCount = %d\n", pBlob->pszAdapterDomainName, pBlob->fQueryAdapterName, pBlob->fRegistrationEnabled, pBlob->fRegisterAdapterName, pBlob->RegistrationMaxAddressCount )); return ERROR_SUCCESS; } DNS_STATUS Reg_DefaultAdapterInfo( OUT PREG_ADAPTER_INFO pBlob, IN PREG_GLOBAL_INFO pRegInfo, IN PIP_ADAPTER_ADDRESSES pIpAdapter ) /*++ Routine Description: Default adapter info, when reg read fails. Use for building netinfo on IP6 only adapters that don't show in TCPIP adapters. Arguments: pBlob -- adapter info blob to fill in pRegInfo -- registry global info pIPAdapter -- IP help adapter info Return Value: ERROR_SUCCESS if successful. Error code on failure. --*/ { PWSTR padapterDomainName = NULL; DNSDBG( TRACE, ( "Reg_DefaultAdapterInfo( %p, %p, %p )\n", pBlob, pRegInfo, pIpAdapter )); if ( !pBlob || !pRegInfo || !pIpAdapter ) { return ERROR_INVALID_PARAMETER; } // // clear adapter blob // RtlZeroMemory( pBlob, sizeof(*pBlob) ); // // query with adapter name // - OFF global overrides // pBlob->fQueryAdapterName = g_QueryAdapterName; // // check if adapter IPs get registered // - OFF global overrides // pBlob->fRegistrationEnabled = g_RegistrationEnabled; // // adapter name registration // - policy may override // - OFF global overrides // - then adapter // if ( pRegInfo->fPolicyRegisterAdapterName ) { pBlob->fRegisterAdapterName = pRegInfo->fRegisterAdapterName; } else { pBlob->fRegisterAdapterName = g_RegisterAdapterName; } // // max addresses to register // if ( pBlob->fRegistrationEnabled ) { pBlob->RegistrationMaxAddressCount = g_RegistrationMaxAddressCount; } // // get adapter name // - policy may override AND // allow policy to override with NULL string to kill domain name // padapterDomainName = pRegInfo->pszAdapterDomainName; if ( !padapterDomainName ) { padapterDomainName = pIpAdapter->DnsSuffix; } if ( padapterDomainName ) { if ( IS_EMPTY_STRING( padapterDomainName ) ) { padapterDomainName = NULL; } else { padapterDomainName = Dns_CreateStringCopy_W( padapterDomainName ); } pBlob->pszAdapterDomainName = padapterDomainName; } DNSDBG( TRACE, ( "Leave Reg_DefaultAdapterInfo()\n" "\tDomainName = %S\n" "\tQueryAdapterName = %d\n" "\tRegistrationEnabled = %d\n" "\tRegisterAdapterName = %d\n" "\tRegisterAddrCount = %d\n", pBlob->pszAdapterDomainName, pBlob->fQueryAdapterName, pBlob->fRegistrationEnabled, pBlob->fRegisterAdapterName, pBlob->RegistrationMaxAddressCount )); return ERROR_SUCCESS; } DNS_STATUS Reg_ReadAdapterInfoA( IN PSTR pszAdapterName, IN PREG_SESSION pRegSession, IN PREG_GLOBAL_INFO pRegInfo, OUT PREG_ADAPTER_INFO pBlob ) /*++ Routine Description: Read adapter registry info. ANSI version. This is available simply for use with IPHelp PIP_ADAPTER_ADDRESSES structure which has ANSI adapter name (for some reason). Arguments: pszAdapterName -- adapter name (registry name) pRegSession -- registry session pRegInfo -- registry global info pBlob -- adapter info blob to fill in Return Value: ERROR_SUCCESS if successful. Error code on failure. --*/ { DWORD nameBufLength = MAX_PATH * sizeof(WCHAR); WCHAR wideName[ MAX_PATH ]; DNSDBG( TRACE, ( "ReadRegAdapterInfoA( %s, %p, %p, %p )\n", pszAdapterName, pRegSession, pRegInfo, pBlob )); // // convert adapter name to unicode // if ( ! pszAdapterName || ! Dns_StringCopy( (PCHAR) wideName, & nameBufLength, pszAdapterName, 0, DnsCharSetAnsi, DnsCharSetUnicode ) ) { return ERROR_INVALID_PARAMETER; } return Reg_ReadAdapterInfo( wideName, pRegSession, pRegInfo, pBlob ); } VOID Reg_FreeAdapterInfo( IN OUT PREG_ADAPTER_INFO pRegAdapterInfo, IN BOOL fFreeBlob ) /*++ Routine Description: Free registry adapter info blob. Arguments: pRegAdapterInfo -- adapter registry info blob to free fFreeBlob -- flag to free blob itself FALSE -- just free allocated data fields TRUE -- also free blob itself Return Value: ERROR_SUCCESS if successful. Error code on failure. --*/ { DNSDBG( TRACE, ( "FreeRegAdapterInfo( %p )\n", pRegAdapterInfo )); // // free data // - adapter domain name // if ( pRegAdapterInfo->pszAdapterDomainName ) { FREE_HEAP( pRegAdapterInfo->pszAdapterDomainName ); pRegAdapterInfo->pszAdapterDomainName = NULL; } // free blob itself if ( fFreeBlob ) { FREE_HEAP( pRegAdapterInfo ); } } DNS_STATUS Reg_ReadUpdateInfo( IN PWSTR pszAdapterName, OUT PREG_UPDATE_INFO pUpdateInfo ) /*++ Routine Description: Read update info. // // DCR: shouldn't need this routine, just get NETINFO // this blob is just mix of global stuff and // mostly adapter stuff // even if want in single blob for update routines -- // ok, but not ideal -- // should be getting blob from resolver and reformatting // info; // reg read should happen just once producing network // info in resolver // Arguments: pszAdapterName -- adapter name pUpdateInfo -- blob to hold reg info Return Value: ERROR_SUCCESS if successful. Error code on failure. --*/ { DNS_STATUS status; REG_SESSION regSession; PREG_SESSION pregSession; REG_GLOBAL_INFO regInfo; REG_ADAPTER_INFO regAdapterInfo; BOOL freadRegInfo = FALSE; BOOL freadRegAdapterInfo = FALSE; DNSDBG( TRACE, ( "Reg_ReadUpdateInfo( %S, %p )\n", pszAdapterName, pUpdateInfo )); // // clear update info blob // RtlZeroMemory( pUpdateInfo, sizeof( *pUpdateInfo ) ); // // open the registry // pregSession = ®Session; status = Reg_OpenSession( pregSession, 0, 0 ); if ( status != ERROR_SUCCESS ) { return( status ); } // // read registry // - global DWORDs // - global info // - adapter specific info // // DCR_PERF: global read should be RPC // DCR_REG: fix this with reg read // have flag for IN caching resolver process (skip RPC) // have cookie for last read // #if 0 // Reg_ReadGlobalInfo() calls Reg_ReadGlobalsEx() status = Reg_ReadGlobalsEx( 0, // no flag, update variables desired pregSession ); #endif status = Reg_ReadGlobalInfo( pregSession, & regInfo ); if ( status != ERROR_SUCCESS ) { goto Done; } freadRegInfo = TRUE; status = Reg_ReadAdapterInfo( pszAdapterName, pregSession, & regInfo, & regAdapterInfo ); if ( status != ERROR_SUCCESS ) { goto Done; } freadRegAdapterInfo = TRUE; // // alternate computer name // Reg_GetValue( pregSession, NULL, // no key RegIdAlternateNames, REGTYPE_ALTERNATE_NAMES, (PBYTE *) &pUpdateInfo->pmszAlternateNames ); // // set update results // - PDN always needed // - adapter domain if policy override // - DNS servers if policy override // // note, in all cases we don't realloc, we steal the // info and NULL it out so not freed on cleanup // pUpdateInfo->pszPrimaryDomainName = regInfo.pszPrimaryDomainName; regInfo.pszPrimaryDomainName = NULL; pUpdateInfo->pszAdapterDomainName = regInfo.pszAdapterDomainName; regInfo.pszAdapterDomainName = NULL; pUpdateInfo->pDnsServerArray = regInfo.pDnsServerArray; regInfo.pDnsServerArray = NULL; pUpdateInfo->pDnsServerIp6Array = regInfo.pDnsServerIp6Array; regInfo.pDnsServerIp6Array = NULL; // update flags pUpdateInfo->fRegistrationEnabled = regAdapterInfo.fRegistrationEnabled; pUpdateInfo->fRegisterAdapterName = regAdapterInfo.fRegisterAdapterName; pUpdateInfo->RegistrationMaxAddressCount = regAdapterInfo.RegistrationMaxAddressCount; Done: // // cleanup // if ( pregSession ) { Reg_CloseSession( pregSession ); } // don't free blobs -- they're on stack if ( freadRegInfo ) { Reg_FreeGlobalInfo( ®Info, FALSE ); } if ( freadRegAdapterInfo ) { Reg_FreeAdapterInfo( ®AdapterInfo, FALSE ); } DNSDBG( TRACE, ( "Leave Reg_ReadUpdateInfo( %S )\n" "\tPDN = %S\n" "\tAlternateNames = %S\n" "\tAdapterDomainName = %S\n" "\tDNS servers = %p\n" "\tDNS servers IP6 = %p\n" "\tRegister = %d\n" "\tRegisterAdapterName = %d\n" "\tRegisterAddrCount = %d\n", pszAdapterName, pUpdateInfo->pszPrimaryDomainName, pUpdateInfo->pmszAlternateNames, pUpdateInfo->pszAdapterDomainName, pUpdateInfo->pDnsServerArray, pUpdateInfo->pDnsServerIp6Array, pUpdateInfo->fRegistrationEnabled, pUpdateInfo->fRegisterAdapterName, pUpdateInfo->RegistrationMaxAddressCount )); return ERROR_SUCCESS; } VOID Reg_FreeUpdateInfo( IN OUT PREG_UPDATE_INFO pUpdateInfo, IN BOOL fFreeBlob ) /*++ Routine Description: Free registry update info blob. Arguments: pUpdateInfo -- update registry info blob to free fFreeBlob -- flag to free blob itself FALSE -- just free allocated data fields TRUE -- also free blob itself Return Value: ERROR_SUCCESS if successful. Error code on failure. --*/ { DNSDBG( TRACE, ( "FreeRegUpdateInfo( %p )\n", pUpdateInfo )); // // free data // - PDN // - adapter domain name // - DNS server lists // if ( pUpdateInfo->pszPrimaryDomainName ) { FREE_HEAP( pUpdateInfo->pszPrimaryDomainName ); } if ( pUpdateInfo->pmszAlternateNames ) { FREE_HEAP( pUpdateInfo->pmszAlternateNames ); } if ( pUpdateInfo->pszAdapterDomainName ) { FREE_HEAP( pUpdateInfo->pszAdapterDomainName ); } if ( pUpdateInfo->pDnsServerArray ) { FREE_HEAP( pUpdateInfo->pDnsServerArray ); } if ( pUpdateInfo->pDnsServerIp6Array ) { FREE_HEAP( pUpdateInfo->pDnsServerIp6Array ); } // free blob itself if ( fFreeBlob ) { FREE_HEAP( pUpdateInfo ); } } // // Special // DNS_STATUS Reg_WriteLoopbackDnsServerList( IN PWSTR pszAdapterName, IN PREG_SESSION pRegSession ) /*++ Routine Description: Write loopback IP as DNS server list. Arguments: pszAdapterName -- adapter name (registry name) pRegSession -- registry session Return Value: ERROR_SUCCESS if successful. Error code on failure. --*/ { DNS_STATUS status; HKEY hkeyAdapter = NULL; WCHAR adapterParamKey[ MAX_PATH+1 ]; PWSTR pstring; DNSDBG( TRACE, ( "Reg_WriteLookupbackDnsServerList( %S )\n", pszAdapterName )); // // open adapter key for write // // DCR: fail on adapter key name overflow // if ( !pszAdapterName ) { return ERROR_INVALID_NAME; } _snwprintf( adapterParamKey, MAX_PATH, L"%s%s", TCPIP_INTERFACES_KEY, pszAdapterName ); adapterParamKey[ MAX_PATH ] = 0; status = RegOpenKeyExW( HKEY_LOCAL_MACHINE, adapterParamKey, 0, KEY_READ | KEY_WRITE, & hkeyAdapter ); if ( status != NO_ERROR ) { return( status ); } // // write loopback address // pstring = L"127.0.0.1"; status = RegSetValueExW( hkeyAdapter, DNS_SERVERS, 0, REGTYPE_DNS_SERVER, (PBYTE) pstring, (wcslen(pstring)+1) * sizeof(WCHAR) ); RegCloseKey( hkeyAdapter ); return( status ); } // // PDN Query // PSTR WINAPI Reg_GetPrimaryDomainName( IN DNS_CHARSET CharSet ) /*++ Routine Description: Get primary domain name (PDN). Arguments: CharSet -- desired char set. Return Value: Ptr to primary domain name in desired charset. --*/ { DNS_STATUS status; PWSTR pnameW = NULL; PSTR pnameReturn; status = Reg_ReadPrimaryDomainName( NULL, // no session NULL, // no regkey &pnameW ); if ( !pnameW ) { SetLastError( status ); return NULL; } // // convert to desired char set // if ( CharSet == DnsCharSetUnicode ) { return (PSTR) pnameW; } else { pnameReturn = Dns_NameCopyAllocate( (PBYTE) pnameW, 0, DnsCharSetUnicode, CharSet ); FREE_HEAP( pnameW ); return pnameReturn; } } // // Hostname query // PSTR WINAPI Reg_GetHostName( IN DNS_CHARSET CharSet ) /*++ Routine Description: Get host name. Arguments: CharSet -- desired char set. Return Value: Ptr to host name in desired charset. --*/ { PWSTR pnameW = NULL; PSTR pnameReturn; DNS_STATUS status; // // get hostname from registry // status = Reg_GetValue( NULL, // no session NULL, // no key RegIdHostName, REGTYPE_DNS_NAME, (PBYTE *) &pnameW ); if ( !pnameW ) { SetLastError( status ); return NULL; } // // convert to desired char set // if ( CharSet == DnsCharSetUnicode ) { return (PSTR) pnameW; } else { pnameReturn = Dns_NameCopyAllocate( (PBYTE) pnameW, 0, DnsCharSetUnicode, CharSet ); FREE_HEAP( pnameW ); return pnameReturn; } } PSTR WINAPI Reg_GetFullHostName( IN DNS_CHARSET CharSet ) /*++ Routine Description: Get full host name. Arguments: CharSet -- desired char set. Return Value: Ptr to full host name in desired charset. --*/ { PWSTR pnameW = NULL; PWSTR pdomainW = NULL; PSTR presult = NULL; DNS_STATUS status; WCHAR nameBuffer[ DNS_MAX_NAME_BUFFER_LENGTH+4 ]; // // get hostname from registry // status = Reg_GetValue( NULL, // no session NULL, // no key RegIdHostName, REGTYPE_DNS_NAME, (PBYTE *) &pnameW ); if ( !pnameW ) { SetLastError( status ); return NULL; } // // get domain name from registry // status = Reg_ReadPrimaryDomainName( NULL, // no session NULL, // no regkey &pdomainW ); if ( status != ERROR_SUCCESS ) { SetLastError( status ); return NULL; } // // create appended name // - wire format is narrow // // allocate result in desired char set // if ( pdomainW ) { if ( Dns_NameAppend_W( nameBuffer, DNS_MAX_NAME_BUFFER_LENGTH, pnameW, pdomainW ) ) { presult = Dns_NameCopyAllocate( (PBYTE) nameBuffer, 0, DnsCharSetUnicode, CharSet ); } } else { presult = Dns_NameCopyAllocate( (PBYTE) pnameW, 0, DnsCharSetUnicode, CharSet ); } // // free registry allocations // FREE_HEAP( pnameW ); FREE_HEAP( pdomainW ); return presult; } // // DWORD Get\Set // DWORD Reg_ReadDwordValueFromGlobal( IN DWORD PropId ) /*++ Routine Description: Read DWORD from global. This is direct access to global through RegId, rather than by name. Arguments: PropId -- property ID of desired value Return Value: ERROR_SUCCESS if successful. ErrorCode on failure. --*/ { PDWORD pdword; // // validate PropId -- within DWORD array // if ( PropId > RegIdValueGlobalMax ) { DNS_ASSERT( FALSE ); return( 0 ); } // // get DWORD ptr and read value (if exists) // pdword = RegDwordPtrArray[ PropId ]; if ( !pdword ) { DNS_ASSERT( FALSE ); return( 0 ); } return( *pdword ); } DWORD Reg_ReadDwordProperty( IN DNS_REGID RegId, IN PWSTR pwsAdapterName OPTIONAL ) /*++ Routine Description: Read through to registry for DWORD\BOOL value. Simplified interface for DWORD reads. Arguments: RegId -- registry ID of value pwsAdapterName -- adapter name if adapter specific registration value is desired Return Value: Value for global -- from registry or defaulted --*/ { DWORD value; // // read value // Reg_GetDword( NULL, // no session NULL, // no key given pwsAdapterName, RegId, & value ); return( value ); } DNS_STATUS WINAPI Reg_SetDwordPropertyAndAlertCache( IN PWSTR pwsKey, IN DWORD RegId, IN DWORD dwValue ) /*++ Routine Description: Write DWORD property -- cause cache to reload config. Arguments: pwsRey -- key or adapater name to set RegId -- reg id dwValue -- value to set Return Value: None. --*/ { DNS_STATUS status; // set value status = Reg_SetDwordValue( NULL, // reserved NULL, // no open key pwsKey, RegId, dwValue ); // // if reg write successful // - poke cache // - mark any local netinfo dirty // if ( status == NO_ERROR ) { DnsNotifyResolverEx( POKE_OP_UPDATE_NETINFO, 0, POKE_COOKIE_UPDATE_NETINFO, NULL ); NetInfo_MarkDirty(); } return status; } // // Environment variable configuration // BOOL Reg_ReadDwordEnvar( IN DWORD Id, OUT PENVAR_DWORD_INFO pEnvar ) /*++ Routine Description: Read DWORD environment variable. Note: this function read environment variables that allow per process control of registry configurable params. The environment variable is assumed to be the same as the regkey with Dns prepended ( Dns ). Ex. FilterClusterIp controlled with envar DnsFilterClusterIp. Arguments: Id -- registry ID (registry.h) of environment value to read pEnvar -- ptr to blob to hold results Return Value: ERROR_SUCCESS if successful. ErrorCode on failure. --*/ { DWORD count; PWSTR pnameBuffer; PWSTR pvarBuffer; BOOL found = FALSE; DNSDBG( TRACE, ( "Reg_ReadDwordEnvar( %d, %p )\n", Id, pEnvar )); if ( Id > RegIdValueGlobalMax ) { DNS_ASSERT( FALSE ); return FALSE; } // // init struct (for not found) // pEnvar->Id = Id; pEnvar->Value = 0; pEnvar->fFound = FALSE; // // prepend "Dns" to reg value name to create environment var name // pnameBuffer = (PWSTR) ALLOCATE_HEAP( 2 * (sizeof(WCHAR) * MAX_PATH) ); if ( !pnameBuffer ) { return FALSE; } pvarBuffer = pnameBuffer + MAX_PATH; wcscpy( pnameBuffer, L"Dns" ); wcscpy( &pnameBuffer[3], REGPROP_NAME(Id) ); // // lookup // // note: no handling of values greater than MAX_PATH // assuming busted string // // DCR: could add base discrimination (scan for non-digit) // or try decimal first // DNSDBG( TRACE, ( "Reg_ReadDwordEnvar() looking up %S.\n", pnameBuffer )); count = GetEnvironmentVariableW( pnameBuffer, pvarBuffer, MAX_PATH ); if ( count && count < MAX_PATH ) { pEnvar->Value = wcstoul( pvarBuffer, NULL, 10 ); found = TRUE; } pEnvar->fFound = found; DNSDBG( TRACE, ( "Leave Reg_ReadDwordEnvar() %S found=%d, value=%d.\n", pnameBuffer, pEnvar->fFound, pEnvar->Value )); FREE_HEAP( pnameBuffer ); return found; } #if 0 // // Remote resolver not currently supported // PWSTR Reg_GetResolverAddress( VOID ) /*++ Routine Description: Get address (string form) of remote resolver. Arguments: None Return Value: Ptr to string of remote resolver name. --*/ { PWSTR pnameResolver = NULL; Reg_GetValueEx( NULL, // no session NULL, // no key NULL, // no adapter RegIdRemoteResolver, REGTYPE_DNS_NAME, DNSREG_FLAG_GET_UNICODE | DNSREG_FLAG_DUMP_EMPTY, (PBYTE *) &pnameResolver ); return pnameResolver; } #endif // // End regfig.c //