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.

3275 lines
81 KiB

  1. /*++
  2. Copyright (c) 1995-1996 Microsoft Corporation
  3. Module Name :
  4. authent.cxx
  5. Abstract:
  6. Authentication support functions for IIS
  7. Author:
  8. Murali R. Krishnan ( MuraliK ) 11-Dec-1996
  9. Environment:
  10. User Mode - Win32
  11. Project:
  12. Internet Server DLL
  13. Functions Exported:
  14. TCP_AUTHENT::*
  15. Revision History:
  16. --*/
  17. /************************************************************
  18. * Include Headers
  19. ************************************************************/
  20. #include "tcpdllp.hxx"
  21. #pragma hdrstop
  22. #if 1 // DBCS
  23. #include <mbstring.h>
  24. #endif
  25. # include "infosec.hxx"
  26. #include "TokenAcl.hxx"
  27. #include <softpub.h>
  28. #include <wininet.h>
  29. #include <wincrypt.h>
  30. #include <iiscert.hxx>
  31. #include <iisctl.hxx>
  32. #include <sslinfo.hxx>
  33. #if !defined(CRYPT_E_REVOKED)
  34. #define CRYPT_E_REVOKED _HRESULT_TYPEDEF_(0x80092010L)
  35. #endif
  36. #if !defined(CRYPT_E_NO_REVOCATION_CHECK)
  37. #define CRYPT_E_NO_REVOCATION_CHECK _HRESULT_TYPEDEF_(0x80092012L)
  38. #endif
  39. #if !defined(CRYPT_E_REVOCATION_OFFLINE)
  40. #define CRYPT_E_REVOCATION_OFFLINE _HRESULT_TYPEDEF_(0x80092013L)
  41. #endif
  42. BOOL
  43. IsCertificateVerified(
  44. PSecPkgContext_RemoteCredentialInfo pspRCI
  45. );
  46. extern BOOL g_fCertCheckCA;
  47. /************************************************************
  48. * Functions
  49. ************************************************************/
  50. BOOL
  51. IsCertificateVerified(
  52. PSecPkgContext_RemoteCredentialInfo pspRCI
  53. )
  54. {
  55. if ( g_fCertCheckCA )
  56. {
  57. return ((pspRCI->fFlags & RCRED_STATUS_UNKNOWN_ISSUER) == 0);
  58. }
  59. return TRUE;
  60. }
  61. TCP_AUTHENT::TCP_AUTHENT(
  62. DWORD AuthFlags
  63. )
  64. /*++
  65. Routine Description:
  66. Constructor for the Authentication class
  67. Arguments:
  68. AuthFlags - One of the TCPAUTH_* flags.
  69. --*/
  70. : _hToken ( NULL ),
  71. _hSSPToken ( NULL ),
  72. _hSSPPrimaryToken( NULL ),
  73. _fHaveCredHandle ( FALSE ),
  74. _fHaveCtxtHandle ( FALSE ),
  75. _fClient ( FALSE ),
  76. _fUUEncodeData ( FALSE ),
  77. _pDeleteFunction ( NULL ),
  78. _fBase64 ( FALSE ),
  79. _fKnownToBeGuest ( FALSE ),
  80. _pClientCertContext( NULL ),
  81. _pSslInfo ( NULL ),
  82. _pServerX509Certificate( NULL ),
  83. _fCertCheckForRevocation( TRUE ),
  84. _fCertCheckCacheOnly( FALSE )
  85. {
  86. if ( AuthFlags & TCPAUTH_SERVER )
  87. {
  88. DBG_ASSERT( !(AuthFlags & TCPAUTH_CLIENT));
  89. }
  90. if ( AuthFlags & TCPAUTH_CLIENT )
  91. {
  92. _fClient = TRUE;
  93. }
  94. if ( AuthFlags & TCPAUTH_UUENCODE )
  95. {
  96. _fUUEncodeData = TRUE;
  97. }
  98. if ( AuthFlags & TCPAUTH_BASE64 )
  99. {
  100. _fBase64 = TRUE;
  101. }
  102. DBG_REQUIRE( Reset( TRUE ) );
  103. }
  104. /*******************************************************************/
  105. TCP_AUTHENT::~TCP_AUTHENT(
  106. )
  107. /*++
  108. Routine Description:
  109. Destructor for the Authentication class
  110. --*/
  111. {
  112. Reset( TRUE );
  113. }
  114. BOOL
  115. TCP_AUTHENT::DeleteCachedTokenOnReset(
  116. VOID
  117. )
  118. {
  119. if ( _hToken != NULL )
  120. {
  121. CACHED_TOKEN *pct = (CACHED_TOKEN*)_hToken;
  122. DBG_ASSERT( _fClearText );
  123. RemoveTokenFromCache( pct);
  124. }
  125. return TRUE;
  126. }
  127. BOOL
  128. TCP_AUTHENT::Reset(
  129. BOOL fSessionReset
  130. )
  131. /*++
  132. Routine Description:
  133. Resets this object in preparation for a brand new conversation
  134. --*/
  135. {
  136. if ( _hToken != NULL )
  137. {
  138. DBG_ASSERT( _fClearText );
  139. TsDeleteUserToken( _hToken );
  140. _hToken = NULL;
  141. }
  142. if ( _hSSPToken )
  143. {
  144. ////if ( !_pDeleteFunction )
  145. {
  146. CloseHandle( _hSSPToken );
  147. }
  148. //
  149. // Don't delete the SSPI Token as we queried it directly from SSPI
  150. //
  151. _hSSPToken = NULL;
  152. }
  153. //
  154. // We close this token because we duplicated it from _hSSPToken
  155. //
  156. if ( _hSSPPrimaryToken )
  157. {
  158. CloseHandle( _hSSPPrimaryToken );
  159. _hSSPPrimaryToken = NULL;
  160. }
  161. if ( _pDeleteFunction )
  162. {
  163. (_pDeleteFunction)( &_hctxt, _pDeleteArg );
  164. _pDeleteFunction = NULL;
  165. _fHaveCtxtHandle = FALSE;
  166. _fHaveCredHandle = FALSE;
  167. }
  168. else
  169. {
  170. if ( _fHaveCtxtHandle )
  171. {
  172. pfnDeleteSecurityContext( &_hctxt );
  173. _fHaveCtxtHandle = FALSE;
  174. }
  175. if ( _fHaveCredHandle )
  176. {
  177. pfnFreeCredentialsHandle( &_hcred );
  178. _fHaveCredHandle = FALSE;
  179. }
  180. }
  181. if ( fSessionReset )
  182. {
  183. if ( _pClientCertContext )
  184. {
  185. (pfnFreeCertCtxt)( _pClientCertContext );
  186. _pClientCertContext = NULL;
  187. }
  188. if ( _pServerX509Certificate )
  189. {
  190. (fnFreeCert)( _pServerX509Certificate );
  191. _pServerX509Certificate = NULL;
  192. }
  193. _phSslCtxt = NULL;
  194. _fCertCheckForRevocation = TRUE;
  195. _fCertCheckCacheOnly = FALSE;
  196. if ( _pSslInfo )
  197. {
  198. IIS_SSL_INFO::Release( _pSslInfo );
  199. _pSslInfo = NULL;
  200. }
  201. }
  202. _fNewConversation = TRUE;
  203. _fClearText = FALSE;
  204. _fHaveAccessTokens= FALSE;
  205. _cbMaxToken = 0;
  206. _fDelegate = FALSE;
  207. _pDeleteArg = NULL;
  208. _fKnownToBeGuest = FALSE;
  209. _fHaveExpiry = FALSE;
  210. return TRUE;
  211. }
  212. /*******************************************************************/
  213. BOOL
  214. TCP_AUTHENT::SetSecurityContextToken(
  215. CtxtHandle* pCtxt,
  216. HANDLE hPrimaryToken,
  217. SECURITY_CONTEXT_DELETE_FUNCTION pFn,
  218. PVOID pArg,
  219. IIS_SSL_INFO *pSslInfo
  220. )
  221. /*++
  222. Routine Description:
  223. Store security context & impersonation token
  224. Arguments:
  225. pCtxt - SSPI security context
  226. hPrimaryToken - access token associated with security context
  227. pFn - function to call to notify security context destruction
  228. pArg - argument for pFn call
  229. pSslInfo - pointer to SSL info object to be used for this security context
  230. Return Value:
  231. TRUE on success, FALSE on failure
  232. --*/
  233. {
  234. if ( hPrimaryToken != NULL )
  235. {
  236. if ( _hSSPToken )
  237. {
  238. CloseHandle( _hSSPToken );
  239. _hSSPToken = NULL;
  240. }
  241. if ( _hSSPPrimaryToken )
  242. {
  243. CloseHandle( _hSSPPrimaryToken );
  244. _hSSPPrimaryToken = NULL;
  245. }
  246. AdjustTokenPrivileges( hPrimaryToken, TRUE, NULL, NULL, NULL, NULL );
  247. if ( g_pTokPrev )
  248. {
  249. AdjustTokenPrivileges( hPrimaryToken,
  250. FALSE,
  251. g_pTokPrev,
  252. NULL,
  253. NULL,
  254. NULL );
  255. }
  256. //
  257. // We need to convert the NTLM primary token into a
  258. // impersonation token
  259. //
  260. if ( !pfnDuplicateTokenEx( hPrimaryToken,
  261. TOKEN_ALL_ACCESS,
  262. NULL,
  263. SecurityImpersonation,
  264. TokenImpersonation,
  265. &_hSSPToken ))
  266. {
  267. DBGPRINTF(( DBG_CONTEXT,
  268. "[SetSecurityContextToken] DuplicateToken failed, error %lx\n",
  269. GetLastError() ));
  270. return FALSE;
  271. }
  272. // Bug 86498:
  273. // Grant all access to the token for "Everyone" so that ISAPIs that run out of proc
  274. // can do an OpenThreadToken call
  275. HRESULT hr;
  276. if (FAILED( hr = GrantAllAccessToToken( _hSSPToken ) ) )
  277. {
  278. DBG_ASSERT( FALSE );
  279. DBGPRINTF(( DBG_CONTEXT,
  280. "[SetSecurityContextToken] Failed to grant access to the token to everyone, error %lx\n",
  281. hr ));
  282. return FALSE;
  283. }
  284. _hSSPPrimaryToken = hPrimaryToken;
  285. _hctxt = *pCtxt;
  286. _fHaveCtxtHandle = TRUE;
  287. _pDeleteFunction = pFn;
  288. _pDeleteArg = pArg;
  289. }
  290. _phSslCtxt = pCtxt;
  291. if ( _pSslInfo )
  292. {
  293. IIS_SSL_INFO::Release( _pSslInfo );
  294. }
  295. _pSslInfo = pSslInfo;
  296. return TRUE;
  297. }
  298. BOOL
  299. TCP_AUTHENT::IsForwardable(
  300. VOID
  301. ) const
  302. /*++
  303. Routine Description:
  304. returns TRUE if auth info is forwardable ( e.g. kerberos )
  305. Arguments:
  306. None
  307. Return Value:
  308. TRUE if forwardable, otherwise FALSE
  309. --*/
  310. {
  311. return _fDelegate;
  312. }
  313. BOOL
  314. TCP_AUTHENT::IsSslCertPresent(
  315. )
  316. /*++
  317. Routine Description:
  318. Check if SSL cert bound on this security context
  319. Arguments:
  320. None
  321. Return Value:
  322. TRUE if SSL cert present, otherwise FALSE
  323. --*/
  324. {
  325. return _phSslCtxt != NULL;
  326. }
  327. static BOOL IsValidKeyUsageForClientCert(
  328. PCCERT_CONTEXT pCliCert
  329. )
  330. /*++
  331. Routine Description:
  332. private routine checkin extended key usage validity for client certificate
  333. Arguments:
  334. pCliCert - client certificate to be verified
  335. Return Value:
  336. TRUE if client cert usage is valid, otherwise FALSE
  337. in the case of any error FALSE is returned and GetLastError() can be used to
  338. retrieve the error code
  339. --*/
  340. {
  341. HRESULT hr = S_OK;
  342. BOOL fRet = TRUE;
  343. DWORD dwRet = ERROR_SUCCESS;
  344. const DWORD cbDefaultEnhKeyUsage = 100;
  345. STACK_BUFFER( buffEnhKeyUsage, cbDefaultEnhKeyUsage );
  346. PCERT_ENHKEY_USAGE pCertEnhKeyUsage = NULL;
  347. DWORD cbEnhKeyUsage = cbDefaultEnhKeyUsage;
  348. BOOL fEnablesClientAuth = FALSE;
  349. //
  350. // Now verify extended usage flags (only for the end certificate)
  351. //
  352. fRet = CertGetEnhancedKeyUsage( pCliCert,
  353. 0, //dwFlags,
  354. (PCERT_ENHKEY_USAGE) buffEnhKeyUsage.QueryPtr(),
  355. &cbEnhKeyUsage );
  356. dwRet = GetLastError();
  357. if ( !fRet && ( dwRet == ERROR_MORE_DATA ) )
  358. {
  359. //
  360. // Resize buffer
  361. //
  362. if ( !buffEnhKeyUsage.Resize( cbEnhKeyUsage ) )
  363. {
  364. dwRet = GetLastError();
  365. goto ExitPoint;
  366. }
  367. fRet = CertGetEnhancedKeyUsage( pCliCert,
  368. 0, //dwFlags,
  369. (PCERT_ENHKEY_USAGE) buffEnhKeyUsage.QueryPtr(),
  370. &cbEnhKeyUsage );
  371. dwRet = GetLastError();
  372. }
  373. if ( !fRet )
  374. {
  375. //
  376. // Bad. Couldn't get the Enhanced Key Usage
  377. //
  378. goto ExitPoint;
  379. }
  380. pCertEnhKeyUsage = (PCERT_ENHKEY_USAGE) buffEnhKeyUsage.QueryPtr();
  381. //
  382. // If the cUsageIdentifier member is zero (0), the certificate might be valid
  383. // for all uses or the certificate it might have no valid uses. The return from
  384. // a call to GetLastError can be used to determine whether the certificate is
  385. // good for all uses or for no uses. If GetLastError returns CRYPT_E_NOT_FOUND
  386. // if the certificate is good for all uses. If it returns zero (0), the
  387. // certificate has no valid uses
  388. //
  389. if ( pCertEnhKeyUsage->cUsageIdentifier == 0 )
  390. {
  391. if ( dwRet == CRYPT_E_NOT_FOUND )
  392. {
  393. //
  394. // Certificate valid for any use
  395. //
  396. fEnablesClientAuth = TRUE;
  397. }
  398. else
  399. {
  400. //
  401. // Certificate NOT valid for any use
  402. //
  403. }
  404. }
  405. else
  406. {
  407. //
  408. // Find out if pCertEnhKeyUsage enables CLIENT_AUTH
  409. //
  410. for ( DWORD i = 0; i < pCertEnhKeyUsage->cUsageIdentifier; i++ )
  411. {
  412. DBG_ASSERT( pCertEnhKeyUsage->rgpszUsageIdentifier[i] != NULL );
  413. if ( strcmp( pCertEnhKeyUsage->rgpszUsageIdentifier[i], szOID_PKIX_KP_CLIENT_AUTH ) == 0 )
  414. {
  415. //
  416. // certificate enables CLIENT_AUTH
  417. //
  418. fEnablesClientAuth = TRUE;
  419. break;
  420. }
  421. }
  422. }
  423. //
  424. // If ExtendedKeyUsage doesn't enable CLIENT_AUTH then add flag to CertFlags
  425. //
  426. ExitPoint:
  427. return fEnablesClientAuth;
  428. }
  429. BOOL
  430. TCP_AUTHENT::QueryCertificateInfo(
  431. LPBOOL pfNoCert
  432. )
  433. /*++
  434. Routine Description:
  435. Get certificate information from SSL security context
  436. Arguments:
  437. pfNoCert - updated with TRUE if no cert
  438. Return Value:
  439. TRUE on success, FALSE on failure
  440. --*/
  441. {
  442. SECURITY_STATUS ss;
  443. CERT_REVOCATION_STATUS CertRevocationStatus;
  444. SecPkgContext_RemoteCredentialInfo spRCI;
  445. HCERTCHAINENGINE hEngine = NULL;
  446. PCCERT_CHAIN_CONTEXT pCertChain = NULL;
  447. if ( _pClientCertContext != NULL )
  448. {
  449. *pfNoCert = FALSE;
  450. return TRUE;
  451. }
  452. //
  453. // NULL handle <==> no certificate
  454. //
  455. if ( _phSslCtxt == NULL || pfnFreeCertCtxt == NULL )
  456. {
  457. goto LNoCertificate;
  458. }
  459. //
  460. // Win95 <==> no certificate
  461. // NOTE Currently security.dll is not supported in Win95.
  462. //
  463. if ( TsIsWindows95() )
  464. {
  465. goto LNoCertificate;
  466. }
  467. //
  468. // get cert context - if null, we have no certificate
  469. //
  470. DBG_ASSERT( RtlValidateProcessHeaps() );
  471. ss = (pfnQueryContextAttributes)( _phSslCtxt,
  472. SECPKG_ATTR_REMOTE_CERT_CONTEXT,
  473. &_pClientCertContext );
  474. DBG_ASSERT( RtlValidateProcessHeaps() );
  475. if ( ss || _pClientCertContext == NULL ) {
  476. goto LNoCertificate;
  477. }
  478. //
  479. // Try to verify the client certificate
  480. //
  481. #if DBG
  482. CHAR szSubjectName[1024];
  483. if ( CertGetNameString( _pClientCertContext,
  484. CERT_NAME_SIMPLE_DISPLAY_TYPE,
  485. 0,
  486. NULL,
  487. szSubjectName,
  488. 1024 ) )
  489. {
  490. DBGPRINTF((DBG_CONTEXT,
  491. "Verifying client cert for %s \n",
  492. szSubjectName));
  493. }
  494. if ( CertGetNameString( _pClientCertContext,
  495. CERT_NAME_SIMPLE_DISPLAY_TYPE,
  496. CERT_NAME_ISSUER_FLAG,
  497. NULL,
  498. szSubjectName,
  499. 1024 ) )
  500. {
  501. DBGPRINTF((DBG_CONTEXT,
  502. "Client cert issued by %s \n",
  503. szSubjectName));
  504. }
  505. #endif
  506. _dwX509Flags = RCRED_CRED_EXISTS;
  507. if ( _pSslInfo && _pSslInfo->GetCertChainEngine( &hEngine ) )
  508. {
  509. //
  510. // Don't set any usage bits, because there are probably lots of certs floating
  511. // around out there with no usage bits and we don't want to break them
  512. //
  513. // CODEWORK : might want to consider adding eg MB flag that allows setting of
  514. // required usage bits on certs
  515. //
  516. DWORD dwRevocationFlags = 0;
  517. DWORD dwCacheFlags = 0;
  518. CERT_CHAIN_PARA CCP;
  519. memset( &CCP, 0, sizeof( CCP ) );
  520. CCP.cbSize = sizeof(CCP);
  521. DBG_ASSERT( RtlValidateProcessHeaps() );
  522. //
  523. // Determine the CertGetCertificateChain() flags related to revocation
  524. // checking and cache retrieval
  525. //
  526. dwRevocationFlags = ( _fCertCheckForRevocation
  527. || g_fCertCheckForRevocation )
  528. ? CERT_CHAIN_REVOCATION_CHECK_CHAIN : 0;
  529. dwCacheFlags = _fCertCheckCacheOnly
  530. ? CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY : 0;
  531. if ( CertGetCertificateChain( hEngine,
  532. _pClientCertContext,
  533. NULL,
  534. _pClientCertContext->hCertStore,
  535. &CCP,
  536. dwRevocationFlags | dwCacheFlags,
  537. NULL,
  538. &pCertChain ) )
  539. {
  540. //
  541. // Got a chain, look at the status bits and see whether we like it
  542. //
  543. DWORD dwChainStatus = pCertChain->TrustStatus.dwErrorStatus;
  544. if ( ( dwChainStatus & CERT_TRUST_IS_NOT_TIME_VALID ) ||
  545. ( dwChainStatus & CERT_TRUST_CTL_IS_NOT_TIME_VALID ) )
  546. {
  547. DBGPRINTF((DBG_CONTEXT,
  548. "Cert/CTL is not time-valid\n"));
  549. _dwX509Flags |= CRED_STATUS_INVALID_TIME;
  550. }
  551. if ( ( dwChainStatus & CERT_TRUST_IS_UNTRUSTED_ROOT ) ||
  552. ( dwChainStatus & CERT_TRUST_IS_PARTIAL_CHAIN ) )
  553. {
  554. //
  555. // If we sign our CTLs, then we should be able to construct a complete
  556. // chain up to a trusted root for valid client certs, so we just look at
  557. // the status bits of the chain.
  558. //
  559. // If our CTLs are not signed, we have to manually check whether the cert at the
  560. // top of the chain is in our CTL
  561. //
  562. #if SIGNED_CTL
  563. DBGPRINTF((DBG_CONTEXT,
  564. "Cert doesn't chain up to a trusted root\n"));
  565. _dwX509Flags |= RCRED_STATUS_UNKNOWN_ISSUER;
  566. #else //SIGNED_CTL
  567. PCERT_SIMPLE_CHAIN pSimpleChain = pCertChain->rgpChain[pCertChain->cChain - 1];
  568. PCERT_CHAIN_ELEMENT pChainElement =
  569. pSimpleChain->rgpElement[pSimpleChain->cElement - 1];
  570. PCCERT_CONTEXT pChainTop = pChainElement->pCertContext;
  571. BOOL fContains = FALSE;
  572. if ( !_pSslInfo->CTLContainsCert( pChainTop,
  573. &fContains ) ||
  574. !fContains )
  575. {
  576. _dwX509Flags |= RCRED_STATUS_UNKNOWN_ISSUER;
  577. }
  578. #endif //SIGNED_CTL
  579. }
  580. if ( ( dwChainStatus & CERT_TRUST_IS_NOT_SIGNATURE_VALID ) ||
  581. ( dwChainStatus & CERT_TRUST_CTL_IS_NOT_SIGNATURE_VALID ) ||
  582. ( !IsValidKeyUsageForClientCert(_pClientCertContext) ) )
  583. {
  584. DBGPRINTF((DBG_CONTEXT,
  585. "Cert/CTL is not signature valid\n"));
  586. //
  587. // if the signature has been tampered with, we'll just treat it
  588. // as an unknown issuer
  589. //
  590. _dwX509Flags |= RCRED_STATUS_UNKNOWN_ISSUER;
  591. }
  592. if ( dwChainStatus & CERT_TRUST_CTL_IS_NOT_VALID_FOR_USAGE )
  593. {
  594. DBGPRINTF((DBG_CONTEXT,
  595. "CTL isn't valid for usage\n"));
  596. }
  597. //
  598. // If we were supposed to check for revocation and we couldn't do so,
  599. // treat it as if it were revoked ... ?
  600. //
  601. if ( _fCertCheckForRevocation || g_fCertCheckForRevocation )
  602. {
  603. BOOL fRevoke = FALSE;
  604. if ( dwChainStatus & CERT_TRUST_IS_REVOKED )
  605. {
  606. fRevoke = TRUE;
  607. }
  608. else if ( dwChainStatus & CERT_TRUST_REVOCATION_STATUS_UNKNOWN )
  609. {
  610. PCERT_SIMPLE_CHAIN pSimpleChain;
  611. PCERT_CHAIN_ELEMENT pChainElement;
  612. PCERT_REVOCATION_INFO pRevocationInfo;
  613. DWORD dwCounter;
  614. pSimpleChain = pCertChain->rgpChain[ 0 ];
  615. for ( dwCounter = 0;
  616. dwCounter < pSimpleChain->cElement;
  617. dwCounter++ )
  618. {
  619. pChainElement = pSimpleChain->rgpElement[ dwCounter ];
  620. pRevocationInfo = pChainElement->pRevocationInfo;
  621. if ( pRevocationInfo &&
  622. ( ( pRevocationInfo->dwRevocationResult == CRYPT_E_REVOKED ) ||
  623. ( pRevocationInfo->dwRevocationResult != CRYPT_E_NO_REVOCATION_CHECK ) ) )
  624. {
  625. fRevoke = TRUE;
  626. break;
  627. }
  628. }
  629. }
  630. if ( fRevoke )
  631. {
  632. DBGPRINTF(( DBG_CONTEXT,
  633. "'Certificate revoked' or 'CRL needed but not found'\n" ));
  634. _dwX509Flags |= CRED_STATUS_REVOKED;
  635. }
  636. }
  637. CERT_CHAIN_POLICY_STATUS ChainPolicyStatus = {0};
  638. ChainPolicyStatus.cbSize = sizeof(ChainPolicyStatus);
  639. if ( CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_BASIC_CONSTRAINTS,
  640. pCertChain, NULL, &ChainPolicyStatus) )
  641. {
  642. if ( ChainPolicyStatus.dwError != NOERROR )
  643. _dwX509Flags |= RCRED_STATUS_UNKNOWN_ISSUER;
  644. }
  645. else
  646. {
  647. DBGPRINTF((DBG_CONTEXT,
  648. "Couldn't verify certificate chain basic constraints : 0x%d\n",
  649. GetLastError()));
  650. _dwX509Flags |= RCRED_STATUS_UNKNOWN_ISSUER;
  651. }
  652. CertFreeCertificateChain( pCertChain );
  653. pCertChain = NULL;
  654. }
  655. else
  656. {
  657. //
  658. // We don't know anything about the client cert, so treat it as being
  659. // issued by an unknown CA
  660. //
  661. DBGPRINTF((DBG_CONTEXT,
  662. "Couldn't get certificate chain : 0x%d\n",
  663. GetLastError()));
  664. _dwX509Flags |= RCRED_STATUS_UNKNOWN_ISSUER;
  665. }
  666. }
  667. else
  668. {
  669. //
  670. // We don't know anything about the client cert, so treat it as being issued by
  671. // an unknown CA
  672. //
  673. DBGPRINTF((DBG_CONTEXT,
  674. "Can't check anything about the client cert\n"));
  675. _dwX509Flags |= RCRED_STATUS_UNKNOWN_ISSUER;
  676. }
  677. DBG_ASSERT( RtlValidateProcessHeaps() );
  678. *pfNoCert = FALSE;
  679. return TRUE;
  680. LNoCertificate:
  681. *pfNoCert = TRUE;
  682. return FALSE;
  683. }
  684. BOOL
  685. TCP_AUTHENT::QueryServerCertificateInfo(
  686. LPBOOL pfNoCert
  687. )
  688. /*++
  689. Routine Description:
  690. Get servercertificate information from SSL security context
  691. Arguments:
  692. pfNoCert - updated with TRUE if no cert
  693. Return Value:
  694. TRUE on success, FALSE on failure
  695. --*/
  696. {
  697. SECURITY_STATUS ss;
  698. _SecPkgContext_LocalCredentialInfo spcRCI;
  699. if ( _pServerX509Certificate == NULL )
  700. {
  701. if ( _phSslCtxt == NULL
  702. || fnCrackCert == NULL
  703. || fnFreeCert == NULL )
  704. {
  705. *pfNoCert = TRUE;
  706. return FALSE;
  707. }
  708. ss = pfnQueryContextAttributes( _phSslCtxt,
  709. SECPKG_ATTR_LOCAL_CRED,
  710. &spcRCI );
  711. if ( ss != STATUS_SUCCESS || !spcRCI.cCertificates )
  712. {
  713. *pfNoCert = FALSE;
  714. SetLastError( ss );
  715. return FALSE;
  716. }
  717. if ( !(fnCrackCert)( spcRCI.pbCertificateChain,
  718. spcRCI.cbCertificateChain,
  719. 0,
  720. &_pServerX509Certificate ) )
  721. {
  722. pfnFreeContextBuffer(spcRCI.pbCertificateChain);
  723. *pfNoCert = FALSE;
  724. return FALSE;
  725. }
  726. _dwServerX509Flags = spcRCI.fFlags;
  727. _dwServerBitsInKey = spcRCI.dwBits;
  728. pfnFreeContextBuffer(spcRCI.pbCertificateChain);
  729. }
  730. return TRUE;
  731. }
  732. BOOL
  733. TCP_AUTHENT::QueryEncryptionKeySize(
  734. LPDWORD pdw,
  735. LPBOOL pfNoCert
  736. )
  737. /*++
  738. Routine Description:
  739. Get encryption session key size
  740. Arguments:
  741. pdw - updated with number of bits in key size
  742. pfNoCert - updated with TRUE if no cert
  743. Return Value:
  744. TRUE on success, FALSE on failure
  745. --*/
  746. {
  747. SecPkgContext_KeyInfo ski;
  748. SECURITY_STATUS ss;
  749. if ( _phSslCtxt == NULL )
  750. {
  751. *pfNoCert = TRUE;
  752. return FALSE;
  753. }
  754. ss = pfnQueryContextAttributes( _phSslCtxt,
  755. SECPKG_ATTR_KEY_INFO,
  756. &ski );
  757. if ( ss != STATUS_SUCCESS )
  758. {
  759. SetLastError( ss );
  760. *pfNoCert = FALSE;
  761. return FALSE;
  762. }
  763. *pdw = ski.KeySize;
  764. if ( ski.sSignatureAlgorithmName )
  765. {
  766. pfnFreeContextBuffer( ski.sSignatureAlgorithmName );
  767. }
  768. if ( ski.sEncryptAlgorithmName )
  769. {
  770. pfnFreeContextBuffer( ski.sEncryptAlgorithmName );
  771. }
  772. return TRUE;
  773. }
  774. BOOL
  775. TCP_AUTHENT::QueryEncryptionServerPrivateKeySize(
  776. LPDWORD pdw,
  777. LPBOOL pfNoCert
  778. )
  779. /*++
  780. Routine Description:
  781. Get encryption server private key size
  782. Arguments:
  783. pdw - updated with number of bits in key size
  784. pfNoCert - updated with TRUE if no cert
  785. Return Value:
  786. TRUE on success, FALSE on failure
  787. --*/
  788. {
  789. if ( QueryServerCertificateInfo( pfNoCert ) )
  790. {
  791. *pdw = _dwServerBitsInKey;
  792. return TRUE;
  793. }
  794. return FALSE;
  795. }
  796. BOOL
  797. TCP_AUTHENT::QueryServerCertificateIssuer(
  798. LPSTR* ppIssuer,
  799. LPBOOL pfNoCert
  800. )
  801. /*++
  802. Routine Description:
  803. Get server certificate Issuer information from SSL security context
  804. Arguments:
  805. ppIssuer - updated with ptr to Issuer name
  806. guaranteed to remain valid until auth Reset()
  807. pfNoCert - updated with TRUE if no cert
  808. Return Value:
  809. TRUE on success, FALSE on failure
  810. --*/
  811. {
  812. if ( QueryServerCertificateInfo( pfNoCert ) )
  813. {
  814. *ppIssuer = _pServerX509Certificate->pszIssuer;
  815. return TRUE;
  816. }
  817. return FALSE;
  818. }
  819. BOOL
  820. TCP_AUTHENT::QueryServerCertificateSubject(
  821. LPSTR* ppSubject,
  822. LPBOOL pfNoCert
  823. )
  824. /*++
  825. Routine Description:
  826. Get server certificate Subject information from SSL security context
  827. Arguments:
  828. ppSubject - updated with ptr to Subject name
  829. guaranteed to remain valid until auth Reset()
  830. pfNoCert - updated with TRUE if no cert
  831. Return Value:
  832. TRUE on success, FALSE on failure
  833. --*/
  834. {
  835. if ( QueryServerCertificateInfo( pfNoCert ) )
  836. {
  837. *ppSubject = _pServerX509Certificate->pszSubject;
  838. return TRUE;
  839. }
  840. return FALSE;
  841. }
  842. BOOL
  843. TCP_AUTHENT::QueryCertificateIssuer(
  844. LPSTR pIssuer,
  845. DWORD dwIssuerMaxLen,
  846. LPBOOL pfNoCert
  847. )
  848. /*++
  849. Routine Description:
  850. Get certificate Issuer information from SSL security context
  851. Arguments:
  852. pIssuer - ptr to buffer filled with Issuer name
  853. dwIssuerMaxLen - size of pIssuer
  854. pfNoCert - updated with TRUE if no cert
  855. Return Value:
  856. TRUE on success, FALSE on failure
  857. --*/
  858. {
  859. if ( QueryCertificateInfo( pfNoCert) && pfnCertNameToStrA )
  860. {
  861. pfnCertNameToStrA( _pClientCertContext->dwCertEncodingType,
  862. &_pClientCertContext->pCertInfo->Issuer,
  863. CERT_X500_NAME_STR,
  864. pIssuer,
  865. dwIssuerMaxLen );
  866. return TRUE;
  867. }
  868. return FALSE;
  869. }
  870. BOOL
  871. TCP_AUTHENT::QueryCertificateFlags(
  872. LPDWORD pdwFlags,
  873. LPBOOL pfNoCert
  874. )
  875. /*++
  876. Routine Description:
  877. Get certificate flags information from SSL security context
  878. Arguments:
  879. pdwFlags - updated with certificate flags
  880. pfNoCert - updated with TRUE if no cert
  881. Return Value:
  882. TRUE on success, FALSE on failure
  883. --*/
  884. {
  885. if ( QueryCertificateInfo( pfNoCert ) )
  886. {
  887. *pdwFlags = _dwX509Flags;
  888. return TRUE;
  889. }
  890. return FALSE;
  891. }
  892. BOOL
  893. TCP_AUTHENT::QueryCertificateSubject(
  894. LPSTR pSubject,
  895. DWORD dwSubjectMaxLen,
  896. LPBOOL pfNoCert
  897. )
  898. /*++
  899. Routine Description:
  900. Get certificate Subject information from SSL security context
  901. Arguments:
  902. ppSubject - updated with ptr to Subject name
  903. guaranteed to remain valid until auth Reset()
  904. pfNoCert - updated with TRUE if no cert
  905. Return Value:
  906. TRUE on success, FALSE on failure
  907. --*/
  908. {
  909. if ( QueryCertificateInfo( pfNoCert) && pfnCertNameToStrA )
  910. {
  911. pfnCertNameToStrA( _pClientCertContext->dwCertEncodingType,
  912. &_pClientCertContext->pCertInfo->Subject,
  913. CERT_X500_NAME_STR,
  914. pSubject,
  915. dwSubjectMaxLen );
  916. return TRUE;
  917. }
  918. return FALSE;
  919. }
  920. BOOL
  921. TCP_AUTHENT::QueryCertificateSerialNumber(
  922. LPBYTE* ppSerialNumber,
  923. LPDWORD pdwLen,
  924. LPBOOL pfNoCert
  925. )
  926. /*++
  927. Routine Description:
  928. Get certificate serial number information from SSL security context
  929. Arguments:
  930. ppSerialNumber - updated with ptr to serial number as
  931. array of bytes
  932. guaranteed to remain valid until auth Reset()
  933. pdwLen - length of serial number
  934. pfNoCert - updated with TRUE if no cert
  935. Return Value:
  936. TRUE on success, FALSE on failure
  937. --*/
  938. {
  939. if ( QueryCertificateInfo( pfNoCert ) )
  940. {
  941. *ppSerialNumber = _pClientCertContext->pCertInfo->SerialNumber.pbData;
  942. *pdwLen = _pClientCertContext->pCertInfo->SerialNumber.cbData;
  943. return TRUE;
  944. }
  945. return FALSE;
  946. }
  947. HANDLE
  948. TCP_AUTHENT::QueryPrimaryToken(
  949. VOID
  950. )
  951. /*++
  952. Routine Description:
  953. Returns a non-impersonated token suitable for use with CreateProcessAsUser
  954. --*/
  955. {
  956. SECURITY_STATUS sc;
  957. if ( _hToken && _fClearText )
  958. {
  959. return CTO_TO_TOKEN( _hToken );
  960. }
  961. else if ( _fHaveAccessTokens )
  962. {
  963. return _hSSPPrimaryToken;
  964. }
  965. else if ( _fHaveCtxtHandle )
  966. {
  967. if ( !_hSSPPrimaryToken )
  968. {
  969. if ( !_hSSPToken )
  970. {
  971. sc = pfnQuerySecurityContextToken( &_hctxt,
  972. &_hSSPToken );
  973. if ( !NT_SUCCESS( sc ))
  974. {
  975. DBGPRINTF(( DBG_CONTEXT,
  976. "[QueryPrimaryToken] QuerySecurityContext failed, error 0x%lx\n",
  977. sc ));
  978. SetLastError( sc );
  979. return NULL;
  980. }
  981. // Bug 86498:
  982. // Grant all access to the token for "Everyone" so that ISAPIs that run out of proc
  983. // can do an OpenThreadToken call
  984. HRESULT hr;
  985. if (FAILED( hr = GrantAllAccessToToken( _hSSPToken ) ) )
  986. {
  987. DBG_ASSERT( FALSE );
  988. DBGPRINTF(( DBG_CONTEXT,
  989. "[QueryPrimaryToken] Failed to grant access to the token to everyone, error %lx\n",
  990. hr ));
  991. return FALSE;
  992. }
  993. AdjustTokenPrivileges( _hSSPToken, TRUE, NULL, NULL, NULL, NULL );
  994. if ( g_pTokPrev )
  995. {
  996. AdjustTokenPrivileges( _hSSPToken,
  997. FALSE,
  998. g_pTokPrev,
  999. NULL,
  1000. NULL,
  1001. NULL );
  1002. }
  1003. }
  1004. //
  1005. // We need to convert the NTLM impersonation token into a
  1006. // primary token
  1007. //
  1008. if ( !pfnDuplicateTokenEx( _hSSPToken,
  1009. TOKEN_ALL_ACCESS,
  1010. NULL,
  1011. SecurityImpersonation,
  1012. TokenPrimary,
  1013. &_hSSPPrimaryToken ))
  1014. {
  1015. DBGPRINTF(( DBG_CONTEXT,
  1016. "[QueryPrimaryToken] DuplicateToken failed, error %lx\n",
  1017. GetLastError() ));
  1018. }
  1019. }
  1020. return _hSSPPrimaryToken;
  1021. }
  1022. SetLastError( ERROR_INVALID_HANDLE );
  1023. return NULL;
  1024. }
  1025. HANDLE
  1026. TCP_AUTHENT::QueryImpersonationToken(
  1027. VOID
  1028. )
  1029. /*++
  1030. Routine Description:
  1031. Returns an impersonation token for use with APIs like AccessCheck.
  1032. --*/
  1033. {
  1034. SECURITY_STATUS sc;
  1035. if ( _hToken == (TS_TOKEN)BOGUS_WIN95_TOKEN ) {
  1036. return((HANDLE)BOGUS_WIN95_TOKEN);
  1037. }
  1038. if ( _hToken && _fClearText )
  1039. {
  1040. return ((CACHED_TOKEN *) _hToken)->QueryImpersonationToken();
  1041. }
  1042. else if ( _fHaveAccessTokens )
  1043. {
  1044. return _hSSPToken;
  1045. }
  1046. else if ( _fHaveCtxtHandle )
  1047. {
  1048. //
  1049. // We don't need to impersonate since this is already an impersonation
  1050. // token
  1051. //
  1052. if ( !_hSSPToken )
  1053. {
  1054. sc = pfnQuerySecurityContextToken( &_hctxt,
  1055. &_hSSPToken );
  1056. if ( !NT_SUCCESS( sc ))
  1057. {
  1058. DBGPRINTF(( DBG_CONTEXT,
  1059. "[QueryImpersonationToken] QuerySecurityContext failed, error 0x%lx\n",
  1060. sc ));
  1061. SetLastError( sc );
  1062. return NULL;
  1063. }
  1064. // Bug 86498:
  1065. // Grant all access to the token for "Everyone" so that ISAPIs that run out of proc
  1066. // can do an OpenThreadToken call
  1067. HRESULT hr;
  1068. if (FAILED( hr = GrantAllAccessToToken( _hSSPToken ) ) )
  1069. {
  1070. DBG_ASSERT( FALSE );
  1071. DBGPRINTF(( DBG_CONTEXT,
  1072. "[QueryImpersonationToken] Failed to grant access to the token to everyone, error %lx\n",
  1073. hr ));
  1074. return NULL;
  1075. }
  1076. AdjustTokenPrivileges( _hSSPToken, TRUE, NULL, NULL, NULL, NULL );
  1077. if ( g_pTokPrev )
  1078. {
  1079. AdjustTokenPrivileges( _hSSPToken,
  1080. FALSE,
  1081. g_pTokPrev,
  1082. NULL,
  1083. NULL,
  1084. NULL );
  1085. }
  1086. }
  1087. return _hSSPToken;
  1088. }
  1089. SetLastError( ERROR_INVALID_HANDLE );
  1090. return NULL;
  1091. }
  1092. BOOL
  1093. TCP_AUTHENT::IsGuest(
  1094. BOOL fIsImpersonated
  1095. )
  1096. /*++
  1097. Routine Description:
  1098. Returns TRUE if the account is the guest account
  1099. --*/
  1100. {
  1101. fIsImpersonated; // Unreferenced variable
  1102. if ( _fHaveCtxtHandle )
  1103. {
  1104. return _fKnownToBeGuest;
  1105. }
  1106. return IsGuestUser( GetUserHandle() );
  1107. }
  1108. BOOL TCP_AUTHENT::EnumAuthPackages(
  1109. BUFFER * pBuff
  1110. )
  1111. /*++
  1112. Routine Description:
  1113. Places a double null terminated list of authentication packages on the
  1114. system in pBuff that looks like:
  1115. NTLM\0
  1116. MSKerberos\0
  1117. Netware\0
  1118. \0
  1119. Arguments:
  1120. pBuff - Buffer to receive list
  1121. Return Value:
  1122. TRUE if successful, FALSE otherwise (call GetLastError)
  1123. --*/
  1124. {
  1125. SECURITY_STATUS ss;
  1126. PSecPkgInfo pPackageInfo = NULL;
  1127. ULONG cPackages;
  1128. ULONG i;
  1129. ULONG fCaps;
  1130. DWORD cbBuffNew = 0;
  1131. DWORD cbBuffOld = 0;
  1132. if ( !pBuff->Resize( 64 ) )
  1133. return FALSE;
  1134. //
  1135. // Get the list of security packages on this machine
  1136. //
  1137. ss = pfnEnumerateSecurityPackages( &cPackages,
  1138. &pPackageInfo );
  1139. if ( ss != STATUS_SUCCESS )
  1140. {
  1141. DBGPRINTF(( DBG_CONTEXT,
  1142. "[EnumAuthPackages] Failed with error %d\n",
  1143. ss ));
  1144. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  1145. return FALSE;
  1146. }
  1147. for ( i = 0; i < cPackages ; i++ )
  1148. {
  1149. //
  1150. // We'll only use the security package if it supports connection
  1151. // oriented security and it supports the appropriate side (client
  1152. // or server)
  1153. //
  1154. fCaps = pPackageInfo[i].fCapabilities;
  1155. if ( fCaps & SECPKG_FLAG_CONNECTION )
  1156. {
  1157. if ( (fCaps & SECPKG_FLAG_CLIENT_ONLY) && !_fClient )
  1158. continue;
  1159. cbBuffNew += strlen( pPackageInfo[i].Name ) + 1;
  1160. if ( pBuff->QuerySize() < cbBuffNew )
  1161. {
  1162. if ( !pBuff->Resize( cbBuffNew + 64 ))
  1163. {
  1164. pfnFreeContextBuffer( pPackageInfo );
  1165. return FALSE;
  1166. }
  1167. }
  1168. strcpy( (CHAR *)pBuff->QueryPtr() + cbBuffOld,
  1169. pPackageInfo[i].Name );
  1170. cbBuffOld = cbBuffNew;
  1171. }
  1172. }
  1173. *((CHAR *)pBuff->QueryPtr() + cbBuffOld) = '\0';
  1174. pfnFreeContextBuffer( pPackageInfo );
  1175. return TRUE;
  1176. } // EnumAuthPackages
  1177. BOOL
  1178. TCP_AUTHENT::QueryExpiry(
  1179. PTimeStamp pExpiry
  1180. )
  1181. /*++
  1182. Routine Description:
  1183. Queries the expiration date/time for a SSPI logon
  1184. Arguments:
  1185. pExpiry - ptr to buffer to update with expiration date
  1186. Return Value:
  1187. TRUE if successful, FALSE if not available
  1188. --*/
  1189. {
  1190. SECURITY_STATUS ss;
  1191. SecPkgContext_PasswordExpiry speExpiry;
  1192. if ( _fHaveCtxtHandle && !_pDeleteFunction )
  1193. {
  1194. ss = pfnQueryContextAttributes( &_hctxt,
  1195. SECPKG_ATTR_PASSWORD_EXPIRY,
  1196. &speExpiry );
  1197. if ( ss != STATUS_SUCCESS )
  1198. {
  1199. ((LARGE_INTEGER*)pExpiry)->HighPart = 0x7fffffff;
  1200. ((LARGE_INTEGER*)pExpiry)->LowPart = 0xffffffff;
  1201. SetLastError( ss );
  1202. return FALSE;
  1203. }
  1204. memcpy( pExpiry,
  1205. &speExpiry.tsPasswordExpires,
  1206. sizeof(speExpiry.tsPasswordExpires) );
  1207. return TRUE;
  1208. }
  1209. else if ( _fHaveExpiry )
  1210. {
  1211. memcpy( pExpiry, (LPVOID)&_liPwdExpiry, sizeof(_liPwdExpiry) );
  1212. return TRUE;
  1213. }
  1214. else
  1215. {
  1216. return FALSE;
  1217. }
  1218. }
  1219. BOOL
  1220. TCP_AUTHENT::QueryFullyQualifiedUserName(
  1221. LPSTR pszUser,
  1222. STR * pstrU,
  1223. PIIS_SERVER_INSTANCE psi,
  1224. PTCP_AUTHENT_INFO pTAI
  1225. )
  1226. /*++
  1227. Routine Description:
  1228. Get fully qualified user name ( domain \ user name )
  1229. Arguments:
  1230. pszUser - user name ( prefixed by optional domain )
  1231. strU - string updated with fully qualified name
  1232. psi - server instance data
  1233. Return Value:
  1234. TRUE if successful, FALSE otherwise
  1235. --*/
  1236. {
  1237. CHAR szDomainAndUser[IIS_DNLEN+UNLEN+2];
  1238. //
  1239. // Empty user defaults to the anonymous user
  1240. //
  1241. if ( !pszUser || *pszUser == '\0' )
  1242. {
  1243. return FALSE;
  1244. }
  1245. //
  1246. // Validate parameters & state.
  1247. //
  1248. if ( strlen( pszUser ) >= sizeof( szDomainAndUser ) )
  1249. {
  1250. SetLastError( ERROR_INSUFFICIENT_BUFFER );
  1251. return FALSE;
  1252. }
  1253. //
  1254. // Save a copy of the domain\user so we can squirrel around
  1255. // with it a bit.
  1256. //
  1257. int cL = 0;
  1258. //
  1259. // prepend default logon domain if no domain
  1260. // and the default user name was not used
  1261. //
  1262. if ( strchr( pszUser, '/' ) == NULL
  1263. #if 1 // DBCS enabling for user name
  1264. && _mbschr( (PUCHAR)pszUser, '\\' ) == NULL )
  1265. #else
  1266. && strchr( pszUser, '\\' ) == NULL )
  1267. #endif
  1268. {
  1269. psi->LockThisForRead();
  1270. PCSTR pD = pTAI->strDefaultLogonDomain.QueryStr();
  1271. PCSTR pL;
  1272. if ( pD != NULL && pD[0] != '\0' )
  1273. {
  1274. #if 1 // DBCS enabling for user name
  1275. if ( ( pL = (PCHAR)_mbschr( (PUCHAR)pD, '\\' ) ) )
  1276. #else
  1277. if ( ( pL = strchr( pD, '\\' ) ) )
  1278. #endif
  1279. {
  1280. cL = DIFF(pL - pD);
  1281. }
  1282. else
  1283. {
  1284. cL = strlen( pD );
  1285. }
  1286. memcpy( szDomainAndUser, pD, cL );
  1287. szDomainAndUser[ cL++ ] = '\\';
  1288. }
  1289. else
  1290. {
  1291. DWORD dwL = DNLEN + 1;
  1292. if ( GetComputerName( szDomainAndUser, &dwL ) )
  1293. {
  1294. cL = dwL;
  1295. szDomainAndUser[ cL++ ] = '\\';
  1296. }
  1297. }
  1298. psi->UnlockThis();
  1299. }
  1300. strcpy( szDomainAndUser + cL, pszUser );
  1301. return pstrU->Copy( (TCHAR*)szDomainAndUser );
  1302. }
  1303. BOOL
  1304. TCP_AUTHENT::QueryUserName(
  1305. STR * pBuff,
  1306. BOOL fImpersonated
  1307. )
  1308. /*++
  1309. Routine Description:
  1310. Queries the name associated with this *authenticated* object
  1311. Arguments:
  1312. pBuff - Buffer to receive name
  1313. Return Value:
  1314. TRUE if successful, FALSE otherwise (call GetLastError)
  1315. --*/
  1316. {
  1317. SECURITY_STATUS ss;
  1318. DWORD cbName;
  1319. SecPkgContext_Names CredNames;
  1320. UINT l;
  1321. if ( _pDeleteFunction )
  1322. {
  1323. //
  1324. // this context is bound to a SSL/PCT client certificate
  1325. // SECPKG_ATTR_NAMES returns certificate info in this case,
  1326. // 1st try SECPKG_ATTR_MAPNAMES. If fails, use GetUserName()
  1327. //
  1328. #if defined(SECPKG_ATTR_MAPNAMES)
  1329. if ( _fHaveCtxtHandle )
  1330. {
  1331. ss = pfnQueryContextAttributes( &_hctxt,
  1332. SECPKG_ATTR_MAPNAMES,
  1333. &CredNames );
  1334. if ( ss == STATUS_SUCCESS )
  1335. {
  1336. cbName = strlen( CredNames.sUserName ) + 1;
  1337. if ( !pBuff->Resize( cbName ))
  1338. {
  1339. LocalFree( CredNames.sUserName );
  1340. return FALSE;
  1341. }
  1342. memcpy( pBuff->QueryPtr(), CredNames.sUserName, cbName );
  1343. pBuff->SetLen( cbName - 1 );
  1344. LocalFree( CredNames.sUserName );
  1345. return TRUE;
  1346. }
  1347. }
  1348. #endif
  1349. if ( !fImpersonated && !Impersonate() )
  1350. {
  1351. return FALSE;
  1352. }
  1353. DWORD cL = pBuff->QuerySize();
  1354. BOOL fSt = TRUE;
  1355. if ( !GetUserName( (LPTSTR)pBuff->QueryPtr(), &cL ) )
  1356. {
  1357. if ( fSt = pBuff->Resize( cL ) )
  1358. {
  1359. fSt = GetUserName( (LPTSTR)pBuff->QueryPtr(), &cL );
  1360. }
  1361. }
  1362. //
  1363. // Add domain name if not present
  1364. //
  1365. #if 1 // DBCS enabling for user name
  1366. if ( fSt && _mbschr( (PUCHAR)pBuff->QueryPtr(), '\\') == NULL )
  1367. #else
  1368. if ( fSt && strchr( (LPSTR)pBuff->QueryPtr(), '\\') == NULL )
  1369. #endif
  1370. {
  1371. cL = strlen(g_achComputerName);
  1372. if ( pBuff->Resize( l=(cL+1+strlen((LPSTR)pBuff->QueryPtr()))+1 ) )
  1373. {
  1374. memmove( (LPBYTE)pBuff->QueryPtr()+cL+1,
  1375. pBuff->QueryPtr(),
  1376. strlen((LPSTR)pBuff->QueryPtr())+sizeof(CHAR) );
  1377. memcpy( pBuff->QueryPtr(), g_achComputerName, cL );
  1378. ((LPBYTE)pBuff->QueryPtr())[cL] = '\\';
  1379. pBuff->SetLen( l );
  1380. }
  1381. }
  1382. if ( !fImpersonated )
  1383. {
  1384. RevertToSelf();
  1385. }
  1386. return fSt;
  1387. }
  1388. else
  1389. {
  1390. if ( _fHaveCtxtHandle )
  1391. {
  1392. ss = pfnQueryContextAttributes( &_hctxt,
  1393. SECPKG_ATTR_NAMES,
  1394. &CredNames );
  1395. }
  1396. else
  1397. {
  1398. ss = ERROR_INVALID_HANDLE;
  1399. }
  1400. if ( ss != STATUS_SUCCESS )
  1401. {
  1402. SetLastError( ss );
  1403. return FALSE;
  1404. }
  1405. cbName = strlen( CredNames.sUserName ) + 1;
  1406. if ( !pBuff->Resize( cbName ))
  1407. {
  1408. pfnFreeContextBuffer( CredNames.sUserName );
  1409. return FALSE;
  1410. }
  1411. memcpy( pBuff->QueryPtr(), CredNames.sUserName, cbName );
  1412. pBuff->SetLen( cbName - 1 );
  1413. pfnFreeContextBuffer( CredNames.sUserName );
  1414. }
  1415. return TRUE;
  1416. }
  1417. /*******************************************************************/
  1418. BOOL TCP_AUTHENT::Converse(
  1419. VOID * pBuffIn,
  1420. DWORD cbBuffIn,
  1421. BUFFER * pbuffOut,
  1422. DWORD * pcbBuffOut,
  1423. BOOL * pfNeedMoreData,
  1424. PTCP_AUTHENT_INFO pTAI,
  1425. CHAR * pszPackage,
  1426. CHAR * pszUser,
  1427. CHAR * pszPassword,
  1428. PIIS_SERVER_INSTANCE psi
  1429. )
  1430. /*++
  1431. Routine Description:
  1432. Initiates or continues a previously initiated authentication conversation
  1433. Client calls this first to get the negotiation message which
  1434. it then sends to the server. The server calls this with the
  1435. client result and sends back the result. The conversation
  1436. continues until *pfNeedMoreData is FALSE.
  1437. On the first call, pszPackage must point to the zero terminated
  1438. authentication package name to be used and pszUser and pszPassword
  1439. should point to the user name and password to authenticated with
  1440. on the client side (server side will always be NULL).
  1441. Arguments:
  1442. pBuffIn - Points to SSP message received from the
  1443. client. If TCPAUTH_UUENCODE is used, then this must point to a
  1444. zero terminated uuencoded string (except for the first call).
  1445. cbBuffIn - Number of bytes in pBuffIn or zero if pBuffIn points to a
  1446. zero terminated, uuencoded string.
  1447. pbuffOut - If *pfDone is not set to TRUE, this buffer contains the data
  1448. that should be sent to the other side. If this is zero, then no
  1449. data needs to be sent.
  1450. pcbBuffOut - Number of bytes in pbuffOut
  1451. pfNeedMoreData - Set to TRUE while this side of the conversation is
  1452. expecting more data from the remote side.
  1453. pszPackage - On the first call points to a zero terminate string indicating
  1454. the security package to use
  1455. pszUser - Specifies user or domain\user the first time the client calls
  1456. this method (client side only)
  1457. pszPassword - Specifies the password for pszUser the first time the
  1458. client calls this method (client side only)
  1459. Return Value:
  1460. TRUE if successful, FALSE otherwise (call GetLastError). Access is
  1461. denied if FALSE is returned and GetLastError is ERROR_ACCESS_DENIED.
  1462. --*/
  1463. {
  1464. SECURITY_STATUS ss;
  1465. TimeStamp Lifetime;
  1466. SecBufferDesc OutBuffDesc;
  1467. SecBuffer OutSecBuff;
  1468. SecBufferDesc InBuffDesc;
  1469. SecBuffer InSecBuff;
  1470. ULONG ContextAttributes;
  1471. BUFFER buffData;
  1472. BUFFER buff;
  1473. STACK_STR ( strDefaultLogonDomain, IIS_DNLEN+1 );
  1474. //
  1475. // Decode the data if there's something to decode
  1476. //
  1477. if ( _fUUEncodeData &&
  1478. pBuffIn &&
  1479. PackageSupportsEncoding( pszPackage ) )
  1480. {
  1481. if ( !uudecode( (CHAR *) pBuffIn,
  1482. &buffData,
  1483. &cbBuffIn,
  1484. _fBase64
  1485. ))
  1486. {
  1487. return FALSE;
  1488. }
  1489. pBuffIn = buffData.QueryPtr();
  1490. }
  1491. //
  1492. // If this is a new conversation, then we need to get the credential
  1493. // handle and find out the maximum token size
  1494. //
  1495. if ( _fNewConversation )
  1496. {
  1497. if ( !_fClient )
  1498. {
  1499. if ( !CACHED_CREDENTIAL::GetCredential(
  1500. pszPackage,
  1501. psi,
  1502. pTAI,
  1503. &_hcred,
  1504. &_cbMaxToken ) )
  1505. {
  1506. return FALSE;
  1507. }
  1508. }
  1509. else
  1510. {
  1511. SecPkgInfo * pspkg;
  1512. SEC_WINNT_AUTH_IDENTITY AuthIdentity;
  1513. SEC_WINNT_AUTH_IDENTITY * pAuthIdentity;
  1514. CHAR * pszDomain = NULL;
  1515. CHAR szDomainAndUser[IIS_DNLEN+UNLEN+2];
  1516. //
  1517. // If this is the client and a username and password were
  1518. // specified, then fill out the authentication information
  1519. //
  1520. if ( _fClient &&
  1521. ((pszUser != NULL) ||
  1522. (pszPassword != NULL)) )
  1523. {
  1524. pAuthIdentity = &AuthIdentity;
  1525. //
  1526. // Break out the domain from the username if one was specified
  1527. //
  1528. if ( pszUser != NULL )
  1529. {
  1530. strcpy( szDomainAndUser, pszUser );
  1531. if ( !CrackUserAndDomain( szDomainAndUser,
  1532. &pszUser,
  1533. &pszDomain ))
  1534. {
  1535. return FALSE;
  1536. }
  1537. }
  1538. memset( &AuthIdentity,
  1539. 0,
  1540. sizeof( AuthIdentity ));
  1541. if ( pszUser != NULL )
  1542. {
  1543. AuthIdentity.User = (unsigned char *) pszUser;
  1544. AuthIdentity.UserLength = strlen( pszUser );
  1545. }
  1546. if ( pszPassword != NULL )
  1547. {
  1548. AuthIdentity.Password = (unsigned char *) pszPassword;
  1549. AuthIdentity.PasswordLength = strlen( pszPassword );
  1550. }
  1551. if ( pszDomain != NULL )
  1552. {
  1553. AuthIdentity.Domain = (unsigned char *) pszDomain;
  1554. AuthIdentity.DomainLength = strlen( pszDomain );
  1555. }
  1556. AuthIdentity.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
  1557. }
  1558. else
  1559. {
  1560. //
  1561. // provide default logon domain
  1562. //
  1563. if ( psi == NULL )
  1564. {
  1565. pAuthIdentity = NULL;
  1566. }
  1567. else
  1568. {
  1569. pAuthIdentity = &AuthIdentity;
  1570. memset( &AuthIdentity,
  1571. 0,
  1572. sizeof( AuthIdentity ));
  1573. if ( pTAI->strDefaultLogonDomain.QueryCCH() <= IIS_DNLEN )
  1574. {
  1575. strDefaultLogonDomain.Copy( pTAI->strDefaultLogonDomain );
  1576. AuthIdentity.Domain = (LPBYTE)strDefaultLogonDomain.QueryStr();
  1577. }
  1578. if ( AuthIdentity.Domain != NULL )
  1579. {
  1580. if ( AuthIdentity.DomainLength =
  1581. strlen( (LPCTSTR)AuthIdentity.Domain ) )
  1582. {
  1583. // remove trailing '\\' if present
  1584. if ( AuthIdentity.Domain[AuthIdentity.DomainLength-1]
  1585. == '\\' )
  1586. {
  1587. --AuthIdentity.DomainLength;
  1588. }
  1589. }
  1590. }
  1591. if ( AuthIdentity.DomainLength == 0 )
  1592. {
  1593. pAuthIdentity = NULL;
  1594. }
  1595. else
  1596. {
  1597. AuthIdentity.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
  1598. }
  1599. }
  1600. }
  1601. ss = pfnAcquireCredentialsHandle( NULL, // New principal
  1602. pszPackage, // Package name
  1603. (_fClient ? SECPKG_CRED_OUTBOUND :
  1604. SECPKG_CRED_INBOUND),
  1605. NULL, // Logon ID
  1606. pAuthIdentity, // Auth Data
  1607. NULL, // Get key func
  1608. NULL, // Get key arg
  1609. &_hcred,
  1610. &Lifetime );
  1611. //
  1612. // Need to determine the max token size for this package
  1613. //
  1614. if ( ss == STATUS_SUCCESS )
  1615. {
  1616. _fHaveCredHandle = TRUE;
  1617. ss = pfnQuerySecurityPackageInfo( (char *) pszPackage,
  1618. &pspkg );
  1619. }
  1620. if ( ss != STATUS_SUCCESS )
  1621. {
  1622. DBGPRINTF(( DBG_CONTEXT,
  1623. "[Converse] AcquireCredentialsHandle or QuerySecurityPackageInfo failed, error %d\n",
  1624. ss ));
  1625. SetLastError( ss );
  1626. return FALSE;
  1627. }
  1628. _cbMaxToken = pspkg->cbMaxToken;
  1629. DBG_ASSERT( pspkg->fCapabilities & SECPKG_FLAG_CONNECTION );
  1630. pfnFreeContextBuffer( pspkg );
  1631. }
  1632. }
  1633. //
  1634. // Prepare our output buffer. We use a temporary buffer because
  1635. // the real output buffer will most likely need to be uuencoded
  1636. //
  1637. if ( !buff.Resize( _cbMaxToken ))
  1638. return FALSE;
  1639. OutBuffDesc.ulVersion = 0;
  1640. OutBuffDesc.cBuffers = 1;
  1641. OutBuffDesc.pBuffers = &OutSecBuff;
  1642. OutSecBuff.cbBuffer = _cbMaxToken;
  1643. OutSecBuff.BufferType = SECBUFFER_TOKEN;
  1644. OutSecBuff.pvBuffer = buff.QueryPtr();
  1645. //
  1646. // Prepare our Input buffer - Note the server is expecting the client's
  1647. // negotiation packet on the first call
  1648. //
  1649. if ( pBuffIn )
  1650. {
  1651. InBuffDesc.ulVersion = 0;
  1652. InBuffDesc.cBuffers = 1;
  1653. InBuffDesc.pBuffers = &InSecBuff;
  1654. InSecBuff.cbBuffer = cbBuffIn;
  1655. InSecBuff.BufferType = SECBUFFER_TOKEN;
  1656. InSecBuff.pvBuffer = pBuffIn;
  1657. }
  1658. //
  1659. // Client side uses InitializeSecurityContext, server side uses
  1660. // AcceptSecurityContext
  1661. //
  1662. if ( _fClient )
  1663. {
  1664. //
  1665. // Note the client will return success when its done but we still
  1666. // need to send the out buffer if there are bytes to send
  1667. //
  1668. ss = pfnInitializeSecurityContext( &_hcred,
  1669. _fNewConversation ? NULL :
  1670. &_hctxt,
  1671. _strTarget.IsEmpty() ?
  1672. TCPAUTH_TARGET_NAME :
  1673. _strTarget.QueryStr(),
  1674. 0,
  1675. 0,
  1676. SECURITY_NATIVE_DREP,
  1677. _fNewConversation ? NULL :
  1678. &InBuffDesc,
  1679. 0,
  1680. &_hctxt,
  1681. &OutBuffDesc,
  1682. &ContextAttributes,
  1683. &Lifetime );
  1684. }
  1685. else
  1686. {
  1687. //
  1688. // This is the server side
  1689. //
  1690. SetLastError ( 0 );
  1691. ss = pfnAcceptSecurityContext( &_hcred,
  1692. _fNewConversation ? NULL :
  1693. &_hctxt,
  1694. &InBuffDesc,
  1695. ASC_REQ_EXTENDED_ERROR,
  1696. SECURITY_NATIVE_DREP,
  1697. &_hctxt,
  1698. &OutBuffDesc,
  1699. &ContextAttributes,
  1700. &Lifetime );
  1701. }
  1702. if ( !NT_SUCCESS( ss ) )
  1703. {
  1704. DBGPRINTF(( DBG_CONTEXT,
  1705. "[Converse] Initialize/AcceptCredentialsHandle failed, error %d\n",
  1706. ss ));
  1707. if ( !_fNewConversation )
  1708. {
  1709. //
  1710. // If not a new conversation, then when we fail we still have a context
  1711. // handle from previous to AcceptSecurityContext. Need to call
  1712. // DeleteSecurityContext to avoid leaking the context.
  1713. // AcceptSecurityContext does not touch _hctxt if it fails.
  1714. //
  1715. DBG_ASSERT( _fHaveCtxtHandle );
  1716. pfnDeleteSecurityContext( &_hctxt );
  1717. }
  1718. _fHaveCtxtHandle = FALSE;
  1719. if ( ss == SEC_E_LOGON_DENIED ||
  1720. ss == SEC_E_INVALID_TOKEN )
  1721. {
  1722. ss = ERROR_LOGON_FAILURE;
  1723. }
  1724. if ( GetLastError() != ERROR_PASSWORD_EXPIRED
  1725. && GetLastError() != ERROR_PASSWORD_MUST_CHANGE )
  1726. {
  1727. SetLastError( ss );
  1728. }
  1729. return FALSE;
  1730. }
  1731. if( ContextAttributes & ASC_RET_NULL_SESSION )
  1732. {
  1733. SetLastError( ERROR_LOGON_FAILURE );
  1734. return FALSE;
  1735. }
  1736. _fHaveCtxtHandle = TRUE;
  1737. //
  1738. // NTLMSSP will set the last error to ERROR_NO_SUCH_USER
  1739. // if success and Guest account was used
  1740. //
  1741. if ( GetLastError() == ERROR_NO_SUCH_USER )
  1742. {
  1743. _fKnownToBeGuest = TRUE;
  1744. }
  1745. //
  1746. // Now we just need to complete the token (if requested) and prepare
  1747. // it for shipping to the other side if needed
  1748. //
  1749. BOOL fReply = !!OutSecBuff.cbBuffer;
  1750. if ( (ss == SEC_I_COMPLETE_NEEDED) ||
  1751. (ss == SEC_I_COMPLETE_AND_CONTINUE) )
  1752. {
  1753. ss = pfnCompleteAuthToken( &_hctxt,
  1754. &OutBuffDesc );
  1755. if ( !NT_SUCCESS( ss ))
  1756. return FALSE;
  1757. }
  1758. //
  1759. // Format or copy to the output buffer if we need to reply
  1760. //
  1761. if ( fReply )
  1762. {
  1763. if ( _fUUEncodeData &&
  1764. PackageSupportsEncoding( pszPackage ) )
  1765. {
  1766. if ( !uuencode( (BYTE *) OutSecBuff.pvBuffer,
  1767. OutSecBuff.cbBuffer,
  1768. pbuffOut,
  1769. _fBase64 ))
  1770. {
  1771. return FALSE;
  1772. }
  1773. *pcbBuffOut = strlen( (CHAR *) pbuffOut->QueryPtr() );
  1774. }
  1775. else
  1776. {
  1777. if ( !pbuffOut->Resize( OutSecBuff.cbBuffer ))
  1778. return FALSE;
  1779. memcpy( pbuffOut->QueryPtr(),
  1780. OutSecBuff.pvBuffer,
  1781. OutSecBuff.cbBuffer );
  1782. *pcbBuffOut = OutSecBuff.cbBuffer;
  1783. }
  1784. }
  1785. else
  1786. {
  1787. *pcbBuffOut = 0;
  1788. }
  1789. if ( _fNewConversation )
  1790. _fNewConversation = FALSE;
  1791. *pfNeedMoreData = ((ss == SEC_I_CONTINUE_NEEDED) ||
  1792. (ss == SEC_I_COMPLETE_AND_CONTINUE));
  1793. if ( !*pfNeedMoreData && !_fClient )
  1794. {
  1795. _fDelegate = !!(ContextAttributes & ASC_RET_DELEGATE);
  1796. }
  1797. return TRUE;
  1798. }
  1799. BOOL TCP_AUTHENT::ConverseEx(
  1800. SecBufferDesc* pInSecBufDesc, // passed in by caller
  1801. BUFFER * pDecodedBuffer, // passed in by caller
  1802. BUFFER * pbuffOut,
  1803. DWORD * pcbBuffOut,
  1804. BOOL * pfNeedMoreData,
  1805. PTCP_AUTHENT_INFO pTAI,
  1806. CHAR * pszPackage,
  1807. CHAR * pszUser,
  1808. CHAR * pszPassword,
  1809. PIIS_SERVER_INSTANCE psi
  1810. )
  1811. /*
  1812. * A variant of Converse that takes variable number of input SecBuffer.
  1813. * Caller will set the SecBuffers and pass in the SecBufferDesc pointer to ConverseEx.
  1814. * If the SecBuffer.pvBuffer needs to be decoded, caller has to pass in
  1815. * an array of BUFFER to hold the decoded data. The number of BUFFER elements
  1816. * should be the same as the number of SecBuffer.
  1817. * If decoding it not needed, pass NULL instead.
  1818. *
  1819. */
  1820. {
  1821. SECURITY_STATUS ss;
  1822. TimeStamp Lifetime;
  1823. SecBufferDesc OutBuffDesc;
  1824. SecBuffer OutSecBuff;
  1825. ULONG ContextAttributes;
  1826. BUFFER buffData;
  1827. BUFFER buff;
  1828. STACK_STR ( strDefaultLogonDomain, IIS_DNLEN+1 );
  1829. DWORD dw, dwDecodedLen;
  1830. SecBuffer *pSecBuffer;
  1831. // make sure we have at least one SecBuffer to process
  1832. if (pInSecBufDesc->cBuffers == 0)
  1833. return FALSE;
  1834. //
  1835. // Decode the data if there's something to decode
  1836. //
  1837. if (_fUUEncodeData &&
  1838. pInSecBufDesc &&
  1839. pDecodedBuffer &&
  1840. PackageSupportsEncoding( pszPackage ) )
  1841. {
  1842. pSecBuffer = pInSecBufDesc->pBuffers;
  1843. for (dw = 0; dw < pInSecBufDesc->cBuffers; dw++, pSecBuffer++)
  1844. {
  1845. if (!uudecode((CHAR *)pSecBuffer->pvBuffer, // points to data to be decoded
  1846. &pDecodedBuffer[dw], // to hold decoded data
  1847. &dwDecodedLen, // length of decoded data
  1848. _fBase64
  1849. ))
  1850. {
  1851. return FALSE;
  1852. }
  1853. // update the SecBuffer so it now points to the decoded data in BUFFER
  1854. pSecBuffer->pvBuffer = pDecodedBuffer[dw].QueryPtr();
  1855. pSecBuffer->cbBuffer = dwDecodedLen;
  1856. }
  1857. }
  1858. //
  1859. // If this is a new conversation, then we need to get the credential
  1860. // handle and find out the maximum token size
  1861. //
  1862. if ( _fNewConversation )
  1863. {
  1864. SecPkgInfo * pspkg;
  1865. SEC_WINNT_AUTH_IDENTITY AuthIdentity;
  1866. SEC_WINNT_AUTH_IDENTITY * pAuthIdentity;
  1867. CHAR * pszDomain = NULL;
  1868. CHAR szDomainAndUser[IIS_DNLEN+UNLEN+2];
  1869. //
  1870. // If this is the client and a username and password were
  1871. // specified, then fill out the authentication information
  1872. //
  1873. if ( _fClient &&
  1874. ((pszUser != NULL) ||
  1875. (pszPassword != NULL)) )
  1876. {
  1877. pAuthIdentity = &AuthIdentity;
  1878. //
  1879. // Break out the domain from the username if one was specified
  1880. //
  1881. if ( pszUser != NULL )
  1882. {
  1883. strcpy( szDomainAndUser, pszUser );
  1884. if ( !CrackUserAndDomain( szDomainAndUser,
  1885. &pszUser,
  1886. &pszDomain ))
  1887. {
  1888. return FALSE;
  1889. }
  1890. }
  1891. memset( &AuthIdentity,
  1892. 0,
  1893. sizeof( AuthIdentity ));
  1894. if ( pszUser != NULL )
  1895. {
  1896. AuthIdentity.User = (unsigned char *) pszUser;
  1897. AuthIdentity.UserLength = strlen( pszUser );
  1898. }
  1899. if ( pszPassword != NULL )
  1900. {
  1901. AuthIdentity.Password = (unsigned char *) pszPassword;
  1902. AuthIdentity.PasswordLength = strlen( pszPassword );
  1903. }
  1904. if ( pszDomain != NULL )
  1905. {
  1906. AuthIdentity.Domain = (unsigned char *) pszDomain;
  1907. AuthIdentity.DomainLength = strlen( pszDomain );
  1908. }
  1909. AuthIdentity.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
  1910. }
  1911. else
  1912. {
  1913. //
  1914. // provide default logon domain
  1915. //
  1916. if ( psi == NULL )
  1917. {
  1918. pAuthIdentity = NULL;
  1919. }
  1920. else
  1921. {
  1922. pAuthIdentity = &AuthIdentity;
  1923. memset( &AuthIdentity,
  1924. 0,
  1925. sizeof( AuthIdentity ));
  1926. if ( pTAI->strDefaultLogonDomain.QueryCCH() <= IIS_DNLEN )
  1927. {
  1928. strDefaultLogonDomain.Copy( pTAI->strDefaultLogonDomain );
  1929. AuthIdentity.Domain = (LPBYTE)strDefaultLogonDomain.QueryStr();
  1930. }
  1931. if ( AuthIdentity.Domain != NULL )
  1932. {
  1933. if ( AuthIdentity.DomainLength =
  1934. strlen( (LPCTSTR)AuthIdentity.Domain ) )
  1935. {
  1936. // remove trailing '\\' if present
  1937. if ( AuthIdentity.Domain[AuthIdentity.DomainLength-1]
  1938. == '\\' )
  1939. {
  1940. --AuthIdentity.DomainLength;
  1941. }
  1942. }
  1943. }
  1944. if ( AuthIdentity.DomainLength == 0 )
  1945. {
  1946. pAuthIdentity = NULL;
  1947. }
  1948. else
  1949. {
  1950. AuthIdentity.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
  1951. }
  1952. }
  1953. }
  1954. ss = pfnAcquireCredentialsHandle( NULL, // New principal
  1955. pszPackage, // Package name
  1956. (_fClient ? SECPKG_CRED_OUTBOUND :
  1957. SECPKG_CRED_INBOUND),
  1958. NULL, // Logon ID
  1959. pAuthIdentity, // Auth Data
  1960. NULL, // Get key func
  1961. NULL, // Get key arg
  1962. &_hcred,
  1963. &Lifetime );
  1964. //
  1965. // Need to determine the max token size for this package
  1966. //
  1967. if ( ss == STATUS_SUCCESS )
  1968. {
  1969. _fHaveCredHandle = TRUE;
  1970. ss = pfnQuerySecurityPackageInfo( (char *) pszPackage,
  1971. &pspkg );
  1972. }
  1973. if ( ss != STATUS_SUCCESS )
  1974. {
  1975. DBGPRINTF(( DBG_CONTEXT,
  1976. "[Converse] AcquireCredentialsHandle or QuerySecurityPackageInfo failed, error %d\n",
  1977. ss ));
  1978. SetLastError( ss );
  1979. return FALSE;
  1980. }
  1981. _cbMaxToken = pspkg->cbMaxToken;
  1982. DBG_ASSERT( pspkg->fCapabilities & SECPKG_FLAG_CONNECTION );
  1983. pfnFreeContextBuffer( pspkg );
  1984. }
  1985. //
  1986. // Prepare our output buffer. We use a temporary buffer because
  1987. // the real output buffer will most likely need to be uuencoded
  1988. //
  1989. if ( !buff.Resize( _cbMaxToken ))
  1990. return FALSE;
  1991. OutBuffDesc.ulVersion = 0;
  1992. OutBuffDesc.cBuffers = 1;
  1993. OutBuffDesc.pBuffers = &OutSecBuff;
  1994. OutSecBuff.cbBuffer = _cbMaxToken;
  1995. OutSecBuff.BufferType = SECBUFFER_TOKEN;
  1996. OutSecBuff.pvBuffer = buff.QueryPtr();
  1997. //
  1998. // Input sec buffer is passed by caller
  1999. //
  2000. //
  2001. // Client side uses InitializeSecurityContext, server side uses
  2002. // AcceptSecurityContext
  2003. //
  2004. if ( _fClient )
  2005. {
  2006. //
  2007. // Note the client will return success when its done but we still
  2008. // need to send the out buffer if there are bytes to send
  2009. //
  2010. ss = pfnInitializeSecurityContext( &_hcred,
  2011. _fNewConversation ? NULL : &_hctxt,
  2012. _strTarget.IsEmpty() ?
  2013. TCPAUTH_TARGET_NAME :
  2014. _strTarget.QueryStr(),
  2015. 0,
  2016. 0,
  2017. SECURITY_NATIVE_DREP,
  2018. _fNewConversation ? NULL : pInSecBufDesc,
  2019. 0,
  2020. &_hctxt,
  2021. &OutBuffDesc,
  2022. &ContextAttributes,
  2023. &Lifetime );
  2024. }
  2025. else
  2026. {
  2027. //
  2028. // This is the server side
  2029. //
  2030. SetLastError ( 0 );
  2031. ss = pfnAcceptSecurityContext( &_hcred,
  2032. _fNewConversation ? NULL : &_hctxt,
  2033. pInSecBufDesc,
  2034. ASC_REQ_EXTENDED_ERROR,
  2035. SECURITY_NATIVE_DREP,
  2036. &_hctxt,
  2037. &OutBuffDesc,
  2038. &ContextAttributes,
  2039. &Lifetime );
  2040. }
  2041. if ( !NT_SUCCESS( ss ) )
  2042. {
  2043. DBGPRINTF(( DBG_CONTEXT,
  2044. "[Converse] Initialize/AcceptCredentialsHandle failed, error %d\n",
  2045. ss ));
  2046. if ( ss == SEC_E_LOGON_DENIED ||
  2047. ss == SEC_E_INVALID_TOKEN )
  2048. {
  2049. ss = ERROR_LOGON_FAILURE;
  2050. }
  2051. if ( GetLastError() != ERROR_PASSWORD_EXPIRED
  2052. && GetLastError() != ERROR_PASSWORD_MUST_CHANGE )
  2053. {
  2054. SetLastError( ss );
  2055. }
  2056. return FALSE;
  2057. }
  2058. _fHaveCtxtHandle = TRUE;
  2059. //
  2060. // NTLMSSP will set the last error to ERROR_NO_SUCH_USER
  2061. // if success and Guest account was used
  2062. //
  2063. if ( GetLastError() == ERROR_NO_SUCH_USER )
  2064. {
  2065. _fKnownToBeGuest = TRUE;
  2066. }
  2067. //
  2068. // Now we just need to complete the token (if requested) and prepare
  2069. // it for shipping to the other side if needed
  2070. //
  2071. BOOL fReply = !!OutSecBuff.cbBuffer;
  2072. if ( (ss == SEC_I_COMPLETE_NEEDED) ||
  2073. (ss == SEC_I_COMPLETE_AND_CONTINUE) )
  2074. {
  2075. ss = pfnCompleteAuthToken( &_hctxt,
  2076. &OutBuffDesc );
  2077. if ( !NT_SUCCESS( ss ))
  2078. return FALSE;
  2079. }
  2080. //
  2081. // Format or copy to the output buffer if we need to reply
  2082. //
  2083. if ( fReply )
  2084. {
  2085. if ( _fUUEncodeData &&
  2086. PackageSupportsEncoding( pszPackage ) )
  2087. {
  2088. if ( !uuencode( (BYTE *) OutSecBuff.pvBuffer,
  2089. OutSecBuff.cbBuffer,
  2090. pbuffOut,
  2091. _fBase64 ))
  2092. {
  2093. return FALSE;
  2094. }
  2095. *pcbBuffOut = strlen( (CHAR *) pbuffOut->QueryPtr() );
  2096. }
  2097. else
  2098. {
  2099. if ( !pbuffOut->Resize( OutSecBuff.cbBuffer ))
  2100. return FALSE;
  2101. memcpy( pbuffOut->QueryPtr(),
  2102. OutSecBuff.pvBuffer,
  2103. OutSecBuff.cbBuffer );
  2104. *pcbBuffOut = OutSecBuff.cbBuffer;
  2105. }
  2106. }
  2107. else
  2108. {
  2109. *pcbBuffOut = 0;
  2110. }
  2111. if ( _fNewConversation )
  2112. _fNewConversation = FALSE;
  2113. *pfNeedMoreData = ((ss == SEC_I_CONTINUE_NEEDED) ||
  2114. (ss == SEC_I_COMPLETE_AND_CONTINUE));
  2115. if ( !*pfNeedMoreData && !_fClient )
  2116. {
  2117. _fDelegate = !!(ContextAttributes & ASC_RET_DELEGATE);
  2118. }
  2119. return TRUE;
  2120. }
  2121. /*******************************************************************/
  2122. #if 0
  2123. BOOL
  2124. TCP_AUTHENT::DigestLogon(
  2125. PSTR pszUserName,
  2126. PSTR pszRealm,
  2127. PSTR pszUri,
  2128. PSTR pszMethod,
  2129. PSTR pszNonce,
  2130. PSTR pszServerNonce,
  2131. PSTR pszDigest,
  2132. DWORD dwAlgo,
  2133. LPTSVC_INFO psi
  2134. )
  2135. {
  2136. HANDLE hToken;
  2137. CHAR szDomainAndUser[IIS_DNLEN+UNLEN+2];
  2138. int cL = 0;
  2139. CHAR * pszUserOnly;
  2140. CHAR * pszDomain;
  2141. //
  2142. // prepend default logon domain if no domain
  2143. //
  2144. if ( strchr( pszUserName, '/' ) == NULL
  2145. && strchr( pszUserName, '\\' ) == NULL )
  2146. {
  2147. psi->LockThisForRead();
  2148. PCSTR pD = psi->QueryDefaultLogonDomain();
  2149. PCSTR pL;
  2150. if ( pD != NULL && pD[0] != '\0' )
  2151. {
  2152. if ( ( pL = strchr( pD, '\\' ) ) )
  2153. {
  2154. cL = pL - pD;
  2155. }
  2156. else
  2157. {
  2158. cL = strlen( pD );
  2159. }
  2160. memcpy( szDomainAndUser, pD, cL );
  2161. szDomainAndUser[ cL++ ] = '\\';
  2162. }
  2163. psi->UnlockThis();
  2164. }
  2165. strcpy( szDomainAndUser + cL, pszUserName );
  2166. //
  2167. // Crack the name into domain/user components.
  2168. //
  2169. if ( !CrackUserAndDomain( szDomainAndUser,
  2170. &pszUserOnly,
  2171. &pszDomain ))
  2172. {
  2173. return FALSE;
  2174. }
  2175. if ( LogonDigestUserA(
  2176. pszUserOnly,
  2177. pszDomain,
  2178. pszRealm,
  2179. pszUri,
  2180. pszMethod,
  2181. pszNonce,
  2182. pszServerNonce,
  2183. pszDigest,
  2184. dwAlgo,
  2185. &hToken )
  2186. && SetAccessToken( NULL, hToken ) )
  2187. {
  2188. return TRUE;
  2189. }
  2190. return FALSE;
  2191. }
  2192. #endif
  2193. BOOL
  2194. TCP_AUTHENT::ClearTextLogon(
  2195. IN PCHAR pszUser,
  2196. IN PCHAR pszPassword,
  2197. OUT PBOOL pfAsGuest,
  2198. OUT PBOOL pfAsAnonymous,
  2199. IN PIIS_SERVER_INSTANCE pInstance,
  2200. PTCP_AUTHENT_INFO pTAI,
  2201. IN PCHAR pszWorkstation
  2202. )
  2203. /*++
  2204. Routine Description:
  2205. Gets a network logon token using clear text
  2206. Arguments:
  2207. pszUser - User name (optionally with domain)
  2208. pszPassword - password
  2209. pfAsGuest - Set to TRUE if granted with guest access (NOT SUPPORTED)
  2210. pfAsAnonymous - Set to TRUE if the user received the anonymous token
  2211. pInstance - pointer to Server instance
  2212. Return Value:
  2213. TRUE if successful, FALSE otherwise (call GetLastError)
  2214. --*/
  2215. {
  2216. BOOL fHaveExp;
  2217. DBG_ASSERT( !_fHaveCredHandle && !_fHaveCtxtHandle );
  2218. //
  2219. // short circuit fast path
  2220. //
  2221. if ( pszUser == NULL ) {
  2222. _hToken = FastFindAnonymousToken( pTAI );
  2223. //
  2224. // success!
  2225. //
  2226. if ( _hToken != NULL ) {
  2227. _liPwdExpiry.LowPart = _hToken->QueryExpiry()->LowPart;
  2228. _liPwdExpiry.HighPart = _hToken->QueryExpiry()->HighPart;
  2229. _fHaveExpiry = TRUE;
  2230. _fClearText = TRUE;
  2231. *pfAsGuest = _hToken->IsGuest();
  2232. *pfAsAnonymous = TRUE;
  2233. return TRUE;
  2234. }
  2235. //
  2236. // use normal path
  2237. //
  2238. }
  2239. _hToken = TsLogonUser( pszUser,
  2240. pszPassword,
  2241. pfAsGuest,
  2242. pfAsAnonymous,
  2243. pInstance,
  2244. pTAI,
  2245. pszWorkstation,
  2246. &_liPwdExpiry,
  2247. &fHaveExp );
  2248. if ( _hToken == NULL ) {
  2249. return FALSE;
  2250. }
  2251. _fClearText = TRUE;
  2252. _fHaveExpiry = fHaveExp;
  2253. switch ( pTAI->dwLogonMethod )
  2254. {
  2255. case LOGON32_LOGON_BATCH:
  2256. case LOGON32_LOGON_INTERACTIVE:
  2257. case LOGON32_LOGON_NETWORK_CLEARTEXT:
  2258. _fDelegate = TRUE;
  2259. }
  2260. return TRUE;
  2261. } // TCP_AUTHENT::ClearTextLogon
  2262. BOOL TCP_AUTHENT::SetAccessToken(
  2263. HANDLE hPrimaryToken,
  2264. HANDLE hImpersonationToken
  2265. )
  2266. /*++
  2267. Routine Description:
  2268. Set primary & impersonation token
  2269. Arguments:
  2270. hPrimaryToken -- Primary Access Token
  2271. hImpersonationToken -- Impersonation Access Token
  2272. One the two above tokens can be NULL ( but not both )
  2273. psi - pointer to Service info struct
  2274. Return Value:
  2275. TRUE if successful, FALSE otherwise ( tokens will be closed )
  2276. --*/
  2277. {
  2278. if ( !hPrimaryToken )
  2279. {
  2280. if ( !hImpersonationToken )
  2281. {
  2282. SetLastError( ERROR_INVALID_PARAMETER );
  2283. return FALSE;
  2284. }
  2285. if ( !pfnDuplicateTokenEx( hImpersonationToken,
  2286. TOKEN_ALL_ACCESS,
  2287. NULL,
  2288. SecurityImpersonation,
  2289. TokenPrimary,
  2290. &hPrimaryToken ))
  2291. {
  2292. CloseHandle( hImpersonationToken );
  2293. return FALSE;
  2294. }
  2295. }
  2296. if ( !hImpersonationToken )
  2297. {
  2298. if ( !pfnDuplicateTokenEx( hPrimaryToken,
  2299. TOKEN_ALL_ACCESS,
  2300. NULL,
  2301. SecurityImpersonation,
  2302. TokenImpersonation,
  2303. &hImpersonationToken ))
  2304. {
  2305. CloseHandle( hPrimaryToken );
  2306. return FALSE;
  2307. }
  2308. }
  2309. _hSSPToken = hImpersonationToken;
  2310. _hSSPPrimaryToken = hPrimaryToken;
  2311. _fHaveAccessTokens = TRUE;
  2312. return TRUE;
  2313. }
  2314. /*******************************************************************/
  2315. BOOL TCP_AUTHENT::Impersonate(
  2316. VOID
  2317. )
  2318. /*++
  2319. Routine Description:
  2320. Impersonates the authenticated user
  2321. Arguments:
  2322. Return Value:
  2323. TRUE if successful, FALSE otherwise (call GetLastError)
  2324. --*/
  2325. {
  2326. if ( _hToken == (TS_TOKEN)BOGUS_WIN95_TOKEN )
  2327. {
  2328. return(TRUE);
  2329. }
  2330. if ( _fClearText )
  2331. {
  2332. return TsImpersonateUser( _hToken );
  2333. }
  2334. else if ( _fHaveAccessTokens || _pDeleteFunction )
  2335. {
  2336. return ImpersonateLoggedOnUser( _hSSPToken );
  2337. }
  2338. else
  2339. {
  2340. DBG_ASSERT( _fHaveCtxtHandle );
  2341. return !!NT_SUCCESS( pfnImpersonateSecurityContext( &_hctxt ));
  2342. }
  2343. }
  2344. /*******************************************************************/
  2345. BOOL TCP_AUTHENT::RevertToSelf(
  2346. VOID
  2347. )
  2348. /*++
  2349. Routine Description:
  2350. Undoes the impersonation
  2351. Arguments:
  2352. Return Value:
  2353. TRUE if successful, FALSE otherwise (call GetLastError)
  2354. --*/
  2355. {
  2356. if ( _hToken == (TS_TOKEN)BOGUS_WIN95_TOKEN )
  2357. {
  2358. return(TRUE);
  2359. }
  2360. if ( _fClearText || _fHaveAccessTokens || _pDeleteFunction )
  2361. {
  2362. return ::RevertToSelf();
  2363. }
  2364. else
  2365. {
  2366. DBG_ASSERT( _fHaveCtxtHandle );
  2367. return !!NT_SUCCESS( pfnRevertSecurityContext( &_hctxt ));
  2368. }
  2369. }
  2370. /*******************************************************************/
  2371. BOOL TCP_AUTHENT::StartProcessAsUser(
  2372. LPCSTR lpApplicationName,
  2373. LPSTR lpCommandLine,
  2374. BOOL bInheritHandles,
  2375. DWORD dwCreationFlags,
  2376. LPVOID lpEnvironment,
  2377. LPCSTR lpCurrentDirectory,
  2378. LPSTARTUPINFOA lpStartupInfo,
  2379. LPPROCESS_INFORMATION lpProcessInformation
  2380. )
  2381. /*++
  2382. Routine Description:
  2383. Creates a process as the authenticated user
  2384. Arguments:
  2385. Standard CreateProcess args
  2386. Return Value:
  2387. TRUE if successful, FALSE otherwise (call GetLastError)
  2388. --*/
  2389. {
  2390. HANDLE htoken;
  2391. BOOL fRet;
  2392. if ( _fClearText )
  2393. {
  2394. htoken = CTO_TO_TOKEN( _hToken );
  2395. }
  2396. else
  2397. {
  2398. //
  2399. // Need to extract the impersonation token from the opaque SSP
  2400. // structures
  2401. //
  2402. if ( !Impersonate() )
  2403. {
  2404. return FALSE;
  2405. }
  2406. if ( !OpenThreadToken( GetCurrentThread(),
  2407. TOKEN_QUERY,
  2408. TRUE,
  2409. &htoken ))
  2410. {
  2411. RevertToSelf();
  2412. return FALSE;
  2413. }
  2414. RevertToSelf();
  2415. }
  2416. fRet = CreateProcessAsUser( htoken,
  2417. lpApplicationName,
  2418. lpCommandLine,
  2419. NULL,
  2420. NULL,
  2421. bInheritHandles,
  2422. dwCreationFlags,
  2423. lpEnvironment,
  2424. lpCurrentDirectory,
  2425. lpStartupInfo,
  2426. lpProcessInformation );
  2427. if ( !_fClearText )
  2428. {
  2429. DBG_REQUIRE( CloseHandle( htoken ) );
  2430. }
  2431. return fRet;
  2432. }
  2433. BOOL
  2434. TCP_AUTHENT::GetClientCertBlob
  2435. (
  2436. IN DWORD cbAllocated,
  2437. OUT DWORD * pdwCertEncodingType,
  2438. OUT unsigned char * pbCertEncoded,
  2439. OUT DWORD * pcbCertEncoded,
  2440. OUT DWORD * pdwCertificateFlags
  2441. )
  2442. {
  2443. if ( (pdwCertEncodingType == NULL) ||
  2444. (pbCertEncoded == NULL) ||
  2445. (pcbCertEncoded == NULL)
  2446. ) {
  2447. SetLastError( ERROR_INVALID_PARAMETER );
  2448. return ( FALSE);
  2449. }
  2450. BOOL fReturn = FALSE;
  2451. BOOL fNoCert;
  2452. //
  2453. // Win95 <==> no certificate
  2454. // NOTE Currently security.dll is not supported in Win95.
  2455. //
  2456. if ( TsIsWindows95() ) {
  2457. goto LNoCertificate;
  2458. }
  2459. if ( !QueryCertificateInfo( &fNoCert) ) {
  2460. goto LNoCertificate;
  2461. }
  2462. //
  2463. // fill in cert size out-parameter
  2464. //
  2465. *pcbCertEncoded = _pClientCertContext->cbCertEncoded;
  2466. //
  2467. // if buffer is adequate, fill in remaining out-parameters
  2468. // else return error
  2469. //
  2470. if ( cbAllocated >= *pcbCertEncoded ) {
  2471. CopyMemory( pbCertEncoded,
  2472. _pClientCertContext->pbCertEncoded,
  2473. _pClientCertContext->cbCertEncoded );
  2474. *pdwCertEncodingType = _pClientCertContext->dwCertEncodingType;
  2475. *pdwCertificateFlags = _dwX509Flags;
  2476. fReturn = TRUE;
  2477. } else {
  2478. SetLastError( ERROR_INSUFFICIENT_BUFFER );
  2479. fReturn = FALSE;
  2480. }
  2481. LExit:
  2482. return fReturn;
  2483. LNoCertificate:
  2484. //
  2485. // No cert: zero-out buffer and return success
  2486. //
  2487. *pbCertEncoded = NULL;
  2488. *pcbCertEncoded = 0;
  2489. *pdwCertEncodingType = 0;
  2490. *pdwCertificateFlags = 0;
  2491. fReturn = TRUE;
  2492. goto LExit;
  2493. } // TCP_AUTHENT::GetClientCertBlob()
  2494. BOOL
  2495. TCP_AUTHENT::UpdateClientCertFlags(
  2496. DWORD dwFlags,
  2497. LPBOOL pfNoCert,
  2498. LPBYTE pbCa,
  2499. DWORD dwCa
  2500. )
  2501. {
  2502. BOOL fNoCert;
  2503. _fCertCheckForRevocation = !( dwFlags & MD_CERT_NO_REVOC_CHECK );
  2504. _fCertCheckCacheOnly = !!( dwFlags & MD_CERT_CACHE_RETRIEVAL_ONLY );
  2505. if ( QueryCertificateInfo( pfNoCert ) )
  2506. {
  2507. *pfNoCert = FALSE;
  2508. return TRUE;
  2509. }
  2510. return FALSE;
  2511. }
  2512. BOOL
  2513. TCP_AUTHENT::PackageSupportsEncoding(
  2514. LPSTR pszPackage
  2515. )
  2516. /*++
  2517. Routine Description:
  2518. Check whether the SSPI package should (not) be encoded.
  2519. Arguments:
  2520. pszPackage - Name of SSPI package
  2521. Return Value:
  2522. TRUE if should encode, FALSE otherwise
  2523. --*/
  2524. {
  2525. SECURITY_STATUS SecurityStatus;
  2526. PSecPkgInfo pPackageInfo;
  2527. BOOL fRet = FALSE;
  2528. if ( pszPackage != NULL )
  2529. {
  2530. SecurityStatus = pfnQuerySecurityPackageInfo( pszPackage,
  2531. &pPackageInfo );
  2532. if ( SecurityStatus == SEC_E_OK )
  2533. {
  2534. if ( !( pPackageInfo->fCapabilities & SECPKG_FLAG_ASCII_BUFFERS ) )
  2535. {
  2536. fRet = TRUE;
  2537. }
  2538. pfnFreeContextBuffer( pPackageInfo );
  2539. }
  2540. }
  2541. else
  2542. {
  2543. SetLastError( ERROR_INVALID_PARAMETER );
  2544. DBG_ASSERT( FALSE );
  2545. }
  2546. return fRet;
  2547. }
  2548. BOOL
  2549. TCP_AUTHENT::SetTargetName(
  2550. LPSTR pszTargetName
  2551. )
  2552. /*++
  2553. Routine Description:
  2554. Set the target name to pass into InitializeSecurityContext() calls
  2555. Arguments:
  2556. pszTargetName - Target name
  2557. Return Value:
  2558. TRUE if successful, else FALSE. Use GetLastError() for error
  2559. --*/
  2560. {
  2561. if ( pszTargetName != NULL )
  2562. {
  2563. return _strTarget.Copy( pszTargetName );
  2564. }
  2565. else
  2566. {
  2567. SetLastError( ERROR_INVALID_PARAMETER );
  2568. return FALSE;
  2569. }
  2570. }
  2571. /************************ End of File ***********************/