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.

480 lines
9.9 KiB

  1. /*++
  2. Copyright(c) 1995 Microsoft Corporation
  3. MODULE NAME
  4. impersn.c
  5. ABSTRACT
  6. Impersonation routines for the automatic connection service.
  7. AUTHOR
  8. Anthony Discolo (adiscolo) 04-Aug-1995
  9. REVISION HISTORY
  10. mquinton 8/2/96 - stole this code to use in remotesp
  11. --*/
  12. #define UNICODE
  13. #include <nt.h>
  14. #include <ntrtl.h>
  15. #include <nturtl.h>
  16. //#include <stdlib.h>
  17. #include <windows.h>
  18. #include <stdio.h>
  19. //#include <npapi.h>
  20. #include "utils.h"
  21. #include "imperson.h"
  22. // some constant stuff for registry
  23. #define SHELL_REGKEY L"\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"
  24. #define SHELL_REGVAL L"shell"
  25. #define DEFAULT_SHELL L"explorer.exe"
  26. // for remotesp dbgout
  27. #if DBG
  28. #define DBGOUT(arg) DbgPrt arg
  29. VOID
  30. DbgPrt(
  31. IN DWORD dwDbgLevel,
  32. IN PUCHAR DbgMessage,
  33. IN ...
  34. );
  35. #else
  36. #define DBGOUT(arg)
  37. #endif
  38. //
  39. // The static information we
  40. // need to impersonate the currently
  41. // logged-in user.
  42. //
  43. HANDLE ghTokenImpersonation = NULL;
  44. //
  45. // Security attributes and descriptor
  46. // necessary for creating shareable handles.
  47. //
  48. SECURITY_ATTRIBUTES SecurityAttributeG;
  49. SECURITY_DESCRIPTOR SecurityDescriptorG;
  50. PSYSTEM_PROCESS_INFORMATION
  51. GetSystemProcessInfo()
  52. /*++
  53. DESCRIPTION
  54. Return a block containing information about all processes
  55. currently running in the system.
  56. ARGUMENTS
  57. None.
  58. RETURN VALUE
  59. A pointer to the system process information or NULL if it could
  60. not be allocated or retrieved.
  61. --*/
  62. {
  63. NTSTATUS status;
  64. PUCHAR pLargeBuffer;
  65. ULONG ulcbLargeBuffer = 64 * 1024;
  66. //
  67. // Get the process list.
  68. //
  69. for (;;) {
  70. pLargeBuffer = VirtualAlloc(
  71. NULL,
  72. ulcbLargeBuffer, MEM_COMMIT, PAGE_READWRITE);
  73. if (pLargeBuffer == NULL) {
  74. LOG((TL_ERROR,
  75. "GetSystemProcessInfo: VirtualAlloc failed (status=0x%x)",
  76. status));
  77. return NULL;
  78. }
  79. status = NtQuerySystemInformation(
  80. SystemProcessInformation,
  81. pLargeBuffer,
  82. ulcbLargeBuffer,
  83. NULL);
  84. if (status == STATUS_SUCCESS) break;
  85. if (status == STATUS_INFO_LENGTH_MISMATCH) {
  86. VirtualFree(pLargeBuffer, 0, MEM_RELEASE);
  87. ulcbLargeBuffer += 8192;
  88. LOG((TL_INFO,
  89. "GetSystemProcesInfo: enlarging buffer to %d",
  90. ulcbLargeBuffer));
  91. }
  92. }
  93. return (PSYSTEM_PROCESS_INFORMATION)pLargeBuffer;
  94. } // GetSystemProcessInfo
  95. PSYSTEM_PROCESS_INFORMATION
  96. FindProcessByName(
  97. IN PSYSTEM_PROCESS_INFORMATION pProcessInfo,
  98. IN LPTSTR lpExeName
  99. )
  100. /*++
  101. DESCRIPTION
  102. Given a pointer returned by GetSystemProcessInfo(), find
  103. a process by name.
  104. ARGUMENTS
  105. pProcessInfo: a pointer returned by GetSystemProcessInfo().
  106. lpExeName: a pointer to a Unicode string containing the
  107. process to be found.
  108. RETURN VALUE
  109. A pointer to the process information for the supplied
  110. process or NULL if it could not be found.
  111. --*/
  112. {
  113. PUCHAR pLargeBuffer = (PUCHAR)pProcessInfo;
  114. ULONG ulTotalOffset = 0;
  115. //
  116. // Look in the process list for lpExeName.
  117. //
  118. for (;;)
  119. {
  120. if (pProcessInfo->ImageName.Buffer != NULL) {
  121. //DBGOUT((
  122. // 3,
  123. // "FindProcessByName: process: %S (%d)",
  124. // pProcessInfo->ImageName.Buffer,
  125. // pProcessInfo->UniqueProcessId
  126. // ));
  127. if (!_wcsicmp(pProcessInfo->ImageName.Buffer, lpExeName))
  128. {
  129. return pProcessInfo;
  130. }
  131. }
  132. //
  133. // Increment offset to next process information block.
  134. //
  135. if (!pProcessInfo->NextEntryOffset)
  136. {
  137. break;
  138. }
  139. ulTotalOffset += pProcessInfo->NextEntryOffset;
  140. pProcessInfo = (PSYSTEM_PROCESS_INFORMATION)&pLargeBuffer[ulTotalOffset];
  141. }
  142. return NULL;
  143. } // FindProcessByName
  144. VOID
  145. FreeSystemProcessInfo(
  146. IN PSYSTEM_PROCESS_INFORMATION pProcessInfo
  147. )
  148. /*++
  149. DESCRIPTION
  150. Free a buffer returned by GetSystemProcessInfo().
  151. ARGUMENTS
  152. pProcessInfo: the pointer returned by GetSystemProcessInfo().
  153. RETURN VALUE
  154. None.
  155. --*/
  156. {
  157. VirtualFree((PUCHAR)pProcessInfo, 0, MEM_RELEASE);
  158. } // FreeSystemProcessInfo
  159. BOOLEAN
  160. SetProcessImpersonationToken(
  161. HANDLE hProcess
  162. )
  163. {
  164. NTSTATUS status;
  165. BOOL fDuplicated = FALSE;
  166. HANDLE hThread, hToken;
  167. static lCookie = 0;
  168. //
  169. // Open the impersonation token for the
  170. // process we want to impersonate.
  171. //
  172. // Note: we use InterlockedExchange as an inexpensive mutex
  173. //
  174. while (InterlockedExchange (&lCookie, 1) != 0)
  175. {
  176. Sleep (50);
  177. }
  178. if (ghTokenImpersonation == NULL)
  179. {
  180. if (!OpenProcessToken(
  181. hProcess,
  182. TOKEN_ALL_ACCESS,
  183. &hToken))
  184. {
  185. InterlockedExchange (&lCookie, 0);
  186. LOG((
  187. TL_ERROR,
  188. "SetProcessImpersonationToken: OpenProcessToken " \
  189. "failed, err=%d",
  190. GetLastError()
  191. ));
  192. return FALSE;
  193. }
  194. //
  195. // Duplicate the impersonation token.
  196. //
  197. fDuplicated = DuplicateToken(
  198. hToken,
  199. TokenImpersonation,
  200. &ghTokenImpersonation);
  201. if (!fDuplicated)
  202. {
  203. InterlockedExchange (&lCookie, 0);
  204. LOG((
  205. TL_ERROR,
  206. "SetProcessImpersonationToken: NtSetInformationThread " \
  207. "failed, err=%d",
  208. GetLastError()
  209. ));
  210. return FALSE;
  211. }
  212. }
  213. InterlockedExchange (&lCookie, 0);
  214. //
  215. // Set the impersonation token on the current
  216. // thread. We are now running in the same
  217. // security context as the supplied process.
  218. //
  219. hThread = NtCurrentThread();
  220. status = NtSetInformationThread(
  221. hThread,
  222. ThreadImpersonationToken,
  223. (PVOID)&ghTokenImpersonation,
  224. sizeof (ghTokenImpersonation));
  225. if (status != STATUS_SUCCESS)
  226. {
  227. LOG((TL_ERROR,
  228. "SetProcessImpersonationToken: NtSetInformationThread failed (error=%d)",
  229. GetLastError()));
  230. }
  231. if (fDuplicated)
  232. {
  233. CloseHandle(hToken);
  234. CloseHandle(hThread);
  235. }
  236. return (status == STATUS_SUCCESS);
  237. } // SetProcessImpersonationToken
  238. VOID
  239. ClearImpersonationToken()
  240. {
  241. //
  242. // Clear the impersonation token on the current
  243. // thread. We are now running in LocalSystem
  244. // security context.
  245. //
  246. if (!SetThreadToken(NULL, NULL))
  247. {
  248. LOG((TL_ERROR,
  249. "ClearImpersonationToken: SetThreadToken failed (error=%d)",
  250. GetLastError()));
  251. }
  252. } // ClearImpersonationToken
  253. BOOLEAN
  254. GetCurrentlyLoggedOnUser(
  255. HANDLE *phProcess
  256. )
  257. {
  258. BOOLEAN fSuccess = FALSE;
  259. HKEY hkey;
  260. DWORD dwType;
  261. DWORD dwDisp;
  262. WCHAR szShell[512];
  263. PSYSTEM_PROCESS_INFORMATION pSystemInfo, pProcessInfo;
  264. PWCHAR psz;
  265. DWORD dwSize = sizeof (szShell);
  266. NTSTATUS status;
  267. HANDLE hProcess = NULL;
  268. //
  269. // Get the shell process name. We will look for this
  270. // to find out who the currently logged-on user is.
  271. // Create a unicode string that describes this name.
  272. //
  273. wcscpy (szShell, DEFAULT_SHELL);
  274. if (RegCreateKeyEx(
  275. HKEY_LOCAL_MACHINE,
  276. SHELL_REGKEY,
  277. 0,
  278. NULL,
  279. REG_OPTION_NON_VOLATILE,
  280. KEY_ALL_ACCESS,
  281. NULL,
  282. &hkey,
  283. &dwDisp) == ERROR_SUCCESS)
  284. {
  285. if (RegQueryValueEx(
  286. hkey,
  287. SHELL_REGVAL,
  288. NULL,
  289. &dwType,
  290. (PBYTE)&szShell,
  291. &dwSize) == ERROR_SUCCESS)
  292. {
  293. //
  294. // Remove parameters from command line.
  295. //
  296. psz = szShell;
  297. while (*psz != L' ' && *psz != L'\0')
  298. psz++;
  299. *psz = L'\0';
  300. }
  301. RegCloseKey(hkey);
  302. }
  303. LOG((TL_INFO,
  304. "ImpersonateCurrentlyLoggedInUser: shell is %S",
  305. &szShell));
  306. //
  307. // Get the process list.
  308. //
  309. pSystemInfo = GetSystemProcessInfo();
  310. //
  311. // See if szShell is running.
  312. //
  313. pProcessInfo = pSystemInfo ?
  314. FindProcessByName(pSystemInfo, (LPTSTR)&szShell) : NULL;
  315. if (pProcessInfo != NULL)
  316. {
  317. HANDLE hToken;
  318. //
  319. // Open the process.
  320. //
  321. hProcess = OpenProcess(
  322. PROCESS_ALL_ACCESS,
  323. FALSE,
  324. (DWORD) ((ULONG_PTR) pProcessInfo->UniqueProcessId)
  325. );
  326. if (hProcess == NULL)
  327. {
  328. LOG((TL_ERROR,
  329. "ImpersonateCurrentlyLoggedInUser: OpenProcess(x%x) failed (dwErr=%d)",
  330. pProcessInfo->UniqueProcessId,
  331. GetLastError()));
  332. }
  333. fSuccess = (hProcess != NULL);
  334. }
  335. //
  336. // Free resources.
  337. //
  338. if (pSystemInfo)
  339. {
  340. FreeSystemProcessInfo(pSystemInfo);
  341. }
  342. //
  343. // Return process handle.
  344. //
  345. *phProcess = hProcess;
  346. return fSuccess;
  347. } // GetCurrentlyLoggedOnUser
  348. VOID
  349. RevertImpersonation()
  350. /*++
  351. DESCRIPTION
  352. Close all open handles associated with the
  353. logged-in user who has just logged out.
  354. ARGUMENTS
  355. None.
  356. RETURN VALUE
  357. None.
  358. --*/
  359. {
  360. CloseHandle (ghTokenImpersonation);
  361. ghTokenImpersonation = NULL;
  362. } // RevertImpersonation
  363.