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 "zbxregexp.h"
21 #include "log.h"
22 #include "zbxembed.h"
23 #include "zbxprometheus.h"
24 
25 /* LIBXML2 is used */
26 #ifdef HAVE_LIBXML2
27 #	include <libxml/parser.h>
28 #	include <libxml/tree.h>
29 #	include <libxml/xpath.h>
30 #endif
31 
32 #include "preproc_history.h"
33 
34 #include "item_preproc.h"
35 
36 extern zbx_es_t	es_engine;
37 
38 /******************************************************************************
39  *                                                                            *
40  * Function: item_preproc_numeric_type_hint                                   *
41  *                                                                            *
42  * Purpose: returns numeric type hint based on item value type                *
43  *                                                                            *
44  * Parameters: value_type - [IN] the item value type                          *
45  *                                                                            *
46  * Return value: variant numeric type or none                                 *
47  *                                                                            *
48  ******************************************************************************/
item_preproc_numeric_type_hint(unsigned char value_type)49 static int	item_preproc_numeric_type_hint(unsigned char value_type)
50 {
51 	switch (value_type)
52 	{
53 		case ITEM_VALUE_TYPE_FLOAT:
54 			return ZBX_VARIANT_DBL;
55 		case ITEM_VALUE_TYPE_UINT64:
56 			return ZBX_VARIANT_UI64;
57 		default:
58 			return ZBX_VARIANT_NONE;
59 	}
60 }
61 
62 /******************************************************************************
63  *                                                                            *
64  * Function: item_preproc_convert_value                                       *
65  *                                                                            *
66  * Purpose: convert variant value to the requested type                       *
67  *                                                                            *
68  * Parameters: value  - [IN/OUT] the value to convert                         *
69  *             type   - [IN] the new value type                               *
70  *             errmsg - [OUT] error message                                   *
71  *                                                                            *
72  * Return value: SUCCEED - the value was converted successfully               *
73  *               FAIL - otherwise, errmsg contains the error message          *
74  *                                                                            *
75  ******************************************************************************/
item_preproc_convert_value(zbx_variant_t * value,unsigned char type,char ** errmsg)76 static int	item_preproc_convert_value(zbx_variant_t *value, unsigned char type, char **errmsg)
77 {
78 	if (FAIL == zbx_variant_convert(value, type))
79 	{
80 		*errmsg = zbx_dsprintf(*errmsg, "cannot convert value to %s", zbx_get_variant_type_desc(type));
81 		return FAIL;
82 	}
83 
84 	return SUCCEED;
85 }
86 
87 /******************************************************************************
88  *                                                                            *
89  * Function: zbx_item_preproc_convert_value_to_numeric                        *
90  *                                                                            *
91  * Purpose: converts variant value to numeric                                 *
92  *                                                                            *
93  * Parameters: value_num  - [OUT] the converted value                         *
94  *             value      - [IN] the value to convert                         *
95  *             value_type - [IN] item value type                              *
96  *             errmsg     - [OUT] error message                               *
97  *                                                                            *
98  * Return value: SUCCEED - the value was converted successfully               *
99  *               FAIL - otherwise                                             *
100  *                                                                            *
101  ******************************************************************************/
zbx_item_preproc_convert_value_to_numeric(zbx_variant_t * value_num,const zbx_variant_t * value,unsigned char value_type,char ** errmsg)102 int	zbx_item_preproc_convert_value_to_numeric(zbx_variant_t *value_num, const zbx_variant_t *value,
103 		unsigned char value_type, char **errmsg)
104 {
105 	int	ret = FAIL, type_hint;
106 
107 	switch (value->type)
108 	{
109 		case ZBX_VARIANT_DBL:
110 		case ZBX_VARIANT_UI64:
111 			zbx_variant_copy(value_num, value);
112 			ret = SUCCEED;
113 			break;
114 		case ZBX_VARIANT_STR:
115 			ret = zbx_variant_set_numeric(value_num, value->data.str);
116 			break;
117 		default:
118 			ret = FAIL;
119 	}
120 
121 	if (FAIL == ret)
122 	{
123 		*errmsg = zbx_strdup(*errmsg, "cannot convert value to numeric type");
124 		return FAIL;
125 	}
126 
127 	if (ZBX_VARIANT_NONE != (type_hint = item_preproc_numeric_type_hint(value_type)))
128 		zbx_variant_convert(value_num, type_hint);
129 
130 	return SUCCEED;
131 }
132 
133 /******************************************************************************
134  *                                                                            *
135  * Function: item_preproc_multiplier_variant                                  *
136  *                                                                            *
137  * Purpose: execute custom multiplier preprocessing operation on variant      *
138  *          value type                                                        *
139  *                                                                            *
140  * Parameters: value_type - [IN] the item type                                *
141  *             value      - [IN/OUT] the value to process                     *
142  *             params     - [IN] the operation parameters                     *
143  *             errmsg     - [OUT] error message                               *
144  *                                                                            *
145  * Return value: SUCCEED - the preprocessing step finished successfully       *
146  *               FAIL - otherwise, errmsg contains the error message          *
147  *                                                                            *
148  ******************************************************************************/
item_preproc_multiplier_variant(unsigned char value_type,zbx_variant_t * value,const char * params,char ** errmsg)149 static int	item_preproc_multiplier_variant(unsigned char value_type, zbx_variant_t *value, const char *params,
150 		char **errmsg)
151 {
152 	zbx_uint64_t	multiplier_ui64, value_ui64;
153 	double		value_dbl;
154 	zbx_variant_t	value_num;
155 
156 	if (FAIL == zbx_item_preproc_convert_value_to_numeric(&value_num, value, value_type, errmsg))
157 		return FAIL;
158 
159 	switch (value_num.type)
160 	{
161 		case ZBX_VARIANT_DBL:
162 			value_dbl = value_num.data.dbl * atof(params);
163 			zbx_variant_clear(value);
164 			zbx_variant_set_dbl(value, value_dbl);
165 			break;
166 		case ZBX_VARIANT_UI64:
167 			if (SUCCEED == is_uint64(params, &multiplier_ui64))
168 				value_ui64 = value_num.data.ui64 * multiplier_ui64;
169 			else
170 				value_ui64 = (double)value_num.data.ui64 * atof(params);
171 
172 			zbx_variant_clear(value);
173 			zbx_variant_set_ui64(value, value_ui64);
174 			break;
175 	}
176 
177 	zbx_variant_clear(&value_num);
178 
179 	return SUCCEED;
180 }
181 
182 /******************************************************************************
183  *                                                                            *
184  * Function: item_preproc_validate_notsupport                                 *
185  *                                                                            *
186  * Purpose: executes during notsupported item preprocessing                   *
187  *                                                                            *
188  * Return value: FAIL - for further error handling                            *
189  *                                                                            *
190  ******************************************************************************/
item_preproc_validate_notsupport(char ** errmsg)191 static int	item_preproc_validate_notsupport(char **errmsg)
192 {
193 	*errmsg = zbx_dsprintf(*errmsg, "item is not supported");
194 	return FAIL;
195 }
196 
197 /******************************************************************************
198  *                                                                            *
199  * Function: item_preproc_multiplier                                          *
200  *                                                                            *
201  * Purpose: execute custom multiplier preprocessing operation                 *
202  *                                                                            *
203  * Parameters: value_type - [IN] the item type                                *
204  *             value      - [IN/OUT] the value to process                     *
205  *             params     - [IN] the operation parameters                     *
206  *             errmsg     - [OUT] error message                               *
207  *                                                                            *
208  * Return value: SUCCEED - the preprocessing step finished successfully       *
209  *               FAIL - otherwise, errmsg contains the error message          *
210  *                                                                            *
211  ******************************************************************************/
item_preproc_multiplier(unsigned char value_type,zbx_variant_t * value,const char * params,char ** errmsg)212 static int	item_preproc_multiplier(unsigned char value_type, zbx_variant_t *value, const char *params,
213 		char **errmsg)
214 {
215 	char	buffer[MAX_STRING_LEN];
216 	char	*err = NULL;
217 
218 	zbx_strlcpy(buffer, params, sizeof(buffer));
219 
220 	zbx_trim_float(buffer);
221 
222 	if (FAIL == is_double(buffer, NULL))
223 		err = zbx_dsprintf(NULL, "a numerical value is expected or the value is out of range");
224 	else if (SUCCEED == item_preproc_multiplier_variant(value_type, value, buffer, &err))
225 		return SUCCEED;
226 
227 	*errmsg = zbx_dsprintf(*errmsg, "cannot apply multiplier \"%s\" to value of type \"%s\": %s",
228 			params, zbx_variant_type_desc(value), err);
229 	zbx_free(err);
230 
231 	return FAIL;
232 }
233 
234 /******************************************************************************
235  *                                                                            *
236  * Function: item_preproc_delta_float                                         *
237  *                                                                            *
238  * Purpose: execute delta type preprocessing operation                        *
239  *                                                                            *
240  * Parameters: value         - [IN/OUT] the value to process                  *
241  *             ts            - [IN] the value timestamp                       *
242  *             op_type       - [IN] the operation type                        *
243  *             history_value - [IN] the item historical data                  *
244  *             history_ts    - [IN] the historical data timestamp             *
245  *                                                                            *
246  * Return value: SUCCEED - the value was calculated successfully              *
247  *               FAIL - otherwise                                             *
248  *                                                                            *
249  ******************************************************************************/
item_preproc_delta_float(zbx_variant_t * value,const zbx_timespec_t * ts,unsigned char op_type,const zbx_variant_t * history_value,const zbx_timespec_t * history_ts)250 static int	item_preproc_delta_float(zbx_variant_t *value, const zbx_timespec_t *ts, unsigned char op_type,
251 		const zbx_variant_t *history_value, const zbx_timespec_t *history_ts)
252 {
253 	if (0 == history_ts->sec || history_value->data.dbl > value->data.dbl)
254 		return FAIL;
255 
256 	switch (op_type)
257 	{
258 		case ZBX_PREPROC_DELTA_SPEED:
259 			if (0 <= zbx_timespec_compare(history_ts, ts))
260 				return FAIL;
261 
262 			value->data.dbl = (value->data.dbl - history_value->data.dbl) /
263 					((ts->sec - history_ts->sec) +
264 						(double)(ts->ns - history_ts->ns) / 1000000000);
265 			break;
266 		case ZBX_PREPROC_DELTA_VALUE:
267 			value->data.dbl = value->data.dbl - history_value->data.dbl;
268 			break;
269 	}
270 
271 	return SUCCEED;
272 }
273 
274 /******************************************************************************
275  *                                                                            *
276  * Function: item_preproc_delta_uint64                                        *
277  *                                                                            *
278  * Purpose: execute delta type preprocessing operation                        *
279  *                                                                            *
280  * Parameters: value         - [IN/OUT] the value to process                  *
281  *             ts            - [IN] the value timestamp                       *
282  *             op_type       - [IN] the operation type                        *
283  *             history_value - [IN] the item historical data                  *
284  *             history_ts    - [IN] the historical data timestamp             *
285  *                                                                            *
286  * Return value: SUCCEED - the value was calculated successfully              *
287  *               FAIL - otherwise                                             *
288  *                                                                            *
289  ******************************************************************************/
item_preproc_delta_uint64(zbx_variant_t * value,const zbx_timespec_t * ts,unsigned char op_type,const zbx_variant_t * history_value,const zbx_timespec_t * history_ts)290 static int	item_preproc_delta_uint64(zbx_variant_t *value, const zbx_timespec_t *ts, unsigned char op_type,
291 		const zbx_variant_t *history_value, const zbx_timespec_t *history_ts)
292 {
293 	if (0 == history_ts->sec || history_value->data.ui64 > value->data.ui64)
294 		return FAIL;
295 
296 	switch (op_type)
297 	{
298 		case ZBX_PREPROC_DELTA_SPEED:
299 			if (0 <= zbx_timespec_compare(history_ts, ts))
300 				return FAIL;
301 
302 			value->data.ui64 = (value->data.ui64 - history_value->data.ui64) /
303 					((ts->sec - history_ts->sec) +
304 						(double)(ts->ns - history_ts->ns) / 1000000000);
305 			break;
306 		case ZBX_PREPROC_DELTA_VALUE:
307 			value->data.ui64 = value->data.ui64 - history_value->data.ui64;
308 			break;
309 	}
310 
311 	return SUCCEED;
312 }
313 
314 /******************************************************************************
315  *                                                                            *
316  * Function: item_preproc_delta                                               *
317  *                                                                            *
318  * Purpose: execute delta type preprocessing operation                        *
319  *                                                                            *
320  * Parameters: value_type    - [IN] the item value type                       *
321  *             value         - [IN/OUT] the value to process                  *
322  *             ts            - [IN] the value timestamp                       *
323  *             op_type       - [IN] the operation type                        *
324  *             history_value - [IN/OUT] the historical (previous) data        *
325  *             history_ts    - [IN/OUT] the timestamp of the historical data  *
326  *             errmsg        - [OUT] error message                            *
327  *                                                                            *
328  * Return value: SUCCEED - the value was calculated successfully              *
329  *               FAIL - otherwise                                             *
330  *                                                                            *
331  ******************************************************************************/
item_preproc_delta(unsigned char value_type,zbx_variant_t * value,const zbx_timespec_t * ts,unsigned char op_type,zbx_variant_t * history_value,zbx_timespec_t * history_ts,char ** errmsg)332 static int	item_preproc_delta(unsigned char value_type, zbx_variant_t *value, const zbx_timespec_t *ts,
333 		unsigned char op_type, zbx_variant_t *history_value, zbx_timespec_t *history_ts, char **errmsg)
334 {
335 	zbx_variant_t			value_num;
336 
337 	if (FAIL == zbx_item_preproc_convert_value_to_numeric(&value_num, value, value_type, errmsg))
338 		return FAIL;
339 
340 	zbx_variant_clear(value);
341 
342 	if (ZBX_VARIANT_NONE != history_value->type)
343 	{
344 		int				ret;
345 
346 		zbx_variant_copy(value, &value_num);
347 
348 		if (ZBX_VARIANT_DBL == value->type || ZBX_VARIANT_DBL == history_value->type)
349 		{
350 			zbx_variant_convert(value, ZBX_VARIANT_DBL);
351 			zbx_variant_convert(history_value, ZBX_VARIANT_DBL);
352 			ret = item_preproc_delta_float(value, ts, op_type, history_value, history_ts);
353 		}
354 		else
355 		{
356 			zbx_variant_convert(value, ZBX_VARIANT_UI64);
357 			zbx_variant_convert(history_value, ZBX_VARIANT_UI64);
358 			ret = item_preproc_delta_uint64(value, ts, op_type, history_value, history_ts);
359 		}
360 
361 		if (SUCCEED != ret)
362 			zbx_variant_clear(value);
363 	}
364 
365 	*history_ts = *ts;
366 	zbx_variant_clear(history_value);
367 	zbx_variant_copy(history_value, &value_num);
368 	zbx_variant_clear(&value_num);
369 
370 	return SUCCEED;
371 }
372 
373 /******************************************************************************
374  *                                                                            *
375  * Function: item_preproc_delta_value                                         *
376  *                                                                            *
377  * Purpose: execute delta (simple change) preprocessing operation             *
378  *                                                                            *
379  * Parameters: value_type    - [IN] the item value type                       *
380  *             value         - [IN/OUT] the value to process                  *
381  *             ts            - [IN] the value timestamp                       *
382  *             history_value - [IN] historical data of item with delta        *
383  *                                  preprocessing operation                   *
384  *             errmsg        - [OUT] error message                            *
385  *                                                                            *
386  * Return value: SUCCEED - the value was calculated successfully              *
387  *               FAIL - otherwise                                             *
388  *                                                                            *
389  ******************************************************************************/
item_preproc_delta_value(unsigned char value_type,zbx_variant_t * value,const zbx_timespec_t * ts,zbx_variant_t * history_value,zbx_timespec_t * history_ts,char ** errmsg)390 static int	item_preproc_delta_value(unsigned char value_type, zbx_variant_t *value, const zbx_timespec_t *ts,
391 		zbx_variant_t *history_value, zbx_timespec_t *history_ts, char **errmsg)
392 {
393 	char	*err = NULL;
394 
395 	if (SUCCEED == item_preproc_delta(value_type, value, ts, ZBX_PREPROC_DELTA_VALUE, history_value, history_ts,
396 			&err))
397 	{
398 		return SUCCEED;
399 	}
400 
401 	*errmsg = zbx_dsprintf(*errmsg, "cannot calculate delta (simple change) for value of type"
402 				" \"%s\": %s", zbx_variant_type_desc(value), err);
403 
404 	zbx_free(err);
405 
406 	return FAIL;
407 }
408 
409 /******************************************************************************
410  *                                                                            *
411  * Function: item_preproc_delta_speed                                         *
412  *                                                                            *
413  * Purpose: execute delta (speed per second) preprocessing operation          *
414  *                                                                            *
415  * Parameters: value_type    - [IN] the item value type                       *
416  *             value         - [IN/OUT] the value to process                  *
417  *             ts            - [IN] the value timestamp                       *
418  *             history_value - [IN] historical data of item with delta        *
419  *                                  preprocessing operation                   *
420  *             errmsg        - [OUT] error message                            *
421  *                                                                            *
422  * Return value: SUCCEED - the value was calculated successfully              *
423  *               FAIL - otherwise                                             *
424  *                                                                            *
425  ******************************************************************************/
item_preproc_delta_speed(unsigned char value_type,zbx_variant_t * value,const zbx_timespec_t * ts,zbx_variant_t * history_value,zbx_timespec_t * history_ts,char ** errmsg)426 static int	item_preproc_delta_speed(unsigned char value_type, zbx_variant_t *value, const zbx_timespec_t *ts,
427 		zbx_variant_t *history_value, zbx_timespec_t *history_ts, char **errmsg)
428 {
429 	char	*err = NULL;
430 
431 	if (SUCCEED == item_preproc_delta(value_type, value, ts, ZBX_PREPROC_DELTA_SPEED, history_value, history_ts,
432 			&err))
433 	{
434 		return SUCCEED;
435 	}
436 
437 	*errmsg = zbx_dsprintf(*errmsg, "cannot calculate delta (speed per second) for value of type"
438 				" \"%s\": %s", zbx_variant_type_desc(value), err);
439 
440 	zbx_free(err);
441 
442 	return FAIL;
443 }
444 
445 /******************************************************************************
446  *                                                                            *
447  * Function: unescape_param                                                   *
448  *                                                                            *
449  * Purpose: copy first n chars from in to out, unescape escaped characters    *
450  *          during copying                                                    *
451  *                                                                            *
452  * Parameters: op_type - [IN] the operation type                              *
453  *             in      - [IN] the value to unescape                           *
454  *             len     - [IN] the length of the value to be unescaped         *
455  *             out     - [OUT] the value to process                           *
456  *                                                                            *
457  ******************************************************************************/
unescape_param(int op_type,const char * in,int len,char * out)458 static void	unescape_param(int op_type, const char *in, int len, char *out)
459 {
460 	const char	*end = in + len;
461 
462 	for (;in < end; in++, out++)
463 	{
464 		if ('\\' == *in)
465 		{
466 			switch (*(++in))
467 			{
468 				case 's':
469 					*out = ' ';
470 					break;
471 				case 'r':
472 					*out = '\r';
473 					break;
474 				case 'n':
475 					*out = '\n';
476 					break;
477 				case 't':
478 					*out = '\t';
479 					break;
480 				case '\\':
481 					if (ZBX_PREPROC_STR_REPLACE == op_type)
482 					{
483 						*out = '\\';
484 						break;
485 					}
486 					ZBX_FALLTHROUGH;
487 				default:
488 					*out = *(--in);
489 			}
490 		}
491 		else
492 			*out = *in;
493 	}
494 
495 	*out = '\0';
496 }
497 
498 /******************************************************************************
499  *                                                                            *
500  * Function: item_preproc_trim                                                *
501  *                                                                            *
502  * Purpose: execute trim type preprocessing operation                         *
503  *                                                                            *
504  * Parameters: value   - [IN/OUT] the value to process                        *
505  *             op_type - [IN] the operation type                              *
506  *             params  - [IN] the characters to trim                          *
507  *             errmsg  - [OUT] error message                                  *
508  *                                                                            *
509  * Return value: SUCCEED - the value was trimmed successfully                 *
510  *               FAIL - otherwise                                             *
511  *                                                                            *
512  ******************************************************************************/
item_preproc_trim(zbx_variant_t * value,unsigned char op_type,const char * params,char ** errmsg)513 static int item_preproc_trim(zbx_variant_t *value, unsigned char op_type, const char *params, char **errmsg)
514 {
515 	char	params_raw[ITEM_PREPROC_PARAMS_LEN * ZBX_MAX_BYTES_IN_UTF8_CHAR + 1];
516 
517 	if (FAIL == item_preproc_convert_value(value, ZBX_VARIANT_STR, errmsg))
518 		return FAIL;
519 
520 	unescape_param(op_type, params, strlen(params), params_raw);
521 
522 	if (ZBX_PREPROC_LTRIM == op_type || ZBX_PREPROC_TRIM == op_type)
523 		zbx_ltrim(value->data.str, params_raw);
524 
525 	if (ZBX_PREPROC_RTRIM == op_type || ZBX_PREPROC_TRIM == op_type)
526 		zbx_rtrim(value->data.str, params_raw);
527 
528 	return SUCCEED;
529 }
530 
531 /******************************************************************************
532  *                                                                            *
533  * Function: item_preproc_rtrim                                               *
534  *                                                                            *
535  * Purpose: execute right trim preprocessing operation                        *
536  *                                                                            *
537  * Parameters: value   - [IN/OUT] the value to process                        *
538  *             params  - [IN] the characters to trim                          *
539  *             errmsg  - [OUT] error message                                  *
540  *                                                                            *
541  * Return value: SUCCEED - the value was trimmed successfully                 *
542  *               FAIL - otherwise                                             *
543  *                                                                            *
544  ******************************************************************************/
item_preproc_rtrim(zbx_variant_t * value,const char * params,char ** errmsg)545 static int item_preproc_rtrim(zbx_variant_t *value, const char *params, char **errmsg)
546 {
547 	char	*err = NULL, *characters;
548 
549 	if (SUCCEED == item_preproc_trim(value, ZBX_PREPROC_RTRIM, params, &err))
550 		return SUCCEED;
551 
552 	characters = zbx_str_printable_dyn(params);
553 	*errmsg = zbx_dsprintf(*errmsg, "cannot perform right trim of \"%s\" for value of type \"%s\": %s",
554 			characters, zbx_variant_type_desc(value), err);
555 
556 	zbx_free(characters);
557 	zbx_free(err);
558 
559 	return FAIL;
560 }
561 
562 /******************************************************************************
563  *                                                                            *
564  * Function: item_preproc_ltrim                                               *
565  *                                                                            *
566  * Purpose: execute left trim preprocessing operation                         *
567  *                                                                            *
568  * Parameters: value   - [IN/OUT] the value to process                        *
569  *             params  - [IN] the characters to trim                          *
570  *             errmsg  - [OUT] error message                                  *
571  *                                                                            *
572  * Return value: SUCCEED - the value was trimmed successfully                 *
573  *               FAIL - otherwise                                             *
574  *                                                                            *
575  ******************************************************************************/
item_preproc_ltrim(zbx_variant_t * value,const char * params,char ** errmsg)576 static int item_preproc_ltrim(zbx_variant_t *value, const char *params, char **errmsg)
577 {
578 	char	*err = NULL, *characters;
579 
580 	if (SUCCEED == item_preproc_trim(value, ZBX_PREPROC_LTRIM, params, &err))
581 		return SUCCEED;
582 
583 	characters = zbx_str_printable_dyn(params);
584 	*errmsg = zbx_dsprintf(*errmsg, "cannot perform left trim of \"%s\" for value of type \"%s\": %s",
585 			characters, zbx_variant_type_desc(value), err);
586 
587 	zbx_free(characters);
588 	zbx_free(err);
589 
590 	return FAIL;
591 }
592 
593 /******************************************************************************
594  *                                                                            *
595  * Function: item_preproc_lrtrim                                              *
596  *                                                                            *
597  * Purpose: execute left and right trim preprocessing operation               *
598  *                                                                            *
599  * Parameters: value   - [IN/OUT] the value to process                        *
600  *             params  - [IN] the characters to trim                          *
601  *             errmsg  - [OUT] error message                                  *
602  *                                                                            *
603  * Return value: SUCCEED - the value was trimmed successfully                 *
604  *               FAIL - otherwise                                             *
605  *                                                                            *
606  ******************************************************************************/
item_preproc_lrtrim(zbx_variant_t * value,const char * params,char ** errmsg)607 static int item_preproc_lrtrim(zbx_variant_t *value, const char *params, char **errmsg)
608 {
609 	char	*err = NULL, *characters;
610 
611 	if (SUCCEED == item_preproc_trim(value, ZBX_PREPROC_TRIM, params, &err))
612 		return SUCCEED;
613 
614 	characters = zbx_str_printable_dyn(params);
615 	*errmsg = zbx_dsprintf(*errmsg, "cannot perform trim of \"%s\" for value of type \"%s\": %s",
616 			characters, zbx_variant_type_desc(value), err);
617 
618 	zbx_free(characters);
619 	zbx_free(err);
620 
621 	return FAIL;
622 }
623 
624 /******************************************************************************
625  *                                                                            *
626  * Function: item_preproc_2dec                                                *
627  *                                                                            *
628  * Purpose: execute decimal value conversion operation                        *
629  *                                                                            *
630  * Parameters: value   - [IN/OUT] the value to convert                        *
631  *             op_type - [IN] the operation type                              *
632  *             errmsg  - [OUT] error message                                  *
633  *                                                                            *
634  * Return value: SUCCEED - the value was converted successfully               *
635  *               FAIL - otherwise                                             *
636  *                                                                            *
637  ******************************************************************************/
item_preproc_2dec(zbx_variant_t * value,unsigned char op_type,char ** errmsg)638 static int	item_preproc_2dec(zbx_variant_t *value, unsigned char op_type, char **errmsg)
639 {
640 	zbx_uint64_t	value_ui64;
641 
642 	if (FAIL == item_preproc_convert_value(value, ZBX_VARIANT_STR, errmsg))
643 		return FAIL;
644 
645 	zbx_ltrim(value->data.str, " \"");
646 	zbx_rtrim(value->data.str, " \"\n\r");
647 
648 	switch (op_type)
649 	{
650 		case ZBX_PREPROC_BOOL2DEC:
651 			if (SUCCEED != is_boolean(value->data.str, &value_ui64))
652 			{
653 				*errmsg = zbx_strdup(NULL, "invalid value format");
654 				return FAIL;
655 			}
656 			break;
657 		case ZBX_PREPROC_OCT2DEC:
658 			if (SUCCEED != is_uoct(value->data.str))
659 			{
660 				*errmsg = zbx_strdup(NULL, "invalid value format");
661 				return FAIL;
662 			}
663 			ZBX_OCT2UINT64(value_ui64, value->data.str);
664 			break;
665 		case ZBX_PREPROC_HEX2DEC:
666 			if (SUCCEED != is_uhex(value->data.str))
667 			{
668 				if (SUCCEED != is_hex_string(value->data.str))
669 				{
670 					*errmsg = zbx_strdup(NULL, "invalid value format");
671 					return FAIL;
672 				}
673 
674 				zbx_remove_chars(value->data.str, " \n");
675 			}
676 			ZBX_HEX2UINT64(value_ui64, value->data.str);
677 			break;
678 		default:
679 			*errmsg = zbx_strdup(NULL, "unknown operation type");
680 			return FAIL;
681 	}
682 
683 	zbx_variant_clear(value);
684 	zbx_variant_set_ui64(value, value_ui64);
685 
686 	return SUCCEED;
687 }
688 
689 /******************************************************************************
690  *                                                                            *
691  * Function: item_preproc_bool2dec                                            *
692  *                                                                            *
693  * Purpose: execute boolean to decimal value conversion operation             *
694  *                                                                            *
695  * Parameters: value   - [IN/OUT] the value to convert                        *
696  *             errmsg  - [OUT] error message                                  *
697  *                                                                            *
698  * Return value: SUCCEED - the value was converted successfully               *
699  *               FAIL - otherwise                                             *
700  *                                                                            *
701  ******************************************************************************/
item_preproc_bool2dec(zbx_variant_t * value,char ** errmsg)702 static int	item_preproc_bool2dec(zbx_variant_t *value, char **errmsg)
703 {
704 	char	*err = NULL;
705 
706 	if (SUCCEED == item_preproc_2dec(value, ZBX_PREPROC_BOOL2DEC, &err))
707 		return SUCCEED;
708 
709 	*errmsg = zbx_dsprintf(*errmsg, "cannot convert value of type \"%s\" from boolean format: %s",
710 			zbx_variant_type_desc(value), err);
711 
712 	zbx_free(err);
713 
714 	return FAIL;
715 }
716 
717 /******************************************************************************
718  *                                                                            *
719  * Function: item_preproc_oct2dec                                             *
720  *                                                                            *
721  * Purpose: execute octal to decimal value conversion operation               *
722  *                                                                            *
723  * Parameters: value   - [IN/OUT] the value to convert                        *
724  *             errmsg  - [OUT] error message                                  *
725  *                                                                            *
726  * Return value: SUCCEED - the value was converted successfully               *
727  *               FAIL - otherwise                                             *
728  *                                                                            *
729  ******************************************************************************/
item_preproc_oct2dec(zbx_variant_t * value,char ** errmsg)730 static int	item_preproc_oct2dec(zbx_variant_t *value, char **errmsg)
731 {
732 	char	*err = NULL;
733 
734 	if (SUCCEED == item_preproc_2dec(value, ZBX_PREPROC_OCT2DEC, &err))
735 		return SUCCEED;
736 
737 	*errmsg = zbx_dsprintf(*errmsg, "cannot convert value of type \"%s\" from octal format: %s",
738 			zbx_variant_type_desc(value), err);
739 
740 	zbx_free(err);
741 
742 	return FAIL;
743 }
744 
745 /******************************************************************************
746  *                                                                            *
747  * Function: item_preproc_hex2dec                                             *
748  *                                                                            *
749  * Purpose: execute hexadecimal to decimal value conversion operation         *
750  *                                                                            *
751  * Parameters: value   - [IN/OUT] the value to convert                        *
752  *             errmsg  - [OUT] error message                                  *
753  *                                                                            *
754  * Return value: SUCCEED - the value was converted successfully               *
755  *               FAIL - otherwise                                             *
756  *                                                                            *
757  ******************************************************************************/
item_preproc_hex2dec(zbx_variant_t * value,char ** errmsg)758 static int	item_preproc_hex2dec(zbx_variant_t *value, char **errmsg)
759 {
760 	char	*err = NULL;
761 
762 	if (SUCCEED == item_preproc_2dec(value, ZBX_PREPROC_HEX2DEC, &err))
763 		return SUCCEED;
764 
765 	*errmsg = zbx_dsprintf(*errmsg, "cannot convert value of type \"%s\" from hexadecimal format: %s",
766 			zbx_variant_type_desc(value), err);
767 
768 	zbx_free(err);
769 
770 	return FAIL;
771 }
772 
773 /******************************************************************************
774  *                                                                            *
775  * Function: item_preproc_regsub_op                                           *
776  *                                                                            *
777  * Purpose: execute regular expression substitution operation                 *
778  *                                                                            *
779  * Parameters: value  - [IN/OUT] the value to process                         *
780  *             params - [IN] the operation parameters                         *
781  *             errmsg - [OUT] error message                                   *
782  *                                                                            *
783  * Return value: SUCCEED - the value was processed successfully               *
784  *               FAIL - otherwise                                             *
785  *                                                                            *
786  ******************************************************************************/
item_preproc_regsub_op(zbx_variant_t * value,const char * params,char ** errmsg)787 static int	item_preproc_regsub_op(zbx_variant_t *value, const char *params, char **errmsg)
788 {
789 	char		pattern[ITEM_PREPROC_PARAMS_LEN * ZBX_MAX_BYTES_IN_UTF8_CHAR + 1];
790 	char		*output, *new_value = NULL;
791 	const char	*regex_error;
792 	zbx_regexp_t	*regex = NULL;
793 
794 	if (FAIL == item_preproc_convert_value(value, ZBX_VARIANT_STR, errmsg))
795 		return FAIL;
796 
797 	zbx_strlcpy(pattern, params, sizeof(pattern));
798 
799 	if (NULL == (output = strchr(pattern, '\n')))
800 	{
801 		*errmsg = zbx_strdup(*errmsg, "cannot find second parameter");
802 		return FAIL;
803 	}
804 
805 	*output++ = '\0';
806 
807 	if (FAIL == zbx_regexp_compile_ext(pattern, &regex, 0, &regex_error))	/* PCRE_MULTILINE is not used here */
808 	{
809 		*errmsg = zbx_dsprintf(*errmsg, "invalid regular expression: %s", regex_error);
810 		return FAIL;
811 	}
812 
813 	if (FAIL == zbx_mregexp_sub_precompiled(value->data.str, regex, output, ZBX_MAX_RECV_DATA_SIZE, &new_value))
814 	{
815 		*errmsg = zbx_strdup(*errmsg, "pattern does not match");
816 		zbx_regexp_free(regex);
817 		return FAIL;
818 	}
819 
820 	zbx_variant_clear(value);
821 	zbx_variant_set_str(value, new_value);
822 
823 	zbx_regexp_free(regex);
824 
825 	return SUCCEED;
826 }
827 
828 /******************************************************************************
829  *                                                                            *
830  * Function: item_preproc_regsub                                              *
831  *                                                                            *
832  * Purpose: execute regular expression substitution operation                 *
833  *                                                                            *
834  * Parameters: value  - [IN/OUT] the value to process                         *
835  *             params - [IN] the operation parameters                         *
836  *             errmsg - [OUT] error message                                   *
837  *                                                                            *
838  * Return value: SUCCEED - the value was processed successfully               *
839  *               FAIL - otherwise                                             *
840  *                                                                            *
841  ******************************************************************************/
item_preproc_regsub(zbx_variant_t * value,const char * params,char ** errmsg)842 static int	item_preproc_regsub(zbx_variant_t *value, const char *params, char **errmsg)
843 {
844 	char	*err = NULL, *ptr;
845 	int	len;
846 
847 	if (SUCCEED == item_preproc_regsub_op(value, params, &err))
848 		return SUCCEED;
849 
850 	if (NULL == (ptr = strchr(params, '\n')))
851 		len = strlen(params);
852 	else
853 		len = ptr - params;
854 
855 	*errmsg = zbx_dsprintf(*errmsg, "cannot perform regular expression \"%.*s\" match for value of type \"%s\": %s",
856 			len, params, zbx_variant_type_desc(value), err);
857 
858 	zbx_free(err);
859 
860 	return FAIL;
861 }
862 
863 /******************************************************************************
864  *                                                                            *
865  * Function: item_preproc_jsonpath_op                                         *
866  *                                                                            *
867  * Purpose: execute jsonpath query                                            *
868  *                                                                            *
869  * Parameters: value  - [IN/OUT] the value to process                         *
870  *             params - [IN] the operation parameters                         *
871  *             errmsg - [OUT] error message                                   *
872  *                                                                            *
873  * Return value: SUCCEED - the value was processed successfully               *
874  *               FAIL - otherwise                                             *
875  *                                                                            *
876  ******************************************************************************/
item_preproc_jsonpath_op(zbx_variant_t * value,const char * params,char ** errmsg)877 static int	item_preproc_jsonpath_op(zbx_variant_t *value, const char *params, char **errmsg)
878 {
879 	struct zbx_json_parse	jp;
880 	char			*data = NULL;
881 
882 	if (FAIL == item_preproc_convert_value(value, ZBX_VARIANT_STR, errmsg))
883 		return FAIL;
884 
885 	if (FAIL == zbx_json_open(value->data.str, &jp) || FAIL == zbx_jsonpath_query(&jp, params, &data))
886 	{
887 		*errmsg = zbx_strdup(*errmsg, zbx_json_strerror());
888 		return FAIL;
889 	}
890 
891 	if (NULL == data)
892 	{
893 		*errmsg = zbx_strdup(*errmsg, "no data matches the specified path");
894 		return FAIL;
895 	}
896 
897 	zbx_variant_clear(value);
898 	zbx_variant_set_str(value, data);
899 
900 	return SUCCEED;
901 }
902 
903 /******************************************************************************
904  *                                                                            *
905  * Function: item_preproc_jsonpath                                            *
906  *                                                                            *
907  * Purpose: execute jsonpath query                                            *
908  *                                                                            *
909  * Parameters: value  - [IN/OUT] the value to process                         *
910  *             params - [IN] the operation parameters                         *
911  *             errmsg - [OUT] error message                                   *
912  *                                                                            *
913  * Return value: SUCCEED - the value was processed successfully               *
914  *               FAIL - otherwise                                             *
915  *                                                                            *
916  ******************************************************************************/
item_preproc_jsonpath(zbx_variant_t * value,const char * params,char ** errmsg)917 static int	item_preproc_jsonpath(zbx_variant_t *value, const char *params, char **errmsg)
918 {
919 	char	*err = NULL;
920 
921 	if (SUCCEED == item_preproc_jsonpath_op(value, params, &err))
922 		return SUCCEED;
923 
924 	*errmsg = zbx_dsprintf(*errmsg, "cannot extract value from json by path \"%s\": %s", params, err);
925 
926 	zbx_free(err);
927 
928 	return FAIL;
929 }
930 
931 /******************************************************************************
932  *                                                                            *
933  * Function: item_preproc_xpath                                               *
934  *                                                                            *
935  * Purpose: execute xpath query                                               *
936  *                                                                            *
937  * Parameters: value  - [IN/OUT] the value to process                         *
938  *             params - [IN] the operation parameters                         *
939  *             errmsg - [OUT] error message                                   *
940  *                                                                            *
941  * Return value: SUCCEED - the value was processed successfully               *
942  *               FAIL - otherwise                                             *
943  *                                                                            *
944  ******************************************************************************/
item_preproc_xpath(zbx_variant_t * value,const char * params,char ** errmsg)945 static int	item_preproc_xpath(zbx_variant_t *value, const char *params, char **errmsg)
946 {
947 	char	*err = NULL;
948 
949 	if (FAIL == item_preproc_convert_value(value, ZBX_VARIANT_STR, errmsg))
950 		return FAIL;
951 
952 	if (SUCCEED == zbx_query_xpath(value, params, &err))
953 		return SUCCEED;
954 
955 	*errmsg = zbx_dsprintf(*errmsg, "cannot extract XML value with xpath \"%s\": %s", params, err);
956 	zbx_free(err);
957 
958 	return FAIL;
959 }
960 
961 /******************************************************************************
962  *                                                                            *
963  * Function: item_preproc_validate_range                                      *
964  *                                                                            *
965  * Purpose: validates value to be within the specified range                  *
966  * Parameters: value_type - [IN] the item type                                *
967  *             value      - [IN/OUT] the value to process                     *
968  *             params     - [IN] the operation parameters                     *
969  *             errmsg     - [OUT] error message                               *
970  *                                                                            *
971  * Return value: SUCCEED - the preprocessing step finished successfully       *
972  *               FAIL - otherwise, errmsg contains the error message          *
973  *                                                                            *
974  ******************************************************************************/
item_preproc_validate_range(unsigned char value_type,const zbx_variant_t * value,const char * params,char ** errmsg)975 static int	item_preproc_validate_range(unsigned char value_type, const zbx_variant_t *value, const char *params,
976 		char **errmsg)
977 {
978 	zbx_variant_t	value_num;
979 	char		min[ITEM_PREPROC_PARAMS_LEN * ZBX_MAX_BYTES_IN_UTF8_CHAR + 1], *max;
980 	zbx_variant_t	range_min, range_max;
981 	int		ret = FAIL;
982 
983 	if (FAIL == zbx_item_preproc_convert_value_to_numeric(&value_num, value, value_type, errmsg))
984 		return FAIL;
985 
986 	zbx_variant_set_none(&range_min);
987 	zbx_variant_set_none(&range_max);
988 
989 	zbx_strlcpy(min, params, sizeof(min));
990 	if (NULL == (max = strchr(min, '\n')))
991 	{
992 		*errmsg = zbx_strdup(*errmsg, "validation range is not specified");
993 		goto out;
994 	}
995 
996 	*max++ = '\0';
997 
998 	if ('\0' != *min && FAIL == zbx_variant_set_numeric(&range_min, min))
999 	{
1000 		*errmsg = zbx_dsprintf(*errmsg, "validation range minimum value is invalid: %s", min);
1001 		goto out;
1002 	}
1003 
1004 	if ('\0' != *max && FAIL == zbx_variant_set_numeric(&range_max, max))
1005 	{
1006 		*errmsg = zbx_dsprintf(*errmsg, "validation range maximum value is invalid: %s", max);
1007 		goto out;
1008 	}
1009 
1010 	if ((ZBX_VARIANT_NONE != range_min.type && 0 > zbx_variant_compare(&value_num, &range_min)) ||
1011 			(ZBX_VARIANT_NONE != range_max.type && 0 > zbx_variant_compare(&range_max, &value_num)))
1012 	{
1013 		size_t	errmsg_alloc = 0, errmsg_offset = 0;
1014 
1015 		zbx_free(*errmsg);
1016 
1017 		zbx_strcpy_alloc(errmsg, &errmsg_alloc, &errmsg_offset, "value is");
1018 		if ('\0' != *min)
1019 		{
1020 			zbx_snprintf_alloc(errmsg, &errmsg_alloc, &errmsg_offset, " less than %s", min);
1021 			if ('\0' != *max)
1022 				zbx_strcpy_alloc(errmsg, &errmsg_alloc, &errmsg_offset, " or");
1023 		}
1024 		if ('\0' != *max)
1025 			zbx_snprintf_alloc(errmsg, &errmsg_alloc, &errmsg_offset, " greater than %s", max);
1026 
1027 		goto out;
1028 	}
1029 
1030 	ret = SUCCEED;
1031 out:
1032 	zbx_variant_clear(&value_num);
1033 	zbx_variant_clear(&range_min);
1034 	zbx_variant_clear(&range_max);
1035 
1036 	return ret;
1037 }
1038 
1039 /******************************************************************************
1040  *                                                                            *
1041  * Function: item_preproc_validate_regex                                      *
1042  *                                                                            *
1043  * Purpose: validates value to match regular expression                       *
1044  * Parameters: value_type - [IN] the item type                                *
1045  *             value      - [IN/OUT] the value to process                     *
1046  *             params     - [IN] the operation parameters                     *
1047  *             errmsg     - [OUT] error message                               *
1048  *                                                                            *
1049  * Return value: SUCCEED - the preprocessing step finished successfully       *
1050  *               FAIL - otherwise, errmsg contains the error message          *
1051  *                                                                            *
1052  ******************************************************************************/
item_preproc_validate_regex(const zbx_variant_t * value,const char * params,char ** error)1053 static int	item_preproc_validate_regex(const zbx_variant_t *value, const char *params, char **error)
1054 {
1055 	zbx_variant_t	value_str;
1056 	int		ret = FAIL;
1057 	zbx_regexp_t	*regex;
1058 	const char	*errptr = NULL;
1059 	char		*errmsg;
1060 
1061 	zbx_variant_copy(&value_str, value);
1062 
1063 	if (FAIL == zbx_variant_convert(&value_str, ZBX_VARIANT_STR))
1064 	{
1065 		errmsg = zbx_strdup(NULL, "cannot convert value to string");
1066 		goto out;
1067 	}
1068 
1069 	if (FAIL == zbx_regexp_compile(params, &regex, &errptr))
1070 	{
1071 		errmsg = zbx_dsprintf(NULL, "invalid regular expression pattern: %s", errptr);
1072 		goto out;
1073 	}
1074 
1075 	if (0 != zbx_regexp_match_precompiled(value_str.data.str, regex))
1076 		errmsg = zbx_strdup(NULL, "value does not match regular expression");
1077 	else
1078 		ret = SUCCEED;
1079 
1080 	zbx_regexp_free(regex);
1081 out:
1082 	zbx_variant_clear(&value_str);
1083 
1084 	if (FAIL == ret)
1085 	{
1086 		*error = zbx_dsprintf(*error, "cannot perform regular expression \"%s\" validation"
1087 				" for value of type \"%s\": %s",
1088 				params, zbx_variant_type_desc(value), errmsg);
1089 		zbx_free(errmsg);
1090 	}
1091 
1092 	return ret;
1093 }
1094 
1095 /******************************************************************************
1096  *                                                                            *
1097  * Function: item_preproc_validate_not_regex                                  *
1098  *                                                                            *
1099  * Purpose: validates value to not match regular expression                   *
1100  * Parameters: value_type - [IN] the item type                                *
1101  *             value      - [IN/OUT] the value to process                     *
1102  *             params     - [IN] the operation parameters                     *
1103  *             errmsg     - [OUT] error message                               *
1104  *                                                                            *
1105  * Return value: SUCCEED - the preprocessing step finished successfully       *
1106  *               FAIL - otherwise, errmsg contains the error message          *
1107  *                                                                            *
1108  ******************************************************************************/
item_preproc_validate_not_regex(const zbx_variant_t * value,const char * params,char ** error)1109 static int	item_preproc_validate_not_regex(const zbx_variant_t *value, const char *params, char **error)
1110 {
1111 	zbx_variant_t	value_str;
1112 	int		ret = FAIL;
1113 	zbx_regexp_t	*regex;
1114 	const char	*errptr = NULL;
1115 	char		*errmsg;
1116 
1117 	zbx_variant_copy(&value_str, value);
1118 
1119 	if (FAIL == zbx_variant_convert(&value_str, ZBX_VARIANT_STR))
1120 	{
1121 		errmsg = zbx_strdup(NULL, "cannot convert value to string");
1122 		goto out;
1123 	}
1124 
1125 	if (FAIL == zbx_regexp_compile(params, &regex, &errptr))
1126 	{
1127 		errmsg = zbx_dsprintf(NULL, "invalid regular expression pattern: %s", errptr);
1128 		goto out;
1129 	}
1130 
1131 	if (0 == zbx_regexp_match_precompiled(value_str.data.str, regex))
1132 	{
1133 		errmsg = zbx_strdup(NULL, "value matches regular expression");
1134 	}
1135 	else
1136 		ret = SUCCEED;
1137 
1138 	zbx_regexp_free(regex);
1139 out:
1140 	zbx_variant_clear(&value_str);
1141 
1142 	if (FAIL == ret)
1143 	{
1144 		*error = zbx_dsprintf(*error, "cannot perform regular expression \"%s\" validation"
1145 				" for value of type \"%s\": %s",
1146 				params, zbx_variant_type_desc(value), errmsg);
1147 		zbx_free(errmsg);
1148 	}
1149 
1150 	return ret;
1151 }
1152 
1153 /******************************************************************************
1154  *                                                                            *
1155  * Function: item_preproc_get_error_from_json                                 *
1156  *                                                                            *
1157  * Purpose: checks for presence of error field in json data                   *
1158  *                                                                            *
1159  * Parameters: value  - [IN/OUT] the value to process                         *
1160  *             params - [IN] the operation parameters                         *
1161  *             error  - [OUT] error message                                   *
1162  *                                                                            *
1163  * Return value: FAIL - preprocessing step error                              *
1164  *               SUCCEED - preprocessing step succeeded, error may contain    *
1165  *                         extracted error message                            *
1166  *                                                                            *
1167  * Comments: This preprocessing step is used to check if the returned data    *
1168  *           contains explicit (API related) error message and sets it as     *
1169  *           error, while returning SUCCEED.                                  *
1170  *                                                                            *
1171  ******************************************************************************/
item_preproc_get_error_from_json(const zbx_variant_t * value,const char * params,char ** error)1172 static int	item_preproc_get_error_from_json(const zbx_variant_t *value, const char *params, char **error)
1173 {
1174 	zbx_variant_t		value_str;
1175 	int			ret;
1176 	struct zbx_json_parse	jp;
1177 
1178 	zbx_variant_copy(&value_str, value);
1179 
1180 	if (FAIL == (ret = item_preproc_convert_value(&value_str, ZBX_VARIANT_STR, error)))
1181 	{
1182 		THIS_SHOULD_NEVER_HAPPEN;
1183 		goto out;
1184 	}
1185 
1186 	if (FAIL == zbx_json_open(value->data.str, &jp))
1187 		goto out;
1188 
1189 	if (FAIL == (ret = zbx_jsonpath_query(&jp, params, error)))
1190 	{
1191 		*error = zbx_strdup(NULL, zbx_json_strerror());
1192 		goto out;
1193 	}
1194 
1195 	if (NULL != *error)
1196 	{
1197 		zbx_lrtrim(*error, ZBX_WHITESPACE);
1198 		if ('\0' == **error)
1199 			zbx_free(*error);
1200 		else
1201 			ret = FAIL;
1202 	}
1203 out:
1204 	zbx_variant_clear(&value_str);
1205 
1206 	return ret;
1207 }
1208 
1209 /******************************************************************************
1210  *                                                                            *
1211  * Function: item_preproc_get_error_from_xml                                  *
1212  *                                                                            *
1213  * Purpose: checks for presence of error field in XML data                    *
1214  *                                                                            *
1215  * Parameters: value  - [IN/OUT] the value to process                         *
1216  *             params - [IN] the operation parameters                         *
1217  *             error  - [OUT] the error message                               *
1218  *                                                                            *
1219  * Return value: FAIL - preprocessing step error                              *
1220  *               SUCCEED - preprocessing step succeeded, error may contain    *
1221  *                         extracted error message                            *
1222  *                                                                            *
1223  * Comments: This preprocessing step is used to check if the returned data    *
1224  *           contains explicit (API related) error message and sets it as     *
1225  *           error, while returning SUCCEED.                                  *
1226  *                                                                            *
1227  ******************************************************************************/
item_preproc_get_error_from_xml(const zbx_variant_t * value,const char * params,char ** error)1228 static int	item_preproc_get_error_from_xml(const zbx_variant_t *value, const char *params, char **error)
1229 {
1230 #ifndef HAVE_LIBXML2
1231 	ZBX_UNUSED(value);
1232 	ZBX_UNUSED(params);
1233 	ZBX_UNUSED(error);
1234 	*error = zbx_dsprintf(*error, "Zabbix was compiled without libxml2 support");
1235 	return FAIL;
1236 #else
1237 	zbx_variant_t		value_str;
1238 	int			ret = SUCCEED, i;
1239 	xmlDoc			*doc = NULL;
1240 	xmlXPathContext		*xpathCtx = NULL;
1241 	xmlXPathObject		*xpathObj = NULL;
1242 	xmlErrorPtr		pErr;
1243 	xmlBufferPtr		xmlBufferLocal;
1244 
1245 	zbx_variant_copy(&value_str, value);
1246 
1247 	if (FAIL == (ret = item_preproc_convert_value(&value_str, ZBX_VARIANT_STR, error)))
1248 	{
1249 		THIS_SHOULD_NEVER_HAPPEN;
1250 		goto out;
1251 	}
1252 
1253 	if (NULL == (doc = xmlReadMemory(value_str.data.str, strlen(value_str.data.str), "noname.xml", NULL, 0)))
1254 		goto out;
1255 
1256 	xpathCtx = xmlXPathNewContext(doc);
1257 
1258 	if (NULL == (xpathObj = xmlXPathEvalExpression((xmlChar *)params, xpathCtx)))
1259 	{
1260 		pErr = xmlGetLastError();
1261 		*error = zbx_dsprintf(*error, "cannot parse xpath \"%s\": %s", params, pErr->message);
1262 		ret = FAIL;
1263 		goto out;
1264 	}
1265 
1266 	switch (xpathObj->type)
1267 	{
1268 		case XPATH_NODESET:
1269 			if (0 != xmlXPathNodeSetIsEmpty(xpathObj->nodesetval))
1270 				goto out;
1271 
1272 			xmlBufferLocal = xmlBufferCreate();
1273 
1274 			for (i = 0; i < xpathObj->nodesetval->nodeNr; i++)
1275 				xmlNodeDump(xmlBufferLocal, doc, xpathObj->nodesetval->nodeTab[i], 0, 0);
1276 
1277 			*error = zbx_strdup(*error, (const char *)xmlBufferLocal->content);
1278 			xmlBufferFree(xmlBufferLocal);
1279 			break;
1280 		case XPATH_STRING:
1281 			*error = zbx_strdup(*error, (const char *)xpathObj->stringval);
1282 			break;
1283 		case XPATH_BOOLEAN:
1284 			*error = zbx_dsprintf(*error, "%d", xpathObj->boolval);
1285 			break;
1286 		case XPATH_NUMBER:
1287 			*error = zbx_dsprintf(*error, ZBX_FS_DBL, xpathObj->floatval);
1288 			break;
1289 		default:
1290 			*error = zbx_strdup(*error, "Unknown error");
1291 			break;
1292 	}
1293 
1294 	zbx_lrtrim(*error, ZBX_WHITESPACE);
1295 	if ('\0' == **error)
1296 		zbx_free(*error);
1297 	else
1298 		ret = FAIL;
1299 out:
1300 	zbx_variant_clear(&value_str);
1301 
1302 	if (NULL != xpathObj)
1303 		xmlXPathFreeObject(xpathObj);
1304 
1305 	if (NULL != xpathCtx)
1306 		xmlXPathFreeContext(xpathCtx);
1307 
1308 	if (NULL != doc)
1309 		xmlFreeDoc(doc);
1310 
1311 	return ret;
1312 #endif
1313 }
1314 
1315 /******************************************************************************
1316  *                                                                            *
1317  * Function: item_preproc_get_error_from_regex                                *
1318  *                                                                            *
1319  * Purpose: checks for presence of error pattern matching regular expression  *
1320  *                                                                            *
1321  * Parameters: value  - [IN/OUT] the value to process                         *
1322  *             params - [IN] the operation parameters                         *
1323  *             error  - [OUT] the error message                               *
1324  *                                                                            *
1325  * Return value: FAIL - preprocessing step error                              *
1326  *               SUCCEED - preprocessing step succeeded, error may contain    *
1327  *                         extracted error message                            *
1328  *                                                                            *
1329  * Comments: This preprocessing step is used to check if the returned data    *
1330  *           contains explicit (API related) error message and sets it as     *
1331  *           error, while returning SUCCEED.                                  *
1332  *                                                                            *
1333  ******************************************************************************/
item_preproc_get_error_from_regex(const zbx_variant_t * value,const char * params,char ** error)1334 static int	item_preproc_get_error_from_regex(const zbx_variant_t *value, const char *params, char **error)
1335 {
1336 	zbx_variant_t	value_str;
1337 	int		ret;
1338 	char		pattern[ITEM_PREPROC_PARAMS_LEN * ZBX_MAX_BYTES_IN_UTF8_CHAR + 1], *output;
1339 
1340 	zbx_variant_copy(&value_str, value);
1341 
1342 	if (FAIL == (ret = item_preproc_convert_value(&value_str, ZBX_VARIANT_STR, error)))
1343 	{
1344 		THIS_SHOULD_NEVER_HAPPEN;
1345 		goto out;
1346 	}
1347 
1348 	zbx_strlcpy(pattern, params, sizeof(pattern));
1349 	if (NULL == (output = strchr(pattern, '\n')))
1350 	{
1351 		*error = zbx_strdup(*error, "cannot find second parameter");
1352 		ret = FAIL;
1353 		goto out;
1354 	}
1355 
1356 	*output++ = '\0';
1357 
1358 	if (FAIL == zbx_mregexp_sub(value_str.data.str, pattern, output, error))
1359 	{
1360 		*error = zbx_dsprintf(*error, "invalid regular expression \"%s\"", pattern);
1361 		ret = FAIL;
1362 		goto out;
1363 	}
1364 
1365 	if (NULL != *error)
1366 	{
1367 		zbx_lrtrim(*error, ZBX_WHITESPACE);
1368 		if ('\0' == **error)
1369 			zbx_free(*error);
1370 		else
1371 			ret = FAIL;
1372 	}
1373 out:
1374 	zbx_variant_clear(&value_str);
1375 
1376 	return ret;
1377 }
1378 
1379 /******************************************************************************
1380  *                                                                            *
1381  * Function: item_preproc_throttle_value                                      *
1382  *                                                                            *
1383  * Purpose: throttles value by suppressing identical values                   *
1384  *                                                                            *
1385  * Parameters: value         - [IN/OUT] the value to process                  *
1386  *             ts            - [IN] the value timestamp                       *
1387  *             history_value - [IN] historical data of item with delta        *
1388  *                                  preprocessing operation                   *
1389  *             errmsg        - [OUT] error message                            *
1390  *                                                                            *
1391  * Return value: SUCCEED - the value was calculated successfully              *
1392  *               FAIL - otherwise                                             *
1393  *                                                                            *
1394  ******************************************************************************/
item_preproc_throttle_value(zbx_variant_t * value,const zbx_timespec_t * ts,zbx_variant_t * history_value,zbx_timespec_t * history_ts)1395 static int	item_preproc_throttle_value(zbx_variant_t *value, const zbx_timespec_t *ts,
1396 		zbx_variant_t *history_value, zbx_timespec_t *history_ts)
1397 {
1398 	int	ret;
1399 
1400 	ret = zbx_variant_compare(value, history_value);
1401 
1402 	zbx_variant_clear(history_value);
1403 	zbx_variant_copy(history_value, value);
1404 
1405 	if (0 == ret)
1406 		zbx_variant_clear(value);
1407 	else
1408 		*history_ts = *ts;
1409 
1410 	return SUCCEED;
1411 }
1412 
1413 /******************************************************************************
1414  *                                                                            *
1415  * Function: item_preproc_throttle_timed_value                                *
1416  *                                                                            *
1417  * Purpose: throttles value by suppressing identical values                   *
1418  *                                                                            *
1419  * Parameters: value         - [IN/OUT] the value to process                  *
1420  *             ts            - [IN] the value timestamp                       *
1421  *             params        - [IN] the throttle period                       *
1422  *             history_value - [IN] historical data of item with delta        *
1423  *                                  preprocessing operation                   *
1424  *             errmsg        - [OUT] error message                            *
1425  *                                                                            *
1426  * Return value: SUCCEED - the value was calculated successfully              *
1427  *               FAIL - otherwise                                             *
1428  *                                                                            *
1429  ******************************************************************************/
item_preproc_throttle_timed_value(zbx_variant_t * value,const zbx_timespec_t * ts,const char * params,zbx_variant_t * history_value,zbx_timespec_t * history_ts,char ** errmsg)1430 static int	item_preproc_throttle_timed_value(zbx_variant_t *value, const zbx_timespec_t *ts, const char *params,
1431 		zbx_variant_t *history_value, zbx_timespec_t *history_ts, char **errmsg)
1432 {
1433 	int	ret, timeout, period = 0;
1434 
1435 	if (FAIL == is_time_suffix(params, &timeout, strlen(params)))
1436 	{
1437 		*errmsg = zbx_dsprintf(*errmsg, "invalid time period: %s", params);
1438 		zbx_variant_clear(history_value);
1439 		return FAIL;
1440 	}
1441 
1442 	ret = zbx_variant_compare(value, history_value);
1443 
1444 	zbx_variant_clear(history_value);
1445 	zbx_variant_copy(history_value, value);
1446 
1447 	if (ZBX_VARIANT_NONE != history_value->type)
1448 		period = ts->sec - history_ts->sec;
1449 
1450 	if (0 == ret && period < timeout )
1451 		zbx_variant_clear(value);
1452 	else
1453 		*history_ts = *ts;
1454 
1455 	return SUCCEED;
1456 }
1457 
1458 /******************************************************************************
1459  *                                                                            *
1460  * Function: item_preproc_script                                              *
1461  *                                                                            *
1462  * Purpose: executes script passed with params                                *
1463  *                                                                            *
1464  * Parameters: value    - [IN/OUT] the value to process                       *
1465  *             params   - [IN] the script to execute                          *
1466  *             bytecode - [IN] precompiled bytecode, can be NULL              *
1467  *             errmsg   - [OUT] error message                                 *
1468  *                                                                            *
1469  * Return value: SUCCEED - the value was calculated successfully              *
1470  *               FAIL - otherwise                                             *
1471  *                                                                            *
1472  ******************************************************************************/
item_preproc_script(zbx_variant_t * value,const char * params,zbx_variant_t * bytecode,char ** errmsg)1473 static int	item_preproc_script(zbx_variant_t *value, const char *params, zbx_variant_t *bytecode, char **errmsg)
1474 {
1475 	char	*code, *output = NULL, *error = NULL;
1476 	int	size;
1477 
1478 	if (FAIL == item_preproc_convert_value(value, ZBX_VARIANT_STR, errmsg))
1479 		return FAIL;
1480 
1481 	if (SUCCEED != zbx_es_is_env_initialized(&es_engine))
1482 	{
1483 		if (SUCCEED != zbx_es_init_env(&es_engine, errmsg))
1484 			return FAIL;
1485 	}
1486 
1487 	if (ZBX_VARIANT_BIN != bytecode->type)
1488 	{
1489 		if (SUCCEED != zbx_es_compile(&es_engine, params, &code, &size, errmsg))
1490 			goto fail;
1491 
1492 		zbx_variant_clear(bytecode);
1493 		zbx_variant_set_bin(bytecode, zbx_variant_data_bin_create(code, size));
1494 		zbx_free(code);
1495 	}
1496 
1497 	size = zbx_variant_data_bin_get(bytecode->data.bin, (void **)&code);
1498 
1499 	if (SUCCEED == zbx_es_execute(&es_engine, params, code, size, value->data.str, &output, errmsg))
1500 	{
1501 		zbx_variant_clear(value);
1502 
1503 		if (NULL != output)
1504 			zbx_variant_set_str(value, output);
1505 
1506 		return SUCCEED;
1507 	}
1508 fail:
1509 	if (SUCCEED == zbx_es_fatal_error(&es_engine))
1510 	{
1511 		if (SUCCEED != zbx_es_destroy_env(&es_engine, &error))
1512 		{
1513 			zabbix_log(LOG_LEVEL_WARNING,
1514 					"Cannot destroy embedded scripting engine environment: %s", error);
1515 			zbx_free(error);
1516 		}
1517 	}
1518 
1519 	return FAIL;
1520 }
1521 
1522 /******************************************************************************
1523  *                                                                            *
1524  * Function: item_preproc_prometheus_pattern                                  *
1525  *                                                                            *
1526  * Purpose: parse Prometheus format metrics                                   *
1527  *                                                                            *
1528  * Parameters: value  - [IN/OUT] the value to process                         *
1529  *             params - [IN] the operation parameters                         *
1530  *             errmsg - [OUT] error message                                   *
1531  *                                                                            *
1532  * Return value: SUCCEED - the value was processed successfully               *
1533  *               FAIL - otherwise                                             *
1534  *                                                                            *
1535  ******************************************************************************/
item_preproc_prometheus_pattern(zbx_variant_t * value,const char * params,char ** errmsg)1536 static int	item_preproc_prometheus_pattern(zbx_variant_t *value, const char *params, char **errmsg)
1537 {
1538 	char	pattern[ITEM_PREPROC_PARAMS_LEN * ZBX_MAX_BYTES_IN_UTF8_CHAR + 1], *output, *value_out = NULL,
1539 		*err = NULL;
1540 
1541 	if (FAIL == item_preproc_convert_value(value, ZBX_VARIANT_STR, errmsg))
1542 		return FAIL;
1543 
1544 	zbx_strlcpy(pattern, params, sizeof(pattern));
1545 
1546 	if (NULL == (output = strchr(pattern, '\n')))
1547 	{
1548 		*errmsg = zbx_strdup(*errmsg, "cannot find second parameter");
1549 		return FAIL;
1550 	}
1551 
1552 	*output++ = '\0';
1553 
1554 	if (FAIL == zbx_prometheus_pattern(value->data.str, pattern, output, &value_out, &err))
1555 	{
1556 		*errmsg = zbx_dsprintf(*errmsg, "cannot apply Prometheus pattern: %s", err);
1557 		zbx_free(err);
1558 		return FAIL;
1559 	}
1560 
1561 	zbx_variant_clear(value);
1562 	zbx_variant_set_str(value, value_out);
1563 
1564 	return SUCCEED;
1565 }
1566 
1567 /******************************************************************************
1568  *                                                                            *
1569  * Function: item_preproc_prometheus_to_json                                  *
1570  *                                                                            *
1571  * Purpose: convert Prometheus format metrics to JSON format                  *
1572  *                                                                            *
1573  * Parameters: value  - [IN/OUT] the value to process                         *
1574  *             params - [IN] the operation parameters                         *
1575  *             errmsg - [OUT] error message                                   *
1576  *                                                                            *
1577  * Return value: SUCCEED - the value was processed successfully               *
1578  *               FAIL - otherwise                                             *
1579  *                                                                            *
1580  ******************************************************************************/
item_preproc_prometheus_to_json(zbx_variant_t * value,const char * params,char ** errmsg)1581 static int	item_preproc_prometheus_to_json(zbx_variant_t *value, const char *params, char **errmsg)
1582 {
1583 	char	*value_out = NULL, *err = NULL;
1584 
1585 	if (FAIL == item_preproc_convert_value(value, ZBX_VARIANT_STR, errmsg))
1586 		return FAIL;
1587 
1588 	if (FAIL == zbx_prometheus_to_json(value->data.str, params, &value_out, &err))
1589 	{
1590 		*errmsg = zbx_dsprintf(*errmsg, "cannot convert Prometheus data to JSON: %s", err);
1591 		zbx_free(err);
1592 		return FAIL;
1593 	}
1594 
1595 	zbx_variant_clear(value);
1596 	zbx_variant_set_str(value, value_out);
1597 
1598 	return SUCCEED;
1599 }
1600 
1601 /******************************************************************************
1602  *                                                                            *
1603  * Function: item_preproc_csv_to_json_add_field                               *
1604  *                                                                            *
1605  * Purpose: convert CSV format metrics to JSON format                         *
1606  *                                                                            *
1607  * Parameters: json    - [IN/OUT] json object                                 *
1608  *             names   - [IN/OUT] column names                                *
1609  *             field   - [IN] field                                           *
1610  *             num     - [IN] field number                                    *
1611  *             num_max - [IN] maximum number of fields                        *
1612  *             header  - [IN] header line option                              *
1613  *             errmsg  - [OUT] error message                                  *
1614  *                                                                            *
1615  * Return value: SUCCEED - the field was added successfully                   *
1616  *               FAIL - otherwise                                             *
1617  *                                                                            *
1618  ******************************************************************************/
item_preproc_csv_to_json_add_field(struct zbx_json * json,char *** names,char * field,unsigned int num,unsigned int num_max,unsigned int header,char ** errmsg)1619 static int	item_preproc_csv_to_json_add_field(struct zbx_json *json, char ***names, char *field, unsigned int num,
1620 		unsigned int num_max, unsigned int header, char **errmsg)
1621 {
1622 	char	**fld_names = *names;
1623 
1624 	if (0 < num_max && num >= num_max && 1 == header)
1625 	{
1626 		*errmsg = zbx_strdup(*errmsg,
1627 				"cannot convert CSV to JSON: data row contains more fields than header row");
1628 		return FAIL;
1629 	}
1630 
1631 	if (NULL == field)
1632 		field = "";
1633 
1634 	if (0 == num_max && 1 == header)
1635 	{
1636 		unsigned int	i;
1637 
1638 		for (i = 0; i < num; i++)
1639 		{
1640 			if (0 == strcmp(fld_names[i], field))
1641 			{
1642 				*errmsg = zbx_dsprintf(*errmsg,
1643 						"cannot convert CSV to JSON: duplicated column name \"%s\"", field);
1644 				return FAIL;
1645 			}
1646 		}
1647 
1648 		fld_names = zbx_realloc(fld_names, (num + 1) * sizeof(char*));
1649 		fld_names[num] = zbx_strdup(NULL, field);
1650 		*names = fld_names;
1651 	}
1652 	else
1653 	{
1654 		if (0 == num)
1655 			zbx_json_addobject(json, NULL);
1656 
1657 		if (0 == header)
1658 		{
1659 			char	num_buf[ZBX_MAX_UINT64_LEN];
1660 
1661 			zbx_snprintf(num_buf, ZBX_MAX_UINT64_LEN, "%u", num + 1);
1662 			zbx_json_addstring(json, num_buf, field, ZBX_JSON_TYPE_STRING);
1663 		}
1664 		else
1665 			zbx_json_addstring(json, fld_names[num], field, ZBX_JSON_TYPE_STRING);
1666 
1667 		if (ZBX_MAX_RECV_DATA_SIZE <= json->buffer_allocated)
1668 		{
1669 			*errmsg = zbx_strdup(*errmsg, "cannot convert CSV to JSON: input data is too large");
1670 			return FAIL;
1671 		}
1672 	}
1673 
1674 	return SUCCEED;
1675 }
1676 
1677 /******************************************************************************
1678  *                                                                            *
1679  * Function: item_preproc_csv_to_json                                         *
1680  *                                                                            *
1681  * Purpose: convert CSV format metrics to JSON format                         *
1682  *                                                                            *
1683  * Parameters: value  - [IN/OUT] the value to process                         *
1684  *             params - [IN] the operation parameters                         *
1685  *             errmsg - [OUT] error message                                   *
1686  *                                                                            *
1687  * Return value: SUCCEED - the value was processed successfully               *
1688  *               FAIL - otherwise                                             *
1689  *                                                                            *
1690  ******************************************************************************/
item_preproc_csv_to_json(zbx_variant_t * value,const char * params,char ** errmsg)1691 static int	item_preproc_csv_to_json(zbx_variant_t *value, const char *params, char **errmsg)
1692 {
1693 #define CSV_STATE_FIELD		0
1694 #define CSV_STATE_DELIM		1
1695 #define CSV_STATE_FIELD_QUOTED	2
1696 
1697 	unsigned int	fld_num = 0, fld_num_max = 0, hdr_line, state = CSV_STATE_DELIM;
1698 	char		*field, *field_esc = NULL, **field_names = NULL, *data, *value_out = NULL,
1699 			delim[ZBX_MAX_BYTES_IN_UTF8_CHAR], quote[ZBX_MAX_BYTES_IN_UTF8_CHAR];
1700 	struct zbx_json	json;
1701 	size_t		data_len, delim_sz = 1, quote_sz = 0, step;
1702 	int		ret = SUCCEED;
1703 
1704 	if (FAIL == item_preproc_convert_value(value, ZBX_VARIANT_STR, errmsg))
1705 		return FAIL;
1706 
1707 	delim[0] = ',';
1708 	zbx_json_initarray(&json, ZBX_JSON_STAT_BUF_LEN);
1709 	data = value->data.str;
1710 	data_len = strlen(value->data.str);
1711 
1712 #define CSV_SEP_LINE	"sep="
1713 	if (0 == zbx_strncasecmp(data, CSV_SEP_LINE, ZBX_CONST_STRLEN(CSV_SEP_LINE)))
1714 	{
1715 		char	*p;
1716 		size_t	del_sz;
1717 
1718 		p = value->data.str + ZBX_CONST_STRLEN(CSV_SEP_LINE);
1719 
1720 		if (NULL == (field = strpbrk(p, "\r\n")))
1721 			field = data + data_len;
1722 
1723 		if (0 < (del_sz = zbx_utf8_char_len(p)) && p + del_sz == field)
1724 		{
1725 			memcpy(delim, p, del_sz);
1726 			delim_sz = del_sz;
1727 
1728 			if ('\0' == *field)
1729 				data = field;
1730 			else if ('\r' == *field)
1731 				data = field + 2;
1732 			else
1733 				data = field + 1;
1734 		}
1735 	}
1736 #undef CSV_SEP_LINE
1737 
1738 	if ('\n' != *params)
1739 	{
1740 		if (NULL == (field = strchr(params, '\n')))
1741 		{
1742 			*errmsg = zbx_strdup(*errmsg, "cannot find second parameter");
1743 			return FAIL;
1744 		}
1745 
1746 		if (0 == (delim_sz = zbx_utf8_char_len(params)) || params + delim_sz != field)
1747 		{
1748 			*errmsg = zbx_strdup(*errmsg, "invalid first parameter");
1749 			return FAIL;
1750 		}
1751 
1752 		memcpy(delim, params, delim_sz);
1753 		params = field;
1754 	}
1755 
1756 	if ('\n' != *(++params))
1757 	{
1758 		if (NULL == (field = strchr(params, '\n')))
1759 		{
1760 			*errmsg = zbx_strdup(*errmsg, "cannot find third parameter");
1761 			return FAIL;
1762 		}
1763 
1764 		if (0 == (quote_sz = zbx_utf8_char_len(params)) || params + quote_sz != field)
1765 		{
1766 			*errmsg = zbx_strdup(*errmsg, "invalid second parameter");
1767 			return FAIL;
1768 		}
1769 
1770 		memcpy(quote, params, quote_sz);
1771 		params = field;
1772 	}
1773 
1774 	hdr_line = ('1' == *(++params) ? 1 : 0);
1775 
1776 	if ('\0' == *data)
1777 		goto out;
1778 
1779 	for (field = NULL; value->data.str + data_len >= data; data += step)
1780 	{
1781 		if (0 == (step = zbx_utf8_char_len(data)))
1782 		{
1783 			*errmsg = zbx_strdup(*errmsg, "cannot convert CSV to JSON: invalid UTF-8 character in value");
1784 			ret = FAIL;
1785 			goto out;
1786 		}
1787 
1788 		if (CSV_STATE_FIELD_QUOTED != state)
1789 		{
1790 			if ('\r' == *data)
1791 			{
1792 				*data = '\0';
1793 
1794 				if ('\n' != *(++data) && '\0' != *data)
1795 				{
1796 					*errmsg = zbx_strdup(*errmsg, "cannot convert CSV to JSON: unsupported line "
1797 							"break");
1798 					ret = FAIL;
1799 					goto out;
1800 				}
1801 			}
1802 
1803 			if ('\n' == *data || '\0' == *data)
1804 			{
1805 				if (CSV_STATE_FIELD == state || 1 == hdr_line || 0 != fld_num)
1806 				{
1807 					*data = '\0';
1808 
1809 					do
1810 					{
1811 						if (FAIL == (ret = item_preproc_csv_to_json_add_field(&json,
1812 								&field_names, field, fld_num, fld_num_max, hdr_line,
1813 								errmsg)))
1814 							goto out;
1815 
1816 						field = NULL;
1817 						zbx_free(field_esc);
1818 					} while (++fld_num < fld_num_max && 1 == hdr_line);
1819 
1820 					if (fld_num > fld_num_max)
1821 						fld_num_max = fld_num;
1822 
1823 					fld_num = 0;
1824 				}
1825 				else
1826 					zbx_json_addobject(&json, NULL);
1827 
1828 				zbx_json_close(&json);
1829 				state = CSV_STATE_DELIM;
1830 			}
1831 			else if (step == delim_sz && 0 == memcmp(data, delim, delim_sz))
1832 			{
1833 				*data = '\0';
1834 
1835 				if (FAIL == (ret = item_preproc_csv_to_json_add_field(&json,
1836 						&field_names, field, fld_num, fld_num_max, hdr_line,
1837 						errmsg)))
1838 					goto out;
1839 
1840 				field = NULL;
1841 				zbx_free(field_esc);
1842 				fld_num++;
1843 				state = CSV_STATE_DELIM;
1844 			}
1845 			else if (CSV_STATE_DELIM == state && step == quote_sz && 0 == memcmp(data, quote, quote_sz))
1846 			{
1847 				state = CSV_STATE_FIELD_QUOTED;
1848 			}
1849 			else if (CSV_STATE_FIELD != state)
1850 			{
1851 				field = data;
1852 				state = CSV_STATE_FIELD;
1853 			}
1854 		}
1855 		else if (step == quote_sz && 0 == memcmp(data, quote, quote_sz))
1856 		{
1857 			char	*data_next = data + quote_sz;
1858 			size_t	char_sz;
1859 
1860 			if (0 == (char_sz = zbx_utf8_char_len(data_next)))
1861 				continue;	/* invalid UTF-8 */
1862 
1863 			if (char_sz == quote_sz && 0 == memcmp(data_next, quote, quote_sz))
1864 			{
1865 				if (NULL == field)
1866 					field = data;
1867 
1868 				*data_next = '\0';
1869 				field_esc = zbx_dsprintf(field_esc, "%s%s", ZBX_NULL2EMPTY_STR(field_esc), field);
1870 				field = NULL;
1871 				data = data_next;
1872 			}
1873 			else if ('\r' == *data_next || '\n' == *data_next || '\0' == *data_next ||
1874 					(char_sz == delim_sz && 0 == memcmp(data_next, delim, delim_sz)))
1875 			{
1876 				state = CSV_STATE_FIELD;
1877 				*data = '\0';
1878 
1879 				if (NULL != field_esc)
1880 				{
1881 					field_esc = zbx_dsprintf(field_esc, "%s%s", field_esc,
1882 							ZBX_NULL2EMPTY_STR(field));
1883 					field = field_esc;
1884 				}
1885 			}
1886 			else
1887 			{
1888 				*errmsg = zbx_dsprintf(*errmsg, "cannot convert CSV to JSON: delimiter character or "
1889 						"end of line are not detected after quoted field \"%.*s\"",
1890 						(int)(data - field), field);
1891 				ret = FAIL;
1892 				goto out;
1893 			}
1894 		}
1895 		else if (NULL == field)
1896 		{
1897 			field = data;
1898 		}
1899 	}
1900 
1901 	if (CSV_STATE_FIELD_QUOTED == state)
1902 	{
1903 		*errmsg = zbx_dsprintf(*errmsg, "cannot convert CSV to JSON: unclosed quoted field \"%s\"", field);
1904 		ret = FAIL;
1905 	}
1906 
1907 out:
1908 	if (SUCCEED == ret)
1909 	{
1910 		value_out = zbx_strdup(NULL, json.buffer);
1911 		zbx_variant_clear(value);
1912 		zbx_variant_set_str(value, value_out);
1913 	}
1914 
1915 	if (1 == hdr_line)
1916 	{
1917 		if (0 == fld_num_max)
1918 			fld_num_max = fld_num;
1919 
1920 		for (fld_num = 0; fld_num < fld_num_max; fld_num++)
1921 			zbx_free(field_names[fld_num]);
1922 
1923 		zbx_free(field_names);
1924 	}
1925 
1926 	zbx_free(field_esc);
1927 	zbx_json_free(&json);
1928 
1929 	return ret;
1930 #undef CSV_STATE_FIELD
1931 #undef CSV_STATE_DELIM
1932 #undef CSV_STATE_FIELD_QUOTED
1933 }
1934 
1935 /******************************************************************************
1936  *                                                                            *
1937  * Function: item_preproc_xml_to_json                                         *
1938  *                                                                            *
1939  * Purpose: convert XML format value to JSON format                           *
1940  *                                                                            *
1941  * Parameters: value  - [IN/OUT] the value to process                         *
1942  *             errmsg - [OUT] error message                                   *
1943  *                                                                            *
1944  * Return value: SUCCEED - the value was processed successfully               *
1945  *               FAIL - otherwise                                             *
1946  *                                                                            *
1947  ******************************************************************************/
item_preproc_xml_to_json(zbx_variant_t * value,char ** errmsg)1948 static int	item_preproc_xml_to_json(zbx_variant_t *value, char **errmsg)
1949 {
1950 	char	*json = NULL;
1951 
1952 	if (FAIL == item_preproc_convert_value(value, ZBX_VARIANT_STR, errmsg))
1953 		return FAIL;
1954 
1955 	if (FAIL == zbx_xml_to_json(value->data.str, &json, errmsg))
1956 		return FAIL;
1957 
1958 	zbx_variant_clear(value);
1959 	zbx_variant_set_str(value, json);
1960 
1961 	return SUCCEED;
1962 }
1963 
1964 /******************************************************************************
1965  *                                                                            *
1966  * Function: item_preproc_str_replace                                         *
1967  *                                                                            *
1968  * Purpose: replace substrings in string                                      *
1969  *                                                                            *
1970  * Parameters: value  - [IN/OUT] the value to process                         *
1971  *             params - [IN] the operation parameters                         *
1972  *             errmsg - [OUT] error message                                   *
1973  *                                                                            *
1974  * Return value: SUCCEED - the value was processed successfully               *
1975  *               FAIL - otherwise                                             *
1976  *                                                                            *
1977  ******************************************************************************/
item_preproc_str_replace(zbx_variant_t * value,const char * params,char ** errmsg)1978 static int	item_preproc_str_replace(zbx_variant_t *value, const char *params, char **errmsg)
1979 {
1980 	unsigned int	len_search, len_replace;
1981 	const char	*ptr;
1982 	char		*new_string, search_str[ITEM_PREPROC_PARAMS_LEN * ZBX_MAX_BYTES_IN_UTF8_CHAR + 1],
1983 			replace_str[ITEM_PREPROC_PARAMS_LEN * ZBX_MAX_BYTES_IN_UTF8_CHAR + 1];
1984 
1985 	if (NULL == (ptr = strchr(params, '\n')))
1986 	{
1987 		THIS_SHOULD_NEVER_HAPPEN;
1988 		*errmsg = zbx_strdup(*errmsg, "cannot find second parameter");
1989 		return FAIL;
1990 	}
1991 
1992 	if (0 == (len_search = ptr - params))
1993 	{
1994 		*errmsg = zbx_strdup(*errmsg, "first parameter is expected");
1995 		return FAIL;
1996 	}
1997 
1998 	unescape_param(ZBX_PREPROC_STR_REPLACE, params, MIN(len_search, sizeof(search_str) - 1), search_str);
1999 
2000 	len_replace = strlen(ptr + 1);
2001 	unescape_param(ZBX_PREPROC_STR_REPLACE, ptr + 1, MIN(len_replace, sizeof(replace_str) - 1), replace_str);
2002 
2003 	if (SUCCEED != item_preproc_convert_value(value, ZBX_VARIANT_STR, errmsg))
2004 	{
2005 		THIS_SHOULD_NEVER_HAPPEN;
2006 		return FAIL;
2007 	}
2008 
2009 	new_string = string_replace(value->data.str, search_str, replace_str);
2010 	zbx_variant_clear(value);
2011 	zbx_variant_set_str(value, new_string);
2012 
2013 	return SUCCEED;
2014 }
2015 
2016 /******************************************************************************
2017  *                                                                            *
2018  * Function: zbx_item_preproc                                                 *
2019  *                                                                            *
2020  * Purpose: execute preprocessing operation                                   *
2021  *                                                                            *
2022  * Parameters: value_type    - [IN] the item value type                       *
2023  *             value         - [IN/OUT] the value to process                  *
2024  *             ts            - [IN] the value timestamp                       *
2025  *             op            - [IN] the preprocessing operation to execute    *
2026  *             history_value - [IN/OUT] last historical data of items with    *
2027  *                                      delta type preprocessing operation    *
2028  *             error         - [OUT] error message                            *
2029  *                                                                            *
2030  * Return value: SUCCEED - the preprocessing step finished successfully       *
2031  *               FAIL - otherwise, error contains the error message           *
2032  *                                                                            *
2033  * Comments: When preprocessing step was executed successfully, but it must   *
2034  *           force an error (extract error steps), then success will be       *
2035  *           returned with error set.                                         *
2036  *                                                                            *
2037  ******************************************************************************/
zbx_item_preproc(unsigned char value_type,zbx_variant_t * value,const zbx_timespec_t * ts,const zbx_preproc_op_t * op,zbx_variant_t * history_value,zbx_timespec_t * history_ts,char ** error)2038 int	zbx_item_preproc(unsigned char value_type, zbx_variant_t *value, const zbx_timespec_t *ts,
2039 		const zbx_preproc_op_t *op, zbx_variant_t *history_value, zbx_timespec_t *history_ts, char **error)
2040 {
2041 	int	ret;
2042 
2043 	switch (op->type)
2044 	{
2045 		case ZBX_PREPROC_MULTIPLIER:
2046 			ret = item_preproc_multiplier(value_type, value, op->params, error);
2047 			break;
2048 		case ZBX_PREPROC_RTRIM:
2049 			ret = item_preproc_rtrim(value, op->params, error);
2050 			break;
2051 		case ZBX_PREPROC_LTRIM:
2052 			ret = item_preproc_ltrim(value, op->params, error);
2053 			break;
2054 		case ZBX_PREPROC_TRIM:
2055 			ret = item_preproc_lrtrim(value, op->params, error);
2056 			break;
2057 		case ZBX_PREPROC_REGSUB:
2058 			ret = item_preproc_regsub(value, op->params, error);
2059 			break;
2060 		case ZBX_PREPROC_BOOL2DEC:
2061 			ret = item_preproc_bool2dec(value, error);
2062 			break;
2063 		case ZBX_PREPROC_OCT2DEC:
2064 			ret = item_preproc_oct2dec(value, error);
2065 			break;
2066 		case ZBX_PREPROC_HEX2DEC:
2067 			ret = item_preproc_hex2dec(value, error);
2068 			break;
2069 		case ZBX_PREPROC_DELTA_VALUE:
2070 			ret = item_preproc_delta_value(value_type, value, ts, history_value, history_ts, error);
2071 			break;
2072 		case ZBX_PREPROC_DELTA_SPEED:
2073 			ret = item_preproc_delta_speed(value_type, value, ts, history_value, history_ts, error);
2074 			break;
2075 		case ZBX_PREPROC_XPATH:
2076 			ret = item_preproc_xpath(value, op->params, error);
2077 			break;
2078 		case ZBX_PREPROC_JSONPATH:
2079 			ret = item_preproc_jsonpath(value, op->params, error);
2080 			break;
2081 		case ZBX_PREPROC_VALIDATE_RANGE:
2082 			ret = item_preproc_validate_range(value_type, value, op->params, error);
2083 			break;
2084 		case ZBX_PREPROC_VALIDATE_REGEX:
2085 			ret = item_preproc_validate_regex(value, op->params, error);
2086 			break;
2087 		case ZBX_PREPROC_VALIDATE_NOT_REGEX:
2088 			ret = item_preproc_validate_not_regex(value, op->params, error);
2089 			break;
2090 		case ZBX_PREPROC_ERROR_FIELD_JSON:
2091 			ret = item_preproc_get_error_from_json(value, op->params, error);
2092 			break;
2093 		case ZBX_PREPROC_ERROR_FIELD_XML:
2094 			ret = item_preproc_get_error_from_xml(value, op->params, error);
2095 			break;
2096 		case ZBX_PREPROC_ERROR_FIELD_REGEX:
2097 			ret = item_preproc_get_error_from_regex(value, op->params, error);
2098 			break;
2099 		case ZBX_PREPROC_THROTTLE_VALUE:
2100 			ret = item_preproc_throttle_value(value, ts, history_value, history_ts);
2101 			break;
2102 		case ZBX_PREPROC_THROTTLE_TIMED_VALUE:
2103 			ret = item_preproc_throttle_timed_value(value, ts, op->params, history_value, history_ts,
2104 					error);
2105 			break;
2106 		case ZBX_PREPROC_SCRIPT:
2107 			ret = item_preproc_script(value, op->params, history_value, error);
2108 			break;
2109 		case ZBX_PREPROC_PROMETHEUS_PATTERN:
2110 			ret = item_preproc_prometheus_pattern(value, op->params, error);
2111 			break;
2112 		case ZBX_PREPROC_PROMETHEUS_TO_JSON:
2113 			ret = item_preproc_prometheus_to_json(value, op->params, error);
2114 			break;
2115 		case ZBX_PREPROC_CSV_TO_JSON:
2116 			ret = item_preproc_csv_to_json(value, op->params, error);
2117 			break;
2118 		case ZBX_PREPROC_STR_REPLACE:
2119 			ret = item_preproc_str_replace(value, op->params, error);
2120 			break;
2121 		case ZBX_PREPROC_VALIDATE_NOT_SUPPORTED:
2122 			ret = item_preproc_validate_notsupport(error);
2123 			break;
2124 		case ZBX_PREPROC_XML_TO_JSON:
2125 			ret = item_preproc_xml_to_json(value, error);
2126 			break;
2127 		default:
2128 			*error = zbx_dsprintf(*error, "unknown preprocessing operation");
2129 			ret = FAIL;
2130 	}
2131 
2132 	return ret;
2133 }
2134 
2135 /******************************************************************************
2136  *                                                                            *
2137  * Function: zbx_item_preproc_handle_error                                    *
2138  *                                                                            *
2139  * Purpose: apply 'on fail' preprocessing error handler                       *
2140  *                                                                            *
2141  * Parameters: value         - [IN/OUT] the value                             *
2142  *             op            - [IN] the preprocessing operation that produced *
2143  *                                  the error                                 *
2144  *             error         - [INT/OUT] error message                        *
2145  *                                                                            *
2146  * Return value: SUCCEED - the preprocessing step result was overridden by    *
2147  *                         error handler to successful result.                *
2148  *               FAIL    - the preprocessing step must still fail, error might*
2149  *                         have been changed.                                 *
2150  *                                                                            *
2151  ******************************************************************************/
zbx_item_preproc_handle_error(zbx_variant_t * value,const zbx_preproc_op_t * op,char ** error)2152 int	zbx_item_preproc_handle_error(zbx_variant_t *value, const zbx_preproc_op_t *op, char **error)
2153 {
2154 	switch (op->error_handler)
2155 	{
2156 		case ZBX_PREPROC_FAIL_DISCARD_VALUE:
2157 			zbx_variant_clear(value);
2158 			zbx_free(*error);
2159 			return SUCCEED;
2160 		case ZBX_PREPROC_FAIL_SET_VALUE:
2161 			zbx_variant_clear(value);
2162 			zbx_variant_set_str(value, zbx_strdup(NULL, op->error_handler_params));
2163 			zbx_free(*error);
2164 			return SUCCEED;
2165 		case ZBX_PREPROC_FAIL_SET_ERROR:
2166 			*error = zbx_strdup(*error, op->error_handler_params);
2167 			return FAIL;
2168 		default:
2169 			return FAIL;
2170 	}
2171 }
2172 
2173 /******************************************************************************
2174  *                                                                            *
2175  * Function: zbx_item_preproc_test                                            *
2176  *                                                                            *
2177  * Purpose: test preprocessing steps                                          *
2178  *                                                                            *
2179  * Parameters: value_type    - [IN] the item value type                       *
2180  *             value         - [IN/OUT] the value to process                  *
2181  *             ts            - [IN] the value timestamp                       *
2182  *             steps         - [IN] the preprocessing steps to execute        *
2183  *             steps_num     - [IN] the number of preprocessing steps         *
2184  *             history_in    - [IN] the preprocessing history                 *
2185  *             history_out   - [OUT] the new preprocessing history            *
2186  *             results       - [OUT] the preprocessing step results           *
2187  *             results_num   - [OUT] the number of step results               *
2188  *             error         - [OUT] error message                            *
2189  *                                                                            *
2190  * Return value: SUCCEED - the preprocessing steps finished successfully      *
2191  *               FAIL - otherwise, error contains the error message           *
2192  *                                                                            *
2193  ******************************************************************************/
zbx_item_preproc_test(unsigned char value_type,zbx_variant_t * value,const zbx_timespec_t * ts,zbx_preproc_op_t * steps,int steps_num,zbx_vector_ptr_t * history_in,zbx_vector_ptr_t * history_out,zbx_preproc_result_t * results,int * results_num,char ** error)2194 int	zbx_item_preproc_test(unsigned char value_type, zbx_variant_t *value, const zbx_timespec_t *ts,
2195 		zbx_preproc_op_t *steps, int steps_num, zbx_vector_ptr_t *history_in, zbx_vector_ptr_t *history_out,
2196 		zbx_preproc_result_t *results, int *results_num, char **error)
2197 {
2198 	int	i, ret = SUCCEED;
2199 
2200 	for (i = 0; i < steps_num; i++)
2201 	{
2202 		zbx_preproc_op_t	*op = &steps[i];
2203 		zbx_variant_t		history_value;
2204 		zbx_timespec_t		history_ts;
2205 
2206 		zbx_preproc_history_pop_value(history_in, i, &history_value, &history_ts);
2207 
2208 		if (FAIL == (ret = zbx_item_preproc(value_type, value, ts, op, &history_value, &history_ts, error)))
2209 		{
2210 			results[i].action = op->error_handler;
2211 			results[i].error = zbx_strdup(NULL, *error);
2212 			ret = zbx_item_preproc_handle_error(value, op, error);
2213 		}
2214 		else
2215 		{
2216 			results[i].action = ZBX_PREPROC_FAIL_DEFAULT;
2217 			results[i].error = NULL;
2218 		}
2219 
2220 		if (SUCCEED != ret)
2221 		{
2222 			zbx_variant_set_none(&results[i].value);
2223 			zbx_variant_clear(&history_value);
2224 			break;
2225 		}
2226 
2227 		zbx_variant_copy(&results[i].value, value);
2228 
2229 		if (ZBX_VARIANT_NONE != history_value.type)
2230 		{
2231 			/* the value is byte copied to history_out vector and doesn't have to be cleared */
2232 			zbx_preproc_history_add_value(history_out, i, &history_value, &history_ts);
2233 		}
2234 
2235 		if (ZBX_VARIANT_NONE == value->type)
2236 			break;
2237 	}
2238 
2239 	*results_num = (i == steps_num ? i : i + 1);
2240 
2241 	return ret;
2242 }
2243 
2244 #ifdef HAVE_TESTS
2245 #	include "../../../tests/zabbix_server/preprocessor/item_preproc_test.c"
2246 #endif
2247