Example #1
0
    def _action(self) -> None:
        assert user.id is not None

        users = userdb.load_users(lock=True)
        user_spec = users[user.id]

        cur_password = request.get_str_input_mandatory("cur_password")
        password = request.get_str_input_mandatory("password")
        password2 = request.get_str_input_mandatory("password2", "")

        # Force change pw mode
        if not cur_password:
            raise MKUserError("cur_password", _("You need to provide your current password."))

        if not password:
            raise MKUserError("password", _("You need to change your password."))

        if cur_password == password:
            raise MKUserError("password", _("The new password must differ from your current one."))

        if userdb.check_credentials(user.id, cur_password) is False:
            raise MKUserError("cur_password", _("Your old password is wrong."))

        if password2 and password != password2:
            raise MKUserError("password2", _("The both new passwords do not match."))

        watolib.verify_password_policy(password)
        user_spec["password"] = hash_password(password)
        user_spec["last_pw_change"] = int(time.time())

        # In case the user was enforced to change it's password, remove the flag
        try:
            del user_spec["enforce_pw_change"]
        except KeyError:
            pass

        # Increase serial to invalidate old authentication cookies
        if "serial" not in user_spec:
            user_spec["serial"] = 1
        else:
            user_spec["serial"] += 1

        userdb.save_users(users)

        flash(_("Successfully changed password."))

        # Set the new cookie to prevent logout for the current user
        login.update_auth_cookie(user.id)

        # In distributed setups with remote sites where the user can login, start the
        # user profile replication now which will redirect the user to the destination
        # page after completion. Otherwise directly open up the destination page.
        origtarget = request.get_str_input_mandatory("_origtarget", "user_change_pw.py")
        if user.authorized_login_sites():
            raise redirect(
                makeuri_contextless(
                    request, [("back", origtarget)], filename="user_profile_replicate.py"
                )
            )
        raise redirect(origtarget)
Example #2
0
def ajax_tree_openclose() -> None:
    tree = request.get_str_input_mandatory("tree")
    name = request.get_str_input_mandatory("name")

    user.set_tree_state(tree, name, request.get_str_input("state"))
    user.save_tree_states()
    response.set_data("OK")  # Write out something to make debugging easier
Example #3
0
    def page(self) -> PageResult:
        """ Determines the hosts to be shown """
        config.user.need_permission("general.parent_child_topology")

        topology_settings = TopologySettings()
        if request.var("filled_in"):
            # Parameters from the check_mk filters
            topology_settings.growth_root_nodes = self._get_hostnames_from_filters(
            )
        elif request.var("host_name"):
            # Explicit host_name. Used by icon linking to Topology
            topology_settings.growth_root_nodes = {
                request.get_str_input_mandatory("host_name")
            }
        else:
            # Default page without further context
            topology_settings.growth_root_nodes = self._get_default_view_hostnames(
                topology_settings.growth_auto_max_nodes)

        if request.has_var("topology_settings"):
            # These parameters are usually generated within javascript through user interactions
            try:
                settings_from_var = json.loads(
                    request.get_str_input_mandatory("topology_settings"))
                for key, value in settings_from_var.items():
                    setattr(topology_settings, key, value)
            except (TypeError, ValueError):
                raise MKGeneralException(
                    _("Invalid topology_settings %r") % topology_settings)

        self.show_topology(topology_settings)
Example #4
0
def ajax_set_rowselection() -> None:
    ident = request.get_str_input_mandatory('id')
    action = request.get_str_input_mandatory('action', 'set')
    if action not in ['add', 'del', 'set', 'unset']:
        raise MKUserError(None, _('Invalid action'))

    rows = request.get_str_input_mandatory('rows', '').split(',')
    config.user.set_rowselection(selection_id(), ident, rows, action)
Example #5
0
def ajax_set_rowselection() -> None:
    ident = request.get_str_input_mandatory("id")
    action = request.get_str_input_mandatory("action", "set")
    if action not in ["add", "del", "set", "unset"]:
        raise MKUserError(None, _("Invalid action"))

    rows = request.get_str_input_mandatory("rows", "").split(",")
    user.set_rowselection(selection_id(), ident, rows, action)
Example #6
0
    def _ajax_speedometer(self):
        response.set_content_type("application/json")
        try:
            # Try to get values from last call in order to compute
            # driftig speedometer-needle and to reuse the scheduled
            # check reate.
            # TODO: Do we need a get_float_input_mandatory?
            last_perc = float(request.get_str_input_mandatory("last_perc"))
            scheduled_rate = float(
                request.get_str_input_mandatory("scheduled_rate"))
            last_program_start = request.get_integer_input_mandatory(
                "program_start")

            # Get the current rates and the program start time. If there
            # are more than one site, we simply add the start times.
            data = sites.live().query_summed_stats(
                "GET status\n"
                "Columns: service_checks_rate program_start")
            current_rate = data[0]
            program_start = data[1]

            # Recompute the scheduled_rate only if it is not known (first call)
            # or if one of the sites has been restarted. The computed value cannot
            # change during the monitoring since it just reflects the configuration.
            # That way we save CPU resources since the computation of the
            # scheduled checks rate needs to loop over all hosts and services.
            if last_program_start != program_start:
                # These days, we configure the correct check interval for Checkmk checks.
                # We do this correctly for active and for passive ones. So we can simply
                # use the check_interval of all services. Hosts checks are ignored.
                #
                # Manually added services without check_interval could be a problem, but
                # we have no control there.
                scheduled_rate = (sites.live().query_summed_stats(
                    "GET services\n"
                    "Stats: suminv check_interval\n")[0] / 60.0)

            percentage = 100.0 * current_rate / scheduled_rate
            title = _(
                "Scheduled service check rate: %.1f/s, current rate: %.1f/s, that is "
                "%.0f%% of the scheduled rate") % (scheduled_rate,
                                                   current_rate, percentage)

        except Exception as e:
            scheduled_rate = 0.0
            program_start = 0
            percentage = 0
            last_perc = 0.0
            title = _("No performance data: %s") % e

        response.set_data(
            json.dumps({
                "scheduled_rate": scheduled_rate,
                "program_start": program_start,
                "percentage": percentage,
                "last_perc": last_perc,
                "title": title,
            }))
Example #7
0
 def _execute_cmk_automation(self):
     cmk_command = request.get_str_input_mandatory("automation")
     args = watolib.mk_eval(request.get_str_input_mandatory("arguments"))
     indata = watolib.mk_eval(request.get_str_input_mandatory("indata"))
     stdin_data = watolib.mk_eval(request.get_str_input_mandatory("stdin_data"))
     timeout = watolib.mk_eval(request.get_str_input_mandatory("timeout"))
     result = watolib.check_mk_local_automation(cmk_command, args, indata, stdin_data, timeout)
     # Don't use write_text() here (not needed, because no HTML document is rendered)
     response.set_data(repr(result))
Example #8
0
def recover_pre_2_1_range_filter_request_vars(query: query_filters.NumberRangeQuery):
    """Some range filters used the _to suffix instead of the standard _until.

    Do inverse translation to search for this request vars."""
    request_var_match = ((var, re.sub("_until(_|$)", "_to\\1", var)) for var in query.request_vars)
    return {
        current_var: (
            request.get_str_input_mandatory(current_var, "")
            or request.get_str_input_mandatory(old_var, "")
        )
        for current_var, old_var in request_var_match
    }
Example #9
0
def page_graph_dashlet() -> None:
    spec = request.var("spec")
    if not spec:
        raise MKUserError("spec", _("Missing spec parameter"))
    graph_identification = json.loads(request.get_str_input_mandatory("spec"))

    render = request.var("render")
    if not render:
        raise MKUserError("render", _("Missing render parameter"))
    custom_graph_render_options = json.loads(request.get_str_input_mandatory("render"))

    host_service_graph_dashlet_cmk(graph_identification, custom_graph_render_options)
Example #10
0
def _check_auth_automation() -> UserId:
    secret = request.get_str_input_mandatory("_secret", "").strip()
    user_id = request.get_str_input_mandatory("_username", "")

    user_id = UserId(user_id.strip())
    request.del_var_from_env("_username")
    request.del_var_from_env("_secret")

    if verify_automation_secret(user_id, secret):
        # Auth with automation secret succeeded - mark transid as unneeded in this case
        transactions.ignore()
        set_auth_type("automation")
        return user_id
    raise MKAuthException(_("Invalid automation secret for user %s") % user_id)
Example #11
0
    def _from_vars(self):
        self._hostname = self._vs_host().from_html_vars("host")
        self._vs_host().validate_value(self._hostname, "host")

        # TODO: validate all fields
        self._item = request.get_str_input_mandatory("file", "")
        self._match_txt = request.get_str_input_mandatory("match", "")

        self._host = watolib.Folder.current().host(self._hostname)

        if self._hostname and not self._host:
            raise MKUserError(None, _("This host does not exist."))

        if self._item and not self._hostname:
            raise MKUserError(None, _("You need to specify a host name to test file matching."))
Example #12
0
 def _file_path(self, file_id: Optional[str] = None) -> Path:
     if file_id is None:
         file_id = request.get_str_input_mandatory("file_id")
     if not file_id.isalnum():
         raise MKUserError("file_id",
                           _("The file_id has to be alphanumeric."))
     return self._upload_tmp_path / ("%s.csv" % file_id)
Example #13
0
    def _get_time_range_of(self, what: str) -> Union[None, int, float]:
        varprefix = self.ident + "_" + what

        rangename = request.var(varprefix + "_range")
        if rangename == "abs":
            try:
                return time.mktime(
                    time.strptime(request.get_str_input_mandatory(varprefix),
                                  "%Y-%m-%d"))
            except Exception:
                user_errors.add(
                    MKUserError(
                        varprefix,
                        _("Please enter the date in the format YYYY-MM-DD.")))
                return None

        if rangename == "unix":
            return request.get_integer_input_mandatory(varprefix)
        if rangename is None:
            return None

        try:
            count = request.get_integer_input_mandatory(varprefix)
            secs = count * int(rangename)
            return int(time.time()) - secs
        except Exception:
            request.set_var(varprefix, "")
            return None
Example #14
0
 def filter(self, infoname):
     self.check_wato_data_update()
     folder = request.get_str_input_mandatory(self.ident, "")
     if folder:
         return "Filter: host_filename %s\n" % _wato_folders_to_lq_regex(
             folder)
     return ""
Example #15
0
def _get_api_call() -> APICallDefinitionDict:
    action = request.get_str_input_mandatory("action")
    for cls in api_call_collection_registry.values():
        api_call = cls().get_api_calls().get(action)
        if api_call:
            return api_call
    raise MKUserError(None, "Unknown API action %s" % escaping.escape_attribute(action))
Example #16
0
 def _ajax_tag_tree_enter(self):
     response.set_content_type("application/json")
     self._load()
     path = request.get_str_input_mandatory("path").split("|") if request.var("path") else []
     self._cwds[self._current_tree_id] = path
     self._save_user_settings()
     response.set_data("OK")
Example #17
0
 def value(self) -> FilterHTTPVariables:
     """Returns the current representation of the filter settings from the HTML
     var context. This can be used to persist the filter settings."""
     return {
         varname: request.get_str_input_mandatory(varname, "")
         for varname in self.htmlvars
     }
Example #18
0
    def show(self, view: "View", rows: Rows) -> None:
        csv_separator = request.get_str_input_mandatory("csv_separator", ";")
        first = True
        resp = []
        for cell in view.group_cells + view.row_cells:
            if first:
                first = False
            else:
                resp.append(csv_separator)
            title = cell.export_title()
            resp.append('"%s"' % self._format_for_csv(title))

        for row in rows:
            resp.append("\n")
            first = True
            for cell in view.group_cells + view.row_cells:
                if first:
                    first = False
                else:
                    resp.append(csv_separator)
                joined_row = join_row(row, cell)
                content = cell.render_for_export(joined_row)
                resp.append('"%s"' % self._format_for_csv(content))

        response.set_data("".join(resp))
Example #19
0
def page_api() -> None:
    try:
        if not request.has_var("output_format"):
            response.set_content_type("application/json")
            output_format = "json"
        else:
            output_format = request.get_ascii_input_mandatory(
                "output_format", "json").lower()

        if output_format not in _FORMATTERS:
            response.set_content_type("text/plain")
            raise MKUserError(
                None,
                "Only %s are supported as output formats" %
                " and ".join('"%s"' % f for f in _FORMATTERS),
            )

        # TODO: Add some kind of helper for boolean-valued variables?
        pretty_print = False
        pretty_print_var = request.get_str_input_mandatory(
            "pretty_print", "no").lower()
        if pretty_print_var not in ("yes", "no"):
            raise MKUserError(None, 'pretty_print must be "yes" or "no"')
        pretty_print = pretty_print_var == "yes"

        api_call = _get_api_call()
        _check_permissions(api_call)
        request_object = _get_request(api_call)
        _check_formats(output_format, api_call, request_object)
        _check_request_keys(api_call, request_object)
        resp = _execute_action(api_call, request_object)

    except MKAuthException as e:
        resp = {
            "result_code":
            1,
            "result":
            _("Authorization Error. Insufficent permissions for '%s'") % e,
        }
    except MKException as e:
        resp = {
            "result_code":
            1,
            "result":
            _("Checkmk exception: %s\n%s") %
            (e, "".join(traceback.format_exc())),
        }
    except Exception:
        if active_config.debug:
            raise
        logger.exception("error handling web API call")
        resp = {
            "result_code": 1,
            "result": _("Unhandled exception: %s") % traceback.format_exc(),
        }

    response.set_data(
        _FORMATTERS[output_format][1 if pretty_print else 0](resp))
Example #20
0
 def page(self) -> AjaxPageResult:
     try:
         name = request.get_str_input_mandatory("name")
         url = makeuri_contextless(request, [("name", name)], "dashboard.py")
         cmk.gui.utils.validate_start_url(url, "")
         _set_user_attribute("start_url", repr(url))
     except Exception:
         raise MKUserError(None, _("Failed to set start URL"))
     return {}
Example #21
0
    def page(self):
        settings = json.loads(request.get_str_input_mandatory("settings"))

        try:
            dashlet_type = cast(Type[ABCFigureDashlet], dashlet_registry[settings.get("type")])
        except KeyError:
            raise MKUserError("type", _('The requested element type does not exist.'))

        settings = dashlet_vs_general_settings(
            dashlet_type, dashlet_type.single_infos()).value_from_json(settings)

        raw_properties = request.get_str_input_mandatory("properties")
        properties = dashlet_type.vs_parameters().value_from_json(json.loads(raw_properties))
        context = json.loads(request.get_str_input_mandatory("context", "{}"))
        # Inject the infos because the datagenerator is a separate instance to dashlet
        settings["infos"] = dashlet_type.infos()
        response_data = dashlet_type.generate_response_data(properties, context, settings)
        return create_figures_response(response_data)
Example #22
0
def robotmk_report_page() -> cmk.gui.pages.PageResult:
    """Renders the content of the RobotMK html log file"""
    site_id, host_name, service_description = _get_mandatory_request_vars()
    report_type: str = request.get_str_input_mandatory("report_type")

    content = _get_html_from_livestatus(report_type, site_id, host_name, service_description)

    html_content = _get_cleaned_html_content(content[0].decode("utf-8"))
    html.write_html(html_content)
Example #23
0
    def infos(self):
        # Hack for create mode of dashlet editor. The user first selects a datasource and then the
        # single contexts, the dashlet editor needs to use these information.
        if requested_file_name(request) == "edit_dashlet" and request.has_var(
                "datasource"):
            ds_name = request.get_str_input_mandatory("datasource")
            return views.data_source_registry[ds_name]().infos

        return self._get_infos_from_view_spec(self._dashlet_spec)
Example #24
0
def ajax_save_treestate():
    path_id = request.get_str_input_mandatory("path")
    current_ex_level_str, path = path_id.split(":", 1)
    current_ex_level = int(current_ex_level_str)

    if user.bi_expansion_level != current_ex_level:
        user.set_tree_states("bi", {})
    user.set_tree_state("bi", path, request.var("state") == "open")
    user.save_tree_states()

    user.bi_expansion_level = current_ex_level
Example #25
0
 def page(self):
     # To prevent mixups in written files we use the same lock here as for
     # the normal WATO page processing. This might not be needed for some
     # special automation requests, like inventory e.g., but to keep it simple,
     # we request the lock in all cases.
     lock_config = not (self._command == "checkmk-automation"
                        and request.get_str_input_mandatory("automation")
                        == "active-check")
     with store.lock_checkmk_configuration(
     ) if lock_config else nullcontext():
         self._execute_automation()
Example #26
0
 def _execute_cmk_automation(self):
     cmk_command = request.get_str_input_mandatory("automation")
     args = watolib.mk_eval(request.get_str_input_mandatory("arguments"))
     indata = watolib.mk_eval(request.get_str_input_mandatory("indata"))
     stdin_data = watolib.mk_eval(
         request.get_str_input_mandatory("stdin_data"))
     timeout = watolib.mk_eval(request.get_str_input_mandatory("timeout"))
     cmdline_cmd, serialized_result = watolib.check_mk_local_automation_serialized(
         command=cmk_command,
         args=args,
         indata=indata,
         stdin_data=stdin_data,
         timeout=timeout,
     )
     # Don't use write_text() here (not needed, because no HTML document is rendered)
     response.set_data(
         self._format_cmk_automation_result(
             serialized_result=SerializedResult(serialized_result),
             cmk_command=cmk_command,
             cmdline_cmd=cmdline_cmd,
         ))
Example #27
0
def ajax_graph():
    response.set_content_type("application/json")
    try:
        context_var = request.get_str_input_mandatory("context")
        context = json.loads(context_var)
        response_data = render_ajax_graph(context)
        response.set_data(json.dumps(response_data))
    except Exception as e:
        logger.error("Ajax call ajax_graph.py failed: %s\n%s", e,
                     traceback.format_exc())
        if config.debug:
            raise
        response.set_data("ERROR: %s" % e)
Example #28
0
def ajax_snapin():
    """Renders and returns the contents of the requested sidebar snapin(s) in JSON format"""
    response.set_content_type("application/json")
    user_config = UserSidebarConfig(user, config.sidebar)

    snapin_id = request.var("name")
    snapin_ids = ([snapin_id] if snapin_id else
                  request.get_str_input_mandatory("names", "").split(","))

    snapin_code: List[str] = []
    for snapin_id in snapin_ids:
        try:
            snapin_instance = user_config.get_snapin(snapin_id).snapin_type()
        except KeyError:
            continue  # Skip not existing snapins

        if not snapin_instance.may_see():
            continue

        # When restart snapins are about to be refreshed, only render
        # them, when the core has been restarted after their initial
        # rendering
        if not snapin_instance.refresh_regularly(
        ) and snapin_instance.refresh_on_restart():
            since = request.get_float_input_mandatory("since", 0)
            newest = since
            for site in sites.states().values():
                prog_start = site.get("program_start", 0)
                if prog_start > newest:
                    newest = prog_start
            if newest <= since:
                # no restart
                snapin_code.append("")
                continue

        with output_funnel.plugged():
            try:
                snapin_instance.show()
            except Exception as e:
                write_snapin_exception(e)
                e_message = (
                    _("Exception during element refresh (element '%s')") %
                    snapin_instance.type_name())
                logger.error("%s %s: %s", request.requested_url, e_message,
                             traceback.format_exc())
            finally:
                snapin_code.append(output_funnel.drain())

    response.set_data(json.dumps(snapin_code))
Example #29
0
def selection_id() -> str:
    """Generates a selection id or uses the given one"""
    if not request.has_var('selection'):
        sel_id = utils.gen_id()
        request.set_var('selection', sel_id)
        return sel_id

    sel_id = request.get_str_input_mandatory('selection')

    # Avoid illegal file access by introducing .. or /
    if not re.match("^[-0-9a-zA-Z]+$", sel_id):
        new_id = utils.gen_id()
        request.set_var('selection', new_id)
        return new_id
    return sel_id
Example #30
0
    def _evaluate_user_opts(self) -> Tuple[TableRows, bool, Optional[str]]:
        assert self.id is not None
        table_id = self.id
        rows = self.rows

        search_term = None
        actions_enabled = self.options["searchable"] or self.options["sortable"]

        if not actions_enabled:
            return rows, False, None

        table_opts = user.tableoptions.setdefault(table_id, {})

        # Handle the initial visibility of the actions
        actions_visible = table_opts.get("actions_visible", False)
        if request.get_ascii_input("_%s_actions" % table_id):
            actions_visible = request.get_ascii_input("_%s_actions" %
                                                      table_id) == "1"
            table_opts["actions_visible"] = actions_visible

        if self.options["searchable"]:
            search_term = request.get_str_input_mandatory("search", "")
            # Search is always lower case -> case insensitive
            search_term = search_term.lower()
            if search_term:
                request.set_var("search", search_term)
                rows = _filter_rows(rows, search_term)

        if request.get_ascii_input("_%s_reset_sorting" % table_id):
            request.del_var("_%s_sort" % table_id)
            if "sort" in table_opts:
                del table_opts["sort"]  # persist

        if self.options["sortable"]:
            # Now apply eventual sorting settings
            sort = self._get_sort_column(table_opts)
            if sort is not None:
                request.set_var("_%s_sort" % table_id, sort)
                table_opts["sort"] = sort  # persist
                sort_col, sort_reverse = map(int, sort.split(",", 1))
                rows = _sort_rows(rows, sort_col, sort_reverse)

        if actions_enabled:
            user.save_tableoptions()

        return rows, actions_visible, search_term