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.

3482 lines
92 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 "wincrypt.h"
  37. #include <msaudite.h>
  38. #include <mapper.h>
  39. #include <kerberos.h>
  40. #include <sidfilter.h>
  41. #include <lsaitf.h>
  42. LONG WINAPI
  43. SslLocalRefMapper(
  44. PHMAPPER Mapper);
  45. LONG WINAPI
  46. SslLocalDerefMapper(
  47. PHMAPPER Mapper);
  48. DWORD WINAPI
  49. SslLocalGetIssuerList(
  50. IN PHMAPPER Mapper,
  51. IN PVOID Reserved,
  52. OUT PBYTE pIssuerList,
  53. OUT PDWORD IssuerListLength);
  54. DWORD WINAPI
  55. SslLocalGetChallenge(
  56. IN PHMAPPER Mapper,
  57. IN PUCHAR AuthenticatorId,
  58. IN DWORD AuthenticatorIdLength,
  59. OUT PUCHAR Challenge,
  60. OUT DWORD * ChallengeLength);
  61. DWORD WINAPI
  62. SslLocalMapCredential(
  63. IN PHMAPPER Mapper,
  64. IN DWORD CredentialType,
  65. VOID const *pCredential,
  66. VOID const *pAuthority,
  67. OUT HLOCATOR * phLocator);
  68. DWORD WINAPI
  69. SslRemoteMapCredential(
  70. IN PHMAPPER Mapper,
  71. IN DWORD CredentialType,
  72. VOID const *pCredential,
  73. VOID const *pAuthority,
  74. OUT HLOCATOR * phLocator);
  75. DWORD WINAPI
  76. SslLocalCloseLocator(
  77. IN PHMAPPER Mapper,
  78. IN HLOCATOR Locator);
  79. DWORD WINAPI
  80. SslLocalGetAccessToken(
  81. IN PHMAPPER Mapper,
  82. IN HLOCATOR Locator,
  83. OUT HANDLE *Token);
  84. MAPPER_VTABLE SslLocalTable = { SslLocalRefMapper,
  85. SslLocalDerefMapper,
  86. SslLocalGetIssuerList,
  87. SslLocalGetChallenge,
  88. SslLocalMapCredential,
  89. SslLocalGetAccessToken,
  90. SslLocalCloseLocator
  91. };
  92. MAPPER_VTABLE SslRemoteTable = {SslLocalRefMapper,
  93. SslLocalDerefMapper,
  94. SslLocalGetIssuerList,
  95. SslLocalGetChallenge,
  96. SslRemoteMapCredential,
  97. SslLocalGetAccessToken,
  98. SslLocalCloseLocator
  99. };
  100. typedef struct _SSL_MAPPER_CONTEXT {
  101. HMAPPER Mapper ;
  102. LONG Ref ;
  103. } SSL_MAPPER_CONTEXT, * PSSL_MAPPER_CONTEXT ;
  104. NTSTATUS
  105. WINAPI
  106. SslBuildCertLogonRequest(
  107. PCCERT_CHAIN_CONTEXT pChainContext,
  108. DWORD dwMethods,
  109. PSSL_CERT_LOGON_REQ *ppRequest,
  110. PDWORD pcbRequest);
  111. NTSTATUS
  112. WINAPI
  113. SslMapCertAtDC(
  114. IN PUNICODE_STRING DomainName,
  115. IN VOID const *pCredential,
  116. IN DWORD cbCredential,
  117. IN BOOL IsDC,
  118. OUT PUCHAR *UserPac,
  119. OUT PULONG UserPacLen,
  120. OUT PMSV1_0_PASSTHROUGH_RESPONSE * DcResponse);
  121. SECURITY_STRING SslNullString = { 0, sizeof( WCHAR ), L"" };
  122. HANDLE SslLogonHandle = NULL;
  123. ULONG SslKerberosPackageId = 0;
  124. ULONG SslMsvPackageId = 0;
  125. TOKEN_GROUPS *SslPackageSid = 0;
  126. NTSTATUS
  127. SslInitSystemMapper(void)
  128. {
  129. NTSTATUS Status;
  130. ULONG Dummy;
  131. LSA_STRING Name;
  132. //
  133. // Get handle to Kerberos package.
  134. //
  135. Status = LsaRegisterLogonProcess(
  136. &SslPackageNameA,
  137. &SslLogonHandle,
  138. &Dummy
  139. );
  140. if(!NT_SUCCESS(Status))
  141. {
  142. return SP_LOG_RESULT(Status);
  143. }
  144. RtlInitString(&Name,
  145. MICROSOFT_KERBEROS_NAME_A );
  146. Status = LsaLookupAuthenticationPackage(
  147. SslLogonHandle,
  148. &Name,
  149. &SslKerberosPackageId
  150. );
  151. if (!NT_SUCCESS(Status))
  152. {
  153. return SP_LOG_RESULT(Status);
  154. }
  155. //
  156. // Get handle to NTLM package.
  157. //
  158. RtlInitString(&Name,
  159. MSV1_0_PACKAGE_NAME );
  160. Status = LsaLookupAuthenticationPackage(
  161. SslLogonHandle,
  162. &Name,
  163. &SslMsvPackageId
  164. );
  165. if (!NT_SUCCESS(Status))
  166. {
  167. return SP_LOG_RESULT(Status);
  168. }
  169. //
  170. // Build schannel package SID.
  171. //
  172. {
  173. SID_IDENTIFIER_AUTHORITY PackageSidAuthority = SECURITY_NT_AUTHORITY;
  174. BYTE PackageSidBuffer[ SECURITY_MAX_SID_SIZE ];
  175. PSID PackageSid = (PSID)PackageSidBuffer;
  176. ULONG Length;
  177. RtlInitializeSid(PackageSid, &PackageSidAuthority, 2);
  178. *(RtlSubAuthoritySid(PackageSid, 0)) = SECURITY_PACKAGE_BASE_RID;
  179. *(RtlSubAuthoritySid(PackageSid, 1)) = UNISP_RPC_ID;
  180. Length = RtlLengthSid(PackageSid);
  181. SslPackageSid = LocalAlloc(LPTR, sizeof(TOKEN_GROUPS) + Length);
  182. if(SslPackageSid == NULL)
  183. {
  184. return SP_LOG_RESULT(STATUS_INSUFFICIENT_RESOURCES);
  185. }
  186. SslPackageSid->GroupCount = 1;
  187. SslPackageSid->Groups[0].Sid = (PSID)&SslPackageSid->Groups[1];
  188. SslPackageSid->Groups[0].Attributes = SE_GROUP_MANDATORY |
  189. SE_GROUP_ENABLED_BY_DEFAULT |
  190. SE_GROUP_ENABLED;
  191. RtlCopySid(Length, SslPackageSid->Groups[0].Sid, PackageSid);
  192. }
  193. g_SslS4U2SelfInitialized = TRUE;
  194. return STATUS_SUCCESS;
  195. }
  196. PHMAPPER
  197. SslGetMapper(
  198. BOOL Ignored
  199. )
  200. {
  201. PSSL_MAPPER_CONTEXT Context ;
  202. NT_PRODUCT_TYPE ProductType ;
  203. BOOL DC ;
  204. UNREFERENCED_PARAMETER(Ignored);
  205. if ( RtlGetNtProductType( &ProductType ) )
  206. {
  207. DC = (ProductType == NtProductLanManNt );
  208. }
  209. else
  210. {
  211. return NULL ;
  212. }
  213. Context = (PSSL_MAPPER_CONTEXT) SPExternalAlloc( sizeof( SSL_MAPPER_CONTEXT ) );
  214. if ( Context )
  215. {
  216. Context->Mapper.m_dwMapperVersion = MAPPER_INTERFACE_VER ;
  217. Context->Mapper.m_dwFlags = SCH_FLAG_SYSTEM_MAPPER ;
  218. Context->Mapper.m_Reserved1 = NULL ;
  219. Context->Ref = 0;
  220. if ( DC )
  221. {
  222. Context->Mapper.m_vtable = &SslLocalTable ;
  223. }
  224. else
  225. {
  226. Context->Mapper.m_vtable = &SslRemoteTable ;
  227. }
  228. return &Context->Mapper ;
  229. }
  230. else
  231. {
  232. return NULL ;
  233. }
  234. }
  235. LONG
  236. WINAPI
  237. SslLocalRefMapper(
  238. PHMAPPER Mapper
  239. )
  240. {
  241. PSSL_MAPPER_CONTEXT Context ;
  242. Context = (PSSL_MAPPER_CONTEXT) Mapper ;
  243. if ( Context == NULL )
  244. {
  245. return( -1 );
  246. }
  247. DebugLog(( DEB_TRACE_MAPPER, "Ref of Context %x\n", Mapper ));
  248. return( InterlockedIncrement( &Context->Ref ) );
  249. }
  250. LONG
  251. WINAPI
  252. SslLocalDerefMapper(
  253. PHMAPPER Mapper
  254. )
  255. {
  256. PSSL_MAPPER_CONTEXT Context ;
  257. DWORD RefCount;
  258. Context = (PSSL_MAPPER_CONTEXT) Mapper ;
  259. if ( Context == NULL )
  260. {
  261. return( -1 );
  262. }
  263. DebugLog(( DEB_TRACE_MAPPER, "Deref of Context %x\n", Mapper ));
  264. RefCount = InterlockedDecrement( &Context->Ref );
  265. if(RefCount == 0)
  266. {
  267. SPExternalFree(Context);
  268. }
  269. return RefCount;
  270. }
  271. DWORD
  272. WINAPI
  273. SslLocalGetIssuerList(
  274. IN PHMAPPER Mapper,
  275. IN PVOID Reserved,
  276. OUT PBYTE pIssuerList,
  277. OUT PDWORD IssuerListLength
  278. )
  279. {
  280. UNREFERENCED_PARAMETER(Mapper);
  281. UNREFERENCED_PARAMETER(Reserved);
  282. DebugLog(( DEB_TRACE_MAPPER, "SslLocalGetIssuerList\n" ));
  283. return( (DWORD)GetDefaultIssuers(pIssuerList, IssuerListLength) );
  284. }
  285. DWORD
  286. WINAPI
  287. SslLocalGetChallenge(
  288. IN PHMAPPER Mapper,
  289. IN PUCHAR AuthenticatorId,
  290. IN DWORD AuthenticatorIdLength,
  291. OUT PUCHAR Challenge,
  292. OUT DWORD * ChallengeLength
  293. )
  294. {
  295. UNREFERENCED_PARAMETER(Mapper);
  296. UNREFERENCED_PARAMETER(AuthenticatorId);
  297. UNREFERENCED_PARAMETER(AuthenticatorIdLength);
  298. UNREFERENCED_PARAMETER(Challenge);
  299. UNREFERENCED_PARAMETER(ChallengeLength);
  300. DebugLog(( DEB_TRACE_MAPPER, "SslLocalGetChallenge\n" ));
  301. return (DWORD)SEC_E_UNSUPPORTED_FUNCTION;
  302. }
  303. //+---------------------------------------------------------------------------
  304. //
  305. // Function: GetTokenUserSid
  306. //
  307. // Synopsis: Obtain the user SID from the specified user token
  308. //
  309. // Arguments: [hUserToken] -- User token.
  310. // [ppUserSid] -- Returned SID.
  311. //
  312. // History: 10-08-2001 jbanes Created
  313. //
  314. // Notes:
  315. //
  316. //----------------------------------------------------------------------------
  317. BOOL
  318. GetTokenUserSid(
  319. IN HANDLE hUserToken, // token to query
  320. IN OUT PSID *ppUserSid // resultant user sid
  321. )
  322. {
  323. BYTE FastBuffer[256];
  324. LPBYTE SlowBuffer = NULL;
  325. PTOKEN_USER ptgUser;
  326. DWORD cbBuffer;
  327. BOOL fSuccess = FALSE;
  328. *ppUserSid = NULL;
  329. if(hUserToken == NULL)
  330. {
  331. return FALSE;
  332. }
  333. //
  334. // try querying based on a fast stack based buffer first.
  335. //
  336. ptgUser = (PTOKEN_USER)FastBuffer;
  337. cbBuffer = sizeof(FastBuffer);
  338. fSuccess = GetTokenInformation(
  339. hUserToken,// identifies access token
  340. TokenUser, // TokenUser info type
  341. ptgUser, // retrieved info buffer
  342. cbBuffer, // size of buffer passed-in
  343. &cbBuffer // required buffer size
  344. );
  345. if(!fSuccess)
  346. {
  347. if(GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  348. {
  349. // try again with the specified buffer size
  350. SlowBuffer = (LPBYTE)SPExternalAlloc(cbBuffer);
  351. if(SlowBuffer != NULL)
  352. {
  353. ptgUser = (PTOKEN_USER)SlowBuffer;
  354. fSuccess = GetTokenInformation(
  355. hUserToken,// identifies access token
  356. TokenUser, // TokenUser info type
  357. ptgUser, // retrieved info buffer
  358. cbBuffer, // size of buffer passed-in
  359. &cbBuffer // required buffer size
  360. );
  361. }
  362. }
  363. }
  364. //
  365. // if we got the token info successfully, copy the
  366. // relevant element for the caller.
  367. //
  368. if(fSuccess)
  369. {
  370. DWORD cbSid;
  371. // reset to assume failure
  372. fSuccess = FALSE;
  373. cbSid = GetLengthSid(ptgUser->User.Sid);
  374. *ppUserSid = SPExternalAlloc( cbSid );
  375. if(*ppUserSid != NULL)
  376. {
  377. fSuccess = CopySid(cbSid, *ppUserSid, ptgUser->User.Sid);
  378. }
  379. else
  380. {
  381. fSuccess = FALSE;
  382. }
  383. }
  384. if(!fSuccess)
  385. {
  386. if(*ppUserSid)
  387. {
  388. SPExternalFree(*ppUserSid);
  389. *ppUserSid = NULL;
  390. }
  391. }
  392. if(SlowBuffer)
  393. {
  394. SPExternalFree(SlowBuffer);
  395. }
  396. return fSuccess;
  397. }
  398. SECURITY_STATUS
  399. SslCreateTokenFromPac(
  400. PUCHAR AuthInfo,
  401. ULONG AuthInfoLength,
  402. PUNICODE_STRING Domain,
  403. PLUID NewLogonId,
  404. PHANDLE NewToken
  405. )
  406. {
  407. NTSTATUS Status ;
  408. LUID LogonId ;
  409. HANDLE TokenHandle ;
  410. NTSTATUS SubStatus ;
  411. SECURITY_STRING PacUserName ;
  412. //
  413. // Get the marshalled blob into a more useful form:
  414. //
  415. PacUserName.Buffer = NULL ;
  416. Status = LsaTable->ConvertAuthDataToToken(
  417. AuthInfo,
  418. AuthInfoLength,
  419. SecurityImpersonation,
  420. &SslTokenSource,
  421. Network,
  422. Domain,
  423. &TokenHandle,
  424. &LogonId,
  425. &PacUserName,
  426. &SubStatus
  427. );
  428. if ( NT_SUCCESS( Status ) )
  429. {
  430. PSID pSid;
  431. if(!GetTokenUserSid(TokenHandle, &pSid))
  432. {
  433. pSid = NULL;
  434. }
  435. LsaTable->AuditLogon(
  436. STATUS_SUCCESS,
  437. STATUS_SUCCESS,
  438. &PacUserName,
  439. Domain,
  440. NULL,
  441. pSid,
  442. Network,
  443. &SslTokenSource,
  444. &LogonId );
  445. if(pSid)
  446. {
  447. SPExternalFree(pSid);
  448. }
  449. }
  450. else
  451. {
  452. LsaTable->AuditLogon(
  453. Status,
  454. Status,
  455. &SslNullString,
  456. &SslNullString,
  457. NULL,
  458. NULL,
  459. Network,
  460. &SslTokenSource,
  461. &LogonId );
  462. }
  463. if ( !NT_SUCCESS( Status ) )
  464. {
  465. return Status ;
  466. }
  467. *NewToken = TokenHandle ;
  468. *NewLogonId = LogonId ;
  469. if ( PacUserName.Buffer )
  470. {
  471. LsaTable->FreeLsaHeap( PacUserName.Buffer );
  472. }
  473. return Status ;
  474. }
  475. #define ISSUER_HEADER L"<I>"
  476. #define CCH_ISSUER_HEADER 3
  477. #define SUBJECT_HEADER L"<S>"
  478. #define CCH_SUBJECT_HEADER 3
  479. //+---------------------------------------------------------------------------
  480. //
  481. // Function: SslGetNameFromCertificate
  482. //
  483. // Synopsis: Extracts the UPN name from the certificate
  484. //
  485. // Arguments: [pCert] --
  486. // [ppszName] --
  487. // [pfMachineCert] --
  488. //
  489. // History: 8-8-2000 jbanes Created
  490. //
  491. // Notes:
  492. //
  493. //----------------------------------------------------------------------------
  494. NTSTATUS
  495. SslGetNameFromCertificate(
  496. PCCERT_CONTEXT pCert,
  497. PWSTR * ppszName,
  498. BOOL * pfMachineCert)
  499. {
  500. ULONG ExtensionIndex;
  501. PWSTR pszName;
  502. DWORD cbName;
  503. *pfMachineCert = FALSE;
  504. //
  505. // See if cert has UPN in AltSubjectName->otherName
  506. //
  507. pszName = NULL;
  508. for(ExtensionIndex = 0;
  509. ExtensionIndex < pCert->pCertInfo->cExtension;
  510. ExtensionIndex++)
  511. {
  512. if(strcmp(pCert->pCertInfo->rgExtension[ExtensionIndex].pszObjId,
  513. szOID_SUBJECT_ALT_NAME2) == 0)
  514. {
  515. PCERT_ALT_NAME_INFO AltName = NULL;
  516. DWORD AltNameStructSize = 0;
  517. ULONG CertAltNameIndex = 0;
  518. if(CryptDecodeObjectEx(pCert->dwCertEncodingType,
  519. X509_ALTERNATE_NAME,
  520. pCert->pCertInfo->rgExtension[ExtensionIndex].Value.pbData,
  521. pCert->pCertInfo->rgExtension[ExtensionIndex].Value.cbData,
  522. CRYPT_DECODE_ALLOC_FLAG,
  523. NULL,
  524. (PVOID)&AltName,
  525. &AltNameStructSize))
  526. {
  527. for(CertAltNameIndex = 0; CertAltNameIndex < AltName->cAltEntry; CertAltNameIndex++)
  528. {
  529. PCERT_ALT_NAME_ENTRY AltNameEntry = &AltName->rgAltEntry[CertAltNameIndex];
  530. if((CERT_ALT_NAME_OTHER_NAME == AltNameEntry->dwAltNameChoice) &&
  531. (NULL != AltNameEntry->pOtherName) &&
  532. (0 == strcmp(szOID_NT_PRINCIPAL_NAME, AltNameEntry->pOtherName->pszObjId)))
  533. {
  534. PCERT_NAME_VALUE PrincipalNameBlob = NULL;
  535. DWORD PrincipalNameBlobSize = 0;
  536. // We found a UPN!
  537. if(CryptDecodeObjectEx(pCert->dwCertEncodingType,
  538. X509_UNICODE_ANY_STRING,
  539. AltNameEntry->pOtherName->Value.pbData,
  540. AltNameEntry->pOtherName->Value.cbData,
  541. CRYPT_DECODE_ALLOC_FLAG,
  542. NULL,
  543. (PVOID)&PrincipalNameBlob,
  544. &PrincipalNameBlobSize))
  545. {
  546. pszName = LocalAlloc(LPTR, PrincipalNameBlob->Value.cbData + sizeof(WCHAR));
  547. if(pszName != NULL)
  548. {
  549. CopyMemory(pszName, PrincipalNameBlob->Value.pbData, PrincipalNameBlob->Value.cbData);
  550. }
  551. LocalFree(PrincipalNameBlob);
  552. PrincipalNameBlob = NULL;
  553. if(pszName == NULL)
  554. {
  555. LocalFree(AltName);
  556. return STATUS_NO_MEMORY;
  557. }
  558. }
  559. if(pszName)
  560. {
  561. break;
  562. }
  563. }
  564. }
  565. LocalFree(AltName);
  566. AltName = NULL;
  567. if(pszName)
  568. {
  569. break;
  570. }
  571. }
  572. }
  573. }
  574. //
  575. // See if cert has DNS in AltSubjectName->pwszDNSName
  576. //
  577. if(pszName == NULL)
  578. {
  579. for(ExtensionIndex = 0;
  580. ExtensionIndex < pCert->pCertInfo->cExtension;
  581. ExtensionIndex++)
  582. {
  583. if(strcmp(pCert->pCertInfo->rgExtension[ExtensionIndex].pszObjId,
  584. szOID_SUBJECT_ALT_NAME2) == 0)
  585. {
  586. PCERT_ALT_NAME_INFO AltName = NULL;
  587. DWORD AltNameStructSize = 0;
  588. ULONG CertAltNameIndex = 0;
  589. if(CryptDecodeObjectEx(pCert->dwCertEncodingType,
  590. X509_ALTERNATE_NAME,
  591. pCert->pCertInfo->rgExtension[ExtensionIndex].Value.pbData,
  592. pCert->pCertInfo->rgExtension[ExtensionIndex].Value.cbData,
  593. CRYPT_DECODE_ALLOC_FLAG,
  594. NULL,
  595. (PVOID)&AltName,
  596. &AltNameStructSize))
  597. {
  598. for(CertAltNameIndex = 0; CertAltNameIndex < AltName->cAltEntry; CertAltNameIndex++)
  599. {
  600. PCERT_ALT_NAME_ENTRY AltNameEntry = &AltName->rgAltEntry[CertAltNameIndex];
  601. if((CERT_ALT_NAME_DNS_NAME == AltNameEntry->dwAltNameChoice) &&
  602. (NULL != AltNameEntry->pwszDNSName))
  603. {
  604. // We found a DNS!
  605. cbName = (lstrlen(AltNameEntry->pwszDNSName) + 1) * sizeof(WCHAR);
  606. pszName = LocalAlloc(LPTR, cbName);
  607. if(pszName == NULL)
  608. {
  609. LocalFree(AltName);
  610. return STATUS_NO_MEMORY;
  611. }
  612. CopyMemory(pszName, AltNameEntry->pwszDNSName, cbName);
  613. *pfMachineCert = TRUE;
  614. break;
  615. }
  616. }
  617. LocalFree(AltName);
  618. AltName = NULL;
  619. if(pszName)
  620. {
  621. break;
  622. }
  623. }
  624. }
  625. }
  626. }
  627. //
  628. // There was no UPN in the AltSubjectName, so look for
  629. // one in the Subject Name, in case this is a B3 compatability
  630. // cert.
  631. //
  632. if(pszName == NULL)
  633. {
  634. ULONG Length;
  635. Length = CertGetNameString( pCert,
  636. CERT_NAME_ATTR_TYPE,
  637. 0,
  638. szOID_COMMON_NAME,
  639. NULL,
  640. 0 );
  641. if(Length)
  642. {
  643. pszName = LocalAlloc(LPTR, Length * sizeof(WCHAR));
  644. if(!pszName)
  645. {
  646. return STATUS_NO_MEMORY ;
  647. }
  648. if ( !CertGetNameStringW(pCert,
  649. CERT_NAME_ATTR_TYPE,
  650. 0,
  651. szOID_COMMON_NAME,
  652. pszName,
  653. Length))
  654. {
  655. LocalFree(pszName);
  656. return STATUS_OBJECT_NAME_NOT_FOUND;
  657. }
  658. }
  659. }
  660. if(pszName)
  661. {
  662. *ppszName = pszName;
  663. }
  664. else
  665. {
  666. return STATUS_NOT_FOUND;
  667. }
  668. return STATUS_SUCCESS;
  669. }
  670. //+---------------------------------------------------------------------------
  671. //
  672. // Function: SslTryS4U2Self
  673. //
  674. // Synopsis: Creates a user token via the Kerberos S4U2Self mechanism.
  675. // This should work even cross-forest, provided that all of the
  676. // DC's are running Whistler. Pretty cool!
  677. //
  678. // Arguments: [pChainContext] --
  679. // [UserToken] --
  680. //
  681. // History: 06-13-2002 jbanes Created
  682. //
  683. // Notes:
  684. //
  685. //----------------------------------------------------------------------------
  686. NTSTATUS
  687. SslTryS4U2Self(
  688. IN PCCERT_CHAIN_CONTEXT pChainContext,
  689. OUT HANDLE *UserToken
  690. )
  691. {
  692. NTSTATUS Status;
  693. NTSTATUS SubStatus;
  694. BOOL fMachineCert;
  695. PWSTR pszUserName = NULL;
  696. PCERT_SIMPLE_CHAIN pSimpleChain;
  697. PCCERT_CONTEXT pCert;
  698. PKERB_S4U_LOGON LogonInfo = NULL;
  699. ULONG LogonInfoSize = sizeof(KERB_S4U_LOGON);
  700. PKERB_INTERACTIVE_PROFILE Profile = NULL;
  701. ULONG ProfileSize;
  702. LUID LogonId;
  703. QUOTA_LIMITS Quotas;
  704. *UserToken = NULL;
  705. if(!g_SslS4U2SelfInitialized)
  706. {
  707. return SP_LOG_RESULT(STATUS_NOT_SUPPORTED);
  708. }
  709. //
  710. // Get the client name from the cert
  711. //
  712. pSimpleChain = pChainContext->rgpChain[0];
  713. pCert = pSimpleChain->rgpElement[0]->pCertContext;
  714. Status = SslGetNameFromCertificate(pCert, &pszUserName, &fMachineCert);
  715. if(!NT_SUCCESS(Status))
  716. {
  717. return Status;
  718. }
  719. if(fMachineCert)
  720. {
  721. // S4U2Self doesn't work with machine accounts.
  722. Status = STATUS_NOT_FOUND;
  723. goto cleanup;
  724. }
  725. DebugLog(( DEB_TRACE_MAPPER, "Looking for UPN name %ws\n", pszUserName ));
  726. //
  727. // Build logon info structure.
  728. //
  729. LogonInfoSize = sizeof(KERB_S4U_LOGON) +
  730. (lstrlen(pszUserName) + 1) * sizeof(WCHAR);
  731. LogonInfo = (PKERB_S4U_LOGON) LocalAlloc(LPTR, LogonInfoSize);
  732. if (NULL == LogonInfo)
  733. {
  734. Status = STATUS_NO_MEMORY;
  735. goto cleanup;
  736. }
  737. LogonInfo->MessageType = KerbS4ULogon;
  738. LogonInfo->ClientUpn.Buffer = (LPWSTR)(LogonInfo + 1);
  739. LogonInfo->ClientUpn.Length = (USHORT)(lstrlen(pszUserName)) * sizeof(WCHAR);
  740. LogonInfo->ClientUpn.MaximumLength = LogonInfo->ClientUpn.Length + sizeof(WCHAR);
  741. memcpy((PUCHAR)(LogonInfo + 1),
  742. pszUserName,
  743. LogonInfo->ClientUpn.MaximumLength);
  744. //
  745. // Attempt to log the user on.
  746. //
  747. Status = LsaLogonUser(
  748. SslLogonHandle,
  749. &SslPackageNameA,
  750. Network,
  751. SslKerberosPackageId,
  752. LogonInfo,
  753. LogonInfoSize,
  754. SslPackageSid,
  755. &SslTokenSource,
  756. (PVOID *)&Profile,
  757. &ProfileSize,
  758. &LogonId,
  759. UserToken,
  760. &Quotas,
  761. &SubStatus
  762. );
  763. if (NT_SUCCESS(Status))
  764. {
  765. Status = SubStatus;
  766. }
  767. if (!NT_SUCCESS(Status))
  768. {
  769. goto cleanup;
  770. }
  771. Status = LsaISetTokenDacl(*UserToken);
  772. cleanup:
  773. if(Profile)
  774. {
  775. LsaFreeReturnBuffer(Profile);
  776. }
  777. if(LogonInfo)
  778. {
  779. LocalFree(LogonInfo);
  780. }
  781. if(pszUserName)
  782. {
  783. LocalFree(pszUserName);
  784. }
  785. return Status;
  786. }
  787. //+---------------------------------------------------------------------------
  788. //
  789. // Function: SslTryUpn
  790. //
  791. // Synopsis: Tries to find the user by UPN encoded in Cert
  792. //
  793. // Arguments: [User] --
  794. // [AuthData] --
  795. // [AuthDataLen] --
  796. //
  797. // History: 5-11-98 RichardW Created
  798. //
  799. // Notes:
  800. //
  801. //----------------------------------------------------------------------------
  802. NTSTATUS
  803. SslTryUpn(
  804. PCCERT_CONTEXT User,
  805. PUCHAR * AuthData,
  806. PULONG AuthDataLen,
  807. PWSTR * ReferencedDomain
  808. )
  809. {
  810. NTSTATUS Status ;
  811. UNICODE_STRING Upn = {0, 0, NULL};
  812. UNICODE_STRING Cracked = {0};
  813. UNICODE_STRING DnsDomain = {0};
  814. UNICODE_STRING FlatName = { 0 };
  815. ULONG SubStatus ;
  816. BOOL fMachineCert;
  817. PWSTR pszName = NULL;
  818. PWSTR pszServiceName = NULL;
  819. DWORD cchServiceName;
  820. *ReferencedDomain = NULL ;
  821. //
  822. // Get the client name from the cert
  823. //
  824. Status = SslGetNameFromCertificate(User, &pszName, &fMachineCert);
  825. if(!NT_SUCCESS(Status))
  826. {
  827. return Status;
  828. }
  829. //
  830. // now, try and find this guy:
  831. //
  832. if(fMachineCert)
  833. {
  834. // Search for "host/foo.com".
  835. cchServiceName = lstrlenW(L"host/") + lstrlenW(pszName);
  836. SafeAllocaAllocate(pszServiceName, (cchServiceName + 1) * sizeof(WCHAR));
  837. if(pszServiceName == NULL)
  838. {
  839. Status = STATUS_NO_MEMORY;
  840. }
  841. else
  842. {
  843. lstrcpyW(pszServiceName, L"host/");
  844. lstrcatW(pszServiceName, pszName);
  845. RtlInitUnicodeString(&Upn, pszServiceName);
  846. DebugLog(( DEB_TRACE_MAPPER, "Looking for SPN name %ws\n", Upn.Buffer ));
  847. Status = LsaTable->GetAuthDataForUser( &Upn,
  848. SecNameSPN,
  849. NULL,
  850. AuthData,
  851. AuthDataLen,
  852. &FlatName );
  853. if ( FlatName.Length )
  854. {
  855. LsaTable->AuditAccountLogon(
  856. SE_AUDITID_ACCOUNT_MAPPED,
  857. (BOOLEAN) NT_SUCCESS( Status ),
  858. &SslPackageName,
  859. &Upn,
  860. &FlatName,
  861. Status );
  862. LsaTable->FreeLsaHeap( FlatName.Buffer );
  863. }
  864. }
  865. }
  866. else
  867. {
  868. // Search for "[email protected]".
  869. RtlInitUnicodeString(&Upn, pszName);
  870. DebugLog(( DEB_TRACE_MAPPER, "Looking for UPN name %ws\n", Upn.Buffer ));
  871. Status = LsaTable->GetAuthDataForUser( &Upn,
  872. SecNameFlat,
  873. NULL,
  874. AuthData,
  875. AuthDataLen,
  876. &FlatName );
  877. if ( FlatName.Length )
  878. {
  879. LsaTable->AuditAccountLogon(
  880. SE_AUDITID_ACCOUNT_MAPPED,
  881. (BOOLEAN) NT_SUCCESS( Status ),
  882. &SslPackageName,
  883. &Upn,
  884. &FlatName,
  885. Status );
  886. LsaTable->FreeLsaHeap( FlatName.Buffer );
  887. }
  888. }
  889. if ( Status == STATUS_NOT_FOUND )
  890. {
  891. UNICODE_STRING DomainName;
  892. BOOL NameMatch;
  893. //
  894. // Do the hacky check of seeing if this is our own domain, and
  895. // if so, try opening the user as a flat, SAM name.
  896. //
  897. if(fMachineCert)
  898. {
  899. PWSTR pPeriod;
  900. WCHAR ch;
  901. pPeriod = wcschr( pszName, L'.' );
  902. if(pPeriod)
  903. {
  904. RtlInitUnicodeString( &DomainName, pPeriod + 1 );
  905. SslGlobalReadLock();
  906. NameMatch = RtlEqualUnicodeString(&DomainName, &SslGlobalDnsDomainName, TRUE);
  907. SslGlobalReleaseLock();
  908. if(NameMatch)
  909. {
  910. ch = *(pPeriod + 1);
  911. *pPeriod = L'$';
  912. *(pPeriod + 1) = L'\0';
  913. RtlInitUnicodeString(&Upn, pszName);
  914. DebugLog(( DEB_TRACE_MAPPER, "Looking for machine name %ws\n", Upn.Buffer ));
  915. // Search for "computer$".
  916. Status = LsaTable->GetAuthDataForUser( &Upn,
  917. SecNameSamCompatible,
  918. NULL,
  919. AuthData,
  920. AuthDataLen,
  921. NULL );
  922. *pPeriod = L'.';
  923. *(pPeriod + 1) = ch;
  924. }
  925. }
  926. }
  927. else
  928. {
  929. PWSTR AtSign;
  930. AtSign = wcschr( pszName, L'@' );
  931. if ( AtSign )
  932. {
  933. RtlInitUnicodeString( &DomainName, AtSign + 1 );
  934. SslGlobalReadLock();
  935. NameMatch = RtlEqualUnicodeString(&DomainName, &SslGlobalDnsDomainName, TRUE);
  936. SslGlobalReleaseLock();
  937. if(NameMatch)
  938. {
  939. *AtSign = L'\0';
  940. RtlInitUnicodeString(&Upn, pszName);
  941. DebugLog(( DEB_TRACE_MAPPER, "Looking for user name %ws\n", Upn.Buffer ));
  942. // Search for "username".
  943. Status = LsaTable->GetAuthDataForUser( &Upn,
  944. SecNameSamCompatible,
  945. NULL,
  946. AuthData,
  947. AuthDataLen,
  948. NULL );
  949. *AtSign = L'@';
  950. }
  951. }
  952. }
  953. if (Status == STATUS_NOT_FOUND )
  954. {
  955. if(fMachineCert)
  956. {
  957. RtlInitUnicodeString(&Upn, pszServiceName);
  958. DebugLog(( DEB_TRACE_MAPPER, "Cracking name %ws at GC\n", Upn.Buffer ));
  959. Status = LsaTable->CrackSingleName(
  960. DS_SERVICE_PRINCIPAL_NAME,
  961. TRUE,
  962. &Upn,
  963. NULL,
  964. DS_NT4_ACCOUNT_NAME,
  965. &Cracked,
  966. &DnsDomain,
  967. &SubStatus );
  968. }
  969. else
  970. {
  971. RtlInitUnicodeString(&Upn, pszName);
  972. DebugLog(( DEB_TRACE_MAPPER, "Cracking name %ws at GC\n", Upn.Buffer ));
  973. Status = LsaTable->CrackSingleName(
  974. DS_USER_PRINCIPAL_NAME,
  975. TRUE,
  976. &Upn,
  977. NULL,
  978. DS_NT4_ACCOUNT_NAME,
  979. &Cracked,
  980. &DnsDomain,
  981. &SubStatus );
  982. }
  983. if ( NT_SUCCESS( Status ) )
  984. {
  985. if ( SubStatus == 0 )
  986. {
  987. *ReferencedDomain = DnsDomain.Buffer ;
  988. DnsDomain.Buffer = NULL;
  989. }
  990. if(Cracked.Buffer != NULL)
  991. {
  992. LsaTable->FreeLsaHeap( Cracked.Buffer );
  993. }
  994. if(DnsDomain.Buffer != NULL)
  995. {
  996. LsaTable->FreeLsaHeap( DnsDomain.Buffer );
  997. }
  998. Status = STATUS_NOT_FOUND ;
  999. }
  1000. }
  1001. }
  1002. if(pszName)
  1003. {
  1004. LocalFree(pszName);
  1005. }
  1006. if(pszServiceName)
  1007. {
  1008. SafeAllocaFree(pszServiceName);
  1009. }
  1010. return Status ;
  1011. }
  1012. void
  1013. ConvertNameString(UNICODE_STRING *Name)
  1014. {
  1015. PWSTR Comma1, Comma2;
  1016. //
  1017. // Scan through the name, converting "\r\n" to ",". This should be
  1018. // done by the CertNameToStr APIs, but that won't happen for a while.
  1019. //
  1020. Comma1 = Comma2 = Name->Buffer ;
  1021. while ( *Comma2 )
  1022. {
  1023. *Comma1 = *Comma2 ;
  1024. if ( *Comma2 == L'\r' )
  1025. {
  1026. if ( *(Comma2 + 1) == L'\n' )
  1027. {
  1028. *Comma1 = L',';
  1029. Comma2++ ;
  1030. }
  1031. }
  1032. Comma1++;
  1033. Comma2++;
  1034. }
  1035. *Comma1 = L'\0';
  1036. Name->Length = (USHORT)(wcslen( Name->Buffer ) * sizeof( WCHAR ));
  1037. }
  1038. //+---------------------------------------------------------------------------
  1039. //
  1040. // Function: SslTryCompoundName
  1041. //
  1042. // Synopsis: Tries to find the user by concatenating the issuer and subject
  1043. // names, and looking for an AlternateSecurityId.
  1044. //
  1045. // Arguments: [User] --
  1046. // [AuthData] --
  1047. // [AuthDataLen] --
  1048. //
  1049. // History: 5-11-98 RichardW Created
  1050. //
  1051. // Notes:
  1052. //
  1053. //----------------------------------------------------------------------------
  1054. NTSTATUS
  1055. SslTryCompoundName(
  1056. PCCERT_CONTEXT User,
  1057. PUCHAR * AuthData,
  1058. PULONG AuthDataLen,
  1059. PWSTR * ReferencedDomain
  1060. )
  1061. {
  1062. UNICODE_STRING CompoundName ;
  1063. ULONG Length ;
  1064. ULONG IssuerLength ;
  1065. NTSTATUS Status ;
  1066. PWSTR Current ;
  1067. UNICODE_STRING Cracked = {0};
  1068. UNICODE_STRING DnsDomain = {0};
  1069. UNICODE_STRING FlatName = { 0 };
  1070. ULONG SubStatus ;
  1071. const DWORD dwNameToStrFlags = CERT_X500_NAME_STR |
  1072. CERT_NAME_STR_NO_PLUS_FLAG |
  1073. CERT_NAME_STR_CRLF_FLAG;
  1074. *ReferencedDomain = NULL ;
  1075. IssuerLength = CertNameToStr( User->dwCertEncodingType,
  1076. &User->pCertInfo->Issuer,
  1077. dwNameToStrFlags,
  1078. NULL,
  1079. 0 );
  1080. Length = CertNameToStr( User->dwCertEncodingType,
  1081. &User->pCertInfo->Subject,
  1082. dwNameToStrFlags,
  1083. NULL,
  1084. 0 );
  1085. if ( ( IssuerLength == 0 ) ||
  1086. ( Length == 0 ) )
  1087. {
  1088. return STATUS_NO_MEMORY ;
  1089. }
  1090. CompoundName.MaximumLength = (USHORT) (Length + IssuerLength +
  1091. CCH_ISSUER_HEADER + CCH_SUBJECT_HEADER) *
  1092. sizeof( WCHAR ) ;
  1093. SafeAllocaAllocate( CompoundName.Buffer, CompoundName.MaximumLength );
  1094. if ( CompoundName.Buffer )
  1095. {
  1096. wcscpy( CompoundName.Buffer, ISSUER_HEADER );
  1097. Current = CompoundName.Buffer + CCH_ISSUER_HEADER ;
  1098. IssuerLength = CertNameToStrW( User->dwCertEncodingType,
  1099. &User->pCertInfo->Issuer,
  1100. dwNameToStrFlags,
  1101. Current,
  1102. IssuerLength );
  1103. Current += IssuerLength - 1 ;
  1104. wcscpy( Current, SUBJECT_HEADER );
  1105. Current += CCH_SUBJECT_HEADER ;
  1106. Length = CertNameToStrW( User->dwCertEncodingType,
  1107. &User->pCertInfo->Subject,
  1108. dwNameToStrFlags,
  1109. Current,
  1110. Length );
  1111. ConvertNameString(&CompoundName);
  1112. Status = LsaTable->GetAuthDataForUser( &CompoundName,
  1113. SecNameAlternateId,
  1114. &SslNamePrefix,
  1115. AuthData,
  1116. AuthDataLen,
  1117. &FlatName );
  1118. if ( FlatName.Length )
  1119. {
  1120. LsaTable->AuditAccountLogon(
  1121. SE_AUDITID_ACCOUNT_MAPPED,
  1122. (BOOLEAN) NT_SUCCESS( Status ),
  1123. &SslPackageName,
  1124. &CompoundName,
  1125. &FlatName,
  1126. Status );
  1127. LsaTable->FreeLsaHeap( FlatName.Buffer );
  1128. }
  1129. if ( Status == STATUS_NOT_FOUND )
  1130. {
  1131. Status = LsaTable->CrackSingleName(
  1132. DS_ALT_SECURITY_IDENTITIES_NAME,
  1133. TRUE,
  1134. &CompoundName,
  1135. &SslNamePrefix,
  1136. DS_NT4_ACCOUNT_NAME,
  1137. &Cracked,
  1138. &DnsDomain,
  1139. &SubStatus );
  1140. if ( NT_SUCCESS( Status ) )
  1141. {
  1142. if ( SubStatus == 0 )
  1143. {
  1144. *ReferencedDomain = DnsDomain.Buffer ;
  1145. DnsDomain.Buffer = NULL;
  1146. }
  1147. if(Cracked.Buffer != NULL)
  1148. {
  1149. LsaTable->FreeLsaHeap( Cracked.Buffer );
  1150. }
  1151. if(DnsDomain.Buffer != NULL)
  1152. {
  1153. LsaTable->FreeLsaHeap( DnsDomain.Buffer );
  1154. }
  1155. Status = STATUS_NOT_FOUND ;
  1156. }
  1157. }
  1158. SafeAllocaFree( CompoundName.Buffer );
  1159. }
  1160. else
  1161. {
  1162. Status = STATUS_NO_MEMORY ;
  1163. }
  1164. return Status ;
  1165. }
  1166. //+---------------------------------------------------------------------------
  1167. //
  1168. // Function: SslTryIssuer
  1169. //
  1170. // Synopsis: Tries to find a user that has an issuer mapped to it.
  1171. //
  1172. // Arguments: [User] --
  1173. // [AuthData] --
  1174. // [AuthDataLen] --
  1175. //
  1176. // History: 5-11-98 RichardW Created
  1177. //
  1178. // Notes:
  1179. //
  1180. //----------------------------------------------------------------------------
  1181. NTSTATUS
  1182. SslTryIssuer(
  1183. PBYTE pIssuer,
  1184. DWORD cbIssuer,
  1185. PUCHAR * AuthData,
  1186. PULONG AuthDataLen,
  1187. PWSTR * ReferencedDomain
  1188. )
  1189. {
  1190. UNICODE_STRING IssuerName ;
  1191. ULONG IssuerLength ;
  1192. NTSTATUS Status ;
  1193. UNICODE_STRING Cracked = { 0 };
  1194. UNICODE_STRING DnsDomain = { 0 };
  1195. UNICODE_STRING FlatName = { 0 };
  1196. ULONG SubStatus ;
  1197. const DWORD dwNameToStrFlags = CERT_X500_NAME_STR |
  1198. CERT_NAME_STR_NO_PLUS_FLAG |
  1199. CERT_NAME_STR_CRLF_FLAG;
  1200. CERT_NAME_BLOB Issuer;
  1201. BOOL fReferral = FALSE;
  1202. *ReferencedDomain = NULL ;
  1203. //
  1204. // See if issuer is in cache. If so, then we know that this issuer
  1205. // doesn't map to a user account.
  1206. //
  1207. if(SPFindIssuerInCache(pIssuer, cbIssuer))
  1208. {
  1209. return STATUS_NOT_FOUND;
  1210. }
  1211. LogDistinguishedName(DEB_TRACE, "SslTryIssuer: %s\n", pIssuer, cbIssuer);
  1212. //
  1213. // Attempt to map the issuer.
  1214. //
  1215. Issuer.pbData = pIssuer;
  1216. Issuer.cbData = cbIssuer;
  1217. IssuerLength = CertNameToStr( CRYPT_ASN_ENCODING,
  1218. &Issuer,
  1219. dwNameToStrFlags,
  1220. NULL,
  1221. 0 );
  1222. if ( IssuerLength == 0 )
  1223. {
  1224. return STATUS_NO_MEMORY ;
  1225. }
  1226. IssuerName.MaximumLength = (USHORT)(CCH_ISSUER_HEADER + IssuerLength) * sizeof( WCHAR ) ;
  1227. SafeAllocaAllocate( IssuerName.Buffer, IssuerName.MaximumLength );
  1228. if ( IssuerName.Buffer )
  1229. {
  1230. wcscpy( IssuerName.Buffer, ISSUER_HEADER );
  1231. IssuerLength = CertNameToStrW(CRYPT_ASN_ENCODING,
  1232. &Issuer,
  1233. dwNameToStrFlags,
  1234. IssuerName.Buffer + CCH_ISSUER_HEADER,
  1235. IssuerLength );
  1236. ConvertNameString(&IssuerName);
  1237. Status = LsaTable->GetAuthDataForUser( &IssuerName,
  1238. SecNameAlternateId,
  1239. &SslNamePrefix,
  1240. AuthData,
  1241. AuthDataLen,
  1242. &FlatName );
  1243. if ( FlatName.Length )
  1244. {
  1245. LsaTable->AuditAccountLogon(
  1246. SE_AUDITID_ACCOUNT_MAPPED,
  1247. (BOOLEAN) NT_SUCCESS( Status ),
  1248. &SslPackageName,
  1249. &IssuerName,
  1250. &FlatName,
  1251. Status );
  1252. LsaTable->FreeLsaHeap( FlatName.Buffer );
  1253. }
  1254. if ( Status == STATUS_NOT_FOUND )
  1255. {
  1256. Status = LsaTable->CrackSingleName(
  1257. DS_ALT_SECURITY_IDENTITIES_NAME,
  1258. TRUE,
  1259. &IssuerName,
  1260. &SslNamePrefix,
  1261. DS_NT4_ACCOUNT_NAME,
  1262. &Cracked,
  1263. &DnsDomain,
  1264. &SubStatus );
  1265. if ( NT_SUCCESS( Status ) )
  1266. {
  1267. if ( SubStatus == 0 )
  1268. {
  1269. *ReferencedDomain = DnsDomain.Buffer ;
  1270. DnsDomain.Buffer = NULL;
  1271. fReferral = TRUE;
  1272. }
  1273. if(Cracked.Buffer != NULL)
  1274. {
  1275. LsaTable->FreeLsaHeap( Cracked.Buffer );
  1276. }
  1277. if(DnsDomain.Buffer != NULL)
  1278. {
  1279. LsaTable->FreeLsaHeap( DnsDomain.Buffer );
  1280. }
  1281. Status = STATUS_NOT_FOUND ;
  1282. }
  1283. if(!fReferral)
  1284. {
  1285. // No mapping was found for this issuer, and no referral
  1286. // either. Add this issuer to the issuer cache, so that
  1287. // we don't attempt to map it again (until the cache entry
  1288. // expires).
  1289. SPAddIssuerToCache(pIssuer, cbIssuer);
  1290. }
  1291. }
  1292. SafeAllocaFree(IssuerName.Buffer);
  1293. }
  1294. else
  1295. {
  1296. Status = STATUS_NO_MEMORY ;
  1297. }
  1298. return Status ;
  1299. }
  1300. //+---------------------------------------------------------------------------
  1301. //
  1302. // Function: SslMapCertToUserPac
  1303. //
  1304. // Synopsis: Maps a certificate to a user (hopefully) and the PAC,
  1305. //
  1306. // Arguments: [Request] --
  1307. // [RequestLength] --
  1308. // [UserPac] --
  1309. // [UserPacLen] --
  1310. //
  1311. // History: 5-11-98 RichardW Created
  1312. //
  1313. // Notes:
  1314. //
  1315. //----------------------------------------------------------------------------
  1316. NTSTATUS
  1317. SslMapCertToUserPac(
  1318. IN PSSL_CERT_LOGON_REQ Request,
  1319. IN ULONG RequestLength,
  1320. OUT PUCHAR * UserPac,
  1321. OUT PULONG UserPacLen,
  1322. OUT PWSTR * ReferencedDomain
  1323. )
  1324. {
  1325. PCCERT_CONTEXT User ;
  1326. NTSTATUS Status = STATUS_LOGON_FAILURE;
  1327. NTSTATUS SubStatus = STATUS_NOT_FOUND;
  1328. ULONG i;
  1329. *ReferencedDomain = NULL;
  1330. DebugLog(( DEB_TRACE_MAPPER, "SslMapCertToUserPac called\n" ));
  1331. //
  1332. // Validate logon request.
  1333. //
  1334. if(RequestLength < sizeof(SSL_CERT_LOGON_REQ))
  1335. {
  1336. return SP_LOG_RESULT(STATUS_INVALID_PARAMETER);
  1337. }
  1338. if(Request->Length > RequestLength)
  1339. {
  1340. return SP_LOG_RESULT(STATUS_INVALID_PARAMETER);
  1341. }
  1342. //
  1343. // Extract certificate from request.
  1344. //
  1345. if((Request->OffsetCertificate > RequestLength) ||
  1346. (Request->CertLength > 0x10000) ||
  1347. (Request->OffsetCertificate + Request->CertLength > RequestLength))
  1348. {
  1349. return SP_LOG_RESULT(STATUS_INVALID_PARAMETER);
  1350. }
  1351. User = CertCreateCertificateContext( X509_ASN_ENCODING,
  1352. (PBYTE)Request + Request->OffsetCertificate,
  1353. Request->CertLength );
  1354. if ( !User )
  1355. {
  1356. Status = STATUS_NO_MEMORY ;
  1357. goto Cleanup ;
  1358. }
  1359. //
  1360. // First, try the UPN
  1361. //
  1362. if((Request->Flags & REQ_UPN_MAPPING) &&
  1363. (g_dwCertMappingMethods & SP_REG_CERTMAP_UPN_FLAG))
  1364. {
  1365. DebugLog(( DEB_TRACE_MAPPER, "Trying UPN mapping\n" ));
  1366. Status = SslTryUpn( User,
  1367. UserPac,
  1368. UserPacLen,
  1369. ReferencedDomain );
  1370. if ( NT_SUCCESS( Status ) ||
  1371. ( *ReferencedDomain ) )
  1372. {
  1373. goto Cleanup;
  1374. }
  1375. DebugLog(( DEB_TRACE_MAPPER, "Failed with error 0x%x\n", Status ));
  1376. }
  1377. //
  1378. // Swing and a miss. Try the constructed issuer+subject name
  1379. //
  1380. if((Request->Flags & REQ_SUBJECT_MAPPING) &&
  1381. (g_dwCertMappingMethods & SP_REG_CERTMAP_SUBJECT_FLAG))
  1382. {
  1383. DebugLog(( DEB_TRACE_MAPPER, "Trying Subject mapping\n" ));
  1384. Status = SslTryCompoundName( User,
  1385. UserPac,
  1386. UserPacLen,
  1387. ReferencedDomain );
  1388. if ( NT_SUCCESS( Status ) ||
  1389. ( *ReferencedDomain ) )
  1390. {
  1391. goto Cleanup;
  1392. }
  1393. DebugLog(( DEB_TRACE_MAPPER, "Failed with error 0x%x\n", Status ));
  1394. // Return error code from issuer+subject name mapping
  1395. // in preference to the error code from many-to-one mapping.
  1396. SubStatus = Status;
  1397. }
  1398. //
  1399. // Strike two. Try the issuer for a many-to-one mapping:
  1400. //
  1401. if((Request->Flags & REQ_ISSUER_MAPPING) &&
  1402. (g_dwCertMappingMethods & SP_REG_CERTMAP_ISSUER_FLAG))
  1403. {
  1404. DebugLog(( DEB_TRACE_MAPPER, "Trying issuer mapping\n" ));
  1405. if((Request->Flags & REQ_ISSUER_CHAIN_MAPPING) && (Request->CertCount > 0))
  1406. {
  1407. if(sizeof(SSL_CERT_LOGON_REQ) +
  1408. (Request->CertCount - 1) * sizeof(SSL_CERT_NAME_INFO) > RequestLength)
  1409. {
  1410. Status = SP_LOG_RESULT(STATUS_INVALID_PARAMETER);
  1411. goto Cleanup;
  1412. }
  1413. // Loop through each issuer in the certificate chain.
  1414. for(i = 0; i < Request->CertCount; i++)
  1415. {
  1416. DWORD IssuerOffset = Request->NameInfo[i].IssuerOffset;
  1417. DWORD IssuerLength = Request->NameInfo[i].IssuerLength;
  1418. if((IssuerOffset > RequestLength) ||
  1419. (IssuerLength > 0x10000) ||
  1420. (IssuerOffset + IssuerLength > RequestLength))
  1421. {
  1422. return SP_LOG_RESULT(STATUS_INVALID_PARAMETER);
  1423. }
  1424. Status = SslTryIssuer( (PBYTE)Request + Request->NameInfo[i].IssuerOffset,
  1425. Request->NameInfo[i].IssuerLength,
  1426. UserPac,
  1427. UserPacLen,
  1428. ReferencedDomain );
  1429. if ( NT_SUCCESS( Status ) ||
  1430. ( *ReferencedDomain ) )
  1431. {
  1432. goto Cleanup;
  1433. }
  1434. }
  1435. }
  1436. else
  1437. {
  1438. // Extract the issuer name from the certificate and try
  1439. // to map it.
  1440. Status = SslTryIssuer( User->pCertInfo->Issuer.pbData,
  1441. User->pCertInfo->Issuer.cbData,
  1442. UserPac,
  1443. UserPacLen,
  1444. ReferencedDomain );
  1445. if ( NT_SUCCESS( Status ) ||
  1446. ( *ReferencedDomain ) )
  1447. {
  1448. goto Cleanup;
  1449. }
  1450. }
  1451. DebugLog(( DEB_TRACE_MAPPER, "Failed with error 0x%x\n", Status ));
  1452. }
  1453. //
  1454. // Certificate mapping failed. Decide what error code to return.
  1455. //
  1456. if(Status == STATUS_OBJECT_NAME_COLLISION ||
  1457. SubStatus == STATUS_OBJECT_NAME_COLLISION)
  1458. {
  1459. Status = SEC_E_MULTIPLE_ACCOUNTS;
  1460. }
  1461. else if(Status != STATUS_NO_MEMORY)
  1462. {
  1463. Status = STATUS_LOGON_FAILURE ;
  1464. }
  1465. Cleanup:
  1466. if ( User )
  1467. {
  1468. CertFreeCertificateContext( User );
  1469. }
  1470. DebugLog(( DEB_TRACE_MAPPER, "SslMapCertToUserPac returned 0x%x\n", Status ));
  1471. return Status ;
  1472. }
  1473. DWORD
  1474. WINAPI
  1475. MapperVerifyClientChain(
  1476. PCCERT_CONTEXT pCertContext,
  1477. DWORD dwMapperFlags,
  1478. DWORD * pdwMethods,
  1479. NTSTATUS * pVerifyStatus,
  1480. PCCERT_CHAIN_CONTEXT *ppChainContext) // optional
  1481. {
  1482. DWORD dwCertFlags = 0;
  1483. DWORD dwIgnoreErrors = 0;
  1484. NTSTATUS Status;
  1485. *pdwMethods = 0;
  1486. *pVerifyStatus = STATUS_SUCCESS;
  1487. DebugLog(( DEB_TRACE_MAPPER, "Checking to see if cert is verified.\n" ));
  1488. if(dwMapperFlags & SCH_FLAG_REVCHECK_END_CERT)
  1489. dwCertFlags |= CERT_CHAIN_REVOCATION_CHECK_END_CERT;
  1490. if(dwMapperFlags & SCH_FLAG_REVCHECK_CHAIN)
  1491. dwCertFlags |= CERT_CHAIN_REVOCATION_CHECK_CHAIN;
  1492. if(dwMapperFlags & SCH_FLAG_REVCHECK_CHAIN_EXCLUDE_ROOT)
  1493. dwCertFlags |= CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT;
  1494. if(dwMapperFlags & SCH_FLAG_IGNORE_NO_REVOCATION_CHECK)
  1495. dwIgnoreErrors |= CRED_FLAG_IGNORE_NO_REVOCATION_CHECK;
  1496. if(dwMapperFlags & SCH_FLAG_IGNORE_REVOCATION_OFFLINE)
  1497. dwIgnoreErrors |= CRED_FLAG_IGNORE_REVOCATION_OFFLINE;
  1498. if(dwMapperFlags & SCH_FLAG_NO_VALIDATION)
  1499. {
  1500. DebugLog((DEB_TRACE, "Skipping certificate validation.\n"));
  1501. if(ppChainContext != NULL)
  1502. {
  1503. CERT_CHAIN_PARA ChainPara;
  1504. ZeroMemory(&ChainPara, sizeof(ChainPara));
  1505. ChainPara.cbSize = sizeof(ChainPara);
  1506. if(!CertGetCertificateChain(
  1507. NULL, // hChainEngine
  1508. pCertContext, // pCertContext
  1509. NULL, // pTime
  1510. pCertContext->hCertStore, // hAdditionalStore
  1511. &ChainPara, // pChainPara
  1512. dwCertFlags, // dwFlags
  1513. NULL, // pvReserved
  1514. ppChainContext)) // ppChainContext
  1515. {
  1516. Status = SP_LOG_RESULT(GetLastError());
  1517. return Status;
  1518. }
  1519. }
  1520. }
  1521. else
  1522. {
  1523. // Check to see if the certificate chain is properly signed all the way
  1524. // up and that we trust the issuer of the root certificate.
  1525. Status = VerifyClientCertificate(pCertContext,
  1526. dwCertFlags,
  1527. dwIgnoreErrors,
  1528. CERT_CHAIN_POLICY_SSL,
  1529. ppChainContext);
  1530. if(Status != STATUS_SUCCESS)
  1531. {
  1532. DebugLog((DEB_WARN, "Client certificate failed to verify with SSL policy (0x%x)\n", Status));
  1533. LogBogusClientCertEvent(pCertContext, Status);
  1534. return Status;
  1535. }
  1536. }
  1537. // Turn on Subject and Issuer mapping.
  1538. *pdwMethods |= REQ_SUBJECT_MAPPING | REQ_ISSUER_MAPPING;
  1539. if(dwMapperFlags & SCH_FLAG_NO_VALIDATION)
  1540. {
  1541. // Turn on UPN mapping.
  1542. *pdwMethods |= REQ_UPN_MAPPING;
  1543. }
  1544. else
  1545. {
  1546. // Check to see if the certificate chain is valid for UPN mapping.
  1547. Status = VerifyClientCertificate(pCertContext,
  1548. dwCertFlags,
  1549. dwIgnoreErrors,
  1550. CERT_CHAIN_POLICY_NT_AUTH,
  1551. NULL);
  1552. if(Status == STATUS_SUCCESS)
  1553. {
  1554. // Turn on UPN mapping.
  1555. *pdwMethods |= REQ_UPN_MAPPING;
  1556. }
  1557. else
  1558. {
  1559. DebugLog((DEB_WARN, "Client certificate failed to verify with NT_AUTH policy (0x%x)\n", Status));
  1560. LogFastMappingFailureEvent(pCertContext, Status);
  1561. *pVerifyStatus = Status;
  1562. }
  1563. }
  1564. DebugLog((DEB_TRACE, "Client certificate verified with methods: 0x%x\n", *pdwMethods));
  1565. return SEC_E_OK;
  1566. }
  1567. DWORD
  1568. WINAPI
  1569. SslLocalMapCredential(
  1570. IN PHMAPPER Mapper,
  1571. IN DWORD CredentialType,
  1572. VOID const *pCredential,
  1573. VOID const *pAuthority,
  1574. OUT HLOCATOR * phLocator
  1575. )
  1576. {
  1577. PCCERT_CONTEXT pCert = (PCERT_CONTEXT)pCredential;
  1578. PMSV1_0_PASSTHROUGH_RESPONSE Response = NULL ;
  1579. PSSL_CERT_LOGON_REQ pRequest = NULL;
  1580. PSSL_CERT_LOGON_RESP CertResp ;
  1581. DWORD cbRequest;
  1582. PUCHAR Pac = NULL ;
  1583. ULONG PacLength ;
  1584. PUCHAR DirectPac = NULL ;
  1585. PUCHAR IndirectPac = NULL ;
  1586. PUCHAR ExpandedPac = NULL ;
  1587. ULONG ExpandedPacLength ;
  1588. NTSTATUS Status ;
  1589. NTSTATUS VerifyStatus ;
  1590. HANDLE Token ;
  1591. LUID LogonId ;
  1592. DWORD dwMethods ;
  1593. PWSTR ReferencedDomain ;
  1594. UNICODE_STRING DomainName ;
  1595. UNICODE_STRING AccountDomain = { 0 };
  1596. PCCERT_CHAIN_CONTEXT pChainContext = NULL;
  1597. UNREFERENCED_PARAMETER(pAuthority);
  1598. DebugLog(( DEB_TRACE_MAPPER, "SslLocalMapCredential, context %x\n", Mapper ));
  1599. if ( CredentialType != X509_ASN_CHAIN )
  1600. {
  1601. return( (DWORD)SEC_E_UNKNOWN_CREDENTIALS );
  1602. }
  1603. //
  1604. // Validate client certificate, and obtain pointer to
  1605. // entire certificate chain.
  1606. //
  1607. Status = MapperVerifyClientChain(pCert,
  1608. Mapper->m_dwFlags,
  1609. &dwMethods,
  1610. &VerifyStatus,
  1611. &pChainContext);
  1612. if(Status != STATUS_SUCCESS)
  1613. {
  1614. return Status;
  1615. }
  1616. //
  1617. // Attempt to logon via Kerberos S4U2Self.
  1618. //
  1619. if((dwMethods & REQ_UPN_MAPPING) &&
  1620. (g_dwCertMappingMethods & SP_REG_CERTMAP_S4U2SELF_FLAG))
  1621. {
  1622. DebugLog(( DEB_TRACE_MAPPER, "Trying S4U2Self mapping\n" ));
  1623. Status = SslTryS4U2Self(pChainContext, &Token);
  1624. if ( NT_SUCCESS( Status ) )
  1625. {
  1626. CertFreeCertificateChain(pChainContext);
  1627. pChainContext = NULL;
  1628. *phLocator = (HLOCATOR) Token ;
  1629. return Status;
  1630. }
  1631. DebugLog(( DEB_TRACE_MAPPER, "Failed with error 0x%x\n", Status ));
  1632. }
  1633. //
  1634. // Build the logon request.
  1635. //
  1636. Status = SslBuildCertLogonRequest(pChainContext,
  1637. dwMethods,
  1638. &pRequest,
  1639. &cbRequest);
  1640. CertFreeCertificateChain(pChainContext);
  1641. pChainContext = NULL;
  1642. if(FAILED(Status))
  1643. {
  1644. return Status;
  1645. }
  1646. //
  1647. // Attempt to find the user locally.
  1648. //
  1649. Status = SslMapCertToUserPac(
  1650. pRequest,
  1651. cbRequest,
  1652. &Pac,
  1653. &PacLength,
  1654. &ReferencedDomain );
  1655. if(NT_SUCCESS(Status))
  1656. {
  1657. // Free this PAC later using LsaTable->FreeLsaHeap.
  1658. DirectPac = Pac;
  1659. }
  1660. if ( !NT_SUCCESS( Status ) &&
  1661. ( ReferencedDomain != NULL ) )
  1662. {
  1663. //
  1664. // Didn't find it at this DC, but another domain appears to
  1665. // have the mapping. Forward it there:
  1666. //
  1667. RtlInitUnicodeString( &DomainName, ReferencedDomain );
  1668. Status = SslMapCertAtDC(
  1669. &DomainName,
  1670. pRequest,
  1671. pRequest->Length,
  1672. TRUE,
  1673. &Pac,
  1674. &PacLength,
  1675. &Response );
  1676. if ( NT_SUCCESS( Status ) )
  1677. {
  1678. // Free this later using MIDL_user_free.
  1679. IndirectPac = Pac;
  1680. CertResp = (PSSL_CERT_LOGON_RESP) Response->ValidationData ;
  1681. //
  1682. // older servers (pre 2010 or so) won't return the full structure,
  1683. // so we need to examine it carefully.
  1684. if ( CertResp->Length - CertResp->AuthDataLength <= sizeof( SSL_CERT_LOGON_RESP ))
  1685. {
  1686. AccountDomain = SslDomainName ;
  1687. }
  1688. else
  1689. {
  1690. if ( CertResp->DomainLength < 65536 )
  1691. {
  1692. AccountDomain.Length = (USHORT) CertResp->DomainLength ;
  1693. AccountDomain.MaximumLength = AccountDomain.Length ;
  1694. AccountDomain.Buffer = (PWSTR) (((PUCHAR) CertResp) + CertResp->OffsetDomain );
  1695. }
  1696. else
  1697. {
  1698. AccountDomain = SslDomainName ;
  1699. }
  1700. }
  1701. }
  1702. LsaTable->FreeLsaHeap( ReferencedDomain );
  1703. }
  1704. else
  1705. {
  1706. AccountDomain = SslDomainName ;
  1707. }
  1708. //
  1709. // Expand the domain local groups.
  1710. //
  1711. if ( NT_SUCCESS( Status ) )
  1712. {
  1713. Status = LsaTable->ExpandAuthDataForDomain(
  1714. Pac,
  1715. PacLength,
  1716. NULL,
  1717. &ExpandedPac,
  1718. &ExpandedPacLength );
  1719. if ( NT_SUCCESS( Status ) )
  1720. {
  1721. Pac = ExpandedPac ;
  1722. PacLength = ExpandedPacLength ;
  1723. }
  1724. }
  1725. //
  1726. // Create the user token.
  1727. //
  1728. if ( NT_SUCCESS( Status ) )
  1729. {
  1730. VerifyStatus = STATUS_SUCCESS;
  1731. Status = SslCreateTokenFromPac( Pac,
  1732. PacLength,
  1733. &AccountDomain,
  1734. &LogonId,
  1735. &Token );
  1736. if ( NT_SUCCESS( Status ) )
  1737. {
  1738. *phLocator = (HLOCATOR) Token ;
  1739. }
  1740. }
  1741. if(pRequest)
  1742. {
  1743. LocalFree(pRequest);
  1744. }
  1745. if(Response)
  1746. {
  1747. LsaTable->FreeReturnBuffer(Response);
  1748. }
  1749. if(DirectPac)
  1750. {
  1751. LsaTable->FreeLsaHeap(DirectPac);
  1752. }
  1753. if(IndirectPac)
  1754. {
  1755. MIDL_user_free(IndirectPac);
  1756. }
  1757. if(ExpandedPac)
  1758. {
  1759. LsaTable->FreeLsaHeap(ExpandedPac);
  1760. }
  1761. if(!NT_SUCCESS(Status))
  1762. {
  1763. DebugLog((DEB_WARN, "Certificate mapping failed (0x%x)\n", Status));
  1764. LogCertMappingFailureEvent(Status);
  1765. if(!NT_SUCCESS(VerifyStatus))
  1766. {
  1767. // Return certificate validation error code, unless the mapper
  1768. // error has already been mapped to a proper sspi error code.
  1769. if(HRESULT_FACILITY(Status) != FACILITY_SECURITY)
  1770. {
  1771. Status = VerifyStatus;
  1772. }
  1773. }
  1774. }
  1775. return ( Status );
  1776. }
  1777. NTSTATUS
  1778. NTAPI
  1779. SslDoClientRequest(
  1780. IN PLSA_CLIENT_REQUEST ClientRequest,
  1781. IN PVOID ProtocolSubmitBuffer,
  1782. IN PVOID ClientBufferBase,
  1783. IN ULONG SubmitBufferLen,
  1784. OUT PVOID * ProtocolReturnBuffer,
  1785. OUT PULONG ReturnBufferLength,
  1786. OUT PNTSTATUS ProtocolStatus
  1787. )
  1788. {
  1789. NTSTATUS Status ;
  1790. PSSL_CERT_LOGON_REQ Request ;
  1791. PSSL_CERT_LOGON_RESP Response, IndirectResponse ;
  1792. PUCHAR Pac = NULL ;
  1793. ULONG PacLength ;
  1794. PUCHAR DirectPac = NULL ;
  1795. PUCHAR IndirectPac = NULL ;
  1796. PUCHAR ExpandedPac = NULL ;
  1797. ULONG ExpandedPacLength ;
  1798. PWSTR ReferencedDomain = NULL;
  1799. PWSTR FirstDot ;
  1800. UNICODE_STRING DomainName = { 0 };
  1801. PMSV1_0_PASSTHROUGH_RESPONSE MsvResponse = NULL ;
  1802. SECPKG_CALL_INFO CallInfo;
  1803. UNREFERENCED_PARAMETER(ClientRequest);
  1804. UNREFERENCED_PARAMETER(ClientBufferBase);
  1805. DebugLog(( DEB_TRACE_MAPPER, "Handling request to do mapping\n" ));
  1806. if ( ARGUMENT_PRESENT( ProtocolReturnBuffer ) )
  1807. {
  1808. *ProtocolReturnBuffer = NULL ;
  1809. }
  1810. //
  1811. // Attempt to map the certificate locally.
  1812. //
  1813. Request = (PSSL_CERT_LOGON_REQ) ProtocolSubmitBuffer ;
  1814. Status = SslMapCertToUserPac(
  1815. Request,
  1816. SubmitBufferLen,
  1817. &Pac,
  1818. &PacLength,
  1819. &ReferencedDomain );
  1820. DebugLog(( DEB_TRACE_MAPPER, "Local lookup returns %x\n", Status ));
  1821. if(NT_SUCCESS(Status))
  1822. {
  1823. // Free this PAC later using LsaTable->FreeLsaHeap.
  1824. DirectPac = Pac;
  1825. }
  1826. if(!NT_SUCCESS(Status) &&
  1827. (ReferencedDomain != NULL))
  1828. {
  1829. BOOL NameMatch;
  1830. //
  1831. // Didn't find it at this DC, but another domain appears to
  1832. // have the mapping. Forward it there:
  1833. //
  1834. RtlInitUnicodeString( &DomainName, ReferencedDomain );
  1835. SslGlobalReadLock();
  1836. DsysAssert(!RtlEqualUnicodeString(&DomainName, &SslGlobalDnsDomainName, TRUE));
  1837. DsysAssert(!RtlEqualUnicodeString(&DomainName, &SslDomainName, TRUE));
  1838. NameMatch = (RtlEqualUnicodeString(&DomainName, &SslGlobalDnsDomainName, TRUE) ||
  1839. RtlEqualUnicodeString(&DomainName, &SslDomainName, TRUE));
  1840. SslGlobalReleaseLock();
  1841. if(NameMatch)
  1842. {
  1843. DebugLog(( DEB_TRACE_MAPPER, "GC is out of sync, bailing on this user\n" ));
  1844. Status = STATUS_LOGON_FAILURE ;
  1845. }
  1846. else if(LsaTable->GetCallInfo(&CallInfo) &&
  1847. (CallInfo.Attributes & SECPKG_CALL_RECURSIVE))
  1848. {
  1849. DebugLog(( DEB_ERROR, "Certificate mapper is recursing!\n" ));
  1850. }
  1851. else
  1852. {
  1853. DebugLog(( DEB_TRACE_MAPPER, "Mapping certificate at DC for domain %ws\n",
  1854. ReferencedDomain ));
  1855. Status = SslMapCertAtDC(
  1856. &DomainName,
  1857. Request,
  1858. Request->Length,
  1859. TRUE,
  1860. &Pac,
  1861. &PacLength,
  1862. &MsvResponse );
  1863. if ( NT_SUCCESS( Status ) )
  1864. {
  1865. // Free this later using MIDL_user_free.
  1866. IndirectPac = Pac;
  1867. IndirectResponse = (PSSL_CERT_LOGON_RESP) MsvResponse->ValidationData ;
  1868. FirstDot = wcschr( ReferencedDomain, L'.' );
  1869. if ( FirstDot )
  1870. {
  1871. *FirstDot = L'\0';
  1872. RtlInitUnicodeString( &DomainName, ReferencedDomain );
  1873. }
  1874. if ( IndirectResponse->Length - IndirectResponse->AuthDataLength <= sizeof( SSL_CERT_LOGON_RESP ))
  1875. {
  1876. //
  1877. // use the first token from the referenced domain
  1878. //
  1879. NOTHING ;
  1880. }
  1881. else
  1882. {
  1883. if ( IndirectResponse->DomainLength < 65536 )
  1884. {
  1885. DomainName.Length = (USHORT) IndirectResponse->DomainLength ;
  1886. DomainName.MaximumLength = DomainName.Length ;
  1887. DomainName.Buffer = (PWSTR) (((PUCHAR) IndirectResponse) + IndirectResponse->OffsetDomain );
  1888. }
  1889. else
  1890. {
  1891. NOTHING ;
  1892. }
  1893. }
  1894. }
  1895. }
  1896. }
  1897. else
  1898. {
  1899. DomainName = SslDomainName ;
  1900. }
  1901. if ( NT_SUCCESS( Status ) )
  1902. {
  1903. //
  1904. // expand resource groups
  1905. //
  1906. Status = LsaTable->ExpandAuthDataForDomain(
  1907. Pac,
  1908. PacLength,
  1909. NULL,
  1910. &ExpandedPac,
  1911. &ExpandedPacLength );
  1912. if ( NT_SUCCESS( Status ) )
  1913. {
  1914. Pac = ExpandedPac ;
  1915. PacLength = ExpandedPacLength ;
  1916. }
  1917. }
  1918. if ( !NT_SUCCESS( Status ) )
  1919. {
  1920. *ReturnBufferLength = 0;
  1921. *ProtocolStatus = Status ;
  1922. Status = STATUS_SUCCESS ;
  1923. goto Cleanup ;
  1924. }
  1925. #ifdef ROGUE_DC
  1926. if(DirectPac)
  1927. {
  1928. // We're a rogue user DC, so let's add some bogus SIDs to the PAC.
  1929. // Yo ho ho.
  1930. DebugLog((DEB_TRACE, "SslDoClientRequest: Calling SslInstrumentRoguePac\n"));
  1931. Status = SslInstrumentRoguePac(&Pac, &PacLength);
  1932. ExpandedPac = Pac;
  1933. if (!NT_SUCCESS(Status))
  1934. {
  1935. DebugLog((DEB_ERROR, "SslDoClientRequest: Failed SslInstrumentRoguePac 0x%x\n", Status));
  1936. goto Cleanup;
  1937. }
  1938. }
  1939. #endif
  1940. //
  1941. // Construct the response blob:
  1942. //
  1943. Response = VirtualAlloc(
  1944. NULL,
  1945. sizeof( SSL_CERT_LOGON_RESP ) + PacLength + DomainName.Length,
  1946. MEM_COMMIT,
  1947. PAGE_READWRITE );
  1948. if ( Response )
  1949. {
  1950. Response->MessageType = SSL_LOOKUP_CERT_MESSAGE;
  1951. Response->Length = sizeof( SSL_CERT_LOGON_RESP ) +
  1952. PacLength + DomainName.Length ;
  1953. Response->OffsetAuthData = sizeof( SSL_CERT_LOGON_RESP );
  1954. Response->AuthDataLength = PacLength ;
  1955. RtlCopyMemory(
  1956. ( Response + 1 ),
  1957. Pac,
  1958. PacLength );
  1959. Response->OffsetDomain = sizeof( SSL_CERT_LOGON_RESP ) + PacLength ;
  1960. Response->DomainLength = DomainName.Length ;
  1961. RtlCopyMemory( (PUCHAR) Response + Response->OffsetDomain,
  1962. DomainName.Buffer,
  1963. DomainName.Length );
  1964. *ProtocolReturnBuffer = Response ;
  1965. *ReturnBufferLength = Response->Length ;
  1966. *ProtocolStatus = STATUS_SUCCESS ;
  1967. Status = STATUS_SUCCESS ;
  1968. }
  1969. else
  1970. {
  1971. Status = STATUS_NO_MEMORY ;
  1972. }
  1973. Cleanup:
  1974. if(MsvResponse)
  1975. {
  1976. LsaTable->FreeReturnBuffer( MsvResponse );
  1977. }
  1978. if(DirectPac)
  1979. {
  1980. LsaTable->FreeLsaHeap(DirectPac);
  1981. }
  1982. if(IndirectPac)
  1983. {
  1984. MIDL_user_free(IndirectPac);
  1985. }
  1986. if(ExpandedPac)
  1987. {
  1988. LsaTable->FreeLsaHeap(ExpandedPac);
  1989. }
  1990. if(ReferencedDomain)
  1991. {
  1992. LsaTable->FreeLsaHeap(ReferencedDomain);
  1993. }
  1994. return Status ;
  1995. }
  1996. //+---------------------------------------------------------------------------
  1997. //
  1998. // Function: SslBuildCertLogonRequest
  1999. //
  2000. // Synopsis: Builds a certificate logon request to send to the server.
  2001. //
  2002. // Arguments: [pChainContext] --
  2003. // [dwMethods] --
  2004. // [ppRequest] --
  2005. // [pcbRequest] --
  2006. //
  2007. // History: 2-26-2001 Jbanes Created
  2008. //
  2009. // Notes: The certificate data that this function builds
  2010. // looks something like this:
  2011. //
  2012. // typedef struct _SSL_CERT_LOGON_REQ {
  2013. // ULONG MessageType ;
  2014. // ULONG Length ;
  2015. // ULONG OffsetCertficate ;
  2016. // ULONG CertLength ;
  2017. // ULONG Flags;
  2018. // ULONG CertCount;
  2019. // SSL_CERT_NAME_INFO NameInfo[1];
  2020. // } SSL_CERT_LOGON_REQ, * PSSL_CERT_LOGON_REQ ;
  2021. //
  2022. // <client certificate>
  2023. // <issuer #1 name>
  2024. // <issuer #2 name>
  2025. // ...
  2026. //
  2027. //----------------------------------------------------------------------------
  2028. NTSTATUS
  2029. WINAPI
  2030. SslBuildCertLogonRequest(
  2031. PCCERT_CHAIN_CONTEXT pChainContext,
  2032. DWORD dwMethods,
  2033. PSSL_CERT_LOGON_REQ *ppRequest,
  2034. PDWORD pcbRequest)
  2035. {
  2036. PCERT_SIMPLE_CHAIN pSimpleChain;
  2037. PCCERT_CONTEXT pCert;
  2038. PCCERT_CONTEXT pCurrentCert;
  2039. PSSL_CERT_LOGON_REQ pCertReq = NULL;
  2040. DWORD Size;
  2041. DWORD Offset;
  2042. DWORD CertCount;
  2043. ULONG i;
  2044. //
  2045. // Compute the request size.
  2046. //
  2047. pSimpleChain = pChainContext->rgpChain[0];
  2048. pCert = pSimpleChain->rgpElement[0]->pCertContext;
  2049. Size = sizeof(SSL_CERT_LOGON_REQ) +
  2050. pCert->cbCertEncoded;
  2051. CertCount = 0;
  2052. for(i = 0; i < pSimpleChain->cElement; i++)
  2053. {
  2054. pCurrentCert = pSimpleChain->rgpElement[i]->pCertContext;
  2055. if(i > 0)
  2056. {
  2057. // Verify that this is not a root certificate.
  2058. if(CertCompareCertificateName(pCurrentCert->dwCertEncodingType,
  2059. &pCurrentCert->pCertInfo->Issuer,
  2060. &pCurrentCert->pCertInfo->Subject))
  2061. {
  2062. break;
  2063. }
  2064. Size += sizeof(SSL_CERT_NAME_INFO);
  2065. }
  2066. Size += pCurrentCert->pCertInfo->Issuer.cbData;
  2067. CertCount++;
  2068. }
  2069. Size = ROUND_UP_COUNT( Size, ALIGN_DWORD );
  2070. //
  2071. // Build the request.
  2072. //
  2073. pCertReq = (PSSL_CERT_LOGON_REQ)LocalAlloc(LPTR, Size);
  2074. if ( !pCertReq )
  2075. {
  2076. return SEC_E_INSUFFICIENT_MEMORY ;
  2077. }
  2078. Offset = sizeof(SSL_CERT_LOGON_REQ) + (CertCount - 1) * sizeof(SSL_CERT_NAME_INFO);
  2079. pCertReq->MessageType = SSL_LOOKUP_CERT_MESSAGE;
  2080. pCertReq->Length = Size;
  2081. pCertReq->OffsetCertificate = Offset;
  2082. pCertReq->CertLength = pCert->cbCertEncoded;
  2083. pCertReq->Flags = dwMethods | REQ_ISSUER_CHAIN_MAPPING;
  2084. RtlCopyMemory((PBYTE)pCertReq + Offset,
  2085. pCert->pbCertEncoded,
  2086. pCert->cbCertEncoded);
  2087. Offset += pCert->cbCertEncoded;
  2088. pCertReq->CertCount = CertCount;
  2089. for(i = 0; i < CertCount; i++)
  2090. {
  2091. pCurrentCert = pSimpleChain->rgpElement[i]->pCertContext;
  2092. pCertReq->NameInfo[i].IssuerOffset = Offset;
  2093. pCertReq->NameInfo[i].IssuerLength = pCurrentCert->pCertInfo->Issuer.cbData;
  2094. RtlCopyMemory((PBYTE)pCertReq + Offset,
  2095. pCurrentCert->pCertInfo->Issuer.pbData,
  2096. pCurrentCert->pCertInfo->Issuer.cbData);
  2097. Offset += pCurrentCert->pCertInfo->Issuer.cbData;
  2098. }
  2099. Offset = ROUND_UP_COUNT( Offset, ALIGN_DWORD );
  2100. #if DBG
  2101. DsysAssert(Offset == Size);
  2102. #endif
  2103. //
  2104. // Return completed request.
  2105. //
  2106. *ppRequest = pCertReq;
  2107. *pcbRequest = Size;
  2108. return STATUS_SUCCESS;
  2109. }
  2110. //+---------------------------------------------------------------------------
  2111. //
  2112. // Function: SslMapCertAtDC
  2113. //
  2114. // Synopsis: Maps a certificate to a user (hopefully) and the PAC,
  2115. //
  2116. // Arguments: [DomainName] --
  2117. // [pCredential] --
  2118. // [cbCredential] --
  2119. // [DcResponse] --
  2120. //
  2121. // History: 5-11-1998 RichardW Created
  2122. // 2-26-2001 Jbanes Added certificate chaining support.
  2123. //
  2124. // Notes: The request that gets sent to the DC looks something
  2125. // like this:
  2126. //
  2127. // typedef struct _MSV1_0_PASSTHROUGH_REQUEST {
  2128. // MSV1_0_PROTOCOL_MESSAGE_TYPE MessageType;
  2129. // UNICODE_STRING DomainName;
  2130. // UNICODE_STRING PackageName;
  2131. // ULONG DataLength;
  2132. // PUCHAR LogonData;
  2133. // ULONG Pad ;
  2134. // } MSV1_0_PASSTHROUGH_REQUEST, *PMSV1_0_PASSTHROUGH_REQUEST;
  2135. //
  2136. // <domain name>
  2137. // <package name>
  2138. // [ padding ]
  2139. //
  2140. // <credential>
  2141. // [ padding ]
  2142. //
  2143. //----------------------------------------------------------------------------
  2144. NTSTATUS
  2145. WINAPI
  2146. SslMapCertAtDC(
  2147. IN PUNICODE_STRING DomainName,
  2148. IN VOID const *pCredential,
  2149. IN DWORD cbCredential,
  2150. IN BOOL IsDC,
  2151. OUT PUCHAR *UserPac,
  2152. OUT PULONG UserPacLen,
  2153. OUT PMSV1_0_PASSTHROUGH_RESPONSE * DcResponse)
  2154. {
  2155. NTSTATUS Status ;
  2156. PMSV1_0_PASSTHROUGH_REQUEST Request ;
  2157. PMSV1_0_PASSTHROUGH_RESPONSE Response = NULL;
  2158. PSSL_CERT_LOGON_RESP CertResp ;
  2159. DWORD Size ;
  2160. DWORD RequestSize ;
  2161. DWORD ResponseSize ;
  2162. PUCHAR Where ;
  2163. NTSTATUS SubStatus ;
  2164. #if DBG
  2165. DWORD CheckSize2 ;
  2166. #endif
  2167. PSID pTrustSid = NULL;
  2168. PUCHAR Pac = NULL;
  2169. ULONG PacLength;
  2170. DebugLog(( DEB_TRACE_MAPPER, "Remote call to DC to do the mapping\n" ));
  2171. //
  2172. // Validate the input parameters.
  2173. //
  2174. if(cbCredential > 0x4000)
  2175. {
  2176. return SEC_E_ILLEGAL_MESSAGE;
  2177. }
  2178. //
  2179. // Verify that the target DC is in the same forest. Cross-forest
  2180. // certificate mapping is not supported, except via the S4U2Self
  2181. // mechanism.
  2182. if(IsDC)
  2183. {
  2184. BOOL fWithinForest = TRUE;
  2185. Status = LsaIIsDomainWithinForest(DomainName,
  2186. &fWithinForest,
  2187. NULL,
  2188. &pTrustSid,
  2189. NULL,
  2190. NULL,
  2191. NULL);
  2192. if (!NT_SUCCESS (Status))
  2193. {
  2194. DebugLog((DEB_ERROR, "SslMapCertAtDC: LsaIIsDomainWithinForest failed 0x%x\n", Status));
  2195. goto cleanup;
  2196. }
  2197. if (!fWithinForest)
  2198. {
  2199. Status = SEC_E_NO_AUTHENTICATING_AUTHORITY;
  2200. DebugLog((DEB_ERROR, "SslMapCertAtDC: Target DC is outside forest - fail request 0x%x\n", Status));
  2201. goto cleanup;
  2202. }
  2203. }
  2204. //
  2205. // Build the request to send to the DC.
  2206. //
  2207. Size = cbCredential;
  2208. Size = ROUND_UP_COUNT( Size, ALIGN_DWORD );
  2209. RequestSize = DomainName->Length +
  2210. SslLegacyPackageName.Length ;
  2211. RequestSize = ROUND_UP_COUNT( RequestSize, ALIGN_DWORD );
  2212. #if DBG
  2213. CheckSize2 = RequestSize ;
  2214. #endif
  2215. RequestSize += sizeof( MSV1_0_PASSTHROUGH_REQUEST ) +
  2216. Size ;
  2217. SafeAllocaAllocate( (PMSV1_0_PASSTHROUGH_REQUEST)Request, RequestSize );
  2218. if ( !Request )
  2219. {
  2220. Status = SEC_E_INSUFFICIENT_MEMORY;
  2221. goto cleanup;
  2222. }
  2223. Where = (PUCHAR) (Request + 1);
  2224. Request->MessageType = MsV1_0GenericPassthrough ;
  2225. Request->DomainName = *DomainName ;
  2226. Request->DomainName.Buffer = (LPWSTR) Where ;
  2227. RtlCopyMemory( Where,
  2228. DomainName->Buffer,
  2229. DomainName->Length );
  2230. Where += DomainName->Length ;
  2231. Request->PackageName = SslLegacyPackageName ;
  2232. Request->PackageName.Buffer = (LPWSTR) Where ;
  2233. RtlCopyMemory( Where,
  2234. SslLegacyPackageName.Buffer,
  2235. SslLegacyPackageName.Length );
  2236. Where += SslLegacyPackageName.Length ;
  2237. Where = ROUND_UP_POINTER( Where, ALIGN_DWORD );
  2238. #if DBG
  2239. DsysAssert( (((PUCHAR) Request) + CheckSize2 + sizeof( MSV1_0_PASSTHROUGH_REQUEST ) )
  2240. == (PUCHAR) Where );
  2241. #endif
  2242. Request->LogonData = Where ;
  2243. Request->DataLength = Size ;
  2244. RtlCopyMemory( Request->LogonData,
  2245. pCredential,
  2246. cbCredential );
  2247. //
  2248. // Now, call through to our DC:
  2249. //
  2250. Status = LsaCallAuthenticationPackage(
  2251. SslLogonHandle,
  2252. SslMsvPackageId,
  2253. Request,
  2254. RequestSize,
  2255. &Response,
  2256. &ResponseSize,
  2257. &SubStatus );
  2258. SafeAllocaFree( Request );
  2259. Request = NULL;
  2260. if ( !NT_SUCCESS( Status ) )
  2261. {
  2262. DebugLog(( DEB_TRACE_MAPPER, "SslMapCertAtDC returned status 0x%x\n", Status ));
  2263. goto cleanup;
  2264. }
  2265. if ( !NT_SUCCESS( SubStatus ) )
  2266. {
  2267. DebugLog(( DEB_TRACE_MAPPER, "SslMapCertAtDC returned sub-status 0x%x\n", SubStatus ));
  2268. Status = SubStatus;
  2269. goto cleanup;
  2270. }
  2271. //
  2272. // Extract out the returned PAC and perform SID filtering
  2273. //
  2274. CertResp = (PSSL_CERT_LOGON_RESP) Response->ValidationData ;
  2275. PacLength = CertResp->AuthDataLength;
  2276. Pac = MIDL_user_allocate( PacLength );
  2277. if(Pac == NULL)
  2278. {
  2279. Status = STATUS_NO_MEMORY;
  2280. goto cleanup;
  2281. }
  2282. memcpy(Pac, ((PUCHAR)CertResp) + CertResp->OffsetAuthData, PacLength);
  2283. Status = SslCheckPacForSidFiltering(
  2284. pTrustSid,
  2285. &Pac,
  2286. &PacLength);
  2287. if ( !NT_SUCCESS( Status ) )
  2288. {
  2289. DebugLog(( DEB_TRACE_MAPPER, "SslCheckPacForSidFiltering returned status 0x%x\n", Status ));
  2290. goto cleanup;
  2291. }
  2292. //
  2293. // Set output parameters.
  2294. //
  2295. *UserPac = Pac;
  2296. *UserPacLen = PacLength;
  2297. Pac = NULL;
  2298. *DcResponse = Response;
  2299. Response = NULL;
  2300. DebugLog(( DEB_TRACE_MAPPER, "SslMapCertAtDC returned 0x%x\n", Status ));
  2301. Status = STATUS_SUCCESS;
  2302. cleanup:
  2303. if(Pac)
  2304. {
  2305. MIDL_user_free(Pac);
  2306. }
  2307. if(pTrustSid)
  2308. {
  2309. MIDL_user_free(pTrustSid);
  2310. }
  2311. if(Response)
  2312. {
  2313. LsaTable->FreeReturnBuffer(Response);
  2314. }
  2315. return Status;
  2316. }
  2317. NTSTATUS
  2318. NTAPI
  2319. SslMapExternalCredential(
  2320. IN PLSA_CLIENT_REQUEST ClientRequest,
  2321. IN PVOID ProtocolSubmitBuffer,
  2322. IN PVOID ClientBufferBase,
  2323. IN ULONG SubmitBufferLen,
  2324. OUT PVOID * ProtocolReturnBuffer,
  2325. OUT PULONG ReturnBufferLength,
  2326. OUT PNTSTATUS ProtocolStatus
  2327. )
  2328. {
  2329. PSSL_EXTERNAL_CERT_LOGON_REQ Request;
  2330. PSSL_EXTERNAL_CERT_LOGON_RESP Response;
  2331. NT_PRODUCT_TYPE ProductType;
  2332. BOOL DC;
  2333. HMAPPER Mapper;
  2334. NTSTATUS Status;
  2335. HANDLE hUserToken = NULL;
  2336. UNREFERENCED_PARAMETER(ClientRequest);
  2337. UNREFERENCED_PARAMETER(ClientBufferBase);
  2338. DebugLog(( DEB_TRACE_MAPPER, "SslMapExternalCredential\n" ));
  2339. //
  2340. // Validate the input parameters.
  2341. //
  2342. if ( ARGUMENT_PRESENT( ProtocolReturnBuffer ) )
  2343. {
  2344. *ProtocolReturnBuffer = NULL ;
  2345. }
  2346. if(SubmitBufferLen < sizeof(SSL_EXTERNAL_CERT_LOGON_REQ))
  2347. {
  2348. Status = STATUS_INVALID_PARAMETER;
  2349. goto cleanup;
  2350. }
  2351. Request = (PSSL_EXTERNAL_CERT_LOGON_REQ) ProtocolSubmitBuffer ;
  2352. if(Request->Length != sizeof(SSL_EXTERNAL_CERT_LOGON_REQ))
  2353. {
  2354. Status = STATUS_INVALID_PARAMETER;
  2355. goto cleanup;
  2356. }
  2357. //
  2358. // Attempt to map the certificate.
  2359. //
  2360. if(RtlGetNtProductType(&ProductType))
  2361. {
  2362. DC = (ProductType == NtProductLanManNt);
  2363. }
  2364. else
  2365. {
  2366. Status = STATUS_NO_MEMORY ;
  2367. goto cleanup;
  2368. }
  2369. memset(&Mapper, 0, sizeof(Mapper));
  2370. Mapper.m_dwFlags = SCH_FLAG_SYSTEM_MAPPER | Request->Flags;
  2371. if(DC)
  2372. {
  2373. Status = SslLocalMapCredential( &Mapper,
  2374. Request->CredentialType,
  2375. Request->Credential,
  2376. NULL,
  2377. (PHLOCATOR)&hUserToken);
  2378. }
  2379. else
  2380. {
  2381. Status = SslRemoteMapCredential(&Mapper,
  2382. Request->CredentialType,
  2383. Request->Credential,
  2384. NULL,
  2385. (PHLOCATOR)&hUserToken);
  2386. }
  2387. if(!NT_SUCCESS(Status))
  2388. {
  2389. *ReturnBufferLength = 0;
  2390. *ProtocolStatus = Status;
  2391. Status = STATUS_SUCCESS;
  2392. goto cleanup;
  2393. }
  2394. //
  2395. // Build the response.
  2396. //
  2397. Response = VirtualAlloc(
  2398. NULL,
  2399. sizeof(SSL_EXTERNAL_CERT_LOGON_RESP),
  2400. MEM_COMMIT,
  2401. PAGE_READWRITE);
  2402. if ( Response )
  2403. {
  2404. Response->MessageType = SSL_LOOKUP_EXTERNAL_CERT_MESSAGE;
  2405. Response->Length = sizeof(SSL_EXTERNAL_CERT_LOGON_RESP);
  2406. Response->UserToken = hUserToken;
  2407. Response->Flags = 0;
  2408. *ProtocolReturnBuffer = Response;
  2409. *ReturnBufferLength = Response->Length;
  2410. *ProtocolStatus = STATUS_SUCCESS;
  2411. hUserToken = NULL;
  2412. Status = STATUS_SUCCESS;
  2413. }
  2414. else
  2415. {
  2416. Status = STATUS_NO_MEMORY;
  2417. }
  2418. cleanup:
  2419. if(hUserToken)
  2420. {
  2421. CloseHandle(hUserToken);
  2422. }
  2423. DebugLog(( DEB_TRACE_MAPPER, "SslRemoteMapCredential returns 0x%x\n", Status ));
  2424. return Status;
  2425. }
  2426. DWORD
  2427. WINAPI
  2428. SslRemoteMapCredential(
  2429. IN PHMAPPER Mapper,
  2430. IN DWORD CredentialType,
  2431. VOID const *pCredential,
  2432. VOID const *pAuthority,
  2433. OUT HLOCATOR * phLocator
  2434. )
  2435. {
  2436. PCCERT_CONTEXT pCert = (PCERT_CONTEXT)pCredential;
  2437. NTSTATUS Status ;
  2438. NTSTATUS VerifyStatus ;
  2439. HANDLE Token ;
  2440. LUID LogonId = { 0 };
  2441. PMSV1_0_PASSTHROUGH_RESPONSE Response ;
  2442. PSSL_CERT_LOGON_RESP CertResp ;
  2443. UNICODE_STRING AccountDomain ;
  2444. DWORD dwMethods;
  2445. PCCERT_CHAIN_CONTEXT pChainContext = NULL;
  2446. PSSL_CERT_LOGON_REQ pRequest = NULL;
  2447. DWORD cbRequest;
  2448. PUCHAR Pac = NULL;
  2449. ULONG PacLength;
  2450. UNREFERENCED_PARAMETER(pAuthority);
  2451. DebugLog(( DEB_TRACE_MAPPER, "SslRemoteMapCredential, context %x\n", Mapper ));
  2452. if ( CredentialType != X509_ASN_CHAIN )
  2453. {
  2454. return( (DWORD)SEC_E_UNKNOWN_CREDENTIALS );
  2455. }
  2456. //
  2457. // Validate client certificate, and obtain pointer to
  2458. // entire certificate chain.
  2459. //
  2460. Status = MapperVerifyClientChain(pCert,
  2461. Mapper->m_dwFlags,
  2462. &dwMethods,
  2463. &VerifyStatus,
  2464. &pChainContext);
  2465. if(Status != STATUS_SUCCESS)
  2466. {
  2467. return Status;
  2468. }
  2469. //
  2470. // Attempt to logon via Kerberos S4U2Self.
  2471. //
  2472. if((dwMethods & REQ_UPN_MAPPING) &&
  2473. (g_dwCertMappingMethods & SP_REG_CERTMAP_S4U2SELF_FLAG))
  2474. {
  2475. DebugLog(( DEB_TRACE_MAPPER, "Trying S4U2Self mapping\n" ));
  2476. Status = SslTryS4U2Self(pChainContext, &Token);
  2477. if ( NT_SUCCESS( Status ) )
  2478. {
  2479. CertFreeCertificateChain(pChainContext);
  2480. pChainContext = NULL;
  2481. *phLocator = (HLOCATOR) Token ;
  2482. return Status;
  2483. }
  2484. DebugLog(( DEB_TRACE_MAPPER, "Failed with error 0x%x\n", Status ));
  2485. }
  2486. //
  2487. // Build the logon request.
  2488. //
  2489. Status = SslBuildCertLogonRequest(pChainContext,
  2490. dwMethods,
  2491. &pRequest,
  2492. &cbRequest);
  2493. CertFreeCertificateChain(pChainContext);
  2494. pChainContext = NULL;
  2495. if(FAILED(Status))
  2496. {
  2497. return Status;
  2498. }
  2499. //
  2500. // Send the request to the DC.
  2501. //
  2502. Status = SslMapCertAtDC(
  2503. &SslDomainName,
  2504. pRequest,
  2505. cbRequest,
  2506. FALSE,
  2507. &Pac,
  2508. &PacLength,
  2509. &Response );
  2510. LocalFree(pRequest);
  2511. pRequest = NULL;
  2512. if ( !NT_SUCCESS( Status ) )
  2513. {
  2514. LsaTable->AuditLogon(
  2515. Status,
  2516. VerifyStatus,
  2517. &SslNullString,
  2518. &SslNullString,
  2519. NULL,
  2520. NULL,
  2521. Network,
  2522. &SslTokenSource,
  2523. &LogonId );
  2524. LogCertMappingFailureEvent(Status);
  2525. if(!NT_SUCCESS(VerifyStatus))
  2526. {
  2527. // Return certificate validation error code, unless the mapper
  2528. // error has already been mapped to a proper sspi error code.
  2529. if(HRESULT_FACILITY(Status) != FACILITY_SECURITY)
  2530. {
  2531. Status = VerifyStatus;
  2532. }
  2533. }
  2534. return Status ;
  2535. }
  2536. //
  2537. // Ok, we got mapping data. Try to use it:
  2538. //
  2539. CertResp = (PSSL_CERT_LOGON_RESP) Response->ValidationData ;
  2540. //
  2541. // older servers (pre 2010 or so) won't return the full structure,
  2542. // so we need to examine it carefully.
  2543. if ( CertResp->Length - CertResp->AuthDataLength <= sizeof( SSL_CERT_LOGON_RESP ))
  2544. {
  2545. AccountDomain = SslDomainName ;
  2546. }
  2547. else
  2548. {
  2549. if ( CertResp->DomainLength < 65536 )
  2550. {
  2551. AccountDomain.Length = (USHORT) CertResp->DomainLength ;
  2552. AccountDomain.MaximumLength = AccountDomain.Length ;
  2553. AccountDomain.Buffer = (PWSTR) (((PUCHAR) CertResp) + CertResp->OffsetDomain );
  2554. }
  2555. else
  2556. {
  2557. AccountDomain = SslDomainName ;
  2558. }
  2559. }
  2560. Status = SslCreateTokenFromPac( Pac,
  2561. PacLength,
  2562. &AccountDomain,
  2563. &LogonId,
  2564. &Token );
  2565. if ( NT_SUCCESS( Status ) )
  2566. {
  2567. *phLocator = (HLOCATOR) Token ;
  2568. }
  2569. else
  2570. {
  2571. LogCertMappingFailureEvent(Status);
  2572. }
  2573. LsaTable->FreeReturnBuffer( Response );
  2574. MIDL_user_free(Pac);
  2575. return ( Status );
  2576. }
  2577. DWORD
  2578. WINAPI
  2579. SslLocalCloseLocator(
  2580. IN PHMAPPER Mapper,
  2581. IN HLOCATOR Locator
  2582. )
  2583. {
  2584. UNREFERENCED_PARAMETER(Mapper);
  2585. DebugLog(( DEB_TRACE_MAPPER, "SslLocalCloseLocator (%p)\n", Locator ));
  2586. NtClose( (HANDLE) Locator );
  2587. return( SEC_E_OK );
  2588. }
  2589. DWORD
  2590. WINAPI
  2591. SslLocalGetAccessToken(
  2592. IN PHMAPPER Mapper,
  2593. IN HLOCATOR Locator,
  2594. OUT HANDLE *Token
  2595. )
  2596. {
  2597. UNREFERENCED_PARAMETER(Mapper);
  2598. DebugLog(( DEB_TRACE_MAPPER, "SslLocalGetAccessToken (%p)\n", Locator ));
  2599. *Token = (HANDLE) Locator ;
  2600. return( SEC_E_OK );
  2601. }
  2602. BOOL
  2603. SslRelocateToken(
  2604. IN HLOCATOR Locator,
  2605. OUT HLOCATOR * NewLocator)
  2606. {
  2607. NTSTATUS Status ;
  2608. Status = LsaTable->DuplicateHandle( (HANDLE) Locator,
  2609. (PHANDLE) NewLocator );
  2610. if ( NT_SUCCESS( Status ) )
  2611. {
  2612. return( TRUE );
  2613. }
  2614. return( FALSE );
  2615. }
  2616. #if 0
  2617. DWORD
  2618. TestExternalMapper(
  2619. PCCERT_CONTEXT pCertContext)
  2620. {
  2621. NTSTATUS Status;
  2622. NTSTATUS AuthPackageStatus;
  2623. SSL_EXTERNAL_CERT_LOGON_REQ Request;
  2624. PSSL_EXTERNAL_CERT_LOGON_RESP pResponse;
  2625. ULONG ResponseLength;
  2626. UNICODE_STRING PackageName;
  2627. //
  2628. // Build request.
  2629. //
  2630. memset(&Request, 0, sizeof(SSL_EXTERNAL_CERT_LOGON_REQ));
  2631. Request.MessageType = SSL_LOOKUP_EXTERNAL_CERT_MESSAGE;
  2632. Request.Length = sizeof(SSL_EXTERNAL_CERT_LOGON_REQ);
  2633. Request.CredentialType = X509_ASN_CHAIN;
  2634. Request.Credential = (PVOID)pCertContext;
  2635. //
  2636. // Call security package (must make call as local system).
  2637. //
  2638. RtlInitUnicodeString(&PackageName, L"Schannel");
  2639. Status = LsaICallPackage(
  2640. &PackageName,
  2641. &Request,
  2642. Request.Length,
  2643. (PVOID *)&pResponse,
  2644. &ResponseLength,
  2645. &AuthPackageStatus
  2646. );
  2647. if(!NT_SUCCESS(Status))
  2648. {
  2649. return Status;
  2650. }
  2651. if(NT_SUCCESS(AuthPackageStatus))
  2652. {
  2653. //
  2654. // Mapping was successful.
  2655. //
  2656. }
  2657. LsaIFreeReturnBuffer( pResponse );
  2658. return ERROR_SUCCESS;
  2659. }
  2660. #endif
  2661. //+-------------------------------------------------------------------------
  2662. //
  2663. // Function: SslDomainChangeCallback
  2664. //
  2665. // Synopsis: Function to be called when domain changes
  2666. //
  2667. // Effects:
  2668. //
  2669. // Arguments:
  2670. //
  2671. // Requires:
  2672. //
  2673. // Returns:
  2674. //
  2675. // Notes:
  2676. //
  2677. //
  2678. //--------------------------------------------------------------------------
  2679. VOID NTAPI
  2680. SslDomainChangeCallback(
  2681. IN POLICY_NOTIFICATION_INFORMATION_CLASS ChangedInfoClass
  2682. )
  2683. {
  2684. NTSTATUS Status;
  2685. PLSAPR_POLICY_INFORMATION Policy = NULL;
  2686. BOOL AcquiredLock = FALSE;
  2687. UNICODE_STRING TempDnsDomainName = {0};
  2688. //
  2689. // We only care about domain dns information
  2690. //
  2691. if (ChangedInfoClass != PolicyNotifyDnsDomainInformation)
  2692. {
  2693. return;
  2694. }
  2695. DebugLog((DEB_TRACE,"SSL domain change callback\n"));
  2696. // OutputDebugStringA("SSL domain change callback\n");
  2697. //
  2698. // Get the new domain information
  2699. //
  2700. Status = I_LsaIQueryInformationPolicyTrusted(
  2701. PolicyDnsDomainInformation,
  2702. &Policy
  2703. );
  2704. if (!NT_SUCCESS(Status))
  2705. {
  2706. DebugLog((DEB_ERROR,"Failed to query domain dns information %x - not updating.\n", Status));
  2707. goto Cleanup;
  2708. }
  2709. //
  2710. // Copy the domain name
  2711. //
  2712. Status = SslDuplicateString(
  2713. &TempDnsDomainName,
  2714. (PUNICODE_STRING) &Policy->PolicyDnsDomainInfo.DnsDomainName
  2715. );
  2716. if (!NT_SUCCESS(Status))
  2717. {
  2718. goto Cleanup;
  2719. }
  2720. //
  2721. // Acquire the global lock so we can update the data
  2722. //
  2723. if (!SslGlobalWriteLock())
  2724. {
  2725. DebugLog((DEB_ERROR,"Failed to acquire global resource. Not changing domain.\n"));
  2726. goto Cleanup;
  2727. }
  2728. AcquiredLock = TRUE;
  2729. //
  2730. // Copy all the data to the global structures
  2731. //
  2732. SslFreeString(&SslGlobalDnsDomainName);
  2733. SslGlobalDnsDomainName = TempDnsDomainName;
  2734. TempDnsDomainName.Buffer = NULL;
  2735. DebugLog((DEB_TRACE,"SSL DNS Domain Name changed to:%ls\n", SslGlobalDnsDomainName.Buffer));
  2736. // OutputDebugStringA("SSL DNS Domain Name changed to:");
  2737. // OutputDebugStringW(SslGlobalDnsDomainName.Buffer);
  2738. // OutputDebugStringA("\n");
  2739. Cleanup:
  2740. if (AcquiredLock)
  2741. {
  2742. SslGlobalReleaseLock();
  2743. }
  2744. if (Policy != NULL)
  2745. {
  2746. I_LsaIFree_LSAPR_POLICY_INFORMATION(
  2747. PolicyDnsDomainInformation,
  2748. Policy
  2749. );
  2750. }
  2751. SslFreeString(&TempDnsDomainName);
  2752. }
  2753. //+-------------------------------------------------------------------------
  2754. //
  2755. // Function: SslRegisterForDomainChange
  2756. //
  2757. // Synopsis: Register with the LSA to be notified of domain changes
  2758. //
  2759. // Effects:
  2760. //
  2761. // Arguments:
  2762. //
  2763. // Requires:
  2764. //
  2765. // Returns:
  2766. //
  2767. // Notes:
  2768. //
  2769. //
  2770. //--------------------------------------------------------------------------
  2771. NTSTATUS
  2772. SslRegisterForDomainChange(
  2773. VOID
  2774. )
  2775. {
  2776. NTSTATUS Status;
  2777. Status = I_LsaIRegisterPolicyChangeNotificationCallback(
  2778. SslDomainChangeCallback,
  2779. PolicyNotifyDnsDomainInformation
  2780. );
  2781. if (!NT_SUCCESS(Status))
  2782. {
  2783. DebugLog((DEB_ERROR,"Failed to register for domain change notification: 0x%x.\n",Status));
  2784. }
  2785. return(Status);
  2786. }
  2787. //+-------------------------------------------------------------------------
  2788. //
  2789. // Function: SslUnregisterForDomainChange
  2790. //
  2791. // Synopsis: Unregister for domain change notification
  2792. //
  2793. // Effects:
  2794. //
  2795. // Arguments:
  2796. //
  2797. // Requires:
  2798. //
  2799. // Returns:
  2800. //
  2801. // Notes:
  2802. //
  2803. //
  2804. //--------------------------------------------------------------------------
  2805. VOID
  2806. SslUnregisterForDomainChange(
  2807. VOID
  2808. )
  2809. {
  2810. (VOID) I_LsaIUnregisterPolicyChangeNotificationCallback(
  2811. SslDomainChangeCallback,
  2812. PolicyNotifyDnsDomainInformation
  2813. );
  2814. }