Source code of Windows XP (NT5)
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.

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