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.

1194 lines
30 KiB

  1. //+-----------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (c) Microsoft Corporation 1992 - 1996
  6. //
  7. // File: rpcutil.cxx
  8. //
  9. // Contents: Utilities for RPC for Kerberos package
  10. //
  11. //
  12. // History: 19-April-1996 Created MikeSw
  13. //
  14. //------------------------------------------------------------------------
  15. #include <kerb.hxx>
  16. #include <kerbp.h>
  17. #ifdef RETAIL_LOG_SUPPORT
  18. static TCHAR THIS_FILE[]=TEXT(__FILE__);
  19. #endif
  20. extern "C"
  21. {
  22. #include <lmaccess.h>
  23. #include <lmapibuf.h>
  24. #include <lmerr.h>
  25. #ifndef WIN32_CHICAGO
  26. #include <netlibnt.h>
  27. #endif // WIN32_CHICAGO
  28. }
  29. SOCKET KerbPNPSocket;
  30. HANDLE KerbPNPSocketEvent = NULL;
  31. HANDLE KerbPNPSocketWaitHandle = NULL;
  32. #ifndef WIN32_CHICAGO
  33. // The problem here is that we need to read the domain info once after
  34. // joining domain. (for rebootless join) and once after the reboot
  35. // (if there was one). We can only delete the data after a reboot.
  36. // This one controls whether I read the domain info that JoinDomain dumps
  37. // in the registry.
  38. BOOLEAN fNewDataAboutDomain = TRUE;
  39. // This one controls when I should delete the domain info that JoinDomain
  40. // dumps in the registry
  41. BOOLEAN fRebootedSinceJoin = TRUE;
  42. RTL_CRITICAL_SECTION KerbCallKdcDataLock;
  43. BOOLEAN KerbCallKdcDataInitialized = FALSE;
  44. #define KerbLockKdcData() (RtlEnterCriticalSection(&KerbCallKdcDataLock))
  45. #define KerbUnlockKdcData() (RtlLeaveCriticalSection(&KerbCallKdcDataLock))
  46. #endif // WIN32_CHICAGO
  47. #ifndef WIN32_CHICAGO
  48. NTSTATUS
  49. KerbInitKdcData()
  50. {
  51. NTSTATUS Status = STATUS_SUCCESS;
  52. if (!KerbCallKdcDataInitialized)
  53. {
  54. Status = RtlInitializeCriticalSection(&KerbCallKdcDataLock);
  55. if (!NT_SUCCESS(Status))
  56. {
  57. goto Cleanup;
  58. }
  59. KerbCallKdcDataInitialized = TRUE;
  60. }
  61. Cleanup:
  62. return Status;
  63. }
  64. VOID
  65. KerbFreeKdcData()
  66. {
  67. if (KerbCallKdcDataInitialized)
  68. {
  69. RtlDeleteCriticalSection(&KerbCallKdcDataLock);
  70. KerbCallKdcDataInitialized = FALSE;
  71. }
  72. }
  73. VOID
  74. KerbSetKdcData(BOOLEAN fNewDomain, BOOLEAN fRebooted)
  75. {
  76. KerbLockKdcData();
  77. fNewDataAboutDomain = fNewDomain;
  78. fRebootedSinceJoin = fRebooted;
  79. KerbUnlockKdcData();
  80. }
  81. #endif // WIN32_CHICAGO
  82. //+-------------------------------------------------------------------------
  83. //
  84. // Function: MIDL_user_allocate
  85. //
  86. // Synopsis: Allocation routine for use by RPC client stubs
  87. //
  88. // Effects: allocates memory with LsaFunctions.AllocateLsaHeap
  89. //
  90. // Arguments: BufferSize - size of buffer, in bytes, to allocate
  91. //
  92. // Requires:
  93. //
  94. // Returns: Buffer pointer or NULL on allocation failure
  95. //
  96. // Notes:
  97. //
  98. //
  99. //--------------------------------------------------------------------------
  100. PVOID
  101. MIDL_user_allocate(
  102. IN size_t BufferSize
  103. )
  104. {
  105. return(KerbAllocate( ROUND_UP_COUNT(BufferSize, 8) ) );
  106. }
  107. //+-------------------------------------------------------------------------
  108. //
  109. // Function: MIDL_user_free
  110. //
  111. // Synopsis: Memory free routine for RPC client stubs
  112. //
  113. // Effects: frees the buffer with LsaFunctions.FreeLsaHeap
  114. //
  115. // Arguments: Buffer - Buffer to free
  116. //
  117. // Requires:
  118. //
  119. // Returns: none
  120. //
  121. // Notes:
  122. //
  123. //
  124. //--------------------------------------------------------------------------
  125. VOID
  126. MIDL_user_free(
  127. IN PVOID Buffer
  128. )
  129. {
  130. KerbFree( Buffer );
  131. }
  132. #ifndef WIN32_CHICAGO
  133. #define NETSETUPP_NETLOGON_PARAMETERS \
  134. L"SYSTEM\\CurrentControlSet\\Services\\Netlogon\\Parameters"
  135. #define NETSETUPP_NETLOGON_KERB_JD\
  136. L"KerbIsDoneWithJoinDomainEntry"
  137. #define NETSETUPP_NETLOGON_JD \
  138. L"SYSTEM\\CurrentControlSet\\Services\\Netlogon\\JoinDomain"
  139. #define NETSETUPP_NETLOGON_JD_DCA L"DomainControllerAddress"
  140. #define NETSETUPP_NETLOGON_JD_DCAT L"DomainControllerAddressType"
  141. #define NETSETUPP_NETLOGON_JD_F L"Flags"
  142. BOOLEAN
  143. ReadInitialDcRecord(PUNICODE_STRING uString,
  144. PULONG RegAddressType,
  145. PULONG RegFlags)
  146. {
  147. ULONG WinError = ERROR_SUCCESS;
  148. HKEY hJoinKey = NULL, hParametersKey = NULL;
  149. ULONG Flags = 0, AddressType = 0, KdcNameSize = 0, dwTRUE = 1, Type =0;
  150. LPWSTR KdcName = NULL;
  151. BOOLEAN fReadCache = FALSE;
  152. ULONG dwsize = sizeof(ULONG);
  153. USHORT TempLen = 0;
  154. RtlInitUnicodeString(
  155. uString,
  156. NULL
  157. );
  158. *RegAddressType = 0;
  159. *RegFlags = 0;
  160. WinError = RegOpenKey( HKEY_LOCAL_MACHINE,
  161. NETSETUPP_NETLOGON_JD,
  162. &hJoinKey);
  163. if ( WinError != ERROR_SUCCESS) {
  164. goto Cleanup;
  165. }
  166. WinError = RegQueryValueEx( hJoinKey,
  167. NETSETUPP_NETLOGON_JD_DCA,
  168. 0,
  169. &Type,
  170. NULL,
  171. &KdcNameSize);
  172. if ( WinError != ERROR_SUCCESS) {
  173. goto Cleanup;
  174. }
  175. KdcName = (LPWSTR) KerbAllocate(KdcNameSize);
  176. if (KdcName == NULL)
  177. {
  178. goto Cleanup;
  179. }
  180. WinError = RegQueryValueEx( hJoinKey,
  181. NETSETUPP_NETLOGON_JD_DCA,
  182. 0,
  183. &Type,
  184. (PUCHAR) KdcName,
  185. &KdcNameSize);
  186. if ( WinError != ERROR_SUCCESS) {
  187. goto Cleanup;
  188. }
  189. WinError = RegQueryValueEx( hJoinKey,
  190. NETSETUPP_NETLOGON_JD_DCAT,
  191. 0,
  192. &Type,
  193. (PUCHAR)&AddressType,
  194. &dwsize );
  195. if ( WinError != ERROR_SUCCESS) {
  196. goto Cleanup;
  197. }
  198. WinError = RegQueryValueEx( hJoinKey,
  199. NETSETUPP_NETLOGON_JD_F,
  200. 0,
  201. &Type,
  202. (PUCHAR)&Flags,
  203. &dwsize);
  204. if ( WinError != ERROR_SUCCESS) {
  205. goto Cleanup;
  206. }
  207. TempLen = (USHORT)wcslen(KdcName+2);
  208. uString->Buffer = (PWSTR) KerbAllocate ((TempLen + 1) *sizeof(WCHAR));
  209. if (uString->Buffer == NULL)
  210. {
  211. goto Cleanup;
  212. }
  213. wcscpy(uString->Buffer,
  214. KdcName+2);
  215. uString->Length = TempLen * sizeof(WCHAR);
  216. uString->MaximumLength = uString->Length + sizeof(WCHAR);
  217. uString->Buffer[TempLen] = L'\0';
  218. *RegAddressType = AddressType;
  219. *RegFlags = Flags;
  220. // Now set the reg entry so that netlogon knows that we've read it.
  221. if (fRebootedSinceJoin)
  222. {
  223. WinError = RegOpenKey( HKEY_LOCAL_MACHINE,
  224. NETSETUPP_NETLOGON_PARAMETERS,
  225. &hParametersKey);
  226. if ( WinError != ERROR_SUCCESS) {
  227. goto Cleanup;
  228. }
  229. WinError = RegSetValueEx( hParametersKey,
  230. NETSETUPP_NETLOGON_KERB_JD,
  231. 0,
  232. REG_DWORD,
  233. (PUCHAR)&dwTRUE,
  234. sizeof(DWORD));
  235. if ( WinError != ERROR_SUCCESS) {
  236. goto Cleanup;
  237. }
  238. DebugLog((DEB_ERROR, "Setting DoneWJoin key!\n"));
  239. }
  240. fReadCache = TRUE;
  241. Cleanup:
  242. KerbSetKdcData(FALSE, fRebootedSinceJoin);
  243. if (hJoinKey)
  244. {
  245. RegCloseKey( hJoinKey );
  246. }
  247. if (hParametersKey)
  248. {
  249. RegCloseKey( hParametersKey );
  250. }
  251. if (KdcName)
  252. {
  253. KerbFree(KdcName);
  254. }
  255. return (fReadCache);
  256. }
  257. #endif // WIN32_CHICAGO
  258. //+-------------------------------------------------------------------------
  259. //
  260. // Function: KerbSocketChangeHandler
  261. //
  262. // Synopsis: Simply setups up a WSA Pnp event, so that we catch network
  263. // changes.
  264. //
  265. // Effects:
  266. //
  267. // Arguments:
  268. //
  269. // Requires:
  270. //
  271. // Returns:
  272. //
  273. // Notes:
  274. //
  275. //
  276. //--------------------------------------------------------------------------
  277. VOID
  278. KerbSocketChangeHandler(
  279. VOID* Context,
  280. BOOLEAN WaitStatus
  281. )
  282. {
  283. WSAPROTOCOL_INFO *lpProtocolBuf = NULL;
  284. DWORD dwBufLen = 0;
  285. INT protocols[2];
  286. int nRet = 0;
  287. NTSTATUS Status;
  288. NET_API_STATUS NetStatus;
  289. //
  290. // Determine if TCP is installed.
  291. //
  292. protocols[0] = IPPROTO_TCP;
  293. protocols[1] = NULL;
  294. nRet = WSAEnumProtocols(protocols, lpProtocolBuf, &dwBufLen);
  295. KerbGlobalWriteLock();
  296. if (nRet == 0)
  297. {
  298. D_DebugLog((DEB_TRACE, "Turning OFF! TCP %x\n", nRet));
  299. KerbGlobalNoTcpUdp = TRUE;
  300. }
  301. else
  302. {
  303. KerbGlobalNoTcpUdp = FALSE;
  304. if (nRet == SOCKET_ERROR)
  305. {
  306. nRet = WSAGetLastError();
  307. }
  308. D_DebugLog((DEB_TRACE, "Turning on TCP %x\n", nRet));
  309. }
  310. KerbGlobalReleaseLock();
  311. //
  312. // Re-Register the wait - but make sure the values are init'd / correct.
  313. //
  314. KerbLockKdcData();
  315. if ( KerbPNPSocketWaitHandle && KerbPNPSocketEvent )
  316. {
  317. NetStatus = WSAEventSelect(
  318. KerbPNPSocket,
  319. KerbPNPSocketEvent,
  320. FD_ADDRESS_LIST_CHANGE
  321. );
  322. if ( NetStatus != 0 )
  323. {
  324. NetStatus = WSAGetLastError();
  325. DebugLog(( DEB_ERROR, "Can't WSAEventSelect %ld\n", NetStatus ));
  326. }
  327. Status = RtlRegisterWait(
  328. &KerbPNPSocketWaitHandle,
  329. KerbPNPSocketEvent,
  330. KerbSocketChangeHandler,
  331. NULL,
  332. INFINITE,
  333. WT_EXECUTEDEFAULT | WT_EXECUTEONLYONCE
  334. );
  335. if (!NT_SUCCESS( Status ))
  336. {
  337. DebugLog((DEB_ERROR, "RtlRegisterWait failed %x\n", Status));
  338. }
  339. //
  340. // Issue the IOCTL, so we'll get notified.
  341. //
  342. NetStatus = WSAIoctl(
  343. KerbPNPSocket,
  344. SIO_ADDRESS_LIST_CHANGE,
  345. NULL, // No input buffer
  346. 0, // No input buffer
  347. NULL, // No output buffer
  348. 0, // No output buffer
  349. &dwBufLen,
  350. NULL, // No overlapped,
  351. NULL // Not async
  352. );
  353. if ( NetStatus != 0 )
  354. {
  355. NetStatus = WSAGetLastError();
  356. if ( NetStatus != WSAEWOULDBLOCK)
  357. {
  358. DebugLog((DEB_ERROR, "WSAIOCTL failed %x\n", NetStatus));
  359. Status = STATUS_INTERNAL_ERROR;
  360. }
  361. }
  362. }
  363. KerbUnlockKdcData();
  364. KerbCleanupBindingCache(FALSE);
  365. }
  366. //+-------------------------------------------------------------------------
  367. //
  368. // Function: KerbInitNetworkChangeEvent
  369. //
  370. // Synopsis: Simply setups up a WSA Pnp event, so that we catch network
  371. // changes.
  372. //
  373. // Effects:
  374. //
  375. // Arguments:
  376. //
  377. // Requires:
  378. //
  379. // Returns:
  380. //
  381. // Notes:
  382. //
  383. //
  384. //--------------------------------------------------------------------------
  385. NTSTATUS
  386. KerbInitNetworkChangeEvent()
  387. {
  388. NET_API_STATUS NetStatus;
  389. NTSTATUS Status = STATUS_INTERNAL_ERROR;
  390. DWORD BytesReturned;
  391. KerbLockKdcData();
  392. if ( KerbPNPSocket != NULL )
  393. {
  394. goto Cleanup;
  395. }
  396. //
  397. // Open a socket to get winsock PNP notifications on.
  398. //
  399. KerbPNPSocket = WSASocket(
  400. AF_INET,
  401. SOCK_DGRAM,
  402. 0, // PF_INET,
  403. NULL,
  404. 0,
  405. 0
  406. );
  407. if ( KerbPNPSocket == INVALID_SOCKET )
  408. {
  409. NetStatus = WSAGetLastError();
  410. DebugLog(( DEB_ERROR, "Can't WSASocket %ld\n", NetStatus ));
  411. if ( NetStatus == WSAEAFNOSUPPORT )
  412. {
  413. Status = STATUS_SUCCESS;
  414. goto Cleanup;
  415. }
  416. goto Cleanup;
  417. }
  418. //
  419. // Open an event to wait on.
  420. //
  421. KerbPNPSocketEvent = CreateEvent(
  422. NULL, // No security ettibutes
  423. FALSE, // Auto reset
  424. FALSE, // Initially not signaled
  425. NULL
  426. );
  427. if ( KerbPNPSocketEvent == NULL )
  428. {
  429. DebugLog(( DEB_ERROR,"Cannot create Winsock PNP event %ld\n", GetLastError() ));
  430. Status = STATUS_INTERNAL_ERROR;
  431. goto Cleanup;
  432. }
  433. NetStatus = WSAEventSelect(
  434. KerbPNPSocket,
  435. KerbPNPSocketEvent,
  436. FD_ADDRESS_LIST_CHANGE
  437. );
  438. if ( NetStatus != 0 )
  439. {
  440. NetStatus = WSAGetLastError();
  441. DebugLog(( DEB_ERROR, "Can't WSAEventSelect %ld\n", NetStatus ));
  442. goto Cleanup;
  443. }
  444. //
  445. // Register a wait.
  446. //
  447. Status = RtlRegisterWait(
  448. &KerbPNPSocketWaitHandle,
  449. KerbPNPSocketEvent,
  450. KerbSocketChangeHandler,
  451. NULL,
  452. INFINITE,
  453. WT_EXECUTEDEFAULT | WT_EXECUTEONLYONCE
  454. );
  455. if (!NT_SUCCESS( Status ))
  456. {
  457. DebugLog((DEB_ERROR, "RtlRegisterWait failed %x\n", Status));
  458. goto Cleanup;
  459. }
  460. //
  461. // Issue the IOCTL, so we'll get notified.
  462. //
  463. NetStatus = WSAIoctl(
  464. KerbPNPSocket,
  465. SIO_ADDRESS_LIST_CHANGE,
  466. NULL, // No input buffer
  467. 0, // No input buffer
  468. NULL, // No output buffer
  469. 0, // No output buffer
  470. &BytesReturned,
  471. NULL, // No overlapped,
  472. NULL // Not async
  473. );
  474. if ( NetStatus != 0 )
  475. {
  476. NetStatus = WSAGetLastError();
  477. if ( NetStatus != WSAEWOULDBLOCK) {
  478. DebugLog((DEB_ERROR, "WSAIOCTL failed %x\n", NetStatus));
  479. Status = STATUS_INTERNAL_ERROR;
  480. }
  481. }
  482. Cleanup:
  483. if (!NT_SUCCESS( Status ))
  484. {
  485. if ( KerbPNPSocketWaitHandle )
  486. {
  487. RtlDeregisterWait(KerbPNPSocketWaitHandle);
  488. KerbPNPSocketWaitHandle = NULL;
  489. }
  490. if ( KerbPNPSocketEvent )
  491. {
  492. CloseHandle( KerbPNPSocketEvent );
  493. KerbPNPSocketEvent = NULL;
  494. }
  495. if ( KerbPNPSocket )
  496. {
  497. closesocket( KerbPNPSocket );
  498. KerbPNPSocket = NULL;
  499. }
  500. }
  501. KerbUnlockKdcData();
  502. return Status;
  503. }
  504. //
  505. // This address type is used for talking to MIT KDCs
  506. //
  507. #define DS_UNKNOWN_ADDRESS_TYPE 0
  508. //+-------------------------------------------------------------------------
  509. //
  510. // Function: KerbGetKdcBinding
  511. //
  512. // Synopsis: Gets a binding to the KDC in the specified domain
  513. //
  514. // Effects:
  515. //
  516. // Arguments: Realm - Domain in which to find KDC
  517. // PrincipalName - name of a principal that must be on the KDC
  518. // DesiredFlags - Flags to pass to the locator.
  519. // FindKpasswd - if domain is an MIT realm, then returns Kpasswd
  520. // addresses instead of KDC addresses KDC
  521. // BindingCacheEntry - receives binding handle cache entry for
  522. // TCP to the KDC
  523. //
  524. // Requires:
  525. //
  526. // Returns: RPC errors, NET API errors
  527. //
  528. // Notes:
  529. //
  530. //
  531. //--------------------------------------------------------------------------
  532. NTSTATUS
  533. KerbGetKdcBinding(
  534. IN PUNICODE_STRING RealmName,
  535. IN OPTIONAL PUNICODE_STRING PrincipalName,
  536. IN ULONG DesiredFlags,
  537. IN BOOLEAN FindKpasswd,
  538. IN BOOLEAN UseTcp,
  539. OUT PKERB_BINDING_CACHE_ENTRY * BindingCacheEntry
  540. )
  541. {
  542. NTSTATUS Status = STATUS_NETLOGON_NOT_STARTED;
  543. NTSTATUS TempStatus = STATUS_SUCCESS;
  544. LPWSTR DomainName = NULL;
  545. LPWSTR AccountName = NULL;
  546. ULONG NetStatus = 0;
  547. ULONG AddressType = DS_INET_ADDRESS;
  548. UNICODE_STRING KdcNameString = {0};
  549. PDOMAIN_CONTROLLER_INFOW DcInfo = NULL;
  550. PKERB_MIT_REALM MitRealm = NULL;
  551. BOOLEAN UsedAlternateName;
  552. BOOLEAN CacheDc = FALSE;
  553. BOOLEAN CalledNetlogonDirectly = FALSE;
  554. KERBEROS_MACHINE_ROLE Role;
  555. ULONG ActualFlags = 0;
  556. ULONG CacheFlags = 0, DcFlags = 0;
  557. #ifndef WIN32_CHICAGO
  558. ULONG CachedAddressType = DS_INET_ADDRESS;
  559. ULONG CachedFlags = 0;
  560. UNICODE_STRING CachedKdcNameString = {0};
  561. UNICODE_STRING LocalMachineName;
  562. #endif // WIN32_CHICAGO
  563. Role = KerbGetGlobalRole();
  564. #ifndef WIN32_CHICAGO
  565. LocalMachineName.Buffer = NULL;
  566. KerbGlobalReadLock();
  567. //
  568. // use TempStatus to retain initial Status value.
  569. //
  570. TempStatus = KerbDuplicateString( &LocalMachineName, &KerbGlobalMachineName );
  571. KerbGlobalReleaseLock();
  572. if(!NT_SUCCESS(TempStatus))
  573. {
  574. DebugLog((DEB_ERROR, "Failed to duplicate KerbGlobalMachineName\n"));
  575. Status = TempStatus;
  576. goto Cleanup;
  577. }
  578. if ((Role != KerbRoleDomainController) &&
  579. (RtlEqualDomainName(
  580. RealmName,
  581. &LocalMachineName
  582. )))
  583. {
  584. //
  585. // This is an attempt at a local logon on a workstation. We don't do that.
  586. //
  587. DebugLog((DEB_WARN, "Attempting to locate a KDC for the workstation - failing\n"));
  588. Status = STATUS_NO_LOGON_SERVERS;
  589. goto Cleanup;
  590. }
  591. //
  592. // If we are logging on for the first time after join domain, the
  593. // following registry entry should exist.
  594. // Cache that entry, we should try to get to that dc.
  595. // Don't cache the entry if we are a dc
  596. // Don't cache the entry if this is not for our domain
  597. //
  598. if ( fNewDataAboutDomain &&
  599. KerbGlobalRole != KerbRoleDomainController)
  600. {
  601. if (ReadInitialDcRecord(&CachedKdcNameString, &CachedAddressType, &CachedFlags))
  602. {
  603. KerbFreeString(&KerbGlobalInitialDcRecord);
  604. RtlInitUnicodeString(
  605. &KerbGlobalInitialDcRecord,
  606. CachedKdcNameString.Buffer
  607. );
  608. KerbGlobalInitialDcAddressType = CachedAddressType;
  609. KerbGlobalInitialDcFlags = CachedFlags;
  610. CacheDc = TRUE;
  611. }
  612. else if (KerbGlobalInitialDcRecord.Buffer != NULL)
  613. {
  614. CacheDc = TRUE;
  615. }
  616. if (CacheDc && KerbIsThisOurDomain( RealmName))
  617. {
  618. PKERB_BINDING_CACHE_ENTRY TempBindingCacheEntry = NULL;
  619. TempStatus = KerbCacheBinding(
  620. RealmName,
  621. &KerbGlobalInitialDcRecord,
  622. KerbGlobalInitialDcAddressType,
  623. DesiredFlags,
  624. KerbGlobalInitialDcFlags,
  625. 0,
  626. &TempBindingCacheEntry
  627. );
  628. if ( TempBindingCacheEntry ) {
  629. KerbDereferenceBindingCacheEntry( TempBindingCacheEntry );
  630. }
  631. KerbFreeString(&KerbGlobalInitialDcRecord);
  632. }
  633. }
  634. #endif // WIN32_CHICAGO
  635. //
  636. // Check the cache if we don't want to force rediscovery
  637. //
  638. if ((DesiredFlags & DS_FORCE_REDISCOVERY) == 0)
  639. {
  640. *BindingCacheEntry = KerbLocateBindingCacheEntry(
  641. RealmName,
  642. DesiredFlags,
  643. FALSE
  644. );
  645. if (NULL != *BindingCacheEntry)
  646. {
  647. //
  648. // For realmless workstations, we add negative cache entries.
  649. // This is because the netlogon service doesn't run on non-joined
  650. // machines, so we don't have the benefit of its negative caching.
  651. // The end result is that we need to do that ourselves.
  652. //
  653. if (( Role == KerbRoleRealmlessWksta ) &&
  654. (( (*BindingCacheEntry)->CacheFlags & KERB_BINDING_NEGATIVE_ENTRY ) != 0))
  655. {
  656. DebugLog((DEB_TRACE, "Found negative entry for %wZ\n", RealmName));
  657. Status = STATUS_NO_LOGON_SERVERS;
  658. }
  659. else
  660. {
  661. Status = STATUS_SUCCESS;
  662. }
  663. goto Cleanup;
  664. }
  665. }
  666. //
  667. // If we are a domain controller, then we can simply use our global
  668. // computer name.
  669. //
  670. #ifndef WIN32_CHICAGO
  671. if ((Role == KerbRoleDomainController) &&
  672. ((DesiredFlags & DS_PDC_REQUIRED) == 0) &&
  673. KerbIsThisOurDomain(
  674. RealmName
  675. ))
  676. {
  677. DsysAssert(LocalMachineName.Buffer[LocalMachineName.Length/sizeof(WCHAR)] == L'\0');
  678. if (!KerbKdcStarted)
  679. {
  680. Status = KerbWaitForKdc( KerbGlobalKdcWaitTime ); // wait for KerbGlobalKdcWaitTime seconds
  681. if (NT_SUCCESS(Status))
  682. {
  683. KerbKdcStarted = TRUE;
  684. }
  685. else
  686. {
  687. DebugLog((DEB_WARN, "Failed to wait for KDC to start: 0x%x\n",Status));
  688. }
  689. }
  690. if (KerbKdcStarted)
  691. {
  692. Status = STATUS_SUCCESS;
  693. KdcNameString = LocalMachineName;
  694. AddressType = DS_NETBIOS_ADDRESS;
  695. CacheFlags |= KERB_BINDING_LOCAL;
  696. DcFlags |= DS_CLOSEST_FLAG;
  697. }
  698. }
  699. #endif // WIN32_CHICAGO
  700. //
  701. // Check to see if this is an MIT realm
  702. //
  703. if (!NT_SUCCESS(Status) &&
  704. KerbLookupMitRealmWithSrvLookup(
  705. RealmName,
  706. &MitRealm,
  707. FindKpasswd,
  708. UseTcp
  709. ))
  710. {
  711. LONG ServerIndex;
  712. PKERB_MIT_SERVER_LIST ServerList;
  713. if ((MitRealm->Flags & KERB_MIT_REALM_TCP_SUPPORTED) == 0)
  714. {
  715. CacheFlags |= KERB_BINDING_NO_TCP;
  716. }
  717. //
  718. // Pick which of the servers we want to use.
  719. //
  720. if (FindKpasswd)
  721. {
  722. ServerList = &MitRealm->KpasswdNames;
  723. }
  724. else
  725. {
  726. ServerList = &MitRealm->KdcNames;
  727. }
  728. //
  729. // If we aren't forcing rediscovery, use the last known KDC
  730. //
  731. if (ServerList->ServerCount <= 0)
  732. {
  733. Status = STATUS_NO_LOGON_SERVERS;
  734. goto Cleanup;
  735. }
  736. if ((DesiredFlags & DS_FORCE_REDISCOVERY) == 0)
  737. {
  738. ServerIndex = ServerList->LastServerUsed;
  739. }
  740. else
  741. {
  742. //
  743. // If we are forcing rediscovery, try the next realm in the list
  744. //
  745. #ifndef WIN32_CHICAGO // Implement using a global & cs
  746. ServerIndex = InterlockedExchangeAdd(&ServerList->LastServerUsed, 1) + 1;
  747. #else // WIN32_CHICAGO
  748. ServerIndex = ServerList->LastServerUsed + 1;
  749. (ServerList->LastServerUsed) ++;
  750. #endif // WIN32_CHICAGO // Implement using a global & cs
  751. if (ServerIndex >= ServerList->ServerCount)
  752. {
  753. InterlockedExchange(&ServerList->LastServerUsed, 0);
  754. }
  755. }
  756. ServerIndex = ServerIndex % ServerList->ServerCount;
  757. KdcNameString = ServerList->ServerNames[ServerIndex];
  758. AddressType = DS_UNKNOWN_ADDRESS_TYPE;
  759. Status = STATUS_SUCCESS;
  760. }
  761. //
  762. // If we haven't yet found a KDC try DsGetDcName
  763. //
  764. if (!NT_SUCCESS(Status))
  765. {
  766. //
  767. // We are dependent on AFD, so wait for it to start
  768. //
  769. #ifndef WIN32_CHICAGO
  770. if (!KerbAfdStarted)
  771. {
  772. Status = KerbWaitForService(L"LanmanWorkstation", NULL, KerbGlobalKdcWaitTime);
  773. if (!NT_SUCCESS(Status))
  774. {
  775. DebugLog((DEB_WARN, "Failed to wait forAFD: 0x%x\n",Status));
  776. goto Cleanup;
  777. }
  778. KerbAfdStarted = TRUE;
  779. //
  780. // Setup for network change initialization.
  781. //
  782. KerbInitNetworkChangeEvent();
  783. }
  784. #endif // WIN32_CHICAGO
  785. //
  786. // Build the null-terminated domain name.
  787. //
  788. DomainName = (LPWSTR) KerbAllocate(RealmName->Length + sizeof(WCHAR));
  789. if (DomainName == NULL)
  790. {
  791. Status = STATUS_INSUFFICIENT_RESOURCES;
  792. goto Cleanup;
  793. }
  794. RtlCopyMemory(
  795. DomainName,
  796. RealmName->Buffer,
  797. RealmName->Length
  798. );
  799. DomainName[RealmName->Length/sizeof(WCHAR)] = L'\0';
  800. //
  801. // If a principal name was provided, pass it to Netlogon
  802. //
  803. if ((PrincipalName != NULL) && (PrincipalName->Length != 0))
  804. {
  805. AccountName = (LPWSTR) KerbAllocate(PrincipalName->Length + sizeof(WCHAR));
  806. if (AccountName == NULL)
  807. {
  808. Status = STATUS_INSUFFICIENT_RESOURCES;
  809. goto Cleanup;
  810. }
  811. RtlCopyMemory(
  812. AccountName,
  813. PrincipalName->Buffer,
  814. PrincipalName->Length
  815. );
  816. AccountName[PrincipalName->Length/sizeof(WCHAR)] = L'\0';
  817. }
  818. //
  819. // Actual flags that will be used.
  820. //
  821. if (DesiredFlags & DS_PDC_REQUIRED)
  822. {
  823. ActualFlags = (DesiredFlags | KERB_LOCATOR_FLAGS) & ~DS_KDC_REQUIRED;
  824. }
  825. else
  826. {
  827. ActualFlags = DesiredFlags | KERB_LOCATOR_FLAGS;
  828. }
  829. //
  830. // Find the name of a DC in this domain:
  831. //
  832. #ifndef WIN32_CHICAGO
  833. //
  834. // Note: Watch out for changes in the enumeration below.
  835. //
  836. if ( !KerbNetlogonStarted &&
  837. ( Role > KerbRoleStandalone ) &&
  838. ( fRebootedSinceJoin ))
  839. {
  840. Status = KerbWaitForService(
  841. SERVICE_NETLOGON,
  842. NETLOGON_STARTED_EVENT,
  843. KerbGlobalKdcWaitTime
  844. );
  845. if (NT_SUCCESS(Status))
  846. {
  847. KerbNetlogonStarted = TRUE;
  848. }
  849. else
  850. {
  851. Status = STATUS_SUCCESS;
  852. }
  853. }
  854. if (KerbNetlogonStarted)
  855. {
  856. CalledNetlogonDirectly = TRUE;
  857. NetStatus = DsrGetDcNameEx2(
  858. NULL,
  859. AccountName, // no account name
  860. UF_ACCOUNT_TYPE_MASK, // any account type
  861. DomainName,
  862. NULL, // no domain GUID
  863. NULL, // no site GUID,
  864. ActualFlags,
  865. &DcInfo
  866. );
  867. }
  868. else
  869. #endif // WIN32_CHICAGO
  870. {
  871. TryNetapi:
  872. NetStatus = DsGetDcNameW(
  873. NULL,
  874. DomainName,
  875. NULL, // no domain GUID
  876. NULL, // no site GUID,
  877. ActualFlags,
  878. &DcInfo
  879. );
  880. }
  881. if (NetStatus != NO_ERROR)
  882. {
  883. if (NetStatus == STATUS_NETLOGON_NOT_STARTED)
  884. {
  885. KerbNetlogonStarted = FALSE;
  886. if (CalledNetlogonDirectly)
  887. {
  888. CalledNetlogonDirectly = FALSE;
  889. goto TryNetapi;
  890. }
  891. }
  892. DebugLog((
  893. DEB_WARN,
  894. "No MS DC for domain %ws, account name %ws, locator flags 0x%x: %d. %ws, line %d\n",
  895. DomainName,
  896. (AccountName ? AccountName :L"NULL"),
  897. ActualFlags,
  898. NetStatus,
  899. THIS_FILE,
  900. __LINE__
  901. ));
  902. if (NetStatus == ERROR_NETWORK_UNREACHABLE)
  903. {
  904. Status = STATUS_NETWORK_UNREACHABLE;
  905. }
  906. else
  907. {
  908. if ( Role == KerbRoleRealmlessWksta )
  909. {
  910. DebugLog((DEB_TRACE, "NEG Caching realm %wZ\n", RealmName));
  911. KerbCacheBinding(
  912. RealmName,
  913. &KdcNameString,
  914. AddressType,
  915. DesiredFlags,
  916. DcFlags,
  917. ( CacheFlags | KERB_BINDING_NEGATIVE_ENTRY ),
  918. BindingCacheEntry
  919. );
  920. }
  921. Status = STATUS_NO_LOGON_SERVERS;
  922. }
  923. }
  924. else // no error
  925. {
  926. RtlInitUnicodeString(
  927. &KdcNameString,
  928. DcInfo->DomainControllerAddress+2
  929. );
  930. AddressType = DcInfo->DomainControllerAddressType;
  931. DcFlags |= DcInfo->Flags;
  932. Status = STATUS_SUCCESS;
  933. }
  934. }
  935. if (!NT_SUCCESS(Status))
  936. {
  937. DebugLog((
  938. DEB_ERROR,
  939. "No DC for domain %ws, account name %ws, locator flags 0x%x: %d. %ws, line %d\n",
  940. DomainName,
  941. (AccountName ? AccountName :L"NULL"),
  942. ActualFlags,
  943. NetStatus,
  944. THIS_FILE,
  945. __LINE__
  946. ));
  947. goto Cleanup;
  948. }
  949. //
  950. // Make a binding
  951. //
  952. //
  953. // If this is a local call so don't bother with the socket
  954. //
  955. Status = KerbCacheBinding(
  956. RealmName,
  957. &KdcNameString,
  958. AddressType,
  959. DesiredFlags, // Flags that we would like to have
  960. DcFlags, // This is what the dc has
  961. CacheFlags, // Special kerberos flags so we don't use
  962. // locator's bit space
  963. BindingCacheEntry
  964. );
  965. if (!NT_SUCCESS(Status))
  966. {
  967. goto Cleanup;
  968. }
  969. Cleanup:
  970. if (DomainName != NULL)
  971. {
  972. KerbFree(DomainName);
  973. }
  974. if (AccountName != NULL)
  975. {
  976. KerbFree(AccountName);
  977. }
  978. #ifndef WIN32_CHICAGO
  979. if (DcInfo != NULL)
  980. {
  981. if (CalledNetlogonDirectly)
  982. {
  983. I_NetLogonFree(DcInfo);
  984. }
  985. else
  986. {
  987. NetApiBufferFree(DcInfo);
  988. }
  989. }
  990. KerbFreeString( &LocalMachineName );
  991. #endif // WIN32_CHICAGO
  992. return(Status);
  993. }