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.

2776 lines
76 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: security.c
  3. *
  4. * Copyright (c) 1991, Microsoft Corporation
  5. *
  6. * Handles security aspects of winlogon operation.
  7. *
  8. * History:
  9. * 12-05-91 Davidc Created - mostly taken from old winlogon.c
  10. \***************************************************************************/
  11. #include "msgina.h"
  12. #include "authmon.h"
  13. #pragma hdrstop
  14. #define SECURITY_WIN32
  15. #define SECURITY_KERBEROS
  16. #include <security.h>
  17. #include <secint.h>
  18. #include <wincrypt.h>
  19. #include <sclogon.h>
  20. #include <md5.h>
  21. #include <align.h>
  22. #include <ginacomn.h>
  23. #include <Winsock2.h>
  24. extern BOOL g_IsTerminalServer;
  25. //
  26. // 'Constants' used in this module only.
  27. //
  28. SID_IDENTIFIER_AUTHORITY gSystemSidAuthority = SECURITY_NT_AUTHORITY;
  29. SID_IDENTIFIER_AUTHORITY gLocalSidAuthority = SECURITY_LOCAL_SID_AUTHORITY;
  30. PSID gLocalSid; // Initialized in 'InitializeSecurityGlobals'
  31. PSID gAdminSid; // Initialized in 'InitializeSecurityGlobals'
  32. PSID pWinlogonSid; // Initialized in 'InitializeSecurityGlobals'
  33. //
  34. // This structure wraps parameters passed to the background logon thread.
  35. // The background logon is queued to the thread pool after a fast-cached
  36. // logon to update the cached credentials.
  37. //
  38. typedef struct _BACKGROUND_LOGON_PARAMETERS {
  39. ULONG AuthenticationPackage;
  40. ULONG AuthenticationInformationLength;
  41. PVOID AuthenticationInformation;
  42. PWCHAR UserSidString;
  43. HANDLE LsaHandle;
  44. } BACKGROUND_LOGON_PARAMETERS, *PBACKGROUND_LOGON_PARAMETERS;
  45. //
  46. // Routines to check for & perform fast cached logon if policy allows it.
  47. //
  48. NTSTATUS
  49. AttemptCachedLogon(
  50. HANDLE LsaHandle,
  51. PLSA_STRING OriginName,
  52. SECURITY_LOGON_TYPE LogonType,
  53. ULONG AuthenticationPackage,
  54. PVOID AuthenticationInformation,
  55. ULONG AuthenticationInformationLength,
  56. PTOKEN_GROUPS LocalGroups,
  57. PTOKEN_SOURCE SourceContext,
  58. PVOID *ProfileBuffer,
  59. PULONG ProfileBufferLength,
  60. PLUID LogonId,
  61. PHANDLE UserToken,
  62. PQUOTA_LIMITS Quotas,
  63. PNTSTATUS SubStatus,
  64. POPTIMIZED_LOGON_STATUS OptimizedLogonStatus
  65. );
  66. DWORD
  67. BackgroundLogonWorker(
  68. PBACKGROUND_LOGON_PARAMETERS LogonParameters
  69. );
  70. #define PASSWORD_HASH_STRING TEXT("Long string used by msgina inside of winlogon to hash out the password")
  71. typedef LONG ACEINDEX;
  72. typedef ACEINDEX *PACEINDEX;
  73. typedef struct _MYACE {
  74. PSID Sid;
  75. ACCESS_MASK AccessMask;
  76. UCHAR InheritFlags;
  77. } MYACE;
  78. typedef MYACE *PMYACE;
  79. BOOL
  80. InitializeWindowsSecurity(
  81. PGLOBALS pGlobals
  82. );
  83. BOOL
  84. InitializeAuthentication(
  85. IN PGLOBALS pGlobals
  86. );
  87. /***************************************************************************\
  88. * SetMyAce
  89. *
  90. * Helper routine that fills in a MYACE structure.
  91. *
  92. * History:
  93. * 02-06-92 Davidc Created
  94. \***************************************************************************/
  95. VOID
  96. SetMyAce(
  97. PMYACE MyAce,
  98. PSID Sid,
  99. ACCESS_MASK Mask,
  100. UCHAR InheritFlags
  101. )
  102. {
  103. MyAce->Sid = Sid;
  104. MyAce->AccessMask= Mask;
  105. MyAce->InheritFlags = InheritFlags;
  106. }
  107. /***************************************************************************\
  108. * CreateAccessAllowedAce
  109. *
  110. * Allocates memory for an ACCESS_ALLOWED_ACE and fills it in.
  111. * The memory should be freed by calling DestroyACE.
  112. *
  113. * Returns pointer to ACE on success, NULL on failure
  114. *
  115. * History:
  116. * 12-05-91 Davidc Created
  117. \***************************************************************************/
  118. PVOID
  119. CreateAccessAllowedAce(
  120. PSID Sid,
  121. ACCESS_MASK AccessMask,
  122. UCHAR AceFlags,
  123. UCHAR InheritFlags
  124. )
  125. {
  126. ULONG LengthSid = RtlLengthSid(Sid);
  127. ULONG LengthACE = sizeof(ACE_HEADER) + sizeof(ACCESS_MASK) + LengthSid;
  128. PACCESS_ALLOWED_ACE Ace;
  129. Ace = (PACCESS_ALLOWED_ACE)Alloc(LengthACE);
  130. if (Ace == NULL) {
  131. DebugLog((DEB_ERROR, "CreateAccessAllowedAce : Failed to allocate ace\n"));
  132. return NULL;
  133. }
  134. Ace->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
  135. Ace->Header.AceSize = (UCHAR)LengthACE;
  136. Ace->Header.AceFlags = AceFlags | InheritFlags;
  137. Ace->Mask = AccessMask;
  138. RtlCopySid(LengthSid, (PSID)(&(Ace->SidStart)), Sid );
  139. return(Ace);
  140. }
  141. /***************************************************************************\
  142. * DestroyAce
  143. *
  144. * Frees the memory allocate for an ACE
  145. *
  146. * History:
  147. * 12-05-91 Davidc Created
  148. \***************************************************************************/
  149. VOID
  150. DestroyAce(
  151. PVOID Ace
  152. )
  153. {
  154. Free(Ace);
  155. }
  156. /***************************************************************************\
  157. * CreateSecurityDescriptor
  158. *
  159. * Creates a security descriptor containing an ACL containing the specified ACEs
  160. *
  161. * A SD created with this routine should be destroyed using
  162. * DeleteSecurityDescriptor
  163. *
  164. * Returns a pointer to the security descriptor or NULL on failure.
  165. *
  166. * 02-06-92 Davidc Created.
  167. \***************************************************************************/
  168. PSECURITY_DESCRIPTOR
  169. CreateSecurityDescriptor(
  170. PMYACE MyAce,
  171. ACEINDEX AceCount
  172. )
  173. {
  174. NTSTATUS Status;
  175. ACEINDEX AceIndex;
  176. PACCESS_ALLOWED_ACE *Ace;
  177. PACL Acl = NULL;
  178. PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
  179. ULONG LengthAces;
  180. ULONG LengthAcl;
  181. ULONG LengthSd;
  182. //
  183. // Allocate space for the ACE pointer array
  184. //
  185. Ace = (PACCESS_ALLOWED_ACE *)Alloc(sizeof(PACCESS_ALLOWED_ACE) * AceCount);
  186. if (Ace == NULL) {
  187. DebugLog((DEB_ERROR, "Failed to allocated ACE array\n"));
  188. return(NULL);
  189. }
  190. //
  191. // Create the ACEs and calculate total ACE size
  192. //
  193. LengthAces = 0;
  194. for (AceIndex=0; AceIndex < AceCount; AceIndex ++) {
  195. Ace[AceIndex] = CreateAccessAllowedAce(MyAce[AceIndex].Sid,
  196. MyAce[AceIndex].AccessMask,
  197. 0,
  198. MyAce[AceIndex].InheritFlags);
  199. if (Ace[AceIndex] == NULL) {
  200. DebugLog((DEB_ERROR, "Failed to allocate ace\n"));
  201. } else {
  202. LengthAces += Ace[AceIndex]->Header.AceSize;
  203. }
  204. }
  205. //
  206. // Calculate ACL and SD sizes
  207. //
  208. LengthAcl = sizeof(ACL) + LengthAces;
  209. LengthSd = SECURITY_DESCRIPTOR_MIN_LENGTH;
  210. //
  211. // Create the ACL
  212. //
  213. Acl = Alloc(LengthAcl);
  214. if (Acl != NULL) {
  215. Status = RtlCreateAcl(Acl, LengthAcl, ACL_REVISION);
  216. ASSERT(NT_SUCCESS(Status));
  217. //
  218. // Add the ACES to the ACL and destroy the ACEs
  219. //
  220. for (AceIndex = 0; AceIndex < AceCount; AceIndex ++) {
  221. if (Ace[AceIndex] != NULL) {
  222. Status = RtlAddAce(Acl, ACL_REVISION, 0, Ace[AceIndex],
  223. Ace[AceIndex]->Header.AceSize);
  224. if (!NT_SUCCESS(Status)) {
  225. DebugLog((DEB_ERROR, "AddAce failed, status = 0x%lx", Status));
  226. }
  227. DestroyAce( Ace[AceIndex] );
  228. }
  229. }
  230. } else {
  231. DebugLog((DEB_ERROR, "Failed to allocate ACL\n"));
  232. for ( AceIndex = 0 ; AceIndex < AceCount ; AceIndex++ )
  233. {
  234. if ( Ace[AceIndex] )
  235. {
  236. DestroyAce( Ace[ AceIndex ] );
  237. }
  238. }
  239. }
  240. //
  241. // Free the ACE pointer array
  242. //
  243. Free(Ace);
  244. //
  245. // Create the security descriptor
  246. //
  247. SecurityDescriptor = Alloc(LengthSd);
  248. if (SecurityDescriptor != NULL) {
  249. Status = RtlCreateSecurityDescriptor(SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
  250. ASSERT(NT_SUCCESS(Status));
  251. //
  252. // Set the DACL on the security descriptor
  253. //
  254. Status = RtlSetDaclSecurityDescriptor(SecurityDescriptor, TRUE, Acl, FALSE);
  255. if (!NT_SUCCESS(Status)) {
  256. DebugLog((DEB_ERROR, "SetDACLSD failed, status = 0x%lx", Status));
  257. }
  258. } else {
  259. DebugLog((DEB_ERROR, "Failed to allocate security descriptor\n"));
  260. Free( Acl );
  261. }
  262. //
  263. // Return with our spoils
  264. //
  265. return(SecurityDescriptor);
  266. }
  267. //+---------------------------------------------------------------------------
  268. //
  269. // Function: FreeSecurityDescriptor
  270. //
  271. // Synopsis: Frees security descriptors created by CreateSecurityDescriptor
  272. //
  273. // Arguments: [SecurityDescriptor] --
  274. //
  275. // History: 5-09-96 RichardW Created
  276. //
  277. // Notes:
  278. //
  279. //----------------------------------------------------------------------------
  280. VOID
  281. FreeSecurityDescriptor(
  282. PSECURITY_DESCRIPTOR SecurityDescriptor
  283. )
  284. {
  285. PACL Acl;
  286. BOOL Present;
  287. BOOL Defaulted;
  288. Acl = NULL;
  289. GetSecurityDescriptorDacl( SecurityDescriptor,
  290. &Present,
  291. &Acl,
  292. &Defaulted );
  293. if ( Acl )
  294. {
  295. Free( Acl );
  296. }
  297. Free( SecurityDescriptor );
  298. }
  299. /***************************************************************************\
  300. * CreateUserThreadTokenSD
  301. *
  302. * Creates a security descriptor to protect tokens on user threads
  303. *
  304. * History:
  305. * 12-05-91 Davidc Created
  306. \***************************************************************************/
  307. PSECURITY_DESCRIPTOR
  308. CreateUserThreadTokenSD(
  309. PSID UserSid,
  310. PSID WinlogonSid
  311. )
  312. {
  313. MYACE Ace[2];
  314. ACEINDEX AceCount = 0;
  315. PSECURITY_DESCRIPTOR SecurityDescriptor;
  316. ASSERT(UserSid != NULL); // should always have a non-null user sid
  317. //
  318. // Define the User ACEs
  319. //
  320. SetMyAce(&(Ace[AceCount++]),
  321. UserSid,
  322. TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS |
  323. TOKEN_ADJUST_DEFAULT | TOKEN_QUERY |
  324. TOKEN_DUPLICATE | TOKEN_IMPERSONATE | READ_CONTROL,
  325. 0
  326. );
  327. //
  328. // Define the Winlogon ACEs
  329. //
  330. SetMyAce(&(Ace[AceCount++]),
  331. WinlogonSid,
  332. TOKEN_ALL_ACCESS,
  333. 0
  334. );
  335. // Check we didn't goof
  336. ASSERT((sizeof(Ace) / sizeof(MYACE)) >= AceCount);
  337. //
  338. // Create the security descriptor
  339. //
  340. SecurityDescriptor = CreateSecurityDescriptor(Ace, AceCount);
  341. if (SecurityDescriptor == NULL) {
  342. DebugLog((DEB_ERROR, "failed to create user process token security descriptor\n"));
  343. }
  344. return(SecurityDescriptor);
  345. }
  346. /****************************************************************************\
  347. *
  348. * FUNCTION: DuplicateSID
  349. *
  350. * PURPOSE: Duplicates a given SID
  351. *
  352. * PARAMS: PSID, the SID to duplicate
  353. *
  354. * RETURNS: the duplicated SID or
  355. * NULL.
  356. *
  357. * HISTORY: 10/08/2001 - crisilac created
  358. *
  359. *
  360. \****************************************************************************/
  361. PSID DuplicateSID(PSID pSrcSID)
  362. {
  363. ULONG uSidLength = 0;
  364. PSID pOutSID = NULL;
  365. if ( pSrcSID && RtlValidSid(pSrcSID) )
  366. {
  367. uSidLength = RtlLengthSid(pSrcSID);
  368. pOutSID = Alloc(uSidLength);
  369. if( NULL != pOutSID )
  370. {
  371. if( !NT_SUCCESS(RtlCopySid(uSidLength, pOutSID, pSrcSID)) )
  372. {
  373. Free(pOutSID);
  374. pOutSID = NULL;
  375. }
  376. }
  377. }
  378. return pOutSID;
  379. }
  380. /***************************************************************************\
  381. * InitializeSecurityGlobals
  382. *
  383. * Initializes the various global constants (mainly Sids used in this module.
  384. *
  385. * History:
  386. * 12-05-91 Davidc Created
  387. \***************************************************************************/
  388. VOID
  389. InitializeSecurityGlobals(
  390. VOID
  391. )
  392. {
  393. NTSTATUS Status;
  394. SID_IDENTIFIER_AUTHORITY SystemSidAuthority = SECURITY_NT_AUTHORITY;
  395. ULONG SidLength;
  396. //
  397. // Get our sid so it can be put on object ACLs
  398. //
  399. SidLength = RtlLengthRequiredSid(1);
  400. pWinlogonSid = (PSID)Alloc(SidLength);
  401. if (!pWinlogonSid)
  402. {
  403. //
  404. // We're dead. Couldn't even allocate memory for a measly SID...
  405. //
  406. return;
  407. }
  408. RtlInitializeSid(pWinlogonSid, &SystemSidAuthority, 1);
  409. *(RtlSubAuthoritySid(pWinlogonSid, 0)) = SECURITY_LOCAL_SYSTEM_RID;
  410. //
  411. // Initialize the local sid for later
  412. //
  413. Status = RtlAllocateAndInitializeSid(
  414. &gLocalSidAuthority,
  415. 1,
  416. SECURITY_LOCAL_RID,
  417. 0, 0, 0, 0, 0, 0, 0,
  418. &gLocalSid
  419. );
  420. if (!NT_SUCCESS(Status)) {
  421. WLPrint(("Failed to initialize local sid, status = 0x%lx", Status));
  422. }
  423. //
  424. // Initialize the admin sid for later
  425. //
  426. Status = RtlAllocateAndInitializeSid(
  427. &gSystemSidAuthority,
  428. 2,
  429. SECURITY_BUILTIN_DOMAIN_RID,
  430. DOMAIN_ALIAS_RID_ADMINS,
  431. 0, 0, 0, 0, 0, 0,
  432. &gAdminSid
  433. );
  434. if (!NT_SUCCESS(Status)) {
  435. WLPrint(("Failed to initialize admin alias sid, status = 0x%lx", Status));
  436. }
  437. }
  438. VOID
  439. FreeSecurityGlobals(
  440. VOID
  441. )
  442. {
  443. RtlFreeSid(gAdminSid);
  444. RtlFreeSid(gLocalSid);
  445. LocalFree(pWinlogonSid);
  446. }
  447. /***************************************************************************\
  448. * InitializeAuthentication
  449. *
  450. * Initializes the authentication service. i.e. connects to the authentication
  451. * package using the Lsa.
  452. *
  453. * On successful return, the following fields of our global structure are
  454. * filled in :
  455. * LsaHandle
  456. * SecurityMode
  457. * AuthenticationPackage
  458. *
  459. * Returns TRUE on success, FALSE on failure
  460. *
  461. * History:
  462. * 12-05-91 Davidc Created
  463. \***************************************************************************/
  464. BOOL
  465. InitializeAuthentication(
  466. IN PGLOBALS pGlobals
  467. )
  468. {
  469. NTSTATUS Status;
  470. STRING LogonProcessName;
  471. if (!EnablePrivilege(SE_TCB_PRIVILEGE, TRUE))
  472. {
  473. DebugLog((DEB_ERROR, "Failed to enable SeTcbPrivilege!\n"));
  474. return(FALSE);
  475. }
  476. //
  477. // Hookup to the LSA and locate our authentication package.
  478. //
  479. RtlInitString(&LogonProcessName, "Winlogon\\MSGina");
  480. Status = LsaRegisterLogonProcess(
  481. &LogonProcessName,
  482. &pGlobals->LsaHandle,
  483. &pGlobals->SecurityMode
  484. );
  485. if (!NT_SUCCESS(Status)) {
  486. DebugLog((DEB_ERROR, "LsaRegisterLogonProcess failed: %#x\n", Status));
  487. return(FALSE);
  488. }
  489. return TRUE;
  490. }
  491. PVOID
  492. FormatPasswordCredentials(
  493. IN PUNICODE_STRING UserName,
  494. IN PUNICODE_STRING Domain,
  495. IN PUNICODE_STRING Password,
  496. IN BOOLEAN Unlock,
  497. IN OPTIONAL PLUID LogonId,
  498. OUT PULONG Size
  499. )
  500. {
  501. PKERB_INTERACTIVE_LOGON KerbAuthInfo;
  502. ULONG AuthInfoSize;
  503. PSECURITY_SEED_AND_LENGTH SeedAndLength;
  504. UCHAR Seed;
  505. PBYTE Where;
  506. PWCHAR BackSlash;
  507. UNICODE_STRING UserNameBackup = {0};
  508. UNICODE_STRING DomainBackup = {0};
  509. SeedAndLength = (PSECURITY_SEED_AND_LENGTH)(&Password->Length);
  510. Seed = SeedAndLength->Seed;
  511. if (NULL != (BackSlash = wcschr(UserName->Buffer, L'\\')))
  512. {
  513. // we're going to massage UserName Domain
  514. // Let's save the current param
  515. memcpy(&UserNameBackup, UserName, sizeof(UNICODE_STRING));
  516. memcpy(&DomainBackup, Domain, sizeof(UNICODE_STRING));
  517. *BackSlash = 0; // turn \ in 0
  518. RtlInitUnicodeString(UserName, BackSlash+1);
  519. RtlInitUnicodeString(Domain, UserNameBackup.Buffer);
  520. }
  521. // else BackSlash = NULL will be our trigger
  522. //
  523. // Build the authentication information buffer
  524. //
  525. if (Seed != 0) {
  526. RevealPassword( Password );
  527. }
  528. AuthInfoSize = sizeof(KERB_INTERACTIVE_UNLOCK_LOGON) +
  529. UserName->Length + 2 +
  530. Domain->Length + 2 +
  531. Password->Length + 2 ;
  532. KerbAuthInfo = Alloc(AuthInfoSize);
  533. if (KerbAuthInfo == NULL) {
  534. DebugLog((DEB_ERROR, "failed to allocate memory for authentication buffer\n"));
  535. if ( Seed != 0 )
  536. {
  537. HidePassword( &Seed, Password);
  538. }
  539. return( NULL );
  540. }
  541. //
  542. // This authentication buffer will be used for a logon attempt
  543. //
  544. if (Unlock)
  545. {
  546. ASSERT(ARGUMENT_PRESENT(LogonId));
  547. KerbAuthInfo->MessageType = KerbWorkstationUnlockLogon ;
  548. ((PKERB_INTERACTIVE_UNLOCK_LOGON) KerbAuthInfo)->LogonId = *LogonId;
  549. Where = (PBYTE) (KerbAuthInfo) + sizeof(KERB_INTERACTIVE_UNLOCK_LOGON);
  550. }
  551. else
  552. {
  553. KerbAuthInfo->MessageType = KerbInteractiveLogon ;
  554. Where = (PBYTE) (KerbAuthInfo + 1);
  555. }
  556. //
  557. // Copy the user name into the authentication buffer
  558. //
  559. KerbAuthInfo->UserName.Length =
  560. (USHORT) sizeof(TCHAR) * (USHORT) lstrlen(UserName->Buffer);
  561. KerbAuthInfo->UserName.MaximumLength =
  562. KerbAuthInfo->UserName.Length + sizeof(TCHAR);
  563. KerbAuthInfo->UserName.Buffer = (PWSTR)Where;
  564. lstrcpy(KerbAuthInfo->UserName.Buffer, UserName->Buffer);
  565. //
  566. // Copy the domain name into the authentication buffer
  567. //
  568. KerbAuthInfo->LogonDomainName.Length =
  569. (USHORT) sizeof(TCHAR) * (USHORT) lstrlen(Domain->Buffer);
  570. KerbAuthInfo->LogonDomainName.MaximumLength =
  571. KerbAuthInfo->LogonDomainName.Length + sizeof(TCHAR);
  572. KerbAuthInfo->LogonDomainName.Buffer = (PWSTR)
  573. ((PBYTE)(KerbAuthInfo->UserName.Buffer) +
  574. KerbAuthInfo->UserName.MaximumLength);
  575. lstrcpy(KerbAuthInfo->LogonDomainName.Buffer, Domain->Buffer);
  576. //
  577. // Copy the password into the authentication buffer
  578. // Hide it once we have copied it. Use the same seed value
  579. // that we used for the original password in pGlobals.
  580. //
  581. KerbAuthInfo->Password.Length =
  582. (USHORT) sizeof(TCHAR) * (USHORT) lstrlen(Password->Buffer);
  583. KerbAuthInfo->Password.MaximumLength =
  584. KerbAuthInfo->Password.Length + sizeof(TCHAR);
  585. KerbAuthInfo->Password.Buffer = (PWSTR)
  586. ((PBYTE)(KerbAuthInfo->LogonDomainName.Buffer) +
  587. KerbAuthInfo->LogonDomainName.MaximumLength);
  588. lstrcpy(KerbAuthInfo->Password.Buffer, Password->Buffer);
  589. if ( Seed != 0 )
  590. {
  591. HidePassword( &Seed, Password);
  592. }
  593. HidePassword( &Seed, (PUNICODE_STRING) &KerbAuthInfo->Password);
  594. *Size = AuthInfoSize ;
  595. if (NULL != BackSlash) // We need to restore our parameters
  596. {
  597. *BackSlash = L'\\';
  598. memcpy(UserName, &UserNameBackup, sizeof(UNICODE_STRING));
  599. memcpy(Domain, &DomainBackup, sizeof(UNICODE_STRING));
  600. }
  601. return KerbAuthInfo ;
  602. }
  603. PVOID
  604. FormatSmartCardCredentials(
  605. PUNICODE_STRING Pin,
  606. PVOID SmartCardInfo,
  607. IN BOOLEAN Unlock,
  608. IN OPTIONAL PLUID LogonId,
  609. OUT PULONG Size
  610. )
  611. {
  612. PKERB_SMART_CARD_LOGON KerbAuthInfo;
  613. ULONG AuthInfoSize;
  614. PSECURITY_SEED_AND_LENGTH SeedAndLength;
  615. UCHAR Seed;
  616. PULONG ScInfo ;
  617. PUCHAR Where ;
  618. SeedAndLength = (PSECURITY_SEED_AND_LENGTH)(&Pin->Length);
  619. Seed = SeedAndLength->Seed;
  620. //
  621. // Build the authentication information buffer
  622. //
  623. ScInfo = (PULONG) SmartCardInfo ;
  624. if (Seed != 0) {
  625. RevealPassword( Pin );
  626. }
  627. AuthInfoSize = sizeof( KERB_SMART_CARD_UNLOCK_LOGON ) +
  628. ROUND_UP_COUNT(Pin->Length + 2, 8) + *ScInfo ;
  629. KerbAuthInfo = (PKERB_SMART_CARD_LOGON) LocalAlloc( LMEM_FIXED, AuthInfoSize );
  630. if ( !KerbAuthInfo )
  631. {
  632. if ( Seed != 0 )
  633. {
  634. HidePassword( &Seed, Pin );
  635. }
  636. return NULL ;
  637. }
  638. if (Unlock)
  639. {
  640. ASSERT(ARGUMENT_PRESENT(LogonId));
  641. KerbAuthInfo->MessageType = KerbSmartCardUnlockLogon ;
  642. ((PKERB_SMART_CARD_UNLOCK_LOGON) KerbAuthInfo)->LogonId = *LogonId;
  643. Where = (PUCHAR) (KerbAuthInfo) + sizeof(KERB_SMART_CARD_UNLOCK_LOGON) ;
  644. }
  645. else
  646. {
  647. KerbAuthInfo->MessageType = KerbSmartCardLogon ;
  648. Where = (PUCHAR) (KerbAuthInfo + 1) ;
  649. }
  650. KerbAuthInfo->Pin.Buffer = (PWSTR) Where ;
  651. KerbAuthInfo->Pin.Length = Pin->Length ;
  652. KerbAuthInfo->Pin.MaximumLength = Pin->Length + 2 ;
  653. RtlCopyMemory( Where, Pin->Buffer, Pin->Length + 2 );
  654. Where += ROUND_UP_COUNT(Pin->Length + 2, 8) ;
  655. if ( Seed != 0 )
  656. {
  657. HidePassword( &Seed, Pin );
  658. }
  659. KerbAuthInfo->CspDataLength = *ScInfo ;
  660. KerbAuthInfo->CspData = Where ;
  661. RtlCopyMemory( Where, SmartCardInfo, *ScInfo );
  662. *Size = AuthInfoSize ;
  663. return KerbAuthInfo ;
  664. }
  665. /***************************************************************************\
  666. * LogonUser
  667. *
  668. * Calls the Lsa to logon the specified user.
  669. *
  670. * The LogonSid and a LocalSid is added to the user's groups on successful logon
  671. *
  672. * For this release, password lengths are restricted to 255 bytes in length.
  673. * This allows us to use the upper byte of the String.Length field to
  674. * carry a seed needed to decode the run-encoded password. If the password
  675. * is not run-encoded, the upper byte of the String.Length field should
  676. * be zero.
  677. *
  678. * NOTE: This function will LocalFree the passed in AuthInfo buffer.
  679. *
  680. * On successful return, LogonToken is a handle to the user's token,
  681. * the profile buffer contains user profile information.
  682. *
  683. * History:
  684. * 12-05-91 Davidc Created
  685. \***************************************************************************/
  686. NTSTATUS
  687. WinLogonUser(
  688. IN HANDLE LsaHandle,
  689. IN ULONG AuthenticationPackage,
  690. IN SECURITY_LOGON_TYPE LogonType,
  691. IN PVOID AuthInfo,
  692. IN ULONG AuthInfoSize,
  693. IN PSID LogonSid,
  694. OUT PLUID LogonId,
  695. OUT PHANDLE LogonToken,
  696. OUT PQUOTA_LIMITS Quotas,
  697. OUT PVOID *pProfileBuffer,
  698. OUT PULONG pProfileBufferLength,
  699. OUT PNTSTATUS pSubStatus,
  700. OUT POPTIMIZED_LOGON_STATUS OptimizedLogonStatus
  701. )
  702. {
  703. NTSTATUS Status;
  704. STRING OriginName;
  705. TOKEN_SOURCE SourceContext;
  706. PTOKEN_GROUPS TokenGroups = NULL;
  707. PMSV1_0_INTERACTIVE_PROFILE UserProfile;
  708. PWCHAR UserSidString;
  709. DWORD ErrorCode;
  710. DWORD LogonCacheable;
  711. DWORD DaysToCheck;
  712. DWORD DaysToExpiry;
  713. LARGE_INTEGER CurrentTime;
  714. BOOLEAN UserLoggedOnUsingCache;
  715. DebugLog((DEB_TRACE, " LsaHandle = %x\n", LsaHandle));
  716. DebugLog((DEB_TRACE, " AuthenticationPackage = %d\n", AuthenticationPackage));
  717. #if DBG
  718. if (!RtlValidSid(LogonSid))
  719. {
  720. DebugLog((DEB_ERROR, "LogonSid is invalid!\n"));
  721. Status = STATUS_INVALID_PARAMETER;
  722. goto cleanup;
  723. }
  724. #endif
  725. //
  726. // Initialize source context structure
  727. //
  728. strncpy(SourceContext.SourceName, "User32 ", sizeof(SourceContext.SourceName)); // LATER from res file
  729. Status = NtAllocateLocallyUniqueId(&SourceContext.SourceIdentifier);
  730. if (!NT_SUCCESS(Status)) {
  731. DebugLog((DEB_ERROR, "failed to allocate locally unique id, status = 0x%lx", Status));
  732. goto cleanup;
  733. }
  734. //
  735. // Get any run-encoding information out of the way
  736. // and decode the password. This creates a window
  737. // where the cleartext password will be in memory.
  738. // Keep it short.
  739. //
  740. // Save the seed so we can use the same one again.
  741. //
  742. //
  743. // Set logon origin
  744. //
  745. RtlInitString(&OriginName, "Winlogon");
  746. //
  747. // Create logon token groups
  748. //
  749. #define TOKEN_GROUP_COUNT 2 // We'll add the local SID and the logon SID
  750. TokenGroups = (PTOKEN_GROUPS)Alloc(sizeof(TOKEN_GROUPS) +
  751. (TOKEN_GROUP_COUNT - ANYSIZE_ARRAY) * sizeof(SID_AND_ATTRIBUTES));
  752. if (TokenGroups == NULL) {
  753. DebugLog((DEB_ERROR, "failed to allocate memory for token groups"));
  754. Status = STATUS_NO_MEMORY;
  755. goto cleanup;
  756. }
  757. //
  758. // Fill in the logon token group list
  759. //
  760. TokenGroups->GroupCount = TOKEN_GROUP_COUNT;
  761. TokenGroups->Groups[0].Sid = LogonSid;
  762. TokenGroups->Groups[0].Attributes =
  763. SE_GROUP_MANDATORY | SE_GROUP_ENABLED |
  764. SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_LOGON_ID;
  765. TokenGroups->Groups[1].Sid = gLocalSid;
  766. TokenGroups->Groups[1].Attributes =
  767. SE_GROUP_MANDATORY | SE_GROUP_ENABLED |
  768. SE_GROUP_ENABLED_BY_DEFAULT;
  769. //
  770. // If logging on Interactive to the console, try cached logon first.
  771. //
  772. UserLoggedOnUsingCache = FALSE;
  773. if (LogonType == Interactive) {
  774. //
  775. // Optimized logon that does not hit the network does not
  776. // make sense for local logins.
  777. //
  778. if (IsMachineDomainMember()) {
  779. Status = AttemptCachedLogon(LsaHandle,
  780. &OriginName,
  781. CachedInteractive,
  782. AuthenticationPackage,
  783. AuthInfo,
  784. AuthInfoSize,
  785. TokenGroups,
  786. &SourceContext,
  787. pProfileBuffer,
  788. pProfileBufferLength,
  789. LogonId,
  790. LogonToken,
  791. Quotas,
  792. pSubStatus,
  793. OptimizedLogonStatus);
  794. if (NT_SUCCESS(Status)) {
  795. UserLoggedOnUsingCache = TRUE;
  796. //
  797. // AttemptCachedLogon will take care of freeing AuthInfo.
  798. //
  799. AuthInfo = NULL;
  800. }
  801. } else {
  802. *OptimizedLogonStatus = OLS_MachineIsNotDomainMember;
  803. }
  804. } else {
  805. *OptimizedLogonStatus = OLS_NonCachedLogonType;
  806. }
  807. //
  808. // If we have not been able to log the user on using cached credentials,
  809. // fall back to real network logon.
  810. //
  811. if (!UserLoggedOnUsingCache) {
  812. SOCKADDR_IN sa;
  813. sa.sin_family = AF_INET; // initial values in case this is not a TS session
  814. sa.sin_addr.S_un.S_un_b.s_b1 = 127; // local host 127.0.0.1:0
  815. sa.sin_addr.S_un.S_un_b.s_b2 = 0;
  816. sa.sin_addr.S_un.S_un_b.s_b3 = 0;
  817. sa.sin_addr.S_un.S_un_b.s_b4 = 1;
  818. sa.sin_port = 0;
  819. if ( g_IsTerminalServer )
  820. {
  821. if ( !IsActiveConsoleSession())
  822. {
  823. WINSTATIONREMOTEADDRESS WinStationRemoteAddress_Info;
  824. WINSTATIONINFOCLASS WinStationInformationClass;
  825. ULONG Length = 0;
  826. BOOL fResult = FALSE;
  827. WinStationInformationClass = WinStationRemoteAddress;
  828. memset(&WinStationRemoteAddress_Info, 0, sizeof(WINSTATIONREMOTEADDRESS));
  829. fResult = WinStationQueryInformation(
  830. SERVERNAME_CURRENT,
  831. LOGONID_CURRENT,
  832. WinStationInformationClass,
  833. (PVOID)&WinStationRemoteAddress_Info,
  834. sizeof(WINSTATIONREMOTEADDRESS),
  835. &Length);
  836. //init for error case
  837. sa.sin_addr.S_un.S_un_b.s_b1 = 0;
  838. sa.sin_addr.S_un.S_un_b.s_b2 = 0;
  839. sa.sin_addr.S_un.S_un_b.s_b3 = 0;
  840. sa.sin_addr.S_un.S_un_b.s_b4 = 0;
  841. if(fResult)
  842. {
  843. sa.sin_family = WinStationRemoteAddress_Info.sin_family;
  844. switch( sa.sin_family )
  845. {
  846. case AF_INET:
  847. sa.sin_port = WinStationRemoteAddress_Info.ipv4.sin_port;
  848. sa.sin_addr.S_un.S_un_b.s_b1 = ( (PUCHAR)&WinStationRemoteAddress_Info.ipv4.in_addr ) [0] ;
  849. sa.sin_addr.S_un.S_un_b.s_b2 = ( (PUCHAR)&WinStationRemoteAddress_Info.ipv4.in_addr ) [1] ;
  850. sa.sin_addr.S_un.S_un_b.s_b3 = ( (PUCHAR)&WinStationRemoteAddress_Info.ipv4.in_addr ) [2] ;
  851. sa.sin_addr.S_un.S_un_b.s_b4 = ( (PUCHAR)&WinStationRemoteAddress_Info.ipv4.in_addr ) [3] ;
  852. break;
  853. }
  854. }
  855. }
  856. }
  857. // Either we will use the local host ip, or in TS case, the ip of the remote client.
  858. SecpSetIPAddress ( (PUCHAR ) &sa, sizeof( sa ));
  859. Status = LsaLogonUser (
  860. LsaHandle,
  861. &OriginName,
  862. LogonType,
  863. AuthenticationPackage,
  864. AuthInfo,
  865. AuthInfoSize,
  866. TokenGroups,
  867. &SourceContext,
  868. pProfileBuffer,
  869. pProfileBufferLength,
  870. LogonId,
  871. LogonToken,
  872. Quotas,
  873. pSubStatus
  874. );
  875. if (NT_SUCCESS(Status))
  876. {
  877. ASSERT(*pProfileBuffer != NULL);
  878. if (*pProfileBuffer == NULL)
  879. {
  880. Status = STATUS_INSUFFICIENT_RESOURCES;
  881. CloseHandle(*LogonToken);
  882. }
  883. }
  884. }
  885. #if 0
  886. // If this failed it may be because we are doing a UPN logon. Try again
  887. // with no domain
  888. if (!NT_SUCCESS(Status))
  889. {
  890. *pfUpnLogon = TRUE;
  891. PKERB_INTERACTIVE_LOGON pinfo = (PKERB_INTERACTIVE_LOGON) AuthInfo;
  892. // Null out domain string
  893. pinfo->LogonDomainName.Length = 0;
  894. pinfo->LogonDomainName.Buffer[0] = 0;
  895. Status = LsaLogonUser (
  896. LsaHandle,
  897. &OriginName,
  898. LogonType,
  899. AuthenticationPackage,
  900. AuthInfo,
  901. AuthInfoSize,
  902. TokenGroups,
  903. &SourceContext,
  904. pProfileBuffer,
  905. pProfileBufferLength,
  906. LogonId,
  907. LogonToken,
  908. Quotas,
  909. pSubStatus
  910. );
  911. }
  912. #endif
  913. //
  914. // If this was a successful login perform tasks for optimized logon
  915. // maintenance.
  916. //
  917. if (NT_SUCCESS(Status)) {
  918. UserProfile = *pProfileBuffer;
  919. //
  920. // Get user's SID in string form.
  921. //
  922. UserSidString = GcGetSidString(*LogonToken);
  923. if (UserSidString) {
  924. //
  925. // Save whether we did an optimized logon or the reason why
  926. // we did not.
  927. //
  928. GcSetOptimizedLogonStatus(UserSidString, *OptimizedLogonStatus);
  929. //
  930. // Check if this was a cached logon.
  931. //
  932. if (!(UserProfile->UserFlags & LOGON_CACHED_ACCOUNT))
  933. {
  934. FgPolicyRefreshInfo UserPolicyRefreshInfo;
  935. //
  936. // If this is not a cached logon because user's profile
  937. // does not allow it, we have to force group policy to
  938. // apply synchronously.
  939. //
  940. ErrorCode = GcCheckIfProfileAllowsCachedLogon(&UserProfile->HomeDirectory,
  941. &UserProfile->ProfilePath,
  942. UserSidString,
  943. &LogonCacheable);
  944. if (ErrorCode != ERROR_SUCCESS || !LogonCacheable) {
  945. //
  946. // If policy is already sync, leave it alone.
  947. //
  948. GetNextFgPolicyRefreshInfo( UserSidString, &UserPolicyRefreshInfo );
  949. if ( UserPolicyRefreshInfo.mode == GP_ModeAsyncForeground )
  950. {
  951. UserPolicyRefreshInfo.reason = GP_ReasonNonCachedCredentials;
  952. UserPolicyRefreshInfo.mode = GP_ModeSyncForeground;
  953. SetNextFgPolicyRefreshInfo( UserSidString, UserPolicyRefreshInfo );
  954. }
  955. }
  956. //
  957. // Determine if we should allow next logon to be optimized.
  958. // We may have disallowed optimizing next logon via this
  959. // mechanism because
  960. // - Our background logon attempt failed e.g. password has
  961. // changed, account has been disabled etc.
  962. // - We are entering the password expiry warning period.
  963. // When we do an optimized logon warning dialogs don't show
  964. // because cached logon invents password expiry time field.
  965. //
  966. // We will allow optimized logon again if this was a non
  967. // cached logon and user got authenticated by the DC, unless
  968. // we are entering the password expiry warning period.
  969. //
  970. if (LogonType == Interactive) {
  971. //
  972. // Are we entering password expiry warning period?
  973. //
  974. GetSystemTimeAsFileTime((FILETIME*) &CurrentTime);
  975. DaysToCheck = GetPasswordExpiryWarningPeriod();
  976. if (GetDaysToExpiry(&CurrentTime,
  977. &UserProfile->PasswordMustChange,
  978. &DaysToExpiry)) {
  979. if (DaysToExpiry > DaysToCheck) {
  980. //
  981. // We passed this check too. We can allow optimized
  982. // logon next time. Note that, even if we allow it,
  983. // policy, profile, logon scripts etc. might still
  984. // disallow it!
  985. //
  986. GcSetNextLogonCacheable(UserSidString, TRUE);
  987. }
  988. }
  989. }
  990. }
  991. GcDeleteSidString(UserSidString);
  992. }
  993. }
  994. cleanup:
  995. if (AuthInfo) {
  996. // Zeroize this for security reason, even though the password is run encoded
  997. ZeroMemory(AuthInfo, AuthInfoSize);
  998. LocalFree(AuthInfo);
  999. }
  1000. if (TokenGroups) {
  1001. Free(TokenGroups);
  1002. }
  1003. return(Status);
  1004. }
  1005. /***************************************************************************\
  1006. * EnablePrivilege
  1007. *
  1008. * Enables/disables the specified well-known privilege in the current thread
  1009. * token if there is one, otherwise the current process token.
  1010. *
  1011. * Returns TRUE on success, FALSE on failure
  1012. *
  1013. * History:
  1014. * 12-05-91 Davidc Created
  1015. \***************************************************************************/
  1016. BOOL
  1017. EnablePrivilege(
  1018. ULONG Privilege,
  1019. BOOL Enable
  1020. )
  1021. {
  1022. NTSTATUS Status;
  1023. BOOLEAN WasEnabled;
  1024. //
  1025. // Try the thread token first
  1026. //
  1027. Status = RtlAdjustPrivilege(Privilege,
  1028. (BOOLEAN)Enable,
  1029. TRUE,
  1030. &WasEnabled);
  1031. if (Status == STATUS_NO_TOKEN) {
  1032. //
  1033. // No thread token, use the process token
  1034. //
  1035. Status = RtlAdjustPrivilege(Privilege,
  1036. (BOOLEAN)Enable,
  1037. FALSE,
  1038. &WasEnabled);
  1039. }
  1040. if (!NT_SUCCESS(Status)) {
  1041. DebugLog((DEB_ERROR, "Failed to %ws privilege : 0x%lx, status = 0x%lx", Enable ? TEXT("enable") : TEXT("disable"), Privilege, Status));
  1042. return(FALSE);
  1043. }
  1044. return(TRUE);
  1045. }
  1046. /***************************************************************************\
  1047. * TestTokenForAdmin
  1048. *
  1049. * Returns TRUE if the token passed represents an admin user, otherwise FALSE
  1050. *
  1051. * The token handle passed must have TOKEN_QUERY access.
  1052. *
  1053. * History:
  1054. * 05-06-92 Davidc Created
  1055. \***************************************************************************/
  1056. BOOL
  1057. TestTokenForAdmin(
  1058. HANDLE Token
  1059. )
  1060. {
  1061. BOOL FoundAdmin ;
  1062. TOKEN_TYPE Type ;
  1063. NTSTATUS Status ;
  1064. ULONG Actual ;
  1065. HANDLE ImpToken ;
  1066. Status = NtQueryInformationToken( Token,
  1067. TokenType,
  1068. (PVOID) &Type,
  1069. sizeof( Type ),
  1070. &Actual );
  1071. if ( !NT_SUCCESS( Status ) )
  1072. {
  1073. return FALSE ;
  1074. }
  1075. if ( Type == TokenPrimary )
  1076. {
  1077. //
  1078. // Need an impersonation token for this:
  1079. //
  1080. if ( DuplicateTokenEx( Token,
  1081. TOKEN_IMPERSONATE | TOKEN_READ,
  1082. NULL,
  1083. SecurityImpersonation,
  1084. TokenImpersonation,
  1085. &ImpToken ) )
  1086. {
  1087. if ( !CheckTokenMembership( ImpToken, gAdminSid, &FoundAdmin ) )
  1088. {
  1089. FoundAdmin = FALSE ;
  1090. }
  1091. CloseHandle( ImpToken );
  1092. }
  1093. else
  1094. {
  1095. FoundAdmin = FALSE ;
  1096. }
  1097. }
  1098. else
  1099. {
  1100. if ( !CheckTokenMembership( Token, gAdminSid, &FoundAdmin ) )
  1101. {
  1102. FoundAdmin = FALSE ;
  1103. }
  1104. }
  1105. return FoundAdmin ;
  1106. }
  1107. /***************************************************************************\
  1108. * TestUserForAdmin
  1109. *
  1110. * Returns TRUE if the named user is an admin. This is done by attempting to
  1111. * log the user on and examining their token.
  1112. *
  1113. * NOTE: The password will be erased upon return to prevent it from being
  1114. * visually identifiable in a pagefile.
  1115. *
  1116. * History:
  1117. * 03-16-92 Davidc Created
  1118. \***************************************************************************/
  1119. BOOL
  1120. TestUserForAdmin(
  1121. PGLOBALS pGlobals,
  1122. IN PWCHAR UserName,
  1123. IN PWCHAR Domain,
  1124. IN PUNICODE_STRING PasswordString
  1125. )
  1126. {
  1127. NTSTATUS Status, SubStatus, IgnoreStatus;
  1128. UNICODE_STRING UserNameString;
  1129. UNICODE_STRING DomainString;
  1130. PVOID ProfileBuffer;
  1131. ULONG ProfileBufferLength;
  1132. QUOTA_LIMITS Quotas;
  1133. HANDLE Token;
  1134. BOOL UserIsAdmin;
  1135. LUID LogonId;
  1136. PVOID AuthInfo ;
  1137. ULONG AuthInfoSize ;
  1138. RtlInitUnicodeString(&UserNameString, UserName);
  1139. RtlInitUnicodeString(&DomainString, Domain);
  1140. //
  1141. // Temporarily log this new subject on and see if their groups
  1142. // contain the appropriate admin group
  1143. //
  1144. AuthInfo = FormatPasswordCredentials(
  1145. &UserNameString,
  1146. &DomainString,
  1147. PasswordString,
  1148. FALSE, // no unlock
  1149. NULL, // no logon id
  1150. &AuthInfoSize );
  1151. if ( !AuthInfo )
  1152. {
  1153. return FALSE ;
  1154. }
  1155. Status = WinLogonUser(
  1156. pGlobals->LsaHandle,
  1157. pGlobals->AuthenticationPackage,
  1158. Interactive,
  1159. AuthInfo,
  1160. AuthInfoSize,
  1161. pGlobals->LogonSid, // any sid will do
  1162. &LogonId,
  1163. &Token,
  1164. &Quotas,
  1165. &ProfileBuffer,
  1166. &ProfileBufferLength,
  1167. &SubStatus,
  1168. &pGlobals->OptimizedLogonStatus);
  1169. RtlEraseUnicodeString( PasswordString );
  1170. //
  1171. // If we couldn't log them on, they're not an admin
  1172. //
  1173. if (!NT_SUCCESS(Status)) {
  1174. return(FALSE);
  1175. }
  1176. //
  1177. // Free up the profile buffer
  1178. //
  1179. IgnoreStatus = LsaFreeReturnBuffer(ProfileBuffer);
  1180. ASSERT(NT_SUCCESS(IgnoreStatus));
  1181. //
  1182. // See if the token represents an admin user
  1183. //
  1184. UserIsAdmin = TestTokenForAdmin(Token);
  1185. //
  1186. // We're finished with the token
  1187. //
  1188. IgnoreStatus = NtClose(Token);
  1189. ASSERT(NT_SUCCESS(IgnoreStatus));
  1190. return(UserIsAdmin);
  1191. }
  1192. BOOL
  1193. UnlockLogon(
  1194. PGLOBALS pGlobals,
  1195. IN BOOL SmartCardUnlock,
  1196. IN PWCHAR UserName,
  1197. IN PWCHAR Domain,
  1198. IN PUNICODE_STRING PasswordString,
  1199. OUT PNTSTATUS pStatus,
  1200. OUT PBOOL IsAdmin,
  1201. OUT PBOOL IsLoggedOnUser,
  1202. OUT PVOID *pProfileBuffer,
  1203. OUT ULONG *pProfileBufferLength
  1204. )
  1205. {
  1206. NTSTATUS Status, SubStatus, IgnoreStatus;
  1207. UNICODE_STRING UserNameString;
  1208. UNICODE_STRING DomainString;
  1209. QUOTA_LIMITS Quotas;
  1210. HANDLE Token;
  1211. HANDLE ImpToken ;
  1212. LUID LogonId;
  1213. PVOID AuthInfo ;
  1214. ULONG AuthInfoSize ;
  1215. ULONG SidSize ;
  1216. UCHAR Buffer[ sizeof( TOKEN_USER ) + 8 + SID_MAX_SUB_AUTHORITIES * sizeof(DWORD) ];
  1217. PTOKEN_USER User ;
  1218. PUCHAR SmartCardInfo ;
  1219. PWLX_SC_NOTIFICATION_INFO ScInfo = NULL;
  1220. PVOID LocalProfileBuffer = NULL;
  1221. ULONG LocalProfileBufferLength;
  1222. #ifdef SMARTCARD_DOGFOOD
  1223. DWORD StartTime, EndTime;
  1224. #endif
  1225. //
  1226. // Assume no admin
  1227. //
  1228. *IsAdmin = FALSE ;
  1229. *IsLoggedOnUser = FALSE ;
  1230. //
  1231. // Bundle up the credentials for passing down to the auth pkgs:
  1232. //
  1233. if ( !SmartCardUnlock )
  1234. {
  1235. RtlInitUnicodeString(&UserNameString, UserName);
  1236. RtlInitUnicodeString(&DomainString, Domain);
  1237. AuthInfo = FormatPasswordCredentials(
  1238. &UserNameString,
  1239. &DomainString,
  1240. PasswordString,
  1241. TRUE, // unlock
  1242. &pGlobals->LogonId,
  1243. &AuthInfoSize );
  1244. }
  1245. else
  1246. {
  1247. if ( !pWlxFuncs->WlxGetOption( pGlobals->hGlobalWlx,
  1248. WLX_OPTION_SMART_CARD_INFO,
  1249. (PULONG_PTR) &ScInfo ) )
  1250. {
  1251. return FALSE ;
  1252. }
  1253. if ( ScInfo == NULL )
  1254. {
  1255. return FALSE ;
  1256. }
  1257. SmartCardInfo = ScBuildLogonInfo(
  1258. ScInfo->pszCard,
  1259. ScInfo->pszReader,
  1260. ScInfo->pszContainer,
  1261. ScInfo->pszCryptoProvider );
  1262. #ifndef SMARTCARD_DOGFOOD
  1263. LocalFree(ScInfo);
  1264. #endif
  1265. if ( SmartCardInfo == NULL )
  1266. {
  1267. #ifdef SMARTCARD_DOGFOOD
  1268. LocalFree(ScInfo);
  1269. #endif
  1270. return FALSE ;
  1271. }
  1272. AuthInfo = FormatSmartCardCredentials(
  1273. PasswordString,
  1274. SmartCardInfo,
  1275. TRUE, // unlock
  1276. &pGlobals->LogonId,
  1277. &AuthInfoSize);
  1278. LocalFree( SmartCardInfo );
  1279. }
  1280. //
  1281. // Make sure that worked:
  1282. //
  1283. if ( !AuthInfo )
  1284. {
  1285. #ifdef SMARTCARD_DOGFOOD
  1286. if (ScInfo)
  1287. LocalFree(ScInfo);
  1288. #endif
  1289. return FALSE ;
  1290. }
  1291. #ifdef SMARTCARD_DOGFOOD
  1292. StartTime = GetTickCount();
  1293. #endif
  1294. //
  1295. // Initialize profile buffer
  1296. //
  1297. if ( !pProfileBuffer )
  1298. {
  1299. pProfileBuffer = &LocalProfileBuffer;
  1300. pProfileBufferLength = &LocalProfileBufferLength;
  1301. }
  1302. SubStatus = 0;
  1303. Status = WinLogonUser(
  1304. pGlobals->LsaHandle,
  1305. ( SmartCardUnlock ? pGlobals->SmartCardLogonPackage : pGlobals->PasswordLogonPackage ),
  1306. Unlock,
  1307. AuthInfo,
  1308. AuthInfoSize,
  1309. pGlobals->LogonSid, // any sid will do
  1310. &LogonId,
  1311. &Token,
  1312. &Quotas,
  1313. pProfileBuffer,
  1314. pProfileBufferLength,
  1315. &SubStatus,
  1316. &pGlobals->OptimizedLogonStatus);
  1317. if (SmartCardUnlock)
  1318. {
  1319. switch (SubStatus)
  1320. {
  1321. case STATUS_SMARTCARD_WRONG_PIN:
  1322. case STATUS_SMARTCARD_CARD_BLOCKED:
  1323. case STATUS_SMARTCARD_CARD_NOT_AUTHENTICATED:
  1324. case STATUS_SMARTCARD_NO_CARD:
  1325. case STATUS_SMARTCARD_NO_KEY_CONTAINER:
  1326. case STATUS_SMARTCARD_NO_CERTIFICATE:
  1327. case STATUS_SMARTCARD_NO_KEYSET:
  1328. case STATUS_SMARTCARD_IO_ERROR:
  1329. case STATUS_SMARTCARD_CERT_EXPIRED:
  1330. case STATUS_SMARTCARD_CERT_REVOKED:
  1331. case STATUS_ISSUING_CA_UNTRUSTED:
  1332. case STATUS_REVOCATION_OFFLINE_C:
  1333. case STATUS_PKINIT_CLIENT_FAILURE:
  1334. Status = SubStatus;
  1335. break;
  1336. }
  1337. }
  1338. #ifdef SMARTCARD_DOGFOOD
  1339. EndTime = GetTickCount();
  1340. if (SmartCardUnlock)
  1341. {
  1342. AuthMonitor(
  1343. AuthOperUnlock,
  1344. g_Console,
  1345. &pGlobals->UserNameString,
  1346. &pGlobals->DomainString,
  1347. (ScInfo ? ScInfo->pszCard : NULL),
  1348. (ScInfo ? ScInfo->pszReader : NULL),
  1349. (PKERB_SMART_CARD_PROFILE) pGlobals->Profile,
  1350. EndTime - StartTime,
  1351. Status
  1352. );
  1353. }
  1354. if (ScInfo)
  1355. LocalFree(ScInfo);
  1356. #endif
  1357. //
  1358. // Do *NOT* erase the password string.
  1359. //
  1360. // RtlEraseUnicodeString( PasswordString );
  1361. if ( !NT_SUCCESS( Status ) )
  1362. {
  1363. if ( Status == STATUS_ACCOUNT_RESTRICTION )
  1364. {
  1365. Status = SubStatus ;
  1366. }
  1367. }
  1368. *pStatus = Status ;
  1369. //
  1370. // If we couldn't log them on, forget it.
  1371. //
  1372. if (!NT_SUCCESS(Status)) {
  1373. return(FALSE);
  1374. }
  1375. //
  1376. // No error check - if we can't tell if the user is an admin, then
  1377. // as far as we're concerned, he isn't.
  1378. //
  1379. *IsAdmin = TestTokenForAdmin( Token );
  1380. //
  1381. // Determine if this really is the logged on user:
  1382. //
  1383. User = (PTOKEN_USER) Buffer ;
  1384. Status = NtQueryInformationToken(
  1385. Token,
  1386. TokenUser,
  1387. User,
  1388. sizeof( Buffer ),
  1389. &SidSize );
  1390. if ( NT_SUCCESS( Status ) )
  1391. {
  1392. if ( pGlobals->UserProcessData.UserSid )
  1393. {
  1394. if ( DuplicateToken( Token,
  1395. SecurityImpersonation,
  1396. &ImpToken ) )
  1397. {
  1398. if ( !CheckTokenMembership(ImpToken,
  1399. pGlobals->UserProcessData.UserSid,
  1400. IsLoggedOnUser ) )
  1401. {
  1402. *IsLoggedOnUser = FALSE ;
  1403. }
  1404. NtClose( ImpToken );
  1405. }
  1406. else
  1407. {
  1408. if ( RtlEqualSid( User->User.Sid,
  1409. pGlobals->UserProcessData.UserSid ) )
  1410. {
  1411. *IsLoggedOnUser = TRUE ;
  1412. }
  1413. else
  1414. {
  1415. *IsLoggedOnUser = FALSE ;
  1416. }
  1417. }
  1418. }
  1419. else
  1420. {
  1421. *IsLoggedOnUser = FALSE ;
  1422. }
  1423. }
  1424. //
  1425. // If we're using our local buffer pointer, free up the profile buffer
  1426. //
  1427. if ( LocalProfileBuffer )
  1428. {
  1429. IgnoreStatus = LsaFreeReturnBuffer(LocalProfileBuffer);
  1430. ASSERT(NT_SUCCESS(IgnoreStatus));
  1431. }
  1432. //
  1433. // We're finished with the token
  1434. //
  1435. IgnoreStatus = NtClose(Token);
  1436. ASSERT(NT_SUCCESS(IgnoreStatus));
  1437. return( TRUE );
  1438. }
  1439. /***************************************************************************\
  1440. * FUNCTION: ImpersonateUser
  1441. *
  1442. * PURPOSE: Impersonates the user by setting the users token
  1443. * on the specified thread. If no thread is specified the token
  1444. * is set on the current thread.
  1445. *
  1446. * RETURNS: Handle to be used on call to StopImpersonating() or NULL on failure
  1447. * If a non-null thread handle was passed in, the handle returned will
  1448. * be the one passed in. (See note)
  1449. *
  1450. * NOTES: Take care when passing in a thread handle and then calling
  1451. * StopImpersonating() with the handle returned by this routine.
  1452. * StopImpersonating() will close any thread handle passed to it -
  1453. * even yours !
  1454. *
  1455. * HISTORY:
  1456. *
  1457. * 04-21-92 Davidc Created.
  1458. *
  1459. \***************************************************************************/
  1460. HANDLE
  1461. ImpersonateUser(
  1462. PUSER_PROCESS_DATA UserProcessData,
  1463. HANDLE ThreadHandle
  1464. )
  1465. {
  1466. NTSTATUS Status, IgnoreStatus;
  1467. HANDLE UserToken = UserProcessData->UserToken;
  1468. SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
  1469. OBJECT_ATTRIBUTES ObjectAttributes;
  1470. HANDLE ImpersonationToken;
  1471. BOOL ThreadHandleOpened = FALSE;
  1472. if (ThreadHandle == NULL) {
  1473. //
  1474. // Get a handle to the current thread.
  1475. // Once we have this handle, we can set the user's impersonation
  1476. // token into the thread and remove it later even though we ARE
  1477. // the user for the removal operation. This is because the handle
  1478. // contains the access rights - the access is not re-evaluated
  1479. // at token removal time.
  1480. //
  1481. Status = NtDuplicateObject( NtCurrentProcess(), // Source process
  1482. NtCurrentThread(), // Source handle
  1483. NtCurrentProcess(), // Target process
  1484. &ThreadHandle, // Target handle
  1485. THREAD_SET_THREAD_TOKEN,// Access
  1486. 0L, // Attributes
  1487. DUPLICATE_SAME_ATTRIBUTES
  1488. );
  1489. if (!NT_SUCCESS(Status)) {
  1490. DebugLog((DEB_ERROR, "ImpersonateUser : Failed to duplicate thread handle, status = 0x%lx", Status));
  1491. return(NULL);
  1492. }
  1493. ThreadHandleOpened = TRUE;
  1494. }
  1495. //
  1496. // If the usertoken is NULL, there's nothing to do
  1497. //
  1498. if (UserToken != NULL) {
  1499. //
  1500. // UserToken is a primary token - create an impersonation token version
  1501. // of it so we can set it on our thread
  1502. //
  1503. InitializeObjectAttributes(
  1504. &ObjectAttributes,
  1505. NULL,
  1506. 0L,
  1507. NULL,
  1508. UserProcessData->NewThreadTokenSD);
  1509. SecurityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  1510. SecurityQualityOfService.ImpersonationLevel = SecurityImpersonation;
  1511. SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  1512. SecurityQualityOfService.EffectiveOnly = FALSE;
  1513. ObjectAttributes.SecurityQualityOfService = &SecurityQualityOfService;
  1514. Status = NtDuplicateToken( UserToken,
  1515. TOKEN_IMPERSONATE | TOKEN_ADJUST_PRIVILEGES |
  1516. TOKEN_QUERY,
  1517. &ObjectAttributes,
  1518. FALSE,
  1519. TokenImpersonation,
  1520. &ImpersonationToken
  1521. );
  1522. if (!NT_SUCCESS(Status)) {
  1523. DebugLog((DEB_ERROR, "Failed to duplicate users token to create impersonation thread, status = 0x%lx", Status));
  1524. if (ThreadHandleOpened) {
  1525. IgnoreStatus = NtClose(ThreadHandle);
  1526. ASSERT(NT_SUCCESS(IgnoreStatus));
  1527. }
  1528. return(NULL);
  1529. }
  1530. //
  1531. // Set the impersonation token on this thread so we 'are' the user
  1532. //
  1533. Status = NtSetInformationThread( ThreadHandle,
  1534. ThreadImpersonationToken,
  1535. (PVOID)&ImpersonationToken,
  1536. sizeof(ImpersonationToken)
  1537. );
  1538. //
  1539. // We're finished with our handle to the impersonation token
  1540. //
  1541. IgnoreStatus = NtClose(ImpersonationToken);
  1542. ASSERT(NT_SUCCESS(IgnoreStatus));
  1543. //
  1544. // Check we set the token on our thread ok
  1545. //
  1546. if (!NT_SUCCESS(Status)) {
  1547. DebugLog((DEB_ERROR, "Failed to set user impersonation token on winlogon thread, status = 0x%lx", Status));
  1548. if (ThreadHandleOpened) {
  1549. IgnoreStatus = NtClose(ThreadHandle);
  1550. ASSERT(NT_SUCCESS(IgnoreStatus));
  1551. }
  1552. return(NULL);
  1553. }
  1554. }
  1555. return(ThreadHandle);
  1556. }
  1557. /***************************************************************************\
  1558. * FUNCTION: StopImpersonating
  1559. *
  1560. * PURPOSE: Stops impersonating the client by removing the token on the
  1561. * current thread.
  1562. *
  1563. * PARAMETERS: ThreadHandle - handle returned by ImpersonateUser() call.
  1564. *
  1565. * RETURNS: TRUE on success, FALSE on failure
  1566. *
  1567. * NOTES: If a thread handle was passed in to ImpersonateUser() then the
  1568. * handle returned was one and the same. If this is passed to
  1569. * StopImpersonating() the handle will be closed. Take care !
  1570. *
  1571. * HISTORY:
  1572. *
  1573. * 04-21-92 Davidc Created.
  1574. *
  1575. \***************************************************************************/
  1576. BOOL
  1577. StopImpersonating(
  1578. HANDLE ThreadHandle
  1579. )
  1580. {
  1581. NTSTATUS Status, IgnoreStatus;
  1582. HANDLE ImpersonationToken;
  1583. //
  1584. // Remove the user's token from our thread so we are 'ourself' again
  1585. //
  1586. ImpersonationToken = NULL;
  1587. Status = NtSetInformationThread( ThreadHandle,
  1588. ThreadImpersonationToken,
  1589. (PVOID)&ImpersonationToken,
  1590. sizeof(ImpersonationToken)
  1591. );
  1592. //
  1593. // We're finished with the thread handle
  1594. //
  1595. IgnoreStatus = NtClose(ThreadHandle);
  1596. ASSERT(NT_SUCCESS(IgnoreStatus));
  1597. if (!NT_SUCCESS(Status)) {
  1598. DebugLog((DEB_ERROR, "Failed to remove user impersonation token from winlogon thread, status = 0x%lx", Status));
  1599. }
  1600. return(NT_SUCCESS(Status));
  1601. }
  1602. /***************************************************************************\
  1603. * TestUserPrivilege
  1604. *
  1605. * Looks at the user token to determine if they have the specified privilege
  1606. *
  1607. * Returns TRUE if the user has the privilege, otherwise FALSE
  1608. *
  1609. * History:
  1610. * 04-21-92 Davidc Created
  1611. \***************************************************************************/
  1612. BOOL
  1613. TestUserPrivilege(
  1614. HANDLE UserToken,
  1615. ULONG Privilege
  1616. )
  1617. {
  1618. NTSTATUS Status;
  1619. NTSTATUS IgnoreStatus;
  1620. BOOL TokenOpened;
  1621. LUID LuidPrivilege;
  1622. LUID TokenPrivilege;
  1623. PTOKEN_PRIVILEGES Privileges;
  1624. ULONG BytesRequired;
  1625. ULONG i;
  1626. BOOL Found;
  1627. TokenOpened = FALSE;
  1628. //
  1629. // If the token is NULL, get a token for the current process since
  1630. // this is the token that will be inherited by new processes.
  1631. //
  1632. if (UserToken == NULL) {
  1633. Status = NtOpenProcessToken(
  1634. NtCurrentProcess(),
  1635. TOKEN_QUERY,
  1636. &UserToken
  1637. );
  1638. if (!NT_SUCCESS(Status)) {
  1639. DebugLog((DEB_ERROR, "Can't open own process token for token_query access"));
  1640. return(FALSE);
  1641. }
  1642. TokenOpened = TRUE;
  1643. }
  1644. //
  1645. // Find out how much memory we need to allocate
  1646. //
  1647. Status = NtQueryInformationToken(
  1648. UserToken, // Handle
  1649. TokenPrivileges, // TokenInformationClass
  1650. NULL, // TokenInformation
  1651. 0, // TokenInformationLength
  1652. &BytesRequired // ReturnLength
  1653. );
  1654. if (Status != STATUS_BUFFER_TOO_SMALL) {
  1655. if (!NT_SUCCESS(Status)) {
  1656. DebugLog((DEB_ERROR, "Failed to query privileges from user token, status = 0x%lx", Status));
  1657. }
  1658. if (TokenOpened) {
  1659. IgnoreStatus = NtClose(UserToken);
  1660. ASSERT(NT_SUCCESS(IgnoreStatus));
  1661. }
  1662. return(FALSE);
  1663. }
  1664. //
  1665. // Allocate space for the privilege array
  1666. //
  1667. Privileges = Alloc(BytesRequired);
  1668. if (Privileges == NULL) {
  1669. DebugLog((DEB_ERROR, "Failed to allocate memory for user privileges"));
  1670. if (TokenOpened) {
  1671. IgnoreStatus = NtClose(UserToken);
  1672. ASSERT(NT_SUCCESS(IgnoreStatus));
  1673. }
  1674. return(FALSE);
  1675. }
  1676. //
  1677. // Read in the user privileges
  1678. //
  1679. Status = NtQueryInformationToken(
  1680. UserToken, // Handle
  1681. TokenPrivileges, // TokenInformationClass
  1682. Privileges, // TokenInformation
  1683. BytesRequired, // TokenInformationLength
  1684. &BytesRequired // ReturnLength
  1685. );
  1686. //
  1687. // We're finished with the token handle
  1688. //
  1689. if (TokenOpened) {
  1690. IgnoreStatus = NtClose(UserToken);
  1691. ASSERT(NT_SUCCESS(IgnoreStatus));
  1692. }
  1693. //
  1694. // See if we got the privileges
  1695. //
  1696. if (!NT_SUCCESS(Status)) {
  1697. DebugLog((DEB_ERROR, "Failed to query privileges from user token"));
  1698. Free(Privileges);
  1699. return(FALSE);
  1700. }
  1701. //
  1702. // See if the user has the privilege we're looking for.
  1703. //
  1704. LuidPrivilege = RtlConvertLongToLuid(Privilege);
  1705. Found = FALSE;
  1706. for (i=0; i<Privileges->PrivilegeCount; i++) {
  1707. TokenPrivilege = *((LUID UNALIGNED *) &Privileges->Privileges[i].Luid);
  1708. if (RtlEqualLuid(&TokenPrivilege, &LuidPrivilege))
  1709. {
  1710. Found = TRUE;
  1711. break;
  1712. }
  1713. }
  1714. Free(Privileges);
  1715. return(Found);
  1716. }
  1717. /***************************************************************************\
  1718. * FUNCTION: HidePassword
  1719. *
  1720. * PURPOSE: Run-encodes the password so that it is not very visually
  1721. * distinguishable. This is so that if it makes it to a
  1722. * paging file, it wont be obvious.
  1723. *
  1724. * if pGlobals->Seed is zero, then we will allocate and assign
  1725. * a seed value. Otherwise, the existing seed value is used.
  1726. *
  1727. * WARNING - This routine will use the upper portion of the
  1728. * password's length field to store the seed used in encoding
  1729. * password. Be careful you don't pass such a string to
  1730. * a routine that looks at the length (like and RPC routine).
  1731. *
  1732. *
  1733. * RETURNS: (None)
  1734. *
  1735. * NOTES:
  1736. *
  1737. * HISTORY:
  1738. *
  1739. * 04-27-93 JimK Created.
  1740. *
  1741. \***************************************************************************/
  1742. VOID
  1743. HidePassword(
  1744. PUCHAR Seed OPTIONAL,
  1745. PUNICODE_STRING Password
  1746. )
  1747. {
  1748. PSECURITY_SEED_AND_LENGTH
  1749. SeedAndLength;
  1750. UCHAR
  1751. LocalSeed;
  1752. //
  1753. // If no seed address passed, use our own local seed buffer
  1754. //
  1755. if (Seed == NULL) {
  1756. Seed = &LocalSeed;
  1757. LocalSeed = 0;
  1758. }
  1759. SeedAndLength = (PSECURITY_SEED_AND_LENGTH)&Password->Length;
  1760. //ASSERT(*((LPWCH)SeedAndLength+Password->Length) == 0);
  1761. ASSERT((SeedAndLength->Seed) == 0);
  1762. RtlRunEncodeUnicodeString(
  1763. Seed,
  1764. Password
  1765. );
  1766. SeedAndLength->Seed = (*Seed);
  1767. return;
  1768. }
  1769. /***************************************************************************\
  1770. * FUNCTION: RevealPassword
  1771. *
  1772. * PURPOSE: Reveals a previously hidden password so that it
  1773. * is plain text once again.
  1774. *
  1775. * RETURNS: (None)
  1776. *
  1777. * NOTES:
  1778. *
  1779. * HISTORY:
  1780. *
  1781. * 04-27-93 JimK Created.
  1782. *
  1783. \***************************************************************************/
  1784. VOID
  1785. RevealPassword(
  1786. PUNICODE_STRING HiddenPassword
  1787. )
  1788. {
  1789. PSECURITY_SEED_AND_LENGTH
  1790. SeedAndLength;
  1791. UCHAR
  1792. Seed;
  1793. SeedAndLength = (PSECURITY_SEED_AND_LENGTH)&HiddenPassword->Length;
  1794. Seed = SeedAndLength->Seed;
  1795. SeedAndLength->Seed = 0;
  1796. RtlRunDecodeUnicodeString(
  1797. Seed,
  1798. HiddenPassword
  1799. );
  1800. return;
  1801. }
  1802. /***************************************************************************\
  1803. * FUNCTION: ErasePassword
  1804. *
  1805. * PURPOSE: zeros a password that is no longer needed.
  1806. *
  1807. * RETURNS: (None)
  1808. *
  1809. * NOTES:
  1810. *
  1811. * HISTORY:
  1812. *
  1813. * 04-27-93 JimK Created.
  1814. *
  1815. \***************************************************************************/
  1816. VOID
  1817. ErasePassword(
  1818. PUNICODE_STRING Password
  1819. )
  1820. {
  1821. PSECURITY_SEED_AND_LENGTH
  1822. SeedAndLength;
  1823. SeedAndLength = (PSECURITY_SEED_AND_LENGTH)&Password->Length;
  1824. SeedAndLength->Seed = 0;
  1825. RtlEraseUnicodeString(
  1826. Password
  1827. );
  1828. return;
  1829. }
  1830. VOID
  1831. HashPassword(
  1832. PUNICODE_STRING Password,
  1833. PUCHAR HashBuffer
  1834. )
  1835. {
  1836. MD5_CTX Context ;
  1837. MD5Init( &Context );
  1838. MD5Update( &Context, (PUCHAR) Password->Buffer, Password->Length );
  1839. MD5Update( &Context, (PUCHAR) PASSWORD_HASH_STRING, sizeof( PASSWORD_HASH_STRING ) );
  1840. MD5Final( &Context );
  1841. RtlCopyMemory( HashBuffer,
  1842. Context.digest,
  1843. MD5DIGESTLEN );
  1844. }
  1845. /***************************************************************************\
  1846. * AttemptCachedLogon
  1847. *
  1848. * Checks to see if we are allowed to use cached credentials to log the user
  1849. * in fast, and does so.
  1850. *
  1851. * Parameters are the same list of parameters passed to LsaLogonUser.
  1852. *
  1853. * On successful return, LogonToken is a handle to the user's token,
  1854. * the profile buffer contains user profile information.
  1855. *
  1856. * History:
  1857. * 03-23-01 Cenke Created
  1858. \***************************************************************************/
  1859. NTSTATUS
  1860. AttemptCachedLogon(
  1861. HANDLE LsaHandle,
  1862. PLSA_STRING OriginName,
  1863. SECURITY_LOGON_TYPE LogonType,
  1864. ULONG AuthenticationPackage,
  1865. PVOID AuthenticationInformation,
  1866. ULONG AuthenticationInformationLength,
  1867. PTOKEN_GROUPS LocalGroups,
  1868. PTOKEN_SOURCE SourceContext,
  1869. PVOID *ProfileBuffer,
  1870. PULONG ProfileBufferLength,
  1871. PLUID LogonId,
  1872. PHANDLE UserToken,
  1873. PQUOTA_LIMITS Quotas,
  1874. PNTSTATUS SubStatus,
  1875. POPTIMIZED_LOGON_STATUS OptimizedLogonStatus
  1876. )
  1877. {
  1878. PWCHAR UserSidString;
  1879. PMSV1_0_INTERACTIVE_PROFILE UserProfile;
  1880. FgPolicyRefreshInfo UserPolicyRefreshInfo;
  1881. PBACKGROUND_LOGON_PARAMETERS LogonParameters;
  1882. OSVERSIONINFOEXW OsVersion;
  1883. NTSTATUS Status;
  1884. DWORD ErrorCode;
  1885. BOOL Success;
  1886. DWORD NextLogonCacheable;
  1887. BOOLEAN UserLoggedOn;
  1888. BOOL RunSynchronous;
  1889. //
  1890. // Initialize locals.
  1891. //
  1892. UserSidString = NULL;
  1893. UserLoggedOn = FALSE;
  1894. LogonParameters = NULL;
  1895. *OptimizedLogonStatus = OLS_Unspecified;
  1896. //
  1897. // Verify parameters.
  1898. //
  1899. ASSERT(LogonType == CachedInteractive);
  1900. //
  1901. // Check if SKU allows cached interactive logons.
  1902. //
  1903. ZeroMemory(&OsVersion, sizeof(OsVersion));
  1904. OsVersion.dwOSVersionInfoSize = sizeof(OsVersion);
  1905. Status = RtlGetVersion((POSVERSIONINFOW)&OsVersion);
  1906. if (!NT_SUCCESS(Status)) {
  1907. *OptimizedLogonStatus = OLS_UnsupportedSKU;
  1908. goto cleanup;
  1909. }
  1910. if (OsVersion.wProductType != VER_NT_WORKSTATION) {
  1911. Status = STATUS_NOT_SUPPORTED;
  1912. *OptimizedLogonStatus = OLS_UnsupportedSKU;
  1913. goto cleanup;
  1914. }
  1915. //
  1916. // Attempt a cached logon.
  1917. //
  1918. Status = LsaLogonUser(LsaHandle,
  1919. OriginName,
  1920. LogonType,
  1921. AuthenticationPackage,
  1922. AuthenticationInformation,
  1923. AuthenticationInformationLength,
  1924. LocalGroups,
  1925. SourceContext,
  1926. ProfileBuffer,
  1927. ProfileBufferLength,
  1928. LogonId,
  1929. UserToken,
  1930. Quotas,
  1931. SubStatus);
  1932. //
  1933. // If cached logon was not successful we cannot continue.
  1934. //
  1935. if (!NT_SUCCESS(Status)) {
  1936. *OptimizedLogonStatus = OLS_LogonFailed;
  1937. goto cleanup;
  1938. }
  1939. UserLoggedOn = TRUE;
  1940. ASSERT(*ProfileBuffer != NULL);
  1941. if (*ProfileBuffer == NULL)
  1942. {
  1943. Status = STATUS_INSUFFICIENT_RESOURCES;
  1944. *OptimizedLogonStatus = OLS_InsufficientResources;
  1945. goto cleanup;
  1946. }
  1947. //
  1948. // Get user's SID.
  1949. //
  1950. UserSidString = GcGetSidString(*UserToken);
  1951. if (!UserSidString) {
  1952. Status = STATUS_INSUFFICIENT_RESOURCES;
  1953. *OptimizedLogonStatus = OLS_InsufficientResources;
  1954. goto cleanup;
  1955. }
  1956. //
  1957. // Check if in last logon of this user we determined we cannot do
  1958. // a cached logon this time.
  1959. //
  1960. ErrorCode = GcGetNextLogonCacheable(UserSidString, &NextLogonCacheable);
  1961. if (ErrorCode == ERROR_SUCCESS && !NextLogonCacheable) {
  1962. Status = STATUS_NOT_SUPPORTED;
  1963. *OptimizedLogonStatus = OLS_NextLogonNotCacheable;
  1964. goto cleanup;
  1965. }
  1966. //
  1967. // Does policy allow cached logons on this machine for the user?
  1968. //
  1969. if (IsSyncForegroundPolicyRefresh(FALSE, *UserToken)) {
  1970. Status = STATUS_NOT_SUPPORTED;
  1971. *OptimizedLogonStatus = OLS_SyncMachinePolicy;
  1972. goto cleanup;
  1973. }
  1974. //
  1975. // Check if policy allows cached logon for this user.
  1976. //
  1977. ErrorCode = GetNextFgPolicyRefreshInfo(UserSidString,
  1978. &UserPolicyRefreshInfo);
  1979. if (ErrorCode != ERROR_SUCCESS ||
  1980. UserPolicyRefreshInfo.mode != GP_ModeAsyncForeground) {
  1981. Status = STATUS_NOT_SUPPORTED;
  1982. *OptimizedLogonStatus = OLS_SyncUserPolicy;
  1983. goto cleanup;
  1984. }
  1985. //
  1986. // Check if user profile does not support default cached logons.
  1987. // e.g if the user has a remote home directory or a roaming profile etc.
  1988. //
  1989. UserProfile = *ProfileBuffer;
  1990. ErrorCode = GcCheckIfProfileAllowsCachedLogon(&UserProfile->HomeDirectory,
  1991. &UserProfile->ProfilePath,
  1992. UserSidString,
  1993. &NextLogonCacheable);
  1994. if (ErrorCode != ERROR_SUCCESS || !NextLogonCacheable) {
  1995. Status = STATUS_NOT_SUPPORTED;
  1996. *OptimizedLogonStatus = OLS_ProfileDisallows;
  1997. goto cleanup;
  1998. }
  1999. //
  2000. // Check if logon scripts are set to run synchronously.
  2001. //
  2002. RunSynchronous = GcCheckIfLogonScriptsRunSync(UserSidString);
  2003. if (RunSynchronous) {
  2004. Status = STATUS_NOT_SUPPORTED;
  2005. *OptimizedLogonStatus = OLS_SyncLogonScripts;
  2006. goto cleanup;
  2007. }
  2008. //
  2009. // We are fine to run with cached logon. We still need to launch a work
  2010. // item to do a real interactive logon that will update the cache.
  2011. //
  2012. LogonParameters = Alloc(sizeof(*LogonParameters));
  2013. if (!LogonParameters) {
  2014. Status = STATUS_INSUFFICIENT_RESOURCES;
  2015. *OptimizedLogonStatus = OLS_InsufficientResources;
  2016. goto cleanup;
  2017. }
  2018. //
  2019. // Initialize the structure so we know what to cleanup.
  2020. //
  2021. ZeroMemory(LogonParameters, sizeof(*LogonParameters));
  2022. LogonParameters->LsaHandle = LsaHandle;
  2023. //
  2024. // Hand over the allocated UserSidString to background logon to cleanup.
  2025. //
  2026. LogonParameters->UserSidString = UserSidString;
  2027. UserSidString = NULL;
  2028. //
  2029. // Hand over AuthenticationInfo structure to background logon.
  2030. // The password is already hidden.
  2031. //
  2032. LogonParameters->AuthenticationPackage = AuthenticationPackage;
  2033. LogonParameters->AuthenticationInformationLength = AuthenticationInformationLength;
  2034. //
  2035. // Background logon will use the authentication information and free it.
  2036. //
  2037. LogonParameters->AuthenticationInformation = AuthenticationInformation;
  2038. //
  2039. // Queue a work item to perform the background logon to update the cache.
  2040. // This background "logon" has nothing to do with the current user
  2041. // successfully logging on, logging off etc. So we don't have to monitor
  2042. // those. All it does is to update the cache.
  2043. //
  2044. Success = QueueUserWorkItem(BackgroundLogonWorker,
  2045. LogonParameters,
  2046. WT_EXECUTELONGFUNCTION);
  2047. if (!Success) {
  2048. //
  2049. // We want to back out from the cached logon if we could not queue
  2050. // an actual logon to update the cache for the next time.
  2051. //
  2052. Status = STATUS_INSUFFICIENT_RESOURCES;
  2053. *OptimizedLogonStatus = OLS_InsufficientResources;
  2054. goto cleanup;
  2055. }
  2056. //
  2057. // We are done.
  2058. //
  2059. Status = STATUS_SUCCESS;
  2060. *OptimizedLogonStatus = OLS_LogonIsCached;
  2061. cleanup:
  2062. if (!NT_SUCCESS(Status)) {
  2063. //
  2064. // If we failed after logging on the user using cached credentials,
  2065. // we have to cleanup.
  2066. //
  2067. if (UserLoggedOn) {
  2068. //
  2069. // Close the user's token.
  2070. //
  2071. CloseHandle(*UserToken);
  2072. //
  2073. // Free the profile buffer.
  2074. //
  2075. if (*ProfileBuffer) {
  2076. LsaFreeReturnBuffer(*ProfileBuffer);
  2077. }
  2078. }
  2079. if (LogonParameters) {
  2080. if (LogonParameters->UserSidString) {
  2081. GcDeleteSidString(LogonParameters->UserSidString);
  2082. }
  2083. Free(LogonParameters);
  2084. }
  2085. }
  2086. if (UserSidString) {
  2087. GcDeleteSidString(UserSidString);
  2088. }
  2089. return Status;
  2090. }
  2091. /***************************************************************************\
  2092. * BackgroundLogonWorker
  2093. *
  2094. * If the actual interactive logon was performed using cached credentials
  2095. * because of policy, this workitem is queued to perform an actual network
  2096. * logon to update the cached information in the security packages.
  2097. *
  2098. * Authentication information to perform the logon is passed in as the
  2099. * parameter and must be freed when the thread is done.
  2100. *
  2101. * History:
  2102. * 03-23-01 Cenke Created
  2103. \***************************************************************************/
  2104. DWORD
  2105. BackgroundLogonWorker(
  2106. PBACKGROUND_LOGON_PARAMETERS LogonParameters
  2107. )
  2108. {
  2109. PMSV1_0_INTERACTIVE_PROFILE Profile;
  2110. HANDLE UserToken;
  2111. LSA_STRING OriginName;
  2112. TOKEN_SOURCE SourceContext;
  2113. QUOTA_LIMITS Quotas;
  2114. PSECURITY_LOGON_SESSION_DATA LogonSessionData;
  2115. LUID LogonId;
  2116. NTSTATUS SubStatus;
  2117. NTSTATUS Status;
  2118. DWORD ErrorCode;
  2119. ULONG ProfileBufferLength;
  2120. ULONG NameBufferNumChars;
  2121. static LONG LogonServicesStarted = 0;
  2122. DWORD MaxWaitTime;
  2123. BOOLEAN UserLoggedOn;
  2124. BOOLEAN ImpersonatingUser;
  2125. WCHAR NameBuffer[UNLEN + 1];
  2126. DWORD DaysToCheck;
  2127. DWORD DaysToExpiry;
  2128. LARGE_INTEGER CurrentTime;
  2129. //
  2130. // Initialize locals.
  2131. //
  2132. Profile = NULL;
  2133. RtlInitString(&OriginName, "Winlogon-Background");
  2134. LogonSessionData = NULL;
  2135. ZeroMemory(&SourceContext, sizeof(SourceContext));
  2136. strncpy(SourceContext.SourceName, "GinaBkg", TOKEN_SOURCE_LENGTH);
  2137. UserLoggedOn = FALSE;
  2138. ImpersonatingUser = FALSE;
  2139. NameBufferNumChars = sizeof(NameBuffer) / sizeof(NameBuffer[0]);
  2140. //
  2141. // Verify parameters.
  2142. //
  2143. ASSERT(LogonParameters);
  2144. ASSERT(LogonParameters->AuthenticationInformation);
  2145. ASSERT(LogonParameters->UserSidString);
  2146. //
  2147. // Make sure workstation and netlogon services have started.
  2148. //
  2149. if (!LogonServicesStarted) {
  2150. MaxWaitTime = 120000; // 2 minutes.
  2151. GcWaitForServiceToStart(SERVICE_WORKSTATION, MaxWaitTime);
  2152. GcWaitForServiceToStart(SERVICE_NETLOGON, MaxWaitTime);
  2153. LogonServicesStarted = 1;
  2154. }
  2155. //
  2156. // Try to log the user in to initiate update of cached credentials.
  2157. //
  2158. Status = LsaLogonUser(LogonParameters->LsaHandle,
  2159. &OriginName,
  2160. Interactive,
  2161. LogonParameters->AuthenticationPackage,
  2162. LogonParameters->AuthenticationInformation,
  2163. LogonParameters->AuthenticationInformationLength,
  2164. NULL,
  2165. &SourceContext,
  2166. &(PVOID)Profile,
  2167. &ProfileBufferLength,
  2168. &LogonId,
  2169. &UserToken,
  2170. &Quotas,
  2171. &SubStatus);
  2172. if (!NT_SUCCESS(Status)) {
  2173. //
  2174. // If the error is real we will force non-cached logon next time.
  2175. //
  2176. if (Status != STATUS_NO_LOGON_SERVERS) {
  2177. GcSetNextLogonCacheable(LogonParameters->UserSidString, FALSE);
  2178. }
  2179. ErrorCode = LsaNtStatusToWinError(Status);
  2180. goto cleanup;
  2181. }
  2182. UserLoggedOn = TRUE;
  2183. ASSERT(Profile != NULL);
  2184. if (Profile == NULL) {
  2185. ErrorCode = ERROR_NO_SYSTEM_RESOURCES; // Generic but enough in this case
  2186. goto cleanup;
  2187. }
  2188. //
  2189. // Did we actually end up doing a cached logon?
  2190. //
  2191. if (Profile->UserFlags & LOGON_CACHED_ACCOUNT) {
  2192. //
  2193. // We are done, just cleanup.
  2194. //
  2195. ErrorCode = ERROR_SUCCESS;
  2196. goto cleanup;
  2197. }
  2198. //
  2199. // If we are entering the password expiry warning period, disable optimized
  2200. // logon for next time so warning dialogs get shown. Otherwise for cached
  2201. // logons password expiry date gets invented to be forever in future.
  2202. //
  2203. if (Profile) {
  2204. GetSystemTimeAsFileTime((FILETIME*) &CurrentTime);
  2205. DaysToCheck = GetPasswordExpiryWarningPeriod();
  2206. if (GetDaysToExpiry(&CurrentTime,
  2207. &Profile->PasswordMustChange,
  2208. &DaysToExpiry)) {
  2209. if (DaysToCheck >= DaysToExpiry) {
  2210. GcSetNextLogonCacheable(LogonParameters->UserSidString, FALSE);
  2211. }
  2212. }
  2213. }
  2214. //
  2215. // Make a GetUserName call to update the user name cache. Ignore errors.
  2216. //
  2217. if (!ImpersonateLoggedOnUser(UserToken)) {
  2218. ErrorCode = GetLastError();
  2219. goto cleanup;
  2220. }
  2221. ImpersonatingUser = TRUE;
  2222. GetUserNameEx(NameSamCompatible, NameBuffer, &NameBufferNumChars);
  2223. //
  2224. // We are done.
  2225. //
  2226. ErrorCode = ERROR_SUCCESS;
  2227. cleanup:
  2228. //
  2229. // Stop impersonation.
  2230. //
  2231. if (ImpersonatingUser) {
  2232. RevertToSelf();
  2233. }
  2234. //
  2235. // Cleanup passed in LogonParameters.
  2236. //
  2237. // Zeroize this for security reason, even though the password is run encoded
  2238. ZeroMemory(LogonParameters->AuthenticationInformation, LogonParameters->AuthenticationInformationLength);
  2239. LocalFree(LogonParameters->AuthenticationInformation);
  2240. Free(LogonParameters->UserSidString);
  2241. Free(LogonParameters);
  2242. //
  2243. // If the user logged on, cleanup.
  2244. //
  2245. if (UserLoggedOn) {
  2246. CloseHandle(UserToken);
  2247. if (Profile) {
  2248. LsaFreeReturnBuffer(Profile);
  2249. }
  2250. }
  2251. if (LogonSessionData) {
  2252. LsaFreeReturnBuffer(LogonSessionData);
  2253. }
  2254. return ErrorCode;
  2255. }