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

1414 lines
35 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. context.cxx
  5. Abstract:
  6. API and support routines for handling security contexts.
  7. Author:
  8. Cliff Van Dyke (CliffV) 13-Jul-1993
  9. Revision History:
  10. ChandanS 03-Aug-1996 Stolen from net\svcdlls\ntlmssp\common\context.c
  11. --*/
  12. //
  13. // Common include files.
  14. //
  15. #include <global.h>
  16. #include <align.h> // ALIGN_WCHAR, etc
  17. #include <lm.h>
  18. #include <dsgetdc.h>
  19. SECURITY_STATUS
  20. SspContextReferenceContext(
  21. IN ULONG_PTR ContextHandle,
  22. IN BOOLEAN RemoveContext,
  23. OUT PSSP_CONTEXT *ContextResult
  24. )
  25. /*++
  26. Routine Description:
  27. This routine checks to see if the Context is for the specified
  28. Client Connection, and references the Context if it is valid.
  29. The caller may optionally request that the Context be
  30. removed from the list of valid Contexts - preventing future
  31. requests from finding this Context.
  32. Arguments:
  33. ContextHandle - Points to the ContextHandle of the Context
  34. to be referenced.
  35. RemoveContext - This boolean value indicates whether the caller
  36. wants the Context to be removed from the list
  37. of Contexts. TRUE indicates the Context is to be removed.
  38. FALSE indicates the Context is not to be removed.
  39. ContextResult set to result context handle if successful.
  40. Return Value:
  41. SEC_E_OK returns a pointer to the referenced Context.
  42. SEC_E_INVALID_HANDLE - invalid handle supplied
  43. SEC_E_CONTEXT_EXPIRED - handle was valid, but expired
  44. --*/
  45. {
  46. PSSP_CONTEXT Context;
  47. SspPrint(( SSP_API_MORE, "Entering SspContextReferenceContext\n" ));
  48. *ContextResult = NULL;
  49. #if DBG
  50. //
  51. // check for leaky client applications.
  52. //
  53. SECPKG_CALL_INFO CallInfo;
  54. if( LsaFunctions->GetCallInfo(&CallInfo) )
  55. {
  56. if ((CallInfo.Attributes & SECPKG_CALL_CLEANUP) != 0)
  57. {
  58. SspPrint(( SSP_LEAK_TRACK, "SspContextReferenceContext: pid: 0x%lx handle: %p refcount: %lu\n",
  59. CallInfo.ProcessId, ContextHandle, CallInfo.CallCount));
  60. }
  61. }
  62. #endif
  63. Context = (PSSP_CONTEXT)ContextHandle;
  64. __try {
  65. if ( (Context->ContextTag != SSP_CONTEXT_TAG_ACTIVE)
  66. || (MSV1_0_USER_SESSION_KEY_LENGTH != RtlCompareMemory(Context->ContextMagicNumber, NtlmGlobalMagicNumber, MSV1_0_USER_SESSION_KEY_LENGTH)) )
  67. {
  68. SspPrint(( SSP_CRITICAL, "Tried to reference unknown Context %p\n",
  69. Context ));
  70. return SEC_E_INVALID_HANDLE;
  71. }
  72. #if 0
  73. ASSERT( (KernelCaller == Context->KernelClient) );
  74. #endif
  75. if (!RemoveContext)
  76. {
  77. if (SspTimeHasElapsed(Context->TickStart, Context->Interval))
  78. {
  79. if ((Context->State != AuthenticatedState) &&
  80. (Context->State != AuthenticateSentState) &&
  81. (Context->State != PassedToServiceState))
  82. {
  83. SspPrint(( SSP_CRITICAL, "Context %p has timed out.\n",
  84. ContextHandle ));
  85. return SEC_E_CONTEXT_EXPIRED;
  86. }
  87. }
  88. InterlockedIncrement( (PLONG)&Context->References );
  89. }
  90. else
  91. {
  92. Context->ContextTag = SSP_CONTEXT_TAG_DELETE;
  93. RtlZeroMemory(Context->ContextMagicNumber, MSV1_0_USER_SESSION_KEY_LENGTH);
  94. SspPrint(( SSP_API_MORE, "Delinked Context %p\n", Context ));
  95. }
  96. } __except (EXCEPTION_EXECUTE_HANDLER)
  97. {
  98. SspPrint(( SSP_CRITICAL, "Tried to reference invalid Context %p\n",
  99. Context ));
  100. return SEC_E_INVALID_HANDLE;
  101. }
  102. *ContextResult = Context;
  103. return SEC_E_OK;
  104. }
  105. VOID
  106. SspContextDereferenceContext(
  107. PSSP_CONTEXT Context
  108. )
  109. /*++
  110. Routine Description:
  111. This routine decrements the specified Context's reference count.
  112. If the reference count drops to zero, then the Context is deleted
  113. Arguments:
  114. Context - Points to the Context to be dereferenced.
  115. Return Value:
  116. None.
  117. --*/
  118. {
  119. LONG References;
  120. SspPrint(( SSP_API_MORE, "Entering SspContextDereferenceContext\n" ));
  121. //
  122. // Decrement the reference count
  123. //
  124. References = InterlockedDecrement( (PLONG)&Context->References );
  125. ASSERT( References >= 0 );
  126. //
  127. // If the count dropped to zero, then run-down the Context
  128. //
  129. if (References != 0)
  130. {
  131. return;
  132. }
  133. SspPrint(( SSP_API_MORE, "Deleting Context 0x%lx\n",
  134. Context ));
  135. Context->ContextTag = SSP_CONTEXT_TAG_DELETE;
  136. RtlZeroMemory(Context->ContextMagicNumber, MSV1_0_USER_SESSION_KEY_LENGTH);
  137. if ( Context->Password.Buffer != NULL ) {
  138. // note: Password.Length may contain run-encoding hint, so size may be illegal.
  139. ZeroMemory( Context->Password.Buffer, Context->Password.MaximumLength );
  140. (VOID) NtLmFree( Context->Password.Buffer );
  141. }
  142. if ( Context->DomainName.Buffer != NULL ) {
  143. (VOID) NtLmFree( Context->DomainName.Buffer );
  144. }
  145. if ( Context->UserName.Buffer != NULL ) {
  146. (VOID) NtLmFree( Context->UserName.Buffer );
  147. }
  148. if( Context->TargetInfo != NULL )
  149. {
  150. //
  151. // CredUnmarshallTargetInfo uses LocalAlloc()
  152. //
  153. LocalFree( Context->TargetInfo );
  154. }
  155. if ( Context->TokenHandle != NULL ) {
  156. NTSTATUS IgnoreStatus;
  157. IgnoreStatus = NtClose( Context->TokenHandle );
  158. ASSERT( NT_SUCCESS(IgnoreStatus) );
  159. }
  160. if( Context->pbMarshalledTargetInfo )
  161. {
  162. LocalFree( Context->pbMarshalledTargetInfo );
  163. }
  164. if (Context->Credential != NULL) {
  165. SspCredentialDereferenceCredential( Context->Credential );
  166. }
  167. ZeroMemory( Context, sizeof(SSP_CONTEXT) );
  168. (VOID) NtLmFree( Context );
  169. return;
  170. }
  171. PSSP_CONTEXT
  172. SspContextAllocateContext(
  173. VOID
  174. )
  175. /*++
  176. Routine Description:
  177. This routine allocates the security context block, initializes it and
  178. links it onto the specified credential.
  179. Arguments: None
  180. Return Value:
  181. NULL -- Not enough memory to allocate context.
  182. otherwise -- pointer to allocated and referenced context.
  183. --*/
  184. {
  185. SspPrint(( SSP_API_MORE, "Entering SspContextAllocateContext\n" ));
  186. PSSP_CONTEXT Context;
  187. SECPKG_CALL_INFO CallInfo;
  188. //
  189. // Allocate a Context block and initialize it.
  190. //
  191. Context = (PSSP_CONTEXT)NtLmAllocate(sizeof(SSP_CONTEXT) );
  192. if ( Context == NULL ) {
  193. SspPrint(( SSP_CRITICAL, "SspContextAllocateContext: Error allocating Context.\n" ));
  194. return NULL;
  195. }
  196. ZeroMemory( Context, sizeof(SSP_CONTEXT) );
  197. if( LsaFunctions->GetCallInfo(&CallInfo) ) {
  198. Context->ClientProcessID = CallInfo.ProcessId;
  199. Context->KernelClient = ((CallInfo.Attributes & SECPKG_CALL_KERNEL_MODE) != 0);
  200. }
  201. //
  202. // The reference count is set to 2. 1 to indicate it is on the
  203. // valid Context list, and one for the our own reference.
  204. //
  205. Context->References = 2;
  206. Context->State = IdleState;
  207. //
  208. // Timeout this context.
  209. //
  210. Context->TickStart = GetTickCount();
  211. (VOID) NtQuerySystemTime( &Context->StartTime );
  212. Context->Interval = NTLMSSP_MAX_LIFETIME;
  213. //
  214. // Add it to the list of valid Context handles.
  215. //
  216. Context->ContextTag = SSP_CONTEXT_TAG_ACTIVE;
  217. RtlCopyMemory(
  218. Context->ContextMagicNumber,
  219. NtlmGlobalMagicNumber,
  220. MSV1_0_USER_SESSION_KEY_LENGTH
  221. );
  222. SspPrint(( SSP_API_MORE, "Added Context 0x%lx\n", Context ));
  223. SspPrint(( SSP_API_MORE, "Leaving SspContextAllocateContext\n" ));
  224. return Context;
  225. }
  226. NTSTATUS
  227. SspContextGetMessage(
  228. IN PVOID InputMessage,
  229. IN ULONG InputMessageSize,
  230. IN NTLM_MESSAGE_TYPE ExpectedMessageType,
  231. OUT PVOID* OutputMessage
  232. )
  233. /*++
  234. Routine Description:
  235. This routine copies the InputMessage into the local address space.
  236. This routine then validates the message header.
  237. Arguments:
  238. InputMessage - Address of the message in the client process.
  239. InputMessageSize - Size of the message (in bytes).
  240. ExpectedMessageType - The type of message the should be in the message
  241. header.
  242. OutputMessage - Returns a pointer to an allocated buffer that contains
  243. the message. The buffer should be freed using NtLmFree.
  244. Return Value:
  245. STATUS_SUCCESS - Call completed successfully
  246. SEC_E_INVALID_TOKEN -- Message improperly formatted
  247. SEC_E_INSUFFICIENT_MEMORY -- Not enough memory to allocate message
  248. --*/
  249. {
  250. NTSTATUS Status = STATUS_SUCCESS;
  251. PNEGOTIATE_MESSAGE TypicalMessage = NULL;
  252. //
  253. // Allocate a local buffer for the message.
  254. //
  255. ASSERT( NTLMSP_MAX_TOKEN_SIZE >= NTLMSSP_MAX_MESSAGE_SIZE );
  256. if ( InputMessageSize > NTLMSSP_MAX_MESSAGE_SIZE ) {
  257. Status = SEC_E_INVALID_TOKEN;
  258. SspPrint(( SSP_CRITICAL, "SspContextGetMessage, invalid input message size.\n" ));
  259. goto Cleanup;
  260. }
  261. TypicalMessage = (PNEGOTIATE_MESSAGE)NtLmAllocate(InputMessageSize );
  262. if ( TypicalMessage == NULL ) {
  263. Status = STATUS_NO_MEMORY;
  264. SspPrint(( SSP_CRITICAL, "SspContextGetMessage: Error allocating TypicalMessage.\n" ));
  265. goto Cleanup;
  266. }
  267. //
  268. // Copy the message into the buffer
  269. //
  270. RtlCopyMemory( TypicalMessage,
  271. InputMessage,
  272. InputMessageSize );
  273. //
  274. // Validate the message header.
  275. //
  276. if ( strncmp( (const char *)TypicalMessage->Signature,
  277. NTLMSSP_SIGNATURE,
  278. sizeof(NTLMSSP_SIGNATURE)) != 0 ||
  279. TypicalMessage->MessageType != ExpectedMessageType ) {
  280. (VOID) NtLmFree( TypicalMessage );
  281. TypicalMessage = NULL;
  282. Status = SEC_E_INVALID_TOKEN;
  283. SspPrint(( SSP_CRITICAL, "SspContextGetMessage, Bogus Message.\n" ));
  284. goto Cleanup;
  285. }
  286. Cleanup:
  287. *OutputMessage = TypicalMessage;
  288. return Status;
  289. }
  290. VOID
  291. SspContextCopyString(
  292. IN PVOID MessageBuffer,
  293. OUT PSTRING32 OutString,
  294. IN PSTRING InString,
  295. IN OUT PCHAR *Where
  296. )
  297. /*++
  298. Routine Description:
  299. This routine copies the InString into the MessageBuffer at Where.
  300. It then updates OutString to be a descriptor for the copied string. The
  301. descriptor 'address' is an offset from the MessageBuffer.
  302. Where is updated to point to the next available space in the MessageBuffer.
  303. The caller is responsible for any alignment requirements and for ensuring
  304. there is room in the buffer for the string.
  305. Arguments:
  306. MessageBuffer - Specifies the base address of the buffer being copied into.
  307. OutString - Returns a descriptor for the copied string. The descriptor
  308. is relative to the begining of the buffer.
  309. InString - Specifies the string to copy.
  310. Where - On input, points to where the string is to be copied.
  311. On output, points to the first byte after the string.
  312. Return Value:
  313. None.
  314. --*/
  315. {
  316. //
  317. // Copy the data to the Buffer.
  318. //
  319. if ( InString->Buffer != NULL ) {
  320. RtlCopyMemory( *Where, InString->Buffer, InString->Length );
  321. }
  322. //
  323. // Build a descriptor to the newly copied data.
  324. //
  325. OutString->Length = OutString->MaximumLength = InString->Length;
  326. OutString->Buffer = (ULONG)(*Where - ((PCHAR)MessageBuffer));
  327. //
  328. // Update Where to point past the copied data.
  329. //
  330. *Where += InString->Length;
  331. }
  332. VOID
  333. SspContextCopyStringAbsolute(
  334. IN PVOID MessageBuffer,
  335. OUT PSTRING OutString,
  336. IN PSTRING InString,
  337. IN OUT PCHAR *Where
  338. )
  339. /*++
  340. Routine Description:
  341. This routine copies the InString into the MessageBuffer at Where.
  342. It then updates OutString to be a descriptor for the copied string.
  343. Where is updated to point to the next available space in the MessageBuffer.
  344. The caller is responsible for any alignment requirements and for ensuring
  345. there is room in the buffer for the string.
  346. Arguments:
  347. MessageBuffer - Specifies the base address of the buffer being copied into.
  348. OutString - Returns a descriptor for the copied string. The descriptor
  349. is relative to the begining of the buffer.
  350. InString - Specifies the string to copy.
  351. Where - On input, points to where the string is to be copied.
  352. On output, points to the first byte after the string.
  353. Return Value:
  354. None.
  355. --*/
  356. {
  357. //
  358. // Copy the data to the Buffer.
  359. //
  360. if ( InString->Buffer != NULL ) {
  361. RtlCopyMemory( *Where, InString->Buffer, InString->Length );
  362. }
  363. //
  364. // Build a descriptor to the newly copied data.
  365. //
  366. OutString->Length = OutString->MaximumLength = InString->Length;
  367. OutString->Buffer = *Where;
  368. //
  369. // Update Where to point past the copied data.
  370. //
  371. *Where += InString->Length;
  372. }
  373. BOOLEAN
  374. SspConvertRelativeToAbsolute (
  375. IN PVOID MessageBase,
  376. IN ULONG MessageSize,
  377. IN PSTRING32 StringToRelocate,
  378. IN PSTRING OutputString,
  379. IN BOOLEAN AlignToWchar,
  380. IN BOOLEAN AllowNullString
  381. )
  382. /*++
  383. Routine Description:
  384. Convert a Relative string desriptor to be absolute.
  385. Perform all boudary condition testing.
  386. Arguments:
  387. MessageBase - a pointer to the base of the buffer that the string
  388. is relative to. The MaximumLength field of the descriptor is
  389. forced to be the same as the Length field.
  390. MessageSize - Size of the message buffer (in bytes).
  391. StringToRelocate - A pointer to the string descriptor to make absolute.
  392. AlignToWchar - If TRUE the passed in StringToRelocate must describe
  393. a buffer that is WCHAR aligned. If not, an error is returned.
  394. AllowNullString - If TRUE, the passed in StringToRelocate may be
  395. a zero length string.
  396. Return Value:
  397. TRUE - The string descriptor is valid and was properly relocated.
  398. --*/
  399. {
  400. ULONG_PTR Offset;
  401. //
  402. // If the buffer is allowed to be null,
  403. // check that special case.
  404. //
  405. if ( AllowNullString ) {
  406. if ( StringToRelocate->Length == 0 ) {
  407. OutputString->MaximumLength = OutputString->Length = StringToRelocate->Length;
  408. OutputString->Buffer = NULL;
  409. return TRUE;
  410. }
  411. }
  412. //
  413. // Ensure the string in entirely within the message.
  414. //
  415. Offset = (ULONG_PTR) StringToRelocate->Buffer;
  416. if ( Offset >= MessageSize ||
  417. Offset + StringToRelocate->Length > MessageSize ) {
  418. return FALSE;
  419. }
  420. //
  421. // Ensure the buffer is properly aligned.
  422. //
  423. if ( AlignToWchar ) {
  424. if ( !COUNT_IS_ALIGNED( Offset, ALIGN_WCHAR) ||
  425. !COUNT_IS_ALIGNED( StringToRelocate->Length, ALIGN_WCHAR) ) {
  426. return FALSE;
  427. }
  428. }
  429. //
  430. // Finally make the pointer absolute.
  431. //
  432. OutputString->Buffer = (((PCHAR)MessageBase) + Offset);
  433. OutputString->MaximumLength = OutputString->Length = StringToRelocate->Length ;
  434. return TRUE;
  435. }
  436. TimeStamp
  437. SspContextGetTimeStamp(
  438. IN PSSP_CONTEXT Context,
  439. IN BOOLEAN GetExpirationTime
  440. )
  441. /*++
  442. Routine Description:
  443. Get the Start time or Expiration time for the specified context.
  444. Arguments:
  445. Context - Pointer to the context to query
  446. GetExpirationTime - If TRUE return the expiration time.
  447. Otherwise, return the start time for the context.
  448. Return Value:
  449. Returns the requested time as a local time.
  450. --*/
  451. {
  452. NTSTATUS Status;
  453. LARGE_INTEGER SystemTime;
  454. LARGE_INTEGER LocalTime;
  455. TimeStamp LocalTimeStamp;
  456. //
  457. // Get the requested time in NT system time format.
  458. //
  459. SystemTime = Context->StartTime;
  460. if ( GetExpirationTime ) {
  461. LARGE_INTEGER Interval;
  462. //
  463. // If the time is infinite, return that
  464. //
  465. if ( Context->Interval == INFINITE ) {
  466. return NtLmGlobalForever;
  467. }
  468. //
  469. // Compute the ending time in NT System Time.
  470. //
  471. Interval.QuadPart = Int32x32To64( (LONG) Context->Interval, 10000 );
  472. SystemTime.QuadPart = Interval.QuadPart + SystemTime.QuadPart;
  473. }
  474. //
  475. // Convert the time to local time
  476. //
  477. Status = RtlSystemTimeToLocalTime( &SystemTime, &LocalTime );
  478. if ( !NT_SUCCESS(Status) ) {
  479. return NtLmGlobalForever;
  480. }
  481. LocalTimeStamp.HighPart = LocalTime.HighPart;
  482. LocalTimeStamp.LowPart = LocalTime.LowPart;
  483. return LocalTimeStamp;
  484. }
  485. VOID
  486. SspContextSetTimeStamp(
  487. IN PSSP_CONTEXT Context,
  488. IN LARGE_INTEGER ExpirationTime
  489. )
  490. /*++
  491. Routine Description:
  492. Set the Expiration time for the specified context.
  493. Arguments:
  494. Context - Pointer to the context to change
  495. ExpirationTime - Expiration time to set
  496. Return Value:
  497. NONE.
  498. --*/
  499. {
  500. LARGE_INTEGER BaseGetTickMagicDivisor = { 0xe219652c, 0xd1b71758 };
  501. CCHAR BaseGetTickMagicShiftCount = 13;
  502. LARGE_INTEGER TimeRemaining;
  503. LARGE_INTEGER MillisecondsRemaining;
  504. //
  505. // If the expiration time is infinite,
  506. // so is the interval
  507. //
  508. if ( ExpirationTime.HighPart == 0x7FFFFFFF &&
  509. ExpirationTime.LowPart == 0xFFFFFFFF ) {
  510. Context->Interval = INFINITE;
  511. //
  512. // Handle non-infinite expiration times
  513. //
  514. } else {
  515. //
  516. // Compute the time remaining before the expiration time
  517. //
  518. TimeRemaining.QuadPart = ExpirationTime.QuadPart -
  519. Context->StartTime.QuadPart;
  520. //
  521. // If the time has already expired,
  522. // indicate so.
  523. //
  524. if ( TimeRemaining.QuadPart < 0 ) {
  525. Context->Interval = 0;
  526. //
  527. // If the time hasn't expired, compute the number of milliseconds
  528. // remaining.
  529. //
  530. } else {
  531. MillisecondsRemaining = RtlExtendedMagicDivide(
  532. TimeRemaining,
  533. BaseGetTickMagicDivisor,
  534. BaseGetTickMagicShiftCount );
  535. if ( MillisecondsRemaining.HighPart == 0 &&
  536. MillisecondsRemaining.LowPart < 0x7fffffff ) {
  537. Context->Interval = MillisecondsRemaining.LowPart;
  538. } else {
  539. Context->Interval = INFINITE;
  540. }
  541. }
  542. }
  543. }
  544. NTSTATUS
  545. SsprDeleteSecurityContext (
  546. IN OUT ULONG_PTR ContextHandle
  547. )
  548. /*++
  549. Routine Description:
  550. Deletes the local data structures associated with the specified
  551. security context and generates a token which is passed to a remote peer
  552. so it too can remove the corresponding security context.
  553. This API terminates a context on the local machine, and optionally
  554. provides a token to be sent to the other machine. The OutputToken
  555. generated by this call is to be sent to the remote peer (initiator or
  556. acceptor). If the context was created with the I _REQ_ALLOCATE_MEMORY
  557. flag, then the package will allocate a buffer for the output token.
  558. Otherwise, it is the responsibility of the caller.
  559. Arguments:
  560. ContextHandle - Handle to the context to delete
  561. Return Value:
  562. STATUS_SUCCESS - Call completed successfully
  563. SEC_E_NO_SPM -- Security Support Provider is not running
  564. SEC_E_INVALID_HANDLE -- Credential/Context Handle is invalid
  565. --*/
  566. {
  567. NTSTATUS Status = STATUS_SUCCESS;
  568. PSSP_CONTEXT Context = NULL;
  569. //
  570. // Initialization
  571. //
  572. SspPrint(( SSP_API_MORE, "SspDeleteSecurityContext Entered\n" ));
  573. //
  574. // Find the currently existing context (and delink it).
  575. //
  576. Status = SspContextReferenceContext( ContextHandle, TRUE, &Context );
  577. if ( NT_SUCCESS(Status) )
  578. {
  579. SspContextDereferenceContext( Context );
  580. }
  581. SspPrint(( SSP_API_MORE, "SspDeleteSecurityContext returns 0x%lx\n", Status));
  582. return Status;
  583. }
  584. NTSTATUS
  585. SspContextInitialize(
  586. VOID
  587. )
  588. /*++
  589. Routine Description:
  590. This function initializes this module.
  591. Arguments:
  592. None.
  593. Return Value:
  594. Status of the operation.
  595. --*/
  596. {
  597. return STATUS_SUCCESS;
  598. }
  599. VOID
  600. SspContextTerminate(
  601. VOID
  602. )
  603. /*++
  604. Routine Description:
  605. This function cleans up any dangling Contexts.
  606. Arguments:
  607. None.
  608. Return Value:
  609. Status of the operation.
  610. --*/
  611. {
  612. //
  613. // don't forcibly try to delete contexts during shutdown, as, the
  614. // state of the machine is in flux during shutdown.
  615. //
  616. return;
  617. }
  618. BOOL
  619. SsprCheckMinimumSecurity(
  620. IN ULONG NegotiateFlags,
  621. IN ULONG MinimumSecurityFlags
  622. )
  623. /*++
  624. Routine Description:
  625. Check that minimum security requirements have been met.
  626. Arguments:
  627. NegotiateFlags: requested security features
  628. MinimumSecurityFlags: minimum required features
  629. Return Value:
  630. TRUE if minimum requirements met
  631. FALSE otherwise
  632. Notes:
  633. The MinimumSecurityFlags can contain features that only apply if
  634. a key is needed when doing signing or sealing. These have to be removed
  635. if SIGN or SEAL is not in the NegotiateFlags.
  636. --*/
  637. {
  638. ULONG EffFlags; // flags in effect
  639. EffFlags = MinimumSecurityFlags;
  640. if( (NegotiateFlags & NTLMSSP_NEGOTIATE_SIGN) == 0 )
  641. EffFlags &= ~(NTLMSSP_NEGOTIATE_SIGN);
  642. if( (NegotiateFlags & NTLMSSP_NEGOTIATE_SEAL) == 0 )
  643. EffFlags &= ~(NTLMSSP_NEGOTIATE_SEAL);
  644. //
  645. // if SIGN or SEAL is not negotiated, then remove all key related
  646. // requirements, since they're not relevant when a key isn't needed
  647. //
  648. if ((NegotiateFlags & (NTLMSSP_NEGOTIATE_SIGN | NTLMSSP_NEGOTIATE_SEAL)) == 0)
  649. {
  650. EffFlags &= ~(
  651. NTLMSSP_NEGOTIATE_128 |
  652. NTLMSSP_NEGOTIATE_56 |
  653. NTLMSSP_NEGOTIATE_KEY_EXCH
  654. );
  655. } else if ((NegotiateFlags & NTLMSSP_NEGOTIATE_SEAL) == 0) {
  656. //
  657. // If SIGN is negotiated, but SEAL isn't, then remove flags
  658. // that aren't relevant to encryption
  659. //
  660. EffFlags &= ~( NTLMSSP_NEGOTIATE_KEY_EXCH );
  661. }
  662. //
  663. // FYI: flags that can be usefully spec'd even without SIGN or SEAL:
  664. // NTLM2 -- forces stronger authentication
  665. // All other flags should never be set.... and are nuked in initcomn
  666. //
  667. return ((NegotiateFlags & EffFlags) == EffFlags);
  668. }
  669. SECURITY_STATUS
  670. SsprMakeSessionKey(
  671. IN PSSP_CONTEXT Context,
  672. IN PSTRING LmChallengeResponse,
  673. IN UCHAR NtUserSessionKey[MSV1_0_USER_SESSION_KEY_LENGTH], // from the DC or GetChalResp
  674. IN UCHAR LanmanSessionKey[MSV1_0_LANMAN_SESSION_KEY_LENGTH], // from the DC of GetChalResp
  675. IN PSTRING DatagramSessionKey
  676. )
  677. /*++
  678. // SsprMakeSessionKey
  679. // on entry:
  680. // if KEY_EXCH has been negotiated, then
  681. // either Context->SessionKey has a random number to be encrypted
  682. // to be sent to the server, or it has the encrypted session key
  683. // received from the client
  684. // if client, DatagramSessionKey must point to STRING set up to hold 16 byte key,
  685. // but with 0 length.
  686. // else Context->SessionKey and DatagramSessionKey are irrelevant on entry
  687. // on exit:
  688. // Context->SessionKey has the session key to be used for the rest of the session
  689. // if (DatagramSessionKey != NULL) then if KEY_EXCH then it has the encrypted session key
  690. // to send to the server, else it is zero length
  691. //
  692. --*/
  693. {
  694. NTSTATUS Status;
  695. UCHAR LocalSessionKey[MSV1_0_USER_SESSION_KEY_LENGTH];
  696. // if we don't need to make any keys, just return
  697. // RDR/SRV expect session key but don't ask for it! work-around this...
  698. // if ((Context->NegotiateFlags & (NTLMSSP_NEGOTIATE_SIGN| NTLMSSP_NEGOTIATE_SEAL)) == 0)
  699. // return(SEC_E_OK);
  700. if ((Context->NegotiateFlags & (NTLMSSP_NEGOTIATE_SIGN| NTLMSSP_NEGOTIATE_SEAL)) == 0)
  701. {
  702. RtlCopyMemory(
  703. Context->SessionKey,
  704. NtUserSessionKey,
  705. sizeof(LocalSessionKey)
  706. );
  707. return SEC_E_OK;
  708. }
  709. if (Context->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM2)
  710. {
  711. //
  712. // when using NTLM2, LSA gets passed flags that cause
  713. // it to make good session keys -- nothing for us to do
  714. //
  715. RtlCopyMemory(
  716. LocalSessionKey,
  717. NtUserSessionKey,
  718. sizeof(LocalSessionKey)
  719. );
  720. }
  721. else if( Context->NegotiateFlags & NTLMSSP_NEGOTIATE_LM_KEY )
  722. {
  723. LM_OWF_PASSWORD LmKey;
  724. LM_RESPONSE LmResponseKey;
  725. BYTE TemporaryResponse[ LM_RESPONSE_LENGTH ];
  726. RtlZeroMemory(
  727. LocalSessionKey,
  728. MSV1_0_USER_SESSION_KEY_LENGTH
  729. );
  730. if (LmChallengeResponse->Length > LM_RESPONSE_LENGTH)
  731. return(SEC_E_UNSUPPORTED_FUNCTION);
  732. ZeroMemory( TemporaryResponse, sizeof(TemporaryResponse) );
  733. CopyMemory( TemporaryResponse, LmChallengeResponse->Buffer, LmChallengeResponse->Length );
  734. //
  735. // The LM session key is made by taking the LM sesion key
  736. // given to us by the LSA, extending it to LM_OWF_LENGTH
  737. // with our salt, and then producing a new challenge-response
  738. // with it and the original challenge response. The key is
  739. // made from the first 8 bytes of the key.
  740. //
  741. RtlCopyMemory( &LmKey,
  742. LanmanSessionKey,
  743. MSV1_0_LANMAN_SESSION_KEY_LENGTH );
  744. memset( (PUCHAR)(&LmKey) + MSV1_0_LANMAN_SESSION_KEY_LENGTH,
  745. NTLMSSP_KEY_SALT,
  746. LM_OWF_PASSWORD_LENGTH - MSV1_0_LANMAN_SESSION_KEY_LENGTH );
  747. Status = RtlCalculateLmResponse(
  748. (PLM_CHALLENGE) TemporaryResponse,
  749. &LmKey,
  750. &LmResponseKey
  751. );
  752. ZeroMemory( TemporaryResponse, sizeof(TemporaryResponse) );
  753. if (!NT_SUCCESS(Status))
  754. return(SspNtStatusToSecStatus(Status, SEC_E_NO_CREDENTIALS));
  755. RtlCopyMemory(
  756. LocalSessionKey,
  757. &LmResponseKey,
  758. MSV1_0_USER_SESSION_KEY_LENGTH
  759. );
  760. } else {
  761. RtlCopyMemory(
  762. LocalSessionKey,
  763. NtUserSessionKey,
  764. MSV1_0_USER_SESSION_KEY_LENGTH
  765. );
  766. }
  767. //
  768. // If we aren't doing key exchange, store the session key in the
  769. // context. Otherwise encrypt the session key to send to the
  770. // server.
  771. //
  772. if (Context->NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
  773. struct RC4_KEYSTRUCT Rc4Key;
  774. //
  775. // make a key schedule from the temp key to form key exchange key
  776. //
  777. rc4_key(
  778. &Rc4Key,
  779. MSV1_0_USER_SESSION_KEY_LENGTH,
  780. LocalSessionKey
  781. );
  782. if (DatagramSessionKey == NULL)
  783. {
  784. //
  785. // decrypt what's in Context->SessionKey, leave it there
  786. //
  787. rc4(
  788. &Rc4Key,
  789. MSV1_0_USER_SESSION_KEY_LENGTH,
  790. Context->SessionKey
  791. );
  792. } else {
  793. //
  794. // set the proper length so client will send something (length was 0)
  795. //
  796. DatagramSessionKey->Length =
  797. DatagramSessionKey->MaximumLength =
  798. MSV1_0_USER_SESSION_KEY_LENGTH;
  799. //
  800. // copy randomly generated key to buffer to send to server
  801. //
  802. RtlCopyMemory(
  803. DatagramSessionKey->Buffer,
  804. Context->SessionKey,
  805. MSV1_0_USER_SESSION_KEY_LENGTH
  806. );
  807. //
  808. // encrypt it with the key exchange key
  809. //
  810. rc4(
  811. &Rc4Key,
  812. MSV1_0_USER_SESSION_KEY_LENGTH,
  813. (unsigned char*)DatagramSessionKey->Buffer
  814. );
  815. }
  816. } else {
  817. //
  818. // just make the temp key into the real one
  819. //
  820. RtlCopyMemory(
  821. Context->SessionKey,
  822. LocalSessionKey,
  823. MSV1_0_USER_SESSION_KEY_LENGTH
  824. );
  825. }
  826. /*
  827. //
  828. // These casts currently generate an alignment fault on 64-bit and AV on 32-bit.
  829. //
  830. SspPrint((SSP_SESSION_KEYS, "SsprMakeSessionKey NegotiateFlags %lx, session key %lx %lx %lx %lx\n",
  831. Context->NegotiateFlags,
  832. ((DWORD*)Context->SessionKey)[0],
  833. ((DWORD*)Context->SessionKey)[1],
  834. ((DWORD*)Context->SessionKey)[2],
  835. ((DWORD*)Context->SessionKey)[3]
  836. ));
  837. SspPrint((SSP_SESSION_KEYS, "SsprMakeSessionKey LmChallengeResponse %lx %lx %lx %lx %lx %lx\n",
  838. ((DWORD*)LmChallengeResponse->Buffer)[0],
  839. ((DWORD*)LmChallengeResponse->Buffer)[1],
  840. ((DWORD*)LmChallengeResponse->Buffer)[2],
  841. ((DWORD*)LmChallengeResponse->Buffer)[3],
  842. ((DWORD*)LmChallengeResponse->Buffer)[4],
  843. ((DWORD*)LmChallengeResponse->Buffer)[5]
  844. ));
  845. if (DatagramSessionKey && DatagramSessionKey->Length >= MSV1_0_USER_SESSION_KEY_LENGTH)
  846. {
  847. SspPrint((SSP_SESSION_KEYS, "SsprMakeSessionKey datagram session key %lx %lx %lx %lx\n",
  848. ((DWORD*)DatagramSessionKey->Buffer)[0],
  849. ((DWORD*)DatagramSessionKey->Buffer)[1],
  850. ((DWORD*)DatagramSessionKey->Buffer)[2],
  851. ((DWORD*)DatagramSessionKey->Buffer)[3]
  852. ));
  853. }
  854. */
  855. return(SEC_E_OK);
  856. }
  857. NTSTATUS
  858. SsprQueryTreeName(
  859. OUT PUNICODE_STRING TreeName
  860. )
  861. {
  862. PDS_DOMAIN_TRUSTSW Trusts = NULL;
  863. ULONG TrustCount ;
  864. ULONG Index;
  865. LPWSTR DnsTreeName = NULL;
  866. DWORD NetStatus;
  867. ZeroMemory( TreeName, sizeof(*TreeName) );
  868. NetStatus = DsEnumerateDomainTrustsW(
  869. NULL,
  870. DS_DOMAIN_PRIMARY | DS_DOMAIN_IN_FOREST,
  871. &Trusts,
  872. &TrustCount
  873. );
  874. if( NetStatus != NO_ERROR )
  875. {
  876. // TODO: Talk to CliffV about failure causes.
  877. // in any event, the failure is not catastrophic.
  878. //
  879. return STATUS_SUCCESS;
  880. }
  881. for(Index = 0 ; Index < TrustCount; Index++)
  882. {
  883. ULONG Attempts; // bound the attempts in the event bogus data comes back.
  884. if( (Trusts[Index].Flags & DS_DOMAIN_PRIMARY) == 0)
  885. {
  886. continue;
  887. }
  888. for( Attempts = 0 ; Index < TrustCount; Attempts++ )
  889. {
  890. if( Attempts > TrustCount )
  891. {
  892. break;
  893. }
  894. if( (Trusts[Index].Flags & DS_DOMAIN_TREE_ROOT) == 0 )
  895. {
  896. Index = Trusts[Index].ParentIndex;
  897. continue;
  898. }
  899. DnsTreeName = Trusts[Index].DnsDomainName;
  900. break;
  901. }
  902. break;
  903. }
  904. if( DnsTreeName )
  905. {
  906. DWORD cchTreeName = lstrlenW( DnsTreeName );
  907. TreeName->Buffer = (PWSTR)NtLmAllocate( cchTreeName*sizeof(WCHAR) );
  908. if( TreeName->Buffer == NULL )
  909. {
  910. return STATUS_INSUFFICIENT_RESOURCES;
  911. }
  912. TreeName->Length = (USHORT)(cchTreeName*sizeof(WCHAR));
  913. TreeName->MaximumLength = TreeName->Length;
  914. RtlCopyMemory( TreeName->Buffer, DnsTreeName, TreeName->Length );
  915. }
  916. NetApiBufferFree( Trusts );
  917. return STATUS_SUCCESS;
  918. }
  919. NTSTATUS
  920. SsprUpdateTargetInfo(
  921. VOID
  922. )
  923. /*++
  924. Update the NtLmGlobalNtLm3TargetInfo buffer based on the current values
  925. of the various global variables.
  926. NOTE: the global lock must be held for exclusive access prior to making
  927. this call!
  928. --*/
  929. {
  930. PMSV1_0_AV_PAIR pAV;
  931. PUNICODE_STRING pDnsTargetName;
  932. PUNICODE_STRING pDnsComputerName;
  933. PUNICODE_STRING pDnsTreeName;
  934. ULONG cbAV;
  935. ULONG AvFlags = 0;
  936. if( NtLmGlobalNtLm3TargetInfo.Buffer != NULL )
  937. {
  938. NtLmFree(NtLmGlobalNtLm3TargetInfo.Buffer);
  939. NtLmGlobalNtLm3TargetInfo.Buffer = NULL;
  940. NtLmGlobalNtLm3TargetInfo.MaximumLength = NtLmGlobalNtLm3TargetInfo.Length = 0;
  941. }
  942. if( NtLmGlobalTargetFlags == NTLMSSP_TARGET_TYPE_DOMAIN ) {
  943. pDnsTargetName = &NtLmGlobalUnicodeDnsDomainNameString;
  944. } else {
  945. pDnsTargetName = &NtLmGlobalUnicodeDnsComputerNameString;
  946. }
  947. pDnsComputerName = &NtLmGlobalUnicodeDnsComputerNameString;
  948. pDnsTreeName = &NtLmGlobalUnicodeDnsTreeName;
  949. cbAV = NtLmGlobalUnicodeTargetName.Length +
  950. NtLmGlobalUnicodeComputerNameString.Length +
  951. pDnsComputerName->Length +
  952. pDnsTargetName->Length +
  953. pDnsTreeName->Length +
  954. sizeof( AvFlags ) +
  955. (sizeof( MSV1_0_AV_PAIR ) * 6) +
  956. sizeof( MSV1_0_AV_PAIR );
  957. NtLmGlobalNtLm3TargetInfo.Buffer = (PWSTR)NtLmAllocate( cbAV );
  958. if( NtLmGlobalNtLm3TargetInfo.Buffer == NULL )
  959. {
  960. SspPrint((SSP_CRITICAL, "SsprUpdateTargetInfo, Error from NtLmAllocate\n"));
  961. return STATUS_INSUFFICIENT_RESOURCES;
  962. }
  963. ZeroMemory( NtLmGlobalNtLm3TargetInfo.Buffer, cbAV );
  964. pAV = MsvpAvlInit( NtLmGlobalNtLm3TargetInfo.Buffer );
  965. MsvpAvlAdd( pAV, MsvAvNbDomainName, &NtLmGlobalUnicodeTargetName, cbAV );
  966. MsvpAvlAdd( pAV, MsvAvNbComputerName, &NtLmGlobalUnicodeComputerNameString, cbAV );
  967. if( pDnsTargetName->Length != 0 && pDnsTargetName->Buffer != NULL )
  968. {
  969. MsvpAvlAdd( pAV, MsvAvDnsDomainName, pDnsTargetName, cbAV );
  970. }
  971. if( pDnsComputerName->Length != 0 && pDnsComputerName->Buffer != NULL )
  972. {
  973. MsvpAvlAdd( pAV, MsvAvDnsComputerName, pDnsComputerName, cbAV );
  974. }
  975. if( pDnsTreeName->Length != 0 && pDnsTreeName->Buffer != NULL )
  976. {
  977. MsvpAvlAdd( pAV, MsvAvDnsTreeName, pDnsTreeName, cbAV );
  978. }
  979. //
  980. // add in AvFlags into TargetInfo, if applicable.
  981. //
  982. if( NtLmGlobalForceGuest )
  983. {
  984. AvFlags |= MSV1_0_AV_FLAG_FORCE_GUEST;
  985. }
  986. if( AvFlags )
  987. {
  988. UNICODE_STRING AvString;
  989. AvString.Buffer = (PWSTR)&AvFlags;
  990. AvString.Length = sizeof( AvFlags );
  991. AvString.MaximumLength = AvString.Length;
  992. MsvpAvlAdd( pAV, MsvAvFlags, &AvString, cbAV );
  993. }
  994. NtLmGlobalNtLm3TargetInfo.Length = (USHORT)MsvpAvlLen( pAV, cbAV );
  995. NtLmGlobalNtLm3TargetInfo.MaximumLength = NtLmGlobalNtLm3TargetInfo.Length;
  996. return STATUS_SUCCESS;
  997. }