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.

2367 lines
50 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. MaxRealmLength *= sizeof( WCHAR );
  549. Realms = LocalAlloc( LMEM_FIXED, MaxRealmLength );
  550. if ( Realms)
  551. {
  552. for ( Index = 0 ; Index < NumRealms ; Index++ )
  553. {
  554. RealmSize = MaxRealmLength ;
  555. err = RegEnumKeyEx( MitKey,
  556. Index,
  557. Realms,
  558. &RealmSize,
  559. NULL,
  560. NULL,
  561. NULL,
  562. &KeyTime );
  563. if ( err == 0 )
  564. {
  565. DebugLog(( DEB_TRACE_CACHE, "Found realm %ws\n", Realms ));
  566. RtlInitUnicodeString( &DnsName, Realms );
  567. Entry = DCacheCreateEntry(
  568. DomainMitUntrusted,
  569. &DnsName,
  570. &DnsName,
  571. NULL );
  572. if ( Entry )
  573. {
  574. Entry->Flags |= DCE_REACHABLE_MIT ;
  575. if ( !DCacheInsertArray( Array, Entry ) )
  576. {
  577. //
  578. // If the insert failed, then there's already an entry
  579. // in the list for this domain. Locate it, and tag it
  580. // so that it will be displayed
  581. //
  582. TrustedDomain = DCacheSearchArray( Array, &DnsName );
  583. if ( TrustedDomain )
  584. {
  585. TrustedDomain->Flags |= DCE_REACHABLE_MIT ;
  586. }
  587. }
  588. DCacheDereferenceEntry( Entry );
  589. }
  590. }
  591. }
  592. LocalFree( Realms );
  593. }
  594. RegCloseKey( MitKey );
  595. }
  596. return TRUE ;
  597. }
  598. BOOL
  599. DCacheAddNetworkProviders(
  600. PDOMAIN_CACHE_ARRAY Array
  601. )
  602. {
  603. WCHAR szProviderName[128];
  604. WCHAR szKeyPath[MAX_PATH];
  605. PWSTR pszProviders;
  606. PWSTR pszScan;
  607. PWSTR pszStart;
  608. WCHAR Save;
  609. HKEY hKey;
  610. DWORD dwType;
  611. DWORD dwLen;
  612. DWORD Class;
  613. int err;
  614. PDOMAIN_CACHE_ENTRY Entry ;
  615. UNICODE_STRING String ;
  616. err = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  617. TEXT("System\\CurrentControlSet\\Control\\NetworkProvider\\Order"),
  618. 0,
  619. KEY_READ,
  620. &hKey );
  621. if ( err )
  622. {
  623. return FALSE ;
  624. }
  625. err = RegQueryValueEx( hKey,
  626. TEXT("ProviderOrder"),
  627. NULL,
  628. &dwType,
  629. NULL,
  630. &dwLen );
  631. if ( (err) || (dwType != REG_SZ) )
  632. {
  633. RegCloseKey( hKey );
  634. return FALSE ;
  635. }
  636. pszProviders = LocalAlloc( LMEM_FIXED, dwLen );
  637. if ( !pszProviders )
  638. {
  639. RegCloseKey( hKey );
  640. return FALSE ;
  641. }
  642. err = RegQueryValueEx( hKey,
  643. TEXT("ProviderOrder"),
  644. NULL,
  645. &dwType,
  646. (PUCHAR) pszProviders,
  647. &dwLen );
  648. RegCloseKey( hKey );
  649. if ( err )
  650. {
  651. LocalFree( pszProviders );
  652. return FALSE ;
  653. }
  654. //
  655. // Initialize things.
  656. //
  657. pszStart = pszProviders;
  658. szProviderName[0] = TEXT('<');
  659. szProviderName[1] = TEXT(' ');
  660. while ( *pszStart )
  661. {
  662. pszScan = pszStart;
  663. while ( (*pszScan) && (*pszScan != TEXT(',') ) )
  664. {
  665. pszScan++;
  666. }
  667. Save = *pszScan;
  668. *pszScan = TEXT('\0');
  669. wsprintf( szKeyPath,
  670. TEXT("System\\CurrentControlSet\\Services\\%s\\networkprovider"),
  671. pszStart );
  672. err = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  673. szKeyPath,
  674. 0,
  675. KEY_READ,
  676. &hKey );
  677. if ( err == 0 )
  678. {
  679. dwLen = sizeof(DWORD) ;
  680. err = RegQueryValueEx( hKey,
  681. TEXT("Class"),
  682. NULL,
  683. &dwType,
  684. (PUCHAR) &Class,
  685. &dwLen );
  686. if ( (err == 0) && (dwType == REG_DWORD) )
  687. {
  688. if ( Class & WN_CREDENTIAL_CLASS )
  689. {
  690. dwLen = 126 * sizeof(WCHAR);
  691. err = RegQueryValueEx( hKey,
  692. TEXT("Name"),
  693. NULL,
  694. &dwType,
  695. (PUCHAR) &szProviderName[2],
  696. &dwLen );
  697. wcscpy( &szProviderName[ (dwLen / sizeof(WCHAR) ) + 2 ],
  698. TEXT(" >") );
  699. RtlInitUnicodeString( &String, szProviderName );
  700. Entry = DCacheCreateEntry(
  701. DomainNetworkProvider,
  702. &String,
  703. NULL,
  704. NULL );
  705. if ( Entry )
  706. {
  707. DCacheInsertArray( Array, Entry );
  708. DCacheDereferenceEntry( Entry );
  709. }
  710. }
  711. }
  712. RegCloseKey( hKey );
  713. }
  714. *pszScan = Save;
  715. if ( *pszScan )
  716. {
  717. pszStart = pszScan + 1;
  718. }
  719. else
  720. {
  721. pszStart = NULL;
  722. break;
  723. }
  724. }
  725. LocalFree( pszProviders );
  726. return TRUE ;
  727. }
  728. BOOL
  729. DCacheGetDomainsFromCache(
  730. PDOMAIN_CACHE_ARRAY *pArray,
  731. PLARGE_INTEGER RegistryTime
  732. )
  733. {
  734. HKEY Key ;
  735. int err ;
  736. DWORD NumDomains ;
  737. DWORD i ;
  738. WCHAR FlatName[ DNLEN + 2 ];
  739. WCHAR DnsDomain[ MAX_PATH ];
  740. DWORD dwType ;
  741. DWORD FlatNameSize ;
  742. DWORD DnsDomainSize ;
  743. UNICODE_STRING Flat ;
  744. UNICODE_STRING Dns ;
  745. PDOMAIN_CACHE_ENTRY Entry ;
  746. PDOMAIN_CACHE_ARRAY Array ;
  747. DWORD dwSize ;
  748. PWSTR DomainBuffer ;
  749. PWSTR DomainBufferEnd ;
  750. PWSTR Scan ;
  751. ULONG Disp ;
  752. BOOL ReturnFalseAnyway = FALSE ;
  753. if ( SafeBootMode == SAFEBOOT_MINIMAL )
  754. {
  755. RegistryTime->QuadPart = 0 ;
  756. return FALSE ;
  757. }
  758. dwSize = 0 ;
  759. err = RegQueryValueEx(
  760. WinlogonKey,
  761. szCacheValue,
  762. NULL,
  763. &dwType,
  764. NULL,
  765. &dwSize );
  766. if ( ( err == ERROR_MORE_DATA ) ||
  767. ( err == ERROR_BUFFER_OVERFLOW ) ||
  768. ( err == 0 ) )
  769. {
  770. //
  771. //
  772. DomainBuffer = LocalAlloc( LMEM_FIXED, dwSize );
  773. if ( DomainBuffer )
  774. {
  775. err = RegQueryValueEx(
  776. WinlogonKey,
  777. szCacheValue,
  778. NULL,
  779. &dwType,
  780. (PUCHAR) DomainBuffer,
  781. &dwSize );
  782. if ( err == 0 )
  783. {
  784. DomainBufferEnd = (PWSTR)((PUCHAR) DomainBuffer + dwSize);
  785. Scan = DomainBuffer ;
  786. err = RegCreateKeyEx(
  787. HKEY_LOCAL_MACHINE,
  788. szCache,
  789. 0,
  790. NULL,
  791. REG_OPTION_NON_VOLATILE,
  792. KEY_ALL_ACCESS,
  793. NULL,
  794. &Key,
  795. &Disp );
  796. if ( err == 0 )
  797. {
  798. while ( Scan != DomainBufferEnd )
  799. {
  800. err = RegSetValueEx(
  801. Key,
  802. Scan,
  803. 0,
  804. REG_SZ,
  805. (PUCHAR) TEXT(""),
  806. sizeof( WCHAR ) );
  807. Scan += wcslen(Scan) ;
  808. while ( (*Scan == L'\0' ) &&
  809. (Scan != DomainBufferEnd ) )
  810. {
  811. Scan++ ;
  812. }
  813. }
  814. RegCloseKey( Key );
  815. }
  816. }
  817. LocalFree( DomainBuffer );
  818. }
  819. RegDeleteValue( WinlogonKey, szCacheValue );
  820. ReturnFalseAnyway = TRUE ;
  821. }
  822. err = RegOpenKeyEx(
  823. HKEY_LOCAL_MACHINE,
  824. szCache,
  825. 0,
  826. KEY_READ,
  827. &Key );
  828. if ( err )
  829. {
  830. return FALSE ;
  831. }
  832. err = RegQueryInfoKey( Key,
  833. NULL,
  834. NULL,
  835. NULL,
  836. NULL,
  837. NULL,
  838. NULL,
  839. &NumDomains,
  840. NULL,
  841. NULL,
  842. NULL,
  843. NULL );
  844. if ( *pArray )
  845. {
  846. Array = *pArray ;
  847. }
  848. else
  849. {
  850. Array = DCacheCreateArray( NumDomains + 5, TRUE );
  851. }
  852. if ( Array )
  853. {
  854. for ( i = 0 ; i < NumDomains ; i++ )
  855. {
  856. FlatNameSize = DNLEN + 2 ;
  857. DnsDomainSize = MAX_PATH ;
  858. err = RegEnumValue(
  859. Key,
  860. i,
  861. FlatName,
  862. &FlatNameSize,
  863. NULL,
  864. &dwType,
  865. (PUCHAR) DnsDomain,
  866. &DnsDomainSize );
  867. if ( err == 0 )
  868. {
  869. RtlInitUnicodeString( &Flat, FlatName );
  870. RtlInitUnicodeString( &Dns, DnsDomain );
  871. Entry = DCacheCreateEntry(
  872. ( Dns.Length ? DomainNt5 : DomainNt4),
  873. &Flat,
  874. ( Dns.Length ? &Dns : NULL ),
  875. NULL );
  876. if ( Entry )
  877. {
  878. DCacheInsertArray( Array, Entry );
  879. DCacheDereferenceEntry( Entry );
  880. }
  881. }
  882. }
  883. }
  884. RegCloseKey( Key );
  885. if ( RegistryTime )
  886. {
  887. dwSize = sizeof( LARGE_INTEGER ) ;
  888. if ( RegQueryValueEx( WinlogonKey,
  889. szCacheUpdate,
  890. 0,
  891. &dwType,
  892. (PUCHAR) RegistryTime,
  893. &dwSize ) ||
  894. (dwType != REG_BINARY ) ||
  895. (dwSize != sizeof( LARGE_INTEGER ) ) )
  896. {
  897. RegistryTime->QuadPart = 0 ;
  898. }
  899. }
  900. *pArray = Array ;
  901. if ( ReturnFalseAnyway )
  902. {
  903. return FALSE ;
  904. }
  905. else
  906. {
  907. return TRUE ;
  908. }
  909. }
  910. PDOMAIN_CACHE_ENTRY
  911. DCacheEntryFromRegistry(
  912. PUNICODE_STRING FlatName
  913. )
  914. {
  915. PDOMAIN_CACHE_ENTRY Entry = NULL ;
  916. HKEY Key ;
  917. int err ;
  918. DWORD dwType ;
  919. WCHAR DnsName[ MAX_PATH ];
  920. DWORD dwSize ;
  921. UNICODE_STRING Dns ;
  922. err = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  923. szCache,
  924. 0,
  925. KEY_READ,
  926. &Key );
  927. if ( err == 0 )
  928. {
  929. dwSize = MAX_PATH ;
  930. DnsName[ 0 ] = L'\0';
  931. err = RegQueryValueEx(
  932. Key,
  933. FlatName->Buffer,
  934. NULL,
  935. &dwType,
  936. (PUCHAR) DnsName,
  937. &dwSize );
  938. if ( err == 0 )
  939. {
  940. if ( dwType == REG_SZ )
  941. {
  942. RtlInitUnicodeString( &Dns, DnsName );
  943. Entry = DCacheCreateEntry(
  944. ( Dns.Length ? DomainNt5 : DomainNt4 ),
  945. FlatName,
  946. ( Dns.Length ? &Dns : NULL ),
  947. NULL );
  948. }
  949. }
  950. RegCloseKey( Key );
  951. }
  952. return Entry ;
  953. }
  954. VOID
  955. DCacheWriteDomainsToCache(
  956. PDOMAIN_CACHE_ARRAY Array
  957. )
  958. {
  959. HKEY Key ;
  960. ULONG i ;
  961. ULONG Disp ;
  962. int err ;
  963. PDOMAIN_CACHE_ENTRY Entry ;
  964. LARGE_INTEGER Now ;
  965. //
  966. // Delete what's there. Ignore the error, since we are
  967. // just going to rewrite all the values, anyway.
  968. //
  969. err = RegDeleteKey( HKEY_LOCAL_MACHINE,
  970. szCache );
  971. err = RegCreateKeyEx(
  972. HKEY_LOCAL_MACHINE,
  973. szCache,
  974. 0,
  975. NULL,
  976. REG_OPTION_NON_VOLATILE,
  977. KEY_ALL_ACCESS,
  978. NULL,
  979. &Key,
  980. &Disp );
  981. if ( err )
  982. {
  983. return ;
  984. }
  985. for ( i = 0 ; i < Array->Count ; i++ )
  986. {
  987. Entry = Array->List[ i ];
  988. if ( ( Entry->Type == DomainNt5 ) )
  989. {
  990. if ( ( Entry->FlatName.Buffer == NULL ) ||
  991. ( Entry->DnsName.Buffer == NULL ) )
  992. {
  993. DebugLog(( DEB_ERROR, "Corrupt uplevel domain cache entry at %p\n", Entry ));
  994. continue;
  995. }
  996. RegSetValueEx(
  997. Key,
  998. Entry->FlatName.Buffer,
  999. 0,
  1000. REG_SZ,
  1001. (PUCHAR) Entry->DnsName.Buffer,
  1002. Entry->DnsName.Length + sizeof(WCHAR) );
  1003. }
  1004. else if ( Entry->Type == DomainNt4 )
  1005. {
  1006. if ( Entry->FlatName.Buffer == NULL )
  1007. {
  1008. DebugLog(( DEB_ERROR, "Corrupt downlevel domain cache entry at %p\n", Entry ));
  1009. }
  1010. RegSetValueEx(
  1011. Key,
  1012. Entry->FlatName.Buffer,
  1013. 0,
  1014. REG_SZ,
  1015. (PUCHAR) TEXT(""),
  1016. sizeof(WCHAR) );
  1017. }
  1018. else
  1019. {
  1020. //
  1021. // Other types don't get to live in the cache
  1022. //
  1023. NOTHING ;
  1024. }
  1025. }
  1026. RegCloseKey( Key );
  1027. GetSystemTimeAsFileTime( (LPFILETIME) &Now );
  1028. RegSetValueEx(
  1029. WinlogonKey,
  1030. szCacheUpdate,
  1031. 0,
  1032. REG_BINARY,
  1033. (PUCHAR) &Now,
  1034. sizeof( LARGE_INTEGER ) );
  1035. }
  1036. BOOL
  1037. DCacheInitialize(
  1038. VOID
  1039. )
  1040. {
  1041. DOMAIN_ENTRY_TYPE Types ;
  1042. WCHAR StringBuffer[ MAX_PATH ];
  1043. LONG Size ;
  1044. int err ;
  1045. DWORD dwSize ;
  1046. DWORD dwType ;
  1047. for (Types = 0 ; Types < DomainTypeMax ; Types++ )
  1048. {
  1049. if ( CacheDomainModifiers[ Types ].StringId )
  1050. {
  1051. Size = LoadString( hDllInstance,
  1052. CacheDomainModifiers[ Types ].StringId,
  1053. StringBuffer,
  1054. MAX_PATH );
  1055. if ( Size )
  1056. {
  1057. RtlCreateUnicodeString( &CacheDomainModifiers[ Types ].String,
  1058. StringBuffer );
  1059. }
  1060. }
  1061. }
  1062. dwSize = sizeof( CacheShowDnsNames );
  1063. err = RegQueryValueEx(
  1064. WinlogonKey,
  1065. DCACHE_SHOW_DNS_NAMES,
  1066. NULL,
  1067. &dwType,
  1068. (PUCHAR) &CacheShowDnsNames,
  1069. &dwSize );
  1070. dwSize = sizeof( CacheAppendDomainInfo );
  1071. err = RegQueryValueEx(
  1072. WinlogonKey,
  1073. DCACHE_SHOW_DOMAIN_TAGS,
  1074. NULL,
  1075. &dwType,
  1076. (PUCHAR) &CacheAppendDomainInfo,
  1077. &dwSize );
  1078. //
  1079. // Convert and delete old cache:
  1080. //
  1081. return TRUE ;
  1082. }
  1083. BOOL
  1084. DCachepInitializeCache(
  1085. PDOMAIN_CACHE pCache
  1086. )
  1087. {
  1088. NTSTATUS Status ;
  1089. ZeroMemory( pCache, sizeof(DOMAIN_CACHE) );
  1090. Status = RtlInitializeCriticalSectionAndSpinCount(
  1091. & pCache->CriticalSection,
  1092. 0x80000000 );
  1093. return NT_SUCCESS( Status );
  1094. }
  1095. PDOMAIN_CACHE
  1096. DCacheCreate(
  1097. VOID
  1098. )
  1099. {
  1100. PDOMAIN_CACHE Cache ;
  1101. Cache = (PDOMAIN_CACHE) LocalAlloc( LMEM_FIXED, sizeof( DOMAIN_CACHE ) );
  1102. if ( !Cache )
  1103. {
  1104. return NULL ;
  1105. }
  1106. if ( !DCachepInitializeCache( Cache ) )
  1107. {
  1108. LocalFree( Cache );
  1109. return NULL ;
  1110. }
  1111. Cache->State = DomainCacheEmpty ;
  1112. if ( !g_Console )
  1113. {
  1114. Cache->Flags |= DCACHE_READ_ONLY ;
  1115. }
  1116. if ( SafeBootMode == SAFEBOOT_MINIMAL )
  1117. {
  1118. Cache->Flags |= DCACHE_MIT_MODE ;
  1119. }
  1120. return Cache ;
  1121. }
  1122. BOOL
  1123. DCacheGetMinimalArray(
  1124. PDOMAIN_CACHE_ARRAY Array,
  1125. PWSTR DefaultDomain OPTIONAL,
  1126. PBOOL DomainMember OPTIONAL,
  1127. PBOOL NewDomain OPTIONAL
  1128. )
  1129. {
  1130. BOOL SidPresent = FALSE ;
  1131. UNICODE_STRING String = { 0 } ;
  1132. UNICODE_STRING DnsDomain = { 0 } ;
  1133. PDOMAIN_CACHE_ENTRY Entry = NULL ;
  1134. PDOMAIN_CACHE_ENTRY ComputerEntry = NULL ;
  1135. PDOMAIN_CACHE_ENTRY OldDefault = NULL ;
  1136. NT_PRODUCT_TYPE ProductType = NtProductWinNt;
  1137. WCHAR ComputerName[ CNLEN + 1 ];
  1138. ULONG Size ;
  1139. ULONG Type ;
  1140. WCHAR LastPrimary[ DNLEN + 1 ];
  1141. UNICODE_STRING LastPrimary_U ;
  1142. //
  1143. // First, find out what we are
  1144. //
  1145. RtlGetNtProductType( &ProductType );
  1146. if ( Array == NULL )
  1147. {
  1148. Array = DCacheCreateArray( 5, TRUE );
  1149. }
  1150. if ( Array == NULL )
  1151. {
  1152. return FALSE ;
  1153. }
  1154. if ( SafeBootMode != SAFEBOOT_MINIMAL )
  1155. {
  1156. if ( GetPrimaryDomainEx( &String, &DnsDomain, NULL, &SidPresent ) )
  1157. {
  1158. //
  1159. // Ok, we are configured to be part of a domain.
  1160. //
  1161. if ( SidPresent )
  1162. {
  1163. //
  1164. // Ok, this is an NT domain.
  1165. //
  1166. Entry = DCacheCreateEntry(
  1167. ( DnsDomain.Buffer ? DomainNt5 : DomainNt4 ),
  1168. &String,
  1169. &DnsDomain,
  1170. NULL );
  1171. if ( Entry )
  1172. {
  1173. if ( ProductType == NtProductLanManNt )
  1174. {
  1175. //
  1176. // We're a DC. Until we know otherwise, tag this as the default
  1177. //
  1178. Entry->Flags |= DCE_DEFAULT_ENTRY ;
  1179. }
  1180. DCacheInsertArray( Array, Entry );
  1181. DCacheDereferenceEntry( Entry );
  1182. Entry = NULL ;
  1183. }
  1184. //
  1185. // Check to see if we've changed domains:
  1186. //
  1187. if ( NewDomain )
  1188. {
  1189. Size = sizeof( LastPrimary );
  1190. if ( RegQueryValueEx(
  1191. WinlogonKey,
  1192. szCachePrimary,
  1193. 0,
  1194. &Type,
  1195. (PUCHAR) LastPrimary,
  1196. &Size ) == 0 )
  1197. {
  1198. RtlInitUnicodeString( &LastPrimary_U, LastPrimary );
  1199. *NewDomain = !RtlEqualUnicodeString( &LastPrimary_U,
  1200. &String,
  1201. TRUE );
  1202. }
  1203. else
  1204. {
  1205. //
  1206. // If the value can't be read for any reason, assume that it's
  1207. // missing and we're in a different domain than last time.
  1208. //
  1209. *NewDomain = TRUE ;
  1210. }
  1211. }
  1212. RegSetValueEx(
  1213. WinlogonKey,
  1214. szCachePrimary,
  1215. 0,
  1216. REG_SZ,
  1217. (PUCHAR) String.Buffer,
  1218. String.Length + sizeof(WCHAR));
  1219. }
  1220. else
  1221. {
  1222. //
  1223. // Part of an MIT realm, skip for now. It will get added
  1224. // below when all the MIT realms are added.
  1225. //
  1226. NOTHING ;
  1227. }
  1228. if ( String.Buffer )
  1229. {
  1230. LocalFree( String.Buffer );
  1231. }
  1232. if ( DnsDomain.Buffer )
  1233. {
  1234. LocalFree( DnsDomain.Buffer );
  1235. }
  1236. }
  1237. }
  1238. if ( ( ProductType != NtProductLanManNt ) ||
  1239. ( SafeBootMode == SAFEBOOT_MINIMAL ) )
  1240. {
  1241. //
  1242. // Do the machine name:
  1243. //
  1244. Size = CNLEN + 1;
  1245. GetComputerName( ComputerName, &Size );
  1246. RtlInitUnicodeString( &String, ComputerName );
  1247. ComputerEntry = DCacheCreateEntry(
  1248. DomainMachine,
  1249. &String,
  1250. NULL,
  1251. NULL );
  1252. if ( ComputerEntry )
  1253. {
  1254. DCacheInsertArray( Array, ComputerEntry );
  1255. DCacheDereferenceEntry( ComputerEntry );
  1256. }
  1257. }
  1258. DCacheAddMitRealms( Array );
  1259. if ( DefaultDomain && (*DefaultDomain) )
  1260. {
  1261. RtlInitUnicodeString( &String, DefaultDomain );
  1262. OldDefault = DCacheFindDefaultEntry( Array );
  1263. if ( Entry )
  1264. {
  1265. Entry->Flags &= ~(DCE_DEFAULT_ENTRY);
  1266. }
  1267. Entry = DCacheSearchArray( Array, &String );
  1268. if ( !Entry )
  1269. {
  1270. Entry = DCacheEntryFromRegistry( &String );
  1271. if ( Entry )
  1272. {
  1273. DCacheInsertArray( Array, Entry );
  1274. }
  1275. }
  1276. else
  1277. {
  1278. DCacheReferenceEntry( Entry );
  1279. }
  1280. if ( Entry )
  1281. {
  1282. Entry->Flags |= DCE_DEFAULT_ENTRY ;
  1283. DCacheDereferenceEntry( Entry );
  1284. if ( OldDefault )
  1285. {
  1286. OldDefault->Flags &= ~(DCE_DEFAULT_ENTRY);
  1287. }
  1288. }
  1289. }
  1290. if ( DomainMember )
  1291. {
  1292. *DomainMember = SidPresent ;
  1293. }
  1294. return TRUE ;
  1295. }
  1296. BOOL
  1297. DCacheUpdateMinimal(
  1298. PDOMAIN_CACHE Cache,
  1299. PWSTR DefaultDomain OPTIONAL,
  1300. BOOL CompleteAsync
  1301. )
  1302. {
  1303. PDOMAIN_CACHE_ARRAY Array = NULL ;
  1304. LARGE_INTEGER RegistryTime = { 0 };
  1305. BOOL DomainMember = FALSE ;
  1306. BOOL NewDomain = FALSE ;
  1307. BOOL RetryDomain = FALSE ;
  1308. BOOL NoCache = FALSE ;
  1309. BOOL StartThread = FALSE ;
  1310. HANDLE hThread ;
  1311. DWORD tid ;
  1312. WCHAR ComputerName[ 20 ];
  1313. ULONG Size ;
  1314. if ( !DCacheGetDomainsFromCache( &Array, &RegistryTime ) ||
  1315. ( Array == NULL ) )
  1316. {
  1317. NoCache = TRUE ;
  1318. }
  1319. //
  1320. // In rare events, we will leave a domain, and the cache
  1321. // will still be in the registry. This is caught later,
  1322. // and deleted, and this is the retry point.
  1323. //
  1324. ReloadWithoutCache:
  1325. if ( !Array )
  1326. {
  1327. Array = DCacheCreateArray( 5, TRUE );
  1328. if ( !Array )
  1329. {
  1330. return FALSE ;
  1331. }
  1332. }
  1333. if ( !DCacheGetMinimalArray( Array,
  1334. DefaultDomain,
  1335. &DomainMember,
  1336. &NewDomain ) )
  1337. {
  1338. DCacheFreeArray( Array );
  1339. return FALSE ;
  1340. }
  1341. //
  1342. // If we are no longer in the same domain, either in a workgroup, or
  1343. // in a different domain, toss the cache. If we just retried this
  1344. // don't keep doing it...
  1345. //
  1346. if ( ( RetryDomain == FALSE ) &&
  1347. ( ( ( NoCache == FALSE ) &&
  1348. ( DomainMember == FALSE ) ) ||
  1349. ( NewDomain == TRUE ) ) )
  1350. {
  1351. //
  1352. // Cleanup. The cache is still present, but we are no longer part of a domain
  1353. //
  1354. DCacheFreeArray( Array );
  1355. RegDeleteKey( HKEY_LOCAL_MACHINE, szCache );
  1356. RegDeleteValue( WinlogonKey, szCachePrimary );
  1357. if ( DefaultDomain )
  1358. {
  1359. Size = 20 ;
  1360. if ( GetComputerName( ComputerName, &Size ) )
  1361. {
  1362. if ( _wcsicmp( DefaultDomain, ComputerName ) )
  1363. {
  1364. DefaultDomain = NULL ;
  1365. RegSetValueEx(
  1366. WinlogonKey,
  1367. DEFAULT_DOMAIN_NAME_KEY,
  1368. 0,
  1369. REG_SZ,
  1370. (PUCHAR) ComputerName,
  1371. (Size + 1) * sizeof( WCHAR ) );
  1372. }
  1373. }
  1374. }
  1375. NoCache = TRUE ;
  1376. Array = NULL ;
  1377. RetryDomain = TRUE ;
  1378. goto ReloadWithoutCache;
  1379. }
  1380. LockDomainCache( Cache );
  1381. if ( Cache->Array )
  1382. {
  1383. DCacheFreeArray( Cache->Array );
  1384. }
  1385. Cache->Array = Array ;
  1386. Cache->RegistryUpdateTime = RegistryTime ;
  1387. if ( NoCache )
  1388. {
  1389. Cache->Flags |= DCACHE_NO_CACHE ;
  1390. }
  1391. GetSystemTimeAsFileTime( (LPFILETIME) &Cache->CacheUpdateTime );
  1392. if ( DomainMember )
  1393. {
  1394. if ( !NoCache )
  1395. {
  1396. if ( Cache->CacheUpdateTime.QuadPart - Cache->RegistryUpdateTime.QuadPart < TWO_WEEKS )
  1397. {
  1398. Cache->State = DomainCacheRegistryCache ;
  1399. }
  1400. else
  1401. {
  1402. Cache->State = DomainCacheDefaultOnly ;
  1403. }
  1404. }
  1405. else
  1406. {
  1407. Cache->State = DomainCacheDefaultOnly ;
  1408. }
  1409. Cache->Flags |= DCACHE_MEMBER ;
  1410. }
  1411. else
  1412. {
  1413. Cache->State = DomainCacheReady ;
  1414. }
  1415. if ( DCacheFindDefaultEntry( Array ) == NULL )
  1416. {
  1417. Cache->Flags |= DCACHE_DEF_UNKNOWN ;
  1418. }
  1419. if ( ( Cache->State != DomainCacheReady ) &&
  1420. ( CompleteAsync ) )
  1421. {
  1422. StartThread = TRUE ;
  1423. if ( DefaultDomain )
  1424. {
  1425. Cache->DefaultDomain = DupString( DefaultDomain );
  1426. }
  1427. else
  1428. {
  1429. Cache->DefaultDomain = NULL ;
  1430. }
  1431. }
  1432. UnlockDomainCache( Cache );
  1433. if ( StartThread )
  1434. {
  1435. hThread = CreateThread( NULL,
  1436. 0,
  1437. DCacheUpdateThread,
  1438. Cache,
  1439. 0,
  1440. &tid );
  1441. if ( hThread )
  1442. {
  1443. CloseHandle( hThread );
  1444. }
  1445. else
  1446. {
  1447. LockDomainCache( Cache );
  1448. Cache->State = DomainCacheReady ;
  1449. UnlockDomainCache( Cache );
  1450. }
  1451. }
  1452. return TRUE ;
  1453. }
  1454. BOOL
  1455. DCacheUpdateFull(
  1456. PDOMAIN_CACHE Cache,
  1457. PWSTR Default OPTIONAL
  1458. )
  1459. {
  1460. PDOMAIN_CACHE_ARRAY Array = NULL ;
  1461. ULONG NetStatus = 0 ;
  1462. ULONG RetryCount = 3 ;
  1463. BOOL DomainMember = FALSE ;
  1464. NT_PRODUCT_TYPE ProductType = NtProductWinNt;
  1465. LARGE_INTEGER RegistryTime = { 0 };
  1466. if ( ( Cache->Flags & DCACHE_MEMBER ) != 0 )
  1467. {
  1468. DomainMember = TRUE ;
  1469. RtlGetNtProductType( &ProductType );
  1470. if ( ProductType == NtProductLanManNt )
  1471. {
  1472. RetryCount = 3600 ;
  1473. }
  1474. //
  1475. // now, call netlogon, and see if it has the list.
  1476. //
  1477. NetStatus = DCacheGetTrustedDomains( &Array );
  1478. if ( NetStatus != 0 )
  1479. {
  1480. while ( RetryCount-- )
  1481. {
  1482. Sleep( 3000 );
  1483. NetStatus = DCacheGetTrustedDomains( &Array );
  1484. if ( NetStatus == 0 )
  1485. {
  1486. break;
  1487. }
  1488. }
  1489. }
  1490. if ( NetStatus != 0 )
  1491. {
  1492. //
  1493. // Try to read from the cache
  1494. //
  1495. DCacheGetDomainsFromCache( &Array, &RegistryTime );
  1496. }
  1497. }
  1498. if ( Array )
  1499. {
  1500. DCacheGetMinimalArray( Array, Default, &DomainMember, NULL );
  1501. }
  1502. if ( Array )
  1503. {
  1504. LockDomainCache( Cache );
  1505. if ( Cache->Array )
  1506. {
  1507. DCacheFreeArray( Cache->Array );
  1508. }
  1509. Cache->Array = Array ;
  1510. if ( DomainMember )
  1511. {
  1512. Cache->Flags |= DCACHE_MEMBER ;
  1513. }
  1514. else
  1515. {
  1516. Cache->Flags &= ~( DCACHE_MEMBER ) ;
  1517. }
  1518. if ( NetStatus == 0 )
  1519. {
  1520. Cache->State = DomainCacheReady ;
  1521. if ( ( Cache->Flags & DCACHE_READ_ONLY ) == 0 )
  1522. {
  1523. DCacheWriteDomainsToCache( Array );
  1524. }
  1525. GetSystemTimeAsFileTime( (LPFILETIME) &Cache->RegistryUpdateTime );
  1526. Cache->Flags &= ~(DCACHE_NO_CACHE);
  1527. }
  1528. else if ( (Cache->Flags & DCACHE_NO_CACHE) == 0 )
  1529. {
  1530. Cache->State = DomainCacheRegistryCache ;
  1531. Cache->RegistryUpdateTime = RegistryTime ;
  1532. }
  1533. else
  1534. {
  1535. Cache->State = DomainCacheDefaultOnly ;
  1536. Cache->RegistryUpdateTime.QuadPart = 0 ;
  1537. }
  1538. if ( Cache->DefaultDomain )
  1539. {
  1540. DCacheSetDefaultEntry( Cache,
  1541. Cache->DefaultDomain,
  1542. NULL );
  1543. Free( Cache->DefaultDomain );
  1544. Cache->DefaultDomain = NULL ;
  1545. }
  1546. UnlockDomainCache( Cache );
  1547. }
  1548. return ( Array != NULL ) ;
  1549. }
  1550. DWORD
  1551. DCacheUpdateThread(
  1552. PDOMAIN_CACHE Cache
  1553. )
  1554. {
  1555. HWND Notify ;
  1556. UINT Message ;
  1557. LockDomainCache( Cache );
  1558. if ( ( Cache->Flags & DCACHE_ASYNC_UPDATE ) != 0 )
  1559. {
  1560. //
  1561. // Another thread is already doing this.
  1562. //
  1563. UnlockDomainCache( Cache );
  1564. return 0 ;
  1565. }
  1566. Cache->Flags |= DCACHE_ASYNC_UPDATE ;
  1567. UnlockDomainCache( Cache );
  1568. DCacheUpdateFull( Cache, NULL );
  1569. LockDomainCache( Cache );
  1570. Notify = Cache->UpdateNotifyWindow ;
  1571. Message = Cache->Message ;
  1572. Cache->UpdateNotifyWindow = NULL ;
  1573. Cache->Message = 0 ;
  1574. Cache->Flags &= ~( DCACHE_ASYNC_UPDATE );
  1575. UnlockDomainCache( Cache );
  1576. if ( Notify )
  1577. {
  1578. DebugLog(( DEB_TRACE_CACHE, "Notifying window %x of cache complete\n" ));
  1579. PostMessage( Notify, Message, 0, 0 );
  1580. }
  1581. return 0;
  1582. }
  1583. BOOL
  1584. DCachePopulateListBoxFromArray(
  1585. PDOMAIN_CACHE_ARRAY Array,
  1586. HWND ComboBox,
  1587. LPWSTR LastKey OPTIONAL
  1588. )
  1589. {
  1590. ULONG i ;
  1591. ULONG_PTR Index ;
  1592. PDOMAIN_CACHE_ENTRY Default = NULL ;
  1593. LRESULT Result ;
  1594. //
  1595. // Reset the combo box
  1596. //
  1597. DebugLog((DEB_TRACE_CACHE, "Flushing listbox\n" ));
  1598. SendMessage( ComboBox, CB_RESETCONTENT, 0, 0);
  1599. for ( i = 0 ; i < Array->Count ; i++ )
  1600. {
  1601. DebugLog(( DEB_TRACE_CACHE, "Adding domain %ws (%d) to listbox\n",
  1602. Array->List[ i ]->DisplayName.Buffer,
  1603. Array->List[ i ]->Type ));
  1604. if ( Array->List[ i ]->Type == DomainMitRealm )
  1605. {
  1606. if ( (Array->List[ i ]->Flags & DCE_REACHABLE_MIT ) == 0 )
  1607. {
  1608. DebugLog(( DEB_TRACE_CACHE, "MIT Realm %ws is not reachable, skipping\n",
  1609. Array->List[ i ]->FlatName.Buffer ));
  1610. continue;
  1611. }
  1612. }
  1613. Index = SendMessage( ComboBox,
  1614. CB_ADDSTRING,
  1615. 0,
  1616. (LPARAM) Array->List[ i ]->DisplayName.Buffer );
  1617. if ( Index != CB_ERR )
  1618. {
  1619. SendMessage( ComboBox,
  1620. CB_SETITEMDATA,
  1621. (WPARAM) Index,
  1622. (LPARAM) Array->List[ i ] );
  1623. }
  1624. if ( ( Array->List[ i ]->Type == DomainMachine ) &&
  1625. ( Default == NULL ) )
  1626. {
  1627. Default = Array->List[ i ] ;
  1628. }
  1629. if ( Array->List[ i ]->Flags & DCE_DEFAULT_ENTRY )
  1630. {
  1631. Default = Array->List[ i ];
  1632. }
  1633. }
  1634. //
  1635. // Select the default entry:
  1636. //
  1637. if ( LastKey && (*LastKey) )
  1638. {
  1639. Result = SendMessage( ComboBox,
  1640. CB_SELECTSTRING,
  1641. (WPARAM) -1,
  1642. (LPARAM) LastKey );
  1643. #if DBG
  1644. if ( Result != CB_ERR )
  1645. {
  1646. DebugLog(( DEB_TRACE_CACHE, "Selected first entry starting with %ws\n", LastKey ));
  1647. }
  1648. else
  1649. {
  1650. DebugLog(( DEB_TRACE_CACHE, "No entry found starting with %ws. Trying default\n", LastKey ));
  1651. }
  1652. #endif
  1653. }
  1654. else
  1655. {
  1656. Result = CB_ERR ;
  1657. }
  1658. if ( ( Result == CB_ERR ) &&
  1659. ( Default != NULL ) )
  1660. {
  1661. SendMessage( ComboBox,
  1662. CB_SELECTSTRING,
  1663. (WPARAM) -1,
  1664. (LPARAM) Default->DisplayName.Buffer );
  1665. DebugLog(( DEB_TRACE_CACHE, "Selecting '%ws' as the default entry\n",
  1666. Default->DisplayName.Buffer ));
  1667. }
  1668. return TRUE ;
  1669. }
  1670. BOOL
  1671. DCacheSetNotifyWindowIfNotReady(
  1672. PDOMAIN_CACHE Cache,
  1673. HWND Window,
  1674. UINT Message
  1675. )
  1676. {
  1677. BOOL IsReady = FALSE ;
  1678. HANDLE hThread ;
  1679. DWORD tid ;
  1680. LockDomainCache( Cache );
  1681. IsReady = ( Cache->State == DomainCacheReady );
  1682. if ( !IsReady )
  1683. {
  1684. Cache->UpdateNotifyWindow = Window ;
  1685. Cache->Message = Message ;
  1686. }
  1687. else
  1688. {
  1689. if ( ( Cache->Flags & DCACHE_ASYNC_UPDATE ) == 0 )
  1690. {
  1691. hThread = CreateThread( NULL,
  1692. 0,
  1693. DCacheUpdateThread,
  1694. Cache,
  1695. 0,
  1696. &tid );
  1697. }
  1698. }
  1699. UnlockDomainCache( Cache );
  1700. return IsReady ;
  1701. }
  1702. PDOMAIN_CACHE_ARRAY
  1703. DCacheCopyCacheArray(
  1704. PDOMAIN_CACHE Cache
  1705. )
  1706. {
  1707. PDOMAIN_CACHE_ARRAY Array = NULL ;
  1708. LockDomainCache( Cache );
  1709. if ( Cache->Array )
  1710. {
  1711. Array = DCacheCopyArray( Cache->Array );
  1712. }
  1713. UnlockDomainCache( Cache );
  1714. return Array ;
  1715. }
  1716. BOOL
  1717. DCacheValidateCache(
  1718. PDOMAIN_CACHE Cache
  1719. )
  1720. {
  1721. LARGE_INTEGER Now ;
  1722. LARGE_INTEGER Diff ;
  1723. LockDomainCache( Cache );
  1724. GetSystemTimeAsFileTime( (LPFILETIME) &Now );
  1725. Diff.QuadPart = Now.QuadPart - Cache->CacheUpdateTime.QuadPart ;
  1726. UnlockDomainCache( Cache );
  1727. return (Diff.QuadPart < TWO_MINUTES );
  1728. }
  1729. DOMAIN_CACHE_STATE
  1730. DCacheGetCacheState(
  1731. PDOMAIN_CACHE Cache
  1732. )
  1733. {
  1734. DOMAIN_CACHE_STATE State ;
  1735. LockDomainCache( Cache );
  1736. State = Cache->State ;
  1737. UnlockDomainCache( Cache );
  1738. return State ;
  1739. }
  1740. BOOL
  1741. DCacheSetDefaultEntry(
  1742. PDOMAIN_CACHE Cache,
  1743. PWSTR FlatName OPTIONAL,
  1744. PWSTR DnsName OPTIONAL
  1745. )
  1746. {
  1747. UNICODE_STRING String ;
  1748. PDOMAIN_CACHE_ENTRY Entry ;
  1749. BOOL Result ;
  1750. if ( ( FlatName == NULL ) &&
  1751. ( DnsName == NULL ) )
  1752. {
  1753. return FALSE ;
  1754. }
  1755. LockDomainCache( Cache );
  1756. Entry = DCacheFindDefaultEntry( Cache->Array );
  1757. if ( Entry )
  1758. {
  1759. Entry->Flags &= ~(DCE_DEFAULT_ENTRY) ;
  1760. }
  1761. if ( FlatName )
  1762. {
  1763. RtlInitUnicodeString( &String, FlatName );
  1764. Entry = DCacheSearchArray( Cache->Array,
  1765. &String );
  1766. }
  1767. else
  1768. {
  1769. RtlInitUnicodeString( &String, DnsName );
  1770. Entry = DCacheSearchArrayByDns( Cache->Array,
  1771. &String );
  1772. }
  1773. if ( Entry )
  1774. {
  1775. Entry->Flags |= DCE_DEFAULT_ENTRY ;
  1776. Result = TRUE ;
  1777. DebugLog(( DEB_TRACE_CACHE, "Setting '%ws' to be the default\n",
  1778. Entry->DisplayName.Buffer ));
  1779. }
  1780. else
  1781. {
  1782. Result = FALSE ;
  1783. }
  1784. if ( Result )
  1785. {
  1786. Cache->Flags &= ~(DCACHE_DEF_UNKNOWN) ;
  1787. }
  1788. else
  1789. {
  1790. Cache->Flags |= DCACHE_DEF_UNKNOWN ;
  1791. }
  1792. UnlockDomainCache( Cache );
  1793. return Result ;
  1794. }
  1795. PDOMAIN_CACHE_ENTRY
  1796. DCacheLocateEntry(
  1797. PDOMAIN_CACHE Cache,
  1798. PWSTR Domain
  1799. )
  1800. {
  1801. PDOMAIN_CACHE_ENTRY Entry = NULL ;
  1802. UNICODE_STRING String ;
  1803. LockDomainCache( Cache );
  1804. if ( Domain )
  1805. {
  1806. RtlInitUnicodeString( &String, Domain );
  1807. Entry = DCacheSearchArray( Cache->Array,
  1808. &String );
  1809. if ( Entry )
  1810. {
  1811. DCacheReferenceEntry( Entry );
  1812. }
  1813. }
  1814. UnlockDomainCache( Cache );
  1815. return Entry ;
  1816. }
  1817. ULONG
  1818. DCacheGetFlags(
  1819. PDOMAIN_CACHE Cache
  1820. )
  1821. {
  1822. ULONG Flags ;
  1823. LockDomainCache( Cache );
  1824. Flags = Cache->Flags ;
  1825. UnlockDomainCache( Cache );
  1826. return Flags ;
  1827. }