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

2458 lines
68 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. stub.c
  5. Abstract:
  6. NT LM Security Support Provider client stubs.
  7. Author:
  8. Cliff Van Dyke (CliffV) 29-Jun-1993
  9. Environment: User Mode
  10. Revision History:
  11. --*/
  12. #ifdef BLDR_KERNEL_RUNTIME
  13. #include <bootdefs.h>
  14. #endif
  15. #ifdef WIN
  16. #include <windows.h>
  17. #include <ctype.h>
  18. #include <security.h>
  19. #include <ntlmsspi.h>
  20. #include <crypt.h>
  21. #include <ntlmssp.h>
  22. #include <cred.h>
  23. #include <debug.h>
  24. #include <string.h>
  25. #include <memory.h>
  26. #include <cache.h>
  27. #include <persist.h>
  28. #include <rpc.h>
  29. #include <md5.h>
  30. #include <context.h>
  31. #endif
  32. #ifdef MAC
  33. #include "ntlmsspi.h"
  34. #include "sspi.h"
  35. #include "crypt.h"
  36. #include "ntlmssp.h"
  37. #include "cred.h"
  38. #include "cache.h"
  39. //#include "debug.h"
  40. #include "string.h"
  41. #include "memory.h"
  42. //#include "cache.h"
  43. //#include "persist.h"
  44. //#include "rpc.h"
  45. #include "md5.h"
  46. #include "context.h"
  47. #include "winerror.h"
  48. #endif
  49. #include <stdio.h>
  50. #include "crc32.h"
  51. #if 0
  52. static SecurityFunctionTable FunctionTable =
  53. {
  54. SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION,
  55. EnumerateSecurityPackages,
  56. 0, // QueryCredentialsAttributes
  57. AcquireCredentialsHandle,
  58. FreeCredentialsHandle,
  59. 0,
  60. InitializeSecurityContext,
  61. 0,
  62. CompleteAuthToken,
  63. DeleteSecurityContext,
  64. ApplyControlToken,
  65. QueryContextAttributes,
  66. 0,
  67. 0,
  68. MakeSignature,
  69. VerifySignature,
  70. FreeContextBuffer,
  71. QuerySecurityPackageInfo,
  72. SealMessage,
  73. UnsealMessage
  74. };
  75. PSecurityFunctionTable SEC_ENTRY
  76. InitSecurityInterface(
  77. )
  78. /*++
  79. Routine Description:
  80. RPC calls this function to get the addresses of all the other functions
  81. that it might call.
  82. Arguments:
  83. None.
  84. Return Value:
  85. A pointer to our static SecurityFunctionTable. The caller need
  86. not deallocate this table.
  87. --*/
  88. {
  89. CacheInitializeCache();
  90. return &FunctionTable;
  91. }
  92. #endif // 0
  93. BOOL
  94. __loadds
  95. GetPassword(
  96. PSSP_CREDENTIAL Credential,
  97. int NeverPrompt
  98. )
  99. {
  100. #ifdef BL_USE_LM_PASSWORD
  101. if ((Credential->LmPassword != NULL) && (Credential->NtPassword != NULL)) {
  102. return (TRUE);
  103. }
  104. #else
  105. if (Credential->NtPassword != NULL) {
  106. return (TRUE);
  107. }
  108. #endif
  109. if (CacheGetPassword(Credential) == TRUE) {
  110. return (TRUE);
  111. }
  112. return (FALSE);
  113. }
  114. #if 0
  115. BOOLEAN
  116. SspTimeHasElapsed(
  117. IN DWORD StartTime,
  118. IN DWORD Timeout
  119. )
  120. /*++
  121. Routine Description:
  122. Determine if "Timeout" milliseconds have elapsed since StartTime.
  123. Arguments:
  124. StartTime - Specifies an absolute time when the event started
  125. (in millisecond units).
  126. Timeout - Specifies a relative time in milliseconds. 0xFFFFFFFF indicates
  127. that the time will never expire.
  128. Return Value:
  129. TRUE -- iff Timeout milliseconds have elapsed since StartTime.
  130. --*/
  131. {
  132. DWORD TimeNow;
  133. DWORD ElapsedTime;
  134. //
  135. // If the period to too large to handle (i.e., 0xffffffff is forever),
  136. // just indicate that the timer has not expired.
  137. //
  138. //
  139. if ( Timeout == 0xffffffff ) {
  140. return FALSE;
  141. }
  142. TimeNow = SspTicks();
  143. ElapsedTime = TimeNow - StartTime;
  144. if (ElapsedTime > Timeout) {
  145. return (TRUE);
  146. }
  147. return (FALSE);
  148. }
  149. #endif
  150. #ifndef MAC
  151. SECURITY_STATUS SEC_ENTRY
  152. QuerySecurityPackageInfo(
  153. IN SEC_CHAR SEC_FAR * PackageName,
  154. OUT PSecPkgInfo SEC_FAR *PackageInfo
  155. )
  156. /*++
  157. Routine Description:
  158. This API is intended to provide basic information about Security
  159. Packages themselves. This information will include the bounds on sizes
  160. of authentication information, credentials and contexts.
  161. ?? This is a local routine rather than the real API call since the API
  162. call has a bad interface that neither allows me to allocate the
  163. buffer nor tells me how big the buffer is. Perhaps when the real API
  164. is fixed, I'll make this the real API.
  165. Arguments:
  166. PackageName - Name of the package being queried.
  167. PackageInfo - Returns a pointer to an allocated block describing the
  168. security package. The allocated block must be freed using
  169. FreeContextBuffer.
  170. Return Value:
  171. SEC_E_OK -- Call completed successfully
  172. SEC_E_PACKAGE_UNKNOWN -- Package being queried is not this package
  173. SEC_E_INSUFFICIENT_MEMORY -- Not enough memory
  174. --*/
  175. {
  176. SEC_CHAR *Where;
  177. //
  178. // Ensure the correct package name was passed in.
  179. //
  180. if ( _fstrcmp( PackageName, NTLMSP_NAME ) != 0 ) {
  181. return SEC_E_PACKAGE_UNKNOWN;
  182. }
  183. //
  184. // Allocate a buffer for the PackageInfo
  185. //
  186. *PackageInfo = (PSecPkgInfo) SspAlloc (sizeof(SecPkgInfo) +
  187. sizeof(NTLMSP_NAME) +
  188. sizeof(NTLMSP_COMMENT) );
  189. if ( *PackageInfo == NULL ) {
  190. return SEC_E_INSUFFICIENT_MEMORY;
  191. }
  192. //
  193. // Fill in the information.
  194. //
  195. (*PackageInfo)->fCapabilities = NTLMSP_CAPABILITIES;
  196. (*PackageInfo)->wVersion = NTLMSP_VERSION;
  197. (*PackageInfo)->wRPCID = RPC_C_AUTHN_WINNT;
  198. (*PackageInfo)->cbMaxToken = NTLMSP_MAX_TOKEN_SIZE;
  199. Where = (SEC_CHAR *)((*PackageInfo)+1);
  200. (*PackageInfo)->Name = Where;
  201. _fstrcpy( Where, NTLMSP_NAME);
  202. Where += _fstrlen(Where) + 1;
  203. (*PackageInfo)->Comment = Where;
  204. _fstrcpy( Where, NTLMSP_COMMENT);
  205. Where += _fstrlen(Where) + 1;
  206. return SEC_E_OK;
  207. }
  208. SECURITY_STATUS SEC_ENTRY
  209. EnumerateSecurityPackages(
  210. OUT PULONG PackageCount,
  211. OUT PSecPkgInfo * PackageInfo
  212. )
  213. /*++
  214. Routine Description:
  215. This API returns a list of Security Packages available to client (i.e.
  216. those that are either loaded or can be loaded on demand). The caller
  217. must free the returned buffer with FreeContextBuffer. This API returns
  218. a list of all the security packages available to a service. The names
  219. returned can then be used to acquire credential handles, as well as
  220. determine which package in the system best satisfies the requirements
  221. of the caller. It is assumed that all available packages can be
  222. included in the single call.
  223. This is really a dummy API that just returns information about this
  224. security package. It is provided to ensure this security package has the
  225. same interface as the multiplexer DLL does.
  226. Arguments:
  227. PackageCount - Returns the number of packages supported.
  228. PackageInfo - Returns an allocate array of structures
  229. describing the security packages. The array must be freed
  230. using FreeContextBuffer.
  231. Return Value:
  232. SEC_E_OK -- Call completed successfully
  233. SEC_E_PACKAGE_UNKNOWN -- Package being queried is not this package
  234. SEC_E_INSUFFICIENT_MEMORY -- Not enough memory
  235. --*/
  236. {
  237. SECURITY_STATUS SecStatus;
  238. //
  239. // Get the information for this package.
  240. //
  241. SecStatus = QuerySecurityPackageInfo( NTLMSP_NAME,
  242. PackageInfo );
  243. if ( SecStatus != SEC_E_OK ) {
  244. return SecStatus;
  245. }
  246. *PackageCount = 1;
  247. return (SEC_E_OK);
  248. }
  249. #endif
  250. SECURITY_STATUS SEC_ENTRY
  251. AcquireCredentialsHandle(
  252. IN SEC_CHAR * PrincipalName,
  253. IN SEC_CHAR * PackageName,
  254. IN ULONG CredentialUseFlags,
  255. IN PVOID LogonId,
  256. IN PVOID AuthData,
  257. IN SEC_GET_KEY_FN GetKeyFunction,
  258. IN PVOID GetKeyArgument,
  259. OUT PCredHandle CredentialHandle,
  260. OUT PTimeStamp Lifetime
  261. )
  262. /*++
  263. Routine Description:
  264. This API allows applications to acquire a handle to pre-existing
  265. credentials associated with the user on whose behalf the call is made
  266. i.e. under the identity this application is running. These pre-existing
  267. credentials have been established through a system logon not described
  268. here. Note that this is different from "login to the network" and does
  269. not imply gathering of credentials.
  270. Note for DOS we will ignore the previous note. On DOS we will gather
  271. logon credentials through the AuthData parameter.
  272. This API returns a handle to the credentials of a principal (user, client)
  273. as used by a specific security package. This handle can then be used
  274. in subsequent calls to the Context APIs. This API will not let a
  275. process obtain a handle to credentials that are not related to the
  276. process; i.e. we won't allow a process to grab the credentials of
  277. another user logged into the same machine. There is no way for us
  278. to determine if a process is a trojan horse or not, if it is executed
  279. by the user.
  280. Arguments:
  281. PrincipalName - Name of the principal for whose credentials the handle
  282. will reference. Note, if the process requesting the handle does
  283. not have access to the credentials, an error will be returned.
  284. A null string indicates that the process wants a handle to the
  285. credentials of the user under whose security it is executing.
  286. PackageName - Name of the package with which these credentials will
  287. be used.
  288. CredentialUseFlags - Flags indicating the way with which these
  289. credentials will be used.
  290. #define CRED_INBOUND 0x00000001
  291. #define CRED_OUTBOUND 0x00000002
  292. #define CRED_BOTH 0x00000003
  293. #define CRED_OWF_PASSWORD 0x00000010
  294. The credentials created with CRED_INBOUND option can only be used
  295. for (validating incoming calls and can not be used for making accesses.
  296. CRED_OWF_PASSWORD means that the password in AuthData has already
  297. been through the OWF function.
  298. LogonId - Pointer to NT style Logon Id which is a LUID. (Provided for
  299. file system ; processes such as network redirectors.)
  300. CredentialHandle - Returned credential handle.
  301. Lifetime - Time that these credentials expire. The value returned in
  302. this field depends on the security package.
  303. Return Value:
  304. STATUS_SUCCESS -- Call completed successfully
  305. SEC_E_NO_SPM -- Security Support Provider is not running
  306. SEC_E_PACKAGE_UNKNOWN -- Package being queried is not this package
  307. SEC_E_PRINCIPAL_UNKNOWN -- No such principal
  308. SEC_E_NOT_OWNER -- caller does not own the specified credentials
  309. SEC_E_INSUFFICIENT_MEMORY -- Not enough memory
  310. --*/
  311. {
  312. SECURITY_STATUS SecStatus;
  313. PSSP_CREDENTIAL Credential = NULL;
  314. #ifdef DEBUGRPC_DETAIL
  315. SspPrint(( SSP_API, "SspAcquireCredentialHandle Entered\n" ));
  316. #endif
  317. //
  318. // Validate the arguments
  319. //
  320. if ( _fstrcmp( PackageName, NTLMSP_NAME ) != 0 ) {
  321. return (SEC_E_PACKAGE_UNKNOWN);
  322. }
  323. if ( (CredentialUseFlags & SECPKG_CRED_OUTBOUND) &&
  324. ARGUMENT_PRESENT(PrincipalName) && *PrincipalName != L'\0' ) {
  325. return (SEC_E_PRINCIPAL_UNKNOWN);
  326. }
  327. if ( ARGUMENT_PRESENT(LogonId) ) {
  328. return (SEC_E_PRINCIPAL_UNKNOWN);
  329. }
  330. if ( ARGUMENT_PRESENT(GetKeyFunction) ) {
  331. return (SEC_E_PRINCIPAL_UNKNOWN);
  332. }
  333. if ( ARGUMENT_PRESENT(GetKeyArgument) ) {
  334. return (SEC_E_PRINCIPAL_UNKNOWN);
  335. }
  336. //
  337. // Ensure at least one Credential use bit is set.
  338. //
  339. if ( (CredentialUseFlags & (SECPKG_CRED_INBOUND|SECPKG_CRED_OUTBOUND)) == 0 ) {
  340. SspPrint(( SSP_API,
  341. "SspAcquireCredentialHandle: invalid credential use.\n" ));
  342. SecStatus = SEC_E_INVALID_CREDENTIAL_USE;
  343. goto Cleanup;
  344. }
  345. //
  346. // Allocate a credential block and initialize it.
  347. //
  348. Credential = SspCredentialAllocateCredential(CredentialUseFlags);
  349. if ( Credential == NULL ) {
  350. SecStatus = SEC_E_INSUFFICIENT_MEMORY;
  351. goto Cleanup;
  352. }
  353. SecStatus = CacheSetCredentials( AuthData, Credential );
  354. if (SecStatus != SEC_E_OK)
  355. goto Cleanup;
  356. //
  357. // Return output parameters to the caller.
  358. //
  359. CredentialHandle->dwUpper = (ULONG_PTR)Credential;
  360. CredentialHandle->dwLower = 0;
  361. #ifndef MAC
  362. Lifetime->HighPart = 0;
  363. Lifetime->LowPart = 0xffffffffL;
  364. #else
  365. *Lifetime = 0xffffffffL;
  366. #endif
  367. SecStatus = SEC_E_OK;
  368. //
  369. // Free and locally used resources.
  370. //
  371. Cleanup:
  372. if ( SecStatus != SEC_E_OK ) {
  373. if ( Credential != NULL ) {
  374. SspFree( Credential );
  375. }
  376. }
  377. #ifdef DEBUGRPC_DETAIL
  378. SspPrint(( SSP_API, "SspAcquireCredentialHandle returns 0x%x\n", SecStatus ));
  379. #endif
  380. return SecStatus;
  381. }
  382. SECURITY_STATUS SEC_ENTRY
  383. FreeCredentialsHandle(
  384. IN PCredHandle CredentialHandle
  385. )
  386. /*++
  387. Routine Description:
  388. This API is used to notify the security system that the credentials are
  389. no longer needed and allows the application to free the handle acquired
  390. in the call described above. When all references to this credential
  391. set has been removed then the credentials may themselves be removed.
  392. Arguments:
  393. CredentialHandle - Credential Handle obtained through
  394. AcquireCredentialHandle.
  395. Return Value:
  396. STATUS_SUCCESS -- Call completed successfully
  397. SEC_E_NO_SPM -- Security Support Provider is not running
  398. SEC_E_INVALID_HANDLE -- Credential Handle is invalid
  399. --*/
  400. {
  401. SECURITY_STATUS SecStatus;
  402. PSSP_CREDENTIAL Credential;
  403. //
  404. // Initialization
  405. //
  406. #ifdef DEBUGRPC_DETAIL
  407. SspPrint(( SSP_API, "SspFreeCredentialHandle Entered\n" ));
  408. #endif
  409. //
  410. // Find the referenced credential and delink it.
  411. //
  412. Credential = SspCredentialReferenceCredential(CredentialHandle, TRUE);
  413. if ( Credential == NULL ) {
  414. SecStatus = SEC_E_INVALID_HANDLE;
  415. goto Cleanup;
  416. }
  417. SspCredentialDereferenceCredential( Credential );
  418. SspCredentialDereferenceCredential( Credential );
  419. SecStatus = SEC_E_OK;
  420. Cleanup:
  421. #ifdef DEBUGRPC_DETAIL
  422. SspPrint(( SSP_API, "SspFreeCredentialHandle returns 0x%x\n", SecStatus ));
  423. #endif
  424. return SecStatus;
  425. }
  426. BOOLEAN
  427. SspGetTokenBuffer(
  428. IN PSecBufferDesc TokenDescriptor OPTIONAL,
  429. OUT PVOID * TokenBuffer,
  430. OUT PULONG * TokenSize,
  431. IN BOOLEAN ReadonlyOK
  432. )
  433. /*++
  434. Routine Description:
  435. This routine parses a Token Descriptor and pulls out the useful
  436. information.
  437. Arguments:
  438. TokenDescriptor - Descriptor of the buffer containing (or to contain) the
  439. token. If not specified, TokenBuffer and TokenSize will be returned
  440. as NULL.
  441. TokenBuffer - Returns a pointer to the buffer for the token.
  442. TokenSize - Returns a pointer to the location of the size of the buffer.
  443. ReadonlyOK - TRUE if the token buffer may be readonly.
  444. Return Value:
  445. TRUE - If token buffer was properly found.
  446. --*/
  447. {
  448. ULONG i;
  449. //
  450. // If there is no TokenDescriptor passed in,
  451. // just pass out NULL to our caller.
  452. //
  453. if ( !ARGUMENT_PRESENT( TokenDescriptor) ) {
  454. *TokenBuffer = NULL;
  455. *TokenSize = NULL;
  456. return TRUE;
  457. }
  458. //
  459. // Check the version of the descriptor.
  460. //
  461. if ( TokenDescriptor->ulVersion != 0 ) {
  462. return FALSE;
  463. }
  464. //
  465. // Loop through each described buffer.
  466. //
  467. for ( i=0; i<TokenDescriptor->cBuffers ; i++ ) {
  468. PSecBuffer Buffer = &TokenDescriptor->pBuffers[i];
  469. if ( (Buffer->BufferType & (~SECBUFFER_READONLY)) == SECBUFFER_TOKEN ) {
  470. //
  471. // If the buffer is readonly and readonly isn't OK,
  472. // reject the buffer.
  473. //
  474. if ( !ReadonlyOK && (Buffer->BufferType & SECBUFFER_READONLY) ) {
  475. return FALSE;
  476. }
  477. //
  478. // Return the requested information
  479. //
  480. *TokenBuffer = Buffer->pvBuffer;
  481. *TokenSize = &Buffer->cbBuffer;
  482. return TRUE;
  483. }
  484. }
  485. return FALSE;
  486. }
  487. SECURITY_STATUS
  488. SspHandleFirstCall(
  489. IN PCredHandle CredentialHandle,
  490. IN OUT PCtxtHandle ContextHandle,
  491. IN ULONG ContextReqFlags,
  492. IN ULONG QoPFlags,
  493. IN ULONG InputTokenSize,
  494. IN PVOID InputToken,
  495. IN OUT PULONG OutputTokenSize,
  496. OUT PVOID OutputToken,
  497. OUT PULONG ContextAttributes,
  498. OUT PTimeStamp ExpirationTime
  499. )
  500. /*++
  501. Routine Description:
  502. Handle the First Call part of InitializeSecurityContext.
  503. Arguments:
  504. QoPFlags - Indicates security configuration
  505. All other arguments same as for InitializeSecurityContext
  506. Return Value:
  507. STATUS_SUCCESS -- All OK
  508. SEC_I_CALLBACK_NEEDED -- Caller should call again later
  509. SEC_E_INVALID_HANDLE -- Credential/Context Handle is invalid
  510. SEC_E_BUFFER_TOO_SMALL -- Buffer for output token isn't big enough
  511. SEC_E_INSUFFICIENT_MEMORY -- Not enough memory
  512. --*/
  513. {
  514. SECURITY_STATUS SecStatus;
  515. PSSP_CONTEXT Context = NULL;
  516. PSSP_CREDENTIAL Credential = NULL;
  517. NEGOTIATE_MESSAGE NegotiateMessage;
  518. //
  519. // Initialization
  520. //
  521. *ContextAttributes = 0;
  522. //
  523. // Get a pointer to the credential
  524. //
  525. Credential = SspCredentialReferenceCredential(
  526. CredentialHandle,
  527. FALSE );
  528. if ( Credential == NULL ) {
  529. SspPrint(( SSP_API,
  530. "SspHandleFirstCall: invalid credential handle.\n" ));
  531. SecStatus = SEC_E_INVALID_HANDLE;
  532. goto Cleanup;
  533. }
  534. if ( (Credential->CredentialUseFlags & SECPKG_CRED_OUTBOUND) == 0 ) {
  535. SspPrint(( SSP_API, "SspHandleFirstCall: invalid credential use.\n" ));
  536. SecStatus = SEC_E_INVALID_CREDENTIAL_USE;
  537. goto Cleanup;
  538. }
  539. //
  540. // Allocate a new context
  541. //
  542. Context = SspContextAllocateContext();
  543. if ( Context == NULL ) {
  544. SecStatus = SEC_E_INSUFFICIENT_MEMORY;
  545. goto Cleanup;
  546. }
  547. //
  548. // Build a handle to the newly created context.
  549. //
  550. ContextHandle->dwUpper = (ULONG_PTR) Context;
  551. ContextHandle->dwLower = 0;
  552. //
  553. // We don't support any options.
  554. //
  555. // Complain about those that require we do something.
  556. //
  557. if ( (ContextReqFlags & (ISC_REQ_ALLOCATE_MEMORY |
  558. ISC_REQ_PROMPT_FOR_CREDS |
  559. ISC_REQ_USE_SUPPLIED_CREDS )) != 0 ) {
  560. SspPrint(( SSP_API,
  561. "SspHandleFirstCall: invalid ContextReqFlags 0x%lx.\n",
  562. ContextReqFlags ));
  563. SecStatus = SEC_E_INVALID_CONTEXT_REQ;
  564. goto Cleanup;
  565. }
  566. //
  567. // If this is the first call,
  568. // build a Negotiate message.
  569. //
  570. // Offer to talk Oem character set.
  571. //
  572. _fstrcpy((CHAR*)NegotiateMessage.Signature, NTLMSSP_SIGNATURE );
  573. NegotiateMessage.MessageType = (NTLM_MESSAGE_TYPE)NtLmNegotiate;
  574. if (QoPFlags & QOP_NTLMV2)
  575. {
  576. Context->NegotiateFlags =
  577. NTLMSSP_NEGOTIATE_UNICODE |
  578. NTLMSSP_NEGOTIATE_OEM |
  579. NTLMSSP_NEGOTIATE_NTLM |
  580. NTLMSSP_NEGOTIATE_NTLM2 |
  581. NTLMSSP_REQUEST_TARGET |
  582. NTLMSSP_NEGOTIATE_ALWAYS_SIGN |
  583. NTLMSSP_NEGOTIATE_128;
  584. NegotiateMessage.NegotiateFlags = NTLMSSP_NEGOTIATE_UNICODE |
  585. NTLMSSP_NEGOTIATE_OEM |
  586. NTLMSSP_REQUEST_TARGET |
  587. NTLMSSP_NEGOTIATE_NTLM |
  588. NTLMSSP_NEGOTIATE_ALWAYS_SIGN |
  589. NTLMSSP_NEGOTIATE_NTLM2 |
  590. NTLMSSP_NEGOTIATE_56 |
  591. NTLMSSP_NEGOTIATE_128;
  592. }
  593. else
  594. {
  595. NegotiateMessage.NegotiateFlags = NTLMSSP_NEGOTIATE_OEM |
  596. NTLMSSP_NEGOTIATE_NTLM |
  597. NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
  598. if (Credential->Domain == NULL)
  599. {
  600. NegotiateMessage.NegotiateFlags |= NTLMSSP_REQUEST_TARGET;
  601. }
  602. }
  603. if ( *OutputTokenSize < sizeof(NEGOTIATE_MESSAGE) ) {
  604. SecStatus = SEC_E_BUFFER_TOO_SMALL;
  605. goto Cleanup;
  606. }
  607. if (ContextReqFlags & (ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT)) {
  608. Context->NegotiateFlags |= NTLMSSP_NEGOTIATE_SIGN;
  609. NegotiateMessage.NegotiateFlags |= NTLMSSP_NEGOTIATE_SIGN |
  610. NTLMSSP_NEGOTIATE_NT_ONLY;
  611. }
  612. if (ContextReqFlags & ISC_REQ_CONFIDENTIALITY) {
  613. Context->NegotiateFlags |= NTLMSSP_NEGOTIATE_SEAL;
  614. NegotiateMessage.NegotiateFlags |= NTLMSSP_NEGOTIATE_SEAL |
  615. NTLMSSP_NEGOTIATE_NT_ONLY;
  616. }
  617. swaplong(NegotiateMessage.NegotiateFlags);
  618. swaplong(*((ULONG*)&NegotiateMessage.MessageType));
  619. _fmemcpy(OutputToken, &NegotiateMessage, sizeof(NEGOTIATE_MESSAGE));
  620. *OutputTokenSize = sizeof(NEGOTIATE_MESSAGE);
  621. //
  622. // Return output parameters to the caller.
  623. //
  624. *ExpirationTime = SspContextGetTimeStamp( Context, TRUE );
  625. Context->Credential = SspCredentialReferenceCredential(
  626. CredentialHandle,
  627. FALSE);
  628. SecStatus = SEC_I_CALLBACK_NEEDED;
  629. Context->State = NegotiateSentState;
  630. //
  631. // Free locally used resources.
  632. //
  633. Cleanup:
  634. if ( Context != NULL ) {
  635. if (SecStatus != SEC_I_CALLBACK_NEEDED) {
  636. SspContextDereferenceContext( Context );
  637. }
  638. }
  639. if ( Credential != NULL ) {
  640. SspCredentialDereferenceCredential( Credential );
  641. }
  642. return SecStatus;
  643. UNREFERENCED_PARAMETER( InputToken );
  644. UNREFERENCED_PARAMETER( InputTokenSize );
  645. }
  646. SECURITY_STATUS
  647. SspHandleChallengeMessage(
  648. IN PLUID LogonId,
  649. IN PCredHandle CredentialHandle,
  650. IN OUT PCtxtHandle ContextHandle,
  651. IN ULONG ContextReqFlags,
  652. IN ULONG InputTokenSize,
  653. IN PVOID InputToken,
  654. IN OUT PULONG OutputTokenSize,
  655. OUT PVOID OutputToken,
  656. OUT PULONG ContextAttributes,
  657. OUT PTimeStamp ExpirationTime
  658. )
  659. /*++
  660. Routine Description:
  661. Handle the Challenge message part of InitializeSecurityContext.
  662. Arguments:
  663. LogonId -- LogonId of the calling process.
  664. All other arguments same as for InitializeSecurityContext
  665. Return Value:
  666. STATUS_SUCCESS - Message handled
  667. SEC_I_CALLBACK_NEEDED -- Caller should call again later
  668. SEC_E_INVALID_TOKEN -- Token improperly formatted
  669. SEC_E_INVALID_HANDLE -- Credential/Context Handle is invalid
  670. SEC_E_BUFFER_TOO_SMALL -- Buffer for output token isn't big enough
  671. SEC_E_NO_CREDENTIALS -- There are no credentials for this client
  672. SEC_E_INSUFFICIENT_MEMORY -- Not enough memory
  673. --*/
  674. {
  675. SECURITY_STATUS SecStatus;
  676. PSSP_CONTEXT Context = NULL;
  677. PSSP_CREDENTIAL Credential = NULL;
  678. PCHALLENGE_MESSAGE ChallengeMessage = NULL;
  679. PAUTHENTICATE_MESSAGE AuthenticateMessage = NULL;
  680. ULONG AuthenticateMessageSize;
  681. PCHAR Where;
  682. #ifdef BL_USE_LM_PASSWORD
  683. LM_RESPONSE LmResponse;
  684. #endif
  685. NT_RESPONSE NtResponse;
  686. STRING32* pString;
  687. //
  688. // Initialization
  689. //
  690. *ContextAttributes = 0;
  691. //
  692. // Find the currently existing context.
  693. //
  694. Context = SspContextReferenceContext( ContextHandle, FALSE );
  695. if ( Context == NULL ) {
  696. SecStatus = SEC_E_INVALID_HANDLE;
  697. goto Cleanup;
  698. }
  699. //
  700. // If we have already sent the authenticate message, then this must be
  701. // RPC calling Initialize a third time to re-authenticate a connection.
  702. // This happens when a new interface is called over an existing
  703. // connection. What we do here is build a NULL authenticate message
  704. // that the server will recognize and also ignore.
  705. //
  706. if ( Context->State == AuthenticateSentState ) {
  707. AUTHENTICATE_MESSAGE NullMessage;
  708. //
  709. // To make sure this is the intended meaning of the call, check
  710. // that the input token is NULL.
  711. //
  712. if ( (InputTokenSize != 0) || (InputToken != NULL) ) {
  713. SecStatus = SEC_E_INVALID_TOKEN;
  714. goto Cleanup;
  715. }
  716. if ( *OutputTokenSize < sizeof(NullMessage) ) {
  717. SecStatus = SEC_E_BUFFER_TOO_SMALL;
  718. } else {
  719. _fstrcpy((CHAR*)NullMessage.Signature, NTLMSSP_SIGNATURE );
  720. NullMessage.MessageType = NtLmAuthenticate;
  721. swaplong(NullMessage.MessageType) ;
  722. _fmemset(&NullMessage.LmChallengeResponse, 0, 5*sizeof(STRING));
  723. *OutputTokenSize = sizeof(NullMessage);
  724. _fmemcpy(OutputToken, &NullMessage, sizeof(NullMessage));
  725. SecStatus = SEC_E_OK;
  726. }
  727. goto Cleanup;
  728. }
  729. if ( Context->State != NegotiateSentState ) {
  730. SspPrint(( SSP_API,
  731. "SspHandleChallengeMessage: "
  732. "Context not in NegotiateSentState\n" ));
  733. SecStatus = SEC_E_OUT_OF_SEQUENCE;
  734. goto Cleanup;
  735. }
  736. //
  737. // We don't support any options.
  738. //
  739. // Complain about those that require we do something.
  740. //
  741. if ( (ContextReqFlags & (ISC_REQ_ALLOCATE_MEMORY |
  742. ISC_REQ_PROMPT_FOR_CREDS |
  743. ISC_REQ_USE_SUPPLIED_CREDS )) != 0 ) {
  744. SspPrint(( SSP_API,
  745. "SspHandleFirstCall: invalid ContextReqFlags 0x%lx.\n",
  746. ContextReqFlags ));
  747. SecStatus = SEC_E_INVALID_CONTEXT_REQ;
  748. goto Cleanup;
  749. }
  750. if (ContextReqFlags & (ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT)) {
  751. Context->NegotiateFlags |= NTLMSSP_NEGOTIATE_SIGN;
  752. }
  753. if (ContextReqFlags & ISC_REQ_CONFIDENTIALITY) {
  754. Context->NegotiateFlags |= NTLMSSP_NEGOTIATE_SEAL;
  755. }
  756. //
  757. // Ignore the Credential Handle.
  758. //
  759. // Since this is the second call,
  760. // the credential is implied by the Context.
  761. // We could double check that the Credential Handle is either NULL or
  762. // correct. However, our implementation doesn't maintain a close
  763. // association between the two (actually no association) so checking
  764. // would require a lot of overhead.
  765. //
  766. UNREFERENCED_PARAMETER( CredentialHandle );
  767. ASSERT(Context->Credential != NULL);
  768. Credential = Context->Credential;
  769. //
  770. // Get the ChallengeMessage.
  771. //
  772. if ( InputTokenSize < sizeof(CHALLENGE_MESSAGE) ) {
  773. SspPrint(( SSP_API,
  774. "SspHandleChallengeMessage: "
  775. "ChallengeMessage size wrong %ld\n",
  776. InputTokenSize ));
  777. SecStatus = SEC_E_INVALID_TOKEN;
  778. goto Cleanup;
  779. }
  780. if ( InputTokenSize > NTLMSSP_MAX_MESSAGE_SIZE ) {
  781. SspPrint(( SSP_API,
  782. "SspHandleChallengeMessage: "
  783. "InputTokenSize > NTLMSSP_MAX_MESSAGE_SIZE\n" ));
  784. SecStatus = SEC_E_INVALID_TOKEN;
  785. goto Cleanup;
  786. }
  787. ChallengeMessage = (PCHALLENGE_MESSAGE) InputToken;
  788. swaplong(ChallengeMessage->MessageType) ;
  789. swaplong(ChallengeMessage->NegotiateFlags) ;
  790. if ( _fstrncmp((CHAR*)ChallengeMessage->Signature,
  791. NTLMSSP_SIGNATURE,
  792. sizeof(NTLMSSP_SIGNATURE)) != 0 ||
  793. ChallengeMessage->MessageType != NtLmChallenge ) {
  794. SspPrint(( SSP_API,
  795. "SspHandleChallengeMessage: "
  796. "InputToken has invalid NTLMSSP signature\n" ));
  797. SecStatus = SEC_E_INVALID_TOKEN;
  798. goto Cleanup;
  799. }
  800. //
  801. // Only negotiate OEM
  802. //
  803. if ( !(ChallengeMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM2) && ChallengeMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_UNICODE ) {
  804. SspPrint(( SSP_API,
  805. "SspHandleChallengeMessage: "
  806. "ChallengeMessage bad NegotiateFlags (UNICODE) 0x%lx\n",
  807. ChallengeMessage->NegotiateFlags ));
  808. SecStatus = SEC_E_INVALID_TOKEN;
  809. goto Cleanup;
  810. }
  811. //
  812. // Check whether the server negotiated ALWAYS_SIGN
  813. //
  814. if ( ChallengeMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN ) {
  815. Context->NegotiateFlags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
  816. }
  817. //
  818. // Only negotiate NTLM
  819. //
  820. if ( ( ChallengeMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_NETWARE ) &&
  821. !( ChallengeMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM ) ) {
  822. SspPrint(( SSP_API,
  823. "SspHandleChallengeMessage: "
  824. "ChallengeMessage bad NegotiateFlags (NETWARE) 0x%lx\n",
  825. ChallengeMessage->NegotiateFlags ));
  826. SecStatus = SEC_E_INVALID_TOKEN;
  827. goto Cleanup;
  828. }
  829. #if 0
  830. //
  831. // Make sure that if we are signing or sealing we only have to use the
  832. // LM key
  833. //
  834. if ((Context->NegotiateFlags & (NTLMSSP_NEGOTIATE_SIGN | NTLMSSP_NEGOTIATE_SEAL)) &&
  835. !(ChallengeMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_LM_KEY))
  836. {
  837. SspPrint(( SSP_API,
  838. "SspHandleChallengeMessage: "
  839. "ChallengeMessage bad NegotiateFlags (Sign or Seal but no LM key) 0x%lx\n",
  840. ChallengeMessage->NegotiateFlags ));
  841. SecStatus = SEC_E_INVALID_TOKEN;
  842. goto Cleanup;
  843. }
  844. #endif
  845. if (!Credential || !Credential->Username || !Credential->Domain)
  846. {
  847. SspPrint((SSP_CRITICAL, "SspHandleChallengeMessage no credential\n"));
  848. SecStatus = SEC_E_NO_CREDENTIALS;
  849. goto Cleanup;
  850. }
  851. SspPrint((SSP_CRED, "User name: (%s)\n", Credential->Username));
  852. SspPrint((SSP_CRED, "Domain name: (%s)\n", Credential->Domain));
  853. SspPrint((SSP_CRED, "Workstation: (%s)\n", Credential->Workstation));
  854. if (ChallengeMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM2)
  855. {
  856. if (!Credential || !Credential->NtPassword)
  857. {
  858. SspPrint((SSP_CRITICAL, "No NtPassword\n"));
  859. SecStatus = SEC_E_NO_CREDENTIALS;
  860. goto Cleanup;
  861. }
  862. SecStatus = SsprHandleNtlmv2ChallengeMessage(
  863. Credential,
  864. InputTokenSize,
  865. InputToken,
  866. &Context->NegotiateFlags,
  867. OutputTokenSize,
  868. OutputToken,
  869. &Context->UserSessionKey
  870. );
  871. if (SEC_E_BUFFER_TOO_SMALL == SEC_E_OK)
  872. {
  873. SecStatus = SEC_E_INSUFFICIENT_MEMORY;
  874. }
  875. if (SecStatus != SEC_E_OK)
  876. {
  877. goto Cleanup;
  878. }
  879. SspMakeNtlmv2SKeys(
  880. &Context->UserSessionKey,
  881. Context->NegotiateFlags,
  882. 0, // SendNonce
  883. 0, // RecvNonce
  884. &Context->Ntlmv2SKeys
  885. );
  886. goto ReturnSuccess;
  887. }
  888. if (Credential->Domain == NULL) {
  889. ASSERT(ChallengeMessage->TargetName.Length != 0);
  890. Credential->Domain = SspAlloc(ChallengeMessage->TargetName.Length + 1);
  891. if (Credential->Domain == NULL) {
  892. SecStatus = SEC_E_INSUFFICIENT_MEMORY;
  893. goto Cleanup;
  894. }
  895. pString = &ChallengeMessage->TargetName;
  896. #if defined(_WIN64)
  897. _fmemcpy(Credential->Domain, (PCHAR)ChallengeMessage + (ULONG)((__int64)pString->Buffer), pString->Length);
  898. #else
  899. _fmemcpy(Credential->Domain, (PCHAR)ChallengeMessage + (ULONG)pString->Buffer, pString->Length);
  900. #endif
  901. Credential->Domain[pString->Length] = '\0';
  902. }
  903. if (GetPassword(Credential, 0) == FALSE) {
  904. SecStatus = SEC_E_NO_CREDENTIALS;
  905. goto Cleanup;
  906. }
  907. #ifdef BL_USE_LM_PASSWORD
  908. if (CalculateLmResponse((PLM_CHALLENGE)ChallengeMessage->Challenge, Credential->LmPassword, &LmResponse) == FALSE) {
  909. SecStatus = SEC_E_INSUFFICIENT_MEMORY;
  910. goto Cleanup;
  911. }
  912. #endif
  913. if (CalculateNtResponse((PNT_CHALLENGE)ChallengeMessage->Challenge, Credential->NtPassword, &NtResponse) == FALSE) {
  914. SecStatus = SEC_E_INSUFFICIENT_MEMORY;
  915. goto Cleanup;
  916. }
  917. //
  918. // Allocate an authenticate message. Change this #if 0 and the next one
  919. // to send an LM challenge response also.
  920. //
  921. #ifdef BL_USE_LM_PASSWORD
  922. AuthenticateMessageSize = sizeof(*AuthenticateMessage)+LM_RESPONSE_LENGTH+NT_RESPONSE_LENGTH;
  923. #else
  924. AuthenticateMessageSize = sizeof(*AuthenticateMessage)+NT_RESPONSE_LENGTH;
  925. #endif
  926. if (Credential->Domain != NULL) {
  927. AuthenticateMessageSize += _fstrlen(Credential->Domain);
  928. }
  929. if (Credential->Username != NULL) {
  930. AuthenticateMessageSize += _fstrlen(Credential->Username);
  931. }
  932. if (Credential->Workstation != NULL) {
  933. AuthenticateMessageSize += _fstrlen(Credential->Workstation);
  934. }
  935. if ( AuthenticateMessageSize > *OutputTokenSize ) {
  936. SecStatus = SEC_E_BUFFER_TOO_SMALL;
  937. goto Cleanup;
  938. }
  939. AuthenticateMessage = (PAUTHENTICATE_MESSAGE) SspAlloc ((int)AuthenticateMessageSize );
  940. if ( AuthenticateMessage == NULL ) {
  941. SecStatus = SEC_E_INSUFFICIENT_MEMORY;
  942. goto Cleanup;
  943. }
  944. //
  945. // Build the authenticate message
  946. //
  947. _fstrcpy((CHAR*)AuthenticateMessage->Signature, NTLMSSP_SIGNATURE );
  948. AuthenticateMessage->MessageType = NtLmAuthenticate;
  949. swaplong(AuthenticateMessage->MessageType) ;
  950. Where = (PCHAR)(AuthenticateMessage+1);
  951. #ifdef BL_USE_LM_PASSWORD
  952. SspCopyStringFromRaw( AuthenticateMessage,
  953. &AuthenticateMessage->LmChallengeResponse,
  954. (PCHAR)&LmResponse,
  955. LM_RESPONSE_LENGTH,
  956. &Where);
  957. #else
  958. SspCopyStringFromRaw( AuthenticateMessage,
  959. &AuthenticateMessage->LmChallengeResponse,
  960. NULL,
  961. 0,
  962. &Where);
  963. #endif
  964. SspCopyStringFromRaw( AuthenticateMessage,
  965. &AuthenticateMessage->NtChallengeResponse,
  966. (PCHAR)&NtResponse,
  967. NT_RESPONSE_LENGTH,
  968. &Where);
  969. if (Credential->Domain != NULL) {
  970. SspCopyStringFromRaw( AuthenticateMessage,
  971. &AuthenticateMessage->DomainName,
  972. Credential->Domain,
  973. _fstrlen(Credential->Domain),
  974. &Where);
  975. } else {
  976. SspCopyStringFromRaw( AuthenticateMessage,
  977. &AuthenticateMessage->DomainName,
  978. NULL, 0, &Where);
  979. }
  980. if (Credential->Username != NULL) {
  981. SspCopyStringFromRaw( AuthenticateMessage,
  982. &AuthenticateMessage->UserName,
  983. Credential->Username,
  984. _fstrlen(Credential->Username),
  985. &Where);
  986. } else {
  987. SspCopyStringFromRaw( AuthenticateMessage,
  988. &AuthenticateMessage->UserName,
  989. NULL, 0, &Where);
  990. }
  991. if (Credential->Workstation != NULL) {
  992. SspCopyStringFromRaw( AuthenticateMessage,
  993. &AuthenticateMessage->Workstation,
  994. Credential->Workstation,
  995. _fstrlen(Credential->Workstation),
  996. &Where);
  997. } else {
  998. SspCopyStringFromRaw( AuthenticateMessage,
  999. &AuthenticateMessage->Workstation,
  1000. NULL, 0, &Where);
  1001. }
  1002. _fmemcpy(OutputToken, AuthenticateMessage, (int)AuthenticateMessageSize);
  1003. *OutputTokenSize = AuthenticateMessageSize;
  1004. //
  1005. // The session key is the password, so convert it to a rc4 key.
  1006. //
  1007. if (Context->NegotiateFlags & (NTLMSSP_NEGOTIATE_SIGN |
  1008. NTLMSSP_NEGOTIATE_SEAL)) {
  1009. #ifdef BL_USE_LM_PASSWORD
  1010. if (ChallengeMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_LM_KEY) {
  1011. LM_RESPONSE SessionKey;
  1012. LM_OWF_PASSWORD LmKey;
  1013. UCHAR Key[LM_SESSION_KEY_LENGTH];
  1014. //
  1015. // The session key is the first 8 bytes of the challenge response,
  1016. // re-encrypted with the password with the second 8 bytes set to 0xbd
  1017. //
  1018. _fmemcpy(&LmKey,Credential->LmPassword,LM_SESSION_KEY_LENGTH);
  1019. _fmemset( (PUCHAR)(&LmKey) + LM_SESSION_KEY_LENGTH,
  1020. 0xbd,
  1021. LM_OWF_PASSWORD_LENGTH - LM_SESSION_KEY_LENGTH);
  1022. if (CalculateLmResponse( (PLM_CHALLENGE) &LmResponse,
  1023. &LmKey,
  1024. &SessionKey) == FALSE) {
  1025. SecStatus = SEC_E_INSUFFICIENT_MEMORY;
  1026. goto Cleanup;
  1027. }
  1028. _fmemcpy(Key,&SessionKey,5);
  1029. ASSERT(LM_SESSION_KEY_LENGTH == 8);
  1030. //
  1031. // Put a well-known salt at the end of the key to limit
  1032. // the changing part to 40 bits.
  1033. //
  1034. Key[5] = 0xe5;
  1035. Key[6] = 0x38;
  1036. Key[7] = 0xb0;
  1037. Context->Rc4Key = SspAlloc(sizeof(struct RC4_KEYSTRUCT));
  1038. if (Context->Rc4Key == NULL)
  1039. {
  1040. SecStatus = SEC_E_INSUFFICIENT_MEMORY;
  1041. goto Cleanup;
  1042. }
  1043. rc4_key(Context->Rc4Key, LM_SESSION_KEY_LENGTH, Key);
  1044. Context->Nonce = 0;
  1045. } else
  1046. #endif
  1047. if (ChallengeMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_NT_ONLY) {
  1048. MD5_CTX Md5Context;
  1049. USER_SESSION_KEY UserSessionKey;
  1050. if (AuthenticateMessage->NtChallengeResponse.Length != NT_RESPONSE_LENGTH) {
  1051. SecStatus = SEC_E_UNSUPPORTED_FUNCTION;
  1052. goto Cleanup;
  1053. }
  1054. CalculateUserSessionKeyNt(
  1055. &NtResponse,
  1056. Credential->NtPassword,
  1057. &UserSessionKey);
  1058. //
  1059. // The NT session key is made by MD5'ing the challenge response,
  1060. // user name, domain name, and nt user session key together.
  1061. //
  1062. _fmemset(&Md5Context, 0, sizeof(MD5_CTX));
  1063. MD5Init(
  1064. &Md5Context
  1065. );
  1066. MD5Update(
  1067. &Md5Context,
  1068. (PUCHAR)&NtResponse,
  1069. NT_RESPONSE_LENGTH
  1070. );
  1071. MD5Update(
  1072. &Md5Context,
  1073. (PUCHAR)Credential->Username,
  1074. _fstrlen(Credential->Username)
  1075. );
  1076. MD5Update(
  1077. &Md5Context,
  1078. (PUCHAR)Credential->Domain,
  1079. _fstrlen(Credential->Domain)
  1080. );
  1081. MD5Update(
  1082. &Md5Context,
  1083. (PUCHAR)&UserSessionKey,
  1084. NT_SESSION_KEY_LENGTH
  1085. );
  1086. MD5Final(
  1087. &Md5Context
  1088. );
  1089. ASSERT(MD5DIGESTLEN == NT_SESSION_KEY_LENGTH);
  1090. Context->Rc4Key = SspAlloc(sizeof(struct RC4_KEYSTRUCT));
  1091. if (Context->Rc4Key == NULL)
  1092. {
  1093. SecStatus = SEC_E_INSUFFICIENT_MEMORY;
  1094. goto Cleanup;
  1095. }
  1096. rc4_key(Context->Rc4Key, NT_SESSION_KEY_LENGTH, Md5Context.digest);
  1097. Context->Nonce = 0;
  1098. } else {
  1099. USER_SESSION_KEY UserSessionKey;
  1100. if (AuthenticateMessage->NtChallengeResponse.Length != NT_RESPONSE_LENGTH) {
  1101. SecStatus = SEC_E_UNSUPPORTED_FUNCTION;
  1102. goto Cleanup;
  1103. }
  1104. CalculateUserSessionKeyNt(
  1105. &NtResponse,
  1106. Credential->NtPassword,
  1107. &UserSessionKey);
  1108. Context->Rc4Key = SspAlloc(sizeof(struct RC4_KEYSTRUCT));
  1109. if (Context->Rc4Key == NULL)
  1110. {
  1111. SecStatus = SEC_E_INSUFFICIENT_MEMORY;
  1112. goto Cleanup;
  1113. }
  1114. rc4_key(Context->Rc4Key, NT_SESSION_KEY_LENGTH, (PUCHAR) &UserSessionKey);
  1115. Context->Nonce = 0;
  1116. }
  1117. }
  1118. ReturnSuccess:
  1119. //
  1120. // Return output parameters to the caller.
  1121. //
  1122. *ExpirationTime = SspContextGetTimeStamp( Context, TRUE );
  1123. SecStatus = SEC_E_OK;
  1124. //
  1125. // Free and locally used resources.
  1126. //
  1127. Cleanup:
  1128. if ( Context != NULL ) {
  1129. //
  1130. // Don't allow this context to be used again.
  1131. //
  1132. if ( SecStatus == SEC_E_OK ) {
  1133. Context->State = AuthenticateSentState;
  1134. } else {
  1135. Context->State = IdleState;
  1136. }
  1137. SspContextDereferenceContext( Context );
  1138. }
  1139. if ( AuthenticateMessage != NULL ) {
  1140. SspFree( AuthenticateMessage );
  1141. }
  1142. return SecStatus;
  1143. }
  1144. SECURITY_STATUS SEC_ENTRY
  1145. InitializeSecurityContext(
  1146. IN PCredHandle CredentialHandle,
  1147. IN PCtxtHandle OldContextHandle,
  1148. IN SEC_CHAR * TargetName,
  1149. IN ULONG ContextReqFlags,
  1150. IN ULONG Reserved1,
  1151. IN ULONG TargetDataRep,
  1152. IN PSecBufferDesc InputToken,
  1153. IN ULONG Reserved2,
  1154. OUT PCtxtHandle NewContextHandle,
  1155. OUT PSecBufferDesc OutputToken,
  1156. OUT PULONG ContextAttributes,
  1157. OUT PTimeStamp ExpirationTime
  1158. )
  1159. /*++
  1160. Routine Description:
  1161. This routine initiates the outbound security context from a credential
  1162. handle. This results in the establishment of a security context
  1163. between the application and a remote peer. The routine returns a token
  1164. which must be passed to the remote peer which in turn submits it to the
  1165. local security implementation via the AcceptSecurityContext() call.
  1166. The token generated should be considered opaque by all callers.
  1167. This function is used by a client to initialize an outbound context.
  1168. For a two leg security package, the calling sequence is as follows: The
  1169. client calls the function with OldContextHandle set to NULL and
  1170. InputToken set either to NULL or to a pointer to a security package
  1171. specific data structure. The package returns a context handle in
  1172. NewContextHandle and a token in OutputToken. The handle can then be
  1173. used for message APIs if desired.
  1174. The OutputToken returned here is sent across to target server which
  1175. calls AcceptSecuirtyContext() with this token as an input argument and
  1176. may receive a token which is returned to the initiator so it can call
  1177. InitializeSecurityContext() again.
  1178. For a three leg (mutual authentication) security package, the calling
  1179. sequence is as follows: The client calls the function as above, but the
  1180. package will return SEC_I_CALLBACK_NEEDED. The client then sends the
  1181. output token to the server and waits for the server's reply. Upon
  1182. receipt of the server's response, the client calls this function again,
  1183. with OldContextHandle set to the handle that was returned from the
  1184. first call. The token received from the server is supplied in the
  1185. InputToken parameter. If the server has successfully responded, then
  1186. the package will respond with success, or it will invalidate the
  1187. context.
  1188. Initialization of security context may require more than one call to
  1189. this function depending upon the underlying authentication mechanism as
  1190. well as the "choices" indicated via ContextReqFlags. The
  1191. ContextReqFlags and ContextAttributes are bit masks representing
  1192. various context level functions viz. delegation, mutual
  1193. authentication, confidentiality, replay detection and sequence
  1194. detection.
  1195. When ISC_REQ_PROMPT_FOR_CREDS flag is set the security package always
  1196. prompts the user for credentials, irrespective of whether credentials
  1197. are present or not. If user indicated that the supplied credentials be
  1198. used then they will be stashed (overwriting existing ones if any) for
  1199. future use. The security packages will always prompt for credentials
  1200. if none existed, this optimizes for the most common case before a
  1201. credentials database is built. But the security packages can be
  1202. configured to not do that. Security packages will ensure that they
  1203. only prompt to the interactive user, for other logon sessions, this
  1204. flag is ignored.
  1205. When ISC_REQ_USE_SUPPLIED_CREDS flag is set the security package always
  1206. uses the credentials supplied in the InitializeSecurityContext() call
  1207. via InputToken parameter. If the package does not have any credentials
  1208. available it will prompt for them and record it as indicated above.
  1209. It is an error to set both these flags simultaneously.
  1210. If the ISC_REQ_ALLOCATE_MEMORY was specified then the caller must free
  1211. the memory pointed to by OutputToken by calling FreeContextBuffer().
  1212. For example, the InputToken may be the challenge from a LAN Manager or
  1213. NT file server. In this case, the OutputToken would be the NTLM
  1214. encrypted response to the challenge. The caller of this API can then
  1215. take the appropriate response (case-sensitive v. case-insensitive) and
  1216. return it to the server for an authenticated connection.
  1217. Arguments:
  1218. CredentialHandle - Handle to the credentials to be used to
  1219. create the context.
  1220. OldContextHandle - Handle to the partially formed context, if this is
  1221. a second call (see above) or NULL if this is the first call.
  1222. TargetName - String indicating the target of the context. The name will
  1223. be security package specific. For example it will be a fully
  1224. qualified Cairo name for Kerberos package and can be UNC name or
  1225. domain name for the NTLM package.
  1226. ContextReqFlags - Requirements of the context, package specific.
  1227. #define ISC_REQ_DELEGATE 0x00000001
  1228. #define ISC_REQ_MUTUAL_AUTH 0x00000002
  1229. #define ISC_REQ_REPLAY_DETECT 0x00000004
  1230. #define ISC_REQ_SEQUENCE_DETECT 0x00000008
  1231. #define ISC_REQ_CONFIDENTIALITY 0x00000010
  1232. #define ISC_REQ_USE_SESSION_KEY 0x00000020
  1233. #define ISC_REQ_PROMT_FOR__CREDS 0x00000040
  1234. #define ISC_REQ_USE_SUPPLIED_CREDS 0x00000080
  1235. #define ISC_REQ_ALLOCATE_MEMORY 0x00000100
  1236. #define ISC_REQ_USE_DCE_STYLE 0x00000200
  1237. Reserved1 - Reserved value, MBZ.
  1238. TargetDataRep - Long indicating the data representation (byte ordering, etc)
  1239. on the target. The constant SECURITY_NATIVE_DREP may be supplied
  1240. by the transport indicating that the native format is in use.
  1241. InputToken - Pointer to the input token. In the first call this
  1242. token can either be NULL or may contain security package specific
  1243. information.
  1244. Reserved2 - Reserved value, MBZ.
  1245. NewContextHandle - New context handle. If this is a second call, this
  1246. can be the same as OldContextHandle.
  1247. OutputToken - Buffer to receive the output token.
  1248. ContextAttributes -Attributes of the context established.
  1249. #define ISC_RET_DELEGATE 0x00000001
  1250. #define ISC_RET_MUTUAL_AUTH 0x00000002
  1251. #define ISC_RET_REPLAY_DETECT 0x00000004
  1252. #define ISC_RET_SEQUENCE_DETECT 0x00000008
  1253. #define ISC_REP_CONFIDENTIALITY 0x00000010
  1254. #define ISC_REP_USE_SESSION_KEY 0x00000020
  1255. #define ISC_REP_USED_COLLECTED_CREDS 0x00000040
  1256. #define ISC_REP_USED_SUPPLIED_CREDS 0x00000080
  1257. #define ISC_REP_ALLOCATED_MEMORY 0x00000100
  1258. #define ISC_REP_USED_DCE_STYLE 0x00000200
  1259. ExpirationTime - Expiration time of the context.
  1260. Return Value:
  1261. STATUS_SUCCESS - Message handled
  1262. SEC_I_CALLBACK_NEEDED -- Caller should call again later
  1263. SEC_E_NO_SPM -- Security Support Provider is not running
  1264. SEC_E_INVALID_TOKEN -- Token improperly formatted
  1265. SEC_E_INVALID_HANDLE -- Credential/Context Handle is invalid
  1266. SEC_E_BUFFER_TOO_SMALL -- Buffer for output token isn't big enough
  1267. SEC_E_NO_CREDENTIALS -- There are no credentials for this client
  1268. SEC_E_INSUFFICIENT_MEMORY -- Not enough memory
  1269. --*/
  1270. {
  1271. SECURITY_STATUS SecStatus;
  1272. PVOID InputTokenBuffer;
  1273. PULONG InputTokenSize;
  1274. ULONG LocalInputTokenSize;
  1275. PVOID OutputTokenBuffer;
  1276. PULONG OutputTokenSize;
  1277. SspPrint((SSP_API, "SspInitializeSecurityContext Entered\n"));
  1278. //
  1279. // Check argument validity
  1280. //
  1281. if (!ARGUMENT_PRESENT(OutputToken)) {
  1282. return (ERROR_BAD_ARGUMENTS);
  1283. }
  1284. #ifdef notdef // ? RPC passes 0x10 or 0 here depending on attitude
  1285. if ( TargetDataRep != SECURITY_NATIVE_DREP ) {
  1286. return (STATUS_INVALID_PARAMETER);
  1287. }
  1288. #else // notdef
  1289. UNREFERENCED_PARAMETER( TargetDataRep );
  1290. #endif // notdef
  1291. if ( !SspGetTokenBuffer( InputToken,
  1292. &InputTokenBuffer,
  1293. &InputTokenSize,
  1294. TRUE ) ) {
  1295. return (SEC_E_INVALID_TOKEN);
  1296. }
  1297. if ( InputTokenSize == 0 ) {
  1298. InputTokenSize = &LocalInputTokenSize;
  1299. LocalInputTokenSize = 0;
  1300. }
  1301. if ( !SspGetTokenBuffer( OutputToken,
  1302. &OutputTokenBuffer,
  1303. &OutputTokenSize,
  1304. FALSE ) ) {
  1305. return (SEC_E_INVALID_TOKEN);
  1306. }
  1307. //
  1308. // If no previous context was passed in this is the first call.
  1309. //
  1310. if ( !ARGUMENT_PRESENT( OldContextHandle ) ) {
  1311. if ( !ARGUMENT_PRESENT( CredentialHandle ) ) {
  1312. return (SEC_E_INVALID_HANDLE);
  1313. }
  1314. return SspHandleFirstCall(
  1315. CredentialHandle,
  1316. NewContextHandle,
  1317. ContextReqFlags,
  1318. QOP_NTLMV2,
  1319. *InputTokenSize,
  1320. InputTokenBuffer,
  1321. OutputTokenSize,
  1322. OutputTokenBuffer,
  1323. ContextAttributes,
  1324. ExpirationTime
  1325. );
  1326. //
  1327. // If context was passed in, continue where we left off.
  1328. //
  1329. } else {
  1330. *NewContextHandle = *OldContextHandle;
  1331. return SspHandleChallengeMessage(
  1332. NULL,
  1333. CredentialHandle,
  1334. NewContextHandle,
  1335. ContextReqFlags,
  1336. *InputTokenSize,
  1337. InputTokenBuffer,
  1338. OutputTokenSize,
  1339. OutputTokenBuffer,
  1340. ContextAttributes,
  1341. ExpirationTime
  1342. );
  1343. }
  1344. return (SecStatus);
  1345. }
  1346. #if 0
  1347. SECURITY_STATUS SEC_ENTRY
  1348. QueryContextAttributes(
  1349. IN PCtxtHandle ContextHandle,
  1350. IN ULONG Attribute,
  1351. OUT PVOID Buffer
  1352. )
  1353. /*++
  1354. Routine Description:
  1355. This API allows a customer of the security services to determine
  1356. certain attributes of the context. These are: sizes, names, and
  1357. lifespan.
  1358. Arguments:
  1359. ContextHandle - Handle to the context to query.
  1360. Attribute - Attribute to query.
  1361. #define SECPKG_ATTR_SIZES 0
  1362. #define SECPKG_ATTR_NAMES 1
  1363. #define SECPKG_ATTR_LIFESPAN 2
  1364. Buffer - Buffer to copy the data into. The buffer must be large enough
  1365. to fit the queried attribute.
  1366. Return Value:
  1367. SEC_E_OK - Call completed successfully
  1368. SEC_E_NO_SPM -- Security Support Provider is not running
  1369. SEC_E_INVALID_HANDLE -- Credential/Context Handle is invalid
  1370. SEC_E_UNSUPPORTED_FUNCTION -- Function code is not supported
  1371. --*/
  1372. {
  1373. SecPkgContext_Sizes ContextSizes;
  1374. SecPkgContext_Lifespan ContextLifespan;
  1375. UCHAR ContextNamesBuffer[sizeof(SecPkgContext_Names)+20];
  1376. PSecPkgContext_Names ContextNames;
  1377. int ContextNamesSize;
  1378. SECURITY_STATUS SecStatus = SEC_E_OK;
  1379. PSSP_CONTEXT Context = NULL;
  1380. //
  1381. // Initialization
  1382. //
  1383. SspPrint(( SSP_API, "SspQueryContextAttributes Entered\n" ));
  1384. //
  1385. // Find the currently existing context.
  1386. //
  1387. Context = SspContextReferenceContext( ContextHandle,
  1388. FALSE );
  1389. if ( Context == NULL ) {
  1390. SecStatus = SEC_E_INVALID_HANDLE;
  1391. goto Cleanup;
  1392. }
  1393. //
  1394. // Handle each of the various queried attributes
  1395. //
  1396. switch ( Attribute) {
  1397. case SECPKG_ATTR_SIZES:
  1398. ContextSizes.cbMaxToken = NTLMSP_MAX_TOKEN_SIZE;
  1399. if (Context->NegotiateFlags & (NTLMSSP_NEGOTIATE_ALWAYS_SIGN |
  1400. NTLMSSP_NEGOTIATE_SIGN |
  1401. NTLMSSP_NEGOTIATE_SEAL ))
  1402. {
  1403. ContextSizes.cbMaxSignature = NTLMSSP_MESSAGE_SIGNATURE_SIZE;
  1404. }
  1405. else
  1406. {
  1407. ContextSizes.cbMaxSignature = 0;
  1408. }
  1409. if (Context->NegotiateFlags & NTLMSSP_NEGOTIATE_SEAL)
  1410. {
  1411. ContextSizes.cbBlockSize = 1;
  1412. ContextSizes.cbSecurityTrailer = NTLMSSP_MESSAGE_SIGNATURE_SIZE;
  1413. }
  1414. else
  1415. {
  1416. ContextSizes.cbBlockSize = 0;
  1417. ContextSizes.cbSecurityTrailer = 0;
  1418. }
  1419. _fmemcpy(Buffer, &ContextSizes, sizeof(ContextSizes));
  1420. break;
  1421. //
  1422. // No one uses the function so don't go to the overhead of maintaining
  1423. // the username in the context structure.
  1424. //
  1425. case SECPKG_ATTR_NAMES:
  1426. ContextNames = (PSecPkgContext_Names)Buffer;
  1427. ContextNames->sUserName = (SEC_CHAR *) SspAlloc(1);
  1428. if (ContextNames->sUserName == NULL) {
  1429. SecStatus = SEC_E_INSUFFICIENT_MEMORY;
  1430. goto Cleanup;
  1431. }
  1432. *ContextNames->sUserName = '\0';
  1433. break;
  1434. case SECPKG_ATTR_LIFESPAN:
  1435. // Use the correct times here
  1436. ContextLifespan.tsStart = SspContextGetTimeStamp( Context, FALSE );
  1437. ContextLifespan.tsExpiry = SspContextGetTimeStamp( Context, TRUE );
  1438. _fmemcpy(Buffer, &ContextLifespan, sizeof(ContextLifespan));
  1439. break;
  1440. default:
  1441. SecStatus = SEC_E_NOT_SUPPORTED;
  1442. break;
  1443. }
  1444. //
  1445. // Free local resources
  1446. //
  1447. Cleanup:
  1448. if ( Context != NULL ) {
  1449. SspContextDereferenceContext( Context );
  1450. }
  1451. SspPrint(( SSP_API, "SspQueryContextAttributes returns 0x%x\n", SecStatus ));
  1452. return SecStatus;
  1453. }
  1454. #endif
  1455. SECURITY_STATUS SEC_ENTRY
  1456. DeleteSecurityContext (
  1457. PCtxtHandle ContextHandle
  1458. )
  1459. /*++
  1460. Routine Description:
  1461. Deletes the local data structures associated with the specified
  1462. security context and generates a token which is passed to a remote peer
  1463. so it too can remove the corresponding security context.
  1464. This API terminates a context on the local machine, and optionally
  1465. provides a token to be sent to the other machine. The OutputToken
  1466. generated by this call is to be sent to the remote peer (initiator or
  1467. acceptor). If the context was created with the I _REQ_ALLOCATE_MEMORY
  1468. flag, then the package will allocate a buffer for the output token.
  1469. Otherwise, it is the responsibility of the caller.
  1470. Arguments:
  1471. ContextHandle - Handle to the context to delete
  1472. TokenLength - Size of the output token (if any) that should be sent to
  1473. the process at the other end of the session.
  1474. Token - Pointer to the token to send.
  1475. Return Value:
  1476. SEC_E_OK - Call completed successfully
  1477. SEC_E_NO_SPM -- Security Support Provider is not running
  1478. SEC_E_INVALID_HANDLE -- Credential/Context Handle is invalid
  1479. --*/
  1480. {
  1481. SECURITY_STATUS SecStatus;
  1482. PSSP_CONTEXT Context = NULL;
  1483. //
  1484. // Initialization
  1485. //
  1486. SspPrint(( SSP_API, "SspDeleteSecurityContext Entered\n" ));
  1487. //
  1488. // Find the currently existing context (and delink it).
  1489. //
  1490. Context = SspContextReferenceContext( ContextHandle,
  1491. TRUE );
  1492. if ( Context == NULL ) {
  1493. SecStatus = SEC_E_INVALID_HANDLE;
  1494. goto cleanup;
  1495. } else {
  1496. SspContextDereferenceContext( Context );
  1497. SecStatus = SEC_E_OK;
  1498. }
  1499. cleanup:
  1500. if (Context != NULL) {
  1501. SspContextDereferenceContext(Context);
  1502. Context = NULL;
  1503. }
  1504. SspPrint(( SSP_API, "SspDeleteSecurityContext returns 0x%x\n", SecStatus ));
  1505. return SecStatus;
  1506. }
  1507. SECURITY_STATUS SEC_ENTRY
  1508. FreeContextBuffer (
  1509. void * ContextBuffer
  1510. )
  1511. /*++
  1512. Routine Description:
  1513. This API is provided to allow callers of security API such as
  1514. InitializeSecurityContext() for free the memory buffer allocated for
  1515. returning the outbound context token.
  1516. Arguments:
  1517. ContextBuffer - Address of the buffer to be freed.
  1518. Return Value:
  1519. SEC_E_OK - Call completed successfully
  1520. --*/
  1521. {
  1522. //
  1523. // The only allocated buffer that NtLmSsp currently returns to the caller
  1524. // is from EnumeratePackages. It uses LocalAlloc to allocate memory. If
  1525. // we ever need memory to be allocated by the service, we have to rethink
  1526. // how this routine distinguishes between to two types of allocated memory.
  1527. //
  1528. SspFree( ContextBuffer );
  1529. return (SEC_E_OK);
  1530. }
  1531. SECURITY_STATUS SEC_ENTRY
  1532. ApplyControlToken (
  1533. PCtxtHandle ContextHandle,
  1534. PSecBufferDesc Input
  1535. )
  1536. {
  1537. #ifdef DEBUGRPC
  1538. SspPrint(( SSP_API, "ApplyContextToken Called\n" ));
  1539. #endif // DEBUGRPC
  1540. return SEC_E_UNSUPPORTED_FUNCTION;
  1541. UNREFERENCED_PARAMETER( ContextHandle );
  1542. UNREFERENCED_PARAMETER( Input );
  1543. }
  1544. void
  1545. SsprGenCheckSum(
  1546. IN PSecBuffer pMessage,
  1547. OUT PNTLMSSP_MESSAGE_SIGNATURE pSig
  1548. )
  1549. {
  1550. Crc32(pSig->CheckSum,pMessage->cbBuffer,pMessage->pvBuffer,&pSig->CheckSum);
  1551. }
  1552. SECURITY_STATUS SEC_ENTRY
  1553. MakeSignature(
  1554. IN OUT PCtxtHandle ContextHandle,
  1555. IN ULONG fQOP,
  1556. IN OUT PSecBufferDesc pMessage,
  1557. IN ULONG MessageSeqNo
  1558. )
  1559. {
  1560. PSSP_CONTEXT pContext;
  1561. PNTLMSSP_MESSAGE_SIGNATURE pSig;
  1562. int Signature;
  1563. ULONG i;
  1564. pContext = SspContextReferenceContext(ContextHandle,FALSE);
  1565. if (!pContext ||
  1566. (!(pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM2)
  1567. && (pContext->Rc4Key == NULL)
  1568. && !(pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN)
  1569. )
  1570. )
  1571. {
  1572. return(SEC_E_INVALID_HANDLE);
  1573. }
  1574. if (pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM2)
  1575. {
  1576. return SspNtlmv2MakeSignature(
  1577. &pContext->Ntlmv2SKeys,
  1578. pContext->NegotiateFlags,
  1579. fQOP,
  1580. MessageSeqNo,
  1581. pMessage
  1582. );
  1583. }
  1584. Signature = -1;
  1585. for (i = 0; i < pMessage->cBuffers; i++)
  1586. {
  1587. if ((pMessage->pBuffers[i].BufferType & 0xFF) == SECBUFFER_TOKEN)
  1588. {
  1589. Signature = i;
  1590. break;
  1591. }
  1592. }
  1593. if (Signature == -1)
  1594. {
  1595. SspContextDereferenceContext(pContext);
  1596. return(SEC_E_INVALID_TOKEN);
  1597. }
  1598. pSig = pMessage->pBuffers[Signature].pvBuffer;
  1599. if (!(pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_SIGN))
  1600. {
  1601. _fmemset(pSig,0,NTLMSSP_MESSAGE_SIGNATURE_SIZE);
  1602. pSig->Version = NTLMSSP_SIGN_VERSION;
  1603. swaplong(pSig->Version) ; // MACBUG
  1604. SspContextDereferenceContext(pContext);
  1605. return(SEC_E_OK);
  1606. }
  1607. //
  1608. // required by CRC-32 algorithm
  1609. //
  1610. pSig->CheckSum = 0xffffffff;
  1611. for (i = 0; i < pMessage->cBuffers ; i++ )
  1612. {
  1613. if (((pMessage->pBuffers[i].BufferType & 0xFF) == SECBUFFER_DATA) &&
  1614. !(pMessage->pBuffers[i].BufferType & SECBUFFER_READONLY))
  1615. {
  1616. SsprGenCheckSum(&pMessage->pBuffers[i], pSig);
  1617. }
  1618. }
  1619. //
  1620. // Required by CRC-32 algorithm
  1621. //
  1622. pSig->CheckSum ^= 0xffffffff;
  1623. pSig->Nonce = pContext->Nonce++;
  1624. pSig->Version = NTLMSSP_SIGN_VERSION; // MACBUG
  1625. swaplong(pSig->CheckSum) ;
  1626. swaplong(pSig->Nonce) ;
  1627. swaplong(pSig->Version) ;
  1628. rc4(pContext->Rc4Key, sizeof(NTLMSSP_MESSAGE_SIGNATURE) - sizeof(ULONG),
  1629. (unsigned char SEC_FAR *) &pSig->RandomPad);
  1630. pMessage->pBuffers[Signature].cbBuffer = sizeof(NTLMSSP_MESSAGE_SIGNATURE);
  1631. SspContextDereferenceContext(pContext);
  1632. return(SEC_E_OK);
  1633. }
  1634. SECURITY_STATUS SEC_ENTRY
  1635. VerifySignature(
  1636. IN OUT PCtxtHandle ContextHandle,
  1637. IN OUT PSecBufferDesc pMessage,
  1638. IN ULONG MessageSeqNo,
  1639. OUT PULONG pfQOP
  1640. )
  1641. {
  1642. PSSP_CONTEXT pContext;
  1643. PNTLMSSP_MESSAGE_SIGNATURE pSig;
  1644. NTLMSSP_MESSAGE_SIGNATURE Sig;
  1645. int Signature;
  1646. ULONG i;
  1647. UNREFERENCED_PARAMETER(pfQOP);
  1648. UNREFERENCED_PARAMETER(MessageSeqNo);
  1649. pContext = SspContextReferenceContext(ContextHandle,FALSE);
  1650. if (!pContext ||
  1651. (!(pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM2)
  1652. && (pContext->Rc4Key == NULL)
  1653. && !(pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN)
  1654. )
  1655. )
  1656. {
  1657. return(SEC_E_INVALID_HANDLE);
  1658. }
  1659. if (pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM2)
  1660. {
  1661. return SspNtlmv2VerifySignature(
  1662. &pContext->Ntlmv2SKeys,
  1663. pContext->NegotiateFlags,
  1664. MessageSeqNo,
  1665. pMessage,
  1666. pfQOP
  1667. );
  1668. }
  1669. Signature = -1;
  1670. for (i = 0; i < pMessage->cBuffers; i++)
  1671. {
  1672. if ((pMessage->pBuffers[i].BufferType & 0xFF) == SECBUFFER_TOKEN)
  1673. {
  1674. Signature = i;
  1675. break;
  1676. }
  1677. }
  1678. if (Signature == -1)
  1679. {
  1680. SspContextDereferenceContext(pContext);
  1681. return(SEC_E_INVALID_TOKEN);
  1682. }
  1683. pSig = pMessage->pBuffers[Signature].pvBuffer;
  1684. swaplong(pSig->Version) ;
  1685. //
  1686. // Check if this is just a trailer and not a real signature
  1687. //
  1688. if (!(pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_SIGN))
  1689. {
  1690. SspContextDereferenceContext(pContext);
  1691. _fmemset(&Sig,0,NTLMSSP_MESSAGE_SIGNATURE_SIZE);
  1692. Sig.Version = NTLMSSP_SIGN_VERSION;
  1693. if (!_fmemcmp(&Sig,pSig,NTLMSSP_MESSAGE_SIGNATURE_SIZE))
  1694. {
  1695. return(SEC_E_OK);
  1696. }
  1697. return(SEC_E_MESSAGE_ALTERED);
  1698. }
  1699. Sig.CheckSum = 0xffffffff;
  1700. for (i = 0; i < pMessage->cBuffers ; i++ )
  1701. {
  1702. if (((pMessage->pBuffers[i].BufferType & 0xFF) == SECBUFFER_DATA) &&
  1703. !(pMessage->pBuffers[i].BufferType & SECBUFFER_READONLY))
  1704. {
  1705. SsprGenCheckSum(&pMessage->pBuffers[i], &Sig);
  1706. }
  1707. }
  1708. Sig.CheckSum ^= 0xffffffff;
  1709. Sig.Nonce = pContext->Nonce++;
  1710. rc4(pContext->Rc4Key, sizeof(NTLMSSP_MESSAGE_SIGNATURE) - sizeof(ULONG),
  1711. (unsigned char SEC_FAR *) &pSig->RandomPad);
  1712. SspContextDereferenceContext(pContext);
  1713. swaplong(pSig->CheckSum) ;
  1714. swaplong(pSig->Nonce) ;
  1715. if (pSig->CheckSum != Sig.CheckSum)
  1716. {
  1717. return(SEC_E_MESSAGE_ALTERED);
  1718. }
  1719. if (pSig->Nonce != Sig.Nonce)
  1720. {
  1721. return(SEC_E_OUT_OF_SEQUENCE);
  1722. }
  1723. return(SEC_E_OK);
  1724. }
  1725. SECURITY_STATUS SEC_ENTRY
  1726. SealMessage(
  1727. IN OUT PCtxtHandle ContextHandle,
  1728. IN ULONG fQOP,
  1729. IN OUT PSecBufferDesc pMessage,
  1730. IN ULONG MessageSeqNo
  1731. )
  1732. {
  1733. PSSP_CONTEXT pContext;
  1734. PNTLMSSP_MESSAGE_SIGNATURE pSig;
  1735. int Signature;
  1736. ULONG i;
  1737. UNREFERENCED_PARAMETER(fQOP);
  1738. UNREFERENCED_PARAMETER(MessageSeqNo);
  1739. pContext = SspContextReferenceContext(ContextHandle, FALSE);
  1740. if (!pContext ||
  1741. (!(pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM2)
  1742. && (pContext->Rc4Key == NULL)
  1743. )
  1744. )
  1745. {
  1746. return(SEC_E_INVALID_HANDLE);
  1747. }
  1748. if (pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM2)
  1749. {
  1750. return SspNtlmv2SealMessage(
  1751. &pContext->Ntlmv2SKeys,
  1752. pContext->NegotiateFlags,
  1753. fQOP,
  1754. MessageSeqNo,
  1755. pMessage
  1756. );
  1757. }
  1758. Signature = -1;
  1759. for (i = 0; i < pMessage->cBuffers; i++)
  1760. {
  1761. if ((pMessage->pBuffers[i].BufferType & 0xFF) == SECBUFFER_TOKEN)
  1762. {
  1763. Signature = i;
  1764. break;
  1765. }
  1766. }
  1767. if (Signature == -1)
  1768. {
  1769. SspContextDereferenceContext(pContext);
  1770. return(SEC_E_INVALID_TOKEN);
  1771. }
  1772. pSig = pMessage->pBuffers[Signature].pvBuffer;
  1773. //
  1774. // required by CRC-32 algorithm
  1775. //
  1776. pSig->CheckSum = 0xffffffff;
  1777. for (i = 0; i < pMessage->cBuffers ; i++ )
  1778. {
  1779. if (((pMessage->pBuffers[i].BufferType & 0xFF) == SECBUFFER_DATA) &&
  1780. !(pMessage->pBuffers[i].BufferType & SECBUFFER_READONLY))
  1781. {
  1782. SsprGenCheckSum(&pMessage->pBuffers[i], pSig);
  1783. if (pMessage->pBuffers[i].cbBuffer) // rc4 fails with zero byte buffers
  1784. {
  1785. rc4(pContext->Rc4Key,
  1786. (int) pMessage->pBuffers[i].cbBuffer,
  1787. (PUCHAR) pMessage->pBuffers[i].pvBuffer );
  1788. }
  1789. }
  1790. }
  1791. //
  1792. // Required by CRC-32 algorithm
  1793. //
  1794. pSig->CheckSum ^= 0xffffffff;
  1795. pSig->Nonce = pContext->Nonce++;
  1796. pSig->Version = NTLMSSP_SIGN_VERSION; // MACBUG
  1797. swaplong(pSig->CheckSum) ;
  1798. swaplong(pSig->Nonce) ;
  1799. swaplong(pSig->Version) ;
  1800. rc4(pContext->Rc4Key, sizeof(NTLMSSP_MESSAGE_SIGNATURE) - sizeof(ULONG),
  1801. (PUCHAR) &pSig->RandomPad);
  1802. pMessage->pBuffers[Signature].cbBuffer = sizeof(NTLMSSP_MESSAGE_SIGNATURE);
  1803. SspContextDereferenceContext(pContext);
  1804. return(SEC_E_OK);
  1805. }
  1806. SECURITY_STATUS SEC_ENTRY
  1807. UnsealMessage(
  1808. IN OUT PCtxtHandle ContextHandle,
  1809. IN OUT PSecBufferDesc pMessage,
  1810. IN ULONG MessageSeqNo,
  1811. OUT PULONG pfQOP
  1812. )
  1813. {
  1814. PSSP_CONTEXT pContext;
  1815. PNTLMSSP_MESSAGE_SIGNATURE pSig;
  1816. NTLMSSP_MESSAGE_SIGNATURE Sig;
  1817. int Signature;
  1818. ULONG i;
  1819. UNREFERENCED_PARAMETER(pfQOP);
  1820. UNREFERENCED_PARAMETER(MessageSeqNo);
  1821. pContext = SspContextReferenceContext(ContextHandle, FALSE);
  1822. if (!pContext ||
  1823. (!(pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM2)
  1824. && (!pContext->Rc4Key)
  1825. )
  1826. )
  1827. {
  1828. return(SEC_E_INVALID_HANDLE);
  1829. }
  1830. if (pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM2)
  1831. {
  1832. return SspNtlmv2UnsealMessage(
  1833. &pContext->Ntlmv2SKeys,
  1834. pContext->NegotiateFlags,
  1835. MessageSeqNo,
  1836. pMessage,
  1837. pfQOP
  1838. );
  1839. }
  1840. Signature = -1;
  1841. for (i = 0; i < pMessage->cBuffers; i++)
  1842. {
  1843. if ((pMessage->pBuffers[i].BufferType & 0xFF) == SECBUFFER_TOKEN)
  1844. {
  1845. Signature = i;
  1846. break;
  1847. }
  1848. }
  1849. if (Signature == -1)
  1850. {
  1851. SspContextDereferenceContext(pContext);
  1852. return(SEC_E_INVALID_TOKEN);
  1853. }
  1854. pSig = pMessage->pBuffers[Signature].pvBuffer;
  1855. Sig.CheckSum = 0xffffffff;
  1856. for (i = 0; i < pMessage->cBuffers ; i++ )
  1857. {
  1858. if (((pMessage->pBuffers[i].BufferType & 0xFF) == SECBUFFER_DATA) &&
  1859. !(pMessage->pBuffers[i].BufferType & SECBUFFER_READONLY))
  1860. {
  1861. if (pMessage->pBuffers[i].cbBuffer)
  1862. {
  1863. rc4(pContext->Rc4Key,
  1864. (int) pMessage->pBuffers[i].cbBuffer,
  1865. (unsigned char *) pMessage->pBuffers[i].pvBuffer );
  1866. }
  1867. SsprGenCheckSum(&pMessage->pBuffers[i], &Sig);
  1868. }
  1869. }
  1870. Sig.CheckSum ^= 0xffffffff;
  1871. Sig.Nonce = pContext->Nonce++;
  1872. rc4(pContext->Rc4Key, sizeof(NTLMSSP_MESSAGE_SIGNATURE) - sizeof(ULONG),
  1873. (unsigned char *) &pSig->RandomPad);
  1874. SspContextDereferenceContext(pContext);
  1875. swaplong(pSig->Nonce) ;
  1876. swaplong(pSig->CheckSum) ;
  1877. if (pSig->Nonce != Sig.Nonce)
  1878. {
  1879. return(SEC_E_OUT_OF_SEQUENCE);
  1880. }
  1881. if (pSig->CheckSum != Sig.CheckSum)
  1882. {
  1883. return(SEC_E_MESSAGE_ALTERED);
  1884. }
  1885. return(SEC_E_OK);
  1886. }
  1887. #if 0
  1888. SECURITY_STATUS SEC_ENTRY
  1889. CompleteAuthToken (
  1890. PCtxtHandle ContextHandle,
  1891. PSecBufferDesc BufferDescriptor
  1892. )
  1893. {
  1894. #ifdef DEBUGRPC
  1895. SspPrint(( SSP_API, "CompleteAuthToken Called\n" ));
  1896. #endif // DEBUGRPC
  1897. return SEC_E_UNSUPPORTED_FUNCTION;
  1898. UNREFERENCED_PARAMETER( ContextHandle );
  1899. UNREFERENCED_PARAMETER( BufferDescriptor );
  1900. }
  1901. #endif