1 /*
2  * Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved.
3  * Use of this source code is governed by a BSD-style license that can be
4  * found in the LICENSE file.
5  *
6  * Security related functions for Windows platform (Set privileges such as
7  * SE DEBUG).
8  */
9 
10 #include <windows.h>
11 #include <Python.h>
12 
13 #include "../../_psutil_common.h"
14 
15 
16 static BOOL
psutil_set_privilege(HANDLE hToken,LPCTSTR Privilege,BOOL bEnablePrivilege)17 psutil_set_privilege(HANDLE hToken, LPCTSTR Privilege, BOOL bEnablePrivilege) {
18     TOKEN_PRIVILEGES tp;
19     LUID luid;
20     TOKEN_PRIVILEGES tpPrevious;
21     DWORD cbPrevious = sizeof(TOKEN_PRIVILEGES);
22 
23     if (! LookupPrivilegeValue(NULL, Privilege, &luid)) {
24         PyErr_SetFromOSErrnoWithSyscall("LookupPrivilegeValue");
25         return 1;
26     }
27 
28     // first pass.  get current privilege setting
29     tp.PrivilegeCount = 1;
30     tp.Privileges[0].Luid = luid;
31     tp.Privileges[0].Attributes = 0;
32 
33     if (! AdjustTokenPrivileges(
34             hToken,
35             FALSE,
36             &tp,
37             sizeof(TOKEN_PRIVILEGES),
38             &tpPrevious,
39             &cbPrevious))
40     {
41         PyErr_SetFromOSErrnoWithSyscall("AdjustTokenPrivileges");
42         return 1;
43     }
44 
45     // Second pass. Set privilege based on previous setting.
46     tpPrevious.PrivilegeCount = 1;
47     tpPrevious.Privileges[0].Luid = luid;
48 
49     if (bEnablePrivilege)
50         tpPrevious.Privileges[0].Attributes |= (SE_PRIVILEGE_ENABLED);
51     else
52         tpPrevious.Privileges[0].Attributes ^=
53             (SE_PRIVILEGE_ENABLED & tpPrevious.Privileges[0].Attributes);
54 
55     if (! AdjustTokenPrivileges(
56             hToken,
57             FALSE,
58             &tpPrevious,
59             cbPrevious,
60             NULL,
61             NULL))
62     {
63         PyErr_SetFromOSErrnoWithSyscall("AdjustTokenPrivileges");
64         return 1;
65     }
66 
67     return 0;
68 }
69 
70 
71 static HANDLE
psutil_get_thisproc_token()72 psutil_get_thisproc_token() {
73     HANDLE hToken = NULL;
74     HANDLE me = GetCurrentProcess();
75 
76     if (! OpenProcessToken(
77             me, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
78     {
79         if (GetLastError() == ERROR_NO_TOKEN)
80         {
81             if (! ImpersonateSelf(SecurityImpersonation)) {
82                 PyErr_SetFromOSErrnoWithSyscall("ImpersonateSelf");
83                 return NULL;
84             }
85             if (! OpenProcessToken(
86                     me, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
87             {
88                 PyErr_SetFromOSErrnoWithSyscall("OpenProcessToken");
89                 return NULL;
90             }
91         }
92         else {
93             PyErr_SetFromOSErrnoWithSyscall("OpenProcessToken");
94             return NULL;
95         }
96     }
97 
98     return hToken;
99 }
100 
101 
102 static void
psutil_print_err()103 psutil_print_err() {
104     char *msg = "psutil module couldn't set SE DEBUG mode for this process; " \
105         "please file an issue against psutil bug tracker";
106     psutil_debug(msg);
107     if (GetLastError() != ERROR_ACCESS_DENIED)
108         PyErr_WarnEx(PyExc_RuntimeWarning, msg, 1);
109     PyErr_Clear();
110 }
111 
112 
113 /*
114  * Set this process in SE DEBUG mode so that we have more chances of
115  * querying processes owned by other users, including many owned by
116  * Administrator and Local System.
117  * https://docs.microsoft.com/windows-hardware/drivers/debugger/debug-privilege
118  * This is executed on module import and we don't crash on error.
119  */
120 int
psutil_set_se_debug()121 psutil_set_se_debug() {
122     HANDLE hToken;
123 
124     if ((hToken = psutil_get_thisproc_token()) == NULL) {
125         // "return 1;" to get an exception
126         psutil_print_err();
127         return 0;
128     }
129 
130     if (psutil_set_privilege(hToken, SE_DEBUG_NAME, TRUE) != 0) {
131         // "return 1;" to get an exception
132         psutil_print_err();
133     }
134 
135     RevertToSelf();
136     CloseHandle(hToken);
137     return 0;
138 }
139