Beispiel #1
0
def browser_supports_canvas():
    user_agent = html.request.user_agent

    if 'MSIE' in user_agent:
        matches = regex(r'MSIE ([0-9]{1,}[\.0-9]{0,})').search(user_agent)
        if matches:
            ie_version = float(matches.group(1))
            if ie_version >= 9.0:
                return True

        # Trying to deal with the IE compatiblity mode to detect the real IE version
        matches = regex(r'Trident/([0-9]{1,}[\.0-9]{0,})').search(user_agent)
        if matches:
            trident_version = float(matches.group(1)) + 4
            if trident_version >= 9.0:
                return True

        return False
    else:
        return True
Beispiel #2
0
    def _convert_pattern_list(self, patterns):
        # type: (List[Text]) -> Tuple[bool, Pattern[Text]]
        """Compiles a list of service match patterns to a to a single regex

        Reducing the number of individual regex matches improves the performance dramatically.
        This function assumes either all or no pattern is negated (like WATO creates the rules).
        """
        if not patterns:
            return False, regex(u"")  # Match everything

        negate, patterns = parse_negated_condition_list(patterns)

        pattern_parts = []
        for p in patterns:
            if isinstance(p, dict):
                pattern_parts.append(p["$regex"])
            else:
                pattern_parts.append(p)

        return negate, regex("(?:%s)" % "|".join("(?:%s)" % p for p in pattern_parts))
Beispiel #3
0
def _event_match_servicegroups(rule, context, is_regex):
    # type: (EventRule, EventContext, bool) -> Optional[str]
    if is_regex:
        match_type, required_groups = rule.get("match_servicegroups_regex",
                                               (None, None))
    else:
        required_groups = rule.get("match_servicegroups")

    if context["WHAT"] != "SERVICE":
        if required_groups:
            return "This rule requires membership in a service group, but this is a host notification"
        return None

    if required_groups is not None:
        sgn = context.get("SERVICEGROUPNAMES")
        if sgn is None:
            return (
                "No information about service groups is in the context, but service "
                "must be in group %s" % (" or ".join(required_groups)))
        if sgn:
            servicegroups = sgn.split(",")
        else:
            return "The service is in no service group, but %s%s is required" % (
                (is_regex and "regex " or ""), " or ".join(required_groups))

        for group in required_groups:
            if is_regex:
                r = regex(group)
                for sg in servicegroups:
                    if config.define_servicegroups is None:
                        continue
                    match_value = config.define_servicegroups[
                        sg] if match_type == "match_alias" else sg
                    if r.search(match_value):
                        return None
            elif group in servicegroups:
                return None

        if is_regex:
            if match_type == "match_alias":
                if config.define_servicegroups is None:
                    return "No service groups defined."
                return "The service is only in the groups %s. None of these patterns match: %s" % (
                    '"' + '", "'.join(config.define_servicegroups[x]
                                      for x in servicegroups) + '"',
                    '"' + '" or "'.join(required_groups)) + '"'

            return "The service is only in the groups %s. None of these patterns match: %s" % (
                '"' + '", "'.join(servicegroups) + '"',
                '"' + '" or "'.join(required_groups)) + '"'

        return "The service is only in the groups %s, but %s is required" % (
            sgn, " or ".join(required_groups))
    return None
Beispiel #4
0
def event_match_plugin_output(rule, context):
    if "match_plugin_output" in rule:
        r = regex(rule["match_plugin_output"])

        if context["WHAT"] == "SERVICE":
            output = context["SERVICEOUTPUT"]
        else:
            output = context["HOSTOUTPUT"]
        if not r.search(output):
            return "The expression '%s' cannot be found in the plugin output '%s'" % \
                (rule["match_plugin_output"], output)
Beispiel #5
0
def _get_service_filter_func(
    service_whitelist: Optional[List[str]],
    service_blacklist: Optional[List[str]],
) -> _ServiceFilter:
    if not service_whitelist and not service_blacklist:
        return _accept_all_services

    whitelist = (
        regex("|".join(f"({p})" for p in service_whitelist))  #
        if service_whitelist else _MATCH_EVERYTHING)

    blacklist = (
        regex("|".join(f"({p})" for p in service_blacklist))  #
        if service_blacklist else _MATCH_NOTHING)

    def _filter_service_by_patterns(service_name: ServiceName) -> bool:
        return whitelist.match(
            service_name) is not None and blacklist.match(service_name) is None

    return _filter_service_by_patterns
Beispiel #6
0
def _evaluate_snmp_detection_atom(
    atom: SNMPDetectAtom,
    oid_value_getter: Callable[[str], Optional[str]],
) -> bool:
    oid, pattern, flag = atom
    value = oid_value_getter(oid)
    if value is None:
        # check for "not_exists"
        return pattern == ".*" and not flag
    # ignore case!
    return bool(regex(pattern,
                      re.IGNORECASE | re.DOTALL).fullmatch(value)) is flag
Beispiel #7
0
 def get_service_description_matches(self, hosts: List[BIHostData],
                                     pattern: str) -> List[BIServiceSearchMatch]:
     matched_services = []
     regex_pattern = regex(pattern)
     for host in hosts:
         for service_description in host.services.keys():
             match = regex_pattern.match(service_description)
             if match is None:
                 continue
             matched_services.append(
                 BIServiceSearchMatch(host, service_description, tuple(match.groups())))
     return matched_services
Beispiel #8
0
    def _host_renamed_into(self, hostname, renaming_config):
        prefix_regex = regex(renaming_config["match_hostname"])
        if not prefix_regex.match(hostname):
            return None

        new_hostname = hostname
        for operation in renaming_config["renamings"]:
            new_hostname = self._host_renaming_operation(operation, new_hostname)

        if new_hostname != hostname:
            return new_hostname
        return None
Beispiel #9
0
 def get_service_description_matches(
     self,
     host_matches: List[BIHostSearchMatch],
     pattern: str,
 ) -> List[BIServiceSearchMatch]:
     matched_services = []
     regex_pattern = regex(pattern)
     for host_match in host_matches:
         for service_description in host_match.host.services.keys():
             if match := regex_pattern.match(service_description):
                 matched_services.append(
                     BIServiceSearchMatch(host_match, service_description,
                                          tuple(match.groups())))
Beispiel #10
0
def _evaluate_snmp_detection_atom(atom, host_config, cp_name, do_snmp_scan):
    # type: (SNMPDetectAtom, SNMPHostConfig, str, bool) -> bool
    oid, pattern, flag = atom
    value = snmp.get_single_oid(
        host_config,
        oid,
        cp_name,
        do_snmp_scan=do_snmp_scan,
    )
    if value is None:
        # check for "not_exists"
        return pattern == '.*' and not flag
    # ignore case!
    return bool(regex(pattern, re.IGNORECASE).fullmatch(value)) is flag
Beispiel #11
0
 def get_host_alias_matches(self, hosts: List[BIHostData],
                            pattern: str) -> Tuple[List[BIHostData], Dict]:
     # TODO: alias matches currently costs way more performmance than the host matches
     #       requires alias lookup to fix
     matched_hosts = []
     matched_re_groups = {}
     regex_pattern = regex(pattern)
     for host in hosts:
         match = regex_pattern.match(host.alias)
         if match is None:
             continue
         matched_hosts.append(host)
         matched_re_groups[host.name] = tuple(match.groups())
     return matched_hosts, matched_re_groups
Beispiel #12
0
def _evaluate_snmp_detection_atom(atom: SNMPDetectAtom, cp_name: str, do_snmp_scan: bool, *,
                                  backend: ABCSNMPBackend) -> bool:
    oid, pattern, flag = atom
    value = snmp_modes.get_single_oid(
        oid,
        cp_name,
        do_snmp_scan=do_snmp_scan,
        backend=backend,
    )
    if value is None:
        # check for "not_exists"
        return pattern == '.*' and not flag
    # ignore case!
    return bool(regex(pattern, re.IGNORECASE).fullmatch(value)) is flag
Beispiel #13
0
    def _process_assignments(self, aggr_name, aggr_data):
        if not self._assignments:
            self._aggregation_targets.setdefault(None, {})[aggr_name] = aggr_data
            return

        if "querying_host" in self._assignments:
            self._aggregation_targets.setdefault(None, {})[aggr_name] = aggr_data

        if "affected_hosts" in self._assignments:
            for hostname in aggr_data["hosts"]:
                self._aggregation_targets.setdefault(hostname, {})[aggr_name] = aggr_data

        for pattern, target_host in self._assignments.get("regex", []):
            if regex(pattern).match(aggr_name):
                self._aggregation_targets.setdefault(target_host, {})[aggr_name] = aggr_data
Beispiel #14
0
def _get_matching_time_settings(source_hostnames, piggybacked_hostname, time_settings):
    # type: (List[str], str, List[Tuple[Optional[str], str, int]]) -> Dict[Tuple[Optional[str], str], int]
    matching_time_settings = {}  # type: Dict[Tuple[Optional[str], str], int]
    for expr, key, value in time_settings:
        # expr may be
        #   - None (global settings) or
        #   - 'source-hostname' or
        #   - 'piggybacked-hostname' or
        #   - '~piggybacked-[hH]ostname'
        # the first entry ('piggybacked-hostname' vs '~piggybacked-[hH]ostname') wins
        if expr is None or expr in source_hostnames or expr == piggybacked_hostname:
            matching_time_settings.setdefault((expr, key), value)
        elif expr.startswith("~") and regex(expr[1:]).match(piggybacked_hostname):
            matching_time_settings.setdefault((piggybacked_hostname, key), value)
    return matching_time_settings
Beispiel #15
0
    def get_host_name_matches(
        self,
        hosts: List[BIHostData],
        pattern: str,
    ) -> Tuple[List[BIHostData], Dict]:

        if pattern == "(.*)":
            return hosts, self._host_match_groups(hosts)

        is_regex_match = any(
            map(lambda x: x in pattern, ["(", ")", "*", "$", "|", "[", "]"]))
        if not is_regex_match:
            host = self.hosts.get(pattern)
            if host:
                return [host], {pattern: (pattern, )}
            return [], {}

        # Hidden "feature": The regex pattern condition for hosts implicitly uses a $ at the end
        pattern_with_anchor = pattern
        if not pattern_with_anchor.endswith("$"):
            pattern_with_anchor += "$"

        matched_hosts = []
        matched_re_groups = {}
        regex_pattern = regex(pattern_with_anchor)
        pattern_match_cache = self._host_regex_match_cache.setdefault(
            pattern_with_anchor, {})
        pattern_miss_cache = self._host_regex_miss_cache.setdefault(
            pattern_with_anchor, {})
        for host in hosts:
            if host.name in pattern_miss_cache:
                continue

            cached_match = pattern_match_cache.get(host.name)
            if cached_match:
                matched_hosts.append(host)
                matched_re_groups[host.name] = cached_match
                continue

            match = regex_pattern.match(host.name)
            if match is None:
                pattern_miss_cache[host.name] = True
                continue
            pattern_match_cache[host.name] = match.groups()
            matched_hosts.append(host)
            matched_re_groups[host.name] = pattern_match_cache[host.name]

        return matched_hosts, matched_re_groups
Beispiel #16
0
    def _get_sanitized_and_translated_piggybacked_hostname(
        orig_piggyback_header: bytes,
        hostname: HostName,
    ) -> Optional[HostName]:
        piggybacked_hostname = ensure_str(orig_piggyback_header[4:-4])
        if not piggybacked_hostname:
            return None

        piggybacked_hostname = config.translate_piggyback_host(hostname, piggybacked_hostname)
        if piggybacked_hostname == hostname or not piggybacked_hostname:
            return None  # unpiggybacked "normal" host

        # Protect Checkmk against unallowed host names. Normally source scripts
        # like agent plugins should care about cleaning their provided host names
        # up, but we need to be sure here to prevent bugs in Checkmk code.
        return regex("[^%s]" % REGEX_HOST_NAME_CHARS).sub("_", piggybacked_hostname)
Beispiel #17
0
 def from_headerline(
     cls,
     line: bytes,
     translation: TranslationOptions,
     *,
     encoding_fallback: str,
 ) -> "PiggybackMarker":
     hostname = ensure_str(line.strip()[4:-4])
     assert hostname
     hostname = translate_piggyback_host(
         hostname,
         translation,
         encoding_fallback=encoding_fallback,
     )
     # Protect Checkmk against unallowed host names. Normally source scripts
     # like agent plugins should care about cleaning their provided host names
     # up, but we need to be sure here to prevent bugs in Checkmk code.
     return cls(regex("[^%s]" % REGEX_HOST_NAME_CHARS).sub("_", hostname))
Beispiel #18
0
    def matches_host_name(self,
                          host_entries: Optional[HostOrServiceConditions],
                          hostname: HostName) -> bool:
        if not host_entries:
            return True

        negate, host_entries = parse_negated_condition_list(host_entries)
        if hostname == "":  # -> generic agent host
            return negate

        for entry in host_entries:
            if not isinstance(entry, dict) and hostname == entry:
                return not negate

            if isinstance(entry, dict) and regex(
                    entry["$regex"]).match(hostname) is not None:
                return not negate

        return negate
Beispiel #19
0
    def _matches_host_name(self, host_entries, hostname):
        if not host_entries:
            return True

        negate, host_entries = parse_negated_condition_list(host_entries)

        for entry in host_entries:
            use_regex = isinstance(entry, dict)

            if hostname is True:  # -> generic agent host
                continue

            if not use_regex and hostname == entry:
                return not negate

            if use_regex and regex(entry["$regex"]).match(hostname) is not None:
                return not negate

        return negate
Beispiel #20
0
def _event_match_exclude_servicegroups(
    rule: EventRule, context: EventContext, is_regex: bool
) -> Optional[str]:
    if is_regex:
        match_type, excluded_groups = rule.get("match_exclude_servicegroups_regex", (None, None))
    else:
        excluded_groups = rule.get("match_exclude_servicegroups")

    if context["WHAT"] != "SERVICE":
        # excluded_groups do not apply to a host notification
        return None

    if excluded_groups is not None:
        context_sgn = context.get("SERVICEGROUPNAMES")
        if not context_sgn:
            # No actual groups means no possible negative match
            return None

        servicegroups = context_sgn.split(",")

        for group in excluded_groups:
            if is_regex:
                r = regex(group)
                for sg in servicegroups:
                    if config.define_servicegroups is None:
                        continue
                    match_value = (
                        config.define_servicegroups[sg] if match_type == "match_alias" else sg
                    )
                    match_value_inverse = (
                        sg if match_type == "match_alias" else config.define_servicegroups[sg]
                    )

                    if r.search(match_value):
                        return 'The service group "%s" (%s) is excluded per regex pattern: %s' % (
                            match_value,
                            match_value_inverse,
                            group,
                        )
            elif group in servicegroups:
                return "The service group %s is excluded" % group
    return None
Beispiel #21
0
def _get_matching_time_settings(
    source_hostnames: Container[HostName],
    piggybacked_hostname: HostName,
    time_settings: PiggybackTimeSettings,
) -> Mapping[Tuple[Optional[str], str], int]:
    matching_time_settings: Dict[Tuple[Optional[str], str], int] = {}
    for expr, key, value in time_settings:
        # expr may be
        #   - None (global settings) or
        #   - 'source-hostname' or
        #   - 'piggybacked-hostname' or
        #   - '~piggybacked-[hH]ostname'
        # the first entry ('piggybacked-hostname' vs '~piggybacked-[hH]ostname') wins
        if expr is None or expr in source_hostnames or expr == piggybacked_hostname:
            matching_time_settings.setdefault((expr, key), value)
        elif expr.startswith("~") and regex(
                expr[1:]).match(piggybacked_hostname):
            matching_time_settings.setdefault((piggybacked_hostname, key),
                                              value)
    return matching_time_settings
Beispiel #22
0
def _check_plugins_missing_data(
    plugins_missing_data: List[CheckPluginName],
    exit_spec: ExitSpec,
    some_success: bool,
) -> Iterable[ActiveCheckResult]:
    if not plugins_missing_data:
        return

    if not some_success:
        yield ActiveCheckResult(exit_spec.get("empty_output", 2),
                                ("Got no information from host", ), (), ())
        return

    # key is a legacy name, kept for compatibility.
    specific_plugins_missing_data_spec = exit_spec.get(
        "specific_missing_sections", [])

    specific_plugins, generic_plugins = set(), set()
    for check_plugin_name in plugins_missing_data:
        for pattern, status in specific_plugins_missing_data_spec:
            reg = regex(pattern)
            if reg.match(str(check_plugin_name)):
                specific_plugins.add((check_plugin_name, status))
                break
        else:  # no break
            generic_plugins.add(str(check_plugin_name))

    # key is a legacy name, kept for compatibility.
    missing_status = exit_spec.get("missing_sections", 1)
    plugin_list = ", ".join(sorted(generic_plugins))
    yield ActiveCheckResult(
        missing_status,
        (f"Missing monitoring data for plugins: {plugin_list}{state_markers[missing_status]}",
         ),
        (),
        (),
    )

    yield from (ActiveCheckResult(status, f"{plugin}{state_markers[status]}",
                                  (), ())
                for plugin, status in sorted(specific_plugins))
Beispiel #23
0
def _translate(translation: TranslationOptions, name: str) -> str:
    # 1. Case conversion
    caseconf = translation.get("case")
    if caseconf == "upper":
        name = name.upper()
    elif caseconf == "lower":
        name = name.lower()

    # 2. Drop domain part (not applied to IP addresses!)
    if translation.get("drop_domain"):
        try:
            ipaddress.ip_address(name)
        except ValueError:
            # Drop domain if "name " is not a valid IP address
            name = name.split(".", 1)[0]

    # 3. Multiple regular expression conversion
    if isinstance(translation.get("regex"), tuple):
        translations = [translation["regex"]]
    else:
        translations = translation.get("regex", [])

    for expr, subst in translations:
        if not expr.endswith('$'):
            expr += '$'
        rcomp = regex(expr)
        # re.RegexObject.sub() by hand to handle non-existing references
        mo = rcomp.match(name)
        if mo:
            name = subst
            for nr, text in enumerate(mo.groups("")):
                name = name.replace("\\%d" % (nr + 1), text)
            break

    # 4. Explicity mapping
    for from_name, to_name in translation.get("mapping", []):
        if from_name == name:
            name = to_name
            break

    return name.strip()
Beispiel #24
0
def convert_pattern_list(patterns: List[str]) -> Optional[Pattern[str]]:
    """Compiles a list of service match patterns to a single regex

    Reducing the number of individual regex matches improves the performance dramatically.
    This function assumes either all or no pattern is negated (like WATO creates the rules).
    """
    if not patterns:
        return None

    pattern_parts = []

    for pattern in patterns:
        negate, pattern = _parse_negated(pattern)
        # Skip ALL_SERVICES from end of negated lists
        if negate:
            if pattern == ALL_SERVICES[0]:
                continue
            pattern_parts.append("(?!%s)" % pattern)
        else:
            pattern_parts.append("(?:%s)" % pattern)

    return regex("(?:%s)" % "|".join(pattern_parts))
Beispiel #25
0
    def from_headerline(
        cls,
        line: bytes,
        translation: TranslationOptions,
        *,
        encoding_fallback: str,
    ) -> "PiggybackMarker":
        raw_host_name = ensure_str_with_fallback(
            line.strip()[4:-4],
            encoding='utf-8',
            fallback=encoding_fallback,
        )
        assert raw_host_name
        hostname = translate_hostname(translation, raw_host_name)

        # Protect Checkmk against unallowed host names. Normally source scripts
        # like agent plugins should care about cleaning their provided host names
        # up, but we need to be sure here to prevent bugs in Checkmk code.
        # TODO: this should be moved into the HostName class, if it is ever created.
        return cls(
            HostName(
                regex("[^%s]" % REGEX_HOST_NAME_CHARS).sub("_", hostname)))
Beispiel #26
0
    def _matches_host_name(self, host_entries, hostname):
        if not host_entries:
            return True

        negate = False
        if isinstance(host_entries, dict) and "$nor" in host_entries:
            negate = True
            host_entries = host_entries["$nor"]

        for entry in host_entries:
            use_regex = isinstance(entry, dict)

            if hostname is True:  # -> generic agent host
                continue

            if not use_regex and hostname == entry:
                return not negate

            if use_regex and regex(entry["$regex"]).match(hostname) is not None:
                return not negate

        return negate
Beispiel #27
0
def _check_plugins_missing_data(
    plugins_missing_data: List[CheckPluginName],
    exit_spec: config.ExitSpec,
    some_success: bool,
) -> Tuple[ServiceState, ServiceDetails]:
    if not some_success:
        return (cast(int, exit_spec.get("empty_output",
                                        2)), "Got no information from host")

    specific_plugins_missing_data_spec = cast(
        List[config.ExitSpecSection],
        exit_spec.get("specific_missing_sections", []),
    )

    specific_plugins, generic_plugins = set(), set()
    for check_plugin_name in plugins_missing_data:
        for pattern, status in specific_plugins_missing_data_spec:
            reg = regex(pattern)
            if reg.match(str(check_plugin_name)):
                specific_plugins.add((check_plugin_name, status))
                break
        else:  # no break
            generic_plugins.add(str(check_plugin_name))

    generic_plugins_status = cast(int, exit_spec.get("missing_sections", 1))
    infotexts = [
        "Missing monitoring data for check plugins: %s%s" % (
            ", ".join(sorted(generic_plugins)),
            check_api_utils.state_markers[generic_plugins_status],
        ),
    ]

    for plugin, status in sorted(specific_plugins):
        infotexts.append("%s%s" %
                         (plugin, check_api_utils.state_markers[status]))
        generic_plugins_status = max(generic_plugins_status, status)

    return generic_plugins_status, ", ".join(infotexts)
Beispiel #28
0
    def add_matching_services(name, description, service_state, start_type, entry):
        # New wato rule handling
        svc, *statespec = entry
        # First match name or description (optional since rule based config option available)
        if svc:
            if svc.startswith("~"):
                r = regex(svc[1:])

                if not r.match(name) and not r.match(description):
                    return
            elif svc not in (name, description):
                return

        if isinstance(statespec, list):
            # New wato rule handling (always given as tuple of two)
            if (statespec[0] and statespec[0] != service_state) or (statespec[1] and
                                                                    statespec[1] != start_type):
                return

        else:
            for match_criteria in statespec.split("/"):
                if match_criteria not in {service_state, start_type}:
                    return
        yield Service(item=name)
Beispiel #29
0
def in_extraconf_hostlist(hostlist, hostname):
    """Whether or not the given host matches the hostlist.

    Entries in list are hostnames that must equal the hostname.
    Expressions beginning with ! are negated: if they match,
    the item is excluded from the list.

    Expressions beginning with ~ are treated as regular expression.
    Also the three special tags '@all', '@clusters', '@physical'
    are allowed.
    """

    # Migration help: print error if old format appears in config file
    # FIXME: When can this be removed?
    try:
        if hostlist[0] == "":
            raise MKGeneralException(
                'Invalid empty entry [ "" ] in configuration')
    except IndexError:
        pass  # Empty list, no problem.

    for hostentry in hostlist:
        if hostentry == '':
            raise MKGeneralException('Empty hostname in host list %r' %
                                     hostlist)
        negate = False
        use_regex = False
        if hostentry[0] == '@':
            if hostentry == '@all':
                return True
            # TODO: Is not used anymore for a long time. Will be cleaned up
            # with 1.6 tuple ruleset cleanup
            #ic = is_cluster(hostname)
            #if hostentry == '@cluster' and ic:
            #    return True
            #elif hostentry == '@physical' and not ic:
            #    return True

        # Allow negation of hostentry with prefix '!'
        else:
            if hostentry[0] == '!':
                hostentry = hostentry[1:]
                negate = True

            # Allow regex with prefix '~'
            if hostentry[0] == '~':
                hostentry = hostentry[1:]
                use_regex = True

        try:
            if not use_regex and hostname == hostentry:
                return not negate
            # Handle Regex. Note: hostname == True -> generic unknown host
            elif use_regex and hostname != True:
                if regex(hostentry).match(hostname) is not None:
                    return not negate
        except MKGeneralException:
            if cmk.utils.debug.enabled():
                raise

    return False
Beispiel #30
0
 def validate_job_id(job_id: str) -> None:
     if not regex(REGEX_GENERIC_IDENTIFIER).match(job_id):
         raise MKGeneralException(_("Invalid Job ID"))