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.

388 lines
11 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. if ( pMetaData->QuerySslAccessPerms() & MD_ACCESS_MAP_CERT )
  54. {
  55. pCertificateContext = pMainContext->QueryCertificateContext();
  56. if ( pCertificateContext == NULL )
  57. {
  58. fApplies = FALSE;
  59. goto Finished;
  60. }
  61. pSite = pMainContext->QuerySite();
  62. DBG_ASSERT( pSite != NULL );
  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( pMainContext,
  102. pbClientCertBlob,
  103. cbClientCertBlob,
  104. &pCachedIISMappedToken,
  105. &fClientCertDeniedByMapper );
  106. if ( FAILED( hr ) )
  107. {
  108. //
  109. // IISCERTMAP applies only when there was successful mapping
  110. // Otherwise it will yield other auth providers
  111. //
  112. if ( hr == SEC_E_UNKNOWN_CREDENTIALS )
  113. {
  114. //
  115. // DoMapCredential didn't find any mathing mapping
  116. // or user/pwd in the mapping was invalid
  117. //
  118. hr = S_OK;
  119. }
  120. fApplies = FALSE;
  121. goto Finished;
  122. }
  123. DBG_ASSERT ( fClientCertDeniedByMapper || pCachedIISMappedToken!= NULL );
  124. if( ( pCachedIISMappedToken != NULL &&
  125. pCachedIISMappedToken->QueryImpersonationToken() != NULL ) ||
  126. fClientCertDeniedByMapper )
  127. {
  128. IISCERTMAP_CONTEXT_STATE * pContextState = NULL;
  129. //
  130. // Use IISCERTMAP_CONTEXT_STATE to communicate information
  131. // from DoesApply() to DoAuthenticate()
  132. // We don't want to be calling mapper twice
  133. //
  134. pContextState = new (pMainContext) IISCERTMAP_CONTEXT_STATE(
  135. pCachedIISMappedToken,
  136. fClientCertDeniedByMapper );
  137. if ( pContextState == NULL )
  138. {
  139. if ( pCachedIISMappedToken != NULL )
  140. {
  141. pCachedIISMappedToken->DereferenceCacheEntry();
  142. pCachedIISMappedToken = NULL;
  143. }
  144. hr = HRESULT_FROM_WIN32( ERROR_OUTOFMEMORY );
  145. goto Finished;
  146. }
  147. //
  148. // pContextState is taking ownership of pCachedIISMappedToken
  149. //
  150. pMainContext->SetContextState( pContextState );
  151. fApplies = TRUE;
  152. }
  153. }
  154. }
  155. Finished:
  156. *pfApplies = fApplies;
  157. if ( pCachedIISMappedToken != NULL )
  158. {
  159. //
  160. // if creating CERTMAP_CONTEXT_STATE succeeded it will hold it's own reference
  161. // to cached token
  162. //
  163. pCachedIISMappedToken->DereferenceCacheEntry();
  164. pCachedIISMappedToken = NULL;
  165. }
  166. return NO_ERROR;
  167. }
  168. HRESULT
  169. IISCERTMAP_AUTH_PROVIDER::DoAuthenticate(
  170. W3_MAIN_CONTEXT * pMainContext,
  171. BOOL * pfFilterFinished
  172. )
  173. /*++
  174. Routine Description:
  175. Create a user context representing a cert mapped token
  176. Arguments:
  177. pMainContext - Main context
  178. pfFilterFinished - Set to TRUE if filter wants out
  179. Return Value:
  180. HRESULT
  181. --*/
  182. {
  183. IISCERTMAP_USER_CONTEXT * pUserContext = NULL;
  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. pfFilterFinished == NULL )
  190. {
  191. DBG_ASSERT( FALSE );
  192. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  193. }
  194. *pfFilterFinished = FALSE;
  195. pSite = pMainContext->QuerySite();
  196. DBG_ASSERT( pSite != NULL );
  197. // IIS mapper
  198. DBG_ASSERT ( !pSite->QueryUseDSMapper() );
  199. pContextState = (IISCERTMAP_CONTEXT_STATE *) pMainContext->QueryContextState();
  200. DBG_ASSERT( pContextState != NULL );
  201. if ( pContextState->QueryClientCertDeniedByIISCertMap() )
  202. {
  203. //
  204. // Report denied by IIS mapper error
  205. //
  206. pMainContext->QueryResponse()->SetStatus( HttpStatusForbidden,
  207. Http403MapperDenyAccess);
  208. pMainContext->SetErrorStatus( S_OK );
  209. return S_OK;
  210. }
  211. CachedToken = pContextState->QueryCachedIISCertMapToken();
  212. DBG_ASSERT( CachedToken != NULL );
  213. //
  214. // Create the user context for this request
  215. //
  216. pUserContext = new IISCERTMAP_USER_CONTEXT( this );
  217. if ( pUserContext == NULL )
  218. {
  219. CachedToken->DereferenceCacheEntry();
  220. return HRESULT_FROM_WIN32( GetLastError() );
  221. }
  222. hr = pUserContext->Create( CachedToken );
  223. if ( FAILED( hr ) )
  224. {
  225. pUserContext->DereferenceUserContext();
  226. pUserContext = NULL;
  227. return hr;
  228. }
  229. pMainContext->SetUserContext( pUserContext );
  230. return NO_ERROR;
  231. }
  232. HRESULT
  233. IISCERTMAP_AUTH_PROVIDER::OnAccessDenied(
  234. W3_MAIN_CONTEXT * /*pMainContext*/
  235. )
  236. /*++
  237. Routine Description:
  238. NOP since we have nothing to do on access denied
  239. Arguments:
  240. pMainContext - Main context (not used)
  241. Return Value:
  242. HRESULT
  243. --*/
  244. {
  245. //
  246. // No headers to add
  247. //
  248. return NO_ERROR;
  249. }
  250. HRESULT
  251. IISCERTMAP_USER_CONTEXT::Create(
  252. TOKEN_CACHE_ENTRY * pCachedToken
  253. )
  254. /*++
  255. Routine Description:
  256. Create a certificate mapped user context
  257. Arguments:
  258. pCachedToken - cached token
  259. Note: function takes ownership of pCachedToken.
  260. It will dereference it even in the case of failure
  261. Return Value:
  262. HRESULT
  263. --*/
  264. {
  265. HRESULT hr = E_FAIL;
  266. if ( pCachedToken == NULL )
  267. {
  268. DBG_ASSERT( FALSE );
  269. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  270. }
  271. //
  272. // First the easy stuff
  273. //
  274. pCachedToken->ReferenceCacheEntry();
  275. _pCachedToken = pCachedToken;
  276. SetCachedToken( TRUE );
  277. //
  278. // Now get the user name
  279. //
  280. if ( !SetThreadToken( NULL, _pCachedToken->QueryImpersonationToken() ) )
  281. {
  282. hr = HRESULT_FROM_WIN32( GetLastError() );
  283. goto Failed;
  284. }
  285. // cchUserName will be set to size of the buffer in chars (including terminating one)
  286. DWORD cchUserName = sizeof( _achUserName ) / sizeof( WCHAR );
  287. if ( !GetUserNameEx( NameSamCompatible,
  288. _achUserName,
  289. &cchUserName ) )
  290. {
  291. hr = HRESULT_FROM_WIN32( GetLastError() );
  292. RevertToSelf();
  293. goto Failed;
  294. }
  295. RevertToSelf();
  296. return NO_ERROR;
  297. Failed:
  298. if ( _pCachedToken != NULL )
  299. {
  300. _pCachedToken->DereferenceCacheEntry();
  301. _pCachedToken = NULL;
  302. }
  303. return hr;
  304. }