# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# Mobius Forensic Toolkit
# Copyright (C) 2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019 Eduardo Aguiar
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
import pymobius.vfs
import pymobius.registry
import pymobius.registry.main
import pymobius.registry.installed_programs

# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief Scan installed operating systems
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
def scan (item):

  # get item VFS
  vfs = pymobius.vfs.get_item_vfs (item)
  if not vfs:
    raise Exception, "Datasource is not available"

  # scan VFS
  return [os_win (vfs, item)]

# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief OS Windows object
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
class os_win (object):

  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  # @brief initialize object
  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  def __init__ (self, vfs, item):
    self.__vfs = vfs
    self.__installed_programs = []
    self.__installed_programs_loaded = False
    self.__item = item

    # retrieve registry object
    ant = pymobius.registry.main.Ant (item)
    data = ant.get_data ()
    
    if not data:
      raise Exception, 'OS.Win has no registry'

    elif len (data) == 1:
      self.__registry = data[0]

    else:
      import mobius
      mobius.core.log ('OS.Win: item with %d registries' % len (data))
      self.__registry = data[0]

  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  # @brief get item
  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  def get_item (self):
    return self.__item

  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  # @brief get registry object
  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  def get_registry (self):
    return self.__registry

  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  # @brief get system folder path
  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  def get_folder (self, name):
    return pymobius.registry.get_system_folder (self.__registry, name)

  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  # @brief get installed programs
  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  def get_installed_programs (self):
    if not self.__installed_programs_loaded:
      self.__installed_programs = pymobius.registry.installed_programs.get (self.__registry)
      self.__installed_programs_loaded = True

    return self.__installed_programs

  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  # @brief get system profiles
  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  def get_profiles (self):

    # get profiles path
    profiles_path = self.get_folder ('PROFILES') or 'C:\\Users'
    profiles_path = profiles_path[3:].replace ('\\', '/')

    # retrieve profiles
    for root in self.__vfs:

      try:
        profile_folder = root.get_child_by_path (profiles_path)

        if profile_folder:
          for child in profile_folder.get_children ():
            if not child.is_reallocated and child.is_folder ():
              yield os_win_profile (self, child)

      except Exception, e:
        print 'Warning (OS.get_profiles):', e

# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief OS Windows profile object
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
class os_win_profile (object):

  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  # @brief initialize object
  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  def __init__ (self, operating_system, folder):
    self.__folder = folder
    self.__operating_system = operating_system
    self.__ntuser_dat = None
    self.__control_folders = {}
    self.folder = folder
    self.path = folder.path.replace ('/', '\\')
    self.username = folder.path.rsplit ('/', 1)[-1]
    self.is_deleted = folder.is_deleted

    # get NTUSER.DAT root key
    nt_path = folder.path + '/NTUSER.DAT'
    nt_path = nt_path.replace ('/', '\\').lower ()

    registry = operating_system.get_registry ()

    for f in registry.files:
      if f.role == 'NTUSER' and f.path.lower () == nt_path:
        self.__ntuser_dat = f.root_key

    # get user shell folders
    if self.__ntuser_dat:
      for value in self.__ntuser_dat.get_value_by_mask ('Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders\\*'):
        path = value.data.get_data_as_string ('utf-16')
        if path.startswith ('%USERPROFILE%\\'):
          self.__control_folders[value.name.lower ()] = path[14:].replace ('\\', '/')

    #for name, path in self.__control_folders.iteritems ():
    #  print name, '\t', path

  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  # @brief get AppData folder
  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  def get_appdata_folder (self, rpath):
    appdata = self.__control_folders.get ('appdata', 'AppData/Roaming')

    if rpath:
      appdata = appdata + '/' + rpath

    folder = None

    try:
      folder = self.__folder.get_child_by_path (appdata, False)
    except Exception, e:
      print 'Warning (OS.get_appdata_folder):', e
      folder = None

    return folder

  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  # @brief get AppDataLocal folder
  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  def get_appdata_local_folder (self, rpath):
    appdata = self.__control_folders.get ('local appdata', 'AppData/Local')

    if rpath:
      appdata = appdata + '/' + rpath

    folder = None

    try:
      folder = self.__folder.get_child_by_path (appdata, False)
    except Exception, e:
      print 'Warning (OS.get_appdata_local_folder):', e
      folder = None

    return folder

  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  # @brief get control folder
  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  def get_control_folder (self, folder_id, folder_default):
    rpath = self.__control_folders.get (folder_id, folder_default)
    folder = None

    try:
      folder = self.__folder.get_child_by_path (rpath, False)
    except Exception, e:
      print 'Warning (OS.get_control_folder):', e
      folder = None

    return folder
