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.

5020 lines
144 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. dns.c
  5. Abstract:
  6. Routines to register DNS names.
  7. Author:
  8. Cliff Van Dyke (CliffV) 28-May-1996
  9. Revision History:
  10. --*/
  11. //
  12. // Common include files.
  13. //
  14. #include "logonsrv.h" // Include files common to entire service
  15. #pragma hdrstop
  16. BOOL NlGlobalDnsScavengeNeeded = FALSE;
  17. BOOL NlGlobalDnsScavengingInProgress = FALSE;
  18. ULONG NlGlobalDnsScavengeFlags = 0;
  19. WORKER_ITEM NlGlobalDnsScavengeWorkItem;
  20. BOOL NlDnsWriteServerFailureEventLog = FALSE;
  21. ULONG NlDnsInitCount = 0; // The number of times we have been started
  22. //
  23. // The timeout after our start when it's OK to write DNS errors into
  24. // the event log. We postpone error output because the DNS server
  25. // (if it runs locally) may not have started yet.
  26. //
  27. #define NL_DNS_EVENTLOG_TIMEOUT (2 * 60 * 1000) // 2 minutes
  28. //
  29. // Max time that a name update should reasonably take.
  30. // We will indicate in netlogon.log if a given update
  31. // takes longer than this threshold.
  32. //
  33. #define NL_DNS_ONE_THRESHOLD (15*1000) // 15 seconds
  34. //
  35. // Max time that DNS deregistrations are allowed to take on shutdown.
  36. // We will abort deregistration cycle on shutdown if total deregisrtaion
  37. // time for all records takes longer than this timeout.
  38. //
  39. #define NL_DNS_SHUTDOWN_THRESHOLD 60000 // 1 minute
  40. //
  41. // Max number of times we will restart concurrent DNS scavenging
  42. // before giving up.
  43. //
  44. #define NL_DNS_MAX_SCAVENGE_RESTART 10 // 10 times
  45. //
  46. // State of a DNS name.
  47. //
  48. typedef enum {
  49. RegisterMe, // Name needs to be registered
  50. Registered, // Name is registered
  51. DeregisterMe, // Name needs to be deregistered
  52. DelayedDeregister, // Name will be marked for deregistration in the future
  53. DeleteMe, // This entry should be deleted.
  54. DnsNameStateInvalid // State is invalid
  55. } NL_DNS_NAME_STATE;
  56. //
  57. // Structure representing an added DNS name.
  58. // (All fields serialized by NlGlobalDnsCritSect)
  59. //
  60. typedef struct _NL_DNS_NAME {
  61. //
  62. // Link in list of all such structures headed by NlGlobalDnsList
  63. //
  64. LIST_ENTRY Next;
  65. //
  66. // Type of name registed.
  67. //
  68. NL_DNS_NAME_TYPE NlDnsNameType;
  69. //
  70. // Domain this entry refers to.
  71. //
  72. PDOMAIN_INFO DomainInfo;
  73. //
  74. // Flags describing the entry.
  75. //
  76. ULONG Flags;
  77. #define NL_DNS_REGISTER_DOMAIN 0x0001 // All names for domain being registered.
  78. #define NL_DNS_REGISTERED_ONCE 0x0002 // Name has been registered at least once
  79. //
  80. // The time of the first failure to deregister this name.
  81. // Reset to zero on successful deregistration.
  82. //
  83. LARGE_INTEGER FirstDeregFailureTime;
  84. //
  85. // Each regisration is periodically re-done (whether successful or not).
  86. // This timer indicates when the next re-registration should be done.
  87. //
  88. // The initial re-registration is done after 5 minute. The period then
  89. // doubles until it reaches a maximum of DnsRefreshInterval.
  90. //
  91. TIMER ScavengeTimer;
  92. #define ORIG_DNS_SCAVENGE_PERIOD (5*60*1000) // 5 minute
  93. //
  94. // Actual DNS name registered.
  95. //
  96. LPSTR DnsRecordName;
  97. //
  98. // Data for the SRV record
  99. //
  100. ULONG Priority;
  101. ULONG Weight;
  102. ULONG Port;
  103. LPSTR DnsHostName;
  104. //
  105. // Data for the A record
  106. //
  107. ULONG IpAddress;
  108. //
  109. // State of this entry.
  110. //
  111. NL_DNS_NAME_STATE State;
  112. //
  113. // Last DNS update status for this name
  114. //
  115. NET_API_STATUS NlDnsNameLastStatus;
  116. } NL_DNS_NAME, *PNL_DNS_NAME;
  117. //
  118. // Header for binary Dns log file.
  119. //
  120. typedef struct _NL_DNSLOG_HEADER {
  121. ULONG Version;
  122. } NL_DNSLOG_HEADER, *PNL_DNSLOG_HEADER;
  123. #define NL_DNSLOG_VERSION 1
  124. //
  125. // Entry in the binary Dns log file.
  126. //
  127. typedef struct _NL_DNSLOG_ENTRY {
  128. //
  129. // Size (in bytes) of this entry
  130. //
  131. ULONG EntrySize;
  132. //
  133. // Type of name registed.
  134. //
  135. NL_DNS_NAME_TYPE NlDnsNameType;
  136. //
  137. // Data for the SRV record
  138. //
  139. ULONG Priority;
  140. ULONG Weight;
  141. ULONG Port;
  142. //
  143. // Data for the A record
  144. //
  145. ULONG IpAddress;
  146. } NL_DNSLOG_ENTRY, *PNL_DNSLOG_ENTRY;
  147. //
  148. // Globals specific to this .c file.
  149. //
  150. //
  151. // True if the DNS list needs to be output to netlogon.dns
  152. //
  153. BOOLEAN NlGlobalDnsListDirty;
  154. //
  155. // True if the initial cleanup of previously registered names has been done.
  156. //
  157. BOOLEAN NlGlobalDnsInitialCleanupDone;
  158. //
  159. // Time when netlogon was started.
  160. //
  161. DWORD NlGlobalDnsStartTime;
  162. #define NL_DNS_INITIAL_CLEANUP_TIME (10 * 60 * 1000) // 10 minutes
  163. VOID
  164. NlDnsNameToStr(
  165. IN PNL_DNS_NAME NlDnsName,
  166. OUT CHAR Utf8DnsRecord[NL_DNS_RECORD_STRING_SIZE]
  167. )
  168. /*++
  169. Routine Description:
  170. This routine builds a textual representation of NlDnsName
  171. Arguments:
  172. NlDnsName - Name to register or deregister.
  173. Utf8DnsRecord - Preallocated buffer to build the text string into.
  174. The built record is a UTF-8 zero terminated string.
  175. The string is concatenated to this buffer.
  176. Return Value:
  177. None.
  178. --*/
  179. {
  180. CHAR Number[33];
  181. //
  182. // Write the record name
  183. //
  184. strcat( Utf8DnsRecord, NlDnsName->DnsRecordName );
  185. //
  186. // Concatenate the TTL
  187. //
  188. _ltoa( NlGlobalParameters.DnsTtl, Number, 10 );
  189. strcat( Utf8DnsRecord, " " );
  190. strcat( Utf8DnsRecord, Number );
  191. //
  192. // Build an A record.
  193. //
  194. if ( NlDnsARecord( NlDnsName->NlDnsNameType ) ) {
  195. CHAR IpAddressString[NL_IP_ADDRESS_LENGTH+1];
  196. strcat( Utf8DnsRecord, NL_DNS_A_RR_VALUE_1 );
  197. NetpIpAddressToStr( NlDnsName->IpAddress, IpAddressString );
  198. strcat( Utf8DnsRecord, IpAddressString );
  199. //
  200. // Build a CNAME record
  201. //
  202. } else if ( NlDnsCnameRecord( NlDnsName->NlDnsNameType ) ) {
  203. strcat( Utf8DnsRecord, NL_DNS_CNAME_RR_VALUE_1 );
  204. strcat( Utf8DnsRecord, NlDnsName->DnsHostName );
  205. strcat( Utf8DnsRecord, "." );
  206. //
  207. // Build a SRV record
  208. //
  209. } else {
  210. strcat( Utf8DnsRecord, NL_DNS_SRV_RR_VALUE_1 );
  211. _ltoa( NlDnsName->Priority, Number, 10 );
  212. strcat( Utf8DnsRecord, Number );
  213. strcat( Utf8DnsRecord, " " );
  214. _ltoa( NlDnsName->Weight, Number, 10 );
  215. strcat( Utf8DnsRecord, Number );
  216. strcat( Utf8DnsRecord, " " );
  217. _ltoa( NlDnsName->Port, Number, 10 );
  218. strcat( Utf8DnsRecord, Number );
  219. strcat( Utf8DnsRecord, " " );
  220. strcat( Utf8DnsRecord, NlDnsName->DnsHostName );
  221. strcat( Utf8DnsRecord, "." );
  222. }
  223. }
  224. LPWSTR
  225. NlDnsNameToWStr(
  226. IN PNL_DNS_NAME NlDnsName
  227. )
  228. /*++
  229. Routine Description:
  230. This routine builds a textual representation of NlDnsName
  231. Arguments:
  232. NlDnsName - Name to register or deregister.
  233. Utf8DnsRecord - Preallocated buffer to build the text string into.
  234. The built record is a UTF-8 zero terminated string.
  235. The string is concatenated to this buffer.
  236. Return Value:
  237. Buffer containing a textual representation of NlDnsName
  238. NULL: Buffer could not be allocated
  239. Buffer should be free by calling NetApiBufferFree();
  240. --*/
  241. {
  242. LPSTR DnsRecord = NULL;
  243. LPWSTR UnicodeDnsRecord;
  244. //
  245. // Allocate a buffer for the UTF-8 version of the string.
  246. //
  247. DnsRecord = LocalAlloc( 0, NL_DNS_RECORD_STRING_SIZE + 1 );
  248. if ( DnsRecord == NULL ) {
  249. return NULL;
  250. }
  251. DnsRecord[0] = '\0';
  252. //
  253. // Create the text string in UTF-8
  254. //
  255. NlDnsNameToStr( NlDnsName, DnsRecord );
  256. //
  257. // Convert to Unicode
  258. //
  259. UnicodeDnsRecord = NetpAllocWStrFromUtf8Str( DnsRecord );
  260. LocalFree( DnsRecord );
  261. return UnicodeDnsRecord;
  262. }
  263. LPWSTR
  264. NlDnsNameToDomainName(
  265. IN PNL_DNS_NAME NlDnsName
  266. )
  267. /*++
  268. Routine Description:
  269. This routine parses the record and returns the DNS name
  270. of the domain the record belongs to.
  271. Note that we have to parse the name because we may not have
  272. the DomainInfo structure hanging off NlDnsName if this is a
  273. deregistration of no longer hosted domain.
  274. Note that this routine relies on a particular structure
  275. of DNS records that netlogon registers. If that structure
  276. changes, this routine will have to change accordingly.
  277. Arguments:
  278. NlDnsName - Name to register or deregister.
  279. Return Value:
  280. Pointer to the alocated DNS domain name. Must be freed
  281. by calling NetApiBufferFree.
  282. --*/
  283. {
  284. LPWSTR UnicodeRecordName = NULL;
  285. LPWSTR UnicodeDnsDomainName = NULL;
  286. LPWSTR Ptr = NULL;
  287. LPWSTR DotPtr = NULL;
  288. //
  289. // The record name has a structure where the label immediately
  290. // before the domain name has a leading underscore. There might
  291. // be no label before the domain name for A records -- we will
  292. // treat the absence of underscore in the name as an indication
  293. // of that the record name is the domain name itself.
  294. //
  295. UnicodeRecordName = NetpAllocWStrFromUtf8Str( NlDnsName->DnsRecordName );
  296. if ( UnicodeRecordName == NULL || *UnicodeRecordName == UNICODE_NULL ) {
  297. goto Cleanup;
  298. }
  299. //
  300. // Starting from the last character and going to the front,
  301. // search for the characters of interest.
  302. //
  303. Ptr = UnicodeRecordName + wcslen( UnicodeRecordName ) - 1;
  304. while ( Ptr != UnicodeRecordName ) {
  305. //
  306. // If this is the next dot going from the end,
  307. // remember its location
  308. //
  309. if ( *Ptr == NL_DNS_DOT ) {
  310. DotPtr = Ptr;
  311. }
  312. //
  313. // If this is the first underscore going from the end,
  314. // break from the loop: the domain name is immediately
  315. // after the previous dot
  316. //
  317. if ( *Ptr == NL_DNS_UNDERSCORE ) {
  318. NlAssert( DotPtr != NULL );
  319. break;
  320. }
  321. Ptr --;
  322. }
  323. //
  324. // If there is no underscore in the name,
  325. // the domain name is the record name itself.
  326. // Otherwise, the domain name follows immediately
  327. // after the last dot.
  328. //
  329. if ( Ptr == UnicodeRecordName ) {
  330. UnicodeDnsDomainName = NetpAllocWStrFromWStr( UnicodeRecordName );
  331. } else if ( DotPtr != NULL ) {
  332. UnicodeDnsDomainName = NetpAllocWStrFromWStr( DotPtr + 1 );
  333. }
  334. Cleanup:
  335. if ( UnicodeRecordName != NULL ) {
  336. NetApiBufferFree( UnicodeRecordName );
  337. }
  338. return UnicodeDnsDomainName;
  339. }
  340. #if NETLOGONDBG
  341. #define NlPrintDns(_x_) NlPrintDnsRoutine _x_
  342. #else
  343. #define NlPrintDns(_x_)
  344. #endif // NETLOGONDBG
  345. #if NETLOGONDBG
  346. VOID
  347. NlPrintDnsRoutine(
  348. IN DWORD DebugFlag,
  349. IN PNL_DNS_NAME NlDnsName,
  350. IN LPSTR Format,
  351. ...
  352. )
  353. {
  354. va_list arglist;
  355. CHAR Utf8DnsRecord[NL_DNS_RECORD_STRING_SIZE];
  356. //
  357. // vsprintf isn't multithreaded + we don't want to intermingle output
  358. // from different threads.
  359. //
  360. EnterCriticalSection( &NlGlobalLogFileCritSect );
  361. //
  362. // Prefix the printed line with the domain name
  363. //
  364. if ( NlGlobalServicedDomainCount > 1 ) {
  365. if ( NlDnsName->DomainInfo == NULL ) {
  366. NlPrint(( DebugFlag, "%ws: ", L"[Unknown]" ));
  367. } else if ( NlDnsName->DomainInfo->DomUnicodeDomainName != NULL &&
  368. *(NlDnsName->DomainInfo->DomUnicodeDomainName) != UNICODE_NULL ) {
  369. NlPrint(( DebugFlag, "%ws: ", NlDnsName->DomainInfo->DomUnicodeDomainName ));
  370. } else {
  371. NlPrint(( DebugFlag, "%ws: ", NlDnsName->DomainInfo->DomUnicodeDnsDomainName ));
  372. }
  373. }
  374. //
  375. // Simply change arguments to va_list form and call NlPrintRoutineV
  376. //
  377. va_start(arglist, Format);
  378. NlPrintRoutineV( DebugFlag, Format, arglist );
  379. va_end(arglist);
  380. //
  381. // Finally print a description of the DNS record in question.
  382. //
  383. Utf8DnsRecord[0] = '\0';
  384. NlDnsNameToStr( NlDnsName, Utf8DnsRecord );
  385. NlPrint(( DebugFlag,
  386. ": %ws: %s\n",
  387. NlDcDnsNameTypeDesc[NlDnsName->NlDnsNameType].Name,
  388. Utf8DnsRecord ));
  389. LeaveCriticalSection( &NlGlobalLogFileCritSect );
  390. }
  391. #endif // NETLOGONDBG
  392. BOOL
  393. NlDnsSetAvoidRegisterNameParam(
  394. IN LPTSTR_ARRAY NewDnsAvoidRegisterRecords
  395. )
  396. /*++
  397. Routine Description:
  398. This routine sets the names of DNS records this DC should avoid registering.
  399. Arguments:
  400. NewSiteCoverage - Specifies the new list of names to avoid registering
  401. Return Value:
  402. TRUE: iff the list of names to avoid registering changed
  403. --*/
  404. {
  405. BOOL DnsAvoidRegisterRecordsChanged = FALSE;
  406. EnterCriticalSection( &NlGlobalParametersCritSect );
  407. //
  408. // Handle DnsAvoidRegisterRecords changing
  409. //
  410. DnsAvoidRegisterRecordsChanged = !NetpEqualTStrArrays(
  411. NlGlobalParameters.DnsAvoidRegisterRecords,
  412. NewDnsAvoidRegisterRecords );
  413. if ( DnsAvoidRegisterRecordsChanged ) {
  414. //
  415. // Swap in the new value.
  416. (VOID) NetApiBufferFree( NlGlobalParameters.DnsAvoidRegisterRecords );
  417. NlGlobalParameters.DnsAvoidRegisterRecords = NewDnsAvoidRegisterRecords;
  418. }
  419. LeaveCriticalSection( &NlGlobalParametersCritSect );
  420. return DnsAvoidRegisterRecordsChanged;
  421. }
  422. NET_API_STATUS
  423. NlGetConfiguredDnsDomainName(
  424. OUT LPWSTR *DnsDomainName
  425. )
  426. /*++
  427. Routine Description:
  428. This routine gets the DNS domain name of domain as configured by DNS or DHCP
  429. NOTE: THIS ROUTINE IS CURRENTLY UNUSED
  430. Arguments:
  431. DnsDomainName - Returns the DNS domain name of the domain.
  432. The returned name has a trailing . since the name is an absolute name.
  433. The allocated buffer must be freed via NetApiBufferFree.
  434. Returns NO_ERROR and a pointer to a NULL buffer if there is no
  435. domain name configured.
  436. Return Value:
  437. Status of the operation.
  438. --*/
  439. {
  440. NET_API_STATUS NetStatus;
  441. WCHAR LocalDnsDomainNameBuffer[NL_MAX_DNS_LENGTH+1];
  442. LPWSTR LocalDnsDomainName = NULL;
  443. LPNET_CONFIG_HANDLE SectionHandle = NULL;
  444. *DnsDomainName = NULL;
  445. //
  446. // Get the domain name from the registery
  447. //
  448. NetStatus = NetpOpenConfigData(
  449. &SectionHandle,
  450. NULL, // no server name.
  451. SERVICE_TCPIP,
  452. TRUE ); // we only want readonly access
  453. if ( NetStatus != NO_ERROR ) {
  454. //
  455. // Simply return success if TCP/IP isn't configured.
  456. //
  457. if ( NetStatus == NERR_CfgCompNotFound ) {
  458. NetStatus = NO_ERROR;
  459. }
  460. SectionHandle = NULL;
  461. goto Cleanup;
  462. }
  463. //
  464. // Get the "Domain" parameter from the TCPIP service.
  465. //
  466. NetStatus = NetpGetConfigValue (
  467. SectionHandle,
  468. L"Domain", // key wanted
  469. &LocalDnsDomainName ); // Must be freed by NetApiBufferFree().
  470. if ( NetStatus == NO_ERROR && *LocalDnsDomainName == L'\0' ) {
  471. NetStatus = NERR_CfgParamNotFound;
  472. NetApiBufferFree( LocalDnsDomainName );
  473. LocalDnsDomainName = NULL;
  474. }
  475. if (NetStatus != NERR_CfgParamNotFound ) {
  476. goto Cleanup;
  477. }
  478. //
  479. // Fall back to the "DhcpDomain" parameter from the TCPIP service.
  480. //
  481. NetStatus = NetpGetConfigValue (
  482. SectionHandle,
  483. L"DhcpDomain", // key wanted
  484. &LocalDnsDomainName ); // Must be freed by NetApiBufferFree().
  485. if ( NetStatus == NO_ERROR && *LocalDnsDomainName == L'\0' ) {
  486. NetStatus = NERR_CfgParamNotFound;
  487. NetApiBufferFree( LocalDnsDomainName );
  488. LocalDnsDomainName = NULL;
  489. }
  490. if (NetStatus == NERR_CfgParamNotFound ) {
  491. NetStatus = NO_ERROR;
  492. }
  493. Cleanup:
  494. if ( NetStatus == NO_ERROR ) {
  495. if ( LocalDnsDomainName != NULL ) {
  496. ULONG LocalDnsDomainNameLen = wcslen(LocalDnsDomainName);
  497. if ( LocalDnsDomainNameLen != 0 ) {
  498. if ( LocalDnsDomainNameLen > NL_MAX_DNS_LENGTH-1 ) {
  499. NetStatus = ERROR_INVALID_DOMAINNAME;
  500. } else {
  501. NetStatus = NetapipBufferAllocate(
  502. (LocalDnsDomainNameLen + 2) * sizeof(WCHAR),
  503. DnsDomainName );
  504. if ( NetStatus == NO_ERROR ) {
  505. wcscpy( *DnsDomainName, LocalDnsDomainName );
  506. if ( (*DnsDomainName)[LocalDnsDomainNameLen-1] != L'.' ) {
  507. wcscat( *DnsDomainName, L"." );
  508. }
  509. }
  510. }
  511. }
  512. }
  513. }
  514. if ( SectionHandle != NULL ) {
  515. (VOID) NetpCloseConfigData( SectionHandle );
  516. }
  517. if ( LocalDnsDomainName != NULL ) {
  518. NetApiBufferFree( LocalDnsDomainName );
  519. }
  520. return NetStatus;
  521. }
  522. VOID
  523. NlDnsSetState(
  524. PNL_DNS_NAME NlDnsName,
  525. NL_DNS_NAME_STATE State
  526. )
  527. /*++
  528. Routine Description:
  529. Set the state of the entry.
  530. Arguments:
  531. NlDnsName - Structure describing name.
  532. State - New state for the name.
  533. Return Value:
  534. None.
  535. --*/
  536. {
  537. EnterCriticalSection( &NlGlobalDnsCritSect );
  538. //
  539. // If this name got registered,
  540. // remember that fact
  541. //
  542. if ( State == Registered ) {
  543. NlDnsName->Flags |= NL_DNS_REGISTERED_ONCE;
  544. }
  545. //
  546. // If the state changes, do appropriate updates
  547. //
  548. if ( NlDnsName->State != State ) {
  549. NlDnsName->State = State;
  550. NlGlobalDnsListDirty = TRUE;
  551. //
  552. // If the new state says I need to update the DNS server,
  553. // set the retry period to indicate to do that now.
  554. //
  555. if ( NlDnsName->State == RegisterMe ||
  556. NlDnsName->State == DeregisterMe ) {
  557. NlDnsName->ScavengeTimer.StartTime.QuadPart = 0;
  558. NlDnsName->ScavengeTimer.Period = 0;
  559. }
  560. }
  561. LeaveCriticalSection( &NlGlobalDnsCritSect );
  562. }
  563. NET_API_STATUS
  564. NlDnsBuildName(
  565. IN PDOMAIN_INFO DomainInfo,
  566. IN NL_DNS_NAME_TYPE NlDnsNameType,
  567. IN LPWSTR SiteName,
  568. IN BOOL DnsNameAlias,
  569. OUT char DnsName[NL_MAX_DNS_LENGTH+1]
  570. )
  571. /*++
  572. Routine Description:
  573. This routine returns the textual DNS name for a particular domain and
  574. name type.
  575. Arguments:
  576. DomainInfo - Domain the name is for.
  577. NlDnsNameType - The specific type of name.
  578. SiteName - If NlDnsNameType is any of the *AtSite values,
  579. the site name of the site this name is registered for.
  580. DnsNameAlias - If TRUE, the built name should correspond to the
  581. alias of the domain/forest name.
  582. DnsName - Textual representation of the name. If the name is not
  583. applicable (DnsNameAlias is TRUE but there is no alias for
  584. the name), the returned string will be empty.
  585. Return Value:
  586. NO_ERROR: The name was returned;
  587. ERROR_NO_SUCH_DOMAIN: No (active) domain name is known for this domain.
  588. ERROR_INVALID_DOMAINNAME: Domain's name is too long. Additional labels
  589. cannot be concatenated.
  590. --*/
  591. {
  592. NET_API_STATUS NetStatus = NO_ERROR;
  593. GUID DomainGuid;
  594. LPSTR DnsDomainName = NULL;
  595. BOOLEAN UseForestName = FALSE;
  596. //
  597. // Initialization
  598. //
  599. RtlZeroMemory( DnsName, (NL_MAX_DNS_LENGTH+1)*sizeof(char) );
  600. //
  601. // Get the Domain GUID for the case where the DC domain name.
  602. // The Domain GUID is registered at the TreeName
  603. //
  604. EnterCriticalSection(&NlGlobalDomainCritSect);
  605. if ( NlDnsDcGuid( NlDnsNameType ) ) {
  606. if ( DomainInfo->DomDomainGuid == NULL ) {
  607. NlPrintDom((NL_CRITICAL, DomainInfo,
  608. "NlDnsBuildName: Domain has no GUID.\n" ));
  609. NetStatus = ERROR_NO_SUCH_DOMAIN;
  610. goto Cleanup;
  611. }
  612. DomainGuid = *(DomainInfo->DomDomainGuid);
  613. UseForestName = TRUE;
  614. //
  615. // Get the DSA Guid for the case where the DC is renamed.
  616. //
  617. } else if ( NlDnsCnameRecord( NlDnsNameType) ) {
  618. if ( IsEqualGUID( &NlGlobalDsaGuid, &NlGlobalZeroGuid) ) {
  619. NlPrintDom((NL_DNS, DomainInfo,
  620. "NlDnsBuildName: DSA has no GUID.\n" ));
  621. NetStatus = ERROR_NO_SUCH_DOMAIN;
  622. goto Cleanup;
  623. }
  624. DomainGuid = NlGlobalDsaGuid;
  625. UseForestName = TRUE;
  626. }
  627. //
  628. // Ensure site specific names have been passed a site name
  629. //
  630. if ( NlDcDnsNameTypeDesc[NlDnsNameType].IsSiteSpecific ) {
  631. if ( SiteName == NULL ) {
  632. NlPrintDom((NL_CRITICAL, DomainInfo,
  633. "NlDnsBuildName: DC has no Site Name.\n" ));
  634. NetStatus = ERROR_NO_SUCH_DOMAIN;
  635. goto Cleanup;
  636. }
  637. }
  638. //
  639. // GC's are registered at the Forest name.
  640. //
  641. if ( NlDnsGcName( NlDnsNameType ) ) {
  642. UseForestName = TRUE;
  643. }
  644. //
  645. // Pick up the ForestName or DomainName as flagged above.
  646. //
  647. if ( UseForestName ) {
  648. if ( !DnsNameAlias ) {
  649. DnsDomainName = NlGlobalUtf8DnsForestName;
  650. //
  651. // We must have an active forest name
  652. //
  653. if ( NlGlobalUtf8DnsForestName == NULL ) {
  654. NlPrintDom((NL_CRITICAL, DomainInfo,
  655. "NlDnsBuildName: Domain has no Forest Name.\n" ));
  656. NetStatus = ERROR_NO_SUCH_DOMAIN;
  657. goto Cleanup;
  658. }
  659. } else {
  660. DnsDomainName = NlGlobalUtf8DnsForestNameAlias;
  661. }
  662. } else {
  663. if ( !DnsNameAlias ) {
  664. DnsDomainName = DomainInfo->DomUtf8DnsDomainName;
  665. //
  666. // We must have an active domain name
  667. //
  668. if ( DomainInfo->DomUtf8DnsDomainName == NULL ) {
  669. NlPrintDom((NL_CRITICAL, DomainInfo,
  670. "NlDnsBuildName: Domain has no Domain Name.\n" ));
  671. NetStatus = ERROR_NO_SUCH_DOMAIN;
  672. goto Cleanup;
  673. }
  674. } else {
  675. DnsDomainName = DomainInfo->DomUtf8DnsDomainNameAlias;
  676. }
  677. }
  678. //
  679. // Build the appropriate name as applicable
  680. //
  681. if ( DnsDomainName != NULL ) {
  682. NetStatus = NetpDcBuildDnsName( NlDnsNameType,
  683. &DomainGuid,
  684. SiteName,
  685. DnsDomainName,
  686. DnsName );
  687. }
  688. Cleanup:
  689. LeaveCriticalSection(&NlGlobalDomainCritSect);
  690. return NetStatus;
  691. }
  692. HKEY
  693. NlOpenNetlogonKey(
  694. LPSTR KeyName
  695. )
  696. /*++
  697. Routine Description:
  698. Create/Open the Netlogon key in the registry.
  699. Arguments:
  700. KeyName - Name of the key to open
  701. Return Value:
  702. Return a handle to the key. NULL means the key couldn't be opened.
  703. --*/
  704. {
  705. LONG RegStatus;
  706. HKEY ParmHandle = NULL;
  707. ULONG Disposition;
  708. //
  709. // Open the key for Netlogon\Parameters
  710. //
  711. RegStatus = RegCreateKeyExA(
  712. HKEY_LOCAL_MACHINE,
  713. KeyName,
  714. 0, //Reserved
  715. NULL, // Class
  716. REG_OPTION_NON_VOLATILE,
  717. KEY_SET_VALUE | KEY_QUERY_VALUE | KEY_NOTIFY,
  718. NULL, // Security descriptor
  719. &ParmHandle,
  720. &Disposition );
  721. if ( RegStatus != ERROR_SUCCESS ) {
  722. NlPrint(( NL_CRITICAL,
  723. "NlOpenNetlogonKey: Cannot create registy key %s %ld.\n",
  724. KeyName,
  725. RegStatus ));
  726. return NULL;
  727. }
  728. return ParmHandle;
  729. }
  730. VOID
  731. NlDnsWriteBinaryLog(
  732. VOID
  733. )
  734. /*++
  735. Routine Description:
  736. Write the list of registered DNS names to the registry.
  737. Arguments:
  738. None
  739. Return Value:
  740. None.
  741. --*/
  742. {
  743. NET_API_STATUS NetStatus;
  744. PLIST_ENTRY ListEntry;
  745. PNL_DNS_NAME NlDnsName;
  746. ULONG DnsRecordBufferSize;
  747. PNL_DNSLOG_HEADER DnsRecordBuffer = NULL;
  748. PNL_DNSLOG_ENTRY DnsLogEntry;
  749. ULONG CurrentSize;
  750. LPBYTE Where;
  751. //
  752. // Compute the size of the buffer to allocate.
  753. //
  754. DnsRecordBufferSize = ROUND_UP_COUNT( sizeof(NL_DNSLOG_HEADER), ALIGN_WORST );
  755. EnterCriticalSection( &NlGlobalDnsCritSect );
  756. for ( ListEntry = NlGlobalDnsList.Flink ;
  757. ListEntry != &NlGlobalDnsList ;
  758. ListEntry = ListEntry->Flink ) {
  759. NlDnsName = CONTAINING_RECORD( ListEntry, NL_DNS_NAME, Next );
  760. //
  761. // If this entry is marked for deletion,
  762. // skip it
  763. //
  764. if ( NlDnsName->State == DeleteMe ) {
  765. continue;
  766. }
  767. //
  768. // Only do entries that have been registered.
  769. //
  770. // The whole purpose of this log is to keep track of names that
  771. // need to be deregistered sooner or later.
  772. //
  773. if ( NlDnsName->Flags & NL_DNS_REGISTERED_ONCE ) {
  774. //
  775. // Compute the size of this entry.
  776. //
  777. CurrentSize = sizeof(NL_DNSLOG_ENTRY);
  778. CurrentSize += strlen( NlDnsName->DnsRecordName ) + 1;
  779. if ( NlDnsName->DnsHostName != NULL ) {
  780. CurrentSize += strlen( NlDnsName->DnsHostName ) + 1;
  781. }
  782. CurrentSize = ROUND_UP_COUNT( CurrentSize, ALIGN_WORST );
  783. //
  784. // Add it to the size needed for the file.
  785. //
  786. DnsRecordBufferSize += CurrentSize;
  787. }
  788. }
  789. //
  790. // Allocate a block to build the binary log into.
  791. // (and the build the file name in)
  792. //
  793. DnsRecordBuffer = LocalAlloc( LMEM_ZEROINIT, DnsRecordBufferSize );
  794. if ( DnsRecordBuffer == NULL ) {
  795. LeaveCriticalSection( &NlGlobalDnsCritSect );
  796. goto Cleanup;
  797. }
  798. DnsRecordBuffer->Version = NL_DNSLOG_VERSION;
  799. DnsLogEntry = (PNL_DNSLOG_ENTRY)ROUND_UP_POINTER( (DnsRecordBuffer + 1), ALIGN_WORST );
  800. for ( ListEntry = NlGlobalDnsList.Flink ;
  801. ListEntry != &NlGlobalDnsList ;
  802. ListEntry = ListEntry->Flink ) {
  803. ULONG DnsRecordNameSize;
  804. ULONG DnsHostNameSize;
  805. NlDnsName = CONTAINING_RECORD( ListEntry, NL_DNS_NAME, Next );
  806. //
  807. // If this entry is marked for deletion,
  808. // skip it
  809. //
  810. if ( NlDnsName->State == DeleteMe ) {
  811. continue;
  812. }
  813. //
  814. // Only do entries that have been registered.
  815. //
  816. // The whole purpose of this log is to keep track of names that
  817. // need to be deregistered sooner or later.
  818. //
  819. if ( NlDnsName->Flags & NL_DNS_REGISTERED_ONCE ) {
  820. //
  821. // Compute the size of this entry.
  822. //
  823. DnsRecordNameSize = strlen( NlDnsName->DnsRecordName ) + 1;
  824. CurrentSize = sizeof(NL_DNSLOG_ENTRY) + DnsRecordNameSize;
  825. if ( NlDnsName->DnsHostName != NULL ) {
  826. DnsHostNameSize = strlen( NlDnsName->DnsHostName ) + 1;
  827. CurrentSize += DnsHostNameSize;
  828. }
  829. CurrentSize = ROUND_UP_COUNT( CurrentSize, ALIGN_WORST );
  830. //
  831. // Put the constant size fields in the buffer.
  832. //
  833. DnsLogEntry->EntrySize = CurrentSize;
  834. DnsLogEntry->NlDnsNameType = NlDnsName->NlDnsNameType;
  835. DnsLogEntry->IpAddress = NlDnsName->IpAddress;
  836. DnsLogEntry->Priority = NlDnsName->Priority;
  837. DnsLogEntry->Weight = NlDnsName->Weight;
  838. DnsLogEntry->Port = NlDnsName->Port;
  839. //
  840. // Copy the variable length entries.
  841. //
  842. Where = (LPBYTE) (DnsLogEntry+1);
  843. strcpy( Where, NlDnsName->DnsRecordName );
  844. Where += DnsRecordNameSize;
  845. if ( NlDnsName->DnsHostName != NULL ) {
  846. strcpy( Where, NlDnsName->DnsHostName );
  847. Where += DnsHostNameSize;
  848. }
  849. Where = ROUND_UP_POINTER( Where, ALIGN_WORST );
  850. NlAssert( (ULONG)(Where-(LPBYTE)DnsLogEntry) == CurrentSize );
  851. NlAssert( (ULONG)(Where-(LPBYTE)DnsRecordBuffer) <= DnsRecordBufferSize );
  852. //
  853. // Move on to the next entry.
  854. //
  855. DnsLogEntry = (PNL_DNSLOG_ENTRY)Where;
  856. } else {
  857. NlPrintDns(( NL_DNS_MORE, NlDnsName,
  858. "NlDnsWriteBinaryLog: not written to binary log file." ));
  859. }
  860. }
  861. //
  862. // Write the buffer to the file.
  863. //
  864. NetStatus = NlWriteBinaryLog(
  865. NL_DNS_BINARY_LOG_FILE,
  866. (LPBYTE) DnsRecordBuffer,
  867. DnsRecordBufferSize );
  868. LeaveCriticalSection( &NlGlobalDnsCritSect );
  869. //
  870. // Write event log on error
  871. //
  872. if ( NetStatus != NO_ERROR ) {
  873. LPWSTR MsgStrings[2];
  874. MsgStrings[0] = NL_DNS_BINARY_LOG_FILE;
  875. MsgStrings[1] = (LPWSTR) UlongToPtr( NetStatus );
  876. NlpWriteEventlog (NELOG_NetlogonFailedFileCreate,
  877. EVENTLOG_ERROR_TYPE,
  878. (LPBYTE) &NetStatus,
  879. sizeof(NetStatus),
  880. MsgStrings,
  881. 2 | NETP_LAST_MESSAGE_IS_NETSTATUS );
  882. }
  883. Cleanup:
  884. if ( DnsRecordBuffer != NULL ) {
  885. LocalFree( DnsRecordBuffer );
  886. }
  887. return;
  888. }
  889. PNL_DNS_NAME
  890. NlDnsAllocateEntry(
  891. IN NL_DNS_NAME_TYPE NlDnsNameType,
  892. IN LPSTR DnsRecordName,
  893. IN ULONG Priority,
  894. IN ULONG Weight,
  895. IN ULONG Port,
  896. IN LPCSTR DnsHostName OPTIONAL,
  897. IN ULONG IpAddress,
  898. IN NL_DNS_NAME_STATE State
  899. )
  900. /*++
  901. Routine Description:
  902. Allocate and initialize a DNS name entry.
  903. Arguments:
  904. Fields of the structure.
  905. Return Value:
  906. Pointer to the allocated structure.
  907. NULL: not enough memory to allocate the structure
  908. --*/
  909. {
  910. PNL_DNS_NAME NlDnsName;
  911. ULONG Utf8DnsHostNameSize;
  912. ULONG DnsRecordNameSize;
  913. LPBYTE Where;
  914. //
  915. // Allocate a structure to represent this name.
  916. //
  917. if ( NlDnsARecord( NlDnsNameType ) ) {
  918. Utf8DnsHostNameSize = 0;
  919. } else {
  920. Utf8DnsHostNameSize = strlen(DnsHostName) + 1;
  921. }
  922. DnsRecordNameSize = strlen( DnsRecordName ) + 1;
  923. NlDnsName = LocalAlloc( LMEM_ZEROINIT, sizeof( NL_DNS_NAME ) +
  924. Utf8DnsHostNameSize +
  925. DnsRecordNameSize );
  926. if ( NlDnsName == NULL ) {
  927. return NULL;
  928. }
  929. Where = (LPBYTE)(NlDnsName+1);
  930. //
  931. // Initialize it and link it in.
  932. //
  933. NlDnsName->NlDnsNameType = NlDnsNameType;
  934. NlDnsName->DnsRecordName = Where;
  935. RtlCopyMemory( Where, DnsRecordName, DnsRecordNameSize );
  936. Where += DnsRecordNameSize;
  937. if ( NlDnsARecord( NlDnsNameType ) ) {
  938. NlDnsName->IpAddress = IpAddress;
  939. } else if ( NlDnsCnameRecord( NlDnsNameType ) ) {
  940. NlDnsName->DnsHostName = Where;
  941. RtlCopyMemory( Where, DnsHostName, Utf8DnsHostNameSize );
  942. // Where += Utf8DnsHostNameSize;
  943. } else {
  944. NlDnsName->Priority = Priority;
  945. NlDnsName->Port = Port;
  946. NlDnsName->Weight = Weight;
  947. NlDnsName->DnsHostName = Where;
  948. RtlCopyMemory( Where, DnsHostName, Utf8DnsHostNameSize );
  949. // Where += Utf8DnsHostNameSize;
  950. }
  951. NlDnsName->State = State;
  952. NlGlobalDnsListDirty = TRUE;
  953. EnterCriticalSection( &NlGlobalDnsCritSect );
  954. InsertTailList(&NlGlobalDnsList, &NlDnsName->Next);
  955. LeaveCriticalSection( &NlGlobalDnsCritSect );
  956. return NlDnsName;
  957. }
  958. VOID
  959. NlDnsWriteLog(
  960. VOID
  961. )
  962. /*++
  963. Routine Description:
  964. Write the list of registered DNS names to
  965. %SystemRoot%\System32\Config\netlogon.dns.
  966. Arguments:
  967. None
  968. Return Value:
  969. None.
  970. --*/
  971. {
  972. PLIST_ENTRY ListEntry;
  973. PNL_DNS_NAME NlDnsName;
  974. NET_API_STATUS NetStatus;
  975. LPWSTR AllocatedBuffer = NULL;
  976. LPWSTR FileName;
  977. LPSTR DnsRecord;
  978. LPSTR DnsName;
  979. UINT WindowsDirectoryLength;
  980. HANDLE FileHandle = INVALID_HANDLE_VALUE;
  981. EnterCriticalSection( &NlGlobalDnsCritSect );
  982. if ( !NlGlobalDnsListDirty ) {
  983. LeaveCriticalSection( &NlGlobalDnsCritSect );
  984. return;
  985. }
  986. //
  987. // Allocate a buffer for storage local to this procedure.
  988. // (Don't put it on the stack since we don't want to commit a huge stack.)
  989. //
  990. AllocatedBuffer = LocalAlloc( 0, sizeof(WCHAR) * (MAX_PATH+1) +
  991. NL_MAX_DNS_LENGTH+1 +
  992. NL_DNS_RECORD_STRING_SIZE + 1 );
  993. if ( AllocatedBuffer == NULL ) {
  994. NetStatus = ERROR_NOT_ENOUGH_MEMORY;
  995. goto Cleanup;
  996. }
  997. FileName = AllocatedBuffer;
  998. DnsName = (LPSTR)(&AllocatedBuffer[MAX_PATH+1]);
  999. DnsRecord = &DnsName[NL_MAX_DNS_LENGTH+1];
  1000. //
  1001. // Write the binary version of the log first.
  1002. //
  1003. NlDnsWriteBinaryLog();
  1004. //
  1005. // Build the name of the log file
  1006. //
  1007. WindowsDirectoryLength = GetSystemWindowsDirectoryW(
  1008. FileName,
  1009. sizeof(WCHAR) * (MAX_PATH+1) );
  1010. if ( WindowsDirectoryLength == 0 ) {
  1011. NetStatus = GetLastError();
  1012. NlPrint(( NL_CRITICAL,
  1013. "NlDnsWriteLog: Unable to GetSystemWindowsDirectoryW (%ld)\n",
  1014. NetStatus ));
  1015. goto Cleanup;
  1016. }
  1017. if ( WindowsDirectoryLength * sizeof(WCHAR) +
  1018. sizeof(WCHAR) +
  1019. sizeof(NL_DNS_LOG_FILE)
  1020. >= sizeof(WCHAR) * MAX_PATH ) {
  1021. NlPrint((NL_CRITICAL,
  1022. "NlDnsWriteLog: file name length is too long \n" ));
  1023. goto Cleanup;
  1024. }
  1025. wcscat( FileName, NL_DNS_LOG_FILE );
  1026. //
  1027. // Create a file to write to.
  1028. // If it exists already then truncate it.
  1029. //
  1030. FileHandle = CreateFileW(
  1031. FileName,
  1032. GENERIC_READ | GENERIC_WRITE,
  1033. FILE_SHARE_READ, // allow backups and debugging
  1034. NULL, // Supply better security ??
  1035. CREATE_ALWAYS, // Overwrites always
  1036. FILE_ATTRIBUTE_NORMAL,
  1037. NULL ); // No template
  1038. if ( FileHandle == INVALID_HANDLE_VALUE) {
  1039. LPWSTR MsgStrings[2];
  1040. NetStatus = GetLastError();
  1041. NlPrint((NL_CRITICAL,
  1042. "NlDnsWriteLog: %ws: Unable to create file: %ld \n",
  1043. FileName,
  1044. NetStatus));
  1045. MsgStrings[0] = FileName;
  1046. MsgStrings[1] = (LPWSTR) UlongToPtr( NetStatus );
  1047. NlpWriteEventlog (NELOG_NetlogonFailedFileCreate,
  1048. EVENTLOG_ERROR_TYPE,
  1049. (LPBYTE) &NetStatus,
  1050. sizeof(NetStatus),
  1051. MsgStrings,
  1052. 2 | NETP_LAST_MESSAGE_IS_NETSTATUS );
  1053. goto Cleanup;
  1054. }
  1055. //
  1056. // Loop through the list of DNS names writing each one to the log
  1057. //
  1058. for ( ListEntry = NlGlobalDnsList.Flink ;
  1059. ListEntry != &NlGlobalDnsList ;
  1060. ListEntry = ListEntry->Flink ) {
  1061. ULONG DnsRecordLength;
  1062. ULONG BytesWritten;
  1063. //
  1064. // If this entry really doesn't exist,
  1065. // comment it out.
  1066. //
  1067. NlDnsName = CONTAINING_RECORD( ListEntry, NL_DNS_NAME, Next );
  1068. //
  1069. // If this entry is marked for deletion,
  1070. // skip it (we must have successfully
  1071. // deregistered it and only need to
  1072. // delink and free this entry).
  1073. //
  1074. if ( NlDnsName->State == DeleteMe ) {
  1075. continue;
  1076. }
  1077. DnsRecord[0] = '\0';
  1078. switch (NlDnsName->State) {
  1079. case RegisterMe:
  1080. case Registered:
  1081. break;
  1082. default:
  1083. NlPrint(( NL_CRITICAL,
  1084. "NlDnsWriteLog: %ld: Invalid state\n",
  1085. NlDnsName->State ));
  1086. /* Drop through */
  1087. case DeregisterMe:
  1088. case DelayedDeregister:
  1089. strcat( DnsRecord, "; " );
  1090. break;
  1091. }
  1092. //
  1093. // Create the text string to write.
  1094. //
  1095. NlDnsNameToStr( NlDnsName, DnsRecord );
  1096. strcat( DnsRecord, NL_DNS_RR_EOL );
  1097. //
  1098. // Write the record to the file.
  1099. //
  1100. DnsRecordLength = strlen( DnsRecord );
  1101. if ( !WriteFile( FileHandle,
  1102. DnsRecord,
  1103. DnsRecordLength,
  1104. &BytesWritten,
  1105. NULL ) ) { // Not Overlapped
  1106. NetStatus = GetLastError();
  1107. NlPrint(( NL_CRITICAL,
  1108. "NlDnsWriteLog: %ws: Unable to WriteFile. %ld\n",
  1109. FileName,
  1110. NetStatus ));
  1111. goto Cleanup;
  1112. }
  1113. if ( BytesWritten != DnsRecordLength) {
  1114. NlPrint((NL_CRITICAL,
  1115. "NlDnsWriteLog: %ws: Write bad byte count %ld s.b. %ld\n",
  1116. FileName,
  1117. BytesWritten,
  1118. DnsRecordLength ));
  1119. goto Cleanup;
  1120. }
  1121. }
  1122. NlGlobalDnsListDirty = FALSE;
  1123. Cleanup:
  1124. if ( FileHandle != INVALID_HANDLE_VALUE ) {
  1125. CloseHandle( FileHandle );
  1126. }
  1127. LeaveCriticalSection( &NlGlobalDnsCritSect );
  1128. if ( AllocatedBuffer != NULL ) {
  1129. LocalFree(AllocatedBuffer);
  1130. }
  1131. return;
  1132. }
  1133. BOOLEAN
  1134. NlDnsHasDnsServers(
  1135. VOID
  1136. )
  1137. /*++
  1138. Routine Description:
  1139. Returns TRUE if this machine has one or more DNS servers configured.
  1140. If FALSE, it is highly unlikely that DNS name resolution will work.
  1141. Arguments:
  1142. None.
  1143. Return Value:
  1144. TRUE: This machine has one or more DNS servers configured.
  1145. --*/
  1146. {
  1147. BOOLEAN RetVal;
  1148. NET_API_STATUS NetStatus;
  1149. PDNS_RECORD DnsARecords = NULL;
  1150. //
  1151. // If there are no IP addresses,
  1152. // there are no DNS servers.
  1153. //
  1154. if ( NlGlobalWinsockPnpAddresses == NULL ) {
  1155. RetVal = FALSE;
  1156. } else {
  1157. //
  1158. // Try getting the A records for the DNS servers from DNS
  1159. //
  1160. // REVIEW: consider having DNS notify us when the DNS server state changes.
  1161. // Then we wouldn't have to bother DNS each time we need to know.
  1162. //
  1163. NetStatus = DnsQuery_UTF8(
  1164. "", // Ask for addresses of the DNS servers
  1165. DNS_TYPE_A,
  1166. 0, // No special flags
  1167. NULL, // No list of DNS servers
  1168. &DnsARecords,
  1169. NULL );
  1170. if ( NetStatus != NO_ERROR ) {
  1171. RetVal = FALSE;
  1172. } else {
  1173. RetVal = (DnsARecords != NULL);
  1174. }
  1175. if ( DnsARecords != NULL ) {
  1176. DnsRecordListFree( DnsARecords, DnsFreeRecordListDeep );
  1177. }
  1178. }
  1179. return RetVal;
  1180. }
  1181. BOOL
  1182. NlDnsCheckLastStatus(
  1183. VOID
  1184. )
  1185. /*++
  1186. Routine Description:
  1187. Query the status of DNS updates for all records as they
  1188. were registered/deregistered last time.
  1189. Arguments:
  1190. None
  1191. Return Value:
  1192. Returns TRUE if there was no error for last DNS updates
  1193. for all records. Otherwise returns FALSE.
  1194. --*/
  1195. {
  1196. PLIST_ENTRY ListEntry;
  1197. PNL_DNS_NAME NlDnsName;
  1198. BOOL Result = TRUE;
  1199. EnterCriticalSection( &NlGlobalDnsCritSect );
  1200. for ( ListEntry = NlGlobalDnsList.Flink ;
  1201. ListEntry != &NlGlobalDnsList ;
  1202. ListEntry = ListEntry->Flink ) {
  1203. NlDnsName = CONTAINING_RECORD( ListEntry, NL_DNS_NAME, Next );
  1204. if ( NlDnsName->State != DeleteMe &&
  1205. NlDnsName->NlDnsNameLastStatus != NO_ERROR ) {
  1206. Result = FALSE;
  1207. break;
  1208. }
  1209. }
  1210. LeaveCriticalSection( &NlGlobalDnsCritSect );
  1211. return Result;
  1212. }
  1213. VOID
  1214. NlDnsServerFailureOutputCheck(
  1215. VOID
  1216. )
  1217. /*++
  1218. Routine Description:
  1219. Check if it's OK to write DNS server failure event logs
  1220. Arguments:
  1221. None
  1222. Return Value:
  1223. None.
  1224. --*/
  1225. {
  1226. SC_HANDLE ScManagerHandle = NULL;
  1227. SC_HANDLE ServiceHandle = NULL;
  1228. //
  1229. // If we have already determined on any previous
  1230. // start on this boot that we should write the
  1231. // event log, there is nothing we need to check.
  1232. //
  1233. if ( NlDnsWriteServerFailureEventLog ) {
  1234. return;
  1235. }
  1236. //
  1237. // Query the service controller to see
  1238. // whether the DNS service exists
  1239. //
  1240. ScManagerHandle = OpenSCManager(
  1241. NULL,
  1242. NULL,
  1243. SC_MANAGER_CONNECT );
  1244. //
  1245. // If we couldn't open the SC,
  1246. // proceed with checking the timeout
  1247. //
  1248. if ( ScManagerHandle == NULL ) {
  1249. NlPrint(( NL_CRITICAL,
  1250. "NlDnsServerFailureOutputCheck: OpenSCManager failed: 0x%lx\n",
  1251. GetLastError()));
  1252. } else {
  1253. ServiceHandle = OpenService(
  1254. ScManagerHandle,
  1255. L"DNS",
  1256. SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG );
  1257. (VOID) CloseServiceHandle( ScManagerHandle );
  1258. //
  1259. // If DNS service does not exits locally,
  1260. // we should write DNS server failure errors
  1261. //
  1262. if ( ServiceHandle == NULL ) {
  1263. if ( GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST ) {
  1264. NlDnsWriteServerFailureEventLog = TRUE;
  1265. return;
  1266. }
  1267. //
  1268. // Service exists. Proceed with checking the timeout
  1269. //
  1270. } else {
  1271. (VOID) CloseServiceHandle( ServiceHandle );
  1272. }
  1273. }
  1274. //
  1275. // If this is not the first time we have been started or
  1276. // the timeout has elapsed, it is time to write event errors
  1277. //
  1278. if ( NlDnsInitCount > 1 ||
  1279. NetpDcElapsedTime(NlGlobalDnsStartTime) > NL_DNS_EVENTLOG_TIMEOUT ) {
  1280. NlDnsWriteServerFailureEventLog = TRUE;
  1281. }
  1282. return;
  1283. }
  1284. NET_API_STATUS
  1285. NlDnsUpdate(
  1286. IN PNL_DNS_NAME NlDnsName,
  1287. IN BOOLEAN Register
  1288. )
  1289. /*++
  1290. Routine Description:
  1291. This routine does the actual call to DNS to register or deregister a name.
  1292. Arguments:
  1293. NlDnsName - Name to register or deregister.
  1294. Register - True to register the name.
  1295. False to deregister the name.
  1296. Return Value:
  1297. NO_ERROR: The name was registered or deregistered.
  1298. --*/
  1299. {
  1300. NET_API_STATUS NetStatus = NO_ERROR;
  1301. DNS_RECORD DnsRecord;
  1302. LPWSTR MsgStrings[5] = {NULL};
  1303. ULONG DnsUpdateFlags = DNS_UPDATE_SECURITY_USE_DEFAULT;
  1304. DNS_UPDATE_EXTRA_INFO DnsUpdateExtraInfo = {0};
  1305. WCHAR DnsServerIpAddressString[NL_IP_ADDRESS_LENGTH+1];
  1306. WCHAR RcodeString[] = L"<UNAVAILABLE>";
  1307. WCHAR StatusString[] = L"<UNAVAILABLE>";
  1308. static BOOL NetlogonNoDynamicDnsLogged = FALSE;
  1309. //
  1310. // Don't let the service controller think we've hung.
  1311. //
  1312. if ( !GiveInstallHints( FALSE ) ) {
  1313. NetStatus = ERROR_DNS_NOT_CONFIGURED;
  1314. goto Cleanup;
  1315. }
  1316. //
  1317. // If dynamic DNS is manually disabled,
  1318. // warn the user to update DNS manually.
  1319. // But do not abuse the event log, write only once
  1320. //
  1321. if ( !NlGlobalParameters.UseDynamicDns ) {
  1322. NetStatus = ERROR_DYNAMIC_DNS_NOT_SUPPORTED;
  1323. if ( !NetlogonNoDynamicDnsLogged ) {
  1324. NlpWriteEventlog( NELOG_NetlogonNoDynamicDnsManual,
  1325. EVENTLOG_WARNING_TYPE,
  1326. NULL,
  1327. 0,
  1328. NULL,
  1329. 0 );
  1330. NetlogonNoDynamicDnsLogged = TRUE;
  1331. }
  1332. goto Cleanup;
  1333. //
  1334. // Otherwise, reset the boolean to account for the case when
  1335. // dynamic DNS being disabled gets enabled and then disabled again.
  1336. //
  1337. } else {
  1338. NetlogonNoDynamicDnsLogged = FALSE;
  1339. }
  1340. //
  1341. // Build the common parts of the RR.
  1342. //
  1343. RtlZeroMemory( &DnsRecord, sizeof(DnsRecord) );
  1344. DnsRecord.pNext = NULL;
  1345. DnsRecord.pName = (LPTSTR) NlDnsName->DnsRecordName;
  1346. DnsRecord.dwTtl = NlGlobalParameters.DnsTtl;
  1347. //
  1348. // Build an A RR
  1349. //
  1350. if ( NlDnsARecord( NlDnsName->NlDnsNameType ) ) {
  1351. DnsRecord.wType = DNS_TYPE_A;
  1352. DnsRecord.wDataLength = sizeof( DNS_A_DATA );
  1353. DnsRecord.Data.A.IpAddress = NlDnsName->IpAddress;
  1354. //
  1355. // Build a CNAME RR
  1356. //
  1357. } else if ( NlDnsCnameRecord( NlDnsName->NlDnsNameType ) ) {
  1358. DnsRecord.wType = DNS_TYPE_CNAME;
  1359. DnsRecord.wDataLength = sizeof( DNS_PTR_DATA );
  1360. DnsRecord.Data.CNAME.pNameHost = (LPTSTR) NlDnsName->DnsHostName;
  1361. //
  1362. // Build a SRV RR
  1363. //
  1364. } else {
  1365. DnsRecord.wType = DNS_TYPE_SRV;
  1366. DnsRecord.wDataLength = sizeof( DNS_SRV_DATA );
  1367. DnsRecord.Data.SRV.pNameTarget = (LPTSTR) NlDnsName->DnsHostName;
  1368. DnsRecord.Data.SRV.wPriority = (WORD) NlDnsName->Priority;
  1369. DnsRecord.Data.SRV.wWeight = (WORD) NlDnsName->Weight;
  1370. DnsRecord.Data.SRV.wPort = (WORD) NlDnsName->Port;
  1371. }
  1372. //
  1373. // Tell DNS to skip adapters where dynamic DNS updates
  1374. // are disabled unless we are instructed otherwise
  1375. //
  1376. if ( !NlGlobalParameters.DnsUpdateOnAllAdapters ) {
  1377. DnsUpdateFlags |= DNS_UPDATE_SKIP_NO_UPDATE_ADAPTERS;
  1378. }
  1379. //
  1380. // If it's a CNAME record (used by the DS replication),
  1381. // tell DNS to register on a remote server (in addition
  1382. // to the local server if this machine is a DNS server)
  1383. // to avoid the following so called island problem (chicken
  1384. // & egg problem): Other DCs (i.e replication destinations)
  1385. // can't locate this replication source because their DNS database
  1386. // doesn't contain this CNAME record, and their DNS database doesn't
  1387. // contain this CNAME record because the the destination DCs can't
  1388. // locate the source and can't replicate this record.
  1389. //
  1390. if ( NlDnsCnameRecord(NlDnsName->NlDnsNameType) ) {
  1391. DnsUpdateFlags |= DNS_UPDATE_REMOTE_SERVER;
  1392. }
  1393. //
  1394. // Ask DNS to return the debug info
  1395. //
  1396. DnsUpdateExtraInfo.Id = DNS_UPDATE_INFO_ID_RESULT_INFO;
  1397. //
  1398. // Call DNS to do the update.
  1399. //
  1400. if ( Register ) {
  1401. // According to RFC 2136 (and bug 173936) we need to replace the RRSet for
  1402. // CNAME records to avoid an error if other records exist by the
  1403. // same name.
  1404. //
  1405. // Note that the dynamic DNS RFC says that CNAME records ALWAYS overwrite the
  1406. // existing single record (ignoring the DNS_UPDATE_SHARED).
  1407. //
  1408. // Also, replace the record if this is a PDC name (there should be only one PDC)
  1409. //
  1410. if ( NlDnsCnameRecord( NlDnsName->NlDnsNameType ) ||
  1411. NlDnsPdcName( NlDnsName->NlDnsNameType ) ) {
  1412. NetStatus = DnsReplaceRecordSetUTF8(
  1413. &DnsRecord, // New record set
  1414. DnsUpdateFlags,
  1415. NULL, // No context handle
  1416. NULL, // DNS will choose the servers
  1417. &DnsUpdateExtraInfo );
  1418. } else {
  1419. NetStatus = DnsModifyRecordsInSet_UTF8(
  1420. &DnsRecord, // Add record
  1421. NULL, // No delete records
  1422. DnsUpdateFlags,
  1423. NULL, // No context handle
  1424. NULL, // DNS will choose the servers
  1425. &DnsUpdateExtraInfo );
  1426. }
  1427. } else {
  1428. NetStatus = DnsModifyRecordsInSet_UTF8(
  1429. NULL, // No add records
  1430. &DnsRecord, // Delete this record
  1431. DnsUpdateFlags,
  1432. NULL, // No context handle
  1433. NULL, // DNS will choose the servers
  1434. &DnsUpdateExtraInfo );
  1435. }
  1436. //
  1437. // Convert the status codes to ones we understand.
  1438. //
  1439. switch ( NetStatus ) {
  1440. case NO_ERROR:
  1441. NlDnsName->NlDnsNameLastStatus = NetStatus;
  1442. break;
  1443. case ERROR_TIMEOUT: // DNS server isn't available
  1444. case DNS_ERROR_RCODE_SERVER_FAILURE: // Server failed
  1445. //
  1446. // Don't log an error specific to the DnsRecordName since all of them
  1447. // are probably going to fail.
  1448. //
  1449. if ( NlDnsWriteServerFailureEventLog ) {
  1450. LPWSTR LocalDnsDomainName = NULL;
  1451. //
  1452. // Remember the status of the failure
  1453. //
  1454. NlDnsName->NlDnsNameLastStatus = NetStatus;
  1455. //
  1456. // Get the name of the domain that this record belongs to.
  1457. //
  1458. LocalDnsDomainName = NlDnsNameToDomainName( NlDnsName );
  1459. if ( LocalDnsDomainName != NULL ) {
  1460. MsgStrings[0] = LocalDnsDomainName;
  1461. NlpWriteEventlog( NELOG_NetlogonDynamicDnsServerFailure,
  1462. EVENTLOG_WARNING_TYPE,
  1463. (LPBYTE) &NetStatus,
  1464. sizeof(NetStatus),
  1465. MsgStrings,
  1466. 1 );
  1467. NetApiBufferFree( LocalDnsDomainName );
  1468. }
  1469. }
  1470. NetStatus = ERROR_DNS_NOT_AVAILABLE;
  1471. break;
  1472. case DNS_ERROR_NO_TCPIP: // TCP/IP not configured
  1473. case DNS_ERROR_NO_DNS_SERVERS: // DNS not configured
  1474. case WSAEAFNOSUPPORT: // Winsock Address Family not supported ??
  1475. NlDnsName->NlDnsNameLastStatus = NetStatus;
  1476. MsgStrings[0] = (LPWSTR) UlongToPtr( NetStatus );
  1477. // Don't log an error specific to the DnsRecordName since all of them
  1478. // are probably going to fail.
  1479. NlpWriteEventlog( NELOG_NetlogonDynamicDnsFailure,
  1480. EVENTLOG_WARNING_TYPE,
  1481. (LPBYTE) &NetStatus,
  1482. sizeof(NetStatus),
  1483. MsgStrings,
  1484. 1 | NETP_LAST_MESSAGE_IS_NETSTATUS );
  1485. NetStatus = ERROR_DNS_NOT_CONFIGURED;
  1486. break;
  1487. default:
  1488. NlDnsName->NlDnsNameLastStatus = NetStatus;
  1489. //
  1490. // Get the IP address
  1491. //
  1492. if ( DnsUpdateExtraInfo.U.Results.ServerIp4 != 0 ) {
  1493. NetpIpAddressToWStr( DnsUpdateExtraInfo.U.Results.ServerIp4,
  1494. DnsServerIpAddressString );
  1495. } else {
  1496. wcscpy( DnsServerIpAddressString, L"<UNAVAILABLE>" );
  1497. }
  1498. //
  1499. // Get the RCODE. Rcode is a WORD, but let's be careful to avoid
  1500. // buffer overrun problems if they change it to __int64 one day.
  1501. // Max DWORD in decimal is "4294967295" which is 11 characters
  1502. // long, so we've got enough storage for it in RcodeString.
  1503. //
  1504. if ( DnsUpdateExtraInfo.U.Results.Rcode <= MAXULONG ) {
  1505. swprintf( RcodeString, L"%lu", DnsUpdateExtraInfo.U.Results.Rcode );
  1506. }
  1507. //
  1508. // Get the status string. Above comment applies here, too.
  1509. //
  1510. if ( DnsUpdateExtraInfo.U.Results.Status <= MAXULONG ) {
  1511. swprintf( StatusString, L"%lu", DnsUpdateExtraInfo.U.Results.Status );
  1512. }
  1513. // Old server that doesn't understand dynamic DNS
  1514. if ( NetStatus == DNS_ERROR_RCODE_NOT_IMPLEMENTED ) {
  1515. MsgStrings[0] = DnsServerIpAddressString;
  1516. MsgStrings[1] = RcodeString;
  1517. MsgStrings[2] = StatusString;
  1518. NlpWriteEventlog( NELOG_NetlogonNoDynamicDns,
  1519. EVENTLOG_WARNING_TYPE,
  1520. (LPBYTE) &DnsUpdateExtraInfo.U.Results.Rcode,
  1521. sizeof(DnsUpdateExtraInfo.U.Results.Rcode),
  1522. MsgStrings,
  1523. 3 );
  1524. NetStatus = ERROR_DYNAMIC_DNS_NOT_SUPPORTED;
  1525. // All other errors
  1526. } else {
  1527. MsgStrings[0] = NlDnsNameToWStr( NlDnsName );
  1528. if ( MsgStrings[0] != NULL ) {
  1529. MsgStrings[1] = (LPWSTR) UlongToPtr( NetStatus );
  1530. MsgStrings[2] = DnsServerIpAddressString;
  1531. MsgStrings[3] = RcodeString;
  1532. MsgStrings[4] = StatusString;
  1533. NlpWriteEventlogEx(
  1534. Register ?
  1535. NELOG_NetlogonDynamicDnsRegisterFailure :
  1536. NELOG_NetlogonDynamicDnsDeregisterFailure,
  1537. EVENTLOG_ERROR_TYPE,
  1538. (LPBYTE) &DnsUpdateExtraInfo.U.Results.Rcode,
  1539. sizeof(DnsUpdateExtraInfo.U.Results.Rcode),
  1540. MsgStrings,
  1541. 5 | NETP_LAST_MESSAGE_IS_NETSTATUS,
  1542. 1 ); // status message index
  1543. NetApiBufferFree( MsgStrings[0] );
  1544. }
  1545. }
  1546. break;
  1547. }
  1548. Cleanup:
  1549. //
  1550. // Compute when we want to try this name again
  1551. //
  1552. NlQuerySystemTime( &NlDnsName->ScavengeTimer.StartTime );
  1553. if ( NlDnsName->ScavengeTimer.Period == 0 ) {
  1554. NlDnsName->ScavengeTimer.Period = min( ORIG_DNS_SCAVENGE_PERIOD, NlGlobalParameters.DnsRefreshIntervalPeriod );
  1555. } else if ( NlDnsName->ScavengeTimer.Period < NlGlobalParameters.DnsRefreshIntervalPeriod / 2 ) {
  1556. NlDnsName->ScavengeTimer.Period *= 2;
  1557. } else {
  1558. NlDnsName->ScavengeTimer.Period = NlGlobalParameters.DnsRefreshIntervalPeriod;
  1559. }
  1560. return NetStatus;
  1561. }
  1562. NET_API_STATUS
  1563. NlDnsRegisterOne(
  1564. IN PNL_DNS_NAME NlDnsName,
  1565. OUT NL_DNS_NAME_STATE *ResultingState
  1566. )
  1567. /*++
  1568. Routine Description:
  1569. This routine registers a SRV record for a particular name with DNS.
  1570. Arguments:
  1571. NlDnsName - Structure describing name to register.
  1572. ResultingState - The state of the entry after it has been scavenged.
  1573. May be undefined if we couldn't scavenge the entry for some reason.
  1574. Return Value:
  1575. NO_ERROR: The name was registered
  1576. --*/
  1577. {
  1578. NET_API_STATUS NetStatus;
  1579. //
  1580. // Initialization
  1581. //
  1582. *ResultingState = DnsNameStateInvalid;
  1583. //
  1584. // Register the name with DNS
  1585. //
  1586. NetStatus = NlDnsUpdate( NlDnsName, TRUE );
  1587. if ( NetStatus == NO_ERROR ) {
  1588. //
  1589. // Mark that the name is really registered.
  1590. //
  1591. *ResultingState = Registered;
  1592. NlPrintDns(( NL_DNS_MORE, NlDnsName,
  1593. "NlDnsRegisterOne: registered (success)" ));
  1594. //
  1595. // If DNS is not configured on this machine,
  1596. // silently ignore the error.
  1597. //
  1598. } else if ( NetStatus == ERROR_DNS_NOT_CONFIGURED ) {
  1599. NetStatus = NO_ERROR;
  1600. NlPrintDns(( NL_DNS_MORE, NlDnsName,
  1601. "NlDnsRegisterOne: not registered (dns not configured)" ));
  1602. //
  1603. // If the DNS server cannot be reached at this time,
  1604. // simply don't mark the name as registered. We'll register it later.
  1605. //
  1606. } else if ( NetStatus == ERROR_DNS_NOT_AVAILABLE ) {
  1607. NetStatus = NO_ERROR;
  1608. NlPrintDns(( NL_DNS_MORE, NlDnsName,
  1609. "NlDnsRegisterOne: not registered (dns server not available)" ));
  1610. //
  1611. // If Dynamic Dns is not supported,
  1612. // complain so the names can be added manually.
  1613. //
  1614. } else if ( NetStatus == ERROR_DYNAMIC_DNS_NOT_SUPPORTED ) {
  1615. NlPrintDns(( NL_DNS_MORE, NlDnsName,
  1616. "NlDnsRegisterOne: not registered (dynamic dns not supported)" ));
  1617. NetStatus = NO_ERROR;
  1618. }
  1619. return NetStatus;
  1620. }
  1621. NET_API_STATUS
  1622. NlDnsAddName(
  1623. IN PDOMAIN_INFO DomainInfo,
  1624. IN NL_DNS_NAME_TYPE NlDnsNameType,
  1625. IN LPWSTR SiteName,
  1626. IN ULONG IpAddress
  1627. )
  1628. /*++
  1629. Routine Description:
  1630. This routine adds a particular DNS name to the global list
  1631. of all DNS names registed by this DC.
  1632. Enter with NlGlobalDnsCritSect locked
  1633. Arguments:
  1634. DomainInfo - Domain the name is to be registered for.
  1635. NlDnsNameType - The specific type of name to be registered.
  1636. SiteName - If NlDnsNameType is any of the *AtSite values,
  1637. the site name of the site this name is registered for.
  1638. IpAddress - If NlDnsNameType is NlDnsLdapIpAddress or NlDnsGcIpAddress,
  1639. the IP address of the DC.
  1640. Return Value:
  1641. NO_ERROR: The name was registered or queued to be registered.
  1642. --*/
  1643. {
  1644. NET_API_STATUS NetStatus;
  1645. CHAR DnsRecordName[NL_MAX_DNS_LENGTH+1];
  1646. PNL_DNS_NAME NlDnsName = NULL;
  1647. PNL_DNS_NAME FoundNlDnsName = NULL;
  1648. ULONG Weight;
  1649. ULONG Port;
  1650. ULONG Priority;
  1651. ULONG LoopCount;
  1652. PLIST_ENTRY ListEntry;
  1653. //
  1654. // If there is no DNS domain name for this domain,
  1655. // silently return;
  1656. //
  1657. if ( DomainInfo->DomUtf8DnsDomainName == NULL ) {
  1658. NlPrintDom(( NL_DNS, DomainInfo,
  1659. "NlDnsRegister: %ws: Domain has no DNS domain name (silently return)\n",
  1660. NlDcDnsNameTypeDesc[NlDnsNameType].Name ));
  1661. return NO_ERROR;
  1662. }
  1663. //
  1664. // If this is a SRV or CNAME record,
  1665. // require that there is a dns host name.
  1666. //
  1667. if ( (NlDnsSrvRecord( NlDnsNameType ) || NlDnsCnameRecord( NlDnsNameType ) ) &&
  1668. DomainInfo->DomUtf8DnsHostName == NULL ) {
  1669. NlPrintDom(( NL_DNS, DomainInfo,
  1670. "NlDnsRegister: %ws: Domain has no DNS host name (silently return)\n",
  1671. NlDcDnsNameTypeDesc[NlDnsNameType].Name ));
  1672. return NO_ERROR;
  1673. }
  1674. //
  1675. // Grab the parameters we're going to register.
  1676. //
  1677. Priority = NlGlobalParameters.LdapSrvPriority;
  1678. Weight = NlGlobalParameters.LdapSrvWeight;
  1679. if ( NlDnsGcName( NlDnsNameType ) ) {
  1680. Port = NlGlobalParameters.LdapGcSrvPort;
  1681. } else if ( NlDnsKpwdRecord( NlDnsNameType )) {
  1682. Port = 464;
  1683. } else if ( NlDnsKdcRecord( NlDnsNameType ) ) {
  1684. Port = NlGlobalParameters.KdcSrvPort;
  1685. } else {
  1686. Port = NlGlobalParameters.LdapSrvPort;
  1687. }
  1688. //
  1689. // Register the record for the name and for the name alias, if any
  1690. //
  1691. for ( LoopCount = 0; LoopCount < 2; LoopCount++ ) {
  1692. NlDnsName = NULL;
  1693. FoundNlDnsName = NULL;
  1694. //
  1695. // Build the name of this DNS record.
  1696. //
  1697. // On the first loop iteration, build the active name.
  1698. // On the second loop iteration, build the name alias, if any.
  1699. //
  1700. NetStatus = NlDnsBuildName( DomainInfo,
  1701. NlDnsNameType,
  1702. SiteName,
  1703. (LoopCount == 0) ?
  1704. FALSE : // active name
  1705. TRUE, // name alias
  1706. DnsRecordName );
  1707. if ( NetStatus != NO_ERROR ) {
  1708. //
  1709. // If the domain has no DNS domain name,
  1710. // simply bypass the name registration forever.
  1711. //
  1712. if ( NetStatus == ERROR_NO_SUCH_DOMAIN ) {
  1713. NlPrintDom(( NL_CRITICAL, DomainInfo,
  1714. "NlDnsAddName: %ws: NlDnsBuildName indicates something is missing and this DNS name cannot be built (ignored)\n",
  1715. NlDcDnsNameTypeDesc[NlDnsNameType].Name ));
  1716. return NO_ERROR;
  1717. } else {
  1718. NlPrintDom(( NL_CRITICAL, DomainInfo,
  1719. "NlDnsAddName: %ws: Cannot NlDnsBuildName %ld\n",
  1720. NlDcDnsNameTypeDesc[NlDnsNameType].Name,
  1721. NetStatus ));
  1722. return NetStatus;
  1723. }
  1724. }
  1725. //
  1726. // If this name doesn't exist, skip it
  1727. //
  1728. if ( *DnsRecordName == '\0' ) {
  1729. continue;
  1730. }
  1731. //
  1732. // Loop through the list of DNS names finding any that match the one we're
  1733. // about to register.
  1734. //
  1735. for ( ListEntry = NlGlobalDnsList.Flink ;
  1736. ListEntry != &NlGlobalDnsList ;
  1737. ListEntry = ListEntry->Flink ) {
  1738. NlDnsName = CONTAINING_RECORD( ListEntry, NL_DNS_NAME, Next );
  1739. //
  1740. // If this entry is marked for deletion,
  1741. // skip it
  1742. //
  1743. if ( NlDnsName->State == DeleteMe ) {
  1744. continue;
  1745. }
  1746. //
  1747. // The names will only be equal if the name types are equal,
  1748. // the domains are compatible (equal or not specified),
  1749. // and the DnsRecordName is identical.
  1750. //
  1751. // This first test sees if the record "identifies" the same record.
  1752. //
  1753. //
  1754. if ( NlDnsName->NlDnsNameType == NlDnsNameType &&
  1755. (NlDnsName->DomainInfo == DomainInfo ||
  1756. NlDnsName->DomainInfo == NULL ) &&
  1757. NlDnsName->IpAddress == IpAddress &&
  1758. NlEqualDnsNameUtf8( DnsRecordName, NlDnsName->DnsRecordName ) ) {
  1759. BOOLEAN Identical;
  1760. BOOLEAN DeleteIt;
  1761. //
  1762. // Assume the records are identical.
  1763. //
  1764. // This second test sees if any of the "data" portion of the record
  1765. // changes.
  1766. //
  1767. // The Dynamic DNS RFC says that the Ttl field isn't used to
  1768. // distiguish the record. So, ignore it here knowing we'll
  1769. // simply re-register with the new value if the Ttl has changed.
  1770. //
  1771. DeleteIt = FALSE;
  1772. Identical = TRUE;
  1773. // Compare A records
  1774. if ( NlDnsARecord( NlDnsNameType ) ) {
  1775. // Nothing else to compare
  1776. // Compare CNAME records
  1777. } else if ( NlDnsCnameRecord( NlDnsNameType ) ) {
  1778. //
  1779. // The Dynamic DNS RFC says that the host name part of the
  1780. // CNAME record isn't used for comparison purposes. There
  1781. // can only be one record for a particular name.
  1782. // So, if the host name is different, simply ditch this entry and
  1783. // allocate a new one with the right host name.
  1784. //
  1785. if ( !NlEqualDnsNameUtf8( DomainInfo->DomUtf8DnsHostName, NlDnsName->DnsHostName )) {
  1786. DeleteIt = TRUE;
  1787. NlPrintDns(( NL_DNS_MORE, NlDnsName,
  1788. "NlDnsAddName: CNAME Host not equal. %s %s",
  1789. DomainInfo->DomUtf8DnsHostName,
  1790. NlDnsName->DnsHostName ));
  1791. }
  1792. // Compare SRV records
  1793. } else {
  1794. if ( NlDnsName->Priority != Priority ) {
  1795. Identical = FALSE;
  1796. NlPrintDns(( NL_DNS_MORE, NlDnsName,
  1797. "NlDnsAddName: Priority not equal. %ld %ld",
  1798. NlDnsName->Priority,
  1799. Priority ));
  1800. } else if ( NlDnsName->Port != Port ) {
  1801. Identical = FALSE;
  1802. NlPrintDns(( NL_DNS_MORE, NlDnsName,
  1803. "NlDnsAddName: Port not equal. %ld %ld",
  1804. NlDnsName->Port,
  1805. Port ));
  1806. } else if ( NlDnsName->Weight != Weight ) {
  1807. Identical = FALSE;
  1808. NlPrintDns(( NL_DNS_MORE, NlDnsName,
  1809. "NlDnsAddName: Weight not equal. %ld %ld",
  1810. NlDnsName->Weight,
  1811. Weight ));
  1812. } else if ( !NlEqualDnsNameUtf8( DomainInfo->DomUtf8DnsHostName, NlDnsName->DnsHostName )) {
  1813. Identical = FALSE;
  1814. NlPrintDns(( NL_DNS_MORE, NlDnsName,
  1815. "NlDnsAddName: Host not equal. %s %s",
  1816. DomainInfo->DomUtf8DnsHostName,
  1817. NlDnsName->DnsHostName ));
  1818. }
  1819. }
  1820. //
  1821. // If the entry should simply be deleted,
  1822. // do so now.
  1823. //
  1824. if ( DeleteIt ) {
  1825. NlDnsSetState( NlDnsName, DeleteMe );
  1826. NlPrintDns(( NL_CRITICAL, NlDnsName,
  1827. "NlDnsAddName: Annoying entry found (recovering)" ));
  1828. //
  1829. // If this is the exact record,
  1830. // simply mark it for registration.
  1831. //
  1832. } else if ( Identical ) {
  1833. //
  1834. // If this is the second such entry we've found,
  1835. // this is an internal error.
  1836. // But recover by deleting the entry.
  1837. //
  1838. if ( FoundNlDnsName != NULL ) {
  1839. NlDnsSetState( NlDnsName, DeleteMe );
  1840. NlPrintDns(( NL_CRITICAL, NlDnsName,
  1841. "NlDnsAddName: Duplicate entry found (recovering)" ));
  1842. } else {
  1843. if ( NlDnsName->State != Registered ) {
  1844. NlDnsSetState( NlDnsName, RegisterMe );
  1845. }
  1846. //
  1847. // DomainInfo might be NULL if this was a record marked for
  1848. // deletion.
  1849. //
  1850. NlDnsName->DomainInfo = DomainInfo;
  1851. //
  1852. // Cooperate with NlDnsAddDomainRecords and tell it that
  1853. // this entry can be kept.
  1854. //
  1855. NlDnsName->Flags &= ~NL_DNS_REGISTER_DOMAIN;
  1856. FoundNlDnsName = NlDnsName;
  1857. }
  1858. //
  1859. // If this record isn't exact,
  1860. // deregister the previous value.
  1861. //
  1862. // Don't scavenge yet. We'll pick this up when the scavenger gets
  1863. // around to running.
  1864. //
  1865. } else {
  1866. NlDnsSetState( NlDnsName, DeregisterMe );
  1867. NlPrintDns(( NL_CRITICAL, NlDnsName,
  1868. "NlDnsAddName: Similar entry found and marked for deregistration" ));
  1869. }
  1870. }
  1871. }
  1872. //
  1873. // If the name was found,
  1874. // use it.
  1875. if ( FoundNlDnsName != NULL ) {
  1876. NlDnsName = FoundNlDnsName;
  1877. NlPrintDns(( NL_DNS_MORE, NlDnsName,
  1878. "NlDnsAddName: Name already on the list" ));
  1879. //
  1880. // If not,
  1881. // allocate the structure now.
  1882. //
  1883. } else {
  1884. NlDnsName = NlDnsAllocateEntry(
  1885. NlDnsNameType,
  1886. DnsRecordName,
  1887. Priority,
  1888. Weight,
  1889. Port,
  1890. DomainInfo->DomUtf8DnsHostName,
  1891. IpAddress,
  1892. RegisterMe );
  1893. if ( NlDnsName == NULL ) {
  1894. NlPrintDom(( NL_CRITICAL, DomainInfo,
  1895. "NlDnsRegister: %ws: Cannot allocate DnsName structure\n",
  1896. NlDcDnsNameTypeDesc[NlDnsNameType].Name ));
  1897. return ERROR_NOT_ENOUGH_MEMORY;
  1898. }
  1899. NlPrintDns(( NL_DNS, NlDnsName,
  1900. "NlDnsAddName: New name added to the list" ));
  1901. NlDnsName->DomainInfo = DomainInfo;
  1902. }
  1903. }
  1904. return NO_ERROR;
  1905. }
  1906. NET_API_STATUS
  1907. NlDnsDeregisterOne(
  1908. IN PNL_DNS_NAME NlDnsName,
  1909. OUT NL_DNS_NAME_STATE *ResultingState
  1910. )
  1911. /*++
  1912. Routine Description:
  1913. This routine deregisters a the SRV record for a particular name with DNS.
  1914. Arguments:
  1915. NlDnsName - Structure describing name to deregister.
  1916. ResultingState - The state of the entry after it has been scavenged.
  1917. May be undefined if we couldn't scavenge the entry for some reason.
  1918. Return Value:
  1919. NO_ERROR: The name was deregistered
  1920. Otherwise, the name was not deregistered. The operation should be retried.
  1921. --*/
  1922. {
  1923. NET_API_STATUS NetStatus;
  1924. //
  1925. // Initialization
  1926. //
  1927. *ResultingState = DnsNameStateInvalid;
  1928. //
  1929. // Deregister the name with DNS
  1930. //
  1931. NetStatus = NlDnsUpdate( NlDnsName, FALSE );
  1932. //
  1933. // If the name has been removed for all practical purposes,
  1934. // Indicate this routine was successful.
  1935. //
  1936. if ( NetStatus == NO_ERROR ||
  1937. NetStatus == ERROR_DYNAMIC_DNS_NOT_SUPPORTED ) {
  1938. NlPrintDns(( NL_DNS, NlDnsName,
  1939. "NlDnsDeregisterOne: being deregistered (success) %ld",
  1940. NetStatus ));
  1941. *ResultingState = DeleteMe;
  1942. NetStatus = NO_ERROR;
  1943. //
  1944. // If the DNS server cannot be reached at this time,
  1945. // we'll deregister it later.
  1946. //
  1947. } else if ( NetStatus == ERROR_DNS_NOT_AVAILABLE ) {
  1948. NlPrintDns(( NL_DNS, NlDnsName,
  1949. "NlDnsDeregisterOne: being deregistered (DNS server not available)" ));
  1950. //
  1951. // If the DNS server is not configured,
  1952. // we'll deregister it later.
  1953. //
  1954. // DNS was available when we registered the name. So this is probably
  1955. // a temporary condition (such as we temporarily don't have an IP address).
  1956. //
  1957. } else if ( NetStatus == ERROR_DNS_NOT_CONFIGURED ) {
  1958. //
  1959. // If it's never really been registered,
  1960. // ditch the name
  1961. //
  1962. if ( NlDnsName->Flags & NL_DNS_REGISTERED_ONCE ) {
  1963. NlPrintDns(( NL_DNS, NlDnsName,
  1964. "NlDnsDeregisterOne: being deregistered (DNS not configured) (Try later)" ));
  1965. } else {
  1966. NlPrintDns(( NL_DNS, NlDnsName,
  1967. "NlDnsDeregisterOne: being deregistered (DNS not configured) (Ditch it)" ));
  1968. *ResultingState = DeleteMe;
  1969. NetStatus = NO_ERROR;
  1970. }
  1971. }
  1972. //
  1973. // If we successfully deregistered,
  1974. // reset the first deregistration failure time stamp
  1975. //
  1976. EnterCriticalSection( &NlGlobalDnsCritSect );
  1977. if ( NetStatus == NO_ERROR ) {
  1978. NlDnsName->FirstDeregFailureTime.QuadPart = 0;
  1979. //
  1980. // If we failed to deregister and we postponed it until later,
  1981. // check if it's time to give up on this entry
  1982. //
  1983. } else if ( *ResultingState != DeleteMe ) {
  1984. ULONG LocalDnsFailedDeregisterTimeout;
  1985. BOOLEAN FirstFailure = FALSE;
  1986. //
  1987. // Set the first deregistration failure time stamp
  1988. //
  1989. if ( NlDnsName->FirstDeregFailureTime.QuadPart == 0 ) {
  1990. NlQuerySystemTime( &NlDnsName->FirstDeregFailureTime );
  1991. FirstFailure = TRUE;
  1992. }
  1993. //
  1994. // Get the reg value for failed deregistration timeout (in seconds)
  1995. // and convert it to milliseconds
  1996. //
  1997. LocalDnsFailedDeregisterTimeout = NlGlobalParameters.DnsFailedDeregisterTimeout;
  1998. // if the value converted into milliseconds fits into a ULONG, use it
  1999. if ( LocalDnsFailedDeregisterTimeout <= MAXULONG/1000 ) {
  2000. LocalDnsFailedDeregisterTimeout *= 1000; // convert into milliseconds
  2001. // otherwise, use the max ULONG
  2002. } else {
  2003. LocalDnsFailedDeregisterTimeout = MAXULONG; // infinity
  2004. }
  2005. //
  2006. // Determine if it's time to give up on this entry
  2007. //
  2008. // If timeout is zero we are to delete immediately
  2009. // after the first failure
  2010. // Otherwise, if this is not the first failure,
  2011. // check the timestamp
  2012. //
  2013. if ( LocalDnsFailedDeregisterTimeout == 0 ||
  2014. (!FirstFailure &&
  2015. NetpLogonTimeHasElapsed(NlDnsName->FirstDeregFailureTime,
  2016. LocalDnsFailedDeregisterTimeout)) ) {
  2017. NlPrintDns(( NL_DNS, NlDnsName,
  2018. "NlDnsDeregisterOne: Ditch it due to time expire" ));
  2019. *ResultingState = DeleteMe;
  2020. NetStatus = NO_ERROR;
  2021. }
  2022. }
  2023. LeaveCriticalSection( &NlGlobalDnsCritSect );
  2024. return NetStatus;
  2025. }
  2026. VOID
  2027. NlDnsScavengeOne(
  2028. IN PNL_DNS_NAME NlDnsName,
  2029. OUT NL_DNS_NAME_STATE *ResultingState
  2030. )
  2031. /*++
  2032. Routine Description:
  2033. Register or Deregister any DNS names that need it.
  2034. Arguments:
  2035. NlDnsName - Name to scavenge. This structure will be marked for deletion
  2036. if it is no longer needed.
  2037. ResultingState - The state of the entry after it has been scavenged.
  2038. May be undefined if we couldn't scavenge the entry for some reason.
  2039. Return Value:
  2040. None.
  2041. --*/
  2042. {
  2043. LARGE_INTEGER TimeNow;
  2044. ULONG Timeout;
  2045. //
  2046. // Only scavenge this entry if its timer has expired
  2047. //
  2048. Timeout = (DWORD) -1;
  2049. NlQuerySystemTime( &TimeNow );
  2050. if ( TimerExpired( &NlDnsName->ScavengeTimer, &TimeNow, &Timeout)) {
  2051. //
  2052. // If the name needs to be deregistered,
  2053. // do it now.
  2054. //
  2055. switch ( NlDnsName->State ) {
  2056. case DeregisterMe:
  2057. NlDnsDeregisterOne( NlDnsName, ResultingState );
  2058. break;
  2059. //
  2060. // If the name needs to be registered,
  2061. // do it now.
  2062. //
  2063. case RegisterMe:
  2064. case Registered:
  2065. NlDnsRegisterOne( NlDnsName, ResultingState );
  2066. break;
  2067. }
  2068. }
  2069. }
  2070. VOID
  2071. NlDnsScavengeWorker(
  2072. IN LPVOID ScavengeRecordsParam
  2073. )
  2074. /*++
  2075. Routine Description:
  2076. Scavenge through the list of all DNS records and
  2077. register/deregisteer each record as apprropriate.
  2078. Arguments:
  2079. ScavengeRecordsParam - not used
  2080. Return Value:
  2081. None.
  2082. --*/
  2083. {
  2084. ULONG LoopCount = 0;
  2085. ULONG StartTime = 0;
  2086. ULONG CycleStartTime = 0;
  2087. ULONG Timeout = MAXULONG;
  2088. ULONG Flags = 0;
  2089. LARGE_INTEGER TimeNow;
  2090. BOOL ReasonLogged = FALSE;
  2091. BOOL ScavengeAbortedOnShutdown = FALSE;
  2092. PLIST_ENTRY ListEntry = NULL;
  2093. PNL_DNS_NAME NlDnsName = NULL;
  2094. NL_DNS_NAME_STATE ResultingState = DnsNameStateInvalid;
  2095. EnterCriticalSection( &NlGlobalDnsCritSect );
  2096. while ( NlGlobalDnsScavengeNeeded ) {
  2097. NlGlobalDnsScavengeNeeded = FALSE;
  2098. CycleStartTime = GetTickCount();
  2099. //
  2100. // Guard against infinite loop processing
  2101. //
  2102. LoopCount ++;
  2103. if ( LoopCount > NL_DNS_MAX_SCAVENGE_RESTART ) {
  2104. NlPrint(( NL_CRITICAL,
  2105. "NlDnsScavengeWorker: Avoid ReStarting DNS scavenge after too many times %ld\n",
  2106. LoopCount ));
  2107. break;
  2108. }
  2109. //
  2110. // If required,
  2111. // ensure the DomainName<1B> names are properly registered.
  2112. // Doing this only once is enough.
  2113. //
  2114. // Avoid having a crit sect locked while doing network I/O
  2115. //
  2116. if ( NlGlobalDnsScavengeFlags & NL_DNS_FIX_BROWSER_NAMES ) {
  2117. NlGlobalDnsScavengeFlags &= ~NL_DNS_FIX_BROWSER_NAMES;
  2118. LeaveCriticalSection( &NlGlobalDnsCritSect );
  2119. (VOID) NlEnumerateDomains( FALSE, NlBrowserFixAllNames, NULL );
  2120. EnterCriticalSection( &NlGlobalDnsCritSect );
  2121. }
  2122. //
  2123. // Restart the scavenge if some other thread indicated so
  2124. // and we still can do another loop. If we have no loop
  2125. // left, just press on and finish this loop -- we will
  2126. // remember this fact and retry scavenging in 5 minutes.
  2127. //
  2128. if ( NlGlobalDnsScavengeNeeded &&
  2129. LoopCount < NL_DNS_MAX_SCAVENGE_RESTART ) {
  2130. NlPrint(( NL_DNS,
  2131. "NlDnsScavengeWorker: ReStarting scavenge %ld (after adding <1B> names)\n",
  2132. LoopCount ));
  2133. continue;
  2134. }
  2135. //
  2136. // Refresh records for all domains/NDNCs in the global list
  2137. // as needed.
  2138. //
  2139. // Avoid having a crit sect locked while doing network I/O.
  2140. //
  2141. if ( NlGlobalDnsScavengeFlags & NL_DNS_REFRESH_DOMAIN_RECORDS ||
  2142. NlGlobalDnsScavengeFlags & NL_DNS_FORCE_REFRESH_DOMAIN_RECORDS ) {
  2143. Flags = NlGlobalDnsScavengeFlags;
  2144. LeaveCriticalSection( &NlGlobalDnsCritSect );
  2145. NlEnumerateDomains( TRUE, NlDnsAddDomainRecordsWithSiteRefresh, &Flags );
  2146. EnterCriticalSection( &NlGlobalDnsCritSect );
  2147. }
  2148. //
  2149. // Restart the scavenge if some other thread indicated so
  2150. // and we still can do another loop. If we have no loop
  2151. // left, just press on and finish this loop -- we will
  2152. // remember this fact and retry scavenging in 5 minutes.
  2153. //
  2154. if ( NlGlobalDnsScavengeNeeded &&
  2155. LoopCount < NL_DNS_MAX_SCAVENGE_RESTART ) {
  2156. NlPrint(( NL_DNS,
  2157. "NlDnsScavengeWorker: ReStarting scavenge %ld (after adding domain records)\n",
  2158. LoopCount ));
  2159. continue;
  2160. }
  2161. //
  2162. // Now that the global list has been updated,
  2163. // register/deregister each record as appropriate
  2164. //
  2165. for ( ListEntry = NlGlobalDnsList.Flink ;
  2166. ListEntry != &NlGlobalDnsList ;
  2167. ListEntry = ListEntry->Flink ) {
  2168. NlDnsName = CONTAINING_RECORD( ListEntry, NL_DNS_NAME, Next );
  2169. //
  2170. // If this entry is marked for deletion,
  2171. // skip it -- we will remove it below
  2172. //
  2173. if ( NlDnsName->State == DeleteMe ) {
  2174. continue;
  2175. }
  2176. //
  2177. // Abort the scavenge if we are terminating
  2178. // unless we are configured otherwise
  2179. //
  2180. if ( NlGlobalTerminate ) {
  2181. ULONG TotalElapsedTime = NetpDcElapsedTime( CycleStartTime );
  2182. //
  2183. // Continue if we are in the process of demotion
  2184. //
  2185. if ( NlGlobalDcDemotionInProgress ) {
  2186. if ( !ReasonLogged ) {
  2187. NlPrint(( NL_DNS,
  2188. "NlDnsScavengeWorker: Continue DNS scavenge on demotion\n" ));
  2189. ReasonLogged = TRUE;
  2190. }
  2191. //
  2192. // Continue if we are configured to deregister on shutdown
  2193. //
  2194. } else if ( !NlGlobalParameters.AvoidDnsDeregOnShutdown ) {
  2195. if ( !ReasonLogged ) {
  2196. NlPrint(( NL_DNS,
  2197. "NlDnsScavengeWorker: Continue DNS scavenge on shutdown (config)\n" ));
  2198. ReasonLogged = TRUE;
  2199. }
  2200. //
  2201. // Otherwise, abort the scavenge cycle
  2202. //
  2203. } else {
  2204. NlPrint(( NL_DNS_MORE,
  2205. "NlDnsScavengeWorker: Avoiding DNS scavenge on shutdown\n" ));
  2206. break;
  2207. }
  2208. //
  2209. // If we have spent all the time alloted for DNS deregistartions
  2210. // on shutdown, abort the scavenge cycle as we can't wait.
  2211. // Don't be tempted to measure the time spent on the entire
  2212. // routine rather than this cycle because previous cycles
  2213. // (if any) might not be due to a shutdown deregistration cleanup.
  2214. //
  2215. if ( TotalElapsedTime > NL_DNS_SHUTDOWN_THRESHOLD ) {
  2216. ScavengeAbortedOnShutdown = TRUE;
  2217. NlPrint(( NL_CRITICAL,
  2218. "NlDnsScavengeWorker: Abort DNS scavenge on shutdown because DNS is too slow %lu\n",
  2219. TotalElapsedTime ));
  2220. break;
  2221. }
  2222. //
  2223. // We continue the deregistration scavenge on shutdown.
  2224. // Set this entry state to deregister it.
  2225. //
  2226. NlDnsSetState( NlDnsName, DeregisterMe );
  2227. }
  2228. //
  2229. // Scavenge this entry
  2230. //
  2231. // Avoid having crit sect locked while doing network IO
  2232. //
  2233. NlPrintDns(( NL_DNS_MORE, NlDnsName, "NlDnsScavengeWorker: scavenging name" ));
  2234. StartTime = GetTickCount();
  2235. LeaveCriticalSection( &NlGlobalDnsCritSect );
  2236. ResultingState = DnsNameStateInvalid;
  2237. NlDnsScavengeOne( NlDnsName, &ResultingState );
  2238. EnterCriticalSection( &NlGlobalDnsCritSect );
  2239. //
  2240. // Report if we've spent a long time on this DNS record
  2241. //
  2242. if ( NetpDcElapsedTime(StartTime) > NL_DNS_ONE_THRESHOLD ) {
  2243. NlPrintDns(( NL_CRITICAL, NlDnsName,
  2244. "NlDnsScavengeWorker: DNS is really slow: %ld",
  2245. NetpDcElapsedTime(StartTime) ));
  2246. }
  2247. //
  2248. // Restart the scavenge if some other thread indicated so
  2249. // and we still can do another loop. If we have no loop
  2250. // left, just press on and finish this loop -- we will
  2251. // remember this fact and retry scavenging in 5 minutes.
  2252. //
  2253. if ( NlGlobalDnsScavengeNeeded &&
  2254. LoopCount < NL_DNS_MAX_SCAVENGE_RESTART ) {
  2255. NlPrint(( NL_DNS,
  2256. "NlDnsScavengeWorker: ReStarting scavenge %ld of DNS names\n",
  2257. LoopCount ));
  2258. break;
  2259. }
  2260. //
  2261. // Set the state of this entry if it's known.
  2262. //
  2263. // Note that we set the state only if the record list was
  2264. // intact while we release the crit sect doing the network
  2265. // I/O. We do this to avoid reseting the new state to
  2266. // preserve the updated knowledge about what needs to be
  2267. // done with this record on the next cycle (which is just
  2268. // about to start).
  2269. //
  2270. if ( ResultingState != DnsNameStateInvalid ) {
  2271. NlDnsSetState( NlDnsName, ResultingState );
  2272. }
  2273. }
  2274. }
  2275. //
  2276. // Do a pass through all records to:
  2277. //
  2278. // * Delete names which we successfully deregistered above
  2279. // * Determine when we should scavenge next
  2280. //
  2281. NlQuerySystemTime( &TimeNow );
  2282. for ( ListEntry = NlGlobalDnsList.Flink ;
  2283. ListEntry != &NlGlobalDnsList ;
  2284. ) {
  2285. NlDnsName = CONTAINING_RECORD( ListEntry, NL_DNS_NAME, Next );
  2286. ListEntry = ListEntry->Flink;
  2287. //
  2288. // Remove this entry if it has been deregistered successfully
  2289. //
  2290. if ( NlDnsName->State == DeleteMe ) {
  2291. RemoveEntryList( &NlDnsName->Next );
  2292. LocalFree( NlDnsName );
  2293. continue;
  2294. }
  2295. //
  2296. // Determine when this entry should be scavenged next
  2297. //
  2298. // Note that the only way the timer can expire here is when it took
  2299. // exceptionally long to update through all names so that by the
  2300. // end of the update cycle it's time to restart the cycle again.
  2301. //
  2302. if ( TimerExpired(&NlDnsName->ScavengeTimer, &TimeNow, &Timeout) ) {
  2303. Timeout = 0;
  2304. }
  2305. }
  2306. //
  2307. // Wait a couple of extra seconds. There are multiple DNS entries. They
  2308. // won't all expire at the same time. They typically expire within
  2309. // a couple of seconds of one another. Doing this will increase the
  2310. // likelihood that all DNS names will get scavenged in a single
  2311. // scavenge cycle.
  2312. //
  2313. if ( Timeout < (MAXULONG - 2000) ) {
  2314. Timeout += 2000;
  2315. } else {
  2316. Timeout = MAXULONG;
  2317. }
  2318. //
  2319. // Check whether the auto site coverage scavenging needs to happen earlier.
  2320. //
  2321. // If it does, we will do site coverage refresh (as part of DNS scavenging)
  2322. // earlier but we will not update records in DNS (because records will
  2323. // not timeout) unless site coverages changes.
  2324. //
  2325. if ( NlGlobalParameters.AutoSiteCoverage &&
  2326. NlGlobalParameters.SiteCoverageRefreshInterval*1000 < Timeout ) {
  2327. Timeout = NlGlobalParameters.SiteCoverageRefreshInterval * 1000;
  2328. }
  2329. //
  2330. // Now reset the scavenger timer unless we are terminating
  2331. //
  2332. if ( !NlGlobalTerminate ) {
  2333. NlGlobalDnsScavengerTimer.StartTime.QuadPart = TimeNow.QuadPart;
  2334. //
  2335. // If we had to abort the scavenge due to too many concurrent
  2336. // requests, backoff for 5 minutes
  2337. //
  2338. if ( NlGlobalDnsScavengeNeeded ) {
  2339. NlGlobalDnsScavengerTimer.Period = ORIG_DNS_SCAVENGE_PERIOD;
  2340. } else {
  2341. NlGlobalDnsScavengerTimer.Period = Timeout;
  2342. }
  2343. NlPrint(( NL_DNS,
  2344. "NlDnsScavengeWorker: Set DNS scavenger to run in %ld minutes (%ld).\n",
  2345. (NlGlobalDnsScavengerTimer.Period+59999)/60000,
  2346. NlGlobalDnsScavengerTimer.Period ));
  2347. if ( !SetEvent(NlGlobalTimerEvent) ) {
  2348. NlPrint(( NL_CRITICAL,
  2349. "NlDnsScavengeWorker: SetEvent failed %ld\n",
  2350. GetLastError() ));
  2351. }
  2352. }
  2353. //
  2354. // In all cases, flush any changes to disk
  2355. //
  2356. NlDnsWriteLog();
  2357. //
  2358. // If we had to abort the scavenge on demotion,
  2359. // log the event log to that effect. Do this
  2360. // after flushing the changes to the log file
  2361. // as the file is referenced in the event message.
  2362. //
  2363. if ( NlGlobalDcDemotionInProgress && ScavengeAbortedOnShutdown ) {
  2364. NlpWriteEventlog( NELOG_NetlogonDnsDeregAborted,
  2365. EVENTLOG_ERROR_TYPE,
  2366. NULL,
  2367. 0,
  2368. NULL,
  2369. 0 );
  2370. }
  2371. //
  2372. // If we had to abort the scavenge due to too many concurrent
  2373. // requests, preserve the flags so that we redo what's needed
  2374. // in 5 minutes. Set the bit to avoid forced DNS scavenge within
  2375. // these 5 minutes.
  2376. //
  2377. if ( NlGlobalDnsScavengeNeeded ) {
  2378. NlGlobalDnsScavengeFlags |= NL_DNS_AVOID_FORCED_SCAVENGE;
  2379. NlPrint(( NL_CRITICAL,
  2380. "NlDnsScavengeWorker: Preserving the scavenge flags for future re-do: %ld\n",
  2381. NlGlobalDnsScavengeFlags ));
  2382. } else {
  2383. NlGlobalDnsScavengeFlags = 0;
  2384. }
  2385. //
  2386. // Indicate that we are done
  2387. //
  2388. NlGlobalDnsScavengingInProgress = FALSE;
  2389. LeaveCriticalSection( &NlGlobalDnsCritSect );
  2390. UNREFERENCED_PARAMETER( ScavengeRecordsParam );
  2391. }
  2392. VOID
  2393. NlDnsScavenge(
  2394. IN BOOL NormalScavenge,
  2395. IN BOOL RefreshDomainRecords,
  2396. IN BOOL ForceRefreshDomainRecords,
  2397. IN BOOL ForceReregister
  2398. )
  2399. /*++
  2400. Routine Description:
  2401. Register or Deregister any DNS (and <1B>) names that need it.
  2402. Arguments:
  2403. NormalScavenge -- Indicates whether this is a normal periodic
  2404. scavenge vs. scavenge forced by some external event like PnP
  2405. event. For normal scavenge, we will do periodic browser <1B>
  2406. name refresh.
  2407. RefreshDomainRecords -- Indicates whether domain records should be
  2408. refreshed in the global list before doing the DNS updates
  2409. ForceRefreshDomainRecords -- Indicates whether the refresh is forced,
  2410. that is whether we should refresh even if there is no site coverage
  2411. change. Ignored if RefreshDomainRecords is FALSE.
  2412. ForceReregister -- TRUE if records that have been already
  2413. registered should be re-registered even if their scavenge
  2414. timer hasn't expired yet.
  2415. Return Value:
  2416. None.
  2417. --*/
  2418. {
  2419. PLIST_ENTRY ListEntry;
  2420. PNL_DNS_NAME NlDnsName;
  2421. //
  2422. // Nothing to register on a workstation
  2423. //
  2424. if ( NlGlobalMemberWorkstation ) {
  2425. return;
  2426. }
  2427. NlPrint(( NL_DNS,
  2428. "NlDnsScavenge: Starting DNS scavenge with: %s %s %s %s\n",
  2429. (NormalScavenge ? "Normal" : "Force"),
  2430. (RefreshDomainRecords ? "RefreshDomainRecords" : "0"),
  2431. (ForceRefreshDomainRecords ? "ForceRefreshDomainRecords" : "0"),
  2432. (ForceReregister ? "ForceReregister" : "0") ));
  2433. //
  2434. // If Netlogon has been started for a long time,
  2435. // deregister any names that have been registered in
  2436. // a previous incarnation, but have not been registered in this incarnation.
  2437. //
  2438. // We wait a while to do these deregistrations because:
  2439. //
  2440. // * Some of the registrations done by netlogon are a function of multiple
  2441. // hosted domains. The initialization of such domains are done asynchronously.
  2442. // * Some of the registrations done by netlogon are done as a function of
  2443. // other processes telling us that a name needs registration. (e.g., the
  2444. // GC name is registered only after the DS starts completely.)
  2445. //
  2446. // So, it is better to wait a long time to deregister these old registrations
  2447. // than to risk deregistering them then immediately re-registering them.
  2448. //
  2449. EnterCriticalSection( &NlGlobalDnsCritSect );
  2450. if ( !NlGlobalDnsInitialCleanupDone &&
  2451. NetpDcElapsedTime(NlGlobalDnsStartTime) > NL_DNS_INITIAL_CLEANUP_TIME ) {
  2452. NlPrint(( NL_DNS,
  2453. "NlDnsScavenge: Mark all delayed deregistrations for deregistration.\n" ));
  2454. //
  2455. // Mark all delayed deregistrations to deregister now.
  2456. //
  2457. for ( ListEntry = NlGlobalDnsList.Flink ;
  2458. ListEntry != &NlGlobalDnsList ;
  2459. ListEntry = ListEntry->Flink ) {
  2460. NlDnsName = CONTAINING_RECORD( ListEntry, NL_DNS_NAME, Next );
  2461. if ( NlDnsName->State == DelayedDeregister ) {
  2462. NlDnsSetState( NlDnsName, DeregisterMe );
  2463. }
  2464. }
  2465. NlGlobalDnsInitialCleanupDone = TRUE;
  2466. }
  2467. //
  2468. // Check if it's time to log "DNS server failure" errors.
  2469. // We do this check before the series of updates so that
  2470. // we don't miss an error for any given name we register.
  2471. //
  2472. NlDnsServerFailureOutputCheck();
  2473. //
  2474. // Indicate that a new scavenge cycle is needed
  2475. //
  2476. NlGlobalDnsScavengeNeeded = TRUE;
  2477. //
  2478. // Set the scavenge flags. Don't clear any flags as there might
  2479. // already be an outstanding scavenge running that requires
  2480. // a bigger work. This way we will do all the work required
  2481. // in the last of the oustanding scavenging cycles. The scavenge
  2482. // worker will clear all the bits when it's done.
  2483. //
  2484. // Indicate whether domain records should be refreshed in
  2485. // the global list before doing the DNS updates
  2486. //
  2487. if ( RefreshDomainRecords ) {
  2488. //
  2489. // Indicate whether the refresh if forced even if there is
  2490. // no site coverage change
  2491. //
  2492. if ( ForceRefreshDomainRecords ) {
  2493. NlGlobalDnsScavengeFlags |= NL_DNS_FORCE_REFRESH_DOMAIN_RECORDS;
  2494. } else {
  2495. NlGlobalDnsScavengeFlags |= NL_DNS_REFRESH_DOMAIN_RECORDS;
  2496. }
  2497. }
  2498. //
  2499. // Indicate wether we should re-register all those records which
  2500. // have already been registered in the previous cycle even if
  2501. // their timers have not expired yet.
  2502. //
  2503. if ( ForceReregister ) {
  2504. NlGlobalDnsScavengeFlags |= NL_DNS_FORCE_RECORD_REREGISTER;
  2505. }
  2506. //
  2507. // The periodic DNS scavenger has good backoff characteristics so
  2508. // take this opportunity to ensure the DomainName<1B> names are
  2509. // properly registered.
  2510. //
  2511. if ( NormalScavenge ) {
  2512. NlGlobalDnsScavengeFlags |= NL_DNS_FIX_BROWSER_NAMES;
  2513. }
  2514. //
  2515. // Start a worker thread if it's not already running
  2516. //
  2517. if ( !NlGlobalDnsScavengingInProgress ) {
  2518. //
  2519. // Avoid starting the worker if this scavenge is forced by some external
  2520. // event while we are backing off due to high scavenging load.
  2521. // Preserve all the flags we set above so that we do all the work
  2522. // requested later when normal scavenging kicks off that should
  2523. // happen within 5 minutes.
  2524. //
  2525. if ( !NormalScavenge &&
  2526. (NlGlobalDnsScavengeFlags & NL_DNS_AVOID_FORCED_SCAVENGE) != 0 ) {
  2527. NlPrint(( NL_CRITICAL, "NlDnsScavengeRecords: avoid forced scavenge due to high load\n" ));
  2528. } else {
  2529. if ( NlQueueWorkItem( &NlGlobalDnsScavengeWorkItem, TRUE, FALSE ) ) {
  2530. NlGlobalDnsScavengingInProgress = TRUE;
  2531. } else {
  2532. NlPrint(( NL_CRITICAL, "NlDnsScavengeRecords: couldn't queue DNS scavenging\n" ));
  2533. }
  2534. }
  2535. }
  2536. LeaveCriticalSection( &NlGlobalDnsCritSect );
  2537. }
  2538. VOID
  2539. NlDnsForceScavenge(
  2540. IN BOOL RefreshDomainRecords,
  2541. IN BOOL ForceReregister
  2542. )
  2543. /*++
  2544. Routine Description:
  2545. Thing wrapper around NlDnsScavenge to pass proper
  2546. arguments for induced scavenging
  2547. Arguments:
  2548. RefreshDomainRecords -- If TRUE, domain records will be
  2549. refreshed and refreshed with force (even if site coverege
  2550. doesn't change) before doing DNS updates
  2551. ForceReregister -- TRUE if records that have been already
  2552. registered should be re-registered even if their scavenge
  2553. timer hasn't expired yet.
  2554. Return Value:
  2555. None.
  2556. --*/
  2557. {
  2558. BOOL LocalRefreshDomainRecords = FALSE;
  2559. BOOL ForceRefreshDomainRecords = FALSE;
  2560. //
  2561. // Indicate that we should refresh domain records
  2562. // in the global list with force unless we are
  2563. // instructed otherwise
  2564. //
  2565. if ( RefreshDomainRecords ) {
  2566. LocalRefreshDomainRecords = TRUE;
  2567. ForceRefreshDomainRecords = TRUE;
  2568. }
  2569. //
  2570. // Do the work
  2571. //
  2572. NlDnsScavenge( FALSE, // not a normal periodic scavenge
  2573. LocalRefreshDomainRecords,
  2574. ForceRefreshDomainRecords,
  2575. ForceReregister );
  2576. }
  2577. NET_API_STATUS
  2578. NlDnsNtdsDsaDeleteOne(
  2579. IN NL_DNS_NAME_TYPE NlDnsNameType,
  2580. IN GUID *DomainGuid OPTIONAL,
  2581. IN LPCWSTR SiteName OPTIONAL,
  2582. IN LPCSTR DnsDomainName,
  2583. IN LPCSTR DnsHostName OPTIONAL
  2584. )
  2585. /*++
  2586. Routine Description:
  2587. This routine adds a single DNS entry associated with a particular
  2588. NtDsDsa object and/or a particular DNS host name to the global
  2589. list of all DNS records registered/deregistered by this DC. The
  2590. entry is marked for deregistration.
  2591. Arguments:
  2592. NlDnsNameType - The specific type of name.
  2593. DomainGuid - Guid to append to DNS name.
  2594. For NlDnsDcByGuid, this is the GUID of the domain being located.
  2595. For NlDnsDsaCname, this is the GUID of the DSA being located.
  2596. SiteName - Name of the site to append to DNS name.
  2597. If NlDnsNameType is any of the *AtSite values,
  2598. this is the name of the site the DC is in.
  2599. DnsDomainName - Specifies the DNS domain for the name.
  2600. For NlDnsDcByGuid or any of the GC names,
  2601. this is the DNS domain name of the domain at the root of the tree of
  2602. domains.
  2603. For all others, this is the DNS domain for the DC.
  2604. DnsHostName - Specifies the DnsHostName for the record.
  2605. For SRV and CNAME records, this name must be specified
  2606. For A records, this name is ignored
  2607. Return Value:
  2608. NO_ERROR: The name was returned;
  2609. ERROR_INVALID_DOMAINNAME: Domain's name is too long. Additional labels
  2610. cannot be concatenated.
  2611. ERROR_NOT_ENOUGH_MEMORY: Not enough memory to complete the operation.
  2612. --*/
  2613. {
  2614. NET_API_STATUS NetStatus;
  2615. PNL_DNS_NAME NlDnsName;
  2616. ULONG Port;
  2617. ULONG DefaultPort;
  2618. char DnsRecordName[NL_MAX_DNS_LENGTH+1];
  2619. //
  2620. // Build the name of the record to delete
  2621. //
  2622. NetStatus = NetpDcBuildDnsName( NlDnsNameType,
  2623. DomainGuid,
  2624. SiteName,
  2625. DnsDomainName,
  2626. DnsRecordName );
  2627. if ( NetStatus != NO_ERROR ) {
  2628. return NetStatus;
  2629. }
  2630. //
  2631. // Compute the port number for this SRV record
  2632. //
  2633. if ( NlDnsGcName( NlDnsNameType ) ) {
  2634. Port = NlGlobalParameters.LdapGcSrvPort;
  2635. DefaultPort = DEFAULT_LDAPGCSRVPORT;
  2636. } else if ( NlDnsKpwdRecord( NlDnsNameType )) {
  2637. Port = 464;
  2638. DefaultPort = 464;
  2639. } else if ( NlDnsKdcRecord( NlDnsNameType )) {
  2640. Port = NlGlobalParameters.KdcSrvPort;
  2641. DefaultPort = DEFAULT_KDCSRVPORT;
  2642. } else {
  2643. Port = NlGlobalParameters.LdapSrvPort;
  2644. DefaultPort = DEFAULT_LDAPSRVPORT;
  2645. }
  2646. //
  2647. // Queue the entry for deletion.
  2648. //
  2649. EnterCriticalSection( &NlGlobalDnsCritSect );
  2650. NlDnsName = NlDnsAllocateEntry( NlDnsNameType,
  2651. DnsRecordName,
  2652. NlGlobalParameters.LdapSrvPriority, // Priority
  2653. NlGlobalParameters.LdapSrvWeight, // Weight
  2654. Port, // Port
  2655. DnsHostName,
  2656. 0, // IpAddress
  2657. DeregisterMe );
  2658. if ( NlDnsName == NULL ) {
  2659. LeaveCriticalSection( &NlGlobalDnsCritSect );
  2660. return ERROR_NOT_ENOUGH_MEMORY;
  2661. }
  2662. //
  2663. // Persist this entry so we try to delete it after a reboot
  2664. //
  2665. NlDnsName->Flags |= NL_DNS_REGISTERED_ONCE;
  2666. NlPrintDns(( NL_DNS, NlDnsName,
  2667. "NlDnsNtdsDsaDelete: Name queued for deletion" ));
  2668. //
  2669. // If any of the parameters configured on this machine aren't the default values,
  2670. // try the defaults, too
  2671. //
  2672. if ( NlGlobalParameters.LdapSrvPriority != DEFAULT_LDAPSRVPRIORITY ||
  2673. NlGlobalParameters.LdapSrvWeight != DEFAULT_LDAPSRVWEIGHT ||
  2674. Port != DefaultPort ) {
  2675. //
  2676. // Queue the entry for deletion.
  2677. //
  2678. NlDnsName = NlDnsAllocateEntry( NlDnsNameType,
  2679. DnsRecordName,
  2680. DEFAULT_LDAPSRVPRIORITY, // Priority
  2681. DEFAULT_LDAPSRVWEIGHT, // Weight
  2682. DefaultPort, // Port
  2683. DnsHostName,
  2684. 0, // IpAddress
  2685. DeregisterMe );
  2686. if ( NlDnsName == NULL ) {
  2687. LeaveCriticalSection( &NlGlobalDnsCritSect );
  2688. return ERROR_NOT_ENOUGH_MEMORY;
  2689. }
  2690. //
  2691. // Persist this entry so we try to delete it after a reboot
  2692. //
  2693. NlDnsName->Flags |= NL_DNS_REGISTERED_ONCE;
  2694. NlPrintDns(( NL_DNS, NlDnsName,
  2695. "NlDnsNtdsDsaDelete: Name queued for deletion" ));
  2696. }
  2697. LeaveCriticalSection( &NlGlobalDnsCritSect );
  2698. return NO_ERROR;
  2699. }
  2700. NTSTATUS
  2701. NlDnsNtdsDsaDeletion (
  2702. IN LPWSTR DnsDomainName OPTIONAL,
  2703. IN GUID *DomainGuid OPTIONAL,
  2704. IN GUID *DsaGuid OPTIONAL,
  2705. IN LPWSTR DnsHostName
  2706. )
  2707. /*++
  2708. Routine Description:
  2709. This function deletes all DNS entries associated with a particular
  2710. NtDsDsa object and/or a particular DNS host name.
  2711. This routine does NOT delete A records registered by the DC. We have
  2712. no way of finding out the IP addresses of the long gone DC.
  2713. Arguments:
  2714. DnsDomainName - DNS domain name of the domain the DC was in.
  2715. This need not be a domain hosted by this DC.
  2716. If NULL, it is implied to be the DnsHostName with the leftmost label
  2717. removed.
  2718. DomainGuid - Domain Guid of the domain specified by DnsDomainName
  2719. If NULL, GUID specific names will not be removed.
  2720. DsaGuid - GUID of the NtdsDsa object that is being deleted.
  2721. DnsHostName - DNS host name of the DC whose NTDS-DSA object is being deleted.
  2722. Return Value:
  2723. Status of the operation.
  2724. --*/
  2725. {
  2726. NET_API_STATUS NetStatus;
  2727. NTSTATUS Status;
  2728. LPSTR Utf8DnsDomainName = NULL;
  2729. LPSTR Utf8DnsHostName = NULL;
  2730. PLSAP_SITE_INFO SiteInformation = NULL;
  2731. ULONG i;
  2732. ULONG NameIndex;
  2733. //
  2734. // Validate passed parameters
  2735. //
  2736. if ( DnsHostName == NULL ||
  2737. !NetpDcValidDnsDomain(DnsHostName) ) {
  2738. NetStatus = ERROR_INVALID_NAME;
  2739. goto Cleanup;
  2740. }
  2741. //
  2742. // If DNS domain name isn't specified,
  2743. // infer it from the DnsHostName
  2744. //
  2745. if ( DnsDomainName == NULL ) {
  2746. DnsDomainName = wcschr( DnsHostName, L'.' );
  2747. if ( DnsDomainName == NULL ) {
  2748. NetStatus = ERROR_INVALID_NAME;
  2749. goto Cleanup;
  2750. }
  2751. DnsDomainName ++;
  2752. if ( *DnsDomainName == '\0' ) {
  2753. NetStatus = ERROR_INVALID_NAME;
  2754. goto Cleanup;
  2755. }
  2756. } else if ( !NetpDcValidDnsDomain(DnsDomainName) ) {
  2757. NetStatus = ERROR_INVALID_NAME;
  2758. goto Cleanup;
  2759. }
  2760. //
  2761. // Initialization
  2762. //
  2763. Utf8DnsDomainName = NetpAllocUtf8StrFromWStr( DnsDomainName );
  2764. if ( Utf8DnsDomainName == NULL ) {
  2765. NetStatus = ERROR_NOT_ENOUGH_MEMORY;
  2766. goto Cleanup;
  2767. }
  2768. Utf8DnsHostName = NetpAllocUtf8StrFromWStr( DnsHostName );
  2769. if ( Utf8DnsHostName == NULL ) {
  2770. NetStatus = ERROR_NOT_ENOUGH_MEMORY;
  2771. goto Cleanup;
  2772. }
  2773. //
  2774. // Enumerate the sites supported by this forest so we can delete
  2775. // the records that are named by site.
  2776. //
  2777. // We need to delete the records for all sites since we don't know which
  2778. // sites are "covered" by the removed DC.
  2779. //
  2780. Status = LsaIQuerySiteInfo( &SiteInformation );
  2781. if ( !NT_SUCCESS(Status) ) {
  2782. NlPrint(( NL_CRITICAL,
  2783. "NlDnsNtdsDsaDeletion: Cannot LsaIQuerySiteInfo 0x%lx\n", Status ));
  2784. NetStatus = NetpNtStatusToApiStatus( Status );
  2785. goto Cleanup;
  2786. }
  2787. //
  2788. // Loop through the list of names Netlogon understands deleting them all
  2789. //
  2790. for ( NameIndex = 0;
  2791. NameIndex < NL_DNS_NAME_TYPE_COUNT;
  2792. NameIndex++) {
  2793. LPSTR LocalDomainName;
  2794. GUID *LocalGuid;
  2795. //
  2796. // If the name is obsolete,
  2797. // ignore it.
  2798. //
  2799. if ( NlDcDnsNameTypeDesc[NameIndex].DsGetDcFlags == 0 ) {
  2800. continue;
  2801. }
  2802. //
  2803. // We don't know how to delete the A records since we don't know the IP address.
  2804. //
  2805. // We'd ask DNS what the IP address is, but the name might not exist. If it does
  2806. // we don't know whether the IP address has already been assign to another DC.
  2807. //
  2808. if ( NlDnsARecord( NameIndex ) ) {
  2809. continue;
  2810. }
  2811. //
  2812. // Use either the DomainName or ForestName
  2813. //
  2814. if ( NlDcDnsNameTypeDesc[NameIndex].IsForestRelative ) {
  2815. LocalDomainName = NlGlobalUtf8DnsForestName;
  2816. } else {
  2817. LocalDomainName = Utf8DnsDomainName;
  2818. }
  2819. //
  2820. // Figure out which GUID to use for this name.
  2821. //
  2822. if ( NlDnsCnameRecord( NameIndex ) ) {
  2823. //
  2824. // If we don't know the Dsa GUID,
  2825. // ignore names that need it.
  2826. //
  2827. if ( DsaGuid == NULL || IsEqualGUID( DsaGuid, &NlGlobalZeroGuid) ) {
  2828. continue;
  2829. }
  2830. LocalGuid = DsaGuid;
  2831. } else if ( NlDnsDcGuid( NameIndex )) {
  2832. //
  2833. // If we don't know the Domain GUID,
  2834. // ignore names that need it.
  2835. //
  2836. if ( DomainGuid == NULL || IsEqualGUID( DomainGuid, &NlGlobalZeroGuid) ) {
  2837. continue;
  2838. }
  2839. LocalGuid = DomainGuid;
  2840. } else {
  2841. LocalGuid = NULL;
  2842. }
  2843. //
  2844. // If the name isn't site specific,
  2845. // just delete the one name.
  2846. //
  2847. if ( !NlDcDnsNameTypeDesc[NameIndex].IsSiteSpecific ) {
  2848. NetStatus = NlDnsNtdsDsaDeleteOne( (NL_DNS_NAME_TYPE) NameIndex,
  2849. LocalGuid,
  2850. NULL, // No site name
  2851. LocalDomainName,
  2852. Utf8DnsHostName );
  2853. if ( NetStatus != NO_ERROR ) {
  2854. goto Cleanup;
  2855. }
  2856. //
  2857. // If the name is site specific,
  2858. // we need to delete the records for all sites since we don't know which
  2859. // sites are "covered" by the removed DC.
  2860. //
  2861. } else {
  2862. //
  2863. // Loop deleting entries for each Site
  2864. //
  2865. for ( i=0; i<SiteInformation->SiteCount; i++ ) {
  2866. NetStatus = NlDnsNtdsDsaDeleteOne( (NL_DNS_NAME_TYPE) NameIndex,
  2867. LocalGuid,
  2868. SiteInformation->Sites[i].SiteName.Buffer,
  2869. LocalDomainName,
  2870. Utf8DnsHostName );
  2871. if ( NetStatus != NO_ERROR ) {
  2872. goto Cleanup;
  2873. }
  2874. }
  2875. }
  2876. }
  2877. //
  2878. // Now that the entries are on the list,
  2879. // scavenge through the list and delete
  2880. // the entries (in a worker thread)
  2881. //
  2882. NlDnsForceScavenge( FALSE, // don't refresh domain records
  2883. FALSE ); // don't force re-register
  2884. NetStatus = NO_ERROR;
  2885. //
  2886. // Clean up locally used resources.
  2887. //
  2888. Cleanup:
  2889. if ( Utf8DnsDomainName != NULL ) {
  2890. NetpMemoryFree( Utf8DnsDomainName );
  2891. }
  2892. if ( Utf8DnsHostName != NULL ) {
  2893. NetpMemoryFree( Utf8DnsHostName );
  2894. }
  2895. if ( SiteInformation != NULL ) {
  2896. LsaIFree_LSAP_SITE_INFO( SiteInformation );
  2897. }
  2898. //
  2899. // Flush the log
  2900. //
  2901. NlDnsWriteLog();
  2902. return NetStatus;
  2903. }
  2904. NET_API_STATUS
  2905. NlDnsAddDomainRecordsWithSiteRefresh(
  2906. IN PDOMAIN_INFO DomainInfo,
  2907. IN PULONG Flags
  2908. )
  2909. /*++
  2910. Routine Description:
  2911. This routine refreshes site coverage for a particular domain and then
  2912. it adds all of the DNS names that are supposed to be registered for
  2913. that domain to the global list of all records. It marks for deregister
  2914. any name that should not be registered for that domain.
  2915. ?? This routine should be called when ANY of the information changing the
  2916. registration changes. For instance, if the domain name changes, simply
  2917. call this routine.
  2918. Arguments:
  2919. DomainInfo - Domain the names are to be registered for.
  2920. Flags - Indicates the actions to take:
  2921. NL_DNS_FORCED_SCAVENGE - Register even if site coverage doesn't change
  2922. NL_DNS_FORCE_REREGISTER - Force re-registration of all previously
  2923. registered records
  2924. Return Value:
  2925. NO_ERROR: All names could be registered
  2926. --*/
  2927. {
  2928. NET_API_STATUS NetStatus = NO_ERROR;
  2929. NTSTATUS Status = STATUS_SUCCESS;
  2930. WCHAR CapturedSiteName[NL_MAX_DNS_LABEL_LENGTH+1];
  2931. PISM_CONNECTIVITY SiteConnect = NULL;
  2932. ULONG ThisSiteIndex = 0xFFFFFFFF;
  2933. PSOCKET_ADDRESS SocketAddresses = NULL;
  2934. ULONG SocketAddressCount = 0;
  2935. ULONG BufferSize;
  2936. PNL_SITE_ENTRY SiteEntry = NULL;
  2937. LPWSTR IpAddressList = NULL;
  2938. ULONG Index;
  2939. BOOLEAN SiteCoverageChanged = FALSE;
  2940. HANDLE DsHandle = NULL;
  2941. //
  2942. // This operation is meaningless on a workstation
  2943. //
  2944. if ( NlGlobalMemberWorkstation ) {
  2945. goto Cleanup;
  2946. }
  2947. //
  2948. // Capture the name of the site this machine is in.
  2949. //
  2950. if ( !NlCaptureSiteName( CapturedSiteName ) ) {
  2951. NlPrintDom(( NL_CRITICAL, DomainInfo,
  2952. "NlDnsAddDomainRecordsWithSiteRefresh: Cannot NlCaptureSiteName.\n" ));
  2953. goto Cleanup;
  2954. }
  2955. //
  2956. // If we are to automatically determine site coverage,
  2957. // get the site link costs.
  2958. //
  2959. if ( NlGlobalParameters.AutoSiteCoverage ) {
  2960. if ( !NlSitesGetIsmConnect(CapturedSiteName,
  2961. &SiteConnect,
  2962. &ThisSiteIndex) ) {
  2963. NlPrintDom(( NL_CRITICAL, DomainInfo,
  2964. "NlDnsAddDomainRecordsWithSiteRefresh: NlSitesGetIsmConnect failed\n" ));
  2965. }
  2966. }
  2967. //
  2968. // Ensure that ntdsapi.dll is loaded
  2969. //
  2970. Status = NlLoadNtDsApiDll();
  2971. if ( !NT_SUCCESS(Status) ) {
  2972. NlPrintDom(( NL_CRITICAL, DomainInfo,
  2973. "NlDnsAddDomainRecordsWithSiteRefresh: Cannot NlLoadNtDsApiDll 0x%lx.\n",
  2974. Status ));
  2975. DsHandle = NULL;
  2976. } else {
  2977. //
  2978. // Bind to the DS
  2979. //
  2980. NetStatus = (*NlGlobalpDsBindW)(
  2981. // L"localhost",
  2982. DomainInfo->DomUnicodeComputerNameString.Buffer,
  2983. NULL,
  2984. &DsHandle );
  2985. if ( NetStatus != NO_ERROR ) {
  2986. NlPrintDom(( NL_CRITICAL, DomainInfo,
  2987. "NlDnsAddDomainRecordsWithSiteRefresh: Cannot DsBindW %ld.\n",
  2988. NetStatus ));
  2989. DsHandle = NULL;
  2990. }
  2991. }
  2992. //
  2993. // Update the site coverage for each role we play in
  2994. // this forest/domain/NDNC
  2995. //
  2996. if ( DomainInfo->DomFlags & DOM_REAL_DOMAIN ) {
  2997. NlSitesUpdateSiteCoverageForRole( DomainInfo,
  2998. DOM_FOREST,
  2999. DsHandle,
  3000. SiteConnect,
  3001. CapturedSiteName,
  3002. ThisSiteIndex,
  3003. &SiteCoverageChanged );
  3004. NlSitesUpdateSiteCoverageForRole( DomainInfo,
  3005. DOM_REAL_DOMAIN,
  3006. DsHandle,
  3007. SiteConnect,
  3008. CapturedSiteName,
  3009. ThisSiteIndex,
  3010. &SiteCoverageChanged );
  3011. }
  3012. if ( DomainInfo->DomFlags & DOM_NON_DOMAIN_NC ) {
  3013. NlSitesUpdateSiteCoverageForRole( DomainInfo,
  3014. DOM_NON_DOMAIN_NC,
  3015. DsHandle,
  3016. SiteConnect,
  3017. CapturedSiteName,
  3018. ThisSiteIndex,
  3019. &SiteCoverageChanged );
  3020. }
  3021. //
  3022. // If the site coverage changed or we are forced to refresh
  3023. // domain records even if site coverage hasn't changed,
  3024. // do so
  3025. //
  3026. if ( ((*Flags) & NL_DNS_FORCE_REFRESH_DOMAIN_RECORDS) != 0 ||
  3027. SiteCoverageChanged ) {
  3028. NetStatus = NlDnsAddDomainRecords( DomainInfo, *Flags );
  3029. if ( NetStatus != NO_ERROR ) {
  3030. NlPrintDom(( NL_CRITICAL, DomainInfo,
  3031. "NlDnsAddDomainRecordsWithSiteRefresh: Cannot NlDnsAddDomainRecords 0x%lx.\n",
  3032. NetStatus ));
  3033. }
  3034. }
  3035. //
  3036. // Inform the user if none of our IP addresses maps to our site.
  3037. // Do it only once (for the primary domain processing).
  3038. // ?? When we support multihosting, our site will be different depending
  3039. // on the forest of a particular domain we host. So we will need to do
  3040. // this check for each site.
  3041. //
  3042. if ( DomainInfo->DomFlags & DOM_PRIMARY_DOMAIN ) {
  3043. SocketAddressCount = NlTransportGetIpAddresses(
  3044. 0, // No special header,
  3045. FALSE, // Return pointers
  3046. &SocketAddresses,
  3047. &BufferSize );
  3048. for ( Index = 0; Index < SocketAddressCount; Index++ ) {
  3049. SiteEntry = NlFindSiteEntryBySockAddr( SocketAddresses[Index].lpSockaddr );
  3050. if ( SiteEntry != NULL ) {
  3051. if ( _wcsicmp(SiteEntry->SiteName, CapturedSiteName) == 0 ) {
  3052. break;
  3053. }
  3054. NlDerefSiteEntry( SiteEntry );
  3055. SiteEntry = NULL;
  3056. }
  3057. }
  3058. //
  3059. // Log the error
  3060. //
  3061. if ( SiteEntry == NULL && SocketAddressCount != 0 ) {
  3062. LPWSTR MsgStrings[2];
  3063. //
  3064. // Form the list of IP addresses for event log output
  3065. //
  3066. IpAddressList = LocalAlloc( LMEM_ZEROINIT,
  3067. SocketAddressCount * (NL_SOCK_ADDRESS_LENGTH+1) * sizeof(WCHAR) );
  3068. if ( IpAddressList == NULL ) {
  3069. goto Cleanup;
  3070. }
  3071. //
  3072. // Loop adding all addresses to the list
  3073. //
  3074. for ( Index = 0; Index < SocketAddressCount; Index++ ) {
  3075. WCHAR IpAddressString[NL_SOCK_ADDRESS_LENGTH+1] = {0};
  3076. NetStatus = NetpSockAddrToWStr(
  3077. SocketAddresses[Index].lpSockaddr,
  3078. SocketAddresses[Index].iSockaddrLength,
  3079. IpAddressString );
  3080. if ( NetStatus != NO_ERROR ) {
  3081. goto Cleanup;
  3082. }
  3083. //
  3084. // If this is not the first address on the list,
  3085. // separate addresses by space
  3086. //
  3087. if ( *IpAddressList != UNICODE_NULL ) {
  3088. wcscat( IpAddressList, L" " );
  3089. }
  3090. //
  3091. // Add this address to the list
  3092. //
  3093. wcscat( IpAddressList, IpAddressString );
  3094. }
  3095. //
  3096. // Now write the event
  3097. //
  3098. MsgStrings[0] = CapturedSiteName;
  3099. MsgStrings[1] = IpAddressList;
  3100. NlpWriteEventlog( NELOG_NetlogonNoAddressToSiteMapping,
  3101. EVENTLOG_WARNING_TYPE,
  3102. NULL,
  3103. 0,
  3104. MsgStrings,
  3105. 2 );
  3106. }
  3107. }
  3108. Cleanup:
  3109. if ( DsHandle != NULL ) {
  3110. (*NlGlobalpDsUnBindW)( &DsHandle );
  3111. }
  3112. if ( SiteConnect != NULL ) {
  3113. I_ISMFree( SiteConnect );
  3114. }
  3115. if ( SocketAddresses != NULL ) {
  3116. LocalFree( SocketAddresses );
  3117. }
  3118. if ( IpAddressList != NULL ) {
  3119. LocalFree( IpAddressList );
  3120. }
  3121. if ( SiteEntry != NULL ) {
  3122. NlDerefSiteEntry( SiteEntry );
  3123. }
  3124. return NO_ERROR;
  3125. }
  3126. NET_API_STATUS
  3127. NlDnsAddDomainRecords(
  3128. IN PDOMAIN_INFO DomainInfo,
  3129. IN ULONG Flags
  3130. )
  3131. /*++
  3132. Routine Description:
  3133. This routine adds all of the DNS names that are supposed to be
  3134. registered for a particular domain to the global list of all records.
  3135. It marks for deregister any name that should not be registered.
  3136. ?? This routine should be called when ANY of the information changing the
  3137. registration changes. For instance, if the domain name changes, simply
  3138. call this routine.
  3139. Arguments:
  3140. DomainInfo - Domain the names are to be registered for.
  3141. Flags - Indicates the actions to take:
  3142. NL_DNS_FORCE_REREGISTER - Force re-registration of all previously
  3143. registered records
  3144. Return Value:
  3145. NO_ERROR: All names could be registered
  3146. --*/
  3147. {
  3148. NET_API_STATUS NetStatus;
  3149. NET_API_STATUS SaveNetStatus = NO_ERROR;
  3150. PNL_DNS_NAME NlDnsName = NULL;
  3151. PLIST_ENTRY ListEntry;
  3152. ULONG DomainFlags;
  3153. ULONG i;
  3154. ULONG SocketAddressCount;
  3155. PSOCKET_ADDRESS SocketAddresses = NULL;
  3156. ULONG BufferSize;
  3157. PNL_SITE_NAME_ARRAY DcSiteNames = NULL;
  3158. PNL_SITE_NAME_ARRAY GcSiteNames = NULL;
  3159. ULONG SiteIndex;
  3160. ULONG NameIndex;
  3161. //
  3162. // Get the list of IP Addresses for this machine.
  3163. //
  3164. SocketAddressCount = NlTransportGetIpAddresses(
  3165. 0, // No special header,
  3166. FALSE, // Return pointers
  3167. &SocketAddresses,
  3168. &BufferSize );
  3169. //
  3170. // Loop marking all of the current entries for this domain.
  3171. //
  3172. EnterCriticalSection( &NlGlobalDnsCritSect );
  3173. for ( ListEntry = NlGlobalDnsList.Flink ;
  3174. ListEntry != &NlGlobalDnsList ;
  3175. ListEntry = ListEntry->Flink ) {
  3176. //
  3177. // If entry is for this domain,
  3178. // mark it.
  3179. //
  3180. NlDnsName = CONTAINING_RECORD( ListEntry, NL_DNS_NAME, Next );
  3181. if ( NlDnsName->DomainInfo == DomainInfo ) {
  3182. NlDnsName->Flags |= NL_DNS_REGISTER_DOMAIN;
  3183. //
  3184. // If we are to force the re-registration of this record,
  3185. // mark the name as RegisterMe to force us to try again
  3186. //
  3187. if ( (Flags & NL_DNS_FORCE_RECORD_REREGISTER) != 0 ) {
  3188. if ( NlDnsName->State == Registered ) {
  3189. NlDnsSetState ( NlDnsName, RegisterMe );
  3190. }
  3191. }
  3192. }
  3193. }
  3194. //
  3195. // If the hosted domain still exists,
  3196. // register all of the appropriate names.
  3197. //
  3198. if ( (DomainInfo->DomFlags & DOM_DELETED) == 0 ) {
  3199. //
  3200. // Determine which names should be registered now.
  3201. //
  3202. DomainFlags = NlGetDomainFlags( DomainInfo );
  3203. // Always register the DS names regardless of whether the DS is
  3204. // actually running.
  3205. //
  3206. // We actually think this will always be a no-op except during
  3207. // installation and when booted to use the registry version of SAM.
  3208. //
  3209. if ( DomainInfo->DomFlags & DOM_REAL_DOMAIN ) {
  3210. DomainFlags |= DS_DS_FLAG;
  3211. }
  3212. //
  3213. // Get the list of Sites covered by this DC/NDNC
  3214. //
  3215. NetStatus = NlSitesGetCloseSites( DomainInfo,
  3216. DOM_REAL_DOMAIN | DOM_NON_DOMAIN_NC,
  3217. &DcSiteNames );
  3218. if ( NetStatus != NERR_Success ) {
  3219. NlPrintDom((NL_INIT, DomainInfo,
  3220. "Couldn't NlSitesGetCloseSites %ld 0x%lx.\n",
  3221. NetStatus, NetStatus ));
  3222. SaveNetStatus = NetStatus;
  3223. }
  3224. //
  3225. // Get the list of Sites covered by this GC
  3226. //
  3227. NetStatus = NlSitesGetCloseSites( DomainInfo,
  3228. DOM_FOREST,
  3229. &GcSiteNames );
  3230. if ( NetStatus != NERR_Success ) {
  3231. NlPrintDom((NL_CRITICAL, DomainInfo,
  3232. "Couldn't NlSitesGetCloseSites (GcAtSite) %ld 0x%lx.\n",
  3233. NetStatus, NetStatus ));
  3234. SaveNetStatus = NetStatus;
  3235. }
  3236. //
  3237. // Loop through each name seeing if it needs to be registered.
  3238. //
  3239. for ( NameIndex = 0;
  3240. NameIndex < NL_DNS_NAME_TYPE_COUNT;
  3241. NameIndex++) {
  3242. //
  3243. // If this DC is playing the role described by this name,
  3244. // register the name.
  3245. //
  3246. if ( DomainFlags & NlDcDnsNameTypeDesc[NameIndex].DsGetDcFlags ) {
  3247. BOOL SkipName = FALSE;
  3248. //
  3249. // Don't register this name if we are to avoid it
  3250. //
  3251. EnterCriticalSection( &NlGlobalParametersCritSect );
  3252. if ( NlGlobalParameters.DnsAvoidRegisterRecords != NULL ) {
  3253. LPTSTR_ARRAY TStrArray;
  3254. TStrArray = NlGlobalParameters.DnsAvoidRegisterRecords;
  3255. while ( !NetpIsTStrArrayEmpty(TStrArray) ) {
  3256. if ( _wcsicmp(TStrArray,
  3257. NlDcDnsNameTypeDesc[NameIndex].Name + NL_DNS_NAME_PREFIX_LENGTH) == 0 ) {
  3258. SkipName = TRUE;
  3259. break;
  3260. }
  3261. TStrArray = NetpNextTStrArrayEntry(TStrArray);
  3262. }
  3263. }
  3264. LeaveCriticalSection( &NlGlobalParametersCritSect );
  3265. if ( SkipName ) {
  3266. NlPrintDom(( NL_DNS, DomainInfo,
  3267. "NlDnsAddDomainRecords: Skipping name %ws (per registry)\n",
  3268. NlDcDnsNameTypeDesc[NameIndex].Name ));
  3269. continue;
  3270. }
  3271. //
  3272. // Do other checks since we have to support the old
  3273. // ways of disabling DNS registrations
  3274. //
  3275. // If the name registers an A record,
  3276. // register it for each IP address.
  3277. //
  3278. if ( NlDnsARecord( NameIndex) ) {
  3279. //
  3280. // If we aren't supposed to register A records,
  3281. // Just skip this name
  3282. //
  3283. if ( !NlGlobalParameters.RegisterDnsARecords ) {
  3284. continue;
  3285. }
  3286. //
  3287. // Register the domain name for each IP address of the machine.
  3288. //
  3289. for ( i=0; i<SocketAddressCount; i++ ) {
  3290. ULONG IpAddress;
  3291. //
  3292. // Require AF_INET for now
  3293. //
  3294. if ( SocketAddresses[i].lpSockaddr->sa_family != AF_INET ) {
  3295. continue;
  3296. }
  3297. IpAddress =
  3298. ((PSOCKADDR_IN) SocketAddresses[i].lpSockaddr)->sin_addr.S_un.S_addr;
  3299. NetStatus = NlDnsAddName( DomainInfo,
  3300. (NL_DNS_NAME_TYPE)NameIndex,
  3301. NULL,
  3302. IpAddress );
  3303. if ( NetStatus != NERR_Success ) {
  3304. #if NETLOGONDBG
  3305. CHAR IpAddressString[NL_IP_ADDRESS_LENGTH+1];
  3306. NetpIpAddressToStr( IpAddress, IpAddressString );
  3307. NlPrintDom((NL_CRITICAL, DomainInfo,
  3308. "Couldn't NlDnsAddName (%ws %s) %ld 0x%lx.\n",
  3309. NlDcDnsNameTypeDesc[NameIndex].Name,
  3310. IpAddressString,
  3311. NetStatus, NetStatus ));
  3312. #endif // NETLOGONDBG
  3313. SaveNetStatus = NetStatus;
  3314. }
  3315. }
  3316. //
  3317. // If the name isn't site specific,
  3318. // just register the single name.
  3319. //
  3320. } else if ( !NlDcDnsNameTypeDesc[NameIndex].IsSiteSpecific ) {
  3321. NetStatus = NlDnsAddName( DomainInfo,
  3322. (NL_DNS_NAME_TYPE)NameIndex,
  3323. NULL,
  3324. 0 );
  3325. if ( NetStatus != NERR_Success ) {
  3326. NlPrintDom((NL_CRITICAL, DomainInfo,
  3327. "Couldn't NlDnsAddName (%ws) %ld 0x%lx.\n",
  3328. NlDcDnsNameTypeDesc[NameIndex].Name,
  3329. NetStatus, NetStatus ));
  3330. SaveNetStatus = NetStatus;
  3331. }
  3332. //
  3333. // If the name is site specific,
  3334. // register the name for each covered site.
  3335. //
  3336. } else {
  3337. PUNICODE_STRING SiteNames;
  3338. ULONG SiteCount;
  3339. //
  3340. // Use a different site coverage list depending on the role.
  3341. //
  3342. if ( NlDnsGcName( NameIndex) ) {
  3343. if ( GcSiteNames != NULL ) {
  3344. SiteNames = GcSiteNames->SiteNames;
  3345. SiteCount = GcSiteNames->EntryCount;
  3346. } else {
  3347. SiteNames = NULL;
  3348. SiteCount = 0;
  3349. }
  3350. //
  3351. // Use the domain/NDNC specific sites
  3352. //
  3353. } else {
  3354. // ???: Should KDCs have their own site coverage list?
  3355. if ( DcSiteNames != NULL ) {
  3356. SiteNames = DcSiteNames->SiteNames;
  3357. SiteCount = DcSiteNames->EntryCount;
  3358. } else {
  3359. SiteNames = NULL;
  3360. SiteCount = 0;
  3361. }
  3362. }
  3363. //
  3364. // Loop through the list of sites.
  3365. //
  3366. for ( SiteIndex=0; SiteIndex < SiteCount; SiteIndex ++) {
  3367. NetStatus = NlDnsAddName( DomainInfo,
  3368. (NL_DNS_NAME_TYPE)NameIndex,
  3369. SiteNames[SiteIndex].Buffer,
  3370. 0 );
  3371. if ( NetStatus != NERR_Success ) {
  3372. NlPrintDom((NL_INIT, DomainInfo,
  3373. "Couldn't NlDnsAddName (%ws %ws) %ld 0x%lx.\n",
  3374. NlDcDnsNameTypeDesc[NameIndex].Name,
  3375. SiteNames[SiteIndex].Buffer,
  3376. NetStatus, NetStatus ));
  3377. SaveNetStatus = NetStatus;
  3378. }
  3379. }
  3380. }
  3381. }
  3382. }
  3383. }
  3384. //
  3385. // Do the second pass through records for this domain
  3386. // and process those which need our attention.
  3387. //
  3388. // * Any names that are still marked should be deleted.
  3389. // * If domain is being deleted, indicate that the record
  3390. // doesn't belong to any domain anymore.
  3391. //
  3392. for ( ListEntry = NlGlobalDnsList.Flink ;
  3393. ListEntry != &NlGlobalDnsList ;
  3394. ListEntry = ListEntry->Flink ) {
  3395. NlDnsName = CONTAINING_RECORD( ListEntry, NL_DNS_NAME, Next );
  3396. //
  3397. // If the entry is marked for deletion,
  3398. // skip it
  3399. //
  3400. if ( NlDnsName->State == DeleteMe ) {
  3401. continue;
  3402. }
  3403. if ( NlDnsName->DomainInfo == DomainInfo ) {
  3404. //
  3405. // If entry is still marked, deregister it
  3406. //
  3407. if ( (NlDnsName->Flags & NL_DNS_REGISTER_DOMAIN) != 0 ) {
  3408. NlPrintDns(( NL_DNS, NlDnsName,
  3409. "NlDnsAddDomainRecords: marked for deregister" ));
  3410. NlDnsSetState( NlDnsName, DeregisterMe );
  3411. }
  3412. //
  3413. // If the domain is being deleted,
  3414. // ditch the dangling pointer to the domain info structure.
  3415. //
  3416. if ( DomainInfo->DomFlags & DOM_DELETED ) {
  3417. NlDnsName->DomainInfo = NULL;
  3418. }
  3419. }
  3420. }
  3421. LeaveCriticalSection( &NlGlobalDnsCritSect );
  3422. if ( SocketAddresses != NULL ) {
  3423. LocalFree( SocketAddresses );
  3424. }
  3425. if ( DcSiteNames != NULL ) {
  3426. NetApiBufferFree( DcSiteNames );
  3427. }
  3428. if ( GcSiteNames != NULL ) {
  3429. NetApiBufferFree( GcSiteNames );
  3430. }
  3431. return SaveNetStatus;
  3432. }
  3433. NET_API_STATUS
  3434. NlDnsInitialize(
  3435. VOID
  3436. )
  3437. /*++
  3438. Routine Description:
  3439. Initialize the dynamic DNS code.
  3440. Read the list of registered DNS names from the binary log file. Put each entry in the
  3441. list of registered DNS names. The names will be marked as DelayedDeregister.
  3442. Such names will be marked for deleting if they aren't re-registered
  3443. during the Netlogon startup process.
  3444. Arguments:
  3445. None
  3446. Return Value:
  3447. None.
  3448. --*/
  3449. {
  3450. NET_API_STATUS NetStatus;
  3451. PLIST_ENTRY ListEntry;
  3452. PNL_DNS_NAME NlDnsName;
  3453. ULONG DnsRecordBufferSize;
  3454. PNL_DNSLOG_HEADER DnsRecordBuffer = NULL;
  3455. LPBYTE DnsRecordBufferEnd;
  3456. PNL_DNSLOG_ENTRY DnsLogEntry;
  3457. ULONG CurrentSize;
  3458. LPBYTE Where;
  3459. //
  3460. // Initialization
  3461. //
  3462. EnterCriticalSection( &NlGlobalDnsCritSect );
  3463. NlGlobalDnsStartTime = GetTickCount();
  3464. NlGlobalDnsInitialCleanupDone = FALSE;
  3465. NlGlobalDnsListDirty = FALSE;
  3466. NlGlobalDnsScavengeNeeded = FALSE;
  3467. NlGlobalDnsScavengingInProgress = FALSE;
  3468. NlGlobalDnsScavengeFlags = 0;
  3469. NlDnsInitCount ++;
  3470. //
  3471. // That's it for a workstation.
  3472. //
  3473. if ( NlGlobalMemberWorkstation ) {
  3474. NetStatus = NO_ERROR;
  3475. goto Cleanup;
  3476. }
  3477. NlInitializeWorkItem( &NlGlobalDnsScavengeWorkItem, NlDnsScavengeWorker, NULL );
  3478. //
  3479. // Set the DNS scavenger timer
  3480. //
  3481. NlQuerySystemTime( &NlGlobalDnsScavengerTimer.StartTime );
  3482. NlGlobalDnsScavengerTimer.Period = min( ORIG_DNS_SCAVENGE_PERIOD, NlGlobalParameters.DnsRefreshIntervalPeriod );
  3483. //
  3484. // Read the file into a buffer.
  3485. //
  3486. NetStatus = NlReadBinaryLog(
  3487. NL_DNS_BINARY_LOG_FILE,
  3488. FALSE, // Don't delete the file
  3489. (LPBYTE *) &DnsRecordBuffer,
  3490. &DnsRecordBufferSize );
  3491. if ( NetStatus != NO_ERROR ) {
  3492. NlPrint(( NL_CRITICAL,
  3493. "NlDnsInitialize: error reading binary log: %ld.\n",
  3494. NL_DNS_BINARY_LOG_FILE,
  3495. DnsRecordBufferSize ));
  3496. goto Cleanup;
  3497. }
  3498. //
  3499. // Validate the returned data.
  3500. //
  3501. if ( DnsRecordBufferSize < sizeof(NL_DNSLOG_HEADER) ) {
  3502. NlPrint(( NL_CRITICAL,
  3503. "NlDnsInitialize: %ws: size too small: %ld.\n",
  3504. NL_DNS_BINARY_LOG_FILE,
  3505. DnsRecordBufferSize ));
  3506. NetStatus = NO_ERROR;
  3507. goto Cleanup;
  3508. }
  3509. if ( DnsRecordBuffer->Version != NL_DNSLOG_VERSION ) {
  3510. NlPrint(( NL_CRITICAL,
  3511. "NlDnsInitialize: %ws: Version wrong: %ld.\n",
  3512. NL_DNS_BINARY_LOG_FILE,
  3513. DnsRecordBuffer->Version ));
  3514. NetStatus = NO_ERROR;
  3515. goto Cleanup;
  3516. }
  3517. //
  3518. // Loop through each log entry.
  3519. //
  3520. DnsRecordBufferEnd = ((LPBYTE)DnsRecordBuffer) + DnsRecordBufferSize;
  3521. DnsLogEntry = (PNL_DNSLOG_ENTRY)ROUND_UP_POINTER( (DnsRecordBuffer + 1), ALIGN_WORST );
  3522. while ( (LPBYTE)(DnsLogEntry+1) <= DnsRecordBufferEnd ) {
  3523. LPSTR DnsRecordName;
  3524. LPSTR DnsHostName;
  3525. LPBYTE DnsLogEntryEnd;
  3526. DnsLogEntryEnd = ((LPBYTE)DnsLogEntry) + DnsLogEntry->EntrySize;
  3527. //
  3528. // Ensure this entry is entirely within the allocated buffer.
  3529. //
  3530. if ( DnsLogEntryEnd > DnsRecordBufferEnd ) {
  3531. NlPrint(( NL_CRITICAL,
  3532. "NlDnsInitialize: Entry too big: %lx %lx.\n",
  3533. ((LPBYTE)DnsLogEntry)-((LPBYTE)DnsRecordBuffer),
  3534. DnsLogEntry->EntrySize ));
  3535. break;
  3536. }
  3537. //
  3538. // Validate the entry
  3539. //
  3540. if ( !COUNT_IS_ALIGNED(DnsLogEntry->EntrySize, ALIGN_DWORD) ) {
  3541. NlPrint(( NL_CRITICAL,
  3542. "NlDnsInitialize: size not aligned %lx.\n",
  3543. DnsLogEntry->EntrySize ));
  3544. break;
  3545. }
  3546. if ( DnsLogEntry->NlDnsNameType < 0 ||
  3547. DnsLogEntry->NlDnsNameType >= NlDnsInvalid ) {
  3548. NlPrint(( NL_CRITICAL,
  3549. "NlDnsInitialize: Bogus DnsNameType: %lx.\n",
  3550. DnsLogEntry->NlDnsNameType ));
  3551. break;
  3552. }
  3553. if ( DnsLogEntry->Priority > 0xFFFF ) {
  3554. NlPrint(( NL_CRITICAL,
  3555. "NlDnsInitialize: Bogus priority: %lx.\n",
  3556. DnsLogEntry->Priority ));
  3557. break;
  3558. }
  3559. if ( DnsLogEntry->Weight > 0xFFFF ) {
  3560. NlPrint(( NL_CRITICAL,
  3561. "NlDnsInitialize: Bogus weight %lx.\n",
  3562. DnsLogEntry->Weight ));
  3563. break;
  3564. }
  3565. if ( DnsLogEntry->Port > 0xFFFF ) {
  3566. NlPrint(( NL_CRITICAL,
  3567. "NlDnsInitialize: Bogus port %lx.\n",
  3568. DnsLogEntry->Port ));
  3569. break;
  3570. }
  3571. //
  3572. // Grab the DnsRecordName from the entry.
  3573. //
  3574. Where = (LPBYTE) (DnsLogEntry+1);
  3575. if ( Where >= DnsLogEntryEnd ) {
  3576. NlPrint(( NL_CRITICAL,
  3577. "NlDnsInitialize: DnsRecordName missing: %lx\n",
  3578. ((LPBYTE)DnsLogEntry)-((LPBYTE)DnsRecordBuffer) ));
  3579. break;
  3580. }
  3581. DnsRecordName = Where;
  3582. while ( *Where != '\0' && Where < DnsLogEntryEnd ) {
  3583. Where ++;
  3584. }
  3585. if ( Where >= DnsLogEntryEnd ) {
  3586. NlPrint(( NL_CRITICAL,
  3587. "NlDnsInitialize: DnsRecordName has no trailing 0: %lx\n",
  3588. ((LPBYTE)DnsLogEntry)-((LPBYTE)DnsRecordBuffer) ));
  3589. break;
  3590. }
  3591. Where ++;
  3592. //
  3593. // Validate the record name is syntactically valid
  3594. //
  3595. NetStatus = DnsValidateName_UTF8( DnsRecordName, DnsNameDomain );
  3596. if ( NetStatus != ERROR_SUCCESS && NetStatus != DNS_ERROR_NON_RFC_NAME ) {
  3597. NlPrint(( NL_CRITICAL,
  3598. "NlDnsInitialize: Bad DNS record name encountered: %s\n",
  3599. DnsRecordName ));
  3600. break;
  3601. }
  3602. //
  3603. // Grab the DnsHostName from the entry.
  3604. //
  3605. if ( !NlDnsARecord( DnsLogEntry->NlDnsNameType ) ) {
  3606. if ( Where >= DnsLogEntryEnd ) {
  3607. NlPrint(( NL_CRITICAL,
  3608. "NlDnsInitialize: DnsHostName missing: %lx\n",
  3609. ((LPBYTE)DnsLogEntry)-((LPBYTE)DnsRecordBuffer) ));
  3610. break;
  3611. }
  3612. DnsHostName = Where;
  3613. while ( *Where != '\0' && Where < DnsLogEntryEnd ) {
  3614. Where ++;
  3615. }
  3616. if ( Where >= DnsLogEntryEnd ) {
  3617. NlPrint(( NL_CRITICAL,
  3618. "NlDnsInitialize: DnsHostName has no trailing 0: %lx\n",
  3619. ((LPBYTE)DnsLogEntry)-((LPBYTE)DnsRecordBuffer) ));
  3620. break;
  3621. }
  3622. Where ++;
  3623. } else {
  3624. DnsHostName = NULL;
  3625. }
  3626. //
  3627. // Validate the host name is syntactically valid
  3628. //
  3629. if ( DnsHostName != NULL ) {
  3630. NetStatus = DnsValidateName_UTF8( DnsHostName, DnsNameHostnameFull );
  3631. if ( NetStatus != ERROR_SUCCESS && NetStatus != DNS_ERROR_NON_RFC_NAME ) {
  3632. NlPrint(( NL_CRITICAL,
  3633. "NlDnsInitialize: Bad DNS host name encountered: %s\n",
  3634. DnsHostName ));
  3635. break;
  3636. }
  3637. }
  3638. //
  3639. // Allocate the entry and mark it as DelayedDeregister.
  3640. //
  3641. NlDnsName = NlDnsAllocateEntry(
  3642. DnsLogEntry->NlDnsNameType,
  3643. DnsRecordName,
  3644. DnsLogEntry->Priority,
  3645. DnsLogEntry->Weight,
  3646. DnsLogEntry->Port,
  3647. DnsHostName,
  3648. DnsLogEntry->IpAddress,
  3649. DelayedDeregister );
  3650. if ( NlDnsName == NULL ) {
  3651. NlPrint(( NL_CRITICAL,
  3652. "NlDnsInitialize: %s: Cannot allocate DnsName structure %lx\n",
  3653. ((LPBYTE)DnsLogEntry)-((LPBYTE)DnsRecordBuffer) ));
  3654. NetStatus = ERROR_NOT_ENOUGH_MEMORY;
  3655. goto Cleanup;
  3656. }
  3657. //
  3658. // This name has been registered once or it wouldn't be here.
  3659. //
  3660. NlDnsName->Flags |= NL_DNS_REGISTERED_ONCE;
  3661. NlPrintDns(( NL_DNS, NlDnsName,
  3662. "NlDnsInitialize: Previously registered name noticed" ));
  3663. //
  3664. // Move to the next entry.
  3665. //
  3666. DnsLogEntry = (PNL_DNSLOG_ENTRY)(((LPBYTE)DnsLogEntry) + DnsLogEntry->EntrySize);
  3667. }
  3668. NetStatus = NO_ERROR;
  3669. //
  3670. // Be tidy.
  3671. //
  3672. Cleanup:
  3673. if ( DnsRecordBuffer != NULL ) {
  3674. LocalFree( DnsRecordBuffer );
  3675. }
  3676. LeaveCriticalSection( &NlGlobalDnsCritSect );
  3677. return NetStatus;
  3678. }
  3679. VOID
  3680. NlDnsShutdown(
  3681. VOID
  3682. )
  3683. /*++
  3684. Routine Description:
  3685. Cleanup DNS names upon shutdown.
  3686. Arguments:
  3687. None.
  3688. Return Value:
  3689. None
  3690. --*/
  3691. {
  3692. NET_API_STATUS NetStatus;
  3693. PNL_DNS_NAME NlDnsName = NULL;
  3694. PLIST_ENTRY ListEntry;
  3695. EnterCriticalSection( &NlGlobalDnsCritSect );
  3696. //
  3697. // Deregister records on shutdown as needed.
  3698. // Do the work in this thread as we are shutting down.
  3699. //
  3700. NlGlobalDnsScavengeNeeded = TRUE;
  3701. //
  3702. // Clear all options,
  3703. // just deregister records that are already on the list as appropriate
  3704. //
  3705. NlGlobalDnsScavengeFlags = 0;
  3706. NlDnsScavengeWorker( NULL );
  3707. //
  3708. // Loop deleting all the entries.
  3709. //
  3710. while ( !IsListEmpty( &NlGlobalDnsList ) ) {
  3711. NlDnsName = CONTAINING_RECORD( NlGlobalDnsList.Flink, NL_DNS_NAME, Next );
  3712. RemoveEntryList( &NlDnsName->Next );
  3713. LocalFree( NlDnsName );
  3714. }
  3715. LeaveCriticalSection( &NlGlobalDnsCritSect );
  3716. return;
  3717. }
  3718. NET_API_STATUS
  3719. NlSetDnsForestName(
  3720. IN PUNICODE_STRING DnsForestName OPTIONAL,
  3721. OUT PBOOLEAN DnsForestNameChanged OPTIONAL
  3722. )
  3723. /*++
  3724. Routine Description:
  3725. Set the DNS tree name in the appropriate globals.
  3726. Arguments:
  3727. DnsForestName: of the tree this machine is in.
  3728. DnsForestNameChanged: Returns TRUE if the tree name changed.
  3729. Return Value:
  3730. NO_ERROR - String was saved successfully.
  3731. --*/
  3732. {
  3733. NET_API_STATUS NetStatus;
  3734. ULONG DnsForestNameLength;
  3735. LPWSTR LocalUnicodeDnsForestName = NULL;
  3736. ULONG LocalUnicodeDnsForestNameLen = 0;
  3737. LPSTR LocalUtf8DnsForestName = NULL;
  3738. BOOLEAN LocalDnsForestNameChanged = FALSE;
  3739. //
  3740. // If a tree name is specified,
  3741. // allocate buffers for them.
  3742. //
  3743. EnterCriticalSection( &NlGlobalDnsForestNameCritSect );
  3744. if ( DnsForestName != NULL && DnsForestName->Length != 0 ) {
  3745. //
  3746. // If the tree name hasn't changed,
  3747. // avoid setting it.
  3748. //
  3749. if ( NlGlobalUnicodeDnsForestNameString.Length != 0 ) {
  3750. if ( NlEqualDnsNameU( &NlGlobalUnicodeDnsForestNameString, DnsForestName ) ) {
  3751. NetStatus = NO_ERROR;
  3752. goto Cleanup;
  3753. }
  3754. }
  3755. NlPrint(( NL_DNS,
  3756. "Set DnsForestName to: %wZ\n",
  3757. DnsForestName ));
  3758. //
  3759. // Save the . terminated Unicode version of the string.
  3760. //
  3761. LocalUnicodeDnsForestNameLen = DnsForestName->Length / sizeof(WCHAR);
  3762. if ( LocalUnicodeDnsForestNameLen > NL_MAX_DNS_LENGTH ) {
  3763. NetStatus = ERROR_INVALID_NAME;
  3764. goto Cleanup;
  3765. }
  3766. LocalUnicodeDnsForestName = NetpMemoryAllocate( (LocalUnicodeDnsForestNameLen+2) * sizeof(WCHAR));
  3767. if ( LocalUnicodeDnsForestName == NULL) {
  3768. NetStatus = ERROR_NOT_ENOUGH_MEMORY;
  3769. goto Cleanup;
  3770. }
  3771. RtlCopyMemory( LocalUnicodeDnsForestName,
  3772. DnsForestName->Buffer,
  3773. LocalUnicodeDnsForestNameLen*sizeof(WCHAR) );
  3774. if ( LocalUnicodeDnsForestName[LocalUnicodeDnsForestNameLen-1] != L'.' ) {
  3775. LocalUnicodeDnsForestName[LocalUnicodeDnsForestNameLen++] = L'.';
  3776. }
  3777. LocalUnicodeDnsForestName[LocalUnicodeDnsForestNameLen] = L'\0';
  3778. //
  3779. // Convert it to zero terminated UTF-8
  3780. //
  3781. LocalUtf8DnsForestName = NetpAllocUtf8StrFromWStr( LocalUnicodeDnsForestName );
  3782. if (LocalUtf8DnsForestName == NULL) {
  3783. NetpMemoryFree( LocalUnicodeDnsForestName );
  3784. NetStatus = ERROR_NOT_ENOUGH_MEMORY;
  3785. goto Cleanup;
  3786. }
  3787. if ( strlen(LocalUtf8DnsForestName) > NL_MAX_DNS_LENGTH ) {
  3788. NetpMemoryFree( LocalUnicodeDnsForestName );
  3789. NetpMemoryFree( LocalUtf8DnsForestName );
  3790. NetStatus = ERROR_INVALID_NAME;
  3791. goto Cleanup;
  3792. }
  3793. //
  3794. // Indicate the the name has changed.
  3795. //
  3796. LocalDnsForestNameChanged = TRUE;
  3797. }
  3798. //
  3799. // Free any existing global tree name.
  3800. //
  3801. if ( NlGlobalUnicodeDnsForestName != NULL ) {
  3802. NetApiBufferFree( NlGlobalUnicodeDnsForestName );
  3803. }
  3804. if ( NlGlobalUtf8DnsForestName != NULL ) {
  3805. NetpMemoryFree( NlGlobalUtf8DnsForestName );
  3806. }
  3807. //
  3808. // Save the new names in the globals.
  3809. //
  3810. NlGlobalUnicodeDnsForestName = LocalUnicodeDnsForestName;
  3811. NlGlobalUnicodeDnsForestNameLen = LocalUnicodeDnsForestNameLen;
  3812. NlGlobalUnicodeDnsForestNameString.Buffer = LocalUnicodeDnsForestName;
  3813. NlGlobalUnicodeDnsForestNameString.Length = (USHORT)(LocalUnicodeDnsForestNameLen*sizeof(WCHAR));
  3814. NlGlobalUnicodeDnsForestNameString.MaximumLength = (USHORT)((LocalUnicodeDnsForestNameLen+1)*sizeof(WCHAR));
  3815. NlGlobalUtf8DnsForestName = LocalUtf8DnsForestName;
  3816. NetStatus = NO_ERROR;
  3817. Cleanup:
  3818. LeaveCriticalSection( &NlGlobalDnsForestNameCritSect );
  3819. //
  3820. // If the name changed,
  3821. // recompute the DOM_FOREST_ROOT bit on all domains.
  3822. //
  3823. if ( LocalDnsForestNameChanged ) {
  3824. (VOID) NlEnumerateDomains( FALSE, NlSetDomainForestRoot, NULL );
  3825. }
  3826. if ( ARGUMENT_PRESENT( DnsForestNameChanged) ) {
  3827. *DnsForestNameChanged = LocalDnsForestNameChanged;
  3828. }
  3829. return NetStatus;
  3830. }
  3831. VOID
  3832. NlCaptureDnsForestName(
  3833. OUT WCHAR DnsForestName[NL_MAX_DNS_LENGTH+1]
  3834. )
  3835. /*++
  3836. Routine Description:
  3837. Captures a copy of the DnsForestName for this machine.
  3838. Arguments:
  3839. DnsForestName - Returns the DNS name of the tree this machine is in.
  3840. If there is none, an empty string is returned.
  3841. Return Value:
  3842. None.
  3843. --*/
  3844. {
  3845. EnterCriticalSection(&NlGlobalDnsForestNameCritSect);
  3846. if ( NlGlobalUnicodeDnsForestName == NULL ) {
  3847. *DnsForestName = L'\0';
  3848. } else {
  3849. wcscpy( DnsForestName, NlGlobalUnicodeDnsForestName );
  3850. }
  3851. LeaveCriticalSection(&NlGlobalDnsForestNameCritSect);
  3852. return;
  3853. }