1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 **/
19
20 #include "common.h"
21 #include "zbxjson.h"
22 #include "zbxalgo.h"
23 #include "preproc.h"
24 #include "../preprocessor/preproc_history.h"
25
26 #include "trapper_auth.h"
27 #include "trapper_preproc.h"
28
29 #define ZBX_STATE_NOT_SUPPORTED 1
30
31 extern int CONFIG_DOUBLE_PRECISION;
32
33 /******************************************************************************
34 * *
35 * Function: trapper_parse_preproc_test *
36 * *
37 * Purpose: parses preprocessing test request *
38 * *
39 * Parameters: jp - [IN] the request *
40 * values - [OUT] the values to test optional *
41 * (history + current) *
42 * ts - [OUT] value timestamps *
43 * values_num - [OUT] the number of values *
44 * value_type - [OUT] the value type *
45 * steps - [OUT] the preprocessing steps *
46 * single - [OUT] is preproc step single *
47 * state - [OUT] the item state *
48 * bypass_first - [OUT] the flag to bypass first step *
49 * error - [OUT] the error message *
50 * *
51 * Return value: SUCCEED - the request was parsed successfully *
52 * FAIL - otherwise *
53 * *
54 ******************************************************************************/
trapper_parse_preproc_test(const struct zbx_json_parse * jp,char ** values,zbx_timespec_t * ts,int * values_num,unsigned char * value_type,zbx_vector_ptr_t * steps,int * single,int * state,int * bypass_first,char ** error)55 static int trapper_parse_preproc_test(const struct zbx_json_parse *jp, char **values, zbx_timespec_t *ts,
56 int *values_num, unsigned char *value_type, zbx_vector_ptr_t *steps, int *single, int *state,
57 int *bypass_first, char **error)
58 {
59 char buffer[MAX_STRING_LEN], *step_params = NULL, *error_handler_params = NULL;
60 const char *ptr;
61 zbx_user_t user;
62 int ret = FAIL;
63 struct zbx_json_parse jp_data, jp_history, jp_steps, jp_step;
64 size_t size;
65 zbx_timespec_t ts_now;
66
67 if (FAIL == zbx_get_user_from_json(jp, &user, NULL) || USER_TYPE_ZABBIX_ADMIN > user.type)
68 {
69 *error = zbx_strdup(NULL, "Permission denied.");
70 goto out;
71 }
72
73 if (FAIL == zbx_json_brackets_by_name(jp, ZBX_PROTO_TAG_DATA, &jp_data))
74 {
75 *error = zbx_strdup(NULL, "Missing data field.");
76 goto out;
77 }
78
79 if (FAIL == zbx_json_value_by_name(&jp_data, ZBX_PROTO_TAG_VALUE_TYPE, buffer, sizeof(buffer), NULL))
80 {
81 *error = zbx_strdup(NULL, "Missing value type field.");
82 goto out;
83 }
84 *value_type = atoi(buffer);
85
86 if (FAIL == zbx_json_value_by_name(&jp_data, ZBX_PROTO_TAG_SINGLE, buffer, sizeof(buffer), NULL))
87 *single = 0;
88 else
89 *single = (0 == strcmp(buffer, "true") ? 1 : 0);
90
91 *state = 0;
92 if (SUCCEED == zbx_json_value_by_name(&jp_data, ZBX_PROTO_TAG_STATE, buffer, sizeof(buffer), NULL))
93 *state = atoi(buffer);
94
95 zbx_timespec(&ts_now);
96 if (SUCCEED == zbx_json_brackets_by_name(&jp_data, ZBX_PROTO_TAG_HISTORY, &jp_history))
97 {
98 size = 0;
99 if (FAIL == zbx_json_value_by_name_dyn(&jp_history, ZBX_PROTO_TAG_VALUE, values, &size, NULL))
100 {
101 *error = zbx_strdup(NULL, "Missing history value field.");
102 goto out;
103 }
104 (*values_num)++;
105
106 if (FAIL == zbx_json_value_by_name(&jp_history, ZBX_PROTO_TAG_TIMESTAMP, buffer, sizeof(buffer), NULL))
107 {
108 *error = zbx_strdup(NULL, "Missing history timestamp field.");
109 goto out;
110 }
111
112 if (0 != strncmp(buffer, "now", ZBX_CONST_STRLEN("now")))
113 {
114 *error = zbx_dsprintf(NULL, "invalid history value timestamp: %s", buffer);
115 goto out;
116 }
117
118 ts[0] = ts_now;
119 ptr = buffer + ZBX_CONST_STRLEN("now");
120
121 if ('\0' != *ptr)
122 {
123 int delay;
124
125 if ('-' != *ptr || FAIL == is_time_suffix(ptr + 1, &delay, strlen(ptr + 1)))
126 {
127 *error = zbx_dsprintf(NULL, "invalid history value timestamp: %s", buffer);
128 goto out;
129 }
130
131 ts[0].sec -= delay;
132 }
133 }
134
135 size = 0;
136 if (FAIL == zbx_json_value_by_name_dyn(&jp_data, ZBX_PROTO_TAG_VALUE, &values[*values_num], &size, NULL))
137 {
138 *error = zbx_strdup(NULL, "Missing value field.");
139 goto out;
140 }
141 ts[(*values_num)++] = ts_now;
142
143 if (FAIL == zbx_json_brackets_by_name(&jp_data, ZBX_PROTO_TAG_STEPS, &jp_steps))
144 {
145 *error = zbx_strdup(NULL, "Missing preprocessing steps field.");
146 goto out;
147 }
148
149 *bypass_first = 0;
150
151 for (ptr = NULL; NULL != (ptr = zbx_json_next(&jp_steps, ptr));)
152 {
153 zbx_preproc_op_t *step;
154 unsigned char step_type, error_handler;
155
156 if (FAIL == zbx_json_brackets_open(ptr, &jp_step))
157 {
158 *error = zbx_strdup(NULL, "Cannot parse preprocessing step.");
159 goto out;
160 }
161
162 if (FAIL == zbx_json_value_by_name(&jp_step, ZBX_PROTO_TAG_TYPE, buffer, sizeof(buffer), NULL))
163 {
164 *error = zbx_strdup(NULL, "Missing preprocessing step type field.");
165 goto out;
166 }
167 step_type = atoi(buffer);
168
169 if (FAIL == zbx_json_value_by_name(&jp_step, ZBX_PROTO_TAG_ERROR_HANDLER, buffer, sizeof(buffer), NULL))
170 {
171 *error = zbx_strdup(NULL, "Missing preprocessing step type error handler field.");
172 goto out;
173 }
174 error_handler = atoi(buffer);
175
176 size = 0;
177 if (FAIL == zbx_json_value_by_name_dyn(&jp_step, ZBX_PROTO_TAG_PARAMS, &step_params, &size, NULL))
178 {
179 *error = zbx_strdup(NULL, "Missing preprocessing step type params field.");
180 goto out;
181 }
182
183 size = 0;
184 if (FAIL == zbx_json_value_by_name_dyn(&jp_step, ZBX_PROTO_TAG_ERROR_HANDLER_PARAMS,
185 &error_handler_params, &size, NULL))
186 {
187 *error = zbx_strdup(NULL, "Missing preprocessing step type error handler params field.");
188 goto out;
189 }
190
191 if (ZBX_PREPROC_VALIDATE_NOT_SUPPORTED != step_type || ZBX_STATE_NOT_SUPPORTED == *state)
192 {
193 step = (zbx_preproc_op_t *)zbx_malloc(NULL, sizeof(zbx_preproc_op_t));
194 step->type = step_type;
195 step->params = step_params;
196 step->error_handler = error_handler;
197 step->error_handler_params = error_handler_params;
198 zbx_vector_ptr_append(steps, step);
199 }
200 else
201 {
202 zbx_free(step_params);
203 zbx_free(error_handler_params);
204 *bypass_first = 1;
205 }
206
207 step_params = NULL;
208 error_handler_params = NULL;
209 }
210
211 ret = SUCCEED;
212 out:
213 if (FAIL == ret)
214 {
215 zbx_vector_ptr_clear_ext(steps, (zbx_clean_func_t)zbx_preproc_op_free);
216 zbx_free(values[0]);
217 zbx_free(values[1]);
218 }
219
220 zbx_free(step_params);
221 zbx_free(error_handler_params);
222
223 return ret;
224 }
225
226 /******************************************************************************
227 * *
228 * Function: trapper_preproc_test_run *
229 * *
230 * Purpose: executes preprocessing test request *
231 * *
232 * Parameters: jp - [IN] the request *
233 * json - [OUT] the output json *
234 * error - [OUT] the error message *
235 * *
236 * Return value: SUCCEED - the request was executed successfully *
237 * FAIL - otherwise *
238 * *
239 * Comments: This function will fail if the request format is not valid or *
240 * there was connection (to preprocessing manager) error. *
241 * Any errors in the preprocessing itself are reported in output *
242 * json and success is returned. *
243 * *
244 ******************************************************************************/
trapper_preproc_test_run(const struct zbx_json_parse * jp,struct zbx_json * json,char ** error)245 static int trapper_preproc_test_run(const struct zbx_json_parse *jp, struct zbx_json *json, char **error)
246 {
247 char *values[2] = {NULL, NULL}, *preproc_error = NULL;
248 int i, single, state, bypass_first, ret = FAIL, values_num = 0;
249 unsigned char value_type, first_step_type;
250 zbx_vector_ptr_t steps, results, history;
251 zbx_timespec_t ts[2];
252 zbx_preproc_result_t *result;
253
254 zbx_vector_ptr_create(&steps);
255 zbx_vector_ptr_create(&results);
256 zbx_vector_ptr_create(&history);
257
258 if (FAIL == trapper_parse_preproc_test(jp, values, ts, &values_num, &value_type, &steps, &single, &state,
259 &bypass_first, error))
260 {
261 goto out;
262 }
263
264 first_step_type = 0;
265 if (0 != steps.values_num)
266 first_step_type = ((zbx_preproc_op_t *)steps.values[0])->type;
267
268 if (ZBX_PREPROC_VALIDATE_NOT_SUPPORTED != first_step_type && ZBX_STATE_NOT_SUPPORTED == state)
269 {
270 preproc_error = zbx_strdup(NULL, "This item is not supported. Please, add a preprocessing step"
271 " \"Check for not supported value\" to process it.");
272 zbx_json_addstring(json, ZBX_PROTO_TAG_RESPONSE, "success", ZBX_JSON_TYPE_STRING);
273 zbx_json_addobject(json, ZBX_PROTO_TAG_DATA);
274 zbx_json_addarray(json, ZBX_PROTO_TAG_STEPS);
275 goto err;
276 }
277
278 for (i = 0; i < values_num; i++)
279 {
280 zbx_vector_ptr_clear_ext(&results, (zbx_clean_func_t)zbx_preproc_result_free);
281
282 if (0 == steps.values_num)
283 {
284 zbx_variant_t value;
285
286 result = (zbx_preproc_result_t *)zbx_malloc(NULL, sizeof(zbx_preproc_result_t));
287
288 result->error = NULL;
289 zbx_variant_set_str(&value, values[i]);
290 zbx_variant_copy(&result->value, &value);
291 zbx_vector_ptr_append(&results, result);
292 }
293 else if (FAIL == zbx_preprocessor_test(value_type, values[i], &ts[i], &steps, &results, &history,
294 &preproc_error, error))
295 {
296 goto out;
297 }
298
299 if (NULL != preproc_error)
300 break;
301
302 if (0 == single)
303 {
304 result = (zbx_preproc_result_t *)results.values[results.values_num - 1];
305 if (ZBX_VARIANT_NONE != result->value.type && FAIL == zbx_variant_to_value_type(&result->value,
306 value_type, CONFIG_DOUBLE_PRECISION, &preproc_error))
307 {
308 break;
309 }
310 }
311 }
312
313 zbx_json_addstring(json, ZBX_PROTO_TAG_RESPONSE, "success", ZBX_JSON_TYPE_STRING);
314 zbx_json_addobject(json, ZBX_PROTO_TAG_DATA);
315
316 if (i + 1 < values_num)
317 zbx_json_addstring(json, ZBX_PROTO_TAG_PREVIOUS, "true", ZBX_JSON_TYPE_INT);
318
319 zbx_json_addarray(json, ZBX_PROTO_TAG_STEPS);
320
321 if (1 == bypass_first)
322 {
323 zbx_json_addobject(json, NULL);
324 zbx_json_addstring(json, ZBX_PROTO_TAG_RESULT, ZBX_PROTO_TAG_VALUE, ZBX_JSON_TYPE_STRING);
325 zbx_json_close(json);
326 }
327
328 if (0 != steps.values_num)
329 {
330 for (i = 0; i < results.values_num; i++)
331 {
332 result = (zbx_preproc_result_t *)results.values[i];
333
334 zbx_json_addobject(json, NULL);
335
336 if (NULL != result->error)
337 zbx_json_addstring(json, ZBX_PROTO_TAG_ERROR, result->error, ZBX_JSON_TYPE_STRING);
338
339 if (ZBX_PREPROC_FAIL_DEFAULT != result->action)
340 zbx_json_adduint64(json, ZBX_PROTO_TAG_ACTION, result->action);
341
342 if (i == results.values_num - 1 && NULL != result->error)
343 {
344 if (ZBX_PREPROC_FAIL_SET_ERROR == result->action)
345 {
346 zbx_json_addstring(json, ZBX_PROTO_TAG_FAILED, preproc_error,
347 ZBX_JSON_TYPE_STRING);
348 }
349 }
350
351 if (ZBX_VARIANT_NONE != result->value.type)
352 {
353 zbx_json_addstring(json, ZBX_PROTO_TAG_RESULT, zbx_variant_value_desc(&result->value),
354 ZBX_JSON_TYPE_STRING);
355 }
356 else if (NULL == result->error || ZBX_PREPROC_FAIL_DISCARD_VALUE == result->action)
357 zbx_json_addstring(json, ZBX_PROTO_TAG_RESULT, NULL, ZBX_JSON_TYPE_NULL);
358
359 zbx_json_close(json);
360 }
361 }
362 err:
363 zbx_json_close(json);
364
365 if (NULL == preproc_error)
366 {
367 result = (zbx_preproc_result_t *)results.values[results.values_num - 1];
368
369 if (ZBX_VARIANT_NONE != result->value.type)
370 {
371 zbx_json_addstring(json, ZBX_PROTO_TAG_RESULT, zbx_variant_value_desc(&result->value),
372 ZBX_JSON_TYPE_STRING);
373 }
374 else
375 zbx_json_addstring(json, ZBX_PROTO_TAG_RESULT, NULL, ZBX_JSON_TYPE_NULL);
376 }
377 else
378 zbx_json_addstring(json, ZBX_PROTO_TAG_ERROR, preproc_error, ZBX_JSON_TYPE_STRING);
379
380 ret = SUCCEED;
381 out:
382 for (i = 0; i < values_num; i++)
383 zbx_free(values[i]);
384
385 zbx_free(preproc_error);
386
387 zbx_vector_ptr_clear_ext(&history, (zbx_clean_func_t)zbx_preproc_op_history_free);
388 zbx_vector_ptr_destroy(&history);
389 zbx_vector_ptr_clear_ext(&results, (zbx_clean_func_t)zbx_preproc_result_free);
390 zbx_vector_ptr_destroy(&results);
391 zbx_vector_ptr_clear_ext(&steps, (zbx_clean_func_t)zbx_preproc_op_free);
392 zbx_vector_ptr_destroy(&steps);
393
394 return ret;
395 }
396
397 /******************************************************************************
398 * *
399 * Function: zbx_trapper_preproc_test *
400 * *
401 * Purpose: processes preprocessing test request *
402 * *
403 * Parameters: sock - [IN] the request source socket (frontend) *
404 * jp - [IN] the request *
405 * *
406 * Return value: SUCCEED - the request was processed successfully *
407 * FAIL - otherwise *
408 * *
409 * Comments: This function will send proper (success/fail) response to the *
410 * request socket. *
411 * Preprocessing failure (error returned by a preprocessing step) *
412 * is counted as successful test and will return success response. *
413 * *
414 ******************************************************************************/
zbx_trapper_preproc_test(zbx_socket_t * sock,const struct zbx_json_parse * jp)415 int zbx_trapper_preproc_test(zbx_socket_t *sock, const struct zbx_json_parse *jp)
416 {
417 char *error = NULL;
418 int ret;
419 struct zbx_json json;
420
421 zbx_json_init(&json, 1024);
422
423 if (SUCCEED == (ret = trapper_preproc_test_run(jp, &json, &error)))
424 {
425 zbx_tcp_send_bytes_to(sock, json.buffer, json.buffer_size, CONFIG_TIMEOUT);
426 }
427 else
428 {
429 zbx_send_response(sock, ret, error, CONFIG_TIMEOUT);
430 zbx_free(error);
431 }
432
433 zbx_json_free(&json);
434
435 return ret;
436 }
437
438 #ifdef HAVE_TESTS
439 # include "../../../tests/zabbix_server/trapper/trapper_preproc_test_run.c"
440 #endif
441