Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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