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.

1191 lines
32 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. SAFE_CRITICAL_SECTION KerbCallKdcDataLock;
  43. BOOLEAN KerbCallKdcDataInitialized = FALSE;
  44. #define KerbLockKdcData() (SafeEnterCriticalSection(&KerbCallKdcDataLock))
  45. #define KerbUnlockKdcData() (SafeLeaveCriticalSection(&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 = SafeInitializeCriticalSection(&KerbCallKdcDataLock, KDC_DATA_LOCK_ENUM);
  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. SafeDeleteCriticalSection(&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((ULONG) 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. SafeAllocaAllocate(KdcName, 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. SafeAllocaFree(KdcName);
  252. return (fReadCache);
  253. }
  254. #endif // WIN32_CHICAGO
  255. //+-------------------------------------------------------------------------
  256. //
  257. // Function: KerbSocketChangeHandler
  258. //
  259. // Synopsis: Simply setups up a WSA Pnp event, so that we catch network
  260. // changes.
  261. //
  262. // Effects:
  263. //
  264. // Arguments:
  265. //
  266. // Requires:
  267. //
  268. // Returns:
  269. //
  270. // Notes:
  271. //
  272. //
  273. //--------------------------------------------------------------------------
  274. VOID
  275. KerbSocketChangeHandler(
  276. VOID* Context,
  277. BOOLEAN WaitStatus
  278. )
  279. {
  280. WSAPROTOCOL_INFO *lpProtocolBuf = NULL;
  281. DWORD dwBufLen = 0;
  282. INT protocols[2];
  283. int nRet = 0;
  284. NTSTATUS Status;
  285. NET_API_STATUS NetStatus;
  286. D_DebugLog((DEB_TRACE, "API: KerbSocketChangeHandler()\n"));
  287. //
  288. // Determine if TCP is installed.
  289. //
  290. protocols[0] = IPPROTO_TCP;
  291. protocols[1] = NULL;
  292. nRet = WSAEnumProtocols(protocols, lpProtocolBuf, &dwBufLen);
  293. KerbGlobalWriteLock();
  294. if (nRet == 0)
  295. {
  296. D_DebugLog((DEB_TRACE_SOCK, "Turning OFF! TCP %x\n", nRet));
  297. KerbGlobalNoTcpUdp = TRUE;
  298. }
  299. else
  300. {
  301. KerbGlobalNoTcpUdp = FALSE;
  302. if (nRet == SOCKET_ERROR)
  303. {
  304. nRet = WSAGetLastError();
  305. D_DebugLog((DEB_TRACE_SOCK, "TCP problem? %x\n", nRet));
  306. }
  307. D_DebugLog((DEB_TRACE_SOCK, "Turning on TCP %x\n", nRet));
  308. }
  309. KerbGlobalReleaseLock();
  310. //
  311. // Re-Register the wait - but make sure the values are init'd / correct.
  312. //
  313. KerbLockKdcData();
  314. if ( KerbPNPSocketWaitHandle && KerbPNPSocketEvent )
  315. {
  316. NetStatus = WSAEventSelect(
  317. KerbPNPSocket,
  318. KerbPNPSocketEvent,
  319. FD_ADDRESS_LIST_CHANGE
  320. );
  321. if ( NetStatus != 0 )
  322. {
  323. NetStatus = WSAGetLastError();
  324. DebugLog(( DEB_ERROR, "Can't WSAEventSelect %ld\n", NetStatus ));
  325. }
  326. Status = RtlRegisterWait(
  327. &KerbPNPSocketWaitHandle,
  328. KerbPNPSocketEvent,
  329. KerbSocketChangeHandler,
  330. NULL,
  331. INFINITE,
  332. WT_EXECUTEDEFAULT | WT_EXECUTEONLYONCE
  333. );
  334. if (!NT_SUCCESS( Status ))
  335. {
  336. DebugLog((DEB_ERROR, "RtlRegisterWait failed %x\n", Status));
  337. }
  338. //
  339. // Issue the IOCTL, so we'll get notified.
  340. //
  341. NetStatus = WSAIoctl(
  342. KerbPNPSocket,
  343. SIO_ADDRESS_LIST_CHANGE,
  344. NULL, // No input buffer
  345. 0, // No input buffer
  346. NULL, // No output buffer
  347. 0, // No output buffer
  348. &dwBufLen,
  349. NULL, // No overlapped,
  350. NULL // Not async
  351. );
  352. if ( NetStatus != 0 )
  353. {
  354. NetStatus = WSAGetLastError();
  355. if ( NetStatus != WSAEWOULDBLOCK)
  356. {
  357. DebugLog((DEB_ERROR, "WSAIOCTL failed %x\n", NetStatus));
  358. Status = STATUS_INTERNAL_ERROR;
  359. }
  360. }
  361. }
  362. KerbUnlockKdcData();
  363. KerbCleanupBindingCache(FALSE);
  364. }
  365. //+-------------------------------------------------------------------------
  366. //
  367. // Function: KerbInitNetworkChangeEvent
  368. //
  369. // Synopsis: Simply setups up a WSA Pnp event, so that we catch network
  370. // changes.
  371. //
  372. // Effects:
  373. //
  374. // Arguments:
  375. //
  376. // Requires:
  377. //
  378. // Returns:
  379. //
  380. // Notes:
  381. //
  382. //
  383. //--------------------------------------------------------------------------
  384. NTSTATUS
  385. KerbInitNetworkChangeEvent()
  386. {
  387. NET_API_STATUS NetStatus;
  388. NTSTATUS Status = STATUS_INTERNAL_ERROR;
  389. DWORD BytesReturned;
  390. KerbLockKdcData();
  391. if ( KerbPNPSocket != NULL )
  392. {
  393. D_DebugLog((DEB_ERROR, "second init of network change event\n"));
  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. if ( NetStatus == WSAEAFNOSUPPORT )
  411. {
  412. Status = STATUS_SUCCESS;
  413. goto Cleanup;
  414. }
  415. goto Cleanup;
  416. }
  417. //
  418. // Open an event to wait on.
  419. //
  420. KerbPNPSocketEvent = CreateEvent(
  421. NULL, // No security ettibutes
  422. FALSE, // Auto reset
  423. FALSE, // Initially not signaled
  424. NULL
  425. );
  426. if ( KerbPNPSocketEvent == NULL )
  427. {
  428. DebugLog(( DEB_ERROR,"Cannot create Winsock PNP event %ld\n", GetLastError() ));
  429. Status = STATUS_INTERNAL_ERROR;
  430. goto Cleanup;
  431. }
  432. NetStatus = WSAEventSelect(
  433. KerbPNPSocket,
  434. KerbPNPSocketEvent,
  435. FD_ADDRESS_LIST_CHANGE
  436. );
  437. if ( NetStatus != 0 )
  438. {
  439. NetStatus = WSAGetLastError();
  440. DebugLog(( DEB_ERROR, "Can't WSAEventSelect %ld\n", NetStatus ));
  441. goto Cleanup;
  442. }
  443. //
  444. // Register a wait.
  445. //
  446. Status = RtlRegisterWait(
  447. &KerbPNPSocketWaitHandle,
  448. KerbPNPSocketEvent,
  449. KerbSocketChangeHandler,
  450. NULL,
  451. INFINITE,
  452. WT_EXECUTEDEFAULT | WT_EXECUTEONLYONCE
  453. );
  454. if (!NT_SUCCESS( Status ))
  455. {
  456. DebugLog((DEB_ERROR, "RtlRegisterWait failed %x\n", Status));
  457. goto Cleanup;
  458. }
  459. //
  460. // Issue the IOCTL, so we'll get notified.
  461. //
  462. NetStatus = WSAIoctl(
  463. KerbPNPSocket,
  464. SIO_ADDRESS_LIST_CHANGE,
  465. NULL, // No input buffer
  466. 0, // No input buffer
  467. NULL, // No output buffer
  468. 0, // No output buffer
  469. &BytesReturned,
  470. NULL, // No overlapped,
  471. NULL // Not async
  472. );
  473. if ( NetStatus != 0 )
  474. {
  475. NetStatus = WSAGetLastError();
  476. if ( NetStatus != WSAEWOULDBLOCK) {
  477. DebugLog((DEB_ERROR, "WSAIOCTL failed %x\n", NetStatus));
  478. Status = STATUS_INTERNAL_ERROR;
  479. }
  480. }
  481. Cleanup:
  482. if (!NT_SUCCESS( Status ))
  483. {
  484. if ( KerbPNPSocketWaitHandle )
  485. {
  486. RtlDeregisterWait(KerbPNPSocketWaitHandle);
  487. KerbPNPSocketWaitHandle = NULL;
  488. }
  489. if ( KerbPNPSocketEvent )
  490. {
  491. CloseHandle( KerbPNPSocketEvent );
  492. KerbPNPSocketEvent = NULL;
  493. }
  494. if ( KerbPNPSocket )
  495. {
  496. closesocket( KerbPNPSocket );
  497. KerbPNPSocket = NULL;
  498. }
  499. }
  500. KerbUnlockKdcData();
  501. return Status;
  502. }
  503. //
  504. // This address type is used for talking to MIT KDCs
  505. //
  506. #define DS_UNKNOWN_ADDRESS_TYPE 0
  507. //+-------------------------------------------------------------------------
  508. //
  509. // Function: KerbGetKdcBinding
  510. //
  511. // Synopsis: Gets a binding to the KDC in the specified domain
  512. //
  513. // Effects:
  514. //
  515. // Arguments: Realm - Domain in which to find KDC
  516. // PrincipalName - name of a principal that must be on the KDC
  517. // DesiredFlags - Flags to pass to the locator.
  518. // FindKpasswd - if domain is an MIT realm, then returns Kpasswd
  519. // addresses instead of KDC addresses KDC
  520. // BindingCacheEntry - receives binding handle cache entry for
  521. // TCP to the KDC
  522. //
  523. // Requires:
  524. //
  525. // Returns: RPC errors, NET API errors
  526. //
  527. // Notes:
  528. //
  529. //
  530. //--------------------------------------------------------------------------
  531. NTSTATUS
  532. KerbGetKdcBinding(
  533. IN PUNICODE_STRING RealmName,
  534. IN OPTIONAL PUNICODE_STRING PrincipalName,
  535. IN ULONG DesiredFlags,
  536. IN BOOLEAN FindKpasswd,
  537. IN BOOLEAN UseTcp,
  538. OUT PKERB_BINDING_CACHE_ENTRY * BindingCacheEntry
  539. )
  540. {
  541. NTSTATUS Status = STATUS_NETLOGON_NOT_STARTED;
  542. NTSTATUS TempStatus = STATUS_SUCCESS;
  543. LPWSTR DomainName = NULL;
  544. LPWSTR AccountName = NULL;
  545. ULONG NetStatus = 0;
  546. ULONG AddressType = DS_INET_ADDRESS;
  547. UNICODE_STRING KdcNameString = {0};
  548. PDOMAIN_CONTROLLER_INFOW DcInfo = NULL;
  549. PKERB_MIT_REALM MitRealm = NULL;
  550. BOOLEAN CacheDc = FALSE;
  551. BOOLEAN CalledNetlogonDirectly = FALSE;
  552. KERBEROS_MACHINE_ROLE Role;
  553. ULONG ActualFlags = 0;
  554. ULONG CacheFlags = 0, DcFlags = 0;
  555. #ifndef WIN32_CHICAGO
  556. ULONG CachedAddressType = DS_INET_ADDRESS;
  557. ULONG CachedFlags = 0;
  558. UNICODE_STRING CachedKdcNameString = {0};
  559. UNICODE_STRING LocalMachineName;
  560. #endif // WIN32_CHICAGO
  561. Role = KerbGetGlobalRole();
  562. #ifndef WIN32_CHICAGO
  563. LocalMachineName.Buffer = NULL;
  564. KerbGlobalReadLock();
  565. //
  566. // use TempStatus to retain initial Status value.
  567. //
  568. TempStatus = KerbDuplicateString( &LocalMachineName, &KerbGlobalMachineName );
  569. KerbGlobalReleaseLock();
  570. if(!NT_SUCCESS(TempStatus))
  571. {
  572. DebugLog((DEB_ERROR, "Failed to duplicate KerbGlobalMachineName\n"));
  573. Status = TempStatus;
  574. goto Cleanup;
  575. }
  576. if ((Role != KerbRoleDomainController) &&
  577. (RtlEqualDomainName(
  578. RealmName,
  579. &LocalMachineName
  580. )))
  581. {
  582. //
  583. // This is an attempt at a local logon on a workstation. We don't do that.
  584. //
  585. DebugLog((DEB_WARN, "Attempting to locate a KDC for the workstation - failing\n"));
  586. Status = STATUS_NO_LOGON_SERVERS;
  587. goto Cleanup;
  588. }
  589. //
  590. // If we are logging on for the first time after join domain, the
  591. // following registry entry should exist.
  592. // Cache that entry, we should try to get to that dc.
  593. // Don't cache the entry if we are a dc
  594. // Don't cache the entry if this is not for our domain
  595. //
  596. if ( fNewDataAboutDomain &&
  597. KerbGlobalRole != KerbRoleDomainController)
  598. {
  599. if (ReadInitialDcRecord(&CachedKdcNameString, &CachedAddressType, &CachedFlags))
  600. {
  601. KerbFreeString(&KerbGlobalInitialDcRecord);
  602. RtlInitUnicodeString(
  603. &KerbGlobalInitialDcRecord,
  604. CachedKdcNameString.Buffer
  605. );
  606. KerbGlobalInitialDcAddressType = CachedAddressType;
  607. KerbGlobalInitialDcFlags = CachedFlags;
  608. CacheDc = TRUE;
  609. }
  610. else if (KerbGlobalInitialDcRecord.Buffer != NULL)
  611. {
  612. CacheDc = TRUE;
  613. }
  614. if (CacheDc && KerbIsThisOurDomain( RealmName))
  615. {
  616. PKERB_BINDING_CACHE_ENTRY TempBindingCacheEntry = NULL;
  617. TempStatus = KerbCacheBinding(
  618. RealmName,
  619. &KerbGlobalInitialDcRecord,
  620. KerbGlobalInitialDcAddressType,
  621. DesiredFlags,
  622. KerbGlobalInitialDcFlags,
  623. 0,
  624. &TempBindingCacheEntry
  625. );
  626. if ( TempBindingCacheEntry ) {
  627. KerbDereferenceBindingCacheEntry( TempBindingCacheEntry );
  628. }
  629. KerbFreeString(&KerbGlobalInitialDcRecord);
  630. }
  631. }
  632. #endif // WIN32_CHICAGO
  633. //
  634. // Check the cache if we don't want to force rediscovery
  635. //
  636. if ((DesiredFlags & DS_FORCE_REDISCOVERY) == 0)
  637. {
  638. *BindingCacheEntry = KerbLocateBindingCacheEntry(
  639. RealmName,
  640. DesiredFlags,
  641. FALSE
  642. );
  643. if (NULL != *BindingCacheEntry)
  644. {
  645. //
  646. // For realmless workstations, we add negative cache entries.
  647. // This is because the netlogon service doesn't run on non-joined
  648. // machines, so we don't have the benefit of its negative caching.
  649. // The end result is that we need to do that ourselves.
  650. //
  651. if (( Role == KerbRoleRealmlessWksta ) &&
  652. (( (*BindingCacheEntry)->CacheFlags & KERB_BINDING_NEGATIVE_ENTRY ) != 0))
  653. {
  654. DebugLog((DEB_TRACE_BND_CACHE, "Found negative entry for %wZ\n", RealmName));
  655. Status = STATUS_NO_LOGON_SERVERS;
  656. }
  657. else
  658. {
  659. Status = STATUS_SUCCESS;
  660. }
  661. goto Cleanup;
  662. }
  663. }
  664. //
  665. // If we are a domain controller, then we can simply use our global
  666. // computer name.
  667. //
  668. #ifndef WIN32_CHICAGO
  669. if ((Role == KerbRoleDomainController) &&
  670. ((DesiredFlags & DS_PDC_REQUIRED) == 0) &&
  671. KerbIsThisOurDomain(
  672. RealmName
  673. ))
  674. {
  675. DsysAssert(LocalMachineName.Buffer[LocalMachineName.Length/sizeof(WCHAR)] == L'\0');
  676. if (!KerbKdcStarted)
  677. {
  678. Status = KerbWaitForKdc( KerbGlobalKdcWaitTime ); // wait for KerbGlobalKdcWaitTime seconds
  679. if (NT_SUCCESS(Status))
  680. {
  681. KerbKdcStarted = TRUE;
  682. }
  683. else
  684. {
  685. DebugLog((DEB_WARN, "Failed to wait for KDC to start: 0x%x\n",Status));
  686. }
  687. }
  688. if (KerbKdcStarted)
  689. {
  690. Status = STATUS_SUCCESS;
  691. KdcNameString = LocalMachineName;
  692. AddressType = DS_NETBIOS_ADDRESS;
  693. CacheFlags |= KERB_BINDING_LOCAL;
  694. DcFlags |= DS_CLOSEST_FLAG;
  695. }
  696. }
  697. #endif // WIN32_CHICAGO
  698. //
  699. // Check to see if this is an MIT realm
  700. //
  701. if (!NT_SUCCESS(Status) &&
  702. KerbLookupMitRealmWithSrvLookup(
  703. RealmName,
  704. &MitRealm,
  705. FindKpasswd,
  706. UseTcp
  707. ))
  708. {
  709. LONG ServerIndex;
  710. PKERB_MIT_SERVER_LIST ServerList;
  711. if ((MitRealm->Flags & KERB_MIT_REALM_TCP_SUPPORTED) == 0)
  712. {
  713. CacheFlags |= KERB_BINDING_NO_TCP;
  714. }
  715. //
  716. // Pick which of the servers we want to use.
  717. //
  718. if (FindKpasswd)
  719. {
  720. ServerList = &MitRealm->KpasswdNames;
  721. }
  722. else
  723. {
  724. ServerList = &MitRealm->KdcNames;
  725. }
  726. //
  727. // If we aren't forcing rediscovery, use the last known KDC
  728. //
  729. if (ServerList->ServerCount <= 0)
  730. {
  731. Status = STATUS_NO_LOGON_SERVERS;
  732. goto Cleanup;
  733. }
  734. if ((DesiredFlags & DS_FORCE_REDISCOVERY) == 0)
  735. {
  736. ServerIndex = ServerList->LastServerUsed;
  737. }
  738. else
  739. {
  740. //
  741. // If we are forcing rediscovery, try the next realm in the list
  742. //
  743. #ifndef WIN32_CHICAGO // Implement using a global & cs
  744. ServerIndex = InterlockedExchangeAdd(&ServerList->LastServerUsed, 1) + 1;
  745. #else // WIN32_CHICAGO
  746. ServerIndex = ServerList->LastServerUsed + 1;
  747. (ServerList->LastServerUsed) ++;
  748. #endif // WIN32_CHICAGO // Implement using a global & cs
  749. if (ServerIndex >= ServerList->ServerCount)
  750. {
  751. InterlockedExchange(&ServerList->LastServerUsed, 0);
  752. }
  753. }
  754. ServerIndex = ServerIndex % ServerList->ServerCount;
  755. KdcNameString = ServerList->ServerNames[ServerIndex];
  756. AddressType = DS_UNKNOWN_ADDRESS_TYPE;
  757. Status = STATUS_SUCCESS;
  758. }
  759. //
  760. // If we haven't yet found a KDC try DsGetDcName
  761. //
  762. if (!NT_SUCCESS(Status))
  763. {
  764. //
  765. // We are dependent on AFD, so wait for it to start
  766. //
  767. #ifndef WIN32_CHICAGO
  768. if (!KerbAfdStarted)
  769. {
  770. Status = KerbWaitForService(L"LanmanWorkstation", NULL, KerbGlobalKdcWaitTime);
  771. if (!NT_SUCCESS(Status))
  772. {
  773. DebugLog((DEB_WARN, "Failed to wait forAFD: 0x%x\n",Status));
  774. goto Cleanup;
  775. }
  776. KerbAfdStarted = TRUE;
  777. //
  778. // Setup for network change initialization.
  779. //
  780. KerbInitNetworkChangeEvent();
  781. }
  782. #endif // WIN32_CHICAGO
  783. //
  784. // Build the null-terminated domain name.
  785. //
  786. SafeAllocaAllocate(DomainName, RealmName->Length + sizeof(WCHAR));
  787. if (DomainName == NULL)
  788. {
  789. Status = STATUS_INSUFFICIENT_RESOURCES;
  790. goto Cleanup;
  791. }
  792. RtlCopyMemory(
  793. DomainName,
  794. RealmName->Buffer,
  795. RealmName->Length
  796. );
  797. DomainName[RealmName->Length/sizeof(WCHAR)] = L'\0';
  798. //
  799. // If a principal name was provided, pass it to Netlogon
  800. //
  801. if ((PrincipalName != NULL) && (PrincipalName->Length != 0))
  802. {
  803. SafeAllocaAllocate(AccountName, PrincipalName->Length + sizeof(WCHAR));
  804. if (AccountName == NULL)
  805. {
  806. Status = STATUS_INSUFFICIENT_RESOURCES;
  807. goto Cleanup;
  808. }
  809. RtlCopyMemory(
  810. AccountName,
  811. PrincipalName->Buffer,
  812. PrincipalName->Length
  813. );
  814. AccountName[PrincipalName->Length/sizeof(WCHAR)] = L'\0';
  815. }
  816. //
  817. // Actual flags that will be used.
  818. //
  819. if (DesiredFlags & DS_PDC_REQUIRED)
  820. {
  821. ActualFlags = (DesiredFlags | KERB_LOCATOR_FLAGS) & ~DS_KDC_REQUIRED;
  822. }
  823. else
  824. {
  825. ActualFlags = DesiredFlags | KERB_LOCATOR_FLAGS;
  826. }
  827. //
  828. // Find the name of a DC in this domain:
  829. //
  830. #ifndef WIN32_CHICAGO
  831. //
  832. // Make sure that changes to the enumeration are
  833. // taken into account here.
  834. //
  835. if ( !KerbNetlogonStarted &&
  836. ( Role > KerbRoleStandalone ) &&
  837. ( fRebootedSinceJoin ))
  838. {
  839. Status = KerbWaitForService(
  840. SERVICE_NETLOGON,
  841. NETLOGON_STARTED_EVENT,
  842. KerbGlobalKdcWaitTime
  843. );
  844. if (NT_SUCCESS(Status))
  845. {
  846. KerbNetlogonStarted = TRUE;
  847. }
  848. else
  849. {
  850. Status = STATUS_SUCCESS;
  851. }
  852. }
  853. if (KerbNetlogonStarted)
  854. {
  855. CalledNetlogonDirectly = TRUE;
  856. NetStatus = DsrGetDcNameEx2(
  857. NULL,
  858. AccountName, // no account name
  859. UF_ACCOUNT_TYPE_MASK, // any account type
  860. DomainName,
  861. NULL, // no domain GUID
  862. NULL, // no site GUID,
  863. ActualFlags,
  864. &DcInfo
  865. );
  866. }
  867. else
  868. #endif // WIN32_CHICAGO
  869. {
  870. TryNetapi:
  871. NetStatus = DsGetDcNameW(
  872. NULL,
  873. DomainName,
  874. NULL, // no domain GUID
  875. NULL, // no site GUID,
  876. ActualFlags,
  877. &DcInfo
  878. );
  879. }
  880. if (NetStatus != NO_ERROR)
  881. {
  882. if (NetStatus == STATUS_NETLOGON_NOT_STARTED ||
  883. NetStatus == ERROR_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_BND_CACHE, "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. KerbResetTransportCounter();
  924. }
  925. else // no error
  926. {
  927. RtlInitUnicodeString(
  928. &KdcNameString,
  929. DcInfo->DomainControllerAddress+2
  930. );
  931. AddressType = DcInfo->DomainControllerAddressType;
  932. DcFlags |= DcInfo->Flags;
  933. Status = STATUS_SUCCESS;
  934. }
  935. }
  936. if (!NT_SUCCESS(Status))
  937. {
  938. DebugLog((
  939. DEB_TRACE,
  940. "No DC for domain %ws, account name %ws, locator flags 0x%x: %d. %ws, line %d\n",
  941. DomainName,
  942. (AccountName ? AccountName : L"NULL"),
  943. ActualFlags,
  944. NetStatus,
  945. THIS_FILE,
  946. __LINE__
  947. ));
  948. goto Cleanup;
  949. }
  950. //
  951. // Make a binding
  952. //
  953. //
  954. // If this is a local call so don't bother with the socket
  955. //
  956. Status = KerbCacheBinding(
  957. RealmName,
  958. &KdcNameString,
  959. AddressType,
  960. DesiredFlags, // Flags that we would like to have
  961. DcFlags, // This is what the dc has
  962. CacheFlags, // Special kerberos flags so we don't use
  963. // locator's bit space
  964. BindingCacheEntry
  965. );
  966. if (!NT_SUCCESS(Status))
  967. {
  968. goto Cleanup;
  969. }
  970. Cleanup:
  971. SafeAllocaFree(DomainName);
  972. SafeAllocaFree(AccountName);
  973. #ifndef WIN32_CHICAGO
  974. if (DcInfo != NULL)
  975. {
  976. if (CalledNetlogonDirectly)
  977. {
  978. I_NetLogonFree(DcInfo);
  979. }
  980. else
  981. {
  982. NetApiBufferFree(DcInfo);
  983. }
  984. }
  985. KerbFreeString( &LocalMachineName );
  986. #endif // WIN32_CHICAGO
  987. return(Status);
  988. }