Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4378 lines
118 KiB

  1. //+-----------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (c) Microsoft Corporation 1992 - 1996
  6. //
  7. // File: userapi.cxx
  8. //
  9. // Contents: User-mode APIs to Kerberos package
  10. //
  11. //
  12. // History: 17-April-1996 Created MikeSw
  13. // 26-Sep-1998 ChandanS
  14. // Added more debugging support etc.
  15. //
  16. //------------------------------------------------------------------------
  17. /*
  18. * Copyright 1993 by OpenVision Technologies, Inc.
  19. *
  20. * Permission to use, copy, modify, distribute, and sell this software
  21. * and its documentation for any purpose is hereby granted without fee,
  22. * provided that the above copyright notice appears in all copies and
  23. * that both that copyright notice and this permission notice appear in
  24. * supporting documentation, and that the name of OpenVision not be used
  25. * in advertising or publicity pertaining to distribution of the software
  26. * without specific, written prior permission. OpenVision makes no
  27. * representations about the suitability of this software for any
  28. * purpose. It is provided "as is" without express or implied warranty.
  29. *
  30. * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  31. * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
  32. * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  33. * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
  34. * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
  35. * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  36. * PERFORMANCE OF THIS SOFTWARE.
  37. */
  38. #include <kerb.hxx>
  39. #define USERAPI_ALLOCATE
  40. #include <kerbp.h>
  41. #ifdef RETAIL_LOG_SUPPORT
  42. static TCHAR THIS_FILE[]=TEXT(__FILE__);
  43. #endif
  44. #ifndef WIN32_CHICAGO
  45. extern "C"
  46. {
  47. #include <cryptdll.h>
  48. }
  49. #endif // WIN32_CHICAGO
  50. #include "userapi.h"
  51. #define DONT_SUPPORT_OLD_TYPES_USER 1
  52. // can't sign or seal messages greater than this
  53. #define KERB_MAX_MESSAGE_SIZE 0x40000000
  54. //
  55. // Common GSS object IDs, taken from MIT kerberos distribution.
  56. //
  57. gss_OID_desc oids[] = {
  58. {5, "\053\005\001\005\002"}, // original mech id
  59. {9, "\052\206\110\206\367\022\001\002\002"}, // standard mech id
  60. {10, "\052\206\110\206\367\022\001\002\002\001"}, // krb5_name type
  61. {10, "\052\206\110\206\367\022\001\002\002\002"}, // krb5_principal type
  62. {10, "\052\206\110\206\367\022\001\002\002\003"}, // user2user mech id
  63. {9, "\052\206\110\202\367\022\001\002\002"}, // bogus mangled OID from spnego
  64. };
  65. gss_OID_desc * gss_mech_krb5 = oids;
  66. gss_OID_desc * gss_mech_krb5_new = oids+1;
  67. gss_OID_desc * gss_mech_krb5_u2u = oids+4;
  68. gss_OID_desc * gss_mech_krb5_spnego = oids+5;
  69. #ifndef WIN32_CHICAGO
  70. //+-------------------------------------------------------------------------
  71. //
  72. // Function: SpUserModeInitialize
  73. //
  74. // Synopsis: Returns table of usermode functions to caller
  75. //
  76. // Effects:
  77. //
  78. // Arguments:
  79. //
  80. // Requires:
  81. //
  82. // Returns: SUCCESS if version is correct
  83. //
  84. // Notes:
  85. //
  86. //
  87. //--------------------------------------------------------------------------
  88. NTSTATUS
  89. SEC_ENTRY
  90. SpUserModeInitialize(
  91. IN ULONG LsaVersion,
  92. OUT PULONG PackageVersion,
  93. OUT PSECPKG_USER_FUNCTION_TABLE * UserFunctionTable,
  94. OUT PULONG pcTables)
  95. {
  96. if (LsaVersion != SECPKG_INTERFACE_VERSION)
  97. {
  98. DebugLog((DEB_ERROR,"Invalid LSA version: %d. %ws, line %d\n", LsaVersion, THIS_FILE, __LINE__));
  99. return(STATUS_INVALID_PARAMETER);
  100. }
  101. *PackageVersion = SECPKG_INTERFACE_VERSION ;
  102. KerberosUserFunctionTable.InstanceInit = SpInstanceInit;
  103. KerberosUserFunctionTable.MakeSignature = SpMakeSignature;
  104. KerberosUserFunctionTable.VerifySignature = SpVerifySignature;
  105. KerberosUserFunctionTable.SealMessage = SpSealMessage;
  106. KerberosUserFunctionTable.UnsealMessage = SpUnsealMessage;
  107. KerberosUserFunctionTable.GetContextToken = SpGetContextToken;
  108. KerberosUserFunctionTable.QueryContextAttributes = SpQueryContextAttributes;
  109. KerberosUserFunctionTable.CompleteAuthToken = SpCompleteAuthToken;
  110. KerberosUserFunctionTable.InitUserModeContext = SpInitUserModeContext;
  111. KerberosUserFunctionTable.DeleteUserModeContext = SpDeleteUserModeContext;
  112. KerberosUserFunctionTable.FormatCredentials = SpFormatCredentials;
  113. KerberosUserFunctionTable.MarshallSupplementalCreds = SpMarshallSupplementalCreds;
  114. KerberosUserFunctionTable.ExportContext = SpExportSecurityContext;
  115. KerberosUserFunctionTable.ImportContext = SpImportSecurityContext;
  116. *pcTables = 1;
  117. *UserFunctionTable = &KerberosUserFunctionTable;
  118. return( STATUS_SUCCESS );
  119. }
  120. #endif // WIN32_CHICAGO
  121. //+-------------------------------------------------------------------------
  122. //
  123. // Function: SpInstanceInit
  124. //
  125. // Synopsis: Initialize an instance of the Kerberos package in a client's
  126. // address space
  127. //
  128. // Effects:
  129. //
  130. // Arguments: Version - Version of the security dll loading the package
  131. // FunctionTable - Contains helper routines for use by Kerberos
  132. // UserFunctions - Receives a copy of Kerberos's user mode
  133. // function table
  134. //
  135. // Requires:
  136. //
  137. // Returns: STATUS_SUCCESS
  138. //
  139. // Notes:
  140. //
  141. //
  142. //--------------------------------------------------------------------------
  143. NTSTATUS NTAPI
  144. SpInstanceInit(
  145. IN ULONG Version,
  146. IN PSECPKG_DLL_FUNCTIONS DllFunctionTable,
  147. OUT PVOID * UserFunctionTable
  148. )
  149. {
  150. NTSTATUS Status = STATUS_SUCCESS;
  151. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  152. if (!KerbGlobalInitialized)
  153. {
  154. #ifndef WIN32_CHICAGO
  155. KerbInitializeDebugging();
  156. #endif // WIN32_CHICAGO
  157. KerberosState = KerberosUserMode;
  158. Status = KerbInitContextList();
  159. if (!NT_SUCCESS(Status))
  160. {
  161. DebugLog((DEB_ERROR,"Failed to initialize context list: 0x%x. %ws, line %d\n",
  162. Status, THIS_FILE, __LINE__ ));
  163. goto Cleanup;
  164. }
  165. }
  166. else
  167. {
  168. D_DebugLog((DEB_TRACE,"Re-initializing kerberos from LSA mode to User Mode\n"));
  169. }
  170. UserFunctions = DllFunctionTable;
  171. #ifndef WIN32_CHICAGO
  172. //
  173. // Build the two well known sids we need.
  174. //
  175. if( KerbGlobalLocalSystemSid == NULL )
  176. {
  177. Status = RtlAllocateAndInitializeSid(
  178. &NtAuthority,
  179. 1,
  180. SECURITY_LOCAL_SYSTEM_RID,
  181. 0,0,0,0,0,0,0,
  182. &KerbGlobalLocalSystemSid
  183. );
  184. if (!NT_SUCCESS(Status))
  185. {
  186. goto Cleanup;
  187. }
  188. }
  189. if( KerbGlobalAliasAdminsSid == NULL )
  190. {
  191. Status = RtlAllocateAndInitializeSid(
  192. &NtAuthority,
  193. 2,
  194. SECURITY_BUILTIN_DOMAIN_RID,
  195. DOMAIN_ALIAS_RID_ADMINS,
  196. 0,0,0,0,0,0,
  197. &KerbGlobalAliasAdminsSid
  198. );
  199. if (!NT_SUCCESS(Status))
  200. {
  201. goto Cleanup;
  202. }
  203. }
  204. #endif // WIN32_CHICAGO
  205. KerbGlobalInitialized = TRUE;
  206. Cleanup:
  207. if( !KerbGlobalInitialized && !NT_SUCCESS(Status) )
  208. {
  209. if( KerbGlobalLocalSystemSid != NULL )
  210. {
  211. RtlFreeSid( KerbGlobalLocalSystemSid );
  212. KerbGlobalLocalSystemSid = NULL;
  213. }
  214. if( KerbGlobalAliasAdminsSid != NULL )
  215. {
  216. RtlFreeSid( KerbGlobalAliasAdminsSid );
  217. KerbGlobalAliasAdminsSid = NULL;
  218. }
  219. }
  220. return(Status);
  221. }
  222. //+-------------------------------------------------------------------------
  223. //
  224. // Function: SpDeleteUserModeContext
  225. //
  226. // Synopsis: Deletes a user mode context by unlinking it and then
  227. // dereferencing it.
  228. //
  229. // Effects:
  230. //
  231. // Arguments: ContextHandle - Lsa context handle of the context to delete
  232. //
  233. // Requires:
  234. //
  235. // Returns: STATUS_SUCCESS on success, STATUS_INVALID_HANDLE if the
  236. // context can't be located, SEC_I_NO_LSA_CONTEXT if this was
  237. // created from an exported context
  238. //
  239. // Notes:
  240. //
  241. //
  242. //--------------------------------------------------------------------------
  243. NTSTATUS NTAPI
  244. SpDeleteUserModeContext(
  245. IN LSA_SEC_HANDLE ContextHandle
  246. )
  247. {
  248. NTSTATUS Status = STATUS_SUCCESS;
  249. PKERB_CONTEXT Context = NULL;
  250. D_DebugLog((DEB_TRACE_API,"SpDeleteUserModeContext called\n"));
  251. Status = KerbReferenceContextByLsaHandle(
  252. ContextHandle,
  253. TRUE,
  254. &Context // unlink it
  255. );
  256. if (!NT_SUCCESS(Status))
  257. {
  258. D_DebugLog((DEB_TRACE,"Failed to reference context 0x%x by lsa handle\n",
  259. ContextHandle));
  260. return(STATUS_SUCCESS); // no error code should be returned in this case
  261. }
  262. //
  263. // Make sure we don't try to call the LSA to delete imported contexts
  264. //
  265. KerbReadLockContexts();
  266. if ((Context->ContextAttributes & KERB_CONTEXT_IMPORTED) != 0)
  267. {
  268. Status = SEC_I_NO_LSA_CONTEXT;
  269. }
  270. KerbUnlockContexts();
  271. KerbDereferenceContext(
  272. Context
  273. );
  274. D_DebugLog((DEB_TRACE_API, "SpDeleteUserModeContext returned 0x%x\n", KerbMapKerbNtStatusToNtStatus(Status)));
  275. return(KerbMapKerbNtStatusToNtStatus(Status));
  276. }
  277. //+-------------------------------------------------------------------------
  278. //
  279. // Function: SpInitUserModeContext
  280. //
  281. // Synopsis: Creates a user-mode context from a packed LSA mode context
  282. //
  283. // Effects:
  284. //
  285. // Arguments: ContextHandle - Lsa mode context handle for the context
  286. // PackedContext - A marshalled buffer containing the LSA
  287. // mode context.
  288. //
  289. // Requires:
  290. //
  291. // Returns: STATUS_SUCCESS or STATUS_INSUFFICIENT_RESOURCES
  292. //
  293. // Notes:
  294. //
  295. //
  296. //--------------------------------------------------------------------------
  297. NTSTATUS NTAPI
  298. SpInitUserModeContext(
  299. IN LSA_SEC_HANDLE ContextHandle,
  300. IN PSecBuffer PackedContext
  301. )
  302. {
  303. NTSTATUS Status = STATUS_SUCCESS;
  304. PKERB_CONTEXT Context = NULL;
  305. D_DebugLog((DEB_TRACE_API,"SpInitUserModeContext called\n"));
  306. Status = KerbCreateUserModeContext(
  307. ContextHandle,
  308. PackedContext,
  309. &Context
  310. );
  311. if (!NT_SUCCESS(Status))
  312. {
  313. DebugLog((DEB_ERROR,"Failed to create user mode context: 0x%x. %ws, line %d\n",
  314. Status, THIS_FILE, __LINE__));
  315. goto Cleanup;
  316. }
  317. Cleanup:
  318. if (Context != NULL)
  319. {
  320. KerbDereferenceContext(Context);
  321. }
  322. if (PackedContext->pvBuffer != NULL)
  323. {
  324. FreeContextBuffer(PackedContext->pvBuffer);
  325. PackedContext->pvBuffer = NULL;
  326. }
  327. D_DebugLog((DEB_TRACE_API, "SpInitUserModeContext returned 0x%x\n", KerbMapKerbNtStatusToNtStatus(Status)));
  328. return(KerbMapKerbNtStatusToNtStatus(Status));
  329. }
  330. //+-------------------------------------------------------------------------
  331. //
  332. // Function: SpExportSecurityContext
  333. //
  334. // Synopsis: Exports a security context to another process
  335. //
  336. // Effects: Allocates memory for output
  337. //
  338. // Arguments: ContextHandle - handle to context to export
  339. // Flags - Flags concerning duplication. Allowable flags:
  340. // SECPKG_CONTEXT_EXPORT_DELETE_OLD - causes old context
  341. // to be deleted.
  342. // PackedContext - Receives serialized context to be freed with
  343. // FreeContextBuffer
  344. // TokenHandle - Optionally receives handle to context's token.
  345. //
  346. // Requires:
  347. //
  348. // Returns:
  349. //
  350. // Notes:
  351. //
  352. //
  353. //--------------------------------------------------------------------------
  354. NTSTATUS
  355. SpExportSecurityContext(
  356. IN LSA_SEC_HANDLE ContextHandle,
  357. IN ULONG Flags,
  358. OUT PSecBuffer PackedContext,
  359. OUT PHANDLE TokenHandle
  360. )
  361. {
  362. PKERB_CONTEXT Context = NULL;
  363. NTSTATUS Status = STATUS_SUCCESS;
  364. BOOLEAN MappedContext = FALSE;
  365. D_DebugLog((DEB_TRACE_API,"SpExportContext Called\n"));
  366. D_DebugLog((DEB_TRACE_USER,"Exporting context 0x%p, flags 0x%x\n",ContextHandle, Flags));
  367. //
  368. // We don't support reseting the context
  369. //
  370. if ((Flags & SECPKG_CONTEXT_EXPORT_RESET_NEW) != 0)
  371. {
  372. return(SEC_E_UNSUPPORTED_FUNCTION);
  373. }
  374. if (ARGUMENT_PRESENT(TokenHandle))
  375. {
  376. *TokenHandle = NULL;
  377. }
  378. PackedContext->pvBuffer = NULL;
  379. PackedContext->cbBuffer = 0;
  380. PackedContext->BufferType = 0;
  381. Status = KerbReferenceContextByLsaHandle(
  382. ContextHandle,
  383. FALSE, // don't unlink
  384. &Context
  385. );
  386. if (!NT_SUCCESS(Status))
  387. {
  388. DebugLog((DEB_ERROR, "Invalid handle supplied for ExportSecurityContext(%p) Status = 0x%x. %ws, line %d\n",
  389. ContextHandle, Status, THIS_FILE, __LINE__));
  390. goto Cleanup;
  391. }
  392. Status = KerbMapContext(
  393. Context,
  394. &MappedContext,
  395. PackedContext
  396. );
  397. if (!NT_SUCCESS(Status))
  398. {
  399. goto Cleanup;
  400. }
  401. DsysAssert(MappedContext);
  402. //
  403. // We need to figure out if this was exported
  404. //
  405. ((PKERB_CONTEXT)PackedContext->pvBuffer)->ContextAttributes |= KERB_CONTEXT_EXPORTED;
  406. //
  407. // Now either duplicate the token or copy it.
  408. //
  409. if (ARGUMENT_PRESENT(TokenHandle))
  410. {
  411. KerbWriteLockContexts();
  412. if ((Flags & SECPKG_CONTEXT_EXPORT_DELETE_OLD) != 0)
  413. {
  414. *TokenHandle = Context->TokenHandle;
  415. Context->TokenHandle = NULL;
  416. }
  417. else
  418. {
  419. Status = NtDuplicateObject(
  420. NtCurrentProcess(),
  421. Context->TokenHandle,
  422. NULL,
  423. TokenHandle,
  424. 0, // no new access
  425. 0, // no handle attributes
  426. DUPLICATE_SAME_ACCESS
  427. );
  428. }
  429. KerbUnlockContexts();
  430. if (!NT_SUCCESS(Status))
  431. {
  432. goto Cleanup;
  433. }
  434. }
  435. Cleanup:
  436. if (Context != NULL)
  437. {
  438. KerbDereferenceContext(Context);
  439. }
  440. D_DebugLog((DEB_TRACE_API, "SpExportSecurityContext returned 0x%x\n", KerbMapKerbNtStatusToNtStatus(Status)));
  441. return(KerbMapKerbNtStatusToNtStatus(Status));
  442. }
  443. //+-------------------------------------------------------------------------
  444. //
  445. // Function: SpImportSecurityContext
  446. //
  447. // Synopsis:
  448. //
  449. // Effects:
  450. //
  451. // Arguments:
  452. //
  453. // Requires:
  454. //
  455. // Returns:
  456. //
  457. // Notes:
  458. //
  459. //
  460. //--------------------------------------------------------------------------
  461. NTSTATUS
  462. SpImportSecurityContext(
  463. IN PSecBuffer PackedContext,
  464. IN HANDLE Token,
  465. OUT PLSA_SEC_HANDLE ContextHandle
  466. )
  467. {
  468. NTSTATUS Status = STATUS_SUCCESS;
  469. PKERB_CONTEXT Context = NULL;
  470. D_DebugLog((DEB_TRACE_API,"SpImportSecurityContext called\n"));
  471. Status = KerbCreateUserModeContext(
  472. 0, // no lsa context
  473. PackedContext,
  474. &Context
  475. );
  476. if (!NT_SUCCESS(Status))
  477. {
  478. DebugLog((DEB_ERROR,"Failed to create user mode context: 0x%x. %ws, line %d\n",
  479. Status, THIS_FILE, __LINE__));
  480. goto Cleanup;
  481. }
  482. KerbWriteLockContexts();
  483. Context->TokenHandle = Token;
  484. Context->ContextAttributes |= KERB_CONTEXT_IMPORTED;
  485. *ContextHandle = KerbGetContextHandle(Context);
  486. // Context->LsaContextHandle = *ContextHandle;
  487. KerbUnlockContexts();
  488. Cleanup:
  489. if (Context != NULL)
  490. {
  491. KerbDereferenceContext(Context);
  492. }
  493. D_DebugLog((DEB_TRACE_API, "SpImportSecurityContext returned 0x%x\n", KerbMapKerbNtStatusToNtStatus(Status)));
  494. D_DebugLog((DEB_TRACE_USER," Imported Context handle = 0x%x\n",*ContextHandle));
  495. return(KerbMapKerbNtStatusToNtStatus(Status));
  496. }
  497. //+-------------------------------------------------------------------------
  498. //
  499. // Function: KerbGetChecksumAndEncryptionType
  500. //
  501. // Synopsis: Gets the ChecksumType and the EncryptionType
  502. //
  503. // Effects:
  504. //
  505. // Arguments: Context - Context to use for signing
  506. // QualityOfProtection - flags indicating what kind of checksum
  507. // to use
  508. // ChecksumType - Receives the type of checksum to use
  509. // EncryptionType - Receives the type of encryption to use
  510. //
  511. // Requires: The context must be write locked
  512. //
  513. // Returns:
  514. //
  515. // Notes:
  516. //
  517. //
  518. //--------------------------------------------------------------------------
  519. NTSTATUS
  520. KerbGetChecksumAndEncryptionType(
  521. IN PKERB_CONTEXT Context,
  522. IN ULONG QualityOfProtection,
  523. OUT PULONG ChecksumType,
  524. OUT PULONG EncryptionType
  525. )
  526. {
  527. NTSTATUS Status = STATUS_SUCCESS;
  528. //
  529. // If the keytype is an MS keytype, we need to use an MS encryption
  530. // scheme.
  531. //
  532. if (!KERB_IS_DES_ENCRYPTION(Context->SessionKey.keytype))
  533. {
  534. #ifndef DONT_SUPPORT_OLD_TYPES_USER
  535. if (Context->SessionKey.keytype == KERB_ETYPE_RC4_HMAC_OLD)
  536. {
  537. *ChecksumType = KERB_CHECKSUM_HMAC_MD5;
  538. *EncryptionType = KERB_ETYPE_RC4_PLAIN_OLD;
  539. }
  540. else if (Context->SessionKey.keytype == KERB_ETYPE_RC4_HMAC_OLD_EXP)
  541. {
  542. *ChecksumType = KERB_CHECKSUM_HMAC_MD5;
  543. *EncryptionType = KERB_ETYPE_RC4_PLAIN_OLD_EXP;
  544. }
  545. else
  546. #endif
  547. if (Context->SessionKey.keytype == KERB_ETYPE_RC4_HMAC_NT)
  548. {
  549. *ChecksumType = KERB_CHECKSUM_HMAC_MD5;
  550. *EncryptionType = KERB_ETYPE_RC4_PLAIN;
  551. }
  552. else
  553. {
  554. DsysAssert (Context->SessionKey.keytype == KERB_ETYPE_RC4_HMAC_NT_EXP);
  555. *ChecksumType = KERB_CHECKSUM_HMAC_MD5;
  556. *EncryptionType = KERB_ETYPE_RC4_PLAIN_EXP;
  557. }
  558. }
  559. else
  560. {
  561. //
  562. // Use the exportable version if necessasry
  563. //
  564. *EncryptionType = KERB_ETYPE_DES_PLAIN;
  565. switch(QualityOfProtection)
  566. {
  567. case GSS_KRB5_INTEG_C_QOP_MD5:
  568. *ChecksumType = KERB_CHECKSUM_MD25;
  569. break;
  570. case KERB_WRAP_NO_ENCRYPT:
  571. case GSS_KRB5_INTEG_C_QOP_DEFAULT:
  572. case GSS_KRB5_INTEG_C_QOP_DES_MD5:
  573. *ChecksumType = KERB_CHECKSUM_DES_MAC_MD5;
  574. break;
  575. case GSS_KRB5_INTEG_C_QOP_DES_MAC:
  576. *ChecksumType = KERB_CHECKSUM_DES_MAC;
  577. break;
  578. default:
  579. DebugLog((DEB_ERROR,"Invalid quality of protection sent to MakeSignature: %d. %ws, line %d\n",
  580. QualityOfProtection, THIS_FILE, __LINE__ ));
  581. Status = STATUS_INVALID_PARAMETER;
  582. goto Cleanup;
  583. }
  584. }
  585. Cleanup:
  586. return(Status);
  587. }
  588. //+-------------------------------------------------------------------------
  589. //
  590. // Function: KerbMakeSignatureToken
  591. //
  592. // Synopsis: Makes the signature token for a signed or sealed message
  593. //
  594. // Effects:
  595. //
  596. // Arguments: Context - Context to use for signing
  597. // QualityOfProtection - flags indicating what kind of checksum
  598. // to use
  599. // SignatureBuffer - Buffer in which to place signature
  600. // TotalBufferSize - Total size of all buffers to be signed
  601. // Encrypt - if TRUE, then prepare a header for an encrypted buffer
  602. // SuppliedNonce - Nonce supplied by caller, used for datagram
  603. //
  604. // Requires: The context must be write locked
  605. //
  606. // Returns:
  607. //
  608. // Notes:
  609. //
  610. //
  611. //--------------------------------------------------------------------------
  612. NTSTATUS
  613. KerbMakeSignatureToken(
  614. IN PKERB_CONTEXT Context,
  615. IN ULONG QualityOfProtection,
  616. IN PSecBuffer SignatureBuffer,
  617. IN ULONG TotalBufferSize,
  618. IN BOOLEAN Encrypt,
  619. IN ULONG SuppliedNonce,
  620. OUT PKERB_GSS_SIGNATURE * OutputSignature,
  621. OUT PULONG SequenceNumber
  622. )
  623. {
  624. NTSTATUS Status = STATUS_SUCCESS;
  625. PKERB_GSS_SIGNATURE Signature;
  626. PKERB_GSS_SEAL_SIGNATURE SealSignature;
  627. ULONG MessageSize;
  628. ULONG SignatureSize;
  629. PULONG Nonce;
  630. gss_OID MechUsed;
  631. BOOLEAN GssCompatible = TRUE;
  632. //
  633. // Compute the size of the header. For encryption headers, we need
  634. // to round up the size of the data & add 8 bytes for a confounder.
  635. //
  636. if ((Context->ContextFlags & ISC_RET_USED_DCE_STYLE) != 0 ||
  637. (Context->ContextFlags & ISC_RET_DATAGRAM) != 0)
  638. {
  639. GssCompatible = FALSE;
  640. }
  641. //
  642. // Since RPC doesn't carry around the size of the size of the
  643. // signature bufer, we use it in the header. This break rfc1964 compat.
  644. //
  645. if (!GssCompatible || !Encrypt)
  646. {
  647. TotalBufferSize = 0;
  648. }
  649. if ((Context->ContextAttributes & KERB_CONTEXT_USER_TO_USER) != 0)
  650. {
  651. MechUsed = gss_mech_krb5_u2u;
  652. }
  653. else
  654. {
  655. MechUsed = gss_mech_krb5_new;
  656. }
  657. if (Encrypt)
  658. {
  659. //
  660. // NOTE: according to rfc1964, buffers that are an even multiple of
  661. // 8 bytes have 8 bytes of zeros appended. Because we cannot modify
  662. // the input buffers, the caller will have to do this for us.
  663. //
  664. MessageSize = TotalBufferSize + sizeof(KERB_GSS_SEAL_SIGNATURE);
  665. }
  666. else
  667. {
  668. MessageSize = TotalBufferSize + sizeof(KERB_GSS_SIGNATURE);
  669. }
  670. SignatureSize = g_token_size(MechUsed, MessageSize) - TotalBufferSize;
  671. //
  672. // Make Dave happy (verify that the supplied signature buffer is large
  673. // enough for a signature):
  674. //
  675. if (SignatureBuffer->cbBuffer < SignatureSize)
  676. {
  677. Status = STATUS_BUFFER_TOO_SMALL;
  678. goto Cleanup;
  679. }
  680. //
  681. // create the header with the GSS oid
  682. //
  683. Signature = (PKERB_GSS_SIGNATURE) SignatureBuffer->pvBuffer;
  684. g_make_token_header(
  685. MechUsed,
  686. MessageSize,
  687. (PUCHAR *) &Signature,
  688. (Encrypt ? KG_TOK_WRAP_MSG : KG_TOK_MIC_MSG)
  689. );
  690. //
  691. // Fill in the header information according to RFC1964
  692. //
  693. Signature->SignatureAlgorithm[1] = KERB_GSS_SIG_SECOND;
  694. //
  695. // If the keytype is an MS keytype, we need to use an MS encryption
  696. // scheme.
  697. //
  698. if (!KERB_IS_DES_ENCRYPTION(Context->SessionKey.keytype))
  699. {
  700. #ifndef DONT_SUPPORT_OLD_TYPES_USER
  701. if (Context->SessionKey.keytype == KERB_ETYPE_RC4_HMAC_OLD)
  702. {
  703. Signature->SignatureAlgorithm[0] = KERB_GSS_SIG_HMAC;
  704. if (Encrypt)
  705. {
  706. Signature->SealAlgorithm[1] = KERB_GSS_SIG_SECOND;
  707. Signature->SealAlgorithm[0] = KERB_GSS_SEAL_RC4_OLD;
  708. }
  709. }
  710. else if (Context->SessionKey.keytype == KERB_ETYPE_RC4_HMAC_OLD_EXP)
  711. {
  712. Signature->SignatureAlgorithm[0] = KERB_GSS_SIG_HMAC;
  713. if (Encrypt)
  714. {
  715. Signature->SealAlgorithm[1] = KERB_GSS_SIG_SECOND;
  716. Signature->SealAlgorithm[0] = KERB_GSS_SEAL_RC4_OLD;
  717. }
  718. }
  719. else
  720. #endif
  721. if (Context->SessionKey.keytype == KERB_ETYPE_RC4_HMAC_NT)
  722. {
  723. Signature->SignatureAlgorithm[0] = KERB_GSS_SIG_HMAC;
  724. if (Encrypt)
  725. {
  726. Signature->SealAlgorithm[1] = KERB_GSS_SIG_SECOND;
  727. Signature->SealAlgorithm[0] = KERB_GSS_SEAL_RC4;
  728. }
  729. }
  730. else
  731. {
  732. DsysAssert (Context->SessionKey.keytype == KERB_ETYPE_RC4_HMAC_NT_EXP);
  733. Signature->SignatureAlgorithm[0] = KERB_GSS_SIG_HMAC;
  734. if (Encrypt)
  735. {
  736. Signature->SealAlgorithm[1] = KERB_GSS_SIG_SECOND;
  737. Signature->SealAlgorithm[0] = KERB_GSS_SEAL_RC4;
  738. }
  739. }
  740. //
  741. // if we aren't actually encrypting, reset the encryption alg
  742. //
  743. if (QualityOfProtection == KERB_WRAP_NO_ENCRYPT)
  744. {
  745. if (!Encrypt)
  746. {
  747. DebugLog((DEB_ERROR,"KERB_WRAP_NO_ENCRYPT flag passed to MakeSignature!\n"));
  748. Status = STATUS_INVALID_PARAMETER;
  749. goto Cleanup;
  750. }
  751. //
  752. // In this case use the default, but we will not encrypt
  753. //
  754. Signature->SealAlgorithm[1] = KERB_GSS_NO_SEAL_SECOND;
  755. Signature->SealAlgorithm[0] = KERB_GSS_NO_SEAL;
  756. }
  757. }
  758. else
  759. {
  760. if (Encrypt)
  761. {
  762. Signature->SealAlgorithm[1] = KERB_GSS_SIG_SECOND;
  763. Signature->SealAlgorithm[0] = KERB_GSS_SEAL_DES_CBC;
  764. }
  765. //
  766. // Use the exportable version if necessasry
  767. //
  768. switch(QualityOfProtection)
  769. {
  770. case GSS_KRB5_INTEG_C_QOP_MD5:
  771. Signature->SignatureAlgorithm[0] = KERB_GSS_SIG_MD25;
  772. break;
  773. case KERB_WRAP_NO_ENCRYPT:
  774. if (!Encrypt)
  775. {
  776. DebugLog((DEB_ERROR,"KERB_WRAP_NO_ENCRYPT flag passed to MakeSignature!\n"));
  777. Status = STATUS_INVALID_PARAMETER;
  778. goto Cleanup;
  779. }
  780. //
  781. // In this case use the default, but we will not encrypt
  782. //
  783. Signature->SealAlgorithm[1] = KERB_GSS_NO_SEAL_SECOND;
  784. Signature->SealAlgorithm[0] = KERB_GSS_NO_SEAL;
  785. case GSS_KRB5_INTEG_C_QOP_DEFAULT:
  786. case GSS_KRB5_INTEG_C_QOP_DES_MD5:
  787. Signature->SignatureAlgorithm[0] = KERB_GSS_SIG_DES_MAC_MD5;
  788. break;
  789. case GSS_KRB5_INTEG_C_QOP_DES_MAC:
  790. Signature->SignatureAlgorithm[0] = KERB_GSS_SIG_DES_MAC;
  791. break;
  792. default:
  793. DebugLog((DEB_ERROR,"Invalid quality of protection sent to MakeSignature: %d. %ws, line %d\n",
  794. QualityOfProtection, THIS_FILE, __LINE__ ));
  795. Status = STATUS_INVALID_PARAMETER;
  796. goto Cleanup;
  797. }
  798. }
  799. //
  800. // Put in the filler - it is different for signing & sealing
  801. //
  802. if (Encrypt)
  803. {
  804. memset(Signature->SealFiller,0xff,2);
  805. }
  806. else
  807. {
  808. memset(Signature->SignFiller,0xff,4);
  809. }
  810. //
  811. // Inbound contexts get a high dword of 0xffffffff, outbound gets
  812. // 0x00000000.
  813. //
  814. Nonce = &Context->Nonce;
  815. if (Context->ContextAttributes & KERB_CONTEXT_INBOUND)
  816. {
  817. *(ULONG UNALIGNED *)(&Signature->SequenceNumber[4]) = 0xffffffff;
  818. }
  819. else
  820. {
  821. DsysAssert((Context->ContextAttributes & KERB_CONTEXT_OUTBOUND) != 0);
  822. *(ULONG UNALIGNED *)(&Signature->SequenceNumber[4]) = 0x00000000;
  823. }
  824. //
  825. // If this is datagram, or integrity without replay & sequence detection,
  826. // use the nonce from the caller
  827. //
  828. if (((Context->ContextFlags & ISC_RET_DATAGRAM) != 0) ||
  829. ((Context->ContextFlags & (ISC_RET_INTEGRITY | ISC_RET_SEQUENCE_DETECT | ISC_RET_REPLAY_DETECT)) == ISC_RET_INTEGRITY))
  830. {
  831. Nonce = &SuppliedNonce;
  832. }
  833. if (!KERB_IS_DES_ENCRYPTION(Context->SessionKey.keytype))
  834. {
  835. Signature->SequenceNumber[0] = (UCHAR) ((*Nonce & 0xff000000) >> 24);
  836. Signature->SequenceNumber[1] = (UCHAR) ((*Nonce & 0x00ff0000) >> 16);
  837. Signature->SequenceNumber[2] = (UCHAR) ((*Nonce & 0x0000ff00) >> 8);
  838. Signature->SequenceNumber[3] = (UCHAR) (*Nonce & 0x000000ff);
  839. }
  840. else
  841. {
  842. Signature->SequenceNumber[3] = (UCHAR) ((*Nonce & 0xff000000) >> 24);
  843. Signature->SequenceNumber[2] = (UCHAR) ((*Nonce & 0x00ff0000) >> 16);
  844. Signature->SequenceNumber[1] = (UCHAR) ((*Nonce & 0x0000ff00) >> 8);
  845. Signature->SequenceNumber[0] = (UCHAR) (*Nonce & 0x000000ff);
  846. }
  847. (*Nonce)++;
  848. *SequenceNumber = *(ULONG UNALIGNED *)Signature->SequenceNumber;
  849. D_DebugLog((DEB_TRACE_USER,"Makign signature buffer (encrypt = %d) with nonce 0x%x\n",
  850. Encrypt,
  851. *SequenceNumber
  852. ));
  853. //
  854. // If we are encrypting, add the confounder to the end of the signature
  855. //
  856. if (Encrypt)
  857. {
  858. SealSignature = (PKERB_GSS_SEAL_SIGNATURE) Signature;
  859. KerbRandomFill(
  860. SealSignature->Confounder,
  861. KERB_GSS_SIG_CONFOUNDER_SIZE
  862. );
  863. }
  864. //
  865. // Set the size of the signature
  866. //
  867. SignatureBuffer->cbBuffer = SignatureSize;
  868. *OutputSignature = Signature;
  869. Cleanup:
  870. return(Status);
  871. }
  872. //+-------------------------------------------------------------------------
  873. //
  874. // Function: KerbVerifySignatureToken
  875. //
  876. // Synopsis: Verifies the header on a signed or sealed message
  877. //
  878. // Effects:
  879. //
  880. // Arguments: Context - context to use for verification
  881. // SignatureBuffer - Buffer containing signature
  882. // TotalBufferSize - Size of all buffers signed/encrypted
  883. // Decrypt - TRUE if we are unsealing
  884. // SuppliedNonce - Nonce supplied by caller, used for datagram
  885. // QualityOfProtection - returns GSS quality of protection flags
  886. // ChecksumType - Type of checksum used in this signature
  887. // EncryptionType - Type of encryption used in this signature
  888. //
  889. // Requires:
  890. //
  891. // Returns:
  892. //
  893. // Notes:
  894. //
  895. //
  896. //--------------------------------------------------------------------------
  897. NTSTATUS
  898. KerbVerifySignatureToken(
  899. IN PKERB_CONTEXT Context,
  900. IN PSecBuffer SignatureBuffer,
  901. IN ULONG TotalBufferSize,
  902. IN BOOLEAN Decrypt,
  903. IN ULONG SuppliedNonce,
  904. OUT PKERB_GSS_SIGNATURE * OutputSignature,
  905. OUT PULONG QualityOfProtection,
  906. OUT PULONG ChecksumType,
  907. OUT PCRYPTO_SYSTEM * CryptSystem,
  908. OUT PULONG SequenceNumber
  909. )
  910. {
  911. NTSTATUS Status = STATUS_SUCCESS;
  912. ULONG SignatureSize = 0;
  913. UCHAR Nonce[8];
  914. PCRYPT_STATE_BUFFER CryptBuffer = NULL;
  915. ULONG OutputSize;
  916. ULONG EncryptionType = 0;
  917. PCRYPTO_SYSTEM LocalCryptSystem = NULL ;
  918. PKERB_GSS_SIGNATURE Signature;
  919. PULONG ContextNonce;
  920. gss_OID MechUsed;
  921. //
  922. // Since RPC doesn't carry around the size of the size of the
  923. // signature bufer, we use it in the header. This break rfc1964 compat.
  924. //
  925. if (!Decrypt ||
  926. ((Context->ContextFlags & ISC_RET_USED_DCE_STYLE) != 0) ||
  927. ((Context->ContextFlags & ISC_RET_DATAGRAM) != 0))
  928. {
  929. TotalBufferSize = 0;
  930. }
  931. //
  932. // Verify the signature header
  933. //
  934. if ((Context->ContextAttributes & KERB_CONTEXT_USER_TO_USER) != 0)
  935. {
  936. MechUsed = gss_mech_krb5_u2u;
  937. }
  938. else
  939. {
  940. MechUsed = gss_mech_krb5_new;
  941. }
  942. Signature = (PKERB_GSS_SIGNATURE) SignatureBuffer->pvBuffer;
  943. if (!g_verify_token_header(
  944. MechUsed,
  945. (INT *) &SignatureSize,
  946. (PUCHAR *) &Signature,
  947. (Decrypt ? KG_TOK_WRAP_MSG : KG_TOK_MIC_MSG),
  948. SignatureBuffer->cbBuffer + TotalBufferSize))
  949. {
  950. //Status = SEC_E_MESSAGE_ALTERED; bug 28448
  951. Status = SEC_E_INVALID_TOKEN;
  952. }
  953. //
  954. // If that didn't work, try with the old mech. Need this is for DCE clients
  955. // for whom we can't tell what mech they use.
  956. //
  957. if (!NT_SUCCESS(Status) && ((Context->ContextFlags & ISC_RET_USED_DCE_STYLE) != 0))
  958. {
  959. Signature = (PKERB_GSS_SIGNATURE) SignatureBuffer->pvBuffer;
  960. if (!g_verify_token_header(
  961. gss_mech_krb5,
  962. (INT *) &SignatureSize,
  963. (PUCHAR *) &Signature,
  964. (Decrypt ? KG_TOK_WRAP_MSG : KG_TOK_MIC_MSG),
  965. SignatureBuffer->cbBuffer + TotalBufferSize))
  966. {
  967. //Status = SEC_E_MESSAGE_ALTERED; bug 28448
  968. Status = SEC_E_INVALID_TOKEN;
  969. }
  970. else
  971. {
  972. Status = STATUS_SUCCESS;
  973. }
  974. }
  975. //
  976. // MS RPC clients don't send the size properly, so set the total size
  977. // to zero and try again.
  978. //
  979. if (Decrypt && !NT_SUCCESS(Status))
  980. {
  981. TotalBufferSize = 0;
  982. Signature = (PKERB_GSS_SIGNATURE) SignatureBuffer->pvBuffer;
  983. if (!g_verify_token_header(
  984. MechUsed,
  985. (INT *) &SignatureSize,
  986. (PUCHAR *) &Signature,
  987. (Decrypt ? KG_TOK_WRAP_MSG : KG_TOK_MIC_MSG),
  988. SignatureBuffer->cbBuffer + TotalBufferSize))
  989. {
  990. //Status = SEC_E_MESSAGE_ALTERED; bug 28448
  991. Status = SEC_E_INVALID_TOKEN;
  992. }
  993. else
  994. {
  995. Status = STATUS_SUCCESS;
  996. }
  997. //
  998. // If that didn't work, try with the old mech. Need this is for DCE clients
  999. // for whom we can't tell what mech they use.
  1000. //
  1001. if (!NT_SUCCESS(Status) && ((Context->ContextFlags & ISC_RET_USED_DCE_STYLE) != 0))
  1002. {
  1003. Signature = (PKERB_GSS_SIGNATURE) SignatureBuffer->pvBuffer;
  1004. if (!g_verify_token_header(
  1005. gss_mech_krb5,
  1006. (INT *) &SignatureSize,
  1007. (PUCHAR *) &Signature,
  1008. (Decrypt ? KG_TOK_WRAP_MSG : KG_TOK_MIC_MSG),
  1009. SignatureBuffer->cbBuffer + TotalBufferSize))
  1010. {
  1011. //Status = SEC_E_MESSAGE_ALTERED; bug 28448
  1012. Status = SEC_E_INVALID_TOKEN;
  1013. }
  1014. else
  1015. {
  1016. Status = STATUS_SUCCESS;
  1017. }
  1018. }
  1019. }
  1020. //
  1021. // Protection from bad Signature Size
  1022. //
  1023. if (SignatureSize == 0)
  1024. {
  1025. Status = SEC_E_MESSAGE_ALTERED;
  1026. goto Cleanup;
  1027. }
  1028. //
  1029. // Subtract the total buffer size from Signature size to get the real
  1030. // size of the signature.
  1031. //
  1032. SignatureSize -= TotalBufferSize;
  1033. //
  1034. // Make sure the signature is big enough. We can't enforce a strict
  1035. // size because RPC will transmit the maximum number of bytes instead
  1036. // of the actual number.
  1037. //
  1038. if ((Decrypt && (SignatureSize < sizeof(KERB_GSS_SEAL_SIGNATURE))) ||
  1039. (!Decrypt && (SignatureSize < sizeof(KERB_GSS_SIGNATURE))))
  1040. {
  1041. //Status = SEC_E_MESSAGE_ALTERED; bug 28448
  1042. Status = SEC_E_INVALID_TOKEN;
  1043. goto Cleanup;
  1044. }
  1045. //
  1046. // Verify the sequence number
  1047. //
  1048. if (Signature->SignatureAlgorithm[1] != KERB_GSS_SIG_SECOND)
  1049. {
  1050. Status = SEC_E_MESSAGE_ALTERED;
  1051. goto Cleanup;
  1052. }
  1053. //
  1054. // Figure out the algorithm
  1055. //
  1056. switch(Context->SessionKey.keytype) {
  1057. case KERB_ETYPE_DES_CBC_MD5:
  1058. case KERB_ETYPE_DES_CBC_CRC:
  1059. EncryptionType = KERB_ETYPE_DES_PLAIN;
  1060. break;
  1061. case KERB_ETYPE_RC4_HMAC_OLD_EXP:
  1062. EncryptionType = KERB_ETYPE_RC4_PLAIN_OLD_EXP;
  1063. break;
  1064. case KERB_ETYPE_RC4_HMAC_OLD:
  1065. EncryptionType = KERB_ETYPE_RC4_PLAIN_OLD;
  1066. break;
  1067. case KERB_ETYPE_RC4_HMAC_NT_EXP:
  1068. EncryptionType = KERB_ETYPE_RC4_PLAIN_EXP;
  1069. break;
  1070. case KERB_ETYPE_RC4_HMAC_NT:
  1071. EncryptionType = KERB_ETYPE_RC4_PLAIN;
  1072. break;
  1073. default:
  1074. DebugLog((DEB_ERROR,"Unknown key type: %d. %ws, %d\n",
  1075. Context->SessionKey.keytype,
  1076. THIS_FILE, __LINE__ ));
  1077. Status = STATUS_INTERNAL_ERROR;
  1078. goto Cleanup;
  1079. }
  1080. //
  1081. // if the key is exportable, make sure to use the exportable plain
  1082. // version.
  1083. //
  1084. switch(Signature->SignatureAlgorithm[0]) {
  1085. case KERB_GSS_SIG_MD25:
  1086. *QualityOfProtection = GSS_KRB5_INTEG_C_QOP_MD5;
  1087. *ChecksumType = KERB_CHECKSUM_MD25;
  1088. break;
  1089. case KERB_GSS_SIG_DES_MAC_MD5:
  1090. *QualityOfProtection = GSS_KRB5_INTEG_C_QOP_DES_MD5;
  1091. *ChecksumType = KERB_CHECKSUM_DES_MAC_MD5;
  1092. break;
  1093. case KERB_GSS_SIG_DES_MAC:
  1094. *QualityOfProtection = GSS_KRB5_INTEG_C_QOP_DES_MAC;
  1095. *ChecksumType = KERB_CHECKSUM_DES_MAC;
  1096. break;
  1097. case KERB_GSS_SIG_HMAC:
  1098. *QualityOfProtection = GSS_KRB5_INTEG_C_QOP_DEFAULT;
  1099. *ChecksumType = KERB_CHECKSUM_HMAC_MD5;
  1100. break;
  1101. default:
  1102. DebugLog((DEB_ERROR,"Invalid signature type to VerifySignature: %d. %ws, line %d\n",
  1103. Signature->SignatureAlgorithm[0], THIS_FILE, __LINE__ ));
  1104. Status = SEC_E_MESSAGE_ALTERED;
  1105. goto Cleanup;
  1106. }
  1107. if (Decrypt)
  1108. {
  1109. if ((Signature->SealAlgorithm[1] == KERB_GSS_NO_SEAL_SECOND) &&
  1110. (Signature->SealAlgorithm[0] == KERB_GSS_NO_SEAL))
  1111. {
  1112. *QualityOfProtection = KERB_WRAP_NO_ENCRYPT;
  1113. }
  1114. else
  1115. {
  1116. if (Signature->SealAlgorithm[1] != KERB_GSS_SIG_SECOND)
  1117. {
  1118. Status = SEC_E_MESSAGE_ALTERED;
  1119. goto Cleanup;
  1120. }
  1121. //
  1122. // Verify the seal algorithm
  1123. //
  1124. switch(EncryptionType) {
  1125. case KERB_ETYPE_DES_PLAIN:
  1126. if (Signature->SealAlgorithm[0] != KERB_GSS_SEAL_DES_CBC)
  1127. {
  1128. DebugLog((DEB_ERROR,"Trying to mix encryption types. %ws, line %d\n", THIS_FILE, __LINE__));
  1129. Status = SEC_E_MESSAGE_ALTERED;
  1130. goto Cleanup;
  1131. }
  1132. break;
  1133. case KERB_ETYPE_RC4_PLAIN_OLD_EXP:
  1134. case KERB_ETYPE_RC4_PLAIN_OLD:
  1135. if (Signature->SealAlgorithm[0] != KERB_GSS_SEAL_RC4_OLD)
  1136. {
  1137. DebugLog((DEB_ERROR,"Trying to mix encryption types. %ws, line %d\n", THIS_FILE, __LINE__));
  1138. Status = SEC_E_MESSAGE_ALTERED;
  1139. goto Cleanup;
  1140. }
  1141. break;
  1142. case KERB_ETYPE_RC4_PLAIN_EXP:
  1143. case KERB_ETYPE_RC4_PLAIN:
  1144. if (Signature->SealAlgorithm[0] != KERB_GSS_SEAL_RC4)
  1145. {
  1146. DebugLog((DEB_ERROR,"Trying to mix encryption types. %ws, line %d\n", THIS_FILE, __LINE__));
  1147. Status = SEC_E_MESSAGE_ALTERED;
  1148. goto Cleanup;
  1149. }
  1150. break;
  1151. default:
  1152. DebugLog((DEB_ERROR,"Invalid seal type to VerifySignature: %d, %d. %ws, line %d\n",
  1153. Signature->SealAlgorithm[0], EncryptionType, THIS_FILE, __LINE__ ));
  1154. Status = SEC_E_MESSAGE_ALTERED;
  1155. goto Cleanup;
  1156. }
  1157. }
  1158. }
  1159. //
  1160. // Check the filler
  1161. //
  1162. if ((Decrypt && (*(USHORT UNALIGNED *) Signature->SealFiller != 0xffff)) ||
  1163. (!Decrypt && (*(ULONG UNALIGNED *) Signature->SignFiller != 0xffffffff)))
  1164. {
  1165. Status = SEC_E_MESSAGE_ALTERED;
  1166. goto Cleanup;
  1167. }
  1168. //
  1169. // Verify the sequence number. To do this we need to decrypt it with
  1170. // the session key with the checksum as the IV.
  1171. //
  1172. Status = CDLocateCSystem(EncryptionType, &LocalCryptSystem);
  1173. if (!NT_SUCCESS(Status))
  1174. {
  1175. DebugLog((DEB_ERROR,"Failed to load %d crypt system: 0x%x. %ws, line %d\n",EncryptionType,Status, THIS_FILE, __LINE__));
  1176. goto Cleanup;
  1177. }
  1178. //
  1179. // Now we need to Decrypt the sequence number, using the checksum as the
  1180. // IV
  1181. //
  1182. Status = LocalCryptSystem->Initialize(
  1183. Context->SessionKey.keyvalue.value,
  1184. Context->SessionKey.keyvalue.length,
  1185. 0, // no flags
  1186. &CryptBuffer
  1187. );
  1188. if (!NT_SUCCESS(Status))
  1189. {
  1190. goto Cleanup;
  1191. }
  1192. //
  1193. // Set the initial vector
  1194. //
  1195. Status = LocalCryptSystem->Control(
  1196. CRYPT_CONTROL_SET_INIT_VECT,
  1197. CryptBuffer,
  1198. Signature->Checksum,
  1199. 8
  1200. );
  1201. if (!NT_SUCCESS(Status))
  1202. {
  1203. goto Cleanup;
  1204. }
  1205. //
  1206. // Now encrypt the sequence number
  1207. //
  1208. OutputSize = 8;
  1209. Status = LocalCryptSystem->Decrypt(
  1210. CryptBuffer,
  1211. Signature->SequenceNumber,
  1212. 8,
  1213. Signature->SequenceNumber,
  1214. &OutputSize
  1215. );
  1216. if (!NT_SUCCESS(Status))
  1217. {
  1218. goto Cleanup;
  1219. }
  1220. //
  1221. // For datagram or integrity only, we use just the supplied nonce.
  1222. //
  1223. if (((Context->ContextFlags & ISC_RET_DATAGRAM) != 0) ||
  1224. ((Context->ContextFlags & (ISC_RET_INTEGRITY | ISC_RET_SEQUENCE_DETECT | ISC_RET_REPLAY_DETECT)) == ISC_RET_INTEGRITY))
  1225. {
  1226. ContextNonce = &SuppliedNonce;
  1227. }
  1228. else
  1229. {
  1230. ContextNonce = &Context->ReceiveNonce;
  1231. }
  1232. if (!KERB_IS_DES_ENCRYPTION(Context->SessionKey.keytype))
  1233. {
  1234. Nonce[0] = (UCHAR) ((*ContextNonce & 0xff000000) >> 24);
  1235. Nonce[1] = (UCHAR) ((*ContextNonce & 0x00ff0000) >> 16);
  1236. Nonce[2] = (UCHAR) ((*ContextNonce & 0x0000ff00) >> 8);
  1237. Nonce[3] = (UCHAR) (*ContextNonce & 0x000000ff);
  1238. }
  1239. else
  1240. {
  1241. Nonce[3] = (UCHAR) ((*ContextNonce & 0xff000000) >> 24);
  1242. Nonce[2] = (UCHAR) ((*ContextNonce & 0x00ff0000) >> 16);
  1243. Nonce[1] = (UCHAR) ((*ContextNonce & 0x0000ff00) >> 8);
  1244. Nonce[0] = (UCHAR) (*ContextNonce & 0x000000ff);
  1245. }
  1246. *SequenceNumber = *(ULONG UNALIGNED *) Nonce;
  1247. D_DebugLog((DEB_TRACE_USER,"Verifying signature buffer (decrypt = %d) with nonce 0x%x, message seq 0x%x\n",
  1248. Decrypt,
  1249. *(ULONG UNALIGNED *) Nonce,
  1250. *(ULONG UNALIGNED *) Signature->SequenceNumber
  1251. ));
  1252. if (!RtlEqualMemory(
  1253. Nonce,
  1254. Signature->SequenceNumber,
  1255. 4))
  1256. {
  1257. Status = SEC_E_OUT_OF_SEQUENCE;
  1258. goto Cleanup;
  1259. }
  1260. (*ContextNonce)++;
  1261. //
  1262. // Inbound contexts send a high dword of 0xffffffff, outbound gets
  1263. // 0x00000000.
  1264. //
  1265. if (Context->ContextAttributes & KERB_CONTEXT_OUTBOUND)
  1266. {
  1267. if (*(ULONG UNALIGNED *)(&Signature->SequenceNumber[4]) != 0xffffffff)
  1268. {
  1269. Status = SEC_E_MESSAGE_ALTERED;
  1270. goto Cleanup;
  1271. }
  1272. }
  1273. else
  1274. {
  1275. DsysAssert((Context->ContextAttributes & KERB_CONTEXT_INBOUND) != 0);
  1276. if (*(ULONG UNALIGNED *)(&Signature->SequenceNumber[4]) != 0)
  1277. {
  1278. Status = SEC_E_MESSAGE_ALTERED;
  1279. goto Cleanup;
  1280. }
  1281. }
  1282. if (ARGUMENT_PRESENT(CryptSystem))
  1283. {
  1284. *CryptSystem = LocalCryptSystem;
  1285. }
  1286. *OutputSignature = Signature;
  1287. Cleanup:
  1288. if ( ( CryptBuffer != NULL ) &&
  1289. ( LocalCryptSystem != NULL ) )
  1290. {
  1291. LocalCryptSystem->Discard(&CryptBuffer);
  1292. }
  1293. return(Status);
  1294. }
  1295. #define KERB_MAX_CHECKSUM_LENGTH 24
  1296. #define KERB_MAX_KEY_LENGTH 24
  1297. #define KERB_MAX_BLOCK_LENGTH 24
  1298. //+-------------------------------------------------------------------------
  1299. //
  1300. // Function: SpMakeSignature
  1301. //
  1302. // Synopsis: Signs a message buffer by calculatinga checksum over all
  1303. // the non-read only data buffers and encrypting the checksum
  1304. // along with a nonce.
  1305. //
  1306. // Effects:
  1307. //
  1308. // Arguments: ContextHandle - Handle of the context to use to sign the
  1309. // message.
  1310. // QualityOfProtection - Unused flags.
  1311. // MessageBuffers - Contains an array of buffers to sign and
  1312. // to store the signature.
  1313. // MessageSequenceNumber - Sequence number for this message,
  1314. // only used in datagram cases.
  1315. //
  1316. // Requires: STATUS_INVALID_HANDLE - the context could not be found or
  1317. // was not configured for message integrity.
  1318. // STATUS_INVALID_PARAMETER - the signature buffer could not
  1319. // be found.
  1320. // STATUS_BUFFER_TOO_SMALL - the signature buffer is too small
  1321. // to hold the signature
  1322. //
  1323. // Returns:
  1324. //
  1325. // Notes:
  1326. //
  1327. //
  1328. //--------------------------------------------------------------------------
  1329. NTSTATUS NTAPI
  1330. SpMakeSignature(
  1331. IN LSA_SEC_HANDLE ContextHandle,
  1332. IN ULONG QualityOfProtection,
  1333. IN PSecBufferDesc MessageBuffers,
  1334. IN ULONG MessageSequenceNumber
  1335. )
  1336. {
  1337. NTSTATUS Status = STATUS_SUCCESS;
  1338. PKERB_CONTEXT Context = NULL;
  1339. PCHECKSUM_FUNCTION Check;
  1340. PCRYPTO_SYSTEM CryptSystem = NULL ;
  1341. PSecBuffer SignatureBuffer = NULL;
  1342. ULONG Index;
  1343. PCHECKSUM_BUFFER CheckBuffer = NULL;
  1344. PCRYPT_STATE_BUFFER CryptBuffer = NULL;
  1345. PKERB_GSS_SIGNATURE Signature;
  1346. UCHAR LocalChecksum[KERB_MAX_CHECKSUM_LENGTH];
  1347. BOOLEAN ContextsLocked = FALSE;
  1348. ULONG ChecksumType = 0;
  1349. ULONG EncryptType;
  1350. ULONG TotalBufferSize = 0;
  1351. ULONG OutputSize;
  1352. ULONG SequenceNumber;
  1353. D_DebugLog((DEB_TRACE_API,"SpMakeSignature Called\n"));
  1354. D_DebugLog((DEB_TRACE_USER, "Make Signature handle = 0x%x\n",ContextHandle));
  1355. Status = KerbReferenceContextByLsaHandle(
  1356. ContextHandle,
  1357. FALSE, // don't unlink
  1358. &Context
  1359. );
  1360. if (!NT_SUCCESS(Status))
  1361. {
  1362. DebugLog((DEB_ERROR, "Invalid handle supplied for MakeSignature(0x%x) Status = 0x%x. %ws, line %d\n",
  1363. ContextHandle, Status, THIS_FILE, __LINE__));
  1364. goto Cleanup;
  1365. }
  1366. //
  1367. // Find the body and signature SecBuffers from pMessage
  1368. //
  1369. for (Index = 0; Index < MessageBuffers->cBuffers ; Index++ )
  1370. {
  1371. if (BUFFERTYPE(MessageBuffers->pBuffers[Index]) == SECBUFFER_TOKEN)
  1372. {
  1373. SignatureBuffer = &MessageBuffers->pBuffers[Index];
  1374. }
  1375. else if ((BUFFERTYPE(MessageBuffers->pBuffers[Index]) != SECBUFFER_TOKEN) &&
  1376. (!(MessageBuffers->pBuffers[Index].BufferType & SECBUFFER_READONLY)))
  1377. {
  1378. TotalBufferSize += MessageBuffers->pBuffers[Index].cbBuffer;
  1379. }
  1380. }
  1381. if (SignatureBuffer == NULL)
  1382. {
  1383. DebugLog((DEB_ERROR, "No signature buffer found. %ws, line %d\n", THIS_FILE, __LINE__));
  1384. Status = STATUS_INVALID_PARAMETER;
  1385. goto Cleanup;
  1386. }
  1387. KerbWriteLockContexts();
  1388. ContextsLocked = TRUE;
  1389. //
  1390. // Verify that the context was created with the integrity bit
  1391. //
  1392. if ((Context->ContextFlags & KERB_SIGN_FLAGS) == 0)
  1393. {
  1394. if (SignatureBuffer->cbBuffer < sizeof(KERB_NULL_SIGNATURE))
  1395. {
  1396. Status = SEC_E_BUFFER_TOO_SMALL;
  1397. goto Cleanup;
  1398. }
  1399. SignatureBuffer->cbBuffer = sizeof(KERB_NULL_SIGNATURE);
  1400. *(PKERB_NULL_SIGNATURE) SignatureBuffer->pvBuffer = 0;
  1401. Status = STATUS_SUCCESS;
  1402. goto Cleanup;
  1403. }
  1404. Status = KerbGetChecksumAndEncryptionType(
  1405. Context,
  1406. QualityOfProtection,
  1407. &ChecksumType,
  1408. &EncryptType
  1409. );
  1410. if (!NT_SUCCESS(Status))
  1411. {
  1412. goto Cleanup;
  1413. }
  1414. Status = KerbMakeSignatureToken(
  1415. Context,
  1416. QualityOfProtection,
  1417. SignatureBuffer,
  1418. TotalBufferSize,
  1419. FALSE, // don't encrypt
  1420. MessageSequenceNumber,
  1421. &Signature,
  1422. &SequenceNumber
  1423. );
  1424. if (!NT_SUCCESS(Status))
  1425. {
  1426. goto Cleanup;
  1427. }
  1428. //
  1429. // Locate the checksum for the context, loading it if necessary from the
  1430. // the crypto support DLL
  1431. //
  1432. Status = CDLocateCheckSum(ChecksumType, &Check);
  1433. if (!NT_SUCCESS(Status))
  1434. {
  1435. DebugLog((DEB_ERROR,"Failed to load %d checksum: 0x%x. %ws, line %d\n",ChecksumType,Status, THIS_FILE, __LINE__));
  1436. goto Cleanup;
  1437. }
  1438. DsysAssert(Check->CheckSumSize <= sizeof(LocalChecksum));
  1439. Status = CDLocateCSystem(EncryptType, &CryptSystem);
  1440. if (!NT_SUCCESS(Status))
  1441. {
  1442. DebugLog((DEB_ERROR,"Failed to load %d crypt system: 0x%x. %ws, line %d\n",EncryptType,Status, THIS_FILE, __LINE__));
  1443. goto Cleanup;
  1444. }
  1445. //
  1446. // Generate a check sum of the message, and store it into the signature
  1447. // buffer.
  1448. //
  1449. if (NULL != Check->InitializeEx2)
  1450. {
  1451. Status = Check->InitializeEx2(
  1452. Context->SessionKey.keyvalue.value,
  1453. (ULONG) Context->SessionKey.keyvalue.length,
  1454. NULL,
  1455. KERB_SAFE_SALT,
  1456. &CheckBuffer
  1457. );
  1458. }
  1459. else
  1460. {
  1461. Status = Check->InitializeEx(
  1462. Context->SessionKey.keyvalue.value,
  1463. (ULONG) Context->SessionKey.keyvalue.length,
  1464. KERB_SAFE_SALT,
  1465. &CheckBuffer
  1466. );
  1467. }
  1468. if (!NT_SUCCESS(Status))
  1469. {
  1470. goto Cleanup;
  1471. }
  1472. KerbUnlockContexts();
  1473. ContextsLocked = FALSE;
  1474. //
  1475. // Sum in 8 bytes of the signature
  1476. //
  1477. Check->Sum(
  1478. CheckBuffer,
  1479. 8,
  1480. ((PUCHAR) Signature) -2
  1481. );
  1482. for (Index = 0; Index < MessageBuffers->cBuffers; Index++ )
  1483. {
  1484. if ((BUFFERTYPE(MessageBuffers->pBuffers[Index]) != SECBUFFER_TOKEN) &&
  1485. (!(MessageBuffers->pBuffers[Index].BufferType & SECBUFFER_READONLY)) &&
  1486. (MessageBuffers->pBuffers[Index].cbBuffer != 0))
  1487. {
  1488. Check->Sum(
  1489. CheckBuffer,
  1490. MessageBuffers->pBuffers[Index].cbBuffer,
  1491. (PBYTE) MessageBuffers->pBuffers[Index].pvBuffer
  1492. );
  1493. }
  1494. }
  1495. (void) Check->Finalize(CheckBuffer, LocalChecksum);
  1496. Status = Check->Finish(&CheckBuffer);
  1497. if (!NT_SUCCESS(Status))
  1498. {
  1499. goto Cleanup;
  1500. }
  1501. //
  1502. // Copy in the first 8 bytes of the checksum
  1503. //
  1504. RtlCopyMemory(
  1505. Signature->Checksum,
  1506. LocalChecksum,
  1507. 8
  1508. );
  1509. //
  1510. // Now we need to encrypt the sequence number, using the checksum as the
  1511. // IV
  1512. //
  1513. Status = CryptSystem->Initialize(
  1514. Context->SessionKey.keyvalue.value,
  1515. Context->SessionKey.keyvalue.length,
  1516. 0, // no options
  1517. &CryptBuffer
  1518. );
  1519. if (!NT_SUCCESS(Status))
  1520. {
  1521. goto Cleanup;
  1522. }
  1523. //
  1524. // Set the initial vector
  1525. //
  1526. Status = CryptSystem->Control(
  1527. CRYPT_CONTROL_SET_INIT_VECT,
  1528. CryptBuffer,
  1529. LocalChecksum,
  1530. 8
  1531. );
  1532. if (!NT_SUCCESS(Status))
  1533. {
  1534. goto Cleanup;
  1535. }
  1536. //
  1537. // Now encrypt the sequence number
  1538. //
  1539. Status = CryptSystem->Encrypt(
  1540. CryptBuffer,
  1541. Signature->SequenceNumber,
  1542. 8,
  1543. Signature->SequenceNumber,
  1544. &OutputSize
  1545. );
  1546. if (!NT_SUCCESS(Status))
  1547. {
  1548. goto Cleanup;
  1549. }
  1550. Cleanup:
  1551. if ( ( CryptBuffer != NULL) &&
  1552. ( CryptSystem != NULL ) )
  1553. {
  1554. CryptSystem->Discard(&CryptBuffer);
  1555. }
  1556. if (ContextsLocked)
  1557. {
  1558. KerbUnlockContexts();
  1559. }
  1560. if (Context != NULL)
  1561. {
  1562. KerbDereferenceContext(Context);
  1563. }
  1564. D_DebugLog((DEB_TRACE_API, "SpMakeSignature returned 0x%x\n", KerbMapKerbNtStatusToNtStatus(Status)));
  1565. return(KerbMapKerbNtStatusToNtStatus(Status));
  1566. }
  1567. //+-------------------------------------------------------------------------
  1568. //
  1569. // Function: SpVerifySignature
  1570. //
  1571. // Synopsis: Verifies a signed message buffer by calculating a checksum over all
  1572. // the non-read only data buffers and encrypting the checksum
  1573. // along with a nonce.
  1574. //
  1575. // Effects:
  1576. //
  1577. // Arguments: ContextHandle - Handle of the context to use to sign the
  1578. // message.
  1579. // MessageBuffers - Contains an array of signed buffers and
  1580. // a signature buffer.
  1581. // MessageSequenceNumber - Sequence number for this message,
  1582. // only used in datagram cases.
  1583. // QualityOfProtection - Unused flags.
  1584. //
  1585. // Requires: STATUS_INVALID_HANDLE - the context could not be found or
  1586. // was not configured for message integrity.
  1587. // STATUS_INVALID_PARAMETER - the signature buffer could not
  1588. // be found or was too small.
  1589. //
  1590. // Returns:
  1591. //
  1592. // Notes:
  1593. //
  1594. //
  1595. //--------------------------------------------------------------------------
  1596. NTSTATUS NTAPI
  1597. SpVerifySignature(
  1598. IN LSA_SEC_HANDLE ContextHandle,
  1599. IN PSecBufferDesc MessageBuffers,
  1600. IN ULONG MessageSequenceNumber,
  1601. OUT PULONG QualityOfProtection
  1602. )
  1603. {
  1604. NTSTATUS Status = STATUS_SUCCESS;
  1605. PKERB_CONTEXT Context = NULL;
  1606. PCHECKSUM_FUNCTION Check;
  1607. PSecBuffer SignatureBuffer = NULL;
  1608. ULONG Index;
  1609. PCHECKSUM_BUFFER CheckBuffer = NULL;
  1610. PKERB_GSS_SIGNATURE Signature;
  1611. ULONG ChecksumType;
  1612. BOOLEAN ContextsLocked = FALSE;
  1613. UCHAR LocalChecksum[KERB_MAX_CHECKSUM_LENGTH];
  1614. ULONG Protection;
  1615. ULONG TotalBufferSize = 0;
  1616. ULONG SequenceNumber;
  1617. D_DebugLog((DEB_TRACE_API,"SpVerifySignature Called\n"));
  1618. D_DebugLog((DEB_TRACE_USER, "Verify Signature handle = 0x%x\n",ContextHandle));
  1619. Status = KerbReferenceContextByLsaHandle(
  1620. ContextHandle,
  1621. FALSE, // don't unlink
  1622. &Context
  1623. );
  1624. if (!NT_SUCCESS(Status))
  1625. {
  1626. DebugLog((DEB_ERROR, "Invalid handle supplied for VerifySignature(0x%x) Status = 0x%x. %ws, line %d\n",
  1627. ContextHandle, Status, THIS_FILE, __LINE__));
  1628. goto Cleanup;
  1629. }
  1630. //
  1631. // Find the body and signature SecBuffers from pMessage
  1632. //
  1633. for (Index = 0; Index < MessageBuffers->cBuffers ; Index++ )
  1634. {
  1635. if (BUFFERTYPE(MessageBuffers->pBuffers[Index]) == SECBUFFER_TOKEN)
  1636. {
  1637. SignatureBuffer = &MessageBuffers->pBuffers[Index];
  1638. }
  1639. else if ((BUFFERTYPE(MessageBuffers->pBuffers[Index]) != SECBUFFER_TOKEN) &&
  1640. (!(MessageBuffers->pBuffers[Index].BufferType & SECBUFFER_READONLY)))
  1641. {
  1642. TotalBufferSize += MessageBuffers->pBuffers[Index].cbBuffer;
  1643. }
  1644. }
  1645. if (SignatureBuffer == NULL)
  1646. {
  1647. DebugLog((DEB_ERROR, "No signature buffer found. %ws, line %d\n", THIS_FILE, __LINE__));
  1648. Status = STATUS_INVALID_PARAMETER;
  1649. goto Cleanup;
  1650. }
  1651. KerbWriteLockContexts();
  1652. ContextsLocked = TRUE;
  1653. //
  1654. // Also, verify that the context was created with the integrity bit
  1655. //
  1656. if ((Context->ContextFlags & KERB_SIGN_FLAGS) == 0)
  1657. {
  1658. PKERB_NULL_SIGNATURE NullSignature = (PKERB_NULL_SIGNATURE) SignatureBuffer->pvBuffer;
  1659. if (SignatureBuffer->cbBuffer >= sizeof(KERB_NULL_SIGNATURE) &&
  1660. (*NullSignature == 0))
  1661. {
  1662. Status = STATUS_SUCCESS;
  1663. }
  1664. else
  1665. {
  1666. Status = SEC_E_MESSAGE_ALTERED;
  1667. }
  1668. goto Cleanup;
  1669. }
  1670. //
  1671. // Verify the signature header
  1672. //
  1673. Status = KerbVerifySignatureToken(
  1674. Context,
  1675. SignatureBuffer,
  1676. TotalBufferSize,
  1677. FALSE, // don't decrypt
  1678. MessageSequenceNumber,
  1679. &Signature,
  1680. &Protection,
  1681. &ChecksumType,
  1682. NULL, // don't need crypt system
  1683. &SequenceNumber
  1684. );
  1685. if (!NT_SUCCESS(Status))
  1686. {
  1687. DebugLog((DEB_ERROR, "Failed to verify signature token: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  1688. goto Cleanup;
  1689. }
  1690. //
  1691. // Now compute the checksum and verify it
  1692. //
  1693. Status = CDLocateCheckSum(ChecksumType, &Check);
  1694. if (!NT_SUCCESS(Status))
  1695. {
  1696. DebugLog((DEB_ERROR,"Failed to load MD5 checksum: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  1697. goto Cleanup;
  1698. }
  1699. DsysAssert(Check->CheckSumSize <= sizeof(LocalChecksum));
  1700. //
  1701. // Generate a check sum of the message, and store it into the signature
  1702. // buffer.
  1703. //
  1704. //
  1705. // if available use the Ex2 version for keyed checksums where checksum
  1706. // must be passed in on verification
  1707. //
  1708. if (NULL != Check->InitializeEx2)
  1709. {
  1710. Status = Check->InitializeEx2(
  1711. Context->SessionKey.keyvalue.value,
  1712. (ULONG) Context->SessionKey.keyvalue.length,
  1713. Signature->Checksum,
  1714. KERB_SAFE_SALT,
  1715. &CheckBuffer
  1716. );
  1717. }
  1718. else
  1719. {
  1720. Status = Check->InitializeEx(
  1721. Context->SessionKey.keyvalue.value,
  1722. (ULONG) Context->SessionKey.keyvalue.length,
  1723. KERB_SAFE_SALT,
  1724. &CheckBuffer
  1725. );
  1726. }
  1727. if (!NT_SUCCESS(Status))
  1728. {
  1729. goto Cleanup;
  1730. }
  1731. KerbUnlockContexts();
  1732. ContextsLocked = FALSE;
  1733. //
  1734. // Sum in 8 bytes of the signature
  1735. //
  1736. Check->Sum(
  1737. CheckBuffer,
  1738. 8,
  1739. ((PUCHAR) Signature) -2
  1740. );
  1741. for (Index = 0; Index < MessageBuffers->cBuffers; Index++ )
  1742. {
  1743. if ((BUFFERTYPE(MessageBuffers->pBuffers[Index]) != SECBUFFER_TOKEN) &&
  1744. (!(MessageBuffers->pBuffers[Index].BufferType & SECBUFFER_READONLY)) &&
  1745. (MessageBuffers->pBuffers[Index].cbBuffer != 0))
  1746. {
  1747. Check->Sum(
  1748. CheckBuffer,
  1749. MessageBuffers->pBuffers[Index].cbBuffer,
  1750. (PBYTE) MessageBuffers->pBuffers[Index].pvBuffer
  1751. );
  1752. }
  1753. }
  1754. (void) Check->Finalize(CheckBuffer, LocalChecksum);
  1755. Status = Check->Finish(&CheckBuffer);
  1756. if (!NT_SUCCESS(Status))
  1757. {
  1758. goto Cleanup;
  1759. }
  1760. if (!RtlEqualMemory(
  1761. LocalChecksum,
  1762. Signature->Checksum,
  1763. 8))
  1764. {
  1765. Status = SEC_E_MESSAGE_ALTERED;
  1766. goto Cleanup;
  1767. }
  1768. if (ARGUMENT_PRESENT(QualityOfProtection))
  1769. {
  1770. *QualityOfProtection = Protection;
  1771. }
  1772. Cleanup:
  1773. if (ContextsLocked)
  1774. {
  1775. KerbUnlockContexts();
  1776. }
  1777. if (Context != NULL)
  1778. {
  1779. KerbDereferenceContext(Context);
  1780. }
  1781. D_DebugLog((DEB_TRACE_API, "SpVerifySignature returned 0x%x\n", KerbMapKerbNtStatusToNtStatus(Status)));
  1782. return(KerbMapKerbNtStatusToNtStatus(Status));
  1783. }
  1784. #define STREAM_CIPHER_BLOCKLEN 1
  1785. //+-------------------------------------------------------------------------
  1786. //
  1787. // Function: SpSealMessage
  1788. //
  1789. // Synopsis: Seals a message buffer by calculating a checksum over all
  1790. // the non-read only data buffers and encrypting the data, checksum
  1791. // and a sequence number.
  1792. //
  1793. // Effects:
  1794. //
  1795. // Arguments: ContextHandle - Handle of the context to use to sign the
  1796. // message.
  1797. // QualityOfProtection - Unused flags.
  1798. // MessageBuffers - Contains an array of buffers to sign and
  1799. // to store the signature.
  1800. // MessageSequenceNumber - Sequence number for this message,
  1801. // only used in datagram cases.
  1802. //
  1803. // Requires: STATUS_INVALID_HANDLE - the context could not be found or
  1804. // was not configured for message integrity.
  1805. // STATUS_INVALID_PARAMETER - the signature buffer could not
  1806. // be found.
  1807. // STATUS_BUFFER_TOO_SMALL - the signature buffer is too small
  1808. // to hold the signature
  1809. //
  1810. // Returns:
  1811. //
  1812. // Notes:
  1813. //
  1814. //
  1815. //--------------------------------------------------------------------------
  1816. NTSTATUS NTAPI
  1817. SpSealMessage(
  1818. IN LSA_SEC_HANDLE ContextHandle,
  1819. IN ULONG QualityOfProtection,
  1820. IN PSecBufferDesc MessageBuffers,
  1821. IN ULONG MessageSequenceNumber
  1822. )
  1823. {
  1824. NTSTATUS Status = STATUS_SUCCESS;
  1825. PKERB_CONTEXT Context = NULL;
  1826. PCHECKSUM_FUNCTION Check = NULL ;
  1827. PCRYPTO_SYSTEM CryptSystem = NULL ;
  1828. PSecBuffer SignatureBuffer = NULL;
  1829. ULONG Index;
  1830. PCHECKSUM_BUFFER CheckBuffer = NULL;
  1831. PCRYPT_STATE_BUFFER CryptBuffer = NULL;
  1832. PKERB_GSS_SEAL_SIGNATURE SealSignature;
  1833. UCHAR LocalChecksum[KERB_MAX_CHECKSUM_LENGTH];
  1834. UCHAR LocalKey[KERB_MAX_KEY_LENGTH];
  1835. UCHAR LocalBlockBuffer[KERB_MAX_BLOCK_LENGTH];
  1836. ULONG BeginBlockSize = 0;
  1837. PBYTE BeginBlockPointer = NULL;
  1838. ULONG EndBlockSize = 0;
  1839. ULONG EncryptBufferSize;
  1840. PBYTE EncryptBuffer;
  1841. BOOLEAN ContextsLocked = FALSE;
  1842. BOOLEAN DoEncryption = TRUE;
  1843. ULONG BlockSize = 1;
  1844. ULONG ChecksumType = 0;
  1845. ULONG EncryptType;
  1846. ULONG TotalBufferSize = 0;
  1847. ULONG OutputSize;
  1848. ULONG ContextAttributes;
  1849. ULONG SequenceNumber;
  1850. D_DebugLog((DEB_TRACE_API,"SpSealMessage Called\n"));
  1851. D_DebugLog((DEB_TRACE_USER, "SealMessage handle = 0x%x\n",ContextHandle));
  1852. Status = KerbReferenceContextByLsaHandle(
  1853. ContextHandle,
  1854. FALSE, // don't unlink
  1855. &Context
  1856. );
  1857. if (!NT_SUCCESS(Status))
  1858. {
  1859. DebugLog((DEB_ERROR, "Invalid handle supplied for SpSealMessage(0x%x) Status = 0x%x. %ws, line %d\n",
  1860. ContextHandle, Status, THIS_FILE, __LINE__));
  1861. goto Cleanup;
  1862. }
  1863. //
  1864. // get the encryption type for the context
  1865. //
  1866. Status = KerbGetChecksumAndEncryptionType(
  1867. Context,
  1868. QualityOfProtection,
  1869. &ChecksumType,
  1870. &EncryptType
  1871. );
  1872. if (!NT_SUCCESS(Status))
  1873. {
  1874. goto Cleanup;
  1875. }
  1876. //
  1877. // Locate the cryptsystem for the context, loading it if necessary from the
  1878. // the crypto support DLL
  1879. //
  1880. Status = CDLocateCSystem(EncryptType, &CryptSystem);
  1881. if (!NT_SUCCESS(Status))
  1882. {
  1883. DebugLog((DEB_ERROR,"Failed to load %d crypt system: 0x%x. %ws, line %d\n",EncryptType,Status, THIS_FILE, __LINE__));
  1884. goto Cleanup;
  1885. }
  1886. BlockSize = CryptSystem->BlockSize;
  1887. //
  1888. // Find the body and signature SecBuffers from pMessage
  1889. //
  1890. KerbWriteLockContexts();
  1891. ContextsLocked = TRUE;
  1892. for (Index = 0; Index < MessageBuffers->cBuffers ; Index++ )
  1893. {
  1894. if (BUFFERTYPE(MessageBuffers->pBuffers[Index]) == SECBUFFER_TOKEN)
  1895. {
  1896. SignatureBuffer = &MessageBuffers->pBuffers[Index];
  1897. }
  1898. else if ((BUFFERTYPE(MessageBuffers->pBuffers[Index]) != SECBUFFER_TOKEN) &&
  1899. (!(MessageBuffers->pBuffers[Index].BufferType & SECBUFFER_READONLY)))
  1900. {
  1901. //
  1902. // use real block size from crypt type
  1903. //
  1904. if (BUFFERTYPE(MessageBuffers->pBuffers[Index]) == SECBUFFER_PADDING)
  1905. {
  1906. if (STREAM_CIPHER_BLOCKLEN != BlockSize)
  1907. {
  1908. TotalBufferSize = ROUND_UP_COUNT(TotalBufferSize+1,BlockSize);
  1909. }
  1910. else
  1911. {
  1912. //
  1913. // For stream encryption, only 1 byte of padding
  1914. //
  1915. TotalBufferSize += BlockSize;
  1916. }
  1917. }
  1918. else
  1919. {
  1920. TotalBufferSize += MessageBuffers->pBuffers[Index].cbBuffer;
  1921. }
  1922. }
  1923. }
  1924. if (SignatureBuffer == NULL)
  1925. {
  1926. DebugLog((DEB_ERROR, "No signature buffer found. %ws, line %d\n", THIS_FILE, __LINE__));
  1927. Status = STATUS_INVALID_PARAMETER;
  1928. goto Cleanup;
  1929. }
  1930. ContextAttributes = Context->ContextAttributes;
  1931. //
  1932. // If we are not encrypting, just wrapping, remember that
  1933. //
  1934. if (QualityOfProtection == KERB_WRAP_NO_ENCRYPT)
  1935. {
  1936. DoEncryption = FALSE;
  1937. //
  1938. // Reset the block size because we are not really encrypting
  1939. //
  1940. }
  1941. //
  1942. // Verify that the context was created with the integrity bit
  1943. //
  1944. if (DoEncryption && ((Context->ContextFlags & ISC_RET_CONFIDENTIALITY) == 0))
  1945. {
  1946. DebugLog((DEB_ERROR,"Trying to seal without asking for confidentiality. %ws, line %d\n", THIS_FILE, __LINE__));
  1947. Status = SEC_E_UNSUPPORTED_FUNCTION;
  1948. goto Cleanup;
  1949. }
  1950. Status = KerbMakeSignatureToken(
  1951. Context,
  1952. QualityOfProtection,
  1953. SignatureBuffer,
  1954. TotalBufferSize,
  1955. TRUE, // do encrypt
  1956. MessageSequenceNumber,
  1957. (PKERB_GSS_SIGNATURE *) &SealSignature,
  1958. &SequenceNumber
  1959. );
  1960. if (!NT_SUCCESS(Status))
  1961. {
  1962. goto Cleanup;
  1963. }
  1964. //
  1965. // Locate the checksum for the context, loading it if necessary from the
  1966. // the crypto support DLL
  1967. //
  1968. Status = CDLocateCheckSum(ChecksumType, &Check);
  1969. if (!NT_SUCCESS(Status))
  1970. {
  1971. DebugLog((DEB_ERROR,"Failed to load %d checksum: 0x%x. %ws, line %d\n",ChecksumType,Status, THIS_FILE, __LINE__));
  1972. goto Cleanup;
  1973. }
  1974. DsysAssert(Check->CheckSumSize <= sizeof(LocalChecksum));
  1975. //
  1976. // Generate a check sum of the message, and store it into the signature
  1977. // buffer.
  1978. //
  1979. Status = Check->InitializeEx(
  1980. Context->SessionKey.keyvalue.value,
  1981. (ULONG) Context->SessionKey.keyvalue.length,
  1982. KERB_PRIV_SALT,
  1983. &CheckBuffer
  1984. );
  1985. if (!NT_SUCCESS(Status))
  1986. {
  1987. goto Cleanup;
  1988. }
  1989. //
  1990. // Now we need to encrypt the sequence number, using the checksum as the
  1991. // IV
  1992. //
  1993. //
  1994. // Create the encryption key by xoring with 0xf0f0f0f0
  1995. //
  1996. DsysAssert(Context->SessionKey.keyvalue.length <= sizeof(LocalKey));
  1997. if (Context->SessionKey.keyvalue.length > sizeof(LocalKey))
  1998. {
  1999. Status = SEC_E_UNSUPPORTED_FUNCTION;
  2000. goto Cleanup;
  2001. }
  2002. for (Index = 0; Index < Context->SessionKey.keyvalue.length ; Index++ )
  2003. {
  2004. LocalKey[Index] = Context->SessionKey.keyvalue.value[Index] ^ 0xf0;
  2005. }
  2006. Status = CryptSystem->Initialize(
  2007. LocalKey,
  2008. Context->SessionKey.keyvalue.length,
  2009. 0, // no options
  2010. &CryptBuffer
  2011. );
  2012. if (!NT_SUCCESS(Status))
  2013. {
  2014. goto Cleanup;
  2015. }
  2016. KerbUnlockContexts();
  2017. ContextsLocked = FALSE;
  2018. //
  2019. // Sum in 8 bytes of the signature
  2020. //
  2021. Check->Sum(
  2022. CheckBuffer,
  2023. 8,
  2024. ((PUCHAR) SealSignature) -2
  2025. );
  2026. //
  2027. // Sum the confounder
  2028. //
  2029. Check->Sum(
  2030. CheckBuffer,
  2031. KERB_GSS_SIG_CONFOUNDER_SIZE,
  2032. SealSignature->Confounder
  2033. );
  2034. if ((EncryptType == KERB_ETYPE_RC4_PLAIN) ||
  2035. (EncryptType == KERB_ETYPE_RC4_PLAIN_EXP))
  2036. {
  2037. Status = CryptSystem->Control(
  2038. CRYPT_CONTROL_SET_INIT_VECT,
  2039. CryptBuffer,
  2040. (PUCHAR) &SequenceNumber,
  2041. sizeof(ULONG)
  2042. );
  2043. if (!NT_SUCCESS(Status))
  2044. {
  2045. goto Cleanup;
  2046. }
  2047. }
  2048. //
  2049. // Encrypt the 8 confounder bytes
  2050. //
  2051. if (DoEncryption)
  2052. {
  2053. Status = CryptSystem->Encrypt(
  2054. CryptBuffer,
  2055. SealSignature->Confounder,
  2056. KERB_GSS_SIG_CONFOUNDER_SIZE,
  2057. SealSignature->Confounder,
  2058. &OutputSize
  2059. );
  2060. if (!NT_SUCCESS(Status))
  2061. {
  2062. goto Cleanup;
  2063. }
  2064. }
  2065. for (Index = 0; Index < MessageBuffers->cBuffers; Index++ )
  2066. {
  2067. if ((BUFFERTYPE(MessageBuffers->pBuffers[Index]) != SECBUFFER_TOKEN) &&
  2068. (!(MessageBuffers->pBuffers[Index].BufferType & SECBUFFER_READONLY)) &&
  2069. (MessageBuffers->pBuffers[Index].cbBuffer != 0))
  2070. {
  2071. //
  2072. // Take into account that the input buffers may not all be aligned
  2073. // properly
  2074. //
  2075. DsysAssert(BeginBlockSize < BlockSize);
  2076. if (BeginBlockSize != 0)
  2077. {
  2078. //
  2079. // We have a fragment we still need to encrypt
  2080. //
  2081. EncryptBuffer = (PBYTE) MessageBuffers->pBuffers[Index].pvBuffer +
  2082. (BlockSize - BeginBlockSize);
  2083. EncryptBufferSize = MessageBuffers->pBuffers[Index].cbBuffer -
  2084. (BlockSize - BeginBlockSize);
  2085. }
  2086. else
  2087. {
  2088. //
  2089. // There is no fragment to encrypt, so try to do the whole
  2090. // buffer
  2091. //
  2092. EncryptBuffer = (PBYTE) MessageBuffers->pBuffers[Index].pvBuffer;
  2093. EncryptBufferSize = MessageBuffers->pBuffers[Index].cbBuffer;
  2094. }
  2095. EndBlockSize = EncryptBufferSize - ROUND_DOWN_COUNT(EncryptBufferSize,BlockSize);
  2096. DsysAssert(EndBlockSize < BlockSize);
  2097. EncryptBufferSize = EncryptBufferSize - EndBlockSize;
  2098. //
  2099. // If this is padding, fill it in with the appropriate data &
  2100. // length
  2101. //
  2102. if (MessageBuffers->pBuffers[Index].BufferType == SECBUFFER_PADDING)
  2103. {
  2104. if (MessageBuffers->pBuffers[Index].cbBuffer < BlockSize)
  2105. {
  2106. DebugLog((DEB_ERROR, "Pad buffer is too small: %d instead of %d. %ws, %d\n",
  2107. MessageBuffers->pBuffers[Index].cbBuffer,
  2108. BlockSize,
  2109. THIS_FILE,
  2110. __LINE__
  2111. ));
  2112. Status = STATUS_INVALID_PARAMETER;
  2113. goto Cleanup;
  2114. }
  2115. memset(
  2116. MessageBuffers->pBuffers[Index].pvBuffer,
  2117. BlockSize - BeginBlockSize,
  2118. BlockSize - BeginBlockSize
  2119. );
  2120. MessageBuffers->pBuffers[Index].cbBuffer = BlockSize - BeginBlockSize;
  2121. //
  2122. // If there is a fragment, we will encrypt the padding with the fragment.
  2123. // Otherwise we will do just a padding buffer.
  2124. //
  2125. if (BeginBlockSize != 0)
  2126. {
  2127. EncryptBufferSize = 0;
  2128. }
  2129. //
  2130. // The padding fixes up the end block.
  2131. //
  2132. EndBlockSize = 0;
  2133. }
  2134. //
  2135. // Checksum the whole buffer. We do this now to get the right amount of
  2136. // padding.
  2137. //
  2138. Check->Sum(
  2139. CheckBuffer,
  2140. MessageBuffers->pBuffers[Index].cbBuffer,
  2141. (PBYTE) MessageBuffers->pBuffers[Index].pvBuffer
  2142. );
  2143. if (BeginBlockSize != 0)
  2144. {
  2145. RtlCopyMemory(
  2146. LocalBlockBuffer+BeginBlockSize,
  2147. MessageBuffers->pBuffers[Index].pvBuffer,
  2148. BlockSize - BeginBlockSize
  2149. );
  2150. if (DoEncryption)
  2151. {
  2152. //
  2153. // Now encrypt the buffer
  2154. //
  2155. Status = CryptSystem->Encrypt(
  2156. CryptBuffer,
  2157. LocalBlockBuffer,
  2158. BlockSize,
  2159. LocalBlockBuffer,
  2160. &OutputSize
  2161. );
  2162. if (!NT_SUCCESS(Status))
  2163. {
  2164. goto Cleanup;
  2165. }
  2166. }
  2167. //
  2168. // Copy the pieces back
  2169. //
  2170. RtlCopyMemory(
  2171. BeginBlockPointer,
  2172. LocalBlockBuffer,
  2173. BeginBlockSize
  2174. );
  2175. RtlCopyMemory(
  2176. MessageBuffers->pBuffers[Index].pvBuffer,
  2177. LocalBlockBuffer + BeginBlockSize,
  2178. BlockSize - BeginBlockSize
  2179. );
  2180. }
  2181. if (DoEncryption && (EncryptBufferSize != 0))
  2182. {
  2183. //
  2184. // Now encrypt the buffer
  2185. //
  2186. Status = CryptSystem->Encrypt(
  2187. CryptBuffer,
  2188. EncryptBuffer,
  2189. EncryptBufferSize,
  2190. EncryptBuffer,
  2191. &OutputSize
  2192. );
  2193. if (!NT_SUCCESS(Status))
  2194. {
  2195. goto Cleanup;
  2196. }
  2197. DsysAssert(OutputSize == EncryptBufferSize);
  2198. }
  2199. //
  2200. // Prepare for the next go-round
  2201. //
  2202. RtlCopyMemory(
  2203. LocalBlockBuffer,
  2204. EncryptBuffer+EncryptBufferSize,
  2205. EndBlockSize
  2206. );
  2207. BeginBlockSize = EndBlockSize;
  2208. BeginBlockPointer = (PBYTE) MessageBuffers->pBuffers[Index].pvBuffer +
  2209. MessageBuffers->pBuffers[Index].cbBuffer -
  2210. EndBlockSize;
  2211. }
  2212. }
  2213. //
  2214. // Make sure there are no left-over bits
  2215. //
  2216. if (BeginBlockSize != 0)
  2217. {
  2218. DebugLog((DEB_ERROR,"Non-aligned buffer size to SealMessage: %d extra bytes\n",
  2219. BeginBlockSize ));
  2220. Status = SEC_E_INVALID_TOKEN;
  2221. goto Cleanup;
  2222. }
  2223. (void) Check->Finalize(CheckBuffer, LocalChecksum);
  2224. Status = Check->Finish(&CheckBuffer);
  2225. if (!NT_SUCCESS(Status))
  2226. {
  2227. goto Cleanup;
  2228. }
  2229. CheckBuffer = NULL;
  2230. //
  2231. // Copy in the first 8 bytes of the checksum
  2232. //
  2233. RtlCopyMemory(
  2234. SealSignature->Signature.Checksum,
  2235. LocalChecksum,
  2236. 8
  2237. );
  2238. //
  2239. // Now we need to encrypt the sequence number, using the checksum as the
  2240. // IV
  2241. //
  2242. CryptSystem->Discard( &CryptBuffer );
  2243. Status = CryptSystem->Initialize(
  2244. Context->SessionKey.keyvalue.value,
  2245. Context->SessionKey.keyvalue.length,
  2246. 0, // no options
  2247. &CryptBuffer
  2248. );
  2249. if (!NT_SUCCESS(Status))
  2250. {
  2251. goto Cleanup;
  2252. }
  2253. //
  2254. // Set the initial vector
  2255. //
  2256. Status = CryptSystem->Control(
  2257. CRYPT_CONTROL_SET_INIT_VECT,
  2258. CryptBuffer,
  2259. LocalChecksum,
  2260. 8
  2261. );
  2262. if (!NT_SUCCESS(Status))
  2263. {
  2264. goto Cleanup;
  2265. }
  2266. //
  2267. // Now encrypt the sequence number
  2268. //
  2269. Status = CryptSystem->Encrypt(
  2270. CryptBuffer,
  2271. SealSignature->Signature.SequenceNumber,
  2272. 8,
  2273. SealSignature->Signature.SequenceNumber,
  2274. &OutputSize
  2275. );
  2276. if (!NT_SUCCESS(Status))
  2277. {
  2278. goto Cleanup;
  2279. }
  2280. Cleanup:
  2281. if ( ( CryptBuffer != NULL ) &&
  2282. ( CryptSystem != NULL ) )
  2283. {
  2284. CryptSystem->Discard(&CryptBuffer);
  2285. }
  2286. if ( ( CheckBuffer != NULL ) &&
  2287. ( Check != NULL ) )
  2288. {
  2289. Check->Finish(&CheckBuffer);
  2290. }
  2291. if (ContextsLocked)
  2292. {
  2293. KerbUnlockContexts();
  2294. }
  2295. if (Context != NULL)
  2296. {
  2297. KerbDereferenceContext(Context);
  2298. }
  2299. D_DebugLog((DEB_TRACE_API, "SpSealMessage returned 0x%x\n", KerbMapKerbNtStatusToNtStatus(Status)));
  2300. return(KerbMapKerbNtStatusToNtStatus(Status));
  2301. }
  2302. //+-------------------------------------------------------------------------
  2303. //
  2304. // Function: KerbGetSealMessageBodySize
  2305. //
  2306. // Synopsis: From a input encrypted message, figures out where the
  2307. // body starts
  2308. //
  2309. // Effects:
  2310. //
  2311. // Arguments:
  2312. //
  2313. // Requires:
  2314. //
  2315. // Returns: 0 on failure, # of bytes of data on success
  2316. //
  2317. // Notes:
  2318. //
  2319. //
  2320. //--------------------------------------------------------------------------
  2321. ULONG
  2322. KerbGetSealMessageBodySize(
  2323. IN OUT PVOID * InputBuffer,
  2324. IN ULONG InputBufferSize
  2325. )
  2326. {
  2327. INT BufferSize = (INT) InputBufferSize;
  2328. PBYTE Buffer = (PBYTE) *InputBuffer;
  2329. INT DerBufferSize;
  2330. INT OidLength;
  2331. if ((BufferSize-=1) < 0)
  2332. return(0);
  2333. if (*(Buffer++) != 0x60)
  2334. return(0);
  2335. if ((DerBufferSize = der_read_length(&Buffer, &BufferSize)) < 0)
  2336. return(0);
  2337. if (DerBufferSize != BufferSize)
  2338. return(0);
  2339. if ((BufferSize-=1) < 0)
  2340. return(0);
  2341. if (*(Buffer++) != 0x06)
  2342. return(0);
  2343. if ((BufferSize-=1) < 0)
  2344. return(0);
  2345. OidLength = *(Buffer++);
  2346. if ((OidLength & 0x7fffffff) != OidLength) /* Overflow??? */
  2347. return(0);
  2348. if ((BufferSize-= (int) OidLength) < 0)
  2349. return(0);
  2350. Buffer+=OidLength;
  2351. if ((BufferSize-=2) < 0)
  2352. return(0);
  2353. Buffer += 2;
  2354. //
  2355. // take off size of header
  2356. //
  2357. if ((BufferSize -= sizeof(KERB_GSS_SEAL_SIGNATURE)) < 0)
  2358. {
  2359. return(0);
  2360. }
  2361. Buffer += sizeof(KERB_GSS_SEAL_SIGNATURE);
  2362. *InputBuffer = Buffer;
  2363. return((ULONG) BufferSize);
  2364. }
  2365. //+-------------------------------------------------------------------------
  2366. //
  2367. // Function: SpUnsealMessage
  2368. //
  2369. // Synopsis: Decrypts & Verifies an encrypted message according to
  2370. // RFC 1964 Unwrap() API description
  2371. //
  2372. // Effects:
  2373. //
  2374. // Arguments: ContextHandle - Handle of the context to use to sign the
  2375. // message.
  2376. // MessageBuffers - Contains an array of signed buffers and
  2377. // a signature buffer.
  2378. // MessageSequenceNumber - Sequence number for this message,
  2379. // only used in datagram cases.
  2380. // QualityOfProtection - Unused flags.
  2381. //
  2382. // Requires: STATUS_INVALID_HANDLE - the context could not be found or
  2383. // was not configured for message integrity.
  2384. // STATUS_INVALID_PARAMETER - the signature buffer could not
  2385. // be found or was too small.
  2386. //
  2387. // Returns:
  2388. //
  2389. // Notes:
  2390. //
  2391. //
  2392. //--------------------------------------------------------------------------
  2393. NTSTATUS NTAPI
  2394. SpUnsealMessage(
  2395. IN LSA_SEC_HANDLE ContextHandle,
  2396. IN PSecBufferDesc MessageBuffers,
  2397. IN ULONG MessageSequenceNumber,
  2398. OUT PULONG QualityOfProtection
  2399. )
  2400. {
  2401. NTSTATUS Status = STATUS_SUCCESS;
  2402. PKERB_CONTEXT Context = NULL;
  2403. PCHECKSUM_FUNCTION Check = NULL ;
  2404. PCRYPTO_SYSTEM CryptSystem = NULL ;
  2405. PSecBuffer SignatureBuffer = NULL;
  2406. PSecBuffer StreamBuffer = NULL;
  2407. SecBuffer LocalSignatureBuffer = {0};
  2408. SecBuffer LocalDataBuffer = {0};
  2409. SecBufferDesc LocalBufferDesc = {0};
  2410. PSecBufferDesc BufferList = NULL;
  2411. ULONG Index;
  2412. PCHECKSUM_BUFFER CheckBuffer = NULL;
  2413. PCRYPT_STATE_BUFFER CryptBuffer = NULL;
  2414. PKERB_GSS_SEAL_SIGNATURE SealSignature;
  2415. ULONG ChecksumType;
  2416. BOOLEAN ContextsLocked = FALSE;
  2417. UCHAR LocalChecksum[KERB_MAX_CHECKSUM_LENGTH];
  2418. UCHAR LocalKey[KERB_MAX_KEY_LENGTH];
  2419. UCHAR LocalBlockBuffer[KERB_MAX_BLOCK_LENGTH];
  2420. ULONG BeginBlockSize = 0;
  2421. PBYTE BeginBlockPointer = NULL;
  2422. ULONG EndBlockSize = 0;
  2423. ULONG EncryptBufferSize;
  2424. PBYTE EncryptBuffer;
  2425. BOOLEAN DoDecryption = TRUE;
  2426. ULONG BlockSize = 1;
  2427. ULONG Protection = 0;
  2428. ULONG TotalBufferSize = 0;
  2429. ULONG OutputSize;
  2430. ULONG ContextAttributes;
  2431. ULONG SequenceNumber;
  2432. D_DebugLog((DEB_TRACE_API,"SpUnsealSignature Called\n"));
  2433. D_DebugLog((DEB_TRACE_USER, "SealMessage handle = 0x%x\n",ContextHandle));
  2434. Status = KerbReferenceContextByLsaHandle(
  2435. ContextHandle,
  2436. FALSE, // don't unlink
  2437. &Context
  2438. );
  2439. if (!NT_SUCCESS(Status))
  2440. {
  2441. DebugLog((DEB_ERROR, "Invalid handle supplied for SpUnsealMessage (0x%x) Status = 0x%x. %ws, line %d\n",
  2442. ContextHandle, Status, THIS_FILE, __LINE__));
  2443. goto Cleanup;
  2444. }
  2445. //
  2446. // Find the body and signature SecBuffers from pMessage
  2447. //
  2448. for (Index = 0; Index < MessageBuffers->cBuffers ; Index++ )
  2449. {
  2450. if (BUFFERTYPE(MessageBuffers->pBuffers[Index]) == SECBUFFER_TOKEN)
  2451. {
  2452. SignatureBuffer = &MessageBuffers->pBuffers[Index];
  2453. }
  2454. else if (BUFFERTYPE(MessageBuffers->pBuffers[Index]) == SECBUFFER_STREAM)
  2455. {
  2456. StreamBuffer = &MessageBuffers->pBuffers[Index];
  2457. //
  2458. // The total buffer size is everything in the stream buffer
  2459. //
  2460. TotalBufferSize = MessageBuffers->pBuffers[Index].cbBuffer;
  2461. }
  2462. else if ((MessageBuffers->pBuffers[Index].BufferType & SECBUFFER_READONLY) == 0)
  2463. {
  2464. TotalBufferSize += MessageBuffers->pBuffers[Index].cbBuffer;
  2465. }
  2466. }
  2467. //
  2468. // Check for a stream buffer. If it is present, it contains the whole
  2469. // message
  2470. //
  2471. if (StreamBuffer != NULL)
  2472. {
  2473. if (SignatureBuffer != NULL)
  2474. {
  2475. DebugLog((DEB_ERROR,"Both stream and signature buffer present. %ws, line %d\n",THIS_FILE, __LINE__));
  2476. Status = STATUS_INVALID_PARAMETER;
  2477. goto Cleanup;
  2478. }
  2479. //
  2480. // Parse the stream to distinguish the header from the body
  2481. //
  2482. LocalSignatureBuffer = *StreamBuffer;
  2483. LocalSignatureBuffer.BufferType = SECBUFFER_TOKEN;
  2484. LocalDataBuffer = *StreamBuffer;
  2485. LocalDataBuffer.BufferType = SECBUFFER_DATA;
  2486. LocalDataBuffer.cbBuffer = KerbGetSealMessageBodySize(
  2487. &LocalDataBuffer.pvBuffer,
  2488. LocalDataBuffer.cbBuffer
  2489. );
  2490. if (LocalDataBuffer.cbBuffer == 0)
  2491. {
  2492. DebugLog((DEB_ERROR,"Failed to find header on stream buffer. %ws %d\n",
  2493. THIS_FILE,__LINE__ ));
  2494. Status = STATUS_INVALID_PARAMETER;
  2495. goto Cleanup;
  2496. }
  2497. LocalSignatureBuffer.cbBuffer = StreamBuffer->cbBuffer - LocalDataBuffer.cbBuffer;
  2498. SignatureBuffer = &LocalSignatureBuffer;
  2499. LocalBufferDesc.cBuffers = 1;
  2500. LocalBufferDesc.pBuffers = &LocalDataBuffer;
  2501. BufferList = &LocalBufferDesc;
  2502. //
  2503. // Adjust the total buffer size to remove the signature
  2504. //
  2505. TotalBufferSize -= LocalSignatureBuffer.cbBuffer;
  2506. }
  2507. else if (SignatureBuffer == NULL)
  2508. {
  2509. DebugLog((DEB_ERROR, "No signature buffer found. %ws, line %d\n", THIS_FILE, __LINE__));
  2510. Status = STATUS_INVALID_PARAMETER;
  2511. goto Cleanup;
  2512. }
  2513. else
  2514. {
  2515. BufferList = MessageBuffers;
  2516. }
  2517. KerbWriteLockContexts();
  2518. ContextsLocked = TRUE;
  2519. ContextAttributes = Context->ContextAttributes;
  2520. //
  2521. // Verify the signature header
  2522. //
  2523. Status = KerbVerifySignatureToken(
  2524. Context,
  2525. SignatureBuffer,
  2526. TotalBufferSize,
  2527. TRUE, // do decrypt
  2528. MessageSequenceNumber,
  2529. (PKERB_GSS_SIGNATURE *) &SealSignature,
  2530. &Protection,
  2531. &ChecksumType,
  2532. &CryptSystem,
  2533. &SequenceNumber
  2534. );
  2535. if (!NT_SUCCESS(Status))
  2536. {
  2537. DebugLog((DEB_ERROR, "Failed to verify signature token: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  2538. goto Cleanup;
  2539. }
  2540. //
  2541. // If the protection level is no encryption, remember not to do the
  2542. // decryption
  2543. //
  2544. if (Protection == KERB_WRAP_NO_ENCRYPT)
  2545. {
  2546. DoDecryption = FALSE;
  2547. }
  2548. //
  2549. // Also, verify that the context was created with the Confidentiality bit
  2550. //
  2551. if ((DoDecryption && (Context->ContextFlags & ISC_RET_CONFIDENTIALITY) == 0))
  2552. {
  2553. DebugLog((DEB_ERROR,"Tried to decrypt using non-confidential context. %ws, line %d\n", THIS_FILE, __LINE__));
  2554. Status = SEC_E_UNSUPPORTED_FUNCTION;
  2555. goto Cleanup;
  2556. }
  2557. BlockSize = CryptSystem->BlockSize;
  2558. //
  2559. // Now compute the checksum and verify it
  2560. //
  2561. Status = CDLocateCheckSum(ChecksumType, &Check);
  2562. if (!NT_SUCCESS(Status))
  2563. {
  2564. DebugLog((DEB_ERROR,"Failed to load MD5 checksum: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  2565. goto Cleanup;
  2566. }
  2567. //
  2568. // Create the encryption key by xoring with 0xf0f0f0f0
  2569. //
  2570. DsysAssert(Context->SessionKey.keyvalue.length <= sizeof(LocalKey));
  2571. if (Context->SessionKey.keyvalue.length > sizeof(LocalKey))
  2572. {
  2573. Status = SEC_E_UNSUPPORTED_FUNCTION;
  2574. goto Cleanup;
  2575. }
  2576. //
  2577. // Generate a check sum of the message, and store it into the signature
  2578. // buffer.
  2579. //
  2580. if (NULL != Check->InitializeEx2)
  2581. {
  2582. Status = Check->InitializeEx2(
  2583. Context->SessionKey.keyvalue.value,
  2584. (ULONG) Context->SessionKey.keyvalue.length,
  2585. SealSignature->Signature.Checksum,
  2586. KERB_PRIV_SALT,
  2587. &CheckBuffer
  2588. );
  2589. }
  2590. else
  2591. {
  2592. Status = Check->InitializeEx(
  2593. Context->SessionKey.keyvalue.value,
  2594. (ULONG) Context->SessionKey.keyvalue.length,
  2595. KERB_PRIV_SALT,
  2596. &CheckBuffer
  2597. );
  2598. }
  2599. if (!NT_SUCCESS(Status))
  2600. {
  2601. goto Cleanup;
  2602. }
  2603. for (Index = 0; Index < Context->SessionKey.keyvalue.length ; Index++ )
  2604. {
  2605. LocalKey[Index] = Context->SessionKey.keyvalue.value[Index] ^ 0xf0;
  2606. }
  2607. Status = CryptSystem->Initialize(
  2608. LocalKey,
  2609. Context->SessionKey.keyvalue.length,
  2610. 0, // no options
  2611. &CryptBuffer
  2612. );
  2613. if (!NT_SUCCESS(Status))
  2614. {
  2615. goto Cleanup;
  2616. }
  2617. KerbUnlockContexts();
  2618. ContextsLocked = FALSE;
  2619. //
  2620. // Sum in 8 bytes of the signature
  2621. //
  2622. Check->Sum(
  2623. CheckBuffer,
  2624. 8,
  2625. ((PUCHAR) SealSignature) -2
  2626. );
  2627. //
  2628. // Decrypt the confounder
  2629. //
  2630. if ((CryptSystem->EncryptionType == KERB_ETYPE_RC4_PLAIN) ||
  2631. (CryptSystem->EncryptionType == KERB_ETYPE_RC4_PLAIN_EXP))
  2632. {
  2633. Status = CryptSystem->Control(
  2634. CRYPT_CONTROL_SET_INIT_VECT,
  2635. CryptBuffer,
  2636. (PUCHAR) &SequenceNumber,
  2637. sizeof(ULONG)
  2638. );
  2639. if (!NT_SUCCESS(Status))
  2640. {
  2641. goto Cleanup;
  2642. }
  2643. }
  2644. if (DoDecryption)
  2645. {
  2646. OutputSize = KERB_GSS_SIG_CONFOUNDER_SIZE;
  2647. Status = CryptSystem->Decrypt(
  2648. CryptBuffer,
  2649. SealSignature->Confounder,
  2650. KERB_GSS_SIG_CONFOUNDER_SIZE,
  2651. SealSignature->Confounder,
  2652. &OutputSize
  2653. );
  2654. if (!NT_SUCCESS(Status))
  2655. {
  2656. goto Cleanup;
  2657. }
  2658. }
  2659. //
  2660. // Sum the confounder
  2661. //
  2662. Check->Sum(
  2663. CheckBuffer,
  2664. KERB_GSS_SIG_CONFOUNDER_SIZE,
  2665. SealSignature->Confounder
  2666. );
  2667. for (Index = 0; Index < BufferList->cBuffers; Index++ )
  2668. {
  2669. if ((BUFFERTYPE(BufferList->pBuffers[Index]) != SECBUFFER_TOKEN) &&
  2670. (!(BufferList->pBuffers[Index].BufferType & SECBUFFER_READONLY)) &&
  2671. (BufferList->pBuffers[Index].cbBuffer != 0))
  2672. {
  2673. //
  2674. // Take into account that the input buffers may not all be aligned
  2675. // properly
  2676. //
  2677. //
  2678. // If there is a fragment to decrypt, convert it to a block
  2679. // size fragment
  2680. //
  2681. if (BeginBlockSize != 0)
  2682. {
  2683. EncryptBuffer = (PBYTE) BufferList->pBuffers[Index].pvBuffer +
  2684. (BlockSize - BeginBlockSize);
  2685. EncryptBufferSize = BufferList->pBuffers[Index].cbBuffer -
  2686. (BlockSize - BeginBlockSize);
  2687. }
  2688. else
  2689. {
  2690. EncryptBuffer = (PBYTE) BufferList->pBuffers[Index].pvBuffer;
  2691. EncryptBufferSize = BufferList->pBuffers[Index].cbBuffer;
  2692. }
  2693. EndBlockSize = EncryptBufferSize - ROUND_DOWN_COUNT(EncryptBufferSize,BlockSize);
  2694. DsysAssert(EndBlockSize < BlockSize);
  2695. EncryptBufferSize = EncryptBufferSize - EndBlockSize;
  2696. if (BeginBlockSize != 0)
  2697. {
  2698. RtlCopyMemory(
  2699. LocalBlockBuffer+BeginBlockSize,
  2700. BufferList->pBuffers[Index].pvBuffer,
  2701. BlockSize - BeginBlockSize
  2702. );
  2703. //
  2704. // Now decrpt the buffer
  2705. //
  2706. if (DoDecryption)
  2707. {
  2708. Status = CryptSystem->Decrypt(
  2709. CryptBuffer,
  2710. LocalBlockBuffer,
  2711. BlockSize,
  2712. LocalBlockBuffer,
  2713. &OutputSize
  2714. );
  2715. if (!NT_SUCCESS(Status))
  2716. {
  2717. goto Cleanup;
  2718. }
  2719. }
  2720. //
  2721. // Then checksum the buffer
  2722. //
  2723. Check->Sum(
  2724. CheckBuffer,
  2725. BlockSize,
  2726. LocalBlockBuffer
  2727. );
  2728. //
  2729. // Copy the pieces back
  2730. //
  2731. RtlCopyMemory(
  2732. BeginBlockPointer,
  2733. LocalBlockBuffer,
  2734. BeginBlockSize
  2735. );
  2736. RtlCopyMemory(
  2737. BufferList->pBuffers[Index].pvBuffer,
  2738. LocalBlockBuffer + BeginBlockSize,
  2739. BlockSize - BeginBlockSize
  2740. );
  2741. }
  2742. //
  2743. // Decrypt the buffer first
  2744. //
  2745. if (DoDecryption)
  2746. {
  2747. OutputSize = BufferList->pBuffers[Index].cbBuffer;
  2748. Status = CryptSystem->Decrypt(
  2749. CryptBuffer,
  2750. EncryptBuffer,
  2751. EncryptBufferSize,
  2752. EncryptBuffer,
  2753. &OutputSize
  2754. );
  2755. if (!NT_SUCCESS(Status))
  2756. {
  2757. goto Cleanup;
  2758. }
  2759. DsysAssert(OutputSize == BufferList->pBuffers[Index].cbBuffer);
  2760. }
  2761. //
  2762. // Prepare for the next go-round
  2763. //
  2764. RtlCopyMemory(
  2765. LocalBlockBuffer,
  2766. EncryptBuffer+EncryptBufferSize,
  2767. EndBlockSize
  2768. );
  2769. BeginBlockSize = EndBlockSize;
  2770. BeginBlockPointer = (PBYTE) MessageBuffers->pBuffers[Index].pvBuffer +
  2771. MessageBuffers->pBuffers[Index].cbBuffer -
  2772. EndBlockSize;
  2773. //
  2774. // Then checksum the buffer
  2775. //
  2776. Check->Sum(
  2777. CheckBuffer,
  2778. EncryptBufferSize,
  2779. EncryptBuffer
  2780. );
  2781. }
  2782. }
  2783. (void) Check->Finalize(CheckBuffer, LocalChecksum);
  2784. Status = Check->Finish(&CheckBuffer);
  2785. CheckBuffer = NULL;
  2786. if (!NT_SUCCESS(Status))
  2787. {
  2788. goto Cleanup;
  2789. }
  2790. //
  2791. // Make sure there are no left-over bits
  2792. //
  2793. if (BeginBlockSize != 0)
  2794. {
  2795. DebugLog((DEB_ERROR,"Non-aligned buffer size to SealMessage: %d extra bytes\n",
  2796. BeginBlockSize ));
  2797. Status = SEC_E_INVALID_TOKEN;
  2798. goto Cleanup;
  2799. }
  2800. if (!RtlEqualMemory(
  2801. LocalChecksum,
  2802. SealSignature->Signature.Checksum,
  2803. 8))
  2804. {
  2805. Status = SEC_E_MESSAGE_ALTERED;
  2806. goto Cleanup;
  2807. }
  2808. if (ARGUMENT_PRESENT(QualityOfProtection))
  2809. {
  2810. *QualityOfProtection = Protection;
  2811. }
  2812. //
  2813. // If this was a stream input, return the data in the data buffer
  2814. //
  2815. if (StreamBuffer != NULL)
  2816. {
  2817. BYTE PaddingBytes;
  2818. //
  2819. // Pull the padding off the data buffer
  2820. //
  2821. if (LocalDataBuffer.cbBuffer < 1)
  2822. {
  2823. DebugLog((DEB_ERROR,"Data buffer is zero length!\n"));
  2824. Status = STATUS_INVALID_PARAMETER;
  2825. goto Cleanup;
  2826. }
  2827. PaddingBytes = *(((PBYTE)LocalDataBuffer.pvBuffer) + LocalDataBuffer.cbBuffer - 1 );
  2828. //
  2829. // Verify the padding:
  2830. //
  2831. if ((BlockSize >= PaddingBytes) &&
  2832. (LocalDataBuffer.cbBuffer >= PaddingBytes))
  2833. {
  2834. LocalDataBuffer.cbBuffer -= PaddingBytes;
  2835. for (Index = 0; Index < MessageBuffers->cBuffers; Index++ )
  2836. {
  2837. if (BUFFERTYPE(MessageBuffers->pBuffers[Index]) == SECBUFFER_DATA)
  2838. {
  2839. MessageBuffers->pBuffers[Index] = LocalDataBuffer;
  2840. break;
  2841. }
  2842. }
  2843. }
  2844. else
  2845. {
  2846. DebugLog((DEB_ERROR,"Bad padding: %d bytes\n", PaddingBytes));
  2847. Status = STATUS_INVALID_PARAMETER;
  2848. }
  2849. }
  2850. Cleanup:
  2851. if (ContextsLocked)
  2852. {
  2853. KerbUnlockContexts();
  2854. }
  2855. if (Context != NULL)
  2856. {
  2857. KerbDereferenceContext(Context);
  2858. }
  2859. if ( ( CheckBuffer != NULL ) &&
  2860. ( Check != NULL ) )
  2861. {
  2862. Check->Finish(&CheckBuffer);
  2863. }
  2864. if ( ( CryptBuffer != NULL ) &&
  2865. ( CryptSystem != NULL ) )
  2866. {
  2867. CryptSystem->Discard(&CryptBuffer);
  2868. }
  2869. D_DebugLog((DEB_TRACE_API, "SpUnsealMessage returned 0x%x\n", KerbMapKerbNtStatusToNtStatus(Status)));
  2870. return(KerbMapKerbNtStatusToNtStatus(Status));
  2871. }
  2872. #ifndef WIN32_CHICAGO
  2873. //+-------------------------------------------------------------------------
  2874. //
  2875. // Function: SpGetContextToken
  2876. //
  2877. // Synopsis: returns a pointer to the token for a server-side context
  2878. //
  2879. // Effects:
  2880. //
  2881. // Arguments:
  2882. //
  2883. // Requires:
  2884. //
  2885. // Returns:
  2886. //
  2887. // Notes:
  2888. //
  2889. //
  2890. //--------------------------------------------------------------------------
  2891. NTSTATUS NTAPI
  2892. SpGetContextToken(
  2893. IN LSA_SEC_HANDLE ContextHandle,
  2894. OUT PHANDLE ImpersonationToken
  2895. )
  2896. {
  2897. NTSTATUS Status = STATUS_SUCCESS;
  2898. PKERB_CONTEXT Context = NULL;
  2899. LARGE_INTEGER CurrentTime;
  2900. LARGE_INTEGER ContextExpires;
  2901. D_DebugLog((DEB_TRACE_API,"SpGetContextToken called pid:0x%x, ctxt:0x%x\n", GetCurrentProcessId(), ContextHandle));
  2902. if (ImpersonationToken == NULL)
  2903. {
  2904. Status = STATUS_INVALID_PARAMETER;
  2905. DebugLog((DEB_ERROR, "Null token handle supplied for GetContextToken. %ws, line %d\n", THIS_FILE, __LINE__));
  2906. goto Cleanup;
  2907. }
  2908. Status = KerbReferenceContextByLsaHandle(
  2909. ContextHandle,
  2910. FALSE, // don't unlink
  2911. &Context
  2912. );
  2913. if (!NT_SUCCESS(Status))
  2914. {
  2915. DebugLog((DEB_ERROR, "Invalid handle supplied for GetContextToken(0x%x) Status = 0x%x. %ws, line %d\n",
  2916. ContextHandle, Status, THIS_FILE, __LINE__));
  2917. }
  2918. GetSystemTimeAsFileTime((PFILETIME) &CurrentTime);
  2919. KerbReadLockContexts();
  2920. *ImpersonationToken = Context->TokenHandle;
  2921. ContextExpires = Context->Lifetime;
  2922. KerbUnlockContexts();
  2923. if (KerbGlobalEnforceTime && ContextExpires.QuadPart < CurrentTime.QuadPart)
  2924. {
  2925. DebugLog((DEB_ERROR, "GetContextToken: Context 0x%x expired. %ws, line %d\n", ContextHandle, THIS_FILE, __LINE__));
  2926. Status = SEC_E_CONTEXT_EXPIRED;
  2927. *ImpersonationToken = NULL;
  2928. }
  2929. else if (*ImpersonationToken == NULL)
  2930. {
  2931. Status = SEC_E_NO_IMPERSONATION;
  2932. }
  2933. if (Context != NULL)
  2934. {
  2935. //
  2936. // Note: once we dereference the context the handle we return
  2937. // may go away or be re-used. That is the price we have to pay
  2938. // to avoid duplicating it.
  2939. //
  2940. KerbDereferenceContext(Context);
  2941. }
  2942. Cleanup:
  2943. D_DebugLog((DEB_TRACE_API,"SpGetContextToken returned 0x%x, pid:0x%x, ctxt:0x%x\n", KerbMapKerbNtStatusToNtStatus(Status), GetCurrentProcessId(), ContextHandle));
  2944. return(KerbMapKerbNtStatusToNtStatus(Status));
  2945. }
  2946. #endif // WIN32_CHICAGO
  2947. //+-------------------------------------------------------------------------
  2948. //
  2949. // Function: SpQueryContextAttributes
  2950. //
  2951. // Synopsis: Querys attributes of the specified context
  2952. //
  2953. // Effects:
  2954. //
  2955. // Arguments:
  2956. //
  2957. // Requires:
  2958. //
  2959. // Returns:
  2960. //
  2961. // Notes:
  2962. //
  2963. //
  2964. //--------------------------------------------------------------------------
  2965. NTSTATUS NTAPI
  2966. SpQueryContextAttributes(
  2967. IN LSA_SEC_HANDLE ContextHandle,
  2968. IN ULONG ContextAttribute,
  2969. IN OUT PVOID Buffer
  2970. )
  2971. {
  2972. NTSTATUS Status = STATUS_SUCCESS;
  2973. PKERB_CONTEXT Context = NULL;
  2974. PSecPkgContext_Sizes SizeInfo;
  2975. PSecPkgContext_Names NameInfo;
  2976. PSecPkgContext_DceInfo DceInfo;
  2977. PSecPkgContext_Lifespan LifespanInfo;
  2978. PSecPkgContext_Flags FlagsInfo;
  2979. PSecPkgContext_PackageInfo PackageInfo;
  2980. PSecPkgContext_NegotiationInfo NegInfo ;
  2981. PSecPkgContext_SessionKey SessionKeyInfo;
  2982. PSecPkgContext_KeyInfo KeyInfo;
  2983. PSecPkgContext_AccessToken AccessToken;
  2984. ULONG PackageInfoSize = 0;
  2985. UNICODE_STRING FullName;
  2986. ULONG ChecksumType;
  2987. ULONG EncryptType;
  2988. PCRYPTO_SYSTEM CryptSystem = NULL ;
  2989. TimeStamp CurrentTime;
  2990. D_DebugLog((DEB_TRACE_API,"SpQueryContextAttributes called pid:0x%x, ctxt:0x%x, Attr:0x%x\n", GetCurrentProcessId(), ContextHandle, ContextAttribute));
  2991. Status = KerbReferenceContextByLsaHandle(
  2992. ContextHandle,
  2993. FALSE, // don't unlink
  2994. &Context
  2995. );
  2996. if (!NT_SUCCESS(Status))
  2997. {
  2998. DebugLog((DEB_ERROR, "Invalid handle supplied for QueryContextAttributes(0x%x) Status = 0x%x. %ws, line %d\n",
  2999. ContextHandle, Status, THIS_FILE, __LINE__));
  3000. goto Cleanup;
  3001. }
  3002. //
  3003. // Return the appropriate information
  3004. //
  3005. switch(ContextAttribute)
  3006. {
  3007. case SECPKG_ATTR_SIZES:
  3008. gss_OID_desc * MechId;
  3009. UINT MessageSize;
  3010. if ((Context->ContextAttributes & KERB_CONTEXT_USER_TO_USER) != 0)
  3011. {
  3012. MechId = gss_mech_krb5_u2u;
  3013. }
  3014. else
  3015. {
  3016. MechId = gss_mech_krb5_new;
  3017. }
  3018. //
  3019. // The sizes returned are used by RPC to determine whether to call
  3020. // MakeSignature or SealMessage. The signature size should be zero
  3021. // if neither is to be called, and the block size and trailer size
  3022. // should be zero if SignMessage is not to be called.
  3023. //
  3024. SizeInfo = (PSecPkgContext_Sizes) Buffer;
  3025. SizeInfo->cbMaxToken = KerbGlobalMaxTokenSize;
  3026. // If we need to be Gss Compatible, then the Signature buffer size is
  3027. // dependent on the message size. So, we'll set it to be largest pad
  3028. // for the largest message size, say 1G. But, don't tax dce style
  3029. // callers with extra bytes.
  3030. if (((Context->ContextFlags & ISC_RET_DATAGRAM) != 0) ||
  3031. ((Context->ContextFlags & ISC_RET_USED_DCE_STYLE) != 0))
  3032. {
  3033. MessageSize = 0;
  3034. }
  3035. else
  3036. {
  3037. MessageSize = KERB_MAX_MESSAGE_SIZE;
  3038. }
  3039. if ((Context->ContextFlags & (KERB_SIGN_FLAGS | ISC_RET_CONFIDENTIALITY)) != 0)
  3040. {
  3041. SizeInfo->cbMaxSignature = g_token_size(MechId, sizeof(KERB_GSS_SIGNATURE));
  3042. }
  3043. else
  3044. {
  3045. SizeInfo->cbMaxSignature = sizeof(KERB_NULL_SIGNATURE);
  3046. }
  3047. //
  3048. // get the encryption type for the context
  3049. //
  3050. Status = KerbGetChecksumAndEncryptionType(
  3051. Context,
  3052. KERB_WRAP_NO_ENCRYPT, // checksum not needed so use hardcoded QOP
  3053. &ChecksumType, // checksum not needed here
  3054. &EncryptType
  3055. );
  3056. if (!NT_SUCCESS(Status))
  3057. {
  3058. goto Cleanup;
  3059. }
  3060. //
  3061. // Locate the cryptsystem for the context, loading it if necessary from the
  3062. // the crypto support DLL
  3063. //
  3064. Status = CDLocateCSystem(EncryptType, &CryptSystem);
  3065. if (!NT_SUCCESS(Status))
  3066. {
  3067. DebugLog((DEB_ERROR,"Failed to load %d crypt system: 0x%x. %ws, line %d\n",EncryptType,Status, THIS_FILE, __LINE__));
  3068. goto Cleanup;
  3069. }
  3070. //
  3071. // RPC keys off the trailer size to tell whether or not
  3072. // to encrypt, not the flags from isc/asc. So, for dce style,
  3073. // say the blocksize & trailersize are zero.
  3074. //
  3075. if (((Context->ContextFlags & ISC_RET_CONFIDENTIALITY) != 0) ||
  3076. ((Context->ContextFlags & ISC_RET_USED_DCE_STYLE) == 0))
  3077. {
  3078. //
  3079. // Use block size from crypto system
  3080. //
  3081. SizeInfo->cbBlockSize = CryptSystem->BlockSize;
  3082. SizeInfo->cbSecurityTrailer =
  3083. g_token_size(MechId, sizeof(KERB_GSS_SEAL_SIGNATURE) + MessageSize) - MessageSize;
  3084. }
  3085. else
  3086. {
  3087. SizeInfo->cbBlockSize = 0;
  3088. SizeInfo->cbSecurityTrailer = 0;
  3089. }
  3090. break;
  3091. case SECPKG_ATTR_SESSION_KEY:
  3092. SessionKeyInfo = (PSecPkgContext_SessionKey) Buffer;
  3093. SessionKeyInfo->SessionKeyLength = Context->SessionKey.keyvalue.length;
  3094. if (SessionKeyInfo->SessionKeyLength != 0)
  3095. {
  3096. SessionKeyInfo->SessionKey = (PUCHAR)
  3097. UserFunctions->AllocateHeap(
  3098. SessionKeyInfo->SessionKeyLength);
  3099. if (SessionKeyInfo->SessionKey!=NULL)
  3100. {
  3101. RtlCopyMemory(
  3102. SessionKeyInfo->SessionKey,
  3103. Context->SessionKey.keyvalue.value,
  3104. Context->SessionKey.keyvalue.length
  3105. );
  3106. }
  3107. else
  3108. {
  3109. Status = STATUS_INSUFFICIENT_RESOURCES;
  3110. }
  3111. }
  3112. else
  3113. {
  3114. SessionKeyInfo->SessionKey = (PUCHAR) UserFunctions->AllocateHeap(1);
  3115. if (SessionKeyInfo->SessionKey!=NULL)
  3116. {
  3117. *(PUCHAR) SessionKeyInfo->SessionKey = 0;
  3118. }
  3119. else
  3120. {
  3121. Status = STATUS_INSUFFICIENT_RESOURCES;
  3122. }
  3123. }
  3124. break;
  3125. case SECPKG_ATTR_NAMES:
  3126. NameInfo = (PSecPkgContext_Names) Buffer;
  3127. if (!KERB_SUCCESS(KerbBuildFullServiceName(
  3128. &Context->ClientRealm,
  3129. &Context->ClientName,
  3130. &FullName
  3131. )))
  3132. {
  3133. Status = STATUS_INSUFFICIENT_RESOURCES;
  3134. goto Cleanup;
  3135. }
  3136. #ifndef WIN32_CHICAGO
  3137. NameInfo->sUserName = (LPWSTR) UserFunctions->AllocateHeap(FullName.Length + sizeof(WCHAR));
  3138. if (NameInfo->sUserName != NULL)
  3139. {
  3140. RtlCopyMemory(
  3141. NameInfo->sUserName,
  3142. FullName.Buffer,
  3143. FullName.Length
  3144. );
  3145. NameInfo->sUserName[FullName.Length/sizeof(WCHAR)] = L'\0';
  3146. }
  3147. #else // WIN32_CHICAGO
  3148. ANSI_STRING AnsiString;
  3149. RtlUnicodeStringToAnsiString( &AnsiString,
  3150. &FullName,
  3151. TRUE);
  3152. NameInfo->sUserName = (LPTSTR) UserFunctions->AllocateHeap(AnsiString.Length + sizeof(CHAR));
  3153. if (NameInfo->sUserName != NULL)
  3154. {
  3155. RtlCopyMemory(
  3156. NameInfo->sUserName,
  3157. AnsiString.Buffer,
  3158. AnsiString.Length
  3159. );
  3160. NameInfo->sUserName[AnsiString.Length] = '\0';
  3161. RtlFreeAnsiString(&AnsiString);
  3162. }
  3163. #endif // WIN32_CHICAGO
  3164. else
  3165. {
  3166. Status = STATUS_INSUFFICIENT_RESOURCES;
  3167. }
  3168. KerbFreeString(&FullName);
  3169. break;
  3170. case SECPKG_ATTR_DCE_INFO:
  3171. DceInfo = (PSecPkgContext_DceInfo) Buffer;
  3172. if (!KERB_SUCCESS(KerbBuildFullServiceName(
  3173. &Context->ClientRealm,
  3174. &Context->ClientName,
  3175. &FullName
  3176. )))
  3177. {
  3178. Status = STATUS_INSUFFICIENT_RESOURCES;
  3179. goto Cleanup;
  3180. }
  3181. DceInfo->AuthzSvc = RPC_C_AUTHZ_NAME;
  3182. #ifndef WIN32_CHICAGO
  3183. DceInfo->pPac = UserFunctions->AllocateHeap(FullName.Length + sizeof(WCHAR));
  3184. if (DceInfo->pPac != NULL)
  3185. {
  3186. RtlCopyMemory(
  3187. DceInfo->pPac,
  3188. FullName.Buffer,
  3189. FullName.Length
  3190. );
  3191. ((LPWSTR)DceInfo->pPac)[FullName.Length/sizeof(WCHAR)] = L'\0';
  3192. }
  3193. #else // WIN32_CHICAGO
  3194. RtlUnicodeStringToAnsiString( &AnsiString,
  3195. &FullName,
  3196. TRUE);
  3197. DceInfo->pPac = UserFunctions->AllocateHeap(AnsiString.Length + sizeof(CHAR));
  3198. if (DceInfo->pPac != NULL)
  3199. {
  3200. RtlCopyMemory(
  3201. DceInfo->pPac,
  3202. AnsiString.Buffer,
  3203. AnsiString.Length
  3204. );
  3205. ((LPTSTR) DceInfo->pPac)[AnsiString.Length] = '\0';
  3206. RtlFreeAnsiString(&AnsiString);
  3207. }
  3208. #endif // WIN32_CHICAGO
  3209. else
  3210. {
  3211. Status = STATUS_INSUFFICIENT_RESOURCES;
  3212. }
  3213. KerbFreeString(&FullName);
  3214. break;
  3215. case SECPKG_ATTR_LIFESPAN:
  3216. LifespanInfo = (PSecPkgContext_Lifespan) Buffer;
  3217. if (KerbGetTime(Context->StartTime) != KerbGetTime(KerbGlobalHasNeverTime))
  3218. {
  3219. KerbUtcTimeToLocalTime(
  3220. &LifespanInfo->tsStart,
  3221. &(Context->StartTime)
  3222. );
  3223. D_DebugLog((DEB_TRACE, "Used context start time \n"));
  3224. }
  3225. else if (NULL != Context->TicketCacheEntry)
  3226. {
  3227. KerbUtcTimeToLocalTime(
  3228. &LifespanInfo->tsStart,
  3229. &(Context->TicketCacheEntry->StartTime)
  3230. );
  3231. KerbWriteLockContexts();
  3232. Context->StartTime = Context->TicketCacheEntry->StartTime;
  3233. KerbUnlockContexts();
  3234. DebugLog((DEB_ERROR, "Used tkt cache entry start time \n"));
  3235. }
  3236. else // set it to current time
  3237. {
  3238. // The context is not in a state where we've got a
  3239. // tkt cache entry, so let's use current time.
  3240. GetSystemTimeAsFileTime((PFILETIME)
  3241. &CurrentTime
  3242. );
  3243. KerbUtcTimeToLocalTime(
  3244. &LifespanInfo->tsStart,
  3245. &CurrentTime
  3246. );
  3247. DebugLog((DEB_ERROR, "NO START TIME PRESENT IN CONTEXT, or CACHE ENTRY!\n"));
  3248. }
  3249. KerbUtcTimeToLocalTime(
  3250. &LifespanInfo->tsExpiry,
  3251. &Context->Lifetime
  3252. );
  3253. break;
  3254. case SECPKG_ATTR_FLAGS:
  3255. FlagsInfo = (PSecPkgContext_Flags) Buffer;
  3256. if ((Context->ContextAttributes & KERB_CONTEXT_INBOUND) != 0)
  3257. {
  3258. FlagsInfo->Flags = KerbMapContextFlags( Context->ContextFlags );
  3259. }
  3260. else
  3261. {
  3262. FlagsInfo->Flags = Context->ContextFlags;
  3263. }
  3264. break;
  3265. #ifndef WIN32_CHICAGO
  3266. case SECPKG_ATTR_KEY_INFO:
  3267. PCRYPTO_SYSTEM CryptoSystem;
  3268. KeyInfo = (PSecPkgContext_KeyInfo) Buffer;
  3269. KeyInfo->KeySize = KerbIsKeyExportable(&Context->SessionKey) ? 56 : 128;
  3270. KeyInfo->EncryptAlgorithm = Context->SessionKey.keytype;
  3271. KeyInfo->SignatureAlgorithm = KERB_IS_DES_ENCRYPTION(Context->SessionKey.keytype) ? KERB_CHECKSUM_MD25 : KERB_CHECKSUM_HMAC_MD5;
  3272. KeyInfo->sSignatureAlgorithmName = NULL;
  3273. KeyInfo->sEncryptAlgorithmName = NULL;
  3274. //
  3275. // The checksum doesn't include a name, so don't fill it in - leave
  3276. // it as an empty string, so callers don't die when they
  3277. // try to manipulate it.
  3278. //
  3279. Status = CDLocateCSystem(KeyInfo->EncryptAlgorithm, &CryptoSystem);
  3280. if (NT_SUCCESS(Status))
  3281. {
  3282. KeyInfo->sEncryptAlgorithmName = (LPWSTR)
  3283. UserFunctions->AllocateHeap(sizeof(WCHAR) * (wcslen(CryptoSystem->Name) + 1));
  3284. if (KeyInfo->sEncryptAlgorithmName != NULL)
  3285. {
  3286. wcscpy(
  3287. KeyInfo->sEncryptAlgorithmName,
  3288. CryptoSystem->Name
  3289. );
  3290. KeyInfo->sSignatureAlgorithmName = (LPWSTR)
  3291. UserFunctions->AllocateHeap(sizeof(WCHAR));
  3292. if (KeyInfo->sSignatureAlgorithmName != NULL)
  3293. {
  3294. *KeyInfo->sSignatureAlgorithmName = L'\0';
  3295. }
  3296. else
  3297. {
  3298. Status = STATUS_INSUFFICIENT_RESOURCES;
  3299. UserFunctions->FreeHeap(KeyInfo->sEncryptAlgorithmName);
  3300. KeyInfo->sEncryptAlgorithmName = NULL;
  3301. }
  3302. }
  3303. else
  3304. {
  3305. Status = STATUS_INSUFFICIENT_RESOURCES;
  3306. }
  3307. }
  3308. break;
  3309. #endif // WIN32_CHICAGO
  3310. case SECPKG_ATTR_PACKAGE_INFO:
  3311. case SECPKG_ATTR_NEGOTIATION_INFO:
  3312. //
  3313. // Return the information about this package. This is useful for
  3314. // callers who used SPNEGO and don't know what package they got.
  3315. //
  3316. PackageInfo = (PSecPkgContext_PackageInfo) Buffer;
  3317. PackageInfoSize = sizeof(SecPkgInfo) + sizeof(KERBEROS_PACKAGE_NAME) + sizeof(KERBEROS_PACKAGE_COMMENT);
  3318. PackageInfo->PackageInfo = (PSecPkgInfo) UserFunctions->AllocateHeap(PackageInfoSize);
  3319. if (PackageInfo->PackageInfo == NULL)
  3320. {
  3321. Status = STATUS_INSUFFICIENT_RESOURCES;
  3322. goto Cleanup;
  3323. }
  3324. PackageInfo->PackageInfo->Name = (LPTSTR) (PackageInfo->PackageInfo + 1);
  3325. PackageInfo->PackageInfo->Comment = (LPTSTR) (((PBYTE) PackageInfo->PackageInfo->Name) + sizeof(KERBEROS_PACKAGE_NAME));
  3326. lstrcpy(
  3327. PackageInfo->PackageInfo->Name,
  3328. KERBEROS_PACKAGE_NAME
  3329. );
  3330. lstrcpy(
  3331. PackageInfo->PackageInfo->Comment,
  3332. KERBEROS_PACKAGE_COMMENT
  3333. );
  3334. PackageInfo->PackageInfo->wVersion = SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION;
  3335. PackageInfo->PackageInfo->wRPCID = RPC_C_AUTHN_GSS_KERBEROS;
  3336. PackageInfo->PackageInfo->fCapabilities = KERBEROS_CAPABILITIES;
  3337. PackageInfo->PackageInfo->cbMaxToken = KerbGlobalMaxTokenSize;
  3338. if ( ContextAttribute == SECPKG_ATTR_NEGOTIATION_INFO )
  3339. {
  3340. NegInfo = (PSecPkgContext_NegotiationInfo) PackageInfo ;
  3341. NegInfo->NegotiationState = SECPKG_NEGOTIATION_COMPLETE ;
  3342. }
  3343. break;
  3344. case SECPKG_ATTR_ACCESS_TOKEN:
  3345. {
  3346. AccessToken = (PSecPkgContext_AccessToken) Buffer;
  3347. //
  3348. // ClientTokenHandle can be NULL, for instance:
  3349. // 1. client side context.
  3350. // 2. incomplete server context.
  3351. //
  3352. AccessToken->AccessToken = (void*)Context->TokenHandle;
  3353. break;
  3354. }
  3355. default:
  3356. Status = STATUS_NOT_SUPPORTED;
  3357. break;
  3358. }
  3359. Cleanup:
  3360. if (Context != NULL)
  3361. {
  3362. KerbDereferenceContext(Context);
  3363. }
  3364. D_DebugLog((DEB_TRACE_API,"SpQueryContextAttributes returned 0x%x, pid:0x%x, ctxt:0x%x, Attr:0x%x\n", KerbMapKerbNtStatusToNtStatus(Status), GetCurrentProcessId(), ContextHandle, ContextAttribute));
  3365. return(KerbMapKerbNtStatusToNtStatus(Status));
  3366. }
  3367. //+-------------------------------------------------------------------------
  3368. //
  3369. // Function: SpQueryLsaModeContextAttributes
  3370. //
  3371. // Synopsis: Querys attributes of the specified context
  3372. //
  3373. // Effects:
  3374. //
  3375. // Arguments:
  3376. //
  3377. // Requires:
  3378. //
  3379. // Returns:
  3380. //
  3381. // Notes:
  3382. //
  3383. //
  3384. //--------------------------------------------------------------------------
  3385. NTSTATUS NTAPI
  3386. SpQueryLsaModeContextAttributes(
  3387. IN LSA_SEC_HANDLE ContextHandle,
  3388. IN ULONG ContextAttribute,
  3389. IN OUT PVOID Buffer
  3390. )
  3391. {
  3392. NTSTATUS Status = STATUS_SUCCESS;
  3393. PKERB_CONTEXT Context = NULL;
  3394. SecPkgContext_NativeNames NameInfo = {0};
  3395. BOOLEAN ContextsLocked = FALSE;
  3396. UNICODE_STRING ServerName = {0};
  3397. UNICODE_STRING ClientName = {0};
  3398. BOOLEAN IsClientContext = FALSE;
  3399. D_DebugLog((DEB_TRACE_API,"SpQueryLsaModeContextAttributes called ctxt:0x%x, Attr:0x%x\n", ContextHandle, ContextAttribute));
  3400. Status = KerbReferenceContext(
  3401. ContextHandle,
  3402. FALSE, // don't unlink
  3403. &Context
  3404. );
  3405. if (!NT_SUCCESS(Status))
  3406. {
  3407. DebugLog((DEB_ERROR, "Invalid handle supplied for QueryContextAttributes(0x%x) Status = 0x%x. %ws, line %d\n",
  3408. ContextHandle, Status, THIS_FILE, __LINE__));
  3409. goto Cleanup;
  3410. }
  3411. KerbReadLockContexts();
  3412. ContextsLocked = TRUE;
  3413. //
  3414. // Return the appropriate information
  3415. //
  3416. switch(ContextAttribute)
  3417. {
  3418. case SECPKG_ATTR_NATIVE_NAMES:
  3419. //
  3420. // Get outbound names from the ticket
  3421. //
  3422. if (Context->ContextAttributes & KERB_CONTEXT_OUTBOUND)
  3423. {
  3424. IsClientContext = TRUE;
  3425. if (Context->TicketCacheEntry != NULL)
  3426. {
  3427. KERBERR KerbErr = KDC_ERR_NONE;
  3428. KerbReadLockTicketCache();
  3429. KerbErr = KerbConvertKdcNameToString(
  3430. &ServerName,
  3431. Context->TicketCacheEntry->ServiceName,
  3432. &Context->TicketCacheEntry->DomainName
  3433. );
  3434. if (KERB_SUCCESS(KerbErr))
  3435. {
  3436. KerbErr = KerbConvertKdcNameToString(
  3437. &ClientName,
  3438. Context->TicketCacheEntry->ClientName,
  3439. &Context->TicketCacheEntry->ClientDomainName
  3440. );
  3441. }
  3442. KerbUnlockTicketCache();
  3443. if (!KERB_SUCCESS(KerbErr))
  3444. {
  3445. Status = STATUS_INSUFFICIENT_RESOURCES;
  3446. goto Cleanup;
  3447. }
  3448. }
  3449. else
  3450. {
  3451. //
  3452. // We couldn't find the names, so return an error
  3453. //
  3454. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  3455. goto Cleanup;
  3456. }
  3457. }
  3458. else
  3459. {
  3460. //
  3461. // We have a server context
  3462. //
  3463. ClientName = Context->ClientPrincipalName;
  3464. ServerName = Context->ServerPrincipalName;
  3465. }
  3466. #ifndef WIN32_CHICAGO
  3467. if (ServerName.Length != 0)
  3468. {
  3469. Status = LsaFunctions->AllocateClientBuffer(
  3470. NULL,
  3471. ServerName.Length + sizeof(WCHAR),
  3472. (PVOID *) &NameInfo.sServerName
  3473. );
  3474. if (!NT_SUCCESS(Status))
  3475. {
  3476. goto Cleanup;
  3477. }
  3478. Status = LsaFunctions->CopyToClientBuffer(
  3479. NULL,
  3480. ServerName.Length + sizeof(WCHAR),
  3481. NameInfo.sServerName,
  3482. ServerName.Buffer
  3483. );
  3484. if (!NT_SUCCESS(Status))
  3485. {
  3486. goto Cleanup;
  3487. }
  3488. }
  3489. if (ClientName.Length != 0)
  3490. {
  3491. Status = LsaFunctions->AllocateClientBuffer(
  3492. NULL,
  3493. ClientName.Length + sizeof(WCHAR),
  3494. (PVOID *) &NameInfo.sClientName
  3495. );
  3496. if (!NT_SUCCESS(Status))
  3497. {
  3498. goto Cleanup;
  3499. }
  3500. Status = LsaFunctions->CopyToClientBuffer(
  3501. NULL,
  3502. ClientName.Length + sizeof(WCHAR),
  3503. NameInfo.sClientName,
  3504. ClientName.Buffer
  3505. );
  3506. if (!NT_SUCCESS(Status))
  3507. {
  3508. goto Cleanup;
  3509. }
  3510. }
  3511. //
  3512. // Copy the whole structure
  3513. //
  3514. Status = LsaFunctions->CopyToClientBuffer(
  3515. NULL,
  3516. sizeof(SecPkgContext_NativeNames),
  3517. Buffer,
  3518. &NameInfo
  3519. );
  3520. if (!NT_SUCCESS(Status))
  3521. {
  3522. goto Cleanup;
  3523. }
  3524. #else // WIN32_CHICAGO
  3525. {
  3526. ANSI_STRING AnsiString = {0};
  3527. if (ServerName.Length != 0)
  3528. {
  3529. RtlUnicodeStringToAnsiString(
  3530. &AnsiString,
  3531. &ServerName,
  3532. TRUE);
  3533. if (AnsiString.Length > 0)
  3534. {
  3535. NameInfo.sServerName = (LPSTR) LsaFunctions->AllocateLsaHeap(
  3536. AnsiString.Length + sizeof(CHAR)
  3537. );
  3538. if (NameInfo.sServerName == NULL)
  3539. {
  3540. RtlFreeAnsiString(&AnsiString);
  3541. goto Cleanup;
  3542. }
  3543. RtlCopyMemory(
  3544. NameInfo.sServerName,
  3545. AnsiString.Buffer,
  3546. AnsiString.Length
  3547. );
  3548. NameInfo.sServerName[AnsiString.Length+1] = '\0';
  3549. RtlFreeAnsiString(&AnsiString);
  3550. }
  3551. else
  3552. {
  3553. Status = STATUS_INSUFFICIENT_RESOURCES;
  3554. goto Cleanup;
  3555. }
  3556. }
  3557. if (ClientName.Length != 0)
  3558. {
  3559. RtlUnicodeStringToAnsiString(
  3560. &AnsiString,
  3561. &ClientName,
  3562. TRUE);
  3563. if (AnsiString.Length > 0)
  3564. {
  3565. NameInfo.sClientName = (LPSTR) LsaFunctions->AllocateLsaHeap(
  3566. AnsiString.Length + sizeof(CHAR)
  3567. );
  3568. if (NameInfo.sClientName == NULL)
  3569. {
  3570. RtlFreeAnsiString(&AnsiString);
  3571. goto Cleanup;
  3572. }
  3573. RtlCopyMemory(
  3574. NameInfo.sClientName,
  3575. AnsiString.Buffer,
  3576. AnsiString.Length
  3577. );
  3578. NameInfo.sClientName[AnsiString.Length+1] = '\0';
  3579. RtlFreeAnsiString(&AnsiString);
  3580. }
  3581. else
  3582. {
  3583. Status = STATUS_INSUFFICIENT_RESOURCES;
  3584. goto Cleanup;
  3585. }
  3586. }
  3587. RtlCopyMemory(
  3588. Buffer,
  3589. &NameInfo,
  3590. sizeof(SecPkgContext_NativeNames)
  3591. );
  3592. }
  3593. #endif // WIN32_CHICAGO
  3594. break;
  3595. default:
  3596. Status = STATUS_NOT_SUPPORTED;
  3597. break;
  3598. }
  3599. Cleanup:
  3600. if (ContextsLocked)
  3601. {
  3602. KerbUnlockContexts();
  3603. }
  3604. if (Context != NULL)
  3605. {
  3606. KerbDereferenceContext(Context);
  3607. }
  3608. if (IsClientContext)
  3609. {
  3610. KerbFreeString(
  3611. &ClientName
  3612. );
  3613. KerbFreeString(
  3614. &ServerName
  3615. );
  3616. }
  3617. if (!NT_SUCCESS(Status))
  3618. {
  3619. #ifndef WIN32_CHICAGO
  3620. if (NameInfo.sServerName != NULL)
  3621. {
  3622. LsaFunctions->FreeClientBuffer(
  3623. NULL,
  3624. NameInfo.sServerName
  3625. );
  3626. }
  3627. if (NameInfo.sClientName != NULL)
  3628. {
  3629. LsaFunctions->FreeClientBuffer(
  3630. NULL,
  3631. NameInfo.sClientName
  3632. );
  3633. }
  3634. #else // WIN32_CHICAGO
  3635. if (NameInfo.sServerName != NULL)
  3636. {
  3637. LsaFunctions->FreeLsaHeap(
  3638. NameInfo.sServerName
  3639. );
  3640. }
  3641. if (NameInfo.sClientName != NULL)
  3642. {
  3643. LsaFunctions->FreeLsaHeap(
  3644. NameInfo.sClientName
  3645. );
  3646. }
  3647. #endif
  3648. }
  3649. D_DebugLog((DEB_TRACE_API,"SpQueryLsaModeContextAttributes returned 0x%x, pid:0x%x, ctxt:0x%x, Attr:0x%x\n", KerbMapKerbNtStatusToNtStatus(Status), GetCurrentProcessId(), ContextHandle, ContextAttribute));
  3650. return(KerbMapKerbNtStatusToNtStatus(Status));
  3651. }
  3652. //+-------------------------------------------------------------------------
  3653. //
  3654. // Function: SpCompleteAuthToken
  3655. //
  3656. // Synopsis: Completes a context (in Kerberos case, does nothing)
  3657. //
  3658. // Effects:
  3659. //
  3660. // Arguments:
  3661. //
  3662. // Requires:
  3663. //
  3664. // Returns:
  3665. //
  3666. // Notes:
  3667. //
  3668. //
  3669. //--------------------------------------------------------------------------
  3670. NTSTATUS NTAPI
  3671. SpCompleteAuthToken(
  3672. IN LSA_SEC_HANDLE ContextHandle,
  3673. IN PSecBufferDesc InputBuffer
  3674. )
  3675. {
  3676. return(STATUS_SUCCESS);
  3677. }
  3678. #ifndef WIN32_CHICAGO
  3679. NTSTATUS NTAPI
  3680. SpFormatCredentials(
  3681. IN PSecBuffer Credentials,
  3682. OUT PSecBuffer FormattedCredentials
  3683. )
  3684. {
  3685. return(STATUS_NOT_SUPPORTED);
  3686. }
  3687. NTSTATUS NTAPI
  3688. SpMarshallSupplementalCreds(
  3689. IN ULONG CredentialSize,
  3690. IN PUCHAR Credentials,
  3691. OUT PULONG MarshalledCredSize,
  3692. OUT PVOID * MarshalledCreds
  3693. )
  3694. {
  3695. return(STATUS_NOT_SUPPORTED);
  3696. }
  3697. #endif // WIN32_CHICAGO