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.

2536 lines
66 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1995.
  5. //
  6. // File: mapper.c
  7. //
  8. // Contents: Implements the DS Mapping Layer
  9. //
  10. // Classes:
  11. //
  12. // Functions:
  13. //
  14. // History: 10-15-96 RichardW Created
  15. //
  16. // Notes: The code here has two forks. One, the direct path, for when
  17. // the DLL is running on a DC, and the second, for when we're
  18. // running elsewhere and remoting through the generic channel
  19. // to the DC.
  20. //
  21. //----------------------------------------------------------------------------
  22. #include "sslp.h"
  23. #include <crypt.h>
  24. #include <lmcons.h>
  25. #include <ntsam.h>
  26. #include <samrpc.h>
  27. #include <samisrv.h>
  28. #include <lsarpc.h>
  29. #include <lsaisrv.h>
  30. #include <dnsapi.h>
  31. #include <certmap.h>
  32. #include <align.h>
  33. #include <ntmsv1_0.h>
  34. #include <ntdsapi.h>
  35. #include <ntdsapip.h>
  36. #include "mapsam.h"
  37. #include "wincrypt.h"
  38. #include <msaudite.h>
  39. LONG WINAPI
  40. SslLocalRefMapper(
  41. PHMAPPER Mapper);
  42. LONG WINAPI
  43. SslLocalDerefMapper(
  44. PHMAPPER Mapper);
  45. DWORD WINAPI
  46. SslLocalGetIssuerList(
  47. IN PHMAPPER Mapper,
  48. IN PVOID Reserved,
  49. OUT PBYTE pIssuerList,
  50. OUT PDWORD IssuerListLength);
  51. DWORD WINAPI
  52. SslLocalGetChallenge(
  53. IN PHMAPPER Mapper,
  54. IN PUCHAR AuthenticatorId,
  55. IN DWORD AuthenticatorIdLength,
  56. OUT PUCHAR Challenge,
  57. OUT DWORD * ChallengeLength);
  58. DWORD WINAPI
  59. SslLocalMapCredential(
  60. IN PHMAPPER Mapper,
  61. IN DWORD CredentialType,
  62. VOID const *pCredential,
  63. VOID const *pAuthority,
  64. OUT HLOCATOR * phLocator);
  65. DWORD WINAPI
  66. SslRemoteMapCredential(
  67. IN PHMAPPER Mapper,
  68. IN DWORD CredentialType,
  69. VOID const *pCredential,
  70. VOID const *pAuthority,
  71. OUT HLOCATOR * phLocator);
  72. DWORD WINAPI
  73. SslLocalCloseLocator(
  74. IN PHMAPPER Mapper,
  75. IN HLOCATOR Locator);
  76. DWORD WINAPI
  77. SslLocalGetAccessToken(
  78. IN PHMAPPER Mapper,
  79. IN HLOCATOR Locator,
  80. OUT HANDLE *Token);
  81. MAPPER_VTABLE SslLocalTable = { SslLocalRefMapper,
  82. SslLocalDerefMapper,
  83. SslLocalGetIssuerList,
  84. SslLocalGetChallenge,
  85. SslLocalMapCredential,
  86. SslLocalGetAccessToken,
  87. SslLocalCloseLocator
  88. };
  89. MAPPER_VTABLE SslRemoteTable = {SslLocalRefMapper,
  90. SslLocalDerefMapper,
  91. SslLocalGetIssuerList,
  92. SslLocalGetChallenge,
  93. SslRemoteMapCredential,
  94. SslLocalGetAccessToken,
  95. SslLocalCloseLocator
  96. };
  97. MAPPER_VTABLE SslUserModeTable = {
  98. SslLocalRefMapper,
  99. SslLocalDerefMapper,
  100. NULL,
  101. NULL,
  102. NULL,
  103. SslLocalGetAccessToken,
  104. SslLocalCloseLocator
  105. };
  106. typedef struct _SSL_MAPPER_CONTEXT {
  107. HMAPPER Mapper ;
  108. LONG Ref ;
  109. } SSL_MAPPER_CONTEXT, * PSSL_MAPPER_CONTEXT ;
  110. NTSTATUS
  111. WINAPI
  112. SslBuildCertLogonRequest(
  113. PCCERT_CHAIN_CONTEXT pChainContext,
  114. DWORD dwMethods,
  115. PSSL_CERT_LOGON_REQ *ppRequest,
  116. PDWORD pcbRequest);
  117. NTSTATUS
  118. WINAPI
  119. SslMapCertAtDC(
  120. PUNICODE_STRING DomainName,
  121. VOID const *pCredential,
  122. DWORD cbCredential,
  123. PMSV1_0_PASSTHROUGH_RESPONSE * DcResponse
  124. );
  125. PWSTR SslDnsDomainName ;
  126. SECURITY_STRING SslNullString = { 0, sizeof( WCHAR ), L"" };
  127. PHMAPPER
  128. SslGetMapper(
  129. BOOL Ignored
  130. )
  131. {
  132. PSSL_MAPPER_CONTEXT Context ;
  133. NTSTATUS Status ;
  134. NT_PRODUCT_TYPE ProductType ;
  135. BOOL DC ;
  136. if ( RtlGetNtProductType( &ProductType ) )
  137. {
  138. DC = (ProductType == NtProductLanManNt );
  139. }
  140. else
  141. {
  142. return NULL ;
  143. }
  144. Context = (PSSL_MAPPER_CONTEXT) SPExternalAlloc( sizeof( SSL_MAPPER_CONTEXT ) );
  145. if ( Context )
  146. {
  147. Context->Mapper.m_dwMapperVersion = MAPPER_INTERFACE_VER ;
  148. Context->Mapper.m_dwFlags = SCH_FLAG_SYSTEM_MAPPER ;
  149. Context->Mapper.m_Reserved1 = NULL ;
  150. Context->Ref = 0;
  151. if ( DC )
  152. {
  153. Context->Mapper.m_vtable = &SslLocalTable ;
  154. }
  155. else
  156. {
  157. Context->Mapper.m_vtable = &SslRemoteTable ;
  158. }
  159. return &Context->Mapper ;
  160. }
  161. else
  162. {
  163. return NULL ;
  164. }
  165. }
  166. LONG
  167. WINAPI
  168. SslLocalRefMapper(
  169. PHMAPPER Mapper
  170. )
  171. {
  172. PSSL_MAPPER_CONTEXT Context ;
  173. Context = (PSSL_MAPPER_CONTEXT) Mapper ;
  174. if ( Context == NULL )
  175. {
  176. return( -1 );
  177. }
  178. DebugLog(( DEB_TRACE_MAPPER, "Ref of Context %x\n", Mapper ));
  179. return( InterlockedIncrement( &Context->Ref ) );
  180. }
  181. LONG
  182. WINAPI
  183. SslLocalDerefMapper(
  184. PHMAPPER Mapper
  185. )
  186. {
  187. PSSL_MAPPER_CONTEXT Context ;
  188. DWORD RefCount;
  189. Context = (PSSL_MAPPER_CONTEXT) Mapper ;
  190. if ( Context == NULL )
  191. {
  192. return( -1 );
  193. }
  194. DebugLog(( DEB_TRACE_MAPPER, "Deref of Context %x\n", Mapper ));
  195. RefCount = InterlockedDecrement( &Context->Ref );
  196. if(RefCount == 0)
  197. {
  198. SPExternalFree(Context);
  199. }
  200. return RefCount;
  201. }
  202. DWORD
  203. WINAPI
  204. SslLocalGetIssuerList(
  205. IN PHMAPPER Mapper,
  206. IN PVOID Reserved,
  207. OUT PBYTE pIssuerList,
  208. OUT PDWORD IssuerListLength
  209. )
  210. {
  211. DebugLog(( DEB_TRACE_MAPPER, "GetIssuerList, context %x\n", Mapper ));
  212. return( GetDefaultIssuers(pIssuerList, IssuerListLength) );
  213. }
  214. DWORD
  215. WINAPI
  216. SslLocalGetChallenge(
  217. IN PHMAPPER Mapper,
  218. IN PUCHAR AuthenticatorId,
  219. IN DWORD AuthenticatorIdLength,
  220. OUT PUCHAR Challenge,
  221. OUT DWORD * ChallengeLength
  222. )
  223. {
  224. DebugLog(( DEB_TRACE_MAPPER, "GetChallenge, context %x\n", Mapper ));
  225. return SEC_E_UNSUPPORTED_FUNCTION;
  226. }
  227. SECURITY_STATUS
  228. SslCreateTokenFromPac(
  229. PUCHAR AuthInfo,
  230. ULONG AuthInfoLength,
  231. PUNICODE_STRING Domain,
  232. PLUID NewLogonId,
  233. PHANDLE NewToken
  234. )
  235. {
  236. NTSTATUS Status ;
  237. PVOID TokenInfo ;
  238. LSA_TOKEN_INFORMATION_TYPE TokenInfoType ;
  239. PLSA_TOKEN_INFORMATION_V1 TokenV1 ;
  240. PLSA_TOKEN_INFORMATION_NULL TokenNull ;
  241. LUID LogonId ;
  242. HANDLE TokenHandle ;
  243. NTSTATUS SubStatus ;
  244. SECURITY_STRING PacUserName ;
  245. //
  246. // Get the marshalled blob into a more useful form:
  247. //
  248. PacUserName.Buffer = NULL ;
  249. Status = LsaTable->ConvertAuthDataToToken(
  250. AuthInfo,
  251. AuthInfoLength,
  252. SecurityImpersonation,
  253. &SslTokenSource,
  254. Network,
  255. Domain,
  256. &TokenHandle,
  257. &LogonId,
  258. &PacUserName,
  259. &SubStatus
  260. );
  261. if ( NT_SUCCESS( Status ) )
  262. {
  263. LsaTable->AuditLogon(
  264. STATUS_SUCCESS,
  265. STATUS_SUCCESS,
  266. &PacUserName,
  267. Domain,
  268. NULL,
  269. NULL,
  270. Network,
  271. &SslTokenSource,
  272. &LogonId );
  273. }
  274. else
  275. {
  276. LsaTable->AuditLogon(
  277. Status,
  278. Status,
  279. &SslNullString,
  280. &SslNullString,
  281. NULL,
  282. NULL,
  283. Network,
  284. &SslTokenSource,
  285. &LogonId );
  286. }
  287. if ( !NT_SUCCESS( Status ) )
  288. {
  289. return Status ;
  290. }
  291. *NewToken = TokenHandle ;
  292. *NewLogonId = LogonId ;
  293. if ( PacUserName.Buffer )
  294. {
  295. LsaTable->FreeLsaHeap( PacUserName.Buffer );
  296. }
  297. return Status ;
  298. }
  299. #define ISSUER_HEADER L"<I>"
  300. #define CCH_ISSUER_HEADER 3
  301. #define SUBJECT_HEADER L"<S>"
  302. #define CCH_SUBJECT_HEADER 3
  303. //+---------------------------------------------------------------------------
  304. //
  305. // Function: SslGetNameFromCertificate
  306. //
  307. // Synopsis: Extracts the UPN name from the certificate
  308. //
  309. // Arguments: [pCert] --
  310. // [ppszName] --
  311. // [pfMachineCert] --
  312. //
  313. // History: 8-8-2000 jbanes Created
  314. //
  315. // Notes:
  316. //
  317. //----------------------------------------------------------------------------
  318. NTSTATUS
  319. SslGetNameFromCertificate(
  320. PCCERT_CONTEXT pCert,
  321. PWSTR * ppszName,
  322. BOOL * pfMachineCert)
  323. {
  324. ULONG ExtensionIndex;
  325. PWSTR pszName;
  326. DWORD cbName;
  327. *pfMachineCert = FALSE;
  328. //
  329. // See if cert has UPN in AltSubjectName->otherName
  330. //
  331. pszName = NULL;
  332. for(ExtensionIndex = 0;
  333. ExtensionIndex < pCert->pCertInfo->cExtension;
  334. ExtensionIndex++)
  335. {
  336. if(strcmp(pCert->pCertInfo->rgExtension[ExtensionIndex].pszObjId,
  337. szOID_SUBJECT_ALT_NAME2) == 0)
  338. {
  339. PCERT_ALT_NAME_INFO AltName = NULL;
  340. DWORD AltNameStructSize = 0;
  341. ULONG CertAltNameIndex = 0;
  342. if(CryptDecodeObjectEx(pCert->dwCertEncodingType,
  343. X509_ALTERNATE_NAME,
  344. pCert->pCertInfo->rgExtension[ExtensionIndex].Value.pbData,
  345. pCert->pCertInfo->rgExtension[ExtensionIndex].Value.cbData,
  346. CRYPT_DECODE_ALLOC_FLAG,
  347. NULL,
  348. (PVOID)&AltName,
  349. &AltNameStructSize))
  350. {
  351. for(CertAltNameIndex = 0; CertAltNameIndex < AltName->cAltEntry; CertAltNameIndex++)
  352. {
  353. PCERT_ALT_NAME_ENTRY AltNameEntry = &AltName->rgAltEntry[CertAltNameIndex];
  354. if((CERT_ALT_NAME_OTHER_NAME == AltNameEntry->dwAltNameChoice) &&
  355. (NULL != AltNameEntry->pOtherName) &&
  356. (0 == strcmp(szOID_NT_PRINCIPAL_NAME, AltNameEntry->pOtherName->pszObjId)))
  357. {
  358. PCERT_NAME_VALUE PrincipalNameBlob = NULL;
  359. DWORD PrincipalNameBlobSize = 0;
  360. // We found a UPN!
  361. if(CryptDecodeObjectEx(pCert->dwCertEncodingType,
  362. X509_UNICODE_ANY_STRING,
  363. AltNameEntry->pOtherName->Value.pbData,
  364. AltNameEntry->pOtherName->Value.cbData,
  365. CRYPT_DECODE_ALLOC_FLAG,
  366. NULL,
  367. (PVOID)&PrincipalNameBlob,
  368. &PrincipalNameBlobSize))
  369. {
  370. pszName = LocalAlloc(LPTR, PrincipalNameBlob->Value.cbData + sizeof(WCHAR));
  371. if(pszName != NULL)
  372. {
  373. CopyMemory(pszName, PrincipalNameBlob->Value.pbData, PrincipalNameBlob->Value.cbData);
  374. }
  375. LocalFree(PrincipalNameBlob);
  376. PrincipalNameBlob = NULL;
  377. if(pszName == NULL)
  378. {
  379. LocalFree(AltName);
  380. return STATUS_NO_MEMORY;
  381. }
  382. }
  383. if(pszName)
  384. {
  385. break;
  386. }
  387. }
  388. }
  389. LocalFree(AltName);
  390. AltName = NULL;
  391. if(pszName)
  392. {
  393. break;
  394. }
  395. }
  396. }
  397. }
  398. //
  399. // See if cert has DNS in AltSubjectName->pwszDNSName
  400. //
  401. if(pszName == NULL)
  402. {
  403. for(ExtensionIndex = 0;
  404. ExtensionIndex < pCert->pCertInfo->cExtension;
  405. ExtensionIndex++)
  406. {
  407. if(strcmp(pCert->pCertInfo->rgExtension[ExtensionIndex].pszObjId,
  408. szOID_SUBJECT_ALT_NAME2) == 0)
  409. {
  410. PCERT_ALT_NAME_INFO AltName = NULL;
  411. DWORD AltNameStructSize = 0;
  412. ULONG CertAltNameIndex = 0;
  413. if(CryptDecodeObjectEx(pCert->dwCertEncodingType,
  414. X509_ALTERNATE_NAME,
  415. pCert->pCertInfo->rgExtension[ExtensionIndex].Value.pbData,
  416. pCert->pCertInfo->rgExtension[ExtensionIndex].Value.cbData,
  417. CRYPT_DECODE_ALLOC_FLAG,
  418. NULL,
  419. (PVOID)&AltName,
  420. &AltNameStructSize))
  421. {
  422. for(CertAltNameIndex = 0; CertAltNameIndex < AltName->cAltEntry; CertAltNameIndex++)
  423. {
  424. PCERT_ALT_NAME_ENTRY AltNameEntry = &AltName->rgAltEntry[CertAltNameIndex];
  425. if((CERT_ALT_NAME_DNS_NAME == AltNameEntry->dwAltNameChoice) &&
  426. (NULL != AltNameEntry->pwszDNSName))
  427. {
  428. PCERT_NAME_VALUE PrincipalNameBlob = NULL;
  429. DWORD PrincipalNameBlobSize = 0;
  430. // We found a DNS!
  431. cbName = (wcslen(AltNameEntry->pwszDNSName) + 1) * sizeof(WCHAR);
  432. pszName = LocalAlloc(LPTR, cbName);
  433. if(pszName == NULL)
  434. {
  435. LocalFree(AltName);
  436. return STATUS_NO_MEMORY;
  437. }
  438. CopyMemory(pszName, AltNameEntry->pwszDNSName, cbName);
  439. *pfMachineCert = TRUE;
  440. break;
  441. }
  442. }
  443. LocalFree(AltName);
  444. AltName = NULL;
  445. if(pszName)
  446. {
  447. break;
  448. }
  449. }
  450. }
  451. }
  452. }
  453. //
  454. // There was no UPN in the AltSubjectName, so look for
  455. // one in the Subject Name, in case this is a B3 compatability
  456. // cert.
  457. //
  458. if(pszName == NULL)
  459. {
  460. ULONG Length;
  461. Length = CertGetNameString( pCert,
  462. CERT_NAME_ATTR_TYPE,
  463. 0,
  464. szOID_COMMON_NAME,
  465. NULL,
  466. 0 );
  467. if(Length)
  468. {
  469. pszName = LocalAlloc(LPTR, Length * sizeof(WCHAR));
  470. if(!pszName)
  471. {
  472. return STATUS_NO_MEMORY ;
  473. }
  474. if ( !CertGetNameStringW(pCert,
  475. CERT_NAME_ATTR_TYPE,
  476. 0,
  477. szOID_COMMON_NAME,
  478. pszName,
  479. Length))
  480. {
  481. return GetLastError();
  482. }
  483. }
  484. }
  485. if(pszName)
  486. {
  487. *ppszName = pszName;
  488. }
  489. else
  490. {
  491. return STATUS_NOT_FOUND;
  492. }
  493. return STATUS_SUCCESS;
  494. }
  495. //+---------------------------------------------------------------------------
  496. //
  497. // Function: SslTryUpn
  498. //
  499. // Synopsis: Tries to find the user by UPN encoded in Cert
  500. //
  501. // Arguments: [User] --
  502. // [AuthData] --
  503. // [AuthDataLen] --
  504. //
  505. // History: 5-11-98 RichardW Created
  506. //
  507. // Notes:
  508. //
  509. //----------------------------------------------------------------------------
  510. NTSTATUS
  511. SslTryUpn(
  512. PCCERT_CONTEXT User,
  513. PUCHAR * AuthData,
  514. PULONG AuthDataLen,
  515. PWSTR * ReferencedDomain
  516. )
  517. {
  518. NTSTATUS Status ;
  519. UNICODE_STRING Upn = {0, 0, NULL};
  520. UNICODE_STRING Cracked = {0};
  521. UNICODE_STRING DnsDomain = {0};
  522. UNICODE_STRING FlatName = { 0 };
  523. ULONG SubStatus ;
  524. BOOL fMachineCert;
  525. PWSTR pszName = NULL;
  526. *ReferencedDomain = NULL ;
  527. //
  528. // Get the client name from the cert
  529. //
  530. Status = SslGetNameFromCertificate(User, &pszName, &fMachineCert);
  531. if(!NT_SUCCESS(Status))
  532. {
  533. return Status;
  534. }
  535. //
  536. // now, try and find this guy:
  537. //
  538. if(fMachineCert)
  539. {
  540. Status = STATUS_NOT_FOUND;
  541. }
  542. else
  543. {
  544. // Search for "[email protected]".
  545. Upn.Buffer = pszName;
  546. Upn.Length = wcslen(Upn.Buffer) * sizeof(WCHAR);
  547. Upn.MaximumLength = Upn.Length + sizeof(WCHAR);
  548. DebugLog(( DEB_TRACE_MAPPER, "Looking for UPN name %ws\n", Upn.Buffer ));
  549. Status = LsaTable->GetAuthDataForUser( &Upn,
  550. SecNameFlat,
  551. NULL,
  552. AuthData,
  553. AuthDataLen,
  554. &FlatName );
  555. if ( FlatName.Length )
  556. {
  557. LsaTable->AuditAccountLogon(
  558. SE_AUDITID_ACCOUNT_MAPPED,
  559. (BOOLEAN) NT_SUCCESS( Status ),
  560. &SslPackageName,
  561. &Upn,
  562. &FlatName,
  563. Status );
  564. LsaTable->FreeLsaHeap( FlatName.Buffer );
  565. }
  566. }
  567. if ( Status == STATUS_NOT_FOUND )
  568. {
  569. //
  570. // Do the hacky check of seeing if this is our own domain, and
  571. // if so, try opening the user as a flat, SAM name.
  572. //
  573. if(fMachineCert)
  574. {
  575. PWSTR pPeriod;
  576. WCHAR ch;
  577. pPeriod = wcschr( pszName, L'.' );
  578. if(pPeriod)
  579. {
  580. if ( DnsNameCompare_W( (pPeriod+1), SslDnsDomainName ) )
  581. {
  582. ch = *(pPeriod + 1);
  583. *pPeriod = L'$';
  584. *(pPeriod + 1) = L'\0';
  585. Upn.Buffer = pszName;
  586. Upn.Length = wcslen( Upn.Buffer ) * sizeof( WCHAR );
  587. Upn.MaximumLength = Upn.Length + sizeof(WCHAR);
  588. DebugLog(( DEB_TRACE_MAPPER, "Looking for machine name %ws\n", Upn.Buffer ));
  589. // Search for "computer$".
  590. Status = LsaTable->GetAuthDataForUser( &Upn,
  591. SecNameSamCompatible,
  592. NULL,
  593. AuthData,
  594. AuthDataLen,
  595. NULL );
  596. *pPeriod = L'.';
  597. *(pPeriod + 1) = ch;
  598. }
  599. }
  600. }
  601. else
  602. {
  603. PWSTR AtSign;
  604. AtSign = wcschr( pszName, L'@' );
  605. if ( AtSign )
  606. {
  607. if ( DnsNameCompare_W( (AtSign+1), SslDnsDomainName ) )
  608. {
  609. *AtSign = L'\0';
  610. Upn.Buffer = pszName;
  611. Upn.Length = wcslen( Upn.Buffer ) * sizeof( WCHAR );
  612. Upn.MaximumLength = Upn.Length + sizeof(WCHAR);
  613. DebugLog(( DEB_TRACE_MAPPER, "Looking for user name %ws\n", Upn.Buffer ));
  614. // Search for "username".
  615. Status = LsaTable->GetAuthDataForUser( &Upn,
  616. SecNameSamCompatible,
  617. NULL,
  618. AuthData,
  619. AuthDataLen,
  620. NULL );
  621. *AtSign = L'@';
  622. }
  623. }
  624. }
  625. if (Status == STATUS_NOT_FOUND )
  626. {
  627. Upn.Buffer = pszName;
  628. Upn.Length = wcslen(Upn.Buffer) * sizeof(WCHAR);
  629. Upn.MaximumLength = Upn.Length + sizeof(WCHAR);
  630. DebugLog(( DEB_TRACE_MAPPER, "Cracking name %ws at GC\n", Upn.Buffer ));
  631. Status = LsaTable->CrackSingleName(
  632. DS_USER_PRINCIPAL_NAME,
  633. TRUE,
  634. &Upn,
  635. NULL,
  636. DS_NT4_ACCOUNT_NAME,
  637. &Cracked,
  638. &DnsDomain,
  639. &SubStatus );
  640. if ( NT_SUCCESS( Status ) )
  641. {
  642. if ( SubStatus == 0 )
  643. {
  644. *ReferencedDomain = DnsDomain.Buffer ;
  645. DnsDomain.Buffer = NULL;
  646. }
  647. if(Cracked.Buffer != NULL)
  648. {
  649. LsaTable->FreeLsaHeap( Cracked.Buffer );
  650. }
  651. if(DnsDomain.Buffer != NULL)
  652. {
  653. LsaTable->FreeLsaHeap( DnsDomain.Buffer );
  654. }
  655. Status = STATUS_NOT_FOUND ;
  656. }
  657. }
  658. }
  659. if(pszName)
  660. {
  661. LocalFree(pszName);
  662. }
  663. return Status ;
  664. }
  665. void
  666. ConvertNameString(UNICODE_STRING *Name)
  667. {
  668. PWSTR Comma1, Comma2;
  669. //
  670. // Scan through the name, converting "\r\n" to ",". This should be
  671. // done by the CertNameToStr APIs, but that won't happen for a while.
  672. //
  673. Comma1 = Comma2 = Name->Buffer ;
  674. while ( *Comma2 )
  675. {
  676. *Comma1 = *Comma2 ;
  677. if ( *Comma2 == L'\r' )
  678. {
  679. if ( *(Comma2 + 1) == L'\n' )
  680. {
  681. *Comma1 = L',';
  682. Comma2++ ;
  683. }
  684. }
  685. Comma1++;
  686. Comma2++;
  687. }
  688. *Comma1 = L'\0';
  689. Name->Length = wcslen( Name->Buffer ) * sizeof( WCHAR );
  690. }
  691. //+---------------------------------------------------------------------------
  692. //
  693. // Function: SslTryCompoundName
  694. //
  695. // Synopsis: Tries to find the user by concatenating the issuer and subject
  696. // names, and looking for an AlternateSecurityId.
  697. //
  698. // Arguments: [User] --
  699. // [AuthData] --
  700. // [AuthDataLen] --
  701. //
  702. // History: 5-11-98 RichardW Created
  703. //
  704. // Notes:
  705. //
  706. //----------------------------------------------------------------------------
  707. NTSTATUS
  708. SslTryCompoundName(
  709. PCCERT_CONTEXT User,
  710. PUCHAR * AuthData,
  711. PULONG AuthDataLen,
  712. PWSTR * ReferencedDomain
  713. )
  714. {
  715. UNICODE_STRING CompoundName ;
  716. ULONG Length ;
  717. ULONG IssuerLength ;
  718. NTSTATUS Status ;
  719. PWSTR Current ;
  720. PWSTR Comma1, Comma2 ;
  721. UNICODE_STRING Cracked = {0};
  722. UNICODE_STRING DnsDomain = {0};
  723. UNICODE_STRING FlatName = { 0 };
  724. ULONG SubStatus ;
  725. const DWORD dwNameToStrFlags = CERT_X500_NAME_STR |
  726. CERT_NAME_STR_NO_PLUS_FLAG |
  727. CERT_NAME_STR_CRLF_FLAG;
  728. *ReferencedDomain = NULL ;
  729. IssuerLength = CertNameToStr( User->dwCertEncodingType,
  730. &User->pCertInfo->Issuer,
  731. dwNameToStrFlags,
  732. NULL,
  733. 0 );
  734. Length = CertNameToStr( User->dwCertEncodingType,
  735. &User->pCertInfo->Subject,
  736. dwNameToStrFlags,
  737. NULL,
  738. 0 );
  739. if ( ( IssuerLength == 0 ) ||
  740. ( Length == 0 ) )
  741. {
  742. return STATUS_NO_MEMORY ;
  743. }
  744. CompoundName.MaximumLength = (USHORT) (Length + IssuerLength +
  745. CCH_ISSUER_HEADER + CCH_SUBJECT_HEADER) *
  746. sizeof( WCHAR ) ;
  747. CompoundName.Buffer = LocalAlloc( LMEM_FIXED, CompoundName.MaximumLength );
  748. if ( CompoundName.Buffer )
  749. {
  750. wcscpy( CompoundName.Buffer, ISSUER_HEADER );
  751. Current = CompoundName.Buffer + CCH_ISSUER_HEADER ;
  752. IssuerLength = CertNameToStrW( User->dwCertEncodingType,
  753. &User->pCertInfo->Issuer,
  754. dwNameToStrFlags,
  755. Current,
  756. IssuerLength );
  757. Current += IssuerLength - 1 ;
  758. wcscpy( Current, SUBJECT_HEADER );
  759. Current += CCH_SUBJECT_HEADER ;
  760. Length = CertNameToStrW( User->dwCertEncodingType,
  761. &User->pCertInfo->Subject,
  762. dwNameToStrFlags,
  763. Current,
  764. Length );
  765. ConvertNameString(&CompoundName);
  766. Status = LsaTable->GetAuthDataForUser( &CompoundName,
  767. SecNameAlternateId,
  768. &SslNamePrefix,
  769. AuthData,
  770. AuthDataLen,
  771. &FlatName );
  772. if ( FlatName.Length )
  773. {
  774. LsaTable->AuditAccountLogon(
  775. SE_AUDITID_ACCOUNT_MAPPED,
  776. (BOOLEAN) NT_SUCCESS( Status ),
  777. &SslPackageName,
  778. &CompoundName,
  779. &FlatName,
  780. Status );
  781. LsaTable->FreeLsaHeap( FlatName.Buffer );
  782. }
  783. if ( Status == STATUS_NOT_FOUND )
  784. {
  785. Status = LsaTable->CrackSingleName(
  786. DS_ALT_SECURITY_IDENTITIES_NAME,
  787. TRUE,
  788. &CompoundName,
  789. &SslNamePrefix,
  790. DS_NT4_ACCOUNT_NAME,
  791. &Cracked,
  792. &DnsDomain,
  793. &SubStatus );
  794. if ( NT_SUCCESS( Status ) )
  795. {
  796. if ( SubStatus == 0 )
  797. {
  798. *ReferencedDomain = DnsDomain.Buffer ;
  799. DnsDomain.Buffer = NULL;
  800. }
  801. if(Cracked.Buffer != NULL)
  802. {
  803. LsaTable->FreeLsaHeap( Cracked.Buffer );
  804. }
  805. if(DnsDomain.Buffer != NULL)
  806. {
  807. LsaTable->FreeLsaHeap( DnsDomain.Buffer );
  808. }
  809. Status = STATUS_NOT_FOUND ;
  810. }
  811. }
  812. LocalFree( CompoundName.Buffer );
  813. }
  814. else
  815. {
  816. Status = STATUS_NO_MEMORY ;
  817. }
  818. return Status ;
  819. }
  820. //+---------------------------------------------------------------------------
  821. //
  822. // Function: SslTryIssuer
  823. //
  824. // Synopsis: Tries to find a user that has an issuer mapped to it.
  825. //
  826. // Arguments: [User] --
  827. // [AuthData] --
  828. // [AuthDataLen] --
  829. //
  830. // History: 5-11-98 RichardW Created
  831. //
  832. // Notes:
  833. //
  834. //----------------------------------------------------------------------------
  835. NTSTATUS
  836. SslTryIssuer(
  837. PBYTE pIssuer,
  838. DWORD cbIssuer,
  839. PUCHAR * AuthData,
  840. PULONG AuthDataLen,
  841. PWSTR * ReferencedDomain
  842. )
  843. {
  844. UNICODE_STRING IssuerName ;
  845. ULONG IssuerLength ;
  846. NTSTATUS Status ;
  847. UNICODE_STRING Cracked = { 0 };
  848. UNICODE_STRING DnsDomain = { 0 };
  849. UNICODE_STRING FlatName = { 0 };
  850. ULONG SubStatus ;
  851. const DWORD dwNameToStrFlags = CERT_X500_NAME_STR |
  852. CERT_NAME_STR_NO_PLUS_FLAG |
  853. CERT_NAME_STR_CRLF_FLAG;
  854. CERT_NAME_BLOB Issuer;
  855. *ReferencedDomain = NULL ;
  856. Issuer.pbData = pIssuer;
  857. Issuer.cbData = cbIssuer;
  858. IssuerLength = CertNameToStr( CRYPT_ASN_ENCODING,
  859. &Issuer,
  860. dwNameToStrFlags,
  861. NULL,
  862. 0 );
  863. if ( IssuerLength == 0 )
  864. {
  865. return STATUS_NO_MEMORY ;
  866. }
  867. IssuerName.MaximumLength = (USHORT)(CCH_ISSUER_HEADER + IssuerLength) * sizeof( WCHAR ) ;
  868. IssuerName.Buffer = LocalAlloc( LMEM_FIXED, IssuerName.MaximumLength );
  869. if ( IssuerName.Buffer )
  870. {
  871. wcscpy( IssuerName.Buffer, ISSUER_HEADER );
  872. IssuerLength = CertNameToStrW(CRYPT_ASN_ENCODING,
  873. &Issuer,
  874. dwNameToStrFlags,
  875. IssuerName.Buffer + CCH_ISSUER_HEADER,
  876. IssuerLength );
  877. ConvertNameString(&IssuerName);
  878. Status = LsaTable->GetAuthDataForUser( &IssuerName,
  879. SecNameAlternateId,
  880. &SslNamePrefix,
  881. AuthData,
  882. AuthDataLen,
  883. &FlatName );
  884. if ( FlatName.Length )
  885. {
  886. LsaTable->AuditAccountLogon(
  887. SE_AUDITID_ACCOUNT_MAPPED,
  888. (BOOLEAN) NT_SUCCESS( Status ),
  889. &SslPackageName,
  890. &IssuerName,
  891. &FlatName,
  892. Status );
  893. LsaTable->FreeLsaHeap( FlatName.Buffer );
  894. }
  895. if ( Status == STATUS_NOT_FOUND )
  896. {
  897. Status = LsaTable->CrackSingleName(
  898. DS_ALT_SECURITY_IDENTITIES_NAME,
  899. TRUE,
  900. &IssuerName,
  901. &SslNamePrefix,
  902. DS_NT4_ACCOUNT_NAME,
  903. &Cracked,
  904. &DnsDomain,
  905. &SubStatus );
  906. if ( NT_SUCCESS( Status ) )
  907. {
  908. if ( SubStatus == 0 )
  909. {
  910. *ReferencedDomain = DnsDomain.Buffer ;
  911. DnsDomain.Buffer = NULL;
  912. }
  913. if(Cracked.Buffer != NULL)
  914. {
  915. LsaTable->FreeLsaHeap( Cracked.Buffer );
  916. }
  917. if(DnsDomain.Buffer != NULL)
  918. {
  919. LsaTable->FreeLsaHeap( DnsDomain.Buffer );
  920. }
  921. Status = STATUS_NOT_FOUND ;
  922. }
  923. }
  924. LocalFree(IssuerName.Buffer);
  925. }
  926. else
  927. {
  928. Status = STATUS_NO_MEMORY ;
  929. }
  930. return Status ;
  931. }
  932. //+---------------------------------------------------------------------------
  933. //
  934. // Function: SslMapCertToUserPac
  935. //
  936. // Synopsis: Maps a certificate to a user (hopefully) and the PAC,
  937. //
  938. // Arguments: [Request] --
  939. // [UserPac] --
  940. // [UserPacLen] --
  941. //
  942. // History: 5-11-98 RichardW Created
  943. //
  944. // Notes:
  945. //
  946. //----------------------------------------------------------------------------
  947. NTSTATUS
  948. SslMapCertToUserPac(
  949. IN PSSL_CERT_LOGON_REQ Request,
  950. OUT PUCHAR * UserPac,
  951. OUT PULONG UserPacLen,
  952. OUT PWSTR * ReferencedDomain
  953. )
  954. {
  955. PCCERT_CONTEXT User ;
  956. NTSTATUS Status = STATUS_LOGON_FAILURE;
  957. NTSTATUS SubStatus = STATUS_NOT_FOUND;
  958. UNICODE_STRING UserName ;
  959. HANDLE UserHandle ;
  960. ULONG i;
  961. *ReferencedDomain = NULL;
  962. DebugLog(( DEB_TRACE_MAPPER, "SslMapCertToUserPac called\n" ));
  963. User = CertCreateCertificateContext( X509_ASN_ENCODING,
  964. (PBYTE)Request + Request->OffsetCertificate,
  965. Request->CertLength );
  966. if ( !User )
  967. {
  968. Status = STATUS_NO_MEMORY ;
  969. goto Cleanup ;
  970. }
  971. //
  972. // First, try the UPN
  973. //
  974. if(Request->Flags & REQ_UPN_MAPPING)
  975. {
  976. DebugLog(( DEB_TRACE_MAPPER, "Trying UPN mapping\n" ));
  977. Status = SslTryUpn( User,
  978. UserPac,
  979. UserPacLen,
  980. ReferencedDomain );
  981. if ( NT_SUCCESS( Status ) ||
  982. ( *ReferencedDomain ) )
  983. {
  984. goto Cleanup;
  985. }
  986. DebugLog(( DEB_TRACE_MAPPER, "Failed with error 0x%x\n", Status ));
  987. }
  988. //
  989. // Swing and a miss. Try the constructed issuer+subject name
  990. //
  991. if(Request->Flags & REQ_SUBJECT_MAPPING)
  992. {
  993. DebugLog(( DEB_TRACE_MAPPER, "Trying Subject mapping\n" ));
  994. Status = SslTryCompoundName( User,
  995. UserPac,
  996. UserPacLen,
  997. ReferencedDomain );
  998. if ( NT_SUCCESS( Status ) ||
  999. ( *ReferencedDomain ) )
  1000. {
  1001. goto Cleanup;
  1002. }
  1003. DebugLog(( DEB_TRACE_MAPPER, "Failed with error 0x%x\n", Status ));
  1004. // Return error code from issuer+subject name mapping
  1005. // in preference to the error code from many-to-one mapping.
  1006. SubStatus = Status;
  1007. }
  1008. //
  1009. // Strike two. Try the issuer for a many-to-one mapping:
  1010. //
  1011. if(Request->Flags & REQ_ISSUER_MAPPING)
  1012. {
  1013. DebugLog(( DEB_TRACE_MAPPER, "Trying issuer mapping\n" ));
  1014. if(Request->Flags & REQ_ISSUER_CHAIN_MAPPING)
  1015. {
  1016. // Loop through each issuer in the certificate chain.
  1017. for(i = 0; i < Request->CertCount; i++)
  1018. {
  1019. Status = SslTryIssuer( (PBYTE)Request + Request->NameInfo[i].IssuerOffset,
  1020. Request->NameInfo[i].IssuerLength,
  1021. UserPac,
  1022. UserPacLen,
  1023. ReferencedDomain );
  1024. if ( NT_SUCCESS( Status ) ||
  1025. ( *ReferencedDomain ) )
  1026. {
  1027. goto Cleanup;
  1028. }
  1029. }
  1030. }
  1031. else
  1032. {
  1033. // Extract the issuer name from the certificate and try
  1034. // to map it.
  1035. Status = SslTryIssuer( User->pCertInfo->Issuer.pbData,
  1036. User->pCertInfo->Issuer.cbData,
  1037. UserPac,
  1038. UserPacLen,
  1039. ReferencedDomain );
  1040. if ( NT_SUCCESS( Status ) ||
  1041. ( *ReferencedDomain ) )
  1042. {
  1043. goto Cleanup;
  1044. }
  1045. }
  1046. DebugLog(( DEB_TRACE_MAPPER, "Failed with error 0x%x\n", Status ));
  1047. }
  1048. //
  1049. // Certificate mapping failed. Decide what error code to return.
  1050. //
  1051. if(Status == STATUS_OBJECT_NAME_COLLISION ||
  1052. SubStatus == STATUS_OBJECT_NAME_COLLISION)
  1053. {
  1054. Status = SEC_E_MULTIPLE_ACCOUNTS;
  1055. }
  1056. else if(Status != STATUS_NO_MEMORY)
  1057. {
  1058. Status = STATUS_LOGON_FAILURE ;
  1059. }
  1060. Cleanup:
  1061. if ( User )
  1062. {
  1063. CertFreeCertificateContext( User );
  1064. }
  1065. DebugLog(( DEB_TRACE_MAPPER, "SslMapCertToUserPac returned 0x%x\n", Status ));
  1066. return Status ;
  1067. }
  1068. DWORD
  1069. WINAPI
  1070. MapperVerifyClientChain(
  1071. PCCERT_CONTEXT pCertContext,
  1072. DWORD dwMapperFlags,
  1073. DWORD * pdwMethods,
  1074. NTSTATUS * pVerifyStatus,
  1075. PCCERT_CHAIN_CONTEXT *ppChainContext) // optional
  1076. {
  1077. DWORD dwCertFlags = 0;
  1078. DWORD dwIgnoreErrors = 0;
  1079. NTSTATUS Status;
  1080. *pdwMethods = 0;
  1081. *pVerifyStatus = STATUS_SUCCESS;
  1082. DebugLog(( DEB_TRACE_MAPPER, "Checking to see if cert is verified.\n" ));
  1083. if(dwMapperFlags & SCH_FLAG_REVCHECK_END_CERT)
  1084. dwCertFlags |= CERT_CHAIN_REVOCATION_CHECK_END_CERT;
  1085. if(dwMapperFlags & SCH_FLAG_REVCHECK_CHAIN)
  1086. dwCertFlags |= CERT_CHAIN_REVOCATION_CHECK_CHAIN;
  1087. if(dwMapperFlags & SCH_FLAG_REVCHECK_CHAIN_EXCLUDE_ROOT)
  1088. dwCertFlags |= CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT;
  1089. if(dwMapperFlags & SCH_FLAG_IGNORE_NO_REVOCATION_CHECK)
  1090. dwIgnoreErrors |= CRED_FLAG_IGNORE_NO_REVOCATION_CHECK;
  1091. if(dwMapperFlags & SCH_FLAG_IGNORE_REVOCATION_OFFLINE)
  1092. dwIgnoreErrors |= CRED_FLAG_IGNORE_REVOCATION_OFFLINE;
  1093. // Check to see if the certificate chain is properly signed all the way
  1094. // up and that we trust the issuer of the root certificate.
  1095. Status = VerifyClientCertificate(pCertContext,
  1096. dwCertFlags,
  1097. dwIgnoreErrors,
  1098. CERT_CHAIN_POLICY_SSL,
  1099. ppChainContext);
  1100. if(!NT_SUCCESS(Status))
  1101. {
  1102. DebugLog((DEB_WARN, "Client certificate failed to verify with SSL policy (0x%x)\n", Status));
  1103. LogBogusClientCertEvent(pCertContext, Status);
  1104. return Status;
  1105. }
  1106. // Turn on Subject and Issuer mapping.
  1107. *pdwMethods |= REQ_SUBJECT_MAPPING | REQ_ISSUER_MAPPING;
  1108. // Check to see if the certificate chain is valid for UPN mapping.
  1109. Status = VerifyClientCertificate(pCertContext,
  1110. dwCertFlags,
  1111. dwIgnoreErrors,
  1112. CERT_CHAIN_POLICY_NT_AUTH,
  1113. NULL);
  1114. if(NT_SUCCESS(Status))
  1115. {
  1116. // Turn on UPN mapping.
  1117. *pdwMethods |= REQ_UPN_MAPPING;
  1118. }
  1119. else
  1120. {
  1121. DebugLog((DEB_WARN, "Client certificate failed to verify with NT_AUTH policy (0x%x)\n", Status));
  1122. LogFastMappingFailureEvent(pCertContext, Status);
  1123. *pVerifyStatus = Status;
  1124. }
  1125. DebugLog((DEB_TRACE, "Client certificate verified with methods: 0x%x\n", *pdwMethods));
  1126. return SEC_E_OK;
  1127. }
  1128. DWORD
  1129. WINAPI
  1130. SslLocalMapCredential(
  1131. IN PHMAPPER Mapper,
  1132. IN DWORD CredentialType,
  1133. VOID const *pCredential,
  1134. VOID const *pAuthority,
  1135. OUT HLOCATOR * phLocator
  1136. )
  1137. {
  1138. PCCERT_CONTEXT pCert = (PCERT_CONTEXT)pCredential;
  1139. PMSV1_0_PASSTHROUGH_RESPONSE Response = NULL ;
  1140. PSSL_CERT_LOGON_REQ pRequest = NULL;
  1141. PSSL_CERT_LOGON_RESP CertResp ;
  1142. DWORD cbRequest;
  1143. PUCHAR Pac = NULL ;
  1144. ULONG PacLength ;
  1145. PUCHAR ExpandedPac = NULL ;
  1146. ULONG ExpandedPacLength ;
  1147. NTSTATUS Status ;
  1148. NTSTATUS VerifyStatus ;
  1149. HANDLE Token ;
  1150. LUID LogonId ;
  1151. DWORD dwMethods ;
  1152. PWSTR ReferencedDomain ;
  1153. UNICODE_STRING DomainName ;
  1154. UNICODE_STRING AccountDomain = { 0 };
  1155. PCCERT_CHAIN_CONTEXT pChainContext = NULL;
  1156. DebugLog(( DEB_TRACE_MAPPER, "SslLocalMapCredential, context %x\n", Mapper ));
  1157. if ( CredentialType != X509_ASN_CHAIN )
  1158. {
  1159. return( SEC_E_UNKNOWN_CREDENTIALS );
  1160. }
  1161. //
  1162. // Validate client certificate, and obtain pointer to
  1163. // entire certificate chain.
  1164. //
  1165. Status = MapperVerifyClientChain(pCert,
  1166. Mapper->m_dwFlags,
  1167. &dwMethods,
  1168. &VerifyStatus,
  1169. &pChainContext);
  1170. if(FAILED(Status))
  1171. {
  1172. return Status;
  1173. }
  1174. //
  1175. // Build the logon request.
  1176. //
  1177. Status = SslBuildCertLogonRequest(pChainContext,
  1178. dwMethods,
  1179. &pRequest,
  1180. &cbRequest);
  1181. CertFreeCertificateChain(pChainContext);
  1182. pChainContext = NULL;
  1183. if(FAILED(Status))
  1184. {
  1185. return Status;
  1186. }
  1187. Status = SslMapCertToUserPac(
  1188. pRequest,
  1189. &Pac,
  1190. &PacLength,
  1191. &ReferencedDomain );
  1192. if ( !NT_SUCCESS( Status ) &&
  1193. ( ReferencedDomain != NULL ) )
  1194. {
  1195. //
  1196. // Didn't find it at this DC, but another domain appears to
  1197. // have the mapping. Forward it there:
  1198. //
  1199. RtlInitUnicodeString( &DomainName, ReferencedDomain );
  1200. Status = SslMapCertAtDC(
  1201. &DomainName,
  1202. pRequest,
  1203. pRequest->Length,
  1204. &Response );
  1205. if ( NT_SUCCESS( Status ) )
  1206. {
  1207. CertResp = (PSSL_CERT_LOGON_RESP) Response->ValidationData ;
  1208. Pac = (((PUCHAR) CertResp) + CertResp->OffsetAuthData);
  1209. PacLength = CertResp->AuthDataLength ;
  1210. //
  1211. // older servers (pre 2010 or so) won't return the full structure,
  1212. // so we need to examine it carefully.
  1213. if ( CertResp->Length - CertResp->AuthDataLength <= sizeof( SSL_CERT_LOGON_RESP ))
  1214. {
  1215. AccountDomain = SslDomainName ;
  1216. }
  1217. else
  1218. {
  1219. if ( CertResp->DomainLength < 65536 )
  1220. {
  1221. AccountDomain.Length = (USHORT) CertResp->DomainLength ;
  1222. AccountDomain.MaximumLength = AccountDomain.Length ;
  1223. AccountDomain.Buffer = (PWSTR) (((PUCHAR) CertResp) + CertResp->OffsetDomain );
  1224. }
  1225. else
  1226. {
  1227. AccountDomain = SslDomainName ;
  1228. }
  1229. }
  1230. }
  1231. LsaTable->FreeLsaHeap( ReferencedDomain );
  1232. }
  1233. else
  1234. {
  1235. AccountDomain = SslDomainName ;
  1236. }
  1237. if ( NT_SUCCESS( Status ) )
  1238. {
  1239. Status = LsaTable->ExpandAuthDataForDomain(
  1240. Pac,
  1241. PacLength,
  1242. NULL,
  1243. &ExpandedPac,
  1244. &ExpandedPacLength );
  1245. if ( NT_SUCCESS( Status ) )
  1246. {
  1247. //
  1248. // Since we're about to replace the PAC
  1249. // pointer, determine if we got it indirectly
  1250. // (in the response from a remote server)
  1251. // or directly from this DC
  1252. //
  1253. if ( Response == NULL )
  1254. {
  1255. //
  1256. // This is a direct one. Free the old
  1257. // copy
  1258. //
  1259. LsaTable->FreeLsaHeap( Pac );
  1260. }
  1261. Pac = ExpandedPac ;
  1262. PacLength = ExpandedPacLength ;
  1263. if ( Response == NULL )
  1264. {
  1265. //
  1266. // If we don't have a response, then the pac
  1267. // will get freed. If it is out of the response
  1268. // then leave it set, and it will be caught in
  1269. // the cleanup.
  1270. //
  1271. ExpandedPac = NULL ;
  1272. }
  1273. }
  1274. }
  1275. if ( NT_SUCCESS( Status ) )
  1276. {
  1277. VerifyStatus = STATUS_SUCCESS;
  1278. Status = SslCreateTokenFromPac( Pac,
  1279. PacLength,
  1280. &AccountDomain,
  1281. &LogonId,
  1282. &Token );
  1283. if ( NT_SUCCESS( Status ) )
  1284. {
  1285. *phLocator = (HLOCATOR) Token ;
  1286. }
  1287. }
  1288. if(pRequest)
  1289. {
  1290. LocalFree(pRequest);
  1291. }
  1292. if ( Response )
  1293. {
  1294. LsaTable->FreeReturnBuffer( Response );
  1295. }
  1296. else
  1297. {
  1298. LsaTable->FreeLsaHeap( Pac );
  1299. }
  1300. if ( ExpandedPac )
  1301. {
  1302. LsaTable->FreeLsaHeap( ExpandedPac );
  1303. }
  1304. if(!NT_SUCCESS(Status))
  1305. {
  1306. DebugLog((DEB_WARN, "Certificate mapping failed (0x%x)\n", Status));
  1307. LogCertMappingFailureEvent(Status);
  1308. if(!NT_SUCCESS(VerifyStatus))
  1309. {
  1310. // Return certificate validation error code, unless the mapper
  1311. // error has already been mapped to a proper sspi error code.
  1312. if(HRESULT_FACILITY(Status) != FACILITY_SECURITY)
  1313. {
  1314. Status = VerifyStatus;
  1315. }
  1316. }
  1317. }
  1318. return ( Status );
  1319. }
  1320. NTSTATUS
  1321. NTAPI
  1322. SslDoClientRequest(
  1323. IN PLSA_CLIENT_REQUEST ClientRequest,
  1324. IN PVOID ProtocolSubmitBuffer,
  1325. IN PVOID ClientBufferBase,
  1326. IN ULONG SubmitBufferLen,
  1327. OUT PVOID * ProtocolReturnBuffer,
  1328. OUT PULONG ReturnBufferLength,
  1329. OUT PNTSTATUS ProtocolStatus
  1330. )
  1331. {
  1332. NTSTATUS Status ;
  1333. PSSL_CERT_LOGON_REQ Request ;
  1334. PSSL_CERT_LOGON_RESP Response, IndirectResponse ;
  1335. PUCHAR Pac = NULL ;
  1336. PUCHAR ExpandedPac = NULL ;
  1337. ULONG PacLength ;
  1338. ULONG ExpandedPacLength ;
  1339. PWSTR ReferencedDomain = NULL;
  1340. PWSTR FirstDot ;
  1341. UNICODE_STRING DomainName = { 0 };
  1342. PMSV1_0_PASSTHROUGH_RESPONSE MsvResponse = NULL ;
  1343. DebugLog(( DEB_TRACE_MAPPER, "Handling request to do mapping\n" ));
  1344. if ( ARGUMENT_PRESENT( ProtocolReturnBuffer ) )
  1345. {
  1346. *ProtocolReturnBuffer = NULL ;
  1347. }
  1348. //
  1349. // Attempt to map the certificate locally.
  1350. //
  1351. Request = (PSSL_CERT_LOGON_REQ) ProtocolSubmitBuffer ;
  1352. Status = SslMapCertToUserPac(
  1353. Request,
  1354. &Pac,
  1355. &PacLength,
  1356. &ReferencedDomain );
  1357. DebugLog(( DEB_TRACE_MAPPER, "Local lookup returns %x\n", Status ));
  1358. if ( !NT_SUCCESS( Status ) &&
  1359. ( ReferencedDomain != NULL ) )
  1360. {
  1361. //
  1362. // Didn't find it at this DC, but another domain appears to
  1363. // have the mapping. Forward it there:
  1364. //
  1365. RtlInitUnicodeString( &DomainName, ReferencedDomain );
  1366. DsysAssert( !DnsNameCompare_W( ReferencedDomain, SslDnsDomainName ) );
  1367. DsysAssert( !RtlEqualUnicodeString( &DomainName, &SslDomainName, TRUE ) );
  1368. if ( DnsNameCompare_W( ReferencedDomain, SslDnsDomainName ) ||
  1369. RtlEqualUnicodeString( &DomainName, &SslDomainName, TRUE ) )
  1370. {
  1371. DebugLog(( DEB_TRACE_MAPPER, "GC is out of sync, bailing on this user\n" ));
  1372. Status = STATUS_LOGON_FAILURE ;
  1373. }
  1374. else
  1375. {
  1376. DebugLog(( DEB_TRACE_MAPPER, "Mapping certificate at DC for domain %ws\n",
  1377. ReferencedDomain ));
  1378. Status = SslMapCertAtDC(
  1379. &DomainName,
  1380. Request,
  1381. Request->Length,
  1382. &MsvResponse );
  1383. if ( NT_SUCCESS( Status ) )
  1384. {
  1385. IndirectResponse = (PSSL_CERT_LOGON_RESP) MsvResponse->ValidationData ;
  1386. Pac = (((PUCHAR) IndirectResponse) + IndirectResponse->OffsetAuthData);
  1387. PacLength = IndirectResponse->AuthDataLength ;
  1388. FirstDot = wcschr( ReferencedDomain, L'.' );
  1389. if ( FirstDot )
  1390. {
  1391. *FirstDot = L'\0';
  1392. RtlInitUnicodeString( &DomainName, ReferencedDomain );
  1393. }
  1394. if ( IndirectResponse->Length - IndirectResponse->AuthDataLength <= sizeof( SSL_CERT_LOGON_RESP ))
  1395. {
  1396. //
  1397. // use the first token from the referenced domain
  1398. //
  1399. NOTHING ;
  1400. }
  1401. else
  1402. {
  1403. if ( IndirectResponse->DomainLength < 65536 )
  1404. {
  1405. DomainName.Length = (USHORT) IndirectResponse->DomainLength ;
  1406. DomainName.MaximumLength = DomainName.Length ;
  1407. DomainName.Buffer = (PWSTR) (((PUCHAR) IndirectResponse) + IndirectResponse->OffsetDomain );
  1408. }
  1409. else
  1410. {
  1411. NOTHING ;
  1412. }
  1413. }
  1414. }
  1415. }
  1416. }
  1417. else
  1418. {
  1419. DomainName = SslDomainName ;
  1420. }
  1421. if ( NT_SUCCESS( Status ) )
  1422. {
  1423. //
  1424. // expand resource groups
  1425. //
  1426. Status = LsaTable->ExpandAuthDataForDomain(
  1427. Pac,
  1428. PacLength,
  1429. NULL,
  1430. &ExpandedPac,
  1431. &ExpandedPacLength );
  1432. if ( NT_SUCCESS( Status ) )
  1433. {
  1434. //
  1435. // Careful manipulation of pointers to handle
  1436. // the free cases in the cleanup. This is
  1437. // better explained up one function where
  1438. // the expand call is also made.
  1439. //
  1440. if ( MsvResponse == NULL )
  1441. {
  1442. LsaTable->FreeLsaHeap( Pac );
  1443. }
  1444. Pac = ExpandedPac ;
  1445. PacLength = ExpandedPacLength ;
  1446. if ( MsvResponse == NULL )
  1447. {
  1448. ExpandedPac = NULL ;
  1449. }
  1450. }
  1451. }
  1452. if ( !NT_SUCCESS( Status ) )
  1453. {
  1454. *ReturnBufferLength = 0;
  1455. *ProtocolStatus = Status ;
  1456. Status = STATUS_SUCCESS ;
  1457. goto Cleanup ;
  1458. }
  1459. //
  1460. // Construct the response blob:
  1461. //
  1462. Response = VirtualAlloc(
  1463. NULL,
  1464. sizeof( SSL_CERT_LOGON_RESP ) + PacLength + DomainName.Length,
  1465. MEM_COMMIT,
  1466. PAGE_READWRITE );
  1467. if ( Response )
  1468. {
  1469. Response->MessageType = SSL_LOOKUP_CERT_MESSAGE;
  1470. Response->Length = sizeof( SSL_CERT_LOGON_RESP ) +
  1471. PacLength + DomainName.Length ;
  1472. Response->OffsetAuthData = sizeof( SSL_CERT_LOGON_RESP );
  1473. Response->AuthDataLength = PacLength ;
  1474. RtlCopyMemory(
  1475. ( Response + 1 ),
  1476. Pac,
  1477. PacLength );
  1478. Response->OffsetDomain = sizeof( SSL_CERT_LOGON_RESP ) + PacLength ;
  1479. Response->DomainLength = DomainName.Length ;
  1480. RtlCopyMemory( (PUCHAR) Response + Response->OffsetDomain,
  1481. DomainName.Buffer,
  1482. DomainName.Length );
  1483. *ProtocolReturnBuffer = Response ;
  1484. *ReturnBufferLength = Response->Length ;
  1485. *ProtocolStatus = STATUS_SUCCESS ;
  1486. Status = STATUS_SUCCESS ;
  1487. }
  1488. else
  1489. {
  1490. Status = STATUS_NO_MEMORY ;
  1491. }
  1492. Cleanup:
  1493. if ( MsvResponse == NULL )
  1494. {
  1495. LsaTable->FreeLsaHeap( Pac );
  1496. }
  1497. else
  1498. {
  1499. LsaTable->FreeReturnBuffer( MsvResponse );
  1500. }
  1501. if ( ExpandedPac )
  1502. {
  1503. LsaTable->FreeLsaHeap( ExpandedPac );
  1504. }
  1505. if ( ReferencedDomain )
  1506. {
  1507. LsaTable->FreeLsaHeap( ReferencedDomain );
  1508. }
  1509. return Status ;
  1510. }
  1511. //+---------------------------------------------------------------------------
  1512. //
  1513. // Function: SslBuildCertLogonRequest
  1514. //
  1515. // Synopsis: Builds a certificate logon request to send to the server.
  1516. //
  1517. // Arguments: [pChainContext] --
  1518. // [dwMethods] --
  1519. // [ppRequest] --
  1520. // [pcbRequest] --
  1521. //
  1522. // History: 2-26-2001 Jbanes Created
  1523. //
  1524. // Notes: The certificate data that this function builds
  1525. // looks something like this:
  1526. //
  1527. // typedef struct _SSL_CERT_LOGON_REQ {
  1528. // ULONG MessageType ;
  1529. // ULONG Length ;
  1530. // ULONG OffsetCertficate ;
  1531. // ULONG CertLength ;
  1532. // ULONG Flags;
  1533. // ULONG CertCount;
  1534. // SSL_CERT_NAME_INFO NameInfo[1];
  1535. // } SSL_CERT_LOGON_REQ, * PSSL_CERT_LOGON_REQ ;
  1536. //
  1537. // <client certificate>
  1538. // <issuer #1 name>
  1539. // <issuer #2 name>
  1540. // ...
  1541. //
  1542. //----------------------------------------------------------------------------
  1543. NTSTATUS
  1544. WINAPI
  1545. SslBuildCertLogonRequest(
  1546. PCCERT_CHAIN_CONTEXT pChainContext,
  1547. DWORD dwMethods,
  1548. PSSL_CERT_LOGON_REQ *ppRequest,
  1549. PDWORD pcbRequest)
  1550. {
  1551. PCERT_SIMPLE_CHAIN pSimpleChain;
  1552. PCCERT_CONTEXT pCert;
  1553. PCCERT_CONTEXT pCurrentCert;
  1554. PSSL_CERT_LOGON_REQ pCertReq = NULL;
  1555. DWORD Size;
  1556. DWORD Offset;
  1557. DWORD CertCount;
  1558. NTSTATUS Status;
  1559. ULONG i;
  1560. //
  1561. // Compute the request size.
  1562. //
  1563. pSimpleChain = pChainContext->rgpChain[0];
  1564. pCert = pSimpleChain->rgpElement[0]->pCertContext;
  1565. Size = sizeof(SSL_CERT_LOGON_REQ) +
  1566. pCert->cbCertEncoded;
  1567. CertCount = 0;
  1568. for(i = 0; i < pSimpleChain->cElement; i++)
  1569. {
  1570. pCurrentCert = pSimpleChain->rgpElement[i]->pCertContext;
  1571. if(i > 0)
  1572. {
  1573. // Verify that this is not a root certificate.
  1574. if(CertCompareCertificateName(pCurrentCert->dwCertEncodingType,
  1575. &pCurrentCert->pCertInfo->Issuer,
  1576. &pCurrentCert->pCertInfo->Subject))
  1577. {
  1578. break;
  1579. }
  1580. Size += sizeof(SSL_CERT_NAME_INFO);
  1581. }
  1582. Size += pCurrentCert->pCertInfo->Issuer.cbData;
  1583. CertCount++;
  1584. }
  1585. Size = ROUND_UP_COUNT( Size, ALIGN_DWORD );
  1586. //
  1587. // Build the request.
  1588. //
  1589. pCertReq = (PSSL_CERT_LOGON_REQ)LocalAlloc(LPTR, Size);
  1590. if ( !pCertReq )
  1591. {
  1592. return SEC_E_INSUFFICIENT_MEMORY ;
  1593. }
  1594. Offset = sizeof(SSL_CERT_LOGON_REQ) + (CertCount - 1) * sizeof(SSL_CERT_NAME_INFO);
  1595. pCertReq->MessageType = SSL_LOOKUP_CERT_MESSAGE;
  1596. pCertReq->Length = Size;
  1597. pCertReq->OffsetCertificate = Offset;
  1598. pCertReq->CertLength = pCert->cbCertEncoded;
  1599. pCertReq->Flags = dwMethods | REQ_ISSUER_CHAIN_MAPPING;
  1600. RtlCopyMemory((PBYTE)pCertReq + Offset,
  1601. pCert->pbCertEncoded,
  1602. pCert->cbCertEncoded);
  1603. Offset += pCert->cbCertEncoded;
  1604. pCertReq->CertCount = CertCount;
  1605. for(i = 0; i < CertCount; i++)
  1606. {
  1607. pCurrentCert = pSimpleChain->rgpElement[i]->pCertContext;
  1608. pCertReq->NameInfo[i].IssuerOffset = Offset;
  1609. pCertReq->NameInfo[i].IssuerLength = pCurrentCert->pCertInfo->Issuer.cbData;
  1610. RtlCopyMemory((PBYTE)pCertReq + Offset,
  1611. pCurrentCert->pCertInfo->Issuer.pbData,
  1612. pCurrentCert->pCertInfo->Issuer.cbData);
  1613. Offset += pCurrentCert->pCertInfo->Issuer.cbData;
  1614. }
  1615. Offset = ROUND_UP_COUNT( Offset, ALIGN_DWORD );
  1616. #if DBG
  1617. DsysAssert(Offset == Size);
  1618. #endif
  1619. //
  1620. // Return completed request.
  1621. //
  1622. *ppRequest = pCertReq;
  1623. *pcbRequest = Size;
  1624. return STATUS_SUCCESS;
  1625. }
  1626. //+---------------------------------------------------------------------------
  1627. //
  1628. // Function: SslMapCertAtDC
  1629. //
  1630. // Synopsis: Maps a certificate to a user (hopefully) and the PAC,
  1631. //
  1632. // Arguments: [DomainName] --
  1633. // [pCredential] --
  1634. // [cbCredential] --
  1635. // [DcResponse] --
  1636. //
  1637. // History: 5-11-1998 RichardW Created
  1638. // 2-26-2001 Jbanes Added certificate chaining support.
  1639. //
  1640. // Notes: The request that gets sent to the DC looks something
  1641. // like this:
  1642. //
  1643. // typedef struct _MSV1_0_PASSTHROUGH_REQUEST {
  1644. // MSV1_0_PROTOCOL_MESSAGE_TYPE MessageType;
  1645. // UNICODE_STRING DomainName;
  1646. // UNICODE_STRING PackageName;
  1647. // ULONG DataLength;
  1648. // PUCHAR LogonData;
  1649. // ULONG Pad ;
  1650. // } MSV1_0_PASSTHROUGH_REQUEST, *PMSV1_0_PASSTHROUGH_REQUEST;
  1651. //
  1652. // <domain name>
  1653. // <package name>
  1654. // [ padding ]
  1655. //
  1656. // <credential>
  1657. // [ padding ]
  1658. //
  1659. //----------------------------------------------------------------------------
  1660. NTSTATUS
  1661. WINAPI
  1662. SslMapCertAtDC(
  1663. PUNICODE_STRING DomainName,
  1664. VOID const *pCredential,
  1665. DWORD cbCredential,
  1666. PMSV1_0_PASSTHROUGH_RESPONSE * DcResponse
  1667. )
  1668. {
  1669. PUCHAR Pac ;
  1670. ULONG PacLength ;
  1671. NTSTATUS Status ;
  1672. PMSV1_0_PASSTHROUGH_REQUEST Request ;
  1673. PMSV1_0_PASSTHROUGH_RESPONSE Response ;
  1674. DWORD Size ;
  1675. DWORD RequestSize ;
  1676. DWORD ResponseSize ;
  1677. PUCHAR Where ;
  1678. NTSTATUS SubStatus ;
  1679. #if DBG
  1680. DWORD CheckSize2 ;
  1681. #endif
  1682. DebugLog(( DEB_TRACE_MAPPER, "Remote call to DC to do the mapping\n" ));
  1683. // Reality check size of certificate.
  1684. if(cbCredential > 0x4000)
  1685. {
  1686. return SEC_E_ILLEGAL_MESSAGE;
  1687. }
  1688. Size = cbCredential;
  1689. Size = ROUND_UP_COUNT( Size, ALIGN_DWORD );
  1690. RequestSize = DomainName->Length +
  1691. SslPackageName.Length ;
  1692. RequestSize = ROUND_UP_COUNT( RequestSize, ALIGN_DWORD );
  1693. #if DBG
  1694. CheckSize2 = RequestSize ;
  1695. #endif
  1696. RequestSize += sizeof( MSV1_0_PASSTHROUGH_REQUEST ) +
  1697. Size ;
  1698. Request = (PMSV1_0_PASSTHROUGH_REQUEST) LocalAlloc( LMEM_FIXED, RequestSize );
  1699. if ( !Request )
  1700. {
  1701. return SEC_E_INSUFFICIENT_MEMORY ;
  1702. }
  1703. Where = (PUCHAR) (Request + 1);
  1704. Request->MessageType = MsV1_0GenericPassthrough ;
  1705. Request->DomainName = *DomainName ;
  1706. Request->DomainName.Buffer = (LPWSTR) Where ;
  1707. RtlCopyMemory( Where,
  1708. DomainName->Buffer,
  1709. DomainName->Length );
  1710. Where += DomainName->Length ;
  1711. Request->PackageName = SslPackageName ;
  1712. Request->PackageName.Buffer = (LPWSTR) Where ;
  1713. RtlCopyMemory( Where,
  1714. SslPackageName.Buffer,
  1715. SslPackageName.Length );
  1716. Where += SslPackageName.Length ;
  1717. Where = ROUND_UP_POINTER( Where, ALIGN_DWORD );
  1718. #if DBG
  1719. DsysAssert( (((PUCHAR) Request) + CheckSize2 + sizeof( MSV1_0_PASSTHROUGH_REQUEST ) )
  1720. == (PUCHAR) Where );
  1721. #endif
  1722. Request->LogonData = Where ;
  1723. Request->DataLength = Size ;
  1724. RtlCopyMemory( Request->LogonData,
  1725. pCredential,
  1726. cbCredential );
  1727. //
  1728. // Now, call through to our DC:
  1729. //
  1730. Status = LsaTable->CallPackage(
  1731. &SslMsvName,
  1732. Request,
  1733. RequestSize,
  1734. &Response,
  1735. &ResponseSize,
  1736. &SubStatus );
  1737. LocalFree( Request );
  1738. if ( !NT_SUCCESS( Status ) )
  1739. {
  1740. DebugLog(( DEB_TRACE_MAPPER, "SslMapCertAtDC returned status 0x%x\n", Status ));
  1741. return Status ;
  1742. }
  1743. if ( !NT_SUCCESS( SubStatus ) )
  1744. {
  1745. DebugLog(( DEB_TRACE_MAPPER, "SslMapCertAtDC returned sub-status 0x%x\n", SubStatus ));
  1746. return SubStatus ;
  1747. }
  1748. *DcResponse = Response ;
  1749. DebugLog(( DEB_TRACE_MAPPER, "SslMapCertAtDC returned 0x%x\n", STATUS_SUCCESS ));
  1750. return STATUS_SUCCESS ;
  1751. }
  1752. NTSTATUS
  1753. NTAPI
  1754. SslMapExternalCredential(
  1755. IN PLSA_CLIENT_REQUEST ClientRequest,
  1756. IN PVOID ProtocolSubmitBuffer,
  1757. IN PVOID ClientBufferBase,
  1758. IN ULONG SubmitBufferLen,
  1759. OUT PVOID * ProtocolReturnBuffer,
  1760. OUT PULONG ReturnBufferLength,
  1761. OUT PNTSTATUS ProtocolStatus
  1762. )
  1763. {
  1764. PSSL_EXTERNAL_CERT_LOGON_REQ Request;
  1765. PSSL_EXTERNAL_CERT_LOGON_RESP Response;
  1766. NT_PRODUCT_TYPE ProductType;
  1767. BOOL DC;
  1768. HMAPPER Mapper;
  1769. NTSTATUS Status;
  1770. HANDLE hUserToken = NULL;
  1771. DebugLog(( DEB_TRACE_MAPPER, "SslMapExternalCredential\n" ));
  1772. //
  1773. // Validate the input parameters.
  1774. //
  1775. if ( ARGUMENT_PRESENT( ProtocolReturnBuffer ) )
  1776. {
  1777. *ProtocolReturnBuffer = NULL ;
  1778. }
  1779. Request = (PSSL_EXTERNAL_CERT_LOGON_REQ) ProtocolSubmitBuffer ;
  1780. if(Request->Length != sizeof(SSL_EXTERNAL_CERT_LOGON_REQ))
  1781. {
  1782. return STATUS_INVALID_PARAMETER;
  1783. }
  1784. //
  1785. // Attempt to map the certificate.
  1786. //
  1787. if(RtlGetNtProductType(&ProductType))
  1788. {
  1789. DC = (ProductType == NtProductLanManNt);
  1790. }
  1791. else
  1792. {
  1793. return STATUS_NO_MEMORY ;
  1794. }
  1795. memset(&Mapper, 0, sizeof(Mapper));
  1796. Mapper.m_dwFlags = SCH_FLAG_SYSTEM_MAPPER | Request->Flags;
  1797. if(DC)
  1798. {
  1799. Status = SslLocalMapCredential( &Mapper,
  1800. Request->CredentialType,
  1801. Request->Credential,
  1802. NULL,
  1803. (PHLOCATOR)&hUserToken);
  1804. }
  1805. else
  1806. {
  1807. Status = SslRemoteMapCredential(&Mapper,
  1808. Request->CredentialType,
  1809. Request->Credential,
  1810. NULL,
  1811. (PHLOCATOR)&hUserToken);
  1812. }
  1813. if(!NT_SUCCESS(Status))
  1814. {
  1815. *ReturnBufferLength = 0;
  1816. *ProtocolStatus = Status;
  1817. Status = STATUS_SUCCESS;
  1818. goto cleanup;
  1819. }
  1820. //
  1821. // Build the response.
  1822. //
  1823. Response = VirtualAlloc(
  1824. NULL,
  1825. sizeof(SSL_EXTERNAL_CERT_LOGON_RESP),
  1826. MEM_COMMIT,
  1827. PAGE_READWRITE);
  1828. if ( Response )
  1829. {
  1830. Response->MessageType = SSL_LOOKUP_EXTERNAL_CERT_MESSAGE;
  1831. Response->Length = sizeof(SSL_EXTERNAL_CERT_LOGON_RESP);
  1832. Response->UserToken = hUserToken;
  1833. Response->Flags = 0;
  1834. *ProtocolReturnBuffer = Response;
  1835. *ReturnBufferLength = Response->Length;
  1836. *ProtocolStatus = STATUS_SUCCESS;
  1837. hUserToken = NULL;
  1838. Status = STATUS_SUCCESS;
  1839. }
  1840. else
  1841. {
  1842. Status = STATUS_NO_MEMORY;
  1843. }
  1844. cleanup:
  1845. if(hUserToken)
  1846. {
  1847. CloseHandle(hUserToken);
  1848. }
  1849. return Status;
  1850. }
  1851. DWORD
  1852. WINAPI
  1853. SslRemoteMapCredential(
  1854. IN PHMAPPER Mapper,
  1855. IN DWORD CredentialType,
  1856. VOID const *pCredential,
  1857. VOID const *pAuthority,
  1858. OUT HLOCATOR * phLocator
  1859. )
  1860. {
  1861. PCCERT_CONTEXT pCert = (PCERT_CONTEXT)pCredential;
  1862. PUCHAR Pac ;
  1863. ULONG PacLength ;
  1864. NTSTATUS Status ;
  1865. NTSTATUS VerifyStatus ;
  1866. HANDLE Token ;
  1867. LUID LogonId = { 0 };
  1868. PMSV1_0_PASSTHROUGH_RESPONSE Response ;
  1869. PSSL_CERT_LOGON_RESP CertResp ;
  1870. UNICODE_STRING AccountDomain ;
  1871. DWORD dwMethods;
  1872. PCCERT_CHAIN_CONTEXT pChainContext = NULL;
  1873. PSSL_CERT_LOGON_REQ pRequest = NULL;
  1874. DWORD cbRequest;
  1875. DebugLog(( DEB_TRACE_MAPPER, "SslRemoteMapCredential, context %x\n", Mapper ));
  1876. if ( CredentialType != X509_ASN_CHAIN )
  1877. {
  1878. return( SEC_E_UNKNOWN_CREDENTIALS );
  1879. }
  1880. //
  1881. // Validate client certificate, and obtain pointer to
  1882. // entire certificate chain.
  1883. //
  1884. Status = MapperVerifyClientChain(pCert,
  1885. Mapper->m_dwFlags,
  1886. &dwMethods,
  1887. &VerifyStatus,
  1888. &pChainContext);
  1889. if(FAILED(Status))
  1890. {
  1891. return Status;
  1892. }
  1893. //
  1894. // Build the logon request.
  1895. //
  1896. Status = SslBuildCertLogonRequest(pChainContext,
  1897. dwMethods,
  1898. &pRequest,
  1899. &cbRequest);
  1900. CertFreeCertificateChain(pChainContext);
  1901. pChainContext = NULL;
  1902. if(FAILED(Status))
  1903. {
  1904. return Status;
  1905. }
  1906. //
  1907. // Send the request to the DC.
  1908. //
  1909. Status = SslMapCertAtDC(
  1910. &SslDomainName,
  1911. pRequest,
  1912. cbRequest,
  1913. &Response );
  1914. LocalFree(pRequest);
  1915. pRequest = NULL;
  1916. if ( !NT_SUCCESS( Status ) )
  1917. {
  1918. LsaTable->AuditLogon(
  1919. Status,
  1920. VerifyStatus,
  1921. &SslNullString,
  1922. &SslNullString,
  1923. NULL,
  1924. NULL,
  1925. Network,
  1926. &SslTokenSource,
  1927. &LogonId );
  1928. LogCertMappingFailureEvent(Status);
  1929. if(!NT_SUCCESS(VerifyStatus))
  1930. {
  1931. // Return certificate validation error code, unless the mapper
  1932. // error has already been mapped to a proper sspi error code.
  1933. if(HRESULT_FACILITY(Status) != FACILITY_SECURITY)
  1934. {
  1935. Status = VerifyStatus;
  1936. }
  1937. }
  1938. return Status ;
  1939. }
  1940. //
  1941. // Ok, we got mapping data. Try to use it:
  1942. //
  1943. CertResp = (PSSL_CERT_LOGON_RESP) Response->ValidationData ;
  1944. //
  1945. // older servers (pre 2010 or so) won't return the full structure,
  1946. // so we need to examine it carefully.
  1947. if ( CertResp->Length - CertResp->AuthDataLength <= sizeof( SSL_CERT_LOGON_RESP ))
  1948. {
  1949. AccountDomain = SslDomainName ;
  1950. }
  1951. else
  1952. {
  1953. if ( CertResp->DomainLength < 65536 )
  1954. {
  1955. AccountDomain.Length = (USHORT) CertResp->DomainLength ;
  1956. AccountDomain.MaximumLength = AccountDomain.Length ;
  1957. AccountDomain.Buffer = (PWSTR) (((PUCHAR) CertResp) + CertResp->OffsetDomain );
  1958. }
  1959. else
  1960. {
  1961. AccountDomain = SslDomainName ;
  1962. }
  1963. }
  1964. Status = SslCreateTokenFromPac( (((PUCHAR) CertResp) + CertResp->OffsetAuthData),
  1965. CertResp->AuthDataLength,
  1966. &AccountDomain,
  1967. &LogonId,
  1968. &Token );
  1969. if ( NT_SUCCESS( Status ) )
  1970. {
  1971. *phLocator = (HLOCATOR) Token ;
  1972. }
  1973. else
  1974. {
  1975. LogCertMappingFailureEvent(Status);
  1976. }
  1977. LsaTable->FreeReturnBuffer( Response );
  1978. return ( Status );
  1979. }
  1980. DWORD
  1981. WINAPI
  1982. SslLocalCloseLocator(
  1983. IN PHMAPPER Mapper,
  1984. IN HLOCATOR Locator
  1985. )
  1986. {
  1987. DebugLog(( DEB_TRACE_MAPPER, "CloseLocator, context %x\n", Mapper ));
  1988. NtClose( (HANDLE) Locator );
  1989. return( SEC_E_OK );
  1990. }
  1991. DWORD
  1992. WINAPI
  1993. SslLocalGetAccessToken(
  1994. IN PHMAPPER Mapper,
  1995. IN HLOCATOR Locator,
  1996. OUT HANDLE *Token
  1997. )
  1998. {
  1999. DebugLog(( DEB_TRACE_MAPPER, "GetAccessToken, context %x\n", Mapper ));
  2000. *Token = (HANDLE) Locator ;
  2001. return( SEC_E_OK );
  2002. }
  2003. BOOL
  2004. SslRelocateToken(
  2005. IN HLOCATOR Locator,
  2006. OUT HLOCATOR * NewLocator)
  2007. {
  2008. NTSTATUS Status ;
  2009. Status = LsaTable->DuplicateHandle( (HANDLE) Locator,
  2010. (PHANDLE) NewLocator );
  2011. if ( NT_SUCCESS( Status ) )
  2012. {
  2013. return( TRUE );
  2014. }
  2015. return( FALSE );
  2016. }
  2017. #if 0
  2018. DWORD
  2019. TestExternalMapper(
  2020. PCCERT_CONTEXT pCertContext)
  2021. {
  2022. NTSTATUS Status;
  2023. NTSTATUS AuthPackageStatus;
  2024. SSL_EXTERNAL_CERT_LOGON_REQ Request;
  2025. PSSL_EXTERNAL_CERT_LOGON_RESP pResponse;
  2026. ULONG ResponseLength;
  2027. UNICODE_STRING PackageName;
  2028. //
  2029. // Build request.
  2030. //
  2031. memset(&Request, 0, sizeof(SSL_EXTERNAL_CERT_LOGON_REQ));
  2032. Request.MessageType = SSL_LOOKUP_EXTERNAL_CERT_MESSAGE;
  2033. Request.Length = sizeof(SSL_EXTERNAL_CERT_LOGON_REQ);
  2034. Request.CredentialType = X509_ASN_CHAIN;
  2035. Request.Credential = (PVOID)pCertContext;
  2036. //
  2037. // Call security package (must make call as local system).
  2038. //
  2039. RtlInitUnicodeString(&PackageName, L"Schannel");
  2040. Status = LsaICallPackage(
  2041. &PackageName,
  2042. &Request,
  2043. Request.Length,
  2044. (PVOID *)&pResponse,
  2045. &ResponseLength,
  2046. &AuthPackageStatus
  2047. );
  2048. if(!NT_SUCCESS(Status))
  2049. {
  2050. return Status;
  2051. }
  2052. if(NT_SUCCESS(AuthPackageStatus))
  2053. {
  2054. //
  2055. // Mapping was successful.
  2056. //
  2057. }
  2058. LsaIFreeReturnBuffer( pResponse );
  2059. return ERROR_SUCCESS;
  2060. }
  2061. #endif