Process Hacker
tokprp.c
Go to the documentation of this file.
1 /*
2  * Process Hacker -
3  * token properties
4  *
5  * Copyright (C) 2010-2012 wj32
6  *
7  * This file is part of Process Hacker.
8  *
9  * Process Hacker is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * Process Hacker is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 #include <phapp.h>
24 #include <secedit.h>
25 #include <emenu.h>
26 #include <cpysave.h>
27 
28 typedef struct _ATTRIBUTE_NODE
29 {
30  PH_TREENEW_NODE Node;
31  PPH_LIST Children;
32  PPH_STRING Text;
34 
35 typedef struct _ATTRIBUTE_TREE_CONTEXT
36 {
37  PPH_LIST RootList;
38  PPH_LIST NodeList;
40 
41 typedef struct _TOKEN_PAGE_CONTEXT
42 {
43  PPH_OPEN_OBJECT OpenObject;
44  PVOID Context;
45  DLGPROC HookProc;
46 
47  HWND GroupsListViewHandle;
48  HWND PrivilegesListViewHandle;
49 
50  PTOKEN_GROUPS Groups;
51  PTOKEN_PRIVILEGES Privileges;
52  PTOKEN_GROUPS Capabilities;
53 
54  ATTRIBUTE_TREE_CONTEXT ClaimsTreeContext;
55  ATTRIBUTE_TREE_CONTEXT AuthzTreeContext;
57 
58 INT CALLBACK PhpTokenPropPageProc(
59  _In_ HWND hwnd,
60  _In_ UINT uMsg,
61  _In_ LPPROPSHEETPAGE ppsp
62  );
63 
64 INT_PTR CALLBACK PhpTokenPageProc(
65  _In_ HWND hwndDlg,
66  _In_ UINT uMsg,
67  _In_ WPARAM wParam,
68  _In_ LPARAM lParam
69  );
70 
72  _In_ HWND ParentWindowHandle,
73  _In_ PTOKEN_PAGE_CONTEXT Context
74  );
75 
76 INT_PTR CALLBACK PhpTokenGeneralPageProc(
77  _In_ HWND hwndDlg,
78  _In_ UINT uMsg,
79  _In_ WPARAM wParam,
80  _In_ LPARAM lParam
81  );
82 
83 INT_PTR CALLBACK PhpTokenAdvancedPageProc(
84  _In_ HWND hwndDlg,
85  _In_ UINT uMsg,
86  _In_ WPARAM wParam,
87  _In_ LPARAM lParam
88  );
89 
90 INT_PTR CALLBACK PhpTokenCapabilitiesPageProc(
91  _In_ HWND hwndDlg,
92  _In_ UINT uMsg,
93  _In_ WPARAM wParam,
94  _In_ LPARAM lParam
95  );
96 
97 BOOLEAN NTAPI PhpAttributeTreeNewCallback(
98  _In_ HWND hwnd,
99  _In_ PH_TREENEW_MESSAGE Message,
100  _In_opt_ PVOID Parameter1,
101  _In_opt_ PVOID Parameter2,
102  _In_opt_ PVOID Context
103  );
104 
105 INT_PTR CALLBACK PhpTokenClaimsPageProc(
106  _In_ HWND hwndDlg,
107  _In_ UINT uMsg,
108  _In_ WPARAM wParam,
109  _In_ LPARAM lParam
110  );
111 
112 INT_PTR CALLBACK PhpTokenAttributesPageProc(
113  _In_ HWND hwndDlg,
114  _In_ UINT uMsg,
115  _In_ WPARAM wParam,
116  _In_ LPARAM lParam
117  );
118 
120  _In_ HWND ParentWindowHandle,
121  _In_ PPH_OPEN_OBJECT OpenObject,
122  _In_opt_ PVOID Context,
123  _In_opt_ PWSTR Title
124  )
125 {
126  PROPSHEETHEADER propSheetHeader = { sizeof(propSheetHeader) };
127  HPROPSHEETPAGE pages[1];
128 
129  propSheetHeader.dwFlags =
130  PSH_NOAPPLYNOW |
131  PSH_NOCONTEXTHELP |
132  PSH_PROPTITLE;
133  propSheetHeader.hwndParent = ParentWindowHandle;
134  propSheetHeader.pszCaption = Title ? Title : L"Token";
135  propSheetHeader.nPages = 1;
136  propSheetHeader.nStartPage = 0;
137  propSheetHeader.phpage = pages;
138 
139  pages[0] = PhCreateTokenPage(OpenObject, Context, NULL);
140 
141  PropertySheet(&propSheetHeader);
142 }
143 
144 HPROPSHEETPAGE PhCreateTokenPage(
145  _In_ PPH_OPEN_OBJECT OpenObject,
146  _In_opt_ PVOID Context,
147  _In_opt_ DLGPROC HookProc
148  )
149 {
150  HPROPSHEETPAGE propSheetPageHandle;
151  PROPSHEETPAGE propSheetPage;
152  PTOKEN_PAGE_CONTEXT tokenPageContext;
153 
154  tokenPageContext = PhCreateAlloc(sizeof(TOKEN_PAGE_CONTEXT));
155  memset(tokenPageContext, 0, sizeof(TOKEN_PAGE_CONTEXT));
156  tokenPageContext->OpenObject = OpenObject;
157  tokenPageContext->Context = Context;
158  tokenPageContext->HookProc = HookProc;
159 
160  memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE));
161  propSheetPage.dwSize = sizeof(PROPSHEETPAGE);
162  propSheetPage.dwFlags = PSP_USECALLBACK;
163  propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_OBJTOKEN);
164  propSheetPage.pfnDlgProc = PhpTokenPageProc;
165  propSheetPage.lParam = (LPARAM)tokenPageContext;
166  propSheetPage.pfnCallback = PhpTokenPropPageProc;
167 
168  propSheetPageHandle = CreatePropertySheetPage(&propSheetPage);
169  // CreatePropertySheetPage would have sent PSPCB_ADDREF (below),
170  // which would have added a reference.
171  PhDereferenceObject(tokenPageContext);
172 
173  return propSheetPageHandle;
174 }
175 
176 INT CALLBACK PhpTokenPropPageProc(
177  _In_ HWND hwnd,
178  _In_ UINT uMsg,
179  _In_ LPPROPSHEETPAGE ppsp
180  )
181 {
182  PTOKEN_PAGE_CONTEXT tokenPageContext;
183 
184  tokenPageContext = (PTOKEN_PAGE_CONTEXT)ppsp->lParam;
185 
186  if (uMsg == PSPCB_ADDREF)
187  {
188  PhReferenceObject(tokenPageContext);
189  }
190  else if (uMsg == PSPCB_RELEASE)
191  {
192  PhDereferenceObject(tokenPageContext);
193  }
194 
195  return 1;
196 }
197 
199  _In_ ULONG Attributes
200  )
201 {
202  PWSTR baseString;
203  PPH_STRING string;
204 
205  if (Attributes & SE_GROUP_INTEGRITY)
206  {
207  if (Attributes & SE_GROUP_INTEGRITY_ENABLED)
208  return PhCreateString(L"Integrity");
209  else
210  return PhCreateString(L"Integrity (Disabled)");
211  }
212 
213  if (Attributes & SE_GROUP_LOGON_ID)
214  baseString = L"Logon ID";
215  else if (Attributes & SE_GROUP_MANDATORY)
216  baseString = L"Mandatory";
217  else if (Attributes & SE_GROUP_OWNER)
218  baseString = L"Owner";
219  else if (Attributes & SE_GROUP_RESOURCE)
220  baseString = L"Resource";
221  else if (Attributes & SE_GROUP_USE_FOR_DENY_ONLY)
222  baseString = L"Use for Deny Only";
223  else
224  baseString = NULL;
225 
226  if (!baseString)
227  {
228  if (Attributes & SE_GROUP_ENABLED_BY_DEFAULT)
229  return PhCreateString(L"Default Enabled");
230  else if (Attributes & SE_GROUP_ENABLED)
231  return PhReferenceEmptyString();
232  else
233  return PhCreateString(L"Disabled");
234  }
235 
236  if (Attributes & SE_GROUP_ENABLED_BY_DEFAULT)
237  string = PhConcatStrings2(baseString, L" (Default Enabled)");
238  else if (Attributes & SE_GROUP_ENABLED)
239  string = PhCreateString(baseString);
240  else
241  string = PhConcatStrings2(baseString, L" (Disabled)");
242 
243  return string;
244 }
245 
247  _In_ ULONG Attributes
248  )
249 {
250  if (Attributes & SE_GROUP_INTEGRITY)
251  {
252  if (Attributes & SE_GROUP_INTEGRITY_ENABLED)
253  return RGB(0xe0, 0xf0, 0xe0);
254  else
255  return GetSysColor(COLOR_WINDOW);
256  }
257 
258  if (Attributes & SE_GROUP_ENABLED_BY_DEFAULT)
259  return RGB(0xe0, 0xf0, 0xe0);
260  else if (Attributes & SE_GROUP_ENABLED)
261  return GetSysColor(COLOR_WINDOW);
262  else
263  return RGB(0xf0, 0xe0, 0xe0);
264 }
265 
266 static COLORREF NTAPI PhpTokenGroupColorFunction(
267  _In_ INT Index,
268  _In_ PVOID Param,
269  _In_opt_ PVOID Context
270  )
271 {
272  PSID_AND_ATTRIBUTES sidAndAttributes = Param;
273 
274  return PhGetGroupAttributesColor(sidAndAttributes->Attributes);
275 }
276 
278  _In_ ULONG Attributes
279  )
280 {
281  if (Attributes & SE_PRIVILEGE_ENABLED_BY_DEFAULT)
282  return L"Default Enabled";
283  else if (Attributes & SE_PRIVILEGE_ENABLED)
284  return L"Enabled";
285  else
286  return L"Disabled";
287 }
288 
290  _In_ ULONG Attributes
291  )
292 {
293  if (Attributes & SE_PRIVILEGE_ENABLED_BY_DEFAULT)
294  return RGB(0xc0, 0xf0, 0xc0);
295  else if (Attributes & SE_PRIVILEGE_ENABLED)
296  return RGB(0xe0, 0xf0, 0xe0);
297  else
298  return RGB(0xf0, 0xe0, 0xe0);
299 }
300 
301 static COLORREF NTAPI PhpTokenPrivilegeColorFunction(
302  _In_ INT Index,
303  _In_ PVOID Param,
304  _In_opt_ PVOID Context
305  )
306 {
307  PLUID_AND_ATTRIBUTES luidAndAttributes = Param;
308 
309  return PhGetPrivilegeAttributesColor(luidAndAttributes->Attributes);
310 }
311 
313  _In_ TOKEN_ELEVATION_TYPE ElevationType
314  )
315 {
316  switch (ElevationType)
317  {
318  case TokenElevationTypeFull:
319  return L"Yes";
320  case TokenElevationTypeLimited:
321  return L"No";
322  default:
323  return L"N/A";
324  }
325 }
326 
328  _In_ HWND hwndDlg,
329  _In_ PTOKEN_PAGE_CONTEXT TokenPageContext,
330  _In_ HWND GroupsLv,
331  _In_ HANDLE TokenHandle
332  )
333 {
334  PTOKEN_GROUPS groups;
335  ULONG i;
336 
337  if (!NT_SUCCESS(PhGetTokenGroups(TokenHandle, &groups)))
338  return FALSE;
339 
341 
342  ListView_DeleteAllItems(GroupsLv);
343 
344  for (i = 0; i < groups->GroupCount; i++)
345  {
346  INT lvItemIndex;
347  PPH_STRING fullName;
348  PPH_STRING attributesString;
349 
350  if (!(fullName = PhGetSidFullName(groups->Groups[i].Sid, TRUE, NULL)))
351  fullName = PhSidToStringSid(groups->Groups[i].Sid);
352 
353  if (fullName)
354  {
355  lvItemIndex = PhAddListViewItem(GroupsLv, MAXINT, fullName->Buffer, &groups->Groups[i]);
356  attributesString = PhGetGroupAttributesString(groups->Groups[i].Attributes);
357  PhSetListViewSubItem(GroupsLv, lvItemIndex, 1, attributesString->Buffer);
358 
359  PhDereferenceObject(attributesString);
360  PhDereferenceObject(fullName);
361  }
362  }
363 
364  ExtendedListView_SortItems(GroupsLv);
365 
366  ExtendedListView_SetRedraw(GroupsLv, TRUE);
367 
368  if (TokenPageContext->Groups)
369  PhFree(TokenPageContext->Groups);
370 
371  TokenPageContext->Groups = groups;
372 
373  return TRUE;
374 }
375 
377  _In_ HWND hwndDlg,
378  _In_ UINT uMsg,
379  _In_ WPARAM wParam,
380  _In_ LPARAM lParam
381  )
382 {
384  hwndDlg, uMsg, wParam, lParam, L"TokenPageContext");
385 }
386 
387 INT_PTR CALLBACK PhpTokenPageProc(
388  _In_ HWND hwndDlg,
389  _In_ UINT uMsg,
390  _In_ WPARAM wParam,
391  _In_ LPARAM lParam
392  )
393 {
394  PTOKEN_PAGE_CONTEXT tokenPageContext;
395 
396  tokenPageContext = PhpTokenPageHeader(hwndDlg, uMsg, wParam, lParam);
397 
398  if (!tokenPageContext)
399  return FALSE;
400 
401  if (tokenPageContext->HookProc)
402  {
403  if (tokenPageContext->HookProc(hwndDlg, uMsg, wParam, lParam))
404  return TRUE;
405  }
406 
407  switch (uMsg)
408  {
409  case WM_INITDIALOG:
410  {
411  HWND groupsLv;
412  HWND privilegesLv;
413  HANDLE tokenHandle;
414 
415  tokenPageContext->GroupsListViewHandle = groupsLv = GetDlgItem(hwndDlg, IDC_GROUPS);
416  tokenPageContext->PrivilegesListViewHandle = privilegesLv = GetDlgItem(hwndDlg, IDC_PRIVILEGES);
417  PhSetListViewStyle(groupsLv, FALSE, TRUE);
418  PhSetListViewStyle(privilegesLv, FALSE, TRUE);
419  PhSetControlTheme(groupsLv, L"explorer");
420  PhSetControlTheme(privilegesLv, L"explorer");
421 
422  PhAddListViewColumn(groupsLv, 0, 0, 0, LVCFMT_LEFT, 160, L"Name");
423  PhAddListViewColumn(groupsLv, 1, 1, 1, LVCFMT_LEFT, 200, L"Flags");
424 
425  PhAddListViewColumn(privilegesLv, 0, 0, 0, LVCFMT_LEFT, 100, L"Name");
426  PhAddListViewColumn(privilegesLv, 1, 1, 1, LVCFMT_LEFT, 100, L"Status");
427  PhAddListViewColumn(privilegesLv, 2, 2, 2, LVCFMT_LEFT, 170, L"Description");
428 
429  PhSetExtendedListView(groupsLv);
430  ExtendedListView_SetItemColorFunction(groupsLv, PhpTokenGroupColorFunction);
431 
432  PhSetExtendedListView(privilegesLv);
433  ExtendedListView_SetItemColorFunction(privilegesLv, PhpTokenPrivilegeColorFunction);
434 
435  SetDlgItemText(hwndDlg, IDC_USER, L"Unknown");
436  SetDlgItemText(hwndDlg, IDC_USERSID, L"Unknown");
437  SetDlgItemText(hwndDlg, IDC_APPCONTAINERSID, L"Unknown");
438 
439  if (!WINDOWS_HAS_UAC)
440  ShowWindow(GetDlgItem(hwndDlg, IDC_INTEGRITY), SW_HIDE);
441 
442  if (NT_SUCCESS(tokenPageContext->OpenObject(
443  &tokenHandle,
444  TOKEN_QUERY,
445  tokenPageContext->Context
446  )))
447  {
448  PTOKEN_USER tokenUser;
449  PPH_STRING fullUserName;
450  PPH_STRING stringUserSid;
451  ULONG sessionId;
452  TOKEN_ELEVATION_TYPE elevationType;
453  BOOLEAN isVirtualizationAllowed;
454  BOOLEAN isVirtualizationEnabled;
455  PTOKEN_APPCONTAINER_INFORMATION appContainerInfo;
456  PPH_STRING appContainerSid;
457  ULONG i;
458 
459  if (NT_SUCCESS(PhGetTokenUser(tokenHandle, &tokenUser)))
460  {
461  if (fullUserName = PhGetSidFullName(tokenUser->User.Sid, TRUE, NULL))
462  {
463  SetDlgItemText(hwndDlg, IDC_USER, fullUserName->Buffer);
464  PhDereferenceObject(fullUserName);
465  }
466 
467  if (stringUserSid = PhSidToStringSid(tokenUser->User.Sid))
468  {
469  SetDlgItemText(hwndDlg, IDC_USERSID, stringUserSid->Buffer);
470  PhDereferenceObject(stringUserSid);
471  }
472 
473  PhFree(tokenUser);
474  }
475 
476  if (NT_SUCCESS(PhGetTokenSessionId(tokenHandle, &sessionId)))
477  SetDlgItemInt(hwndDlg, IDC_SESSIONID, sessionId, FALSE);
478 
479  if (WINDOWS_HAS_UAC)
480  {
481  if (NT_SUCCESS(PhGetTokenElevationType(tokenHandle, &elevationType)))
482  SetDlgItemText(hwndDlg, IDC_ELEVATED, PhGetElevationTypeString(elevationType));
483 
484  if (NT_SUCCESS(PhGetTokenIsVirtualizationAllowed(tokenHandle, &isVirtualizationAllowed)))
485  {
486  if (isVirtualizationAllowed)
487  {
488  if (NT_SUCCESS(PhGetTokenIsVirtualizationEnabled(tokenHandle, &isVirtualizationEnabled)))
489  {
490  SetDlgItemText(
491  hwndDlg,
493  isVirtualizationEnabled ? L"Yes" : L"No"
494  );
495  }
496  }
497  else
498  {
499  SetDlgItemText(hwndDlg, IDC_VIRTUALIZED, L"Not Allowed");
500  }
501  }
502  }
503  else
504  {
505  SetDlgItemText(hwndDlg, IDC_ELEVATED, L"N/A");
506  SetDlgItemText(hwndDlg, IDC_VIRTUALIZED, L"N/A");
507  }
508 
510  {
511  appContainerSid = NULL;
512 
513  if (NT_SUCCESS(PhQueryTokenVariableSize(tokenHandle, TokenAppContainerSid, &appContainerInfo)))
514  {
515  if (appContainerInfo->TokenAppContainer)
516  appContainerSid = PhSidToStringSid(appContainerInfo->TokenAppContainer);
517 
518  PhFree(appContainerInfo);
519  }
520 
521  if (appContainerSid)
522  {
523  SetDlgItemText(hwndDlg, IDC_APPCONTAINERSID, appContainerSid->Buffer);
524  PhDereferenceObject(appContainerSid);
525  }
526  else
527  {
528  SetDlgItemText(hwndDlg, IDC_APPCONTAINERSID, L"N/A");
529  }
530  }
531  else
532  {
533  SetDlgItemText(hwndDlg, IDC_APPCONTAINERSID, L"N/A");
534  }
535 
536  // Groups
537  PhpUpdateTokenGroups(hwndDlg, tokenPageContext, groupsLv, tokenHandle);
538 
539  // Privileges
540  if (NT_SUCCESS(PhGetTokenPrivileges(tokenHandle, &tokenPageContext->Privileges)))
541  {
542  for (i = 0; i < tokenPageContext->Privileges->PrivilegeCount; i++)
543  {
544  INT lvItemIndex;
545  PPH_STRING privilegeName;
546  PPH_STRING privilegeDisplayName;
547 
549  &tokenPageContext->Privileges->Privileges[i].Luid,
550  &privilegeName
551  ))
552  {
553  privilegeDisplayName = NULL;
554  PhLookupPrivilegeDisplayName(&privilegeName->sr, &privilegeDisplayName);
555 
556  // Name
557  lvItemIndex = PhAddListViewItem(privilegesLv, MAXINT, privilegeName->Buffer,
558  &tokenPageContext->Privileges->Privileges[i]);
559  // Status
560  PhSetListViewSubItem(privilegesLv, lvItemIndex, 1,
562  tokenPageContext->Privileges->Privileges[i].Attributes));
563  // Description
564  PhSetListViewSubItem(privilegesLv, lvItemIndex, 2,
565  PhGetString(privilegeDisplayName));
566 
567  if (privilegeDisplayName) PhDereferenceObject(privilegeDisplayName);
568  PhDereferenceObject(privilegeName);
569  }
570  }
571 
572  ExtendedListView_SortItems(privilegesLv);
573  }
574 
575  NtClose(tokenHandle);
576  }
577  }
578  break;
579  case WM_DESTROY:
580  {
581  if (tokenPageContext->Groups) PhFree(tokenPageContext->Groups);
582  if (tokenPageContext->Privileges) PhFree(tokenPageContext->Privileges);
583  }
584  break;
585  case WM_COMMAND:
586  {
587  switch (LOWORD(wParam))
588  {
589  case ID_PRIVILEGE_ENABLE:
591  case ID_PRIVILEGE_REMOVE:
592  {
593  NTSTATUS status;
594  PLUID_AND_ATTRIBUTES *privileges;
595  ULONG numberOfPrivileges;
596  HANDLE tokenHandle;
597  ULONG i;
598 
599  if (LOWORD(wParam) == ID_PRIVILEGE_REMOVE)
600  {
602  hwndDlg,
603  L"remove",
604  L"the selected privilege(s)",
605  L"Removing privileges may reduce the functionality of the process, "
606  L"and is permanent for the lifetime of the process.",
607  FALSE
608  ))
609  break;
610  }
611 
613  tokenPageContext->PrivilegesListViewHandle,
614  &privileges,
615  &numberOfPrivileges
616  );
617 
618  status = tokenPageContext->OpenObject(
619  &tokenHandle,
620  TOKEN_ADJUST_PRIVILEGES,
621  tokenPageContext->Context
622  );
623 
624  if (NT_SUCCESS(status))
625  {
626  ExtendedListView_SetRedraw(tokenPageContext->PrivilegesListViewHandle, FALSE);
627 
628  for (i = 0; i < numberOfPrivileges; i++)
629  {
630  PPH_STRING privilegeName = NULL;
631  ULONG newAttributes;
632 
633  PhLookupPrivilegeName(&privileges[i]->Luid, &privilegeName);
634  PhAutoDereferenceObject(privilegeName);
635 
636  switch (LOWORD(wParam))
637  {
638  case ID_PRIVILEGE_ENABLE:
639  newAttributes = SE_PRIVILEGE_ENABLED;
640  break;
642  newAttributes = 0;
643  break;
644  case ID_PRIVILEGE_REMOVE:
645  newAttributes = SE_PRIVILEGE_REMOVED;
646  break;
647  }
648 
649  // Privileges which are enabled by default cannot be
650  // modified except to remove them.
651 
652  if (
653  privileges[i]->Attributes & SE_PRIVILEGE_ENABLED_BY_DEFAULT &&
654  LOWORD(wParam) != ID_PRIVILEGE_REMOVE
655  )
656  {
657  if (LOWORD(wParam) == ID_PRIVILEGE_DISABLE)
658  {
660  hwndDlg,
661  PhaConcatStrings2(L"Unable to disable ", privilegeName->Buffer)->Buffer,
662  STATUS_UNSUCCESSFUL,
663  0
664  ))
665  break;
666  }
667 
668  continue;
669  }
670 
672  tokenHandle,
673  NULL,
674  &privileges[i]->Luid,
675  newAttributes
676  ))
677  {
678  INT lvItemIndex = PhFindListViewItemByParam(
679  tokenPageContext->PrivilegesListViewHandle,
680  -1,
681  privileges[i]
682  );
683 
684  if (LOWORD(wParam) != ID_PRIVILEGE_REMOVE)
685  {
686  // Refresh the status text (and background
687  // color).
688  privileges[i]->Attributes = newAttributes;
690  tokenPageContext->PrivilegesListViewHandle,
691  lvItemIndex,
692  1,
693  PhGetPrivilegeAttributesString(newAttributes)
694  );
695  }
696  else
697  {
698  ListView_DeleteItem(
699  tokenPageContext->PrivilegesListViewHandle,
700  lvItemIndex
701  );
702  }
703  }
704  else
705  {
706  PWSTR action = L"set";
707 
708  switch (LOWORD(wParam))
709  {
710  case ID_PRIVILEGE_ENABLE:
711  action = L"enable";
712  break;
714  action = L"disable";
715  break;
716  case ID_PRIVILEGE_REMOVE:
717  action = L"remove";
718  break;
719  }
720 
722  hwndDlg,
723  PhaFormatString(L"Unable to %s %s", action, privilegeName->Buffer)->Buffer,
724  STATUS_UNSUCCESSFUL,
725  0
726  ))
727  break;
728  }
729  }
730 
731  ExtendedListView_SetRedraw(tokenPageContext->PrivilegesListViewHandle, TRUE);
732 
733  NtClose(tokenHandle);
734  }
735  else
736  {
737  PhShowStatus(hwndDlg, L"Unable to open the token", status, 0);
738  }
739 
740  PhFree(privileges);
741 
742  ExtendedListView_SortItems(tokenPageContext->PrivilegesListViewHandle);
743  }
744  break;
745  case ID_PRIVILEGE_COPY:
746  {
747  PhCopyListView(tokenPageContext->PrivilegesListViewHandle);
748  }
749  break;
750  case IDC_INTEGRITY:
751  {
752  NTSTATUS status;
753  RECT rect;
754  PPH_EMENU menu;
755  HANDLE tokenHandle;
756  MANDATORY_LEVEL integrityLevel;
757  PPH_EMENU_ITEM selectedItem;
758 
759  GetWindowRect(GetDlgItem(hwndDlg, IDC_INTEGRITY), &rect);
760 
761  menu = PhCreateEMenu();
762 
763  PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatoryLevelSecureProcess, L"Protected", NULL, NULL), -1);
764  PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatoryLevelSystem, L"System", NULL, NULL), -1);
765  PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatoryLevelHigh, L"High", NULL, NULL), -1);
766  PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatoryLevelMedium, L"Medium", NULL, NULL), -1);
767  PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatoryLevelLow, L"Low", NULL, NULL), -1);
768  PhInsertEMenuItem(menu, PhCreateEMenuItem(0, MandatoryLevelUntrusted, L"Untrusted", NULL, NULL), -1);
769 
770  integrityLevel = -1;
771 
772  // Put a radio check on the menu item that corresponds with the current integrity level.
773  // Also disable menu items which correspond to higher integrity levels since
774  // NtSetInformationToken doesn't allow integrity levels to be raised.
775  if (NT_SUCCESS(tokenPageContext->OpenObject(
776  &tokenHandle,
777  TOKEN_QUERY,
778  tokenPageContext->Context
779  )))
780  {
782  tokenHandle,
783  &integrityLevel,
784  NULL
785  )))
786  {
787  ULONG i;
788 
789  for (i = 0; i < menu->Items->Count; i++)
790  {
791  PPH_EMENU_ITEM menuItem = menu->Items->Items[i];
792 
793  if (menuItem->Id == integrityLevel)
794  {
796  }
797  else if (menuItem->Id > (ULONG)integrityLevel)
798  {
799  menuItem->Flags |= PH_EMENU_DISABLED;
800  }
801  }
802  }
803 
804  NtClose(tokenHandle);
805  }
806 
807  selectedItem = PhShowEMenu(
808  menu,
809  hwndDlg,
812  rect.left,
813  rect.bottom
814  );
815 
816  if (selectedItem && selectedItem->Id != integrityLevel)
817  {
819  hwndDlg,
820  L"set",
821  L"the integrity level",
822  L"Once lowered, the integrity level of the token cannot be raised again.",
823  FALSE
824  ))
825  {
826  if (NT_SUCCESS(status = tokenPageContext->OpenObject(
827  &tokenHandle,
828  TOKEN_QUERY | TOKEN_ADJUST_DEFAULT,
829  tokenPageContext->Context
830  )))
831  {
832  static SID_IDENTIFIER_AUTHORITY mandatoryLabelAuthority = SECURITY_MANDATORY_LABEL_AUTHORITY;
833 
834  UCHAR newSidBuffer[FIELD_OFFSET(SID, SubAuthority) + sizeof(ULONG)];
835  PSID newSid;
836  TOKEN_MANDATORY_LABEL mandatoryLabel;
837 
838  newSid = (PSID)newSidBuffer;
839  RtlInitializeSid(newSid, &mandatoryLabelAuthority, 1);
840  *RtlSubAuthoritySid(newSid, 0) = MANDATORY_LEVEL_TO_MANDATORY_RID(selectedItem->Id);
841  mandatoryLabel.Label.Sid = newSid;
842  mandatoryLabel.Label.Attributes = SE_GROUP_INTEGRITY;
843 
844  status = NtSetInformationToken(
845  tokenHandle,
846  TokenIntegrityLevel,
847  &mandatoryLabel,
848  sizeof(TOKEN_MANDATORY_LABEL)
849  );
850 
851  if (NT_SUCCESS(status))
852  PhpUpdateTokenGroups(hwndDlg, tokenPageContext, GetDlgItem(hwndDlg, IDC_GROUPS), tokenHandle);
853 
854  NtClose(tokenHandle);
855  }
856 
857  if (!NT_SUCCESS(status))
858  PhShowStatus(hwndDlg, L"Unable to set the integrity level", status, 0);
859  }
860  }
861 
862  PhDestroyEMenu(menu);
863  }
864  break;
865  case IDC_ADVANCED:
866  {
867  PhpShowTokenAdvancedProperties(hwndDlg, tokenPageContext);
868  }
869  break;
870  }
871  }
872  break;
873  case WM_NOTIFY:
874  {
875  LPNMHDR header = (LPNMHDR)lParam;
876 
877  switch (header->code)
878  {
879  case PSN_QUERYINITIALFOCUS:
880  {
881  SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)GetDlgItem(hwndDlg, IDC_SESSIONID));
882  return TRUE;
883  }
884  break;
885  }
886 
887  PhHandleListViewNotifyBehaviors(lParam, tokenPageContext->GroupsListViewHandle, PH_LIST_VIEW_DEFAULT_1_BEHAVIORS);
888  PhHandleListViewNotifyBehaviors(lParam, tokenPageContext->PrivilegesListViewHandle, PH_LIST_VIEW_DEFAULT_1_BEHAVIORS);
889  }
890  break;
891  case WM_CONTEXTMENU:
892  {
893  if ((HWND)wParam == tokenPageContext->PrivilegesListViewHandle)
894  {
895  POINT point;
896 
897  point.x = (SHORT)LOWORD(lParam);
898  point.y = (SHORT)HIWORD(lParam);
899 
900  if (point.x == -1 && point.y == -1)
901  PhGetListViewContextMenuPoint((HWND)wParam, &point);
902 
903  if (ListView_GetSelectedCount(tokenPageContext->PrivilegesListViewHandle) != 0)
904  {
905  PPH_EMENU menu;
906 
907  menu = PhCreateEMenu();
908  PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_PRIVILEGE), 0);
910  PH_ALIGN_LEFT | PH_ALIGN_TOP, point.x, point.y);
911  PhDestroyEMenu(menu);
912  }
913  }
914  }
915  break;
916  }
917 
918  REFLECT_MESSAGE_DLG(hwndDlg, tokenPageContext->GroupsListViewHandle, uMsg, wParam, lParam);
919  REFLECT_MESSAGE_DLG(hwndDlg, tokenPageContext->PrivilegesListViewHandle, uMsg, wParam, lParam);
920 
921  return FALSE;
922 }
923 
925  _In_ HWND ParentWindowHandle,
926  _In_ PTOKEN_PAGE_CONTEXT Context
927  )
928 {
929  PROPSHEETHEADER propSheetHeader = { sizeof(propSheetHeader) };
930  HPROPSHEETPAGE pages[6];
931  PROPSHEETPAGE page;
932  ULONG numberOfPages;
933  PH_STD_OBJECT_SECURITY stdObjectSecurity;
934  PPH_ACCESS_ENTRY accessEntries;
935  ULONG numberOfAccessEntries;
936 
937  propSheetHeader.dwFlags =
938  PSH_NOAPPLYNOW |
939  PSH_NOCONTEXTHELP |
940  PSH_PROPTITLE;
941  propSheetHeader.hwndParent = ParentWindowHandle;
942  propSheetHeader.pszCaption = L"Token";
943  propSheetHeader.nStartPage = 0;
944  propSheetHeader.phpage = pages;
945 
946  numberOfPages = 0;
947 
948  // General
949 
950  memset(&page, 0, sizeof(PROPSHEETPAGE));
951  page.dwSize = sizeof(PROPSHEETPAGE);
952  page.pszTemplate = MAKEINTRESOURCE(IDD_TOKGENERAL);
953  page.pfnDlgProc = PhpTokenGeneralPageProc;
954  page.lParam = (LPARAM)Context;
955  pages[numberOfPages++] = CreatePropertySheetPage(&page);
956 
957  // Advanced
958 
959  memset(&page, 0, sizeof(PROPSHEETPAGE));
960  page.dwSize = sizeof(PROPSHEETPAGE);
961  page.pszTemplate = MAKEINTRESOURCE(IDD_TOKADVANCED);
962  page.pfnDlgProc = PhpTokenAdvancedPageProc;
963  page.lParam = (LPARAM)Context;
964  pages[numberOfPages++] = CreatePropertySheetPage(&page);
965 
966  if (WindowsVersion >= WINDOWS_8)
967  {
968  // Capabilities
969 
970  memset(&page, 0, sizeof(PROPSHEETPAGE));
971  page.dwSize = sizeof(PROPSHEETPAGE);
972  page.pszTemplate = MAKEINTRESOURCE(IDD_TOKCAPABILITIES);
973  page.pfnDlgProc = PhpTokenCapabilitiesPageProc;
974  page.lParam = (LPARAM)Context;
975  pages[numberOfPages++] = CreatePropertySheetPage(&page);
976 
977  // Claims
978 
979  memset(&page, 0, sizeof(PROPSHEETPAGE));
980  page.dwSize = sizeof(PROPSHEETPAGE);
981  page.dwFlags = PSP_USETITLE;
982  page.pszTemplate = MAKEINTRESOURCE(IDD_TOKATTRIBUTES);
983  page.pszTitle = L"Claims";
984  page.pfnDlgProc = PhpTokenClaimsPageProc;
985  page.lParam = (LPARAM)Context;
986  pages[numberOfPages++] = CreatePropertySheetPage(&page);
987 
988  // (Token) Attributes
989 
990  memset(&page, 0, sizeof(PROPSHEETPAGE));
991  page.dwSize = sizeof(PROPSHEETPAGE);
992  page.dwFlags = PSP_USETITLE;
993  page.pszTemplate = MAKEINTRESOURCE(IDD_TOKATTRIBUTES);
994  page.pszTitle = L"Attributes";
995  page.pfnDlgProc = PhpTokenAttributesPageProc;
996  page.lParam = (LPARAM)Context;
997  pages[numberOfPages++] = CreatePropertySheetPage(&page);
998  }
999 
1000  // Security
1001 
1002  stdObjectSecurity.OpenObject = Context->OpenObject;
1003  stdObjectSecurity.ObjectType = L"Token";
1004  stdObjectSecurity.Context = Context->Context;
1005 
1006  if (PhGetAccessEntries(L"Token", &accessEntries, &numberOfAccessEntries))
1007  {
1008  pages[numberOfPages++] = PhCreateSecurityPage(
1009  L"Token",
1012  &stdObjectSecurity,
1013  accessEntries,
1014  numberOfAccessEntries
1015  );
1016  PhFree(accessEntries);
1017  }
1018 
1019  propSheetHeader.nPages = numberOfPages;
1020  PropertySheet(&propSheetHeader);
1021 }
1022 
1023 static NTSTATUS PhpOpenLinkedToken(
1024  _Out_ PHANDLE Handle,
1025  _In_ ACCESS_MASK DesiredAccess,
1026  _In_opt_ PVOID Context
1027  )
1028 {
1029  return PhGetTokenLinkedToken((HANDLE)Context, Handle);
1030 }
1031 
1032 INT_PTR CALLBACK PhpTokenGeneralPageProc(
1033  _In_ HWND hwndDlg,
1034  _In_ UINT uMsg,
1035  _In_ WPARAM wParam,
1036  _In_ LPARAM lParam
1037  )
1038 {
1039  PTOKEN_PAGE_CONTEXT tokenPageContext;
1040 
1041  tokenPageContext = PhpTokenPageHeader(hwndDlg, uMsg, wParam, lParam);
1042 
1043  if (!tokenPageContext)
1044  return FALSE;
1045 
1046  switch (uMsg)
1047  {
1048  case WM_INITDIALOG:
1049  {
1050  HANDLE tokenHandle;
1051  PPH_STRING tokenUserName = NULL;
1052  PPH_STRING tokenUserSid = NULL;
1053  PPH_STRING tokenOwnerName = NULL;
1054  PPH_STRING tokenPrimaryGroupName = NULL;
1055  ULONG tokenSessionId = -1;
1056  PWSTR tokenElevated = L"N/A";
1057  BOOLEAN hasLinkedToken = FALSE;
1058  PWSTR tokenVirtualization = L"N/A";
1059  WCHAR tokenSourceName[TOKEN_SOURCE_LENGTH + 1] = L"Unknown";
1060  WCHAR tokenSourceLuid[PH_PTR_STR_LEN_1] = L"Unknown";
1061 
1062  if (NT_SUCCESS(tokenPageContext->OpenObject(
1063  &tokenHandle,
1064  TOKEN_QUERY,
1065  tokenPageContext->Context
1066  )))
1067  {
1068  PTOKEN_USER tokenUser;
1069  PTOKEN_OWNER tokenOwner;
1070  PTOKEN_PRIMARY_GROUP tokenPrimaryGroup;
1071  TOKEN_ELEVATION_TYPE elevationType;
1072  BOOLEAN isVirtualizationAllowed;
1073  BOOLEAN isVirtualizationEnabled;
1074 
1075  if (NT_SUCCESS(PhGetTokenUser(tokenHandle, &tokenUser)))
1076  {
1077  tokenUserName = PhAutoDereferenceObject(PhGetSidFullName(tokenUser->User.Sid, TRUE, NULL));
1078  tokenUserSid = PhAutoDereferenceObject(PhSidToStringSid(tokenUser->User.Sid));
1079 
1080  PhFree(tokenUser);
1081  }
1082 
1083  if (NT_SUCCESS(PhGetTokenOwner(tokenHandle, &tokenOwner)))
1084  {
1085  tokenOwnerName = PhAutoDereferenceObject(PhGetSidFullName(tokenOwner->Owner, TRUE, NULL));
1086  PhFree(tokenOwner);
1087  }
1088 
1089  if (NT_SUCCESS(PhGetTokenPrimaryGroup(tokenHandle, &tokenPrimaryGroup)))
1090  {
1091  tokenPrimaryGroupName = PhAutoDereferenceObject(PhGetSidFullName(
1092  tokenPrimaryGroup->PrimaryGroup, TRUE, NULL));
1093  PhFree(tokenPrimaryGroup);
1094  }
1095 
1096  PhGetTokenSessionId(tokenHandle, &tokenSessionId);
1097 
1098  if (WINDOWS_HAS_UAC)
1099  {
1100  if (NT_SUCCESS(PhGetTokenElevationType(tokenHandle, &elevationType)))
1101  {
1102  tokenElevated = PhGetElevationTypeString(elevationType);
1103  hasLinkedToken = elevationType != TokenElevationTypeDefault;
1104  }
1105 
1106  if (NT_SUCCESS(PhGetTokenIsVirtualizationAllowed(tokenHandle, &isVirtualizationAllowed)))
1107  {
1108  if (isVirtualizationAllowed)
1109  {
1110  if (NT_SUCCESS(PhGetTokenIsVirtualizationEnabled(tokenHandle, &isVirtualizationEnabled)))
1111  {
1112  tokenVirtualization = isVirtualizationEnabled ? L"Enabled" : L"Disabled";
1113  }
1114  }
1115  else
1116  {
1117  tokenVirtualization = L"Not Allowed";
1118  }
1119  }
1120  }
1121 
1122  NtClose(tokenHandle);
1123  }
1124 
1125  if (NT_SUCCESS(tokenPageContext->OpenObject(
1126  &tokenHandle,
1127  TOKEN_QUERY_SOURCE,
1128  tokenPageContext->Context
1129  )))
1130  {
1131  TOKEN_SOURCE tokenSource;
1132 
1133  if (NT_SUCCESS(PhGetTokenSource(tokenHandle, &tokenSource)))
1134  {
1136  tokenSource.SourceName,
1137  TOKEN_SOURCE_LENGTH,
1138  tokenSourceName,
1139  sizeof(tokenSourceName) / 2,
1140  NULL
1141  );
1142 
1143  PhPrintPointer(tokenSourceLuid, (PVOID)tokenSource.SourceIdentifier.LowPart);
1144  }
1145 
1146  NtClose(tokenHandle);
1147  }
1148 
1149  SetDlgItemText(hwndDlg, IDC_USER, PhGetStringOrDefault(tokenUserName, L"Unknown"));
1150  SetDlgItemText(hwndDlg, IDC_USERSID, PhGetStringOrDefault(tokenUserSid, L"Unknown"));
1151  SetDlgItemText(hwndDlg, IDC_OWNER, PhGetStringOrDefault(tokenOwnerName, L"Unknown"));
1152  SetDlgItemText(hwndDlg, IDC_PRIMARYGROUP, PhGetStringOrDefault(tokenPrimaryGroupName, L"Unknown"));
1153 
1154  if (tokenSessionId != -1)
1155  SetDlgItemInt(hwndDlg, IDC_SESSIONID, tokenSessionId, FALSE);
1156  else
1157  SetDlgItemText(hwndDlg, IDC_SESSIONID, L"Unknown");
1158 
1159  SetDlgItemText(hwndDlg, IDC_ELEVATED, tokenElevated);
1160  SetDlgItemText(hwndDlg, IDC_VIRTUALIZATION, tokenVirtualization);
1161  SetDlgItemText(hwndDlg, IDC_SOURCENAME, tokenSourceName);
1162  SetDlgItemText(hwndDlg, IDC_SOURCELUID, tokenSourceLuid);
1163 
1164  if (!hasLinkedToken)
1165  ShowWindow(GetDlgItem(hwndDlg, IDC_LINKEDTOKEN), SW_HIDE);
1166  }
1167  break;
1168  case WM_COMMAND:
1169  {
1170  switch (LOWORD(wParam))
1171  {
1172  case IDC_LINKEDTOKEN:
1173  {
1174  NTSTATUS status;
1175  HANDLE tokenHandle;
1176 
1177  if (NT_SUCCESS(status = tokenPageContext->OpenObject(
1178  &tokenHandle,
1179  TOKEN_QUERY,
1180  tokenPageContext->Context
1181  )))
1182  {
1183  PhShowTokenProperties(hwndDlg, PhpOpenLinkedToken, (PVOID)tokenHandle, L"Linked Token");
1184  NtClose(tokenHandle);
1185  }
1186  else
1187  {
1188  PhShowStatus(hwndDlg, L"Unable to open the token", status, 0);
1189  }
1190  }
1191  break;
1192  }
1193  }
1194  break;
1195  }
1196 
1197  return FALSE;
1198 }
1199 
1200 INT_PTR CALLBACK PhpTokenAdvancedPageProc(
1201  _In_ HWND hwndDlg,
1202  _In_ UINT uMsg,
1203  _In_ WPARAM wParam,
1204  _In_ LPARAM lParam
1205  )
1206 {
1207  PTOKEN_PAGE_CONTEXT tokenPageContext;
1208 
1209  tokenPageContext = PhpTokenPageHeader(hwndDlg, uMsg, wParam, lParam);
1210 
1211  if (!tokenPageContext)
1212  return FALSE;
1213 
1214  switch (uMsg)
1215  {
1216  case WM_INITDIALOG:
1217  {
1218  HANDLE tokenHandle;
1219  PWSTR tokenType = L"Unknown";
1220  PWSTR tokenImpersonationLevel = L"Unknown";
1221  WCHAR tokenLuid[PH_PTR_STR_LEN_1] = L"Unknown";
1222  WCHAR authenticationLuid[PH_PTR_STR_LEN_1] = L"Unknown";
1223  PPH_STRING memoryUsed = NULL;
1224  PPH_STRING memoryAvailable = NULL;
1225 
1226  if (NT_SUCCESS(tokenPageContext->OpenObject(
1227  &tokenHandle,
1228  TOKEN_QUERY,
1229  tokenPageContext->Context
1230  )))
1231  {
1232  TOKEN_STATISTICS statistics;
1233 
1234  if (NT_SUCCESS(PhGetTokenStatistics(tokenHandle, &statistics)))
1235  {
1236  switch (statistics.TokenType)
1237  {
1238  case TokenPrimary:
1239  tokenType = L"Primary";
1240  break;
1241  case TokenImpersonation:
1242  tokenType = L"Impersonation";
1243  break;
1244  }
1245 
1246  if (statistics.TokenType == TokenImpersonation)
1247  {
1248  switch (statistics.ImpersonationLevel)
1249  {
1250  case SecurityAnonymous:
1251  tokenImpersonationLevel = L"Anonymous";
1252  break;
1253  case SecurityIdentification:
1254  tokenImpersonationLevel = L"Identification";
1255  break;
1256  case SecurityImpersonation:
1257  tokenImpersonationLevel = L"Impersonation";
1258  break;
1259  case SecurityDelegation:
1260  tokenImpersonationLevel = L"Delegation";
1261  break;
1262  }
1263  }
1264  else
1265  {
1266  tokenImpersonationLevel = L"N/A";
1267  }
1268 
1269  PhPrintPointer(tokenLuid, (PVOID)statistics.TokenId.LowPart);
1270  PhPrintPointer(authenticationLuid, (PVOID)statistics.AuthenticationId.LowPart);
1271 
1272  // DynamicCharged contains the number of bytes allocated.
1273  // DynamicAvailable contains the number of bytes free.
1274  memoryUsed = PhaFormatSize(statistics.DynamicCharged - statistics.DynamicAvailable, -1);
1275  memoryAvailable = PhaFormatSize(statistics.DynamicCharged, -1);
1276  }
1277 
1278  NtClose(tokenHandle);
1279  }
1280 
1281  SetDlgItemText(hwndDlg, IDC_TYPE, tokenType);
1282  SetDlgItemText(hwndDlg, IDC_IMPERSONATIONLEVEL, tokenImpersonationLevel);
1283  SetDlgItemText(hwndDlg, IDC_TOKENLUID, tokenLuid);
1284  SetDlgItemText(hwndDlg, IDC_AUTHENTICATIONLUID, authenticationLuid);
1285  SetDlgItemText(hwndDlg, IDC_MEMORYUSED, PhGetStringOrDefault(memoryUsed, L"Unknown"));
1286  SetDlgItemText(hwndDlg, IDC_MEMORYAVAILABLE, PhGetStringOrDefault(memoryAvailable, L"Unknown"));
1287  }
1288  break;
1289  }
1290 
1291  return FALSE;
1292 }
1293 
1294 static COLORREF NTAPI PhpTokenCapabilitiesColorFunction(
1295  _In_ INT Index,
1296  _In_ PVOID Param,
1297  _In_opt_ PVOID Context
1298  )
1299 {
1300  PSID_AND_ATTRIBUTES sidAndAttributes = Param;
1301 
1302  return PhGetGroupAttributesColor(sidAndAttributes->Attributes);
1303 }
1304 
1306  _In_ HWND hwndDlg,
1307  _In_ UINT uMsg,
1308  _In_ WPARAM wParam,
1309  _In_ LPARAM lParam
1310  )
1311 {
1312  PTOKEN_PAGE_CONTEXT tokenPageContext;
1313  HWND lvHandle;
1314 
1315  tokenPageContext = PhpTokenPageHeader(hwndDlg, uMsg, wParam, lParam);
1316 
1317  if (!tokenPageContext)
1318  return FALSE;
1319 
1320  lvHandle = GetDlgItem(hwndDlg, IDC_LIST);
1321 
1322  switch (uMsg)
1323  {
1324  case WM_INITDIALOG:
1325  {
1326  HANDLE tokenHandle;
1327  ULONG i;
1328 
1329  PhSetListViewStyle(lvHandle, FALSE, TRUE);
1330  PhSetControlTheme(lvHandle, L"explorer");
1331  PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 160, L"Name");
1332  PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 200, L"Flags");
1333  PhSetExtendedListView(lvHandle);
1334  ExtendedListView_SetItemColorFunction(lvHandle, PhpTokenCapabilitiesColorFunction);
1335 
1336  if (NT_SUCCESS(tokenPageContext->OpenObject(
1337  &tokenHandle,
1338  TOKEN_QUERY,
1339  tokenPageContext->Context
1340  )))
1341  {
1342  if (NT_SUCCESS(PhQueryTokenVariableSize(tokenHandle, TokenCapabilities, &tokenPageContext->Capabilities)))
1343  {
1344  for (i = 0; i < tokenPageContext->Capabilities->GroupCount; i++)
1345  {
1346  INT lvItemIndex;
1347  PPH_STRING name;
1348  PPH_STRING attributesString;
1349 
1350  name = PhGetSidFullName(tokenPageContext->Capabilities->Groups[i].Sid, TRUE, NULL);
1351 
1352  if (!name)
1353  name = PhSidToStringSid(tokenPageContext->Capabilities->Groups[i].Sid);
1354 
1355  if (name)
1356  {
1357  lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, name->Buffer,
1358  &tokenPageContext->Capabilities->Groups[i]);
1359  attributesString = PhGetGroupAttributesString(
1360  tokenPageContext->Capabilities->Groups[i].Attributes);
1361  PhSetListViewSubItem(lvHandle, lvItemIndex, 1, attributesString->Buffer);
1362 
1363  PhDereferenceObject(attributesString);
1364  PhDereferenceObject(name);
1365  }
1366  }
1367 
1368  if (ListView_GetItemCount(lvHandle) != 0)
1369  {
1370  ListView_SetColumnWidth(lvHandle, 0, LVSCW_AUTOSIZE);
1372  }
1373 
1374  ExtendedListView_SortItems(lvHandle);
1375  }
1376 
1377  NtClose(tokenHandle);
1378  }
1379  }
1380  break;
1381  case WM_DESTROY:
1382  {
1383  PhFree(tokenPageContext->Capabilities);
1384  tokenPageContext->Capabilities = NULL;
1385  }
1386  break;
1387  case WM_NOTIFY:
1388  {
1390  }
1391  break;
1392  }
1393 
1394  REFLECT_MESSAGE_DLG(hwndDlg, lvHandle, uMsg, wParam, lParam);
1395 
1396  return FALSE;
1397 }
1398 
1400  _In_ HWND hwnd,
1401  _In_ PH_TREENEW_MESSAGE Message,
1402  _In_opt_ PVOID Parameter1,
1403  _In_opt_ PVOID Parameter2,
1404  _In_opt_ PVOID Context
1405  )
1406 {
1407  PATTRIBUTE_TREE_CONTEXT context;
1408  PATTRIBUTE_NODE node;
1409 
1410  context = Context;
1411 
1412  switch (Message)
1413  {
1414  case TreeNewGetChildren:
1415  {
1416  PPH_TREENEW_GET_CHILDREN getChildren = Parameter1;
1417 
1418  node = (PATTRIBUTE_NODE)getChildren->Node;
1419 
1420  if (!node)
1421  {
1422  getChildren->Children = (PPH_TREENEW_NODE *)context->RootList->Items;
1423  getChildren->NumberOfChildren = context->RootList->Count;
1424  }
1425  else
1426  {
1427  getChildren->Children = (PPH_TREENEW_NODE *)node->Children->Items;
1428  getChildren->NumberOfChildren = node->Children->Count;
1429  }
1430  }
1431  return TRUE;
1432  case TreeNewIsLeaf:
1433  {
1434  PPH_TREENEW_IS_LEAF isLeaf = Parameter1;
1435 
1436  node = (PATTRIBUTE_NODE)isLeaf->Node;
1437 
1438  isLeaf->IsLeaf = node->Children->Count == 0;
1439  }
1440  return TRUE;
1441  case TreeNewGetCellText:
1442  {
1443  PPH_TREENEW_GET_CELL_TEXT getCellText = Parameter1;
1444 
1445  node = (PATTRIBUTE_NODE)getCellText->Node;
1446 
1447  if (getCellText->Id == 0)
1448  getCellText->Text = PhGetStringRef(node->Text);
1449  else
1450  return FALSE;
1451  }
1452  return TRUE;
1453  case TreeNewKeyDown:
1454  {
1455  PPH_TREENEW_KEY_EVENT keyEvent = Parameter1;
1456 
1457  switch (keyEvent->VirtualKey)
1458  {
1459  case 'C':
1460  if (GetKeyState(VK_CONTROL) < 0)
1461  {
1462  PPH_STRING text;
1463 
1464  text = PhGetTreeNewText(hwnd, 0);
1465  PhSetClipboardString(hwnd, &text->sr);
1466  PhDereferenceObject(text);
1467  }
1468  break;
1469  }
1470  }
1471  return TRUE;
1472  }
1473 
1474  return FALSE;
1475 }
1476 
1478  _In_ PATTRIBUTE_TREE_CONTEXT Context,
1479  _In_opt_ PATTRIBUTE_NODE Parent,
1480  _In_opt_ _Assume_refs_(1) PPH_STRING Text
1481  )
1482 {
1483  PATTRIBUTE_NODE node;
1484 
1485  node = PhAllocate(sizeof(ATTRIBUTE_NODE));
1486  memset(node, 0, sizeof(ATTRIBUTE_NODE));
1487  PhInitializeTreeNewNode(&node->Node);
1488 
1489  node->Children = PhCreateList(2);
1490 
1491  PhAddItemList(Context->NodeList, node);
1492 
1493  if (Parent)
1494  PhAddItemList(Parent->Children, node);
1495  else
1496  PhAddItemList(Context->RootList, node);
1497 
1498  PhMoveReference(&node->Text, Text);
1499 
1500  return node;
1501 }
1502 
1504  _In_ PATTRIBUTE_NODE Node
1505  )
1506 {
1507  PhDereferenceObject(Node->Children);
1508  PhClearReference(&Node->Text);
1509  PhFree(Node);
1510 }
1511 
1513  _Out_ PATTRIBUTE_TREE_CONTEXT Context,
1514  _In_ HWND TreeNewHandle
1515  )
1516 {
1517  PH_TREENEW_VIEW_PARTS parts;
1518 
1519  Context->NodeList = PhCreateList(10);
1520  Context->RootList = PhCreateList(10);
1521 
1522  PhSetControlTheme(TreeNewHandle, L"explorer");
1523  TreeNew_SetCallback(TreeNewHandle, PhpAttributeTreeNewCallback, Context);
1524  TreeNew_GetViewParts(TreeNewHandle, &parts);
1525  PhAddTreeNewColumn(TreeNewHandle, 0, TRUE, L"Attributes", parts.ClientRect.right - parts.VScrollWidth, PH_ALIGN_LEFT, 0, 0);
1526 }
1527 
1529  _Inout_ PATTRIBUTE_TREE_CONTEXT Context
1530  )
1531 {
1532  ULONG i;
1533 
1534  for (i = 0; i < Context->NodeList->Count; i++)
1535  PhpDestroyAttributeNode(Context->NodeList->Items[i]);
1536 
1537  PhDereferenceObject(Context->NodeList);
1538  PhDereferenceObject(Context->RootList);
1539 }
1540 
1542  _In_ USHORT Type
1543  )
1544 {
1545  // These types are shared between CLAIM_* and TOKEN_* security attributes.
1546 
1547  switch (Type)
1548  {
1550  return L"Invalid";
1552  return L"Int64";
1554  return L"UInt64";
1556  return L"String";
1558  return L"FQBN";
1560  return L"SID";
1562  return L"Boolean";
1564  return L"Octet String";
1565  default:
1566  return L"(Unknown)";
1567  }
1568 }
1569 
1571  _In_ ULONG Flags
1572  )
1573 {
1574  PH_STRING_BUILDER sb;
1575 
1576  // These flags are shared between CLAIM_* and TOKEN_* security attributes.
1577 
1578  PhInitializeStringBuilder(&sb, 100);
1579 
1581  PhAppendStringBuilder2(&sb, L"Mandatory, ");
1583  PhAppendStringBuilder2(&sb, L"Disabled, ");
1585  PhAppendStringBuilder2(&sb, L"Default Disabled, ");
1587  PhAppendStringBuilder2(&sb, L"Use for Deny Only, ");
1589  PhAppendStringBuilder2(&sb, L"Case-sensitive, ");
1591  PhAppendStringBuilder2(&sb, L"Non-inheritable, ");
1592 
1593  if (sb.String->Length != 0)
1594  PhRemoveEndStringBuilder(&sb, 2);
1595  else
1596  PhAppendStringBuilder2(&sb, L"(None)");
1597 
1598  return PhFinalStringBuilderString(&sb);
1599 }
1600 
1602  _In_ PCLAIM_SECURITY_ATTRIBUTE_V1 Attribute,
1603  _In_ ULONG ValueIndex
1604  )
1605 {
1606  PH_FORMAT format;
1607 
1608  switch (Attribute->ValueType)
1609  {
1610  case CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64:
1611  PhInitFormatI64D(&format, Attribute->Values.pInt64[ValueIndex]);
1612  return PhFormat(&format, 1, 0);
1613  case CLAIM_SECURITY_ATTRIBUTE_TYPE_UINT64:
1614  PhInitFormatI64U(&format, Attribute->Values.pUint64[ValueIndex]);
1615  return PhFormat(&format, 1, 0);
1616  case CLAIM_SECURITY_ATTRIBUTE_TYPE_STRING:
1617  return PhCreateString(Attribute->Values.ppString[ValueIndex]);
1618  case CLAIM_SECURITY_ATTRIBUTE_TYPE_FQBN:
1619  return PhFormatString(L"Version %I64u: %s",
1620  Attribute->Values.pFqbn[ValueIndex].Version,
1621  Attribute->Values.pFqbn[ValueIndex].Name);
1622  case CLAIM_SECURITY_ATTRIBUTE_TYPE_SID:
1623  {
1624  if (RtlValidSid(Attribute->Values.pOctetString[ValueIndex].pValue))
1625  {
1626  PPH_STRING name;
1627 
1628  name = PhGetSidFullName(Attribute->Values.pOctetString[ValueIndex].pValue, TRUE, NULL);
1629 
1630  if (name)
1631  return name;
1632 
1633  name = PhSidToStringSid(Attribute->Values.pOctetString[ValueIndex].pValue);
1634 
1635  if (name)
1636  return name;
1637  }
1638  }
1639  return PhCreateString(L"(Invalid SID)");
1640  case CLAIM_SECURITY_ATTRIBUTE_TYPE_BOOLEAN:
1641  return PhCreateString(Attribute->Values.pInt64[ValueIndex] != 0 ? L"True" : L"False");
1642  case CLAIM_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING:
1643  return PhCreateString(L"(Octet string)");
1644  default:
1645  return PhCreateString(L"(Unknown)");
1646  }
1647 }
1648 
1650  _In_ PTOKEN_SECURITY_ATTRIBUTE_V1 Attribute,
1651  _In_ ULONG ValueIndex
1652  )
1653 {
1654  PH_FORMAT format;
1655 
1656  switch (Attribute->ValueType)
1657  {
1659  PhInitFormatI64D(&format, Attribute->Values.pInt64[ValueIndex]);
1660  return PhFormat(&format, 1, 0);
1662  PhInitFormatI64U(&format, Attribute->Values.pUint64[ValueIndex]);
1663  return PhFormat(&format, 1, 0);
1665  return PhCreateStringFromUnicodeString(&Attribute->Values.pString[ValueIndex]);
1667  return PhFormatString(L"Version %I64u: %.*s",
1668  Attribute->Values.pFqbn[ValueIndex].Version,
1669  Attribute->Values.pFqbn[ValueIndex].Name.Length / sizeof(WCHAR),
1670  Attribute->Values.pFqbn[ValueIndex].Name.Buffer);
1672  {
1673  if (RtlValidSid(Attribute->Values.pOctetString[ValueIndex].pValue))
1674  {
1675  PPH_STRING name;
1676 
1677  name = PhGetSidFullName(Attribute->Values.pOctetString[ValueIndex].pValue, TRUE, NULL);
1678 
1679  if (name)
1680  return name;
1681 
1682  name = PhSidToStringSid(Attribute->Values.pOctetString[ValueIndex].pValue);
1683 
1684  if (name)
1685  return name;
1686  }
1687  }
1688  return PhCreateString(L"(Invalid SID)");
1690  return PhCreateString(Attribute->Values.pInt64[ValueIndex] != 0 ? L"True" : L"False");
1692  return PhCreateString(L"(Octet string)");
1693  default:
1694  return PhCreateString(L"(Unknown)");
1695  }
1696 }
1697 
1699  _In_ PTOKEN_PAGE_CONTEXT TokenPageContext,
1700  _In_ HWND tnHandle,
1701  _In_ BOOLEAN DeviceClaims,
1702  _In_ PATTRIBUTE_NODE Parent
1703  )
1704 {
1705  HANDLE tokenHandle;
1706  PCLAIM_SECURITY_ATTRIBUTES_INFORMATION info;
1707  ULONG i;
1708  ULONG j;
1709 
1710  if (!NT_SUCCESS(TokenPageContext->OpenObject(
1711  &tokenHandle,
1712  TOKEN_QUERY,
1713  TokenPageContext->Context
1714  )))
1715  return FALSE;
1716 
1717  if (NT_SUCCESS(PhQueryTokenVariableSize(tokenHandle, DeviceClaims ? TokenDeviceClaimAttributes : TokenUserClaimAttributes, &info)))
1718  {
1719  for (i = 0; i < info->AttributeCount; i++)
1720  {
1721  PCLAIM_SECURITY_ATTRIBUTE_V1 attribute = &info->Attribute.pAttributeV1[i];
1722  PATTRIBUTE_NODE node;
1723  PPH_STRING temp;
1724 
1725  // Attribute
1726  node = PhpAddAttributeNode(&TokenPageContext->ClaimsTreeContext, Parent, PhCreateString(attribute->Name));
1727  // Type
1728  PhpAddAttributeNode(&TokenPageContext->ClaimsTreeContext, node,
1729  PhFormatString(L"Type: %s", PhGetSecurityAttributeTypeString(attribute->ValueType)));
1730  // Flags
1731  temp = PhGetSecurityAttributeFlagsString(attribute->Flags);
1732  PhpAddAttributeNode(&TokenPageContext->ClaimsTreeContext, node,
1733  PhFormatString(L"Flags: %s", temp->Buffer));
1734  PhDereferenceObject(temp);
1735 
1736  // Values
1737  for (j = 0; j < attribute->ValueCount; j++)
1738  {
1739  temp = PhFormatClaimSecurityAttributeValue(attribute, j);
1740  PhpAddAttributeNode(&TokenPageContext->ClaimsTreeContext, node,
1741  PhFormatString(L"Value %u: %s", j, temp->Buffer));
1742  PhDereferenceObject(temp);
1743  }
1744  }
1745 
1746  PhFree(info);
1747  }
1748 
1749  NtClose(tokenHandle);
1750 
1751  TreeNew_NodesStructured(tnHandle);
1752 
1753  return TRUE;
1754 }
1755 
1756 INT_PTR CALLBACK PhpTokenClaimsPageProc(
1757  _In_ HWND hwndDlg,
1758  _In_ UINT uMsg,
1759  _In_ WPARAM wParam,
1760  _In_ LPARAM lParam
1761  )
1762 {
1763  PTOKEN_PAGE_CONTEXT tokenPageContext;
1764  HWND tnHandle;
1765 
1766  tokenPageContext = PhpTokenPageHeader(hwndDlg, uMsg, wParam, lParam);
1767 
1768  if (!tokenPageContext)
1769  return FALSE;
1770 
1771  tnHandle = GetDlgItem(hwndDlg, IDC_LIST);
1772 
1773  switch (uMsg)
1774  {
1775  case WM_INITDIALOG:
1776  {
1777  PATTRIBUTE_NODE userNode;
1778  PATTRIBUTE_NODE deviceNode;
1779 
1780  PhpInitializeAttributeTreeContext(&tokenPageContext->ClaimsTreeContext, tnHandle);
1781 
1782  TreeNew_SetRedraw(tnHandle, FALSE);
1783 
1784  userNode = PhpAddAttributeNode(&tokenPageContext->ClaimsTreeContext, NULL, PhCreateString(L"User claims"));
1785  PhpAddTokenClaimAttributes(tokenPageContext, tnHandle, FALSE, userNode);
1786  deviceNode = PhpAddAttributeNode(&tokenPageContext->ClaimsTreeContext, NULL, PhCreateString(L"Device claims"));
1787  PhpAddTokenClaimAttributes(tokenPageContext, tnHandle, TRUE, deviceNode);
1788 
1789  if (userNode->Children->Count == 0)
1790  PhpAddAttributeNode(&tokenPageContext->ClaimsTreeContext, userNode, PhCreateString(L"(None)"));
1791  if (deviceNode->Children->Count == 0)
1792  PhpAddAttributeNode(&tokenPageContext->ClaimsTreeContext, deviceNode, PhCreateString(L"(None)"));
1793 
1794  TreeNew_NodesStructured(tnHandle);
1795  TreeNew_SetRedraw(tnHandle, TRUE);
1796  }
1797  break;
1798  case WM_DESTROY:
1799  {
1800  PhpDeleteAttributeTreeContext(&tokenPageContext->ClaimsTreeContext);
1801  }
1802  break;
1803  }
1804 
1805  return FALSE;
1806 }
1807 
1809  _In_ PTOKEN_PAGE_CONTEXT TokenPageContext,
1810  _In_ HWND tnHandle
1811  )
1812 {
1813  HANDLE tokenHandle;
1815  ULONG i;
1816  ULONG j;
1817 
1818  if (!NT_SUCCESS(TokenPageContext->OpenObject(
1819  &tokenHandle,
1820  TOKEN_QUERY,
1821  TokenPageContext->Context
1822  )))
1823  return FALSE;
1824 
1825  if (NT_SUCCESS(PhQueryTokenVariableSize(tokenHandle, TokenSecurityAttributes, &info)))
1826  {
1827  for (i = 0; i < info->AttributeCount; i++)
1828  {
1829  PTOKEN_SECURITY_ATTRIBUTE_V1 attribute = &info->Attribute.pAttributeV1[i];
1830  PATTRIBUTE_NODE node;
1831  PPH_STRING temp;
1832 
1833  // Attribute
1834  node = PhpAddAttributeNode(&TokenPageContext->AuthzTreeContext, NULL,
1835  PhCreateStringFromUnicodeString(&attribute->Name));
1836  // Type
1837  PhpAddAttributeNode(&TokenPageContext->AuthzTreeContext, node,
1838  PhFormatString(L"Type: %s", PhGetSecurityAttributeTypeString(attribute->ValueType)));
1839  // Flags
1840  temp = PhGetSecurityAttributeFlagsString(attribute->Flags);
1841  PhpAddAttributeNode(&TokenPageContext->AuthzTreeContext, node,
1842  PhFormatString(L"Flags: %s", temp->Buffer));
1843  PhDereferenceObject(temp);
1844 
1845  // Values
1846  for (j = 0; j < attribute->ValueCount; j++)
1847  {
1848  temp = PhFormatTokenSecurityAttributeValue(attribute, j);
1849  PhpAddAttributeNode(&TokenPageContext->AuthzTreeContext, node,
1850  PhFormatString(L"Value %u: %s", j, temp->Buffer));
1851  PhDereferenceObject(temp);
1852  }
1853  }
1854 
1855  PhFree(info);
1856  }
1857 
1858  NtClose(tokenHandle);
1859 
1860  TreeNew_NodesStructured(tnHandle);
1861 
1862  return TRUE;
1863 }
1864 
1866  _In_ HWND hwndDlg,
1867  _In_ UINT uMsg,
1868  _In_ WPARAM wParam,
1869  _In_ LPARAM lParam
1870  )
1871 {
1872  PTOKEN_PAGE_CONTEXT tokenPageContext;
1873  HWND tnHandle;
1874 
1875  tokenPageContext = PhpTokenPageHeader(hwndDlg, uMsg, wParam, lParam);
1876 
1877  if (!tokenPageContext)
1878  return FALSE;
1879 
1880  tnHandle = GetDlgItem(hwndDlg, IDC_LIST);
1881 
1882  switch (uMsg)
1883  {
1884  case WM_INITDIALOG:
1885  {
1886  PhpInitializeAttributeTreeContext(&tokenPageContext->AuthzTreeContext, tnHandle);
1887 
1888  TreeNew_SetRedraw(tnHandle, FALSE);
1889 
1890  PhpAddTokenAttributes(tokenPageContext, tnHandle);
1891 
1892  if (tokenPageContext->AuthzTreeContext.RootList->Count == 0)
1893  PhpAddAttributeNode(&tokenPageContext->AuthzTreeContext, NULL, PhCreateString(L"(None)"));
1894 
1895  TreeNew_NodesStructured(tnHandle);
1896  TreeNew_SetRedraw(tnHandle, TRUE);
1897  }
1898  break;
1899  case WM_DESTROY:
1900  {
1901  PhpDeleteAttributeTreeContext(&tokenPageContext->AuthzTreeContext);
1902  }
1903  break;
1904  }
1905 
1906  return FALSE;
1907 }