# Copyright 2004-2005 SigmaSRC, Inc. All Rights Reserved.
"""Windows specific portion of the runtime library."""


import os
import time
import winreg as _winreg # XXX Maybe get rid of this and use win32api for registry access
import win32api
#import win32con
import win32security
import ntsecuritycon
#import sys
from win32com.client import GetObject
from win32com.client import Dispatch
#import win32file
from sigma.util.fuelset import FuelSet
import tempfile
import pythoncom
import pywintypes
import re
import logging
from sigma.util.netstatinfo import NetstatInfo
import datetime
from sigma.gather import gather_winantivirus
from sigma.gather import gather_winantisw

logger = logging.getLogger("winrtlib")

DEBUG_OUTPUT = False  # Set to True if you want debug output
INF1 = "[version]\r\n"
INF2 = 'signature="$CHICAGO$"\r\n'
INF3 = "DriverVer=07/01/2001,5.1.2600.0\r\n"

ERRMSG_BOTH = """\
Agent may be unable to get complete user log-in history because
Audit Logon Events is not set to success and failure. To set it,
open the Administrative tools in Control Panel, go to
Local Security Settings/Audit Policy/Audit Logon Events, check
Success and Failure and click OK.\n
"""

ERRMSG_SUCCESS = """\
Agent may be unable to get complete user log-in history because
Audit Logon Events is not set to success. To set it,
open the Administrative tools in Control Panel, go to
Local Security Settings/Audit Policy/Audit Logon Events, check
Success and click OK.\n
"""

ERRMSG_FAILURE = """\
Agent may be unable to get complete user log-in history because
Audit Logon Events is not set to failure. To set it,
open the Administrative tools in Control Panel, go to
Local Security Settings/Audit Policy/Audit Logon Events, check
Failure and click OK.\n
"""

# Logon type
logon_map = {
    "2": "Interactive",
    "3": "Network",
    "4": "Batch",
    "5": "Service",
    "7": "Unlock",
    "8": "Network Clear Text",
    "9": "New Credentials",
    "10": "Remote Interactive",
    "11": "Cached Interactive",
    "12": "Cached Remote Interactive",
    "13": "Cached Unlock",
    }

# Logon events
event_map = {
    528: "Successful Logon",
    529: "Unknown user name or bad password",
    530: "Account logon time violation",
    531: "Account currently disabled",
    532: "User account has expired",
    533: "User not allowed at this computer",
    534: "Logon type denied on this machine",
    535: "Account password has expired",
    536: "NetLogon component is not active",
    537: "Logon failed for unknown reasons",
    539: "Account locked out",
    540: "Successful Network Logon",
    }

FORMAT = "%-17s %-33s %-20s %-20s %-20s %-20s %-20s\n"

# table mapping for events
eventmap = {
    1: "Success",
    2: "Failure",
    3: "Success and Failure",
    4: "None",
    }

# Table mapping for privileges
privmap = {
    "SeNetworkLogonRight": "SeNetworkLogonRight",
    "SeTcbPrivilege": win32security.SE_TCB_NAME,
    "SeMachineAccountPrivilege": win32security.SE_MACHINE_ACCOUNT_NAME,
    "SeIncreaseQuotaPrivilege": win32security.SE_INCREASE_QUOTA_NAME,
    "SeRemoteInteractiveLogonRight": "SeRemoteInteractiveLogonRight",
    "SeBackupPrivilege": win32security.SE_BACKUP_NAME,
    "SeChangeNotifyPrivilege": win32security.SE_CHANGE_NOTIFY_NAME,
    "SeSystemtimePrivilege": win32security.SE_SYSTEMTIME_NAME,
    "SeCreatePagefilePrivilege": win32security.SE_CREATE_PAGEFILE_NAME,
    "SeCreateTokenPrivilege": win32security.SE_CREATE_TOKEN_NAME,
    "SeCreatePermanentPrivilege": win32security.SE_CREATE_PERMANENT_NAME,
    "SeDebugPrivilege": win32security.SE_DEBUG_NAME,
    "SeDenyBatchLogonRight": "SeDenyBatchLogonRight",
    "SeDenyServiceLogonRight": "SeDenyServiceLogonRight",
    "SeDenyRemoteInteractiveLogonRight": "SeDenyRemoteInteractiveLogonRight",
    "SeEnableDelegationPrivilege": win32security.SE_ENABLE_DELEGATION_NAME,
    "SeRemoteShutdownPrivilege": "SeRemoteShutdownPrivilege",
    "SeAuditPrivilege": win32security.SE_AUDIT_NAME,
    "SeIncreaseBasePriorityPrivilege": win32security.SE_INC_BASE_PRIORITY_NAME,
    "SeLoadDriverPrivilege": win32security.SE_LOAD_DRIVER_NAME,
    "SeLockMemoryPrivilege": win32security.SE_LOCK_MEMORY_NAME,
    "SeBatchLogonRight": "SeBatchLogonRight",
    "SeServiceLogonRight": "SeServiceLogonRight",
    "SeManageVolumePrivilege": win32security.SE_MANAGE_VOLUME_NAME,
    "SeInteractiveLogonRight": "SeInteractiveLogonRight",
    "SeSecurityPrivilege": win32security.SE_SECURITY_NAME,
    "SeSystemEnvironmentPrivilege": win32security.SE_SYSTEM_ENVIRONMENT_NAME,
    "SeProfileSingleProcessPrivilege": win32security.SE_PROF_SINGLE_PROCESS_NAME,
    "SeSystemProfilePrivilege": win32security.SE_SYSTEM_PROFILE_NAME,
    "SeUndockPrivilege": win32security.SE_UNDOCK_NAME,
    "SeAssignPrimaryTokenPrivilege": win32security.SE_ASSIGNPRIMARYTOKEN_NAME,
    "SeRestorePrivilege": win32security.SE_RESTORE_NAME,
    "SeShutdownPrivilege": win32security.SE_SHUTDOWN_NAME,
    "SeSyncAgentPrivilege": win32security.SE_SYNC_AGENT_NAME,
    "SeTakeOwnershipPrivilege": win32security.SE_TAKE_OWNERSHIP_NAME,
    "SeDenyNetworkLogonRight": "SeDenyNetworkLogonRight",
    "SeDenyInteractiveLogonRight": "SeDenyInteractiveLogonRight",
    }

# Table mapping root HKEY abbreviations
hkeymap = {
    "HKLM": _winreg.HKEY_LOCAL_MACHINE,
    "HKCU": _winreg.HKEY_CURRENT_USER,
    "HKCR": _winreg.HKEY_CLASSES_ROOT,
    "HKU":  _winreg.HKEY_USERS,
    "HKCC": _winreg.HKEY_CURRENT_CONFIG,
    # Aliases used by secedit
    "machine": _winreg.HKEY_LOCAL_MACHINE,
    "users": _winreg.HKEY_USERS,
    "classes_root": _winreg.HKEY_CLASSES_ROOT,
    }

class WMIObject(object):

    def __init__(self, item):
        self.item = item

    def getPropertyValue(self, name):
        try:
            return "%s" % (self.item.Properties_(name).Value)
        except Exception as details:
            logger.exception("Exception in getPropertyValue")
            self.error(0, "COM exception: %s", details)


class AVCollector(object):

    def __init__(self):
        self.avset = FuelSet()

    def table(self, tablename, columnlist):
        return self.avset


class ASWCollector(object):

    def __init__(self):
        self.aswset = FuelSet()

    def table(self, tablename, columnlist):
        return self.aswset


class stringPair(object):

    def __init__(self, str1, str2):
        self.str1 = str1
        self.str2 = str2

    def __eq__(self, other):
        return isinstance(other, stringPair) and self.str1 == other.str1 and self.str2 == other.str2

    def __ne__(self, other):
        return not self.__eq__(other)

    def __hash__(self):
        return hash((self.str1, self.str2))

# Class to represent an NT ACE (Access Control Entry)
class ACE(object):

    def __init__(self, ace=None):
        if ace is not None:
            self.__dict__.update(ace.__dict__)

    def __repr__(self):
        return "ACE" + repr(self.__dict__)

    def __eq__(self, other):
        if not isinstance(other, ACE):
            return False
        return self.__dict__ == other.__dict__

    def __ne__(self, other):
        return not self.__eq__(other)

    def __str__(self):
        auth_rid = self.auth, self.rid
        parts = [
            invacetypemap.get(self.acetype, str(self.acetype)),
            mapaceflags(self.aceflags),
            maprights(self.rights),
            "", # objguid
            "", # inhobjguid
            invsidmap.get(auth_rid, "%d.%d" % auth_rid)
            ]
        return "(" + ";".join(parts) + ")"


def generic_to_file_rights(rights):
    newrights = 0
    subtract = 0
    if (rights & 0x10000000) == 0x10000000:   # GENERIC_ALL
        newrights |= 0x001f01ff                # FILE_ALL_ACCESS
        subtract |= 0x10000000
    if (rights & 0x80000000) == 0x80000000:   # GENERIC_READ
        newrights |= 0x00120089                # FILE_GENERIC_READ
        subtract |= 0x80000000
    if (rights & 0x40000000) == 0x40000000:   # GENERIC_WRITE
        newrights |= 0x00120116                # FILE_GENERIC_WRITE
        subtract |= 0x40000000
    if (rights & 0x20000000) == 0x20000000:   # GENERIC_EXECUTE
        newrights |= 0x001200a0                 # FILE_GENERIC_EXECUTE
        subtract |= 0x20000000

    remainingrights = rights & ~subtract
    return (newrights | remainingrights)

def generic_to_key_rights(rights):
    newrights = 0
    subtract = 0
    if (rights & 0x10000000) == 0x10000000: # GENERIC_ALL
        newrights |= 0x000F003F             #KEY_ALL_ACCESS
        subtract |= 0x10000000
    if (rights & 0x001FFFFF) == 0x001FFFFF: # GENERIC_ALL
        newrights |= 0x000F003F             #KEY_ALL_ACCESS
        subtract |= 0x001FFFFF
    if (rights & 0x80000000) == 0x80000000: # GENERIC_READ
        newrights |= 0x00020019            # KEY_GENERIC_READ
        subtract |= 0x80000000
    if (rights & 0x40000000) == 0x40000000: # GENERIC_WRITE
        newrights |= 0x00020006            # KEY_GENERIC_WRITE
        subtract |= 0x40000000
    if (rights & 0x20000000) == 0x20000000: # GENERIC_EXECUTE
        newrights |= 0x00020019            # KEY_GENERIC_EXECUTE
        subtract |= 0x20000000
    remainingrights = rights & ~subtract
    return (newrights | remainingrights)

def mergeaces(aces):
    # Returns a copy of a list with duplicates merged
    # It merges aces like (A;CI;KA;;;BA) and (A;;KA;;;BA)
    output = []
    for ace in aces:
        if ace not in output:
            found = False
            for a in output:
                if a.rid == ace.rid and a.auth == ace.auth and a.acetype == ace.acetype and a.rights == ace.rights:
                    # they can be merged
                    a.aceflags = a.aceflags | ace.aceflags
                    found = True
            if not found:
                output.append(ace)
    return output


# Helper to compare two lists of ACEs
def aceseq(aces1, aces2, cflags, isAFile):
    # aces1 = list of actual aces
    # aces2 = list of required aces
    # cflags - control flags for actual file/folder
    # isAFile - True for files, False for Folders and registry entries

    # A permission like (A;OICI;FA;;;BA) can also appear as
    # (A;;FA;;;BA)(A;OICIIO;FA;;;BA) in a container.
    # Sometimes the permissions are repeated: (A;;FA;;;BA)(A;;FA;;;BA)
    # so the actual aces may be more but still match with the required aces

    aces1 = rmdups(aces1)
    aces2 = rmdups(aces2)
    aces1 = mergeaces(aces1)
    aces2 = mergeaces(aces2)

    matches = 0
    if isAFile:
        for ace2 in aces2:
            if ace2 not in aces1:
                return False
            else:
                matches += 1
    else:
        for ace2 in aces2:
            if ace2 not in aces1:
                if (ace2.aceflags & 0x08):
                    return False
                else:
                    save_aceflags = ace2.aceflags
                    try:
                        ace2.aceflags |= 0x08 # IO flag
                        if ace2 not in aces1:
                            return False
                        else:
                            matches += 1
                        """
                        removed following block because now we are merging the aces first
                        ace2.aceflags = 0
                        if ace2 not in aces1:
                            return False
                        else:
                            matches += 1
                        """
                    finally:
                        ace2.aceflags = save_aceflags
            else:
                matches += 1
    if len(aces1) != matches:
        return False
    return True

def rmdups(aces):
    # Returns a copy of a list with duplicates removed
    output = []
    for ace in aces:
        if ace not in output:
            output.append(ace)
    return output

# Helper to invert a dict
def invert(d):
    i = {}
    for k, v in d.items():
        i[v] = k
    return i

# Table mapping ACE type names to numeric values
acetypemap = {
    "A": ntsecuritycon.ACCESS_ALLOWED_ACE_TYPE,
    "D": ntsecuritycon.ACCESS_DENIED_ACE_TYPE,
    #"OA": ntsecuritycon.ACCESS_ALLOWED_OBJECT_ACE_TYPE,
    #"OD": ntsecuritycon.ACCESS_DENIED_OBJECT_ACE_TYPE,
    "AU": ntsecuritycon.SYSTEM_AUDIT_ACE_TYPE,
    "AL": ntsecuritycon.SYSTEM_ALARM_ACE_TYPE,
    #"OU": ntsecuritycon.SYSTEM_AUDIT_OBJECT_ACE_TYPE,
    #"OL": ntsecuritycon.SYSTEM_ALARM_OBJECT_ACE_TYPE,
    }

# Its inverse
invacetypemap = invert(acetypemap)

# Table mapping ACE flag names to numeric values
aceflagmap = {
    "OI": ntsecuritycon.OBJECT_INHERIT_ACE,
    "CI": ntsecuritycon.CONTAINER_INHERIT_ACE,
    "NP": ntsecuritycon.NO_PROPAGATE_INHERIT_ACE,
    "IO": ntsecuritycon.INHERIT_ONLY_ACE,
    "ID": 16, # INHERITED_ACE
    "SA": ntsecuritycon.SUCCESSFUL_ACCESS_ACE_FLAG,
    "FA": ntsecuritycon.FAILED_ACCESS_ACE_FLAG,
    }

# Its inverse
invaceflagmap = invert(aceflagmap)

# Helper function to map numeric ACE flags to strings
def mapaceflags(flags):
    s = ""
    for i in range(8):
        flag = 1<<i
        if flags & flag:
            s += invaceflagmap.get(flag, str(i))
    return s

# Registry rights (not found in ntsecuritycon) from win32.h
SYNCHRONIZE =            (0x00100000)
KEY_QUERY_VALUE =        (0x0001)
KEY_SET_VALUE =          (0x0002)
KEY_CREATE_SUB_KEY =     (0x0004)
KEY_ENUMERATE_SUB_KEYS = (0x0008)
KEY_NOTIFY =             (0x0010)
KEY_CREATE_LINK =        (0x0020)

KEY_READ =        ((ntsecuritycon.STANDARD_RIGHTS_READ       |
                                  KEY_QUERY_VALUE            |
                                  KEY_ENUMERATE_SUB_KEYS     |
                                  KEY_NOTIFY)
                                  &
                                 (~SYNCHRONIZE))


KEY_WRITE =       ((ntsecuritycon.STANDARD_RIGHTS_WRITE      |
                                  KEY_SET_VALUE              |
                                  KEY_CREATE_SUB_KEY)
                                  &
                                 (~SYNCHRONIZE))

KEY_EXECUTE =            ((KEY_READ)
                                  &
                                 (~SYNCHRONIZE))

KEY_ALL_ACCESS =  ((ntsecuritycon.STANDARD_RIGHTS_ALL        |
                                  KEY_QUERY_VALUE            |
                                  KEY_SET_VALUE              |
                                  KEY_CREATE_SUB_KEY         |
                                  KEY_ENUMERATE_SUB_KEYS     |
                                  KEY_NOTIFY                 |
                                  KEY_CREATE_LINK)
                                  &
                                 (~SYNCHRONIZE))


# Table mapping rights names to numeric values
rightsmap = {
    "GA": 0x10000000 & 0xffffffff,
    "GR": 0x80000000 & 0xffffffff,
    "GW": 0x40000000 & 0xffffffff,
    "GX": 0x20000000 & 0xffffffff,

    "RC": 0x00020000 & 0xffffffff,
    "SD": 0x00010000 & 0xffffffff,
    "WD": 0x00040000 & 0xffffffff,
    "WO": 0x00080000 & 0xffffffff,

    # XXX skipped directory service object access rights for now

    "FA": 0x001f01ff,
    "FR": 0x00120089,
    "FW": 0x00120116,
    "FX": 0x001200a0,

    "KA": KEY_ALL_ACCESS,
    "KR": KEY_READ,
    "KW": KEY_WRITE,
    # values for KX and KR are same
    # TODO: may be we need to find a better way of dealing with this
    "KR": KEY_EXECUTE,

    "RP": 0x00000010,
    "WP": 0x00000020,
    "CC": 0x00000001,
    "DC": 0x00000002,
    "LC": 0x00000004,
    "SW": 0x00000008,
    "LO": 0x00000080,
    "DT": 0x00000040,
    "CR": 0x00000100,
    }

invrightsmap = invert(rightsmap)

# Helper function to map numeric rights to a string
def maprights(rights):
    s = invrightsmap.get(rights)
    if s is not None:
        return s
    s = ""
    rights = rights & 0xffffffff
    for i in range(32):
        bit = 1<<i
        if rights & bit:
            if bit in invrightsmap:
                s += invrightsmap[bit]
            else:
                return "0x%x" % (rights & 0xffffffff)
    return s

# Table mapping well-known SID names to (authority, RID) pairs
sidmap = {
    # XXX "Pretty sure" that the authority is 5 everywhere...
    "AO": (5, 0x224),
    "RU": (5, 0x22A),
    "AN": (5, 0x7),
    "AU": (5, 0xB),
    "BA": (5, 0x220),
    "BG": (5, 0x222),
    "BO": (5, 0x227),
    "BU": (5, 0x221),
    "CA": (5, 0x205),
    "CG": (3, 0x1),
    "CO": (3, 0x0),
    "DA": (5, 0x200),
    "DC": (5, 0x203),
    "DD": (5, 0x204),
    "DG": (5, 0x202),
    "DU": (5, 0x201),
    "EA": (5, 0x207),
    "ED": (5, 0x9),
    "WD": (1, 0x0),
    "PA": (5, 0x208),
    "IU": (5, 0x4),
    "LA": (5, 0x1F4),
    "LG": (5, 0x1F5),
    "LS": (5, 0x13),
    "SY": (5, 0x12),
    "NU": (5, 0x2),
    "NO": (5, 0x22C),
    "NS": (5, 0x14),
    "PO": (5, 0x226),
    "PS": (5, 0xA),
    "PU": (5, 0x223),
    "RS": (5, 0x229),
    "RD": (5, 0x22B),
    "RE": (5, 0x228),
    "RC": (5, 0xC),
    "SA": (5, 0x206),
    "SO": (5, 0x225),
    "SU": (5, 0x6),
    }

invsidmap = invert(sidmap)

# Dict (used as set) of well-known rids, for fast lookup
wellknownrids = {}
for auth, rid in sidmap.values():
    wellknownrids[rid] = True
del auth, rid

# Helper functions for permission parsing
# These raise ValueError for parse errors

def parseperms(perms):
    if not perms.startswith("D:"):
        raise ValueError("Permission string %r doesn't start with 'D:'" % perms)
    i = perms.find("(")
    if i < 0: # No ACEs found
        cflags = perms[2:]
    else:
        cflags = perms[2:i]
    aces = []
    while i > 0:
        j = perms.find(")", i+1)
        if j <= i:
            raise ValueError("Unmatched parenthesis in %r" % perms)
        aces.append(parseace(perms[i:j+1]))
        i = perms.find("(", j+1)
    return cflags, aces

def parseace(ace):
    if not (ace.startswith("(") and ace.endswith(")")):
        raise ValueError("ACE string %r not parenthesized" % ace)
    acetype, aceflags, rights, objguid, inhobjguid, acctsid = \
        ace[1:-1].split(";")
    if objguid != "":
        raise ValueError("Object guid %r not supported" % objguid)
    if inhobjguid != "":
        raise ValueError("Inherited object guid %r not supported" %
                         inhobjguid)
    ace = ACE()
    if acetype not in acetypemap:
        raise ValueError("ACE type %r not recognized" % acetype)
    ace.acetype = acetypemap[acetype]
    ace.aceflags = 0
    for i in range(0, len(aceflags), 2):
        aceflag = aceflags[i:i+2]
        if aceflag not in aceflagmap:
            raise ValueError("ACE flag %r not recognized" % aceflag)
        ace.aceflags |= aceflagmap[aceflag]
    ace.rights = 0

    # sometimes rights are in hex
    if rights.lower().startswith("0x"):
        ace.rights = int(rights, 0)
    else:
        for i in range(0, len(rights), 2):
            right = rights[i:i+2]
            if right in rightsmap:
                ace.rights |= rightsmap[right]
            else:
                ace.rights = int(rights, 0)
                break
    if acctsid not in sidmap:
        raise ValueError("SID %r not recognized" % acctsid)
    ace.auth, ace.rid = sidmap[acctsid]
    return ace

# Helper function to break apart a security descriptor
def getsd(sd):
    # Returns a triple (cflags, aces, hasDacl) where cflags is a string
    # representing symbolic control flags, aces is a list of ACE objects,
    # and hasDacl is a bool indicating whether a DACL was present (even if
    # empty)
    controlFlag, revNo = sd.GetSecurityDescriptorControl()
    cflags = ""
    if controlFlag & 0x1000:
        cflags += "P"
    if controlFlag & 0x0400:
        cflags += "AI"
    if controlFlag & 0x0100:
        cflags += "AR"
    dacl = sd.GetSecurityDescriptorDacl()
    aces = []
    hasDacl = False
    if dacl is not None:
        hasDacl = True
        naces = dacl.GetAceCount()
        for i in range(naces):
            a = ACE()
            try:
                (a.acetype, a.aceflags), rights, sid = dacl.GetAce(i)
            except NotImplementedError:
                # pywin32 can't unpack callback/conditional ACE types (9/10/11,
                # e.g. ACCESS_ALLOWED_CALLBACK_ACE) on some modern Windows DACLs.
                # Don't silently drop the ACE: an unparsed grant/deny could let an
                # ACL compare as compliant when it actually carries extra access.
                # Inject an unmatchable sentinel ACE instead, so aceseq() can never
                # satisfy len(actual) == matches and the permission check fails
                # closed (reported as a mismatch) rather than a false pass.
                a.acetype = -1
                a.aceflags = 0
                a.rights = 0
                a.auth = -1
                a.rid = -1
                aces.append(a)
                continue
            if rights < 0:
                rights += 0x100000000
            a.rights = rights
            a.auth = sid.GetSidIdentifierAuthority()[5]
            nsa = sid.GetSubAuthorityCount()
            sa = sid.GetSubAuthority(nsa-1)
            if sa < 0:
                sa += 0x100000000
            a.rid = sa
            aces.append(a)
    return cflags, aces, hasDacl

# class for parsed gpresult output
class GPResult(object):

    def __init__(self, lines):
        self.lines = lines
        self.current_line = 0

        self.rsop = {}
        self.user_gpo = {}
        self.user_security_groups = []
        self.computer_gpo = {}
        self.computer_security_groups = []

        self.pattern_secgroup = re.compile("<Name .*>(.*)</Name>")
        self.pattern_gpo_q1_name = re.compile("<q1:Name>(.*)</q1:Name>")
        self.pattern_gpo_q1_value = re.compile("<q1:SettingNumber>(.*)</q1:SettingNumber>")
        self.pattern_gpo_q1_boolean = re.compile("<q1:SettingBoolean>(.*)</q1:SettingBoolean>")
        self.pattern_gpo_q1_system_access_policy_name = re.compile("<q1:SystemAccessPolicyName>(.*)</q1:SystemAccessPolicyName>")

        while True:
            line = self.get_line()
            if line is None:
                break
            # print "1-->" + line

            if line.find("UserResults") > 0:

                while True:
                    line = self.get_line()
                    # print "2-->" + line

                    if line.startswith("</UserResults"):
                        break

                    elif line.startswith("<SecurityGroup"):
                        self.get_security_group(self.user_security_groups)

            elif line.startswith("<ComputerResults"):

                while True:
                    line = self.get_line()
                    # print "3-->" + line

                    if line.startswith("</ComputerResults"):
                        return

                    elif line.startswith("<SecurityGroup"):
                        self.get_security_group(self.computer_security_groups)

                    elif line.startswith("<ExtensionData"):
                        self.get_security_extdata(self.computer_gpo)
                        print("##############")

            elif line.startswith("</Rsop"):
                return



    def get_security_extdata(self, map):

        while True:
            line = self.get_line()
            # print "4-->" + line

            if line.startswith("<Extension ") and line.endswith(" />"):
                print("!!!  self ending")
                pass

            elif line.startswith("</ExtensionData>"):
                print("XXXXXXXXXXXXXXXXXXXX")
                break

            elif line.startswith("<Extension "):
                while True:
                    line = self.get_line()
                    # print "5-->" + line

                    if line.startswith("</Extension>"):
                        break

                    elif line.startswith("<q1:") > 0:
                        name = "unknown"
                        value = "unknown"

                        while True:
                            line = self.get_line()
                            print("5-->" + line)

                            if line.startswith("</q1:"):
                                self.computer_gpo[name] = value
                                print(self.computer_gpo)
                                print("---------------------------------")
                                break

                            # skipped GPO element, which contains the domain name

                            elif line.find("q1:Name") > 0:
                                name = self.pattern_gpo_q1_name.findall(line)[0]

                            elif line.find("q1:SystemAccessPolicyName") > 0:
                                name = self.pattern_gpo_q1_system_access_policy_name.findall(line)[0]

                            elif line.find("q1:SettingNumber") > 0:
                                value = self.pattern_gpo_q1_value.findall(line)[0]

                            elif line.find("q1:SettingBoolean") > 0:
                                value = self.pattern_gpo_q1_boolean.findall(line)[0]

    def get_security_group(self, group):
        line = self.get_line()  # skip the SID
        line = self.get_line()  # contains the security group name
        self.get_line()  # closing xml tag

        group.extend(self.pattern_secgroup.findall(line))

    def get_line(self):
        if self.current_line >= len(self.lines):
            return None
        line = self.lines[self.current_line].strip()
        self.current_line += 1
        # print line
        return line

# Mix-in class for Host (see rtlib.py)
class WinMixin(object):

    # Helper method for Windows registry access
    def winregraw(self, key, name):
        i = key.find("\\")
        if i < 0:
            return None
        hkeyname = key[:i]
        key = key[i+1:]
        hkey = hkeymap.get(hkeyname)
        if hkey is None:
            return None
        try:
            x = _winreg.ConnectRegistry(None, hkey)
            try:
                y = _winreg.OpenKey(x, key)
                try:
                    return _winreg.QueryValueEx(y, name)
                finally:
                    _winreg.CloseKey(y)
            finally:
                _winreg.CloseKey(x)
        except WindowsError:
            return None

    def _setwinregraw(self, key, name, type, value):
        fullkey = "%s\\%s" % (key, name)
        i = key.find("\\")
        if i < 0:
            return -1
        hkeyname = key[:i]
        key = key[i+1:]
        hkey = hkeymap.get(hkeyname)
        if hkey is None:
            return -1
        try:
            hRoot = _winreg.ConnectRegistry(None, hkey)
            before = after = None
            before_tuple = after_tuple = None

            try:
                hKey = _winreg.OpenKey(hRoot, key, 0, _winreg.KEY_ALL_ACCESS)
            except WindowsError as err:
                try:
                    hKey = _winreg.CreateKey(hRoot, key)
                    hKey = _winreg.OpenKey(hRoot, key, 0, _winreg.KEY_ALL_ACCESS)
                except:
                    _winreg.CloseKey(hRoot)
                    return -1
            try:
                before_tuple = _winreg.QueryValueEx(hKey, name)
                before = str(before_tuple)
                if value == None:
                    _winreg.DeleteValue(hKey, name)
            except WindowsError as err:
                pass
            try:
                if value != None:
                    if type == _winreg.REG_DWORD:
                        _winreg.SetValueEx(hKey, name, 0, type, int(value)) # what happens to 0xffffffff?
                    elif type == _winreg.REG_BINARY:
                        _winreg.SetValueEx(hKey, name, 0, type, chr(value))
                    else:
                        _winreg.SetValueEx(hKey, name, 0, type, value)
                after_tuple = _winreg.QueryValueEx(hKey, name)
                after = str(after_tuple)
            finally:
                _winreg.CloseKey(hKey)
                _winreg.CloseKey(hRoot)
                if before_tuple and after_tuple:
                    if type == _winreg.REG_DWORD or type == _winreg.REG_BINARY:
                        usermsg = "Modified from %r to %r" % (before_tuple[0], after_tuple[0])
                    else:
                        usermsg = "Modified from '%s' to '%s'" % (before_tuple[0], after_tuple[0])
                else:
                    usermsg = "Modified"
                self.logaction("Registry", fullkey, before, after, usermsg)
                return 0
        except WindowsError:
            return -1

    # Public methods for Windows registry access

    def winregint(self, key, name):
        z = self.winregraw(key, name)
        if z is not None:
            if z[1] != _winreg.REG_BINARY and z[1] != _winreg.REG_DWORD:return None
            if z[1] == _winreg.REG_BINARY:
                if z[0] is None:
                    return None
                elif len(z[0]) == 1:
                    return ord(z[0])
                else:
                    return None
            try:
                z = int(z[0])
            except ValueError:
                z = None
        return z

    def winregstr(self, key, name):
        z = self.winregraw(key, name)
        if z is not None:
            if z[1] != _winreg.REG_SZ and z[1] != _winreg.REG_EXPAND_SZ and z[1] != _winreg.REG_MULTI_SZ:return None
            z = str(z[0])
        return z

    def setwinregint(self, key, name, value):
        if self.enforce:
            return self._setwinregraw(key, name, _winreg.REG_DWORD, value)

    def setwinregbin(self, key, name, value):
        if self.enforce:
            return self._setwinregraw(key, name, _winreg.REG_BINARY, value)

    def setwinregstr(self, key, name, value):
        if self.enforce:
            return self._setwinregraw(key, name, _winreg.REG_SZ, value)


    # Public methods for permission checking
    def winlikefileperms(self, filename, flag, perms):
        # expand the orginal filename
        exfilename = filename
        i = filename.find("%")
        if i >= 0:
             j = filename.find("%", i+1)
             if j > i:
                 key = filename[i+1: j]
                 env = os.getenv(key)
                 if env is not None:
                     exfilename = filename[:i] + env + filename[j+1:]
        path, name = os.path.split(exfilename)
        filelist = os.listdir(path)
        for afile in filelist:
            if afile.lower().startswith(name.lower()):
                fullpath = os.path.join(path, afile)
                self.winfileperms(fullpath, flag, perms)

    def winfileperms(self, filename, flag, perms):
        if flag not in (0, 1, 2):
            raise ValueError("flag %r ought to be 0, 1 or 2" % flag)
        #if flag == 1:
        #    return # do nothing (used for configuration only)
        entry = '"%s",%d,"%s"' % (filename, flag, perms)
        req_cflags, req_aces = parseperms(perms)
        self.errorcount = 0
        # expand the orginal filename
        exfilename = filename
        i = filename.find("%")
        if i >= 0:
             j = filename.find("%", i+1)
             if j > i:
                 key = filename[i+1: j]
                 env = os.getenv(key)
                 if env is not None:
                     exfilename = filename[:i] + env + filename[j+1:]

        t0 = time.time()

        # check if it is a file, folder or if it does not exist
        if os.path.isfile(exfilename):
            isAFile = True
        elif os.path.isdir(exfilename):
            isAFile = False
        else:
            self.leave(0, "Not available: %r", exfilename)
            if DEBUG_OUTPUT:
                t1 = time.time()
                print("%.3f seconds" % (t1-t0))
                print("%r mismatches are found (file not available)" % self.errorcount)
        if isAFile:
            self._winfileperms(exfilename, flag, req_cflags, req_aces, isAFile, False, self.enforce, entry)
        elif flag == 2:     # recurse thru the folders
            for dirname, directories, files in os.walk(exfilename):
                if dirname == exfilename:
                    stop = self._winfileperms(dirname, flag, req_cflags, req_aces, False, False, self.enforce, entry)
                else:
                    stop = self._winfileperms(dirname, flag, req_cflags, req_aces, False, True, self.enforce, entry)
                if stop:
                    directories[:] = [] # Kill recursion by making it empty
                for aFile in files:
                    fullname = os.path.join(dirname, aFile)
                    self._winfileperms(fullname, flag, req_cflags, req_aces, True, True, self.enforce, entry)
        else:
            self._winfileperms(exfilename, flag, req_cflags, req_aces, isAFile, False, self.enforce, entry)
        if DEBUG_OUTPUT:
            t1 = time.time()
            print("%.3f seconds" % (t1-t0))
            print("%r mismatches are found" % self.errorcount)

    def _winfileperms(self, filename, flag, req_cflags, req_aces_org, isAFile, nested, enforce, entry):
        if flag == 1:
            if enforce:
                self.config_through_secedit("[File Security]", entry, "FILESTORE")
                #usermsg = "Enforced ignore flag"
                #self.logaction("File permission", filename, "ignore", "ignore", usermsg)
            return False

        stop, match, before = self._getfileperms(filename, flag, req_cflags, req_aces_org, isAFile, nested, enforce, entry)
        if stop:
            return stop
        if not match:
            self.errorcount += 1
            self.violation(0, "Permissions mismatch for %s", filename)
            if self.enforce:
                self.config_through_secedit("[File Security]", entry, "FILESTORE")
                stop, match, after = self._getfileperms(filename, flag, req_cflags, req_aces_org, isAFile, nested, enforce, entry)
                usermsg = "Modified from %r to %r" % (before, after)
                self.logaction("File permission", filename, before, after, usermsg)
        return stop

    def _getfileperms(self, filename, flag, req_cflags, req_aces_org, isAFile, nested, enforce, entry):
        try:
            sd = win32security.GetNamedSecurityInfo(filename,
                win32security.SE_FILE_OBJECT,
                win32security.DACL_SECURITY_INFORMATION)
            # The following didn't quite give the same results:
            # sd = win32security.GetFileSecurity(filename,
            #             win32security.DACL_SECURITY_INFORMATION)
        except pywintypes.error as err:
            self.errorcount += 1
            self.error(
                0,
                "File/folder exception: %r (%s)", filename, err)
            # stop recursion for this container
            #return (True, False, "Error")
        except WindowsError as err:
            self.errorcount += 1
            self.error(
                0,
                "File/folder exception: %r (%r)", filename, err)
            # stop recursion for this container
            #return (True, False, "Error")
        cflags, aces, hasDacl = getsd(sd)

        p = "".join(map(str, aces))
        before = '"%s",%d,"D:%s%s"' % (filename, flag, cflags, p)
##        q = "".join(map(str, req_aces))
##        print "File %r" % filename
##        print "Actual ACES"
##        print "%r%r" % (cflags, p)
##        print "Required ACES"
##        print "%r%r" % (req_cflags, q)
##        print "nested %r" % nested

        # if DACL does not exist for nested folders/files, it is a match
        if nested and not hasDacl:
            return (False, True, before)

        # if all aces at nested level have 'ID' (Inherited) set, it's a match
        if nested:
            total = 0
            idcount = 0
            for ace1 in aces:
                total += 1
                if ace1.aceflags & 0x10:
                    idcount += 1

            if ((idcount == total) and (total > 0)):
                return (False, True, before)

        # get rid of all the aces with ID flag;
        # make copies of all relevant ACEs so we can mutate them in place
        if cflags == "AI":
            aces = [ACE(ace) for ace in aces if not ace.aceflags & 0x10]
        else:
            aces = map(ACE, aces) # Make a copy of all ACEs

        # ignore aces with IO (inherit only) flag set for files
        if isAFile:
            req_aces = [ACE(ace) for ace in req_aces_org if not ace.aceflags & 0x08]
        else:
            req_aces = req_aces_org

        # ignore ace_flags (inheritance flags) for files
        if isAFile:
            for ace in aces:
                ace.aceflags = 0
            for ace in req_aces:
                ace.aceflags = 0

        # convert generic rights to specific rights on actual aces
        for ace in aces:
            ace.rights = generic_to_file_rights(ace.rights)

            # if it is not a well known rid, make it AUthenticated user
            if ace.rid not in wellknownrids:
                ace.rid = 0xB

        # convert generic rights to specific rights on required aces
        for ace in req_aces:
            ace.rights = generic_to_file_rights(ace.rights)

        # compare permissions
        if not aceseq(aces, req_aces, cflags, isAFile):
            return (False, False, before)

        # compare DACL flags
        ok = False
        if req_cflags == "PAR":
            if not nested:
                if cflags == "PAI" or cflags == "PAR" or cflags == "P":
                    ok = True
            elif cflags == "PAR":
                ok = True
        elif req_cflags == "PAI":
            if not nested:
                if cflags == "PAI" or cflags == "PAR" or cflags == "P":
                    ok = True
            elif cflags == "PAI":
                ok = True
        elif req_cflags == "P":
            if not nested:
                if cflags == "PAI" or cflags == "PAR" or cflags == "P":
                    ok = True
            elif cflags == "P":
                ok = True
        elif req_cflags == "AR" or req_cflags == "AI":
            if cflags == "AI" or cflags == "AR":
                ok = True
        elif req_cflags == "":
            if cflags == "AI" or cflags == "AR":
                ok = True
        if not ok:
            return (False, False, before)
        return (False, True, before)


    # winfileperms before enforcement, to be deleted after testing
    def _orgwinfileperms(self, filename, flag, req_cflags, req_aces_org, isAFile, nested, enforce, entry):
        #print "filename %r" % filename
        try:
            sd = win32security.GetNamedSecurityInfo(filename,
                win32security.SE_FILE_OBJECT,
                win32security.DACL_SECURITY_INFORMATION)
            # The following didn't quite give the same results:
            # sd = win32security.GetFileSecurity(filename,
            #             win32security.DACL_SECURITY_INFORMATION)
        except pywintypes.error as err:
            self.errorcount += 1
            self.error(
                0,
                "File/folder exception: %r (%s)", filename, err)
            #return True # stop recursion for this container
        except WindowsError as err:
            self.errorcount += 1
            self.error(
                0,
                "File/folder exception: %r (%s)", filename, err)
            #return True # stop recursion for this container
        cflags, aces, hasDacl = getsd(sd)

##        p = "".join(map(str, aces))
##        q = "".join(map(str, req_aces))
##        print "File %r" % filename
##        print "Actual ACES"
##        print "%r%r" % (cflags, p)
##        print "Required ACES"
##        print "%r%r" % (req_cflags, q)
##        print "nested %r" % nested

        # if DACL does not exist for nested folders/files, it is a match
        if nested and not hasDacl:
            return

        # if all aces at nested level have 'ID' (Inherited) set, it's a match
        if nested:
            total = 0
            idcount = 0
            for ace1 in aces:
                total += 1
                if ace1.aceflags & 0x10:
                    idcount += 1

            if ((idcount == total) and (total > 0)):
                return

        # get rid of all the aces with ID flag;
        # make copies of all relevant ACEs so we can mutate them in place
        if cflags == "AI":
            aces = [ACE(ace) for ace in aces if not ace.aceflags & 0x10]
        else:
            aces = map(ACE, aces) # Make a copy of all ACEs

        # ignore aces with IO (inherit only) flag set for files
        if isAFile:
            req_aces = [ACE(ace) for ace in req_aces_org if not ace.aceflags & 0x08]
        else:
            req_aces = req_aces_org

        # ignore ace_flags (inheritance flags) for files
        if isAFile:
            for ace in aces:
                ace.aceflags = 0
            for ace in req_aces:
                ace.aceflags = 0

        # convert generic rights to specific rights on actual aces
        for ace in aces:
            ace.rights = generic_to_file_rights(ace.rights)

            # if it is not a well known rid, make it AUthenticated user
            if ace.rid not in wellknownrids:
                ace.rid = 0xB

        ##p = "".join(map(str, aces))
        ##q = "".join(map(str, req_aces))
        ##print "File %r" % filename
        ##print "Actual ACES"
        ##print "D:%s%s" % (cflags, p)
        ##print "Required ACES"
        ##print "D:%s%s" % (req_cflags, q)
        ##print "nested %r" % nested

        # compare permissions
        if not aceseq(aces, req_aces, cflags, isAFile):
            p = "".join(map(str, aces))
            q = "".join(map(str, req_aces))
            if enforce:
                before = '"%s",%d,"D:%s%s"' % (filename, flag, cflags, p)
                after = '"%s",%d,"D:%s%s"' % (filename, flag, req_cflags, q)
                self.config_through_secedit("[File Security]", entry, "FILESTORE")
                usermsg = "Modified from %r to %r" % (before, after)
                self.logaction("File permission", filename, before, after, usermsg)
                return
            else:
                self.errorcount += 1
                if DEBUG_OUTPUT:
                    self.violation(
                        0,
                        "Ace mismatch for %r,\nactual='%s%s',\nrequired='%s%s'",
                        filename, cflags, p, req_cflags, q)
                else:
                    self.violation(0, "Mismatch for %r", filename)
                return

        # compare DACL flags
        ok = False
        if req_cflags == "PAR":
            if not nested:
                if cflags == "PAI" or cflags == "PAR" or cflags == "P":
                    ok = True
            elif cflags == "PAR":
                ok = True
        elif req_cflags == "PAI":
            if not nested:
                if cflags == "PAI" or cflags == "PAR" or cflags == "P":
                    ok = True
            elif cflags == "PAI":
                ok = True
        elif req_cflags == "AR" or req_cflags == "AI":
            if cflags == "AI" or cflags == "AR":
                ok = True
        elif req_cflags == "":
            if cflags == "AI" or cflags == "AR":
                ok = True
        if not ok:
            if enforce:
                p = "".join(map(str, aces))
                q = "".join(map(str, req_aces))
                before = '"%s",%d,"D:%s%s"' % (filename, flag, cflags, p)
                after = '"%s",%d,"D:%s%s"' % (filename, flag, req_cflags, q)
                self.config_through_secedit("[File Security]", entry, "FILESTORE")
                usermsg = "Modified from %r to %r" % (before, after)
                self.logaction("File permission", filename, before, after, usermsg)
                return
            else:
                self.errorcount += 1
                if DEBUG_OUTPUT:
                    self.violation(
                        0,
                        "cflags don't match: filename=%r, actual %r, required %r",
                        filename, cflags, req_cflags)
                else:
                    self.violation(0, "Mismatch for %r", filename)


    def winregperms(self, keyname, flag, perms):
        if flag not in (0, 1, 2):
            raise ValueError("flag %r ought to be 0, 1 or 2" % flag)
##        if flag == 1:
##            return # do nothing (used for configuration only)
        entry = '"%s",%d,"%s"' % (keyname, flag, perms)
        req_cflags, req_aces = parseperms(perms)
        self.errorcount = 0
        i = keyname.find("\\")
        if i >= 0:
            rootkeyname = keyname[:i]
            subkeyname = keyname[i+1:]
        else:
            rootkeyname = keyname
            subkeyname = ""

        rootkey = hkeymap.get(rootkeyname.lower())
        if rootkey is None:
            self.error(0, "Unknown root key %s", keyname)

        t0 = time.time()
        try:
            subkey = _winreg.OpenKey(rootkey, subkeyname)
        except WindowsError as err:
            ##print >>sys.stderr, path, subkeyname, err
            self.leave(0, "Not available: %r", keyname)
        else:
            try:
                self._walkreg(subkey, keyname, flag, req_cflags, req_aces, False, entry)
            finally:
                _winreg.CloseKey(subkey)

        if DEBUG_OUTPUT:
            t1 = time.time()
            print("%.3f seconds" % (t1-t0))
            print("%r mismatches are found" % self.errorcount)


    def _walkreg(self, key, path, flag, req_cflags, req_aces, nested, entry):
        if flag == 1:
            if self.enforce:
                self.config_through_secedit("[Registry Keys]", entry, "REGKEYS")
                #usermsg = "Enforced ignore flag"
                #self.logaction("Registry permission", filename, "ignore", "ignore", usermsg)
            return
        match, before = self._winregperms(path, flag, req_cflags, req_aces, nested, entry)
        if not match:
            self.errorcount += 1
            self.violation(0, "Permissions mismatch for %s", path)
            if self.enforce:
                self.config_through_secedit("[Registry Keys]", entry, "REGKEYS")
                match, after = self._winregperms(path, flag, req_cflags, req_aces, nested, entry)
                usermsg = "Modified from %r to %r" % (before, after)
                self.logaction("Registry permission", path, before, after, usermsg)

        if flag == 0:
            return
        nsubkeys, nvalues, mtime = _winreg.QueryInfoKey(key)

        for i in range(nsubkeys):
            try:
                subkeyname = _winreg.EnumKey(key, i)
            except WindowsError as err:
                self.errorcount += 1
                ##print >>sys.stderr, path, i, err
                continue # Probably "More data is available" ?!?!?!
            subkeypath = path + "\\" + subkeyname
            try:
                subkey = _winreg.OpenKey(key, subkeyname)
            except WindowsError as err:
                self.errorcount += 1
                ##print >>sys.stderr, path, subkeyname, err
                pass # Probably access denied
            else:
                try:
                    self._walkreg(subkey, subkeypath, flag, req_cflags, req_aces, True, entry)
                finally:
                    _winreg.CloseKey(subkey)
        return


    def _winregperms(self, keyname, flag, req_cflags, req_aces, nested, entry):
        # get the actual permissions
        try:
            sd = win32security.GetNamedSecurityInfo(keyname,
                    win32security.SE_REGISTRY_KEY,
                    win32security.DACL_SECURITY_INFORMATION)
        except WindowsError as err:
            # "Access denied" is all we care about
            self.errorcount += 1
            self.error(
                0,
                "Registry exception: %r (%r)", keyname, err)
        except pywintypes.error as err:
            self.errorcount += 1
            self.error(
                0,
                "Registry exception: %r (%r)", keyname, err)

        cflags, aces, hasDacl = getsd(sd)

##        make printable permissions
        p = "".join(map(str, aces))
        before = '"%s",%d,"D:%s%s"' % (keyname, flag, cflags, p)
##        q = "".join(map(str, req_aces))
##        print "Key %r" % keyname
##        print "Actual ACES"
##        print "%r%r" % (cflags, p)
##        print "Required ACES"
##        print "%r%r" % (req_cflags, q)
##        print "nested %r" % nested

        # if DACL does not exist it is permissions to all - it is a match
        if nested and not hasDacl:
            return (True, before)

        # if all aces have 'ID' flag (inherited flag) set, it is a match
        if nested:
            total = 0
            idcount = 0
            for ace1 in aces:
                total += 1
                if ace1.aceflags & 0x10:
                    idcount += 1

            if ((idcount == total) and (total > 0)):
                return (True, before)

        # get rid of all the aces with ID flag;
        # make copies of all relevant ACEs so we can mutate them in place
        if cflags == "AI":
            aces = [ACE(ace) for ace in aces if not ace.aceflags & 0x10]
        else:
            aces = map(ACE, aces) # Make a copy of all ACEs

        for ace in aces:
            # ignore ace_flag ID
            ace.aceflags &= ~0x10 # ID flag

            # OI flag (Object inheritance) is useless in registry key because
            # it is a container and Registry values do not have permissions
            # ignore OI flag if IO (inherit only) is also present
            if ace.aceflags & 0x9:
                ace.aceflags &= ~0x1

            # convert generic rights to specific
            ace.rights = generic_to_key_rights(ace.rights)

            # if it is not a well known rid, make it AUthenticated user
            if ace.rid not in wellknownrids:
                ace.rid = 0xB

        for ace in req_aces:
            # ignore ace_flag ID
            ace.aceflags &= ~0x10 # ID flag

            # OI flag (Object inheritance) is useless in registry key because
            # it is a container and Registry values do not have permissions
            # ignore OI flag if IO (inherit only) is also present
            if ace.aceflags & 0x9:
                ace.aceflags &= ~0x1

            # convert generic rights to specific
            ace.rights = generic_to_key_rights(ace.rights)

        # compare permissions
        if not aceseq(aces, req_aces, req_cflags, False):
            return (False, before)

        # compare DACL control flags
        ok = False
        if req_cflags == "PAR":
            if not nested:
                if cflags == "PAI" or cflags == "PAR" or cflags == "P":
                    ok = True
            # PAI for second level does not match with PAR,
            # check machine\\software\\microsoft\\windows nt\\currentversion\\perflib\\009
            elif cflags == "PAR":
                ok = True
        elif req_cflags == "PAI":
            if not nested:
                if cflags == "PAI" or cflags == "PAR" or cflags == "P":
                    ok = True
            elif cflags == "PAI":
                ok = True
        elif req_cflags == "AR" or req_cflags == "AI":
            if cflags == "AI" or cflags == "AR":
                ok = True
        elif req_cflags == "":
            if cflags == "AI" or cflags == "AR":
                ok = True

        if not ok:
            return (False, before)
        return (True, before)


    # winregperms before enforcement, to be deleted after testing
    def _orgwinregperms(self, keyname, flag, req_cflags, req_aces, nested, entry):
        # get the actual permissions
        try:
            sd = win32security.GetNamedSecurityInfo(keyname,
                    win32security.SE_REGISTRY_KEY,
                    win32security.DACL_SECURITY_INFORMATION)
        except WindowsError as err:
            # "Access denied" is all we care about
            self.errorcount += 1
            self.error(
                0,
                "Registry exception: %r (%s)", keyname, err)
        except pywintypes.error as err:
            self.errorcount += 1
            self.error(
                0,
                "Registry exception: %r (%s)", keyname, err)

        cflags, aces, hasDacl = getsd(sd)

##        # make printable permissions
##        p = "".join(map(str, aces))
##        q = "".join(map(str, req_aces))
##        print "Key %r" % keyname
##        print "Actual ACES"
##        print "%r%r" % (cflags, p)
##        print "Required ACES"
##        print "%r%r" % (req_cflags, q)
##        #print "nested %r" % nested

        # if DACL does not exist it is permissions to all - it is a match
        if nested and not hasDacl:
            return

        # if all aces have 'ID' flag (inherited flag) set, it is a match
        if nested:
            total = 0
            idcount = 0
            for ace1 in aces:
                total += 1
                if ace1.aceflags & 0x10:
                    idcount += 1

            if ((idcount == total) and (total > 0)):
                return

        # get rid of all the aces with ID flag;
        # make copies of all relevant ACEs so we can mutate them in place
        if cflags == "AI":
            aces = [ACE(ace) for ace in aces if not ace.aceflags & 0x10]
        else:
            aces = map(ACE, aces) # Make a copy of all ACEs

        for ace in aces:
            # ignore ace_flag ID
            ace.aceflags &= ~0x10 # ID flag

            # OI flag (Object inheritance) is useless in registry key because
            # it is a container and Registry values do not have permissions
            # ignore OI flag if IO (inherit only) is also present
            if ace.aceflags & 0x9:
                ace.aceflags &= ~0x1

            # convert generic rights to specific
            ace.rights = generic_to_key_rights(ace.rights)

            # if it is not a well known rid, make it AUthenticated user
            if ace.rid not in wellknownrids:
                ace.rid = 0xB

        for ace in req_aces:
            # ignore ace_flag ID
            ace.aceflags &= ~0x10 # ID flag

            # OI flag (Object inheritance) is useless in registry key because
            # it is a container and Registry values do not have permissions
            # ignore OI flag if IO (inherit only) is also present
            if ace.aceflags & 0x9:
                ace.aceflags &= ~0x1

            # convert generic rights to specific
            ace.rights = generic_to_key_rights(ace.rights)

        ##p = "".join(map(str, aces))
        ##q = "".join(map(str, req_aces))
        ##print "Actual ACES"
        ##print "%r%r" % (cflags, p)
        ##print "Required ACES"
        ##print "%r%r" % (req_cflags, q)

        # compare permissions
        if not aceseq(aces, req_aces, req_cflags, False):
            p = "".join(map(str, aces))
            q = "".join(map(str, req_aces))
            self.errorcount += 1
            if DEBUG_OUTPUT:
                self.violation(
                    0,
                    "Ace mismatch for %r,\nactual='%s%s',\nrequired='%s%s'",
                    keyname, cflags, p, req_cflags, q)
            else:
                self.violation(0, "Mismatch for %r", keyname)
            return

        # compare DACL control flags
        ok = False
        if req_cflags == "PAR":
            if not nested:
                if cflags == "PAI" or cflags == "PAR" or cflags == "P":
                    ok = True
            # PAI for second level does not match with PAR,
            # check machine\\software\\microsoft\\windows nt\\currentversion\\perflib\\009
            elif cflags == "PAR":
                ok = True
        elif req_cflags == "PAI":
            if not nested:
                if cflags == "PAI" or cflags == "PAR" or cflags == "P":
                    ok = True
            elif cflags == "PAI":
                ok = True
        elif req_cflags == "AR" or req_cflags == "AI":
            if cflags == "AI" or cflags == "AR":
                ok = True
        elif req_cflags == "":
            if cflags == "AI" or cflags == "AR":
                ok = True

        if not ok:
            self.errorcount += 1
            if DEBUG_OUTPUT:
                self.violation(
                    0,
                    "cflags don't match for %r, actual %r, required %r",
                    keyname, cflags, req_cflags)
            else:
                self.violation(0, "Mismatch for %r", keyname)


    # gets specified setting in RSOP_SecuritySettingNumeric
    def wmi_rsop_security_settings_numeric(self, name):
        try:
            objItems = GetObject("winmgmts://./root/rsop/computer").InstancesOf("RSOP_SecuritySettingNumeric")
            for item in objItems:
                if item.Properties_("keyname").Value == name:
                    return item.Properties_("setting").Value
            else:
                return None
        except:
            #logger.exception("Exception in wmi_rsop_security_settings_numeric")
            return None


    # gets specified setting in RSOP_SecuritySettingBoolean
    def wmi_rsop_security_settings_boolean(self, name):
        try:
            objItems = GetObject("winmgmts://./root/rsop/computer").InstancesOf("RSOP_SecuritySettingBoolean")
            for item in objItems:
                if item.Properties_("keyname").Value == name:
                    return item.Properties_("setting").Value
            else:
                return None
        except:
            #logger.exception("Exception in wmi_rsop_security_settings_boolean")
            return None


    # gets specified setting from RSOP_AuditPolicy
    def wmi_audit_policy_query(self, name):
        try:
            success, failure, found, ret = False, False, False, 0
            query = "Select * from RSOP_AuditPolicy where Category = '%s'" % (name)
            WMIService = GetObject("winmgmts://./root/rsop/computer")
            objItems = WMIService.ExecQuery(query)
            for item in objItems:
                found = True
                if item.Properties_("Success").Value:
                    ret = ret | 1
                if item.Properties_("Failure").Value:
                    ret = ret | 2
            if found:
                return ret
            else:
                return None
        except:
            #logger.exception("Exception in wmi_audit_policy_query")
            return None


    # Gets the names of users with the specified rid
    def wmi_get_user_names(self, rid):
        hostname = ""
        try:
            import socket
            hostname = socket.gethostname()
        except:
            logger.exception("Exception in wmi_get_user_names")
            return None
        names = FuelSet()
        rid = "-" + rid
        try:
            t0 = time.time()
            # LocalAccount property is not available in Windows 2000
            # can't get the rights for non local accounts, so don't try
            query = "Select * from Win32_UserAccount where domain = '%s'" % (hostname)
            WMIService = GetObject("winmgmts://./root/cimv2")
            objItems = WMIService.ExecQuery(query)
            for item in objItems:
                sid = item.Properties_("SID").Value
                if sid != None and sid.endswith(rid):
                    names.add(item.Properties_("Name").Value)
            if DEBUG_OUTPUT:
                t1 = time.time()
                print("%.3f seconds" % (t1-t0))
            return names
        except Exception as details:
            logger.exception("Exception in wmi_get_user_names")
            self.error(0, "COM exception: %s", details)


    # helper function to create sid object
    def _createSIDObject(self, sidstr):
        tokens = sidstr.split("-")
        num = len(tokens) - 3
        psid = win32security.SID()
        psid.Initialize((0, 0, 0, 0, 0, int(tokens[2])), num)
        for i in range(num):
            sa = int(tokens[i+3])
            if sa > 0x7fffffff:
                sa -= 0x100000000
            psid.SetSubAuthority(i, sa)
        return psid


    # gets the sids with specified privilege
    def wmi_get_sids_for_privilege(self, privilege):
        names = FuelSet()
        policy_handle = win32security.GetPolicyHandle('',
            win32security.POLICY_VIEW_LOCAL_INFORMATION |
            win32security.POLICY_GET_PRIVATE_INFORMATION |
            win32security.POLICY_VIEW_AUDIT_INFORMATION |
            win32security.POLICY_LOOKUP_NAMES)
        try:
            """
            try:
                for item in self._wmi_get_local_accounts():
                    try:
                        sid = item.Properties_("SID").Value
                        #user = item.Properties_("Caption").Value
                        psid = self._createSIDObject(sid)
                        privlist=win32security.LsaEnumerateAccountRights (policy_handle, psid)
                    except:
                        continue
                    for priv in privlist:
                        if priv.lower() == privilege.lower():
                            name = item.Properties_("Name").Value
                            names.add(name)
                            break
                return names
            except Exception as details:
                logger.exception("Exception in wmi_get_sids_for_privilege")
                self.error(0, "COM exception for privilege %s (%s)", privilege, details)
            """
            try:
                sids = win32security.LsaEnumerateAccountsWithUserRight(policy_handle, privilege)
                for asid in sids:
                    try:
                        nameinfo = win32security.LookupAccountSid(None, asid)
                    except:
                        # we can't get the name, so use the sid
                        x = str(asid) #PySID:S-1-5-21-866922546-1215760169-3077768583-1001
                        if x:
                            if len(x) > 6:
                                names.add(x[6:])
                            else:
                                names.add(x)
                    else:
                        if nameinfo:
                            if nameinfo[1].lower() != "builtin" and nameinfo[1].lower() != "nt authority" and nameinfo[1] != "":
                                username = r"%s\%s" % (nameinfo[1], nameinfo[0])
                            else:
                                username = nameinfo[0]
                            names.add(username)
            except Exception as details:
                #ignore pywintypes.error: (259, 'LsaEnumerateAccountsWithUserRight', 'No more data is available.')
                if details[0] != 259:
                    logger.exception("Exception in wmi_get_sids_for_privilege")
                    self.error(0, "COM exception for privilege %s (%s)", privilege, details)

        finally:
            win32security.LsaClose(policy_handle)
            return names



    # sets the sids with specified privilege
    def wmi_set_sids_for_privilege(self, privname, names):
        if self.enforce:
            # get the privilege constant
            privlist = []
            if privname in privmap:
                privlist.append(privmap.get(privname))
            else:
                return -1

            # remove existing users/groups from the privilege
            old_names = self._wmi_remove_sids_for_privilege(privname)

            # add the new users/groups to the privilege
            policy_handle = win32security.GetPolicyHandle('',
                win32security.POLICY_ALL_ACCESS)
            try:
                for name in names:
                    tmp_sid, domain, acctype = win32security.LookupAccountName('', name)
                    win32security.LsaAddAccountRights(policy_handle, tmp_sid, privlist)
            except Exception as details:
                logger.exception("Exception in wmi_set_sids_for_privilege")
            win32security.LsaClose(policy_handle)

            str_old_names = ",".join(old_names)
            new_names = self.wmi_get_sids_for_privilege(privname)
            str_names = ",".join(new_names)
            usermsg = "Modified from '%s' to '%s'" % (str_old_names, str_names)
            self.logaction("Privilege", privname, str_old_names, str_names, usermsg)

        return 0


    # removes all the users/groups having the specified privilege
    def _wmi_remove_sids_for_privilege(self, privname):
        # get the privilege constant
        privlist = []
        if privname in privmap:
            privlist.append(privmap.get(privname))
        else:
            return None
        policy_handle = win32security.GetPolicyHandle('',
            win32security.POLICY_ALL_ACCESS)
        names = self.wmi_get_sids_for_privilege(privname)
        try:
            for name in names:
                tmp_sid, domain, acctype = win32security.LookupAccountName('', name)
                win32security.LsaRemoveAccountRights(policy_handle, tmp_sid, 0, privlist)
        except Exception as details:
            logger.exception("Exception in _wmi_remove_sids_for_privilege")
        win32security.LsaClose(policy_handle)
        return names


    _wmi_local_accounts_cache = None

    def _wmi_get_local_accounts(self):
        hostname = ""
        result = []
        try:
            import socket
            hostname = socket.gethostname()
        except:
            return result
        if self._wmi_local_accounts_cache is None:
            t0 = time.time()
            # LocalAccount property is not available in Windows 2000
            # can't get the rights for non local accounts, so don't try
            query = "Select * from Win32_Account where Domain = '%s'" % hostname
            WMIService = GetObject("winmgmts://./root/cimv2")
            objItems = WMIService.ExecQuery(query)
            for item in objItems:
                result.append(item)
            self._wmi_local_accounts_cache = result
            if DEBUG_OUTPUT:
                t1 = time.time()
                print("%.3f seconds" % (t1-t0))
        return self._wmi_local_accounts_cache


    # gets the member count of a group. groupid is in the form of "00000223"
    def get_group_members(self, grouprid):
        rids = FuelSet()
        try:
            keyname = "SAM\\SAM\\Domains\\Builtin\\Aliases\\" + grouprid
            subkey = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, keyname)
        except WindowsError as err:
            ##print >>sys.stderr, path, subkeyname, err
            self.error(
                0,
                "Windows exception while opening key %s (%r)", keyname, err)
        else:
            try:
                try:
                    nsubkeys, nvalues, mtime = _winreg.QueryInfoKey(subkey)
                    nm, val, typ = _winreg.EnumValue(subkey, 0)
                    if nm.lower() == 'c':
                        ##print "%r %r %r %r" % (val[44], val[45], val[46], val[47])
                        totalLen = len(val)
                        if totalLen >= 48:
                            count = (ord(val[44]) + ord(val[45]) * 0x100 + \
                                ord(val[46]) * 0x10000 + ord(val[47]) * 0x1000000) / 28
                        else:
                            count = 0

                        for i in range(count):
                            rid = ord(val[totalLen - 28 * i - 4]) + \
                                ord(val[totalLen - 28 * i - 3]) * 0x100 + \
                                ord(val[totalLen - 28 * i - 2]) * 0x10000 + \
                                ord(val[totalLen - 28 * i - 1]) * 0x1000000
                            rids.add(rid)
                    return rids
                except WindowsError as err:
                    self.error(
                        0,
                        "Windows exception while querying key %s (%r)", keyname, err)
            finally:
                _winreg.CloseKey(subkey)


    """
    DriveTypes
    0 Unknown
    1 No Root Directory
    2 Removable Disk
    3 Local Disk
    4 Network Drive
    5 Compact Disc
    6 RAM Disk
    """

    # returns file system for each drive of specified type
    def wmi_file_system(self, val):
        driveset = FuelSet()
        try:
            try:
                objItems = GetObject("winmgmts://./root/cimv2").InstancesOf("Win32_LogicalDisk")
                for item in objItems:
                    if item.Properties_("DriveType").Value == val:
                        name = item.Properties_("Caption").Value
                        fs = item.Properties_("FileSystem").Value
                        strPair = stringPair(name, fs)
                        driveset.add(strPair)
            except Exception as details:
                logger.exception("Exception in wmi_file_system")
                self.error(0, "COM exception: %s", details)
        finally:
            return driveset


    # returns permissions on shares
    def wmi_perms_on_shares(self):
        shareset = FuelSet()
        try:
            try:
                # get all the shares
                sharelist = []
                items = GetObject("winmgmts://./root/cimv2").InstancesOf("Win32_Share")
                for item in items:
                    # save only file shares
                    if item.Properties_('Type').Value == 0:
                        sharelist.append(item.Properties_('Name').Value)

                # get permissions for each file share
                for i in range(len(sharelist)):
                    share = "winmgmts:Win32_LogicalShareSecuritySetting.name='%s'" % sharelist[i]
                    try:
                        obj = GetObject(share)
                    except pythoncom.com_error as details:
                        strPair = stringPair(sharelist[i], "Everyone")
                        shareset.add(strPair)
                        continue
                    try:
                        flags = (int)(obj.Properties_('ControlFlags'))
                        if flags & 0x04:
                            try:
                                sd = obj.ExecMethod_('GetSecurityDescriptor')
                            except:
                                # NULL DACL means Full control to everyone
                                strPair = stringPair(sharelist[i], "Everyone")
                                shareset.add(strPair)
                                continue
                            d = sd.Properties_('Descriptor').Value
                            acl = d.Properties_('DACL').Value
                            for ace in acl:
                                ##ids = ace.Properties_('Trustee').Value.Properties_('sid').Value
                                name = ace.Properties_('Trustee').Value.Properties_('Name').Value
                                strPair = stringPair(sharelist[i], name)
                                shareset.add(strPair)
                        else:
                            # No DACL means Full control to everyone
                            strPair = stringPair(sharelist[i], "Everyone")
                            shareset.add(strPair)
                    except:
                        logger.exception("Exception in wmi_perms_on_shares")
            except Exception as details:
                logger.exception("Exception in wmi_perms_on_shares")
                self.error(0, "COM exception: %s", details)
        finally:
            return shareset


    # checks the settings thru secedit.exe
    """
    def check_through_secedit(self, section, entry, area):
        t0 = time.time()

        # create input configuration file
        conf_file = tempfile.mktemp()
        try:
            fout = open(conf_file, "w")
        except:
            self.error(0, "File exception while creating inf file %s", conf_file)
        try:
            fout.write(INF1)
            fout.write(INF2)
            fout.write(INF3)
            fout.write(section)
            fout.write("\r\n")
            fout.write(entry)
            fout.write("\r\n")
            fout.close()
        except:
            fout.close()
            self.error(0, "File exception while creating inf file %s", conf_file)

        # run the secedit utility
        out_file = tempfile.mktemp()

        # w2k needs verbose flag to show mismatches
        command = "secedit /analyze /db temp.pdb /cfg %s /log %s /areas %s /overwrite /verbose" % (conf_file, out_file, area)
        p = os.popen(command)
        p.close()
        if os.path.exists(conf_file):os.remove(conf_file)

        # read the output file
        try:
            f = open (out_file, "rb")
        except:
            self.error(0, "File exception while opening output file (%s)",
                out_file)
        try:
            try:
                bytes = f.read()
            except:
                self.error(0, "File exception while opening output file (%s)",
                    out_file)
        finally:
            f.close()
            if os.path.exists(out_file):os.remove(out_file)

        # decode str
        u = bytes.decode("utf-16")
        k = u.find("Errors occurred")
        if k >= 0:
            err = True
            if area.lower() == "securitypolicy":
                k = u.find("----Analyze Security Policy...")
                if k >= 0:err = False
            elif area.lower() == "filestore":
                k = u.find("----Analyze File Security...")
                if k >= 0:err = False
            elif area.lower() == "regkeys":
                k = u.find("----Analyze Registry Keys...")
                if k >= 0:err = False
            if err == True:
                self.error(0, "Settings could not be analyzed for %s %s %s", section, entry, area)

        # find the string 'Mismatch' and get the whole line
        i = u.find("Mismatch")
        if i >= 0:
            j = u.find("\n", i + 1)
            line = u[i:j]
            self.violation(0, line)

        # find the string 'Warning 2' and get the whole line
        i = u.find("Warning 2")
        if i >= 0:
            j = u.find("\n", i + 1)
            line = u[i:j]
            #return -2
            self.violation(0, line)

        # find the string 'Warning 3' and get the whole line
        i = u.find("Warning 3")
        if i >= 0:
            j = u.find("\n", i + 1)
            line = u[i:j]
            #return -2
            self.violation(0, line)

        if DEBUG_OUTPUT:
            t1 = time.time()
            print("%.3f seconds" % (t1-t0))
    """

    def _regExists(self, rootkeyname, keyname):
        try:
            hRoot = getattr(_winreg, rootkeyname)
            hKey = _winreg.OpenKey(hRoot, keyname, 0, _winreg.KEY_READ)
        except WindowsError as err:
            return False
        _winreg.CloseKey(hKey)
        return True

    # check GPO through GPRESULT
    def get_gpresult(self):
        from time import time
        temppath = os.path.join(r'C:\Users\Public\Downloads', "temp")
        if not os.path.exists(temppath):
            os.makedirs(temppath)
        tempoutput = os.path.join(temppath, "gpo.txt")

        if not os.path.exists(tempoutput):
            return GPResult([])

        with open(tempoutput) as f:
            s = f.read().decode('utf-16')

        f.close()
        os.remove(tempoutput)

        xlines = s.split("\r\n")

        return GPResult(xlines)

    # Check GPresult for String
    def str_through_gpresult(self, keyname):
        gp = self.get_gpresult()
        value = 'unknown'
        parts = keyname.split("\\")
        if keyname.startswith('Computer Configuration'):
            if parts[-1] in gp.computer_gpo:
                value = gp.computer_gpo[parts[-1]]
        else:
            if parts[-1] in gp.user_gpo:
                value = gp.user_gpo[parts[-1]]

        return value

    # Check GPresult for Integer
    def int_through_gpresult(self, keyname):
        gp = self.get_gpresult()
        value = -1
        parts = keyname.split("\\")
        if keyname.startswith('Computer Configuration'):
            if parts[-1] in gp.computer_gpo:
                value = gp.computer_gpo[parts[-1]]
        else:
            if parts[-1] in gp.user_gpo:
                value = gp.user_gpo[parts[-1]]

        return int(value)

    # Check GPresult for Boolean
    def bool_through_gpresult(self, keyname):
        gp = self.get_gpresult()
        value = 'unknown'
        parts = keyname.split("\\")
        if keyname.startswith('Computer Configuration'):
            if parts[-1] in gp.computer_gpo:
                value = gp.computer_gpo[parts[-1]]
        else:
            if parts[-1] in gp.user_gpo:
                value = gp.user_gpo[parts[-1]]

        return value.startswith("true")

    # Check gpresult for existence of key
    def check_key_gpresult(self, keyname):
        gp = self.get_gpresult()
        value = False
        parts = keyname.split("\\")[-1]
        if keyname.startswith('Computer Configuration'):
            value = parts[-1] in gp.computer_gpo
        else:
            value = parts[-1] in gp.user_gpo

        return value

    # checks the settings thru secedit.exe
    def check_through_secedit(self, section, entry, area):
        t0 = time.time()

        # check if the file or registry exists
        parts = entry.split(",")
        name = parts[0].strip()
        if parts[0].startswith('"') and parts[0].endswith('"'):
            name = parts[0][1:len(parts[0]) - 1]
        elif parts[0].startswith("'") and parts[0].endswith("'"):
            name = parts[0][1:len(parts[0]) - 1]
        if area.lower() == "filestore":
            expanded_name = self._expand_file_name(name)
            if not os.path.exists(expanded_name):
                return -2
        elif area.lower() == "regkeys":
            parts = name.split("\\")
            num = len(parts)
            if num > 1:
                key = name[len(parts[0]) + 1:]
                if parts[0].lower() == "machine":
                    if not self._regExists("HKEY_LOCAL_MACHINE", key):
                        return -2
                elif parts[0].lower() == "users":
                    if not self._regExists("HKEY_USERS", key):
                        return -2
                elif parts[0].lower() == "user":
                    if not self._regExists("HKEY_CURRENT_USER", key):
                        return -2
                elif parts[0].lower() == "classes_root":
                    if not self._regExists("HKEY_CLASSES_ROOT", key):
                        return -2
                else:
                    return -2

        # create input configuration file
        temppath = os.path.join(self.options.agentdata, "temp")
        if not os.path.exists(temppath):
            os.makedirs(temppath)
        h, conf_file = tempfile.mkstemp(".inf", "", temppath)
        os.close(h)
        #conf_file = tempfile.mktemp()
        try:
            fout = open(conf_file, "w")
        except:
            logger.exception("Exception in check_through_secedit")
            self.error(0, "File exception while opening the inf file %s", conf_file)
        try:
            fout.write(INF1)
            fout.write(INF2)
            fout.write(INF3)
            fout.write(section)
            fout.write("\r\n")
            fout.write(entry)
            fout.write("\r\n")
            fout.close()
        except:
            logger.exception("Exception in check_through_secedit")
            fout.close()
            self.error(0, "File exception while writing to the inf file %s", conf_file)

        # run the secedit utility
        h, out_file = tempfile.mkstemp(".log", "", temppath)
        os.close(h)
        #out_file = tempfile.mktemp()

        # w2k needs verbose flag to show mismatches
        if os.path.exists("esi.pdb"):os.remove("esi.pdb")
        command = 'secedit /analyze /db esi.pdb /cfg "%s" /log "%s" /verbose' % (conf_file, out_file)
        #command = "secedit /analyze /db temp.pdb /cfg %s /log %s /areas %s /overwrite /verbose" % (conf_file, out_file, area)
        p = os.popen(command)
        p.close()
        if os.path.exists(conf_file):os.remove(conf_file)

        # read the output file
        try:
            f = open (out_file, "rb")
        except:
            logger.exception("Exception in check_through_secedit")
            self.error(0, "File exception while opening the output file (%s)",
                out_file)
        try:
            try:
                bytes = f.read()
            except:
                logger.exception("Exception in check_through_secedit")
                self.error(0, "File exception while reading the output file (%s)",
                    out_file)
        finally:
            f.close()
            if os.path.exists(out_file):os.remove(out_file)

        # decode str
        u = bytes.decode("utf-16")
        k = u.find("Errors occurred")
        if k >= 0:
            err = True
            if area.lower() == "securitypolicy":
                k = u.find("----Analyze Security Policy...")
                if k >= 0:err = False
            elif area.lower() == "filestore":
                k = u.find("----Analyze File Security...")
                if k >= 0:err = False
            elif area.lower() == "regkeys":
                k = u.find("----Analyze Registry Keys...")
                if k >= 0:err = False
            if err:
                self.error(0, "Settings could not be analyzed for %s %s %s", section, entry, area)

        # find the string 'Mismatch' and get the whole line
        # sample: Mismatch       - machine\software\microsoft\netdde
        i = u.find("Mismatch")
        if i >= 0:
            j = u.find("\n", i + 1)
            line = u[i:j]
            return -1
            #self.violation(0, line)

        if DEBUG_OUTPUT:
            t1 = time.time()
            print("%.3f seconds" % (t1-t0))
        return 0

    # configures the settings thru secedit.exe
    def config_through_secedit(self, section, entry, area):
        t0 = time.time()

        # create input configuration file
        temppath = os.path.join(self.options.agentdata, "temp")
        if not os.path.exists(temppath):
            os.makedirs(temppath)
        h, conf_file = tempfile.mkstemp(".inf", "", temppath)
        os.close(h)
        #conf_file = tempfile.mktemp()
        try:
            fout = open(conf_file, "w")
        except:
            logger.exception("Exception in config_through_secedit")
            self.error(0, "File exception while opening the inf file %s", conf_file)
        try:
            fout.write(INF1)
            fout.write(INF2)
            fout.write(INF3)
            fout.write(section)
            fout.write("\r\n")
            fout.write(entry)
            fout.write("\r\n")
            fout.close()
        except:
            fout.close()
            logger.exception("Exception in config_through_secedit")
            self.error(0, "File exception while writing to the inf file %s", conf_file)

        # run the secedit utility
        h, out_file = tempfile.mkstemp(".log", "", temppath)
        os.close(h)
        #out_file = tempfile.mktemp()

        # w2k needs verbose flag to show mismatches
        command = 'secedit /configure /db esi.pdb /cfg "%s" /log "%s" /areas %s /overwrite /quiet' % (conf_file, out_file, area)
        #command = "secedit /configure /db temp.pdb /cfg %s /log %s /areas %s /overwrite /quiet" % (conf_file, out_file, area)
        p = os.popen(command)
        # adding try/except because if the command is improper,
        # it may expect a user input.
        try:
            p.close()
        except Exception:
            # should never happen
            logger.exception("Error on closing the handle")
        if os.path.exists(conf_file):os.remove(conf_file)
        if os.path.exists(out_file):os.remove(out_file)

        if DEBUG_OUTPUT:
            t1 = time.time()
            print("%.3f seconds" % (t1-t0))

    # returns true if system is running Windows XP sp 1
    def is_running_win_xp_sp1(self):
        try:
            objItems = GetObject("WinMgMts://./root/cimv2").InstancesOf("Win32_OperatingSystem")
            for item in objItems:
                ver = item.Properties_("Version").Value
                spmajorver = item.Properties_("ServicePackMajorVersion").Value
                if ver.startswith("5.1.") and spmajorver == 1:
                    return True
            return False
        except Exception as details:
            logger.exception("Exception in is_running_win_xp_sp1")
            self.error(0, "COM exception: %s", details)


    # returns true if system is running Windows XP sp 2
    def is_running_win_xp_sp2(self):
        try:
            objItems = GetObject("WinMgMts://./root/cimv2").InstancesOf("Win32_OperatingSystem")
            for item in objItems:
                ver = item.Properties_("Version").Value
                spmajorver = item.Properties_("ServicePackMajorVersion").Value
                if ver.startswith("5.1.") and spmajorver == 2:
                    return True
            return False
        except Exception as details:
            logger.exception("Exception in is_running_win_xp_sp2")
            self.error(0, "COM exception: %s", details)

    def service_status(self, req_name, modify):
        strPair = stringPair("Not Found", "Not Found")
        try:
            try:
                query = "Select * from Win32_Service where Name = '%s'" % (req_name.strip())
                WMIService = GetObject("winmgmts://./root/cimv2")
                objItems = WMIService.ExecQuery(query)
                for item in objItems:
                    strPair = stringPair(item.Properties_("StartMode").Value,
                                         item.Properties_("State").Value)
                    break
            except Exception as details:
                logger.exception("Exception in service_status")
                self.error(0, "COM exception in service_status: %s", details)
        finally:
            return strPair


    def set_service_status(self, req_name, req_starttype):
        if not self.enforce:
            return
        if req_starttype.lower() not in ("auto", "manual", "disabled"):
            self.error(0, "Invalid service state (%s) specified", req_starttype)
        try:
            bModifiedStartType = False
            bModifiedState = False
            before_starttype = ""
            before_state = ""
            query = "Select * from Win32_Service where Name = '%s'" % (req_name.strip())
            WMIService = GetObject("winmgmts://./root/cimv2")
            objItems = WMIService.ExecQuery(query)
            for item in objItems:
                before_starttype = item.Properties_("StartMode").Value
                before_state = item.Properties_("State").Value
                if before_starttype.lower() != req_starttype.lower():
                    if req_starttype.lower() == "disabled":
                        if item.Properties_("State").Value != "Stopped" and item.Properties_("AcceptStop").Value:
                            item.ExecMethod_('StopService')
                            bModifiedState = True
                    InParam = item.Methods_("ChangeStartMode").InParameters.SpawnInstance_()
                    if req_starttype.lower() == "auto":
                        req_starttype = "Automatic"
                    InParam.Properties_.Item("StartMode").Value = req_starttype
                    item.ExecMethod_("ChangeStartMode", InParam)
                    bModifiedStartType = True
                break
            else:
                self.error(0, "Service %s could not be found", req_name)

            if bModifiedStartType:
                query = "Select * from Win32_Service where Name = '%s'" % (req_name.strip())
                WMIService = GetObject("winmgmts://./root/cimv2")
                objItems = WMIService.ExecQuery(query)
                for item in objItems:
                    after_starttype = item.Properties_("StartMode").Value
                    after_state = item.Properties_("State").Value
                    break
                if bModifiedState and bModifiedStartType:
                    usermsg = "Modified service start type from %s to %s and state from %s to %s" % (before_starttype, after_starttype, before_state, after_state)
                    before = "Service %s, start type %s, state %s" % (req_name, before_starttype, before_state)
                    after = "Service %s, start type %s, state %s" % (req_name, after_starttype, after_state)
                    self.logaction("ModifyService", req_name, before, after, usermsg)
                else:
                    usermsg = "Modified service start type from %s to %s" % (before_starttype, after_starttype)
                    before = "Service %s, start type %s" % (req_name, before_starttype)
                    after = "Service %s, start type %s" % (req_name, after_starttype)
                    self.logaction("ModifyService", req_name, before, after, usermsg)
        except Exception as details:
            logger.exception("Exception in set_service_status")
            self.error(0, "COM exception in service_status: %s", details)


    def check_hotfix(self, hotfixname):
        try:
            rs = re.compile(hotfixname, re.IGNORECASE)
            query = "Select * from Win32_QuickFixEngineering"
            WMIService = GetObject("winmgmts://./root/cimv2")
            objItems = WMIService.ExecQuery(query)
            for item in objItems:
                if re.match(rs, item.Properties_("HotFixID").Value):
                    return True
            return False
        except Exception as details:
            logger.exception("Exception in check_hotfix")
            self.error(0, "COM exception in check_hotfix: %s", details)


    def check_path(self, fullpath):
        if not fullpath:return False
        if os.path.exists(self._expand_file_name(fullpath)):return True
        else: return False


    # returns true if system has greater than or equal sp
    def check_sp(self, sp):
        try:
            objItems = GetObject("WinMgMts://./root/cimv2").InstancesOf("Win32_OperatingSystem")
            for item in objItems:
                spmajorver = item.Properties_("ServicePackMajorVersion").Value
                if spmajorver >= sp:
                    return True
            return False
        except Exception as details:
            logger.exception("Exception in check_sp")
            self.error(0, "COM exception: %s", details)


    def check_installed_app(self, appName):
        ret = False
        path = r"Software\Microsoft\Windows\CurrentVersion\Uninstall"
        try:
            rootkey = _winreg.OpenKey(getattr(_winreg, "HKEY_LOCAL_MACHINE"), path)
        except WindowsError as err:
            return ret
        try:
            nsubkeys, nvalues, mtime = _winreg.QueryInfoKey(rootkey)
            for i in range(nsubkeys):
                try:
                    subkeyname = _winreg.EnumKey(rootkey, i)
                except WindowsError as err:
                    continue # continue if possible
                subkeypath = path + "\\" + subkeyname
                try:
                    subkey = _winreg.OpenKey(rootkey, subkeyname)
                except WindowsError as err:
                    continue # continue if possible
                try:
                    if self._walkregval(subkey, appName):
                        ret = True
                        break
                finally:
                    _winreg.CloseKey(subkey)
        finally:
            _winreg.CloseKey(rootkey)
        return ret


    def _walkregval(self, key, appName):
        rs = re.compile(appName, re.IGNORECASE)
        nsubkeys, nvalues, mtime = _winreg.QueryInfoKey(key)
        for i in range(nvalues):
            nm, val, typ = _winreg.EnumValue(key, i)
            if isinstance(nm, str):
                nm = nm.encode("utf8")
            if isinstance(val, str):
                val = val.encode("utf8")
            if nm.lower() == "displayname":
                if re.match(rs, val):
                    return True
        return False


    def _getGroupMembers(self, DistinguishedNameOfGroup):
        astr = "LDAP://%s" % (DistinguishedNameOfGroup)
        memberList = []
        try:
            result = GetObject(astr)
            #if result.Class == 'group':
            if result.member:
                if not result.member: return memberList
                if type(result.member) == tuple:
                    for r in result.member:
                        memberList.append(r)
                else:
                    memberList.append(result.member)
        except:
            logger.exception("Exception in _getGroupMembers")
        return memberList


    def _expand_file_name(self, filename):
        exfilename = filename
        i = filename.find("%")
        if i >= 0:
             j = filename.find("%", i+1)
             if j > i:
                 key = filename[i+1: j]
                 env = os.getenv(key)
                 if env is not None:
                     exfilename = filename[:i] + env + filename[j+1:]
        return exfilename

    # get the list of logged in users
    def _getLoggedInUsers1(self):
        userList = []
        # adding the path because some W2K machines do not find it
        exfilename = self._expand_file_name("%SystemRoot%\\system32\\qwinsta.exe")

        # adding the path check because some W2K WS do not have qwinsta.exe
        if os.path.exists(exfilename):
            try:
                p = os.popen("%SystemRoot%\\system32\\qwinsta", "r")
                rawdata = p.readlines()
                sts = p.close()
                rs = re.compile(r"(console|rdp-tcp|rdp-tcp#\d+)\s*(\w+)\s+\d+", re.IGNORECASE)
                for line in rawdata:
                    s = re.search(rs,line)
                    if s:
                        userList.append(s.group(2).lower())
            except:
                logger.exception("_getLoggedInUsers1:qwinsta")
        else:
            try:
                objItems = GetObject("WinMgMts://./root/cimv2").InstancesOf("Win32_ComputerSystem")
                for item in objItems:
                    username = item.Properties_("UserName").Value
                    i = username.rfind("\\")
                    if i >= 0:
                        username = username[i + 1:]
                    userList.append(username.lower())
            except:
                logger.exception("_getLoggedInUsers1:Win32_ComputerSystem")
        return userList


    r"""
    # get the list of logged in users including processes running as auth user
    def _getLoggedInUsers2(self):
        userList = []
        p = os.popen("qprocess *", "r")
        rawdata = p.readlines()
        sts = p.close()
        rs = re.compile(">(network service|local service|\w+)\s*.*", re.IGNORECASE)
        for line in rawdata:
            #print line
            s = re.search(rs,line)
            if s:
                if s.group(1) == 'network service' or s.group(1) == 'local service': continue
                if s.group(1) not in userList:
                    userList.append(s.group(1).lower())
        return userList
    """


    # get first RN from the DN
    def _getRN(self, dn):
        try:
            start = dn.find("=")
            if start >= 0:
                end = dn.find(",")
                if end >= 0:
                    rn = dn.lower()[start+1:end]
                    return rn
        except:
            pass
        return ""


    # helper function to get the domain name in DN format
    def _getDomainDN(self, domainName):
        domainDN = ""
        try:
            RNs = domainName.split(".")
            domainstr = ""
            for rn in RNs:
                domainstr = domainstr + "dc=" + rn + ","
            domainDN = domainstr[:len(domainstr) - 1]
        except:
            pass
        return domainDN


    # helper function to get the user DN
    def _getUserDN(self, user, domain):
        try:
            objConnection = Dispatch("ADODB.Connection")
            objConnection.Open("Provider=ADsDSOObject;")
            objCommand = Dispatch("ADODB.Command")
            objCommand.ActiveConnection = objConnection
            objCommand.CommandText = "<LDAP://%s>;(&(objectCategory=user)(samAccountName=%s));distinguishedName" % (domain,user)
            objRecordSet = objCommand.Execute()
            rs = objRecordSet[0]
            while not rs.EOF:
                userDN = rs.Fields("distinguishedName")
                return str(userDN)
        except:
            pass
        return ""


    # helper function to get the computer DN
    def _getComputerDN(self, computer, domain):
        try:
            objConnection = Dispatch("ADODB.Connection")
            objConnection.Open("Provider=ADsDSOObject;")
            objCommand = Dispatch("ADODB.Command")
            objCommand.ActiveConnection = objConnection
            objCommand.CommandText = "<LDAP://%s>;(&(objectCategory=computer)(Name=%s));distinguishedName" % (domain,computer)
            objRecordSet = objCommand.Execute()
            rs = objRecordSet[0]
            while not rs.EOF:
                computerDN = rs.Fields("distinguishedName")
                return str(computerDN)
        except:
            pass
        return ""


    def checkADUserMembership(self, FullyQualifiedDomainName, GroupName):
        # get the list of logged in users
        userList = self._getLoggedInUsers1()

        # get the domain name in DN format
        domain = ""
        try:
            if FullyQualifiedDomainName == "":
                objSysInfo = Dispatch("ADSystemInfo")
                domainName = objSysInfo.DomainDNSName
                domain = self._getDomainDN(domainName)
            else:
                domain = self._getDomainDN(FullyQualifiedDomainName)
        except:
            logger.exception("Exception in checkADUserMembership")

        for user in userList:
            # get the user DN
            userDN = self._getUserDN(user, domain)

            astr = "LDAP://%s" % userDN
            try:
                # get the groups that this user is member of
                objUser = GetObject(astr)
                arrMemberOf = objUser.Get("memberOf")
                #print arrMemberOf,type(arrMemberOf)
                if arrMemberOf:
                    if type(arrMemberOf) == tuple:
                        for member in arrMemberOf:
                            group = self._getRN(member)
                            if group == GroupName.lower():
                                return True
                    else:
                        group = self._getRN(arrMemberOf)
                        if group == GroupName.lower():
                            return True
            except:
                logger.exception("Exception in checkADUserMembership")
        return False


    def checkADComputerMembership(self, FullyQualifiedDomainName, GroupName):
        # get the domain name in DN format
        domain = ""
        try:
            if FullyQualifiedDomainName == "":
                # get the domain name
                objSysInfo = Dispatch("ADSystemInfo")
                domainName = objSysInfo.DomainDNSName
                domain = self._getDomainDN(domainName)
            else:
                domain = self._getDomainDN(FullyQualifiedDomainName)
        except:
            logger.exception("Exception in checkADComputerMembership")

        newComputerDN = ""
        try:
            # get the name of this computer
            objSysInfo = Dispatch("ADSystemInfo")
            computerDN = objSysInfo.ComputerName
            computerRN = self._getRN(computerDN)

            # If the computer is connected to 2 domains, we want the DN for the user specified domain
            newComputerDN = self._getComputerDN(computerRN, domain)
        except:
            logger.exception("Exception in checkADComputerMembership")

        astr = "LDAP://%s" % newComputerDN
        try:
            # find out the groups this computer is member of
            objComputer = GetObject(astr)
            arrMemberOf = objComputer.Get("memberOf")
            if arrMemberOf:
                if type(arrMemberOf) == tuple:
                    for member in arrMemberOf:
                        group = self._getRN(member)
                        if group == GroupName.lower():
                            return True
                else:
                    group = self._getRN(arrMemberOf)
                    if group == GroupName.lower():
                        return True
        except:
            logger.exception("Exception in checkADComputerMembership")
        return False

    """
    # enumerates all the subkeys in HKU and checks the key,value pair
    # in currently logged in user's subkey only
    def _HKUEnum(self, key, valuename, req_value, type, enforce = False):
        noCurrentUser = False
        value = None
        hkey = hkeymap.get("HKU")
        try:
            root = _winreg.ConnectRegistry(None, hkey)
            try:
                nsubkeys, nvalues, mtime = _winreg.QueryInfoKey(root)
                for i in range(nsubkeys):
                    try:
                        subkeyname = _winreg.EnumKey(root, i)
                    except WindowsError as err:
                        continue
                    # ignore 'local system', 'local service' and 'network service' accounts
                    if subkeyname.startswith("S-1-5-18") or subkeyname.startswith("S-1-5-19") or subkeyname.startswith("S-1-5-20"):
                        continue
                    # ignore classes for any user and the default user subkey
                    if subkeyname.lower().endswith("_classes"): continue
                    #if subkeyname.lower().endswith("_classes") or subkeyname.lower() == ".default": continue
                    fullkey = "HKU\\%s\\%s" % (subkeyname, key)
                    #print fullkey
                    if type == _winreg.REG_DWORD:
                        value = self.winregint(fullkey, valuename)
                    elif type == _winreg.REG_SZ:
                        str = self.winregstr(fullkey, valuename)
                        if str:
                            value = str.lower()
                        else:
                            value = str
                    break
                else:
                    noCurrentUser = True
            finally:
                _winreg.CloseKey(root)
        except WindowsError:
            pass

        if noCurrentUser or value == req_value:
            return True
        else:
            return False
    """

    def HKUIntEnum(self, key, valuename, value):
        valList = self._HKUEnum(key, valuename, 0, _winreg.REG_DWORD)
        ret = True
        for val in valList:
            if val != value:
                ret = False
        return ret


    def HKUStrEnum(self, key, valuename, value):
        valList = self._HKUEnum(key, valuename, "", _winreg.REG_SZ)
        ret = True
        for val in valList:
            if val != value.lower():
                ret = False
        return ret


    def GetRunningProcesses(self):
        processList = FuelSet()
        try:
            objItems = GetObject("WinMgMts://./root/cimv2").InstancesOf("Win32_Process")
            for item in objItems:
                caption = item.Properties_("Caption").Value
                processList.add(caption.lower())
        except:
            logger.exception("Exception in GetRunningProcesses")
        return processList


    def KillProcess(self, ProcessName):
        oldcount = 0
        newcount = 0
        try:
            # kill the process named ProcessName
            query = "Select * from Win32_Process where Caption = '%s'" % (ProcessName.strip())
            WMIService = GetObject("winmgmts://./root/cimv2")
            objItems = WMIService.ExecQuery(query)
            for item in objItems:
                self.violation(0, "Process %s is running", ProcessName)
                if self.enforce:
                    handle = win32api.OpenProcess(1, False, item.Properties_("ProcessId").Value)
                    win32api.TerminateProcess(handle, -1)
                    win32api.CloseHandle(handle)
                    oldcount = oldcount + 1
        except:
            logger.exception("Exception in KillProcess")

        if self.enforce:
            # log the kill action
            try:
                query = "Select * from Win32_Process where Caption = '%s'" % (ProcessName.strip())
                WMIService = GetObject("winmgmts://./root/cimv2")
                objItems = WMIService.ExecQuery(query)
                for item in objItems:
                    newcount = newcount + 1
                if oldcount > newcount:
                    usermsg = "Killed %d process(es) named %s" % (oldcount - newcount, ProcessName)
                    before = "%d process(es) named %s running before" % (oldcount, ProcessName)
                    after = "%d process(es) named %s running after" % (newcount, ProcessName)
                    self.logaction("TerminateProcess", ProcessName, before, after, usermsg)
            except:
                logger.exception("Exception in KillProcess")


    def _ModifyADevice(self, accessType, device):
        path = os.path.join(self.options.agentbin, "devpolicy.exe")
        if os.path.exists(path):
            quotedpath = "\"" + path + "\""
            before = self.runscript(quotedpath, "status", device)
            text = self.runscript(quotedpath, accessType, device)
            after = self.runscript(quotedpath, "status", device)
            self.logaction(accessType, device, before, after, text)
        else:
            self.error(0, "Device utility could not be found")


    def GetStatusOfDeviceClass(self, DevClass):
        path = os.path.join(self.options.agentbin, "devpolicy.exe")
        if os.path.exists(path):
            if not DevClass.startswith("="):
                DevClass = "=" + DevClass
            quotedpath = "\"" + path + "\""
            return self.runscript(quotedpath, "status", DevClass)
        else:
            self.error(0, "Device utility could not be found")


    def EnableCDDrives(self, Enable):
        if self.enforce:
            if Enable:
                self._ModifyADevice("enable", "=CDROM")
            else:
                self._ModifyADevice("disable", "=CDROM")


    def EnableHIDClass(self, Enable):
        if self.enforce:
            if Enable:
                self._ModifyADevice("enable", "=HIDClass")
            else:
                self._ModifyADevice("disable", "=HIDClass")


    def _EnableLocalPrinter(self, Enable):
        if self.enforce:
            if Enable:
                self._ModifyADevice("enable", "=Printer")
            else:
                self._ModifyADevice("disable", "=Printer")


    def EnableMedia(self, Enable):
        if self.enforce:
            if Enable:
                self._ModifyADevice("enable", "=Media")
            else:
                self._ModifyADevice("disable", "=Media")


    def EnableModem(self, Enable):
        if self.enforce:
            if Enable:
                self._ModifyADevice("enable", "=Modem")
            else:
                self._ModifyADevice("disable", "=Modem")


    def EnableSmartCardReader(self, Enable):
        if self.enforce:
            if Enable:
                self._ModifyADevice("enable", "=SmartCardReader")
            else:
                self._ModifyADevice("disable", "=SmartCardReader")


    def _GetStatusOfUSBDevice(self, key):
        before = self.winregint(key, "Start")
        return before


    def _EnableUSBDevice(self, key, Enable):
        if self.enforce:
            beforeNum = self.winregint(key, "Start")
            if Enable:
                if beforeNum == 4 or beforeNum == None:
                    newVal = self.winregint(key, "OrigStart")
                    if newVal == None:
                        newVal = 2
                    self._setwinregraw(key, "Start", _winreg.REG_DWORD, newVal)
            else:
                if beforeNum != None and beforeNum != 4:
                    self._setwinregraw(key, "OrigStart", _winreg.REG_DWORD, beforeNum)
                    self._setwinregraw(key, "Start", _winreg.REG_DWORD, 4)


    def GetStatusOfUSBStorage(self):
        return self._GetStatusOfUSBDevice(r"HKLM\SYSTEM\CurrentControlSet\Services\UsbStor")

    def EnableUSBStorage(self, Enable):
        self._EnableUSBDevice(r"HKLM\SYSTEM\CurrentControlSet\Services\UsbStor", Enable)

    def GetStatusOfUSBPrinter(self):
        return self._GetStatusOfUSBDevice(r"HKLM\SYSTEM\CurrentControlSet\Services\UsbPrint")

    def EnableUSBPrinter(self, Enable):
        self._EnableUSBDevice(r"HKLM\SYSTEM\CurrentControlSet\Services\UsbPrint", Enable)

    def _CheckDeviceID(self, DeviceID):
        if DeviceID.find("*") >= 0:
            if len(DeviceID) < 10:
                self.error(0, "Invalid device ID %s", DeviceID)
            if DeviceID.count("*") > 2:
                self.error(0, "Invalid device ID %s", DeviceID)


    def GetStatusOfDevice(self, DeviceID):
        self._CheckDeviceID(DeviceID)
        path = os.path.join(self.options.agentbin, "devpolicy.exe")
        if os.path.exists(path):
            quotedpath = "\"" + path + "\""
            return self.runscript(quotedpath, "status", DeviceID)
        else:
            self.error(0, "Device utility could not be found")


    def EnableDevice(self, DeviceID, Enable):
        if self.enforce:
            self._CheckDeviceID(DeviceID)
            if Enable:
                self._ModifyADevice("enable", DeviceID)
            else:
                self._ModifyADevice("disable", DeviceID)




    # enumerates all the subkeys in HKU and checks the key,value pair
    # in currently logged in user's subkey only
    def _HKUEnum(self, key, valuename, req_value, type, enforce=False, all=False):
        valList = FuelSet()
        hkey = hkeymap.get("HKU")
        try:
            root = _winreg.ConnectRegistry(None, hkey)
            try:
                nsubkeys, nvalues, mtime = _winreg.QueryInfoKey(root)
                for i in range(nsubkeys):
                    try:
                        subkeyname = _winreg.EnumKey(root, i)
                    except WindowsError as err:
                        continue
                    # ignore 'local system', 'local service' and 'network service' accounts
                    if subkeyname.startswith("S-1-5-18") or subkeyname.startswith("S-1-5-19") or subkeyname.startswith("S-1-5-20"):
                        continue
                    # ignore classes for any user and the default user subkey
                    # .default contains the settings that windows uses to display desktop before any user logs in
                    if subkeyname.lower().endswith("_classes") or subkeyname.lower() == ".default": continue
                    fullkey = "HKU\\%s\\%s" % (subkeyname, key)
                    #print fullkey
                    value = None
                    if type == _winreg.REG_DWORD:
                        value = self.winregint(fullkey, valuename)
                        if value != req_value and enforce:
                            self._setwinregraw(fullkey, valuename, _winreg.REG_DWORD, req_value)
                    elif type == _winreg.REG_SZ:
                        astr = self.winregstr(fullkey, valuename)
                        if astr:
                            value = astr.lower()
                        if value != req_value and enforce:
                            self._setwinregraw(fullkey, valuename, _winreg.REG_SZ, req_value)
                    if all:
                        valList.add(value)
                    elif value is not None:
                        valList.add(value)
            finally:
                _winreg.CloseKey(root)
        except WindowsError:
            pass
        return valList


    def GetHKUInt(self, key, valuename, all=False):
        return self._HKUEnum(key, valuename, 0, _winreg.REG_DWORD, False, all)


    def GetHKUStr(self, key, valuename, all=False):
        return self._HKUEnum(key, valuename, "", _winreg.REG_SZ, False, all)


    def SetHKUInt(self, key, valuename, value):
        self._HKUEnum(key, valuename, value, _winreg.REG_DWORD, True)


    def SetHKUStr(self, key, valuename, value):
        self._HKUEnum(key, valuename, value, _winreg.REG_SZ, True)


    def SaveCNACMapping(self, PostureRuleID):
        pattern = r"%d.%d \d+\r\n" % (self.directiveid, self.directivever)
        replacement = "%d.%d %d\r\n" % (self.directiveid, self.directivever, PostureRuleID)
        outpath = os.path.join(self.options.agentdata, "eppdidmap.txt")
        if os.path.exists(outpath):
            try:
                f = open(outpath, "r")
                try:
                    text = f.read()
                finally:
                    f.close()
            except:
                logger.exception("Exception in SaveCNACMapping")
                self.error(0, "Rule mapping could not be written for posture rule id %d", PostureRuleID)
        else:
            text = ""
        if re.search(pattern, text):
            newtext = re.sub(pattern, replacement, text)
            try:
                f = open(outpath, "w")
                try:
                    f.write(newtext)
                finally:
                    f.close()
            except:
                logger.exception("Exception in SaveCNACMapping")
                self.error(0, "Rule mapping could not be written for posture rule id %d", PostureRuleID)
        else:
            try:
                f = open(outpath, "a")
                try:
                    if text != "" and not text.endswith("\r\n"):
                        f.write("\r\n")
                    f.write(replacement)
                finally:
                    f.close()
            except:
                logger.exception("Exception in SaveCNACMapping")
                self.error(0, "Rule mapping could not be written for posture rule id %d", PostureRuleID)


    def GetLocalGroupMembers(self, Group):
        members = FuelSet()
        success, marker = False, False
        command = 'net localgroup "%s"' % Group
        try:
            afile = os.popen(command, "r")
            for line in afile:
                if line.startswith(r"The command completed successfully."):
                    success = True
                    break
                if marker:
                    line = re.sub(r"\n", "", line)
                    line = re.sub(r"\r", "", line)
                    if line != "":
                        members.add(line)
                elif line.startswith("--------------------------------"):
                    marker = True
            afile.close()
            if success:
                return members
            else:
                return None
        except:
            logger.exception("Can't get local group members")
            return None


    def _GetProcessName(self, pid):
        try:
            objItems = GetObject("WinMgMts://./root/cimv2").InstancesOf("Win32_Process")
            for item in objItems:
                processID = item.Properties_("ProcessID").Value
                if processID == int(pid):
                    pname = item.Properties_("Caption").Value
                    if isinstance(pname, str):
                        return pname.encode("utf8")
                    else:
                        return pname
        except:
            logger.exception("Exception in _GetProcessName")
        return None


    def _wingetportbinding(self):
        portInfo = FuelSet()
        columns = ["proto", "localip", "localport",
                   "foreignip", "foreignport", "state", "pid"]
        _ipre = r"\d+\.\d+\.\d+\.\d+"
        _optipre = r"(" + _ipre + r"|\*)"
        _optport = r"(\d+|\*)"
        windows_linere = re.compile(
            r"\s*(?P<proto>(TCP|UDP))\s+"
            + r"(?P<localip>" + _ipre + r"):(?P<localport>\d+)\s+"
            + r"(?P<foreignip>" + _optipre + r"):(?P<foreignport>" + _optport+r")\s+"
            + r"(?P<state>[^\s]*)\s+"
            + r"(?P<pid>\d+)\s*")
        afile = os.popen("netstat -ano", "r")
        try:
            for line in afile:
                match = windows_linere.match(line)
                if match:
                    proto, localip, localport, foreignip, foreignport, state, pid = \
                        match.group("proto", "localip", "localport",
                        "foreignip", "foreignport", "state", "pid")
                    #if localport.isdigit() and int(localport) == port:
                    processName = self._GetProcessName(pid)
                    portInfo.add(NetstatInfo(proto, localip, localport, foreignip, foreignport, state, pid, processName))
        finally:
            afile.close()

##        #for testing only
##        portInfo.add(NetstatInfo("tcp", "", "90", "", "0", "", "0", "a"))
##        portInfo.add(NetstatInfo("udp", "", "90", "", "0", "", "0", "a"))
##        portInfo.add(NetstatInfo("tcp", "", "100", "", "0", "", "0", "b"))

        return portInfo


    def _walkregval_ex(self, key, appName):
        rs = re.compile(appName, re.IGNORECASE)
        nsubkeys, nvalues, mtime = _winreg.QueryInfoKey(key)
        ret = False
        ver = ""
        for i in range(nvalues):
            nm, val, typ = _winreg.EnumValue(key, i)
            if isinstance(nm, str):
                nm = nm.encode("utf8")
            if isinstance(val, str):
                val = val.encode("utf8")
            if nm.lower() == "displayname":
                if re.match(rs, val):
                    ret = True
            if nm.lower() == "displayversion":
                ver = val
        return ret, ver


    def _getAppVer(self, appName):
        ret, ver = False, ""
        path = r"Software\Microsoft\Windows\CurrentVersion\Uninstall"
        try:
            rootkey = _winreg.OpenKey(getattr(_winreg, "HKEY_LOCAL_MACHINE"), path)
        except WindowsError as err:
            return ret, ver
        try:
            nsubkeys, nvalues, mtime = _winreg.QueryInfoKey(rootkey)
            for i in range(nsubkeys):
                try:
                    subkeyname = _winreg.EnumKey(rootkey, i)
                except WindowsError as err:
                    continue # continue if possible
                subkeypath = path + "\\" + subkeyname
                try:
                    subkey = _winreg.OpenKey(rootkey, subkeyname)
                except WindowsError as err:
                    continue # continue if possible
                try:
                    ret, ver =  self._walkregval_ex(subkey, appName)
                    if ret:
                        break
                finally:
                    _winreg.CloseKey(subkey)
        finally:
            _winreg.CloseKey(rootkey)
        return ret, ver


    def _compareVal(self, op, req_val, val):
        if op == ">=":
            return val >= req_val
        if op == "<=":
            return val <= req_val
        if op == ">":
            return val > req_val
        if op == "<":
            return val < req_val
        if op == "=":
            return val == req_val
        if op == "!=":
            return val != req_val
        return True


    def _convertOp(self, opset):
        for op in opset:
            # we are expecting only one operator in the set
            return op


    def _compareVerPart(self, op, req_val, val, part):
        msg = ""
        mismatch = False
        # if both values are numbers, we do integer comparison
        # otherwise we do string comparison
        if req_val.isdigit() and val.isdigit():
            if not self._compareVal(op, int(req_val), int(val)):
                mismatch = True
        else:
            if not self._compareVal(op, req_val, val):
                mismatch = True
        if mismatch:
            msg = "%s part of the version: expected '%s %s' but found %r" % (part, op, req_val, val)
        return msg


    def CheckAppVer(self, AppName, Operator1, VerPart1, Operator2, VerPart2, Operator3, VerPart3, Operator4, VerPart4):
        ret, ver = self._getAppVer(AppName)
        if ret:
            if ver == "":
                msg =  "Application %s is installed but version could not be determined" % AppName
                return msg
##            print AppName
##            print "x%s.%s.%s.%sx" % (VerPart1, VerPart2, VerPart3, VerPart4)
##            print "x%sx" % ver
            VerPart1 = VerPart1.strip()
            VerPart2 = VerPart2.strip()
            VerPart3 = VerPart3.strip()
            VerPart4 = VerPart4.strip()
            msg1, msg2, msg3, msg4 = "", "", "", ""
            ver1, ver2, ver3, ver4 = "", "", "", ""
            verParts = ver.split(".")
            if len(verParts) >= 1:
                ver1 = verParts[0].strip()
            if len(verParts) >= 2:
                ver2 = verParts[1].strip()
            if len(verParts) >= 3:
                ver3 = verParts[2].strip()
            if len(verParts) >= 4:
                ver4 = verParts[3].strip()
            if VerPart1 != "*":
                msg1 = self._compareVerPart(self._convertOp(Operator1), VerPart1, ver1, "First")
            if VerPart2 != "*":
                msg2 = self._compareVerPart(self._convertOp(Operator2), VerPart2, ver2, "Second")
            if VerPart3 != "*":
                msg3 = self._compareVerPart(self._convertOp(Operator3), VerPart3, ver3, "Third")
            if VerPart4 != "*":
                msg4 = self._compareVerPart(self._convertOp(Operator4), VerPart4, ver4, "Fourth")
            if msg1 != "" or msg2 != "" or msg3 != "" or msg4 != "":
                msg = "Version mismatch for %s" % AppName
                if msg1 != "":
                    msg = msg + "\r\n" + msg1
                if msg2 != "":
                    msg = msg + "\r\n" + msg2
                if msg3 != "":
                    msg = msg + "\r\n" + msg3
                if msg4 != "":
                    msg = msg + "\r\n" + msg4
                return msg
            return None
        else:
            msg = "Application %s could not be found" % AppName
            return msg


    # a function to expand file names like %SystemRoot%\abc.txt
    def ExpandFileName(self, filename):
        return self._expand_file_name(filename)


    # this function returns the base key names for all the users except
    # local system, network service, local service.
    def HKUEnumUserKeys(self):
        valList = FuelSet()
        hkey = hkeymap.get("HKU")
        try:
            root = _winreg.ConnectRegistry(None, hkey)
            try:
                nsubkeys, nvalues, mtime = _winreg.QueryInfoKey(root)
                for i in range(nsubkeys):
                    try:
                        subkeyname = _winreg.EnumKey(root, i)
                    except WindowsError as err:
                        continue
                    # ignore 'local system', 'local service' and 'network service' accounts
                    if subkeyname.startswith("S-1-5-18") or subkeyname.startswith("S-1-5-19") or subkeyname.startswith("S-1-5-20"):
                        continue
                    # ignore classes for any user
                    if subkeyname.lower().endswith("_classes"): continue
                    fullkey = "HKU\\%s" % subkeyname
                    valList.add(fullkey)
            finally:
                _winreg.CloseKey(root)
        except:
            pass
        return valList

    def _fixtime(self, s):
        # Input is of the form YYYYMMDDhhmmss.uuuuuu-zzz
        # what is uuuuuu?
        assert len(s) == 25
        YYYY, MM, DD, hh, mm, ss = map(int,
            [s[0:4], s[4:6], s[6:8], s[8:10], s[10:12], s[12:14]])
        #dot_uuuuuu = s[14:21]
        #assert dot_uuuuuu.startswith("."), dot_uuuuuu
        #sgn_zzz = s[21:25]
        #assert sgn_zzz.startswith("+") or sgn_zzz.startswith("-"), sgn_zzz
        t = (YYYY, MM, DD, hh, mm, ss, 0, 1, -1) # Assume it's local time
        return time.strftime("%c", t)

    def GetLoginAttempts(self, Days=1, LoginType="both"):
        count, text = self._GetLoginAttempts(Days, LoginType)
        return count

    def GetLoginAttemptData(self, Days=1, LoginType="both"):
        # check auditlogonevents setting because it generates
        # records for local logins as well as domain logins
        warning = ""
        if (LoginType == "both"):
            if self.check_through_secedit("[Event Audit]", "AuditLogonEvents = 3", "SECURITYPOLICY") < 0:
                warning = ERRMSG_BOTH
        elif (LoginType == "success"):
            if self.check_through_secedit("[Event Audit]", "AuditLogonEvents = 3", "SECURITYPOLICY") < 0:
                if self.check_through_secedit("[Event Audit]", "AuditLogonEvents = 1", "SECURITYPOLICY") < 0:
                    warning = ERRMSG_SUCCESS
        elif (LoginType == "failure"):
            if self.check_through_secedit("[Event Audit]", "AuditLogonEvents = 3", "SECURITYPOLICY") < 0:
                if self.check_through_secedit("[Event Audit]", "AuditLogonEvents = 2", "SECURITYPOLICY") < 0:
                    warning = ERRMSG_FAILURE

        count, text = self._GetLoginAttempts(Days, LoginType)
        return warning + text

    def _GetLoginAttempts(self, Days, LoginType):
        crlf_pattern = re.compile(r"(\r\n)+")
        user_name = "User Name:"
        logon_type = "Logon Type:"
        domain_name = "Domain:"
        workstation_name = "Workstation Name:"
        client_name = "Client Name:"
        client_address = "Client Address:"

        # generate the time stamp to be used in the query
        if Days <= 1:
            days_ago = datetime.date.today()
        else:
            days_ago = datetime.date.today() - datetime.timedelta(days=Days - 1)
        if time.timezone > 0:
            timestr = "%04d%02d%02d000000.000000-%03d" %(days_ago.year, days_ago.month, days_ago.day, time.timezone/60)
        else:
            timestr = "%04d%02d%02d000000.000000+%03d" %(days_ago.year, days_ago.month, days_ago.day, time.timezone/60)

        # prepare the query
        query = "Select * from Win32_NTLogEvent where logfile = 'Security' \
            and TimeWritten > '%s' and \
            (EventCode != 538 and EventCode >= 528 and EventCode <= 540)" % timestr
        if LoginType.lower() == "success":
            query = "Select * from Win32_NTLogEvent where logfile = 'Security' \
                and TimeWritten > '%s' and \
                (EventCode = 528 or EventCode = 540)" % timestr
        elif LoginType.lower() == "failure":
            query = "Select * from Win32_NTLogEvent where logfile = 'Security' \
                and TimeWritten > '%s' and \
                ((EventCode != 538) and (EventCode >= 529 and EventCode <= 539))" % timestr

        #print query

        try:
            objItems = GetObject("winmgmts:{impersonationLevel=impersonate, \
                (Security, Audit)}\\\\.\\root\\cimv2").ExecQuery(query)
        except Exception as err:
            logger.exception("GetLoginAttempts: GetObject on Win32_NTLogEvent failed")
            self.error(0, "Login attempts could not be obtained")

        loginCount = 0
        entryDict = {}
        timeList = []
        try:
            for item in objItems:
                user = ""
                ltype = ""
                domain = ""
                clientmachine = ""
                clientaddress = ""

                try:
                    timegenerated = item.TimeGenerated
                    #print timegenerated
                    # if the time stamp is too old, break out
                    if not self._checktime(timegenerated, Days):
                        break
                    eventcode = item.EventCode
                    code = event_map[eventcode]
                    msg = item.Message
                except Exception as err:
                    logger.exception("GetLoginAttempts: item data error")
                    self.error(0, "Login attempts could not be obtained")

                # message has multiple \r\n pairs and \t at random places
                # get rid of these
                msg = crlf_pattern.sub("\r\n", msg)
                msg = msg.replace('\t', "")

                i = msg.find(user_name)
                if i >= 0:
                    j = msg.find("\r\n", i + 1)
                    if j > i + len(user_name):
                        user = msg[i + len(user_name):j]
                if user == "" and item.User != None:
                    user = item.User

                # ignore events in which user name ends with $, which indicates
                # that system services on a remote system are connected to the
                # system services on this system
                if user.endswith("$"):
                    continue

                # ignore events in which the User Name is SYSTEM, which indicates
                # that one system service was connecting to another service on
                # the same system
                # Anonymous logons identify network logons for which credentials
                # are not provided, such as connections to web server
                if user.upper() in (r"NT AUTHORITY\SYSTEM", r"NT AUTHORITY\ANONYMOUS LOGON", r"NT AUTHORITY\ANONYMOUS", "NETWORK SERVICE", "LOCAL SERVICE", "SYSTEM", "LOCAL SYSTEM", "ANONYMOUS LOGON"):
                    continue

                # get domain
                i = msg.find(domain_name)
                if i >= 0:
                    j = msg.find("\r\n", i + 1)
                    if j > i + len(domain_name):
                        domain = msg[i + len(domain_name):j]

                # not every logon has Logon Type
                i = msg.find(logon_type)
                if i >= 0:
                    j = msg.find("\r\n", i + 1)
                    if j > i + len(logon_type):
                        ltype = str(msg[i + len(logon_type):j])

                        # we don't care for unlock or cached logons
                        if ltype == '7' or ltype == '11' or ltype == '12' or ltype == '13':
                            continue
                        if ltype in logon_map:
                            ltype = logon_map[ltype]


                i = msg.find(workstation_name)
                if i >= 0:
                    j = msg.find("\r\n", i + 1)
                    if j > i + len(workstation_name):
                        clientmachine = msg[i + len(workstation_name):j]

                i = msg.find(client_name)
                if i >= 0:
                    j = msg.find("\r\n", i + 1)
                    if j > i + len(client_name):
                        clientmachine = msg[i + len(client_name):j]

                # not every logon has Client Address
                i = msg.find(client_address)
                if i >= 0:
                    j = msg.find("\r\n", i + 1)
                    if j > i + len(client_address):
                        clientaddress = msg[i + len(client_address):j]

                text = FORMAT % (
                    self._fixtime(timegenerated), code, ltype,
                    user, domain, clientmachine, clientaddress)
                entryDict[timegenerated] = text
                timeList.append(timegenerated)

                loginCount = loginCount + 1

            # sort the lines by date
            timeList.sort()
            timeList.reverse()
            sortedLines = ""
            for a in timeList:
                sortedLines += entryDict[a]
        except:
            logger.exception("_GetLoginAttempts: objItems iterations failed")
            self.error(0, "Login attempts could not be obtained")
        return (loginCount, sortedLines)


    def _checktime(self, s, Days):
        # Input is of the form YYYYMMDDhhmmss.uuuuuu-zzz
        assert len(s) == 25
        YYYY, MM, DD, hh, mm, ss = map(int,
            [s[0:4], s[4:6], s[6:8], s[8:10], s[10:12], s[12:14]])
        date_record = datetime.date(YYYY, MM, DD)
        if Days <= 1:
            days_ago = datetime.date.today()
        else:
            days_ago = datetime.date.today() - datetime.timedelta(days=Days - 1)
        #print date_record, days_ago
        if date_record >= days_ago:
            return True
        else:
            return False


    # helper function to get the current event setting
    def _GetCurrentEventSetting(self, section, event, area):
        value = self.wmi_audit_policy_query(event)
        if value == None:
            entry = "%s = 3" % event
            ret = self.check_through_secedit(section, entry, area)
            if ret < 0:
                entry = "%s = 1" % event
                ret = self.check_through_secedit(section, entry, area)
                if ret < 0:
                    entry = "%s = 2" % event
                    ret = self.check_through_secedit(section, entry, area)
                    if ret < 0:
                        value = 0
                    else:
                        value = 2
                else:
                    value = 1
            else:
                value = 3
        return value


    # this function gets and sets the audit event settings
    def AuditSettings(self, EventType, Condition, Exact):
        # validate the arguments
        if Condition not in (0, 1, 2, 3):
            self.error(0, "Invalid condition (%d) specified", Condition)

        event_type = EventType.lower()
        if event_type not in ('auditaccountlogon', 'auditdsaccess',
            'auditprivilegeuse', 'auditsystemevents', 'auditprocesstracking',
            'auditaccountmanage', 'auditlogonevents', 'auditobjectaccess'):
            self.error(0, "Invalid event (%s) specified", EventType)

        # get the current setting
        before = self._GetCurrentEventSetting("[Event Audit]", EventType, "SECURITYPOLICY")

        # check if proper auditing is set
        entry = ""
        if Exact:
            if Condition != before:
                if before == 0:
                    self.violation(0, "Event %s is not set", EventType)
                else:
                    if before in eventmap:
                        self.violation(0, "Event %s is set to %s", EventType, eventmap.get(before))
                    else:
                        self.violation(0, "Event %s is set to %r", EventType, before)
                if self.enforce:
                    entry = "%s = %d" % (EventType, Condition)
        else:
            if Condition == 0:
                if before != 0:
                    self.violation(0, "Event %s should not be set", EventType)
                    if self.enforce:
                        entry = "%s = 0" % EventType
            elif before != Condition and before != 3:
                if before == 0:
                    self.violation(0, "Event %s is not set", EventType)
                else:
                    if before in eventmap:
                        self.violation(0, "Event %s is set to %s", EventType, eventmap.get(before))
                    else:
                        self.violation(0, "Event %s is set to %r", EventType, before)
                if self.enforce:
                    entry = "%s = %d" % (EventType, before or Condition)

        if entry != "":
            self.config_through_secedit("[Event Audit]", entry, "SECURITYPOLICY")
            after = self._GetCurrentEventSetting("[Event Audit]", EventType, "SECURITYPOLICY")
            if after == before:
                self.error(0, "Event %s setting could not be enforced", EventType)
            else:
                beforestr = "%d" % before
                afterstr = "%d" % after
                usermsg = "Modified from %r to %r" % (beforestr, afterstr)
                self.logaction("Audit setting", EventType, beforestr, afterstr, usermsg)


    # anti virus functions
    avcollector = AVCollector()
    def GetAVName(self):
        avnames = FuelSet()
        if len(self.avcollector.avset) == 0:
            gather_winantivirus.Gather(self.avcollector)
        #print self.avcollector.avset
        for av in self.avcollector.avset:
            avnames.add(av[0])
        return avnames

    def GetAVVersion(self):
        avvers = FuelSet()
        if len(self.avcollector.avset) == 0:
            gather_winantivirus.Gather(self.avcollector)
        for av in self.avcollector.avset:
            avvers.add(av[1])
        #print avvers
        return avvers

    def GetAVDefVersion(self):
        avvers = FuelSet()
        if len(self.avcollector.avset) == 0:
            gather_winantivirus.Gather(self.avcollector)
        for av in self.avcollector.avset:
            avvers.add(av[2])
        #print avvers
        return avvers

    def CheckAVDate(self, Days):
        if Days <= 1:
            days_ago = datetime.date.today()
        else:
            days_ago = datetime.date.today() - datetime.timedelta(days=Days - 1)
        t = (days_ago.year, days_ago.month, days_ago.day, 0, 0, 0, -1, -1, -1) # Assume it's local time
        mintime = int(time.mktime(t))
        if len(self.avcollector.avset) == 0:
            gather_winantivirus.Gather(self.avcollector)
        for av in self.avcollector.avset:
            #print time.ctime(mintime), time.ctime(av[3])
            if mintime <= av[3]:
                return True
        return False

    def CheckAVLastUsed(self, Days):
        if Days <= 1:
            days_ago = datetime.date.today()
        else:
            days_ago = datetime.date.today() - datetime.timedelta(days=Days - 1)
        t = (days_ago.year, days_ago.month, days_ago.day, 0, 0, 0, -1, -1, -1) # Assume it's local time
        mintime = int(time.mktime(t))
        if len(self.avcollector.avset) == 0:
            gather_winantivirus.Gather(self.avcollector)
        for av in self.avcollector.avset:
            #print time.ctime(mintime), time.ctime(av[4])
            if mintime <= av[4]:
                return True
        return False


    # anti spyware functions
    aswcollector = ASWCollector()
    def GetASWName(self):
        aswnames = FuelSet()
        if len(self.aswcollector.aswset) == 0:
            gather_winantisw.Gather(self.aswcollector)
        for asw in self.aswcollector.aswset:
            aswnames.add(asw[0])
        #print aswnames
        return aswnames

    def GetASWVersion(self):
        aswvers = FuelSet()
        if len(self.aswcollector.aswset) == 0:
            gather_winantisw.Gather(self.aswcollector)
        for asw in self.aswcollector.aswset:
            aswvers.add(asw[1])
        #print aswvers
        return aswvers

    def GetASWDefVersion(self):
        aswvers = FuelSet()
        if len(self.aswcollector.aswset) == 0:
            gather_winantisw.Gather(self.aswcollector)
        for asw in self.aswcollector.aswset:
            aswvers.add(asw[2])
        #print aswvers
        return aswvers

    def CheckASWLastUsed(self, Days):
        if Days <= 1:
            days_ago = datetime.date.today()
        else:
            days_ago = datetime.date.today() - datetime.timedelta(days=Days - 1)
        t = (days_ago.year, days_ago.month, days_ago.day, 0, 0, 0, -1, -1, -1) # Assume it's local time
        mintime = int(time.mktime(t))
        if len(self.aswcollector.aswset) == 0:
            gather_winantisw.Gather(self.aswcollector)
        for asw in self.aswcollector.aswset:
            #print time.ctime(mintime), time.ctime(asw[3])
            if mintime <= asw[3]:
                return True
        return False


    def GetWMIObjectsUsingClassName(self, ClassName, NameSpace="root/cimv2", ObjectLimit=1000):
        """Return a set of wmi objects wrapped in fuel."""
        wmiSet = FuelSet()
        count = 0
        moniker = "WinMgMts://./%s" % NameSpace
        try:
            objItems = GetObject(moniker).InstancesOf(ClassName)
            for item in objItems:
                if count >= ObjectLimit:
                    break;
                wmiSet.add(WMIObject(item))
                count = count + 1
            return wmiSet
        except Exception as details:
            logger.exception("Exception in GetWMIObjectsUsingClassName")
            self.error(0, "COM exception: %s", details)


    def GetWMIObjectsUsingQuery(self, Query, NameSpace="root/cimv2", ObjectLimit=1000):
        """Return a set of wmi objects wrapped in fuel."""
        wmiSet = FuelSet()
        count = 0
        moniker = "WinMgMts://./%s" % NameSpace
        try:
            objItems = GetObject(moniker).ExecQuery(Query)
            for item in objItems:
                if count >= ObjectLimit:
                    break;
                wmiSet.add(WMIObject(item))
                count = count + 1
            return wmiSet
        except Exception as details:
            logger.exception("Exception in GetWMIObjectsUsingQuery")
            self.error(0, "COM exception: %s", details)


    def GetWMIObjectsUsingMoniker(self, Moniker, Query, ObjectLimit=1000):
        """Return a set of wmi objects wrapped in fuel."""
        wmiSet = FuelSet()
        count = 0
        try:
            objItems = GetObject(Moniker).ExecQuery(Query)
            for item in objItems:
                if count >= ObjectLimit:
                    break;
                wmiSet.add(WMIObject(item))
                count = count + 1
            return wmiSet
        except Exception as details:
            logger.exception("Exception in GetWMIObjectsUsingMoniker")
            self.error(0, "COM exception: %s", details)
