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.

900 lines
24 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. urlauth.cxx
  5. Abstract:
  6. Implements an ISAPI * scriptmap which handles authorization by calling
  7. into the NT AuthZ framework.
  8. Author:
  9. Bilal Alam (balam) Nov 26, 2001
  10. --*/
  11. #include "precomp.hxx"
  12. DECLARE_DEBUG_PRINTS_OBJECT();
  13. DECLARE_DEBUG_VARIABLE();
  14. // local function declarations
  15. HRESULT
  16. GetTokenForExecution(
  17. EXTENSION_CONTROL_BLOCK *pecb,
  18. HANDLE * phToken
  19. );
  20. // global data
  21. ADMIN_MANAGER_CACHE * g_pAdminManagerCache;
  22. VOID
  23. WINAPI
  24. UrlAuthCompletion(
  25. EXTENSION_CONTROL_BLOCK * pecb,
  26. PVOID pvContext,
  27. DWORD,
  28. DWORD
  29. )
  30. /*++
  31. Routine Description:
  32. Routine to be called whenever ISAPI async stuff completes
  33. Arguments:
  34. pecb - EXTENSION_CONTROL_BLOCK *
  35. pContext - Unused
  36. cbIo - Unused
  37. dwError - Unused
  38. Return Value:
  39. None
  40. --*/
  41. {
  42. if ( pvContext )
  43. {
  44. DBG_REQUIRE( CloseHandle( pvContext ) );
  45. pvContext = NULL;
  46. }
  47. pecb->ServerSupportFunction( pecb->ConnID,
  48. HSE_REQ_DONE_WITH_SESSION,
  49. NULL,
  50. NULL,
  51. NULL );
  52. }
  53. DWORD
  54. WINAPI
  55. HttpExtensionProc(
  56. EXTENSION_CONTROL_BLOCK * pecb
  57. )
  58. /*++
  59. Routine Description:
  60. Main entry point for ISAPI
  61. Arguments:
  62. pecb - EXTENSION_CONTROL_BLOCK *
  63. Return Value:
  64. HSE_STATUS_*
  65. --*/
  66. {
  67. BOOL fRet;
  68. STACK_BUFFER( buff, 512 );
  69. DWORD cbBuffer;
  70. BOOL fAccessGranted = FALSE;
  71. BOOL fFatalError = FALSE;
  72. WCHAR * pszAdminStore;
  73. ADMIN_MANAGER * pAdminManager = NULL;
  74. AZ_APPLICATION * pApplication = NULL;
  75. WCHAR * pszScopeName;
  76. HRESULT hr = NO_ERROR;
  77. METADATA_RECORD * pRecord;
  78. HANDLE hImpersonationToken = NULL;
  79. HSE_CUSTOM_ERROR_INFO CustomErrorInfo = { "500 Server Error", 0, TRUE };
  80. //
  81. // First determine whether URL authorization is even enabled for this
  82. // URL
  83. //
  84. cbBuffer = buff.QuerySize();
  85. fRet = pecb->ServerSupportFunction( pecb,
  86. HSE_REQ_GET_METADATA_PROPERTY,
  87. buff.QueryPtr(),
  88. &cbBuffer,
  89. (LPDWORD) MD_ENABLE_URL_AUTHORIZATION );
  90. if ( !fRet )
  91. {
  92. if ( GetLastError() == ERROR_INVALID_INDEX )
  93. {
  94. // the common case is to fail with ERROR_INVALID_INDEX == access granted by no present metadata
  95. // if the above call failed with someting like OUTOFMEMORY or INVALIDPARAMETER do not allow access.
  96. fAccessGranted = TRUE;
  97. }
  98. else
  99. {
  100. fFatalError = TRUE;
  101. hr = HRESULT_FROM_WIN32( GetLastError() );
  102. }
  103. goto AccessCheckComplete;
  104. }
  105. //
  106. // Check the property now. If invalid type or if 0, then we're done
  107. //
  108. pRecord = (METADATA_RECORD*) buff.QueryPtr();
  109. if ( pRecord->dwMDDataType != DWORD_METADATA ||
  110. *((DWORD*)pRecord->pbMDData) == 0 )
  111. {
  112. fAccessGranted = TRUE;
  113. goto AccessCheckComplete;
  114. }
  115. //
  116. // If we're still a go, then retrieve the store name from the metabase.
  117. // This is our key into the AdminManager cache we maintain
  118. //
  119. cbBuffer = buff.QuerySize();
  120. fRet = pecb->ServerSupportFunction( pecb,
  121. HSE_REQ_GET_METADATA_PROPERTY,
  122. buff.QueryPtr(),
  123. &cbBuffer,
  124. (LPDWORD) MD_URL_AUTHORIZATION_STORE_NAME );
  125. if ( !fRet )
  126. {
  127. //
  128. // The only acceptable error is insufficient buffer. Otherwise, we
  129. // don't have a store name and we're sunk
  130. //
  131. if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER )
  132. {
  133. CustomErrorInfo.pszStatus = "500 Server Error";
  134. CustomErrorInfo.uHttpSubError = 17;
  135. CustomErrorInfo.fAsync = TRUE;
  136. goto AccessCheckComplete;
  137. }
  138. DBG_ASSERT( cbBuffer > buff.QuerySize() );
  139. if ( !buff.Resize( cbBuffer ) )
  140. {
  141. fFatalError = TRUE;
  142. hr = HRESULT_FROM_WIN32( GetLastError() );
  143. goto AccessCheckComplete;
  144. }
  145. cbBuffer = buff.QuerySize();
  146. fRet = pecb->ServerSupportFunction( pecb,
  147. HSE_REQ_GET_METADATA_PROPERTY,
  148. buff.QueryPtr(),
  149. &cbBuffer,
  150. (LPDWORD) MD_URL_AUTHORIZATION_STORE_NAME );
  151. if ( !fRet )
  152. {
  153. DBG_ASSERT( GetLastError() != ERROR_INSUFFICIENT_BUFFER );
  154. fFatalError = TRUE;
  155. hr = HRESULT_FROM_WIN32( GetLastError() );
  156. goto AccessCheckComplete;
  157. }
  158. }
  159. //
  160. // Store name better be a string
  161. //
  162. pRecord = (METADATA_RECORD*) buff.QueryPtr();
  163. if ( pRecord->dwMDDataType != STRING_METADATA )
  164. {
  165. fFatalError = TRUE;
  166. hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
  167. goto AccessCheckComplete;
  168. }
  169. //
  170. // We should have an AdminManager store name now. Get an ADMIN_MANAGER
  171. // from the cache (cache will create it if not already in cache)
  172. //
  173. pszAdminStore = (WCHAR*) pRecord->pbMDData;
  174. DBG_ASSERT( g_pAdminManagerCache != NULL );
  175. hr = g_pAdminManagerCache->GetAdminManager( pszAdminStore,
  176. &pAdminManager );
  177. if ( FAILED( hr ) )
  178. {
  179. //
  180. // That sucks. We couldn't find an admin manager
  181. //
  182. CustomErrorInfo.pszStatus = "500 Server Error";
  183. CustomErrorInfo.uHttpSubError = 18;
  184. CustomErrorInfo.fAsync = TRUE;
  185. goto AccessCheckComplete;
  186. }
  187. DBG_ASSERT( pAdminManager != NULL );
  188. //
  189. // Get the application from the AdminManager. That should be trivial
  190. // since we always have the same application name.
  191. //
  192. hr = pAdminManager->GetApplication( &pApplication );
  193. if ( FAILED( hr ) )
  194. {
  195. fFatalError = TRUE;
  196. goto AccessCheckComplete;
  197. }
  198. DBG_ASSERT( pApplication != NULL );
  199. //
  200. // Get the scope name for this request
  201. //
  202. cbBuffer = buff.QuerySize();
  203. fRet = pecb->ServerSupportFunction( pecb,
  204. HSE_REQ_GET_METADATA_PROPERTY,
  205. buff.QueryPtr(),
  206. &cbBuffer,
  207. (LPDWORD) MD_URL_AUTHORIZATION_SCOPE_NAME );
  208. if ( !fRet )
  209. {
  210. //
  211. // It is acceptable to have no scope name. Then we use the NULL scope
  212. //
  213. if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER )
  214. {
  215. DBG_ASSERT( cbBuffer > buff.QuerySize() );
  216. if ( !buff.Resize( cbBuffer ) )
  217. {
  218. fFatalError = TRUE;
  219. hr = HRESULT_FROM_WIN32( GetLastError() );
  220. goto AccessCheckComplete;
  221. }
  222. cbBuffer = buff.QuerySize();
  223. fRet = pecb->ServerSupportFunction( pecb,
  224. HSE_REQ_GET_METADATA_PROPERTY,
  225. buff.QueryPtr(),
  226. &cbBuffer,
  227. (LPDWORD) MD_URL_AUTHORIZATION_SCOPE_NAME );
  228. if ( !fRet )
  229. {
  230. DBG_ASSERT( GetLastError() != ERROR_INSUFFICIENT_BUFFER );
  231. fFatalError = TRUE;
  232. hr = HRESULT_FROM_WIN32( GetLastError() );
  233. goto AccessCheckComplete;
  234. }
  235. }
  236. }
  237. if ( fRet )
  238. {
  239. pRecord = (METADATA_RECORD*) buff.QueryPtr();
  240. if ( pRecord->dwMDDataType != STRING_METADATA )
  241. {
  242. fFatalError = TRUE;
  243. hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
  244. goto AccessCheckComplete;
  245. }
  246. //
  247. // We have a scope name. It better be a string
  248. //
  249. pszScopeName = (WCHAR*) pRecord->pbMDData;
  250. }
  251. else
  252. {
  253. pszScopeName = NULL;
  254. }
  255. //
  256. // Do the access check
  257. //
  258. hr = pApplication->DoAccessCheck( pecb,
  259. pszScopeName,
  260. &fAccessGranted );
  261. if ( FAILED( hr ) )
  262. {
  263. fFatalError = TRUE;
  264. goto AccessCheckComplete;
  265. }
  266. //
  267. // Determine what impersonation token should be used for execution of real URL
  268. //
  269. if ( fAccessGranted )
  270. {
  271. hr = GetTokenForExecution( pecb, &hImpersonationToken );
  272. if ( FAILED ( hr ) )
  273. {
  274. DBG_ASSERT( !hImpersonationToken );
  275. fAccessGranted = FALSE;
  276. fFatalError = TRUE;
  277. goto AccessCheckComplete;
  278. }
  279. }
  280. else
  281. {
  282. //
  283. // Didn't have access. Thats a 401.7
  284. //
  285. CustomErrorInfo.pszStatus = "401 Unauthorized";
  286. CustomErrorInfo.uHttpSubError = 7;
  287. CustomErrorInfo.fAsync = TRUE;
  288. }
  289. AccessCheckComplete:
  290. // not OK to have both access granted and a fatal error.
  291. DBG_ASSERT ( !( fAccessGranted && fFatalError ) );
  292. //
  293. // Do some cleanup
  294. //
  295. if ( pAdminManager != NULL )
  296. {
  297. pAdminManager->DereferenceCacheEntry();
  298. pAdminManager = NULL;
  299. }
  300. //
  301. // Time to do something (TM).
  302. //
  303. if ( fAccessGranted )
  304. {
  305. HSE_EXEC_UNICODE_URL_INFO ExecUrlInfo;
  306. HSE_EXEC_UNICODE_URL_USER_INFO ExecUrlUserInfo;
  307. //
  308. // Everything is ok. Just execute the original URL
  309. //
  310. fRet = pecb->ServerSupportFunction( pecb->ConnID,
  311. HSE_REQ_IO_COMPLETION,
  312. UrlAuthCompletion,
  313. NULL,
  314. (LPDWORD) hImpersonationToken );
  315. if ( !fRet )
  316. {
  317. DBG_ASSERT( FALSE );
  318. if ( hImpersonationToken )
  319. {
  320. DBG_REQUIRE( CloseHandle( hImpersonationToken ) );
  321. hImpersonationToken = NULL;
  322. }
  323. return HSE_STATUS_ERROR;
  324. }
  325. ZeroMemory( &ExecUrlInfo, sizeof( ExecUrlInfo ) );
  326. ExecUrlInfo.dwExecUrlFlags = HSE_EXEC_URL_IGNORE_CURRENT_INTERCEPTOR;
  327. if ( hImpersonationToken )
  328. {
  329. ExecUrlInfo.pUserInfo = &ExecUrlUserInfo;
  330. ZeroMemory( &ExecUrlUserInfo, sizeof( ExecUrlUserInfo ) );
  331. cbBuffer = buff.QuerySize();
  332. fRet = pecb->GetServerVariable( pecb->ConnID,
  333. "UNICODE_REMOTE_USER",
  334. buff.QueryPtr(),
  335. &cbBuffer );
  336. if ( !fRet )
  337. {
  338. if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER )
  339. {
  340. if ( hImpersonationToken )
  341. {
  342. DBG_REQUIRE( CloseHandle( hImpersonationToken ) );
  343. hImpersonationToken = NULL;
  344. }
  345. return HSE_STATUS_ERROR;
  346. }
  347. DBG_ASSERT( cbBuffer > buff.QuerySize() );
  348. fRet = buff.Resize( cbBuffer );
  349. if ( !fRet )
  350. {
  351. if ( hImpersonationToken )
  352. {
  353. DBG_REQUIRE( CloseHandle( hImpersonationToken ) );
  354. hImpersonationToken = NULL;
  355. }
  356. return HSE_STATUS_ERROR;
  357. }
  358. cbBuffer = buff.QuerySize();
  359. fRet = pecb->GetServerVariable( pecb->ConnID,
  360. "UNICODE_REMOTE_USER",
  361. buff.QueryPtr(),
  362. &cbBuffer );
  363. if ( !fRet )
  364. {
  365. if ( hImpersonationToken )
  366. {
  367. DBG_REQUIRE( CloseHandle( hImpersonationToken ) );
  368. hImpersonationToken = NULL;
  369. }
  370. return HSE_STATUS_ERROR;
  371. }
  372. }
  373. ExecUrlUserInfo.pszCustomUserName = (WCHAR*) buff.QueryPtr();
  374. ExecUrlUserInfo.pszCustomAuthType = "URLAUTH";
  375. ExecUrlUserInfo.hImpersonationToken = hImpersonationToken;
  376. }
  377. fRet = pecb->ServerSupportFunction( pecb->ConnID,
  378. HSE_REQ_EXEC_UNICODE_URL,
  379. &ExecUrlInfo,
  380. NULL,
  381. NULL );
  382. if ( !fRet && hImpersonationToken )
  383. {
  384. DBG_REQUIRE( CloseHandle( hImpersonationToken ) );
  385. }
  386. hImpersonationToken = NULL;
  387. return fRet ? HSE_STATUS_PENDING : HSE_STATUS_ERROR;
  388. }
  389. else if ( !fFatalError )
  390. {
  391. //
  392. // This just means access wasn't granted. Send back an error
  393. //
  394. fRet = pecb->ServerSupportFunction( pecb->ConnID,
  395. HSE_REQ_IO_COMPLETION,
  396. UrlAuthCompletion,
  397. NULL,
  398. NULL );
  399. if ( !fRet )
  400. {
  401. DBG_ASSERT( FALSE );
  402. return HSE_STATUS_ERROR;
  403. }
  404. fRet = pecb->ServerSupportFunction( pecb->ConnID,
  405. HSE_REQ_SEND_CUSTOM_ERROR,
  406. &CustomErrorInfo,
  407. NULL,
  408. NULL );
  409. if ( !fRet )
  410. {
  411. pecb->ServerSupportFunction( pecb->ConnID,
  412. HSE_REQ_SEND_RESPONSE_HEADER,
  413. "500 Server Error",
  414. NULL,
  415. NULL );
  416. return HSE_STATUS_ERROR;
  417. }
  418. else
  419. {
  420. return HSE_STATUS_PENDING;
  421. }
  422. }
  423. else
  424. {
  425. //
  426. // Fatal error. Just set the last error and bail.
  427. //
  428. SetLastError( WIN32_FROM_HRESULT( hr ) );
  429. return HSE_STATUS_ERROR;
  430. }
  431. }
  432. BOOL
  433. WINAPI
  434. GetExtensionVersion(
  435. HSE_VERSION_INFO * pver
  436. )
  437. /*++
  438. Routine Description:
  439. Initialization routine for ISAPI
  440. Arguments:
  441. pver - Version information
  442. Return Value:
  443. TRUE if successful, else FALSE
  444. --*/
  445. {
  446. HRESULT hr;
  447. //
  448. // Do ISAPI interface init crap
  449. //
  450. pver->dwExtensionVersion = MAKELONG( 0, 1 );
  451. strcpy( pver->lpszExtensionDesc,
  452. "URL Authorization ISAPI" );
  453. //
  454. // Create an admin manager cache
  455. //
  456. g_pAdminManagerCache = new ADMIN_MANAGER_CACHE;
  457. if ( g_pAdminManagerCache == NULL )
  458. {
  459. return FALSE;
  460. }
  461. //
  462. // Initialize ADMIN_MANAGER globals
  463. //
  464. hr = ADMIN_MANAGER::Initialize();
  465. if ( FAILED( hr ) )
  466. {
  467. delete g_pAdminManagerCache;
  468. g_pAdminManagerCache = NULL;
  469. return FALSE;
  470. }
  471. //
  472. // Initialize AZ_APPLICATION globals
  473. //
  474. hr = AZ_APPLICATION::Initialize();
  475. if ( FAILED( hr ) )
  476. {
  477. ADMIN_MANAGER::Terminate();
  478. delete g_pAdminManagerCache;
  479. g_pAdminManagerCache = NULL;
  480. return FALSE;
  481. }
  482. return TRUE;
  483. }
  484. BOOL
  485. WINAPI
  486. TerminateExtension(
  487. DWORD
  488. )
  489. /*++
  490. Routine Description:
  491. Cleanup ISAPI extension
  492. Arguments:
  493. None
  494. Return Value:
  495. TRUE if successful, else FALSE
  496. --*/
  497. {
  498. AZ_APPLICATION::Terminate();
  499. ADMIN_MANAGER::Terminate();
  500. delete g_pAdminManagerCache;
  501. g_pAdminManagerCache = NULL;
  502. return TRUE;
  503. }
  504. BOOL
  505. WINAPI
  506. DllMain(
  507. HINSTANCE hDll,
  508. DWORD dwReason,
  509. LPVOID
  510. )
  511. /*++
  512. Routine Description:
  513. DLL Entry Routine
  514. Arguments:
  515. Return Value:
  516. TRUE if successful, else FALSE
  517. --*/
  518. {
  519. switch ( dwReason )
  520. {
  521. case DLL_PROCESS_ATTACH:
  522. CREATE_DEBUG_PRINT_OBJECT( "urlauth" );
  523. DisableThreadLibraryCalls( hDll );
  524. break;
  525. case DLL_PROCESS_DETACH:
  526. DELETE_DEBUG_PRINT_OBJECT();
  527. break;
  528. default:
  529. break;
  530. }
  531. return TRUE;
  532. }
  533. HRESULT
  534. GetTokenForExecution(
  535. EXTENSION_CONTROL_BLOCK *pecb,
  536. HANDLE * phToken
  537. )
  538. /*++
  539. Routine Description:
  540. From metadata, determine the impersonation token to return
  541. Arguments:
  542. pecb - current ecb for request
  543. phToken - where to store the token on success
  544. Return Value:
  545. HRESULT
  546. --*/
  547. {
  548. HRESULT hr = S_OK;
  549. BOOL fRet = FALSE;
  550. METADATA_RECORD *pRecord = NULL;
  551. STACK_BUFFER( buff, 512 );
  552. DWORD cbBuffer;
  553. DWORD dwValue= 0;
  554. HANDLE hToken = NULL;
  555. HANDLE hToken2 = NULL;
  556. DBG_ASSERT(pecb);
  557. DBG_ASSERT(phToken);
  558. *phToken = NULL;
  559. cbBuffer = buff.QuerySize();
  560. fRet = pecb->ServerSupportFunction( pecb,
  561. HSE_REQ_GET_METADATA_PROPERTY,
  562. buff.QueryPtr(),
  563. &cbBuffer,
  564. (LPDWORD) MD_URL_AUTHORIZATION_IMPERSONATION_LEVEL );
  565. if ( !fRet &&
  566. GetLastError() != ERROR_INVALID_INDEX )
  567. {
  568. hr = HRESULT_FROM_WIN32( GetLastError() );
  569. goto exit;
  570. }
  571. else if ( fRet )
  572. {
  573. //
  574. // Check the property now. If invalid type then we're done
  575. //
  576. pRecord = (METADATA_RECORD*) buff.QueryPtr();
  577. if ( pRecord->dwMDDataType != DWORD_METADATA )
  578. {
  579. hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  580. goto exit;
  581. }
  582. // valid type of data - validity of data value done in switch below
  583. dwValue = *(DWORD*)pRecord->pbMDData;
  584. }
  585. else
  586. {
  587. DBG_ASSERT( !fRet && GetLastError() == ERROR_INVALID_INDEX );
  588. // no metadata present, therefore use the default of zero
  589. dwValue = 0;
  590. }
  591. switch(dwValue)
  592. {
  593. case 0:
  594. // use the current authenticated user
  595. fRet = OpenThreadToken( GetCurrentThread(),
  596. TOKEN_ALL_ACCESS,
  597. TRUE,
  598. &hToken );
  599. if ( !fRet )
  600. {
  601. hr = HRESULT_FROM_WIN32( GetLastError() );
  602. goto exit;
  603. }
  604. break;
  605. case 1:
  606. // use the process token to impersonate
  607. // first get the current impersonation token
  608. fRet = OpenThreadToken( GetCurrentThread(),
  609. TOKEN_IMPERSONATE,
  610. TRUE,
  611. &hToken2 );
  612. if ( fRet )
  613. {
  614. DBG_ASSERT( hToken2 != NULL );
  615. RevertToSelf();
  616. }
  617. // get the current process token - it's a primary token
  618. fRet = OpenProcessToken( GetCurrentProcess(),
  619. TOKEN_ALL_ACCESS,
  620. &hToken );
  621. if ( hToken2 != NULL )
  622. {
  623. if ( !SetThreadToken( NULL, hToken2 ) )
  624. {
  625. DBG_ASSERT( FALSE );
  626. }
  627. DBG_REQUIRE( CloseHandle( hToken2 ) );
  628. hToken2 = NULL;
  629. }
  630. // checking the return value from open the process token here
  631. if ( !fRet )
  632. {
  633. hr = HRESULT_FROM_WIN32( GetLastError() );
  634. goto exit;
  635. }
  636. // create an impersonation token from the primary process token
  637. fRet = DuplicateHandle ( GetCurrentProcess(),
  638. hToken,
  639. GetCurrentProcess(),
  640. &hToken2,
  641. 0,
  642. FALSE,
  643. DUPLICATE_SAME_ACCESS );
  644. if ( !fRet )
  645. {
  646. hr = HRESULT_FROM_WIN32( GetLastError() );
  647. goto exit;
  648. }
  649. DBG_REQUIRE( CloseHandle( hToken ) );
  650. hToken = hToken2;
  651. hToken2 = NULL;
  652. break;
  653. case 2:
  654. // get the anonymous token for impersonation
  655. cbBuffer = buff.QuerySize();
  656. fRet = pecb->GetServerVariable( pecb->ConnID,
  657. "UNICODE_SCRIPT_NAME",
  658. (CHAR*) buff.QueryPtr(),
  659. &cbBuffer );
  660. if ( !fRet )
  661. {
  662. if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER )
  663. {
  664. hr = HRESULT_FROM_WIN32( GetLastError() );
  665. goto exit;
  666. }
  667. DBG_ASSERT( cbBuffer > buff.QuerySize() );
  668. fRet = buff.Resize( cbBuffer );
  669. if ( !fRet )
  670. {
  671. hr = HRESULT_FROM_WIN32( GetLastError() );
  672. goto exit;
  673. }
  674. cbBuffer = buff.QuerySize();
  675. fRet = pecb->GetServerVariable( pecb->ConnID,
  676. "UNICODE_SCRIPT_NAME",
  677. (CHAR*) buff.QueryPtr(),
  678. &cbBuffer );
  679. if ( !fRet )
  680. {
  681. hr = HRESULT_FROM_WIN32( GetLastError() );
  682. goto exit;
  683. }
  684. }
  685. fRet = pecb->ServerSupportFunction( pecb->ConnID,
  686. HSE_REQ_GET_UNICODE_ANONYMOUS_TOKEN,
  687. buff.QueryPtr(),
  688. (LPDWORD)&hToken,
  689. NULL );
  690. if ( !fRet )
  691. {
  692. hr = HRESULT_FROM_WIN32( GetLastError() );
  693. goto exit;
  694. }
  695. break;
  696. default:
  697. // If not 0, 1, or 2 then not valid metadata
  698. hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  699. goto exit;
  700. break;
  701. }
  702. *phToken = hToken;
  703. hToken = NULL;
  704. hr = S_OK;
  705. exit:
  706. if ( hToken )
  707. {
  708. DBG_REQUIRE( CloseHandle( hToken ) );
  709. hToken = NULL;
  710. }
  711. return hr;
  712. };