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.

1128 lines
28 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. authstate.cxx
  5. Abstract:
  6. Authenticate state implementation (and authentication utilities)
  7. Author:
  8. Ming Lu ( MingLu ) 2-Feb-2000
  9. Environment:
  10. Win32 User Mode
  11. Revision History:
  12. --*/
  13. #include "precomp.hxx"
  14. #include "sspiprovider.hxx"
  15. #include "digestprovider.hxx"
  16. #include "iisdigestprovider.hxx"
  17. #include "basicprovider.hxx"
  18. #include "anonymousprovider.hxx"
  19. #include "certmapprovider.hxx"
  20. #include "iiscertmapprovider.hxx"
  21. #include "customprovider.hxx"
  22. W3_STATE_AUTHENTICATION * W3_STATE_AUTHENTICATION::sm_pAuthState;
  23. LUID W3_STATE_AUTHENTICATION::sm_BackupPrivilegeTcbValue;
  24. PTOKEN_PRIVILEGES W3_STATE_AUTHENTICATION::sm_pTokenPrivilege = NULL;
  25. PTRACE_LOG W3_USER_CONTEXT::sm_pTraceLog;
  26. PTRACE_LOG CONNECTION_AUTH_CONTEXT::sm_pTraceLog;
  27. HRESULT
  28. W3_STATE_AUTHENTICATION::GetDefaultDomainName(
  29. VOID
  30. )
  31. /*++
  32. Description:
  33. Fills in the member variable with the name of the default domain
  34. to use for logon validation
  35. Arguments:
  36. szDefaultDomainName - Buffer to hold the default domain name
  37. Returns:
  38. HRESULT
  39. --*/
  40. {
  41. OBJECT_ATTRIBUTES ObjectAttributes;
  42. NTSTATUS NtStatus;
  43. DWORD dwLength;
  44. DWORD err = 0;
  45. LSA_HANDLE LsaPolicyHandle = NULL;
  46. PPOLICY_ACCOUNT_DOMAIN_INFO pAcctDomainInfo = NULL;
  47. PPOLICY_PRIMARY_DOMAIN_INFO pPrimaryDomainInfo = NULL;
  48. HRESULT hr = S_OK;
  49. //
  50. // Open a handle to the local machine's LSA policy object.
  51. //
  52. InitializeObjectAttributes( &ObjectAttributes,
  53. NULL,
  54. 0L,
  55. NULL,
  56. NULL );
  57. NtStatus = LsaOpenPolicy( NULL,
  58. &ObjectAttributes,
  59. POLICY_EXECUTE,
  60. &LsaPolicyHandle );
  61. if( !NT_SUCCESS( NtStatus ) )
  62. {
  63. DBGPRINTF(( DBG_CONTEXT,
  64. "cannot open lsa policy, error %08lX\n",
  65. NtStatus ));
  66. err = LsaNtStatusToWinError( NtStatus );
  67. //
  68. // Failure LsaOpenPolicy() does not guarantee that
  69. // LsaPolicyHandle was not touched.
  70. //
  71. LsaPolicyHandle = NULL;
  72. goto Cleanup;
  73. }
  74. //
  75. // Query the account domain information from the policy object.
  76. //
  77. NtStatus = LsaQueryInformationPolicy( LsaPolicyHandle,
  78. PolicyAccountDomainInformation,
  79. (PVOID *)&pAcctDomainInfo );
  80. if( !NT_SUCCESS( NtStatus ) )
  81. {
  82. DBGPRINTF(( DBG_CONTEXT,
  83. "cannot query lsa policy info, error %08lX\n",
  84. NtStatus ));
  85. err = LsaNtStatusToWinError( NtStatus );
  86. goto Cleanup;
  87. }
  88. DBG_ASSERT( pAcctDomainInfo != NULL );
  89. dwLength = pAcctDomainInfo->DomainName.Length / sizeof( WCHAR );
  90. wcsncpy( _achDefaultDomainName,
  91. (LPCWSTR)pAcctDomainInfo->DomainName.Buffer,
  92. sizeof( _achDefaultDomainName ) / sizeof( WCHAR ) );
  93. _achDefaultDomainName[ dwLength ] = L'\0';
  94. //
  95. // Query the primary domain information from the policy object.
  96. //
  97. NtStatus = LsaQueryInformationPolicy( LsaPolicyHandle,
  98. PolicyPrimaryDomainInformation,
  99. (PVOID *)&pPrimaryDomainInfo );
  100. if( !NT_SUCCESS( NtStatus ) )
  101. {
  102. DBGPRINTF(( DBG_CONTEXT,
  103. "cannot query lsa policy info, error %08lX\n",
  104. NtStatus ));
  105. err = LsaNtStatusToWinError( NtStatus );
  106. goto Cleanup;
  107. }
  108. DBG_ASSERT( pPrimaryDomainInfo != NULL );
  109. if( pPrimaryDomainInfo->Sid )
  110. {
  111. //
  112. // We are a domain member
  113. //
  114. _fIsDomainMember = TRUE;
  115. }
  116. else
  117. {
  118. _fIsDomainMember = FALSE;
  119. }
  120. //
  121. // Success!
  122. //
  123. DBG_ASSERT( err == 0 );
  124. Cleanup:
  125. if( pAcctDomainInfo != NULL )
  126. {
  127. LsaFreeMemory( (PVOID)pAcctDomainInfo );
  128. pAcctDomainInfo = NULL;
  129. }
  130. if( pPrimaryDomainInfo != NULL )
  131. {
  132. LsaFreeMemory( (PVOID)pPrimaryDomainInfo );
  133. pPrimaryDomainInfo = NULL;
  134. }
  135. if( LsaPolicyHandle != NULL )
  136. {
  137. LsaClose( LsaPolicyHandle );
  138. }
  139. if ( err )
  140. {
  141. hr = HRESULT_FROM_WIN32( err );
  142. }
  143. return hr;
  144. };
  145. //static
  146. HRESULT
  147. W3_STATE_AUTHENTICATION::SplitUserDomain(
  148. STRU & strUserDomain,
  149. STRU * pstrUserName,
  150. STRU * pstrDomainName,
  151. WCHAR * pszDefaultDomain,
  152. BOOL * pfPossibleUPNLogon
  153. )
  154. /*++
  155. Description:
  156. Split the input user name into user/domain.
  157. Arguments:
  158. strUserDomain - Combined domain\username (not altered)
  159. pstrUserName - Filled with user name only
  160. pstrDomainName - Filled with domain name (either embedded in
  161. *pstrUserName,or from metabase/computer domain name)
  162. pszDefaultDomain - Default domain specified in metabase
  163. pfPossibleUPNLogon - TRUE if we may need to do UNP logon,
  164. otherwise FALSE
  165. Returns:
  166. HRESULT
  167. --*/
  168. {
  169. WCHAR * pszUserName;
  170. W3_METADATA * pMetaData = NULL;
  171. WCHAR * pszDomain;
  172. DWORD cbDomain;
  173. HRESULT hr;
  174. if ( pstrUserName == NULL ||
  175. pstrDomainName == NULL ||
  176. pfPossibleUPNLogon == NULL )
  177. {
  178. DBG_ASSERT( FALSE );
  179. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  180. }
  181. pszUserName = wcspbrk( strUserDomain.QueryStr(), L"/\\" );
  182. if ( pszUserName == NULL )
  183. {
  184. //
  185. // No domain in the user name. First try the metabase domain
  186. // name
  187. //
  188. pszDomain = pszDefaultDomain;
  189. if ( pszDomain == NULL || *pszDomain == L'\0' )
  190. {
  191. //
  192. // No metabase domain, use default domain name
  193. //
  194. pszDomain = QueryDefaultDomainName();
  195. DBG_ASSERT( pszDomain != NULL );
  196. }
  197. pszUserName = strUserDomain.QueryStr();
  198. hr = pstrDomainName->Copy( pszDomain );
  199. if ( FAILED( hr ) )
  200. {
  201. return hr;
  202. }
  203. *pfPossibleUPNLogon = TRUE;
  204. }
  205. else
  206. {
  207. cbDomain = DIFF( pszUserName - strUserDomain.QueryStr() );
  208. if( cbDomain == 0 )
  209. {
  210. hr = pstrDomainName->Copy( L"." );
  211. }
  212. else
  213. {
  214. hr = pstrDomainName->Copy( strUserDomain.QueryStr(), cbDomain );
  215. }
  216. if ( FAILED( hr ) )
  217. {
  218. return hr;
  219. }
  220. pszUserName = pszUserName + 1;
  221. *pfPossibleUPNLogon = FALSE;
  222. }
  223. hr = pstrUserName->Copy( pszUserName );
  224. if ( FAILED( hr ) )
  225. {
  226. return hr;
  227. }
  228. return NO_ERROR;
  229. }
  230. HRESULT
  231. W3_STATE_AUTHENTICATION::OnAccessDenied(
  232. W3_MAIN_CONTEXT * pMainContext
  233. )
  234. /*++
  235. Description:
  236. Called when a resource is access denied. This routines will call
  237. all authentication providers so that they may add authentication
  238. headers, etc.
  239. Arguments:
  240. pMainContext - main context
  241. Returns:
  242. HRESULT
  243. --*/
  244. {
  245. AUTH_PROVIDER * pProvider;
  246. DWORD cProviderCount = 0;
  247. W3_METADATA * pMetaData;
  248. HRESULT hr = NO_ERROR;
  249. if ( pMainContext == NULL )
  250. {
  251. DBG_ASSERT( FALSE );
  252. return HRESULT_FROM_WIN32( GetLastError() );
  253. }
  254. pMetaData = pMainContext->QueryUrlContext()->QueryMetaData();
  255. DBG_ASSERT( pMetaData != NULL );
  256. //
  257. // Loop thru all authentication providers
  258. //
  259. for ( cProviderCount = 0; ; cProviderCount++ )
  260. {
  261. pProvider = _rgAuthProviders[ cProviderCount ];
  262. if ( pProvider == NULL )
  263. {
  264. break;
  265. }
  266. //
  267. // Only call OnAccessDenied() if the authentication provider is
  268. // supported for the given metadata of the denied request
  269. //
  270. if ( !pMetaData->QueryAuthTypeSupported(
  271. pProvider->QueryAuthType() ) )
  272. {
  273. continue;
  274. }
  275. hr = pProvider->OnAccessDenied( pMainContext );
  276. if ( FAILED( hr ) )
  277. {
  278. break;
  279. }
  280. }
  281. return hr;
  282. }
  283. VOID
  284. W3_STATE_AUTHENTICATION::GetSSPTokenPrivilege(
  285. VOID
  286. )
  287. /*++
  288. Description:
  289. Prepare an appropriate token privilege used to adjust the
  290. SSP impersonation token privilege in order to work around
  291. the problem introduced by using FILE_FLAG_BACKUP_SEMANTICS
  292. in CreateFileW call in W3_FILE_INFO::OpenFile.
  293. Arguments:
  294. None.
  295. Returns:
  296. None.
  297. --*/
  298. {
  299. sm_pTokenPrivilege = ( PTOKEN_PRIVILEGES )LocalAlloc( LMEM_FIXED,
  300. sizeof( TOKEN_PRIVILEGES ) + sizeof( LUID_AND_ATTRIBUTES ));
  301. if ( sm_pTokenPrivilege != NULL )
  302. {
  303. if ( !LookupPrivilegeValue( NULL,
  304. L"SeBackupPrivilege",
  305. &sm_BackupPrivilegeTcbValue ) )
  306. {
  307. sm_pTokenPrivilege->PrivilegeCount = 0;
  308. }
  309. else
  310. {
  311. //
  312. // Set attributes to disable SeBackupPrivilege for SSP
  313. // impersonation token
  314. //
  315. sm_pTokenPrivilege->PrivilegeCount = 1;
  316. sm_pTokenPrivilege->Privileges[0].Luid =
  317. sm_BackupPrivilegeTcbValue;
  318. sm_pTokenPrivilege->Privileges[0].Attributes = 0;
  319. }
  320. }
  321. }
  322. W3_STATE_AUTHENTICATION::W3_STATE_AUTHENTICATION()
  323. {
  324. _pAnonymousProvider = NULL;
  325. _pCustomProvider = NULL;
  326. _fHasAssociatedUserBefore = FALSE;
  327. //
  328. // Initialize token privilege for SSP impersionation token
  329. //
  330. GetSSPTokenPrivilege();
  331. //
  332. // Figure out the default domain name once
  333. //
  334. _hr = GetDefaultDomainName();
  335. if ( FAILED( _hr ) )
  336. {
  337. return;
  338. }
  339. //
  340. // Initialize all the authentication providers
  341. //
  342. ZeroMemory( _rgAuthProviders, sizeof( _rgAuthProviders ) );
  343. _hr = InitializeAuthenticationProviders();
  344. if ( FAILED( _hr ) )
  345. {
  346. return;
  347. }
  348. _cbContextSize = sizeof( SSPI_CONTEXT_STATE ) +
  349. sizeof( ANONYMOUS_USER_CONTEXT );
  350. //
  351. // Initialize reverse DNS service
  352. //
  353. if (!InitRDns())
  354. {
  355. _hr = HRESULT_FROM_WIN32(GetLastError());
  356. DBGPRINTF(( DBG_CONTEXT,
  357. "Error initializing RDns service. hr = 0x%x\n",
  358. _hr ));
  359. TerminateAuthenticationProviders();
  360. return;
  361. }
  362. //
  363. // Initialize the W3_USER_CONTEXT reftrace log
  364. //
  365. #if DBG
  366. W3_USER_CONTEXT::sm_pTraceLog = CreateRefTraceLog( 2000, 0 );
  367. #else
  368. W3_USER_CONTEXT::sm_pTraceLog = NULL;
  369. #endif
  370. //
  371. // Store a pointer to the singleton (no C++ goo used in creating
  372. // this singleton)
  373. //
  374. if ( sm_pAuthState != NULL )
  375. {
  376. DBG_ASSERT( sm_pAuthState != NULL );
  377. _hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  378. }
  379. else
  380. {
  381. sm_pAuthState = this;
  382. }
  383. }
  384. W3_STATE_AUTHENTICATION::~W3_STATE_AUTHENTICATION()
  385. {
  386. if ( W3_USER_CONTEXT::sm_pTraceLog != NULL )
  387. {
  388. DestroyRefTraceLog( W3_USER_CONTEXT::sm_pTraceLog );
  389. W3_USER_CONTEXT::sm_pTraceLog = NULL;
  390. }
  391. TerminateRDns();
  392. TerminateAuthenticationProviders();
  393. if (sm_pTokenPrivilege != NULL)
  394. {
  395. LocalFree(sm_pTokenPrivilege);
  396. sm_pTokenPrivilege = NULL;
  397. }
  398. sm_pAuthState = NULL;
  399. }
  400. HRESULT
  401. W3_STATE_AUTHENTICATION::InitializeAuthenticationProviders(
  402. VOID
  403. )
  404. /*++
  405. Routine Description:
  406. Initialize all authentication providers
  407. Arguments:
  408. None
  409. Return Value:
  410. HRESULT
  411. --*/
  412. {
  413. HRESULT hr = NO_ERROR;
  414. DWORD cProviderCount = 0;
  415. //
  416. // Initialize trace for connection contexts
  417. //
  418. hr = CONNECTION_AUTH_CONTEXT::Initialize();
  419. if ( FAILED( hr ) )
  420. {
  421. goto Failure;
  422. }
  423. //
  424. // Certificate map provider. This must be the first !!!!!!
  425. //
  426. DBG_ASSERT( cProviderCount < AUTH_PROVIDER_COUNT );
  427. _rgAuthProviders[ cProviderCount ] = new CERTMAP_AUTH_PROVIDER;
  428. if ( _rgAuthProviders[ cProviderCount ] == NULL )
  429. {
  430. hr = HRESULT_FROM_WIN32( GetLastError() );
  431. goto Failure;
  432. }
  433. hr = _rgAuthProviders[ cProviderCount ]->Initialize( cProviderCount );
  434. if ( FAILED( hr ) )
  435. {
  436. delete _rgAuthProviders[ cProviderCount ];
  437. _rgAuthProviders[ cProviderCount ] = NULL;
  438. goto Failure;
  439. }
  440. cProviderCount++;
  441. DBG_ASSERT( cProviderCount < AUTH_PROVIDER_COUNT );
  442. _rgAuthProviders[ cProviderCount ] = new IISCERTMAP_AUTH_PROVIDER;
  443. if ( _rgAuthProviders[ cProviderCount ] == NULL )
  444. {
  445. hr = HRESULT_FROM_WIN32( GetLastError() );
  446. goto Failure;
  447. }
  448. hr = _rgAuthProviders[ cProviderCount ]->Initialize( cProviderCount );
  449. if ( FAILED( hr ) )
  450. {
  451. delete _rgAuthProviders[ cProviderCount ];
  452. _rgAuthProviders[ cProviderCount ] = NULL;
  453. goto Failure;
  454. }
  455. cProviderCount++;
  456. //
  457. // SSPI provider
  458. //
  459. DBG_ASSERT( cProviderCount < AUTH_PROVIDER_COUNT );
  460. _rgAuthProviders[ cProviderCount ] =
  461. new SSPI_AUTH_PROVIDER( MD_AUTH_NT );
  462. if ( _rgAuthProviders[ cProviderCount ] == NULL )
  463. {
  464. hr = HRESULT_FROM_WIN32( GetLastError() );
  465. goto Failure;
  466. }
  467. hr = _rgAuthProviders[ cProviderCount ]->Initialize( cProviderCount );
  468. if ( FAILED( hr ) )
  469. {
  470. delete _rgAuthProviders[ cProviderCount ];
  471. _rgAuthProviders[ cProviderCount ] = NULL;
  472. goto Failure;
  473. }
  474. cProviderCount++;
  475. //
  476. // Digest provider
  477. //
  478. DBG_ASSERT( cProviderCount < AUTH_PROVIDER_COUNT );
  479. _rgAuthProviders[ cProviderCount ] =
  480. new DIGEST_AUTH_PROVIDER( MD_AUTH_MD5 );
  481. if ( _rgAuthProviders[ cProviderCount ] == NULL )
  482. {
  483. hr = HRESULT_FROM_WIN32( GetLastError() );
  484. goto Failure;
  485. }
  486. hr = _rgAuthProviders[ cProviderCount ]->Initialize( cProviderCount );
  487. if ( FAILED( hr ) )
  488. {
  489. delete _rgAuthProviders[ cProviderCount ];
  490. _rgAuthProviders[ cProviderCount ] = NULL;
  491. goto Failure;
  492. }
  493. cProviderCount++;
  494. //
  495. // IIS Digest provider (for backward compatibility)
  496. //
  497. DBG_ASSERT( cProviderCount < AUTH_PROVIDER_COUNT );
  498. _rgAuthProviders[ cProviderCount ] =
  499. new IIS_DIGEST_AUTH_PROVIDER();
  500. if ( _rgAuthProviders[ cProviderCount ] == NULL )
  501. {
  502. hr = HRESULT_FROM_WIN32( GetLastError() );
  503. goto Failure;
  504. }
  505. hr = _rgAuthProviders[ cProviderCount ]->Initialize( cProviderCount );
  506. if ( FAILED( hr ) )
  507. {
  508. delete _rgAuthProviders[ cProviderCount ];
  509. _rgAuthProviders[ cProviderCount ] = NULL;
  510. goto Failure;
  511. }
  512. cProviderCount++;
  513. //
  514. // Basic provider
  515. //
  516. DBG_ASSERT( cProviderCount < AUTH_PROVIDER_COUNT );
  517. _rgAuthProviders[ cProviderCount ] = new BASIC_AUTH_PROVIDER;
  518. if ( _rgAuthProviders[ cProviderCount ] == NULL )
  519. {
  520. hr = HRESULT_FROM_WIN32( GetLastError() );
  521. goto Failure;
  522. }
  523. hr = _rgAuthProviders[ cProviderCount ]->Initialize( cProviderCount );
  524. if ( FAILED( hr ) )
  525. {
  526. delete _rgAuthProviders[ cProviderCount ];
  527. _rgAuthProviders[ cProviderCount ] = NULL;
  528. goto Failure;
  529. }
  530. cProviderCount++;
  531. //
  532. // Anonymous provider.
  533. //
  534. // Note: This one should always be the last one
  535. //
  536. DBG_ASSERT( cProviderCount < AUTH_PROVIDER_COUNT );
  537. _rgAuthProviders[ cProviderCount ] = new ANONYMOUS_AUTH_PROVIDER;
  538. if ( _rgAuthProviders[ cProviderCount ] == NULL )
  539. {
  540. hr = HRESULT_FROM_WIN32( GetLastError() );
  541. goto Failure;
  542. }
  543. hr = _rgAuthProviders[ cProviderCount ]->Initialize( cProviderCount );
  544. if ( FAILED( hr ) )
  545. {
  546. delete _rgAuthProviders[ cProviderCount ];
  547. _rgAuthProviders[ cProviderCount ] = NULL;
  548. goto Failure;
  549. }
  550. _pAnonymousProvider = _rgAuthProviders[ cProviderCount ];
  551. cProviderCount++;
  552. //
  553. // Custom provider. Not really a provider in the sense that it does not
  554. // participate in authenticating a request. Instead, it is just used
  555. // as a stub provider for custom authentication done with
  556. // HSE_REQ_EXEC_URL
  557. //
  558. _pCustomProvider = new CUSTOM_AUTH_PROVIDER;
  559. if ( _pCustomProvider == NULL )
  560. {
  561. hr = HRESULT_FROM_WIN32( GetLastError() );
  562. goto Failure;
  563. }
  564. return NO_ERROR;
  565. Failure:
  566. for ( DWORD i = 0; i < AUTH_PROVIDER_COUNT; i++ )
  567. {
  568. if ( _rgAuthProviders[ i ] != NULL )
  569. {
  570. _rgAuthProviders[ i ]->Terminate();
  571. delete _rgAuthProviders[ i ];
  572. _rgAuthProviders[ i ] = NULL;
  573. }
  574. }
  575. CONNECTION_AUTH_CONTEXT::Terminate();
  576. return hr;
  577. }
  578. VOID
  579. W3_STATE_AUTHENTICATION::TerminateAuthenticationProviders(
  580. VOID
  581. )
  582. /*++
  583. Routine Description:
  584. Terminate all authentication providers
  585. Arguments:
  586. None
  587. Return Value:
  588. None
  589. --*/
  590. {
  591. for ( DWORD i = 0; i < AUTH_PROVIDER_COUNT; i++ )
  592. {
  593. if ( _rgAuthProviders[ i ] != NULL )
  594. {
  595. _rgAuthProviders[ i ]->Terminate();
  596. delete _rgAuthProviders[ i ];
  597. _rgAuthProviders[ i ] = NULL;
  598. }
  599. }
  600. if ( _pCustomProvider != NULL )
  601. {
  602. delete _pCustomProvider;
  603. _pCustomProvider = NULL;
  604. }
  605. CONNECTION_AUTH_CONTEXT::Terminate();
  606. }
  607. CONTEXT_STATUS
  608. W3_STATE_AUTHENTICATION::DoWork(
  609. W3_MAIN_CONTEXT * pMainContext,
  610. DWORD cbCompletion,
  611. DWORD dwCompletionStatus
  612. )
  613. /*++
  614. Routine Description:
  615. Handle authentication for this request
  616. Arguments:
  617. pMainContext - W3_MAIN_CONTEXT representing execution of state
  618. machine
  619. cbCompletion - Number of bytes in an async completion
  620. dwCompletionStatus - Error status of a completion
  621. Return Value:
  622. CONTEXT_STATUS_CONTINUE - if we should continue in state machine
  623. else stop executing the machine and free up the current thread
  624. --*/
  625. {
  626. DWORD cProviderCount = 0;
  627. AUTH_PROVIDER * pProvider = NULL;
  628. W3_METADATA * pMetaData = NULL;
  629. W3_USER_CONTEXT * pUserContext = NULL;
  630. URL_CONTEXT * pUrlContext = NULL;
  631. BOOL fSupported = FALSE;
  632. HRESULT hr = NO_ERROR;
  633. BOOL fApplies = FALSE;
  634. DBG_ASSERT( pMainContext != NULL );
  635. //
  636. // If we already have a user context, then we must have had an
  637. // AUTH_COMPLETE notification which caused the state machine to back up
  638. // and resume from URLINFO state. In that case, just bail
  639. //
  640. if ( pMainContext->QueryUserContext() != NULL )
  641. {
  642. DBG_ASSERT( pMainContext->IsNotificationNeeded( SF_NOTIFY_AUTH_COMPLETE ) );
  643. return CONTEXT_STATUS_CONTINUE;
  644. }
  645. //
  646. // First, find the authentication provider which applies. We
  647. // should always find a matching provider (since anonymous
  648. // provider) should always match!
  649. //
  650. for ( ; ; )
  651. {
  652. pProvider = _rgAuthProviders[ cProviderCount ];
  653. if ( pProvider == NULL )
  654. {
  655. break;
  656. }
  657. DBG_ASSERT( pProvider != NULL );
  658. hr = pProvider->DoesApply( pMainContext,
  659. &fApplies );
  660. if ( FAILED( hr ) )
  661. {
  662. goto Finished;
  663. }
  664. if ( fApplies )
  665. {
  666. //
  667. // Cool. We have a match!
  668. //
  669. break;
  670. }
  671. cProviderCount++;
  672. }
  673. //
  674. // If only the anonymous provider matched, then check whether we
  675. // have credentials associated with the connection (since IE won't
  676. // send Authorization: header for subsequent SSPI authenticated
  677. // requests on a connection)
  678. //
  679. if ( pProvider->QueryAuthType() == MD_AUTH_ANONYMOUS )
  680. {
  681. //
  682. // Another slimy optimization. If we haven't associated a user
  683. // with the connection, then we don't have to bother looking up
  684. // connection
  685. //
  686. if ( _fHasAssociatedUserBefore )
  687. {
  688. pUserContext = pMainContext->QueryConnectionUserContext();
  689. if ( pUserContext != NULL )
  690. {
  691. pProvider = pUserContext->QueryProvider();
  692. DBG_ASSERT( pProvider != NULL );
  693. }
  694. }
  695. }
  696. else
  697. {
  698. //
  699. // If a provider applies, then ignore/remove any
  700. // cached user associated with the request
  701. //
  702. pUserContext = pMainContext->QueryConnectionUserContext();
  703. if ( pUserContext != NULL )
  704. {
  705. pMainContext->SetConnectionUserContext( NULL );
  706. pUserContext->DereferenceUserContext();
  707. pUserContext = NULL;
  708. }
  709. }
  710. //
  711. // Is the given provider supported (by metadata)
  712. //
  713. pMetaData = pMainContext->QueryUrlContext()->QueryMetaData();
  714. DBG_ASSERT( pMetaData != NULL );
  715. if ( pMetaData->QueryAuthTypeSupported( pProvider->QueryAuthType() ) )
  716. {
  717. fSupported = TRUE;
  718. }
  719. else
  720. {
  721. //
  722. // If anonymous authentication is supported, then we can
  723. // still let it thru
  724. //
  725. if ( pMetaData->QueryAuthTypeSupported( MD_AUTH_ANONYMOUS ) )
  726. {
  727. pProvider = QueryAnonymousProvider();
  728. DBG_ASSERT( pProvider != NULL );
  729. //
  730. // Anonymous provider applies, remove the previous cached
  731. // user associated with the request
  732. //
  733. if ( pUserContext != NULL )
  734. {
  735. pMainContext->SetConnectionUserContext( NULL );
  736. pUserContext->DereferenceUserContext();
  737. pUserContext = NULL;
  738. }
  739. fSupported = TRUE;
  740. }
  741. }
  742. //
  743. // Not supported, you're outta here!
  744. //
  745. if ( !fSupported )
  746. {
  747. pMainContext->QueryResponse()->SetStatus( HttpStatusUnauthorized,
  748. Http401Config );
  749. pMainContext->SetFinishedResponse();
  750. hr = pMainContext->OnAccessDenied();
  751. goto Finished;
  752. }
  753. //
  754. // Now we can authenticate
  755. //
  756. if ( pUserContext != NULL )
  757. {
  758. //
  759. // We already have a context associated with connection. Use it!
  760. //
  761. pUserContext->ReferenceUserContext();
  762. pMainContext->SetUserContext( pUserContext );
  763. }
  764. else
  765. {
  766. DBG_ASSERT( pProvider != NULL );
  767. // perf ctr
  768. pMainContext->QuerySite()->IncLogonAttempts();
  769. hr = pProvider->DoAuthenticate( pMainContext );
  770. if ( FAILED( hr ) )
  771. {
  772. if( WIN32_FROM_HRESULT( hr ) == ERROR_PASSWORD_MUST_CHANGE ||
  773. WIN32_FROM_HRESULT( hr ) == ERROR_PASSWORD_EXPIRED )
  774. {
  775. hr = pMainContext->PasswdChangeExecute();
  776. if( S_OK == hr )
  777. {
  778. return CONTEXT_STATUS_PENDING;
  779. }
  780. else if( S_FALSE == hr )
  781. {
  782. //
  783. // S_FALSE means password change disabled
  784. //
  785. pMainContext->QueryResponse()->SetStatus(
  786. HttpStatusUnauthorized,
  787. Http401BadLogon );
  788. pMainContext->SetErrorStatus( hr );
  789. pMainContext->SetFinishedResponse();
  790. return CONTEXT_STATUS_CONTINUE;
  791. }
  792. }
  793. goto Finished;
  794. }
  795. }
  796. //
  797. // Do we have a valid user now
  798. //
  799. pUserContext = pMainContext->QueryUserContext();
  800. if ( pUserContext != NULL )
  801. {
  802. if ( pUserContext->QueryAuthType() != MD_AUTH_ANONYMOUS )
  803. {
  804. hr = pMainContext->PasswdExpireNotify();
  805. if( FAILED( hr ) )
  806. {
  807. //
  808. // Internal error
  809. //
  810. goto Finished;
  811. }
  812. else if( hr == S_OK )
  813. {
  814. //
  815. // We've successfully handled password expire
  816. // notification
  817. //
  818. return CONTEXT_STATUS_PENDING;
  819. }
  820. //
  821. // Advanced password expire notification is disabled,
  822. // we should allow the user to get access, fall through
  823. //
  824. }
  825. //
  826. // Should we cache the user on the connection? Do so, only if
  827. //
  828. DBG_ASSERT( pMetaData != NULL );
  829. if ( pMetaData->QueryAuthPersistence() != MD_AUTH_SINGLEREQUEST
  830. && pUserContext->QueryProvider()->QueryAuthType() == MD_AUTH_NT
  831. && !pMainContext->QueryRequest()->IsProxyRequest()
  832. && pUserContext != pMainContext->QueryConnectionUserContext() )
  833. {
  834. pUserContext->ReferenceUserContext();
  835. pMainContext->SetConnectionUserContext( pUserContext );
  836. _fHasAssociatedUserBefore = TRUE;
  837. }
  838. }
  839. else
  840. {
  841. //
  842. // If we don't have a user, then we must not allow handle request
  843. // state to happen!
  844. //
  845. pMainContext->SetFinishedResponse();
  846. }
  847. //
  848. // OK. If we got to here and we have a user context, then authentication
  849. // is complete! So lets notify AUTH_COMPLETE filters
  850. //
  851. if ( pUserContext != NULL )
  852. {
  853. if ( pMainContext->IsNotificationNeeded( SF_NOTIFY_AUTH_COMPLETE ) )
  854. {
  855. HTTP_FILTER_AUTH_COMPLETE_INFO AuthInfo;
  856. STACK_STRU( strOriginal, MAX_PATH );
  857. STACK_STRU( strNewUrl, MAX_PATH );
  858. BOOL fFinished = FALSE;
  859. //
  860. // Store away the original URL
  861. //
  862. hr = pMainContext->QueryRequest()->GetUrl( &strOriginal );
  863. if ( FAILED( hr ) )
  864. {
  865. goto Finished;
  866. }
  867. //
  868. // Call the filter
  869. //
  870. pMainContext->NotifyFilters( SF_NOTIFY_AUTH_COMPLETE,
  871. &AuthInfo,
  872. &fFinished );
  873. if ( fFinished )
  874. {
  875. pMainContext->SetDone();
  876. return CONTEXT_STATUS_CONTINUE;
  877. }
  878. //
  879. // If the URL has changed, we'll need to backup the state machine
  880. //
  881. hr = pMainContext->QueryRequest()->GetUrl( &strNewUrl );
  882. if ( FAILED( hr ) )
  883. {
  884. goto Finished;
  885. }
  886. if ( wcscmp( strNewUrl.QueryStr(),
  887. strOriginal.QueryStr() ) != 0 )
  888. {
  889. //
  890. // URL is different!
  891. //
  892. pMainContext->BackupStateMachine();
  893. }
  894. else
  895. {
  896. //
  897. // URL is the same. Do nothing and continue
  898. //
  899. }
  900. }
  901. }
  902. Finished:
  903. if ( FAILED( hr ) )
  904. {
  905. pMainContext->QueryResponse()->
  906. SetStatus( HttpStatusServerError );
  907. pMainContext->SetFinishedResponse();
  908. pMainContext->SetErrorStatus( hr );
  909. }
  910. return CONTEXT_STATUS_CONTINUE;
  911. }