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.

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