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.

4010 lines
115 KiB

  1. //+-----------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (c) Microsoft Corporation 1992 - 1999
  6. //
  7. // File: userapi.cxx
  8. //
  9. // Contents: User-mode APIs to the NtLm security package
  10. //
  11. // Main user mode entry points into this dll:
  12. // SpUserModeInitialize
  13. // SpInstanceInit
  14. // SpDeleteUserModeContext
  15. // SpInitUserModeContext
  16. // SpMakeSignature
  17. // SpVerifySignature
  18. // SpSealMessage
  19. // SpUnsealMessage
  20. // SpGetContextToken
  21. // SpQueryContextAttributes
  22. // SpCompleteAuthToken
  23. // SpFormatCredentials
  24. // SpMarshallSupplementalCreds
  25. // SpExportSecurityContext
  26. // SpImportSecurityContext
  27. //
  28. // Helper functions:
  29. // ReferenceUserContext
  30. // FreeUserContext
  31. // DereferenceUserContext
  32. // SspGenCheckSum
  33. // SspEncryptBuffer
  34. // NtLmMakePackedContext(this is called in the client's process)
  35. // NtLmCreateUserModeContext
  36. // SspGetTokenUser
  37. // SspCreateTokenDacl
  38. // SspMapContext (this is called in Lsa mode)
  39. //
  40. // History: ChandanS 26-Jul-1996 Stolen from kerberos\client2\userapi.cxx
  41. //
  42. //------------------------------------------------------------------------
  43. #include <global.h> // Globals!
  44. #include "crc32.h" // How to use crc32
  45. #include <wincrypt.h>
  46. #include <kerberos.h>
  47. extern "C"
  48. {
  49. #include <nlp.h>
  50. }
  51. // Keep this is sync with NTLM_KERNEL_CONTEXT defined in
  52. // security\msv_sspi\kernel\krnlapi.cxx
  53. typedef struct _NTLM_CLIENT_CONTEXT{
  54. union {
  55. LIST_ENTRY Next;
  56. KSEC_LIST_ENTRY KernelNext;
  57. };
  58. ULONG_PTR LsaContext;
  59. ULONG NegotiateFlags;
  60. HANDLE ClientTokenHandle;
  61. PACCESS_TOKEN AccessToken;
  62. PULONG pSendNonce; // ptr to nonce to use for send
  63. PULONG pRecvNonce; // ptr to nonce to use for receive
  64. struct RC4_KEYSTRUCT * pSealRc4Sched; // ptr to key sched used for Seal
  65. struct RC4_KEYSTRUCT * pUnsealRc4Sched; // ptr to key sched used to Unseal
  66. ULONG SendNonce;
  67. ULONG RecvNonce;
  68. LPWSTR ContextNames;
  69. PUCHAR pbMarshalledTargetInfo;
  70. ULONG cbMarshalledTargetInfo;
  71. UCHAR SessionKey[MSV1_0_USER_SESSION_KEY_LENGTH];
  72. ULONG ContextSignature;
  73. ULONG References ;
  74. TimeStamp PasswordExpiry;
  75. ULONG UserFlags;
  76. UCHAR SignSessionKey[MSV1_0_USER_SESSION_KEY_LENGTH];
  77. UCHAR VerifySessionKey[MSV1_0_USER_SESSION_KEY_LENGTH];
  78. UCHAR SealSessionKey[MSV1_0_USER_SESSION_KEY_LENGTH];
  79. UCHAR UnsealSessionKey[MSV1_0_USER_SESSION_KEY_LENGTH];
  80. ULONG64 Pad1; // pad keystructs to 64.
  81. struct RC4_KEYSTRUCT SealRc4Sched; // key struct used for Seal
  82. ULONG64 Pad2; // pad keystructs to 64.
  83. struct RC4_KEYSTRUCT UnsealRc4Sched; // key struct used to Unseal
  84. } NTLM_CLIENT_CONTEXT, * PNTLM_CLIENT_CONTEXT;
  85. typedef struct _NTLM_PACKED_CONTEXT {
  86. ULONG Tag ;
  87. ULONG NegotiateFlags ;
  88. ULONG ClientTokenHandle ;
  89. ULONG SendNonce ;
  90. ULONG RecvNonce ;
  91. UCHAR SessionKey[ MSV1_0_USER_SESSION_KEY_LENGTH ];
  92. ULONG ContextSignature ;
  93. TimeStamp PasswordExpiry ;
  94. ULONG UserFlags ;
  95. ULONG ContextNames ;
  96. ULONG ContextNameLength ;
  97. ULONG MarshalledTargetInfo; // offset
  98. ULONG MarshalledTargetInfoLength;
  99. UCHAR SignSessionKey[ MSV1_0_USER_SESSION_KEY_LENGTH ];
  100. UCHAR VerifySessionKey[ MSV1_0_USER_SESSION_KEY_LENGTH ];
  101. UCHAR SealSessionKey[ MSV1_0_USER_SESSION_KEY_LENGTH ];
  102. UCHAR UnsealSessionKey[ MSV1_0_USER_SESSION_KEY_LENGTH ];
  103. struct RC4_KEYSTRUCT SealRc4Sched;
  104. struct RC4_KEYSTRUCT UnsealRc4Sched;
  105. } NTLM_PACKED_CONTEXT, * PNTLM_PACKED_CONTEXT ;
  106. #define NTLM_PACKED_CONTEXT_MAP 0
  107. #define NTLM_PACKED_CONTEXT_EXPORT 1
  108. #define CSSEALMAGIC "session key to client-to-server sealing key magic constant"
  109. #define SCSEALMAGIC "session key to server-to-client sealing key magic constant"
  110. #define CSSIGNMAGIC "session key to client-to-server signing key magic constant"
  111. #define SCSIGNMAGIC "session key to server-to-client signing key magic constant"
  112. #define NTLM_USERLIST_COUNT (16) // count of lists
  113. #define NTLM_USERLIST_LOCK_COUNT_MAX (4) // count of locks
  114. LIST_ENTRY NtLmUserContextList[ NTLM_USERLIST_COUNT ]; // list array.
  115. RTL_RESOURCE NtLmUserContextLock[ NTLM_USERLIST_LOCK_COUNT_MAX ]; // lock array
  116. ULONG NtLmUserContextCount[ NTLM_USERLIST_COUNT ]; // count of active contexts
  117. ULONG NtLmUserContextLockCount;
  118. // Counter for exported handles;never de-refed
  119. // Should probably do a GetSystemInfo and get a space of handles that cannot
  120. // be valid in the Lsa process
  121. ULONG_PTR ExportedContext = 0;
  122. NTSTATUS
  123. SspCreateTokenDacl(
  124. HANDLE Token
  125. );
  126. ULONG
  127. HandleToListIndex(
  128. ULONG_PTR ContextHandle
  129. );
  130. ULONG
  131. __inline
  132. ListIndexToLockIndex(
  133. ULONG ListIndex
  134. );
  135. //+-------------------------------------------------------------------------
  136. //
  137. // Function: SpUserModeInitialize
  138. //
  139. // Synopsis: Initialize an the MSV1_0 DLL in a client's
  140. // address space
  141. //
  142. // Effects:
  143. //
  144. // Arguments: LsaVersion - Version of the security dll loading the package
  145. // PackageVersion - Version of the MSV1_0 package
  146. // UserFunctionTable - Receives a copy of Kerberos's user mode
  147. // function table
  148. // pcTables - Receives count of tables returned.
  149. //
  150. // Requires:
  151. //
  152. // Returns: STATUS_SUCCESS
  153. //
  154. // Notes: we do what was done in SspInitLocalContexts()
  155. // from net\svcdlls\ntlmssp\client\sign.c and more.
  156. //
  157. //
  158. //--------------------------------------------------------------------------
  159. NTSTATUS
  160. SEC_ENTRY
  161. SpUserModeInitialize(
  162. IN ULONG LsaVersion,
  163. OUT PULONG PackageVersion,
  164. OUT PSECPKG_USER_FUNCTION_TABLE * UserFunctionTable,
  165. OUT PULONG pcTables
  166. )
  167. {
  168. NTSTATUS Status = STATUS_SUCCESS;
  169. #if DBG
  170. if ( NtLmState != NtLmLsaMode )
  171. {
  172. SspGlobalDbflag = SSP_CRITICAL;
  173. InitializeCriticalSection(&SspGlobalLogFileCritSect);
  174. }
  175. #endif
  176. if (LsaVersion != SECPKG_INTERFACE_VERSION)
  177. {
  178. Status = STATUS_INVALID_PARAMETER;
  179. goto Cleanup;
  180. }
  181. *PackageVersion = SECPKG_INTERFACE_VERSION;
  182. NtLmUserFunctionTable.InstanceInit = SpInstanceInit;
  183. NtLmUserFunctionTable.MakeSignature = SpMakeSignature;
  184. NtLmUserFunctionTable.VerifySignature = SpVerifySignature;
  185. NtLmUserFunctionTable.SealMessage = SpSealMessage;
  186. NtLmUserFunctionTable.UnsealMessage = SpUnsealMessage;
  187. NtLmUserFunctionTable.GetContextToken = SpGetContextToken;
  188. NtLmUserFunctionTable.QueryContextAttributes = SpQueryContextAttributes;
  189. NtLmUserFunctionTable.CompleteAuthToken = SpCompleteAuthToken;
  190. NtLmUserFunctionTable.InitUserModeContext = SpInitUserModeContext;
  191. NtLmUserFunctionTable.DeleteUserModeContext = SpDeleteUserModeContext;
  192. NtLmUserFunctionTable.FormatCredentials = SpFormatCredentials;
  193. NtLmUserFunctionTable.MarshallSupplementalCreds = SpMarshallSupplementalCreds;
  194. NtLmUserFunctionTable.ExportContext = SpExportSecurityContext;
  195. NtLmUserFunctionTable.ImportContext = SpImportSecurityContext;
  196. *UserFunctionTable = &NtLmUserFunctionTable;
  197. *pcTables = 1;
  198. if ( NtLmState != NtLmLsaMode)
  199. {
  200. //
  201. // SafeAllocaInitialize was already called in SpLsaModeInitialize
  202. //
  203. SafeAllocaInitialize(SAFEALLOCA_USE_DEFAULT,
  204. SAFEALLOCA_USE_DEFAULT,
  205. NtLmAllocate,
  206. NtLmFree);
  207. }
  208. Cleanup:
  209. return(SspNtStatusToSecStatus(Status, SEC_E_INTERNAL_ERROR));
  210. }
  211. //+-------------------------------------------------------------------------
  212. //
  213. // Function: ReferenceUserContext
  214. //
  215. // Synopsis: locates a user context in the list, refrences it
  216. //
  217. // Effects:
  218. //
  219. // Arguments:
  220. //
  221. // Requires:
  222. //
  223. // Returns: the context, if it is found, else NULL
  224. //
  225. // Notes: This was SspContextReferenceContext() in
  226. // net\svcdlls\ntlmssp\common\context.c
  227. //
  228. //
  229. //--------------------------------------------------------------------------
  230. PNTLM_CLIENT_CONTEXT
  231. ReferenceUserContext(
  232. IN ULONG_PTR ContextHandle,
  233. IN BOOLEAN RemoveContext )
  234. {
  235. SspPrint(( SSP_API_MORE, "Entering ReferenceUserContext for 0x%x\n", ContextHandle ));
  236. PLIST_ENTRY ListEntry;
  237. PNTLM_CLIENT_CONTEXT pContext = NULL;
  238. ULONG ListIndex;
  239. ULONG LockIndex;
  240. ListIndex = HandleToListIndex( ContextHandle );
  241. LockIndex = ListIndexToLockIndex( ListIndex );
  242. RtlAcquireResourceShared(&NtLmUserContextLock[LockIndex], TRUE);
  243. //
  244. // Look for a match for the LsaContext, not user context
  245. //
  246. for ( ListEntry = NtLmUserContextList[ListIndex].Flink;
  247. ListEntry != &NtLmUserContextList[ListIndex];
  248. ListEntry = ListEntry->Flink )
  249. {
  250. pContext = CONTAINING_RECORD(ListEntry, NTLM_CLIENT_CONTEXT, Next);
  251. if (pContext->LsaContext != ContextHandle)
  252. {
  253. pContext = NULL;
  254. continue;
  255. }
  256. //
  257. // Found it!
  258. //
  259. if (!RemoveContext)
  260. {
  261. InterlockedIncrement( (PLONG)&pContext->References );
  262. }
  263. else
  264. {
  265. RtlConvertSharedToExclusive(&NtLmUserContextLock[LockIndex]);
  266. //
  267. // pContext can be deleted at this moment, in which case,
  268. // applications would simply AV in their own process spaces, this
  269. // is acceptable because there is no need to validate the handle
  270. // in the first place
  271. //
  272. RemoveEntryList(&pContext->Next);
  273. NtLmUserContextCount[ListIndex]--;
  274. SspPrint(( SSP_API_MORE, "ReferenceUserContext delinked Context %p\n", pContext ));
  275. }
  276. break;
  277. }
  278. RtlReleaseResource(&NtLmUserContextLock[LockIndex]);
  279. SspPrint(( SSP_API_MORE, "Leaving ReferenceUserContext for %p, returning %p\n", ContextHandle, pContext ));
  280. return pContext;
  281. }
  282. //+-------------------------------------------------------------------------
  283. //
  284. // Function: FreeUserContext
  285. //
  286. // Synopsis: frees alloced pointers in this context and
  287. // then frees the context
  288. //
  289. // Arguments: lContext - the unlinked user context
  290. //
  291. // Returns: STATUS_SUCCESS on success
  292. //
  293. // Notes:
  294. //
  295. //--------------------------------------------------------------------------
  296. NTSTATUS
  297. FreeUserContext (
  298. PNTLM_CLIENT_CONTEXT UserContext
  299. )
  300. {
  301. SspPrint(( SSP_API_MORE, "Entering FreeUserContext for context 0x%x\n", UserContext ));
  302. NTSTATUS Status = STATUS_SUCCESS;
  303. if (UserContext->ContextNames != NULL)
  304. {
  305. NtLmFree (UserContext->ContextNames);
  306. }
  307. if (UserContext->pbMarshalledTargetInfo != NULL)
  308. {
  309. NtLmFree (UserContext->pbMarshalledTargetInfo);
  310. }
  311. if (UserContext->ClientTokenHandle != NULL)
  312. {
  313. NTSTATUS IgnoreStatus;
  314. IgnoreStatus = NtClose(UserContext->ClientTokenHandle);
  315. ASSERT (NT_SUCCESS (IgnoreStatus));
  316. }
  317. SspPrint(( SSP_API_MORE, "Deleting Context 0x%x\n", UserContext));
  318. ZeroMemory( UserContext, sizeof(*UserContext) );
  319. NtLmFree (UserContext);
  320. SspPrint(( SSP_API_MORE, "Leaving FreeUserContext for context 0x%x, status = 0x%x\n", Status ));
  321. return Status;
  322. }
  323. //+-------------------------------------------------------------------------
  324. //
  325. // Function: DereferenceUserContext
  326. //
  327. // Synopsis: frees alloced elements in the context, frees context
  328. //
  329. // Effects:
  330. //
  331. // Arguments:
  332. //
  333. // Requires:
  334. //
  335. // Returns: None
  336. //
  337. // Notes: This was SspContextDereferenceContext() in
  338. // net\svcdlls\ntlmssp\common\context.c
  339. //
  340. //
  341. //--------------------------------------------------------------------------
  342. NTSTATUS
  343. DereferenceUserContext (
  344. PNTLM_CLIENT_CONTEXT pContext
  345. )
  346. {
  347. SspPrint(( SSP_API_MORE, "Entering DereferenceUserContext 0x%lx\n", pContext ));
  348. NTSTATUS Status = STATUS_SUCCESS;
  349. LONG References;
  350. //
  351. // Decrement the reference count
  352. //
  353. /// RtlAcquireResourceShared(&NtLmUserContextLock, TRUE);
  354. //// ASSERT (pContext->References >= 1);
  355. //// References = -- pContext->References;
  356. References = InterlockedDecrement( (PLONG)&pContext->References );
  357. ASSERT( References >= 0 );
  358. //// RtlReleaseResource(&NtLmUserContextLock);
  359. //
  360. // If the count has dropped to zero, then free all alloced stuff
  361. //
  362. if (References == 0)
  363. {
  364. Status = FreeUserContext(pContext);
  365. }
  366. SspPrint(( SSP_API_MORE, "Leaving DereferenceUserContext\n" ));
  367. return Status;
  368. }
  369. //+-------------------------------------------------------------------------
  370. //
  371. // Function: SpInstanceInit
  372. //
  373. // Synopsis: Initialize an instance of the NtLm package in a client's
  374. // address space
  375. //
  376. // Effects:
  377. //
  378. // Arguments: Version - Version of the security dll loading the package
  379. // FunctionTable - Contains helper routines for use by NtLm
  380. // UserFunctions - Receives a copy of NtLm's user mode
  381. // function table
  382. //
  383. // Requires:
  384. //
  385. // Returns: STATUS_SUCCESS
  386. //
  387. // Notes: we do what was done in SspInitLocalContexts()
  388. // from net\svcdlls\ntlmssp\client\sign.c and more.
  389. //
  390. //
  391. //--------------------------------------------------------------------------
  392. NTSTATUS NTAPI
  393. SpInstanceInit(
  394. IN ULONG Version,
  395. IN PSECPKG_DLL_FUNCTIONS DllFunctionTable,
  396. OUT PVOID * UserFunctionTable
  397. )
  398. {
  399. SspPrint(( SSP_API, "Entering SpInstanceInit\n" ));
  400. NTSTATUS Status = STATUS_SUCCESS;
  401. NT_PRODUCT_TYPE ProductType;
  402. ULONG Index;
  403. ULONG cResourcesInitialized = 0;
  404. // Save the Alloc/Free functions
  405. if( NtLmState != NtLmLsaMode )
  406. {
  407. NtLmState = NtLmUserMode;
  408. }
  409. UserFunctions = DllFunctionTable;
  410. for( Index=0 ; Index < NTLM_USERLIST_COUNT ; Index++ )
  411. {
  412. InitializeListHead (&NtLmUserContextList[Index]);
  413. }
  414. NtLmUserContextLockCount = 1;
  415. RtlGetNtProductType( &ProductType );
  416. if( ProductType == NtProductLanManNt ||
  417. ProductType == NtProductServer )
  418. {
  419. SYSTEM_INFO si;
  420. GetSystemInfo( &si );
  421. //
  422. // if not an even power of two, bump it up.
  423. //
  424. if( si.dwNumberOfProcessors & 1 )
  425. {
  426. si.dwNumberOfProcessors++;
  427. }
  428. //
  429. // insure it fits in the confines of the max allowed.
  430. //
  431. if( si.dwNumberOfProcessors > NTLM_USERLIST_LOCK_COUNT_MAX )
  432. {
  433. si.dwNumberOfProcessors = NTLM_USERLIST_LOCK_COUNT_MAX;
  434. }
  435. if( si.dwNumberOfProcessors )
  436. {
  437. NtLmUserContextLockCount = si.dwNumberOfProcessors;
  438. }
  439. }
  440. //
  441. // list count is 1, or a power of two, for index purposes.
  442. //
  443. ASSERT( (NtLmUserContextLockCount == 1) || ((NtLmUserContextLockCount % 2) == 0) );
  444. for (Index=0; Index < NtLmUserContextLockCount; Index++)
  445. {
  446. __try
  447. {
  448. RtlInitializeResource(&NtLmUserContextLock[Index]);
  449. cResourcesInitialized++; // keep track of Resources that are initialized
  450. }
  451. __except(EXCEPTION_EXECUTE_HANDLER)
  452. {
  453. Status = STATUS_INSUFFICIENT_RESOURCES;
  454. break;
  455. }
  456. }
  457. //
  458. // avoiding deleting RTL_RESOURCEs with un-initialized fields
  459. //
  460. if (!NT_SUCCESS(Status))
  461. {
  462. for (Index = 0; Index < cResourcesInitialized; Index++)
  463. {
  464. RtlDeleteResource(&NtLmUserContextLock[Index]);
  465. }
  466. }
  467. SspPrint(( SSP_API, "Leaving SpInstanceInit: 0x%lx\n", Status ));
  468. return(SspNtStatusToSecStatus(Status, SEC_E_INTERNAL_ERROR));
  469. }
  470. //+-------------------------------------------------------------------------
  471. //
  472. // Function: SpDeleteUserModeContext
  473. //
  474. // Synopsis: Deletes a user mode context by unlinking it and then
  475. // dereferencing it.
  476. //
  477. // Effects:
  478. //
  479. // Arguments: ContextHandle - Lsa context handle of the context to delete
  480. //
  481. // Requires:
  482. //
  483. // Returns: STATUS_SUCCESS on success, STATUS_INVALID_HANDLE if the
  484. // context can't be located
  485. //
  486. // Notes:
  487. // If this is an exported context, send a flag back to the LSA so that
  488. // Lsa does not call the SecpDeleteSecurityContext in the lsa process
  489. //
  490. //
  491. //--------------------------------------------------------------------------
  492. NTSTATUS NTAPI
  493. SpDeleteUserModeContext(
  494. IN ULONG_PTR ContextHandle
  495. )
  496. {
  497. SspPrint(( SSP_API, "Entering SpDeleteUserModeContext 0x%lx\n", ContextHandle ));
  498. PNTLM_CLIENT_CONTEXT pContext = NULL;
  499. NTSTATUS Status = STATUS_SUCCESS, SaveStatus = STATUS_SUCCESS;
  500. //
  501. // Find the currently existing user context and delink it
  502. // so that another context cannot Reference it before we
  503. // Dereference this one.
  504. //
  505. pContext = ReferenceUserContext(ContextHandle, TRUE);
  506. if (pContext == NULL)
  507. {
  508. //
  509. // pContext is legally NULL when we are dealing with an incomplete
  510. // context. This can often be the case when the second call to
  511. // InitializeSecurityContext() fails.
  512. //
  513. /// Status = STATUS_INVALID_HANDLE;
  514. Status = STATUS_SUCCESS;
  515. SspPrint(( SSP_API_MORE, "SpDeleteUserModeContext, local pContext is NULL\n" ));
  516. goto CleanUp;
  517. }
  518. if ((pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_EXPORTED_CONTEXT) != 0)
  519. {
  520. // Ignore all other errors and pass back
  521. SaveStatus = SEC_I_NO_LSA_CONTEXT;
  522. }
  523. CleanUp:
  524. if (pContext != NULL)
  525. {
  526. Status = DereferenceUserContext(pContext);
  527. }
  528. if (SaveStatus == SEC_I_NO_LSA_CONTEXT)
  529. {
  530. Status = SaveStatus;
  531. }
  532. SspPrint(( SSP_API, "Leaving SpDeleteUserModeContext: 0x%lx\n", Status ));
  533. return(SspNtStatusToSecStatus(Status, SEC_E_INTERNAL_ERROR));
  534. }
  535. VOID
  536. SspRc4Key(
  537. IN ULONG NegotiateFlags,
  538. OUT struct RC4_KEYSTRUCT *pRc4Key,
  539. IN PUCHAR pSessionKey
  540. )
  541. /*++
  542. RoutineDescription:
  543. Create an RC4 key schedule, making sure key length is OK for export
  544. Arguments:
  545. NegotiateFlags negotiate feature flags; NTLM2 bit is only one looked at
  546. pRc4Key pointer to RC4 key schedule structure; filled in by this routine
  547. pSessionKey pointer to session key -- must be full 16 bytes
  548. Return Value:
  549. --*/
  550. {
  551. //
  552. // For NTLM2, effective length was already cut down
  553. //
  554. if ((NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM2) != 0) {
  555. rc4_key(pRc4Key, MSV1_0_USER_SESSION_KEY_LENGTH, pSessionKey);
  556. } else if( NegotiateFlags & NTLMSSP_NEGOTIATE_LM_KEY ) {
  557. UCHAR Key[MSV1_0_LANMAN_SESSION_KEY_LENGTH];
  558. ULONG KeyLen;
  559. ASSERT(MSV1_0_LANMAN_SESSION_KEY_LENGTH == 8);
  560. // prior to Win2k, negotiated key strength had no bearing on
  561. // key size. So, to allow proper interop to NT4, we don't
  562. // worry about 128bit. 56bit and 40bit are the only supported options.
  563. // 56bit is enabled because this was introduced in Win2k, and
  564. // Win2k -> Win2k interops correctly.
  565. //
  566. #if 0
  567. if( NegotiateFlags & NTLMSSP_NEGOTIATE_128 ) {
  568. KeyLen = 8;
  569. } else
  570. #endif
  571. if( NegotiateFlags & NTLMSSP_NEGOTIATE_56 ) {
  572. KeyLen = 7;
  573. //
  574. // Put a well-known salt at the end of the key to
  575. // limit the changing part to 56 bits.
  576. //
  577. Key[7] = 0xa0;
  578. } else {
  579. KeyLen = 5;
  580. //
  581. // Put a well-known salt at the end of the key to
  582. // limit the changing part to 40 bits.
  583. //
  584. Key[5] = 0xe5;
  585. Key[6] = 0x38;
  586. Key[7] = 0xb0;
  587. }
  588. RtlCopyMemory(Key,pSessionKey,KeyLen);
  589. SspPrint(( SSP_SESSION_KEYS, "Non NTLMv2 LM_KEY session key size: %lu key=%lx%lx\n",
  590. KeyLen,
  591. ((DWORD*)Key)[0],
  592. ((DWORD*)Key)[1]
  593. ));
  594. rc4_key(pRc4Key, MSV1_0_LANMAN_SESSION_KEY_LENGTH, Key);
  595. } else {
  596. SspPrint(( SSP_SESSION_KEYS, "Non NTLMv2 (not LM_KEY) session key size: %lu\n", 16));
  597. rc4_key(pRc4Key, MSV1_0_USER_SESSION_KEY_LENGTH, pSessionKey);
  598. }
  599. }
  600. //+-------------------------------------------------------------------------
  601. //
  602. // Function: SpInitUserModeContext
  603. //
  604. // Synopsis: Creates a user-mode context from a packed LSA mode context
  605. //
  606. // Effects:
  607. //
  608. // Arguments: ContextHandle - Lsa mode context handle for the context
  609. // PackedContext - A marshalled buffer containing the LSA
  610. // mode context.
  611. //
  612. // Requires:
  613. //
  614. // Returns: STATUS_SUCCESS or STATUS_INSUFFICIENT_RESOURCES
  615. //
  616. // Notes:
  617. //
  618. //
  619. //--------------------------------------------------------------------------
  620. NTSTATUS NTAPI
  621. SpInitUserModeContext(
  622. IN ULONG_PTR ContextHandle,
  623. IN PSecBuffer PackedContext
  624. )
  625. {
  626. ASSERT(PackedContext);
  627. SspPrint(( SSP_API, "Entering SpInitUserModeContext 0x%lx\n", ContextHandle ));
  628. NTSTATUS Status = STATUS_SUCCESS;
  629. PNTLM_CLIENT_CONTEXT pContext = NULL;
  630. PNTLM_PACKED_CONTEXT pTmpContext = (PNTLM_PACKED_CONTEXT) PackedContext->pvBuffer;
  631. ULONG ListIndex;
  632. ULONG LockIndex;
  633. if (PackedContext->cbBuffer < sizeof(NTLM_PACKED_CONTEXT))
  634. {
  635. Status = STATUS_INVALID_PARAMETER;
  636. SspPrint(( SSP_CRITICAL, "SpInitUserModeContext, ContextData size < NTLM_CLIENT_CONTEXT\n" ));
  637. goto Cleanup;
  638. }
  639. pContext = (PNTLM_CLIENT_CONTEXT) NtLmAllocate(sizeof(NTLM_CLIENT_CONTEXT));
  640. if (!pContext)
  641. {
  642. Status = STATUS_INSUFFICIENT_RESOURCES;
  643. SspPrint(( SSP_CRITICAL, "SpInitUserModeContext, NtLmAllocate returns NULL\n" ));
  644. goto Cleanup;
  645. }
  646. //
  647. // If ClientTokenHandle is NULL, we are being called as
  648. // as an effect of InitializeSecurityContext, else we are
  649. // being called because of AcceptSecurityContext
  650. //
  651. if (pTmpContext->ClientTokenHandle != NULL )
  652. {
  653. pContext->ClientTokenHandle = (HANDLE) ULongToPtr(pTmpContext->ClientTokenHandle);
  654. Status = SspCreateTokenDacl(pContext->ClientTokenHandle);
  655. if (!NT_SUCCESS(Status))
  656. {
  657. SspPrint(( SSP_CRITICAL,
  658. "SpInitUserModeContext, SspCreateTokenDacl failed %x, Status\n" ));
  659. goto Cleanup;
  660. }
  661. }
  662. // Copy contents of PackedContext->pvBuffer to pContext
  663. pContext->LsaContext = ContextHandle;
  664. pContext->NegotiateFlags = pTmpContext->NegotiateFlags;
  665. SspPrint((SSP_NEGOTIATE_FLAGS, "SpInitUserModeContext NegotiateFlags: %lx\n", pContext->NegotiateFlags));
  666. pContext->References = 1;
  667. //
  668. // keep all 128 bits here, so signing can be strong even if encrypt can't be
  669. //
  670. RtlCopyMemory( pContext->SessionKey,
  671. pTmpContext->SessionKey,
  672. MSV1_0_USER_SESSION_KEY_LENGTH);
  673. //
  674. // if doing full duplex as part of NTLM2, generate different sign
  675. // and seal keys for each direction
  676. // all we do is MD5 the base session key with a different magic constant
  677. //
  678. if ( pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM2 ) {
  679. MD5_CTX Md5Context;
  680. ULONG KeyLen;
  681. ASSERT(MD5DIGESTLEN == MSV1_0_USER_SESSION_KEY_LENGTH);
  682. if( pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_128 )
  683. KeyLen = 16;
  684. else if( pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_56 )
  685. KeyLen = 7;
  686. else
  687. KeyLen = 5;
  688. SspPrint(( SSP_SESSION_KEYS, "NTLMv2 session key size: %lu\n", KeyLen));
  689. //
  690. // make client to server encryption key
  691. //
  692. MD5Init(&Md5Context);
  693. MD5Update(&Md5Context, pContext->SessionKey, KeyLen);
  694. MD5Update(&Md5Context, (unsigned char*)CSSEALMAGIC, sizeof(CSSEALMAGIC));
  695. MD5Final(&Md5Context);
  696. //
  697. // if TokenHandle == NULL, this is the client side
  698. // put key in the right place: for client it's seal, for server it's unseal
  699. //
  700. if (pContext->ClientTokenHandle == NULL)
  701. RtlCopyMemory(pContext->SealSessionKey, Md5Context.digest, MSV1_0_USER_SESSION_KEY_LENGTH);
  702. else
  703. RtlCopyMemory(pContext->UnsealSessionKey, Md5Context.digest, MSV1_0_USER_SESSION_KEY_LENGTH);
  704. //
  705. // make server to client encryption key
  706. //
  707. MD5Init(&Md5Context);
  708. MD5Update(&Md5Context, pContext->SessionKey, KeyLen);
  709. MD5Update(&Md5Context, (unsigned char*)SCSEALMAGIC, sizeof(SCSEALMAGIC));
  710. MD5Final(&Md5Context);
  711. ASSERT(MD5DIGESTLEN == MSV1_0_USER_SESSION_KEY_LENGTH);
  712. if (pContext->ClientTokenHandle == NULL)
  713. RtlCopyMemory(pContext->UnsealSessionKey, Md5Context.digest, MSV1_0_USER_SESSION_KEY_LENGTH);
  714. else
  715. RtlCopyMemory(pContext->SealSessionKey, Md5Context.digest, MSV1_0_USER_SESSION_KEY_LENGTH);
  716. //
  717. // make client to server signing key -- always 128 bits!
  718. //
  719. MD5Init(&Md5Context);
  720. MD5Update(&Md5Context, pContext->SessionKey, MSV1_0_USER_SESSION_KEY_LENGTH);
  721. MD5Update(&Md5Context, (unsigned char*)CSSIGNMAGIC, sizeof(CSSIGNMAGIC));
  722. MD5Final(&Md5Context);
  723. if (pContext->ClientTokenHandle == NULL)
  724. RtlCopyMemory(pContext->SignSessionKey, Md5Context.digest, MSV1_0_USER_SESSION_KEY_LENGTH);
  725. else
  726. RtlCopyMemory(pContext->VerifySessionKey, Md5Context.digest, MSV1_0_USER_SESSION_KEY_LENGTH);
  727. //
  728. // make server to client signing key
  729. //
  730. MD5Init(&Md5Context);
  731. MD5Update(&Md5Context, pContext->SessionKey, MSV1_0_USER_SESSION_KEY_LENGTH);
  732. MD5Update(&Md5Context, (unsigned char*)SCSIGNMAGIC, sizeof(SCSIGNMAGIC));
  733. MD5Final(&Md5Context);
  734. if (pContext->ClientTokenHandle == NULL)
  735. RtlCopyMemory(pContext->VerifySessionKey, Md5Context.digest, MSV1_0_USER_SESSION_KEY_LENGTH);
  736. else
  737. RtlCopyMemory(pContext->SignSessionKey, Md5Context.digest, MSV1_0_USER_SESSION_KEY_LENGTH);
  738. //
  739. // set pointers to different key schedule and nonce for each direction
  740. // key schedule will be filled in later...
  741. //
  742. pContext->pSealRc4Sched = &pContext->SealRc4Sched;
  743. pContext->pUnsealRc4Sched = &pContext->UnsealRc4Sched;
  744. pContext->pSendNonce = &pContext->SendNonce;
  745. pContext->pRecvNonce = &pContext->RecvNonce;
  746. } else {
  747. //
  748. // just copy session key to all four keys
  749. // leave them 128 bits -- they get cut to 40 bits later
  750. //
  751. RtlCopyMemory( pContext->SealSessionKey,
  752. pContext->SessionKey,
  753. MSV1_0_USER_SESSION_KEY_LENGTH);
  754. RtlCopyMemory( pContext->UnsealSessionKey,
  755. pContext->SessionKey,
  756. MSV1_0_USER_SESSION_KEY_LENGTH);
  757. RtlCopyMemory( pContext->SignSessionKey,
  758. pContext->SessionKey,
  759. MSV1_0_USER_SESSION_KEY_LENGTH);
  760. RtlCopyMemory( pContext->VerifySessionKey,
  761. pContext->SessionKey,
  762. MSV1_0_USER_SESSION_KEY_LENGTH);
  763. //
  764. // set pointers to share a key schedule and nonce for each direction
  765. // (OK because half duplex!)
  766. //
  767. pContext->pSealRc4Sched = &pContext->SealRc4Sched;
  768. pContext->pUnsealRc4Sched = &pContext->SealRc4Sched;
  769. pContext->pSendNonce = &pContext->SendNonce;
  770. pContext->pRecvNonce = &pContext->SendNonce;
  771. }
  772. if ( pTmpContext->ContextNames )
  773. {
  774. pContext->ContextNames = (PWSTR) NtLmAllocate( pTmpContext->ContextNameLength );
  775. if ( pContext->ContextNames == NULL )
  776. {
  777. Status = STATUS_INSUFFICIENT_RESOURCES ;
  778. goto Cleanup ;
  779. }
  780. RtlCopyMemory(
  781. pContext->ContextNames,
  782. ((PUCHAR) pTmpContext) + pTmpContext->ContextNames,
  783. pTmpContext->ContextNameLength );
  784. }
  785. else
  786. {
  787. pContext->ContextNames = NULL ;
  788. }
  789. if ( pTmpContext->MarshalledTargetInfo )
  790. {
  791. pContext->pbMarshalledTargetInfo = (PUCHAR) NtLmAllocate( pTmpContext->MarshalledTargetInfoLength );
  792. if (pContext->pbMarshalledTargetInfo == NULL)
  793. {
  794. Status = STATUS_INSUFFICIENT_RESOURCES;
  795. goto Cleanup;
  796. }
  797. pContext->cbMarshalledTargetInfo = pTmpContext->MarshalledTargetInfoLength;
  798. RtlCopyMemory( pContext->pbMarshalledTargetInfo,
  799. (PUCHAR) pTmpContext + pTmpContext->MarshalledTargetInfo,
  800. pTmpContext->MarshalledTargetInfoLength );
  801. }
  802. pContext->SendNonce = pTmpContext->SendNonce;
  803. pContext->RecvNonce = pTmpContext->RecvNonce;
  804. SspRc4Key(pContext->NegotiateFlags, &pContext->SealRc4Sched, pContext->SealSessionKey);
  805. SspRc4Key(pContext->NegotiateFlags, &pContext->UnsealRc4Sched, pContext->UnsealSessionKey);
  806. pContext->PasswordExpiry = pTmpContext->PasswordExpiry;
  807. pContext->UserFlags = pTmpContext->UserFlags;
  808. ListIndex = HandleToListIndex( pContext->LsaContext );
  809. LockIndex = ListIndexToLockIndex( ListIndex );
  810. RtlAcquireResourceExclusive(&NtLmUserContextLock[LockIndex], TRUE);
  811. InsertHeadList ( &NtLmUserContextList[ListIndex], &pContext->Next );
  812. NtLmUserContextCount[ListIndex]++;
  813. RtlReleaseResource(&NtLmUserContextLock[LockIndex]);
  814. Cleanup:
  815. if (!NT_SUCCESS(Status))
  816. {
  817. if (pContext != NULL)
  818. {
  819. FreeUserContext(pContext);
  820. }
  821. }
  822. // Let FreeContextBuffer handle freeing the virtual allocs
  823. if (PackedContext->pvBuffer != NULL)
  824. {
  825. FreeContextBuffer(PackedContext->pvBuffer);
  826. PackedContext->pvBuffer = NULL;
  827. }
  828. SspPrint(( SSP_API, "Leaving SpInitUserModeContext: 0x%lx\n", Status ));
  829. return(SspNtStatusToSecStatus(Status, SEC_E_INTERNAL_ERROR));
  830. }
  831. //
  832. // Bogus add-shift check sum
  833. //
  834. void
  835. SspGenCheckSum(
  836. IN PSecBuffer pMessage,
  837. OUT PNTLMSSP_MESSAGE_SIGNATURE pSig
  838. )
  839. /*++
  840. RoutineDescription:
  841. Generate a crc-32 checksum for a buffer
  842. Arguments:
  843. Return Value:
  844. Notes: This was stolen from net\svcdlls\ntlmssp\client\sign.c ,
  845. routine SspGenCheckSum. It's possible that
  846. bugs got copied too
  847. --*/
  848. {
  849. Crc32(pSig->CheckSum,pMessage->cbBuffer,pMessage->pvBuffer,&pSig->CheckSum);
  850. }
  851. VOID
  852. SspEncryptBuffer(
  853. IN PNTLM_CLIENT_CONTEXT pContext,
  854. IN struct RC4_KEYSTRUCT * pRc4Key,
  855. IN ULONG BufferSize,
  856. IN OUT PVOID Buffer
  857. )
  858. /*++
  859. RoutineDescription:
  860. Encrypts a buffer with the RC4 key in the context. If the context
  861. is for a datagram session, then the key is copied before being used
  862. to encrypt the buffer.
  863. Arguments:
  864. pContext - Context containing the key to encrypt the data
  865. BufferSize - Length of buffer in bytes
  866. Buffer - Buffer to encrypt.
  867. Notes: This was stolen from net\svcdlls\ntlmssp\client\sign.c ,
  868. routine SspEncryptBuffer. It's possible that
  869. bugs got copied too
  870. Return Value:
  871. --*/
  872. {
  873. struct RC4_KEYSTRUCT TemporaryKey;
  874. /// struct RC4_KEYSTRUCT * EncryptionKey = &pContext->Rc4Key;
  875. struct RC4_KEYSTRUCT * EncryptionKey = pRc4Key;
  876. if (BufferSize == 0)
  877. {
  878. return;
  879. }
  880. //
  881. // For datagram (application supplied sequence numbers) before NTLM2
  882. // we used to copy the key before encrypting so we don't
  883. // have a changing key; but that reused the key stream. Now we only
  884. // do that when backwards compatibility is explicitly called for.
  885. //
  886. if (((pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_DATAGRAM) != 0) &&
  887. ((pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM2) == 0) ) {
  888. RtlCopyMemory(
  889. &TemporaryKey,
  890. EncryptionKey,
  891. sizeof(struct RC4_KEYSTRUCT)
  892. );
  893. EncryptionKey = &TemporaryKey;
  894. }
  895. rc4(
  896. EncryptionKey,
  897. BufferSize,
  898. (PUCHAR) Buffer
  899. );
  900. }
  901. typedef enum _eSignSealOp {
  902. eSign, // MakeSignature is calling
  903. eVerify, // VerifySignature is calling
  904. eSeal, // SealMessage is calling
  905. eUnseal // UnsealMessage is calling
  906. } eSignSealOp;
  907. SECURITY_STATUS
  908. SspSignSealHelper(
  909. IN PNTLM_CLIENT_CONTEXT pContext,
  910. IN eSignSealOp Op,
  911. IN OUT PSecBufferDesc pMessage,
  912. IN ULONG MessageSeqNo,
  913. OUT PNTLMSSP_MESSAGE_SIGNATURE pSig,
  914. OUT PNTLMSSP_MESSAGE_SIGNATURE * ppSig
  915. )
  916. /*++
  917. RoutineDescription:
  918. Handle signing a message
  919. Arguments:
  920. Return Value:
  921. --*/
  922. {
  923. HMACMD5_CTX HMACMD5Context;
  924. UCHAR TempSig[MD5DIGESTLEN];
  925. NTLMSSP_MESSAGE_SIGNATURE Sig;
  926. int Signature;
  927. ULONG i;
  928. PUCHAR pKey; // ptr to key to use for encryption
  929. PUCHAR pSignKey; // ptr to key to use for signing
  930. PULONG pNonce; // ptr to nonce to use
  931. struct RC4_KEYSTRUCT * pRc4Sched; // ptr to key schedule to use
  932. NTLMSSP_MESSAGE_SIGNATURE AlignedSig; // aligned copy of input sig data
  933. Signature = -1;
  934. for (i = 0; i < pMessage->cBuffers; i++)
  935. {
  936. if ((pMessage->pBuffers[i].BufferType & 0xFF) == SECBUFFER_TOKEN)
  937. {
  938. Signature = i;
  939. break;
  940. }
  941. }
  942. if (Signature == -1)
  943. {
  944. return(SEC_E_INVALID_TOKEN);
  945. }
  946. if (pMessage->pBuffers[Signature].cbBuffer < NTLMSSP_MESSAGE_SIGNATURE_SIZE)
  947. {
  948. return(SEC_E_INVALID_TOKEN);
  949. }
  950. *ppSig = (NTLMSSP_MESSAGE_SIGNATURE*)pMessage->pBuffers[Signature].pvBuffer;
  951. RtlCopyMemory( &AlignedSig, *ppSig, sizeof(AlignedSig) );
  952. //
  953. // If sequence detect wasn't requested, put on an empty
  954. // security token . Don't do the check if Seal/Unseal is called.
  955. //
  956. if (!(pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_SIGN) &&
  957. (Op == eSign || Op == eVerify))
  958. {
  959. RtlZeroMemory(pSig,NTLMSSP_MESSAGE_SIGNATURE_SIZE);
  960. pSig->Version = NTLM_SIGN_VERSION;
  961. return(SEC_E_OK);
  962. }
  963. // figure out which key, key schedule, and nonce to use
  964. // depends on the op. SspAddLocalContext set up so that code on client
  965. // and server just (un)seals with (un)seal key or key schedule, etc.
  966. // and also sets pointers to share sending/receiving key schedule/nonce
  967. // when in half duplex mode. Hence, this code gets to act as if it were
  968. // always in full duplex mode.
  969. switch (Op) {
  970. case eSeal:
  971. pSignKey = pContext->SignSessionKey; // if NTLM2
  972. pKey = pContext->SealSessionKey;
  973. pRc4Sched = pContext->pSealRc4Sched;
  974. pNonce = pContext->pSendNonce;
  975. break;
  976. case eUnseal:
  977. pSignKey = pContext->VerifySessionKey; // if NTLM2
  978. pKey = pContext->UnsealSessionKey;
  979. pRc4Sched = pContext->pUnsealRc4Sched;
  980. pNonce = pContext->pRecvNonce;
  981. break;
  982. case eSign:
  983. pSignKey = pContext->SignSessionKey; // if NTLM2
  984. pKey = pContext->SealSessionKey; // might be used to encrypt the signature
  985. pRc4Sched = pContext->pSealRc4Sched;
  986. pNonce = pContext->pSendNonce;
  987. break;
  988. case eVerify:
  989. pSignKey = pContext->VerifySessionKey; // if NTLM2
  990. pKey = pContext->UnsealSessionKey; // might be used to decrypt the signature
  991. pRc4Sched = pContext->pUnsealRc4Sched;
  992. pNonce = pContext->pRecvNonce;
  993. break;
  994. default:
  995. ASSERT(FALSE);
  996. return(STATUS_INVALID_LEVEL);
  997. }
  998. //
  999. // Either we can supply the sequence number, or
  1000. // the application can supply the message sequence number.
  1001. //
  1002. Sig.Version = NTLM_SIGN_VERSION;
  1003. // if we're doing the new NTLM2 version:
  1004. if (pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM2) {
  1005. if ((pContext->NegotiateFlags & NTLMSSP_APP_SEQ) == 0)
  1006. {
  1007. Sig.Nonce = *pNonce; // use our sequence number
  1008. (*pNonce) += 1;
  1009. }
  1010. else {
  1011. if (Op == eSeal || Op == eSign || MessageSeqNo != 0)
  1012. Sig.Nonce = MessageSeqNo;
  1013. else
  1014. Sig.Nonce = AlignedSig.Nonce;
  1015. // if using RC4, must rekey for each packet
  1016. // RC4 is used for seal, unseal; and for encrypting the HMAC hash if
  1017. // key exchange was negotiated (we use just HMAC if no key exchange,
  1018. // so that a good signing option exists with no RC4 encryption needed)
  1019. if (Op == eSeal || Op == eUnseal || pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH)
  1020. {
  1021. MD5_CTX Md5ContextReKey;
  1022. MD5Init(&Md5ContextReKey);
  1023. MD5Update(&Md5ContextReKey, pKey, MSV1_0_USER_SESSION_KEY_LENGTH);
  1024. MD5Update(&Md5ContextReKey, (unsigned char*)&Sig.Nonce, sizeof(Sig.Nonce));
  1025. MD5Final(&Md5ContextReKey);
  1026. ASSERT(MD5DIGESTLEN == MSV1_0_USER_SESSION_KEY_LENGTH);
  1027. SspRc4Key(pContext->NegotiateFlags, pRc4Sched, Md5ContextReKey.digest);
  1028. }
  1029. }
  1030. //
  1031. // using HMAC hash, init it with the key
  1032. //
  1033. HMACMD5Init(&HMACMD5Context, pSignKey, MSV1_0_USER_SESSION_KEY_LENGTH);
  1034. //
  1035. // include the message sequence number
  1036. //
  1037. HMACMD5Update(&HMACMD5Context, (unsigned char*)&Sig.Nonce, sizeof(Sig.Nonce));
  1038. for (i = 0; i < pMessage->cBuffers ; i++ )
  1039. {
  1040. if (((pMessage->pBuffers[i].BufferType & 0xFF) == SECBUFFER_DATA) &&
  1041. (pMessage->pBuffers[i].cbBuffer != 0))
  1042. {
  1043. if ((pMessage->pBuffers[i].BufferType & (SECBUFFER_READONLY | SECBUFFER_READONLY_WITH_CHECKSUM))
  1044. == (SECBUFFER_READONLY | SECBUFFER_READONLY_WITH_CHECKSUM))
  1045. {
  1046. //
  1047. // FESTER: returning INVALID token because of data buffers
  1048. //
  1049. return SEC_E_INVALID_TOKEN;
  1050. }
  1051. // decrypt (before checksum...) if it's not READ_ONLY
  1052. if ( (Op == eUnseal)
  1053. && !(pMessage->pBuffers[i].BufferType & (SECBUFFER_READONLY | SECBUFFER_READONLY_WITH_CHECKSUM) )
  1054. )
  1055. {
  1056. SspEncryptBuffer(
  1057. pContext,
  1058. pRc4Sched,
  1059. pMessage->pBuffers[i].cbBuffer,
  1060. pMessage->pBuffers[i].pvBuffer
  1061. );
  1062. }
  1063. HMACMD5Update(
  1064. &HMACMD5Context,
  1065. (unsigned char*)pMessage->pBuffers[i].pvBuffer,
  1066. pMessage->pBuffers[i].cbBuffer);
  1067. //
  1068. // Encrypt if its not READ_ONLY
  1069. //
  1070. if ( (Op == eSeal)
  1071. && !(pMessage->pBuffers[i].BufferType & (SECBUFFER_READONLY | SECBUFFER_READONLY_WITH_CHECKSUM) )
  1072. )
  1073. {
  1074. SspEncryptBuffer(
  1075. pContext,
  1076. pRc4Sched,
  1077. pMessage->pBuffers[i].cbBuffer,
  1078. pMessage->pBuffers[i].pvBuffer
  1079. );
  1080. }
  1081. }
  1082. }
  1083. HMACMD5Final(&HMACMD5Context, TempSig);
  1084. //
  1085. // use RandomPad and Checksum fields for 8 bytes of MD5 hash
  1086. //
  1087. RtlCopyMemory(&Sig.RandomPad, TempSig, 8);
  1088. //
  1089. // if we're using crypto for KEY_EXCH, may as well use it for signing too...
  1090. //
  1091. if (pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH)
  1092. SspEncryptBuffer(
  1093. pContext,
  1094. pRc4Sched,
  1095. 8,
  1096. &Sig.RandomPad
  1097. );
  1098. }
  1099. //
  1100. // pre-NTLM2 methods
  1101. //
  1102. else {
  1103. //
  1104. // required by CRC-32 algorithm
  1105. //
  1106. Sig.CheckSum = 0xffffffff;
  1107. for (i = 0; i < pMessage->cBuffers ; i++ )
  1108. {
  1109. if (((pMessage->pBuffers[i].BufferType & 0xFF) == SECBUFFER_DATA) &&
  1110. (pMessage->pBuffers[i].cbBuffer != 0))
  1111. {
  1112. if ((pMessage->pBuffers[i].BufferType & (SECBUFFER_READONLY | SECBUFFER_READONLY_WITH_CHECKSUM))
  1113. == (SECBUFFER_READONLY | SECBUFFER_READONLY_WITH_CHECKSUM))
  1114. {
  1115. //
  1116. // FESTER: returning INVALID token because of data buffers
  1117. //
  1118. return SEC_E_INVALID_TOKEN;
  1119. }
  1120. //
  1121. // retain the "read-only" semantics for NTLMv1
  1122. //
  1123. if (pMessage->pBuffers[i].BufferType & SECBUFFER_READONLY)
  1124. {
  1125. continue;
  1126. }
  1127. // decrypt (before checksum...)
  1128. if ( (Op == eUnseal)
  1129. && !(pMessage->pBuffers[i].BufferType & SECBUFFER_READONLY_WITH_CHECKSUM) )
  1130. {
  1131. SspEncryptBuffer(
  1132. pContext,
  1133. pRc4Sched,
  1134. pMessage->pBuffers[i].cbBuffer,
  1135. pMessage->pBuffers[i].pvBuffer
  1136. );
  1137. }
  1138. SspGenCheckSum(&pMessage->pBuffers[i], &Sig);
  1139. // Encrypt
  1140. if ( (Op == eSeal)
  1141. && !(pMessage->pBuffers[i].BufferType & SECBUFFER_READONLY_WITH_CHECKSUM) )
  1142. {
  1143. SspEncryptBuffer(
  1144. pContext,
  1145. pRc4Sched,
  1146. pMessage->pBuffers[i].cbBuffer,
  1147. pMessage->pBuffers[i].pvBuffer
  1148. );
  1149. }
  1150. }
  1151. }
  1152. //
  1153. // Required by CRC-32 algorithm
  1154. //
  1155. Sig.CheckSum ^= 0xffffffff;
  1156. // when we encrypt 0, we will get the cipher stream for the nonce!
  1157. Sig.Nonce = 0;
  1158. SspEncryptBuffer(
  1159. pContext,
  1160. pRc4Sched,
  1161. sizeof(NTLMSSP_MESSAGE_SIGNATURE) - sizeof(ULONG),
  1162. &Sig.RandomPad
  1163. );
  1164. if ((pContext->NegotiateFlags & NTLMSSP_APP_SEQ) == 0)
  1165. {
  1166. Sig.Nonce ^= *pNonce; // use our sequence number and encrypt it
  1167. (*pNonce) += 1;
  1168. }
  1169. else if (Op == eSeal || Op == eSign || MessageSeqNo != 0)
  1170. Sig.Nonce ^= MessageSeqNo; // use caller's sequence number and encrypt it
  1171. else
  1172. Sig.Nonce = AlignedSig.Nonce; // use sender's sequence number
  1173. //
  1174. // for SignMessage calling, does nothing (copies garbage)
  1175. // For VerifyMessage calling, allows it to compare sig block
  1176. // upon return to Verify without knowing whether its MD5 or CRC32
  1177. //
  1178. Sig.RandomPad = AlignedSig.RandomPad;
  1179. }
  1180. pMessage->pBuffers[Signature].cbBuffer = sizeof(NTLMSSP_MESSAGE_SIGNATURE);
  1181. RtlCopyMemory(
  1182. pSig,
  1183. &Sig,
  1184. NTLMSSP_MESSAGE_SIGNATURE_SIZE
  1185. );
  1186. return(SEC_E_OK);
  1187. }
  1188. //+-------------------------------------------------------------------------
  1189. //
  1190. // Function: SpMakeSignature
  1191. //
  1192. // Synopsis: Signs a message buffer by calculatinga checksum over all
  1193. // the non-read only data buffers and encrypting the checksum
  1194. // along with a nonce.
  1195. //
  1196. // Effects:
  1197. //
  1198. // Arguments: ContextHandle - Handle of the context to use to sign the
  1199. // message.
  1200. // QualityOfProtection - Unused flags.
  1201. // MessageBuffers - Contains an array of buffers to sign and
  1202. // to store the signature.
  1203. // MessageSequenceNumber - Sequence number for this message,
  1204. // only used in datagram cases.
  1205. //
  1206. // Requires: STATUS_INVALID_HANDLE - the context could not be found or
  1207. // was not configured for message integrity.
  1208. // STATUS_INVALID_PARAMETER - the signature buffer could not
  1209. // be found.
  1210. // STATUS_BUFFER_TOO_SMALL - the signature buffer is too small
  1211. // to hold the signature
  1212. //
  1213. // Returns:
  1214. //
  1215. // Notes: This was stolen from net\svcdlls\ntlmssp\client\sign.c ,
  1216. // routine SspHandleSignMessage. It's possible that
  1217. // bugs got copied too
  1218. //
  1219. //
  1220. //--------------------------------------------------------------------------
  1221. NTSTATUS NTAPI
  1222. SpMakeSignature(
  1223. IN ULONG_PTR ContextHandle,
  1224. IN ULONG fQOP,
  1225. IN PSecBufferDesc pMessage,
  1226. IN ULONG MessageSeqNo
  1227. )
  1228. {
  1229. SspPrint(( SSP_API, "Entering SpMakeSignature\n" ));
  1230. NTSTATUS Status = S_OK;
  1231. NTSTATUS SubStatus = S_OK;
  1232. PNTLM_CLIENT_CONTEXT pContext;
  1233. NTLMSSP_MESSAGE_SIGNATURE Sig;
  1234. NTLMSSP_MESSAGE_SIGNATURE *pSig;
  1235. UNREFERENCED_PARAMETER(fQOP);
  1236. pContext = ReferenceUserContext(ContextHandle, FALSE);
  1237. if (pContext == NULL)
  1238. {
  1239. Status = STATUS_INVALID_HANDLE;
  1240. SspPrint(( SSP_CRITICAL, "SpMakeSignature, ReferenceUserContext returns NULL\n" ));
  1241. goto CleanUp;
  1242. }
  1243. Status = SspSignSealHelper(
  1244. pContext,
  1245. eSign,
  1246. pMessage,
  1247. MessageSeqNo,
  1248. &Sig,
  1249. &pSig
  1250. );
  1251. if( !NT_SUCCESS(Status) ) {
  1252. SspPrint(( SSP_CRITICAL, "SpMakeSignature, SspSignSealHelper returns %lx\n", Status ));
  1253. goto CleanUp;
  1254. }
  1255. RtlCopyMemory(
  1256. pSig,
  1257. &Sig,
  1258. NTLMSSP_MESSAGE_SIGNATURE_SIZE
  1259. );
  1260. CleanUp:
  1261. if (pContext != NULL)
  1262. {
  1263. SubStatus = DereferenceUserContext(pContext);
  1264. // Don't destroy real status
  1265. if (NT_SUCCESS(Status))
  1266. {
  1267. Status = SubStatus;
  1268. }
  1269. }
  1270. SspPrint(( SSP_API, "Leaving SpMakeSignature: 0x%lx\n", Status ));
  1271. return(SspNtStatusToSecStatus(Status, SEC_E_INTERNAL_ERROR));
  1272. }
  1273. //+-------------------------------------------------------------------------
  1274. //
  1275. // Function: SpVerifySignature
  1276. //
  1277. // Synopsis: Verifies a signed message buffer by calculating a checksum over all
  1278. // the non-read only data buffers and encrypting the checksum
  1279. // along with a nonce.
  1280. //
  1281. // Effects:
  1282. //
  1283. // Arguments: ContextHandle - Handle of the context to use to sign the
  1284. // message.
  1285. // MessageBuffers - Contains an array of signed buffers and
  1286. // a signature buffer.
  1287. // MessageSequenceNumber - Sequence number for this message,
  1288. // only used in datagram cases.
  1289. // QualityOfProtection - Unused flags.
  1290. //
  1291. // Requires: STATUS_INVALID_HANDLE - the context could not be found or
  1292. // was not configured for message integrity.
  1293. // STATUS_INVALID_PARAMETER - the signature buffer could not
  1294. // be found or was too small.
  1295. //
  1296. // Returns:
  1297. //
  1298. // Notes: This was stolen from net\svcdlls\ntlmssp\client\sign.c ,
  1299. // routine SspHandleVerifyMessage. It's possible that
  1300. // bugs got copied too
  1301. //
  1302. //
  1303. //--------------------------------------------------------------------------
  1304. NTSTATUS NTAPI
  1305. SpVerifySignature(
  1306. IN ULONG_PTR ContextHandle,
  1307. IN PSecBufferDesc pMessage,
  1308. IN ULONG MessageSeqNo,
  1309. OUT PULONG pfQOP
  1310. )
  1311. {
  1312. SspPrint(( SSP_API, "Entering SpVerifySignature\n" ));
  1313. NTSTATUS Status = S_OK;
  1314. NTSTATUS SubStatus = S_OK;
  1315. PNTLM_CLIENT_CONTEXT pContext;
  1316. NTLMSSP_MESSAGE_SIGNATURE Sig;
  1317. PNTLMSSP_MESSAGE_SIGNATURE pSig; // pointer to buffer with sig in it
  1318. NTLMSSP_MESSAGE_SIGNATURE AlignedSig; // Aligned sig buffer.
  1319. UNREFERENCED_PARAMETER(pfQOP);
  1320. pContext = ReferenceUserContext(ContextHandle, FALSE);
  1321. if (!pContext)
  1322. {
  1323. Status = STATUS_INVALID_HANDLE;
  1324. SspPrint(( SSP_CRITICAL, "SpVerifySignature, ReferenceUserContext returns NULL\n" ));
  1325. goto CleanUp;
  1326. }
  1327. Status = SspSignSealHelper(
  1328. pContext,
  1329. eVerify,
  1330. pMessage,
  1331. MessageSeqNo,
  1332. &Sig,
  1333. &pSig
  1334. );
  1335. if (!NT_SUCCESS(Status))
  1336. {
  1337. SspPrint(( SSP_CRITICAL, "SpVerifySignature, SspSignSealHelper returns %lx\n", Status ));
  1338. goto CleanUp;
  1339. }
  1340. RtlCopyMemory( &AlignedSig, pSig, sizeof( AlignedSig ) );
  1341. if (AlignedSig.Version != NTLM_SIGN_VERSION) {
  1342. SspPrint(( SSP_CRITICAL, "SpVerifySignature, unknown Version wanted=%lx got=%lx\n",
  1343. NTLM_SIGN_VERSION,
  1344. AlignedSig.Version
  1345. ));
  1346. Status = SEC_E_INVALID_TOKEN;
  1347. goto CleanUp;
  1348. }
  1349. // validate the signature...
  1350. if (AlignedSig.CheckSum != Sig.CheckSum)
  1351. {
  1352. SspPrint(( SSP_CRITICAL, "SpVerifySignature, CheckSum mis-match wanted=%lx got=%lx\n",
  1353. Sig.CheckSum,
  1354. AlignedSig.CheckSum
  1355. ));
  1356. Status = SEC_E_MESSAGE_ALTERED;
  1357. goto CleanUp;
  1358. }
  1359. // with MD5 sig, this now matters!
  1360. if (AlignedSig.RandomPad != Sig.RandomPad)
  1361. {
  1362. SspPrint(( SSP_CRITICAL, "SpVerifySignature, RandomPad mis-match wanted=%lx got=%lx\n",
  1363. Sig.RandomPad,
  1364. AlignedSig.RandomPad
  1365. ));
  1366. Status = SEC_E_MESSAGE_ALTERED;
  1367. goto CleanUp;
  1368. }
  1369. if (AlignedSig.Nonce != Sig.Nonce)
  1370. {
  1371. SspPrint(( SSP_CRITICAL, "SpVerifySignature, Nonce mis-match wanted=%lx got=%lx\n",
  1372. Sig.Nonce,
  1373. AlignedSig.Nonce
  1374. ));
  1375. Status = SEC_E_OUT_OF_SEQUENCE;
  1376. goto CleanUp;
  1377. }
  1378. CleanUp:
  1379. if (pContext != NULL)
  1380. {
  1381. SubStatus = DereferenceUserContext(pContext);
  1382. // Don't destroy real status
  1383. if (NT_SUCCESS(Status))
  1384. {
  1385. Status = SubStatus;
  1386. }
  1387. }
  1388. SspPrint(( SSP_API, "Leaving SpVerifySignature: 0x%lx\n", Status ));
  1389. return(SspNtStatusToSecStatus(Status, SEC_E_INTERNAL_ERROR));
  1390. }
  1391. //+-------------------------------------------------------------------------
  1392. //
  1393. // Function: SpSealMessage
  1394. //
  1395. // Synopsis: Verifies a signed message buffer by calculating a checksum over all
  1396. // the non-read only data buffers and encrypting the checksum
  1397. // along with a nonce.
  1398. //
  1399. // Effects:
  1400. //
  1401. // Arguments: ContextHandle - Handle of the context to use to sign the
  1402. // message.
  1403. // MessageBuffers - Contains an array of signed buffers and
  1404. // a signature buffer.
  1405. // MessageSequenceNumber - Sequence number for this message,
  1406. // only used in datagram cases.
  1407. // QualityOfProtection - Unused flags.
  1408. //
  1409. // Requires: STATUS_INVALID_HANDLE - the context could not be found or
  1410. // was not configured for message integrity.
  1411. // STATUS_INVALID_PARAMETER - the signature buffer could not
  1412. // be found or was too small.
  1413. //
  1414. // Returns:
  1415. //
  1416. // Notes: This was stolen from net\svcdlls\ntlmssp\client\sign.c ,
  1417. // routine SspHandleSealMessage. It's possible that
  1418. // bugs got copied too
  1419. //
  1420. //
  1421. //--------------------------------------------------------------------------
  1422. NTSTATUS NTAPI
  1423. SpSealMessage(
  1424. IN ULONG_PTR ContextHandle,
  1425. IN ULONG fQOP,
  1426. IN PSecBufferDesc pMessage,
  1427. IN ULONG MessageSeqNo
  1428. )
  1429. {
  1430. SspPrint(( SSP_API, "Entering SpSealMessage\n" ));
  1431. NTSTATUS Status = S_OK;
  1432. NTSTATUS SubStatus = S_OK;
  1433. PNTLM_CLIENT_CONTEXT pContext;
  1434. NTLMSSP_MESSAGE_SIGNATURE Sig;
  1435. PNTLMSSP_MESSAGE_SIGNATURE pSig; // pointer to buffer where sig goes
  1436. ULONG i;
  1437. UNREFERENCED_PARAMETER(fQOP);
  1438. pContext = ReferenceUserContext(ContextHandle, FALSE);
  1439. if (!pContext)
  1440. {
  1441. Status = STATUS_INVALID_HANDLE;
  1442. SspPrint(( SSP_CRITICAL, "SpSealMessage, ReferenceUserContext returns NULL\n" ));
  1443. goto CleanUp;
  1444. }
  1445. Status = SspSignSealHelper(
  1446. pContext,
  1447. eSeal,
  1448. pMessage,
  1449. MessageSeqNo,
  1450. &Sig,
  1451. &pSig
  1452. );
  1453. if (!NT_SUCCESS(Status))
  1454. {
  1455. SspPrint(( SSP_CRITICAL, "SpVerifySignature, SspSignSealHelper returns %lx\n", Status ));
  1456. goto CleanUp;
  1457. }
  1458. RtlCopyMemory(
  1459. pSig,
  1460. &Sig,
  1461. NTLMSSP_MESSAGE_SIGNATURE_SIZE
  1462. );
  1463. //
  1464. // for gss style sign/seal, strip the padding as RC4 requires none.
  1465. // (in fact, we rely on this to simplify the size computation in DecryptMessage).
  1466. // if we support some other block cipher, need to rev the NTLM_ token version to make blocksize
  1467. //
  1468. for (i = 0; i < pMessage->cBuffers; i++)
  1469. {
  1470. if ((pMessage->pBuffers[i].BufferType & 0xFF) == SECBUFFER_PADDING)
  1471. {
  1472. //
  1473. // no padding required!
  1474. //
  1475. pMessage->pBuffers[i].cbBuffer = 0;
  1476. break;
  1477. }
  1478. }
  1479. CleanUp:
  1480. if (pContext != NULL)
  1481. {
  1482. SubStatus = DereferenceUserContext(pContext);
  1483. // Don't destroy real status
  1484. if (NT_SUCCESS(Status))
  1485. {
  1486. Status = SubStatus;
  1487. }
  1488. }
  1489. SspPrint(( SSP_API, "Leaving SpSealMessage: 0x%lx\n", Status ));
  1490. return(SspNtStatusToSecStatus(Status, SEC_E_INTERNAL_ERROR));
  1491. }
  1492. //+-------------------------------------------------------------------------
  1493. //
  1494. // Function: SpUnsealMessage
  1495. //
  1496. // Synopsis: Verifies a signed message buffer by calculating a checksum over all
  1497. // the non-read only data buffers and encrypting the checksum
  1498. // along with a nonce.
  1499. //
  1500. // Effects:
  1501. //
  1502. // Arguments: ContextHandle - Handle of the context to use to sign the
  1503. // message.
  1504. // MessageBuffers - Contains an array of signed buffers and
  1505. // a signature buffer.
  1506. // MessageSequenceNumber - Sequence number for this message,
  1507. // only used in datagram cases.
  1508. // QualityOfProtection - Unused flags.
  1509. //
  1510. // Requires: STATUS_INVALID_HANDLE - the context could not be found or
  1511. // was not configured for message integrity.
  1512. // STATUS_INVALID_PARAMETER - the signature buffer could not
  1513. // be found or was too small.
  1514. //
  1515. // Returns:
  1516. //
  1517. // Notes: This was stolen from net\svcdlls\ntlmssp\client\sign.c ,
  1518. // routine SspHandleUnsealMessage. It's possible that
  1519. // bugs got copied too
  1520. //
  1521. //
  1522. //--------------------------------------------------------------------------
  1523. NTSTATUS NTAPI
  1524. SpUnsealMessage(
  1525. IN ULONG_PTR ContextHandle,
  1526. IN PSecBufferDesc pMessage,
  1527. IN ULONG MessageSeqNo,
  1528. OUT PULONG pfQOP
  1529. )
  1530. {
  1531. SspPrint(( SSP_API, "Entering SpUnsealMessage\n" ));
  1532. NTSTATUS Status = S_OK;
  1533. NTSTATUS SubStatus = S_OK;
  1534. PNTLM_CLIENT_CONTEXT pContext;
  1535. NTLMSSP_MESSAGE_SIGNATURE Sig;
  1536. PNTLMSSP_MESSAGE_SIGNATURE pSig; // pointer to buffer where sig goes
  1537. NTLMSSP_MESSAGE_SIGNATURE AlignedSig; // aligned buffer.
  1538. PSecBufferDesc MessageBuffers = pMessage;
  1539. ULONG Index;
  1540. PSecBuffer SignatureBuffer = NULL;
  1541. PSecBuffer StreamBuffer = NULL;
  1542. PSecBuffer DataBuffer = NULL;
  1543. SecBufferDesc ProcessBuffers;
  1544. SecBuffer wrap_bufs[2];
  1545. UNREFERENCED_PARAMETER(pfQOP);
  1546. pContext = ReferenceUserContext(ContextHandle, FALSE);
  1547. if (!pContext)
  1548. {
  1549. Status = STATUS_INVALID_HANDLE;
  1550. SspPrint(( SSP_CRITICAL, "SpUnsealMessage, ReferenceUserContext returns NULL\n" ));
  1551. goto CleanUp;
  1552. }
  1553. //
  1554. // Find the body and signature SecBuffers from pMessage
  1555. //
  1556. for (Index = 0; Index < MessageBuffers->cBuffers ; Index++ )
  1557. {
  1558. if ((MessageBuffers->pBuffers[Index].BufferType & ~SECBUFFER_ATTRMASK) == SECBUFFER_TOKEN)
  1559. {
  1560. SignatureBuffer = &MessageBuffers->pBuffers[Index];
  1561. }
  1562. else if ((MessageBuffers->pBuffers[Index].BufferType & ~SECBUFFER_ATTRMASK) == SECBUFFER_STREAM)
  1563. {
  1564. StreamBuffer = &MessageBuffers->pBuffers[Index];
  1565. }
  1566. else if ((MessageBuffers->pBuffers[Index].BufferType & ~SECBUFFER_ATTRMASK) == SECBUFFER_DATA)
  1567. {
  1568. DataBuffer = &MessageBuffers->pBuffers[Index];
  1569. }
  1570. }
  1571. if( StreamBuffer != NULL )
  1572. {
  1573. if( SignatureBuffer != NULL )
  1574. {
  1575. Status = SEC_E_INVALID_TOKEN;
  1576. SspPrint(( SSP_CRITICAL, "SpUnsealMessage, Both stream and signature buffer present.\n"));
  1577. goto CleanUp;
  1578. }
  1579. //
  1580. // for version 1 NTLM blobs, padding is never present, since RC4 is stream cipher.
  1581. //
  1582. wrap_bufs[0].cbBuffer = NTLMSSP_MESSAGE_SIGNATURE_SIZE;
  1583. wrap_bufs[1].cbBuffer = StreamBuffer->cbBuffer - NTLMSSP_MESSAGE_SIGNATURE_SIZE;
  1584. if( StreamBuffer->cbBuffer < wrap_bufs[0].cbBuffer )
  1585. {
  1586. Status = SEC_E_INVALID_TOKEN;
  1587. SspPrint(( SSP_CRITICAL, "SpUnsealMessage, invalid buffer present in STREAM.\n"));
  1588. goto CleanUp;
  1589. }
  1590. wrap_bufs[0].BufferType = SECBUFFER_TOKEN;
  1591. wrap_bufs[0].pvBuffer = StreamBuffer->pvBuffer;
  1592. wrap_bufs[1].BufferType = SECBUFFER_DATA;
  1593. wrap_bufs[1].pvBuffer = (PBYTE)wrap_bufs[0].pvBuffer + wrap_bufs[0].cbBuffer;
  1594. if( DataBuffer == NULL )
  1595. {
  1596. Status = SEC_E_INVALID_TOKEN;
  1597. SspPrint(( SSP_CRITICAL, "SpUnsealMessage, gss missing SECBUFFER_DATA.\n"));
  1598. goto CleanUp;
  1599. }
  1600. DataBuffer->cbBuffer = wrap_bufs[1].cbBuffer;
  1601. DataBuffer->pvBuffer = wrap_bufs[1].pvBuffer;
  1602. ProcessBuffers.cBuffers = 2;
  1603. ProcessBuffers.pBuffers = wrap_bufs;
  1604. ProcessBuffers.ulVersion = SECBUFFER_VERSION;
  1605. } else {
  1606. ProcessBuffers = *MessageBuffers;
  1607. }
  1608. Status = SspSignSealHelper(
  1609. pContext,
  1610. eUnseal,
  1611. &ProcessBuffers,
  1612. MessageSeqNo,
  1613. &Sig,
  1614. &pSig
  1615. );
  1616. if (!NT_SUCCESS(Status))
  1617. {
  1618. SspPrint(( SSP_CRITICAL, "SpUnsealMessage, SspSignSealHelper returns %lx\n", Status ));
  1619. goto CleanUp;
  1620. }
  1621. RtlCopyMemory( &AlignedSig, pSig, sizeof(AlignedSig) );
  1622. if (AlignedSig.Version != NTLM_SIGN_VERSION) {
  1623. SspPrint(( SSP_CRITICAL, "SpUnsealMessage, unknown Version wanted=%lx got=%lx\n",
  1624. NTLM_SIGN_VERSION,
  1625. AlignedSig.Version
  1626. ));
  1627. Status = SEC_E_INVALID_TOKEN;
  1628. goto CleanUp;
  1629. }
  1630. // validate the signature...
  1631. if (AlignedSig.CheckSum != Sig.CheckSum)
  1632. {
  1633. SspPrint(( SSP_CRITICAL, "SpUnsealMessage, CheckSum mis-match wanted=%lx got=%lx\n",
  1634. Sig.CheckSum,
  1635. AlignedSig.CheckSum
  1636. ));
  1637. Status = SEC_E_MESSAGE_ALTERED;
  1638. goto CleanUp;
  1639. }
  1640. if (AlignedSig.RandomPad != Sig.RandomPad)
  1641. {
  1642. SspPrint(( SSP_CRITICAL, "SpUnsealMessage, RandomPad mis-match wanted=%lx got=%lx\n",
  1643. Sig.RandomPad,
  1644. AlignedSig.RandomPad
  1645. ));
  1646. Status = SEC_E_MESSAGE_ALTERED;
  1647. goto CleanUp;
  1648. }
  1649. if (AlignedSig.Nonce != Sig.Nonce)
  1650. {
  1651. SspPrint(( SSP_CRITICAL, "SpUnsealMessage, Nonce mis-match wanted=%lx got=%lx\n",
  1652. Sig.Nonce,
  1653. AlignedSig.Nonce
  1654. ));
  1655. Status = SEC_E_OUT_OF_SEQUENCE;
  1656. goto CleanUp;
  1657. }
  1658. CleanUp:
  1659. if (pContext != NULL)
  1660. {
  1661. SubStatus = DereferenceUserContext(pContext);
  1662. // Don't destroy real status
  1663. if (NT_SUCCESS(Status))
  1664. {
  1665. Status = SubStatus;
  1666. }
  1667. }
  1668. SspPrint(( SSP_API, "Leaving SpUnsealMessage: 0x%lx\n", Status ));
  1669. return(SspNtStatusToSecStatus(Status, SEC_E_INTERNAL_ERROR));
  1670. }
  1671. //+-------------------------------------------------------------------------
  1672. //
  1673. // Function: SpGetContextToken
  1674. //
  1675. // Synopsis: returns a pointer to the token for a server-side context
  1676. //
  1677. // Effects:
  1678. //
  1679. // Arguments:
  1680. //
  1681. // Requires:
  1682. //
  1683. // Returns:
  1684. //
  1685. // Notes:
  1686. //
  1687. //
  1688. //--------------------------------------------------------------------------
  1689. NTSTATUS NTAPI
  1690. SpGetContextToken(
  1691. IN ULONG_PTR ContextHandle,
  1692. OUT PHANDLE ImpersonationToken
  1693. )
  1694. {
  1695. SspPrint(( SSP_API, "Entering SpGetContextToken\n" ));
  1696. NTSTATUS Status = S_OK;
  1697. PNTLM_CLIENT_CONTEXT pContext;
  1698. pContext = ReferenceUserContext(ContextHandle, FALSE);
  1699. if (pContext && pContext->ClientTokenHandle)
  1700. {
  1701. *ImpersonationToken = pContext->ClientTokenHandle;
  1702. Status= S_OK;
  1703. goto CleanUp;
  1704. }
  1705. Status = STATUS_INVALID_HANDLE;
  1706. SspPrint(( SSP_CRITICAL, "SpGetContextToken, no token handle\n" ));
  1707. CleanUp:
  1708. if (pContext != NULL)
  1709. {
  1710. Status = DereferenceUserContext(pContext);
  1711. }
  1712. SspPrint(( SSP_API, "Leaving SpGetContextToken: 0x%lx\n", Status ));
  1713. return(SspNtStatusToSecStatus(Status, SEC_E_INTERNAL_ERROR));
  1714. }
  1715. //+-------------------------------------------------------------------------
  1716. //
  1717. // Function: SpQueryContextAttributes
  1718. //
  1719. // Synopsis: Querys attributes of the specified context
  1720. // This API allows a customer of the security
  1721. // services to determine certain attributes of
  1722. // the context. These are: sizes, names, and lifespan.
  1723. //
  1724. // Effects:
  1725. //
  1726. // Arguments:
  1727. //
  1728. // ContextHandle - Handle to the context to query.
  1729. //
  1730. // Attribute - Attribute to query.
  1731. //
  1732. // #define SECPKG_ATTR_SIZES 0
  1733. // #define SECPKG_ATTR_NAMES 1
  1734. // #define SECPKG_ATTR_LIFESPAN 2
  1735. //
  1736. // Buffer - Buffer to copy the data into. The buffer must
  1737. // be large enough to fit the queried attribute.
  1738. //
  1739. //
  1740. // Requires:
  1741. //
  1742. // Returns:
  1743. //
  1744. // STATUS_SUCCESS - Call completed successfully
  1745. //
  1746. // STATUS_INVALID_HANDLE -- Credential/Context Handle is invalid
  1747. // STATUS_NOT_SUPPORTED -- Function code is not supported
  1748. //
  1749. // Notes:
  1750. //
  1751. //--------------------------------------------------------------------------
  1752. NTSTATUS NTAPI
  1753. SpQueryContextAttributes(
  1754. IN ULONG_PTR ContextHandle,
  1755. IN ULONG Attribute,
  1756. IN OUT PVOID Buffer
  1757. )
  1758. {
  1759. NTSTATUS Status = STATUS_SUCCESS;
  1760. PNTLM_CLIENT_CONTEXT pContext = NULL;
  1761. PSecPkgContext_Sizes ContextSizes;
  1762. PSecPkgContext_Flags ContextFlags;
  1763. PSecPkgContext_DceInfo ContextDceInfo = NULL;
  1764. PSecPkgContext_Names ContextNames = NULL;
  1765. PSecPkgContext_PackageInfo PackageInfo;
  1766. PSecPkgContext_NegotiationInfo NegInfo ;
  1767. PSecPkgContext_PasswordExpiry PasswordExpires;
  1768. PSecPkgContext_UserFlags UserFlags;
  1769. PSecPkgContext_SessionKey SessionKeyInfo;
  1770. PSecPkgContext_AccessToken AccessToken;
  1771. PSecPkgContext_TargetInformation TargetInformation;
  1772. PSecPkgContext_KeyInfo KeyInfo;
  1773. ULONG PackageInfoSize = 0;
  1774. SspPrint(( SSP_API, "Entering SpQueryContextAttributes\n" ));
  1775. pContext = ReferenceUserContext(ContextHandle, FALSE);
  1776. if (pContext == NULL) {
  1777. Status = STATUS_INVALID_HANDLE;
  1778. SspPrint(( SSP_API_MORE, "SpQueryContextAttributes, ReferenceUserContext returns NULL (possible incomplete context)\n" ));
  1779. goto Cleanup;
  1780. }
  1781. //
  1782. // Handle each of the various queried attributes
  1783. //
  1784. SspPrint(( SSP_API_MORE, "SpQueryContextAttributes : 0x%lx\n", Attribute ));
  1785. switch ( Attribute) {
  1786. case SECPKG_ATTR_SIZES:
  1787. ContextSizes = (PSecPkgContext_Sizes) Buffer;
  1788. ContextSizes->cbMaxToken = NTLMSP_MAX_TOKEN_SIZE;
  1789. if (pContext->NegotiateFlags & (NTLMSSP_NEGOTIATE_ALWAYS_SIGN |
  1790. NTLMSSP_NEGOTIATE_SIGN |
  1791. NTLMSSP_NEGOTIATE_SEAL) ) {
  1792. ContextSizes->cbMaxSignature = NTLMSSP_MESSAGE_SIGNATURE_SIZE;
  1793. } else {
  1794. ContextSizes->cbMaxSignature = 0;
  1795. }
  1796. if (pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_SEAL) {
  1797. ContextSizes->cbBlockSize = 1;
  1798. ContextSizes->cbSecurityTrailer = NTLMSSP_MESSAGE_SIGNATURE_SIZE;
  1799. }
  1800. else
  1801. {
  1802. ContextSizes->cbBlockSize = 0;
  1803. if((pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_SIGN) ||
  1804. (pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
  1805. {
  1806. ContextSizes->cbSecurityTrailer = NTLMSSP_MESSAGE_SIGNATURE_SIZE;
  1807. } else {
  1808. ContextSizes->cbSecurityTrailer = 0;
  1809. }
  1810. }
  1811. break;
  1812. case SECPKG_ATTR_DCE_INFO:
  1813. ContextDceInfo = (PSecPkgContext_DceInfo) Buffer;
  1814. if (pContext->ContextNames)
  1815. {
  1816. UINT Length = (UINT) wcslen(pContext->ContextNames);
  1817. ContextDceInfo->pPac = (LPWSTR)UserFunctions->AllocateHeap((Length + 1) * sizeof(WCHAR));
  1818. if (ContextDceInfo->pPac == NULL) {
  1819. Status = STATUS_NO_MEMORY;
  1820. SspPrint(( SSP_CRITICAL, "SpQueryContextAttributes, NtLmAllocate returns NULL\n" ));
  1821. goto Cleanup;
  1822. }
  1823. RtlCopyMemory(
  1824. (LPWSTR) ContextDceInfo->pPac,
  1825. pContext->ContextNames,
  1826. Length * sizeof(WCHAR)
  1827. );
  1828. *((LPWSTR)(ContextDceInfo->pPac) + Length) = L'\0';
  1829. }
  1830. else
  1831. {
  1832. SspPrint(( SSP_API_MORE, "SpQueryContextAttributes no ContextNames\n" ));
  1833. ContextDceInfo->pPac = (LPWSTR) UserFunctions->AllocateHeap(sizeof(WCHAR));
  1834. *((LPWSTR)(ContextDceInfo->pPac)) = L'\0';
  1835. }
  1836. ContextDceInfo->AuthzSvc = 0;
  1837. break;
  1838. case SECPKG_ATTR_TARGET_INFORMATION:
  1839. {
  1840. ULONG Length;
  1841. TargetInformation = (PSecPkgContext_TargetInformation) Buffer;
  1842. if (TargetInformation == NULL)
  1843. {
  1844. SspPrint(( SSP_CRITICAL, "Null buffer SECPKG_ATTR_TARGET_INFORMATION.\n" ));
  1845. Status = STATUS_INVALID_PARAMETER;
  1846. goto Cleanup;
  1847. }
  1848. TargetInformation->MarshalledTargetInfo = NULL;
  1849. if (pContext->pbMarshalledTargetInfo == NULL)
  1850. {
  1851. TargetInformation->MarshalledTargetInfo = NULL;
  1852. TargetInformation->MarshalledTargetInfoLength = 0;
  1853. goto Cleanup;
  1854. }
  1855. Length = pContext->cbMarshalledTargetInfo;
  1856. SspPrint(( SSP_API_MORE, "NtLmQueryContextAttributes: TargetInformation length is 0x%lx\n", Length));
  1857. TargetInformation->MarshalledTargetInfo = (PUCHAR)UserFunctions->AllocateHeap(
  1858. Length
  1859. );
  1860. if (TargetInformation->MarshalledTargetInfo != NULL)
  1861. {
  1862. RtlCopyMemory(
  1863. TargetInformation->MarshalledTargetInfo,
  1864. pContext->pbMarshalledTargetInfo,
  1865. Length
  1866. );
  1867. TargetInformation->MarshalledTargetInfoLength = Length;
  1868. }
  1869. else
  1870. {
  1871. Status = STATUS_INSUFFICIENT_RESOURCES;
  1872. goto Cleanup;
  1873. }
  1874. break;
  1875. }
  1876. case SECPKG_ATTR_SESSION_KEY:
  1877. {
  1878. if (NtLmState != NtLmLsaMode)
  1879. {
  1880. Status = STATUS_INVALID_PARAMETER;
  1881. break;
  1882. }
  1883. SessionKeyInfo = (PSecPkgContext_SessionKey) Buffer;
  1884. SessionKeyInfo->SessionKeyLength = sizeof(pContext->SessionKey);
  1885. SessionKeyInfo->SessionKey = (PUCHAR) UserFunctions->AllocateHeap(
  1886. SessionKeyInfo->SessionKeyLength
  1887. );
  1888. if (SessionKeyInfo->SessionKey != NULL)
  1889. {
  1890. RtlCopyMemory(
  1891. SessionKeyInfo->SessionKey,
  1892. pContext->SessionKey,
  1893. SessionKeyInfo->SessionKeyLength
  1894. );
  1895. }
  1896. else
  1897. {
  1898. Status = STATUS_INSUFFICIENT_RESOURCES;
  1899. }
  1900. break;
  1901. }
  1902. case SECPKG_ATTR_KEY_INFO:
  1903. {
  1904. LPWSTR EncryptAlgorithm = L"RSADSI RC4";
  1905. KeyInfo = (PSecPkgContext_KeyInfo) Buffer;
  1906. if( pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_128 )
  1907. {
  1908. KeyInfo->KeySize = 128;
  1909. } else if( pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_56 )
  1910. {
  1911. KeyInfo->KeySize = 56;
  1912. } else {
  1913. KeyInfo->KeySize = 40;
  1914. }
  1915. KeyInfo->EncryptAlgorithm = CALG_RC4;
  1916. if( pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM2 )
  1917. {
  1918. KeyInfo->SignatureAlgorithm = (unsigned long)KERB_CHECKSUM_HMAC_MD5;
  1919. } else {
  1920. KeyInfo->SignatureAlgorithm = (unsigned long)KERB_CHECKSUM_REAL_CRC32;
  1921. }
  1922. KeyInfo->sSignatureAlgorithmName = NULL;
  1923. KeyInfo->sEncryptAlgorithmName = NULL;
  1924. //
  1925. // The checksum doesn't include a name, so don't fill it in - leave
  1926. // it as an empty string, so callers don't die when they
  1927. // try to manipulate it.
  1928. //
  1929. KeyInfo->sEncryptAlgorithmName = (LPWSTR)
  1930. UserFunctions->AllocateHeap(sizeof(WCHAR) * ((ULONG) wcslen(EncryptAlgorithm) + 1));
  1931. if (KeyInfo->sEncryptAlgorithmName != NULL)
  1932. {
  1933. wcscpy(
  1934. KeyInfo->sEncryptAlgorithmName,
  1935. EncryptAlgorithm
  1936. );
  1937. KeyInfo->sSignatureAlgorithmName = (LPWSTR)
  1938. UserFunctions->AllocateHeap(sizeof(WCHAR));
  1939. if (KeyInfo->sSignatureAlgorithmName != NULL)
  1940. {
  1941. *KeyInfo->sSignatureAlgorithmName = L'\0';
  1942. }
  1943. else
  1944. {
  1945. Status = STATUS_INSUFFICIENT_RESOURCES;
  1946. UserFunctions->FreeHeap(KeyInfo->sEncryptAlgorithmName);
  1947. KeyInfo->sEncryptAlgorithmName = NULL;
  1948. }
  1949. }
  1950. else
  1951. {
  1952. Status = STATUS_INSUFFICIENT_RESOURCES;
  1953. }
  1954. break;
  1955. }
  1956. case SECPKG_ATTR_NAMES:
  1957. ContextNames = (PSecPkgContext_Names) Buffer;
  1958. if (pContext->ContextNames)
  1959. {
  1960. UINT Length = (UINT) wcslen(pContext->ContextNames);
  1961. ContextNames->sUserName = (LPWSTR) UserFunctions->AllocateHeap((Length+1) * sizeof(WCHAR));
  1962. if (ContextNames->sUserName == NULL) {
  1963. Status = STATUS_NO_MEMORY;
  1964. SspPrint(( SSP_CRITICAL, "SpQueryContextAttributes, NtLmAllocate returns NULL\n" ));
  1965. goto Cleanup;
  1966. }
  1967. RtlCopyMemory(
  1968. ContextNames->sUserName,
  1969. pContext->ContextNames,
  1970. Length * sizeof(WCHAR)
  1971. );
  1972. *(ContextNames->sUserName + Length) = L'\0';
  1973. }
  1974. else
  1975. {
  1976. SspPrint(( SSP_API_MORE, "SpQueryContextAttributes no ContextNames\n" ));
  1977. ContextNames->sUserName = (LPWSTR) UserFunctions->AllocateHeap(sizeof(WCHAR));
  1978. *(ContextNames->sUserName) = L'\0';
  1979. }
  1980. break;
  1981. case SECPKG_ATTR_PACKAGE_INFO:
  1982. case SECPKG_ATTR_NEGOTIATION_INFO:
  1983. //
  1984. // Return the information about this package. This is useful for
  1985. // callers who used SPNEGO and don't know what package they got.
  1986. //
  1987. PackageInfo = (PSecPkgContext_PackageInfo) Buffer;
  1988. PackageInfoSize = sizeof(SecPkgInfoW) + sizeof(NTLMSP_NAME) + sizeof(NTLMSP_COMMENT);
  1989. PackageInfo->PackageInfo = (PSecPkgInfoW) UserFunctions->AllocateHeap(PackageInfoSize);
  1990. if (PackageInfo->PackageInfo == NULL)
  1991. {
  1992. Status = STATUS_INSUFFICIENT_RESOURCES;
  1993. goto Cleanup;
  1994. }
  1995. PackageInfo->PackageInfo->Name = (LPWSTR) (PackageInfo->PackageInfo + 1);
  1996. PackageInfo->PackageInfo->Comment = (LPWSTR) ((((PBYTE) PackageInfo->PackageInfo->Name)) + sizeof(NTLMSP_NAME));
  1997. wcscpy(
  1998. PackageInfo->PackageInfo->Name,
  1999. NTLMSP_NAME
  2000. );
  2001. wcscpy(
  2002. PackageInfo->PackageInfo->Comment,
  2003. NTLMSP_COMMENT
  2004. );
  2005. PackageInfo->PackageInfo->wVersion = SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION;
  2006. PackageInfo->PackageInfo->wRPCID = RPC_C_AUTHN_WINNT;
  2007. PackageInfo->PackageInfo->fCapabilities = NTLMSP_CAPS;
  2008. PackageInfo->PackageInfo->cbMaxToken = NTLMSP_MAX_TOKEN_SIZE;
  2009. if ( Attribute == SECPKG_ATTR_NEGOTIATION_INFO )
  2010. {
  2011. NegInfo = (PSecPkgContext_NegotiationInfo) PackageInfo ;
  2012. NegInfo->NegotiationState = SECPKG_NEGOTIATION_COMPLETE ;
  2013. }
  2014. break;
  2015. case SECPKG_ATTR_PASSWORD_EXPIRY:
  2016. PasswordExpires = (PSecPkgContext_PasswordExpiry) Buffer;
  2017. if(pContext->PasswordExpiry.QuadPart != 0) {
  2018. PasswordExpires->tsPasswordExpires = pContext->PasswordExpiry;
  2019. } else {
  2020. Status = SEC_E_UNSUPPORTED_FUNCTION;
  2021. }
  2022. break;
  2023. case SECPKG_ATTR_USER_FLAGS:
  2024. UserFlags = (PSecPkgContext_UserFlags) Buffer;
  2025. UserFlags->UserFlags = pContext->UserFlags;
  2026. break;
  2027. case SECPKG_ATTR_FLAGS:
  2028. {
  2029. BOOLEAN Client = (pContext->ClientTokenHandle == 0);
  2030. ULONG Flags = 0;
  2031. //
  2032. // note: doesn't return all flags; by design.
  2033. //
  2034. ContextFlags = (PSecPkgContext_Flags) Buffer;
  2035. ContextFlags->Flags = 0;
  2036. if (pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_SEAL) {
  2037. if( Client )
  2038. {
  2039. Flags |= ISC_RET_CONFIDENTIALITY;
  2040. } else {
  2041. Flags |= ASC_RET_CONFIDENTIALITY;
  2042. }
  2043. }
  2044. if (pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_SIGN) {
  2045. if( Client )
  2046. {
  2047. Flags |= ISC_RET_SEQUENCE_DETECT | ISC_RET_REPLAY_DETECT | ISC_RET_INTEGRITY;
  2048. } else {
  2049. Flags |= ASC_RET_SEQUENCE_DETECT | ASC_RET_REPLAY_DETECT | ASC_RET_INTEGRITY;
  2050. }
  2051. }
  2052. if (pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_NULL_SESSION) {
  2053. if( Client )
  2054. {
  2055. Flags |= ISC_RET_NULL_SESSION;
  2056. } else {
  2057. Flags |= ASC_RET_NULL_SESSION;
  2058. }
  2059. }
  2060. if (pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_DATAGRAM) {
  2061. if( Client )
  2062. {
  2063. Flags |= ISC_RET_DATAGRAM;
  2064. } else {
  2065. Flags |= ASC_RET_DATAGRAM;
  2066. }
  2067. }
  2068. if (pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_IDENTIFY) {
  2069. if( Client )
  2070. {
  2071. Flags |= ISC_RET_IDENTIFY;
  2072. } else {
  2073. Flags |= ASC_RET_IDENTIFY;
  2074. }
  2075. }
  2076. ContextFlags->Flags |= Flags;
  2077. break;
  2078. }
  2079. case SECPKG_ATTR_ACCESS_TOKEN:
  2080. AccessToken = (PSecPkgContext_AccessToken) Buffer;
  2081. //
  2082. // ClientTokenHandle can be NULL, for instance:
  2083. // 1. client side context.
  2084. // 2. incomplete server context.
  2085. //
  2086. if(pContext->ClientTokenHandle)
  2087. AccessToken->AccessToken = pContext->ClientTokenHandle;
  2088. else
  2089. Status = SEC_E_NO_IMPERSONATION;
  2090. break;
  2091. case SECPKG_ATTR_LIFESPAN:
  2092. default:
  2093. Status = STATUS_NOT_SUPPORTED;
  2094. break;
  2095. }
  2096. Cleanup:
  2097. if (!NT_SUCCESS(Status))
  2098. {
  2099. switch (Attribute) {
  2100. case SECPKG_ATTR_NAMES:
  2101. if (ContextNames != NULL && ContextNames->sUserName )
  2102. {
  2103. NtLmFree(ContextNames->sUserName);
  2104. }
  2105. break;
  2106. case SECPKG_ATTR_DCE_INFO:
  2107. if (ContextDceInfo != NULL && ContextDceInfo->pPac)
  2108. {
  2109. NtLmFree(ContextDceInfo->pPac);
  2110. }
  2111. break;
  2112. }
  2113. }
  2114. if (pContext != NULL)
  2115. {
  2116. (VOID) DereferenceUserContext(pContext);
  2117. }
  2118. SspPrint(( SSP_API, "Leaving SpQueryContextAttributes: 0x%lx\n", Status ));
  2119. return(SspNtStatusToSecStatus(Status, SEC_E_INTERNAL_ERROR));
  2120. }
  2121. //+-------------------------------------------------------------------------
  2122. //
  2123. // Function: SpCompleteAuthToken
  2124. //
  2125. // Synopsis: Completes a context
  2126. //
  2127. // Effects:
  2128. //
  2129. // Arguments:
  2130. //
  2131. // Requires:
  2132. //
  2133. // Returns:
  2134. //
  2135. // Notes:
  2136. //
  2137. //
  2138. //--------------------------------------------------------------------------
  2139. NTSTATUS NTAPI
  2140. SpCompleteAuthToken(
  2141. IN ULONG_PTR ContextHandle,
  2142. IN PSecBufferDesc InputBuffer
  2143. )
  2144. {
  2145. UNREFERENCED_PARAMETER (ContextHandle);
  2146. UNREFERENCED_PARAMETER (InputBuffer);
  2147. SspPrint(( SSP_API, "Entering SpCompleteAuthToken\n" ));
  2148. SspPrint(( SSP_API, "Leaving SpCompleteAuthToken\n" ));
  2149. return(SEC_E_UNSUPPORTED_FUNCTION);
  2150. }
  2151. NTSTATUS NTAPI
  2152. SpFormatCredentials(
  2153. IN PSecBuffer Credentials,
  2154. OUT PSecBuffer FormattedCredentials
  2155. )
  2156. {
  2157. UNREFERENCED_PARAMETER (Credentials);
  2158. UNREFERENCED_PARAMETER (FormattedCredentials);
  2159. SspPrint(( SSP_API, "Entering SpFormatCredentials\n" ));
  2160. SspPrint(( SSP_API, "Leaving SpFormatCredentials\n" ));
  2161. return(SEC_E_UNSUPPORTED_FUNCTION);
  2162. }
  2163. NTSTATUS NTAPI
  2164. SpMarshallSupplementalCreds(
  2165. IN ULONG CredentialSize,
  2166. IN PUCHAR Credentials,
  2167. OUT PULONG MarshalledCredSize,
  2168. OUT PVOID * MarshalledCreds
  2169. )
  2170. {
  2171. UNREFERENCED_PARAMETER (CredentialSize);
  2172. UNREFERENCED_PARAMETER (Credentials);
  2173. UNREFERENCED_PARAMETER (MarshalledCredSize);
  2174. UNREFERENCED_PARAMETER (MarshalledCreds);
  2175. SspPrint(( SSP_API, "Entering SpMarshallSupplementalCreds\n" ));
  2176. SspPrint(( SSP_API, "Leaving SpMarshallSupplementalCreds\n" ));
  2177. return(SEC_E_UNSUPPORTED_FUNCTION);
  2178. }
  2179. //+-------------------------------------------------------------------------
  2180. //
  2181. // Function: NtLmMakePackedContext
  2182. //
  2183. // Synopsis: Maps a context to the caller's address space
  2184. //
  2185. // Effects:
  2186. //
  2187. // Arguments: Context - The context to map
  2188. // MappedContext - Set to TRUE on success
  2189. // ContextData - Receives a buffer in the caller's address space
  2190. // with the mapped context.
  2191. //
  2192. // Requires:
  2193. //
  2194. // Returns:
  2195. //
  2196. // Notes:
  2197. //
  2198. //
  2199. //--------------------------------------------------------------------------
  2200. NTSTATUS
  2201. NtLmMakePackedContext(
  2202. IN PNTLM_CLIENT_CONTEXT Context,
  2203. OUT PBOOLEAN MappedContext,
  2204. OUT PSecBuffer ContextData,
  2205. IN ULONG Flags
  2206. )
  2207. {
  2208. NTSTATUS Status = STATUS_SUCCESS;
  2209. PNTLM_PACKED_CONTEXT PackedContext = NULL;
  2210. ULONG ContextSize, ContextNameSize = 0;
  2211. if (Context->ContextNames)
  2212. {
  2213. ContextNameSize = (ULONG) wcslen(Context->ContextNames);
  2214. }
  2215. ContextSize = sizeof(NTLM_CLIENT_CONTEXT) +
  2216. ContextNameSize * sizeof(WCHAR) + sizeof( WCHAR );
  2217. PackedContext = (PNTLM_PACKED_CONTEXT) NtLmAllocateLsaHeap( ContextSize );
  2218. if (PackedContext == NULL)
  2219. {
  2220. Status = STATUS_INSUFFICIENT_RESOURCES;
  2221. goto Cleanup;
  2222. }
  2223. // Copy all fields of the old context
  2224. PackedContext->Tag = NTLM_PACKED_CONTEXT_MAP ;
  2225. PackedContext->NegotiateFlags = Context->NegotiateFlags ;
  2226. PackedContext->SendNonce = Context->SendNonce ;
  2227. PackedContext->RecvNonce = Context->RecvNonce ;
  2228. RtlCopyMemory(
  2229. PackedContext->SessionKey,
  2230. Context->SessionKey,
  2231. MSV1_0_USER_SESSION_KEY_LENGTH );
  2232. PackedContext->ContextSignature = Context->ContextSignature ;
  2233. PackedContext->PasswordExpiry = Context->PasswordExpiry ;
  2234. PackedContext->UserFlags = Context->UserFlags ;
  2235. if ( ContextNameSize )
  2236. {
  2237. PackedContext->ContextNames = sizeof( NTLM_PACKED_CONTEXT );
  2238. PackedContext->ContextNameLength = (ContextNameSize + 1) * sizeof( WCHAR ) ;
  2239. RtlCopyMemory(
  2240. (PackedContext + 1),
  2241. Context->ContextNames,
  2242. PackedContext->ContextNameLength );
  2243. }
  2244. else
  2245. {
  2246. PackedContext->ContextNames = 0 ;
  2247. }
  2248. RtlCopyMemory(
  2249. PackedContext->SignSessionKey,
  2250. Context->SignSessionKey,
  2251. MSV1_0_USER_SESSION_KEY_LENGTH );
  2252. RtlCopyMemory(
  2253. PackedContext->VerifySessionKey,
  2254. Context->VerifySessionKey,
  2255. MSV1_0_USER_SESSION_KEY_LENGTH );
  2256. RtlCopyMemory(
  2257. PackedContext->SealSessionKey,
  2258. Context->SealSessionKey,
  2259. MSV1_0_USER_SESSION_KEY_LENGTH );
  2260. RtlCopyMemory(
  2261. PackedContext->UnsealSessionKey,
  2262. Context->SealSessionKey,
  2263. MSV1_0_USER_SESSION_KEY_LENGTH );
  2264. RtlCopyMemory(
  2265. &PackedContext->SealRc4Sched,
  2266. &Context->SealRc4Sched,
  2267. sizeof( struct RC4_KEYSTRUCT ) );
  2268. RtlCopyMemory(
  2269. &PackedContext->UnsealRc4Sched,
  2270. &Context->UnsealRc4Sched,
  2271. sizeof( struct RC4_KEYSTRUCT ) );
  2272. // Replace some fields
  2273. //
  2274. // Token will be returned by the caller of this routine
  2275. //
  2276. PackedContext->ClientTokenHandle = 0 ;
  2277. // Save the fact that it's exported
  2278. PackedContext->NegotiateFlags |= NTLMSSP_NEGOTIATE_EXPORTED_CONTEXT;
  2279. ContextData->pvBuffer = PackedContext;
  2280. ContextData->cbBuffer = ContextSize;
  2281. *MappedContext = TRUE;
  2282. Status = STATUS_SUCCESS;
  2283. Cleanup:
  2284. if (!NT_SUCCESS(Status))
  2285. {
  2286. if (PackedContext != NULL)
  2287. {
  2288. NtLmFreeLsaHeap(PackedContext);
  2289. }
  2290. }
  2291. return(Status);
  2292. }
  2293. //+-------------------------------------------------------------------------
  2294. //
  2295. // Function: SpExportSecurityContext
  2296. //
  2297. // Synopsis: Exports a security context to another process
  2298. //
  2299. // Effects: Allocates memory for output
  2300. //
  2301. // Arguments: ContextHandle - handle to context to export
  2302. // Flags - Flags concerning duplication. Allowable flags:
  2303. // SECPKG_CONTEXT_EXPORT_DELETE_OLD - causes old context
  2304. // to be deleted.
  2305. // PackedContext - Receives serialized context to be freed with
  2306. // FreeContextBuffer
  2307. // TokenHandle - Optionally receives handle to context's token.
  2308. //
  2309. // Requires:
  2310. //
  2311. // Returns:
  2312. //
  2313. // Notes:
  2314. //
  2315. //
  2316. //--------------------------------------------------------------------------
  2317. NTSTATUS
  2318. SpExportSecurityContext(
  2319. IN ULONG_PTR ContextHandle,
  2320. IN ULONG Flags,
  2321. OUT PSecBuffer PackedContext,
  2322. OUT PHANDLE TokenHandle
  2323. )
  2324. {
  2325. PNTLM_CLIENT_CONTEXT Context = NULL ;
  2326. PNTLM_PACKED_CONTEXT pvContext = NULL;
  2327. NTSTATUS Status = STATUS_SUCCESS;
  2328. NTSTATUS SubStatus = STATUS_SUCCESS;
  2329. BOOLEAN MappedContext = FALSE;
  2330. SspPrint(( SSP_API,"Entering SpExportSecurityContext for context 0x%x\n", ContextHandle ));
  2331. if (ARGUMENT_PRESENT(TokenHandle))
  2332. {
  2333. *TokenHandle = NULL;
  2334. }
  2335. PackedContext->pvBuffer = NULL;
  2336. PackedContext->cbBuffer = 0;
  2337. PackedContext->BufferType = 0;
  2338. Context = ReferenceUserContext(
  2339. ContextHandle,
  2340. FALSE // don't unlink
  2341. );
  2342. if (Context == NULL)
  2343. {
  2344. SspPrint((SSP_CRITICAL, "SpExportSecurityContext: Invalid handle supplied (0x%x)\n",
  2345. ContextHandle));
  2346. Status = STATUS_INVALID_HANDLE;
  2347. goto Cleanup;
  2348. }
  2349. Status = NtLmMakePackedContext(
  2350. Context,
  2351. &MappedContext,
  2352. PackedContext,
  2353. Flags
  2354. );
  2355. if (!NT_SUCCESS(Status))
  2356. {
  2357. goto Cleanup;
  2358. }
  2359. ASSERT(MappedContext);
  2360. //
  2361. // Now either duplicate the token or copy it.
  2362. //
  2363. if (ARGUMENT_PRESENT(TokenHandle))
  2364. {
  2365. ULONG LockIndex;
  2366. LockIndex = ListIndexToLockIndex( HandleToListIndex( ContextHandle ) );
  2367. RtlAcquireResourceShared( &NtLmUserContextLock[LockIndex], TRUE );
  2368. if ((Flags & SECPKG_CONTEXT_EXPORT_DELETE_OLD) != 0)
  2369. {
  2370. RtlConvertSharedToExclusive( &NtLmUserContextLock[LockIndex] );
  2371. *TokenHandle = Context->ClientTokenHandle;
  2372. Context->ClientTokenHandle = NULL;
  2373. }
  2374. else
  2375. {
  2376. Status = NtDuplicateObject(
  2377. NtCurrentProcess(),
  2378. Context->ClientTokenHandle,
  2379. NULL,
  2380. TokenHandle,
  2381. 0, // no new access
  2382. 0, // no handle attributes
  2383. DUPLICATE_SAME_ACCESS
  2384. );
  2385. }
  2386. RtlReleaseResource( &NtLmUserContextLock[LockIndex] );
  2387. if (!NT_SUCCESS(Status))
  2388. {
  2389. goto Cleanup;
  2390. }
  2391. }
  2392. pvContext = (PNTLM_PACKED_CONTEXT) PackedContext->pvBuffer;
  2393. // Semantics of this flag: Export from here, but reset the Nonce.
  2394. // We zero out the session key, since all we need is the rc4 key.
  2395. if ((Flags & SECPKG_CONTEXT_EXPORT_RESET_NEW) != 0)
  2396. {
  2397. pvContext->SendNonce = (ULONG) -1;
  2398. pvContext->RecvNonce = (ULONG) -1;
  2399. }
  2400. RtlZeroMemory(
  2401. &pvContext->SessionKey,
  2402. MSV1_0_USER_SESSION_KEY_LENGTH
  2403. );
  2404. Cleanup:
  2405. if (Context != NULL)
  2406. {
  2407. SubStatus = DereferenceUserContext(Context);
  2408. // Don't destroy real status
  2409. if (NT_SUCCESS(Status))
  2410. {
  2411. Status = SubStatus;
  2412. }
  2413. }
  2414. SspPrint(( SSP_API,"Leaving SpExportContext: 0x%lx\n", Status ));
  2415. return(SspNtStatusToSecStatus(Status, SEC_E_INTERNAL_ERROR));
  2416. }
  2417. //+-------------------------------------------------------------------------
  2418. //
  2419. // Function: NtLmCreateUserModeContext
  2420. //
  2421. // Synopsis: Creates a user-mode context to support impersonation and
  2422. // message integrity and privacy
  2423. //
  2424. // Effects:
  2425. //
  2426. // Arguments:
  2427. //
  2428. // Requires:
  2429. //
  2430. // Returns:
  2431. //
  2432. // Notes:
  2433. //
  2434. //
  2435. //--------------------------------------------------------------------------
  2436. NTSTATUS
  2437. NtLmCreateUserModeContext(
  2438. IN ULONG_PTR ContextHandle,
  2439. IN HANDLE Token,
  2440. IN PSecBuffer MarshalledContext,
  2441. OUT PNTLM_CLIENT_CONTEXT * NewContext
  2442. )
  2443. {
  2444. NTSTATUS Status = STATUS_SUCCESS;
  2445. PNTLM_CLIENT_CONTEXT Context = NULL;
  2446. PNTLM_PACKED_CONTEXT PackedContext;
  2447. ULONG ListIndex;
  2448. ULONG LockIndex;
  2449. if (MarshalledContext->cbBuffer < sizeof(NTLM_PACKED_CONTEXT))
  2450. {
  2451. SspPrint((SSP_CRITICAL,"NtLmCreateUserModeContext: Invalid buffer size for marshalled context: was 0x%x, needed 0x%x\n",
  2452. MarshalledContext->cbBuffer, sizeof(NTLM_PACKED_CONTEXT)));
  2453. return(STATUS_INVALID_PARAMETER);
  2454. }
  2455. PackedContext = (PNTLM_PACKED_CONTEXT) MarshalledContext->pvBuffer;
  2456. Context = (PNTLM_CLIENT_CONTEXT)NtLmAllocate ( sizeof(NTLM_CLIENT_CONTEXT));
  2457. if (Context == NULL)
  2458. {
  2459. Status = STATUS_INSUFFICIENT_RESOURCES;
  2460. goto Cleanup;
  2461. }
  2462. Context->NegotiateFlags = PackedContext->NegotiateFlags ;
  2463. Context->SendNonce = PackedContext->SendNonce ;
  2464. Context->RecvNonce = PackedContext->RecvNonce ;
  2465. RtlCopyMemory(
  2466. Context->SessionKey,
  2467. PackedContext->SessionKey,
  2468. MSV1_0_USER_SESSION_KEY_LENGTH );
  2469. Context->ContextSignature = PackedContext->ContextSignature ;
  2470. Context->PasswordExpiry = PackedContext->PasswordExpiry ;
  2471. Context->UserFlags = PackedContext->UserFlags ;
  2472. if ( PackedContext->ContextNames )
  2473. {
  2474. Context->ContextNames = (PWSTR) NtLmAllocate( PackedContext->ContextNameLength );
  2475. if ( Context->ContextNames == NULL )
  2476. {
  2477. Status = STATUS_INSUFFICIENT_RESOURCES ;
  2478. goto Cleanup ;
  2479. }
  2480. RtlCopyMemory(
  2481. Context->ContextNames,
  2482. ((PUCHAR) PackedContext) + PackedContext->ContextNames,
  2483. PackedContext->ContextNameLength );
  2484. }
  2485. else
  2486. {
  2487. Context->ContextNames = NULL ;
  2488. }
  2489. RtlCopyMemory(
  2490. Context->SignSessionKey,
  2491. PackedContext->SignSessionKey,
  2492. MSV1_0_USER_SESSION_KEY_LENGTH );
  2493. RtlCopyMemory(
  2494. Context->VerifySessionKey,
  2495. PackedContext->VerifySessionKey,
  2496. MSV1_0_USER_SESSION_KEY_LENGTH );
  2497. RtlCopyMemory(
  2498. Context->SealSessionKey,
  2499. PackedContext->SealSessionKey,
  2500. MSV1_0_USER_SESSION_KEY_LENGTH );
  2501. RtlCopyMemory(
  2502. Context->UnsealSessionKey,
  2503. PackedContext->UnsealSessionKey,
  2504. MSV1_0_USER_SESSION_KEY_LENGTH );
  2505. RtlCopyMemory(
  2506. &Context->SealRc4Sched,
  2507. &PackedContext->SealRc4Sched,
  2508. sizeof( struct RC4_KEYSTRUCT ) );
  2509. RtlCopyMemory(
  2510. &Context->UnsealRc4Sched,
  2511. &PackedContext->UnsealRc4Sched,
  2512. sizeof( struct RC4_KEYSTRUCT ) );
  2513. // These need to be changed
  2514. Context->ClientTokenHandle = Token;
  2515. if (Context->SendNonce == (ULONG) -1)
  2516. {
  2517. Context->SendNonce = 0;
  2518. }
  2519. if (Context->RecvNonce == (ULONG) -1)
  2520. {
  2521. Context->RecvNonce = 0;
  2522. }
  2523. if ( Context->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM2 )
  2524. {
  2525. Context->pSealRc4Sched = &Context->SealRc4Sched;
  2526. Context->pUnsealRc4Sched = &Context->UnsealRc4Sched;
  2527. Context->pSendNonce = &Context->SendNonce;
  2528. Context->pRecvNonce = &Context->RecvNonce;
  2529. } else {
  2530. Context->pSealRc4Sched = &Context->SealRc4Sched;
  2531. Context->pUnsealRc4Sched = &Context->SealRc4Sched;
  2532. Context->pSendNonce = &Context->SendNonce;
  2533. Context->pRecvNonce = &Context->SendNonce;
  2534. }
  2535. Context->References = 2;
  2536. //
  2537. // Modify the DACL on the token to grant access to the caller
  2538. //
  2539. if (Context->ClientTokenHandle != NULL)
  2540. {
  2541. Status = SspCreateTokenDacl(
  2542. Context->ClientTokenHandle
  2543. );
  2544. if (!NT_SUCCESS(Status))
  2545. {
  2546. goto Cleanup;
  2547. }
  2548. }
  2549. // Dummy up an lsa handle by incrementing a global variable. This
  2550. // will ensure that each imported context has a unique handle.
  2551. // Skip over values that could be interpreted as an aligned pointer,
  2552. // so that they won't get mixed up with real lsa handles.
  2553. Context->LsaContext = InterlockedIncrement((PLONG)&ExportedContext);
  2554. while(Context->LsaContext % MAX_NATURAL_ALIGNMENT == 0)
  2555. {
  2556. Context->LsaContext = InterlockedIncrement((PLONG)&ExportedContext);
  2557. }
  2558. ListIndex = HandleToListIndex( Context->LsaContext );
  2559. LockIndex = ListIndexToLockIndex( ListIndex );
  2560. RtlAcquireResourceExclusive(&NtLmUserContextLock[LockIndex], TRUE);
  2561. InsertHeadList ( &NtLmUserContextList[ListIndex], &Context->Next );
  2562. NtLmUserContextCount[ListIndex]++;
  2563. RtlReleaseResource(&NtLmUserContextLock[LockIndex]);
  2564. *NewContext = Context;
  2565. Cleanup:
  2566. if (!NT_SUCCESS(Status))
  2567. {
  2568. if (Context != NULL)
  2569. {
  2570. FreeUserContext(Context);
  2571. }
  2572. }
  2573. return(Status);
  2574. }
  2575. //+-------------------------------------------------------------------------
  2576. //
  2577. // Function: SpImportSecurityContext
  2578. //
  2579. // Synopsis:
  2580. //
  2581. // Effects:
  2582. //
  2583. // Arguments:
  2584. //
  2585. // Requires:
  2586. //
  2587. // Returns:
  2588. //
  2589. // Notes:
  2590. //
  2591. //
  2592. //--------------------------------------------------------------------------
  2593. NTSTATUS
  2594. SpImportSecurityContext(
  2595. IN PSecBuffer PackedContext,
  2596. IN HANDLE Token,
  2597. OUT PULONG_PTR ContextHandle
  2598. )
  2599. {
  2600. NTSTATUS Status = STATUS_SUCCESS;
  2601. NTSTATUS SubStatus = STATUS_SUCCESS;
  2602. PNTLM_CLIENT_CONTEXT Context = NULL;
  2603. SspPrint(( SSP_API,"Entering SpImportSecurityContext\n"));
  2604. Status = NtLmCreateUserModeContext(
  2605. 0, // no lsa context
  2606. Token,
  2607. PackedContext,
  2608. &Context
  2609. );
  2610. if (!NT_SUCCESS(Status))
  2611. {
  2612. SspPrint((SSP_CRITICAL,"SpImportSecurityContext: Failed to create user mode context: 0x%x\n",
  2613. Status));
  2614. goto Cleanup;
  2615. }
  2616. *ContextHandle = Context->LsaContext;
  2617. Cleanup:
  2618. if (Context != NULL)
  2619. {
  2620. SubStatus = DereferenceUserContext(Context);
  2621. // Don't destroy real status
  2622. if (NT_SUCCESS(Status))
  2623. {
  2624. Status = SubStatus;
  2625. }
  2626. }
  2627. SspPrint(( SSP_API,"Leaving SpImportSecurityContext: 0x%lx\n", Status));
  2628. return(SspNtStatusToSecStatus(Status, SEC_E_INTERNAL_ERROR));
  2629. }
  2630. NTSTATUS
  2631. SspGetTokenUser(
  2632. HANDLE Token,
  2633. PTOKEN_USER pTokenUser,
  2634. PULONG TokenUserSize
  2635. )
  2636. /*++
  2637. RoutineDescription:
  2638. Gets the TOKEN_USER from an open token
  2639. Arguments:
  2640. Token - Handle to a token open for TOKEN_QUERY access
  2641. Return Value:
  2642. STATUS_INSUFFICIENT_RESOURCES - not enough memory to complete the
  2643. function.
  2644. Errors from NtQueryInformationToken.
  2645. --*/
  2646. {
  2647. NTSTATUS Status;
  2648. Status = NtQueryInformationToken(
  2649. Token,
  2650. TokenUser,
  2651. pTokenUser,
  2652. *TokenUserSize,
  2653. TokenUserSize
  2654. );
  2655. return(Status);
  2656. }
  2657. NTSTATUS
  2658. SspCreateTokenDacl(
  2659. HANDLE Token
  2660. )
  2661. /*++
  2662. RoutineDescription:
  2663. Creates a new DACL for the token granting the server and client
  2664. all access to the token.
  2665. Arguments:
  2666. Token - Handle to an impersonation token open for TOKEN_QUERY and
  2667. WRITE_DAC
  2668. Return Value:
  2669. STATUS_INSUFFICIENT_RESOURCES - insufficient memory to complete
  2670. the function.
  2671. Errors from NtSetSecurityObject
  2672. --*/
  2673. {
  2674. NTSTATUS Status;
  2675. PTOKEN_USER ThreadTokenUser;
  2676. PTOKEN_USER ImpersonationTokenUser = NULL;
  2677. PTOKEN_USER SlowProcessTokenUser = NULL;
  2678. PTOKEN_USER SlowThreadTokenUser = NULL;
  2679. PTOKEN_USER SlowImpersonationTokenUser = NULL;
  2680. ULONG_PTR FastThreadTokenUser[ 128/sizeof(ULONG_PTR) ];
  2681. ULONG_PTR FastImpersonationTokenUser[ 128/sizeof(ULONG_PTR) ];
  2682. ULONG TokenUserSize;
  2683. HANDLE ProcessToken = NULL;
  2684. HANDLE ImpersonationToken = NULL;
  2685. BOOL fInsertImpersonatingUser = FALSE;
  2686. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  2687. ULONG AclLength;
  2688. PACL NewDacl;
  2689. PACL SlowNewDacl = NULL;
  2690. ULONG_PTR FastNewDacl[ 512/sizeof(ULONG_PTR) ];
  2691. SECURITY_DESCRIPTOR SecurityDescriptor;
  2692. //
  2693. // Build the two well known sids we need.
  2694. //
  2695. if (NtLmGlobalLocalSystemSid == NULL)
  2696. {
  2697. PSID pLocalSidSystem;
  2698. PSID pOldSid;
  2699. Status = RtlAllocateAndInitializeSid(
  2700. &NtAuthority,
  2701. 1,
  2702. SECURITY_LOCAL_SYSTEM_RID,
  2703. 0,0,0,0,0,0,0,
  2704. &pLocalSidSystem
  2705. );
  2706. if (!NT_SUCCESS(Status))
  2707. {
  2708. SspPrint(( SSP_CRITICAL, "SspCreateTokenDacl, RtlAllocateAndInitializeSid returns 0x%lx\n", Status ));
  2709. goto Cleanup;
  2710. }
  2711. pOldSid = InterlockedCompareExchangePointer(
  2712. &NtLmGlobalLocalSystemSid,
  2713. pLocalSidSystem,
  2714. NULL
  2715. );
  2716. if( pOldSid )
  2717. {
  2718. RtlFreeSid( pLocalSidSystem );
  2719. }
  2720. }
  2721. if (NtLmGlobalAliasAdminsSid == NULL)
  2722. {
  2723. PSID pLocalSidAdmins;
  2724. PSID pOldSid;
  2725. Status = RtlAllocateAndInitializeSid(
  2726. &NtAuthority,
  2727. 2,
  2728. SECURITY_BUILTIN_DOMAIN_RID,
  2729. DOMAIN_ALIAS_RID_ADMINS,
  2730. 0,0,0,0,0,0,
  2731. &pLocalSidAdmins
  2732. );
  2733. if (!NT_SUCCESS(Status))
  2734. {
  2735. SspPrint(( SSP_CRITICAL, "SspCreateTokenDacl, RtlAllocateAndInitializeSid returns 0x%lx\n", Status ));
  2736. goto Cleanup;
  2737. }
  2738. pOldSid = InterlockedCompareExchangePointer(
  2739. &NtLmGlobalAliasAdminsSid,
  2740. pLocalSidAdmins,
  2741. NULL
  2742. );
  2743. if( pOldSid )
  2744. {
  2745. RtlFreeSid( pLocalSidAdmins );
  2746. }
  2747. }
  2748. //
  2749. // it's possible that the current thread is impersonating a user.
  2750. // if that's the case, get it's token user, and revert to insure we
  2751. // can open the process token.
  2752. //
  2753. Status = NtOpenThreadToken(
  2754. NtCurrentThread(),
  2755. TOKEN_QUERY | TOKEN_IMPERSONATE,
  2756. TRUE,
  2757. &ImpersonationToken
  2758. );
  2759. if( NT_SUCCESS(Status) )
  2760. {
  2761. //
  2762. // stop impersonating.
  2763. //
  2764. RevertToSelf();
  2765. //
  2766. // get the token user for the impersonating user.
  2767. //
  2768. ImpersonationTokenUser = (PTOKEN_USER)FastImpersonationTokenUser;
  2769. TokenUserSize = sizeof(FastImpersonationTokenUser);
  2770. Status = SspGetTokenUser(
  2771. ImpersonationToken,
  2772. ImpersonationTokenUser,
  2773. &TokenUserSize
  2774. );
  2775. if( Status == STATUS_BUFFER_TOO_SMALL )
  2776. {
  2777. SlowImpersonationTokenUser = (PTOKEN_USER)NtLmAllocate( TokenUserSize );
  2778. if(SlowImpersonationTokenUser == NULL)
  2779. {
  2780. Status = STATUS_INSUFFICIENT_RESOURCES;
  2781. goto Cleanup;
  2782. }
  2783. ImpersonationTokenUser = SlowImpersonationTokenUser;
  2784. Status = SspGetTokenUser(
  2785. ImpersonationToken,
  2786. ImpersonationTokenUser,
  2787. &TokenUserSize
  2788. );
  2789. }
  2790. if (!NT_SUCCESS(Status))
  2791. {
  2792. SspPrint(( SSP_CRITICAL, "SspCreateTokenDacl, SspGetTokenUser returns 0x%lx\n", Status ));
  2793. goto Cleanup;
  2794. }
  2795. }
  2796. if( NtLmGlobalProcessUserSid == NULL )
  2797. {
  2798. PTOKEN_USER ProcessTokenUser;
  2799. ULONG_PTR FastProcessTokenUser[ 128/sizeof(ULONG_PTR) ];
  2800. PSID pOldSid;
  2801. PSID pNewSid;
  2802. ULONG cbNewSid;
  2803. //
  2804. // Open the process token to find out the user sid
  2805. //
  2806. Status = NtOpenProcessToken(
  2807. NtCurrentProcess(),
  2808. TOKEN_QUERY,
  2809. &ProcessToken
  2810. );
  2811. if(!NT_SUCCESS(Status))
  2812. {
  2813. SspPrint(( SSP_CRITICAL, "SspCreateTokenDacl, NtOpenProcessToken returns 0x%lx\n", Status ));
  2814. goto Cleanup;
  2815. }
  2816. //
  2817. // get the token user for the process token.
  2818. //
  2819. ProcessTokenUser = (PTOKEN_USER)FastProcessTokenUser;
  2820. TokenUserSize = sizeof(FastProcessTokenUser);
  2821. Status = SspGetTokenUser(
  2822. ProcessToken,
  2823. ProcessTokenUser,
  2824. &TokenUserSize
  2825. );
  2826. if( Status == STATUS_BUFFER_TOO_SMALL )
  2827. {
  2828. SlowProcessTokenUser = (PTOKEN_USER)NtLmAllocate( TokenUserSize );
  2829. if(SlowProcessTokenUser == NULL)
  2830. {
  2831. Status = STATUS_INSUFFICIENT_RESOURCES;
  2832. goto Cleanup;
  2833. }
  2834. ProcessTokenUser = SlowProcessTokenUser;
  2835. Status = SspGetTokenUser(
  2836. ProcessToken,
  2837. ProcessTokenUser,
  2838. &TokenUserSize
  2839. );
  2840. }
  2841. if (!NT_SUCCESS(Status))
  2842. {
  2843. SspPrint(( SSP_CRITICAL, "SspCreateTokenDacl, SspGetTokenUser returns 0x%lx\n", Status ));
  2844. goto Cleanup;
  2845. }
  2846. cbNewSid = RtlLengthSid( ProcessTokenUser->User.Sid );
  2847. pNewSid = NtLmAllocate( cbNewSid );
  2848. if( pNewSid == NULL )
  2849. {
  2850. Status = STATUS_INSUFFICIENT_RESOURCES;
  2851. goto Cleanup;
  2852. }
  2853. CopyMemory( pNewSid, ProcessTokenUser->User.Sid, cbNewSid );
  2854. pOldSid = InterlockedCompareExchangePointer(
  2855. &NtLmGlobalProcessUserSid,
  2856. pNewSid,
  2857. NULL
  2858. );
  2859. if( pOldSid )
  2860. {
  2861. NtLmFree( pNewSid );
  2862. }
  2863. }
  2864. //
  2865. // Now get the token user for the thread.
  2866. //
  2867. ThreadTokenUser = (PTOKEN_USER)FastThreadTokenUser;
  2868. TokenUserSize = sizeof(FastThreadTokenUser);
  2869. Status = SspGetTokenUser(
  2870. Token,
  2871. ThreadTokenUser,
  2872. &TokenUserSize
  2873. );
  2874. if( Status == STATUS_BUFFER_TOO_SMALL )
  2875. {
  2876. SlowThreadTokenUser = (PTOKEN_USER)NtLmAllocate( TokenUserSize );
  2877. if(SlowThreadTokenUser == NULL)
  2878. {
  2879. Status = STATUS_INSUFFICIENT_RESOURCES;
  2880. goto Cleanup;
  2881. }
  2882. ThreadTokenUser = SlowThreadTokenUser;
  2883. Status = SspGetTokenUser(
  2884. Token,
  2885. ThreadTokenUser,
  2886. &TokenUserSize
  2887. );
  2888. }
  2889. if (!NT_SUCCESS(Status))
  2890. {
  2891. SspPrint(( SSP_CRITICAL, "SspCreateTokenDacl, SspGetTokenUser returns 0x%lx\n", Status ));
  2892. goto Cleanup;
  2893. }
  2894. AclLength = 4 * sizeof( ACCESS_ALLOWED_ACE ) - 4 * sizeof( ULONG ) +
  2895. RtlLengthSid( NtLmGlobalProcessUserSid ) +
  2896. RtlLengthSid( ThreadTokenUser->User.Sid ) +
  2897. RtlLengthSid( NtLmGlobalLocalSystemSid ) +
  2898. RtlLengthSid( NtLmGlobalAliasAdminsSid ) +
  2899. sizeof( ACL );
  2900. //
  2901. // determine if we need to add impersonation token sid onto the token Dacl.
  2902. //
  2903. if( ImpersonationTokenUser &&
  2904. !RtlEqualSid( ImpersonationTokenUser->User.Sid, NtLmGlobalProcessUserSid ) &&
  2905. !RtlEqualSid( ImpersonationTokenUser->User.Sid, ThreadTokenUser->User.Sid )
  2906. )
  2907. {
  2908. AclLength += (sizeof(ACCESS_ALLOWED_ACE) - sizeof( ULONG )) +
  2909. RtlLengthSid( ImpersonationTokenUser->User.Sid );
  2910. fInsertImpersonatingUser = TRUE;
  2911. }
  2912. if( AclLength <= sizeof(FastNewDacl) )
  2913. {
  2914. NewDacl = (PACL)FastNewDacl;
  2915. } else {
  2916. SlowNewDacl = (PACL)NtLmAllocate(AclLength );
  2917. NewDacl = SlowNewDacl;
  2918. if (SlowNewDacl == NULL) {
  2919. Status = STATUS_INSUFFICIENT_RESOURCES;
  2920. SspPrint(( SSP_CRITICAL, "SspCreateTokenDacl, NtLmallocate returns 0x%lx\n", NewDacl));
  2921. goto Cleanup;
  2922. }
  2923. }
  2924. Status = RtlCreateAcl( NewDacl, AclLength, ACL_REVISION2 );
  2925. ASSERT(NT_SUCCESS( Status ));
  2926. Status = RtlAddAccessAllowedAce (
  2927. NewDacl,
  2928. ACL_REVISION2,
  2929. TOKEN_ALL_ACCESS,
  2930. NtLmGlobalProcessUserSid
  2931. );
  2932. ASSERT( NT_SUCCESS( Status ));
  2933. Status = RtlAddAccessAllowedAce (
  2934. NewDacl,
  2935. ACL_REVISION2,
  2936. TOKEN_ALL_ACCESS,
  2937. ThreadTokenUser->User.Sid
  2938. );
  2939. ASSERT( NT_SUCCESS( Status ));
  2940. if( fInsertImpersonatingUser )
  2941. {
  2942. Status = RtlAddAccessAllowedAce (
  2943. NewDacl,
  2944. ACL_REVISION2,
  2945. TOKEN_ALL_ACCESS,
  2946. ImpersonationTokenUser->User.Sid
  2947. );
  2948. ASSERT( NT_SUCCESS( Status ));
  2949. }
  2950. Status = RtlAddAccessAllowedAce (
  2951. NewDacl,
  2952. ACL_REVISION2,
  2953. TOKEN_ALL_ACCESS,
  2954. NtLmGlobalAliasAdminsSid
  2955. );
  2956. ASSERT( NT_SUCCESS( Status ));
  2957. Status = RtlAddAccessAllowedAce (
  2958. NewDacl,
  2959. ACL_REVISION2,
  2960. TOKEN_ALL_ACCESS,
  2961. NtLmGlobalLocalSystemSid
  2962. );
  2963. ASSERT( NT_SUCCESS( Status ));
  2964. Status = RtlCreateSecurityDescriptor (
  2965. &SecurityDescriptor,
  2966. SECURITY_DESCRIPTOR_REVISION
  2967. );
  2968. ASSERT( NT_SUCCESS( Status ));
  2969. Status = RtlSetDaclSecurityDescriptor(
  2970. &SecurityDescriptor,
  2971. TRUE,
  2972. NewDacl,
  2973. FALSE
  2974. );
  2975. ASSERT( NT_SUCCESS( Status ));
  2976. Status = NtSetSecurityObject(
  2977. Token,
  2978. DACL_SECURITY_INFORMATION,
  2979. &SecurityDescriptor
  2980. );
  2981. ASSERT( NT_SUCCESS( Status ));
  2982. Cleanup:
  2983. if (ImpersonationToken != NULL)
  2984. {
  2985. //
  2986. // put the thread token back if we were impersonating.
  2987. //
  2988. SetThreadToken( NULL, ImpersonationToken );
  2989. NtClose(ImpersonationToken);
  2990. }
  2991. if (SlowThreadTokenUser != NULL) {
  2992. NtLmFree( SlowThreadTokenUser );
  2993. }
  2994. if (SlowProcessTokenUser != NULL) {
  2995. NtLmFree( SlowProcessTokenUser );
  2996. }
  2997. if (SlowImpersonationTokenUser != NULL) {
  2998. NtLmFree( SlowImpersonationTokenUser );
  2999. }
  3000. if (SlowNewDacl != NULL) {
  3001. NtLmFree( SlowNewDacl );
  3002. }
  3003. if (ProcessToken != NULL)
  3004. {
  3005. NtClose(ProcessToken);
  3006. }
  3007. return( Status );
  3008. }
  3009. NTSTATUS
  3010. SspMapContext(
  3011. IN PULONG_PTR phContext,
  3012. IN PUCHAR pSessionKey,
  3013. IN ULONG NegotiateFlags,
  3014. IN HANDLE TokenHandle,
  3015. IN PTimeStamp PasswordExpiry OPTIONAL,
  3016. IN ULONG UserFlags,
  3017. OUT PSecBuffer ContextData
  3018. )
  3019. /*++
  3020. RoutineDescription:
  3021. Create a local context for a real context
  3022. Don't link it to out list of local contexts.
  3023. Arguments:
  3024. Return Value:
  3025. --*/
  3026. {
  3027. NTSTATUS Status = STATUS_SUCCESS;
  3028. PNTLM_PACKED_CONTEXT pContext = NULL;
  3029. ULONG cbContextData;
  3030. WCHAR szContextNames[(UNLEN + DNS_MAX_NAME_LENGTH + 2 + 1) *sizeof (WCHAR)];
  3031. PLUID pLogonId = NULL;
  3032. TOKEN_STATISTICS TokenStats;
  3033. PSSP_CONTEXT pTempContext = (PSSP_CONTEXT)*phContext;
  3034. PACTIVE_LOGON pActiveLogon = NULL;
  3035. LPWSTR pszUserName = NULL;
  3036. UINT Length = 0;
  3037. BOOLEAN bActiveLogonsAreLocked = FALSE;
  3038. if (pTempContext == NULL)
  3039. {
  3040. Status = STATUS_INVALID_HANDLE;
  3041. SspPrint(( SSP_CRITICAL, "SspMapContext, pTempContext is 0x%lx\n", pTempContext));
  3042. goto Cleanup;
  3043. }
  3044. if ( pTempContext->Credential != NULL )
  3045. {
  3046. pLogonId = &(pTempContext->Credential->LogonId);
  3047. }
  3048. else
  3049. {
  3050. //
  3051. // if it was a local call where the default creds were used, lookup
  3052. // the username and domain name based on the AuthenticationId of the
  3053. // access token. The local call gets a duplicated access token
  3054. // associated with the original client, so information on this logon
  3055. // should be found in the active logon list.
  3056. //
  3057. if ( NegotiateFlags & NTLMSSP_NEGOTIATE_LOCAL_CALL &&
  3058. pTempContext->UserName.Length == 0 &&
  3059. pTempContext->UserName.Buffer == NULL &&
  3060. pTempContext->DomainName.Length == 0 &&
  3061. pTempContext->DomainName.Buffer == NULL &&
  3062. TokenHandle )
  3063. {
  3064. DWORD TokenInfoLength = sizeof( TokenStats );
  3065. if ( GetTokenInformation(
  3066. TokenHandle,
  3067. TokenStatistics,
  3068. &TokenStats,
  3069. TokenInfoLength,
  3070. &TokenInfoLength
  3071. ))
  3072. {
  3073. pLogonId = &(TokenStats.AuthenticationId);
  3074. }
  3075. }
  3076. }
  3077. if ( pLogonId )
  3078. {
  3079. NlpLockActiveLogonsRead();
  3080. bActiveLogonsAreLocked = TRUE;
  3081. pActiveLogon = NlpFindActiveLogon(pLogonId);
  3082. }
  3083. szContextNames[0] = L'\0';
  3084. if (pActiveLogon != NULL)
  3085. {
  3086. if ((pActiveLogon->UserName.Length > 0) &&
  3087. (pActiveLogon->LogonDomainName.Length > 0))
  3088. {
  3089. RtlCopyMemory(szContextNames,
  3090. pActiveLogon->LogonDomainName.Buffer,
  3091. pActiveLogon->LogonDomainName.Length);
  3092. Length = (pActiveLogon->LogonDomainName.Length)/sizeof(WCHAR);
  3093. szContextNames[Length] = L'\\';
  3094. Length += 1;
  3095. pszUserName = &szContextNames[Length];
  3096. RtlCopyMemory (pszUserName,
  3097. pActiveLogon->UserName.Buffer,
  3098. pActiveLogon->UserName.Length);
  3099. Length += (pActiveLogon->UserName.Length)/sizeof(WCHAR);
  3100. szContextNames[Length] = L'\0';
  3101. }
  3102. }
  3103. else
  3104. {
  3105. // We don't store network logons, but in the case of server side
  3106. // mapping, the client has sent us the Context Names, so use that.
  3107. // Also, handle the case where we don't have domainnames, just usernames
  3108. // Must handle the valid case where both domainname & username are NULL (rdr)
  3109. if ((pTempContext->DomainName.Length > 0) &&
  3110. (pTempContext->UserName.Length > 0))
  3111. {
  3112. RtlCopyMemory(szContextNames,
  3113. pTempContext->DomainName.Buffer,
  3114. pTempContext->DomainName.Length);
  3115. Length = (pTempContext->DomainName.Length)/sizeof(WCHAR);
  3116. szContextNames[Length] = L'\\';
  3117. Length += 1;
  3118. pszUserName = &szContextNames[Length];
  3119. RtlCopyMemory (pszUserName,
  3120. pTempContext->UserName.Buffer,
  3121. pTempContext->UserName.Length);
  3122. Length += (pTempContext->UserName.Length)/sizeof(WCHAR);
  3123. szContextNames[Length] = L'\0';
  3124. }
  3125. else if ((pTempContext->DomainName.Length == 0) &&
  3126. (pTempContext->UserName.Length >0))
  3127. {
  3128. RtlCopyMemory(szContextNames + Length,
  3129. pTempContext->UserName.Buffer,
  3130. pTempContext->UserName.Length);
  3131. Length = (pTempContext->UserName.Length)/sizeof(WCHAR);
  3132. szContextNames[Length] = L'\0';
  3133. }
  3134. }
  3135. Length = (UINT) (wcslen(szContextNames) * sizeof(WCHAR));
  3136. cbContextData =
  3137. sizeof(NTLM_PACKED_CONTEXT) +
  3138. Length +
  3139. sizeof(WCHAR);
  3140. cbContextData += pTempContext->cbMarshalledTargetInfo;
  3141. // the first sizeof (NTLM_CLIENT_CONTEXT) bytes can be
  3142. // casted to pContext anyway.
  3143. pContext = (PNTLM_PACKED_CONTEXT)NtLmAllocateLsaHeap( cbContextData );
  3144. if (!pContext)
  3145. {
  3146. SspPrint((SSP_CRITICAL, "SspMapContext, NtLmAllocate returns NULL\n"));
  3147. Status = STATUS_INSUFFICIENT_RESOURCES;
  3148. goto Cleanup;
  3149. }
  3150. // ZeroMemory( pContext, cbContextData );
  3151. pContext->NegotiateFlags = NegotiateFlags;
  3152. RtlCopyMemory(pContext->SessionKey,
  3153. pSessionKey,
  3154. MSV1_0_USER_SESSION_KEY_LENGTH);
  3155. // Save away the LsaContextHandle
  3156. // pContext->LsaContext = *phContext;
  3157. // dup token if it exists
  3158. pContext->ClientTokenHandle = 0 ;
  3159. if (TokenHandle != NULL)
  3160. {
  3161. HANDLE Tmp ;
  3162. Status = LsaFunctions->DuplicateHandle(
  3163. TokenHandle,
  3164. &Tmp);
  3165. if (!NT_SUCCESS(Status))
  3166. {
  3167. if (pContext)
  3168. {
  3169. NtLmFreeLsaHeap(pContext);
  3170. }
  3171. SspPrint(( SSP_CRITICAL, "SspMapContext, DuplicateHandle returns 0x%lx\n", Status));
  3172. goto Cleanup;
  3173. }
  3174. pContext->ClientTokenHandle = (ULONG) ((ULONG_PTR) Tmp) ;
  3175. }
  3176. if (cbContextData > sizeof(NTLM_PACKED_CONTEXT) )
  3177. {
  3178. pContext->ContextNames = sizeof(NTLM_PACKED_CONTEXT);
  3179. pContext->ContextNameLength = Length;
  3180. RtlCopyMemory(pContext + 1,
  3181. szContextNames,
  3182. pContext->ContextNameLength
  3183. );
  3184. pContext->ContextNameLength += sizeof(WCHAR);
  3185. }
  3186. else
  3187. {
  3188. pContext->ContextNames = 0;
  3189. pContext->ContextNameLength = 0;
  3190. }
  3191. if ( pTempContext->pbMarshalledTargetInfo )
  3192. {
  3193. pContext->MarshalledTargetInfo = (ULONG)pContext->ContextNameLength + sizeof(NTLM_PACKED_CONTEXT) ;
  3194. pContext->MarshalledTargetInfoLength = pTempContext->cbMarshalledTargetInfo;
  3195. RtlCopyMemory( (PBYTE)pContext + pContext->MarshalledTargetInfo,
  3196. pTempContext->pbMarshalledTargetInfo,
  3197. pContext->MarshalledTargetInfoLength
  3198. );
  3199. }
  3200. pContext->SendNonce = 0;
  3201. pContext->RecvNonce = 0;
  3202. ContextData->pvBuffer = pContext;
  3203. ContextData->cbBuffer = cbContextData;
  3204. if (ARGUMENT_PRESENT(PasswordExpiry))
  3205. {
  3206. pContext->PasswordExpiry = *PasswordExpiry;
  3207. }
  3208. else
  3209. {
  3210. pContext->PasswordExpiry.QuadPart = 0;
  3211. }
  3212. pContext->UserFlags = UserFlags;
  3213. Cleanup:
  3214. if (bActiveLogonsAreLocked)
  3215. {
  3216. NlpUnlockActiveLogons();
  3217. }
  3218. return(Status);
  3219. }
  3220. ULONG
  3221. HandleToListIndex(
  3222. ULONG_PTR ContextHandle
  3223. )
  3224. {
  3225. ASSERT( (NTLM_USERLIST_COUNT != 0) );
  3226. ASSERT( (NTLM_USERLIST_COUNT & 1) == 0 );
  3227. ULONG Number ;
  3228. ULONG Hash;
  3229. ULONG HashFinal;
  3230. Number = (ULONG)ContextHandle;
  3231. Hash = Number;
  3232. Hash += Number >> 8;
  3233. Hash += Number >> 16;
  3234. Hash += Number >> 24;
  3235. HashFinal = Hash;
  3236. HashFinal += Hash >> 4;
  3237. //
  3238. // insure power of two if not one.
  3239. //
  3240. return ( HashFinal & (NTLM_USERLIST_COUNT-1) ) ;
  3241. }
  3242. ULONG
  3243. __inline
  3244. ListIndexToLockIndex(
  3245. ULONG ListIndex
  3246. )
  3247. {
  3248. //
  3249. // insure power of two if not one.
  3250. //
  3251. return ( ListIndex & (NtLmUserContextLockCount-1) );
  3252. }