def __init__(self, configyaml=None): if configyaml == None: self.config = None self.order = None self.fieldmappings = dict() self.logsources = dict() self.defaultindex = None self.backend = None else: config = yaml.safe_load(configyaml) self.config = config self.fieldmappings = dict() try: for source, target in config['fieldmappings'].items(): self.fieldmappings[source] = FieldMapping(source, target) except TypeError as e: raise SigmaConfigParseError("Configuration has wrong type, should be map") from e except KeyError: pass if type(self.fieldmappings) != dict: raise SigmaConfigParseError("Fieldmappings must be a map") self.order = config.setdefault("order", None) self.defaultindex = config.setdefault('defaultindex', None) self.logsources = list() self.backend = None
def __init__(self, configyaml=None): if configyaml == None: self.config = None self.fieldmappings = dict() self.logsources = dict() self.logsourcemerging = SigmaLogsourceConfiguration.MM_AND self.defaultindex = None self.backend = None else: config = yaml.safe_load(configyaml) self.config = config self.fieldmappings = dict() try: for source, target in config['fieldmappings'].items(): self.fieldmappings[source] = FieldMapping(source, target) except KeyError: pass if type(self.fieldmappings) != dict: raise SigmaConfigParseError("Fieldmappings must be a map") try: self.logsourcemerging = config['logsourcemerging'] except KeyError: self.logsourcemerging = SigmaLogsourceConfiguration.MM_AND try: self.defaultindex = config['defaultindex'] except KeyError: self.defaultindex = None self.logsources = list() self.backend = None
def set_backend(self, backend): """Set backend. This is used by other code to determine target properties for index addressing""" self.backend = backend if self.config != None: if 'logsources' in self.config: logsources = self.config['logsources'] if type(logsources) != dict: raise SigmaConfigParseError("Logsources must be a map") for name, logsource in logsources.items(): self.logsources.append(SigmaLogsourceConfiguration(logsource, self.defaultindex))
def __init__(self, logsource=None, defaultindex=None): if logsource == None: # create empty object self.merged = False self.category = None self.product = None self.service = None self.index = list() self.conditions = list( ) # a list of (field, value) tuples which are OR-linked in the generated query. May also contain such a list as list element (in case of merged log sources) self.rewrite = None elif type(logsource) == list and all([ isinstance(o, SigmaLogsourceConfiguration) for o in logsource ]): # list of SigmaLogsourceConfigurations: merge self.merged = True if any([ ls.merged for ls in logsource ]): # Ensure that already merged objects are not merged again raise TypeError( "Nested merging of SigmaLogsourceConfiguration objects is not allowed" ) rewrites = { ls.rewrite for ls in logsource if ls.rewrite is not None } if len(rewrites) > 1: raise ValueError( "More than one matching log source contains a rewrite part" ) elif len(rewrites) == 1: self.rewrite = rewrites.pop() else: self.rewrite = None # Merge category, product and service categories = { ls.category for ls in logsource if ls.category is not None } products = { ls.product for ls in logsource if ls.product is not None } services = { ls.service for ls in logsource if ls.service is not None } if len(categories) > 1 or len(products) > 1 or len(services) > 1: raise ValueError( "Merged SigmaLogsourceConfigurations must have disjunct categories (%s), products (%s) and services (%s)" % (str(categories), str(products), str(services))) try: self.category = categories.pop() except KeyError: self.category = None try: self.product = products.pop() except KeyError: self.product = None try: self.service = services.pop() except KeyError: self.service = None # Merge all index patterns self.index = list( set([index for ls in logsource for index in ls.index])) # unique(flat(logsources.index)) if len( self.index ) == 0 and defaultindex is not None: # if no index pattern matched and default index is present: use default index if type(defaultindex) == str: self.index = [defaultindex] elif type(defaultindex) == list and all( [type(i) == str for i in defaultindex]): self.index = defaultindex else: raise TypeError( "Default index must be string or list of strings") self.conditions = [ ls.conditions for ls in logsource if ls.conditions ] # build list of list of (field, value) tuples as base for merged query condition. elif type(logsource ) == dict: # create logsource configuration from parsed yaml self.merged = False if 'category' in logsource and type(logsource['category']) != str \ or 'product' in logsource and type(logsource['product']) != str \ or 'service' in logsource and type(logsource['service']) != str: raise SigmaConfigParseError( "Logsource category, product or service must be a string") try: self.category = logsource['category'] except KeyError: self.category = None try: self.product = logsource['product'] except KeyError: self.product = None try: self.service = logsource['service'] except KeyError: self.service = None if self.category == None and self.product == None and self.service == None: raise SigmaConfigParseError( "Log source definition will not match") try: if type(logsource['rewrite']) is not dict: raise SigmaConfigParseError("Rewrite rule must be a map") rewrite = logsource['rewrite'] if not {'category', 'product', 'service'}.issuperset( rewrite.keys()): raise SigmaConfigParseError( "Rewrite rule in log source configuration may only contain the keys 'category', 'product' and 'service'" ) if {str} != {type(value) for value in rewrite.values()}: raise SigmaConfigParseError( "Rewrite rule values may only contain strings") self.rewrite = tuple( (rewrite.get(key) for key in ('category', 'product', 'service') )) # build a (category, product, service) tuple from dict except KeyError: self.rewrite = None if 'index' in logsource: index = logsource['index'] if type(index) not in (str, list): raise SigmaConfigParseError( "Logsource index must be string or list of strings") if type(index) == list and not all( [type(index) == str for index in logsource['index']]): raise SigmaConfigParseError( "Logsource index patterns must be strings") if type(index) == list: self.index = index else: self.index = [index] else: # no default index handling here - this branch is executed if log source definitions are parsed from # config and these must not necessarily contain an index definition. A valid index may later be result # from a merge, where default index handling applies. self.index = [] try: if type(logsource['conditions']) != dict: raise SigmaConfigParseError( "Logsource conditions must be a map") self.conditions = [ (field, value) for field, value in logsource['conditions'].items() ] # build list of (field, value) tuples as base for query condition except KeyError: self.conditions = list() else: raise SigmaConfigParseError("Logsource definitions must be maps")
def __init__(self, logsource=None, defaultindex=None, name=None, mergemethod=MM_AND, indexfield=None): self.name = name self.indexfield = indexfield if logsource == None: # create empty object self.category = None self.product = None self.service = None self.index = list() self.conditions = None elif type(logsource) == list and all([isinstance(o, SigmaLogsourceConfiguration) for o in logsource]): # list of SigmaLogsourceConfigurations: merge according to mergemethod # Merge category, product and service categories = set([ ls.category for ls in logsource if ls.category != None ]) products = set([ ls.product for ls in logsource if ls.product != None ]) services = set([ ls.service for ls in logsource if ls.service != None]) if len(categories) > 1 or len(products) > 1 or len(services) > 1: raise ValueError("Merged SigmaLogsourceConfigurations must have disjunct categories (%s), products (%s) and services (%s)" % (str(categories), str(products), str(services))) try: self.category = categories.pop() except KeyError: self.category = None try: self.product = products.pop() except KeyError: self.product = None try: self.service = services.pop() except KeyError: self.service = None # Merge all index patterns self.index = list(set([index for ls in logsource for index in ls.index])) # unique(flat(logsources.index)) if len(self.index) == 0 and defaultindex is not None: # if no index pattern matched and default index is present: use default index if type(defaultindex) == str: self.index = [defaultindex] elif type(defaultindex) == list and all([type(i) == str for i in defaultindex]): self.index = defaultindex else: raise TypeError("Default index must be string or list of strings") # "merge" index field (should never differ between instances because it is provided by backend class indexfields = [ ls.indexfield for ls in logsource if ls.indexfield != None ] try: self.indexfield = indexfields[0] except IndexError: self.indexfield = None # Merge conditions according to mergemethod if mergemethod == self.MM_AND: cond = ConditionAND() elif mergemethod == self.MM_OR: cond = ConditionOR() else: raise ValueError("Mergemethod must be '%s' or '%s'" % (self.MM_AND, self.MM_OR)) for ls in logsource: if ls.conditions != None: cond.add(ls.conditions) if len(cond) > 0: self.conditions = cond else: self.conditions = None elif type(logsource) == dict: # create logsource configuration from parsed yaml if 'category' in logsource and type(logsource['category']) != str \ or 'product' in logsource and type(logsource['product']) != str \ or 'service' in logsource and type(logsource['service']) != str: raise SigmaConfigParseError("Logsource category, product or service must be a string") try: self.category = logsource['category'] except KeyError: self.category = None try: self.product = logsource['product'] except KeyError: self.product = None try: self.service = logsource['service'] except KeyError: self.service = None if self.category == None and self.product == None and self.service == None: raise SigmaConfigParseError("Log source definition will not match") if 'index' in logsource: index = logsource['index'] if type(index) not in (str, list): raise SigmaConfigParseError("Logsource index must be string or list of strings") if type(index) == list and not all([type(index) == str for index in logsource['index']]): raise SigmaConfigParseError("Logsource index patterns must be strings") if type(index) == list: self.index = index else: self.index = [ index ] else: # no default index handling here - this branch is executed if log source definitions are parsed from # config and these must not necessarily contain an index definition. A valid index may later be result # from a merge, where default index handling applies. self.index = [] if 'conditions' in logsource: if type(logsource['conditions']) != dict: raise SigmaConfigParseError("Logsource conditions must be a map") cond = ConditionAND() for key, value in logsource['conditions'].items(): cond.add((key, value)) self.conditions = cond else: self.conditions = None else: raise SigmaConfigParseError("Logsource definitions must be maps")