def openWindow(): ''' Attempts to open a window on the Winlogon desktop. This can also be used to just test opening a window on the Application desktop. NOTE: The Winlogon desktop part is not currently working with this example installed as an interactive service. It may be necessary instead to set this up as something started by a Winlogon Notification Package. ''' logging.basicConfig( level=logging.DEBUG, format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s', datefmt='%m-%d %H:%M', filename=r'C:\temp\myapp.log', filemode='w') logging.debug("Starting") cur_winsta = win32service.GetProcessWindowStation() logging.debug("Got process window station") cur_desktop = win32service.GetThreadDesktop(win32api.GetCurrentThreadId()) logging.debug("Got current desktop") try: new_winsta = win32service.OpenWindowStation( "winsta0", False, win32con.WINSTA_ACCESSCLIPBOARD | win32con.WINSTA_ACCESSGLOBALATOMS | win32con.WINSTA_CREATEDESKTOP | win32con.WINSTA_ENUMDESKTOPS | win32con.WINSTA_ENUMERATE | win32con.WINSTA_EXITWINDOWS | win32con.WINSTA_READATTRIBUTES | win32con.WINSTA_READSCREEN | win32con.WINSTA_WRITEATTRIBUTES) new_winsta.SetProcessWindowStation() desktop = win32service.OpenDesktop( "Winlogon", 0, False, win32con.DESKTOP_CREATEMENU | win32con.DESKTOP_CREATEWINDOW | win32con.DESKTOP_ENUMERATE | win32con.DESKTOP_HOOKCONTROL | win32con.DESKTOP_JOURNALPLAYBACK | win32con.DESKTOP_JOURNALRECORD | win32con.DESKTOP_READOBJECTS | win32con.DESKTOP_SWITCHDESKTOP | win32con.DESKTOP_WRITEOBJECTS) desktop.SetThreadDesktop() logging.debug("Running calculator") os.system("calc") logging.debug("Done") except: logging.debug("Caught exception:") logging.debug(sys.exc_info()[0]) # Print the exception type logging.debug(sys.exc_info()[1]) # Print the exception info cur_winsta.SetProcessWindowStation() cur_desktop.SetThreadDesktop() cur_desktop.CloseDesktop() cur_winsta.CloseWindowStation() if new_winsta is not None: new_winsta.CloseWindowStation() if desktop is not None: desktop.CloseDesktop()
def icon_wndproc(hwnd, msg, wp, lp): """Window proc for the tray icons""" if lp == win32con.WM_LBUTTONDOWN: ## popup menu won't disappear if you don't do this win32gui.SetForegroundWindow(hwnd) curr_desktop = win32service.OpenInputDesktop(0, True, win32con.MAXIMUM_ALLOWED) curr_desktop_name = win32service.GetUserObjectInformation( curr_desktop, win32con.UOI_NAME ) winsta = win32service.GetProcessWindowStation() desktops = winsta.EnumDesktops() m = win32gui.CreatePopupMenu() desktop_cnt = len(desktops) ## *don't* create an item 0 for d in range(1, desktop_cnt + 1): mf_flags = win32con.MF_STRING ## if you switch to winlogon yourself, there's nothing there and you're stuck if desktops[d - 1].lower() in ("winlogon", "disconnect"): mf_flags = mf_flags | win32con.MF_GRAYED | win32con.MF_DISABLED if desktops[d - 1] == curr_desktop_name: mf_flags = mf_flags | win32con.MF_CHECKED win32gui.AppendMenu(m, mf_flags, d, desktops[d - 1]) win32gui.AppendMenu(m, win32con.MF_STRING, desktop_cnt + 1, "Create new ...") win32gui.AppendMenu(m, win32con.MF_STRING, desktop_cnt + 2, "Exit") x, y = win32gui.GetCursorPos() d = win32gui.TrackPopupMenu( m, win32con.TPM_LEFTBUTTON | win32con.TPM_RETURNCMD | win32con.TPM_NONOTIFY, x, y, 0, hwnd, None, ) win32gui.PumpWaitingMessages() win32gui.DestroyMenu(m) if d == desktop_cnt + 1: ## Create new get_new_desktop_name(hwnd) elif d == desktop_cnt + 2: ## Exit win32gui.PostQuitMessage(0) win32gui.Shell_NotifyIcon(win32gui.NIM_DELETE, window_info[hwnd]) del window_info[hwnd] origin_desktop.SwitchDesktop() elif d > 0: hdesk = win32service.OpenDesktop( desktops[d - 1], 0, 0, win32con.MAXIMUM_ALLOWED ) hdesk.SwitchDesktop() return 0 else: return win32gui.DefWindowProc(hwnd, msg, wp, lp)
def _CreateAltDesktop(window_station, name: str): """Creates an alternate desktop. Args: window_station: Handle to window station. name: Name of the desktop. Returns: A handle to the alternate desktop. """ current_desktop = win32service.GetThreadDesktop( win32api.GetCurrentThreadId()) security_attributes = _GetSecurityAttributes(current_desktop) current_station = win32service.GetProcessWindowStation() window_station.SetProcessWindowStation() desktop = win32service.CreateDesktop( name, 0, (DESKTOP_CREATEWINDOW | DESKTOP_READOBJECTS | ntsecuritycon.READ_CONTROL | ntsecuritycon.WRITE_DAC | ntsecuritycon.WRITE_OWNER), security_attributes) current_station.SetProcessWindowStation() return desktop
def _CreateWindowStation(name: Optional[str], access: int): """Creates a window station. Args: name: Name of the window station. access: The type of access the returned handle has to the window station. Returns: A handle to the created window station. """ current_station = win32service.GetProcessWindowStation() security_attributes = _GetSecurityAttributes(current_station) # The try/except originates from the Chromium sandbox code. # They try to create the window station with various level of privilege. try: return win32service.CreateWindowStation( name, 0, access | win32file.GENERIC_READ | WINSTA_CREATEDESKTOP, security_attributes) except pywintypes.error as e: if e.winerror != winerror.ERROR_ACCESS_DENIED: raise return win32service.CreateWindowStation( name, 0, access | WINSTA_READATTRIBUTES | WINSTA_CREATEDESKTOP, security_attributes)
def __init__(self, userHandle, userSID, userName, domain, forceSidAdd=False): """ Constructs a Windows-specific user perspective used to access the event manager. @pre userHandle is a valid PyHANDLE object. @param userHandle Handle to the user's authentication. @param userSID The SID for the user represented by this avatar. @param userName The name of the user represented by this avatar. @param domain The domain for the user. @param forceSidAdd Causes the given ID to be added to the window station and desktop ACLs even if it is already present. Use with caution! """ assert (userHandle is not None) UserPerspective.__init__(self) self.mUserHandle = userHandle self.mUserSID = userSID self.mWinsta = None self.mDesktop = None self.mAddedHandles = [] self.mLogger = logging.getLogger('daemon.WindowsAvatar') # Save the current window station for later. cur_winsta = win32service.GetProcessWindowStation() # Open window station winsta0 and make it the window station for this # process. winsta_flags = win32con.READ_CONTROL | win32con.WRITE_DAC new_winsta = win32service.OpenWindowStation("winsta0", False, winsta_flags) new_winsta.SetProcessWindowStation() # Get a handle to the default desktop so that we can change its access # control list. desktop_flags = win32con.READ_CONTROL | \ win32con.WRITE_DAC | \ win32con.DESKTOP_WRITEOBJECTS | \ win32con.DESKTOP_READOBJECTS desktop = win32service.OpenDesktop("default", 0, False, desktop_flags) # If user_sid is not already among the SIDs who have access to # new_winsta, then add it now. It will be removed in logout(). if forceSidAdd or not windesktop.handleHasSID(new_winsta, self.mUserSID): windesktop.addUserToWindowStation(new_winsta, self.mUserSID) self.mAddedHandles.append(new_winsta) self.mLogger.debug("Added SID to new_winsta") # If user_sid is not already among the SIDs who have access to desktop, # then add it now. It will be removed in logout(). if forceSidAdd or not windesktop.handleHasSID(desktop, self.mUserSID): windesktop.addUserToDesktop(desktop, self.mUserSID) self.mAddedHandles.append(desktop) self.mLogger.debug("Added SID to desktop") cur_winsta.SetProcessWindowStation() self.mWinsta = new_winsta self.mDesktop = desktop # (username, domain, acct_type) = \ # win32security.LookupAccountSid(dc_name, self.mUserSID) # self.mUserName = username # self.mDomain = domain self.mUserName = userName self.mDomain = domain # Get name of domain controller. try: dc_name = win32net.NetGetDCName() except: dc_name = None user_info_4 = win32net.NetUserGetInfo(dc_name, self.mUserName, 4) profilepath = user_info_4['profile'] # LoadUserProfile apparently doesn't like an empty string if not profilepath: profilepath = None try: # Leave Flags in since 2.3 still chokes on some types of optional # keyword args self.mUserProfile = win32profile.LoadUserProfile( self.mUserHandle, { 'UserName': self.mUserName, 'Flags': 0, 'ProfilePath': profilepath }) self.mLogger.debug("self.mUserProfile = %s" % str(self.mUserProfile)) self.mLogger.info("Loaded profile %s" % profilepath) except pywintypes.error, error: self.mLogger.error("Error loading profile: %s" % error)
def runCommandAsOtherUser(): ''' Runs a command (C:\Python24\python.exe C:\read_files.py) as another user (as determined by the global variables USERNAME, DOMAIN, and PASSWORD). The python.exe process will be owned by USERNAME and have access to that user's files. Hence, for this test to be useful, the value in LOG_FILE should be a file to which only DOMAIN\USERNAME has write access, and TEST_DIR should be a directory from which only DOMAIN\USERNAME can read. ''' logging.basicConfig( level=logging.DEBUG, format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s', datefmt='%m-%d %H:%M', filename=r'C:\temp\myapp2.log', filemode='w') logging.debug("Starting") try: cur_winsta = win32service.GetProcessWindowStation() logging.debug("Got process window station") new_winsta = win32service.OpenWindowStation( "winsta0", False, win32con.READ_CONTROL | win32con.WRITE_DAC) new_winsta.SetProcessWindowStation() desktop = win32service.OpenDesktop( "default", 0, False, win32con.READ_CONTROL | win32con.WRITE_DAC | win32con.DESKTOP_WRITEOBJECTS | win32con.DESKTOP_READOBJECTS) handle = win32security.LogonUser(USERNAME, DOMAIN, PASSWORD, win32con.LOGON32_LOGON_INTERACTIVE, win32con.LOGON32_PROVIDER_DEFAULT) tic = win32security.GetTokenInformation(handle, ntsecuritycon.TokenGroups) user_sid = None for sid, flags in tic: if flags & win32con.SE_GROUP_LOGON_ID: user_sid = sid break if user_sid is None: raise Exception('Failed to determine logon ID') winsta_ace_indices = addUserToWindowStation(new_winsta, user_sid) desktop_ace_indices = addUserToDesktop(desktop, user_sid) si = win32process.STARTUPINFO() # Copied from process.py. I don't know what these should be in general. si.dwFlags = win32process.STARTF_USESHOWWINDOW ^ win32con.STARTF_USESTDHANDLES si.wShowWindow = win32con.SW_NORMAL si.lpDesktop = r"winsta0\default" create_flags = win32process.CREATE_NEW_CONSOLE win32security.ImpersonateLoggedOnUser(handle) # Hard-coded paths are bad except that this is just a proof-of-concept # service. # This command validates that the process has the access rights of the # logged on (impersonated) user. # logging.debug('LOG_FILE = ' + LOG_FILE) # logging.debug('TEST_DIR = ' + TEST_DIR) # (process, thread, proc_id, thread_id) = \ # win32process.CreateProcessAsUser(handle, None, # r"C:\Python24\python.exe C:\read_files.py %s %s" % (LOG_FILE, TEST_DIR), # None, None, 1, create_flags, None, # None, si) # This command validates that the process is allowed to open a window # on the current desktop. (process, thread, proc_id, thread_id) = \ win32process.CreateProcessAsUser(handle, None, r"C:\windows\system32\calc.exe", None, None, 1, create_flags, None, None, si) cur_winsta.SetProcessWindowStation() win32security.RevertToSelf() handle.Close() logging.debug("Waiting for completion") win32event.WaitForSingleObject(process, win32event.INFINITE) logging.debug("Done!") logging.debug("Removing added ACEs from new_winsta") removeACEs(new_winsta, winsta_ace_indices) logging.debug("Removing added ACEs from desktop") removeACEs(desktop, desktop_ace_indices) new_winsta.CloseWindowStation() desktop.CloseDesktop() except TypeError, ex: logging.debug(ex)