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.

384 lines
10 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name :
  4. certmapprovider.cxx
  5. Abstract:
  6. IIS Certificate Mapper provider
  7. Author:
  8. Bilal Alam (balam) 10-Jan-2000
  9. Environment:
  10. Win32 - User Mode
  11. Project:
  12. ULW3.DLL
  13. --*/
  14. #include "precomp.hxx"
  15. #include "iiscertmapprovider.hxx"
  16. HRESULT
  17. IISCERTMAP_AUTH_PROVIDER::DoesApply(
  18. W3_MAIN_CONTEXT * pMainContext,
  19. BOOL * pfApplies
  20. )
  21. /*++
  22. Routine Description:
  23. Does certificate map authentication apply?
  24. Arguments:
  25. pMainContext - Main context
  26. pfApplies - Set to TRUE if cert map auth applies
  27. Return Value:
  28. HRESULT
  29. --*/
  30. {
  31. CERTIFICATE_CONTEXT * pCertificateContext;
  32. URL_CONTEXT * pUrlContext = NULL;
  33. W3_METADATA * pMetaData = NULL;
  34. BOOL fApplies = FALSE;
  35. W3_SITE * pSite = NULL;
  36. IIS_CERTIFICATE_MAPPING * pIISCertificateMapping = NULL;
  37. TOKEN_CACHE_ENTRY * pCachedIISMappedToken = NULL;
  38. BOOL fClientCertDeniedByMapper = FALSE;
  39. if ( pMainContext == NULL ||
  40. pfApplies == NULL )
  41. {
  42. DBG_ASSERT( FALSE );
  43. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  44. }
  45. //
  46. // If cert mapping is not allowed for this vroot, then ignore client
  47. // cert token and let other authentication mechanisms do their thing
  48. //
  49. pUrlContext = pMainContext->QueryUrlContext();
  50. DBG_ASSERT( pUrlContext != NULL );
  51. pMetaData = pUrlContext->QueryMetaData();
  52. DBG_ASSERT( pMetaData != NULL );
  53. pSite = pMainContext->QuerySite();
  54. DBG_ASSERT( pSite != NULL );
  55. if ( pMetaData->QuerySslAccessPerms() & VROOT_MASK_MAP_CERT )
  56. {
  57. pCertificateContext = pMainContext->QueryCertificateContext();
  58. if ( pCertificateContext == NULL )
  59. {
  60. fApplies = FALSE;
  61. goto Finished;
  62. }
  63. if ( ! pSite->QueryUseDSMapper() )
  64. {
  65. //
  66. // IIS mapper enabled
  67. //
  68. HRESULT hr = E_FAIL;
  69. PBYTE pbClientCertBlob = NULL;
  70. DWORD cbClientCertBlob = 0;
  71. //
  72. // No need to call DereferenceCertMapping after QueryIISCertificateMapping
  73. // IISCertificateMapping is referenced by W3_SITE and we hold reference
  74. // to W3_SITE already
  75. //
  76. hr = pSite->GetIISCertificateMapping( &pIISCertificateMapping );
  77. if ( FAILED( hr ) ||
  78. ( pIISCertificateMapping == NULL ) )
  79. {
  80. //
  81. // If we couldn't read the mapping because not found, thats OK.
  82. //
  83. // CODEWORK: we may need smarted error handling (ignoring error
  84. // and assuming that mapping was not found is not very good idea
  85. //
  86. fApplies = FALSE;
  87. goto Finished;
  88. }
  89. //
  90. // retrieve client certificate
  91. //
  92. pCertificateContext->QueryEncodedCertificate(
  93. reinterpret_cast<PVOID *>(&pbClientCertBlob),
  94. &cbClientCertBlob );
  95. if( pbClientCertBlob == NULL || cbClientCertBlob == 0 )
  96. {
  97. fApplies = FALSE;
  98. goto Finished;
  99. }
  100. DBG_ASSERT( pIISCertificateMapping != NULL );
  101. hr = pIISCertificateMapping->DoMapCredential( pbClientCertBlob,
  102. cbClientCertBlob,
  103. &pCachedIISMappedToken,
  104. &fClientCertDeniedByMapper );
  105. if ( FAILED( hr ) )
  106. {
  107. //
  108. // IISCERTMAP applies only when there was successful mapping
  109. // Otherwise it will yield other auth providers
  110. //
  111. if ( hr == SEC_E_UNKNOWN_CREDENTIALS )
  112. {
  113. //
  114. // DoMapCredential didn't find any mathing mapping
  115. // or user/pwd in the mapping was invalid
  116. //
  117. hr = S_OK;
  118. }
  119. fApplies = FALSE;
  120. goto Finished;
  121. }
  122. DBG_ASSERT ( fClientCertDeniedByMapper || pCachedIISMappedToken!= NULL );
  123. if( ( pCachedIISMappedToken != NULL &&
  124. pCachedIISMappedToken->QueryImpersonationToken() != NULL ) ||
  125. fClientCertDeniedByMapper )
  126. {
  127. IISCERTMAP_CONTEXT_STATE * pContextState = NULL;
  128. //
  129. // Use IISCERTMAP_CONTEXT_STATE to communicate information
  130. // from DoesApply() to DoAuthenticate()
  131. // We don't want to be calling mapper twice
  132. //
  133. pContextState = new (pMainContext) IISCERTMAP_CONTEXT_STATE(
  134. pCachedIISMappedToken,
  135. fClientCertDeniedByMapper );
  136. if ( pContextState == NULL )
  137. {
  138. if ( pCachedIISMappedToken != NULL )
  139. {
  140. pCachedIISMappedToken->DereferenceCacheEntry();
  141. pCachedIISMappedToken = NULL;
  142. }
  143. hr = HRESULT_FROM_WIN32( ERROR_OUTOFMEMORY );
  144. goto Finished;
  145. }
  146. //
  147. // pContextState is taking ownership of pCachedIISMappedToken
  148. //
  149. pMainContext->SetContextState( pContextState );
  150. fApplies = TRUE;
  151. }
  152. }
  153. }
  154. Finished:
  155. *pfApplies = fApplies;
  156. if ( pCachedIISMappedToken != NULL )
  157. {
  158. //
  159. // if creating CERTMAP_CONTEXT_STATE succeeded it will hold it's own reference
  160. // to cached token
  161. //
  162. pCachedIISMappedToken->DereferenceCacheEntry();
  163. pCachedIISMappedToken = NULL;
  164. }
  165. return NO_ERROR;
  166. }
  167. HRESULT
  168. IISCERTMAP_AUTH_PROVIDER::DoAuthenticate(
  169. W3_MAIN_CONTEXT * pMainContext
  170. )
  171. /*++
  172. Routine Description:
  173. Create a user context representing a cert mapped token
  174. Arguments:
  175. pMainContext - Main context
  176. Return Value:
  177. HRESULT
  178. --*/
  179. {
  180. IISCERTMAP_USER_CONTEXT * pUserContext = NULL;
  181. CERTIFICATE_CONTEXT * pCertificateContext = NULL;
  182. HANDLE hImpersonation;
  183. BOOL fDelegatable = FALSE;
  184. HRESULT hr = NO_ERROR;
  185. W3_SITE * pSite = NULL;
  186. IISCERTMAP_CONTEXT_STATE * pContextState = NULL;
  187. TOKEN_CACHE_ENTRY * CachedToken = NULL;
  188. if ( pMainContext == NULL )
  189. {
  190. DBG_ASSERT( FALSE );
  191. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  192. }
  193. pSite = pMainContext->QuerySite();
  194. DBG_ASSERT( pSite != NULL );
  195. // IIS mapper
  196. DBG_ASSERT ( !pSite->QueryUseDSMapper() );
  197. pContextState = (IISCERTMAP_CONTEXT_STATE *) pMainContext->QueryContextState();
  198. DBG_ASSERT( pContextState != NULL );
  199. if ( pContextState->QueryClientCertDeniedByIISCertMap() )
  200. {
  201. //
  202. // Report denied by IIS mapper error
  203. //
  204. pMainContext->QueryResponse()->SetStatus( HttpStatusForbidden,
  205. Http403MapperDenyAccess);
  206. pMainContext->SetErrorStatus( S_OK );
  207. return S_OK;
  208. }
  209. CachedToken = pContextState->QueryCachedIISCertMapToken();
  210. DBG_ASSERT( CachedToken != NULL );
  211. //
  212. // Create the user context for this request
  213. //
  214. pUserContext = new IISCERTMAP_USER_CONTEXT( this );
  215. if ( pUserContext == NULL )
  216. {
  217. CachedToken->DereferenceCacheEntry();
  218. return HRESULT_FROM_WIN32( GetLastError() );
  219. }
  220. hr = pUserContext->Create( CachedToken );
  221. if ( FAILED( hr ) )
  222. {
  223. pUserContext->DereferenceUserContext();
  224. pUserContext = NULL;
  225. return hr;
  226. }
  227. pMainContext->SetUserContext( pUserContext );
  228. return NO_ERROR;
  229. }
  230. HRESULT
  231. IISCERTMAP_AUTH_PROVIDER::OnAccessDenied(
  232. W3_MAIN_CONTEXT * pMainContext
  233. )
  234. /*++
  235. Routine Description:
  236. NOP since we have nothing to do on access denied
  237. Arguments:
  238. pMainContext - Main context
  239. Return Value:
  240. HRESULT
  241. --*/
  242. {
  243. //
  244. // No headers to add
  245. //
  246. return NO_ERROR;
  247. }
  248. HRESULT
  249. IISCERTMAP_USER_CONTEXT::Create(
  250. TOKEN_CACHE_ENTRY * pCachedToken
  251. )
  252. /*++
  253. Routine Description:
  254. Create a certificate mapped user context
  255. Arguments:
  256. pCachedToken - cached token
  257. Note: function takes ownership of pCachedToken.
  258. It will dereference it even in the case of failure
  259. Return Value:
  260. HRESULT
  261. --*/
  262. {
  263. HRESULT hr = E_FAIL;
  264. DWORD cchUserName = sizeof( _achUserName ) / sizeof( WCHAR );
  265. if ( pCachedToken == NULL )
  266. {
  267. DBG_ASSERT( FALSE );
  268. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  269. }
  270. //
  271. // First the easy stuff
  272. //
  273. pCachedToken->ReferenceCacheEntry();
  274. _pCachedToken = pCachedToken;
  275. //
  276. // Now get the user name
  277. //
  278. if ( !SetThreadToken( NULL, _pCachedToken->QueryImpersonationToken() ) )
  279. {
  280. hr = HRESULT_FROM_WIN32( GetLastError() );
  281. goto Failed;
  282. }
  283. if ( !GetUserNameEx( NameSamCompatible,
  284. _achUserName,
  285. &cchUserName ) )
  286. {
  287. RevertToSelf();
  288. hr = HRESULT_FROM_WIN32( GetLastError() );
  289. goto Failed;
  290. }
  291. RevertToSelf();
  292. return NO_ERROR;
  293. Failed:
  294. if ( _pCachedToken != NULL )
  295. {
  296. _pCachedToken->DereferenceCacheEntry();
  297. _pCachedToken = NULL;
  298. }
  299. return hr;
  300. }