From 1bc6ec32f8c5520f5f36d0ea4271f45a809dddfe Mon Sep 17 00:00:00 2001 From: Igor Chudov Date: Fri, 13 Dec 2019 01:12:59 +0400 Subject: [PATCH] Functionality to create GPT object out of GPT cache directory --- gpoa/gpt/__init__.py | 5 + gpoa/gpt/gpt.py | 206 ++++++++++++++++++++++++++++++++++++++++++ gpoa/gpt/services.py | 0 gpoa/gpt/shortcuts.py | 80 ++++++++++++++++ 4 files changed, 291 insertions(+) create mode 100644 gpoa/gpt/__init__.py create mode 100644 gpoa/gpt/gpt.py create mode 100644 gpoa/gpt/services.py create mode 100644 gpoa/gpt/shortcuts.py diff --git a/gpoa/gpt/__init__.py b/gpoa/gpt/__init__.py new file mode 100644 index 0000000..a260074 --- /dev/null +++ b/gpoa/gpt/__init__.py @@ -0,0 +1,5 @@ +from .gpt import ( + gpt, + get_local_gpt +) + diff --git a/gpoa/gpt/gpt.py b/gpoa/gpt/gpt.py new file mode 100644 index 0000000..230537b --- /dev/null +++ b/gpoa/gpt/gpt.py @@ -0,0 +1,206 @@ +import logging +import os + +from samba.gp_parse.gp_pol import GPPolParser + +from storage import registry_factory +from .shortcuts import read_shortcuts +import util +import util.preg + +global __default_policy_path + +__default_policy_path = '/usr/share/local-policy/default' + +class gpt: + __default_policy_path = '/usr/share/local-policy/default' + __user_policy_mode_key = 'Software\\Policies\\Microsoft\\Windows\\System\\UserPolicyMode' + + def __init__(self, gpt_path, sid=None): + self.path = gpt_path + self.sid = sid + self.storage = registry_factory('registry') + self._scan_gpt() + + def _scan_gpt(self): + ''' + Collect the data from the specified GPT on file system (cached + by Samba). + ''' + self.guid = self.path.rpartition('/')[2] + self.name = '' + if 'default' == self.guid: + self.guid = 'Local Policy' + + self._machine_path = None + self._user_path = None + self._get_machine_user_dirs() + + logging.debug('Looking for machine part of GPT {}'.format(self.guid)) + self._find_machine() + logging.debug('Looking for user part of GPT {}'.format(self.guid)) + self._find_user() + + self._user_policy_mode = self.get_policy_mode() + + def set_name(self, name): + ''' + Set human-readable GPT name. + ''' + self.name = name + + def get_policy_mode(self): + ''' + Get UserPolicyMode parameter value in order to determine if it + is possible to work with user's part of GPT + ''' + upm = 0 + if self._machine_regpol: + keymap = util.preg.preg_keymap(self._machine_regpol) + upm = keymap.get(self.__user_policy_mode_key, 0) + + return upm + + def _get_machine_user_dirs(self): + ''' + Find full path to Machine and User parts of GPT. + ''' + entries = os.listdir(self.path) + for entry in entries: + full_entry_path = os.path.join(self.path, entry) + if os.path.isdir(full_entry_path): + if 'machine' == entry.lower(): + self._machine_path = full_entry_path + if 'user' == entry.lower(): + self._user_path = full_entry_path + + def _find_user(self): + self._user_regpol = self._find_regpol('user') + self._user_shortcuts = self._find_shortcuts('user') + + def _find_machine(self): + self._machine_regpol = self._find_regpol('machine') + self._machine_shortcuts = self._find_shortcuts('machine') + + def _find_regpol(self, part): + ''' + Find Registry.pol files. + ''' + search_path = self._machine_path + if 'user' == part: + search_path = self._user_path + if not search_path: + return None + + return find_file(search_path, 'registry.pol') + + def _find_shortcuts(self, part): + ''' + Find Shortcuts.xml files. + ''' + search_path = os.path.join(self._machine_path, 'Preferences', 'Shortcuts') + if 'user' == part: + search_path = os.path.join(self._user_path, 'Preferences', 'Shortcuts') + if not search_path: + return None + + return find_file(search_path, 'shortcuts.xml') + + def _merge_shortcut(self, sid, sc): + self.storage.add_shortcut(sid, sc) + + def merge(self, sid=None): + ''' + Merge machine and user (if sid provided) settings to storage. + ''' + # Merge machine settings to registry if possible + if self._machine_regpol: + logging.debug('Merging machine settings from {}'.format(self._machine_regpol)) + util.preg.merge_polfile(self._machine_regpol) + + # Merge user settings if UserPolicyMode set accordingly + # and user settings (for HKCU) are exist. + if sid: + if self._user_policy_mode in [None, '0', '1']: + if self._user_regpol: + logging.debug('Merging user settings from {} for {}'.format(self._user_regpol, sid)) + util.preg.merge_polfile(self._user_regpol, sid) + if self._machine_shortcuts: + logging.debug('Merging user settings for shortcuts') + for link in self._user_shortcuts: + self._merge_shortcut(sid, link) + + def __str__(self): + template = ''' +GUID: {} +Name: {} +For SID: {} + +Machine part: {} +Machine Registry.pol: {} +Machine Shortcuts.xml: {} + +User part: {} +User Registry.pol: {} +User Shortcuts.xml: {} + +UserPolicyMode: {} + +''' + result = template.format( + self.guid, + self.name, + self.sid, + + self._machine_path, + self._machine_regpol, + self._machine_shortcuts, + + self._user_path, + self._user_regpol, + self._user_shortcuts, + + self._user_policy_mode + ) + return result + +def find_file(search_path, name): + ''' + Attempt for case-insensitive file search in directory. + ''' + try: + file_list = os.listdir(search_path) + for entry in file_list: + file_path = os.path.join(search_path, entry) + if os.path.isfile(file_path) and name.lower() == entry.lower(): + return file_path + except Exception as exc: + logging.error(exc) + + return None + +def lp2gpt(): + ''' + Convert local-policy to full-featured GPT. + ''' + lppath = os.path.join(__default_policy_path, 'local.xml') + machinesettings = os.path.join(__default_policy_path, 'Machine') + + # Load settings from XML PolFile + polparser = GPPolParser() + polfile = util.preg.load_preg(lppath) + polparser.pol_file = polfile + + # Write PReg + os.makedirs(machinesettings, exist_ok=True) + polparser.write_binary(os.path.join(machinesettings, 'Registry.pol')) + +def get_local_gpt(sid): + ''' + Convert default policy to GPT and create object out of it. + ''' + lp2gpt() + local_policy = gpt(__default_policy_path, sid) + local_policy.set_name('Local Policy') + + return local_policy diff --git a/gpoa/gpt/services.py b/gpoa/gpt/services.py new file mode 100644 index 0000000..e69de29 diff --git a/gpoa/gpt/shortcuts.py b/gpoa/gpt/shortcuts.py new file mode 100644 index 0000000..1ce3ecf --- /dev/null +++ b/gpoa/gpt/shortcuts.py @@ -0,0 +1,80 @@ +import logging + +from xml.etree import ElementTree +from xdg.DesktopEntry import DesktopEntry + +def read_shortcuts(shortcuts_file): + ''' + Read shortcut objects from GPTs XML file + ''' + shortcuts = list() + xml_contents = ElementTree.parse(shortcuts_file) + xml_root = xml_contents.getroot() + + for link in xml_root: + props = link.find('Properties') + path = props.get('targetPath') + arguments = props.get('arguments') + sc = shortcut(path, arguments, link.get('name')) + sc.set_changed(link.get('changed')) + sc.set_clsid(link.get('clsid')) + sc.set_guid(link.get('uid')) + sc.set_usercontext(link.get('userContext', False)) + shortcuts.append(sc) + + return shortcuts + +def merge_shortcuts(username, sid): + ''' + + ''' + return None + +class shortcut: + def __init__(self, path, arguments, name=None): + self.path = path + self.arguments = arguments + self.name = name + self.changed = '' + self.is_in_user_context = self.set_usercontext() + + def __str__(self): + result = ''.format( + self.path, + self.arguments, + self.name + ) + return result + + def set_changed(self, change_date): + ''' + Set object change date + ''' + self.changed = change_date + + def set_clsid(self, clsid): + self.clsid = clsid + + def set_guid(self, uid): + self.guid = uid + + def set_usercontext(self, context=False): + ''' + Perform action in user context or not + ''' + self.is_in_user_context = context + + def desktop(self, file_path=None): + ''' + Returns desktop file object which may be written to disk. + ''' + self.desktop_file = DesktopEntry() + self.desktop_file.addGroup('Desktop Entry') + self.desktop_file.set('Type', 'Application') + self.desktop_file.set('Version', '1.0') + self.desktop_file.set('Terminal', 'false') + self.desktop_file.set('Exec', '{} {}'.format(self.path, self.arguments)) + self.desktop_file.set('Name', self.name) + #desktop_file.write(file_path) + + return self.desktop_file