def GetUncPathOf(filePath): buf = create_string_buffer(1024) dwBufSize = DWORD(1024) err = WNetGetUniversalName(filePath, UNIVERSAL_NAME_INFO_LEVEL, buf, byref(dwBufSize)) if err == 0: return cast(buf, POINTER(UNIVERSAL_NAME_INFO)).contents.lpUniversalName elif err == ERROR_NOT_CONNECTED: pass else: print "GetUncPathOf Error:", err, FormatError(err) return filePath
def ReadPipeMessage(hPipe): data = "" fSuccess = 0 chBuf = create_string_buffer(BUFSIZE) cbRead = DWORD(0) while not fSuccess: # repeat loop if ERROR_MORE_DATA fSuccess = ReadFile(hPipe, chBuf, BUFSIZE, byref(cbRead), None) if fSuccess == 1: data += chBuf.value break elif GetLastError() != ERROR_MORE_DATA: break data += chBuf.value return loads(data)
def ReadPipeMessage(hPipe): data = "" fSuccess = 0 chBuf = create_string_buffer(BUFSIZE) cbRead = DWORD(0) while not fSuccess: # repeat loop if ERROR_MORE_DATA fSuccess = ReadFile( hPipe, chBuf, BUFSIZE, byref(cbRead), None ) if fSuccess == 1: data += chBuf.value break elif GetLastError() != ERROR_MORE_DATA: break data += chBuf.value return loads(data)
def ExecAsAdministrator(scriptPath, funcName, *args, **kwargs): """ Execute some Python code in a process with elevated privileges. This call will only return, after the subprocess has terminated. The sys.stdout and sys.stderr streams of the subprocess will be directed to the calling process through a named pipe. All parameters for the function to call and its return value must be picklable. :param scriptPath: Path to the Python file to load. :param funcName: Name of the function to call inside the Python file :param args: Positional parameters for the function :param kwargs: Keyword parameters for the function :returns: The return value of the function """ Msg("creating named pipe") hPipe = CreateNamedPipe( szPipename, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, BUFSIZE, BUFSIZE, 0, None ) if (hPipe == INVALID_HANDLE_VALUE): raise Exception("Error in creating Named Pipe") overlapped = OVERLAPPED() overlapped.hEvent = CreateEvent(None, 1, 0, None) try: Msg("calling ConnectNamedPipe") ConnectNamedPipe(hPipe, byref(overlapped)) executable = abspath(join( dirname(__file__.decode(sys.getfilesystemencoding())), "..", "..", "EventGhost.exe" )) Msg("starting subprocess") hProcess = RunAsAdministrator( executable, "-execscript", __file__.decode(sys.getfilesystemencoding()), "-client", szPipename, ) Msg("waiting for subprocess to connect") pHandles = (HANDLE * 2)(overlapped.hEvent, hProcess) ret = WaitForMultipleObjects(2, pHandles, 0, 20000) if ret == WAIT_OBJECT_0: # connect event Msg("got connect event") elif ret == WAIT_OBJECT_0 + 1: raise Exception("Unexpected end of subprocess.") elif ret == WAIT_TIMEOUT: raise Exception("Timeout in waiting for subprocess.") else: raise Exception("Unknown return value") # if fConnected == 0 and GetLastError() == ERROR_PIPE_CONNECTED: # fConnected = 1 # if fConnected != 1: # raise Exception("Could not connect to the Named Pipe") # Msg("sending startup message") WritePipeMessage( hPipe, MESSAGE_ARGS, (scriptPath, funcName, args, kwargs) ) chBuf = create_string_buffer(BUFSIZE) cbRead = DWORD(0) while True: fSuccess = ReadFile(hPipe, chBuf, BUFSIZE, byref(cbRead), None) if ((fSuccess == 1) or (cbRead.value != 0)): code, data = loads(chBuf.value) if code == MESSAGE_STDERR: sys.stderr.write(data) elif code == MESSAGE_STDOUT: sys.stdout.write(data) elif code == MESSAGE_RESULT: result = data break elif code == MESSAGE_EXCEPTION: break else: raise Exception("Unknown message type %r" % code) FlushFileBuffers(hPipe) DisconnectNamedPipe(hPipe) finally: CloseHandle(hPipe) CloseHandle(overlapped.hEvent) if code == MESSAGE_EXCEPTION: raise Exception("Child process raised an exception\n" + data) return result
def ExecAs(scriptPath, asAdministrator, funcName, *args, **kwargs): pipeName = "\\\\.\\pipe\\" + str(GUID.create_new()) Msg("creating named pipe") hPipe = CreateNamedPipe( pipeName, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, BUFSIZE, BUFSIZE, 0, None ) if hPipe == INVALID_HANDLE_VALUE: raise Exception("Error in creating Named Pipe") overlapped = OVERLAPPED() overlapped.hEvent = CreateEvent(None, 1, 0, None) try: Msg("calling ConnectNamedPipe") ConnectNamedPipe(hPipe, byref(overlapped)) localPath = dirname(__file__.decode('mbcs')) Msg("starting subprocess") hProcess = RunAs( abspath(join(localPath, "..", "..", "EventGhost.exe")), asAdministrator, "-execfile", GetUncPathOf(join(localPath, "PipedProcessClient.py")), pipeName, str(eg.debugLevel) ) Msg("waiting for subprocess to connect") pHandles = (HANDLE * 2)(overlapped.hEvent, hProcess) ret = WaitForMultipleObjects(2, pHandles, 0, 25000) if ret == WAIT_OBJECT_0: # connect event Msg("got connect event") elif ret == WAIT_OBJECT_0 + 1: raise Exception("Unexpected end of subprocess.") elif ret == WAIT_TIMEOUT: raise Exception("Timeout in waiting for subprocess.") else: raise Exception("Unknown return value") Msg("sending startup message") WritePipeMessage( hPipe, MESSAGE_ARGS, (GetUncPathOf(scriptPath), funcName, args, kwargs) ) chBuf = create_string_buffer(BUFSIZE) cbRead = DWORD(0) while True: fSuccess = ReadFile(hPipe, chBuf, BUFSIZE, byref(cbRead), None) if ((fSuccess == 1) or (cbRead.value != 0)): code, data = loads(chBuf.value) if code == MESSAGE_STDERR: sys.stderr.write(data) elif code == MESSAGE_STDOUT: sys.stdout.write(data) elif code == MESSAGE_RESULT: result = data break elif code == MESSAGE_EXCEPTION: break else: raise Exception("Unknown message type %r" % code) FlushFileBuffers(hPipe) DisconnectNamedPipe(hPipe) finally: CloseHandle(hPipe) CloseHandle(overlapped.hEvent) if code == MESSAGE_EXCEPTION: raise Exception("Child process raised an exception\n" + data) return result
def IsAdmin(): """ Find out if the user (the owner of the current process) is a member of the administrators group on the local computer (not on the domain!). """ # First we must open a handle to the access token for this thread. hThread = HANDLE() if not OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, 0, byref(hThread)): err = GetLastError() if err == ERROR_NO_TOKEN: # If the thread does not have an access token, we'll examine the # access token associated with the process. if not OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, byref(hThread)): raise WinError() else: raise WinError(err) # Then we must query the size of the group information associated with # the token. Note that we expect a FALSE result from GetTokenInformation # because we've given it a NULL buffer. On exit cbTokenGroups will tell # the size of the group information. cbTokenGroups = DWORD() if GetTokenInformation(hThread, TokenGroups, None, 0, byref(cbTokenGroups)): raise WinError() # Here we verify that GetTokenInformation failed for lack of a large # enough buffer. err = GetLastError() if err != ERROR_INSUFFICIENT_BUFFER: raise WinError(err) # Now we allocate a buffer for the group information. ptg = create_string_buffer(cbTokenGroups.value) # Now we ask for the group information again. # This may fail if an administrator has added this account to an additional # group between our first call to GetTokenInformation and this one. if not GetTokenInformation(hThread, TokenGroups, ptg, cbTokenGroups, byref(cbTokenGroups)): raise WinError() # Now we must create a System Identifier for the Admin group. systemSidAuthority = SID_IDENTIFIER_AUTHORITY() systemSidAuthority.Value[5] = SECURITY_NT_AUTHORITY psidAdmin = PSID() if not AllocateAndInitializeSid( byref(systemSidAuthority), 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, byref(psidAdmin)): raise WinError() # Finally we'll iterate through the list of groups for this access # token looking for a match against the SID we created above. ptg = cast(ptg, POINTER(TOKEN_GROUPS)) groups = cast(ptg.contents.Groups, POINTER(SID_AND_ATTRIBUTES)) isAdmin = False for i in range(ptg.contents.GroupCount): if EqualSid(groups[i].Sid, psidAdmin.value): isAdmin = True break # Before we exit we must explicitly deallocate the SID we created. FreeSid(psidAdmin) return isAdmin
def IsAdmin(): """ Find out if the user (the owner of the current process) is a member of the administrators group on the local computer (not on the domain!). """ # First we must open a handle to the access token for this thread. hThread = HANDLE() if not OpenThreadToken( GetCurrentThread(), TOKEN_QUERY, 0 , byref(hThread) ): err = GetLastError() if err == ERROR_NO_TOKEN: # If the thread does not have an access token, we'll examine the # access token associated with the process. if not OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, byref(hThread) ): raise WinError() else: raise WinError(err) # Then we must query the size of the group information associated with # the token. Note that we expect a FALSE result from GetTokenInformation # because we've given it a NULL buffer. On exit cbTokenGroups will tell # the size of the group information. cbTokenGroups = DWORD() if GetTokenInformation( hThread, TokenGroups, None, 0, byref(cbTokenGroups) ): raise WinError() # Here we verify that GetTokenInformation failed for lack of a large # enough buffer. err = GetLastError() if err != ERROR_INSUFFICIENT_BUFFER: raise WinError(err) # Now we allocate a buffer for the group information. ptg = create_string_buffer(cbTokenGroups.value) # Now we ask for the group information again. # This may fail if an administrator has added this account to an additional # group between our first call to GetTokenInformation and this one. if not GetTokenInformation( hThread, TokenGroups, ptg, cbTokenGroups, byref(cbTokenGroups) ): raise WinError() # Now we must create a System Identifier for the Admin group. systemSidAuthority = SID_IDENTIFIER_AUTHORITY() systemSidAuthority.Value[5] = SECURITY_NT_AUTHORITY psidAdmin = PSID() if not AllocateAndInitializeSid( byref(systemSidAuthority), 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, byref(psidAdmin) ): raise WinError() # Finally we'll iterate through the list of groups for this access # token looking for a match against the SID we created above. ptg = cast(ptg, POINTER(TOKEN_GROUPS)) groups = cast(ptg.contents.Groups, POINTER(SID_AND_ATTRIBUTES)) isAdmin = False for i in range(ptg.contents.GroupCount): if EqualSid(groups[i].Sid, psidAdmin.value): isAdmin = True break # Before we exit we must explicitly deallocate the SID we created. FreeSid(psidAdmin) return isAdmin