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.

575 lines
15 KiB

  1. /****************************************************************************
  2. PROGRAM: TOKEN.C
  3. PURPOSE: Contains routines that manipulate tokens
  4. ****************************************************************************/
  5. #include "SECEDIT.h"
  6. HANDLE AllocMyToken(VOID);
  7. BOOL ReadMyToken(HANDLE);
  8. BOOL WriteMyToken(HWND, HANDLE);
  9. BOOL FreeMyToken(HANDLE);
  10. HANDLE OpenToken(HANDLE, ACCESS_MASK);
  11. BOOL CloseToken(HANDLE);
  12. PVOID AllocTokenInfo(HANDLE, TOKEN_INFORMATION_CLASS);
  13. BOOL GetTokenInfo(HANDLE, TOKEN_INFORMATION_CLASS, PPVOID);
  14. BOOL SetTokenInfo(HANDLE, TOKEN_INFORMATION_CLASS, PVOID);
  15. BOOL FreeTokenInfo(PVOID);
  16. /****************************************************************************
  17. FUNCTION: OpenMyToken
  18. PURPOSE: Opens the token of the process of the specified window.
  19. RETURNS : Handle to mytoken on success, or NULL on failure.
  20. ****************************************************************************/
  21. HANDLE OpenMyToken(
  22. HWND hwnd)
  23. {
  24. DWORD ThreadId;
  25. DWORD ProcessId;
  26. PMYTOKEN pMyToken;
  27. HANDLE hMyToken;
  28. ThreadId = GetWindowThreadProcessId(hwnd, &ProcessId);
  29. DbgPrint("Process Id = %ld, ThreadId = %ld\n", ProcessId, ThreadId);
  30. if (ThreadId == 0) {
  31. DbgPrint("SECEDIT: GetWindowThreadProcessId failed\n");
  32. return(NULL);
  33. }
  34. //
  35. // Build a MYTOKEN structure.
  36. hMyToken = AllocMyToken();
  37. if (hMyToken == NULL) {
  38. return(NULL);
  39. }
  40. pMyToken = (PMYTOKEN)hMyToken;
  41. pMyToken->ProcessId = ProcessId;
  42. pMyToken->ThreadId = ThreadId;
  43. if (!ReadMyToken(hMyToken)) {
  44. DbgPrint("SECEDIT : Failed to read token info\n");
  45. Free(pMyToken);
  46. return(NULL);
  47. }
  48. return(hMyToken);
  49. }
  50. /****************************************************************************
  51. FUNCTION: ReadMyToken
  52. PURPOSE: Reads the token info and stores in mytoken structure
  53. RETURNS : TRUE on success, FALSE on failure
  54. ****************************************************************************/
  55. BOOL ReadMyToken(
  56. HANDLE hMyToken)
  57. {
  58. HANDLE Token;
  59. PMYTOKEN pMyToken = (PMYTOKEN)hMyToken;
  60. Token = OpenToken(hMyToken, TOKEN_QUERY);
  61. if (Token == NULL) {
  62. DbgPrint("SECEDIT : Failed to open the token with TOKEN_QUERY access\n");
  63. return(FALSE);
  64. }
  65. if (!GetTokenInfo(Token, TokenStatistics, (PPVOID)&(pMyToken->TokenStats))) {
  66. DbgPrint("SECEDIT : Failed to read token statistics from token\n");
  67. }
  68. if (!GetTokenInfo(Token, TokenGroups, (PPVOID)&(pMyToken->Groups))) {
  69. DbgPrint("SECEDIT : Failed to read group info from token\n");
  70. }
  71. if (!GetTokenInfo(Token, TokenUser, (PPVOID)&(pMyToken->UserId))) {
  72. DbgPrint("SECEDIT : Failed to read userid from token\n");
  73. }
  74. if (!GetTokenInfo(Token, TokenOwner, (PPVOID)&(pMyToken->DefaultOwner))) {
  75. DbgPrint("SECEDIT : Failed to read default owner from token\n");
  76. }
  77. if (!GetTokenInfo(Token, TokenPrimaryGroup, (PPVOID)&(pMyToken->PrimaryGroup))) {
  78. DbgPrint("SECEDIT : Failed to read primary group from token\n");
  79. }
  80. if (!GetTokenInfo(Token, TokenPrivileges, (PPVOID)&(pMyToken->Privileges))) {
  81. DbgPrint("SECEDIT : Failed to read privilege info from token\n");
  82. }
  83. CloseToken(Token);
  84. return(TRUE);
  85. }
  86. /****************************************************************************
  87. FUNCTION: CloseMyToken
  88. PURPOSE: Closes the specified mytoken handle
  89. If fSaveChanges = TRUE, the token information is saved,
  90. otherwise it is discarded.
  91. RETURNS : TRUE on success, FALSE on failure.
  92. ****************************************************************************/
  93. BOOL CloseMyToken(
  94. HWND hDlg,
  95. HANDLE hMyToken,
  96. BOOL fSaveChanges)
  97. {
  98. if (fSaveChanges) {
  99. WriteMyToken(hDlg, hMyToken);
  100. }
  101. return FreeMyToken(hMyToken);
  102. }
  103. /****************************************************************************
  104. FUNCTION: AllocMyToken
  105. PURPOSE: Allocates space for mytoken structure.
  106. RETURNS : HANDLE to mytoken or NULL on failure.
  107. ****************************************************************************/
  108. HANDLE AllocMyToken(VOID)
  109. {
  110. PMYTOKEN pMyToken;
  111. pMyToken = (PMYTOKEN)Alloc(sizeof(MYTOKEN));
  112. return((HANDLE)pMyToken);
  113. }
  114. /****************************************************************************
  115. FUNCTION: FreeMyToken
  116. PURPOSE: Frees the memory allocated to mytoken structure.
  117. RETURNS : TRUE on success, FALSE on failure.
  118. ****************************************************************************/
  119. BOOL FreeMyToken(
  120. HANDLE hMyToken)
  121. {
  122. PMYTOKEN pMyToken = (PMYTOKEN)hMyToken;
  123. if (pMyToken->TokenStats != NULL) {
  124. FreeTokenInfo((PVOID)(pMyToken->TokenStats));
  125. }
  126. if (pMyToken->UserId != NULL) {
  127. FreeTokenInfo((PVOID)(pMyToken->UserId));
  128. }
  129. if (pMyToken->PrimaryGroup != NULL) {
  130. FreeTokenInfo((PVOID)(pMyToken->PrimaryGroup));
  131. }
  132. if (pMyToken->DefaultOwner != NULL) {
  133. FreeTokenInfo((PVOID)(pMyToken->DefaultOwner));
  134. }
  135. if (pMyToken->Groups != NULL) {
  136. FreeTokenInfo((PVOID)(pMyToken->Groups));
  137. }
  138. if (pMyToken->Privileges != NULL) {
  139. FreeTokenInfo((PVOID)(pMyToken->Privileges));
  140. }
  141. Free((PVOID)pMyToken);
  142. return(TRUE);
  143. }
  144. /****************************************************************************
  145. FUNCTION: WriteMyToken
  146. PURPOSE: Writes the token information out to the token
  147. RETURNS : TRUE on success, FALSE on failure.
  148. ****************************************************************************/
  149. BOOL WriteMyToken(
  150. HWND hDlg,
  151. HANDLE hMyToken)
  152. {
  153. PMYTOKEN pMyToken = (PMYTOKEN)hMyToken;
  154. HANDLE Token;
  155. //
  156. // Save default owner and primary group
  157. //
  158. Token = OpenToken(hMyToken, TOKEN_ADJUST_DEFAULT);
  159. if (Token == NULL) {
  160. DbgPrint("SECEDIT: Failed to open token with TOKEN_ADJUST_DEFAULT access\n");
  161. MessageBox(hDlg, "Failed to open token with access required\nUnable to change default owner or primary group", NULL, MB_ICONSTOP | MB_APPLMODAL | MB_OK);
  162. } else {
  163. // Set default owner
  164. //
  165. if ((pMyToken->DefaultOwner != NULL) &&
  166. (!SetTokenInfo(Token, TokenOwner, (PVOID)(pMyToken->DefaultOwner)))) {
  167. MessageBox(hDlg, "Failed to set default owner", NULL, MB_ICONSTOP | MB_APPLMODAL | MB_OK);
  168. }
  169. // Set primary group
  170. //
  171. if ((pMyToken->PrimaryGroup != NULL) &&
  172. (!SetTokenInfo(Token, TokenPrimaryGroup, (PVOID)(pMyToken->PrimaryGroup)))) {
  173. MessageBox(hDlg, "Failed to set primary group", NULL, MB_ICONSTOP | MB_APPLMODAL | MB_OK);
  174. }
  175. CloseToken(Token);
  176. }
  177. //
  178. // Save group info
  179. //
  180. Token = OpenToken(hMyToken, TOKEN_ADJUST_GROUPS);
  181. if (Token == NULL) {
  182. DbgPrint("SECEDIT: Failed to open token with TOKEN_ADJUST_GROUPS access\n");
  183. MessageBox(hDlg, "Failed to open token with access required\nUnable to change group settings", NULL, MB_ICONSTOP | MB_APPLMODAL | MB_OK);
  184. } else {
  185. if ((pMyToken->Groups != NULL) &&
  186. (!SetTokenInfo(Token, TokenGroups, (PVOID)(pMyToken->Groups)))) {
  187. MessageBox(hDlg, "Failed to change group settings", NULL, MB_ICONSTOP | MB_APPLMODAL | MB_OK);
  188. }
  189. CloseToken(Token);
  190. }
  191. //
  192. // Change privileges
  193. //
  194. Token = OpenToken(hMyToken, TOKEN_ADJUST_PRIVILEGES);
  195. if (Token == NULL) {
  196. DbgPrint("SECEDIT: Failed to open token with TOKEN_ADJUST_PRIVILEGES access\n");
  197. MessageBox(hDlg, "Failed to open token with access required\nUnable to change privilege settings", NULL, MB_ICONSTOP | MB_APPLMODAL | MB_OK);
  198. } else {
  199. if ((pMyToken->Privileges != NULL) &&
  200. (!SetTokenInfo(Token, TokenPrivileges, (PVOID)(pMyToken->Privileges)))) {
  201. MessageBox(hDlg, "Failed to change privilege settings", NULL, MB_ICONSTOP | MB_APPLMODAL | MB_OK);
  202. }
  203. CloseToken(Token);
  204. }
  205. return(TRUE);
  206. }
  207. /****************************************************************************
  208. FUNCTION: OpenToken
  209. PURPOSE: Opens the token with the specified access
  210. RETURNS : Handle to token on success, or NULL on failure.
  211. ****************************************************************************/
  212. HANDLE OpenToken(
  213. HANDLE hMyToken,
  214. ACCESS_MASK DesiredAccess)
  215. {
  216. NTSTATUS Status;
  217. HANDLE Token;
  218. HANDLE Process;
  219. PMYTOKEN pMyToken = (PMYTOKEN)hMyToken;
  220. DWORD ThreadId = pMyToken->ThreadId;
  221. DWORD ProcessId = pMyToken->ProcessId;
  222. Process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, ProcessId);
  223. if (Process == NULL) {
  224. DbgPrint("SECEDIT: OpenProcess failed, last error = %ld\n", GetLastError());
  225. return(NULL);
  226. }
  227. Status = NtOpenProcessToken(
  228. Process,
  229. DesiredAccess,
  230. &Token
  231. );
  232. CloseHandle(Process);
  233. if (!NT_SUCCESS(Status)) {
  234. DbgPrint("SECEDIT: Failed to open token with access = 0x%x, status = 0x%lx\n", DesiredAccess, Status);
  235. return(NULL);
  236. }
  237. return(Token);
  238. }
  239. /****************************************************************************
  240. FUNCTION: CloseToken
  241. PURPOSE: Closes the specified token handle
  242. RETURNS : TRUE on success, FALSE on failure.
  243. ****************************************************************************/
  244. BOOL CloseToken(
  245. HANDLE Token)
  246. {
  247. NTSTATUS Status;
  248. Status = NtClose(Token);
  249. return(TRUE);
  250. }
  251. /****************************************************************************
  252. FUNCTION: AllocTokenInfo
  253. PURPOSE: Allocates memory to hold the parameter that
  254. NTQueryInformationToken will return.
  255. Memory should be freed later using FreeTokenInfo
  256. RETURNS : Pointer to allocated memory or NULL on failure
  257. ****************************************************************************/
  258. PVOID AllocTokenInfo(
  259. HANDLE Token,
  260. TOKEN_INFORMATION_CLASS TokenInformationClass)
  261. {
  262. NTSTATUS Status;
  263. ULONG InfoLength;
  264. Status = NtQueryInformationToken(
  265. Token, // Handle
  266. TokenInformationClass, // TokenInformationClass
  267. NULL, // TokenInformation
  268. 0, // TokenInformationLength
  269. &InfoLength // ReturnLength
  270. );
  271. if (Status != STATUS_BUFFER_TOO_SMALL) {
  272. #ifdef NTBUILD
  273. DbgPrint("SECEDIT: NtQueryInformationToken did NOT return buffer_too_small, status = 0x%lx\n", Status);
  274. #endif
  275. return(NULL);
  276. }
  277. return Alloc(InfoLength);
  278. }
  279. /****************************************************************************
  280. FUNCTION: FreeTokenInfo
  281. PURPOSE: Frees the memory previously allocated with AllocTokenInfo
  282. RETURNS : TRUE on success, otherwise FALSE
  283. ****************************************************************************/
  284. BOOL FreeTokenInfo(
  285. PVOID Buffer)
  286. {
  287. return(Free(Buffer));
  288. }
  289. /****************************************************************************
  290. FUNCTION: GetTokenInfo
  291. PURPOSE: Allocates a buffer and reads the specified data
  292. out of the token and into it.
  293. RETURNS : TRUE on success otherwise FALSE.
  294. ****************************************************************************/
  295. BOOL GetTokenInfo(
  296. HANDLE Token,
  297. TOKEN_INFORMATION_CLASS TokenInformationClass,
  298. PPVOID pBuffer)
  299. {
  300. NTSTATUS Status;
  301. ULONG BufferSize;
  302. ULONG InfoLength;
  303. PVOID Buffer;
  304. *pBuffer = NULL; // Prepare for failure
  305. Buffer = AllocTokenInfo(Token, TokenInformationClass);
  306. if (Buffer == NULL) {
  307. return(FALSE);
  308. }
  309. BufferSize = (ULONG)GetAllocSize(Buffer);
  310. Status = NtQueryInformationToken(
  311. Token, // Handle
  312. TokenInformationClass, // TokenInformationClass
  313. Buffer, // TokenInformation
  314. BufferSize, // TokenInformationLength
  315. &InfoLength // ReturnLength
  316. );
  317. if (!NT_SUCCESS(Status)) {
  318. #ifdef NTBUILD
  319. DbgPrint("SECEDIT: NtQueryInformationToken failed, status = 0x%lx\n", Status);
  320. #endif
  321. FreeTokenInfo(Buffer);
  322. return(FALSE);
  323. }
  324. if (InfoLength > BufferSize) {
  325. #ifdef NTBUILD
  326. DbgPrint("SECEDIT: NtQueryInformationToken failed, DataSize > BufferSize");
  327. #endif
  328. FreeTokenInfo(Buffer);
  329. return(FALSE);
  330. }
  331. *pBuffer = Buffer;
  332. return(TRUE);
  333. }
  334. /****************************************************************************
  335. FUNCTION: SetTokenInfo
  336. PURPOSE: Sets the specified information in the given token.
  337. RETURNS : TRUE on success otherwise FALSE.
  338. ****************************************************************************/
  339. BOOL SetTokenInfo(
  340. HANDLE Token,
  341. TOKEN_INFORMATION_CLASS TokenInformationClass,
  342. PVOID Buffer)
  343. {
  344. NTSTATUS Status;
  345. ULONG BufferSize;
  346. BufferSize = (ULONG)GetAllocSize(Buffer);
  347. switch (TokenInformationClass) {
  348. case TokenOwner:
  349. case TokenPrimaryGroup:
  350. case TokenDefaultDacl:
  351. Status = NtSetInformationToken(
  352. Token, // Handle
  353. TokenInformationClass, // TokenInformationClass
  354. Buffer, // TokenInformation
  355. BufferSize // TokenInformationLength
  356. );
  357. if (!NT_SUCCESS(Status)) {
  358. DbgPrint("SECEDIT: NtSetInformationToken failed, info class = 0x%x, status = 0x%lx\n",
  359. TokenInformationClass, Status);
  360. return(FALSE);
  361. }
  362. break;
  363. case TokenGroups:
  364. Status = NtAdjustGroupsToken(
  365. Token, // Handle
  366. FALSE, // Reset to default
  367. (PTOKEN_GROUPS)Buffer, // New State
  368. BufferSize, // Buffer Length
  369. NULL, // Previous State
  370. NULL // Return Length
  371. );
  372. if (!NT_SUCCESS(Status)) {
  373. DbgPrint("SECEDIT: NtAdjustGroupsToken failed, status = 0x%lx\n", Status);
  374. return(FALSE);
  375. }
  376. break;
  377. case TokenPrivileges:
  378. Status = NtAdjustPrivilegesToken(
  379. Token, // Handle
  380. FALSE, // Disable all privileges
  381. (PTOKEN_PRIVILEGES)Buffer, // New State
  382. BufferSize, // Buffer Length
  383. NULL, // Previous State
  384. NULL // Return Length
  385. );
  386. if (!NT_SUCCESS(Status)) {
  387. DbgPrint("SECEDIT: NtAdjustPrivilegesToken failed, status = 0x%lx\n", Status);
  388. return(FALSE);
  389. }
  390. break;
  391. default:
  392. // Unrecognised information type
  393. DbgPrint("SECEDIT: SetTokenInfo passed unrecognised infoclass, class = 0x%x\n", TokenInformationClass);
  394. return(FALSE);
  395. }
  396. return(TRUE);
  397. }