| /* |
| * Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved. |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| * |
| * Security related functions for Windows platform (Set privileges such as |
| * SeDebug), as well as security helper functions. |
| */ |
| |
| #include <windows.h> |
| #include <Python.h> |
| |
| |
| /* |
| * Convert a process handle to a process token handle. |
| */ |
| HANDLE |
| psutil_token_from_handle(HANDLE hProcess) { |
| HANDLE hToken = NULL; |
| |
| if (! OpenProcessToken(hProcess, TOKEN_QUERY, &hToken)) |
| return PyErr_SetFromWindowsErr(0); |
| return hToken; |
| } |
| |
| |
| /* |
| * http://www.ddj.com/windows/184405986 |
| * |
| * There's a way to determine whether we're running under the Local System |
| * account. However (you guessed it), we have to call more Win32 functions to |
| * determine this. Backing up through the code listing, we need to make another |
| * call to GetTokenInformation, but instead of passing through the TOKEN_USER |
| * constant, we pass through the TOKEN_PRIVILEGES constant. This value returns |
| * an array of privileges that the account has in the environment. Iterating |
| * through the array, we call the function LookupPrivilegeName looking for the |
| * string “SeTcbPrivilege. If the function returns this string, then this |
| * account has Local System privileges |
| */ |
| int |
| psutil_has_system_privilege(HANDLE hProcess) { |
| DWORD i; |
| DWORD dwSize = 0; |
| DWORD dwRetval = 0; |
| TCHAR privName[256]; |
| DWORD dwNameSize = 256; |
| // PTOKEN_PRIVILEGES tp = NULL; |
| BYTE *pBuffer = NULL; |
| TOKEN_PRIVILEGES *tp = NULL; |
| HANDLE hToken = psutil_token_from_handle(hProcess); |
| |
| if (NULL == hToken) |
| return -1; |
| // call GetTokenInformation first to get the buffer size |
| if (! GetTokenInformation(hToken, TokenPrivileges, NULL, 0, &dwSize)) { |
| dwRetval = GetLastError(); |
| // if it failed for a reason other than the buffer, bail out |
| if (dwRetval != ERROR_INSUFFICIENT_BUFFER ) { |
| PyErr_SetFromWindowsErr(dwRetval); |
| return 0; |
| } |
| } |
| |
| // allocate buffer and call GetTokenInformation again |
| // tp = (PTOKEN_PRIVILEGES) GlobalAlloc(GPTR, dwSize); |
| pBuffer = (BYTE *) malloc(dwSize); |
| if (pBuffer == NULL) { |
| PyErr_NoMemory(); |
| return -1; |
| } |
| |
| if (! GetTokenInformation(hToken, TokenPrivileges, pBuffer, |
| dwSize, &dwSize)) |
| { |
| PyErr_SetFromWindowsErr(0); |
| free(pBuffer); |
| return -1; |
| } |
| |
| // convert the BYTE buffer to a TOKEN_PRIVILEGES struct pointer |
| tp = (TOKEN_PRIVILEGES *)pBuffer; |
| |
| // check all the privileges looking for SeTcbPrivilege |
| for (i = 0; i < tp->PrivilegeCount; i++) { |
| // reset the buffer contents and the buffer size |
| strcpy(privName, ""); |
| dwNameSize = sizeof(privName) / sizeof(TCHAR); |
| if (! LookupPrivilegeName(NULL, |
| &tp->Privileges[i].Luid, |
| (LPTSTR)privName, |
| &dwNameSize)) |
| { |
| PyErr_SetFromWindowsErr(0); |
| free(pBuffer); |
| return -1; |
| } |
| |
| // if we find the SeTcbPrivilege then it's a LocalSystem process |
| if (! lstrcmpi(privName, TEXT("SeTcbPrivilege"))) { |
| free(pBuffer); |
| return 1; |
| } |
| } |
| |
| free(pBuffer); |
| return 0; |
| } |
| |
| |
| BOOL |
| psutil_set_privilege(HANDLE hToken, LPCTSTR Privilege, BOOL bEnablePrivilege) |
| { |
| TOKEN_PRIVILEGES tp; |
| LUID luid; |
| TOKEN_PRIVILEGES tpPrevious; |
| DWORD cbPrevious = sizeof(TOKEN_PRIVILEGES); |
| |
| if (!LookupPrivilegeValue( NULL, Privilege, &luid )) return FALSE; |
| |
| // first pass. get current privilege setting |
| tp.PrivilegeCount = 1; |
| tp.Privileges[0].Luid = luid; |
| tp.Privileges[0].Attributes = 0; |
| |
| AdjustTokenPrivileges( |
| hToken, |
| FALSE, |
| &tp, |
| sizeof(TOKEN_PRIVILEGES), |
| &tpPrevious, |
| &cbPrevious |
| ); |
| |
| if (GetLastError() != ERROR_SUCCESS) return FALSE; |
| |
| // second pass. set privilege based on previous setting |
| tpPrevious.PrivilegeCount = 1; |
| tpPrevious.Privileges[0].Luid = luid; |
| |
| if (bEnablePrivilege) |
| tpPrevious.Privileges[0].Attributes |= (SE_PRIVILEGE_ENABLED); |
| else |
| tpPrevious.Privileges[0].Attributes ^= |
| (SE_PRIVILEGE_ENABLED & tpPrevious.Privileges[0].Attributes); |
| |
| AdjustTokenPrivileges( |
| hToken, |
| FALSE, |
| &tpPrevious, |
| cbPrevious, |
| NULL, |
| NULL |
| ); |
| |
| if (GetLastError() != ERROR_SUCCESS) return FALSE; |
| |
| return TRUE; |
| } |
| |
| |
| int |
| psutil_set_se_debug() |
| { |
| HANDLE hToken; |
| if (! OpenThreadToken(GetCurrentThread(), |
| TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, |
| FALSE, |
| &hToken) |
| ) { |
| if (GetLastError() == ERROR_NO_TOKEN) { |
| if (!ImpersonateSelf(SecurityImpersonation)) { |
| CloseHandle(hToken); |
| return 0; |
| } |
| if (!OpenThreadToken(GetCurrentThread(), |
| TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, |
| FALSE, |
| &hToken) |
| ) { |
| RevertToSelf(); |
| CloseHandle(hToken); |
| return 0; |
| } |
| } |
| } |
| |
| // enable SeDebugPrivilege (open any process) |
| if (! psutil_set_privilege(hToken, SE_DEBUG_NAME, TRUE)) { |
| RevertToSelf(); |
| CloseHandle(hToken); |
| return 0; |
| } |
| |
| RevertToSelf(); |
| CloseHandle(hToken); |
| return 1; |
| } |
| |
| |
| int |
| psutil_unset_se_debug() |
| { |
| HANDLE hToken; |
| if (! OpenThreadToken(GetCurrentThread(), |
| TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, |
| FALSE, |
| &hToken) |
| ) { |
| if (GetLastError() == ERROR_NO_TOKEN) { |
| if (! ImpersonateSelf(SecurityImpersonation)) |
| return 0; |
| if (!OpenThreadToken(GetCurrentThread(), |
| TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, |
| FALSE, |
| &hToken)) |
| { |
| return 0; |
| } |
| } |
| } |
| |
| // now disable SeDebug |
| if (! psutil_set_privilege(hToken, SE_DEBUG_NAME, FALSE)) |
| return 0; |
| |
| CloseHandle(hToken); |
| return 1; |
| } |