Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2422 lines
55 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1995.
  5. //
  6. // File: domcache.c
  7. //
  8. // Contents: Restructuring the Domain Cache to get away from direct LSA
  9. // calls whenever possible.
  10. //
  11. // Classes:
  12. //
  13. // Functions:
  14. //
  15. // History: 3-29-96 RichardW Created
  16. //
  17. //----------------------------------------------------------------------------
  18. #include <msgina.h>
  19. #include <stdio.h>
  20. #define LockDomainCache( x ) RtlEnterCriticalSection( &(x)->CriticalSection )
  21. #define UnlockDomainCache( x ) RtlLeaveCriticalSection( &(x)->CriticalSection )
  22. #define TWO_MINUTES ((LONGLONG) 0x47868C00)
  23. #define TWO_WEEKS ((LONGLONG) 0xB0051C88000I64)
  24. WCHAR szCache[] = TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\DomainCache");
  25. WCHAR szCacheValue[] = TEXT("DCache");
  26. WCHAR szCacheUpdate[] = TEXT("DCacheUpdate");
  27. WCHAR szCacheInterval[] = TEXT("DCacheMinInterval");
  28. WCHAR szCachePrimary[] = TEXT("CachePrimaryDomain");
  29. LONGLONG CacheUpdateMin;
  30. LONGLONG CacheUpdateMax;
  31. BOOL CacheAppendDomainInfo = FALSE ;
  32. BOOL CacheShowDnsNames = FALSE ;
  33. #define DOMAIN_MOD_ALWAYS 0x00000001
  34. typedef struct _DOMAIN_MODIFIER {
  35. ULONG StringId ;
  36. ULONG Flags ;
  37. UNICODE_STRING String ;
  38. } DOMAIN_MODIFIER ;
  39. DOMAIN_MODIFIER CacheDomainModifiers[ DomainTypeMax ] = {
  40. { 0 }, // Invalid
  41. { IDS_DTYPE_UPNDOMAIN, 0 }, // UPN Domain
  42. { IDS_DTYPE_THISCOMPUTER, DOMAIN_MOD_ALWAYS }, // This computer
  43. { IDS_DTYPE_NT4DOMAIN, 0 }, // NT4 domains
  44. { IDS_DTYPE_NT5DOMAIN, 0 }, // NT5 domains
  45. { IDS_DTYPE_MITDOMAIN, DOMAIN_MOD_ALWAYS }, // MIT domains
  46. { IDS_DTYPE_MITXDOMAIN, DOMAIN_MOD_ALWAYS }, // Untrusted MIT domains
  47. { IDS_DTYPE_NETPROVIDER, DOMAIN_MOD_ALWAYS } // Network provider
  48. };
  49. DWORD
  50. DCacheUpdateThread(
  51. PDOMAIN_CACHE Cache
  52. );
  53. VOID
  54. DCacheDereferenceEntry(
  55. PDOMAIN_CACHE_ENTRY Entry
  56. )
  57. {
  58. if ( InterlockedDecrement( &Entry->RefCount ) == 0 )
  59. {
  60. LocalFree( Entry );
  61. }
  62. }
  63. PDOMAIN_CACHE_ARRAY
  64. DCacheCreateArray(
  65. ULONG Size,
  66. BOOL Sorted
  67. )
  68. {
  69. PDOMAIN_CACHE_ARRAY Array ;
  70. Array = LocalAlloc( LMEM_FIXED, sizeof( DOMAIN_CACHE_ARRAY ) );
  71. if ( Array )
  72. {
  73. Array->List = LocalAlloc( LMEM_FIXED, sizeof( PDOMAIN_CACHE_ENTRY ) * Size );
  74. if ( Array->List )
  75. {
  76. Array->Count = 0 ;
  77. Array->MaxCount = Size ;
  78. Array->Sorted = Sorted ;
  79. return Array ;
  80. }
  81. LocalFree( Array );
  82. }
  83. return NULL ;
  84. }
  85. BOOL
  86. DCachepExpandArray(
  87. PDOMAIN_CACHE_ARRAY Array,
  88. ULONG Size
  89. )
  90. {
  91. PDOMAIN_CACHE_ENTRY * NewArray ;
  92. NewArray = LocalReAlloc( Array->List,
  93. (Array->Count + Size) * sizeof( PDOMAIN_CACHE_ENTRY ),
  94. 0 );
  95. if ( NewArray )
  96. {
  97. Array->List = NewArray ;
  98. Array->MaxCount = Array->Count + Size ;
  99. return TRUE ;
  100. }
  101. return FALSE ;
  102. }
  103. BOOL
  104. DCacheInsertArray(
  105. PDOMAIN_CACHE_ARRAY Array,
  106. PDOMAIN_CACHE_ENTRY Entry
  107. )
  108. {
  109. ULONG i ;
  110. LONG Compare ;
  111. PDOMAIN_CACHE_ENTRY Scan ;
  112. if ( Array->Count == Array->MaxCount )
  113. {
  114. if ( !DCachepExpandArray( Array, 10 ) )
  115. {
  116. return FALSE ;
  117. }
  118. }
  119. DCacheReferenceEntry( Entry );
  120. if ( ( Array->Sorted == FALSE ) ||
  121. ( Array->Count == 0 ) )
  122. {
  123. Array->List[ Array->Count ] = Entry ;
  124. Array->Count++ ;
  125. return TRUE ;
  126. }
  127. else
  128. {
  129. Scan = Array->List[ Array->Count - 1 ];
  130. Compare = RtlCompareUnicodeString( &Entry->FlatName,
  131. &Scan->FlatName,
  132. TRUE );
  133. //
  134. // Efficient check for sorted input:
  135. //
  136. if ( Compare > 0 )
  137. {
  138. Array->List[ Array->Count ] = Entry ;
  139. Array->Count ++ ;
  140. return TRUE ;
  141. }
  142. //
  143. // this is not a terribly efficient sort.
  144. // However, we're expecting
  145. // on the order of <100 objects in the array, so it
  146. // shouldn't be too bad.
  147. //
  148. for ( i = 0 ; i < Array->Count ; i++ )
  149. {
  150. Scan = Array->List[ i ];
  151. Compare = RtlCompareUnicodeString( & Entry->FlatName,
  152. & Scan->FlatName,
  153. TRUE );
  154. if ( Compare == 0 )
  155. {
  156. DCacheDereferenceEntry( Entry );
  157. return FALSE ;
  158. }
  159. if ( Compare < 0 )
  160. {
  161. break;
  162. }
  163. }
  164. RtlMoveMemory(
  165. &Array->List[ i + 1 ],
  166. &Array->List[ i ],
  167. (Array->Count - i) * sizeof( PVOID ) );
  168. Array->List[ i ] = Entry ;
  169. Array->Count++ ;
  170. return TRUE ;
  171. }
  172. }
  173. PDOMAIN_CACHE_ENTRY
  174. DCacheSearchArray(
  175. PDOMAIN_CACHE_ARRAY Array,
  176. PUNICODE_STRING DomainName
  177. )
  178. {
  179. ULONG i ;
  180. PDOMAIN_CACHE_ENTRY Scan = NULL ;
  181. LONG Compare ;
  182. for (i = 0 ; i < Array->Count ; i++ )
  183. {
  184. Scan = Array->List[ i ];
  185. if ( Scan->FlatName.Length == 0 )
  186. {
  187. Scan = NULL ;
  188. continue;
  189. }
  190. Compare = RtlCompareUnicodeString( &Scan->FlatName,
  191. DomainName,
  192. TRUE );
  193. if ( Compare == 0 )
  194. {
  195. break;
  196. }
  197. if ( ( Compare > 0 ) &&
  198. ( Array->Sorted ) )
  199. {
  200. Scan = NULL ;
  201. break;
  202. }
  203. }
  204. return Scan ;
  205. }
  206. PDOMAIN_CACHE_ENTRY
  207. DCacheSearchArrayByDns(
  208. PDOMAIN_CACHE_ARRAY Array,
  209. PUNICODE_STRING DnsDomainName
  210. )
  211. {
  212. ULONG i ;
  213. PDOMAIN_CACHE_ENTRY Scan = NULL ;
  214. for (i = 0 ; i < Array->Count ; i++ )
  215. {
  216. Scan = Array->List[ i ];
  217. if ( Scan->DnsName.Length )
  218. {
  219. if ( RtlEqualUnicodeString( &Scan->DnsName,
  220. DnsDomainName,
  221. TRUE ) )
  222. {
  223. break;
  224. }
  225. }
  226. Scan = NULL ;
  227. }
  228. return Scan ;
  229. }
  230. PDOMAIN_CACHE_ENTRY
  231. DCacheFindDefaultEntry(
  232. PDOMAIN_CACHE_ARRAY Array
  233. )
  234. {
  235. ULONG i ;
  236. PDOMAIN_CACHE_ENTRY Scan = NULL ;
  237. for (i = 0 ; i < Array->Count ; i++ )
  238. {
  239. Scan = Array->List[ i ];
  240. if ( Scan->Flags & DCE_DEFAULT_ENTRY )
  241. {
  242. break;
  243. }
  244. Scan = NULL ;
  245. }
  246. return Scan ;
  247. }
  248. VOID
  249. DCacheFreeArray(
  250. PDOMAIN_CACHE_ARRAY Array
  251. )
  252. {
  253. ULONG i ;
  254. for ( i = 0 ; i < Array->Count ; i++ )
  255. {
  256. DCacheDereferenceEntry( Array->List[ i ] );
  257. }
  258. LocalFree( Array->List );
  259. LocalFree( Array );
  260. }
  261. PDOMAIN_CACHE_ARRAY
  262. DCacheCopyArray(
  263. PDOMAIN_CACHE_ARRAY Source
  264. )
  265. {
  266. PDOMAIN_CACHE_ARRAY Array ;
  267. ULONG i ;
  268. Array = DCacheCreateArray( Source->MaxCount,
  269. Source->Sorted );
  270. if ( Array )
  271. {
  272. for (i = 0 ; i < Source->Count ; i++ )
  273. {
  274. Array->List[ i ] = Source->List[ i ];
  275. DCacheReferenceEntry( Array->List[ i ] );
  276. }
  277. Array->Count = Source->Count ;
  278. }
  279. return Array ;
  280. }
  281. PDOMAIN_CACHE_ENTRY
  282. DCacheCreateEntry(
  283. DOMAIN_ENTRY_TYPE Type,
  284. PUNICODE_STRING FlatName OPTIONAL,
  285. PUNICODE_STRING DnsName OPTIONAL,
  286. PUNICODE_STRING DisplayName OPTIONAL
  287. )
  288. {
  289. ULONG Size ;
  290. PDOMAIN_CACHE_ENTRY Entry ;
  291. PUNICODE_STRING DisplayBase = NULL ;
  292. PUNICODE_STRING Modifier = NULL ;
  293. PUCHAR Current ;
  294. //
  295. // Validation rules:
  296. //
  297. // Display Name is optional if either of FlatName or
  298. // DNS name is present. If both are present, FlatName
  299. // is defaulted over Dns name
  300. //
  301. Size = sizeof( DOMAIN_CACHE_ENTRY );
  302. if ( FlatName )
  303. {
  304. Size += FlatName->Length + sizeof( WCHAR );
  305. }
  306. if ( DnsName )
  307. {
  308. Size += DnsName->Length + sizeof( WCHAR );
  309. }
  310. if ( DisplayName )
  311. {
  312. Size += DisplayName->Length + sizeof( WCHAR );
  313. DisplayBase = DisplayName ;
  314. }
  315. else
  316. {
  317. if ( CacheShowDnsNames ||
  318. ( ( Type == DomainMitRealm ) ||
  319. ( Type == DomainMitUntrusted ) ) )
  320. {
  321. if ( DnsName )
  322. {
  323. DisplayBase = DnsName ;
  324. }
  325. else if ( FlatName )
  326. {
  327. DisplayBase = FlatName ;
  328. }
  329. else
  330. {
  331. return NULL ;
  332. }
  333. }
  334. else
  335. {
  336. if ( FlatName )
  337. {
  338. DisplayBase = FlatName ;
  339. }
  340. else if ( DnsName )
  341. {
  342. DisplayBase = DnsName ;
  343. }
  344. else
  345. {
  346. return NULL ;
  347. }
  348. }
  349. Size += DisplayBase->Length + sizeof( WCHAR );
  350. if ( ( CacheAppendDomainInfo ) ||
  351. ( CacheDomainModifiers[ Type ].Flags & DOMAIN_MOD_ALWAYS ) )
  352. {
  353. Modifier = &CacheDomainModifiers[ Type ].String ;
  354. if ( Modifier->Length )
  355. {
  356. Size += CacheDomainModifiers[ Type ].String.Length;
  357. }
  358. else
  359. {
  360. Modifier = NULL ;
  361. }
  362. }
  363. }
  364. Entry = LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, Size );
  365. if ( !Entry )
  366. {
  367. return NULL ;
  368. }
  369. Entry->RefCount = 1 ;
  370. Entry->Flags = 0 ;
  371. Entry->Type = Type ;
  372. Current = (PUCHAR) ( Entry + 1 );
  373. //
  374. // Copy and pack the strings:
  375. //
  376. if ( FlatName )
  377. {
  378. Entry->FlatName.Buffer = (PWSTR) Current ;
  379. Entry->FlatName.Length = FlatName->Length ;
  380. Entry->FlatName.MaximumLength = FlatName->Length + sizeof( WCHAR );
  381. RtlCopyMemory(
  382. Current,
  383. FlatName->Buffer,
  384. FlatName->Length );
  385. Current += FlatName->Length ;
  386. *Current++ = '\0';
  387. *Current++ = '\0';
  388. }
  389. if ( DnsName )
  390. {
  391. Entry->DnsName.Buffer = (PWSTR) Current ;
  392. Entry->DnsName.Length = DnsName->Length ;
  393. Entry->DnsName.MaximumLength = DnsName->Length + sizeof( WCHAR );
  394. RtlCopyMemory(
  395. Current,
  396. DnsName->Buffer,
  397. DnsName->Length );
  398. Current += DnsName->Length ;
  399. *Current++ = '\0';
  400. *Current++ = '\0';
  401. }
  402. ASSERT( DisplayBase );
  403. Entry->DisplayName.Buffer = (PWSTR) Current ;
  404. Entry->DisplayName.Length = DisplayBase->Length ;
  405. if ( Modifier )
  406. {
  407. Entry->DisplayName.Length = Entry->DisplayName.Length + Modifier->Length ;
  408. }
  409. Entry->DisplayName.MaximumLength = Entry->DisplayName.Length + sizeof( WCHAR );
  410. RtlCopyMemory(
  411. Current,
  412. DisplayBase->Buffer,
  413. DisplayBase->Length );
  414. Current += DisplayBase->Length ;
  415. if ( Modifier )
  416. {
  417. RtlCopyMemory(
  418. Current,
  419. Modifier->Buffer,
  420. Modifier->Length );
  421. Current += Modifier->Length ;
  422. }
  423. *Current++ = '\0';
  424. *Current++ = '\0';
  425. return Entry ;
  426. }
  427. LONG
  428. DCacheGetTrustedDomains(
  429. PDOMAIN_CACHE_ARRAY * pArray
  430. )
  431. {
  432. LONG NetStatus ;
  433. PDOMAIN_CACHE_ARRAY Array ;
  434. PDOMAIN_CACHE_ENTRY Entry ;
  435. PDS_DOMAIN_TRUSTS Trusts ;
  436. ULONG TrustCount ;
  437. ULONG i ;
  438. UNICODE_STRING Flat ;
  439. UNICODE_STRING Dns ;
  440. DOMAIN_ENTRY_TYPE Type ;
  441. *pArray = NULL ;
  442. NetStatus = DsEnumerateDomainTrusts(
  443. NULL,
  444. DS_DOMAIN_IN_FOREST |
  445. DS_DOMAIN_DIRECT_OUTBOUND,
  446. &Trusts,
  447. &TrustCount );
  448. if ( NetStatus != NERR_Success )
  449. {
  450. return NetStatus ;
  451. }
  452. Array = DCacheCreateArray( TrustCount + 5,
  453. TRUE );
  454. if ( !Array )
  455. {
  456. NetApiBufferFree( Trusts );
  457. return ERROR_NOT_ENOUGH_MEMORY ;
  458. }
  459. for ( i = 0 ; i < TrustCount ; i++ )
  460. {
  461. if ( Trusts[ i ].NetbiosDomainName )
  462. {
  463. RtlInitUnicodeString( &Flat, Trusts[ i ].NetbiosDomainName );
  464. }
  465. else
  466. {
  467. ZeroMemory( &Flat, sizeof( Flat ) );
  468. }
  469. if ( Trusts[ i ].DnsDomainName )
  470. {
  471. RtlInitUnicodeString( &Dns, Trusts[ i ].DnsDomainName );
  472. }
  473. else
  474. {
  475. ZeroMemory( &Dns, sizeof( Dns ) );
  476. }
  477. switch ( Trusts[ i ].TrustType )
  478. {
  479. case TRUST_TYPE_DOWNLEVEL :
  480. Type = DomainNt4 ;
  481. break;
  482. case TRUST_TYPE_UPLEVEL:
  483. Type = DomainNt5 ;
  484. break;
  485. case TRUST_TYPE_MIT:
  486. Type = DomainMitRealm ;
  487. break;
  488. default:
  489. continue;
  490. }
  491. DebugLog(( DEB_TRACE_CACHE, "Processing domain (%d) %ws\n",
  492. Type,
  493. Trusts[ i ].NetbiosDomainName ));
  494. Entry = DCacheCreateEntry(
  495. Type,
  496. ( Flat.Buffer ? &Flat : NULL ),
  497. ( Dns.Buffer ? &Dns : NULL ),
  498. NULL );
  499. if ( Entry )
  500. {
  501. DCacheInsertArray(
  502. Array,
  503. Entry );
  504. DCacheDereferenceEntry( Entry );
  505. }
  506. }
  507. NetApiBufferFree( Trusts );
  508. *pArray = Array ;
  509. return 0 ;
  510. }
  511. BOOL
  512. DCacheAddMitRealms(
  513. PDOMAIN_CACHE_ARRAY Array
  514. )
  515. {
  516. HKEY MitKey ;
  517. DWORD Index ;
  518. PWSTR Realms;
  519. DWORD RealmSize;
  520. int err ;
  521. DWORD NumRealms;
  522. DWORD MaxRealmLength ;
  523. FILETIME KeyTime ;
  524. PDOMAIN_CACHE_ENTRY Entry ;
  525. PDOMAIN_CACHE_ENTRY TrustedDomain ;
  526. UNICODE_STRING DnsName ;
  527. err = RegOpenKeyEx(
  528. HKEY_LOCAL_MACHINE,
  529. TEXT("System\\CurrentControlSet\\Control\\Lsa\\Kerberos\\Domains"),
  530. 0,
  531. KEY_READ,
  532. &MitKey );
  533. if ( err == 0 )
  534. {
  535. err = RegQueryInfoKey( MitKey,
  536. NULL,
  537. NULL,
  538. NULL,
  539. &NumRealms,
  540. &MaxRealmLength,
  541. NULL,
  542. NULL,
  543. NULL,
  544. NULL,
  545. NULL,
  546. NULL );
  547. MaxRealmLength++ ;
  548. Realms = LocalAlloc( LMEM_FIXED, MaxRealmLength * sizeof( WCHAR ));
  549. if ( Realms)
  550. {
  551. for ( Index = 0 ; Index < NumRealms ; Index++ )
  552. {
  553. RealmSize = MaxRealmLength ;
  554. err = RegEnumKeyEx( MitKey,
  555. Index,
  556. Realms,
  557. &RealmSize,
  558. NULL,
  559. NULL,
  560. NULL,
  561. &KeyTime );
  562. if ( err == 0 )
  563. {
  564. DebugLog(( DEB_TRACE_CACHE, "Found realm %ws\n", Realms ));
  565. RtlInitUnicodeString( &DnsName, Realms );
  566. Entry = DCacheCreateEntry(
  567. DomainMitUntrusted,
  568. &DnsName,
  569. &DnsName,
  570. NULL );
  571. if ( Entry )
  572. {
  573. Entry->Flags |= DCE_REACHABLE_MIT ;
  574. if ( !DCacheInsertArray( Array, Entry ) )
  575. {
  576. //
  577. // If the insert failed, then there's already an entry
  578. // in the list for this domain. Locate it, and tag it
  579. // so that it will be displayed
  580. //
  581. TrustedDomain = DCacheSearchArray( Array, &DnsName );
  582. if ( TrustedDomain )
  583. {
  584. TrustedDomain->Flags |= DCE_REACHABLE_MIT ;
  585. }
  586. }
  587. DCacheDereferenceEntry( Entry );
  588. }
  589. }
  590. }
  591. LocalFree( Realms );
  592. }
  593. RegCloseKey( MitKey );
  594. }
  595. return TRUE ;
  596. }
  597. BOOL
  598. DCacheAddNetworkProviders(
  599. PDOMAIN_CACHE_ARRAY Array
  600. )
  601. {
  602. WCHAR szProviderName[128];
  603. WCHAR szKeyPath[MAX_PATH];
  604. PWSTR pszProviders;
  605. PWSTR pszScan;
  606. PWSTR pszStart;
  607. WCHAR Save;
  608. HKEY hKey;
  609. DWORD dwType;
  610. DWORD dwLen;
  611. DWORD Class;
  612. int err;
  613. PDOMAIN_CACHE_ENTRY Entry ;
  614. UNICODE_STRING String ;
  615. err = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  616. TEXT("System\\CurrentControlSet\\Control\\NetworkProvider\\Order"),
  617. 0,
  618. KEY_READ,
  619. &hKey );
  620. if ( err )
  621. {
  622. return FALSE ;
  623. }
  624. err = RegQueryValueEx( hKey,
  625. TEXT("ProviderOrder"),
  626. NULL,
  627. &dwType,
  628. NULL,
  629. &dwLen );
  630. if ( (err) || (dwType != REG_SZ) )
  631. {
  632. RegCloseKey( hKey );
  633. return FALSE ;
  634. }
  635. pszProviders = LocalAlloc( LMEM_FIXED, dwLen );
  636. if ( !pszProviders )
  637. {
  638. RegCloseKey( hKey );
  639. return FALSE ;
  640. }
  641. err = RegQueryValueEx( hKey,
  642. TEXT("ProviderOrder"),
  643. NULL,
  644. &dwType,
  645. (PUCHAR) pszProviders,
  646. &dwLen );
  647. RegCloseKey( hKey );
  648. if ( err )
  649. {
  650. LocalFree( pszProviders );
  651. return FALSE ;
  652. }
  653. //
  654. // Initialize things.
  655. //
  656. pszStart = pszProviders;
  657. szProviderName[0] = TEXT('<');
  658. szProviderName[1] = TEXT(' ');
  659. while ( *pszStart )
  660. {
  661. pszScan = pszStart;
  662. while ( (*pszScan) && (*pszScan != TEXT(',') ) )
  663. {
  664. pszScan++;
  665. }
  666. Save = *pszScan;
  667. *pszScan = TEXT('\0');
  668. wsprintf( szKeyPath,
  669. TEXT("System\\CurrentControlSet\\Services\\%s\\networkprovider"),
  670. pszStart );
  671. err = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  672. szKeyPath,
  673. 0,
  674. KEY_READ,
  675. &hKey );
  676. if ( err == 0 )
  677. {
  678. dwLen = sizeof(DWORD) ;
  679. err = RegQueryValueEx( hKey,
  680. TEXT("Class"),
  681. NULL,
  682. &dwType,
  683. (PUCHAR) &Class,
  684. &dwLen );
  685. if ( (err == 0) && (dwType == REG_DWORD) )
  686. {
  687. if ( Class & WN_CREDENTIAL_CLASS )
  688. {
  689. dwLen = 126 * sizeof(WCHAR);
  690. err = RegQueryValueEx( hKey,
  691. TEXT("Name"),
  692. NULL,
  693. &dwType,
  694. (PUCHAR) &szProviderName[2],
  695. &dwLen );
  696. wcscpy( &szProviderName[ (dwLen / sizeof(WCHAR) ) + 2 ],
  697. TEXT(" >") );
  698. RtlInitUnicodeString( &String, szProviderName );
  699. Entry = DCacheCreateEntry(
  700. DomainNetworkProvider,
  701. &String,
  702. NULL,
  703. NULL );
  704. if ( Entry )
  705. {
  706. DCacheInsertArray( Array, Entry );
  707. DCacheDereferenceEntry( Entry );
  708. }
  709. }
  710. }
  711. RegCloseKey( hKey );
  712. }
  713. *pszScan = Save;
  714. if ( *pszScan )
  715. {
  716. pszStart = pszScan + 1;
  717. }
  718. else
  719. {
  720. pszStart = NULL;
  721. break;
  722. }
  723. }
  724. LocalFree( pszProviders );
  725. return TRUE ;
  726. }
  727. BOOL
  728. DCacheGetDomainsFromCache(
  729. PDOMAIN_CACHE_ARRAY *pArray,
  730. PLARGE_INTEGER RegistryTime
  731. )
  732. {
  733. HKEY Key ;
  734. int err ;
  735. DWORD NumDomains ;
  736. DWORD i ;
  737. WCHAR FlatName[ DNLEN + 2 ];
  738. WCHAR DnsDomain[ MAX_PATH ];
  739. DWORD dwType ;
  740. DWORD FlatNameSize ;
  741. DWORD DnsDomainSize ;
  742. UNICODE_STRING Flat ;
  743. UNICODE_STRING Dns ;
  744. PDOMAIN_CACHE_ENTRY Entry ;
  745. PDOMAIN_CACHE_ARRAY Array = NULL;
  746. DWORD dwSize ;
  747. PWSTR DomainBuffer ;
  748. PWSTR DomainBufferEnd ;
  749. PWSTR Scan ;
  750. ULONG Disp ;
  751. BOOL ReturnFalseAnyway = FALSE ;
  752. if ( SafeBootMode == SAFEBOOT_MINIMAL )
  753. {
  754. RegistryTime->QuadPart = 0 ;
  755. return FALSE ;
  756. }
  757. //
  758. // The following appears to be a transfer of
  759. // HKLM\Microsoft\Windows NT\CurrentVersion\Winlogon\DCache
  760. // in the form of a multistring to the current DomainCache format
  761. // Legacy migration?
  762. // In any case, let's not worry if any of this fails.
  763. //
  764. dwSize = 0 ;
  765. err = RegQueryValueEx(
  766. WinlogonKey,
  767. szCacheValue,
  768. NULL,
  769. &dwType,
  770. NULL,
  771. &dwSize );
  772. if ( ( err == ERROR_MORE_DATA ) ||
  773. ( err == ERROR_BUFFER_OVERFLOW ) ||
  774. ( err == 0 ) )
  775. {
  776. //
  777. //
  778. DomainBuffer = LocalAlloc( LMEM_FIXED, dwSize );
  779. if ( DomainBuffer )
  780. {
  781. err = RegQueryValueEx(
  782. WinlogonKey,
  783. szCacheValue,
  784. NULL,
  785. &dwType,
  786. (PUCHAR) DomainBuffer,
  787. &dwSize );
  788. if ( err == 0 )
  789. {
  790. DomainBufferEnd = (PWSTR)((PUCHAR) DomainBuffer + dwSize);
  791. Scan = DomainBuffer ;
  792. err = RegCreateKeyEx(
  793. HKEY_LOCAL_MACHINE,
  794. szCache,
  795. 0,
  796. NULL,
  797. REG_OPTION_NON_VOLATILE,
  798. KEY_ALL_ACCESS,
  799. NULL,
  800. &Key,
  801. &Disp );
  802. if ( err == 0 )
  803. {
  804. while ( Scan != DomainBufferEnd )
  805. {
  806. err = RegSetValueEx(
  807. Key,
  808. Scan,
  809. 0,
  810. REG_SZ,
  811. (PUCHAR) TEXT(""),
  812. sizeof( WCHAR ) );
  813. Scan += wcslen(Scan) ;
  814. while ( (*Scan == L'\0' ) &&
  815. (Scan != DomainBufferEnd ) )
  816. {
  817. Scan++ ;
  818. }
  819. }
  820. RegCloseKey( Key );
  821. }
  822. }
  823. LocalFree( DomainBuffer );
  824. }
  825. RegDeleteValue( WinlogonKey, szCacheValue );
  826. ReturnFalseAnyway = TRUE ;
  827. }
  828. // End of Legacy migration
  829. // Since the DomainCache is "managed" by all sessions w/o protection,
  830. // we need to implement a little bit of retry logic here
  831. //
  832. Key = NULL;
  833. dwSize = 10; // Number of retries
  834. do
  835. {
  836. if (dwSize < 10)
  837. {
  838. Sleep(100); // Let the other session finish its work
  839. }
  840. err = RegOpenKeyEx(
  841. HKEY_LOCAL_MACHINE,
  842. szCache,
  843. 0,
  844. KEY_READ,
  845. &Key );
  846. if ( err == ERROR_SUCCESS)
  847. {
  848. // Query the number of values in the DomainCache
  849. err = RegQueryInfoKey( Key,
  850. NULL,
  851. NULL,
  852. NULL,
  853. NULL,
  854. NULL,
  855. NULL,
  856. &NumDomains,
  857. NULL,
  858. NULL,
  859. NULL,
  860. NULL );
  861. if (err == ERROR_SUCCESS)
  862. {
  863. if (Array) // Initialized during a previous attempt
  864. {
  865. DCacheFreeArray(Array);
  866. }
  867. Array = DCacheCreateArray( NumDomains + 5, TRUE );
  868. if ( Array )
  869. {
  870. for ( i = 0 ; i < NumDomains ; i++ )
  871. {
  872. FlatNameSize = DNLEN + 2 ;
  873. DnsDomainSize = MAX_PATH ;
  874. err = RegEnumValue(
  875. Key,
  876. i,
  877. FlatName,
  878. &FlatNameSize,
  879. NULL,
  880. &dwType,
  881. (PUCHAR) DnsDomain,
  882. &DnsDomainSize );
  883. if ( err == 0 )
  884. {
  885. RtlInitUnicodeString( &Flat, FlatName );
  886. RtlInitUnicodeString( &Dns, DnsDomain );
  887. Entry = DCacheCreateEntry(
  888. ( Dns.Length ? DomainNt5 : DomainNt4),
  889. &Flat,
  890. ( Dns.Length ? &Dns : NULL ),
  891. NULL );
  892. if ( Entry )
  893. {
  894. DCacheInsertArray( Array, Entry );
  895. DCacheDereferenceEntry( Entry );
  896. }
  897. else
  898. {
  899. err = ERROR_OUTOFMEMORY;
  900. }
  901. }
  902. else
  903. {
  904. break;
  905. }
  906. }
  907. if ((i < NumDomains) && (err == ERROR_NO_MORE_ITEMS))
  908. {
  909. // Hit the end of enumeration although we
  910. // knew how many values we had?
  911. // The key was probably deleted in another
  912. // session. Retry.
  913. err = ERROR_FILE_NOT_FOUND;
  914. }
  915. }
  916. else
  917. {
  918. err = ERROR_OUTOFMEMORY;
  919. }
  920. }
  921. RegCloseKey( Key );
  922. }
  923. } while (((err == ERROR_FILE_NOT_FOUND) || (err == ERROR_KEY_DELETED)) && (--dwSize));
  924. //
  925. // Note that we may not have succeeded in the end
  926. // We will return success anyway, with no array or a partial array.
  927. // The callers seem to handle that.
  928. //
  929. if ( RegistryTime )
  930. {
  931. dwSize = sizeof( LARGE_INTEGER ) ;
  932. if ( RegQueryValueEx( WinlogonKey,
  933. szCacheUpdate,
  934. 0,
  935. &dwType,
  936. (PUCHAR) RegistryTime,
  937. &dwSize ) ||
  938. (dwType != REG_BINARY ) ||
  939. (dwSize != sizeof( LARGE_INTEGER ) ) )
  940. {
  941. RegistryTime->QuadPart = 0 ;
  942. }
  943. }
  944. *pArray = Array ;
  945. if ( ReturnFalseAnyway )
  946. {
  947. return FALSE ;
  948. }
  949. else
  950. {
  951. return TRUE ;
  952. }
  953. }
  954. PDOMAIN_CACHE_ENTRY
  955. DCacheEntryFromRegistry(
  956. PUNICODE_STRING FlatName
  957. )
  958. {
  959. PDOMAIN_CACHE_ENTRY Entry = NULL ;
  960. HKEY Key ;
  961. int err ;
  962. DWORD dwType ;
  963. WCHAR DnsName[ MAX_PATH ];
  964. DWORD dwSize ;
  965. UNICODE_STRING Dns ;
  966. err = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  967. szCache,
  968. 0,
  969. KEY_READ,
  970. &Key );
  971. if ( err == 0 )
  972. {
  973. dwSize = MAX_PATH ;
  974. DnsName[ 0 ] = L'\0';
  975. err = RegQueryValueEx(
  976. Key,
  977. FlatName->Buffer,
  978. NULL,
  979. &dwType,
  980. (PUCHAR) DnsName,
  981. &dwSize );
  982. if ( err == 0 )
  983. {
  984. if ( dwType == REG_SZ )
  985. {
  986. RtlInitUnicodeString( &Dns, DnsName );
  987. Entry = DCacheCreateEntry(
  988. ( Dns.Length ? DomainNt5 : DomainNt4 ),
  989. FlatName,
  990. ( Dns.Length ? &Dns : NULL ),
  991. NULL );
  992. }
  993. }
  994. RegCloseKey( Key );
  995. }
  996. return Entry ;
  997. }
  998. VOID
  999. DCacheWriteDomainsToCache(
  1000. PDOMAIN_CACHE_ARRAY Array
  1001. )
  1002. {
  1003. HKEY Key ;
  1004. ULONG i ;
  1005. ULONG Disp ;
  1006. int err ;
  1007. PDOMAIN_CACHE_ENTRY Entry ;
  1008. LARGE_INTEGER Now ;
  1009. //
  1010. // Delete what's there. Ignore the error, since we are
  1011. // just going to rewrite all the values, anyway.
  1012. //
  1013. err = RegDeleteKey( HKEY_LOCAL_MACHINE,
  1014. szCache );
  1015. err = RegCreateKeyEx(
  1016. HKEY_LOCAL_MACHINE,
  1017. szCache,
  1018. 0,
  1019. NULL,
  1020. REG_OPTION_NON_VOLATILE,
  1021. KEY_ALL_ACCESS,
  1022. NULL,
  1023. &Key,
  1024. &Disp );
  1025. if ( err )
  1026. {
  1027. return ;
  1028. }
  1029. for ( i = 0 ; i < Array->Count ; i++ )
  1030. {
  1031. Entry = Array->List[ i ];
  1032. if ( ( Entry->Type == DomainNt5 ) )
  1033. {
  1034. if ( ( Entry->FlatName.Buffer == NULL ) ||
  1035. ( Entry->DnsName.Buffer == NULL ) )
  1036. {
  1037. DebugLog(( DEB_ERROR, "Corrupt uplevel domain cache entry at %p\n", Entry ));
  1038. continue;
  1039. }
  1040. RegSetValueEx(
  1041. Key,
  1042. Entry->FlatName.Buffer,
  1043. 0,
  1044. REG_SZ,
  1045. (PUCHAR) Entry->DnsName.Buffer,
  1046. Entry->DnsName.Length + sizeof(WCHAR) );
  1047. }
  1048. else if ( Entry->Type == DomainNt4 )
  1049. {
  1050. if ( Entry->FlatName.Buffer == NULL )
  1051. {
  1052. DebugLog(( DEB_ERROR, "Corrupt downlevel domain cache entry at %p\n", Entry ));
  1053. }
  1054. RegSetValueEx(
  1055. Key,
  1056. Entry->FlatName.Buffer,
  1057. 0,
  1058. REG_SZ,
  1059. (PUCHAR) TEXT(""),
  1060. sizeof(WCHAR) );
  1061. }
  1062. else
  1063. {
  1064. //
  1065. // Other types don't get to live in the cache
  1066. //
  1067. NOTHING ;
  1068. }
  1069. }
  1070. RegCloseKey( Key );
  1071. GetSystemTimeAsFileTime( (LPFILETIME) &Now );
  1072. RegSetValueEx(
  1073. WinlogonKey,
  1074. szCacheUpdate,
  1075. 0,
  1076. REG_BINARY,
  1077. (PUCHAR) &Now,
  1078. sizeof( LARGE_INTEGER ) );
  1079. }
  1080. BOOL
  1081. DCacheInitialize(
  1082. VOID
  1083. )
  1084. {
  1085. DOMAIN_ENTRY_TYPE Types ;
  1086. WCHAR StringBuffer[ MAX_PATH ];
  1087. LONG Size ;
  1088. int err ;
  1089. DWORD dwSize ;
  1090. DWORD dwType ;
  1091. for (Types = 0 ; Types < DomainTypeMax ; Types++ )
  1092. {
  1093. if ( CacheDomainModifiers[ Types ].StringId )
  1094. {
  1095. Size = LoadString( hDllInstance,
  1096. CacheDomainModifiers[ Types ].StringId,
  1097. StringBuffer,
  1098. MAX_PATH );
  1099. if ( Size )
  1100. {
  1101. RtlCreateUnicodeString( &CacheDomainModifiers[ Types ].String,
  1102. StringBuffer );
  1103. }
  1104. }
  1105. }
  1106. dwSize = sizeof( CacheShowDnsNames );
  1107. err = RegQueryValueEx(
  1108. WinlogonKey,
  1109. DCACHE_SHOW_DNS_NAMES,
  1110. NULL,
  1111. &dwType,
  1112. (PUCHAR) &CacheShowDnsNames,
  1113. &dwSize );
  1114. dwSize = sizeof( CacheAppendDomainInfo );
  1115. err = RegQueryValueEx(
  1116. WinlogonKey,
  1117. DCACHE_SHOW_DOMAIN_TAGS,
  1118. NULL,
  1119. &dwType,
  1120. (PUCHAR) &CacheAppendDomainInfo,
  1121. &dwSize );
  1122. //
  1123. // Convert and delete old cache:
  1124. //
  1125. return TRUE ;
  1126. }
  1127. BOOL
  1128. DCachepInitializeCache(
  1129. PDOMAIN_CACHE pCache
  1130. )
  1131. {
  1132. NTSTATUS Status ;
  1133. ZeroMemory( pCache, sizeof(DOMAIN_CACHE) );
  1134. Status = RtlInitializeCriticalSectionAndSpinCount(
  1135. & pCache->CriticalSection,
  1136. 0x80000000 );
  1137. return NT_SUCCESS( Status );
  1138. }
  1139. PDOMAIN_CACHE
  1140. DCacheCreate(
  1141. VOID
  1142. )
  1143. {
  1144. PDOMAIN_CACHE Cache ;
  1145. Cache = (PDOMAIN_CACHE) LocalAlloc( LMEM_FIXED, sizeof( DOMAIN_CACHE ) );
  1146. if ( !Cache )
  1147. {
  1148. return NULL ;
  1149. }
  1150. if ( !DCachepInitializeCache( Cache ) )
  1151. {
  1152. LocalFree( Cache );
  1153. return NULL ;
  1154. }
  1155. Cache->State = DomainCacheEmpty ;
  1156. if ( !g_Console )
  1157. {
  1158. Cache->Flags |= DCACHE_READ_ONLY ;
  1159. }
  1160. if ( SafeBootMode == SAFEBOOT_MINIMAL )
  1161. {
  1162. Cache->Flags |= DCACHE_MIT_MODE ;
  1163. }
  1164. return Cache ;
  1165. }
  1166. BOOL
  1167. DCacheGetMinimalArray(
  1168. PDOMAIN_CACHE_ARRAY Array,
  1169. PWSTR DefaultDomain OPTIONAL,
  1170. PBOOL DomainMember OPTIONAL,
  1171. PBOOL NewDomain OPTIONAL
  1172. )
  1173. {
  1174. BOOL SidPresent = FALSE ;
  1175. UNICODE_STRING String = { 0 } ;
  1176. UNICODE_STRING DnsDomain = { 0 } ;
  1177. PDOMAIN_CACHE_ENTRY Entry = NULL ;
  1178. PDOMAIN_CACHE_ENTRY ComputerEntry = NULL ;
  1179. PDOMAIN_CACHE_ENTRY OldDefault = NULL ;
  1180. NT_PRODUCT_TYPE ProductType = NtProductWinNt;
  1181. WCHAR ComputerName[ CNLEN + 1 ];
  1182. ULONG Size ;
  1183. ULONG Type ;
  1184. WCHAR LastPrimary[ DNLEN + 1 ];
  1185. UNICODE_STRING LastPrimary_U ;
  1186. //
  1187. // First, find out what we are
  1188. //
  1189. RtlGetNtProductType( &ProductType );
  1190. if ( Array == NULL )
  1191. {
  1192. Array = DCacheCreateArray( 5, TRUE );
  1193. }
  1194. if ( Array == NULL )
  1195. {
  1196. return FALSE ;
  1197. }
  1198. if ( SafeBootMode != SAFEBOOT_MINIMAL )
  1199. {
  1200. if ( GetPrimaryDomainEx( &String, &DnsDomain, NULL, &SidPresent ) )
  1201. {
  1202. //
  1203. // Ok, we are configured to be part of a domain.
  1204. //
  1205. if ( SidPresent )
  1206. {
  1207. //
  1208. // Ok, this is an NT domain.
  1209. //
  1210. Entry = DCacheCreateEntry(
  1211. ( DnsDomain.Buffer ? DomainNt5 : DomainNt4 ),
  1212. &String,
  1213. ( DnsDomain.Buffer ? &DnsDomain : NULL),
  1214. NULL );
  1215. if ( Entry )
  1216. {
  1217. if ( ProductType == NtProductLanManNt )
  1218. {
  1219. //
  1220. // We're a DC. Until we know otherwise, tag this as the default
  1221. //
  1222. Entry->Flags |= DCE_DEFAULT_ENTRY ;
  1223. }
  1224. DCacheInsertArray( Array, Entry );
  1225. DCacheDereferenceEntry( Entry );
  1226. Entry = NULL ;
  1227. }
  1228. //
  1229. // Check to see if we've changed domains:
  1230. //
  1231. if ( NewDomain )
  1232. {
  1233. Size = sizeof( LastPrimary );
  1234. if ( RegQueryValueEx(
  1235. WinlogonKey,
  1236. szCachePrimary,
  1237. 0,
  1238. &Type,
  1239. (PUCHAR) LastPrimary,
  1240. &Size ) == 0 )
  1241. {
  1242. RtlInitUnicodeString( &LastPrimary_U, LastPrimary );
  1243. *NewDomain = !RtlEqualUnicodeString( &LastPrimary_U,
  1244. &String,
  1245. TRUE );
  1246. }
  1247. else
  1248. {
  1249. //
  1250. // If the value can't be read for any reason, assume that it's
  1251. // missing and we're in a different domain than last time.
  1252. //
  1253. *NewDomain = TRUE ;
  1254. }
  1255. }
  1256. RegSetValueEx(
  1257. WinlogonKey,
  1258. szCachePrimary,
  1259. 0,
  1260. REG_SZ,
  1261. (PUCHAR) String.Buffer,
  1262. String.Length + sizeof(WCHAR));
  1263. }
  1264. else
  1265. {
  1266. //
  1267. // Part of an MIT realm, skip for now. It will get added
  1268. // below when all the MIT realms are added.
  1269. //
  1270. NOTHING ;
  1271. }
  1272. if ( String.Buffer )
  1273. {
  1274. LocalFree( String.Buffer );
  1275. }
  1276. if ( DnsDomain.Buffer )
  1277. {
  1278. LocalFree( DnsDomain.Buffer );
  1279. }
  1280. }
  1281. }
  1282. if ( ( ProductType != NtProductLanManNt ) ||
  1283. ( SafeBootMode == SAFEBOOT_MINIMAL ) )
  1284. {
  1285. //
  1286. // Do the machine name:
  1287. //
  1288. Size = CNLEN + 1;
  1289. GetComputerName( ComputerName, &Size );
  1290. RtlInitUnicodeString( &String, ComputerName );
  1291. ComputerEntry = DCacheCreateEntry(
  1292. DomainMachine,
  1293. &String,
  1294. NULL,
  1295. NULL );
  1296. if ( ComputerEntry )
  1297. {
  1298. DCacheInsertArray( Array, ComputerEntry );
  1299. DCacheDereferenceEntry( ComputerEntry );
  1300. }
  1301. }
  1302. DCacheAddMitRealms( Array );
  1303. if ( DefaultDomain && (*DefaultDomain) )
  1304. {
  1305. RtlInitUnicodeString( &String, DefaultDomain );
  1306. OldDefault = DCacheFindDefaultEntry( Array );
  1307. if ( Entry )
  1308. {
  1309. Entry->Flags &= ~(DCE_DEFAULT_ENTRY);
  1310. }
  1311. Entry = DCacheSearchArray( Array, &String );
  1312. if ( !Entry )
  1313. {
  1314. Entry = DCacheEntryFromRegistry( &String );
  1315. if ( Entry )
  1316. {
  1317. DCacheInsertArray( Array, Entry );
  1318. }
  1319. }
  1320. else
  1321. {
  1322. DCacheReferenceEntry( Entry );
  1323. }
  1324. if ( Entry )
  1325. {
  1326. Entry->Flags |= DCE_DEFAULT_ENTRY ;
  1327. DCacheDereferenceEntry( Entry );
  1328. if ( OldDefault )
  1329. {
  1330. OldDefault->Flags &= ~(DCE_DEFAULT_ENTRY);
  1331. }
  1332. }
  1333. }
  1334. if ( DomainMember )
  1335. {
  1336. *DomainMember = SidPresent ;
  1337. }
  1338. return TRUE ;
  1339. }
  1340. BOOL
  1341. DCacheUpdateMinimal(
  1342. PDOMAIN_CACHE Cache,
  1343. PWSTR DefaultDomain OPTIONAL,
  1344. BOOL CompleteAsync
  1345. )
  1346. {
  1347. PDOMAIN_CACHE_ARRAY Array = NULL ;
  1348. LARGE_INTEGER RegistryTime = { 0 };
  1349. BOOL DomainMember = FALSE ;
  1350. BOOL NewDomain = FALSE ;
  1351. BOOL RetryDomain = FALSE ;
  1352. BOOL NoCache = FALSE ;
  1353. BOOL StartThread = FALSE ;
  1354. WCHAR ComputerName[ 20 ];
  1355. ULONG Size ;
  1356. if ( !DCacheGetDomainsFromCache( &Array, &RegistryTime ) ||
  1357. ( Array == NULL ) )
  1358. {
  1359. NoCache = TRUE ;
  1360. }
  1361. //
  1362. // In rare events, we will leave a domain, and the cache
  1363. // will still be in the registry. This is caught later,
  1364. // and deleted, and this is the retry point.
  1365. //
  1366. ReloadWithoutCache:
  1367. if ( !Array )
  1368. {
  1369. Array = DCacheCreateArray( 5, TRUE );
  1370. if ( !Array )
  1371. {
  1372. return FALSE ;
  1373. }
  1374. }
  1375. if ( !DCacheGetMinimalArray( Array,
  1376. DefaultDomain,
  1377. &DomainMember,
  1378. &NewDomain ) )
  1379. {
  1380. DCacheFreeArray( Array );
  1381. return FALSE ;
  1382. }
  1383. //
  1384. // If we are no longer in the same domain, either in a workgroup, or
  1385. // in a different domain, toss the cache. If we just retried this
  1386. // don't keep doing it...
  1387. //
  1388. if ( ( RetryDomain == FALSE ) &&
  1389. ( ( ( NoCache == FALSE ) &&
  1390. ( DomainMember == FALSE ) ) ||
  1391. ( NewDomain == TRUE ) ) )
  1392. {
  1393. //
  1394. // Cleanup. The cache is still present, but we are no longer part of a domain
  1395. //
  1396. DCacheFreeArray( Array );
  1397. RegDeleteKey( HKEY_LOCAL_MACHINE, szCache );
  1398. RegDeleteValue( WinlogonKey, szCachePrimary );
  1399. if ( DefaultDomain )
  1400. {
  1401. Size = 20 ;
  1402. if ( GetComputerName( ComputerName, &Size ) )
  1403. {
  1404. if ( _wcsicmp( DefaultDomain, ComputerName ) )
  1405. {
  1406. DefaultDomain = NULL ;
  1407. RegSetValueEx(
  1408. WinlogonKey,
  1409. DEFAULT_DOMAIN_NAME_KEY,
  1410. 0,
  1411. REG_SZ,
  1412. (PUCHAR) ComputerName,
  1413. (Size + 1) * sizeof( WCHAR ) );
  1414. }
  1415. }
  1416. }
  1417. NoCache = TRUE ;
  1418. Array = NULL ;
  1419. RetryDomain = TRUE ;
  1420. goto ReloadWithoutCache;
  1421. }
  1422. LockDomainCache( Cache );
  1423. if ( Cache->Array )
  1424. {
  1425. DCacheFreeArray( Cache->Array );
  1426. }
  1427. Cache->Array = Array ;
  1428. Cache->RegistryUpdateTime = RegistryTime ;
  1429. if ( NoCache )
  1430. {
  1431. Cache->Flags |= DCACHE_NO_CACHE ;
  1432. }
  1433. GetSystemTimeAsFileTime( (LPFILETIME) &Cache->CacheUpdateTime );
  1434. if ( DomainMember )
  1435. {
  1436. if ( !NoCache )
  1437. {
  1438. if ( Cache->CacheUpdateTime.QuadPart - Cache->RegistryUpdateTime.QuadPart < TWO_WEEKS )
  1439. {
  1440. Cache->State = DomainCacheRegistryCache ;
  1441. }
  1442. else
  1443. {
  1444. Cache->State = DomainCacheDefaultOnly ;
  1445. }
  1446. }
  1447. else
  1448. {
  1449. Cache->State = DomainCacheDefaultOnly ;
  1450. }
  1451. Cache->Flags |= DCACHE_MEMBER ;
  1452. }
  1453. else
  1454. {
  1455. Cache->State = DomainCacheReady ;
  1456. }
  1457. if ( DCacheFindDefaultEntry( Array ) == NULL )
  1458. {
  1459. Cache->Flags |= DCACHE_DEF_UNKNOWN ;
  1460. }
  1461. if ( ( Cache->State != DomainCacheReady ) &&
  1462. ( CompleteAsync ) )
  1463. {
  1464. StartThread = TRUE ;
  1465. if ( DefaultDomain )
  1466. {
  1467. Cache->DefaultDomain = DupString( DefaultDomain );
  1468. }
  1469. else
  1470. {
  1471. Cache->DefaultDomain = NULL ;
  1472. }
  1473. }
  1474. UnlockDomainCache( Cache );
  1475. if ( StartThread )
  1476. {
  1477. DCacheUpdateFullAsync( Cache );
  1478. }
  1479. return TRUE ;
  1480. }
  1481. void
  1482. DCacheUpdateFullAsync(
  1483. PDOMAIN_CACHE Cache
  1484. )
  1485. {
  1486. HANDLE hThread ;
  1487. DWORD tid ;
  1488. hThread = CreateThread( NULL,
  1489. 0,
  1490. DCacheUpdateThread,
  1491. Cache,
  1492. 0,
  1493. &tid );
  1494. if ( hThread )
  1495. {
  1496. CloseHandle( hThread );
  1497. }
  1498. else
  1499. {
  1500. LockDomainCache( Cache );
  1501. Cache->State = DomainCacheReady ;
  1502. UnlockDomainCache( Cache );
  1503. }
  1504. }
  1505. BOOL
  1506. DCacheUpdateFull(
  1507. PDOMAIN_CACHE Cache,
  1508. PWSTR Default OPTIONAL
  1509. )
  1510. {
  1511. PDOMAIN_CACHE_ARRAY Array = NULL ;
  1512. ULONG NetStatus = 0 ;
  1513. ULONG RetryCount = 3 ;
  1514. BOOL DomainMember = FALSE ;
  1515. NT_PRODUCT_TYPE ProductType = NtProductWinNt;
  1516. LARGE_INTEGER RegistryTime = { 0 };
  1517. if ( ( Cache->Flags & DCACHE_MEMBER ) != 0 )
  1518. {
  1519. DomainMember = TRUE ;
  1520. RtlGetNtProductType( &ProductType );
  1521. if ( ProductType == NtProductLanManNt )
  1522. {
  1523. RetryCount = 3600 ;
  1524. }
  1525. //
  1526. // now, call netlogon, and see if it has the list.
  1527. //
  1528. NetStatus = DCacheGetTrustedDomains( &Array );
  1529. if ( NetStatus != 0 )
  1530. {
  1531. while ( RetryCount-- )
  1532. {
  1533. Sleep( 3000 );
  1534. NetStatus = DCacheGetTrustedDomains( &Array );
  1535. if ( NetStatus == 0 )
  1536. {
  1537. break;
  1538. }
  1539. if ( RPC_S_UNKNOWN_IF == NetStatus )
  1540. {
  1541. // exit the loop if no interface (netlogon stopped)
  1542. RetryCount = 0;
  1543. }
  1544. }
  1545. }
  1546. if ( NetStatus != 0 )
  1547. {
  1548. //
  1549. // Try to read from the cache
  1550. //
  1551. DCacheGetDomainsFromCache( &Array, &RegistryTime );
  1552. }
  1553. }
  1554. if ( Array )
  1555. {
  1556. DCacheGetMinimalArray( Array, Default, &DomainMember, NULL );
  1557. }
  1558. if ( Array )
  1559. {
  1560. LockDomainCache( Cache );
  1561. if ( Cache->Array )
  1562. {
  1563. DCacheFreeArray( Cache->Array );
  1564. }
  1565. Cache->Array = Array ;
  1566. if ( DomainMember )
  1567. {
  1568. Cache->Flags |= DCACHE_MEMBER ;
  1569. }
  1570. else
  1571. {
  1572. Cache->Flags &= ~( DCACHE_MEMBER ) ;
  1573. }
  1574. if ( NetStatus == 0 )
  1575. {
  1576. Cache->State = DomainCacheReady ;
  1577. if ( ( Cache->Flags & DCACHE_READ_ONLY ) == 0 )
  1578. {
  1579. DCacheWriteDomainsToCache( Array );
  1580. }
  1581. GetSystemTimeAsFileTime( (LPFILETIME) &Cache->RegistryUpdateTime );
  1582. Cache->Flags &= ~(DCACHE_NO_CACHE);
  1583. }
  1584. else if ( (Cache->Flags & DCACHE_NO_CACHE) == 0 )
  1585. {
  1586. Cache->State = DomainCacheRegistryCache ;
  1587. Cache->RegistryUpdateTime = RegistryTime ;
  1588. }
  1589. else
  1590. {
  1591. Cache->State = DomainCacheDefaultOnly ;
  1592. Cache->RegistryUpdateTime.QuadPart = 0 ;
  1593. }
  1594. if ( Cache->DefaultDomain )
  1595. {
  1596. DCacheSetDefaultEntry( Cache,
  1597. Cache->DefaultDomain,
  1598. NULL );
  1599. Free( Cache->DefaultDomain );
  1600. Cache->DefaultDomain = NULL ;
  1601. }
  1602. UnlockDomainCache( Cache );
  1603. }
  1604. return ( Array != NULL ) ;
  1605. }
  1606. DWORD
  1607. DCacheUpdateThread(
  1608. PDOMAIN_CACHE Cache
  1609. )
  1610. {
  1611. HWND Notify ;
  1612. UINT Message ;
  1613. LockDomainCache( Cache );
  1614. if ( ( Cache->Flags & DCACHE_ASYNC_UPDATE ) != 0 )
  1615. {
  1616. //
  1617. // Another thread is already doing this.
  1618. //
  1619. UnlockDomainCache( Cache );
  1620. return 0 ;
  1621. }
  1622. Cache->Flags |= DCACHE_ASYNC_UPDATE ;
  1623. UnlockDomainCache( Cache );
  1624. DCacheUpdateFull( Cache, NULL );
  1625. LockDomainCache( Cache );
  1626. Notify = Cache->UpdateNotifyWindow ;
  1627. Message = Cache->Message ;
  1628. Cache->UpdateNotifyWindow = NULL ;
  1629. Cache->Message = 0 ;
  1630. Cache->Flags &= ~( DCACHE_ASYNC_UPDATE );
  1631. UnlockDomainCache( Cache );
  1632. if ( Notify )
  1633. {
  1634. DebugLog(( DEB_TRACE_CACHE, "Notifying window %x of cache complete\n" ));
  1635. PostMessage( Notify, Message, 0, 0 );
  1636. }
  1637. return 0;
  1638. }
  1639. BOOL
  1640. DCachePopulateListBoxFromArray(
  1641. PDOMAIN_CACHE_ARRAY Array,
  1642. HWND ComboBox,
  1643. LPWSTR LastKey OPTIONAL
  1644. )
  1645. {
  1646. ULONG i ;
  1647. ULONG_PTR Index ;
  1648. PDOMAIN_CACHE_ENTRY Default = NULL ;
  1649. LRESULT Result ;
  1650. //
  1651. // Reset the combo box
  1652. //
  1653. DebugLog((DEB_TRACE_CACHE, "Flushing listbox\n" ));
  1654. SendMessage( ComboBox, CB_RESETCONTENT, 0, 0);
  1655. for ( i = 0 ; i < Array->Count ; i++ )
  1656. {
  1657. DebugLog(( DEB_TRACE_CACHE, "Adding domain %ws (%d) to listbox\n",
  1658. Array->List[ i ]->DisplayName.Buffer,
  1659. Array->List[ i ]->Type ));
  1660. if ( Array->List[ i ]->Type == DomainMitRealm )
  1661. {
  1662. if ( (Array->List[ i ]->Flags & DCE_REACHABLE_MIT ) == 0 )
  1663. {
  1664. DebugLog(( DEB_TRACE_CACHE, "MIT Realm %ws is not reachable, skipping\n",
  1665. Array->List[ i ]->FlatName.Buffer ));
  1666. continue;
  1667. }
  1668. }
  1669. Index = SendMessage( ComboBox,
  1670. CB_ADDSTRING,
  1671. 0,
  1672. (LPARAM) Array->List[ i ]->DisplayName.Buffer );
  1673. if ( Index != CB_ERR )
  1674. {
  1675. SendMessage( ComboBox,
  1676. CB_SETITEMDATA,
  1677. (WPARAM) Index,
  1678. (LPARAM) Array->List[ i ] );
  1679. }
  1680. if ( ( Array->List[ i ]->Type == DomainMachine ) &&
  1681. ( Default == NULL ) )
  1682. {
  1683. Default = Array->List[ i ] ;
  1684. }
  1685. if ( Array->List[ i ]->Flags & DCE_DEFAULT_ENTRY )
  1686. {
  1687. Default = Array->List[ i ];
  1688. }
  1689. }
  1690. //
  1691. // Select the default entry:
  1692. //
  1693. if ( LastKey && (*LastKey) )
  1694. {
  1695. Result = SendMessage( ComboBox,
  1696. CB_SELECTSTRING,
  1697. (WPARAM) -1,
  1698. (LPARAM) LastKey );
  1699. #if DBG
  1700. if ( Result != CB_ERR )
  1701. {
  1702. DebugLog(( DEB_TRACE_CACHE, "Selected first entry starting with %ws\n", LastKey ));
  1703. }
  1704. else
  1705. {
  1706. DebugLog(( DEB_TRACE_CACHE, "No entry found starting with %ws. Trying default\n", LastKey ));
  1707. }
  1708. #endif
  1709. }
  1710. else
  1711. {
  1712. Result = CB_ERR ;
  1713. }
  1714. if ( ( Result == CB_ERR ) &&
  1715. ( Default != NULL ) )
  1716. {
  1717. SendMessage( ComboBox,
  1718. CB_SELECTSTRING,
  1719. (WPARAM) -1,
  1720. (LPARAM) Default->DisplayName.Buffer );
  1721. DebugLog(( DEB_TRACE_CACHE, "Selecting '%ws' as the default entry\n",
  1722. Default->DisplayName.Buffer ));
  1723. }
  1724. return TRUE ;
  1725. }
  1726. BOOL
  1727. DCacheSetNotifyWindowIfNotReady(
  1728. PDOMAIN_CACHE Cache,
  1729. HWND Window,
  1730. UINT Message
  1731. )
  1732. {
  1733. BOOL IsReady = FALSE ;
  1734. HANDLE hThread ;
  1735. DWORD tid ;
  1736. LockDomainCache( Cache );
  1737. IsReady = ( Cache->State == DomainCacheReady );
  1738. if ( !IsReady )
  1739. {
  1740. Cache->UpdateNotifyWindow = Window ;
  1741. Cache->Message = Message ;
  1742. }
  1743. else
  1744. {
  1745. if ( ( Cache->Flags & DCACHE_ASYNC_UPDATE ) == 0 )
  1746. {
  1747. hThread = CreateThread( NULL,
  1748. 0,
  1749. DCacheUpdateThread,
  1750. Cache,
  1751. 0,
  1752. &tid );
  1753. }
  1754. }
  1755. UnlockDomainCache( Cache );
  1756. return IsReady ;
  1757. }
  1758. PDOMAIN_CACHE_ARRAY
  1759. DCacheCopyCacheArray(
  1760. PDOMAIN_CACHE Cache
  1761. )
  1762. {
  1763. PDOMAIN_CACHE_ARRAY Array = NULL ;
  1764. LockDomainCache( Cache );
  1765. if ( Cache->Array )
  1766. {
  1767. Array = DCacheCopyArray( Cache->Array );
  1768. }
  1769. UnlockDomainCache( Cache );
  1770. return Array ;
  1771. }
  1772. BOOL
  1773. DCacheValidateCache(
  1774. PDOMAIN_CACHE Cache
  1775. )
  1776. {
  1777. LARGE_INTEGER Now ;
  1778. LARGE_INTEGER Diff ;
  1779. LockDomainCache( Cache );
  1780. GetSystemTimeAsFileTime( (LPFILETIME) &Now );
  1781. Diff.QuadPart = Now.QuadPart - Cache->CacheUpdateTime.QuadPart ;
  1782. UnlockDomainCache( Cache );
  1783. return (Diff.QuadPart < TWO_MINUTES );
  1784. }
  1785. DOMAIN_CACHE_STATE
  1786. DCacheGetCacheState(
  1787. PDOMAIN_CACHE Cache
  1788. )
  1789. {
  1790. DOMAIN_CACHE_STATE State ;
  1791. LockDomainCache( Cache );
  1792. State = Cache->State ;
  1793. UnlockDomainCache( Cache );
  1794. return State ;
  1795. }
  1796. BOOL
  1797. DCacheSetDefaultEntry(
  1798. PDOMAIN_CACHE Cache,
  1799. PWSTR FlatName OPTIONAL,
  1800. PWSTR DnsName OPTIONAL
  1801. )
  1802. {
  1803. UNICODE_STRING String ;
  1804. PDOMAIN_CACHE_ENTRY Entry ;
  1805. BOOL Result ;
  1806. if ( ( FlatName == NULL ) &&
  1807. ( DnsName == NULL ) )
  1808. {
  1809. return FALSE ;
  1810. }
  1811. LockDomainCache( Cache );
  1812. Entry = DCacheFindDefaultEntry( Cache->Array );
  1813. if ( Entry )
  1814. {
  1815. Entry->Flags &= ~(DCE_DEFAULT_ENTRY) ;
  1816. }
  1817. if ( FlatName )
  1818. {
  1819. RtlInitUnicodeString( &String, FlatName );
  1820. Entry = DCacheSearchArray( Cache->Array,
  1821. &String );
  1822. }
  1823. else
  1824. {
  1825. RtlInitUnicodeString( &String, DnsName );
  1826. Entry = DCacheSearchArrayByDns( Cache->Array,
  1827. &String );
  1828. }
  1829. if ( Entry )
  1830. {
  1831. Entry->Flags |= DCE_DEFAULT_ENTRY ;
  1832. Result = TRUE ;
  1833. DebugLog(( DEB_TRACE_CACHE, "Setting '%ws' to be the default\n",
  1834. Entry->DisplayName.Buffer ));
  1835. }
  1836. else
  1837. {
  1838. Result = FALSE ;
  1839. }
  1840. if ( Result )
  1841. {
  1842. Cache->Flags &= ~(DCACHE_DEF_UNKNOWN) ;
  1843. }
  1844. else
  1845. {
  1846. Cache->Flags |= DCACHE_DEF_UNKNOWN ;
  1847. }
  1848. UnlockDomainCache( Cache );
  1849. return Result ;
  1850. }
  1851. PDOMAIN_CACHE_ENTRY
  1852. DCacheLocateEntry(
  1853. PDOMAIN_CACHE Cache,
  1854. PWSTR Domain
  1855. )
  1856. {
  1857. PDOMAIN_CACHE_ENTRY Entry = NULL ;
  1858. UNICODE_STRING String ;
  1859. LockDomainCache( Cache );
  1860. if ( Domain )
  1861. {
  1862. RtlInitUnicodeString( &String, Domain );
  1863. Entry = DCacheSearchArray( Cache->Array,
  1864. &String );
  1865. if ( Entry )
  1866. {
  1867. DCacheReferenceEntry( Entry );
  1868. }
  1869. }
  1870. UnlockDomainCache( Cache );
  1871. return Entry ;
  1872. }
  1873. ULONG
  1874. DCacheGetFlags(
  1875. PDOMAIN_CACHE Cache
  1876. )
  1877. {
  1878. ULONG Flags ;
  1879. LockDomainCache( Cache );
  1880. Flags = Cache->Flags ;
  1881. UnlockDomainCache( Cache );
  1882. return Flags ;
  1883. }