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.

4610 lines
110 KiB

  1. //+-----------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (c) Microsoft Corporation 1992 - 1996
  6. //
  7. // File: kerbutil.cxx
  8. //
  9. // Contents: Utility functions for Kerberos package
  10. //
  11. //
  12. // History: 16-April-1996 Created MikeSw
  13. //
  14. //------------------------------------------------------------------------
  15. #include <kerb.hxx>
  16. #include <kerbp.h>
  17. #ifndef WIN32_CHICAGO
  18. #include <nb30.h>
  19. #else // WIN32_CHICAGO
  20. #define NCBNAMSZ 16
  21. #endif // WIN32_CHICAGO
  22. #include <userapi.h> // for gss support routines
  23. #ifdef RETAIL_LOG_SUPPORT
  24. static TCHAR THIS_FILE[]=TEXT(__FILE__);
  25. #endif
  26. GUID GUID_NULL = {0L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  27. //+-------------------------------------------------------------------------
  28. //
  29. // Function: KerbSplitFullServiceName
  30. //
  31. // Synopsis: Splits a full service name into a domain name and a
  32. // service name. The output strings point into the input
  33. // string's buffer and should not be freed
  34. //
  35. // Effects:
  36. //
  37. // Arguments: FullServiceName - The full service name in a domain\service
  38. // format
  39. // DomainName - Receives the domain portion of the full service
  40. // name in a 'domain' format
  41. // ServiceName - Receives the service name in a 'service' format
  42. //
  43. // Requires:
  44. //
  45. // Returns: STATUS_INVALID_PARAMETER if the service name does not
  46. // match the correct format.
  47. //
  48. // Notes:
  49. //
  50. //
  51. //--------------------------------------------------------------------------
  52. NTSTATUS
  53. KerbSplitFullServiceName(
  54. IN PUNICODE_STRING FullServiceName,
  55. OUT PUNICODE_STRING DomainName,
  56. OUT PUNICODE_STRING ServiceName
  57. )
  58. {
  59. UNICODE_STRING TempDomainName;
  60. UNICODE_STRING TempServiceName;
  61. TempDomainName = *FullServiceName;
  62. //
  63. // Find the split between domain and service name
  64. //
  65. TempDomainName.Length = 0;
  66. while ((TempDomainName.Length < FullServiceName->Length) &&
  67. (TempDomainName.Buffer[TempDomainName.Length/sizeof(WCHAR)] != L'\\') &&
  68. (TempDomainName.Buffer[TempDomainName.Length/sizeof(WCHAR)] != L'@') )
  69. {
  70. TempDomainName.Length += sizeof(WCHAR);
  71. }
  72. //
  73. // In this case, there is no separator
  74. //
  75. if (TempDomainName.Length == FullServiceName->Length)
  76. {
  77. *ServiceName = *FullServiceName;
  78. EMPTY_UNICODE_STRING( DomainName );
  79. return(STATUS_SUCCESS);
  80. }
  81. //
  82. // If the separator is an "@" switch the doman & service portion
  83. //
  84. if (TempDomainName.Buffer[TempDomainName.Length/sizeof(WCHAR)] == L'@')
  85. {
  86. TempServiceName = TempDomainName;
  87. TempDomainName.Buffer = TempServiceName.Buffer + TempServiceName.Length/sizeof(WCHAR) + 1;
  88. TempServiceName.MaximumLength = TempServiceName.Length;
  89. //
  90. // The Domain name is everything else
  91. //
  92. TempDomainName.Length = FullServiceName->Length - TempServiceName.Length - sizeof(WCHAR);
  93. TempDomainName.MaximumLength = TempDomainName.Length;
  94. }
  95. else
  96. {
  97. TempServiceName.Buffer = TempDomainName.Buffer + TempDomainName.Length/sizeof(WCHAR) + 1;
  98. TempDomainName.MaximumLength = TempDomainName.Length;
  99. //
  100. // The service name is everything else
  101. //
  102. TempServiceName.Length = FullServiceName->Length - TempDomainName.Length - sizeof(WCHAR);
  103. TempServiceName.MaximumLength = TempServiceName.Length;
  104. }
  105. *ServiceName = TempServiceName;
  106. *DomainName = TempDomainName;
  107. return(STATUS_SUCCESS);
  108. }
  109. //+-------------------------------------------------------------------------
  110. //
  111. // Function: KerbSplitEmailName
  112. //
  113. // Synopsis: Splits a full service name into a domain name and a
  114. // service name. The output strings point into the input
  115. // string's buffer and should not be freed
  116. //
  117. // Effects:
  118. //
  119. // Arguments: EmailName - The full service name in a domain\service
  120. // format
  121. // DomainName - Receives the domain portion of the full service
  122. // name in a 'domain' format
  123. // ServiceName - Receives the service name in a 'service' format
  124. //
  125. // Requires:
  126. //
  127. // Returns: STATUS_INVALID_PARAMETER if the service name does not
  128. // match the correct format.
  129. //
  130. // Notes:
  131. //
  132. //
  133. //--------------------------------------------------------------------------
  134. NTSTATUS
  135. KerbSplitEmailName(
  136. IN PUNICODE_STRING EmailName,
  137. OUT PUNICODE_STRING DomainName,
  138. OUT PUNICODE_STRING ServiceName
  139. )
  140. {
  141. UNICODE_STRING TempServiceName;
  142. UNICODE_STRING TempDomainName;
  143. TempServiceName = *EmailName;
  144. //
  145. // Find the split between service and domain name
  146. //
  147. TempServiceName.Length = 0;
  148. while ((TempServiceName.Length < EmailName->Length) &&
  149. (TempServiceName.Buffer[TempServiceName.Length/sizeof(WCHAR)] != L'@'))
  150. {
  151. TempServiceName.Length += sizeof(WCHAR);
  152. }
  153. if (TempServiceName.Length == EmailName->Length)
  154. {
  155. DebugLog((DEB_ERROR,"Failed to find @ separator in email name: %wZ. %ws, line %d\n",EmailName, THIS_FILE, __LINE__ ));
  156. return(STATUS_INVALID_PARAMETER);
  157. }
  158. TempDomainName.Buffer = TempServiceName.Buffer + TempServiceName.Length/sizeof(WCHAR) + 1;
  159. TempServiceName.MaximumLength = TempServiceName.Length;
  160. //
  161. // The domain name is everything else
  162. //
  163. TempDomainName.Length = EmailName->Length - TempServiceName.Length - sizeof(WCHAR);
  164. TempDomainName.MaximumLength = TempDomainName.Length;
  165. *ServiceName = TempServiceName;
  166. *DomainName = TempDomainName;
  167. return(STATUS_SUCCESS);
  168. }
  169. //+-------------------------------------------------------------------------
  170. //
  171. // Function: KerbAllocateNonce
  172. //
  173. // Synopsis: Allocates a locally unique number
  174. //
  175. // Effects:
  176. //
  177. // Arguments: none
  178. //
  179. // Requires:
  180. //
  181. // Returns: the nonce
  182. //
  183. // Notes:
  184. //
  185. //
  186. //--------------------------------------------------------------------------
  187. ULONG
  188. KerbAllocateNonce(
  189. VOID
  190. )
  191. {
  192. LUID TempLuid;
  193. TimeStamp CurrentTime;
  194. NtAllocateLocallyUniqueId(&TempLuid);
  195. GetSystemTimeAsFileTime((PFILETIME) &CurrentTime);
  196. #ifndef WIN32_CHICAGO
  197. return(0x7fffffff & (TempLuid.LowPart ^ TempLuid.HighPart ^ CurrentTime.LowPart ^ CurrentTime.HighPart));
  198. #else // WIN32_CHICAGO
  199. return(0x7fffffff & ((ULONG)(TempLuid.LowPart ^ TempLuid.HighPart ^ CurrentTime)));
  200. #endif // WIN32_CHICAGO
  201. }
  202. //+-------------------------------------------------------------------------
  203. //
  204. // Function: KerbAllocate
  205. //
  206. // Synopsis: Allocate memory in either lsa mode or user mode
  207. //
  208. // Effects:
  209. //
  210. // Arguments:
  211. //
  212. // Requires:
  213. //
  214. // Returns:
  215. //
  216. // Notes:
  217. //
  218. //
  219. //--------------------------------------------------------------------------
  220. PVOID
  221. KerbAllocate(
  222. IN ULONG BufferSize
  223. )
  224. {
  225. PVOID pBuffer = NULL;
  226. if (KerberosState == KerberosLsaMode)
  227. {
  228. pBuffer = LsaFunctions->AllocateLsaHeap(BufferSize);
  229. // Lsa helper routine zeroes the memory.
  230. }
  231. else
  232. {
  233. DsysAssert(KerberosState == KerberosUserMode);
  234. pBuffer = LocalAlloc(0,BufferSize);
  235. if (pBuffer)
  236. {
  237. RtlZeroMemory (pBuffer, BufferSize);
  238. }
  239. }
  240. return pBuffer;
  241. }
  242. //+-------------------------------------------------------------------------
  243. //
  244. // Function: KerbFree
  245. //
  246. // Synopsis: Free memory in either lsa mode or user mode
  247. //
  248. // Effects:
  249. //
  250. // Arguments:
  251. //
  252. // Requires:
  253. //
  254. // Returns:
  255. //
  256. // Notes:
  257. //
  258. //
  259. //--------------------------------------------------------------------------
  260. VOID
  261. KerbFree(
  262. IN PVOID Buffer
  263. )
  264. {
  265. if (ARGUMENT_PRESENT(Buffer))
  266. {
  267. if (KerberosState == KerberosLsaMode)
  268. {
  269. LsaFunctions->FreeLsaHeap(Buffer);
  270. }
  271. else
  272. {
  273. DsysAssert(KerberosState == KerberosUserMode);
  274. LocalFree(Buffer);
  275. }
  276. }
  277. }
  278. //+-------------------------------------------------------------------------
  279. //
  280. // Function: KerbStringToUnicodeString()
  281. //
  282. // Synopsis: Takes a ansi string and (1) unicodes it, (2) copies it
  283. //
  284. // Effects:
  285. //
  286. // Arguments: pDest must be initialized unicode string
  287. //
  288. // Requires:
  289. //
  290. // Returns: Free .buffer using KerbFree()
  291. //
  292. // Notes:
  293. //
  294. //--------------------------------------------------------------------------
  295. BOOLEAN
  296. KerbMbStringToUnicodeString(PUNICODE_STRING pDest,
  297. char * pszString)
  298. {
  299. USHORT cbNewString;
  300. USHORT cbOriginalString;
  301. cbOriginalString = strlen(pszString) + 1;
  302. cbNewString = cbOriginalString * sizeof(WCHAR);
  303. pDest->Buffer = NULL;
  304. pDest->Buffer = (PWSTR) KerbAllocate(cbNewString);
  305. if (NULL == pDest->Buffer)
  306. {
  307. return FALSE;
  308. }
  309. if (pDest->Buffer)
  310. {
  311. if (MultiByteToWideChar(CP_OEMCP, MB_PRECOMPOSED,
  312. pszString, cbOriginalString,
  313. pDest->Buffer, cbOriginalString))
  314. {
  315. pDest->Length = cbNewString;
  316. pDest->MaximumLength = cbNewString;
  317. }
  318. else
  319. {
  320. KerbFree(pDest->Buffer);
  321. pDest->Buffer = NULL;
  322. return FALSE;
  323. }
  324. }
  325. return TRUE;
  326. }
  327. #ifndef WIN32_CHICAGO
  328. //+-------------------------------------------------------------------------
  329. //
  330. // Function: KerbWaitForEvent
  331. //
  332. // Synopsis: Wait up to Timeout seconds for EventName to be triggered.
  333. //
  334. // Effects:
  335. //
  336. // Arguments: EventName - Name of event to wait on
  337. // Timeout - Timeout for event (in seconds).
  338. //
  339. // Requires:
  340. //
  341. // Returns: STATUS_SUCCESS - Indicates Event was set.
  342. // STATUS_NETLOGON_NOT_STARTED - Timeout occurred.
  343. //
  344. //
  345. // Notes:
  346. //
  347. //
  348. //--------------------------------------------------------------------------
  349. NTSTATUS
  350. KerbWaitForEvent(
  351. IN LPWSTR EventName,
  352. IN ULONG Timeout
  353. )
  354. {
  355. NTSTATUS Status;
  356. HANDLE EventHandle;
  357. OBJECT_ATTRIBUTES EventAttributes;
  358. UNICODE_STRING EventNameString;
  359. LARGE_INTEGER LocalTimeout;
  360. //
  361. // Create an event for us to wait on.
  362. //
  363. RtlInitUnicodeString( &EventNameString, EventName);
  364. InitializeObjectAttributes( &EventAttributes, &EventNameString, 0, 0, NULL);
  365. Status = NtCreateEvent(
  366. &EventHandle,
  367. SYNCHRONIZE,
  368. &EventAttributes,
  369. NotificationEvent,
  370. (BOOLEAN) FALSE // The event is initially not signaled
  371. );
  372. if ( !NT_SUCCESS(Status)) {
  373. //
  374. // If the event already exists, the server beat us to creating it.
  375. // Just open it.
  376. //
  377. if( Status == STATUS_OBJECT_NAME_EXISTS ||
  378. Status == STATUS_OBJECT_NAME_COLLISION ) {
  379. Status = NtOpenEvent( &EventHandle,
  380. SYNCHRONIZE,
  381. &EventAttributes );
  382. }
  383. if ( !NT_SUCCESS(Status)) {
  384. KdPrint(("[MSV1_0] OpenEvent failed %lx\n", Status ));
  385. return Status;
  386. }
  387. }
  388. //
  389. // Wait for NETLOGON to initialize. Wait a maximum of Timeout seconds.
  390. //
  391. LocalTimeout.QuadPart = ((LONGLONG)(Timeout)) * (-10000000);
  392. Status = NtWaitForSingleObject( EventHandle, (BOOLEAN)FALSE, &LocalTimeout);
  393. (VOID) NtClose( EventHandle );
  394. if ( !NT_SUCCESS(Status) || Status == STATUS_TIMEOUT ) {
  395. if ( Status == STATUS_TIMEOUT ) {
  396. Status = STATUS_NETLOGON_NOT_STARTED; // Map to an error condition
  397. }
  398. return Status;
  399. }
  400. return STATUS_SUCCESS;
  401. }
  402. //+-------------------------------------------------------------------------
  403. //
  404. // Function: KerbWaitForKdc
  405. //
  406. // Synopsis: Wait up to Timeout seconds for the netlogon service to start.
  407. //
  408. // Effects:
  409. //
  410. // Arguments: Timeout - Timeout for netlogon (in seconds).
  411. //
  412. // Requires:
  413. //
  414. // Returns: STATUS_SUCCESS - Indicates NETLOGON successfully initialized.
  415. // STATUS_NETLOGON_NOT_STARTED - Timeout occurred.
  416. //
  417. // Notes:
  418. //
  419. //
  420. //--------------------------------------------------------------------------
  421. NTSTATUS
  422. KerbWaitForKdc(
  423. IN ULONG Timeout
  424. )
  425. {
  426. NTSTATUS Status;
  427. ULONG NetStatus;
  428. SC_HANDLE ScManagerHandle = NULL;
  429. SC_HANDLE ServiceHandle = NULL;
  430. SERVICE_STATUS ServiceStatus;
  431. LPQUERY_SERVICE_CONFIG ServiceConfig;
  432. LPQUERY_SERVICE_CONFIG AllocServiceConfig = NULL;
  433. QUERY_SERVICE_CONFIG DummyServiceConfig;
  434. DWORD ServiceConfigSize;
  435. BOOLEAN AutoStart = FALSE;
  436. //
  437. // If the KDC service is currently running,
  438. // skip the rest of the tests.
  439. //
  440. Status = KerbWaitForEvent( KDC_START_EVENT, 0 );
  441. if ( NT_SUCCESS(Status) ) {
  442. KerbKdcStarted = TRUE;
  443. return Status;
  444. }
  445. //
  446. // Open a handle to the KDC Service.
  447. //
  448. ScManagerHandle = OpenSCManager(
  449. NULL,
  450. NULL,
  451. SC_MANAGER_CONNECT );
  452. if (ScManagerHandle == NULL) {
  453. DebugLog((DEB_ERROR, " KerbWaitForKdc: OpenSCManager failed: "
  454. "%lu. %ws, line %d\n", GetLastError(), THIS_FILE, __LINE__));
  455. Status = STATUS_NETLOGON_NOT_STARTED;
  456. goto Cleanup;
  457. }
  458. ServiceHandle = OpenService(
  459. ScManagerHandle,
  460. SERVICE_KDC,
  461. SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG );
  462. if ( ServiceHandle == NULL ) {
  463. D_DebugLog((DEB_ERROR, "KerbWaitForKdc: OpenService failed: "
  464. "%lu. %ws, line %d\n", GetLastError(), THIS_FILE, __LINE__));
  465. Status = STATUS_NETLOGON_NOT_STARTED;
  466. goto Cleanup;
  467. }
  468. //
  469. // If the KDC service isn't configured to be automatically started
  470. // by the service controller, don't bother waiting for it to start -
  471. // just check to see if it is started.
  472. //
  473. // ?? Pass "DummyServiceConfig" and "sizeof(..)" since QueryService config
  474. // won't allow a null pointer, yet.
  475. if ( QueryServiceConfig(
  476. ServiceHandle,
  477. &DummyServiceConfig,
  478. sizeof(DummyServiceConfig),
  479. &ServiceConfigSize )) {
  480. ServiceConfig = &DummyServiceConfig;
  481. } else {
  482. NetStatus = GetLastError();
  483. if ( NetStatus != ERROR_INSUFFICIENT_BUFFER ) {
  484. D_DebugLog((DEB_ERROR,"KerbWaitForKdc: QueryServiceConfig failed: "
  485. "%lu. %ws, line %d\n", NetStatus, THIS_FILE, __LINE__));
  486. Status = STATUS_NETLOGON_NOT_STARTED;
  487. goto Cleanup;
  488. }
  489. AllocServiceConfig = (LPQUERY_SERVICE_CONFIG) KerbAllocate( ServiceConfigSize );
  490. ServiceConfig = AllocServiceConfig;
  491. if ( AllocServiceConfig == NULL ) {
  492. Status = STATUS_NO_MEMORY;
  493. goto Cleanup;
  494. }
  495. if ( !QueryServiceConfig(
  496. ServiceHandle,
  497. ServiceConfig,
  498. ServiceConfigSize,
  499. &ServiceConfigSize )) {
  500. D_DebugLog((DEB_ERROR, "KerbWaitForKdc: QueryServiceConfig "
  501. "failed again: %lu. %ws, line %d\n", GetLastError(), THIS_FILE, __LINE__));
  502. Status = STATUS_NETLOGON_NOT_STARTED;
  503. goto Cleanup;
  504. }
  505. }
  506. if ( ServiceConfig->dwStartType == SERVICE_AUTO_START ) {
  507. AutoStart = TRUE;
  508. }
  509. //
  510. // Loop waiting for the KDC service to start.
  511. //
  512. for (;;) {
  513. //
  514. // Query the status of the KDC service.
  515. //
  516. if (! QueryServiceStatus( ServiceHandle, &ServiceStatus )) {
  517. D_DebugLog((DEB_ERROR, "KerbWaitForKdc: QueryServiceStatus failed: "
  518. "%lu. %ws, line %d\n", GetLastError(), THIS_FILE, __LINE__ ));
  519. Status = STATUS_NETLOGON_NOT_STARTED;
  520. goto Cleanup;
  521. }
  522. //
  523. // Return or continue waiting depending on the state of
  524. // the KDC service.
  525. //
  526. switch( ServiceStatus.dwCurrentState) {
  527. case SERVICE_RUNNING:
  528. Status = STATUS_SUCCESS;
  529. goto Cleanup;
  530. case SERVICE_STOPPED:
  531. //
  532. // If KDC failed to start,
  533. // error out now. The caller has waited long enough to start.
  534. //
  535. if ( ServiceStatus.dwWin32ExitCode != ERROR_SERVICE_NEVER_STARTED ){
  536. #if DBG
  537. D_DebugLog((DEB_ERROR, "KerbWaitForKdc: "
  538. "KDC service couldn't start: %lu %lx. %ws, line %d\n",
  539. ServiceStatus.dwWin32ExitCode,
  540. ServiceStatus.dwWin32ExitCode, THIS_FILE, __LINE__ ));
  541. if ( ServiceStatus.dwWin32ExitCode == ERROR_SERVICE_SPECIFIC_ERROR ) {
  542. D_DebugLog((DEB_ERROR, " Service specific error code: %lu %lx. %ws, line %d\n",
  543. ServiceStatus.dwServiceSpecificExitCode,
  544. ServiceStatus.dwServiceSpecificExitCode,
  545. THIS_FILE, __LINE__ ));
  546. }
  547. #endif // DBG
  548. Status = STATUS_NETLOGON_NOT_STARTED;
  549. goto Cleanup;
  550. }
  551. //
  552. // If KDC has never been started on this boot,
  553. // continue waiting for it to start.
  554. //
  555. break;
  556. //
  557. // If KDC is trying to start up now,
  558. // continue waiting for it to start.
  559. //
  560. case SERVICE_START_PENDING:
  561. break;
  562. //
  563. // Any other state is bogus.
  564. //
  565. default:
  566. D_DebugLog((DEB_ERROR, "KerbWaitForKdc: "
  567. "Invalid service state: %lu. %ws, line %d\n",
  568. ServiceStatus.dwCurrentState, THIS_FILE, __LINE__ ));
  569. Status = STATUS_NETLOGON_NOT_STARTED;
  570. goto Cleanup;
  571. }
  572. //
  573. // If the service wasn't auto start, don't bother waiting and
  574. // retrying
  575. //
  576. if ((ServiceStatus.dwCurrentState) != SERVICE_START_PENDING && !AutoStart) {
  577. break;
  578. }
  579. //
  580. // Wait a second for the KDC service to start.
  581. // If it has successfully started, just return now.
  582. //
  583. Status = KerbWaitForEvent( KDC_START_EVENT, 1 );
  584. if ( Status != STATUS_NETLOGON_NOT_STARTED ) {
  585. goto Cleanup;
  586. }
  587. //
  588. // If we've waited long enough for KDC to start,
  589. // time out now.
  590. //
  591. if ( (--Timeout) == 0 ) {
  592. Status = STATUS_NETLOGON_NOT_STARTED;
  593. goto Cleanup;
  594. }
  595. }
  596. /* NOT REACHED */
  597. Cleanup:
  598. if ( ScManagerHandle != NULL ) {
  599. (VOID) CloseServiceHandle(ScManagerHandle);
  600. }
  601. if ( ServiceHandle != NULL ) {
  602. (VOID) CloseServiceHandle(ServiceHandle);
  603. }
  604. if ( AllocServiceConfig != NULL ) {
  605. KerbFree( AllocServiceConfig );
  606. }
  607. if (NT_SUCCESS(Status)) {
  608. KerbKdcStarted = TRUE;
  609. } else {
  610. KerbKdcStarted = FALSE;
  611. }
  612. return Status;
  613. }
  614. //+-------------------------------------------------------------------------
  615. //
  616. // Function: KerbWaitForService
  617. //
  618. // Synopsis: Wait up to Timeout seconds for the service to start.
  619. //
  620. // Effects:
  621. //
  622. // Arguments: ServiceName - Name of service to wait for
  623. // ServiceEvent - Optionally has event name signalling that
  624. // service is started
  625. // Timeout - Timeout for netlogon (in seconds).
  626. //
  627. // Requires:
  628. //
  629. // Returns: STATUS_SUCCESS - Indicates NETLOGON successfully initialized.
  630. // STATUS_NETLOGON_NOT_STARTED - Timeout occurred.
  631. //
  632. // Notes:
  633. //
  634. //
  635. //--------------------------------------------------------------------------
  636. NTSTATUS
  637. KerbWaitForService(
  638. IN LPWSTR ServiceName,
  639. IN OPTIONAL LPWSTR ServiceEvent,
  640. IN ULONG Timeout
  641. )
  642. {
  643. NTSTATUS Status = STATUS_SUCCESS;
  644. ULONG NetStatus;
  645. SC_HANDLE ScManagerHandle = NULL;
  646. SC_HANDLE ServiceHandle = NULL;
  647. SERVICE_STATUS ServiceStatus;
  648. LPQUERY_SERVICE_CONFIG ServiceConfig;
  649. LPQUERY_SERVICE_CONFIG AllocServiceConfig = NULL;
  650. QUERY_SERVICE_CONFIG DummyServiceConfig;
  651. DWORD ServiceConfigSize;
  652. BOOLEAN AutoStart = FALSE;
  653. if (ARGUMENT_PRESENT(ServiceEvent))
  654. {
  655. //
  656. // If the KDC service is currently running,
  657. // skip the rest of the tests.
  658. //
  659. Status = KerbWaitForEvent( ServiceEvent, 0 );
  660. if ( NT_SUCCESS(Status) ) {
  661. return Status;
  662. }
  663. }
  664. //
  665. // Open a handle to the Service.
  666. //
  667. ScManagerHandle = OpenSCManager(
  668. NULL,
  669. NULL,
  670. SC_MANAGER_CONNECT );
  671. if (ScManagerHandle == NULL) {
  672. D_DebugLog((DEB_ERROR, " KerbWaitForService: OpenSCManager failed: "
  673. "%lu. %ws, line %d\n", GetLastError(), THIS_FILE, __LINE__));
  674. Status = STATUS_NETLOGON_NOT_STARTED;
  675. goto Cleanup;
  676. }
  677. ServiceHandle = OpenService(
  678. ScManagerHandle,
  679. ServiceName,
  680. SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG );
  681. if ( ServiceHandle == NULL ) {
  682. D_DebugLog((DEB_ERROR, "KerbWaitForService: OpenService failed: "
  683. "%lu. %ws, line %d\n", GetLastError(), THIS_FILE, __LINE__));
  684. Status = STATUS_NETLOGON_NOT_STARTED;
  685. goto Cleanup;
  686. }
  687. //
  688. // If the KDC service isn't configured to be automatically started
  689. // by the service controller, don't bother waiting for it to start -
  690. // just check to see if it is started.
  691. //
  692. // ?? Pass "DummyServiceConfig" and "sizeof(..)" since QueryService config
  693. // won't allow a null pointer, yet.
  694. if ( QueryServiceConfig(
  695. ServiceHandle,
  696. &DummyServiceConfig,
  697. sizeof(DummyServiceConfig),
  698. &ServiceConfigSize )) {
  699. ServiceConfig = &DummyServiceConfig;
  700. } else {
  701. NetStatus = GetLastError();
  702. if ( NetStatus != ERROR_INSUFFICIENT_BUFFER ) {
  703. D_DebugLog((DEB_ERROR,"KerbWaitForService: QueryServiceConfig failed: "
  704. "%lu. %ws, line %d\n", NetStatus, THIS_FILE, __LINE__));
  705. Status = STATUS_NETLOGON_NOT_STARTED;
  706. goto Cleanup;
  707. }
  708. AllocServiceConfig = (LPQUERY_SERVICE_CONFIG) KerbAllocate( ServiceConfigSize );
  709. ServiceConfig = AllocServiceConfig;
  710. if ( AllocServiceConfig == NULL ) {
  711. Status = STATUS_NO_MEMORY;
  712. goto Cleanup;
  713. }
  714. if ( !QueryServiceConfig(
  715. ServiceHandle,
  716. ServiceConfig,
  717. ServiceConfigSize,
  718. &ServiceConfigSize )) {
  719. D_DebugLog((DEB_ERROR, "KerbWaitForService: QueryServiceConfig "
  720. "failed again: %lu. %ws, line %d\n", GetLastError(), THIS_FILE, __LINE__));
  721. Status = STATUS_NETLOGON_NOT_STARTED;
  722. goto Cleanup;
  723. }
  724. }
  725. if ( ServiceConfig->dwStartType == SERVICE_AUTO_START ) {
  726. AutoStart = TRUE;
  727. }
  728. //
  729. // Loop waiting for the KDC service to start.
  730. //
  731. for (;;) {
  732. //
  733. // Query the status of the KDC service.
  734. //
  735. if (! QueryServiceStatus( ServiceHandle, &ServiceStatus )) {
  736. D_DebugLog((DEB_ERROR, "KerbWaitForService: QueryServiceStatus failed: "
  737. "%lu. %ws, line %d\n", GetLastError(), THIS_FILE, __LINE__ ));
  738. Status = STATUS_NETLOGON_NOT_STARTED;
  739. goto Cleanup;
  740. }
  741. //
  742. // Return or continue waiting depending on the state of
  743. // the KDC service.
  744. //
  745. switch( ServiceStatus.dwCurrentState) {
  746. case SERVICE_RUNNING:
  747. Status = STATUS_SUCCESS;
  748. goto Cleanup;
  749. case SERVICE_STOPPED:
  750. //
  751. // If KDC failed to start,
  752. // error out now. The caller has waited long enough to start.
  753. //
  754. if ( ServiceStatus.dwWin32ExitCode != ERROR_SERVICE_NEVER_STARTED ){
  755. #if DBG
  756. D_DebugLog((DEB_ERROR, "KerbWaitForService: "
  757. "%ws service couldn't start: %lu %lx. %ws, line %d\n",
  758. ServiceName,
  759. ServiceStatus.dwWin32ExitCode,
  760. ServiceStatus.dwWin32ExitCode, THIS_FILE, __LINE__ ));
  761. if ( ServiceStatus.dwWin32ExitCode == ERROR_SERVICE_SPECIFIC_ERROR ) {
  762. D_DebugLog((DEB_ERROR, " Service specific error code: %lu %lx. %ws, line %d\n",
  763. ServiceStatus.dwServiceSpecificExitCode,
  764. ServiceStatus.dwServiceSpecificExitCode,
  765. THIS_FILE, __LINE__ ));
  766. }
  767. #endif // DBG
  768. Status = STATUS_NETLOGON_NOT_STARTED;
  769. goto Cleanup;
  770. }
  771. //
  772. // If service has never been started on this boot,
  773. // continue waiting for it to start.
  774. //
  775. break;
  776. //
  777. // If service is trying to start up now,
  778. // continue waiting for it to start.
  779. //
  780. case SERVICE_START_PENDING:
  781. break;
  782. //
  783. // Any other state is bogus.
  784. //
  785. default:
  786. D_DebugLog((DEB_ERROR, "KerbWaitForService: "
  787. "Invalid service state: %lu. %ws, line %d\n",
  788. ServiceStatus.dwCurrentState, THIS_FILE, __LINE__ ));
  789. Status = STATUS_NETLOGON_NOT_STARTED;
  790. goto Cleanup;
  791. }
  792. //
  793. // If the service wasn't auto start, don't bother waiting and
  794. // retrying
  795. //
  796. if (!AutoStart) {
  797. break;
  798. }
  799. //
  800. // Wait a second for the KDC service to start.
  801. // If it has successfully started, just return now.
  802. //
  803. if (ARGUMENT_PRESENT(ServiceEvent))
  804. {
  805. Status = KerbWaitForEvent( ServiceEvent, 1 );
  806. if ( Status != STATUS_NETLOGON_NOT_STARTED ) {
  807. goto Cleanup;
  808. }
  809. }
  810. else
  811. {
  812. Sleep(1000);
  813. }
  814. //
  815. // If we've waited long enough for KDC to start,
  816. // time out now.
  817. //
  818. if ( (--Timeout) == 0 ) {
  819. Status = STATUS_NETLOGON_NOT_STARTED;
  820. goto Cleanup;
  821. }
  822. }
  823. /* NOT REACHED */
  824. Cleanup:
  825. if ( ScManagerHandle != NULL ) {
  826. (VOID) CloseServiceHandle(ScManagerHandle);
  827. }
  828. if ( ServiceHandle != NULL ) {
  829. (VOID) CloseServiceHandle(ServiceHandle);
  830. }
  831. if ( AllocServiceConfig != NULL ) {
  832. KerbFree( AllocServiceConfig );
  833. }
  834. return Status;
  835. }
  836. #endif // WIN32_CHICAGO
  837. //+-------------------------------------------------------------------------
  838. //
  839. // Function: KerbMapContextFlags
  840. //
  841. // Synopsis: Maps the ISC_RET_xx flags to ASC_RET_xxx flags
  842. //
  843. // Effects:
  844. //
  845. // Arguments: ContextFlags - Flags to map
  846. //
  847. // Requires:
  848. //
  849. // Returns:
  850. //
  851. // Notes:
  852. //
  853. //
  854. //--------------------------------------------------------------------------
  855. struct _KERB_FLAG_MAPPING {
  856. ULONG InitFlag;
  857. ULONG AcceptFlag;
  858. } KerbContextFlagMappingTable[] = {
  859. {ISC_RET_EXTENDED_ERROR, ASC_RET_EXTENDED_ERROR},
  860. {ISC_RET_INTEGRITY , ASC_RET_INTEGRITY },
  861. {ISC_RET_IDENTIFY, ASC_RET_IDENTIFY },
  862. {ISC_RET_NULL_SESSION, ASC_RET_NULL_SESSION }
  863. };
  864. #define KERB_CONTEXT_FLAG_IDENTICAL 0xFFF & ~( ISC_RET_USED_COLLECTED_CREDS | ISC_RET_USED_SUPPLIED_CREDS)
  865. ULONG
  866. KerbMapContextFlags(
  867. IN ULONG ContextFlags
  868. )
  869. {
  870. ULONG OutputFlags;
  871. ULONG Index;
  872. //
  873. // First copy the identical flags
  874. //
  875. OutputFlags = ContextFlags & KERB_CONTEXT_FLAG_IDENTICAL;
  876. for (Index = 0; Index < sizeof(KerbContextFlagMappingTable) / (2 * sizeof(ULONG)) ;Index++ )
  877. {
  878. if ((ContextFlags & KerbContextFlagMappingTable[Index].InitFlag) != 0)
  879. {
  880. OutputFlags |= KerbContextFlagMappingTable[Index].AcceptFlag;
  881. }
  882. }
  883. return(OutputFlags);
  884. }
  885. //+-------------------------------------------------------------------------
  886. //
  887. // Function: KerbIsIpAddress
  888. //
  889. // Synopsis: Checks to see if a target name is an IP address
  890. //
  891. // Effects: none
  892. //
  893. // Arguments: TargetName - Name to check
  894. //
  895. // Requires:
  896. //
  897. // Returns: TRUE if the name is an ip address
  898. //
  899. // Notes: IP address consist of only digits and periods, possibly
  900. // with a terminating '$'.
  901. //
  902. //
  903. //--------------------------------------------------------------------------
  904. BOOLEAN
  905. KerbIsIpAddress(
  906. IN PUNICODE_STRING TargetName
  907. )
  908. {
  909. ULONG Index;
  910. ULONG PeriodCount = 0;
  911. //
  912. // Null names are not IP addresses.
  913. //
  914. if (!ARGUMENT_PRESENT(TargetName) || (TargetName->Length == 0))
  915. {
  916. return(FALSE);
  917. }
  918. for (Index = 0; Index < TargetName->Length/sizeof(WCHAR) ; Index++ )
  919. {
  920. switch(TargetName->Buffer[Index])
  921. {
  922. case L'0':
  923. case L'1':
  924. case L'2':
  925. case L'3':
  926. case L'4':
  927. case L'5':
  928. case L'6':
  929. case L'7':
  930. case L'8':
  931. case L'9':
  932. continue;
  933. case L'$':
  934. //
  935. // Only allow this at the end.
  936. //
  937. if (Index != (TargetName->Length/sizeof(WCHAR) -1) )
  938. {
  939. return(FALSE);
  940. }
  941. continue;
  942. case L'.':
  943. PeriodCount++;
  944. break;
  945. default:
  946. return(FALSE);
  947. }
  948. }
  949. //
  950. // We require a period in the name, so return the FoundPeriod flag
  951. //
  952. if (PeriodCount == 3)
  953. {
  954. return(TRUE);
  955. }
  956. else
  957. {
  958. return(FALSE);
  959. }
  960. }
  961. //+-------------------------------------------------------------------------
  962. //
  963. // Function: KerbHidePassword
  964. //
  965. // Synopsis: obscures a password in memory
  966. //
  967. // Effects:
  968. //
  969. // Arguments:
  970. //
  971. // Requires:
  972. //
  973. // Returns:
  974. //
  975. // Notes:
  976. //
  977. //
  978. //--------------------------------------------------------------------------
  979. VOID
  980. KerbHidePassword(
  981. IN OUT PUNICODE_STRING Password
  982. )
  983. {
  984. LsaFunctions->LsaProtectMemory(
  985. Password->Buffer,
  986. (ULONG)Password->MaximumLength
  987. );
  988. }
  989. //+-------------------------------------------------------------------------
  990. //
  991. // Function: KerbRevealPassword
  992. //
  993. // Synopsis: Reveals a password that has been hidden
  994. //
  995. // Effects:
  996. //
  997. // Arguments:
  998. //
  999. // Requires:
  1000. //
  1001. // Returns:
  1002. //
  1003. // Notes:
  1004. //
  1005. //
  1006. //--------------------------------------------------------------------------
  1007. VOID
  1008. KerbRevealPassword(
  1009. IN OUT PUNICODE_STRING HiddenPassword
  1010. )
  1011. {
  1012. LsaFunctions->LsaUnprotectMemory(
  1013. HiddenPassword->Buffer,
  1014. (ULONG)HiddenPassword->MaximumLength
  1015. );
  1016. }
  1017. //+-------------------------------------------------------------------------
  1018. //
  1019. // Function: KerbDuplicatePassword
  1020. //
  1021. // Synopsis: Duplicates a UNICODE_STRING. If the source string buffer is
  1022. // NULL the destionation will be too. The MaximumLength contains
  1023. // room for encryption padding data.
  1024. //
  1025. // Effects: allocates memory with LsaFunctions.AllocateLsaHeap
  1026. //
  1027. // Arguments: DestinationString - Receives a copy of the source string
  1028. // SourceString - String to copy
  1029. //
  1030. // Requires:
  1031. //
  1032. // Notes:
  1033. //
  1034. //
  1035. //--------------------------------------------------------------------------
  1036. NTSTATUS
  1037. KerbDuplicatePassword(
  1038. OUT PUNICODE_STRING DestinationString,
  1039. IN OPTIONAL PUNICODE_STRING SourceString
  1040. )
  1041. {
  1042. NTSTATUS Status = STATUS_SUCCESS;
  1043. DestinationString->Buffer = NULL;
  1044. DestinationString->Length =
  1045. DestinationString->MaximumLength =
  1046. 0;
  1047. if ((ARGUMENT_PRESENT(SourceString)) &&
  1048. (SourceString->Buffer != NULL))
  1049. {
  1050. USHORT PaddingLength;
  1051. PaddingLength = RTL_ENCRYPT_MEMORY_SIZE - (SourceString->Length % RTL_ENCRYPT_MEMORY_SIZE);
  1052. if( PaddingLength == RTL_ENCRYPT_MEMORY_SIZE )
  1053. {
  1054. PaddingLength = 0;
  1055. }
  1056. DestinationString->Buffer = (LPWSTR) MIDL_user_allocate(
  1057. SourceString->Length +
  1058. PaddingLength
  1059. );
  1060. if (DestinationString->Buffer != NULL)
  1061. {
  1062. DestinationString->Length = SourceString->Length;
  1063. DestinationString->MaximumLength = SourceString->Length + PaddingLength;
  1064. if( DestinationString->MaximumLength == SourceString->MaximumLength )
  1065. {
  1066. //
  1067. // duplicating an already padded buffer -- pickup the original
  1068. // pad.
  1069. //
  1070. RtlCopyMemory(
  1071. DestinationString->Buffer,
  1072. SourceString->Buffer,
  1073. SourceString->MaximumLength
  1074. );
  1075. } else {
  1076. //
  1077. // duplicating an unpadded buffer -- pickup only the string
  1078. // and fill the rest with pad.
  1079. //
  1080. RtlCopyMemory(
  1081. DestinationString->Buffer,
  1082. SourceString->Buffer,
  1083. SourceString->Length
  1084. );
  1085. }
  1086. }
  1087. else
  1088. {
  1089. Status = STATUS_NO_MEMORY;
  1090. }
  1091. }
  1092. return Status;
  1093. }
  1094. #ifdef notdef
  1095. // use this if we ever need to map errors in kerb to something else.
  1096. //+-------------------------------------------------------------------------
  1097. //
  1098. // Function: KerbMapKerbNtStatusToNtStatus
  1099. //
  1100. // Synopsis: Maps an NT status code to a security status
  1101. // Here's the package's chance to send back generic NtStatus
  1102. // errors
  1103. //
  1104. // Effects:
  1105. //
  1106. // Arguments:
  1107. //
  1108. // Requires:
  1109. //
  1110. // Returns:
  1111. //
  1112. //
  1113. //
  1114. //--------------------------------------------------------------------------
  1115. NTSTATUS
  1116. KerbMapKerbNtStatusToNtStatus(
  1117. IN NTSTATUS Status
  1118. )
  1119. {
  1120. return(Status);
  1121. }
  1122. #endif
  1123. void * __cdecl
  1124. operator new(
  1125. size_t nSize
  1126. )
  1127. {
  1128. return((LPVOID)LocalAlloc(LPTR, nSize));
  1129. }
  1130. void __cdecl
  1131. operator delete(
  1132. void *pv
  1133. )
  1134. {
  1135. LocalFree((HLOCAL)pv);
  1136. }
  1137. //+-------------------------------------------------------------------------
  1138. //
  1139. // Function: KerbExtractDomainName
  1140. //
  1141. // Synopsis: Extracts the domain name from a principal name
  1142. //
  1143. // Effects: Allocates the destination string
  1144. //
  1145. // Arguments:
  1146. //
  1147. // Requires:
  1148. //
  1149. // Returns:
  1150. //
  1151. // Notes:
  1152. //
  1153. //
  1154. //--------------------------------------------------------------------------
  1155. NTSTATUS
  1156. KerbExtractDomainName(
  1157. OUT PUNICODE_STRING DomainName,
  1158. IN PKERB_INTERNAL_NAME PrincipalName,
  1159. IN PUNICODE_STRING TicketSourceDomain
  1160. )
  1161. {
  1162. NTSTATUS Status = STATUS_SUCCESS;
  1163. UNICODE_STRING TempPrincipal;
  1164. UNICODE_STRING TempDomain = NULL_UNICODE_STRING;
  1165. EMPTY_UNICODE_STRING( DomainName );
  1166. //
  1167. // We do different things depending on the name type:
  1168. // - for NT_MS_PRINCIPAL we call KerbSplitFullServiceName, then do the
  1169. // same as for other name types
  1170. // - For all other names, if the first portion is "krbtgt" then
  1171. // we use the second portion of the name, otherwise the
  1172. // TicketSourceRealm
  1173. //
  1174. if (PrincipalName->NameType == KRB_NT_MS_PRINCIPAL)
  1175. {
  1176. if (PrincipalName->NameCount != 1)
  1177. {
  1178. D_DebugLog((DEB_ERROR,"Principal name has more than one name. %ws, line %d\n", THIS_FILE, __LINE__ ));
  1179. Status = STATUS_TOO_MANY_PRINCIPALS;
  1180. return(Status);
  1181. }
  1182. else
  1183. {
  1184. Status = KerbSplitFullServiceName(
  1185. &PrincipalName->Names[0],
  1186. &TempDomain,
  1187. &TempPrincipal
  1188. );
  1189. if (!NT_SUCCESS(Status))
  1190. {
  1191. return(Status);
  1192. }
  1193. }
  1194. }
  1195. else
  1196. {
  1197. //
  1198. // The principal name is the first portion. If there are exactly
  1199. // two portions, the domain name is the second portion
  1200. //
  1201. TempPrincipal = PrincipalName->Names[0];
  1202. if (PrincipalName->NameCount == 2)
  1203. {
  1204. TempDomain = PrincipalName->Names[1];
  1205. }
  1206. else
  1207. {
  1208. TempDomain = *TicketSourceDomain;
  1209. }
  1210. }
  1211. //
  1212. // Check to see if the principal is "krbtgt" - if it is, the domain
  1213. // is TempDomain - otherwise it is TicketSourceDomain.
  1214. //
  1215. if (RtlEqualUnicodeString(
  1216. &TempPrincipal,
  1217. &KerbGlobalKdcServiceName,
  1218. TRUE // case insensitive
  1219. ))
  1220. {
  1221. Status = KerbDuplicateString(
  1222. DomainName,
  1223. &TempDomain
  1224. );
  1225. }
  1226. else
  1227. {
  1228. Status = KerbDuplicateString(
  1229. DomainName,
  1230. TicketSourceDomain
  1231. );
  1232. }
  1233. return(Status);
  1234. }
  1235. //+-------------------------------------------------------------------------
  1236. //
  1237. // Function: KerbUtcTimeToLocalTime
  1238. //
  1239. // Synopsis: Converts system time (used internally) to local time, which
  1240. // is returned to callers.
  1241. //
  1242. // Effects:
  1243. //
  1244. // Arguments:
  1245. //
  1246. // Requires:
  1247. //
  1248. // Returns:
  1249. //
  1250. // Notes:
  1251. //
  1252. //
  1253. //--------------------------------------------------------------------------
  1254. VOID
  1255. KerbUtcTimeToLocalTime(
  1256. OUT PTimeStamp LocalTime,
  1257. IN PTimeStamp SystemTime
  1258. )
  1259. {
  1260. #ifndef WIN32_CHICAGO
  1261. NTSTATUS Status;
  1262. Status = RtlSystemTimeToLocalTime(
  1263. SystemTime,
  1264. LocalTime
  1265. );
  1266. DsysAssert(NT_SUCCESS(Status));
  1267. #else
  1268. BOOL Result;
  1269. Result = FileTimeToLocalFileTime(
  1270. (PFILETIME) SystemTime,
  1271. (PFILETIME) LocalTime
  1272. );
  1273. DsysAssert(Result);
  1274. #endif
  1275. }
  1276. //+-------------------------------------------------------------------------
  1277. //
  1278. // Function: KerbConvertKdcOptionsToTicketFlags
  1279. //
  1280. // Synopsis:
  1281. //
  1282. // Effects:
  1283. //
  1284. // Arguments:
  1285. //
  1286. // Requires:
  1287. //
  1288. // Returns:
  1289. //
  1290. // Notes:
  1291. //
  1292. //
  1293. //--------------------------------------------------------------------------
  1294. ULONG
  1295. KerbConvertKdcOptionsToTicketFlags(
  1296. IN ULONG KdcOptions
  1297. )
  1298. {
  1299. ULONG TicketFlags = 0;
  1300. if ((KdcOptions & KERB_KDC_OPTIONS_forwardable) != 0)
  1301. {
  1302. TicketFlags |= KERB_TICKET_FLAGS_forwardable;
  1303. }
  1304. if ((KdcOptions & KERB_KDC_OPTIONS_forwarded) != 0)
  1305. {
  1306. TicketFlags |= KERB_TICKET_FLAGS_forwarded;
  1307. }
  1308. if ((KdcOptions & KERB_KDC_OPTIONS_proxiable) != 0)
  1309. {
  1310. TicketFlags |= KERB_TICKET_FLAGS_proxiable;
  1311. }
  1312. if ((KdcOptions & KERB_KDC_OPTIONS_proxy) != 0)
  1313. {
  1314. TicketFlags |= KERB_TICKET_FLAGS_proxy;
  1315. }
  1316. if ((KdcOptions & KERB_KDC_OPTIONS_postdated) != 0)
  1317. {
  1318. TicketFlags |= KERB_TICKET_FLAGS_postdated;
  1319. }
  1320. if ((KdcOptions & KERB_KDC_OPTIONS_allow_postdate) != 0)
  1321. {
  1322. TicketFlags |= KERB_TICKET_FLAGS_may_postdate;
  1323. }
  1324. if ((KdcOptions & KERB_KDC_OPTIONS_renewable) != 0)
  1325. {
  1326. TicketFlags |= KERB_TICKET_FLAGS_renewable;
  1327. }
  1328. if ((KdcOptions & KERB_KDC_OPTIONS_cname_in_pa_data) != 0)
  1329. {
  1330. TicketFlags |= KERB_TICKET_FLAGS_cname_in_pa_data;
  1331. }
  1332. return(TicketFlags);
  1333. }
  1334. //+-------------------------------------------------------------------------
  1335. //
  1336. // Function: KerbGetAddressListFromWinsock
  1337. //
  1338. // Synopsis: gets the list of addresses from a winsock ioctl
  1339. //
  1340. // Effects:
  1341. //
  1342. // Arguments:
  1343. //
  1344. // Requires:
  1345. //
  1346. // Returns:
  1347. //
  1348. // Notes:
  1349. //
  1350. //
  1351. //--------------------------------------------------------------------------
  1352. NTSTATUS
  1353. KerbGetAddressListFromWinsock(
  1354. OUT LPSOCKET_ADDRESS_LIST * SocketAddressList
  1355. )
  1356. {
  1357. ULONG BytesReturned = 150;
  1358. LPSOCKET_ADDRESS_LIST AddressList = NULL;
  1359. INT i,j;
  1360. ULONG NetStatus;
  1361. NTSTATUS Status = STATUS_SUCCESS;
  1362. SOCKET AddressSocket = INVALID_SOCKET;
  1363. #ifdef WIN32_CHICAGO
  1364. j = 0;
  1365. AddressList = (LPSOCKET_ADDRESS_LIST) MIDL_user_allocate(sizeof(SOCKET_ADDRESS_LIST));
  1366. if (AddressList == NULL)
  1367. {
  1368. Status = STATUS_INSUFFICIENT_RESOURCES;
  1369. goto Cleanup;
  1370. }
  1371. #else // WIN32_CHICAGO
  1372. AddressSocket = WSASocket( AF_INET,
  1373. SOCK_DGRAM,
  1374. 0, // PF_INET,
  1375. NULL,
  1376. 0,
  1377. 0 );
  1378. if ( AddressSocket == INVALID_SOCKET ) {
  1379. NetStatus = WSAGetLastError();
  1380. D_DebugLog((DEB_ERROR,"WSASocket failed with %ld. %ws, line %d\n", NetStatus, THIS_FILE, __LINE__ ));
  1381. Status = STATUS_UNSUCCESSFUL;
  1382. goto Cleanup;
  1383. }
  1384. for (;;) {
  1385. //
  1386. // Allocate a buffer that should be big enough.
  1387. //
  1388. if ( AddressList != NULL ) {
  1389. MIDL_user_free( AddressList );
  1390. }
  1391. AddressList = (LPSOCKET_ADDRESS_LIST) MIDL_user_allocate( BytesReturned );
  1392. if ( AddressList == NULL ) {
  1393. Status = STATUS_INSUFFICIENT_RESOURCES;
  1394. goto Cleanup;
  1395. }
  1396. //
  1397. // Get the list of IP addresses
  1398. //
  1399. NetStatus = WSAIoctl( AddressSocket,
  1400. SIO_ADDRESS_LIST_QUERY,
  1401. NULL, // No input buffer
  1402. 0, // No input buffer
  1403. (PVOID) AddressList,
  1404. BytesReturned,
  1405. &BytesReturned,
  1406. NULL, // No overlapped,
  1407. NULL ); // Not async
  1408. if ( NetStatus != 0 ) {
  1409. NetStatus = WSAGetLastError();
  1410. //
  1411. // If the buffer isn't big enough, try again.
  1412. //
  1413. if ( NetStatus == WSAEFAULT ) {
  1414. continue;
  1415. }
  1416. D_DebugLog((DEB_ERROR,"KerbGetAddressListFromWinsock: Cannot WSAIoctl SIO_ADDRESS_LIST_QUERY %ld %ld. %ws, line %d\n",
  1417. NetStatus, BytesReturned, THIS_FILE, __LINE__));
  1418. Status = STATUS_UNSUCCESSFUL;
  1419. goto Cleanup;
  1420. }
  1421. break;
  1422. }
  1423. //
  1424. // Weed out any zero IP addresses and other invalid addresses
  1425. //
  1426. for ( i = 0, j = 0; i < AddressList->iAddressCount; i++ ) {
  1427. PSOCKET_ADDRESS SocketAddress;
  1428. //
  1429. // Copy this address to the front of the list.
  1430. //
  1431. AddressList->Address[j] = AddressList->Address[i];
  1432. //
  1433. // If the address isn't valid,
  1434. // skip it.
  1435. //
  1436. SocketAddress = &AddressList->Address[j];
  1437. if ( SocketAddress->iSockaddrLength == 0 ||
  1438. SocketAddress->lpSockaddr == NULL ||
  1439. SocketAddress->lpSockaddr->sa_family != AF_INET ||
  1440. ((PSOCKADDR_IN)(SocketAddress->lpSockaddr))->sin_addr.s_addr == 0 ) {
  1441. } else {
  1442. //
  1443. // Otherwise keep it.
  1444. //
  1445. j++;
  1446. }
  1447. }
  1448. #endif // WIN32_CHICAGO
  1449. AddressList->iAddressCount = j;
  1450. *SocketAddressList = AddressList;
  1451. AddressList = NULL;
  1452. Cleanup:
  1453. if (AddressList != NULL)
  1454. {
  1455. MIDL_user_free(AddressList);
  1456. }
  1457. if ( AddressSocket != INVALID_SOCKET ) {
  1458. closesocket(AddressSocket);
  1459. }
  1460. return(Status);
  1461. }
  1462. //+-------------------------------------------------------------------------
  1463. //
  1464. // Function: KerbBuildHostAddresses
  1465. //
  1466. // Synopsis: Builds a list of host addresses to go in a KDC request
  1467. //
  1468. // Effects:
  1469. //
  1470. // Arguments:
  1471. //
  1472. // Requires:
  1473. //
  1474. // Returns:
  1475. //
  1476. // Notes:
  1477. //
  1478. //
  1479. //--------------------------------------------------------------------------
  1480. NTSTATUS
  1481. KerbBuildHostAddresses(
  1482. IN BOOLEAN IncludeIpAddresses,
  1483. IN BOOLEAN IncludeNetbiosAddresses,
  1484. OUT PKERB_HOST_ADDRESSES * HostAddresses
  1485. )
  1486. {
  1487. NTSTATUS Status = STATUS_SUCCESS;
  1488. PKERB_HOST_ADDRESSES Addresses = NULL;
  1489. PKERB_HOST_ADDRESSES TempAddress = NULL;
  1490. BOOLEAN LockHeld = FALSE;
  1491. #ifndef WIN32_CHICAGO
  1492. KerbGlobalReadLock();
  1493. LockHeld = TRUE;
  1494. //
  1495. // Check to see if we've gotten out addresses from Netlogon yet.
  1496. //
  1497. if ( IncludeIpAddresses &&
  1498. KerbGlobalIpAddressCount == 0)
  1499. {
  1500. LPSOCKET_ADDRESS_LIST SocketAddressList = NULL;
  1501. KerbGlobalReleaseLock();
  1502. LockHeld = FALSE;
  1503. //
  1504. // We haven't get them now
  1505. //
  1506. Status = KerbGetAddressListFromWinsock(
  1507. &SocketAddressList
  1508. );
  1509. if (NT_SUCCESS(Status))
  1510. {
  1511. Status = KerbUpdateGlobalAddresses(
  1512. SocketAddressList->Address,
  1513. SocketAddressList->iAddressCount
  1514. );
  1515. MIDL_user_free(SocketAddressList);
  1516. }
  1517. else
  1518. {
  1519. KerbGlobalWriteLock();
  1520. KerbGlobalIpAddressesInitialized = TRUE;
  1521. KerbGlobalReleaseLock();
  1522. }
  1523. KerbGlobalReadLock();
  1524. LockHeld = TRUE;
  1525. }
  1526. //
  1527. // On failure don't bother inserting the IP addresses
  1528. //
  1529. if ( Status == STATUS_SUCCESS &&
  1530. IncludeIpAddresses ) {
  1531. ULONG Index;
  1532. for (Index = 0; Index < KerbGlobalIpAddressCount ; Index++ )
  1533. {
  1534. TempAddress = (PKERB_HOST_ADDRESSES) KerbAllocate(sizeof(KERB_HOST_ADDRESSES));
  1535. if (TempAddress == NULL)
  1536. {
  1537. Status = STATUS_INSUFFICIENT_RESOURCES;
  1538. goto Cleanup;
  1539. }
  1540. TempAddress->value.address_type = KERB_ADDRTYPE_INET;
  1541. TempAddress->value.address.length = 4;
  1542. TempAddress->value.address.value = (PUCHAR) KerbAllocate(4);
  1543. if (TempAddress->value.address.value == NULL)
  1544. {
  1545. Status = STATUS_INSUFFICIENT_RESOURCES;
  1546. goto Cleanup;
  1547. }
  1548. RtlCopyMemory
  1549. (
  1550. TempAddress->value.address.value,
  1551. &KerbGlobalIpAddresses[Index].sin_addr.S_un.S_addr,
  1552. 4
  1553. );
  1554. TempAddress->next = Addresses;
  1555. Addresses = TempAddress;
  1556. TempAddress = NULL;
  1557. }
  1558. }
  1559. else
  1560. {
  1561. Status = STATUS_SUCCESS;
  1562. }
  1563. #endif // WIN32_CHICAGO
  1564. //
  1565. // Insert the netbios address (if it will fit)
  1566. //
  1567. if (IncludeNetbiosAddresses &&
  1568. KerbGlobalKerbMachineName.Length < NCBNAMSZ)
  1569. {
  1570. TempAddress = (PKERB_HOST_ADDRESSES) KerbAllocate(sizeof(KERB_HOST_ADDRESSES));
  1571. if (TempAddress == NULL)
  1572. {
  1573. Status = STATUS_INSUFFICIENT_RESOURCES;
  1574. goto Cleanup;
  1575. }
  1576. TempAddress->value.address_type = KERB_ADDRTYPE_NETBIOS;
  1577. TempAddress->value.address.length = NCBNAMSZ;
  1578. TempAddress->value.address.value = (PUCHAR) KerbAllocate(NCBNAMSZ);
  1579. if (TempAddress->value.address.value == NULL)
  1580. {
  1581. Status = STATUS_INSUFFICIENT_RESOURCES;
  1582. goto Cleanup;
  1583. }
  1584. RtlCopyMemory(
  1585. TempAddress->value.address.value,
  1586. KerbGlobalKerbMachineName.Buffer,
  1587. KerbGlobalKerbMachineName.Length
  1588. );
  1589. memset(
  1590. TempAddress->value.address.value + KerbGlobalKerbMachineName.Length,
  1591. ' ', // space
  1592. NCBNAMSZ - KerbGlobalKerbMachineName.Length
  1593. );
  1594. TempAddress->next = Addresses;
  1595. Addresses = TempAddress;
  1596. TempAddress = NULL;
  1597. }
  1598. *HostAddresses = Addresses;
  1599. Addresses = NULL;
  1600. Cleanup:
  1601. if (LockHeld)
  1602. {
  1603. KerbGlobalReleaseLock();
  1604. }
  1605. if (TempAddress != NULL)
  1606. {
  1607. if (TempAddress->value.address.value != NULL)
  1608. {
  1609. KerbFree(TempAddress->value.address.value);
  1610. }
  1611. KerbFree(TempAddress);
  1612. }
  1613. if (Addresses != NULL)
  1614. {
  1615. //KerbFreeHostAddresses(Addresses);
  1616. while (Addresses != NULL)
  1617. {
  1618. TempAddress = Addresses;
  1619. Addresses = Addresses->next;
  1620. if (TempAddress->value.address.value != NULL)
  1621. {
  1622. KerbFree(TempAddress->value.address.value);
  1623. }
  1624. KerbFree(TempAddress);
  1625. }
  1626. }
  1627. return(Status);
  1628. }
  1629. //+-------------------------------------------------------------------------
  1630. //
  1631. // Function: KerbBuildGssErrorMessage
  1632. //
  1633. // Synopsis: Builds an error message with GSS framing, if necessary
  1634. //
  1635. // Effects:
  1636. //
  1637. // Arguments:
  1638. //
  1639. // Requires:
  1640. //
  1641. // Returns:
  1642. //
  1643. // Notes:
  1644. //
  1645. //
  1646. //--------------------------------------------------------------------------
  1647. NTSTATUS
  1648. KerbBuildGssErrorMessage(
  1649. IN KERBERR Error,
  1650. IN PBYTE ErrorData,
  1651. IN ULONG ErrorDataSize,
  1652. IN PKERB_CONTEXT Context,
  1653. OUT PULONG ErrorMessageSize,
  1654. OUT PBYTE * ErrorMessage
  1655. )
  1656. {
  1657. KERBERR KerbErr = KDC_ERR_NONE;
  1658. NTSTATUS Status = STATUS_SUCCESS;
  1659. PBYTE RawErrorMessage = NULL;
  1660. ULONG RawErrorMessageSize = 0;
  1661. PBYTE EncodedErrorData = NULL;
  1662. ULONG EncodedErrorDataSize = 0;
  1663. PBYTE MessageStart = NULL;
  1664. KERB_ERROR_METHOD_DATA ApErrorData = {0};
  1665. PKERB_INTERNAL_NAME Spn = NULL;
  1666. gss_OID MechId;
  1667. //
  1668. // First, convert the error data to a specified type
  1669. //
  1670. if (Error == KRB_AP_ERR_SKEW)
  1671. {
  1672. ApErrorData.data_type = KERB_AP_ERR_TYPE_SKEW_RECOVERY;
  1673. ApErrorData.data_value.value = NULL;
  1674. ApErrorData.data_value.length = 0;
  1675. KerbErr = KerbPackData(
  1676. &ApErrorData,
  1677. KERB_ERROR_METHOD_DATA_PDU,
  1678. &EncodedErrorDataSize,
  1679. &EncodedErrorData
  1680. );
  1681. if (!KERB_SUCCESS(KerbErr))
  1682. {
  1683. Status = KerbMapKerbError(KerbErr);
  1684. goto Cleanup;
  1685. }
  1686. }
  1687. else if (ErrorDataSize != 0)
  1688. {
  1689. if (Error == KRB_AP_ERR_USER_TO_USER_REQUIRED)
  1690. {
  1691. EncodedErrorData = ErrorData;
  1692. EncodedErrorDataSize = ErrorDataSize;
  1693. }
  1694. else
  1695. {
  1696. ApErrorData.data_type = KERB_AP_ERR_TYPE_NTSTATUS;
  1697. ApErrorData.data_value.value = ErrorData;
  1698. ApErrorData.data_value.length = ErrorDataSize;
  1699. ApErrorData.bit_mask |= data_value_present;
  1700. KerbErr = KerbPackData(
  1701. &ApErrorData,
  1702. KERB_ERROR_METHOD_DATA_PDU,
  1703. &EncodedErrorDataSize,
  1704. &EncodedErrorData
  1705. );
  1706. if (!KERB_SUCCESS(KerbErr))
  1707. {
  1708. Status = KerbMapKerbError(KerbErr);
  1709. goto Cleanup;
  1710. }
  1711. }
  1712. }
  1713. //
  1714. // First build the error message
  1715. //
  1716. KerbGlobalReadLock();
  1717. if (Context->ServerPrincipalName.Buffer != NULL)
  1718. {
  1719. KerbErr = KerbConvertStringToKdcName(
  1720. &Spn,
  1721. &Context->ServerPrincipalName
  1722. );
  1723. if (!KERB_SUCCESS(KerbErr))
  1724. {
  1725. Status = KerbMapKerbError(KerbErr);
  1726. goto Cleanup;
  1727. }
  1728. }
  1729. else
  1730. {
  1731. Spn = KerbGlobalInternalMachineServiceName;
  1732. }
  1733. KerbErr = KerbBuildErrorMessageEx(
  1734. Error,
  1735. NULL, // no extended error
  1736. &KerbGlobalDnsDomainName,
  1737. Spn,
  1738. NULL, // no client realm
  1739. EncodedErrorData,
  1740. EncodedErrorDataSize,
  1741. &RawErrorMessageSize,
  1742. &RawErrorMessage
  1743. );
  1744. KerbGlobalReleaseLock();
  1745. if (!KERB_SUCCESS(KerbErr))
  1746. {
  1747. Status = KerbMapKerbError(KerbErr);
  1748. goto Cleanup;
  1749. }
  1750. //
  1751. // Figure out what OID to use
  1752. //
  1753. KerbReadLockContexts();
  1754. //
  1755. // For DCE style we don't use an OID
  1756. //
  1757. if ((Context->ContextFlags & ISC_RET_USED_DCE_STYLE) != 0)
  1758. {
  1759. KerbUnlockContexts();
  1760. *ErrorMessage = RawErrorMessage;
  1761. *ErrorMessageSize = RawErrorMessageSize;
  1762. RawErrorMessage = NULL;
  1763. goto Cleanup;
  1764. }
  1765. if ((Context->ContextAttributes & KERB_CONTEXT_USER_TO_USER) != 0)
  1766. {
  1767. MechId = gss_mech_krb5_u2u;
  1768. }
  1769. else
  1770. {
  1771. MechId = gss_mech_krb5_new;
  1772. }
  1773. KerbUnlockContexts();
  1774. *ErrorMessageSize = g_token_size(MechId, RawErrorMessageSize);
  1775. *ErrorMessage = (PBYTE) KerbAllocate(*ErrorMessageSize);
  1776. if (*ErrorMessage == NULL)
  1777. {
  1778. Status = STATUS_INSUFFICIENT_RESOURCES;
  1779. goto Cleanup;
  1780. }
  1781. //
  1782. // the g_make_token_header will reset this to point to the end of the
  1783. // header
  1784. //
  1785. MessageStart = *ErrorMessage;
  1786. g_make_token_header(
  1787. MechId,
  1788. RawErrorMessageSize,
  1789. &MessageStart,
  1790. KG_TOK_CTX_ERROR
  1791. );
  1792. RtlCopyMemory(
  1793. MessageStart,
  1794. RawErrorMessage,
  1795. RawErrorMessageSize
  1796. );
  1797. Cleanup:
  1798. if (RawErrorMessage != NULL)
  1799. {
  1800. MIDL_user_free(RawErrorMessage);
  1801. }
  1802. if (EncodedErrorData != ErrorData)
  1803. {
  1804. MIDL_user_free(EncodedErrorData);
  1805. }
  1806. if (Spn != NULL && Context->ServerPrincipalName.Buffer != NULL)
  1807. {
  1808. MIDL_user_free(Spn);
  1809. }
  1810. return(Status);
  1811. }
  1812. //+-------------------------------------------------------------------------
  1813. //
  1814. // Function: KerbReceiveErrorMessage
  1815. //
  1816. // Synopsis: Unpacks an error message from a context request
  1817. //
  1818. // Effects:
  1819. //
  1820. // Arguments:
  1821. //
  1822. // Requires:
  1823. //
  1824. // Returns:
  1825. //
  1826. // Notes:
  1827. //
  1828. //
  1829. //--------------------------------------------------------------------------
  1830. NTSTATUS
  1831. KerbReceiveErrorMessage(
  1832. IN PBYTE ErrorMessage,
  1833. IN ULONG ErrorMessageSize,
  1834. IN PKERB_CONTEXT Context,
  1835. OUT PKERB_ERROR * DecodedErrorMessage,
  1836. OUT PKERB_ERROR_METHOD_DATA * ErrorData
  1837. )
  1838. {
  1839. NTSTATUS Status = STATUS_SUCCESS;
  1840. KERBERR KerbErr;
  1841. PBYTE MessageStart = NULL;
  1842. ULONG MessageSize = 0;
  1843. BOOLEAN VerifiedHeader = FALSE;
  1844. gss_OID MechId = NULL;
  1845. KerbReadLockContexts();
  1846. //
  1847. // For DCE style we don't use an OID
  1848. //
  1849. if ((Context->ContextAttributes & KERB_CONTEXT_USER_TO_USER) != 0)
  1850. {
  1851. MechId = gss_mech_krb5_u2u;
  1852. }
  1853. else
  1854. {
  1855. MechId = gss_mech_krb5_new;
  1856. }
  1857. KerbUnlockContexts();
  1858. //
  1859. // First try pull off the header
  1860. //
  1861. MessageSize = ErrorMessageSize;
  1862. MessageStart = ErrorMessage;
  1863. if (!g_verify_token_header(
  1864. MechId,
  1865. (INT *) &MessageSize,
  1866. &MessageStart,
  1867. KG_TOK_CTX_ERROR,
  1868. ErrorMessageSize
  1869. ))
  1870. {
  1871. //
  1872. // If we couldn't find the header, try it without
  1873. // a header
  1874. //
  1875. MessageSize = ErrorMessageSize;
  1876. MessageStart = ErrorMessage;
  1877. }
  1878. else
  1879. {
  1880. VerifiedHeader = TRUE;
  1881. }
  1882. KerbErr = KerbUnpackKerbError(
  1883. MessageStart,
  1884. MessageSize,
  1885. DecodedErrorMessage
  1886. );
  1887. if (!KERB_SUCCESS(KerbErr))
  1888. {
  1889. Status = STATUS_INVALID_PARAMETER;
  1890. goto Cleanup;
  1891. }
  1892. if (((*DecodedErrorMessage)->bit_mask & error_data_present) != 0)
  1893. {
  1894. KerbUnpackErrorMethodData(
  1895. *DecodedErrorMessage,
  1896. ErrorData
  1897. );
  1898. }
  1899. else
  1900. {
  1901. Status = KerbMapKerbError(KerbErr);
  1902. }
  1903. Cleanup:
  1904. return(Status);
  1905. }
  1906. #ifndef WIN32_CHICAGO
  1907. //+-------------------------------------------------------------------------
  1908. //
  1909. // Function: KerbUnpackErrorMethodData
  1910. //
  1911. // Synopsis: This routine unpacks extended error information from
  1912. // a KERB_ERROR message
  1913. //
  1914. // Effects:
  1915. //
  1916. // Arguments: Unpacked error message. Returns extended error to
  1917. // be freed using KerbFree
  1918. //
  1919. // Requires:
  1920. //
  1921. // Returns: NTSTATUS
  1922. //
  1923. // Notes:
  1924. //
  1925. //
  1926. //--------------------------------------------------------------------------
  1927. KERBERR
  1928. KerbUnpackErrorMethodData(
  1929. IN PKERB_ERROR ErrorMessage,
  1930. IN OUT OPTIONAL PKERB_ERROR_METHOD_DATA * ppErrorData
  1931. )
  1932. {
  1933. PKERB_ERROR_METHOD_DATA pErrorData = NULL;
  1934. KERBERR KerbErr = KDC_ERR_NONE;
  1935. if (ARGUMENT_PRESENT(ppErrorData))
  1936. {
  1937. *ppErrorData = NULL;
  1938. }
  1939. if ((ErrorMessage->bit_mask & error_data_present) == 0)
  1940. {
  1941. return (KRB_ERR_GENERIC);
  1942. }
  1943. KerbErr = KerbUnpackData(
  1944. ErrorMessage->error_data.value,
  1945. ErrorMessage->error_data.length,
  1946. KERB_ERROR_METHOD_DATA_PDU,
  1947. (void**) &pErrorData
  1948. );
  1949. if (KERB_SUCCESS(KerbErr) && ARGUMENT_PRESENT(ppErrorData) && (NULL != pErrorData))
  1950. {
  1951. *ppErrorData = pErrorData;
  1952. pErrorData = NULL;
  1953. }
  1954. if (pErrorData)
  1955. {
  1956. KerbFreeData(KERB_ERROR_METHOD_DATA_PDU, pErrorData);
  1957. }
  1958. return (KerbErr);
  1959. }
  1960. //+-------------------------------------------------------------------------
  1961. //
  1962. // Function: KerbGetDnsHostName
  1963. //
  1964. // Synopsis: This routine gets DnsHostName of this machine.
  1965. //
  1966. // Effects:
  1967. //
  1968. // Arguments: DnsHostName - Returns the DNS Host Name of the machine.
  1969. // Will return a NULL string if this machine has no DNS host name.
  1970. // Free this buffer using KerbFreeString.
  1971. //
  1972. // Requires:
  1973. //
  1974. // Returns:
  1975. //
  1976. // Notes:
  1977. //
  1978. //
  1979. //--------------------------------------------------------------------------
  1980. NTSTATUS
  1981. KerbGetDnsHostName(
  1982. OUT PUNICODE_STRING DnsHostName
  1983. )
  1984. {
  1985. NTSTATUS Status = STATUS_SUCCESS;
  1986. WCHAR LocalDnsUnicodeHostName[DNS_MAX_NAME_BUFFER_LENGTH+1];
  1987. ULONG LocalDnsUnicodeHostNameLen = DNS_MAX_NAME_BUFFER_LENGTH+1;
  1988. LPWSTR ConfiguredDnsName = LocalDnsUnicodeHostName;
  1989. UNICODE_STRING HostName;
  1990. RtlInitUnicodeString(
  1991. DnsHostName,
  1992. NULL
  1993. );
  1994. //
  1995. // Get the DNS host name.
  1996. //
  1997. if (!GetComputerNameEx(
  1998. ComputerNameDnsHostname,
  1999. ConfiguredDnsName,
  2000. &LocalDnsUnicodeHostNameLen))
  2001. {
  2002. goto Cleanup;
  2003. }
  2004. ConfiguredDnsName = &LocalDnsUnicodeHostName[LocalDnsUnicodeHostNameLen];
  2005. *ConfiguredDnsName = L'.';
  2006. ConfiguredDnsName++;
  2007. //
  2008. // Now get the DNS domain name
  2009. //
  2010. LocalDnsUnicodeHostNameLen = DNS_MAX_NAME_BUFFER_LENGTH - LocalDnsUnicodeHostNameLen;
  2011. if (!GetComputerNameEx(
  2012. ComputerNameDnsDomain,
  2013. ConfiguredDnsName,
  2014. &LocalDnsUnicodeHostNameLen
  2015. ))
  2016. {
  2017. goto Cleanup;
  2018. }
  2019. RtlInitUnicodeString(
  2020. &HostName,
  2021. LocalDnsUnicodeHostName
  2022. );
  2023. Status = RtlDowncaseUnicodeString(
  2024. &HostName,
  2025. &HostName,
  2026. FALSE // don't allocate destination
  2027. );
  2028. if (!NT_SUCCESS(Status))
  2029. {
  2030. goto Cleanup;
  2031. }
  2032. Status = KerbDuplicateString(
  2033. DnsHostName,
  2034. &HostName
  2035. );
  2036. Cleanup:
  2037. return Status;
  2038. }
  2039. #endif // WIN32_CHICAGO
  2040. //+-------------------------------------------------------------------------
  2041. //
  2042. // Function: KerbIsThisOurDomain
  2043. //
  2044. // Synopsis: Compares a domain name to the local domain anme
  2045. //
  2046. // Effects:
  2047. //
  2048. // Arguments:
  2049. //
  2050. // Requires:
  2051. //
  2052. // Returns:
  2053. //
  2054. // Notes:
  2055. //
  2056. //
  2057. //--------------------------------------------------------------------------
  2058. BOOLEAN
  2059. KerbIsThisOurDomain(
  2060. IN PUNICODE_STRING DomainName
  2061. )
  2062. {
  2063. BOOLEAN Result;
  2064. KerbGlobalReadLock();
  2065. Result = KerbCompareUnicodeRealmNames(
  2066. DomainName,
  2067. &KerbGlobalDnsDomainName
  2068. ) ||
  2069. RtlEqualUnicodeString(
  2070. DomainName,
  2071. &KerbGlobalDomainName,
  2072. TRUE
  2073. );
  2074. KerbGlobalReleaseLock();
  2075. return(Result);
  2076. }
  2077. //+-------------------------------------------------------------------------
  2078. //
  2079. // Function: KerbGetOurDomainName
  2080. //
  2081. // Synopsis: Copies the machines dns domain name, if available,
  2082. // netbios otherwise.
  2083. //
  2084. // Effects:
  2085. //
  2086. // Arguments:
  2087. //
  2088. // Requires:
  2089. //
  2090. // Returns:
  2091. //
  2092. // Notes:
  2093. //
  2094. //
  2095. //--------------------------------------------------------------------------
  2096. NTSTATUS
  2097. KerbGetOurDomainName(
  2098. OUT PUNICODE_STRING DomainName
  2099. )
  2100. {
  2101. NTSTATUS Status;
  2102. KerbGlobalReadLock();
  2103. if (KerbGlobalDnsDomainName.Length != 0)
  2104. {
  2105. Status = KerbDuplicateString(
  2106. DomainName,
  2107. &KerbGlobalDnsDomainName
  2108. );
  2109. }
  2110. else
  2111. {
  2112. Status = KerbDuplicateString(
  2113. DomainName,
  2114. &KerbGlobalDomainName
  2115. );
  2116. }
  2117. KerbGlobalReleaseLock();
  2118. return(Status);
  2119. }
  2120. //+-------------------------------------------------------------------------
  2121. //
  2122. // Function: KerbGetGlobalRole
  2123. //
  2124. // Synopsis: Returns the current role of the machine
  2125. //
  2126. // Effects:
  2127. //
  2128. // Arguments:
  2129. //
  2130. // Requires:
  2131. //
  2132. // Returns:
  2133. //
  2134. // Notes:
  2135. //
  2136. //
  2137. //--------------------------------------------------------------------------
  2138. KERBEROS_MACHINE_ROLE
  2139. KerbGetGlobalRole(
  2140. VOID
  2141. )
  2142. {
  2143. KERBEROS_MACHINE_ROLE Role;
  2144. KerbGlobalReadLock();
  2145. Role = KerbGlobalRole;
  2146. KerbGlobalReleaseLock();
  2147. return(Role);
  2148. }
  2149. //+-------------------------------------------------------------------------
  2150. //
  2151. // Function: KerbSetComputerName
  2152. //
  2153. // Synopsis: Sets all computer-name related global variables
  2154. //
  2155. // Effects:
  2156. //
  2157. // Arguments:
  2158. //
  2159. // Requires:
  2160. //
  2161. // Returns:
  2162. //
  2163. // Notes:
  2164. //
  2165. //
  2166. //--------------------------------------------------------------------------
  2167. NTSTATUS
  2168. KerbSetComputerName(
  2169. VOID
  2170. )
  2171. {
  2172. UNICODE_STRING LocalMachineName;
  2173. STRING LocalKerbMachineName;
  2174. UNICODE_STRING OldMachineName;
  2175. STRING OldKerbMachineName;
  2176. ULONG ComputerNameLength;
  2177. NTSTATUS Status;
  2178. BOOLEAN LockHeld = FALSE;
  2179. #ifdef WIN32_CHICAGO
  2180. CHAR TempAnsiBuffer[MAX_COMPUTERNAME_LENGTH + 1];
  2181. ComputerNameLength = sizeof(TempAnsiBuffer);
  2182. #endif
  2183. LocalMachineName.Buffer = NULL;
  2184. LocalKerbMachineName.Buffer = NULL;
  2185. #ifndef WIN32_CHICAGO
  2186. ComputerNameLength = 0;
  2187. if (GetComputerNameW(
  2188. NULL,
  2189. &ComputerNameLength
  2190. ))
  2191. {
  2192. D_DebugLog((DEB_ERROR,"Succeeded to get computer name when failure expected! %ws, line %d\n", THIS_FILE, __LINE__));
  2193. Status = STATUS_UNSUCCESSFUL;
  2194. goto Cleanup;
  2195. }
  2196. LocalMachineName.Buffer = (LPWSTR) KerbAllocate(
  2197. (ComputerNameLength * sizeof(WCHAR))
  2198. );
  2199. if (LocalMachineName.Buffer == NULL)
  2200. {
  2201. Status = STATUS_INSUFFICIENT_RESOURCES;
  2202. goto Cleanup;
  2203. }
  2204. #endif // WIN32_CHICAGO
  2205. #ifndef WIN32_CHICAGO
  2206. if (!GetComputerNameW(
  2207. LocalMachineName.Buffer,
  2208. &ComputerNameLength
  2209. ))
  2210. #else // WIN32_CHICAGO
  2211. if (!GetComputerName(
  2212. TempAnsiBuffer,
  2213. &ComputerNameLength
  2214. ))
  2215. #endif // WIN32_CHICAGO
  2216. {
  2217. D_DebugLog((DEB_ERROR,"Failed to get computer name: %d. %ws, line %d\n",GetLastError(), THIS_FILE, __LINE__));
  2218. Status = STATUS_UNSUCCESSFUL;
  2219. goto Cleanup;
  2220. }
  2221. #ifndef WIN32_CHICAGO
  2222. LocalMachineName.Length = (USHORT)(ComputerNameLength * sizeof(WCHAR));
  2223. LocalMachineName.MaximumLength = LocalMachineName.Length + sizeof(WCHAR);
  2224. #else
  2225. RtlCreateUnicodeStringFromAsciiz (&LocalMachineName, TempAnsiBuffer);
  2226. // KerbFree (TempAnsiBuffer);
  2227. #endif // WIN32_CHICAGO
  2228. //
  2229. // Build the ansi format
  2230. //
  2231. if (!KERB_SUCCESS(KerbUnicodeStringToKerbString(
  2232. &LocalKerbMachineName,
  2233. &LocalMachineName
  2234. )))
  2235. {
  2236. Status = STATUS_INSUFFICIENT_RESOURCES;
  2237. goto Cleanup;
  2238. }
  2239. //
  2240. // free the current globals, and update to point at new values.
  2241. //
  2242. KerbGlobalWriteLock();
  2243. LockHeld = TRUE;
  2244. OldMachineName = KerbGlobalMachineName;
  2245. OldKerbMachineName = KerbGlobalKerbMachineName;
  2246. KerbGlobalMachineName = LocalMachineName;
  2247. KerbGlobalKerbMachineName = LocalKerbMachineName;
  2248. //
  2249. // now, see if the netbios machine name changed versus the prior
  2250. // value.
  2251. //
  2252. if( OldMachineName.Buffer != NULL )
  2253. {
  2254. if(!RtlEqualUnicodeString( &OldMachineName, &LocalMachineName, FALSE ))
  2255. {
  2256. D_DebugLog((DEB_WARN,"Netbios computer name change detected.\n"));
  2257. KerbGlobalMachineNameChanged = TRUE;
  2258. }
  2259. }
  2260. KerbGlobalReleaseLock();
  2261. LockHeld = FALSE;
  2262. LocalMachineName.Buffer = NULL;
  2263. LocalKerbMachineName.Buffer = NULL;
  2264. KerbFreeString( &OldMachineName );
  2265. KerbFreeString( (PUNICODE_STRING)&OldKerbMachineName );
  2266. Status = STATUS_SUCCESS;
  2267. Cleanup:
  2268. if( LockHeld )
  2269. {
  2270. KerbGlobalReleaseLock();
  2271. }
  2272. KerbFreeString( &LocalMachineName );
  2273. KerbFreeString( (PUNICODE_STRING)&LocalKerbMachineName );
  2274. return Status;
  2275. }
  2276. //
  2277. //
  2278. // Routine Description:
  2279. //
  2280. // This function checks the system to see if
  2281. // we are running on the personal version of
  2282. // the operating system.
  2283. //
  2284. // The personal version is denoted by the product
  2285. // id equal to WINNT, which is really workstation,
  2286. // and the product suite containing the personal
  2287. // suite string.
  2288. //
  2289. BOOLEAN
  2290. KerbRunningPersonal(
  2291. VOID
  2292. )
  2293. {
  2294. OSVERSIONINFOEXW OsVer = {0};
  2295. ULONGLONG ConditionMask = 0;
  2296. OsVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  2297. OsVer.wSuiteMask = VER_SUITE_PERSONAL;
  2298. OsVer.wProductType = VER_NT_WORKSTATION;
  2299. VER_SET_CONDITION( ConditionMask, VER_PRODUCT_TYPE, VER_EQUAL );
  2300. VER_SET_CONDITION( ConditionMask, VER_SUITENAME, VER_AND );
  2301. return RtlVerifyVersionInfo( &OsVer,
  2302. VER_PRODUCT_TYPE | VER_SUITENAME,
  2303. ConditionMask) == STATUS_SUCCESS;
  2304. }
  2305. BOOLEAN
  2306. KerbRunningServer(
  2307. VOID
  2308. )
  2309. {
  2310. OSVERSIONINFOEXW OsVer = {0};
  2311. ULONGLONG ConditionMask = 0;
  2312. OsVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  2313. OsVer.wProductType = VER_NT_DOMAIN_CONTROLLER;
  2314. VER_SET_CONDITION( ConditionMask, VER_PRODUCT_TYPE, VER_GREATER_EQUAL );
  2315. return RtlVerifyVersionInfo( &OsVer,
  2316. VER_PRODUCT_TYPE ,
  2317. ConditionMask) == STATUS_SUCCESS;
  2318. }
  2319. //+-------------------------------------------------------------------------
  2320. //
  2321. // Function: KerbSetDomainName
  2322. //
  2323. // Synopsis: Sets all domain-name related global variables
  2324. //
  2325. // Effects:
  2326. //
  2327. // Arguments:
  2328. //
  2329. // Requires:
  2330. //
  2331. // Returns:
  2332. //
  2333. // Notes:
  2334. //
  2335. //
  2336. //--------------------------------------------------------------------------
  2337. NTSTATUS
  2338. KerbSetDomainName(
  2339. IN PUNICODE_STRING DomainName,
  2340. IN PUNICODE_STRING DnsDomainName,
  2341. IN PSID DomainSid,
  2342. IN GUID DomainGuid
  2343. )
  2344. {
  2345. NTSTATUS Status = STATUS_SUCCESS;
  2346. BOOLEAN AcquiredLock = FALSE;
  2347. UNICODE_STRING TempDomainName = {0};
  2348. UNICODE_STRING TempDnsDomainName = {0};
  2349. UNICODE_STRING TempMachineServiceName = {0};
  2350. PKERB_INTERNAL_NAME TempMitMachineServiceName = NULL;
  2351. PKERB_INTERNAL_NAME TempInternalMachineServiceName = NULL;
  2352. PSID TempDomainSid = NULL;
  2353. UNICODE_STRING TempString;
  2354. WCHAR MachineAccountName[CNLEN+2]; // for null and '$'
  2355. UNICODE_STRING DnsString = {0};
  2356. UNICODE_STRING SystemDomain = {0};
  2357. PSID MachineSid = NULL;
  2358. #ifndef WIN32_CHICAGO
  2359. LUID SystemLogonId = SYSTEM_LUID;
  2360. PKERB_LOGON_SESSION SystemLogonSession = NULL;
  2361. #endif
  2362. //
  2363. // Copy the domain name / sid
  2364. //
  2365. Status = KerbDuplicateString(
  2366. &TempDomainName,
  2367. DomainName
  2368. );
  2369. if (!NT_SUCCESS(Status))
  2370. {
  2371. goto Cleanup;
  2372. }
  2373. Status = KerbDuplicateString(
  2374. &TempDnsDomainName,
  2375. DnsDomainName
  2376. );
  2377. if (!NT_SUCCESS(Status))
  2378. {
  2379. goto Cleanup;
  2380. }
  2381. //
  2382. // If we are in an NT domain, uppercase the dns domain name
  2383. //
  2384. #ifndef WIN32_CHICAGO
  2385. if (DomainSid != NULL)
  2386. #endif
  2387. {
  2388. Status = RtlUpcaseUnicodeString(
  2389. &TempDnsDomainName,
  2390. &TempDnsDomainName,
  2391. FALSE // don't allocate
  2392. );
  2393. if (!NT_SUCCESS(Status))
  2394. {
  2395. goto Cleanup;
  2396. }
  2397. }
  2398. #ifndef WIN32_CHICAGO
  2399. if (DomainSid != NULL)
  2400. {
  2401. Status = KerbDuplicateSid(
  2402. &TempDomainSid,
  2403. DomainSid
  2404. );
  2405. if (!NT_SUCCESS(Status))
  2406. {
  2407. goto Cleanup;
  2408. }
  2409. }
  2410. #endif
  2411. //
  2412. // Create the new machine names
  2413. //
  2414. KerbGlobalReadLock();
  2415. ASSERT( (KerbGlobalMachineName.Length <= (CNLEN*sizeof(WCHAR)) ) );
  2416. RtlCopyMemory(
  2417. MachineAccountName,
  2418. KerbGlobalMachineName.Buffer,
  2419. KerbGlobalMachineName.Length
  2420. );
  2421. MachineAccountName[KerbGlobalMachineName.Length/sizeof(WCHAR)] = SSI_ACCOUNT_NAME_POSTFIX_CHAR;
  2422. MachineAccountName[1+KerbGlobalMachineName.Length/sizeof(WCHAR)] = L'\0';
  2423. KerbGlobalReleaseLock();
  2424. RtlInitUnicodeString(
  2425. &TempString,
  2426. MachineAccountName
  2427. );
  2428. Status = KerbDuplicateString(
  2429. &TempMachineServiceName,
  2430. &TempString
  2431. );
  2432. if (!NT_SUCCESS(Status))
  2433. {
  2434. goto Cleanup;
  2435. }
  2436. //
  2437. // Get the machine sid to use in the name
  2438. //
  2439. #ifndef WIN32_CHICAGO
  2440. if (KerbGlobalUseSidCache)
  2441. {
  2442. KerbGetMachineSid( &MachineSid );
  2443. }
  2444. #endif // WIN32_CHICAGO
  2445. //
  2446. // Create the KERB_INTERNAL_NAME version of the name
  2447. //
  2448. if (!KERB_SUCCESS(KerbBuildFullServiceKdcNameWithSid(
  2449. &TempDnsDomainName,
  2450. &TempMachineServiceName,
  2451. MachineSid,
  2452. (MachineSid == NULL) ? KRB_NT_PRINCIPAL : KRB_NT_PRINCIPAL_AND_ID,
  2453. &TempInternalMachineServiceName)))
  2454. {
  2455. Status = STATUS_INSUFFICIENT_RESOURCES;
  2456. goto Cleanup;
  2457. }
  2458. #ifndef WIN32_CHICAGO
  2459. //
  2460. // Now build the MIT version of our machine service name
  2461. //
  2462. Status = KerbGetDnsHostName(
  2463. &DnsString
  2464. );
  2465. if (!NT_SUCCESS(Status))
  2466. {
  2467. goto Cleanup;
  2468. }
  2469. RtlInitUnicodeString(
  2470. &TempString,
  2471. KERB_HOST_STRING
  2472. );
  2473. if (!KERB_SUCCESS(KerbBuildFullServiceKdcName(
  2474. &DnsString,
  2475. &TempString,
  2476. KRB_NT_SRV_HST,
  2477. &TempMitMachineServiceName
  2478. )))
  2479. {
  2480. Status = STATUS_INSUFFICIENT_RESOURCES;
  2481. goto Cleanup;
  2482. }
  2483. //
  2484. // Find the system logon session.
  2485. //
  2486. SystemLogonSession = KerbReferenceLogonSession(
  2487. &SystemLogonId,
  2488. FALSE // don't unlink
  2489. );
  2490. if (SystemLogonSession != NULL)
  2491. {
  2492. Status = KerbDuplicateString(
  2493. &SystemDomain,
  2494. DnsDomainName
  2495. );
  2496. if (!NT_SUCCESS(Status))
  2497. {
  2498. goto Cleanup;
  2499. }
  2500. }
  2501. //
  2502. // Acquire the global lock so we can update the data
  2503. //
  2504. if (!KerbGlobalWriteLock())
  2505. {
  2506. D_DebugLog((DEB_ERROR,"Failed to acquire global resource. Not changing domain. %ws, line %d\n", THIS_FILE, __LINE__));
  2507. goto Cleanup;
  2508. }
  2509. AcquiredLock = TRUE;
  2510. #endif // WIN32_CHICAGO
  2511. //
  2512. // Copy all the data to the global structures
  2513. //
  2514. // If we're NT4, we don't have a dns domain name
  2515. // If we're joined to an MIT domain, we don't have a domain GUID and we
  2516. // have a dns domain name
  2517. if ((DomainGuid == GUID_NULL) && (TempDnsDomainName.Length == 0))
  2518. {
  2519. KerbGlobalDomainIsPreNT5 = TRUE;
  2520. }
  2521. else
  2522. {
  2523. KerbGlobalDomainIsPreNT5 = FALSE;
  2524. }
  2525. KerbFreeString(&KerbGlobalDomainName);
  2526. KerbGlobalDomainName = TempDomainName;
  2527. TempDomainName.Buffer = NULL;
  2528. KerbFreeString(&KerbGlobalDnsDomainName);
  2529. KerbGlobalDnsDomainName = TempDnsDomainName;
  2530. TempDnsDomainName.Buffer = NULL;
  2531. KerbFreeString(&KerbGlobalMachineServiceName);
  2532. KerbGlobalMachineServiceName = TempMachineServiceName;
  2533. TempMachineServiceName.Buffer = NULL;
  2534. KerbFreeKdcName(&KerbGlobalInternalMachineServiceName);
  2535. KerbGlobalInternalMachineServiceName = TempInternalMachineServiceName;
  2536. TempInternalMachineServiceName = NULL;
  2537. #ifndef WIN32_CHICAGO
  2538. KerbFreeKdcName(&KerbGlobalMitMachineServiceName);
  2539. KerbGlobalMitMachineServiceName = TempMitMachineServiceName;
  2540. TempMitMachineServiceName = NULL;
  2541. if (KerbGlobalDomainSid != NULL)
  2542. {
  2543. KerbFree(KerbGlobalDomainSid);
  2544. }
  2545. KerbGlobalDomainSid = TempDomainSid;
  2546. TempDomainSid = NULL;
  2547. //
  2548. // Update the role on non DCs. The role of a DC never changes.
  2549. // Demotion requires a reboot so that the domain controller role
  2550. // will not change.
  2551. //
  2552. if (KerbGlobalRole != KerbRoleDomainController)
  2553. {
  2554. if (KerbRunningPersonal())
  2555. {
  2556. KerbGlobalRole = KerbRoleRealmlessWksta;
  2557. }
  2558. else if (DomainSid == NULL )
  2559. {
  2560. // No machine account, nor associate w/ MIT realm
  2561. if (DnsDomainName->Length == 0 )
  2562. {
  2563. KerbGlobalRole = KerbRoleRealmlessWksta;
  2564. }
  2565. // Member of MIT realm, but not a domain
  2566. else
  2567. {
  2568. KerbGlobalRole = KerbRoleStandalone;
  2569. }
  2570. }
  2571. else
  2572. {
  2573. KerbGlobalRole = KerbRoleWorkstation;
  2574. }
  2575. }
  2576. //
  2577. // Update the system logon session, if there is one
  2578. //
  2579. if (SystemLogonSession != NULL)
  2580. {
  2581. KerbWriteLockLogonSessions(SystemLogonSession);
  2582. KerbFreeString(&SystemLogonSession->PrimaryCredentials.DomainName);
  2583. SystemLogonSession->PrimaryCredentials.DomainName = SystemDomain;
  2584. SystemDomain.Buffer = NULL;
  2585. KerbPurgeTicketCache(&SystemLogonSession->PrimaryCredentials.ServerTicketCache);
  2586. KerbPurgeTicketCache(&SystemLogonSession->PrimaryCredentials.AuthenticationTicketCache);
  2587. SystemLogonSession->LogonSessionFlags |= KERB_LOGON_DEFERRED;
  2588. KerbUnlockLogonSessions(SystemLogonSession);
  2589. }
  2590. #endif
  2591. Cleanup:
  2592. #ifndef WIN32_CHICAGO
  2593. if (AcquiredLock)
  2594. {
  2595. KerbGlobalReleaseLock();
  2596. }
  2597. #endif // WIN32_CHICAGO
  2598. KerbFreeString(
  2599. &DnsString
  2600. );
  2601. KerbFreeString(
  2602. &SystemDomain
  2603. );
  2604. KerbFreeString(
  2605. &TempDomainName
  2606. );
  2607. KerbFreeString(
  2608. &TempDnsDomainName
  2609. );
  2610. KerbFreeString(
  2611. &TempMachineServiceName
  2612. );
  2613. KerbFreeKdcName(
  2614. &TempInternalMachineServiceName
  2615. );
  2616. #ifndef WIN32_CHICAGO
  2617. if (MachineSid != NULL)
  2618. {
  2619. KerbFree(MachineSid);
  2620. }
  2621. KerbFreeKdcName(
  2622. &TempMitMachineServiceName
  2623. );
  2624. if (TempDomainSid != NULL)
  2625. {
  2626. KerbFree(TempDomainSid);
  2627. }
  2628. if (SystemLogonSession != NULL)
  2629. {
  2630. KerbDereferenceLogonSession(SystemLogonSession);
  2631. }
  2632. #endif
  2633. return(Status);
  2634. }
  2635. #ifndef WIN32_CHICAGO
  2636. //+-------------------------------------------------------------------------
  2637. //
  2638. // Function: KerbLoadKdc
  2639. //
  2640. // Synopsis: Loads kdcsvc.dll and gets the address of important functions
  2641. //
  2642. // Effects:
  2643. //
  2644. // Arguments:
  2645. //
  2646. // Requires:
  2647. //
  2648. // Returns: STATUS_SUCCESS if kdcsvc.dll could be loaded and the
  2649. // necessary entrypoints found.
  2650. //
  2651. // Notes:
  2652. //
  2653. //
  2654. //--------------------------------------------------------------------------
  2655. NTSTATUS
  2656. KerbLoadKdc(
  2657. VOID
  2658. )
  2659. {
  2660. NTSTATUS Status = STATUS_SUCCESS;
  2661. KerbKdcHandle = LoadLibraryA("kdcsvc.dll");
  2662. if (KerbKdcHandle == NULL) {
  2663. D_DebugLog((DEB_WARN,"Failed to load kdcsvc.dll: %d\n",GetLastError()));
  2664. return(STATUS_DLL_NOT_FOUND);
  2665. }
  2666. KerbKdcVerifyPac = (PKDC_VERIFY_PAC_ROUTINE) GetProcAddress(
  2667. KerbKdcHandle,
  2668. KDC_VERIFY_PAC_NAME
  2669. );
  2670. if (KerbKdcVerifyPac == NULL)
  2671. {
  2672. D_DebugLog((DEB_WARN, "Failed to get proc address for KdcVerifyPac: %d\n",
  2673. GetLastError()));
  2674. Status = STATUS_PROCEDURE_NOT_FOUND;
  2675. goto Cleanup;
  2676. }
  2677. KerbKdcGetTicket = (PKDC_GET_TICKET_ROUTINE) GetProcAddress(
  2678. KerbKdcHandle,
  2679. KDC_GET_TICKET_NAME
  2680. );
  2681. if (KerbKdcGetTicket == NULL)
  2682. {
  2683. D_DebugLog((DEB_WARN,"Failed to get proc address for KdcGetTicket: %d\n",
  2684. GetLastError()));
  2685. Status = STATUS_PROCEDURE_NOT_FOUND;
  2686. goto Cleanup;
  2687. }
  2688. KerbKdcChangePassword = (PKDC_GET_TICKET_ROUTINE) GetProcAddress(
  2689. KerbKdcHandle,
  2690. KDC_CHANGE_PASSWORD_NAME
  2691. );
  2692. if (KerbKdcChangePassword == NULL)
  2693. {
  2694. D_DebugLog((DEB_WARN,"Failed to get proc address for KdcChangePassword: %d\n",
  2695. GetLastError()));
  2696. Status = STATUS_PROCEDURE_NOT_FOUND;
  2697. goto Cleanup;
  2698. }
  2699. KerbKdcFreeMemory = (PKDC_FREE_MEMORY_ROUTINE) GetProcAddress(
  2700. KerbKdcHandle,
  2701. KDC_FREE_MEMORY_NAME
  2702. );
  2703. if (KerbKdcFreeMemory == NULL)
  2704. {
  2705. D_DebugLog((DEB_WARN,"Failed to get proc address for KdcFreeMemory: %d\n",
  2706. GetLastError()));
  2707. Status = STATUS_PROCEDURE_NOT_FOUND;
  2708. goto Cleanup;
  2709. }
  2710. Cleanup:
  2711. if (!NT_SUCCESS(Status))
  2712. {
  2713. if (KerbKdcHandle != NULL)
  2714. {
  2715. FreeLibrary(KerbKdcHandle);
  2716. KerbKdcHandle = NULL;
  2717. }
  2718. }
  2719. return(Status);
  2720. }
  2721. //+-------------------------------------------------------------------------
  2722. //
  2723. // Function: KerbDomainChangeCallback
  2724. //
  2725. // Synopsis: Function to be called when domain changes
  2726. //
  2727. // Effects:
  2728. //
  2729. // Arguments:
  2730. //
  2731. // Requires:
  2732. //
  2733. // Returns:
  2734. //
  2735. // Notes:
  2736. //
  2737. //
  2738. //--------------------------------------------------------------------------
  2739. VOID NTAPI
  2740. KerbDomainChangeCallback(
  2741. IN POLICY_NOTIFICATION_INFORMATION_CLASS ChangedInfoClass
  2742. )
  2743. {
  2744. NTSTATUS Status = STATUS_SUCCESS;
  2745. PLSAPR_POLICY_INFORMATION Policy = NULL;
  2746. //
  2747. // We only care about domain dns information
  2748. //
  2749. if (ChangedInfoClass != PolicyNotifyDnsDomainInformation)
  2750. {
  2751. return;
  2752. }
  2753. //
  2754. // Get the new domain information
  2755. //
  2756. Status = I_LsaIQueryInformationPolicyTrusted(
  2757. PolicyDnsDomainInformation,
  2758. &Policy
  2759. );
  2760. if (!NT_SUCCESS(Status))
  2761. {
  2762. D_DebugLog((DEB_ERROR,"Failed to query domain dns information %x - not updating. %ws, line %d\n",
  2763. Status, THIS_FILE, __LINE__));
  2764. goto Cleanup;
  2765. }
  2766. //
  2767. // update computer name info.
  2768. //
  2769. Status = KerbSetComputerName();
  2770. if (!NT_SUCCESS(Status))
  2771. {
  2772. D_DebugLog((DEB_ERROR,"Failed to set computer name: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  2773. goto Cleanup;
  2774. }
  2775. Status = KerbSetDomainName(
  2776. (PUNICODE_STRING) &Policy->PolicyDnsDomainInfo.Name,
  2777. (PUNICODE_STRING) &Policy->PolicyDnsDomainInfo.DnsDomainName,
  2778. (PSID) Policy->PolicyDnsDomainInfo.Sid,
  2779. (GUID) Policy->PolicyDnsDomainInfo.DomainGuid
  2780. );
  2781. if (!NT_SUCCESS(Status))
  2782. {
  2783. D_DebugLog((DEB_ERROR,"Failed to set domain name: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  2784. goto Cleanup;
  2785. }
  2786. //
  2787. // Domain Name has changed. So, the cache in the registry will
  2788. // have changed too. And we haven't rebooted yet.
  2789. //
  2790. KerbSetKdcData(TRUE, FALSE);
  2791. if (KerbGetGlobalRole() != KerbRoleDomainController)
  2792. {
  2793. //
  2794. // If we aren't in a domain anymore, flush the machine account sid
  2795. // cache.
  2796. //
  2797. if (Policy->PolicyDnsDomainInfo.Sid == NULL)
  2798. {
  2799. KerbWriteMachineSid(
  2800. NULL
  2801. );
  2802. }
  2803. else
  2804. {
  2805. (VOID) LsaFunctions->RegisterNotification(
  2806. KerbUpdateMachineSidWorker,
  2807. NULL, // no parameter
  2808. NOTIFIER_TYPE_IMMEDIATE,
  2809. 0, // no class
  2810. NOTIFIER_FLAG_ONE_SHOT,
  2811. 0, // no inteval
  2812. NULL // no wait event
  2813. );
  2814. }
  2815. }
  2816. Cleanup:
  2817. if (Policy != NULL)
  2818. {
  2819. I_LsaIFree_LSAPR_POLICY_INFORMATION(
  2820. PolicyDnsDomainInformation,
  2821. Policy
  2822. );
  2823. }
  2824. return;
  2825. }
  2826. //+-------------------------------------------------------------------------
  2827. //
  2828. // Function: KerbRegisterForDomainChange
  2829. //
  2830. // Synopsis: Register with the LSA to be notified of domain changes
  2831. //
  2832. // Effects:
  2833. //
  2834. // Arguments:
  2835. //
  2836. // Requires:
  2837. //
  2838. // Returns:
  2839. //
  2840. // Notes:
  2841. //
  2842. //
  2843. //--------------------------------------------------------------------------
  2844. NTSTATUS
  2845. KerbRegisterForDomainChange(
  2846. VOID
  2847. )
  2848. {
  2849. NTSTATUS Status = STATUS_SUCCESS;
  2850. Status = I_LsaIRegisterPolicyChangeNotificationCallback(
  2851. KerbDomainChangeCallback,
  2852. PolicyNotifyDnsDomainInformation
  2853. );
  2854. if (!NT_SUCCESS(Status))
  2855. {
  2856. D_DebugLog((DEB_ERROR,"Failed to register for domain change notification: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  2857. }
  2858. return(Status);
  2859. }
  2860. //+-------------------------------------------------------------------------
  2861. //
  2862. // Function: KerbUnregisterForDomainChange
  2863. //
  2864. // Synopsis: Unregister for domain change notification
  2865. //
  2866. // Effects:
  2867. //
  2868. // Arguments:
  2869. //
  2870. // Requires:
  2871. //
  2872. // Returns:
  2873. //
  2874. // Notes:
  2875. //
  2876. //
  2877. //--------------------------------------------------------------------------
  2878. VOID
  2879. KerbUnregisterForDomainChange(
  2880. VOID
  2881. )
  2882. {
  2883. (VOID) I_LsaIUnregisterPolicyChangeNotificationCallback(
  2884. KerbDomainChangeCallback,
  2885. PolicyNotifyDnsDomainInformation
  2886. );
  2887. }
  2888. //+-------------------------------------------------------------------------
  2889. //
  2890. // Function: KerbUpdateGlobalAddresses
  2891. //
  2892. // Synopsis: Updates the global array of addresses with information from
  2893. // netlogon.
  2894. //
  2895. // Effects:
  2896. //
  2897. // Arguments:
  2898. //
  2899. // Requires:
  2900. //
  2901. // Returns:
  2902. //
  2903. // Notes: Ideally, we should also have called WSAProviderConfigChange to be
  2904. // notified of when tcp is added/removed. But, we can take advantage
  2905. // of the fact that netlogon is registered for changes in ipaddress
  2906. // so, even though, change of ipaddress & xports notifications are
  2907. // async, we will get to know of it, so, it suffices to rely on
  2908. // netlogon rather than register for a notification change.
  2909. //
  2910. //
  2911. //--------------------------------------------------------------------------
  2912. NTSTATUS
  2913. KerbUpdateGlobalAddresses(
  2914. IN PSOCKET_ADDRESS NewAddresses,
  2915. IN ULONG NewAddressCount
  2916. )
  2917. {
  2918. PSOCKADDR_IN GlobalIpAddresses = NULL;
  2919. ULONG Index;
  2920. ULONG AddressCount = 0;
  2921. WSAPROTOCOL_INFO *lpProtocolBuf = NULL;
  2922. DWORD dwBufLen = 0;
  2923. INT protocols[2];
  2924. int nRet = 0;
  2925. BOOLEAN NoTcpInstalled = FALSE;
  2926. GlobalIpAddresses = (PSOCKADDR_IN) KerbAllocate(sizeof(SOCKADDR_IN) * NewAddressCount);
  2927. if (GlobalIpAddresses == NULL)
  2928. {
  2929. return(STATUS_INSUFFICIENT_RESOURCES);
  2930. }
  2931. for (Index = 0; Index < NewAddressCount ; Index++ )
  2932. {
  2933. if ((NewAddresses[Index].iSockaddrLength == sizeof(SOCKADDR)) &&
  2934. (NewAddresses[Index].lpSockaddr->sa_family == AF_INET))
  2935. {
  2936. RtlCopyMemory(
  2937. &GlobalIpAddresses[AddressCount++],
  2938. NewAddresses[Index].lpSockaddr,
  2939. sizeof(SOCKADDR_IN)
  2940. );
  2941. }
  2942. else
  2943. {
  2944. D_DebugLog((DEB_ERROR,"Netlogon handed us a address of length or type %d, %d. %ws, line %d\n",
  2945. NewAddresses[Index].iSockaddrLength,
  2946. NewAddresses[Index].lpSockaddr->sa_family,
  2947. THIS_FILE, __LINE__ ));
  2948. }
  2949. }
  2950. //
  2951. // winsock is already initialized by now, or we would not have
  2952. // gotten so far. Check if TCP s an available xport
  2953. //
  2954. protocols[0] = IPPROTO_TCP;
  2955. protocols[1] = NULL;
  2956. nRet = WSAEnumProtocols(protocols, lpProtocolBuf, &dwBufLen);
  2957. if (nRet == 0)
  2958. {
  2959. //
  2960. // Tcp is not installed as a xport.
  2961. //
  2962. D_DebugLog((DEB_TRACE_SOCK,"WSAEnumProtocols returned 0x%x. %ws, line %d\n", nRet, THIS_FILE, __LINE__ ));
  2963. NoTcpInstalled = TRUE;
  2964. }
  2965. //
  2966. // Copy them into the global for others to use
  2967. //
  2968. KerbGlobalWriteLock();
  2969. if (KerbGlobalIpAddresses != NULL)
  2970. {
  2971. KerbFree(KerbGlobalIpAddresses);
  2972. }
  2973. KerbGlobalIpAddresses = GlobalIpAddresses;
  2974. KerbGlobalIpAddressCount = AddressCount;
  2975. KerbGlobalIpAddressesInitialized = TRUE;
  2976. KerbGlobalNoTcpUdp = NoTcpInstalled;
  2977. KerbGlobalReleaseLock();
  2978. return(STATUS_SUCCESS);
  2979. }
  2980. //+-------------------------------------------------------------------------
  2981. //
  2982. // Function: KerbUpdateMachineSidWorker
  2983. //
  2984. // Synopsis: Calls the LSA to lookup the machine sid
  2985. //
  2986. // Effects:
  2987. //
  2988. // Arguments: EventHandle - if not NULL and not INVALID_HANDLE_VALUE,
  2989. // containst the event handle being waited on. If
  2990. // NULL, then the routine should retry on failure
  2991. //
  2992. // Requires:
  2993. //
  2994. // Returns:
  2995. //
  2996. // Notes:
  2997. //
  2998. //
  2999. //--------------------------------------------------------------------------
  3000. ULONG
  3001. KerbUpdateMachineSidWorker(
  3002. PVOID EventHandle
  3003. )
  3004. {
  3005. PLSAPR_REFERENCED_DOMAIN_LIST ReferencedDomains = NULL;
  3006. LSAPR_TRANSLATED_SIDS TranslatedSids = {0};
  3007. ULONG MappedCount = 0;
  3008. UNICODE_STRING MachineAccountName = {0};
  3009. NTSTATUS Status = STATUS_SUCCESS;
  3010. PSID MachineSid = NULL;
  3011. PKERB_INTERNAL_NAME MachineServiceName = NULL;
  3012. KERBERR KerbErr;
  3013. //
  3014. // If we aren't running, don't do anything
  3015. //
  3016. if (!KerbGlobalInitialized)
  3017. {
  3018. return((ULONG) STATUS_SUCCESS);
  3019. }
  3020. KerbGlobalReadLock();
  3021. KerbErr = KerbBuildFullServiceName(
  3022. &KerbGlobalDomainName,
  3023. &KerbGlobalMachineServiceName,
  3024. &MachineAccountName
  3025. );
  3026. KerbGlobalReleaseLock();
  3027. if (!KERB_SUCCESS(KerbErr))
  3028. {
  3029. Status = KerbMapKerbError(KerbErr);
  3030. goto Cleanup;
  3031. }
  3032. Status = LsarLookupNames(
  3033. KerbGlobalPolicyHandle,
  3034. 1, // name count,
  3035. (PLSAPR_UNICODE_STRING) &MachineAccountName,
  3036. &ReferencedDomains,
  3037. &TranslatedSids,
  3038. LsapLookupWksta,
  3039. &MappedCount
  3040. );
  3041. if (!NT_SUCCESS(Status))
  3042. {
  3043. goto Cleanup;
  3044. }
  3045. if ((MappedCount == 0) ||
  3046. (TranslatedSids.Entries != 1) ||
  3047. ((TranslatedSids.Sids[0].Use != SidTypeUser) &&
  3048. (TranslatedSids.Sids[0].Use != SidTypeComputer)) ||
  3049. (TranslatedSids.Sids[0].DomainIndex != 0))
  3050. {
  3051. Status = STATUS_NONE_MAPPED;
  3052. goto Cleanup;
  3053. }
  3054. //
  3055. // Build the sid.
  3056. //
  3057. MachineSid = KerbMakeDomainRelativeSid(
  3058. (PSID) ReferencedDomains->Domains[TranslatedSids.Sids[0].DomainIndex].Sid,
  3059. TranslatedSids.Sids[0].RelativeId
  3060. );
  3061. if (MachineSid == NULL)
  3062. {
  3063. Status = STATUS_INSUFFICIENT_RESOURCES;
  3064. goto Cleanup;
  3065. }
  3066. //
  3067. // We have a SID - cache it.
  3068. //
  3069. KerbWriteMachineSid( MachineSid );
  3070. //
  3071. // Update the global machine service name
  3072. //
  3073. //
  3074. // Create the KERB_INTERNAL_NAME version of the name
  3075. //
  3076. KerbGlobalWriteLock();
  3077. if (!KERB_SUCCESS(KerbBuildFullServiceKdcNameWithSid(
  3078. &KerbGlobalDnsDomainName,
  3079. &KerbGlobalMachineServiceName,
  3080. MachineSid,
  3081. KRB_NT_PRINCIPAL_AND_ID,
  3082. &MachineServiceName)))
  3083. {
  3084. KerbGlobalReleaseLock();
  3085. Status = STATUS_INSUFFICIENT_RESOURCES;
  3086. goto Cleanup;
  3087. }
  3088. //
  3089. // Cache it for use next time
  3090. //
  3091. KerbCacheLogonSid(
  3092. &KerbGlobalMachineServiceName,
  3093. &KerbGlobalDnsDomainName,
  3094. &KerbGlobalDnsDomainName,
  3095. MachineSid
  3096. );
  3097. KerbFreeKdcName(&KerbGlobalInternalMachineServiceName);
  3098. KerbGlobalInternalMachineServiceName = MachineServiceName;
  3099. MachineServiceName = NULL;
  3100. KerbGlobalReleaseLock();
  3101. Cleanup:
  3102. //
  3103. // If the name couldn't be mapped, try again later
  3104. //
  3105. if ((Status == STATUS_NONE_MAPPED) &&
  3106. (KerbGetGlobalRole() == KerbRoleWorkstation) &&
  3107. (EventHandle == NULL))
  3108. {
  3109. (VOID) LsaFunctions->RegisterNotification(
  3110. KerbUpdateMachineSidWorker,
  3111. INVALID_HANDLE_VALUE, // no parameter
  3112. NOTIFIER_TYPE_INTERVAL,
  3113. 0, // no class
  3114. NOTIFIER_FLAG_ONE_SHOT,
  3115. 60, // 1 minute
  3116. NULL // no wait event
  3117. );
  3118. }
  3119. if ((EventHandle != NULL) &&
  3120. (EventHandle != INVALID_HANDLE_VALUE))
  3121. {
  3122. NtClose(EventHandle);
  3123. }
  3124. if (MachineServiceName != NULL)
  3125. {
  3126. KerbFreeKdcName(&MachineServiceName);
  3127. }
  3128. if (TranslatedSids.Entries != 0)
  3129. {
  3130. LsaIFree_LSAPR_TRANSLATED_SIDS(
  3131. &TranslatedSids
  3132. );
  3133. }
  3134. if (ReferencedDomains != NULL)
  3135. {
  3136. LsaIFree_LSAPR_REFERENCED_DOMAIN_LIST(
  3137. ReferencedDomains
  3138. );
  3139. }
  3140. return((ULONG) Status);
  3141. }
  3142. //+-------------------------------------------------------------------------
  3143. //
  3144. // Function: KerbWaitGetMachineSid
  3145. //
  3146. // Synopsis: This procedure registers a notification to wait for
  3147. // SAM to start and then to get the machine sid.
  3148. //
  3149. // Effects:
  3150. //
  3151. // Arguments:
  3152. //
  3153. // Requires:
  3154. //
  3155. // Returns:
  3156. //
  3157. // Notes:
  3158. //
  3159. //
  3160. //--------------------------------------------------------------------------
  3161. VOID
  3162. KerbWaitGetMachineSid(
  3163. VOID
  3164. )
  3165. {
  3166. NTSTATUS Status;
  3167. UNICODE_STRING EventName;
  3168. HANDLE EventHandle = NULL;
  3169. OBJECT_ATTRIBUTES EventAttributes;
  3170. KERBEROS_MACHINE_ROLE Role;
  3171. //
  3172. // If we aren't using SIDs, don't bother
  3173. //
  3174. if (!KerbGlobalUseSidCache)
  3175. {
  3176. return;
  3177. }
  3178. //
  3179. // For a domain controller, wait for SAM to start
  3180. //
  3181. Role = KerbGetGlobalRole();
  3182. if (Role == KerbRoleDomainController)
  3183. {
  3184. //
  3185. // open SAM event
  3186. //
  3187. RtlInitUnicodeString( &EventName, L"\\SAM_SERVICE_STARTED");
  3188. InitializeObjectAttributes( &EventAttributes, &EventName, 0, 0, NULL );
  3189. Status = NtOpenEvent( &EventHandle,
  3190. SYNCHRONIZE|EVENT_MODIFY_STATE,
  3191. &EventAttributes );
  3192. if ( !NT_SUCCESS(Status)) {
  3193. if( Status == STATUS_OBJECT_NAME_NOT_FOUND ) {
  3194. //
  3195. // SAM hasn't created this event yet, let us create it now.
  3196. // SAM opens this event to set it.
  3197. //
  3198. Status = NtCreateEvent(
  3199. &EventHandle,
  3200. SYNCHRONIZE|EVENT_MODIFY_STATE,
  3201. &EventAttributes,
  3202. NotificationEvent,
  3203. FALSE // The event is initially not signaled
  3204. );
  3205. if( Status == STATUS_OBJECT_NAME_EXISTS ||
  3206. Status == STATUS_OBJECT_NAME_COLLISION ) {
  3207. //
  3208. // second change, if the SAM created the event before we
  3209. // do.
  3210. //
  3211. Status = NtOpenEvent( &EventHandle,
  3212. SYNCHRONIZE|EVENT_MODIFY_STATE,
  3213. &EventAttributes );
  3214. }
  3215. }
  3216. if ( !NT_SUCCESS(Status)) {
  3217. //
  3218. // could not make the event handle
  3219. //
  3220. D_DebugLog((DEB_ERROR,
  3221. "KerbWaitGetMachineSid couldn't make the event handle : "
  3222. "%lx. %ws, line %d\n", Status, THIS_FILE, __LINE__));
  3223. goto Cleanup;
  3224. }
  3225. }
  3226. //
  3227. // Register a notification to be called back.
  3228. //
  3229. if (LsaFunctions->RegisterNotification(
  3230. KerbUpdateMachineSidWorker,
  3231. EventHandle,
  3232. NOTIFIER_TYPE_HANDLE_WAIT,
  3233. 0, // no class
  3234. NOTIFIER_FLAG_ONE_SHOT,
  3235. 0, // no inteval
  3236. EventHandle
  3237. ) != NULL)
  3238. {
  3239. EventHandle = NULL;
  3240. }
  3241. }
  3242. else if (Role == KerbRoleWorkstation)
  3243. {
  3244. PSID MachineSid;
  3245. //
  3246. // On a workstation, if we don't have a machine sid, wait a while
  3247. // (for the network to start, and then try
  3248. //
  3249. RtlInitUnicodeString( &EventName, L"\\NETLOGON_SERVICE_STARTED");
  3250. InitializeObjectAttributes( &EventAttributes, &EventName, 0, 0, NULL );
  3251. Status = NtOpenEvent( &EventHandle,
  3252. SYNCHRONIZE|EVENT_MODIFY_STATE,
  3253. &EventAttributes );
  3254. if ( !NT_SUCCESS(Status)) {
  3255. if( Status == STATUS_OBJECT_NAME_NOT_FOUND ) {
  3256. //
  3257. // SAM hasn't created this event yet, let us create it now.
  3258. // SAM opens this event to set it.
  3259. //
  3260. Status = NtCreateEvent(
  3261. &EventHandle,
  3262. SYNCHRONIZE|EVENT_MODIFY_STATE,
  3263. &EventAttributes,
  3264. NotificationEvent,
  3265. FALSE // The event is initially not signaled
  3266. );
  3267. if( Status == STATUS_OBJECT_NAME_EXISTS ||
  3268. Status == STATUS_OBJECT_NAME_COLLISION ) {
  3269. //
  3270. // second change, if the SAM created the event before we
  3271. // do.
  3272. //
  3273. Status = NtOpenEvent( &EventHandle,
  3274. SYNCHRONIZE|EVENT_MODIFY_STATE,
  3275. &EventAttributes );
  3276. }
  3277. }
  3278. if ( !NT_SUCCESS(Status)) {
  3279. //
  3280. // could not make the event handle
  3281. //
  3282. D_DebugLog((DEB_ERROR,
  3283. "KerbWaitGetMachineSid couldn't make the event handle : "
  3284. "%lx. %ws, line %d\n", Status, THIS_FILE, __LINE__));
  3285. goto Cleanup;
  3286. }
  3287. }
  3288. if (!NT_SUCCESS(KerbGetMachineSid(&MachineSid)))
  3289. {
  3290. if (LsaFunctions->RegisterNotification(
  3291. KerbUpdateMachineSidWorker,
  3292. NULL, // no parameter
  3293. NOTIFIER_TYPE_INTERVAL,
  3294. 0, // no class
  3295. NOTIFIER_FLAG_ONE_SHOT,
  3296. 2*60, // 2 minute interval
  3297. EventHandle
  3298. ) != NULL)
  3299. {
  3300. EventHandle = NULL;
  3301. }
  3302. }
  3303. else
  3304. {
  3305. KerbFree(MachineSid);
  3306. }
  3307. }
  3308. Cleanup:
  3309. if (EventHandle != NULL)
  3310. {
  3311. NtClose(EventHandle);
  3312. }
  3313. }
  3314. //+-------------------------------------------------------------------------
  3315. //
  3316. // Function: KerbGetTokenInformation
  3317. //
  3318. // Synopsis: Allocates and returns token information
  3319. //
  3320. // Effects:
  3321. //
  3322. // Arguments:
  3323. //
  3324. // Requires:
  3325. //
  3326. // Returns:
  3327. //
  3328. // Notes:
  3329. //
  3330. //
  3331. //--------------------------------------------------------------------------
  3332. NTSTATUS
  3333. KerbGetTokenInformation(
  3334. IN HANDLE TokenHandle,
  3335. IN TOKEN_INFORMATION_CLASS InformationClass,
  3336. IN OUT PVOID * Buffer
  3337. )
  3338. {
  3339. NTSTATUS Status = STATUS_SUCCESS;
  3340. ULONG BufferSize = 0;
  3341. //
  3342. // First retrieve the restricted sids
  3343. //
  3344. Status = NtQueryInformationToken(
  3345. TokenHandle,
  3346. InformationClass,
  3347. NULL,
  3348. 0,
  3349. &BufferSize
  3350. );
  3351. if (Status != STATUS_BUFFER_TOO_SMALL)
  3352. {
  3353. goto Cleanup;
  3354. }
  3355. *Buffer = KerbAllocate(BufferSize);
  3356. if (*Buffer == NULL)
  3357. {
  3358. Status = STATUS_INSUFFICIENT_RESOURCES;
  3359. goto Cleanup;
  3360. }
  3361. Status = NtQueryInformationToken(
  3362. TokenHandle,
  3363. InformationClass,
  3364. *Buffer,
  3365. BufferSize,
  3366. &BufferSize
  3367. );
  3368. if (!NT_SUCCESS(Status))
  3369. {
  3370. goto Cleanup;
  3371. }
  3372. Cleanup:
  3373. return(Status);
  3374. }
  3375. #ifdef RESTRICTED_TOKEN
  3376. //+-------------------------------------------------------------------------
  3377. //
  3378. // Function: KerbCaptureTokenRestrictions
  3379. //
  3380. // Synopsis: Captures the restrictions of a restricted token
  3381. //
  3382. // Effects:
  3383. //
  3384. // Arguments: TokenHandle - token handle open for TOKEN_QUERY access
  3385. //
  3386. // Requires:
  3387. //
  3388. // Returns:
  3389. //
  3390. // Notes:
  3391. //
  3392. //
  3393. //--------------------------------------------------------------------------
  3394. NTSTATUS
  3395. KerbCaptureTokenRestrictions(
  3396. IN HANDLE TokenHandle,
  3397. OUT PKERB_AUTHORIZATION_DATA Restrictions
  3398. )
  3399. {
  3400. PTOKEN_GROUPS Groups = NULL;
  3401. PTOKEN_GROUPS RestrictedSids = NULL;
  3402. PTOKEN_PRIVILEGES Privileges = NULL;
  3403. PTOKEN_PRIVILEGES DeletePrivileges = NULL;
  3404. NTSTATUS Status = STATUS_SUCCESS;
  3405. ULONG BufferSize = 0;
  3406. ULONG Index,Index2,LastIndex;
  3407. KERB_TOKEN_RESTRICTIONS TokenRestrictions = {0};
  3408. Status = KerbGetTokenInformation(
  3409. TokenHandle,
  3410. TokenRestrictedSids,
  3411. (PVOID *) &RestrictedSids
  3412. );
  3413. if (!NT_SUCCESS(Status))
  3414. {
  3415. goto Cleanup;
  3416. }
  3417. Status = KerbGetTokenInformation(
  3418. TokenHandle,
  3419. TokenGroups,
  3420. (PVOID *) &Groups
  3421. );
  3422. if (!NT_SUCCESS(Status))
  3423. {
  3424. goto Cleanup;
  3425. }
  3426. Status = KerbGetTokenInformation(
  3427. TokenHandle,
  3428. TokenPrivileges,
  3429. (PVOID *) &Privileges
  3430. );
  3431. if (!NT_SUCCESS(Status))
  3432. {
  3433. goto Cleanup;
  3434. }
  3435. //
  3436. // Now build the list of just the restricted privileges & groups
  3437. //
  3438. //
  3439. // First, find what groups are restricted.
  3440. //
  3441. LastIndex = 0;
  3442. for (Index = 0; Index < Groups->GroupCount ; Index++ )
  3443. {
  3444. if ((Groups->Groups[Index].Attributes & SE_GROUP_USE_FOR_DENY_ONLY) != 0)
  3445. {
  3446. if (LastIndex != Index)
  3447. {
  3448. Groups->Groups[LastIndex].Sid = Groups->Groups[Index].Sid;
  3449. Groups->Groups[LastIndex].Attributes = 0;
  3450. }
  3451. LastIndex++;
  3452. }
  3453. }
  3454. Groups->GroupCount = LastIndex;
  3455. if (LastIndex != 0)
  3456. {
  3457. TokenRestrictions.GroupsToDisable = (PPAC_TOKEN_GROUPS) Groups;
  3458. TokenRestrictions.Flags |= KERB_TOKEN_RESTRICTION_DISABLE_GROUPS;
  3459. }
  3460. //
  3461. // Add the restricted sids
  3462. //
  3463. if (RestrictedSids->GroupCount != 0)
  3464. {
  3465. for (Index = 0; Index < RestrictedSids->GroupCount ; Index++ )
  3466. {
  3467. RestrictedSids->Groups[Index].Attributes = 0;
  3468. }
  3469. TokenRestrictions.RestrictedSids = (PPAC_TOKEN_GROUPS) RestrictedSids;
  3470. TokenRestrictions.Flags |= KERB_TOKEN_RESTRICTION_RESTRICT_SIDS;
  3471. }
  3472. //
  3473. // Now make a list of all the privileges that _aren't_ enabled
  3474. //
  3475. DeletePrivileges = (PTOKEN_PRIVILEGES) KerbAllocate(
  3476. sizeof(TOKEN_PRIVILEGES) +
  3477. sizeof(LUID_AND_ATTRIBUTES) *
  3478. (1 + SE_MAX_WELL_KNOWN_PRIVILEGE - SE_MIN_WELL_KNOWN_PRIVILEGE)
  3479. );
  3480. if (DeletePrivileges == NULL)
  3481. {
  3482. Status = STATUS_INSUFFICIENT_RESOURCES;
  3483. goto Cleanup;
  3484. }
  3485. DeletePrivileges->PrivilegeCount = 0;
  3486. //
  3487. // Find out what privileges haven't been enabled
  3488. //
  3489. LastIndex = 0;
  3490. for (Index = SE_MIN_WELL_KNOWN_PRIVILEGE; Index <= SE_MAX_WELL_KNOWN_PRIVILEGE ; Index++ )
  3491. {
  3492. LUID TempLuid;
  3493. BOOLEAN Found = FALSE;
  3494. TempLuid = RtlConvertUlongToLuid(Index);
  3495. for (Index2 = 0; Index2 < Privileges->PrivilegeCount ; Index2++ )
  3496. {
  3497. if (RtlEqualLuid(&Privileges->Privileges[Index2].Luid,&TempLuid) &&
  3498. ((Privileges->Privileges[Index2].Attributes & SE_PRIVILEGE_ENABLED) != 0))
  3499. {
  3500. Found = TRUE;
  3501. break;
  3502. }
  3503. }
  3504. if (!Found)
  3505. {
  3506. DeletePrivileges->Privileges[LastIndex].Luid = TempLuid;
  3507. DeletePrivileges->Privileges[LastIndex].Attributes = 0;
  3508. LastIndex++;
  3509. }
  3510. }
  3511. DeletePrivileges->PrivilegeCount = LastIndex;
  3512. if (LastIndex != 0)
  3513. {
  3514. TokenRestrictions.PrivilegesToDelete = (PPAC_TOKEN_PRIVILEGES) DeletePrivileges;
  3515. TokenRestrictions.Flags |= KERB_TOKEN_RESTRICTION_DELETE_PRIVS;
  3516. }
  3517. Restrictions->value.auth_data_type = KERB_AUTH_DATA_TOKEN_RESTRICTIONS;
  3518. Status = PAC_EncodeTokenRestrictions(
  3519. &TokenRestrictions,
  3520. &Restrictions->value.auth_data.value,
  3521. &Restrictions->value.auth_data.length
  3522. );
  3523. Cleanup:
  3524. if (Groups != NULL)
  3525. {
  3526. KerbFree(Groups);
  3527. }
  3528. if (RestrictedSids != NULL)
  3529. {
  3530. KerbFree(RestrictedSids);
  3531. }
  3532. if (Privileges != NULL)
  3533. {
  3534. KerbFree(Privileges);
  3535. }
  3536. if (DeletePrivileges != NULL)
  3537. {
  3538. KerbFree(DeletePrivileges);
  3539. }
  3540. return(Status);
  3541. }
  3542. //+-------------------------------------------------------------------------
  3543. //
  3544. // Function: KerbAddRestrictionsToCredential
  3545. //
  3546. // Synopsis: Captures client'st token restrictions and sticks them in
  3547. // the credential
  3548. //
  3549. // Effects:
  3550. //
  3551. // Arguments:
  3552. //
  3553. // Requires:
  3554. //
  3555. // Returns:
  3556. //
  3557. // Notes:
  3558. //
  3559. //
  3560. //--------------------------------------------------------------------------
  3561. NTSTATUS
  3562. KerbAddRestrictionsToCredential(
  3563. IN PKERB_LOGON_SESSION LogonSession,
  3564. IN PKERB_CREDENTIAL Credential
  3565. )
  3566. {
  3567. NTSTATUS Status = STATUS_SUCCESS;
  3568. PKERB_AUTHORIZATION_DATA AuthData = NULL;
  3569. BOOLEAN CrossRealm;
  3570. PKERB_TICKET_CACHE_ENTRY ExistingTgt = NULL;
  3571. HANDLE ClientToken = NULL;
  3572. PKERB_INTERNAL_NAME ServiceName = NULL;
  3573. UNICODE_STRING ServiceRealm = NULL_UNICODE_STRING;
  3574. PKERB_KDC_REPLY KdcReply = NULL;
  3575. PKERB_ENCRYPTED_KDC_REPLY KdcReplyBody = NULL;
  3576. BOOLEAN TicketCacheLocked = FALSE;
  3577. PKERB_TICKET_CACHE_ENTRY NewTicket = NULL;
  3578. ULONG CacheFlags = 0;
  3579. BOOLEAN UseSuppliedCreds = FALSE;
  3580. //
  3581. // Capture the existing TGT
  3582. //
  3583. Status = LsaFunctions->ImpersonateClient();
  3584. if (!NT_SUCCESS(Status))
  3585. {
  3586. goto Cleanup;
  3587. }
  3588. Status = NtOpenThreadToken(
  3589. NtCurrentThread(),
  3590. TOKEN_QUERY,
  3591. TRUE, // open as self
  3592. &ClientToken
  3593. );
  3594. if (!NT_SUCCESS(Status))
  3595. {
  3596. goto Cleanup;
  3597. }
  3598. RevertToSelf();
  3599. //
  3600. // Capture the restrictions for this token
  3601. //
  3602. AuthData = (PKERB_AUTHORIZATION_DATA) MIDL_user_allocate(sizeof(KERB_AUTHORIZATION_DATA));
  3603. if (AuthData == NULL)
  3604. {
  3605. Status = STATUS_INSUFFICIENT_RESOURCES;
  3606. goto Cleanup;
  3607. }
  3608. Status = KerbCaptureTokenRestrictions(
  3609. ClientToken,
  3610. AuthData
  3611. );
  3612. if (!NT_SUCCESS(Status))
  3613. {
  3614. D_DebugLog((DEB_ERROR,"Failed to capture token restrictions: 0x%x\n",Status));
  3615. goto Cleanup;
  3616. }
  3617. KerbWriteLockLogonSessions(LogonSession);
  3618. Credential->AuthData = AuthData;
  3619. //
  3620. // Turn off tgt avail to force us to get a new tgt
  3621. //
  3622. Credential->CredentialFlags &= ~KERB_CRED_TGT_AVAIL;
  3623. AuthData = NULL;
  3624. KerbUnlockLogonSessions(LogonSession);
  3625. Cleanup:
  3626. if (AuthData != NULL)
  3627. {
  3628. if (AuthData->value.auth_data.value != NULL)
  3629. {
  3630. MIDL_user_free(AuthData->value.auth_data.value);
  3631. }
  3632. MIDL_user_free(AuthData);
  3633. }
  3634. if (ClientToken != NULL)
  3635. {
  3636. NtClose(ClientToken);
  3637. }
  3638. return(Status);
  3639. }
  3640. //+-------------------------------------------------------------------------
  3641. //
  3642. // Function: KerbBuildTokenRestrictionAuthData
  3643. //
  3644. // Synopsis:
  3645. //
  3646. // Effects:
  3647. //
  3648. // Arguments:
  3649. //
  3650. // Requires:
  3651. //
  3652. // Returns:
  3653. //
  3654. // Notes:
  3655. //
  3656. //
  3657. //--------------------------------------------------------------------------
  3658. NTSTATUS
  3659. KerbBuildEncryptedAuthData(
  3660. OUT PKERB_ENCRYPTED_DATA EncryptedAuthData,
  3661. IN PKERB_TICKET_CACHE_ENTRY Ticket,
  3662. IN PKERB_AUTHORIZATION_DATA PlainAuthData
  3663. )
  3664. {
  3665. KERBERR KerbErr;
  3666. NTSTATUS Status = STATUS_SUCCESS;
  3667. KERB_MESSAGE_BUFFER PackedAuthData = {0};
  3668. KerbErr = KerbPackData(
  3669. &PlainAuthData,
  3670. PKERB_AUTHORIZATION_DATA_LIST_PDU,
  3671. &PackedAuthData.BufferSize,
  3672. &PackedAuthData.Buffer
  3673. );
  3674. if (!KERB_SUCCESS(KerbErr))
  3675. {
  3676. Status = KerbMapKerbError(KerbErr);
  3677. goto Cleanup;
  3678. }
  3679. KerbReadLockTicketCache();
  3680. KerbErr = KerbAllocateEncryptionBufferWrapper(
  3681. Ticket->SessionKey.keytype,
  3682. PackedAuthData.BufferSize,
  3683. &EncryptedAuthData->cipher_text.length,
  3684. &EncryptedAuthData->cipher_text.value
  3685. );
  3686. if (KERB_SUCCESS(KerbErr))
  3687. {
  3688. KerbErr = KerbEncryptDataEx(
  3689. EncryptedAuthData,
  3690. PackedAuthData.BufferSize,
  3691. PackedAuthData.Buffer,
  3692. Ticket->SessionKey.keytype,
  3693. KERB_NON_KERB_SALT,
  3694. &Ticket->SessionKey
  3695. );
  3696. }
  3697. KerbUnlockTicketCache();
  3698. if (!KERB_SUCCESS(KerbErr))
  3699. {
  3700. Status = KerbMapKerbError(KerbErr);
  3701. goto Cleanup;
  3702. }
  3703. Cleanup:
  3704. if (PackedAuthData.Buffer != NULL)
  3705. {
  3706. MIDL_user_free(PackedAuthData.Buffer);
  3707. }
  3708. return(Status);
  3709. }
  3710. //+-------------------------------------------------------------------------
  3711. //
  3712. // Function: KerbGetRestrictedTgtForCredential
  3713. //
  3714. // Synopsis:
  3715. //
  3716. // Effects:
  3717. //
  3718. // Arguments:
  3719. //
  3720. // Requires:
  3721. //
  3722. // Returns:
  3723. //
  3724. // Notes:
  3725. //
  3726. //
  3727. //--------------------------------------------------------------------------
  3728. NTSTATUS
  3729. KerbGetRestrictedTgtForCredential(
  3730. IN PKERB_LOGON_SESSION LogonSession,
  3731. IN PKERB_CREDENTIAL Credential
  3732. )
  3733. {
  3734. NTSTATUS Status = STATUS_SUCCESS;
  3735. PKERB_AUTHORIZATION_DATA AuthData = NULL;
  3736. BOOLEAN CrossRealm;
  3737. PKERB_TICKET_CACHE_ENTRY ExistingTgt = NULL;
  3738. PKERB_INTERNAL_NAME ServiceName = NULL;
  3739. UNICODE_STRING ServiceRealm = NULL_UNICODE_STRING;
  3740. PKERB_KDC_REPLY KdcReply = NULL;
  3741. PKERB_ENCRYPTED_KDC_REPLY KdcReplyBody = NULL;
  3742. BOOLEAN TicketCacheLocked = FALSE;
  3743. PKERB_TICKET_CACHE_ENTRY NewTicket = NULL;
  3744. ULONG CacheFlags = 0, RetryFlags = 0;
  3745. BOOLEAN UseSuppliedCreds = FALSE;
  3746. //
  3747. // First get an old TGT
  3748. //
  3749. KerbReadLockLogonSessions(LogonSession);
  3750. if (Credential->SuppliedCredentials == NULL)
  3751. {
  3752. ULONG Flags;
  3753. //
  3754. // We don't have supplied creds, but we need them, so copy
  3755. // from the logon session.
  3756. //
  3757. Status = KerbCaptureSuppliedCreds(
  3758. LogonSession,
  3759. NULL, // no auth data
  3760. NULL, // no principal name
  3761. &Credential->SuppliedCredentials,
  3762. &Flags
  3763. );
  3764. if (!NT_SUCCESS(Status))
  3765. {
  3766. D_DebugLog((DEB_ERROR,"Failed to capture dummy supplied creds: 0x%x\n",Status));
  3767. KerbUnlockLogonSessions(LogonSession);
  3768. goto Cleanup;
  3769. }
  3770. AuthData = Credential->AuthData;
  3771. }
  3772. else
  3773. {
  3774. UseSuppliedCreds = FALSE;
  3775. }
  3776. DsysAssert(Credential->SuppliedCredentials != NULL);
  3777. Status = KerbGetTgtForService(
  3778. LogonSession,
  3779. (UseSuppliedCreds) ? Credential : NULL,
  3780. NULL,
  3781. NULL, // no SuppRealm
  3782. &Credential->SuppliedCredentials->DomainName,
  3783. &ExistingTgt,
  3784. &CrossRealm
  3785. );
  3786. KerbUnlockLogonSessions(LogonSession);
  3787. if (!NT_SUCCESS(Status))
  3788. {
  3789. goto Cleanup;
  3790. }
  3791. //
  3792. // Now get a new TGT with this ticket
  3793. //
  3794. //
  3795. // Copy the names out of the input structures so we can
  3796. // unlock the structures while going over the network.
  3797. //
  3798. KerbReadLockTicketCache();
  3799. TicketCacheLocked = TRUE;
  3800. //
  3801. // If the renew time is not much bigger than the end time, don't bother
  3802. // renewing
  3803. //
  3804. Status = KerbDuplicateString(
  3805. &ServiceRealm,
  3806. &ExistingTgt->DomainName
  3807. );
  3808. if (!NT_SUCCESS(Status))
  3809. {
  3810. goto Cleanup;
  3811. }
  3812. Status = KerbDuplicateKdcName(
  3813. &ServiceName,
  3814. ExistingTgt->ServiceName
  3815. );
  3816. if (!NT_SUCCESS(Status))
  3817. {
  3818. goto Cleanup;
  3819. }
  3820. CacheFlags = ExistingTgt->CacheFlags;
  3821. KerbUnlockTicketCache();
  3822. TicketCacheLocked = FALSE;
  3823. Status = KerbGetTgsTicket(
  3824. &ServiceRealm,
  3825. ExistingTgt,
  3826. ServiceName,
  3827. FALSE,
  3828. 0, // no ticket optiosn
  3829. 0, // no encryption type
  3830. AuthData, // no authorization data
  3831. NULL, // no tgt reply
  3832. &KdcReply,
  3833. &KdcReplyBody,
  3834. &RetryFlags
  3835. );
  3836. if (!NT_SUCCESS(Status))
  3837. {
  3838. D_DebugLog((DEB_ERROR,"Failed to get restricted tgs ticket: 0x%x\n",Status));
  3839. goto Cleanup;
  3840. }
  3841. //
  3842. // Now we want to purge the existing ticket cache and add this ticket
  3843. //
  3844. KerbPurgeTicketCache(
  3845. &Credential->SuppliedCredentials->AuthenticationTicketCache
  3846. );
  3847. KerbPurgeTicketCache(
  3848. &Credential->SuppliedCredentials->ServerTicketCache
  3849. );
  3850. KerbReadLockLogonSessions(LogonSession);
  3851. Status = KerbCacheTicket(
  3852. &Credential->SuppliedCredentials->AuthenticationTicketCache,
  3853. KdcReply,
  3854. KdcReplyBody,
  3855. ServiceName,
  3856. &ServiceRealm,
  3857. CacheFlags,
  3858. TRUE, // link this in
  3859. &NewTicket
  3860. );
  3861. KerbUnlockLogonSessions(LogonSession);
  3862. Cleanup:
  3863. if (TicketCacheLocked)
  3864. {
  3865. KerbUnlockTicketCache();
  3866. }
  3867. if (ExistingTgt != NULL)
  3868. {
  3869. KerbDereferenceTicketCacheEntry(ExistingTgt);
  3870. }
  3871. if (NewTicket != NULL)
  3872. {
  3873. KerbDereferenceTicketCacheEntry(NewTicket);
  3874. }
  3875. KerbFreeTgsReply(KdcReply);
  3876. KerbFreeKdcReplyBody(KdcReplyBody);
  3877. KerbFreeKdcName(&ServiceName);
  3878. KerbFreeString(&ServiceRealm);
  3879. return(Status);
  3880. }
  3881. #endif
  3882. #endif // WIN32_CHICAGO