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.

1406 lines
38 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. #include "passportprovider.hxx"
  23. #define IIS_SUBAUTH_NAME L"iissuba"
  24. W3_STATE_AUTHENTICATION * W3_STATE_AUTHENTICATION::sm_pAuthState;
  25. BOOL W3_STATE_AUTHENTICATION::sm_fSubAuthConfigured = FALSE;
  26. BOOL W3_STATE_AUTHENTICATION::sm_fLocalSystem = FALSE;
  27. LONG W3_STATE_AUTHENTICATION::sm_lSubAuthAnonEvent = 0;
  28. LONG W3_STATE_AUTHENTICATION::sm_lSubAuthDigestEvent = 0;
  29. LONG W3_STATE_AUTHENTICATION::sm_lLocalSystemEvent = 0;
  30. PTRACE_LOG W3_USER_CONTEXT::sm_pTraceLog;
  31. PTRACE_LOG CONNECTION_AUTH_CONTEXT::sm_pTraceLog;
  32. HRESULT
  33. W3_STATE_AUTHENTICATION::GetDefaultDomainName(
  34. VOID
  35. )
  36. /*++
  37. Description:
  38. Fills in the member variable with the name of the default domain
  39. to use for logon validation
  40. Arguments:
  41. None
  42. Returns:
  43. HRESULT
  44. --*/
  45. {
  46. OBJECT_ATTRIBUTES ObjectAttributes;
  47. NTSTATUS NtStatus;
  48. DWORD dwLength;
  49. DWORD err = 0;
  50. LSA_HANDLE LsaPolicyHandle = NULL;
  51. PPOLICY_ACCOUNT_DOMAIN_INFO pAcctDomainInfo = NULL;
  52. PPOLICY_PRIMARY_DOMAIN_INFO pPrimaryDomainInfo = NULL;
  53. HRESULT hr = S_OK;
  54. //
  55. // Open a handle to the local machine's LSA policy object.
  56. //
  57. InitializeObjectAttributes( &ObjectAttributes,
  58. NULL,
  59. 0L,
  60. NULL,
  61. NULL );
  62. NtStatus = LsaOpenPolicy( NULL,
  63. &ObjectAttributes,
  64. POLICY_EXECUTE,
  65. &LsaPolicyHandle );
  66. if( !NT_SUCCESS( NtStatus ) )
  67. {
  68. DBGPRINTF(( DBG_CONTEXT,
  69. "cannot open lsa policy, error %08lX\n",
  70. NtStatus ));
  71. err = LsaNtStatusToWinError( NtStatus );
  72. //
  73. // Failure LsaOpenPolicy() does not guarantee that
  74. // LsaPolicyHandle was not touched.
  75. //
  76. LsaPolicyHandle = NULL;
  77. goto Cleanup;
  78. }
  79. //
  80. // Query the account domain information from the policy object.
  81. //
  82. NtStatus = LsaQueryInformationPolicy( LsaPolicyHandle,
  83. PolicyAccountDomainInformation,
  84. (PVOID *)&pAcctDomainInfo );
  85. if( !NT_SUCCESS( NtStatus ) )
  86. {
  87. DBGPRINTF(( DBG_CONTEXT,
  88. "cannot query lsa policy info, error %08lX\n",
  89. NtStatus ));
  90. err = LsaNtStatusToWinError( NtStatus );
  91. goto Cleanup;
  92. }
  93. DBG_ASSERT( pAcctDomainInfo != NULL );
  94. dwLength = pAcctDomainInfo->DomainName.Length / sizeof( WCHAR );
  95. if( dwLength < sizeof( _achDefaultDomainName ) / sizeof( WCHAR ) )
  96. {
  97. wcsncpy( _achDefaultDomainName,
  98. (LPCWSTR)pAcctDomainInfo->DomainName.Buffer,
  99. dwLength );
  100. _achDefaultDomainName[ dwLength ] = L'\0';
  101. }
  102. else
  103. {
  104. err = ERROR_INSUFFICIENT_BUFFER;
  105. goto Cleanup;
  106. }
  107. //
  108. // Query the primary domain information from the policy object.
  109. //
  110. NtStatus = LsaQueryInformationPolicy( LsaPolicyHandle,
  111. PolicyPrimaryDomainInformation,
  112. (PVOID *)&pPrimaryDomainInfo );
  113. if( !NT_SUCCESS( NtStatus ) )
  114. {
  115. DBGPRINTF(( DBG_CONTEXT,
  116. "cannot query lsa policy info, error %08lX\n",
  117. NtStatus ));
  118. err = LsaNtStatusToWinError( NtStatus );
  119. goto Cleanup;
  120. }
  121. DBG_ASSERT( pPrimaryDomainInfo != NULL );
  122. if( pPrimaryDomainInfo->Sid )
  123. {
  124. //
  125. // We are a domain member
  126. //
  127. _fIsDomainMember = TRUE;
  128. //
  129. // Tres freakin lame. Gotta call into GetComputerNameEx() since I
  130. // need to fully qualified name. If it fails, oh well, we don't
  131. // provide a default domain name for Passport calls
  132. //
  133. dwLength = sizeof( _achMemberDomainName ) / sizeof( WCHAR );
  134. GetComputerNameEx( ComputerNameDnsDomain,
  135. _achMemberDomainName,
  136. &dwLength );
  137. }
  138. else
  139. {
  140. _fIsDomainMember = FALSE;
  141. }
  142. //
  143. // Success!
  144. //
  145. DBG_ASSERT( err == 0 );
  146. Cleanup:
  147. if( pAcctDomainInfo != NULL )
  148. {
  149. LsaFreeMemory( (PVOID)pAcctDomainInfo );
  150. pAcctDomainInfo = NULL;
  151. }
  152. if( pPrimaryDomainInfo != NULL )
  153. {
  154. LsaFreeMemory( (PVOID)pPrimaryDomainInfo );
  155. pPrimaryDomainInfo = NULL;
  156. }
  157. if( LsaPolicyHandle != NULL )
  158. {
  159. LsaClose( LsaPolicyHandle );
  160. }
  161. if ( err )
  162. {
  163. hr = HRESULT_FROM_WIN32( err );
  164. }
  165. return hr;
  166. };
  167. //static
  168. HRESULT
  169. W3_STATE_AUTHENTICATION::SplitUserDomain(
  170. STRU & strUserDomain,
  171. STRU * pstrUserName,
  172. STRU * pstrDomainName,
  173. WCHAR * pszDefaultDomain,
  174. BOOL * pfPossibleUPNLogon
  175. )
  176. /*++
  177. Description:
  178. Split the input user name into user/domain.
  179. Arguments:
  180. strUserDomain - Combined domain\username (not altered)
  181. pstrUserName - Filled with user name only
  182. pstrDomainName - Filled with domain name (either embedded in
  183. *pstrUserName,or from metabase/computer domain name)
  184. pszDefaultDomain - Default domain specified in metabase
  185. pfPossibleUPNLogon - TRUE if we may need to do UNP logon,
  186. otherwise FALSE
  187. Returns:
  188. HRESULT
  189. --*/
  190. {
  191. WCHAR * pszUserName;
  192. WCHAR * pszDomain;
  193. DWORD cbDomain;
  194. HRESULT hr;
  195. if ( pstrUserName == NULL ||
  196. pstrDomainName == NULL ||
  197. pfPossibleUPNLogon == NULL )
  198. {
  199. DBG_ASSERT( FALSE );
  200. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  201. }
  202. pszUserName = wcspbrk( strUserDomain.QueryStr(), L"/\\" );
  203. if ( pszUserName == NULL )
  204. {
  205. //
  206. // No domain in the user name. First try the metabase domain
  207. // name
  208. //
  209. pszDomain = pszDefaultDomain;
  210. if ( pszDomain == NULL || *pszDomain == L'\0' )
  211. {
  212. //
  213. // No metabase domain, use default domain name
  214. //
  215. pszDomain = QueryDefaultDomainName();
  216. DBG_ASSERT( pszDomain != NULL );
  217. }
  218. pszUserName = strUserDomain.QueryStr();
  219. hr = pstrDomainName->Copy( pszDomain );
  220. if ( FAILED( hr ) )
  221. {
  222. return hr;
  223. }
  224. *pfPossibleUPNLogon = TRUE;
  225. }
  226. else
  227. {
  228. cbDomain = DIFF( pszUserName - strUserDomain.QueryStr() );
  229. if( cbDomain == 0 )
  230. {
  231. hr = pstrDomainName->Copy( L"." );
  232. }
  233. else
  234. {
  235. hr = pstrDomainName->Copy( strUserDomain.QueryStr(), cbDomain );
  236. }
  237. if ( FAILED( hr ) )
  238. {
  239. return hr;
  240. }
  241. pszUserName = pszUserName + 1;
  242. *pfPossibleUPNLogon = FALSE;
  243. }
  244. hr = pstrUserName->Copy( pszUserName );
  245. if ( FAILED( hr ) )
  246. {
  247. return hr;
  248. }
  249. return NO_ERROR;
  250. }
  251. HRESULT
  252. W3_STATE_AUTHENTICATION::OnAccessDenied(
  253. W3_MAIN_CONTEXT * pMainContext
  254. )
  255. /*++
  256. Description:
  257. Called when a resource is access denied. This routines will call
  258. all authentication providers so that they may add authentication
  259. headers, etc.
  260. Arguments:
  261. pMainContext - main context
  262. Returns:
  263. HRESULT
  264. --*/
  265. {
  266. AUTH_PROVIDER * pProvider;
  267. DWORD cProviderCount = 0;
  268. W3_METADATA * pMetaData;
  269. HRESULT hr = NO_ERROR;
  270. if ( pMainContext == NULL )
  271. {
  272. DBG_ASSERT( FALSE );
  273. return HRESULT_FROM_WIN32( GetLastError() );
  274. }
  275. pMetaData = pMainContext->QueryUrlContext()->QueryMetaData();
  276. DBG_ASSERT( pMetaData != NULL );
  277. //
  278. // Loop thru all authentication providers
  279. //
  280. for ( cProviderCount = 0; ; cProviderCount++ )
  281. {
  282. pProvider = _rgAuthProviders[ cProviderCount ];
  283. if ( pProvider == NULL )
  284. {
  285. break;
  286. }
  287. //
  288. // Only call OnAccessDenied() if the authentication provider is
  289. // supported for the given metadata of the denied request
  290. //
  291. if ( !pMetaData->QueryAuthTypeSupported(
  292. pProvider->QueryAuthType() ) )
  293. {
  294. continue;
  295. }
  296. //
  297. // Don't care about the return value here since we want to add
  298. // all possible authentication headers
  299. //
  300. hr = pProvider->OnAccessDenied( pMainContext );
  301. }
  302. return hr;
  303. }
  304. HRESULT
  305. W3_STATE_AUTHENTICATION::GetSubAuthConfiguration(
  306. VOID
  307. )
  308. /*++
  309. Description:
  310. Find out if sub authenticator is configured correctly for the
  311. current process.
  312. Arguments:
  313. None.
  314. Returns:
  315. HRESULT
  316. --*/
  317. {
  318. HRESULT hr = S_OK;
  319. PPRIVILEGE_SET pPrivilegeSet = NULL;
  320. HANDLE hProcessToken = NULL;
  321. BOOL fPrivilegeEnabled = FALSE;
  322. HKEY hKey = NULL;
  323. LUID TcbPrivilegeValue;
  324. WCHAR pszSubAuthName[ sizeof( IIS_SUBAUTH_NAME ) ];
  325. DWORD dwType;
  326. DWORD cbValue;
  327. if ( !OpenProcessToken( GetCurrentProcess(),
  328. TOKEN_ALL_ACCESS,
  329. &hProcessToken ) )
  330. {
  331. hr = HRESULT_FROM_WIN32( GetLastError() );
  332. goto Exit;
  333. }
  334. DBG_ASSERT( hProcessToken != NULL );
  335. pPrivilegeSet = ( PPRIVILEGE_SET )LocalAlloc( LMEM_FIXED,
  336. sizeof( PRIVILEGE_SET ) + sizeof( LUID_AND_ATTRIBUTES ) );
  337. if( pPrivilegeSet == NULL )
  338. {
  339. hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  340. goto Exit;
  341. }
  342. if ( !LookupPrivilegeValue( NULL,
  343. L"SeTcbPrivilege",
  344. &TcbPrivilegeValue ) )
  345. {
  346. hr = HRESULT_FROM_WIN32( GetLastError() );
  347. goto Exit;
  348. }
  349. pPrivilegeSet->PrivilegeCount = 1;
  350. pPrivilegeSet->Control = PRIVILEGE_SET_ALL_NECESSARY;
  351. pPrivilegeSet->Privilege[0].Luid = TcbPrivilegeValue;
  352. pPrivilegeSet->Privilege[0].Attributes = SE_PRIVILEGE_ENABLED;
  353. if( !PrivilegeCheck( hProcessToken,
  354. pPrivilegeSet,
  355. &fPrivilegeEnabled ) )
  356. {
  357. hr = HRESULT_FROM_WIN32( GetLastError() );
  358. goto Exit;
  359. }
  360. if( fPrivilegeEnabled )
  361. {
  362. sm_fLocalSystem = TRUE;
  363. }
  364. if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  365. L"System\\CurrentControlSet\\Control\\Lsa\\MSV1_0",
  366. 0,
  367. KEY_READ,
  368. &hKey ) == ERROR_SUCCESS )
  369. {
  370. DBG_ASSERT( hKey != NULL );
  371. cbValue = sizeof pszSubAuthName;
  372. if ( RegQueryValueEx( hKey,
  373. L"Auth132",
  374. NULL,
  375. &dwType,
  376. (LPBYTE) pszSubAuthName,
  377. &cbValue ) != ERROR_SUCCESS ||
  378. dwType != REG_SZ ||
  379. _wcsicmp( pszSubAuthName, IIS_SUBAUTH_NAME ) )
  380. {
  381. }
  382. else
  383. {
  384. sm_fSubAuthConfigured = TRUE;
  385. }
  386. RegCloseKey( hKey );
  387. hKey = NULL;
  388. }
  389. Exit:
  390. if( pPrivilegeSet != NULL )
  391. {
  392. LocalFree( pPrivilegeSet );
  393. pPrivilegeSet = NULL;
  394. }
  395. return hr;
  396. }
  397. W3_STATE_AUTHENTICATION::W3_STATE_AUTHENTICATION()
  398. {
  399. _pAnonymousProvider = NULL;
  400. _pCustomProvider = NULL;
  401. _fHasAssociatedUserBefore = FALSE;
  402. //
  403. // Figure out the default domain name once
  404. //
  405. _hr = GetDefaultDomainName();
  406. if ( FAILED( _hr ) )
  407. {
  408. return;
  409. }
  410. //
  411. // Figure out if we can use the IIS subauthenticator
  412. //
  413. _hr = GetSubAuthConfiguration();
  414. if( FAILED( _hr ) )
  415. {
  416. return;
  417. }
  418. //
  419. // Initialize all the authentication providers
  420. //
  421. ZeroMemory( _rgAuthProviders, sizeof( _rgAuthProviders ) );
  422. _hr = InitializeAuthenticationProviders();
  423. if ( FAILED( _hr ) )
  424. {
  425. return;
  426. }
  427. //
  428. // Initialize reverse DNS service
  429. //
  430. if (!InitRDns())
  431. {
  432. _hr = HRESULT_FROM_WIN32(GetLastError());
  433. DBGPRINTF(( DBG_CONTEXT,
  434. "Error initializing RDns service. hr = 0x%x\n",
  435. _hr ));
  436. TerminateAuthenticationProviders();
  437. return;
  438. }
  439. //
  440. // Initialize the W3_USER_CONTEXT reftrace log
  441. //
  442. #if DBG
  443. W3_USER_CONTEXT::sm_pTraceLog = CreateRefTraceLog( 2000, 0 );
  444. #else
  445. W3_USER_CONTEXT::sm_pTraceLog = NULL;
  446. #endif
  447. //
  448. // Store a pointer to the singleton (no C++ goo used in creating
  449. // this singleton)
  450. //
  451. if ( sm_pAuthState != NULL )
  452. {
  453. DBG_ASSERT( sm_pAuthState != NULL );
  454. _hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  455. }
  456. else
  457. {
  458. sm_pAuthState = this;
  459. }
  460. }
  461. W3_STATE_AUTHENTICATION::~W3_STATE_AUTHENTICATION()
  462. {
  463. if ( W3_USER_CONTEXT::sm_pTraceLog != NULL )
  464. {
  465. DestroyRefTraceLog( W3_USER_CONTEXT::sm_pTraceLog );
  466. W3_USER_CONTEXT::sm_pTraceLog = NULL;
  467. }
  468. TerminateRDns();
  469. TerminateAuthenticationProviders();
  470. sm_pAuthState = NULL;
  471. }
  472. HRESULT
  473. W3_STATE_AUTHENTICATION::InitializeAuthenticationProviders(
  474. VOID
  475. )
  476. /*++
  477. Routine Description:
  478. Initialize all authentication providers
  479. Arguments:
  480. None
  481. Return Value:
  482. HRESULT
  483. --*/
  484. {
  485. HRESULT hr = NO_ERROR;
  486. DWORD cProviderCount = 0;
  487. //
  488. // Initialize trace for connection contexts
  489. //
  490. hr = CONNECTION_AUTH_CONTEXT::Initialize();
  491. if ( FAILED( hr ) )
  492. {
  493. goto Failure;
  494. }
  495. //
  496. // Certificate map provider. This must be the first !!!!!!
  497. //
  498. DBG_ASSERT( cProviderCount < AUTH_PROVIDER_COUNT );
  499. _rgAuthProviders[ cProviderCount ] = new CERTMAP_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. DBG_ASSERT( cProviderCount < AUTH_PROVIDER_COUNT );
  514. _rgAuthProviders[ cProviderCount ] = new IISCERTMAP_AUTH_PROVIDER;
  515. if ( _rgAuthProviders[ cProviderCount ] == NULL )
  516. {
  517. hr = HRESULT_FROM_WIN32( GetLastError() );
  518. goto Failure;
  519. }
  520. hr = _rgAuthProviders[ cProviderCount ]->Initialize( cProviderCount );
  521. if ( FAILED( hr ) )
  522. {
  523. delete _rgAuthProviders[ cProviderCount ];
  524. _rgAuthProviders[ cProviderCount ] = NULL;
  525. goto Failure;
  526. }
  527. cProviderCount++;
  528. //
  529. // SSPI provider
  530. //
  531. DBG_ASSERT( cProviderCount < AUTH_PROVIDER_COUNT );
  532. _rgAuthProviders[ cProviderCount ] =
  533. new SSPI_AUTH_PROVIDER( MD_AUTH_NT );
  534. if ( _rgAuthProviders[ cProviderCount ] == NULL )
  535. {
  536. hr = HRESULT_FROM_WIN32( GetLastError() );
  537. goto Failure;
  538. }
  539. hr = _rgAuthProviders[ cProviderCount ]->Initialize( cProviderCount );
  540. if ( FAILED( hr ) )
  541. {
  542. delete _rgAuthProviders[ cProviderCount ];
  543. _rgAuthProviders[ cProviderCount ] = NULL;
  544. goto Failure;
  545. }
  546. cProviderCount++;
  547. //
  548. // Digest provider
  549. //
  550. DBG_ASSERT( cProviderCount < AUTH_PROVIDER_COUNT );
  551. _rgAuthProviders[ cProviderCount ] =
  552. new DIGEST_AUTH_PROVIDER( MD_AUTH_MD5 );
  553. if ( _rgAuthProviders[ cProviderCount ] == NULL )
  554. {
  555. hr = HRESULT_FROM_WIN32( GetLastError() );
  556. goto Failure;
  557. }
  558. hr = _rgAuthProviders[ cProviderCount ]->Initialize( cProviderCount );
  559. if ( FAILED( hr ) )
  560. {
  561. delete _rgAuthProviders[ cProviderCount ];
  562. _rgAuthProviders[ cProviderCount ] = NULL;
  563. goto Failure;
  564. }
  565. cProviderCount++;
  566. //
  567. // IIS Digest provider (for backward compatibility)
  568. //
  569. DBG_ASSERT( cProviderCount < AUTH_PROVIDER_COUNT );
  570. _rgAuthProviders[ cProviderCount ] =
  571. new IIS_DIGEST_AUTH_PROVIDER();
  572. if ( _rgAuthProviders[ cProviderCount ] == NULL )
  573. {
  574. hr = HRESULT_FROM_WIN32( GetLastError() );
  575. goto Failure;
  576. }
  577. hr = _rgAuthProviders[ cProviderCount ]->Initialize( cProviderCount );
  578. if ( FAILED( hr ) )
  579. {
  580. delete _rgAuthProviders[ cProviderCount ];
  581. _rgAuthProviders[ cProviderCount ] = NULL;
  582. goto Failure;
  583. }
  584. cProviderCount++;
  585. //
  586. // Basic provider
  587. //
  588. DBG_ASSERT( cProviderCount < AUTH_PROVIDER_COUNT );
  589. _rgAuthProviders[ cProviderCount ] = new BASIC_AUTH_PROVIDER;
  590. if ( _rgAuthProviders[ cProviderCount ] == NULL )
  591. {
  592. hr = HRESULT_FROM_WIN32( GetLastError() );
  593. goto Failure;
  594. }
  595. hr = _rgAuthProviders[ cProviderCount ]->Initialize( cProviderCount );
  596. if ( FAILED( hr ) )
  597. {
  598. delete _rgAuthProviders[ cProviderCount ];
  599. _rgAuthProviders[ cProviderCount ] = NULL;
  600. goto Failure;
  601. }
  602. cProviderCount++;
  603. //
  604. // Passport provider
  605. //
  606. DBG_ASSERT( cProviderCount < AUTH_PROVIDER_COUNT );
  607. _rgAuthProviders[ cProviderCount ] = new PASSPORT_AUTH_PROVIDER;
  608. if ( _rgAuthProviders[ cProviderCount ] == NULL )
  609. {
  610. hr = HRESULT_FROM_WIN32( GetLastError() );
  611. goto Failure;
  612. }
  613. hr = _rgAuthProviders[ cProviderCount ]->Initialize( cProviderCount );
  614. if ( FAILED( hr ) )
  615. {
  616. delete _rgAuthProviders[ cProviderCount ];
  617. _rgAuthProviders[ cProviderCount ] = NULL;
  618. goto Failure;
  619. }
  620. cProviderCount++;
  621. //
  622. // Anonymous provider.
  623. //
  624. // Note: This one should always be the last one
  625. //
  626. DBG_ASSERT( cProviderCount < AUTH_PROVIDER_COUNT );
  627. _rgAuthProviders[ cProviderCount ] = new ANONYMOUS_AUTH_PROVIDER;
  628. if ( _rgAuthProviders[ cProviderCount ] == NULL )
  629. {
  630. hr = HRESULT_FROM_WIN32( GetLastError() );
  631. goto Failure;
  632. }
  633. hr = _rgAuthProviders[ cProviderCount ]->Initialize( cProviderCount );
  634. if ( FAILED( hr ) )
  635. {
  636. delete _rgAuthProviders[ cProviderCount ];
  637. _rgAuthProviders[ cProviderCount ] = NULL;
  638. goto Failure;
  639. }
  640. _pAnonymousProvider = _rgAuthProviders[ cProviderCount ];
  641. cProviderCount++;
  642. //
  643. // Custom provider. Not really a provider in the sense that it does not
  644. // participate in authenticating a request. Instead, it is just used
  645. // as a stub provider for custom authentication done with
  646. // HSE_REQ_EXEC_URL
  647. //
  648. _pCustomProvider = new CUSTOM_AUTH_PROVIDER;
  649. if ( _pCustomProvider == NULL )
  650. {
  651. hr = HRESULT_FROM_WIN32( GetLastError() );
  652. goto Failure;
  653. }
  654. return NO_ERROR;
  655. Failure:
  656. for ( DWORD i = 0; i < AUTH_PROVIDER_COUNT; i++ )
  657. {
  658. if ( _rgAuthProviders[ i ] != NULL )
  659. {
  660. _rgAuthProviders[ i ]->Terminate();
  661. delete _rgAuthProviders[ i ];
  662. _rgAuthProviders[ i ] = NULL;
  663. }
  664. }
  665. CONNECTION_AUTH_CONTEXT::Terminate();
  666. return hr;
  667. }
  668. VOID
  669. W3_STATE_AUTHENTICATION::TerminateAuthenticationProviders(
  670. VOID
  671. )
  672. /*++
  673. Routine Description:
  674. Terminate all authentication providers
  675. Arguments:
  676. None
  677. Return Value:
  678. None
  679. --*/
  680. {
  681. for ( DWORD i = 0; i < AUTH_PROVIDER_COUNT; i++ )
  682. {
  683. if ( _rgAuthProviders[ i ] != NULL )
  684. {
  685. _rgAuthProviders[ i ]->Terminate();
  686. delete _rgAuthProviders[ i ];
  687. _rgAuthProviders[ i ] = NULL;
  688. }
  689. }
  690. if ( _pCustomProvider != NULL )
  691. {
  692. delete _pCustomProvider;
  693. _pCustomProvider = NULL;
  694. }
  695. CONNECTION_AUTH_CONTEXT::Terminate();
  696. }
  697. CONTEXT_STATUS
  698. W3_STATE_AUTHENTICATION::DoWork(
  699. W3_MAIN_CONTEXT * pMainContext,
  700. DWORD cbCompletion,
  701. DWORD dwCompletionStatus
  702. )
  703. /*++
  704. Routine Description:
  705. Handle authentication for this request
  706. Arguments:
  707. pMainContext - W3_MAIN_CONTEXT representing execution of state
  708. machine
  709. cbCompletion - Number of bytes in an async completion
  710. dwCompletionStatus - Error status of a completion
  711. Return Value:
  712. CONTEXT_STATUS_CONTINUE - if we should continue in state machine
  713. else stop executing the machine and free up the current thread
  714. --*/
  715. {
  716. DWORD cProviderCount = 0;
  717. AUTH_PROVIDER * pProvider = NULL;
  718. W3_METADATA * pMetaData = NULL;
  719. W3_USER_CONTEXT * pUserContext = NULL;
  720. BOOL fSupported = FALSE;
  721. HRESULT hr = NO_ERROR;
  722. BOOL fApplies = FALSE;
  723. BOOL fFilterFinished = FALSE;
  724. W3_MAIN_CONTEXT_STATE * pContextState = NULL;
  725. UNREFERENCED_PARAMETER( cbCompletion );
  726. UNREFERENCED_PARAMETER( dwCompletionStatus );
  727. DBG_ASSERT( pMainContext != NULL );
  728. //
  729. // If we already have a user context, then we must have had an
  730. // AUTH_COMPLETE notification which caused the state machine to back up
  731. // and resume from URLINFO state. In that case, just bail
  732. //
  733. if ( pMainContext->QueryUserContext() != NULL )
  734. {
  735. DBG_ASSERT( pMainContext->IsNotificationNeeded( SF_NOTIFY_AUTH_COMPLETE ) );
  736. return CONTEXT_STATUS_CONTINUE;
  737. }
  738. //
  739. // First, find the authentication provider which applies. We
  740. // should always find a matching provider (since anonymous
  741. // provider) should always match!
  742. //
  743. pMetaData = pMainContext->QueryUrlContext()->QueryMetaData();
  744. DBG_ASSERT( pMetaData != NULL );
  745. //
  746. // Optimization for path when only anonymous authentication is enabled
  747. // (certmapping is checked as well)
  748. // Issue jaroslad 01/08/23. This may conflict in the future with
  749. // DoesApply of new providers.
  750. //
  751. if ( pMetaData->IsOnlyAnonymousAuthSupported() &&
  752. pMainContext->QueryRequest()->GetHeader( HttpHeaderAuthorization ) == NULL )
  753. {
  754. //
  755. // no authorization header and only anonymous enabled
  756. //
  757. pProvider = QueryAnonymousProvider();
  758. DBG_ASSERT( pProvider != NULL );
  759. }
  760. else
  761. {
  762. for ( ; ; )
  763. {
  764. pProvider = _rgAuthProviders[ cProviderCount ];
  765. if ( pProvider == NULL )
  766. {
  767. break;
  768. }
  769. DBG_ASSERT( pProvider != NULL );
  770. hr = pProvider->DoesApply( pMainContext,
  771. &fApplies );
  772. if ( FAILED( hr ) )
  773. {
  774. goto Finished;
  775. }
  776. if ( fApplies )
  777. {
  778. //
  779. // Cool. We have a match!
  780. //
  781. break;
  782. }
  783. cProviderCount++;
  784. }
  785. }
  786. //
  787. // If only the anonymous provider matched, then check whether we
  788. // have credentials associated with the connection (since IE won't
  789. // send Authorization: header for subsequent SSPI authenticated
  790. // requests on a connection)
  791. //
  792. if ( pProvider->QueryAuthType() == MD_AUTH_ANONYMOUS )
  793. {
  794. //
  795. // Another slimy optimization. If we haven't associated a user
  796. // with the connection, then we don't have to bother looking up
  797. // connection
  798. //
  799. if ( _fHasAssociatedUserBefore )
  800. {
  801. pUserContext = pMainContext->QueryConnectionUserContext();
  802. if ( pUserContext != NULL )
  803. {
  804. pProvider = pUserContext->QueryProvider();
  805. DBG_ASSERT( pProvider != NULL );
  806. }
  807. //
  808. // Clean up the security context if there is one
  809. //
  810. pProvider->SetConnectionAuthContext( pMainContext, NULL );
  811. }
  812. }
  813. else
  814. {
  815. //
  816. // If a provider applies, then ignore/remove any
  817. // cached user associated with the request
  818. //
  819. pUserContext = pMainContext->QueryConnectionUserContext();
  820. if ( pUserContext != NULL )
  821. {
  822. pMainContext->SetConnectionUserContext( NULL );
  823. pUserContext->DereferenceUserContext();
  824. pUserContext = NULL;
  825. }
  826. }
  827. //
  828. // Is the given provider supported (by metadata)
  829. //
  830. if ( pMetaData->QueryAuthTypeSupported( pProvider->QueryAuthType() ) )
  831. {
  832. fSupported = TRUE;
  833. }
  834. else if( pProvider->QueryAuthType() == MD_AUTH_ANONYMOUS )
  835. {
  836. //
  837. // Give the anonymous provider a shot at this request.
  838. //
  839. // We need to do this even if MD_AUTH_ANONYMOUS is not
  840. // supported, so that authentication filters get a
  841. // crack at it. It's up to the anonymous provider to
  842. // fail if it's not supported, and no filter sets
  843. // credentials.
  844. //
  845. pMainContext->SetCheckAnonAuthTypeSupported( TRUE );
  846. fSupported = TRUE;
  847. }
  848. else
  849. {
  850. //
  851. // If anonymous authentication is supported, then we can
  852. // still let it thru
  853. //
  854. if ( pMetaData->QueryAuthTypeSupported( MD_AUTH_ANONYMOUS ) )
  855. {
  856. pProvider = QueryAnonymousProvider();
  857. DBG_ASSERT( pProvider != NULL );
  858. //
  859. // Anonymous provider applies, remove the previous cached
  860. // user associated with the request
  861. //
  862. if ( pUserContext != NULL )
  863. {
  864. pMainContext->SetConnectionUserContext( NULL );
  865. pUserContext->DereferenceUserContext();
  866. pUserContext = NULL;
  867. }
  868. fSupported = TRUE;
  869. }
  870. }
  871. //
  872. // Not supported, you're outta here!
  873. //
  874. if ( !fSupported )
  875. {
  876. //
  877. // Clear any context state which was set
  878. //
  879. pContextState = pMainContext->QueryContextState();
  880. if ( pContextState != NULL )
  881. {
  882. pContextState->Cleanup( pMainContext );
  883. pMainContext->SetContextState( NULL );
  884. }
  885. pMainContext->QueryResponse()->SetStatus( HttpStatusUnauthorized,
  886. Http401Config );
  887. pMainContext->SetErrorStatus( HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) );
  888. pMainContext->SetFinishedResponse();
  889. return CONTEXT_STATUS_CONTINUE;
  890. }
  891. //
  892. // Now we can authenticate
  893. //
  894. if ( pUserContext != NULL )
  895. {
  896. //
  897. // We already have a context associated with connection. Use it!
  898. //
  899. pUserContext->ReferenceUserContext();
  900. pMainContext->SetUserContext( pUserContext );
  901. }
  902. else
  903. {
  904. DBG_ASSERT( pProvider != NULL );
  905. // perf ctr
  906. pMainContext->QuerySite()->IncLogonAttempts();
  907. fFilterFinished = FALSE;
  908. hr = pProvider->DoAuthenticate( pMainContext, &fFilterFinished );
  909. if ( FAILED( hr ) )
  910. {
  911. DWORD dwError = WIN32_FROM_HRESULT( hr );
  912. if( dwError == ERROR_PASSWORD_MUST_CHANGE ||
  913. dwError == ERROR_PASSWORD_EXPIRED )
  914. {
  915. hr = pMainContext->PasswdChangeExecute();
  916. if( S_OK == hr )
  917. {
  918. return CONTEXT_STATUS_PENDING;
  919. }
  920. else if( S_FALSE == hr )
  921. {
  922. //
  923. // S_FALSE means password change disabled
  924. //
  925. pMainContext->QueryResponse()->SetStatus(
  926. HttpStatusUnauthorized,
  927. Http401BadLogon );
  928. pMainContext->SetErrorStatus( hr );
  929. pMainContext->SetFinishedResponse();
  930. return CONTEXT_STATUS_CONTINUE;
  931. }
  932. }
  933. else if( SEC_E_NO_CREDENTIALS == hr )
  934. {
  935. pMainContext->QueryResponse()->SetStatus( HttpStatusUnauthorized,
  936. Http401Config );
  937. pMainContext->SetErrorStatus( hr );
  938. pMainContext->SetFinishedResponse();
  939. return CONTEXT_STATUS_CONTINUE;
  940. }
  941. else
  942. {
  943. pMainContext->SetErrorStatus( hr );
  944. if ( dwError == ERROR_ACCESS_DENIED )
  945. {
  946. pMainContext->QueryResponse()->SetStatus( HttpStatusUnauthorized,
  947. Http401Filter );
  948. }
  949. else if ( dwError == ERROR_FILE_NOT_FOUND ||
  950. dwError == ERROR_PATH_NOT_FOUND )
  951. {
  952. pMainContext->QueryResponse()->SetStatus( HttpStatusNotFound );
  953. }
  954. else
  955. {
  956. pMainContext->QueryResponse()->SetStatus( HttpStatusServerError );
  957. }
  958. pMainContext->SetFinishedResponse();
  959. pMainContext->SetDisconnect( TRUE );
  960. return CONTEXT_STATUS_CONTINUE;
  961. }
  962. goto Finished;
  963. }
  964. if ( fFilterFinished )
  965. {
  966. pMainContext->SetDone();
  967. goto Finished;
  968. }
  969. }
  970. //
  971. // Do we have a valid user now
  972. //
  973. pUserContext = pMainContext->QueryUserContext();
  974. if ( pUserContext != NULL )
  975. {
  976. if ( pUserContext->QueryAuthType() != MD_AUTH_ANONYMOUS )
  977. {
  978. hr = pMainContext->PasswdExpireNotify();
  979. if( FAILED( hr ) )
  980. {
  981. //
  982. // Internal error
  983. //
  984. goto Finished;
  985. }
  986. else if( hr == S_OK )
  987. {
  988. //
  989. // We've successfully handled password expire
  990. // notification
  991. //
  992. return CONTEXT_STATUS_PENDING;
  993. }
  994. //
  995. // Advanced password expire notification is disabled,
  996. // we should allow the user to get access, fall through
  997. //
  998. }
  999. //
  1000. // Should we cache the user on the connection? Do so, only if
  1001. //
  1002. DBG_ASSERT( pMetaData != NULL );
  1003. if ( pMetaData->QueryAuthPersistence() != MD_AUTH_SINGLEREQUEST
  1004. && pUserContext->QueryIsAuthNTLM()
  1005. && !pMainContext->QueryRequest()->IsProxyRequest()
  1006. && pUserContext != pMainContext->QueryConnectionUserContext() )
  1007. {
  1008. pUserContext->ReferenceUserContext();
  1009. pMainContext->SetConnectionUserContext( pUserContext );
  1010. _fHasAssociatedUserBefore = TRUE;
  1011. }
  1012. }
  1013. else
  1014. {
  1015. //
  1016. // If we don't have a user, then we must not allow handle request
  1017. // state to happen!
  1018. //
  1019. pMainContext->SetFinishedResponse();
  1020. }
  1021. //
  1022. // OK. If we got to here and we have a user context, then authentication
  1023. // is complete! So lets notify AUTH_COMPLETE filters
  1024. //
  1025. if ( pUserContext != NULL )
  1026. {
  1027. if ( pMainContext->IsNotificationNeeded( SF_NOTIFY_AUTH_COMPLETE ) )
  1028. {
  1029. HTTP_FILTER_AUTH_COMPLETE_INFO AuthInfo;
  1030. STACK_STRU( strOriginal, MAX_PATH );
  1031. STACK_STRU( strNewUrl, MAX_PATH );
  1032. BOOL fFinished = FALSE;
  1033. //
  1034. // Store away the original URL
  1035. //
  1036. hr = pMainContext->QueryRequest()->GetUrl( &strOriginal );
  1037. if ( FAILED( hr ) )
  1038. {
  1039. goto Finished;
  1040. }
  1041. //
  1042. // Call the filter
  1043. //
  1044. if ( !pMainContext->NotifyFilters( SF_NOTIFY_AUTH_COMPLETE,
  1045. &AuthInfo,
  1046. &fFinished ) )
  1047. {
  1048. DWORD dwError = GetLastError();
  1049. pMainContext->SetErrorStatus( HRESULT_FROM_WIN32( dwError ) );
  1050. if ( dwError == ERROR_ACCESS_DENIED )
  1051. {
  1052. pMainContext->QueryResponse()->SetStatus( HttpStatusUnauthorized,
  1053. Http401Filter );
  1054. }
  1055. else if ( dwError == ERROR_FILE_NOT_FOUND ||
  1056. dwError == ERROR_PATH_NOT_FOUND )
  1057. {
  1058. pMainContext->QueryResponse()->SetStatus( HttpStatusNotFound );
  1059. }
  1060. else
  1061. {
  1062. pMainContext->QueryResponse()->SetStatus( HttpStatusServerError );
  1063. }
  1064. pMainContext->SetFinishedResponse();
  1065. pMainContext->SetDisconnect( TRUE );
  1066. return CONTEXT_STATUS_CONTINUE;
  1067. }
  1068. if ( fFinished )
  1069. {
  1070. pMainContext->SetDone();
  1071. return CONTEXT_STATUS_CONTINUE;
  1072. }
  1073. //
  1074. // If the URL has changed, we'll need to backup the state machine
  1075. //
  1076. hr = pMainContext->QueryRequest()->GetUrl( &strNewUrl );
  1077. if ( FAILED( hr ) )
  1078. {
  1079. goto Finished;
  1080. }
  1081. if ( wcscmp( strNewUrl.QueryStr(),
  1082. strOriginal.QueryStr() ) != 0 )
  1083. {
  1084. //
  1085. // URL is different!
  1086. //
  1087. pMainContext->BackupStateMachine();
  1088. }
  1089. else
  1090. {
  1091. //
  1092. // URL is the same. Do nothing and continue
  1093. //
  1094. }
  1095. }
  1096. }
  1097. Finished:
  1098. if ( FAILED( hr ) )
  1099. {
  1100. pMainContext->QueryResponse()->
  1101. SetStatus( HttpStatusServerError );
  1102. pMainContext->SetFinishedResponse();
  1103. pMainContext->SetErrorStatus( hr );
  1104. }
  1105. return CONTEXT_STATUS_CONTINUE;
  1106. }
  1107. CONTEXT_STATUS
  1108. W3_STATE_AUTHENTICATION::OnCompletion(
  1109. W3_MAIN_CONTEXT * pMainContext,
  1110. DWORD cbCompletion,
  1111. DWORD dwCompletionStatus
  1112. )
  1113. /*++
  1114. Routine Description:
  1115. Complete the done state
  1116. Arguments:
  1117. pMainContext - W3_MAIN_CONTEXT representing an execution of the state machine
  1118. cbCompletion - Number of bytes on completion
  1119. dwCompletionStatus - Win32 Error on completion (if any)
  1120. Return Value:
  1121. CONTEXT_STATUS_CONTINUE - if we should continue in state machine
  1122. else stop executing the machine and free up the current thread
  1123. --*/
  1124. {
  1125. UNREFERENCED_PARAMETER( cbCompletion );
  1126. UNREFERENCED_PARAMETER( dwCompletionStatus );
  1127. DBG_ASSERT( pMainContext != NULL );
  1128. //
  1129. // During authentication state, only the routines for password notification
  1130. // could post asynchonous completion while they are doing child execution.
  1131. // The following assert is to make sure that the completion is posted by
  1132. // ExecuteExpiredURL routine.
  1133. //
  1134. DBG_ASSERT( pMainContext->QueryRequest()->GetHeader( "CFG-ENC-CAPS" )
  1135. != NULL );
  1136. //
  1137. // Since the response has already been send asynchronously, we advance the
  1138. // state machine to CONTEXT_STATE_RESPONSE here.
  1139. //
  1140. pMainContext->SetFinishedResponse();
  1141. return CONTEXT_STATUS_CONTINUE;
  1142. }