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.

990 lines
24 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name :
  4. digestprovider.cxx
  5. Abstract:
  6. Digest authentication provider
  7. Author:
  8. Ming Lu (minglu) 24-Jun-2000
  9. Environment:
  10. Win32 - User Mode
  11. Project:
  12. ULW3.DLL
  13. --*/
  14. #include "precomp.hxx"
  15. #include "sspiprovider.hxx"
  16. #include "digestprovider.hxx"
  17. #include "uuencode.hxx"
  18. ALLOC_CACHE_HANDLER * DIGEST_SECURITY_CONTEXT::sm_pachDIGESTSecContext
  19. = NULL;
  20. //static
  21. HRESULT
  22. DIGEST_AUTH_PROVIDER::Initialize(
  23. DWORD dwInternalId
  24. )
  25. /*++
  26. Routine Description:
  27. Initialize Digest SSPI provider
  28. Arguments:
  29. None
  30. Return Value:
  31. HRESULT
  32. --*/
  33. {
  34. HRESULT hr;
  35. SetInternalId( dwInternalId );
  36. hr = DIGEST_SECURITY_CONTEXT::Initialize();
  37. if ( FAILED( hr ) )
  38. {
  39. DBGPRINTF(( DBG_CONTEXT,
  40. "Error initializing Digest Auth Prov. hr = %x\n",
  41. hr ));
  42. return hr;
  43. }
  44. return NO_ERROR;
  45. }
  46. //static
  47. VOID
  48. DIGEST_AUTH_PROVIDER::Terminate(
  49. VOID
  50. )
  51. /*++
  52. Routine Description:
  53. Terminate SSPI Digest provider
  54. Arguments:
  55. None
  56. Return Value:
  57. None
  58. --*/
  59. {
  60. DIGEST_SECURITY_CONTEXT::Terminate();
  61. }
  62. HRESULT
  63. DIGEST_AUTH_PROVIDER::DoesApply(
  64. W3_MAIN_CONTEXT * pMainContext,
  65. BOOL * pfApplies
  66. )
  67. /*++
  68. Routine Description:
  69. Does the given request have credentials applicable to the Digest
  70. provider
  71. Arguments:
  72. pMainContext - Main context representing request
  73. pfApplies - Set to true if Digest is applicable
  74. Return Value:
  75. HRESULT
  76. --*/
  77. {
  78. CHAR * pszAuthHeader = NULL;
  79. HRESULT hr;
  80. SSPI_CONTEXT_STATE * pContextState;
  81. STACK_STRA( strPackage, 64 );
  82. W3_METADATA * pMetaData = NULL;
  83. if ( pMainContext == NULL ||
  84. pfApplies == NULL )
  85. {
  86. DBG_ASSERT( FALSE );
  87. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  88. }
  89. *pfApplies = FALSE;
  90. //
  91. // Is using of Digest SSP enabled?
  92. //
  93. if ( !g_pW3Server->QueryUseDigestSSP() )
  94. {
  95. return NO_ERROR;
  96. }
  97. //
  98. // Get the auth type
  99. //
  100. hr = pMainContext->QueryRequest()->GetAuthType( &strPackage );
  101. if ( FAILED( hr ) )
  102. {
  103. return hr;
  104. }
  105. //
  106. // No package, no auth
  107. //
  108. if ( strPackage.IsEmpty() )
  109. {
  110. return NO_ERROR;
  111. }
  112. //
  113. // Is it Digest?
  114. //
  115. if ( _stricmp( strPackage.QueryStr(), "Digest" ) == 0 )
  116. {
  117. //
  118. // Save away the package so we don't have to calc again
  119. //
  120. DBG_ASSERT( !strPackage.IsEmpty() );
  121. pszAuthHeader = pMainContext->QueryRequest()->GetHeader( HttpHeaderAuthorization );
  122. DBG_ASSERT( pszAuthHeader != NULL );
  123. pContextState = new (pMainContext) SSPI_CONTEXT_STATE(
  124. pszAuthHeader + strPackage.QueryCCH() + 1 );
  125. if ( pContextState == NULL )
  126. {
  127. return HRESULT_FROM_WIN32( GetLastError() );
  128. }
  129. hr = pContextState->SetPackage( strPackage.QueryStr() );
  130. if ( FAILED( hr ) )
  131. {
  132. DBGPRINTF(( DBG_CONTEXT,
  133. "Error in SetPackage(). hr = %x\n",
  134. hr ));
  135. delete pContextState;
  136. pContextState = NULL;
  137. return hr;
  138. }
  139. pMainContext->SetContextState( pContextState );
  140. *pfApplies = TRUE;
  141. }
  142. return NO_ERROR;
  143. }
  144. HRESULT
  145. DIGEST_AUTH_PROVIDER::DoAuthenticate(
  146. W3_MAIN_CONTEXT * pMainContext
  147. )
  148. /*++
  149. Description:
  150. Do authentication work (we will be called if we apply)
  151. Arguments:
  152. pMainContext - Main context
  153. Return Value:
  154. HRESULT
  155. --*/
  156. {
  157. DWORD err;
  158. HRESULT hr = E_FAIL;
  159. W3_METADATA * pMetaData = NULL;
  160. W3_CONNECTION * pW3Connection = NULL;
  161. DIGEST_SECURITY_CONTEXT * pDigestSecurityContext = NULL;
  162. SSPI_CONTEXT_STATE * pContextState = NULL;
  163. SSPI_USER_CONTEXT * pUserContext = NULL;
  164. SSPI_CREDENTIAL * pDigestCredentials = NULL;
  165. SecBufferDesc SecBuffDescOutput;
  166. SecBufferDesc SecBuffDescInput;
  167. //
  168. // We have 5 input buffer and 1 output buffer to fill data
  169. // in for digest authentication
  170. //
  171. SecBuffer SecBuffTokenOut[ 1 ];
  172. SecBuffer SecBuffTokenIn[ 5 ];
  173. SECURITY_STATUS secStatus = SEC_E_OK;
  174. CtxtHandle hServerCtxtHandle;
  175. TimeStamp Lifetime;
  176. ULONG ContextReqFlags = 0;
  177. ULONG ContextAttributes = 0;
  178. STACK_STRU( strOutputHeader, 256 );
  179. STACK_BUFFER( bufOutputBuffer, 4096 );
  180. STACK_STRA( strMethod, 10 );
  181. STACK_STRU( strUrl, MAX_PATH );
  182. STACK_STRA( strUrlA, MAX_PATH );
  183. STACK_STRA( strRealm, 128 );
  184. if ( pMainContext == NULL )
  185. {
  186. DBG_ASSERT( FALSE );
  187. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  188. }
  189. pContextState = ( SSPI_CONTEXT_STATE* )
  190. pMainContext->QueryContextState();
  191. DBG_ASSERT( pContextState != NULL );
  192. pMetaData = pMainContext->QueryUrlContext()->QueryMetaData();
  193. DBG_ASSERT( pMetaData != NULL );
  194. //
  195. // clean the memory and set it to zero
  196. //
  197. ZeroMemory( &SecBuffDescOutput, sizeof( SecBufferDesc ) );
  198. ZeroMemory( SecBuffTokenOut , sizeof( SecBuffTokenOut ) );
  199. ZeroMemory( &SecBuffDescInput , sizeof( SecBufferDesc ) );
  200. ZeroMemory( SecBuffTokenIn , sizeof( SecBuffTokenIn ) );
  201. //
  202. // define the buffer descriptor for the Outpt
  203. //
  204. SecBuffDescOutput.ulVersion = SECBUFFER_VERSION;
  205. SecBuffDescOutput.cBuffers = 1;
  206. SecBuffDescOutput.pBuffers = SecBuffTokenOut;
  207. SecBuffTokenOut[0].BufferType = SECBUFFER_TOKEN;
  208. SecBuffTokenOut[0].cbBuffer = bufOutputBuffer.QuerySize();
  209. SecBuffTokenOut[0].pvBuffer = ( PVOID )bufOutputBuffer.QueryPtr();
  210. //
  211. // define the buffer descriptor for the Input
  212. //
  213. SecBuffDescInput.ulVersion = SECBUFFER_VERSION;
  214. SecBuffDescInput.cBuffers = 5;
  215. SecBuffDescInput.pBuffers = SecBuffTokenIn;
  216. //
  217. // set the digest auth header in the buffer
  218. //
  219. SecBuffTokenIn[0].BufferType = SECBUFFER_TOKEN;
  220. SecBuffTokenIn[0].cbBuffer = strlen(pContextState->QueryCredentials());
  221. SecBuffTokenIn[0].pvBuffer = pContextState->QueryCredentials();
  222. //
  223. // Get and Set the information for the method
  224. //
  225. hr = pMainContext->QueryRequest()->GetVerbString( &strMethod );
  226. if ( FAILED( hr ) )
  227. {
  228. DBGPRINTF(( DBG_CONTEXT,
  229. "Error getting the method. hr = %x\n",
  230. hr ));
  231. return hr;
  232. }
  233. SecBuffTokenIn[1].BufferType = SECBUFFER_PKG_PARAMS;
  234. SecBuffTokenIn[1].cbBuffer = strMethod.QueryCCH();
  235. SecBuffTokenIn[1].pvBuffer = strMethod.QueryStr();
  236. //
  237. // Get and Set the infomation for the Url
  238. //
  239. hr = pMainContext->QueryRequest()->GetUrl( &strUrl );
  240. if( FAILED( hr ) )
  241. {
  242. DBGPRINTF(( DBG_CONTEXT,
  243. "Error getting the URL. hr = %x\n",
  244. hr ));
  245. return hr;
  246. }
  247. hr = strUrlA.CopyW( strUrl.QueryStr() );
  248. if( FAILED( hr ) )
  249. {
  250. DBGPRINTF(( DBG_CONTEXT,
  251. "Error copying the URL. hr = %x\n",
  252. hr ));
  253. return hr;
  254. }
  255. SecBuffTokenIn[2].BufferType = SECBUFFER_PKG_PARAMS;
  256. SecBuffTokenIn[2].cbBuffer = strUrlA.QueryCB();
  257. SecBuffTokenIn[2].pvBuffer = ( PVOID )strUrlA.QueryStr();
  258. //
  259. // Get and Set the information for the hentity
  260. //
  261. SecBuffTokenIn[3].BufferType = SECBUFFER_PKG_PARAMS;
  262. SecBuffTokenIn[3].cbBuffer = 0; // this is not yet implemeted
  263. SecBuffTokenIn[3].pvBuffer = 0; // this is not yet implemeted
  264. //
  265. //Get and Set the Realm Information
  266. //
  267. if( pMetaData->QueryRealm() )
  268. {
  269. hr = strRealm.CopyW( pMetaData->QueryRealm() );
  270. if( FAILED( hr ) )
  271. {
  272. DBGPRINTF(( DBG_CONTEXT,
  273. "Error copying the realm. hr = %x\n",
  274. hr ));
  275. return hr;
  276. }
  277. }
  278. SecBuffTokenIn[4].BufferType = SECBUFFER_PKG_PARAMS;
  279. SecBuffTokenIn[4].cbBuffer = strRealm.QueryCB();
  280. SecBuffTokenIn[4].pvBuffer = ( PVOID )strRealm.QueryStr();
  281. //
  282. // Get a Security Context
  283. //
  284. //
  285. // get the credential for the server
  286. //
  287. hr = SSPI_CREDENTIAL::GetCredential( NTDIGEST_SP_NAME,
  288. &pDigestCredentials );
  289. if ( FAILED( hr ) )
  290. {
  291. DBGPRINTF((DBG_CONTEXT,
  292. "Error get credential handle. hr = 0x%x \n",
  293. hr ));
  294. return hr;
  295. }
  296. DBG_ASSERT( pDigestCredentials != NULL );
  297. //
  298. // Resize the output buffer to max token size
  299. //
  300. if( !bufOutputBuffer.Resize(
  301. pDigestCredentials->QueryMaxTokenSize() ) )
  302. {
  303. return HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  304. }
  305. pDigestSecurityContext =
  306. ( DIGEST_SECURITY_CONTEXT * ) QueryConnectionAuthContext( pMainContext );
  307. //
  308. // check to see if there is an old Context Handle
  309. //
  310. if ( pDigestSecurityContext != NULL )
  311. {
  312. //
  313. // defined the buffer
  314. //
  315. SecBuffTokenIn[4].BufferType = SECBUFFER_TOKEN;
  316. SecBuffTokenIn[4].cbBuffer = bufOutputBuffer.QuerySize();
  317. SecBuffTokenIn[4].pvBuffer =
  318. ( PVOID )bufOutputBuffer.QueryPtr();
  319. secStatus = VerifySignature(
  320. pDigestSecurityContext->QueryContextHandle(),
  321. &SecBuffDescInput,
  322. 0,
  323. 0 );
  324. }
  325. else
  326. {
  327. //
  328. // set the flags
  329. //
  330. ContextReqFlags = ASC_REQ_REPLAY_DETECT |
  331. ASC_REQ_CONNECTION;
  332. //
  333. // get the security context
  334. //
  335. secStatus = AcceptSecurityContext(
  336. pDigestCredentials->QueryCredHandle(),
  337. NULL,
  338. &SecBuffDescInput,
  339. ContextReqFlags,
  340. SECURITY_NATIVE_DREP,
  341. &hServerCtxtHandle,
  342. &SecBuffDescOutput,
  343. &ContextAttributes,
  344. &Lifetime);
  345. if( SEC_I_COMPLETE_NEEDED == secStatus )
  346. {
  347. //
  348. //defined the buffer
  349. //
  350. SecBuffTokenIn[4].BufferType = SECBUFFER_TOKEN;
  351. SecBuffTokenIn[4].cbBuffer = bufOutputBuffer.QuerySize();
  352. SecBuffTokenIn[4].pvBuffer =
  353. ( PVOID )bufOutputBuffer.QueryPtr();
  354. secStatus = CompleteAuthToken(
  355. &hServerCtxtHandle,
  356. &SecBuffDescInput
  357. );
  358. }
  359. if ( SUCCEEDED( secStatus ) )
  360. {
  361. pDigestSecurityContext = new DIGEST_SECURITY_CONTEXT(
  362. pDigestCredentials );
  363. if ( NULL == pDigestSecurityContext )
  364. {
  365. return HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  366. }
  367. pDigestSecurityContext->SetContextHandle(
  368. hServerCtxtHandle );
  369. pDigestSecurityContext->SetContextAttributes(
  370. ContextAttributes );
  371. //
  372. // Mark the security context is complete, so we can detect
  373. // reauthentication on the same connection
  374. //
  375. // CODEWORK: Can probably get away will just
  376. // un-associating/deleting the
  377. // SSPI_SECURITY_CONTEXT now!
  378. //
  379. pDigestSecurityContext->SetIsComplete( TRUE );
  380. SetConnectionAuthContext( pMainContext,
  381. pDigestSecurityContext );
  382. }
  383. }
  384. //
  385. // Check to see if the nonce has expired
  386. //
  387. if (SEC_E_CONTEXT_EXPIRED == secStatus)
  388. {
  389. //
  390. // stale = true indicates that user knows password but he need to use new nonce
  391. // let's treat stale = true as part of the continuing authentication handshake
  392. // IIS will send back only Digest header in this case ( even if more auth methods
  393. // are enabled )
  394. //
  395. if ( NULL != pDigestSecurityContext )
  396. {
  397. pDigestSecurityContext->SetStale( TRUE );
  398. }
  399. //
  400. // Add Digest headers to response
  401. //
  402. hr = SetDigestHeader( pMainContext,
  403. TRUE //Stale
  404. );
  405. if ( FAILED( hr ) )
  406. {
  407. return hr;
  408. }
  409. //
  410. // Don't let anyone else send back authentication headers when
  411. // the 401 is sent
  412. //
  413. pMainContext->SetProviderHandled( TRUE );
  414. //
  415. // We need to send a 401 response to continue the handshake.
  416. // We have already setup the WWW-Authenticate header
  417. //
  418. pMainContext->QueryResponse()->SetStatus( HttpStatusUnauthorized,
  419. Http401BadLogon );
  420. pMainContext->SetFinishedResponse();
  421. pMainContext->SetErrorStatus( SEC_E_CONTEXT_EXPIRED );
  422. }
  423. else if( FAILED( secStatus ) )
  424. {
  425. err = GetLastError();
  426. if( err == ERROR_PASSWORD_MUST_CHANGE ||
  427. err == ERROR_PASSWORD_EXPIRED )
  428. {
  429. return HRESULT_FROM_WIN32( err );
  430. }
  431. pMainContext->QueryResponse()->SetStatus( HttpStatusUnauthorized,
  432. Http401BadLogon );
  433. pMainContext->SetErrorStatus( HRESULT_FROM_WIN32( secStatus ) );
  434. }
  435. else
  436. {
  437. //
  438. // Create a user context and setup it up
  439. //
  440. pUserContext = new SSPI_USER_CONTEXT( this );
  441. if ( pUserContext == NULL )
  442. {
  443. return HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  444. }
  445. hr = pUserContext->Create( pDigestSecurityContext, pMainContext );
  446. if ( FAILED( hr ) )
  447. {
  448. pUserContext->DereferenceUserContext();
  449. pUserContext = NULL;
  450. return hr;
  451. }
  452. pMainContext->SetUserContext( pUserContext );
  453. }
  454. return NO_ERROR;
  455. }
  456. HRESULT
  457. DIGEST_AUTH_PROVIDER::OnAccessDenied(
  458. W3_MAIN_CONTEXT * pMainContext
  459. )
  460. /*++
  461. Description:
  462. Add WWW-Authenticate Digest headers
  463. Arguments:
  464. pMainContext - main context
  465. Return Value:
  466. HRESULT
  467. --*/
  468. {
  469. W3_METADATA * pMetaData;
  470. if ( pMainContext == NULL )
  471. {
  472. DBG_ASSERT( FALSE );
  473. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  474. }
  475. //
  476. // Is using of Digest SSP enabled?
  477. //
  478. if ( !g_pW3Server->QueryUseDigestSSP() )
  479. {
  480. return NO_ERROR;
  481. }
  482. if( !W3_STATE_AUTHENTICATION::QueryIsDomainMember() )
  483. {
  484. //
  485. // We are not a domain member, so do nothing
  486. //
  487. return NO_ERROR;
  488. }
  489. return SetDigestHeader( pMainContext,
  490. FALSE //stale will not be sent
  491. );
  492. }
  493. HRESULT
  494. DIGEST_AUTH_PROVIDER::SetDigestHeader(
  495. IN W3_MAIN_CONTEXT * pMainContext,
  496. IN BOOL fStale )
  497. /*++
  498. Description:
  499. Add WWW-Authenticate Digest headers
  500. Arguments:
  501. pMainContext - main context
  502. pDigestSecurityContext - Digest context containing information such as
  503. Stale. NULL means that no stale is to be sent
  504. Return Value:
  505. HRESULT
  506. --*/
  507. {
  508. HRESULT hr = E_FAIL;
  509. W3_METADATA * pMetaData;
  510. W3_CONNECTION * pW3Connection;
  511. //
  512. // 4096 is the max output for digest authenticaiton
  513. //
  514. STACK_BUFFER( bufOutputBuffer, 4096 );
  515. STACK_STRA( strOutputHeader, MAX_PATH );
  516. STACK_STRA( strMethod, 10 );
  517. STACK_STRU( strUrl, MAX_PATH );
  518. STACK_STRA( strRealm, 128 );
  519. STACK_STRA( strUrlA, MAX_PATH );
  520. SecBufferDesc SecBuffDescOutput;
  521. SecBufferDesc SecBuffDescInput;
  522. SecBuffer SecBuffTokenOut[ 1 ];
  523. SecBuffer SecBuffTokenIn[ 5 ];
  524. SECURITY_STATUS secStatus = SEC_E_OK;
  525. SSPI_CREDENTIAL * pDigestCredential = NULL;
  526. CtxtHandle hServerCtxtHandle;
  527. ULONG ContextReqFlags = 0;
  528. ULONG ContextAttributes = 0;
  529. TimeStamp Lifetime;
  530. pMetaData = pMainContext->QueryUrlContext()->QueryMetaData();
  531. DBG_ASSERT( pMetaData != NULL );
  532. //
  533. // Get a Security Context
  534. //
  535. //
  536. // get the credential for the server
  537. //
  538. hr = SSPI_CREDENTIAL::GetCredential( NTDIGEST_SP_NAME,
  539. &pDigestCredential );
  540. if ( FAILED( hr ) )
  541. {
  542. DBGPRINTF((DBG_CONTEXT,
  543. "Error get credential handle. hr = 0x%x \n",
  544. hr ));
  545. return hr;
  546. }
  547. DBG_ASSERT( pDigestCredential != NULL );
  548. if( !bufOutputBuffer.Resize(
  549. pDigestCredential->QueryMaxTokenSize() ) )
  550. {
  551. hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  552. DBGPRINTF((DBG_CONTEXT,
  553. "Error resize the output buffer. hr = 0x%x \n",
  554. hr ));
  555. return hr;
  556. }
  557. //
  558. // clean the memory and set it to zero
  559. //
  560. ZeroMemory( &SecBuffDescOutput, sizeof( SecBufferDesc ) );
  561. ZeroMemory( SecBuffTokenOut , sizeof( SecBuffTokenOut ) );
  562. ZeroMemory( &SecBuffDescInput , sizeof( SecBufferDesc ) );
  563. ZeroMemory( SecBuffTokenIn , sizeof( SecBuffTokenIn ) );
  564. //
  565. // define the OUTPUT
  566. //
  567. SecBuffDescOutput.ulVersion = SECBUFFER_VERSION;
  568. SecBuffDescOutput.cBuffers = 1;
  569. SecBuffDescOutput.pBuffers = SecBuffTokenOut;
  570. SecBuffTokenOut[0].BufferType = SECBUFFER_TOKEN;
  571. SecBuffTokenOut[0].cbBuffer = bufOutputBuffer.QuerySize();
  572. SecBuffTokenOut[0].pvBuffer = ( PVOID )bufOutputBuffer.QueryPtr();
  573. //
  574. // define the Input
  575. //
  576. SecBuffDescInput.ulVersion = SECBUFFER_VERSION;
  577. SecBuffDescInput.cBuffers = 5;
  578. SecBuffDescInput.pBuffers = SecBuffTokenIn;
  579. //
  580. // Get and Set the information for the challenge
  581. //
  582. //
  583. // set the inforamtion in the buffer, this case is Null to
  584. // authenticate user
  585. //
  586. SecBuffTokenIn[0].BufferType = SECBUFFER_TOKEN;
  587. SecBuffTokenIn[0].cbBuffer = 0;
  588. SecBuffTokenIn[0].pvBuffer = NULL;
  589. //
  590. // Get and Set the information for the method
  591. //
  592. hr = pMainContext->QueryRequest()->GetVerbString( &strMethod );
  593. if ( FAILED( hr ) )
  594. {
  595. DBGPRINTF(( DBG_CONTEXT,
  596. "Error getting the method. hr = %x\n",
  597. hr ));
  598. return hr;
  599. }
  600. SecBuffTokenIn[1].BufferType = SECBUFFER_PKG_PARAMS;
  601. SecBuffTokenIn[1].cbBuffer = strMethod.QueryCCH();
  602. SecBuffTokenIn[1].pvBuffer = strMethod.QueryStr();
  603. //
  604. // Get and Set the infomation for the Url
  605. //
  606. hr = pMainContext->QueryRequest()->GetUrl( &strUrl );
  607. if( FAILED( hr ) )
  608. {
  609. DBGPRINTF(( DBG_CONTEXT,
  610. "Error getting the URL. hr = %x\n",
  611. hr ));
  612. return hr;
  613. }
  614. hr = strUrlA.CopyW( strUrl.QueryStr() );
  615. if( FAILED( hr ) )
  616. {
  617. DBGPRINTF(( DBG_CONTEXT,
  618. "Error copying the URL. hr = %x\n",
  619. hr ));
  620. return hr;
  621. }
  622. SecBuffTokenIn[2].BufferType = SECBUFFER_PKG_PARAMS;
  623. SecBuffTokenIn[2].cbBuffer = strUrlA.QueryCB();
  624. SecBuffTokenIn[2].pvBuffer = ( PVOID )strUrlA.QueryStr();
  625. //
  626. // Get and Set the information for the hentity
  627. //
  628. SecBuffTokenIn[3].BufferType = SECBUFFER_PKG_PARAMS;
  629. SecBuffTokenIn[3].cbBuffer = 0; // this is not yet implemeted
  630. SecBuffTokenIn[3].pvBuffer = NULL; // this is not yet implemeted
  631. //
  632. //Get and Set the Realm Information
  633. //
  634. if( pMetaData->QueryRealm() )
  635. {
  636. hr = strRealm.CopyW( pMetaData->QueryRealm() );
  637. if( FAILED( hr ) )
  638. {
  639. DBGPRINTF(( DBG_CONTEXT,
  640. "Error copying the realm. hr = %x\n",
  641. hr ));
  642. return hr;
  643. }
  644. }
  645. SecBuffTokenIn[4].BufferType = SECBUFFER_PKG_PARAMS;
  646. SecBuffTokenIn[4].cbBuffer = strRealm.QueryCB();
  647. SecBuffTokenIn[4].pvBuffer = ( PVOID )strRealm.QueryStr();
  648. //
  649. // set the flags
  650. //
  651. ContextReqFlags = ASC_REQ_REPLAY_DETECT |
  652. ASC_REQ_CONNECTION;
  653. //
  654. // get the security context
  655. //
  656. secStatus = AcceptSecurityContext(
  657. pDigestCredential->QueryCredHandle(),
  658. NULL,
  659. &SecBuffDescInput,
  660. ContextReqFlags,
  661. SECURITY_NATIVE_DREP,
  662. &hServerCtxtHandle,
  663. &SecBuffDescOutput,
  664. &ContextAttributes,
  665. &Lifetime);
  666. //
  667. // a challenge has to be send back to the client
  668. //
  669. if ( SEC_I_CONTINUE_NEEDED == secStatus )
  670. {
  671. //
  672. // Do we already have a digest security context
  673. //
  674. if( fStale )
  675. {
  676. hr = strOutputHeader.Copy( "Digest stale=TRUE ," );
  677. }
  678. else
  679. {
  680. hr = strOutputHeader.Copy( "Digest " );
  681. }
  682. if( FAILED( hr ) )
  683. {
  684. return hr;
  685. }
  686. hr = strOutputHeader.Append(
  687. ( CHAR * )SecBuffDescOutput.pBuffers[0].pvBuffer,
  688. SecBuffDescOutput.pBuffers[0].cbBuffer - 1 );
  689. if( FAILED( hr ) )
  690. {
  691. return hr;
  692. }
  693. //
  694. // Add the header WWW-Authenticate to the response after a
  695. // 401 server error
  696. //
  697. hr = pMainContext->QueryResponse()->SetHeader(
  698. "WWW-Authenticate",
  699. 16,
  700. strOutputHeader.QueryStr(),
  701. strOutputHeader.QueryCCH()
  702. );
  703. }
  704. else
  705. {
  706. hr = S_OK;
  707. }
  708. return hr;
  709. }
  710. //static
  711. HRESULT
  712. DIGEST_SECURITY_CONTEXT::Initialize(
  713. VOID
  714. )
  715. /*++
  716. Description:
  717. Global DIGEST_SECURITY_CONTEXT initialization
  718. Arguments:
  719. None
  720. Return Value:
  721. HRESULT
  722. --*/
  723. {
  724. ALLOC_CACHE_CONFIGURATION acConfig;
  725. //
  726. // Initialize allocation lookaside
  727. //
  728. acConfig.nConcurrency = 1;
  729. acConfig.nThreshold = 100;
  730. acConfig.cbSize = sizeof( DIGEST_SECURITY_CONTEXT );
  731. DBG_ASSERT( sm_pachDIGESTSecContext == NULL );
  732. sm_pachDIGESTSecContext = new ALLOC_CACHE_HANDLER(
  733. "DIGEST_SECURITY_CONTEXT",
  734. &acConfig );
  735. if ( sm_pachDIGESTSecContext == NULL )
  736. {
  737. HRESULT hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  738. DBGPRINTF(( DBG_CONTEXT,
  739. "Error initializing sm_pachDIGESTSecContext. hr = 0x%x\n",
  740. hr ));
  741. return hr;
  742. }
  743. return S_OK;
  744. } // DIGEST_SECURITY_CONTEXT::Initialize
  745. //static
  746. VOID
  747. DIGEST_SECURITY_CONTEXT::Terminate(
  748. VOID
  749. )
  750. /*++
  751. Routine Description:
  752. Destroy DIGEST_SECURITY_CONTEXT globals
  753. Arguments:
  754. None
  755. Return Value:
  756. None
  757. --*/
  758. {
  759. DBG_ASSERT( sm_pachDIGESTSecContext != NULL );
  760. delete sm_pachDIGESTSecContext;
  761. sm_pachDIGESTSecContext = NULL;
  762. } // DIGEST_SECURITY_CONTEXT::Terminate