/* ** Zabbix ** Copyright (C) 2001-2023 Zabbix SIA ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. **/ #include "trapper_expressions_evaluate.h" #include "zbxalgo.h" #include "zbxnum.h" #include "trapper_auth.h" #include "zbxcommshigh.h" #include "zbxdbhigh.h" #include "zbxtime.h" #include "zbxeval.h" #include "zbxjson.h" static int trapper_parse_expressions_evaluate(const struct zbx_json_parse *jp, zbx_vector_ptr_t *expressions, char **error) { char buffer[MAX_STRING_LEN]; const char *ptr; zbx_user_t user; int ret = FAIL; struct zbx_json_parse jp_data, jp_expressions; zbx_user_init(&user); if (FAIL == zbx_get_user_from_json(jp, &user, NULL) || USER_TYPE_ZABBIX_ADMIN > user.type) { *error = zbx_strdup(NULL, "Permission denied."); goto out; } if (FAIL == zbx_json_brackets_by_name(jp, ZBX_PROTO_TAG_DATA, &jp_data)) { *error = zbx_strdup(NULL, "Missing data field."); goto out; } if (FAIL == zbx_json_brackets_by_name(&jp_data, ZBX_PROTO_TAG_EXPRESSIONS, &jp_expressions)) { *error = zbx_strdup(NULL, "Missing expressions field."); goto out; } for (ptr = NULL; NULL != (ptr = zbx_json_next_value(&jp_expressions, ptr, buffer, sizeof(buffer), NULL));) { zbx_vector_ptr_append(expressions, zbx_strdup(NULL, buffer)); } ret = SUCCEED; out: zbx_user_free(&user); return ret; } static int trapper_expression_evaluate(const char *expression, const zbx_timespec_t *ts, double *result, char **error) { zbx_eval_context_t ctx; int ret; zbx_variant_t value; if (SUCCEED != zbx_eval_parse_expression(&ctx, expression, ZBX_EVAL_PARSE_TRIGGER_EXPRESSION, error)) return FAIL; if (SUCCEED == (ret = zbx_eval_execute(&ctx, ts, &value, error))) { if (SUCCEED == zbx_variant_convert(&value, ZBX_VARIANT_DBL)) { *result = value.data.dbl; } else { *error = zbx_dsprintf(NULL, "invalid result \"%s\" of type \"%s\"", zbx_variant_value_desc(&value), zbx_variant_type_desc(&value)); zbx_variant_clear(&value); ret = FAIL; } } zbx_eval_clear(&ctx); return ret; } static int trapper_expressions_evaluate_run(const struct zbx_json_parse *jp, struct zbx_json *json, char **error) { int ret = FAIL, i; zbx_vector_ptr_t expressions; zbx_timespec_t ts; zbx_vector_ptr_create(&expressions); if (FAIL == trapper_parse_expressions_evaluate(jp, &expressions, error)) goto out; zbx_json_addstring(json, ZBX_PROTO_TAG_RESPONSE, "success", ZBX_JSON_TYPE_STRING); zbx_json_addarray(json, ZBX_PROTO_TAG_DATA); zbx_timespec(&ts); for (i = 0; i < expressions.values_num; i++) { double expr_result; char *errmsg = NULL; zbx_json_addobject(json, NULL); zbx_json_addstring(json, ZBX_PROTO_TAG_EXPRESSION, expressions.values[i], ZBX_JSON_TYPE_STRING); if (SUCCEED != trapper_expression_evaluate(expressions.values[i], &ts, &expr_result, &errmsg)) { zbx_json_addstring(json, ZBX_PROTO_TAG_ERROR, errmsg, ZBX_JSON_TYPE_STRING); zbx_free(errmsg); } else { zbx_uint64_t res = (ZBX_INFINITY == expr_result || SUCCEED == zbx_double_compare(expr_result, 0.0)) ? 0 : 1; zbx_json_adduint64(json, ZBX_PROTO_TAG_VALUE, res); } zbx_json_close(json); } zbx_json_close(json); ret = SUCCEED; out: zbx_vector_ptr_clear_ext(&expressions, (zbx_clean_func_t)zbx_ptr_free); zbx_vector_ptr_destroy(&expressions); return ret; } int zbx_trapper_expressions_evaluate(zbx_socket_t *sock, const struct zbx_json_parse *jp, int config_timeout) { char *error = NULL; int ret; struct zbx_json json; zbx_json_init(&json, 1024); if (SUCCEED == (ret = trapper_expressions_evaluate_run(jp, &json, &error))) { zbx_tcp_send_bytes_to(sock, json.buffer, json.buffer_size, config_timeout); } else { zbx_send_response(sock, ret, error, config_timeout); zbx_free(error); } zbx_json_free(&json); return ret; }