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.

2025 lines
48 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name :
  4. passportprovider.cxx
  5. Abstract:
  6. Core passport authentication support
  7. Author:
  8. Bilal Alam (balam) 16-Mar-2001
  9. Environment:
  10. Win32 - User Mode
  11. Project:
  12. ULW3.DLL
  13. --*/
  14. #include "precomp.hxx"
  15. #include "passportprovider.hxx"
  16. #define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
  17. const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
  18. #define MAGIC_TWEENER_STRING L"msppchlg=1&mspplogin="
  19. #define MAGIC_TWEENER_STRING_LEN ( sizeof( MAGIC_TWEENER_STRING ) / sizeof( WCHAR ) - 1 )
  20. MIDL_DEFINE_GUID(IID,IID_IPassportManager3,0x1451151f,0x90a0,0x491b,0xb8,0xe1,0x81,0xa1,0x37,0x67,0xed,0x98);
  21. MIDL_DEFINE_GUID(IID,IID_IPassportFactory,0x5602E147,0x27F6,0x11d3,0x94,0xDD,0x00,0xC0,0x4F,0x72,0xDC,0x08);
  22. MIDL_DEFINE_GUID(CLSID,CLSID_PassportFactory,0x74EB2514,0xE239,0x11D2,0x95,0xE9,0x00,0xC0,0x4F,0x8E,0x7A,0x70);
  23. IPassportFactory * PASSPORT_CONTEXT::sm_pPassportManagerFactory;
  24. BSTR PASSPORT_CONTEXT::sm_bstrMemberIdHigh;
  25. BSTR PASSPORT_CONTEXT::sm_bstrMemberIdLow;
  26. BSTR PASSPORT_CONTEXT::sm_bstrReturnUrl;
  27. BSTR PASSPORT_CONTEXT::sm_bstrTimeWindow;
  28. BSTR PASSPORT_CONTEXT::sm_bstrForceSignIn;
  29. BSTR PASSPORT_CONTEXT::sm_bstrCoBrandTemplate;
  30. BSTR PASSPORT_CONTEXT::sm_bstrLanguageId;
  31. BSTR PASSPORT_CONTEXT::sm_bstrSecureLevel;
  32. //static
  33. HRESULT
  34. PASSPORT_CONTEXT::Initialize(
  35. VOID
  36. )
  37. /*++
  38. Routine Description:
  39. Do global initialization for passport goo
  40. Arguments:
  41. None
  42. Return Value:
  43. HRESULT
  44. --*/
  45. {
  46. HRESULT hr = NO_ERROR;
  47. //
  48. // Pre-allocate some BSTRs
  49. //
  50. sm_bstrMemberIdHigh = SysAllocString( L"MemberIdHigh" );
  51. if ( sm_bstrMemberIdHigh == NULL )
  52. {
  53. hr = HRESULT_FROM_WIN32( GetLastError() );
  54. goto Failure;
  55. }
  56. sm_bstrMemberIdLow = SysAllocString( L"MemberIdLow" );
  57. if ( sm_bstrMemberIdLow == NULL )
  58. {
  59. hr = HRESULT_FROM_WIN32( GetLastError() );
  60. goto Failure;
  61. }
  62. sm_bstrReturnUrl = SysAllocString( L"ReturnURL" );
  63. if ( sm_bstrReturnUrl == NULL )
  64. {
  65. hr = HRESULT_FROM_WIN32( GetLastError() );
  66. goto Failure;
  67. }
  68. sm_bstrTimeWindow = SysAllocString( L"TimeWindow" );
  69. if ( sm_bstrTimeWindow == NULL )
  70. {
  71. hr = HRESULT_FROM_WIN32( GetLastError() );
  72. goto Failure;
  73. }
  74. sm_bstrForceSignIn = SysAllocString( L"ForceSignIn" );
  75. if ( sm_bstrForceSignIn == NULL )
  76. {
  77. hr = HRESULT_FROM_WIN32( GetLastError() );
  78. goto Failure;
  79. }
  80. sm_bstrCoBrandTemplate = SysAllocString( L"CoBrandTemplate" );
  81. if ( sm_bstrCoBrandTemplate == NULL )
  82. {
  83. hr = HRESULT_FROM_WIN32( GetLastError() );
  84. goto Failure;
  85. }
  86. sm_bstrLanguageId = SysAllocString( L"LanguageId" );
  87. if ( sm_bstrLanguageId == NULL )
  88. {
  89. hr = HRESULT_FROM_WIN32( GetLastError() );
  90. goto Failure;
  91. }
  92. sm_bstrSecureLevel = SysAllocString( L"SecureLevel" );
  93. if ( sm_bstrSecureLevel == NULL )
  94. {
  95. hr = HRESULT_FROM_WIN32( GetLastError() );
  96. goto Failure;
  97. }
  98. //
  99. // Try to initialize the passport manager factory. If we cannot, then
  100. // we're done
  101. //
  102. hr = CoInitializeEx( NULL, COINIT_MULTITHREADED );
  103. if( FAILED( hr ) )
  104. {
  105. goto Failure;
  106. }
  107. hr = CoCreateInstance( CLSID_PassportFactory,
  108. NULL,
  109. CLSCTX_INPROC_SERVER,
  110. IID_IPassportFactory,
  111. (void**)&sm_pPassportManagerFactory );
  112. CoUninitialize();
  113. if ( FAILED( hr ) )
  114. {
  115. goto Failure;
  116. }
  117. DBG_ASSERT( sm_pPassportManagerFactory != NULL );
  118. return NO_ERROR;
  119. Failure:
  120. if ( FAILED( hr ) )
  121. {
  122. if ( sm_pPassportManagerFactory != NULL )
  123. {
  124. sm_pPassportManagerFactory->Release();
  125. sm_pPassportManagerFactory = NULL;
  126. }
  127. if ( sm_bstrMemberIdLow != NULL )
  128. {
  129. SysFreeString( sm_bstrMemberIdLow );
  130. sm_bstrMemberIdLow = NULL;
  131. }
  132. if ( sm_bstrMemberIdHigh != NULL )
  133. {
  134. SysFreeString( sm_bstrMemberIdHigh );
  135. sm_bstrMemberIdHigh = NULL;
  136. }
  137. if ( sm_bstrReturnUrl != NULL )
  138. {
  139. SysFreeString( sm_bstrReturnUrl );
  140. sm_bstrReturnUrl = NULL;
  141. }
  142. if ( sm_bstrTimeWindow == NULL )
  143. {
  144. SysFreeString( sm_bstrTimeWindow );
  145. sm_bstrTimeWindow = NULL;
  146. }
  147. if ( sm_bstrForceSignIn == NULL )
  148. {
  149. SysFreeString( sm_bstrForceSignIn );
  150. sm_bstrForceSignIn = NULL;
  151. }
  152. if ( sm_bstrCoBrandTemplate == NULL )
  153. {
  154. SysFreeString( sm_bstrCoBrandTemplate );
  155. sm_bstrCoBrandTemplate = NULL;
  156. }
  157. if ( sm_bstrLanguageId == NULL )
  158. {
  159. SysFreeString( sm_bstrLanguageId );
  160. sm_bstrLanguageId = NULL;
  161. }
  162. if ( sm_bstrSecureLevel == NULL )
  163. {
  164. SysFreeString( sm_bstrSecureLevel );
  165. sm_bstrSecureLevel = NULL;
  166. }
  167. }
  168. return hr;
  169. }
  170. //static
  171. VOID
  172. PASSPORT_CONTEXT::Terminate(
  173. VOID
  174. )
  175. /*++
  176. Routine Description:
  177. Cleanup global passport goo
  178. Arguments:
  179. None
  180. Return Value:
  181. None
  182. --*/
  183. {
  184. if ( sm_pPassportManagerFactory != NULL )
  185. {
  186. sm_pPassportManagerFactory->Release();
  187. sm_pPassportManagerFactory = NULL;
  188. }
  189. if ( sm_bstrMemberIdLow != NULL )
  190. {
  191. SysFreeString( sm_bstrMemberIdLow );
  192. sm_bstrMemberIdLow = NULL;
  193. }
  194. if ( sm_bstrMemberIdHigh != NULL )
  195. {
  196. SysFreeString( sm_bstrMemberIdHigh );
  197. sm_bstrMemberIdHigh = NULL;
  198. }
  199. if ( sm_bstrReturnUrl != NULL )
  200. {
  201. SysFreeString( sm_bstrReturnUrl );
  202. sm_bstrReturnUrl = NULL;
  203. }
  204. if ( sm_bstrTimeWindow == NULL )
  205. {
  206. SysFreeString( sm_bstrTimeWindow );
  207. sm_bstrTimeWindow = NULL;
  208. }
  209. if ( sm_bstrForceSignIn == NULL )
  210. {
  211. SysFreeString( sm_bstrForceSignIn );
  212. sm_bstrForceSignIn = NULL;
  213. }
  214. if ( sm_bstrCoBrandTemplate == NULL )
  215. {
  216. SysFreeString( sm_bstrCoBrandTemplate );
  217. sm_bstrCoBrandTemplate = NULL;
  218. }
  219. if ( sm_bstrLanguageId == NULL )
  220. {
  221. SysFreeString( sm_bstrLanguageId );
  222. sm_bstrLanguageId = NULL;
  223. }
  224. if ( sm_bstrSecureLevel == NULL )
  225. {
  226. SysFreeString( sm_bstrSecureLevel );
  227. sm_bstrSecureLevel = NULL;
  228. }
  229. }
  230. BOOL
  231. PASSPORT_CONTEXT::QueryUserError(
  232. VOID
  233. )
  234. /*++
  235. Routine Description:
  236. Returns whether the user cancelled. That we have to do this work
  237. really sucks
  238. Arguments:
  239. None
  240. Return Value:
  241. BOOL
  242. --*/
  243. {
  244. LONG lError;
  245. HRESULT hr;
  246. if ( _pPassportManager == NULL )
  247. {
  248. return FALSE;
  249. }
  250. hr = _pPassportManager->get_Error( &lError );
  251. if ( FAILED( hr ) )
  252. {
  253. return FALSE;
  254. }
  255. return lError != 0;
  256. }
  257. HRESULT
  258. PASSPORT_CONTEXT::SetupDefaultRedirect(
  259. W3_MAIN_CONTEXT * pMainContext,
  260. BOOL * pfFoundRedirect
  261. )
  262. /*++
  263. Routine Description:
  264. Setup default redirect in case of client cancelling
  265. Arguments:
  266. pMainContext - main context
  267. pfFoundRedirect - Set to TRUE if redirect URL found
  268. Return Value:
  269. HRESULT
  270. --*/
  271. {
  272. HRESULT hr;
  273. VARIANT vReturnUrl;
  274. STACK_STRU( strRedirect, 512 );
  275. VariantInit( &vReturnUrl );
  276. if ( pMainContext == NULL ||
  277. pfFoundRedirect == NULL )
  278. {
  279. DBG_ASSERT( FALSE );
  280. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  281. }
  282. *pfFoundRedirect = FALSE;
  283. DBG_ASSERT( _pPassportManager != NULL );
  284. //
  285. // First get the default URL if any
  286. //
  287. hr = _pPassportManager->GetCurrentConfig( sm_bstrReturnUrl,
  288. &vReturnUrl );
  289. if ( FAILED( hr ) )
  290. {
  291. return NO_ERROR;
  292. }
  293. if ( vReturnUrl.vt != VT_BSTR ||
  294. vReturnUrl.bstrVal[ 0 ] == L'\0' )
  295. {
  296. return NO_ERROR;
  297. }
  298. //
  299. // Do the redirect
  300. //
  301. hr = strRedirect.Copy( vReturnUrl.bstrVal );
  302. if ( FAILED( hr ) )
  303. {
  304. return hr;
  305. }
  306. hr = pMainContext->SetupHttpRedirect( strRedirect,
  307. TRUE,
  308. HttpStatusRedirect );
  309. if ( FAILED( hr ) )
  310. {
  311. return hr;
  312. }
  313. *pfFoundRedirect = TRUE;
  314. return NO_ERROR;
  315. }
  316. HRESULT
  317. PASSPORT_CONTEXT::Create(
  318. W3_FILTER_CONTEXT * pFilterContext
  319. )
  320. /*++
  321. Routine Description:
  322. Initialize a passport filter context
  323. -the big thing being getting a passport manager for this request
  324. Arguments:
  325. pFilterContext - Filter context
  326. Return Value:
  327. HRESULT
  328. --*/
  329. {
  330. IDispatch * pDispatch = NULL;
  331. HRESULT hr;
  332. DWORD cbBufferLength;
  333. if ( sm_pPassportManagerFactory == NULL )
  334. {
  335. DBG_ASSERT( FALSE );
  336. return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
  337. }
  338. //
  339. // Do some COM/OLEAUT crap to get a passport manager
  340. //
  341. hr = sm_pPassportManagerFactory->CreatePassportManager( &pDispatch );
  342. if ( FAILED( hr ) )
  343. {
  344. return hr;
  345. }
  346. DBG_ASSERT( pDispatch != NULL );
  347. hr = pDispatch->QueryInterface( IID_IPassportManager3,
  348. (VOID**) &_pPassportManager );
  349. pDispatch->Release();
  350. if ( FAILED( hr ) )
  351. {
  352. return hr;
  353. }
  354. DBG_ASSERT( _pPassportManager != NULL );
  355. //
  356. // Try a cookie of size 4096 since the samples all seem to use that size
  357. //
  358. if ( !_buffCookie.Resize( 4096 ) )
  359. {
  360. return HRESULT_FROM_WIN32( GetLastError() );
  361. }
  362. cbBufferLength = _buffCookie.QuerySize();
  363. //
  364. // Pass filter context to passport manager so that it can inspect the
  365. // request
  366. //
  367. DBG_ASSERT( _pPassportManager != NULL );
  368. hr = _pPassportManager->OnStartPageFilter( (PBYTE) pFilterContext->QueryFC(),
  369. &cbBufferLength,
  370. (LPSTR)
  371. _buffCookie.QueryPtr() );
  372. if ( FAILED( hr ) )
  373. {
  374. return hr;
  375. }
  376. return NO_ERROR;
  377. }
  378. HRESULT
  379. PASSPORT_CONTEXT::DoesApply(
  380. HTTP_FILTER_CONTEXT * pfc,
  381. BOOL * pfApplies,
  382. STRA * pstrReturnCookie
  383. )
  384. /*++
  385. Routine Description:
  386. Check whether the given request has Passport stuff in it
  387. Arguments:
  388. pfc - Filter context
  389. pfApplies - Set to TRUE if passport applies
  390. pstrReturnCookie - Cookie to return in response
  391. Return Value:
  392. HRESULT
  393. --*/
  394. {
  395. HRESULT hr;
  396. VARIANT vTimeWindow;
  397. VARIANT vForceLogin;
  398. VARIANT vSecureLevel;
  399. VARIANT_BOOL vb;
  400. BUFFER bufReturnCookie;
  401. if ( pfc == NULL ||
  402. pfApplies == NULL ||
  403. pstrReturnCookie == NULL )
  404. {
  405. DBG_ASSERT( FALSE );
  406. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  407. }
  408. *pfApplies = FALSE;
  409. //
  410. // Read parameters for IsAuthenticated(). If we can't find
  411. // them then choose arbitrary (tm) defaults
  412. //
  413. VariantInit( &vTimeWindow );
  414. hr = _pPassportManager->GetCurrentConfig( sm_bstrTimeWindow,
  415. &vTimeWindow );
  416. if ( FAILED( hr ) )
  417. {
  418. vTimeWindow.vt = VT_I4;
  419. vTimeWindow.lVal = 10000;
  420. }
  421. VariantInit( &vForceLogin );
  422. hr = _pPassportManager->GetCurrentConfig( sm_bstrForceSignIn,
  423. &vForceLogin );
  424. if ( FAILED( hr ) )
  425. {
  426. vForceLogin.vt = VT_BOOL;
  427. vForceLogin.boolVal = VARIANT_FALSE;
  428. }
  429. VariantInit( &vSecureLevel );
  430. hr = _pPassportManager->GetCurrentConfig( sm_bstrSecureLevel,
  431. &vSecureLevel );
  432. if ( FAILED( hr ) )
  433. {
  434. vSecureLevel.vt = VT_I4;
  435. vSecureLevel.lVal = 10;
  436. }
  437. //
  438. // Are we authenticated?
  439. //
  440. hr = _pPassportManager->IsAuthenticated( vTimeWindow,
  441. vForceLogin,
  442. vSecureLevel,
  443. &vb );
  444. if ( FAILED( hr ) )
  445. {
  446. return hr;
  447. }
  448. if ( vb == VARIANT_TRUE )
  449. {
  450. _fAuthenticated = TRUE;
  451. }
  452. *pfApplies = _fAuthenticated;
  453. return pstrReturnCookie->Copy( (CHAR*) _buffCookie.QueryPtr() );
  454. }
  455. HRESULT
  456. PASSPORT_CONTEXT::DoAuthenticate(
  457. W3_MAIN_CONTEXT * pMainContext,
  458. TOKEN_CACHE_ENTRY ** ppCachedToken,
  459. STRU * pstrAuthUser,
  460. STRU * pstrRemoteUser,
  461. STRU & strDomainName
  462. )
  463. /*++
  464. Routine Description:
  465. Logon the passport user (i.e. get a token)
  466. Arguments:
  467. pMetaData - Metadata for this request
  468. ppCachedToken - Filled with token cache entry represented mapped user
  469. pstrAuthUser - Filled with AUTH_USER
  470. pstrRemoteUser - Filled with PUID
  471. strDomainName - Domain name
  472. Return Value:
  473. HRESULT
  474. --*/
  475. {
  476. VARIANT vMemberId;
  477. HRESULT hr;
  478. WCHAR achLarge[ 64 ];
  479. DWORD dwLogonError;
  480. TOKEN_CACHE_ENTRY * pCachedToken = NULL;
  481. LONG lLowPuid;
  482. LONG lHighPuid;
  483. BOOL fRet;
  484. HANDLE hToken;
  485. STACK_BUFFER( bufName, 512 );
  486. DWORD cchName;
  487. W3_METADATA * pMetaData;
  488. if ( pMainContext == NULL ||
  489. ppCachedToken == NULL ||
  490. pstrAuthUser == NULL ||
  491. pstrRemoteUser == NULL )
  492. {
  493. DBG_ASSERT( FALSE );
  494. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  495. }
  496. pMetaData = pMainContext->QueryUrlContext()->QueryMetaData();
  497. DBG_ASSERT( pMetaData != NULL );
  498. //
  499. // Get the PUID -> this is the remote user name.
  500. // Start with the high part
  501. //
  502. VariantInit( &vMemberId );
  503. DBG_ASSERT( _pPassportManager != NULL );
  504. hr = _pPassportManager->get_Profile( sm_bstrMemberIdHigh, &vMemberId );
  505. if ( FAILED( hr ) )
  506. {
  507. goto Failure;
  508. }
  509. lHighPuid = V_I4( &vMemberId );
  510. //
  511. // Next the low part
  512. //
  513. hr = _pPassportManager->get_Profile( sm_bstrMemberIdLow, &vMemberId );
  514. if ( FAILED( hr ) )
  515. {
  516. goto Failure;
  517. }
  518. lLowPuid = V_I4( &vMemberId );
  519. //
  520. // Now make a string out of the QuadPart
  521. //
  522. wsprintfW( achLarge,
  523. L"%08X%08X",
  524. lHighPuid,
  525. lLowPuid );
  526. //
  527. // The REMOTE_USER server variable is always PUID@domain.
  528. //
  529. hr = pstrRemoteUser->Copy( achLarge );
  530. if ( FAILED( hr ) )
  531. {
  532. goto Failure;
  533. }
  534. hr = pstrRemoteUser->Append( L"@" );
  535. if ( FAILED( hr ) )
  536. {
  537. goto Failure;
  538. }
  539. hr = pstrRemoteUser->Append( strDomainName.QueryStr() );
  540. if ( FAILED( hr ) )
  541. {
  542. goto Failure;
  543. }
  544. //
  545. // Should we be doing mapping at all?
  546. //
  547. if ( pMetaData->QueryRequireMapping() == MD_PASSPORT_NO_MAPPING )
  548. {
  549. //
  550. // No mapping. Just use anonymous.
  551. //
  552. hr = pMetaData->GetAndRefAnonymousToken( &pCachedToken );
  553. if( FAILED( hr ) )
  554. {
  555. return hr;
  556. }
  557. if ( pCachedToken == NULL )
  558. {
  559. return HRESULT_FROM_WIN32( ERROR_LOGON_FAILURE );
  560. }
  561. pstrAuthUser->Reset();
  562. *ppCachedToken = pCachedToken;
  563. return NO_ERROR;
  564. }
  565. //
  566. // If we got here then we must be doing mapping (trying it anyways)
  567. //
  568. //
  569. // Get the cached token (in other words, call into LsaLogonUser() )
  570. //
  571. DBG_ASSERT( g_pW3Server->QueryTokenCache() != NULL );
  572. hr = g_pW3Server->QueryTokenCache()->GetCachedToken(
  573. pstrRemoteUser->QueryStr(),
  574. L"",
  575. L"",
  576. ( DWORD )IIS_LOGON_METHOD_PASSPORT,
  577. FALSE,
  578. FALSE,
  579. pMainContext->QueryRequest()->
  580. QueryRemoteSockAddress(),
  581. &pCachedToken,
  582. &dwLogonError );
  583. if ( FAILED( hr ) )
  584. {
  585. goto Failure;
  586. }
  587. //
  588. // Now, was mapping required or not??? (extra ??? for special effect)
  589. //
  590. if ( pCachedToken == NULL )
  591. {
  592. if ( pMetaData->QueryRequireMapping() == MD_PASSPORT_NEED_MAPPING )
  593. {
  594. //
  595. // No mapping -> fail!
  596. //
  597. return HRESULT_FROM_WIN32( dwLogonError );
  598. }
  599. else
  600. {
  601. //
  602. // We tried, we failed, we'll persevere!
  603. //
  604. hr = pMetaData->GetAndRefAnonymousToken( &pCachedToken );
  605. if ( FAILED( hr ) )
  606. {
  607. return hr;
  608. }
  609. if ( pCachedToken == NULL )
  610. {
  611. return HRESULT_FROM_WIN32( ERROR_LOGON_FAILURE );
  612. }
  613. pstrAuthUser->Reset();
  614. *ppCachedToken = pCachedToken;
  615. return NO_ERROR;
  616. }
  617. }
  618. //
  619. // The AUTH_USER server variable is the account name if mapping worked, else empty string
  620. //
  621. //
  622. // Get the token information by impersonating
  623. // (we could just cache this info, but then again who is going
  624. // to use this mapping feature anyways???)
  625. //
  626. hToken = pCachedToken->QueryImpersonationToken();
  627. if ( hToken == NULL )
  628. {
  629. hr = HRESULT_FROM_WIN32( GetLastError() );
  630. goto Failure;
  631. }
  632. fRet = ImpersonateLoggedOnUser( hToken );
  633. if ( !fRet )
  634. {
  635. hr = HRESULT_FROM_WIN32( GetLastError() );
  636. goto Failure;
  637. }
  638. cchName = bufName.QuerySize() / sizeof( WCHAR );
  639. fRet = GetUserNameExW( NameSamCompatible,
  640. (WCHAR*) bufName.QueryPtr(),
  641. &cchName );
  642. if ( !fRet )
  643. {
  644. hr = HRESULT_FROM_WIN32( GetLastError() );
  645. if ( hr == HRESULT_FROM_WIN32( ERROR_MORE_DATA ) )
  646. {
  647. DBG_ASSERT( cchName > bufName.QuerySize() / sizeof( WCHAR ) );
  648. fRet = bufName.Resize( cchName * sizeof( WCHAR ) );
  649. if ( !fRet )
  650. {
  651. hr = HRESULT_FROM_WIN32( GetLastError() );
  652. }
  653. else
  654. {
  655. fRet = GetUserNameExW( NameSamCompatible,
  656. (WCHAR*) bufName.QueryPtr(),
  657. &cchName );
  658. if ( !fRet )
  659. {
  660. hr = HRESULT_FROM_WIN32( GetLastError() );
  661. }
  662. else
  663. {
  664. hr = NO_ERROR;
  665. }
  666. }
  667. }
  668. }
  669. //
  670. // Always revert
  671. //
  672. if ( !RevertToSelf() )
  673. {
  674. hr = HRESULT_FROM_WIN32( GetLastError() );
  675. goto Failure;
  676. }
  677. //
  678. // If we failed earlier, bail.
  679. //
  680. if ( FAILED( hr ) )
  681. {
  682. goto Failure;
  683. }
  684. hr = pstrAuthUser->Copy( (WCHAR*) bufName.QueryPtr() );
  685. if ( FAILED( hr ) )
  686. {
  687. goto Failure;
  688. }
  689. if ( pCachedToken != NULL )
  690. {
  691. *ppCachedToken = pCachedToken;
  692. }
  693. return NO_ERROR;
  694. Failure:
  695. DBG_ASSERT( FAILED( hr ) );
  696. if ( pCachedToken != NULL )
  697. {
  698. pCachedToken->DereferenceCacheEntry();
  699. pCachedToken = NULL;
  700. }
  701. return hr;
  702. }
  703. HRESULT
  704. PASSPORT_CONTEXT::OnChallenge(
  705. STRU & strOriginalUrl
  706. )
  707. /*++
  708. Routine Description:
  709. Do a passport challenge
  710. Arguments:
  711. strOriginalUrl - Original URL
  712. Return Value:
  713. HRESULT
  714. --*/
  715. {
  716. BSTR bstrOriginalUrl;
  717. VARIANT vReturnURL;
  718. VARIANT vTimeWindow;
  719. VARIANT vForceLogin;
  720. VARIANT vNoParam;
  721. VARIANT vCoBrandTemplate;
  722. VARIANT vSecureLevel;
  723. HRESULT hr = NO_ERROR;
  724. VariantInit( &vTimeWindow );
  725. hr = _pPassportManager->GetCurrentConfig( sm_bstrTimeWindow,
  726. &vTimeWindow );
  727. if ( FAILED( hr ) )
  728. {
  729. vTimeWindow.vt = VT_I4;
  730. vTimeWindow.lVal = 10000;
  731. }
  732. VariantInit( &vForceLogin );
  733. hr = _pPassportManager->GetCurrentConfig( sm_bstrForceSignIn,
  734. &vForceLogin );
  735. if ( FAILED( hr ) )
  736. {
  737. vForceLogin.vt = VT_BOOL;
  738. vForceLogin.boolVal = VARIANT_FALSE;
  739. }
  740. VariantInit( &vCoBrandTemplate );
  741. hr = _pPassportManager->GetCurrentConfig( sm_bstrCoBrandTemplate,
  742. &vCoBrandTemplate );
  743. if ( FAILED( hr ) )
  744. {
  745. vCoBrandTemplate.vt = VT_ERROR;
  746. vCoBrandTemplate.scode = DISP_E_PARAMNOTFOUND;
  747. }
  748. VariantInit( &vSecureLevel );
  749. hr = _pPassportManager->GetCurrentConfig( sm_bstrSecureLevel,
  750. &vSecureLevel );
  751. if ( FAILED( hr ) )
  752. {
  753. vSecureLevel.vt = VT_I4;
  754. vSecureLevel.lVal = 10;
  755. }
  756. //
  757. // Make this a secure return URL if needed (lame)
  758. //
  759. if ( vSecureLevel.lVal > 0 )
  760. {
  761. if ( _wcsnicmp( strOriginalUrl.QueryStr(), L"https://", 8 ) != 0 )
  762. {
  763. STACK_STRU( strTemp, 256 );
  764. //
  765. // Must be a nonsecure url
  766. //
  767. DBG_ASSERT( _wcsnicmp( strOriginalUrl.QueryStr(), L"http://", 7 ) == 0 );
  768. hr = strTemp.Copy( L"https://" );
  769. if ( FAILED( hr ) )
  770. {
  771. return hr;
  772. }
  773. hr = strTemp.Append( strOriginalUrl.QueryStr() + 7 );
  774. if ( FAILED( hr ) )
  775. {
  776. return hr;
  777. }
  778. bstrOriginalUrl = SysAllocString( strTemp.QueryStr() );
  779. }
  780. else
  781. {
  782. //
  783. // Just use the original URL
  784. //
  785. bstrOriginalUrl = SysAllocString( strOriginalUrl.QueryStr() );
  786. }
  787. }
  788. else
  789. {
  790. //
  791. // Just use the original URL
  792. //
  793. bstrOriginalUrl = SysAllocString( strOriginalUrl.QueryStr() );
  794. }
  795. if ( bstrOriginalUrl == NULL )
  796. {
  797. return HRESULT_FROM_WIN32( GetLastError() );
  798. }
  799. VariantInit( &vNoParam );
  800. VariantInit( &vReturnURL );
  801. vReturnURL.vt = VT_BSTR;
  802. vReturnURL.bstrVal = bstrOriginalUrl;
  803. vNoParam.vt = VT_ERROR;
  804. vNoParam.scode = DISP_E_PARAMNOTFOUND;
  805. hr = _pPassportManager->LoginUser( vReturnURL,
  806. vTimeWindow,
  807. vForceLogin,
  808. vCoBrandTemplate,
  809. vNoParam,
  810. vNoParam,
  811. vNoParam,
  812. vSecureLevel,
  813. vNoParam );
  814. if ( FAILED( hr ) )
  815. {
  816. goto Finished;
  817. }
  818. Finished:
  819. VariantClear( &vReturnURL );
  820. return hr;
  821. }
  822. HRESULT
  823. PASSPORT_AUTH_PROVIDER::Initialize(
  824. DWORD dwInternalId
  825. )
  826. /*++
  827. Routine Description:
  828. Initialize passport authentication provider
  829. Arguments:
  830. None
  831. Return Value:
  832. HRESULT
  833. --*/
  834. {
  835. SetInternalId( dwInternalId );
  836. //
  837. // We defer initialization of passport manager crap until we really
  838. // need it. Why? Because loading their DLLs causes a process-wide
  839. // perf hit with string compares. This hit is killing ASP perf
  840. //
  841. if( !INITIALIZE_CRITICAL_SECTION( &_csInitLock ) )
  842. {
  843. return HRESULT_FROM_WIN32( GetLastError() );
  844. }
  845. _fInitialized = FALSE;
  846. return NO_ERROR;
  847. }
  848. VOID
  849. PASSPORT_AUTH_PROVIDER::Terminate(
  850. VOID
  851. )
  852. /*++
  853. Routine Description:
  854. Terminate passport authentication provider
  855. Arguments:
  856. None
  857. Return Value:
  858. None
  859. --*/
  860. {
  861. if ( _fInitialized )
  862. {
  863. PASSPORT_CONTEXT::Terminate();
  864. _fInitialized = FALSE;
  865. }
  866. DeleteCriticalSection( &_csInitLock );
  867. }
  868. HRESULT
  869. PASSPORT_AUTH_PROVIDER::DoesApply(
  870. W3_MAIN_CONTEXT * pMainContext,
  871. BOOL * pfApplies
  872. )
  873. /*++
  874. Routine Description:
  875. Check whether Passport applies to this request
  876. Arguments:
  877. pMainContext - Main context
  878. pfApplies - Set to TRUE if one of the filters indicates the request applies
  879. Return Value:
  880. HRESULT
  881. --*/
  882. {
  883. URL_CONTEXT * pUrlContext;
  884. W3_METADATA * pMetaData;
  885. PASSPORT_CONTEXT * pPassportContext;
  886. W3_FILTER_CONTEXT * pFilterContext;
  887. HRESULT hr = S_OK;
  888. STACK_STRA( strReturnCookie, 256 );
  889. BOOL fTweenerHandled = FALSE;
  890. if ( pMainContext == NULL ||
  891. pfApplies == NULL )
  892. {
  893. DBG_ASSERT( FALSE );
  894. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  895. }
  896. *pfApplies = FALSE;
  897. //
  898. // Before we call into filters, check whether custom auth is enabled.
  899. // This is a departure from the other protocols, but is the practical
  900. // thing to do, since we don't want to call into arbitrary code (or
  901. // Passport Manager) on every request.
  902. //
  903. pUrlContext = pMainContext->QueryUrlContext();
  904. DBG_ASSERT( pUrlContext != NULL );
  905. pMetaData = pUrlContext->QueryMetaData();
  906. DBG_ASSERT( pMetaData != NULL );
  907. if ( !pMetaData->QueryAuthTypeSupported( MD_AUTH_PASSPORT ) )
  908. {
  909. return NO_ERROR;
  910. }
  911. //
  912. // Ok. We need to do passport stuff. Initialize the passport stuff
  913. // now if needed
  914. //
  915. if ( !_fInitialized )
  916. {
  917. EnterCriticalSection( &_csInitLock );
  918. if ( !_fInitialized )
  919. {
  920. hr = PASSPORT_CONTEXT::Initialize();
  921. if ( SUCCEEDED( hr ) )
  922. {
  923. _fInitialized = TRUE;
  924. }
  925. }
  926. LeaveCriticalSection( &_csInitLock );
  927. }
  928. if ( !_fInitialized )
  929. {
  930. DBG_ASSERT( FAILED( hr ) );
  931. return hr;
  932. }
  933. //
  934. // Get a filter context since we'll need it now to ask passport manager
  935. // whether the current request applies
  936. //
  937. pFilterContext = pMainContext->QueryFilterContext();
  938. if ( pFilterContext == NULL )
  939. {
  940. return HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  941. }
  942. //
  943. // Create a passport manager
  944. //
  945. pPassportContext = new (pMainContext) PASSPORT_CONTEXT;
  946. if ( pPassportContext == NULL )
  947. {
  948. return HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  949. }
  950. hr = pPassportContext->Create( pFilterContext );
  951. if ( FAILED( hr ) )
  952. {
  953. delete pPassportContext;
  954. return hr;
  955. }
  956. pMainContext->SetContextState( pPassportContext );
  957. //
  958. // OK. Do some weird Tweener crap. Check the request for magic and if
  959. // we see it, we avoid Passport Manager altogether
  960. //
  961. hr = DoTweenerSpecialCase( pMainContext,
  962. &fTweenerHandled );
  963. if ( FAILED( hr ) )
  964. {
  965. return hr;
  966. }
  967. if ( fTweenerHandled )
  968. {
  969. //
  970. // We have done our thing. Just return success. We'll let the
  971. // DoAuthenticate send the response
  972. //
  973. *pfApplies = TRUE;
  974. pPassportContext->SetTweener( TRUE );
  975. return NO_ERROR;
  976. }
  977. //
  978. // Does this request look destined for passport?
  979. //
  980. hr = pPassportContext->DoesApply( pFilterContext->QueryFC(),
  981. pfApplies,
  982. &strReturnCookie );
  983. if ( FAILED( hr ) )
  984. {
  985. return hr;
  986. }
  987. //
  988. //
  989. // If a cookie was set, add it to the response
  990. //
  991. if ( !strReturnCookie.IsEmpty() )
  992. {
  993. hr = pFilterContext->AddResponseHeaders( strReturnCookie.QueryStr() );
  994. if ( FAILED( hr ) )
  995. {
  996. return hr;
  997. }
  998. }
  999. return NO_ERROR;
  1000. }
  1001. HRESULT
  1002. PASSPORT_AUTH_PROVIDER::DoAuthenticate(
  1003. W3_MAIN_CONTEXT * pMainContext,
  1004. BOOL * pfFilterFinished
  1005. )
  1006. /*++
  1007. Routine Description:
  1008. Allows filter which applies to actually authenticate the request
  1009. Arguments:
  1010. pMainContext - Main context
  1011. pfFilterFinished - Set to TRUE if filter wants out
  1012. Return Value:
  1013. HRESULT
  1014. --*/
  1015. {
  1016. W3_METADATA * pMetaData;
  1017. URL_CONTEXT * pUrlContext;
  1018. TOKEN_CACHE_ENTRY * pToken = NULL;
  1019. PASSPORT_USER_CONTEXT * pUserContext;
  1020. HRESULT hr;
  1021. PASSPORT_CONTEXT * pPassportContext;
  1022. W3_RESPONSE * pResponse;
  1023. STACK_STRU( strAuthUser, 256 );
  1024. STACK_STRU( strRemoteUser, 256 );
  1025. STACK_STRU( strDomainName, 256 );
  1026. if ( pMainContext == NULL ||
  1027. pfFilterFinished == NULL )
  1028. {
  1029. DBG_ASSERT( FALSE );
  1030. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  1031. }
  1032. *pfFilterFinished = FALSE;
  1033. //
  1034. // We must be initialized!
  1035. //
  1036. DBG_ASSERT( _fInitialized );
  1037. //
  1038. // We must be supported by metadata
  1039. //
  1040. pUrlContext = pMainContext->QueryUrlContext();
  1041. DBG_ASSERT( pUrlContext != NULL );
  1042. pMetaData = pUrlContext->QueryMetaData();
  1043. DBG_ASSERT( pMetaData != NULL );
  1044. DBG_ASSERT( pMetaData->QueryAuthTypeSupported( MD_AUTH_PASSPORT ) );
  1045. //
  1046. // Get the saved passport state, we better be able to find it!
  1047. //
  1048. pPassportContext = (PASSPORT_CONTEXT*) pMainContext->QueryContextState();
  1049. DBG_ASSERT( pPassportContext != NULL );
  1050. //
  1051. // Before we go any further, check whether we've already Tweenerized this
  1052. // request. If we have, the response is already setup. Just bail
  1053. //
  1054. if ( pPassportContext->QueryIsTweener() )
  1055. {
  1056. return NO_ERROR;
  1057. }
  1058. //
  1059. // Choose a domain for the logon. If the metabase domain is set, use it,
  1060. // otherwise choose the default domain name
  1061. //
  1062. if ( pMetaData->QueryDomainName() == NULL ||
  1063. pMetaData->QueryDomainName()[ 0 ] == L'\0' )
  1064. {
  1065. //
  1066. // If we're a member of a domain, use that domain name
  1067. //
  1068. if ( W3_STATE_AUTHENTICATION::QueryIsDomainMember() )
  1069. {
  1070. hr = strDomainName.Copy( W3_STATE_AUTHENTICATION::QueryMemberDomainName() );
  1071. }
  1072. else
  1073. {
  1074. hr = strDomainName.Copy( W3_STATE_AUTHENTICATION::QueryDefaultDomainName() );
  1075. }
  1076. if ( FAILED( hr ) )
  1077. {
  1078. return hr;
  1079. }
  1080. }
  1081. else
  1082. {
  1083. //
  1084. // Use the metabase domain name
  1085. //
  1086. hr = strDomainName.Copy( pMetaData->QueryDomainName() );
  1087. if ( FAILED( hr ) )
  1088. {
  1089. return hr;
  1090. }
  1091. }
  1092. //
  1093. // Lets authenticate
  1094. //
  1095. hr = pPassportContext->DoAuthenticate( pMainContext,
  1096. &pToken,
  1097. &strAuthUser,
  1098. &strRemoteUser,
  1099. strDomainName );
  1100. if ( FAILED( hr ) )
  1101. {
  1102. //
  1103. // Setup the 401 response
  1104. //
  1105. DBG_ASSERT( pToken == NULL );
  1106. pMainContext->QueryResponse()->SetStatus( HttpStatusUnauthorized,
  1107. Http401BadLogon );
  1108. return NO_ERROR;
  1109. }
  1110. //
  1111. // Create a user context
  1112. //
  1113. pUserContext = new PASSPORT_USER_CONTEXT( this );
  1114. if ( pUserContext == NULL )
  1115. {
  1116. pToken->DereferenceCacheEntry();
  1117. pToken = NULL;
  1118. return HRESULT_FROM_WIN32( GetLastError() );
  1119. }
  1120. hr = pUserContext->Create( pToken,
  1121. strAuthUser,
  1122. strRemoteUser );
  1123. if ( FAILED( hr ) )
  1124. {
  1125. pToken->DereferenceCacheEntry();
  1126. pToken = NULL;
  1127. pUserContext->DereferenceUserContext();
  1128. pUserContext = NULL;
  1129. }
  1130. pMainContext->SetUserContext( pUserContext );
  1131. return NO_ERROR;
  1132. }
  1133. HRESULT
  1134. PASSPORT_AUTH_PROVIDER::EscapeAmpersands(
  1135. STRA & strUrl
  1136. )
  1137. /*++
  1138. Routine Description:
  1139. Sigh. A special function to escape ampersands so passport is happy
  1140. Arguments:
  1141. strUrl - String to escape
  1142. Return Value:
  1143. HRESULT
  1144. --*/
  1145. {
  1146. STACK_STRA( strTemp, 256 );
  1147. HRESULT hr;
  1148. CHAR * pszCursor;
  1149. CHAR * pszAmpersand;
  1150. pszCursor = strUrl.QueryStr();
  1151. pszAmpersand = strchr( pszCursor, '&' );
  1152. while ( pszAmpersand != NULL )
  1153. {
  1154. hr = strTemp.Append( pszCursor, DIFF( pszAmpersand - pszCursor ) );
  1155. if ( FAILED( hr ) )
  1156. {
  1157. return hr;
  1158. }
  1159. hr = strTemp.Append( "%26" );
  1160. if ( FAILED( hr ) )
  1161. {
  1162. return hr;
  1163. }
  1164. pszCursor = pszAmpersand + 1;
  1165. pszAmpersand = strchr( pszCursor, '&' );
  1166. }
  1167. hr = strTemp.Append( pszCursor );
  1168. if ( FAILED( hr ) )
  1169. {
  1170. return hr;
  1171. }
  1172. return strUrl.Copy( strTemp );
  1173. }
  1174. HRESULT
  1175. PASSPORT_AUTH_PROVIDER::OnAccessDenied(
  1176. W3_MAIN_CONTEXT * pMainContext
  1177. )
  1178. /*++
  1179. Routine Description:
  1180. If we are logged on, present an acecss denied page. Otherwise,
  1181. present the redirect
  1182. Arguments:
  1183. pMainContext - Main context
  1184. Return Value:
  1185. HRESULT
  1186. --*/
  1187. {
  1188. W3_METADATA * pMetaData;
  1189. URL_CONTEXT * pUrlContext;
  1190. HRESULT hr = S_OK;
  1191. PASSPORT_CONTEXT * pPassportContext;
  1192. STACK_STRU( strRedirect, 256 );
  1193. STACK_STRA( strReturnUrl, 256 );
  1194. STACK_STRU( strUnicodeReturnUrl, 256 );
  1195. W3_FILTER_CONTEXT * pFilterContext = NULL;
  1196. STACK_STRA( strRawUrl, 256 );
  1197. W3_RESPONSE * pResponse;
  1198. STACK_STRA( strAuthenticateHeader, 256 );
  1199. if ( pMainContext == NULL )
  1200. {
  1201. DBG_ASSERT( FALSE );
  1202. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  1203. }
  1204. //
  1205. // We must be supported by metadata
  1206. //
  1207. pUrlContext = pMainContext->QueryUrlContext();
  1208. DBG_ASSERT( pUrlContext != NULL );
  1209. pMetaData = pUrlContext->QueryMetaData();
  1210. DBG_ASSERT( pMetaData != NULL );
  1211. DBG_ASSERT( pMetaData->QueryAuthTypeSupported( MD_AUTH_PASSPORT ) );
  1212. //
  1213. // Sigh. Have to check whether a passport challenge is already
  1214. // setup. If so, just NOP
  1215. //
  1216. pResponse = pMainContext->QueryResponse();
  1217. DBG_ASSERT( pResponse != NULL );
  1218. hr = pResponse->GetHeader( "WWW-Authenticate", &strAuthenticateHeader );
  1219. if ( SUCCEEDED( hr ) )
  1220. {
  1221. if ( _strnicmp( strAuthenticateHeader.QueryStr(),
  1222. "Passport1.4 ",
  1223. 12 ) == 0 )
  1224. {
  1225. //
  1226. // Challenge already there. Just NOP
  1227. //
  1228. return NO_ERROR;
  1229. }
  1230. }
  1231. //
  1232. // In some cases (too complicated to explain), we might actually get
  1233. // called on AccessDenied() before anything else. Therefore we do the
  1234. // same deferred init here
  1235. //
  1236. if ( !_fInitialized )
  1237. {
  1238. EnterCriticalSection( &_csInitLock );
  1239. if ( !_fInitialized )
  1240. {
  1241. hr = PASSPORT_CONTEXT::Initialize();
  1242. if ( SUCCEEDED( hr ) )
  1243. {
  1244. _fInitialized = TRUE;
  1245. }
  1246. }
  1247. LeaveCriticalSection( &_csInitLock );
  1248. }
  1249. if ( !_fInitialized )
  1250. {
  1251. DBG_ASSERT( FAILED( hr ) );
  1252. return hr;
  1253. }
  1254. //
  1255. // Get the saved passport state, we better be able to find it!
  1256. //
  1257. pPassportContext = (PASSPORT_CONTEXT*) pMainContext->QueryContextState( CONTEXT_STATE_AUTHENTICATION );
  1258. if ( pPassportContext == NULL )
  1259. {
  1260. pFilterContext = pMainContext->QueryFilterContext();
  1261. if ( pFilterContext == NULL )
  1262. {
  1263. return HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  1264. }
  1265. //
  1266. // Build a context now
  1267. //
  1268. pPassportContext = new (pMainContext) PASSPORT_CONTEXT;
  1269. if ( pPassportContext == NULL )
  1270. {
  1271. return HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  1272. }
  1273. hr = pPassportContext->Create( pFilterContext );
  1274. if ( FAILED( hr ) )
  1275. {
  1276. delete pPassportContext;
  1277. return hr;
  1278. }
  1279. pMainContext->SetContextState( pPassportContext );
  1280. }
  1281. //
  1282. // If we have authenticated, then we'll want to send a local redirect
  1283. // to an access denied page. Otherwise, we'll send a 302 redirect
  1284. //
  1285. if ( !pPassportContext->QueryIsAuthenticated() )
  1286. {
  1287. //
  1288. // Ok. Before we ask PassportManager for the authentication URL
  1289. // to redirect to, first check whether the client just cancelled. If
  1290. // they did we will redirect to the default page.
  1291. //
  1292. if ( pPassportContext->QueryUserError() )
  1293. {
  1294. BOOL fDidRedirect = FALSE;
  1295. hr = pPassportContext->SetupDefaultRedirect( pMainContext, &fDidRedirect );
  1296. if ( FAILED( hr ) || fDidRedirect )
  1297. {
  1298. return hr;
  1299. }
  1300. //
  1301. // If we're here, then there was no DefaultRedirect configured in passport
  1302. //
  1303. // Just set the passport forbidden error
  1304. //
  1305. pMainContext->QueryResponse()->SetStatus( HttpStatusForbidden,
  1306. Http403PassportLoginFailure );
  1307. return NO_ERROR;
  1308. }
  1309. //
  1310. // We want a URL without the extra :80
  1311. //
  1312. hr = pMainContext->QueryRequest()->GetRawUrl( &strRawUrl );
  1313. if ( FAILED( hr ) )
  1314. {
  1315. return hr;
  1316. }
  1317. hr = pMainContext->QueryRequest()->BuildFullUrl( strRawUrl,
  1318. &strReturnUrl,
  1319. FALSE );
  1320. if ( FAILED( hr ) )
  1321. {
  1322. return hr;
  1323. }
  1324. hr = strReturnUrl.Escape();
  1325. if ( FAILED( hr ) )
  1326. {
  1327. return hr;
  1328. }
  1329. hr = EscapeAmpersands( strReturnUrl );
  1330. if ( FAILED( hr ) )
  1331. {
  1332. return hr;
  1333. }
  1334. hr = strUnicodeReturnUrl.CopyA( strReturnUrl.QueryStr() );
  1335. if ( FAILED( hr ) )
  1336. {
  1337. return hr;
  1338. }
  1339. hr = pPassportContext->OnChallenge( strUnicodeReturnUrl );
  1340. if ( FAILED( hr ) )
  1341. {
  1342. return hr;
  1343. }
  1344. }
  1345. return NO_ERROR;
  1346. }
  1347. HRESULT
  1348. PASSPORT_AUTH_PROVIDER::DoTweenerSpecialCase(
  1349. W3_MAIN_CONTEXT * pMainContext,
  1350. BOOL * pfTweenerHandled
  1351. )
  1352. /*++
  1353. Routine Description:
  1354. Handle Tweener crap
  1355. Arguments:
  1356. pMainContext - Main context
  1357. pfTweenerHandled - Set to TRUE if tweener crap was done
  1358. Return Value:
  1359. HRESULT
  1360. --*/
  1361. {
  1362. STACK_STRU( strQueryString, 512 );
  1363. STACK_STRA( strTweenerUrl, 512 );
  1364. HRESULT hr;
  1365. W3_RESPONSE * pResponse;
  1366. W3_REQUEST * pRequest;
  1367. STACK_STRA( strAuthenticateHeader, 512 );
  1368. CHAR * pszAuthenticateHeader = NULL;
  1369. CHAR * pszStupid;
  1370. CHAR * pszBizarre;
  1371. CHAR * pszAcceptAuth;
  1372. WCHAR * pszTweenerMagic;
  1373. STACK_STRA( strAcceptAuth, 32 );
  1374. BOOL fSendRedirect = TRUE;
  1375. if ( pMainContext == NULL ||
  1376. pfTweenerHandled == NULL )
  1377. {
  1378. DBG_ASSERT( FALSE );
  1379. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  1380. }
  1381. *pfTweenerHandled = FALSE;
  1382. pResponse = pMainContext->QueryResponse();
  1383. DBG_ASSERT( pResponse != NULL );
  1384. pRequest = pMainContext->QueryRequest();
  1385. DBG_ASSERT( pRequest != NULL );
  1386. //
  1387. // First check for a query string, if there isn't one, we're done
  1388. //
  1389. hr = pMainContext->QueryRequest()->GetQueryString( &strQueryString );
  1390. if ( FAILED( hr ) )
  1391. {
  1392. return hr;
  1393. }
  1394. if ( strQueryString.QueryStr()[ 0 ] == L'\0' )
  1395. {
  1396. //
  1397. // No query string. We're done.
  1398. //
  1399. return NO_ERROR;
  1400. }
  1401. //
  1402. // Check the query string for the magic "msppchlg=1&mspplogin=" string
  1403. //
  1404. pszTweenerMagic = wcsstr( strQueryString.QueryStr(), MAGIC_TWEENER_STRING );
  1405. if ( pszTweenerMagic == NULL )
  1406. {
  1407. return NO_ERROR;
  1408. }
  1409. //
  1410. // The next part of the string should be the URL
  1411. //
  1412. hr = strTweenerUrl.CopyWToUTF8Unescaped( pszTweenerMagic + MAGIC_TWEENER_STRING_LEN );
  1413. if ( FAILED( hr ) )
  1414. {
  1415. return hr;
  1416. }
  1417. strTweenerUrl.Unescape();
  1418. //
  1419. // Start generating the response
  1420. //
  1421. hr = pResponse->SetHeaderByReference( HttpHeaderContentType,
  1422. "text/html",
  1423. 9 );
  1424. if ( FAILED( hr ) )
  1425. {
  1426. return hr;
  1427. }
  1428. hr = pResponse->SetHeader( HttpHeaderLocation,
  1429. strTweenerUrl.QueryStr(),
  1430. (USHORT)strTweenerUrl.QueryCCH() );
  1431. if ( FAILED( hr ) )
  1432. {
  1433. return hr;
  1434. }
  1435. //
  1436. // Calculate the authenticate header. This is the query string with
  1437. // in the tweener URL
  1438. //
  1439. pszAuthenticateHeader = strchr( strTweenerUrl.QueryStr(), '?' );
  1440. if ( pszAuthenticateHeader == NULL )
  1441. {
  1442. return NO_ERROR;
  1443. }
  1444. else
  1445. {
  1446. pszAuthenticateHeader++;
  1447. }
  1448. hr = strAuthenticateHeader.Copy( "Passport1.4 " );
  1449. if ( FAILED( hr ) )
  1450. {
  1451. return hr;
  1452. }
  1453. hr = strAuthenticateHeader.Append( pszAuthenticateHeader );
  1454. if ( FAILED( hr ) )
  1455. {
  1456. return hr;
  1457. }
  1458. pszBizarre = strchr( strAuthenticateHeader.QueryStr(), '&' );
  1459. while ( pszBizarre != NULL )
  1460. {
  1461. *pszBizarre = ',';
  1462. pszBizarre++;
  1463. pszBizarre = strchr( pszBizarre, '&' );
  1464. }
  1465. hr = pResponse->SetHeader( "WWW-Authenticate",
  1466. 16,
  1467. strAuthenticateHeader.QueryStr(),
  1468. (USHORT)strAuthenticateHeader.QueryCCH() );
  1469. if ( FAILED( hr ) )
  1470. {
  1471. return hr;
  1472. }
  1473. //
  1474. // Finally, if this client supports it, return a 401, else a 302
  1475. //
  1476. pszAcceptAuth = pRequest->GetHeader( "Accept-Auth" );
  1477. if ( pszAcceptAuth != NULL )
  1478. {
  1479. hr = strAcceptAuth.Copy( pszAcceptAuth );
  1480. if ( FAILED( hr ) )
  1481. {
  1482. return hr;
  1483. }
  1484. _strupr( strAcceptAuth.QueryStr() );
  1485. if ( strstr( strAcceptAuth.QueryStr(), "PASSPORT1.4" ) != NULL )
  1486. {
  1487. fSendRedirect = FALSE;
  1488. }
  1489. }
  1490. if ( fSendRedirect )
  1491. {
  1492. pResponse->SetStatus( HttpStatusRedirect );
  1493. }
  1494. else
  1495. {
  1496. pResponse->SetStatus( HttpStatusUnauthorized,
  1497. Http401BadLogon );
  1498. }
  1499. *pfTweenerHandled = TRUE;
  1500. return NO_ERROR;
  1501. }
  1502. HRESULT
  1503. PASSPORT_USER_CONTEXT::Create(
  1504. TOKEN_CACHE_ENTRY * pToken,
  1505. STRU & strAuthUser,
  1506. STRU & strRemoteUser
  1507. )
  1508. /*++
  1509. Routine Description:
  1510. Create a user context based off token
  1511. Arguments:
  1512. pToken - Cached token
  1513. strAuthUser - AUTH_USER
  1514. strRemoteUser - REMOTE_USER
  1515. Return Value:
  1516. HRESULT
  1517. --*/
  1518. {
  1519. HRESULT hr;
  1520. if ( pToken == NULL )
  1521. {
  1522. DBG_ASSERT( FALSE );
  1523. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  1524. }
  1525. hr = _strAuthUser.Copy( strAuthUser );
  1526. if ( FAILED( hr ) )
  1527. {
  1528. return hr;
  1529. }
  1530. hr = _strRemoteUser.Copy( strRemoteUser );
  1531. if ( FAILED( hr ) )
  1532. {
  1533. return hr;
  1534. }
  1535. _pToken = pToken;
  1536. return NO_ERROR;
  1537. }
  1538. HANDLE
  1539. PASSPORT_USER_CONTEXT::QueryPrimaryToken(
  1540. VOID
  1541. )
  1542. /*++
  1543. Routine Description:
  1544. Get primary token for this user
  1545. Arguments:
  1546. None
  1547. Return Value:
  1548. Token handle
  1549. --*/
  1550. {
  1551. DBG_ASSERT( _pToken != NULL );
  1552. return _pToken->QueryPrimaryToken();
  1553. }
  1554. HANDLE
  1555. PASSPORT_USER_CONTEXT::QueryImpersonationToken(
  1556. VOID
  1557. )
  1558. /*++
  1559. Routine Description:
  1560. Get impersonation token for this user
  1561. Arguments:
  1562. None
  1563. Return Value:
  1564. Token handle
  1565. --*/
  1566. {
  1567. DBG_ASSERT( _pToken != NULL );
  1568. return _pToken->QueryImpersonationToken();
  1569. }