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.

583 lines
14 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name :
  4. basicprovider.cxx
  5. Abstract:
  6. Basic authentication 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 "basicprovider.hxx"
  16. #include "uuencode.hxx"
  17. HRESULT
  18. BASIC_AUTH_PROVIDER::DoesApply(
  19. W3_MAIN_CONTEXT * pMainContext,
  20. BOOL * pfApplies
  21. )
  22. /*++
  23. Routine Description:
  24. Does basic authentication apply to this request?
  25. Arguments:
  26. pMainContext - Main context representing request
  27. pfApplies - Set to true if SSPI is applicable
  28. Return Value:
  29. HRESULT
  30. --*/
  31. {
  32. STACK_STRA( strAuthType, 64 );
  33. HRESULT hr;
  34. if ( pMainContext == NULL ||
  35. pfApplies == NULL )
  36. {
  37. DBG_ASSERT( FALSE );
  38. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  39. }
  40. *pfApplies = FALSE;
  41. //
  42. // Get auth type
  43. //
  44. hr = pMainContext->QueryRequest()->GetAuthType( &strAuthType );
  45. if ( FAILED( hr ) )
  46. {
  47. return hr;
  48. }
  49. //
  50. // No package, no auth
  51. //
  52. if ( strAuthType.IsEmpty() )
  53. {
  54. return NO_ERROR;
  55. }
  56. //
  57. // Is it basic?
  58. //
  59. if ( _stricmp( strAuthType.QueryStr(), "Basic" ) == 0 )
  60. {
  61. *pfApplies = TRUE;
  62. }
  63. return NO_ERROR;
  64. }
  65. HRESULT
  66. BASIC_AUTH_PROVIDER::DoAuthenticate(
  67. W3_MAIN_CONTEXT * pMainContext
  68. )
  69. /*++
  70. Routine Description:
  71. Do the authentication thing!
  72. Arguments:
  73. pMainContext - main context
  74. Return Value:
  75. HRESULT
  76. --*/
  77. {
  78. CHAR * pszAuthHeader = NULL;
  79. HRESULT hr;
  80. BOOL fRet;
  81. BOOL fFinished = FALSE;
  82. STACK_BUFFER ( buffDecoded, 256 );
  83. CHAR * pszDecoded;
  84. CHAR * pszColon;
  85. // add 1 to strUserDomain for separator "\"
  86. STACK_STRA( strUserDomain, UNLEN + IIS_DNLEN + 1 + 1 );
  87. STACK_STRA( strUserName, UNLEN + 1 );
  88. STACK_STRA( strPassword, PWLEN + 1 );
  89. STACK_STRA( strDomainName, IIS_DNLEN + 1 );
  90. // add 1 to strUserDomainW for separator "\"
  91. STACK_STRU( strUserDomainW, UNLEN + IIS_DNLEN + 1 + 1 );
  92. STACK_STRU( strUserNameW, UNLEN + 1 );
  93. STACK_STRU( strPasswordW, PWLEN + 1 );
  94. STACK_STRU( strRemotePasswordW, PWLEN + 1 );
  95. STACK_STRU( strDomainNameW, IIS_DNLEN + 1 );
  96. // add 1 to strRemoteUserNameW for separator "\"
  97. STACK_STRU( strRemoteUserNameW, UNLEN + IIS_DNLEN + 1 );
  98. W3_METADATA * pMetaData = NULL;
  99. TOKEN_CACHE_ENTRY * pCachedToken = NULL;
  100. BASIC_USER_CONTEXT * pUserContext = NULL;
  101. DWORD dwLogonError = ERROR_SUCCESS;
  102. BOOL fPossibleUPNLogon = FALSE;
  103. if ( pMainContext == NULL )
  104. {
  105. DBG_ASSERT( FALSE );
  106. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  107. }
  108. //
  109. // Get the part after the auth type
  110. //
  111. pszAuthHeader = pMainContext->QueryRequest()->GetHeader( HttpHeaderAuthorization );
  112. DBG_ASSERT( pszAuthHeader != NULL );
  113. //
  114. // We better have an Authorization: Basic header if we got to here!
  115. //
  116. DBG_ASSERT( _strnicmp( pszAuthHeader, "Basic", 5 ) == 0 );
  117. //
  118. // Advance to good stuff
  119. //
  120. if ( pszAuthHeader[ 5 ] == '\0' )
  121. {
  122. DBG_ASSERT( FALSE );
  123. return HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
  124. }
  125. pszAuthHeader = pszAuthHeader + 6;
  126. //
  127. // UUDecode the buffer
  128. //
  129. if ( !uudecode( pszAuthHeader,
  130. &buffDecoded ) )
  131. {
  132. hr = HRESULT_FROM_WIN32( GetLastError() );
  133. goto exit;
  134. }
  135. pszDecoded = (CHAR*) buffDecoded.QueryPtr();
  136. //
  137. // Now split out user:password
  138. //
  139. pszColon = strchr( pszDecoded, ':' );
  140. if ( pszColon == NULL )
  141. {
  142. //
  143. // Bad credentials
  144. //
  145. pMainContext->QueryResponse()->SetStatus( HttpStatusUnauthorized,
  146. Http401BadLogon );
  147. hr = NO_ERROR;
  148. goto exit;
  149. }
  150. //
  151. // Get user/password
  152. //
  153. hr = strUserDomain.Copy( pszDecoded,
  154. DIFF( pszColon - pszDecoded ) );
  155. if ( FAILED( hr ) )
  156. {
  157. goto exit;
  158. }
  159. hr = strPassword.Copy( pszColon + 1 );
  160. if ( FAILED( hr ) )
  161. {
  162. goto exit;
  163. }
  164. //
  165. // Copy the user name into the request
  166. //
  167. hr = pMainContext->QueryRequest()->SetRequestUserName( strUserDomain );
  168. if ( FAILED( hr ) )
  169. {
  170. goto exit;
  171. }
  172. //
  173. // Remember the unmapped user name and password
  174. //
  175. hr = strRemoteUserNameW.CopyA( strUserDomain.QueryStr() );
  176. if ( FAILED( hr ) )
  177. {
  178. goto exit;
  179. }
  180. hr = strRemotePasswordW.CopyA( strPassword.QueryStr() );
  181. if ( FAILED( hr ) )
  182. {
  183. goto exit;
  184. }
  185. //
  186. // Notify authentication filters
  187. //
  188. if ( pMainContext->IsNotificationNeeded( SF_NOTIFY_AUTHENTICATION ) )
  189. {
  190. HTTP_FILTER_AUTHENT filterAuthent;
  191. hr = strUserDomain.Resize( SF_MAX_USERNAME );
  192. if ( FAILED( hr ) )
  193. {
  194. goto exit;
  195. }
  196. hr = strPassword.Resize( SF_MAX_PASSWORD );
  197. if ( FAILED( hr ) )
  198. {
  199. goto exit;
  200. }
  201. filterAuthent.pszUser = strUserDomain.QueryStr();
  202. filterAuthent.cbUserBuff = SF_MAX_USERNAME;
  203. filterAuthent.pszPassword = strPassword.QueryStr();
  204. filterAuthent.cbPasswordBuff = SF_MAX_PASSWORD;
  205. fRet = pMainContext->NotifyFilters( SF_NOTIFY_AUTHENTICATION,
  206. &filterAuthent,
  207. &fFinished );
  208. if ( !fRet )
  209. {
  210. hr = HRESULT_FROM_WIN32( GetLastError() );
  211. goto exit;
  212. }
  213. if ( fFinished )
  214. {
  215. pMainContext->SetFinishedResponse();
  216. hr = NO_ERROR;
  217. goto exit;
  218. }
  219. strUserDomain.SetLen( strlen( strUserDomain.QueryStr() ) );
  220. strPassword.SetLen( strlen( strPassword.QueryStr() ) );
  221. }
  222. if( strUserDomain.IsEmpty() )
  223. {
  224. //
  225. // If user domain string is empty, then we will fall back to
  226. // anonymous authentication
  227. //
  228. AUTH_PROVIDER * pAnonymousProvider =
  229. W3_STATE_AUTHENTICATION::QueryAnonymousProvider();
  230. DBG_ASSERT( pAnonymousProvider != NULL );
  231. hr = pAnonymousProvider->DoAuthenticate( pMainContext );
  232. goto exit;
  233. }
  234. //
  235. // Convert to unicode
  236. //
  237. hr = strUserDomainW.CopyA( strUserDomain.QueryStr() );
  238. if ( FAILED( hr ) )
  239. {
  240. goto exit;
  241. }
  242. hr = strPasswordW.CopyA( strPassword.QueryStr() );
  243. if ( FAILED( hr ) )
  244. {
  245. goto exit;
  246. }
  247. //
  248. // Get username/domain out of domain\username
  249. //
  250. pMetaData = pMainContext->QueryUrlContext()->QueryMetaData();
  251. DBG_ASSERT( pMetaData != NULL );
  252. hr = W3_STATE_AUTHENTICATION::SplitUserDomain( strUserDomainW,
  253. &strUserNameW,
  254. &strDomainNameW,
  255. pMetaData->QueryDomainName(),
  256. &fPossibleUPNLogon );
  257. if ( FAILED( hr ) )
  258. {
  259. goto exit;
  260. }
  261. //
  262. // Try to get the token
  263. //
  264. DBG_ASSERT( g_pW3Server->QueryTokenCache() != NULL );
  265. hr = g_pW3Server->QueryTokenCache()->GetCachedToken(
  266. strUserNameW.QueryStr(),
  267. strDomainNameW.QueryStr(),
  268. strPasswordW.QueryStr(),
  269. pMetaData->QueryLogonMethod(),
  270. fPossibleUPNLogon,
  271. &pCachedToken,
  272. &dwLogonError );
  273. if ( FAILED( hr ) )
  274. {
  275. goto exit;
  276. }
  277. //
  278. // If pCachedToken is NULL, then logon failed
  279. //
  280. if ( pCachedToken == NULL )
  281. {
  282. DBG_ASSERT( dwLogonError != ERROR_SUCCESS );
  283. if( dwLogonError == ERROR_PASSWORD_MUST_CHANGE ||
  284. dwLogonError == ERROR_PASSWORD_EXPIRED )
  285. {
  286. hr = HRESULT_FROM_WIN32( dwLogonError );
  287. goto exit;
  288. }
  289. pMainContext->QueryResponse()->SetStatus(
  290. HttpStatusUnauthorized,
  291. Http401BadLogon );
  292. pMainContext->SetErrorStatus( HRESULT_FROM_WIN32( dwLogonError ) );
  293. hr = NO_ERROR;
  294. goto exit;
  295. }
  296. //
  297. // We have a token! Setup a W3_USER_CONTEXT and we're done
  298. //
  299. pUserContext = new BASIC_USER_CONTEXT( this );
  300. if ( FAILED( hr ) )
  301. {
  302. goto exit;
  303. }
  304. hr = pUserContext->Create( pCachedToken,
  305. strUserNameW,
  306. strDomainNameW,
  307. strRemotePasswordW,
  308. strRemoteUserNameW,
  309. strUserDomainW,
  310. pMetaData->QueryLogonMethod() );
  311. if ( FAILED( hr ) )
  312. {
  313. pUserContext->DereferenceUserContext();
  314. pUserContext = NULL;
  315. goto exit;
  316. }
  317. pMainContext->SetUserContext( pUserContext );
  318. exit:
  319. //
  320. // Zero out all copies of password in this routine
  321. //
  322. ZeroMemory( buffDecoded.QueryPtr(), buffDecoded.QuerySize() );
  323. if( strPassword.QueryCB() )
  324. {
  325. ZeroMemory( ( VOID * )strPassword.QueryStr(),
  326. strPassword.QueryCB() );
  327. }
  328. if( strPasswordW.QueryCB() )
  329. {
  330. ZeroMemory( ( VOID * )strPasswordW.QueryStr(),
  331. strPassword.QueryCB() );
  332. }
  333. if( strRemotePasswordW.QueryCB() )
  334. {
  335. ZeroMemory( ( VOID * )strRemotePasswordW.QueryStr(),
  336. strPassword.QueryCB() );
  337. }
  338. return hr;
  339. }
  340. HRESULT
  341. BASIC_AUTH_PROVIDER::OnAccessDenied(
  342. W3_MAIN_CONTEXT * pMainContext
  343. )
  344. /*++
  345. Routine Description:
  346. Add basic authentication header
  347. Arguments:
  348. pMainContext - Main context
  349. Return Value:
  350. HRESULT
  351. --*/
  352. {
  353. STACK_STRU( strAuthHeader, 256 );
  354. STACK_STRA( straAuthHeader, 256 );
  355. STACK_STRU( strHostAddr, 256 );
  356. HRESULT hr;
  357. W3_METADATA * pMetaData;
  358. if ( pMainContext == NULL )
  359. {
  360. DBG_ASSERT( FALSE );
  361. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  362. }
  363. hr = strAuthHeader.Copy( L"Basic realm=\"" );
  364. if ( FAILED( hr ) )
  365. {
  366. return hr;
  367. }
  368. pMetaData = pMainContext->QueryUrlContext()->QueryMetaData();
  369. DBG_ASSERT( pMetaData != NULL );
  370. //
  371. // If a realm is configured, use it. Otherwise use host address of
  372. // request
  373. //
  374. if ( pMetaData->QueryRealm() != NULL )
  375. {
  376. hr = strAuthHeader.Append( pMetaData->QueryRealm() );
  377. }
  378. else
  379. {
  380. hr = pMainContext->QueryRequest()->GetHostAddr( &strHostAddr );
  381. if ( FAILED( hr ) )
  382. {
  383. return hr;
  384. }
  385. hr = strAuthHeader.Append( strHostAddr );
  386. }
  387. if ( FAILED( hr ) )
  388. {
  389. return hr;
  390. }
  391. hr = strAuthHeader.Append( L"\"" );
  392. if ( FAILED( hr ) )
  393. {
  394. return hr;
  395. }
  396. if (FAILED(hr = straAuthHeader.CopyW(strAuthHeader.QueryStr())))
  397. {
  398. return hr;
  399. }
  400. return pMainContext->QueryResponse()->SetHeader( "WWW-Authenticate",
  401. 16,
  402. straAuthHeader.QueryStr(),
  403. straAuthHeader.QueryCCH() );
  404. }
  405. HRESULT
  406. BASIC_USER_CONTEXT::Create(
  407. TOKEN_CACHE_ENTRY * pCachedToken,
  408. STRU & strUserName,
  409. STRU & strDomainName,
  410. STRU & strPassword,
  411. STRU & strRemoteUserName,
  412. STRU & strMappedDomainUser,
  413. DWORD dwLogonMethod
  414. )
  415. /*++
  416. Routine Description:
  417. Initialize a basic user context
  418. Arguments:
  419. pCachedToken - The token
  420. strUserName - User name (without embedded domain)
  421. strDomainName - Domain name
  422. strPassword - Password
  423. strRemoteUserName - Unmapped user name
  424. strMappedDomainUser - Mapped domain user (may have embedded domain)
  425. dwLogonMethod - Logon method
  426. Return Value:
  427. HRESULT
  428. --*/
  429. {
  430. HRESULT hr;
  431. if ( pCachedToken == NULL )
  432. {
  433. DBG_ASSERT( FALSE );
  434. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  435. }
  436. hr = _strUserName.Copy( strMappedDomainUser );
  437. if ( FAILED( hr ) )
  438. {
  439. return hr;
  440. }
  441. hr = _strPassword.Append( strPassword );
  442. if ( FAILED( hr ) )
  443. {
  444. return hr;
  445. }
  446. hr = _strRemoteUserName.Append( strRemoteUserName );
  447. if ( FAILED( hr ) )
  448. {
  449. return hr;
  450. }
  451. if ( dwLogonMethod == LOGON32_LOGON_INTERACTIVE ||
  452. dwLogonMethod == LOGON32_LOGON_BATCH )
  453. {
  454. _fDelegatable = TRUE;
  455. }
  456. _pCachedToken = pCachedToken;
  457. return NO_ERROR;
  458. }