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.

890 lines
27 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // Job Scheduler Service
  4. //
  5. // Microsoft Windows
  6. // Copyright (C) Microsoft Corporation, 1992 - 1996.
  7. //
  8. // File: getuser.cxx
  9. //
  10. // Contents: Get the identity of the logged in user.
  11. //
  12. // History: 19-Jun-96 EricB created
  13. //
  14. // Notes: This is for NT only since Win95 doesn't have security.
  15. //
  16. //-----------------------------------------------------------------------------
  17. //
  18. // Some NT header definitions conflict with some of the standard windows
  19. // definitions. Thus, the project precompiled header can't be used.
  20. //
  21. extern "C" {
  22. #include <nt.h> // NT definitions
  23. #include <ntrtl.h> // NT runtime library definitions
  24. #include <nturtl.h>
  25. #include <ntlsa.h> // BUGBUG 254102
  26. }
  27. #include <windows.h>
  28. #define SECURITY_WIN32 // needed by security.h
  29. #include <security.h> // GetUserNameEx
  30. #include <winbase.h> // SecureZeroMemory
  31. #include <StrSafe.h>
  32. #include <lmcons.h> // BUGBUG 254102
  33. #include <defines.hxx> // BUGBUG 254102
  34. #include <..\..\..\smdebug\smdebug.h>
  35. #include <debug.hxx>
  36. #include "globals.hxx"
  37. #include <Wtsapi32.h>
  38. const int SCH_BIGBUF_LEN = 256;
  39. //
  40. // Registry key/value for default shell.
  41. //
  42. #define SHELL_REGKEY L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"
  43. #define SHELL_REGVAL L"Shell"
  44. #define DEFAULT_SHELL L"explorer.exe"
  45. // This function is actually declared in proto.hxx. But including proto.hxx
  46. // brings in alot of things we don't need. Just define it here to the includes
  47. // simple.
  48. //
  49. HANDLE ImpersonateUser(HANDLE hUserToken, HANDLE hImpersonationToken);
  50. // so's this one - here's to hoping that type-safe linkage works well...
  51. HANDLE ImpersonateLoggedInUser(void);
  52. BOOL StopImpersonating(HANDLE ThreadHandle, BOOL fCloseHandle);
  53. // toggle to allow conditional compilation of fix for RAID 720688
  54. // "old" method found user token for shell process (usually explorer.exe)
  55. // "new" method uses Terminal Server functions
  56. #define FIND_USER_WITH_TS
  57. //+----------------------------------------------------------------------------
  58. //
  59. // Function: LogonSessionDataCleanup
  60. //
  61. // Synopsis: Close all open handles and free memory.
  62. //
  63. // Notes: **** Important ****
  64. //
  65. // No need to enter gcsLogonSessionInfoCritSection prior to
  66. // calling this function since it is entered here.
  67. //
  68. //-----------------------------------------------------------------------------
  69. void
  70. LogonSessionDataCleanup(void)
  71. {
  72. EnterCriticalSection(gUserLogonInfo.CritSection);
  73. if (gUserLogonInfo.ImpersonationThread != NULL)
  74. {
  75. CloseHandle(gUserLogonInfo.ImpersonationThread);
  76. gUserLogonInfo.ImpersonationThread = NULL;
  77. }
  78. if (gUserLogonInfo.DomainUserName != NULL)
  79. {
  80. delete gUserLogonInfo.DomainUserName;
  81. gUserLogonInfo.DomainUserName= NULL;
  82. }
  83. if (gUserLogonInfo.ShellToken)
  84. {
  85. CloseHandle(gUserLogonInfo.ShellToken);
  86. gUserLogonInfo.ShellToken = NULL;
  87. }
  88. SecureZeroMemory(gUserLogonInfo.Sid, sizeof(gUserLogonInfo.Sid));
  89. LeaveCriticalSection(gUserLogonInfo.CritSection);
  90. }
  91. //+----------------------------------------------------------------------------
  92. //
  93. // Function: ImpersonateUser
  94. //
  95. // Synopsis: Impersonate the user associated with the token.
  96. //
  97. // Arguments: [hUserToken] - Handle to the token to be impersonated.
  98. // [ThreadHandle] - Handle to the thread that is to impersonate
  99. // hUserToken. If this is NULL, the function opens a handle
  100. // to the current thread.
  101. //
  102. // Returns: Handle to the thread that is impersonating hUserToken.
  103. //
  104. // Notes: BUGBUG : This code was taken from RAS. It is quite different
  105. // than that in winlogon
  106. // (windows\gina\winlogon\secutil.c).
  107. //
  108. //-----------------------------------------------------------------------------
  109. HANDLE
  110. ImpersonateUser(HANDLE hUserToken, HANDLE ThreadHandle)
  111. {
  112. NTSTATUS Status;
  113. SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
  114. OBJECT_ATTRIBUTES ObjectAttributes;
  115. HANDLE ImpersonationToken;
  116. BOOL ThreadHandleOpened = FALSE;
  117. if (ThreadHandle == NULL)
  118. {
  119. //
  120. // Get a handle to the current thread.
  121. // Once we have this handle, we can set the user's impersonation
  122. // token into the thread and remove it later even though we ARE
  123. // the user for the removal operation. This is because the handle
  124. // contains the access rights - the access is not re-evaluated
  125. // at token removal time.
  126. //
  127. Status = NtDuplicateObject( NtCurrentProcess(), // Source process
  128. NtCurrentThread(), // Source handle
  129. NtCurrentProcess(), // Target process
  130. &ThreadHandle, // Target handle
  131. THREAD_SET_THREAD_TOKEN,// Access
  132. 0L, // Attributes
  133. DUPLICATE_SAME_ATTRIBUTES);
  134. if (!NT_SUCCESS(Status))
  135. {
  136. ERR_OUT("ImpersonateUser: NtDuplicateObject", Status);
  137. return(NULL);
  138. }
  139. ThreadHandleOpened = TRUE;
  140. }
  141. //
  142. // If the usertoken is NULL, there's nothing to do
  143. //
  144. if (hUserToken != NULL)
  145. {
  146. //
  147. // hUserToken is a primary token - create an impersonation token
  148. // version of it so we can set it on our thread
  149. //
  150. InitializeObjectAttributes(&ObjectAttributes,
  151. NULL,
  152. 0L,
  153. NULL,
  154. // UserProcessData->NewThreadTokenSD);
  155. NULL);
  156. SecurityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  157. SecurityQualityOfService.ImpersonationLevel = SecurityImpersonation;
  158. SecurityQualityOfService.ContextTrackingMode =
  159. SECURITY_DYNAMIC_TRACKING;
  160. SecurityQualityOfService.EffectiveOnly = FALSE;
  161. ObjectAttributes.SecurityQualityOfService = &SecurityQualityOfService;
  162. Status = NtDuplicateToken(hUserToken,
  163. TOKEN_IMPERSONATE | TOKEN_READ,
  164. &ObjectAttributes,
  165. FALSE,
  166. TokenImpersonation,
  167. &ImpersonationToken);
  168. if (!NT_SUCCESS(Status))
  169. {
  170. ERR_OUT("ImpersonateUser: NtDuplicateToken", Status);
  171. if (ThreadHandleOpened)
  172. {
  173. NtClose(ThreadHandle);
  174. }
  175. return(NULL);
  176. }
  177. //
  178. // Set the impersonation token on this thread so we 'are' the user
  179. //
  180. Status = NtSetInformationThread(ThreadHandle,
  181. ThreadImpersonationToken,
  182. (PVOID)&ImpersonationToken,
  183. sizeof(ImpersonationToken));
  184. //
  185. // We're finished with our handle to the impersonation token
  186. //
  187. NtClose(ImpersonationToken);
  188. //
  189. // Check we set the token on our thread ok
  190. //
  191. if (!NT_SUCCESS(Status))
  192. {
  193. ERR_OUT("ImpersonateUser: NTSetInformationThread", Status);
  194. if (ThreadHandleOpened)
  195. {
  196. NtClose(ThreadHandle);
  197. }
  198. return(NULL);
  199. }
  200. }
  201. return(ThreadHandle);
  202. }
  203. //+----------------------------------------------------------------------------
  204. //
  205. // Function: GetLoggedOnUser
  206. //
  207. // Synopsis: Called when a user logs in.
  208. //
  209. // Returns: None. Sets the global gUserLogonInfo.
  210. //
  211. // Notes: **** Important ****
  212. //
  213. // Caller must have entered the gcsLogonSessionInfoCritSection
  214. // critical section for the duration of this call and continue
  215. // to remain in this critical section for the lifetime use of
  216. // the returned string.
  217. //
  218. // DO NOT attempt to dealloc the returned string! It is a
  219. // pointer to global memory.
  220. //
  221. //-----------------------------------------------------------------------------
  222. void
  223. GetLoggedOnUser(void)
  224. {
  225. LPWSTR pwszLoggedOnUser;
  226. DWORD cchName = 0;
  227. DWORD dwErr = ERROR_SUCCESS;
  228. if (gUserLogonInfo.DomainUserName != NULL)
  229. {
  230. //
  231. // Already done.
  232. //
  233. return;
  234. }
  235. //
  236. // Impersonate the logged in user.
  237. //
  238. if (ImpersonateLoggedInUser())
  239. {
  240. //
  241. // Get the size of the user name string.
  242. //
  243. if (!GetUserNameEx(NameSamCompatible, NULL, &cchName))
  244. {
  245. dwErr = GetLastError();
  246. if (dwErr != ERROR_MORE_DATA || cchName == 0)
  247. {
  248. StopImpersonating(gUserLogonInfo.ImpersonationThread, TRUE);
  249. ERR_OUT("GetLoggedOnUser: GetUserName", dwErr);
  250. return;
  251. }
  252. }
  253. cchName++; // contrary to docs, cchName excludes the null
  254. //
  255. // Allocate the user name string buffer and get the user name.
  256. //
  257. pwszLoggedOnUser = new WCHAR[cchName * 2];
  258. if (pwszLoggedOnUser != NULL)
  259. {
  260. if (!GetUserNameEx(NameSamCompatible, pwszLoggedOnUser, &cchName))
  261. {
  262. dwErr = GetLastError();
  263. ERR_OUT("GetLoggedOnUser: GetUserName", dwErr);
  264. delete pwszLoggedOnUser;
  265. }
  266. else
  267. {
  268. schDebugOut((DEB_ITRACE, "GetLoggedOnUser: got '%S'\n",
  269. pwszLoggedOnUser));
  270. cchName++; // contrary to docs, cchName excludes the null
  271. //
  272. // This name is in the format "domain\\user".
  273. // Make a copy of the domain name right after it, so
  274. // we end up with a single buffer in the format
  275. // "domain\\user\0domain". Set up pointers into this
  276. // buffer for all 3 parts of the name:
  277. // domain
  278. // user
  279. // domain\user
  280. //
  281. gUserLogonInfo.DomainUserName = pwszLoggedOnUser;
  282. WCHAR *pSlash = wcschr(pwszLoggedOnUser, L'\\');
  283. schAssert(pSlash != NULL);
  284. gUserLogonInfo.UserName = pSlash + 1;
  285. DWORD cchDomain = (DWORD) (pSlash - pwszLoggedOnUser);
  286. gUserLogonInfo.DomainName = pwszLoggedOnUser + cchName;
  287. wcsncpy(gUserLogonInfo.DomainName, pwszLoggedOnUser, cchDomain);
  288. gUserLogonInfo.DomainName[cchDomain] = L'\0';
  289. schDebugOut((DEB_ITRACE, "GetLoggedOnUser: domain '%S', user '%S'\n",
  290. gUserLogonInfo.DomainName, gUserLogonInfo.UserName));
  291. }
  292. }
  293. else
  294. {
  295. ERR_OUT("GetLoggedOnUser", ERROR_OUTOFMEMORY);
  296. }
  297. //
  298. // BUGBUG 254102 - Cache the logged-on user's SID, since
  299. // LookupAccountName doesn't do it when offline.
  300. // Remove this code when bug 254102 is fixed.
  301. //
  302. #define USER_TOKEN_STACK_BUFFER_SIZE \
  303. (sizeof(TOKEN_USER) + sizeof(SID_AND_ATTRIBUTES) + MAX_SID_SIZE)
  304. BYTE rgbTokenInformation[USER_TOKEN_STACK_BUFFER_SIZE];
  305. TOKEN_USER * pTokenUser = (TOKEN_USER *)rgbTokenInformation;
  306. DWORD cbReturnLength;
  307. if (!GetTokenInformation(gUserLogonInfo.ShellToken,
  308. TokenUser,
  309. pTokenUser,
  310. USER_TOKEN_STACK_BUFFER_SIZE,
  311. &cbReturnLength))
  312. {
  313. schAssert(GetLastError() != ERROR_INSUFFICIENT_BUFFER);
  314. CHECK_HRESULT(HRESULT_FROM_WIN32(GetLastError()));
  315. SecureZeroMemory(gUserLogonInfo.Sid, sizeof(gUserLogonInfo.Sid));
  316. }
  317. else if (!CopySid(sizeof(gUserLogonInfo.Sid),
  318. gUserLogonInfo.Sid,
  319. pTokenUser->User.Sid))
  320. {
  321. schAssert(!"CopySid failed");
  322. CHECK_HRESULT(HRESULT_FROM_WIN32(GetLastError()));
  323. SecureZeroMemory(gUserLogonInfo.Sid, sizeof(gUserLogonInfo.Sid));
  324. }
  325. StopImpersonating(gUserLogonInfo.ImpersonationThread, FALSE);
  326. }
  327. }
  328. //+----------------------------------------------------------------------------
  329. //
  330. // Function: StopImpersonating
  331. //
  332. // Synopsis: Stop impersonating.
  333. //
  334. // Notes: This code was taken from winlogon. Specifically:
  335. // windows\gina\winlogon\secutil.c.
  336. //
  337. //-----------------------------------------------------------------------------
  338. BOOL
  339. StopImpersonating(HANDLE ThreadHandle, BOOL fCloseHandle)
  340. {
  341. NTSTATUS Status, IgnoreStatus;
  342. HANDLE ImpersonationToken;
  343. //
  344. // Remove the user's token from our thread so we are 'ourself' again
  345. //
  346. ImpersonationToken = NULL;
  347. Status = NtSetInformationThread(ThreadHandle,
  348. ThreadImpersonationToken,
  349. (PVOID)&ImpersonationToken,
  350. sizeof(ImpersonationToken));
  351. //
  352. // We're finished with the thread handle
  353. //
  354. if (fCloseHandle)
  355. {
  356. IgnoreStatus = NtClose(ThreadHandle);
  357. schAssert(NT_SUCCESS(IgnoreStatus));
  358. }
  359. if (!NT_SUCCESS(Status))
  360. {
  361. schDebugOut((DEB_ERROR,
  362. "Failed to remove user impersonation token from SA service, " \
  363. "status = 0x%lx", Status));
  364. }
  365. return(NT_SUCCESS(Status));
  366. }
  367. #ifdef FIND_USER_WITH_TS
  368. //+----------------------------------------------------------------------------
  369. //
  370. // Function: ImpersonateLoggedInUser
  371. //
  372. // Synopsis: Impersonate the shell user.
  373. //
  374. // Returns: Handle to thread that's impersonating user
  375. //
  376. // Notes: **** Important ****
  377. //
  378. // Caller must have entered the gcsLogonSessionInfoCritSection
  379. // critical section for the duration of this call.
  380. //
  381. // GLOBALS: sets gUserLogonInfo.ShellToken and gUserLogonInfo.ImpersonationThread
  382. //
  383. //-----------------------------------------------------------------------------
  384. HANDLE
  385. ImpersonateLoggedInUser(void)
  386. {
  387. if (gUserLogonInfo.ShellToken)
  388. {
  389. CloseHandle(gUserLogonInfo.ShellToken);
  390. gUserLogonInfo.ShellToken = NULL;
  391. }
  392. DWORD sessionID;
  393. sessionID = WTSGetActiveConsoleSessionId();
  394. if (sessionID == 0xFFFFFFFF)
  395. return NULL;
  396. if (!WTSQueryUserToken(sessionID, &gUserLogonInfo.ShellToken))
  397. return NULL;
  398. if (gUserLogonInfo.ImpersonationThread)
  399. CloseHandle(gUserLogonInfo.ImpersonationThread);
  400. return (gUserLogonInfo.ImpersonationThread = ImpersonateUser(
  401. gUserLogonInfo.ShellToken,
  402. gUserLogonInfo.ImpersonationThread));
  403. }
  404. #else // #ifdef FIND_USER_WITH_TS
  405. HANDLE GetShellProcessHandle(void);
  406. PSYSTEM_PROCESS_INFORMATION GetSystemProcessInfo(void);
  407. PSYSTEM_PROCESS_INFORMATION FindProcessByName(PSYSTEM_PROCESS_INFORMATION,
  408. LPWSTR);
  409. VOID FreeSystemProcessInfo(PSYSTEM_PROCESS_INFORMATION pProcessInfo);
  410. //+----------------------------------------------------------------------------
  411. //
  412. // Function: GetShellProcessHandle
  413. //
  414. // Synopsis: Initialize & return the shell handle of the current logged
  415. // on user, gUserLogonInfo.ShellHandle.
  416. //
  417. // Returns: ERROR_SUCCESS or an error code.
  418. //
  419. // Notes: **** Important ****
  420. //
  421. // Caller must have entered gUserLogonInfo.CriticalSection
  422. // for the duration of this call and continue to remain in
  423. // in it for the lifetime use of the returned handle.
  424. //
  425. // DO NOT close the returned handle. It is a global handle.
  426. //
  427. //-----------------------------------------------------------------------------
  428. HANDLE
  429. GetShellProcessHandle(void)
  430. {
  431. PSYSTEM_PROCESS_INFORMATION pSystemInfo, pProcessInfo;
  432. WCHAR wszShellName[MAX_PATH + 1];
  433. WCHAR * pwszShellName = wszShellName;
  434. WCHAR * pwsz;
  435. HKEY hReg = NULL;
  436. HANDLE hProcess = NULL;
  437. DWORD dwErr = ERROR_SUCCESS;
  438. DWORD dwType;
  439. DWORD dwSize;
  440. //
  441. // Get the shell process name. We will look for this
  442. // to find out who the currently logged-on user is.
  443. //
  444. if (gUserLogonInfo.ShellHandle != NULL)
  445. {
  446. //
  447. // Check if the handle is valid.
  448. //
  449. if (WaitForSingleObject(gUserLogonInfo.ShellHandle,
  450. 0) == WAIT_TIMEOUT)
  451. {
  452. //
  453. // Still valid.
  454. //
  455. return(gUserLogonInfo.ShellHandle);
  456. }
  457. //
  458. // Re-acquire handle.
  459. //
  460. CloseHandle(gUserLogonInfo.ShellHandle);
  461. gUserLogonInfo.ShellHandle = NULL;
  462. }
  463. StringCchCopy(pwszShellName, MAX_PATH + 1, DEFAULT_SHELL);
  464. if ((dwErr = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  465. SHELL_REGKEY,
  466. 0,
  467. KEY_READ,
  468. &hReg)) == ERROR_SUCCESS)
  469. {
  470. dwSize = sizeof(wszShellName);
  471. dwErr = RegQueryValueEx(hReg,
  472. SHELL_REGVAL,
  473. NULL,
  474. &dwType,
  475. (PBYTE)pwszShellName,
  476. &dwSize);
  477. RegCloseKey(hReg);
  478. }
  479. if (dwErr != ERROR_SUCCESS)
  480. {
  481. ERR_OUT("GetShellProcessHandle: RegQueryValueEx", dwErr);
  482. return(NULL);
  483. }
  484. //
  485. // Remove parameters from command line.
  486. //
  487. pwsz = pwszShellName;
  488. while (*pwsz != L' ' && *pwsz != L'\0')
  489. {
  490. pwsz++;
  491. }
  492. *pwsz = L'\0';
  493. //
  494. // Get the process list.
  495. //
  496. pSystemInfo = GetSystemProcessInfo();
  497. if (pSystemInfo == NULL)
  498. {
  499. return(NULL);
  500. }
  501. //
  502. // See if wszShell is running.
  503. //
  504. pProcessInfo = FindProcessByName(pSystemInfo, pwszShellName);
  505. if (pProcessInfo != NULL)
  506. {
  507. //
  508. // Open the process.
  509. //
  510. hProcess = OpenProcess(PROCESS_ALL_ACCESS,
  511. FALSE,
  512. HandleToUlong(pProcessInfo->UniqueProcessId));
  513. #if DBG == 1
  514. if (hProcess == NULL)
  515. {
  516. ERR_OUT("GetShellProcessHandle: OpenProcess", GetLastError());
  517. }
  518. #endif
  519. }
  520. //
  521. // Free resources.
  522. //
  523. FreeSystemProcessInfo(pSystemInfo);
  524. //
  525. // Return process handle.
  526. //
  527. return(gUserLogonInfo.ShellHandle = hProcess);
  528. }
  529. //+----------------------------------------------------------------------------
  530. //
  531. // Function: GetShellProcessToken
  532. //
  533. // Synopsis:
  534. //
  535. // Returns: ERROR_SUCCESS or an error code.
  536. //
  537. // Notes: **** Important ****
  538. //
  539. // Caller must have entered the gcsLogonSessionInfoCritSection
  540. // critical section for the duration of this call and continue
  541. // to remain in this critical section for the lifetime use of
  542. // the returned handle.
  543. //
  544. // DO NOT close the returned handle. It is a global handle.
  545. //
  546. //-----------------------------------------------------------------------------
  547. HANDLE
  548. GetShellProcessToken(void)
  549. {
  550. HANDLE hProcess = GetShellProcessHandle();
  551. if (hProcess == NULL)
  552. {
  553. return(NULL);
  554. }
  555. HANDLE hToken = gUserLogonInfo.ShellToken;
  556. if (gUserLogonInfo.ShellToken == NULL)
  557. {
  558. if (OpenProcessToken(hProcess,
  559. TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY,
  560. &hToken))
  561. {
  562. return(gUserLogonInfo.ShellToken = hToken);
  563. }
  564. else
  565. {
  566. ERR_OUT("GetShellProcessToken: OpenProcessToken", GetLastError());
  567. return(NULL);
  568. }
  569. }
  570. return gUserLogonInfo.ShellToken;
  571. }
  572. //+----------------------------------------------------------------------------
  573. //
  574. // Function: GetSystemProcessInfo
  575. //
  576. // Synopsis: Return a block containing information about all processes
  577. // currently running in the system.
  578. //
  579. // Returns: A pointer to the system process information or NULL if it could
  580. // not be allocated or retrieved.
  581. //
  582. //-----------------------------------------------------------------------------
  583. PSYSTEM_PROCESS_INFORMATION
  584. GetSystemProcessInfo(void)
  585. {
  586. #define SYSTEM_PROCESS_BUFFER_INCREMENT 4096
  587. NTSTATUS Status = 0;
  588. PUCHAR pBuffer;
  589. DWORD cbBufferSize;
  590. //
  591. // Get the process list.
  592. //
  593. cbBufferSize = SYSTEM_PROCESS_BUFFER_INCREMENT;
  594. pBuffer = (PUCHAR)LocalAlloc(LMEM_FIXED, cbBufferSize);
  595. if (pBuffer == NULL)
  596. {
  597. ERR_OUT("GetSystemProcessInfo: LocalAlloc", GetLastError());
  598. return(NULL);
  599. }
  600. for (;;)
  601. {
  602. Status = NtQuerySystemInformation(SystemProcessInformation,
  603. pBuffer,
  604. cbBufferSize,
  605. NULL);
  606. if (Status == STATUS_SUCCESS)
  607. {
  608. break;
  609. }
  610. else if (Status == STATUS_INFO_LENGTH_MISMATCH)
  611. {
  612. cbBufferSize += SYSTEM_PROCESS_BUFFER_INCREMENT;
  613. PUCHAR pTempBuffer = (PUCHAR)LocalReAlloc(pBuffer, cbBufferSize, LMEM_MOVEABLE);
  614. if (pTempBuffer == NULL)
  615. {
  616. LocalFree(pBuffer); // original handle is still valid; use it to free the memory
  617. ERR_OUT("GetSystemProcessInfo: LocalReAlloc", GetLastError());
  618. return(NULL);
  619. }
  620. pBuffer = pTempBuffer; // LocalReAlloc succeeded, so use the new handle now
  621. }
  622. else
  623. {
  624. break;
  625. }
  626. }
  627. if (Status != STATUS_SUCCESS && pBuffer != NULL)
  628. {
  629. LocalFree(pBuffer);
  630. pBuffer = NULL;
  631. }
  632. return (PSYSTEM_PROCESS_INFORMATION)pBuffer;
  633. }
  634. //+----------------------------------------------------------------------------
  635. //
  636. // Function: FindProcessByName
  637. //
  638. // Synopsis: Given a pointer returned by GetSystemProcessInfo(), find
  639. // a process by name.
  640. // Hydra modification: Only processes on the physical console
  641. // session are included.
  642. //
  643. // Arguments: [pProcessInfo] - a pointer returned by GetSystemProcessInfo().
  644. // [lpExeName] - a pointer to a Unicode string containing the
  645. // process to be found.
  646. //
  647. // Returns: A pointer to the process information for the supplied
  648. // process or NULL if it could not be found.
  649. //
  650. //-----------------------------------------------------------------------------
  651. PSYSTEM_PROCESS_INFORMATION
  652. FindProcessByName(PSYSTEM_PROCESS_INFORMATION pProcessInfo, LPWSTR lpExeName)
  653. {
  654. PUCHAR pLargeBuffer = (PUCHAR)pProcessInfo;
  655. ULONG ulTotalOffset = 0;
  656. //
  657. // Look in the process list for lpExeName.
  658. //
  659. for (;;)
  660. {
  661. if (pProcessInfo->ImageName.Buffer != NULL)
  662. {
  663. schDebugOut((DEB_USER3, "FindProcessByName: process: %S (%d)\n",
  664. pProcessInfo->ImageName.Buffer,
  665. pProcessInfo->UniqueProcessId));
  666. if (!_wcsicmp(pProcessInfo->ImageName.Buffer, lpExeName))
  667. {
  668. //
  669. // Pick this process only if it's
  670. // running on the physical console session
  671. //
  672. DWORD dwSessionId;
  673. if (! ProcessIdToSessionId(
  674. HandleToUlong(pProcessInfo->UniqueProcessId),
  675. &dwSessionId))
  676. {
  677. schDebugOut((DEB_ERROR, "ProcessIdToSessionId FAILED, %lu\n",
  678. GetLastError));
  679. }
  680. else if (dwSessionId == 0)
  681. {
  682. return pProcessInfo;
  683. }
  684. }
  685. }
  686. //
  687. // Increment offset to next process information block.
  688. //
  689. if (!pProcessInfo->NextEntryOffset)
  690. {
  691. break;
  692. }
  693. ulTotalOffset += pProcessInfo->NextEntryOffset;
  694. pProcessInfo = (PSYSTEM_PROCESS_INFORMATION)&pLargeBuffer[ulTotalOffset];
  695. }
  696. schDebugOut((DEB_ITRACE, "FindProcessByName: process %ws not found\n", lpExeName));
  697. return NULL;
  698. }
  699. //+----------------------------------------------------------------------------
  700. //
  701. // Function: FreeSystemProcessInfo
  702. //
  703. // Synopsis: Free a buffer returned by GetSystemProcessInfo().
  704. //
  705. // Arguments: [pProcessInfo] - a pointer returned by GetSystemProcessInfo().
  706. //
  707. //-----------------------------------------------------------------------------
  708. VOID
  709. FreeSystemProcessInfo(PSYSTEM_PROCESS_INFORMATION pProcessInfo)
  710. {
  711. LocalFree(pProcessInfo);
  712. }
  713. //+----------------------------------------------------------------------------
  714. //
  715. // Function: ImpersonateLoggedInUser
  716. //
  717. // Synopsis: Impersonate the shell user.
  718. //
  719. // Returns:
  720. //
  721. // Notes: **** Important ****
  722. //
  723. // Caller must have entered the gcsLogonSessionInfoCritSection
  724. // critical section for the duration of this call.
  725. //
  726. //-----------------------------------------------------------------------------
  727. HANDLE
  728. ImpersonateLoggedInUser(void)
  729. {
  730. BOOL fDuplicateToken;
  731. //
  732. // Open the impersonation token for the
  733. // process we want to impersonate.
  734. //
  735. if (gUserLogonInfo.ImpersonationThread == NULL)
  736. {
  737. if (gUserLogonInfo.ShellHandle == NULL)
  738. {
  739. if (GetShellProcessHandle() == NULL)
  740. {
  741. return(NULL);
  742. }
  743. }
  744. if (gUserLogonInfo.ShellToken == NULL)
  745. {
  746. if (GetShellProcessToken() == NULL)
  747. {
  748. return(NULL);
  749. }
  750. }
  751. }
  752. return(gUserLogonInfo.ImpersonationThread = ImpersonateUser(
  753. gUserLogonInfo.ShellToken,
  754. gUserLogonInfo.ImpersonationThread));
  755. }
  756. #endif // FIND_USER_WITH_TS