1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 **/
19 
20 #include "common.h"
21 #include "module.h"
22 #include "sysinfo.h"
23 #include "log.h"
24 #include "cfg.h"
25 #include "alias.h"
26 #include "threads.h"
27 #if !defined(_WINDOWS) && !defined(__MINGW32__)
28 #include "sighandler.h"
29 #endif
30 #include "zbxalgo.h"
31 #include "zbxregexp.h"
32 
33 #ifdef WITH_AGENT_METRICS
34 #	include "agent/agent.h"
35 #endif
36 
37 #ifdef WITH_COMMON_METRICS
38 #	include "common/common.h"
39 #endif
40 
41 #ifdef WITH_HTTP_METRICS
42 #	include "common/http_metrics.h"
43 #endif
44 
45 #ifdef WITH_SIMPLE_METRICS
46 #	include "simple/simple.h"
47 #endif
48 
49 #ifdef WITH_SPECIFIC_METRICS
50 #	include "specsysinfo.h"
51 #endif
52 
53 typedef struct
54 {
55 	char				*pattern;
56 	zbx_vector_str_t		elements;
57 	zbx_key_access_rule_type_t	type;
58 	int				empty_arguments;
59 }
60 zbx_key_access_rule_t;
61 
62 #ifdef WITH_HOSTNAME_METRIC
63 extern ZBX_METRIC	parameter_hostname;
64 #endif
65 
66 static ZBX_METRIC	*commands = NULL;
67 static ZBX_METRIC	*commands_local = NULL;
68 zbx_vector_ptr_t	key_access_rules;
69 
70 #define ZBX_COMMAND_ERROR		0
71 #define ZBX_COMMAND_WITHOUT_PARAMS	1
72 #define ZBX_COMMAND_WITH_PARAMS		2
73 
74 static int	compare_key_access_rules(const void *rule_a, const void *rule_b);
75 static int	parse_key_access_rule(char *pattern, zbx_key_access_rule_t *rule);
76 
77 /******************************************************************************
78  *                                                                            *
79  * Function: parse_command_dyn                                                *
80  *                                                                            *
81  * Purpose: parses item key and splits it into command and parameters         *
82  *                                                                            *
83  * Return value: ZBX_COMMAND_ERROR - error                                    *
84  *               ZBX_COMMAND_WITHOUT_PARAMS - command without parameters      *
85  *               ZBX_COMMAND_WITH_PARAMS - command with parameters            *
86  *                                                                            *
87  ******************************************************************************/
parse_command_dyn(const char * command,char ** cmd,char ** param)88 static int	parse_command_dyn(const char *command, char **cmd, char **param)
89 {
90 	const char	*pl, *pr;
91 	size_t		cmd_alloc = 0, param_alloc = 0,
92 			cmd_offset = 0, param_offset = 0;
93 
94 	for (pl = command; SUCCEED == is_key_char(*pl); pl++)
95 		;
96 
97 	if (pl == command)
98 		return ZBX_COMMAND_ERROR;
99 
100 	zbx_strncpy_alloc(cmd, &cmd_alloc, &cmd_offset, command, pl - command);
101 
102 	if ('\0' == *pl)	/* no parameters specified */
103 		return ZBX_COMMAND_WITHOUT_PARAMS;
104 
105 	if ('[' != *pl)		/* unsupported character */
106 		return ZBX_COMMAND_ERROR;
107 
108 	for (pr = ++pl; '\0' != *pr; pr++)
109 		;
110 
111 	if (']' != *--pr)
112 		return ZBX_COMMAND_ERROR;
113 
114 	zbx_strncpy_alloc(param, &param_alloc, &param_offset, pl, pr - pl);
115 
116 	return ZBX_COMMAND_WITH_PARAMS;
117 }
118 
119 
add_to_metrics(ZBX_METRIC ** metrics,ZBX_METRIC * metric,char * error,size_t max_error_len)120 static int	add_to_metrics(ZBX_METRIC **metrics, ZBX_METRIC *metric, char *error, size_t max_error_len)
121 {
122 	int		i = 0;
123 
124 	while (NULL != (*metrics)[i].key)
125 	{
126 		if (0 == strcmp((*metrics)[i].key, metric->key))
127 		{
128 			zbx_snprintf(error, max_error_len, "key \"%s\" already exists", metric->key);
129 			return FAIL;	/* metric already exists */
130 		}
131 		i++;
132 	}
133 
134 	(*metrics)[i].key = zbx_strdup(NULL, metric->key);
135 	(*metrics)[i].flags = metric->flags;
136 	(*metrics)[i].function = metric->function;
137 	(*metrics)[i].test_param = (NULL == metric->test_param ? NULL : zbx_strdup(NULL, metric->test_param));
138 
139 	*metrics = (ZBX_METRIC *)zbx_realloc(*metrics, (i + 2) * sizeof(ZBX_METRIC));
140 	memset(&(*metrics)[i + 1], 0, sizeof(ZBX_METRIC));
141 
142 	return SUCCEED;
143 }
144 
145 /******************************************************************************
146  *                                                                            *
147  * Function: add_metric                                                       *
148  *                                                                            *
149  * Purpose: registers a new item key into the system                          *
150  *                                                                            *
151  ******************************************************************************/
add_metric(ZBX_METRIC * metric,char * error,size_t max_error_len)152 int	add_metric(ZBX_METRIC *metric, char *error, size_t max_error_len)
153 {
154 	return add_to_metrics(&commands, metric, error, max_error_len);
155 }
156 
157 /******************************************************************************
158  *                                                                            *
159  * Function: add_metric_local                                                 *
160  *                                                                            *
161  * Purpose: registers a new item key as local into the system                 *
162  *                                                                            *
163  ******************************************************************************/
add_metric_local(ZBX_METRIC * metric,char * error,size_t max_error_len)164 int	add_metric_local(ZBX_METRIC *metric, char *error, size_t max_error_len)
165 {
166 	return add_to_metrics(&commands_local, metric, error, max_error_len);
167 }
168 
169 #if !defined(__MINGW32__)
add_user_parameter(const char * itemkey,char * command,char * error,size_t max_error_len)170 int	add_user_parameter(const char *itemkey, char *command, char *error, size_t max_error_len)
171 {
172 	int		ret;
173 	unsigned	flags = CF_USERPARAMETER;
174 	ZBX_METRIC	metric;
175 	AGENT_REQUEST	request;
176 
177 	init_request(&request);
178 
179 	if (SUCCEED == (ret = parse_item_key(itemkey, &request)))
180 	{
181 		if (1 == get_rparams_num(&request) && 0 == strcmp("[*]", itemkey + strlen(get_rkey(&request))))
182 			flags |= CF_HAVEPARAMS;
183 		else if (0 != get_rparams_num(&request))
184 			ret = FAIL;
185 	}
186 
187 	if (SUCCEED == ret)
188 	{
189 		metric.key = get_rkey(&request);
190 		metric.flags = flags;
191 		metric.function = &EXECUTE_USER_PARAMETER;
192 		metric.test_param = command;
193 
194 		ret = add_metric(&metric, error, max_error_len);
195 	}
196 	else
197 		zbx_strlcpy(error, "syntax error", max_error_len);
198 
199 	free_request(&request);
200 
201 	return ret;
202 }
203 #endif
204 
init_metrics(void)205 void	init_metrics(void)
206 {
207 	int	i;
208 	char	error[MAX_STRING_LEN];
209 
210 	init_key_access_rules();
211 
212 	commands = (ZBX_METRIC *)zbx_malloc(commands, sizeof(ZBX_METRIC));
213 	commands[0].key = NULL;
214 	commands_local = (ZBX_METRIC *)zbx_malloc(commands_local, sizeof(ZBX_METRIC));
215 	commands_local[0].key = NULL;
216 
217 #ifdef WITH_AGENT_METRICS
218 	for (i = 0; NULL != parameters_agent[i].key; i++)
219 	{
220 		if (SUCCEED != add_metric(&parameters_agent[i], error, sizeof(error)))
221 		{
222 			zabbix_log(LOG_LEVEL_CRIT, "cannot add item key: %s", error);
223 			exit(EXIT_FAILURE);
224 		}
225 	}
226 #endif
227 
228 #ifdef WITH_COMMON_METRICS
229 	for (i = 0; NULL != parameters_common[i].key; i++)
230 	{
231 		if (SUCCEED != add_metric(&parameters_common[i], error, sizeof(error)))
232 		{
233 			zabbix_log(LOG_LEVEL_CRIT, "cannot add item key: %s", error);
234 			exit(EXIT_FAILURE);
235 		}
236 	}
237 
238 	for (i = 0; NULL != parameters_common_local[i].key; i++)
239 	{
240 		if (SUCCEED != add_metric_local(&parameters_common_local[i], error, sizeof(error)))
241 		{
242 			zabbix_log(LOG_LEVEL_CRIT, "cannot add item key: %s", error);
243 			exit(EXIT_FAILURE);
244 		}
245 	}
246 #endif
247 
248 #ifdef WITH_HTTP_METRICS
249 	for (i = 0; NULL != parameters_common_http[i].key; i++)
250 	{
251 		if (SUCCEED != add_metric(&parameters_common_http[i], error, sizeof(error)))
252 		{
253 			zabbix_log(LOG_LEVEL_CRIT, "cannot add item key: %s", error);
254 			exit(EXIT_FAILURE);
255 		}
256 	}
257 #endif
258 
259 #ifdef WITH_SPECIFIC_METRICS
260 	for (i = 0; NULL != parameters_specific[i].key; i++)
261 	{
262 		if (SUCCEED != add_metric(&parameters_specific[i], error, sizeof(error)))
263 		{
264 			zabbix_log(LOG_LEVEL_CRIT, "cannot add item key: %s", error);
265 			exit(EXIT_FAILURE);
266 		}
267 	}
268 #endif
269 
270 #ifdef WITH_SIMPLE_METRICS
271 	for (i = 0; NULL != parameters_simple[i].key; i++)
272 	{
273 		if (SUCCEED != add_metric(&parameters_simple[i], error, sizeof(error)))
274 		{
275 			zabbix_log(LOG_LEVEL_CRIT, "cannot add item key: %s", error);
276 			exit(EXIT_FAILURE);
277 		}
278 	}
279 #endif
280 
281 #ifdef WITH_HOSTNAME_METRIC
282 	if (SUCCEED != add_metric(&parameter_hostname, error, sizeof(error)))
283 	{
284 		zabbix_log(LOG_LEVEL_CRIT, "cannot add item key: %s", error);
285 		exit(EXIT_FAILURE);
286 	}
287 #endif
288 }
289 
free_metrics(void)290 void	free_metrics(void)
291 {
292 	if (NULL != commands)
293 	{
294 		int	i;
295 
296 		for (i = 0; NULL != commands[i].key; i++)
297 		{
298 			zbx_free(commands[i].key);
299 			zbx_free(commands[i].test_param);
300 		}
301 
302 		zbx_free(commands);
303 	}
304 
305 	if (NULL != commands_local)
306 	{
307 		int	i;
308 
309 		for (i = 0; NULL != commands_local[i].key; i++)
310 		{
311 			zbx_free(commands_local[i].key);
312 			zbx_free(commands_local[i].test_param);
313 		}
314 
315 		zbx_free(commands_local);
316 	}
317 
318 	free_key_access_rules();
319 }
320 
321 /******************************************************************************
322  *                                                                            *
323  * Function: init_key_access_rules                                            *
324  *                                                                            *
325  * Purpose: initializes key access rule list                                  *
326  *                                                                            *
327  ******************************************************************************/
init_key_access_rules(void)328 void	init_key_access_rules(void)
329 {
330 	zbx_vector_ptr_create(&key_access_rules);
331 }
332 
333 /******************************************************************************
334  *                                                                            *
335  * Function: zbx_key_access_rule_free                                         *
336  *                                                                            *
337  * Purpose: frees key access rule and its resources                           *
338  *                                                                            *
339  ******************************************************************************/
zbx_key_access_rule_free(zbx_key_access_rule_t * rule)340 static void	zbx_key_access_rule_free(zbx_key_access_rule_t *rule)
341 {
342 	zbx_free(rule->pattern);
343 	zbx_vector_str_clear_ext(&rule->elements, zbx_str_free);
344 	zbx_vector_str_destroy(&rule->elements);
345 	zbx_free(rule);
346 }
347 
348 /******************************************************************************
349  *                                                                            *
350  * Function: zbx_key_access_rule_create                                       *
351  *                                                                            *
352  * Purpose: creates key access rule                                           *
353  *                                                                            *
354  * Parameters: pattern - [IN] the rule pattern                                *
355  *             type    - [IN] the rule type                                   *
356  *                                                                            *
357  *  Return value: The created rule or NULL if pattern was invalid.            *
358  *                                                                            *
359  ******************************************************************************/
zbx_key_access_rule_create(char * pattern,zbx_key_access_rule_type_t type)360 static zbx_key_access_rule_t	*zbx_key_access_rule_create(char *pattern, zbx_key_access_rule_type_t type)
361 {
362 	zbx_key_access_rule_t	*rule;
363 
364 	rule = zbx_malloc(NULL, sizeof(zbx_key_access_rule_t));
365 	rule->type = type;
366 	rule->pattern = zbx_strdup(NULL, pattern);
367 	zbx_vector_str_create(&rule->elements);
368 
369 	if (SUCCEED != parse_key_access_rule(pattern, rule))
370 	{
371 		zbx_key_access_rule_free(rule);
372 		rule = NULL;
373 	}
374 	return rule;
375 }
376 
377 /******************************************************************************
378  *                                                                            *
379  * Function: finalize_key_access_rules_configuration                          *
380  *                                                                            *
381  * Purpose: validates key access rules configuration                          *
382  *                                                                            *
383  ******************************************************************************/
finalize_key_access_rules_configuration(void)384 void	finalize_key_access_rules_configuration(void)
385 {
386 	int			i, j, rules_num, sysrun_index = ZBX_MAX_UINT31_1;
387 	zbx_key_access_rule_t	*rule, *sysrun_deny;
388 	char			sysrun_pattern[] = "system.run[*]";
389 
390 
391 	rules_num = key_access_rules.values_num;
392 
393 	/* prepare default system.run[*] deny rule to be added at the end */
394 	if (NULL == (sysrun_deny = zbx_key_access_rule_create(sysrun_pattern, ZBX_KEY_ACCESS_DENY)))
395 	{
396 		THIS_SHOULD_NEVER_HAPPEN;
397 		exit(EXIT_FAILURE);
398 	}
399 
400 	if (FAIL != (i = zbx_vector_ptr_search(&key_access_rules, sysrun_deny, compare_key_access_rules)))
401 	{
402 		/* exclude system.run[*] from total number of rules */
403 		rules_num--;
404 
405 		/* sysrun_index points at the first rule matching system.run[*] */
406 		sysrun_index = i;
407 	}
408 
409 	if (0 != rules_num)
410 	{
411 		/* throw out all rules after '*', because they would never match */
412 		for (i = 0; i < key_access_rules.values_num; i++)
413 		{
414 			rule = (zbx_key_access_rule_t*)key_access_rules.values[i];
415 			if (1 == rule->elements.values_num && 0 == strcmp(rule->elements.values[0], "*"))
416 			{
417 				/* 'match all' rule also matches system.run[*] */
418 				if (i < sysrun_index)
419 					sysrun_index = i;
420 
421 				break;
422 			}
423 		}
424 
425 		if (i != key_access_rules.values_num)
426 		{
427 			for (j = ++i; j < key_access_rules.values_num; j++)
428 			{
429 				rule = (zbx_key_access_rule_t*)key_access_rules.values[j];
430 				zabbix_log(LOG_LEVEL_WARNING, "removed unreachable %s \"%s\" rule",
431 						(ZBX_KEY_ACCESS_ALLOW == rule->type ? "AllowKey" : "DenyKey"),
432 						rule->pattern);
433 				zbx_key_access_rule_free(rule);
434 			}
435 			key_access_rules.values_num = i;
436 		}
437 
438 		/* trailing AllowKey rules are meaningless, because AllowKey=* is default behavior, */
439 		for (i = key_access_rules.values_num - 1; 0 <= i; i--)
440 		{
441 			rule = (zbx_key_access_rule_t*)key_access_rules.values[i];
442 
443 			if (ZBX_KEY_ACCESS_ALLOW != rule->type)
444 				break;
445 
446 			/* system.run allow rules are not redundant because of default system.run[*] deny rule */
447 			if (0 == rule->elements.values_num || 0 != strcmp(rule->elements.values[0], "system.run"))
448 			{
449 				if (i != sysrun_index)
450 				{
451 					zabbix_log(LOG_LEVEL_WARNING, "removed redundant trailing AllowKey \"%s\" rule",
452 							rule->pattern);
453 				}
454 
455 				zbx_key_access_rule_free(rule);
456 				zbx_vector_ptr_remove(&key_access_rules, i);
457 			}
458 		}
459 
460 		if (0 == key_access_rules.values_num)
461 		{
462 			zabbix_log(LOG_LEVEL_CRIT, "Item key access rules are configured to match all keys,"
463 					" indicating possible configuration problem. "
464 					" Please remove the rules if that was the purpose.");
465 			exit(EXIT_FAILURE);
466 		}
467 	}
468 
469 	if (ZBX_MAX_UINT31_1 == sysrun_index)
470 		zbx_vector_ptr_append(&key_access_rules, sysrun_deny);
471 	else
472 		zbx_key_access_rule_free(sysrun_deny);
473 }
474 
475 /******************************************************************************
476  *                                                                            *
477  * Function: parse_key_access_rule                                            *
478  *                                                                            *
479  * Purpose: parses key access rule expression from AllowKey and DenyKey       *
480  *                                                                            *
481  * Parameters: pattern - [IN] key access rule wildcard                        *
482  *             rule    - [IN] key access rule element to fill                 *
483  *                                                                            *
484  * Return value: SUCCEED - successful execution                               *
485  *               FAIL    - pattern parsing failed                             *
486  *                                                                            *
487  ******************************************************************************/
parse_key_access_rule(char * pattern,zbx_key_access_rule_t * rule)488 static int	parse_key_access_rule(char *pattern, zbx_key_access_rule_t *rule)
489 {
490 	char		*pl, *pr = NULL, *param;
491 	size_t		alloc = 0, offset = 0;
492 	int		i, size;
493 
494 	for (pl = pattern; SUCCEED == is_key_char(*pl) || '*' == *pl; pl++);
495 
496 	if (pl == pattern)
497 		return FAIL; /* empty key */
498 
499 	/* extract rule elements [0] = key pattern and all parameters follow */
500 	zbx_strncpy_alloc(&pr, &alloc, &offset, pattern, pl - pattern);
501 	zbx_wildcard_minimize(pr);
502 	zbx_vector_str_append(&rule->elements, pr);
503 	rule->empty_arguments = 0;
504 
505 	if ('\0' == *pl)	/* no parameters specified */
506 		return SUCCEED;
507 
508 	if ('[' != *pl)		/* unsupported character */
509 		return FAIL;
510 
511 	for (pr = ++pl; '\0' != *pr; pr++);
512 
513 	if (']' != *--pr)
514 		return FAIL;
515 
516 	if (1 > pr - pl)	/* no parameters specified */
517 	{
518 		rule->empty_arguments = 1;
519 		return SUCCEED;
520 	}
521 
522 	*pr = '\0';
523 	size = num_param(pl);
524 	zbx_vector_str_reserve(&rule->elements, size);
525 
526 	for (i = 0; i < size; i++)
527 	{
528 		if (NULL == (param = get_param_dyn(pl, i + 1, NULL)))
529 			return FAIL;
530 
531 		zbx_wildcard_minimize(param);
532 		zbx_vector_str_append(&rule->elements, param);
533 	}
534 
535 	*pr = ']';
536 
537 	/* remove repeated trailing "*" parameters */
538 	if (1 < size && 0 == strcmp(rule->elements.values[i--], "*"))
539 	{
540 		for (; 0 < i; i--)
541 		{
542 			if (0 != strcmp(rule->elements.values[i], "*"))
543 				break;
544 
545 			zbx_free(rule->elements.values[i + 1]);
546 			zbx_vector_str_remove(&rule->elements, i + 1);
547 		}
548 	}
549 
550 	return SUCCEED;
551 }
552 
553 /******************************************************************************
554  *                                                                            *
555  * Function: compare_key_access_rules                                         *
556  *                                                                            *
557  * Purpose: Compares two zbx_key_access_rule_t values to perform search       *
558  *          within vector. Rule type (allow/deny) is not checked here.        *
559  *                                                                            *
560  * Parameters: rule_a - [IN] key access rule 1                                *
561  *             rule_b - [IN] key access rule 2                                *
562  *                                                                            *
563  * Return value: If key access rule values are the same, 0 is returned        *
564  *               otherwise nonzero value is returned.                         *
565  *                                                                            *
566  ******************************************************************************/
compare_key_access_rules(const void * rule_a,const void * rule_b)567 static int	compare_key_access_rules(const void *rule_a, const void *rule_b)
568 {
569 	const zbx_key_access_rule_t	*a, *b;
570 	int				i;
571 
572 	a = *(zbx_key_access_rule_t **)rule_a;
573 	b = *(zbx_key_access_rule_t **)rule_b;
574 
575 	if (a->empty_arguments != b->empty_arguments || a->elements.values_num != b->elements.values_num)
576 		return 1;
577 
578 	for (i = 0; a->elements.values_num > i; i++)
579 	{
580 		if (0 != strcmp(a->elements.values[i], b->elements.values[i]))
581 			return 1;
582 	}
583 
584 	return 0;
585 }
586 
587 /******************************************************************************
588  *                                                                            *
589  * Function: add_key_access_rule                                              *
590  *                                                                            *
591  * Purpose: adds new key access rule from AllowKey and DenyKey parameters     *
592  *                                                                            *
593  * Parameters: parameter - [IN] the parameter that defined the rule           *
594  *             pattern   - [IN] key access rule wildcard                      *
595  *             type      - [IN] key access rule type (allow/deny)             *
596  *                                                                            *
597  * Return value: SUCCEED - successful execution                               *
598  *               FAIL    - pattern parsing failed                             *
599  *                                                                            *
600  ******************************************************************************/
add_key_access_rule(const char * parameter,char * pattern,zbx_key_access_rule_type_t type)601 int	add_key_access_rule(const char *parameter, char *pattern, zbx_key_access_rule_type_t type)
602 {
603 	zbx_key_access_rule_t	*rule, *r;
604 	int			i;
605 
606 	if (NULL == (rule = zbx_key_access_rule_create(pattern, type)))
607 	{
608 		zabbix_log(LOG_LEVEL_WARNING, "failed to process %s access rule \"%s\"", parameter, pattern);
609 		return FAIL;
610 
611 	}
612 
613 	if (FAIL != (i = zbx_vector_ptr_search(&key_access_rules, rule, compare_key_access_rules)))
614 	{
615 		r = (zbx_key_access_rule_t*)key_access_rules.values[i];
616 
617 		zabbix_log(LOG_LEVEL_WARNING, "%s access rule \"%s\" was not added"
618 				" because it %s another rule defined above ",
619 				parameter, pattern, r->type == type ? "duplicates" : "conflicts with");
620 		zbx_key_access_rule_free(rule);
621 
622 		return SUCCEED;
623 	}
624 
625 	zbx_vector_ptr_append(&key_access_rules, rule);
626 
627 	return SUCCEED;
628 }
629 
630 /******************************************************************************
631  *                                                                            *
632  * Function: check_request_access_rules                                       *
633  *                                                                            *
634  * Purpose: checks agent metric request against configured access rules       *
635  *                                                                            *
636  * Parameters: request - [IN] metric request (key and parameters)             *
637  *                                                                            *
638  * Return value: ZBX_KEY_ACCESS_ALLOW - metric access allowed                 *
639  *               ZBX_KEY_ACCESS_DENY  - metric access denied                  *
640  *                                                                            *
641  ******************************************************************************/
check_request_access_rules(AGENT_REQUEST * request)642 int	check_request_access_rules(AGENT_REQUEST *request)
643 {
644 	int			i, j, empty_arguments;
645 	zbx_key_access_rule_t	*rule;
646 
647 	/* empty arguments flag means key is followed by empty brackets, which is not the same as no brackets */
648 	empty_arguments = (1 == request->nparam && 0 == strlen(request->params[0]));
649 
650 	for (i = 0; key_access_rules.values_num > i; i++)
651 	{
652 		rule = (zbx_key_access_rule_t*)key_access_rules.values[i];
653 
654 		if (0 == strcmp("*", rule->elements.values[0]) && 1 == rule->elements.values_num)
655 			return rule->type; /* match all */
656 
657 		if (1 < rule->elements.values_num)
658 		{
659 			if (0 == strcmp("*", rule->elements.values[rule->elements.values_num - 1]))
660 			{
661 				if (2 == rule->elements.values_num && 0 == request->nparam)
662 					continue;	/* rule: key[*], request: key */
663 			}
664 			else
665 			{
666 				if (request->nparam < (rule->elements.values_num - 1))
667 					continue;	/* too few parameters */
668 
669 				if (request->nparam > (rule->elements.values_num - 1) && 0 == empty_arguments)
670 					continue;	/* too many parameters */
671 			}
672 		}
673 
674 		if (0 == zbx_wildcard_match(request->key, rule->elements.values[0]))
675 			continue;	/* key doesn't match */
676 
677 		if (0 != rule->empty_arguments)	/* rule expects empty argument list: key[] */
678 		{
679 			if (0 != empty_arguments)
680 				return rule->type;
681 
682 			continue;
683 		}
684 
685 		if (0 != empty_arguments && 1 == rule->elements.values_num)
686 			continue;	/* no parameters expected by rule */
687 
688 		if (0 == request->nparam && 1 == rule->elements.values_num)	/* no parameters */
689 			return rule->type;
690 
691 		for (j = 1; rule->elements.values_num > j; j++)
692 		{
693 			if ((rule->elements.values_num - 1) == j)	/* last parameter */
694 			{
695 				if (0 == strcmp("*", rule->elements.values[j]))
696 					return rule->type;	/* skip next parameter checks */
697 
698 				if (request->nparam < j)
699 					break;
700 
701 				if (0 == zbx_wildcard_match(request->params[j - 1], rule->elements.values[j]))
702 					break;		/* parameter doesn't match pattern */
703 
704 				return rule->type;
705 			}
706 
707 			if (request->nparam < j ||
708 					0 == zbx_wildcard_match(request->params[j - 1], rule->elements.values[j]))
709 				break;	/* parameter doesn't match pattern */
710 		}
711 	}
712 
713 	return ZBX_KEY_ACCESS_ALLOW;	/* allow by default for backward compatibility */
714 }
715 
716 /******************************************************************************
717  *                                                                            *
718  * Function: check_key_access_rules                                           *
719  *                                                                            *
720  * Purpose: checks agent metric request against configured access rules       *
721  *                                                                            *
722  * Parameters: metric - [IN] metric requested (key and parameters)            *
723  *                                                                            *
724  * Return value: ZBX_KEY_ACCESS_ALLOW - metric access allowed                 *
725  *               ZBX_KEY_ACCESS_DENY  - metric access denied                  *
726  *                                                                            *
727  ******************************************************************************/
check_key_access_rules(const char * metric)728 int	check_key_access_rules(const char *metric)
729 {
730 	int		ret;
731 	AGENT_REQUEST	request;
732 
733 	init_request(&request);
734 
735 	if (SUCCEED == parse_item_key(metric, &request))
736 		ret = check_request_access_rules(&request);
737 	else
738 		ret = ZBX_KEY_ACCESS_DENY;
739 
740 	free_request(&request);
741 
742 	return ret;
743 }
744 
745 /******************************************************************************
746  *                                                                            *
747  * Function: free_key_access_rules                                            *
748  *                                                                            *
749  * Purpose: cleanup key access rule list                                      *
750  *                                                                            *
751  ******************************************************************************/
free_key_access_rules(void)752 void	free_key_access_rules(void)
753 {
754 	int	i;
755 
756 	for(i = 0; i < key_access_rules.values_num; i++)
757 		zbx_key_access_rule_free((zbx_key_access_rule_t *)key_access_rules.values[i]);
758 
759 	zbx_vector_ptr_destroy(&key_access_rules);
760 }
761 
zbx_log_init(zbx_log_t * log)762 static void	zbx_log_init(zbx_log_t *log)
763 {
764 	log->value = NULL;
765 	log->source = NULL;
766 	log->timestamp = 0;
767 	log->severity = 0;
768 	log->logeventid = 0;
769 }
770 
init_result(AGENT_RESULT * result)771 void	init_result(AGENT_RESULT *result)
772 {
773 	memset(result, 0, sizeof(AGENT_RESULT));
774 }
775 
zbx_log_clean(zbx_log_t * log)776 static void	zbx_log_clean(zbx_log_t *log)
777 {
778 	zbx_free(log->source);
779 	zbx_free(log->value);
780 }
781 
zbx_log_free(zbx_log_t * log)782 void	zbx_log_free(zbx_log_t *log)
783 {
784 	zbx_log_clean(log);
785 	zbx_free(log);
786 }
787 
free_result(AGENT_RESULT * result)788 void	free_result(AGENT_RESULT *result)
789 {
790 	UNSET_UI64_RESULT(result);
791 	UNSET_DBL_RESULT(result);
792 	UNSET_STR_RESULT(result);
793 	UNSET_TEXT_RESULT(result);
794 	UNSET_LOG_RESULT(result);
795 	UNSET_MSG_RESULT(result);
796 }
797 
798 /******************************************************************************
799  *                                                                            *
800  * Function: init_request                                                     *
801  *                                                                            *
802  * Purpose: initialize the request structure                                  *
803  *                                                                            *
804  * Parameters: request - pointer to the structure                             *
805  *                                                                            *
806  ******************************************************************************/
init_request(AGENT_REQUEST * request)807 void	init_request(AGENT_REQUEST *request)
808 {
809 	request->key = NULL;
810 	request->nparam = 0;
811 	request->params = NULL;
812 	request->types = NULL;
813 	request->lastlogsize = 0;
814 	request->mtime = 0;
815 }
816 
817 /******************************************************************************
818  *                                                                            *
819  * Function: free_request_params                                              *
820  *                                                                            *
821  * Purpose: free memory used by the request parameters                        *
822  *                                                                            *
823  * Parameters: request - pointer to the request structure                     *
824  *                                                                            *
825  ******************************************************************************/
free_request_params(AGENT_REQUEST * request)826 static void	free_request_params(AGENT_REQUEST *request)
827 {
828 	int	i;
829 
830 	for (i = 0; i < request->nparam; i++)
831 		zbx_free(request->params[i]);
832 	zbx_free(request->params);
833 	zbx_free(request->types);
834 
835 	request->nparam = 0;
836 }
837 
838 /******************************************************************************
839  *                                                                            *
840  * Function: free_request                                                     *
841  *                                                                            *
842  * Purpose: free memory used by the request                                   *
843  *                                                                            *
844  * Parameters: request - pointer to the request structure                     *
845  *                                                                            *
846  ******************************************************************************/
free_request(AGENT_REQUEST * request)847 void	free_request(AGENT_REQUEST *request)
848 {
849 	zbx_free(request->key);
850 	free_request_params(request);
851 }
852 
853 /******************************************************************************
854  *                                                                            *
855  * Function: add_request_param                                                *
856  *                                                                            *
857  * Purpose: add a new parameter                                               *
858  *                                                                            *
859  * Parameters: request - [OUT] pointer to the request structure               *
860  *             pvalue  - [IN]  parameter value string                         *
861  *             type    - [IN]  parameter type                                 *
862  *                                                                            *
863  ******************************************************************************/
add_request_param(AGENT_REQUEST * request,char * pvalue,zbx_request_parameter_type_t type)864 static void	add_request_param(AGENT_REQUEST *request, char *pvalue, zbx_request_parameter_type_t type)
865 {
866 	request->nparam++;
867 	request->params = (char **)zbx_realloc(request->params, request->nparam * sizeof(char *));
868 	request->params[request->nparam - 1] = pvalue;
869 	request->types = (zbx_request_parameter_type_t*)zbx_realloc(request->types,
870 			request->nparam * sizeof(zbx_request_parameter_type_t));
871 	request->types[request->nparam - 1] = type;
872 }
873 
874 /******************************************************************************
875  *                                                                            *
876  * Function: parse_item_key                                                   *
877  *                                                                            *
878  * Purpose: parse item command (key) and fill AGENT_REQUEST structure         *
879  *                                                                            *
880  * Parameters: itemkey - complete item key                                    *
881  *                                                                            *
882  * Return value: request - structure filled with data from item key           *
883  *                                                                            *
884  * Comments: thread-safe                                                      *
885  *                                                                            *
886  ******************************************************************************/
parse_item_key(const char * itemkey,AGENT_REQUEST * request)887 int	parse_item_key(const char *itemkey, AGENT_REQUEST *request)
888 {
889 	int	i, ret = FAIL;
890 	char	*key = NULL, *params = NULL;
891 
892 	switch (parse_command_dyn(itemkey, &key, &params))
893 	{
894 		case ZBX_COMMAND_WITH_PARAMS:
895 			if (0 == (request->nparam = num_param(params)))
896 				goto out;	/* key is badly formatted */
897 
898 			request->params = (char **)zbx_malloc(request->params, request->nparam * sizeof(char *));
899 			request->types = (zbx_request_parameter_type_t*)zbx_malloc(request->types,
900 					request->nparam * sizeof(zbx_request_parameter_type_t));
901 
902 			for (i = 0; i < request->nparam; i++)
903 				request->params[i] = get_param_dyn(params, i + 1, &request->types[i]);
904 			break;
905 		case ZBX_COMMAND_ERROR:
906 			goto out;	/* key is badly formatted */
907 	}
908 
909 	request->key = key;
910 	key = NULL;
911 
912 	ret = SUCCEED;
913 out:
914 	zbx_free(params);
915 	zbx_free(key);
916 
917 	return ret;
918 }
919 
test_parameter(const char * key)920 void	test_parameter(const char *key)
921 {
922 #define ZBX_KEY_COLUMN_WIDTH	45
923 
924 	AGENT_RESULT	result;
925 
926 	printf("%-*s", ZBX_KEY_COLUMN_WIDTH, key);
927 
928 	init_result(&result);
929 
930 	if (SUCCEED == process(key, PROCESS_WITH_ALIAS, &result))
931 	{
932 		char	buffer[ZBX_MAX_DOUBLE_LEN + 1];
933 
934 		if (0 != ISSET_UI64(&result))
935 			printf(" [u|" ZBX_FS_UI64 "]", result.ui64);
936 
937 		if (0 != ISSET_DBL(&result))
938 			printf(" [d|%s]", zbx_print_double(buffer, sizeof(buffer), result.dbl));
939 
940 		if (0 != ISSET_STR(&result))
941 			printf(" [s|%s]", result.str);
942 
943 		if (0 != ISSET_TEXT(&result))
944 			printf(" [t|%s]", result.text);
945 
946 		if (0 != ISSET_MSG(&result))
947 			printf(" [m|%s]", result.msg);
948 	}
949 	else
950 	{
951 		if (0 != ISSET_MSG(&result))
952 			printf(" [m|" ZBX_NOTSUPPORTED "] [%s]", result.msg);
953 		else
954 			printf(" [m|" ZBX_NOTSUPPORTED "]");
955 	}
956 
957 	free_result(&result);
958 
959 	printf("\n");
960 
961 	fflush(stdout);
962 
963 #undef ZBX_KEY_COLUMN_WIDTH
964 }
965 
test_parameters(void)966 void	test_parameters(void)
967 {
968 	int	i;
969 	char	*key = NULL;
970 	size_t	key_alloc = 0;
971 
972 	for (i = 0; NULL != commands[i].key; i++)
973 	{
974 		if (0 != strcmp(commands[i].key, "__UserPerfCounter"))
975 		{
976 			size_t	key_offset = 0;
977 
978 			zbx_strcpy_alloc(&key, &key_alloc, &key_offset, commands[i].key);
979 
980 			if (0 == (commands[i].flags & CF_USERPARAMETER) && NULL != commands[i].test_param)
981 			{
982 				zbx_chrcpy_alloc(&key, &key_alloc, &key_offset, '[');
983 				zbx_strcpy_alloc(&key, &key_alloc, &key_offset, commands[i].test_param);
984 				zbx_chrcpy_alloc(&key, &key_alloc, &key_offset, ']');
985 			}
986 
987 			if (ZBX_KEY_ACCESS_ALLOW == check_key_access_rules(key))
988 				test_parameter(key);
989 		}
990 	}
991 
992 	zbx_free(key);
993 
994 	test_aliases();
995 }
996 
zbx_check_user_parameter(const char * param,char * error,int max_error_len)997 static int	zbx_check_user_parameter(const char *param, char *error, int max_error_len)
998 {
999 	const char	suppressed_chars[] = "\\'\"`*?[]{}~$!&;()<>|#@\n", *c;
1000 	char		*buf = NULL;
1001 	size_t		buf_alloc = 128, buf_offset = 0;
1002 
1003 	if (0 != CONFIG_UNSAFE_USER_PARAMETERS)
1004 		return SUCCEED;
1005 
1006 	for (c = suppressed_chars; '\0' != *c; c++)
1007 	{
1008 		if (NULL == strchr(param, *c))
1009 			continue;
1010 
1011 		buf = (char *)zbx_malloc(buf, buf_alloc);
1012 
1013 		for (c = suppressed_chars; '\0' != *c; c++)
1014 		{
1015 			if (c != suppressed_chars)
1016 				zbx_strcpy_alloc(&buf, &buf_alloc, &buf_offset, ", ");
1017 
1018 			if (0 != isprint(*c))
1019 				zbx_chrcpy_alloc(&buf, &buf_alloc, &buf_offset, *c);
1020 			else
1021 				zbx_snprintf_alloc(&buf, &buf_alloc, &buf_offset, "0x%02x", (unsigned int)(*c));
1022 		}
1023 
1024 		zbx_snprintf(error, max_error_len, "Special characters \"%s\" are not allowed in the parameters.", buf);
1025 
1026 		zbx_free(buf);
1027 
1028 		return FAIL;
1029 	}
1030 
1031 	return SUCCEED;
1032 }
1033 
replace_param(const char * cmd,const AGENT_REQUEST * request,char ** out,char * error,int max_error_len)1034 static int	replace_param(const char *cmd, const AGENT_REQUEST *request, char **out, char *error, int max_error_len)
1035 {
1036 	const char	*pl = cmd, *pr, *tmp;
1037 	size_t		out_alloc = 0, out_offset = 0;
1038 	int		num, ret = SUCCEED;
1039 
1040 	while (NULL != (pr = strchr(pl, '$')))
1041 	{
1042 		zbx_strncpy_alloc(out, &out_alloc, &out_offset, pl, pr - pl);
1043 
1044 		/* check if increasing pointer by 1 will not result in buffer overrun */
1045 		if ('\0' != pr[1])
1046 			pr++;
1047 
1048 		if ('0' == *pr)
1049 		{
1050 			zbx_strcpy_alloc(out, &out_alloc, &out_offset, cmd);
1051 		}
1052 		else if ('1' <= *pr && *pr <= '9')
1053 		{
1054 			num = (int)(*pr - '0');
1055 
1056 			if (request->nparam >= num)
1057 			{
1058 				tmp = get_rparam(request, num - 1);
1059 
1060 				if (SUCCEED != (ret = zbx_check_user_parameter(tmp, error, max_error_len)))
1061 					break;
1062 
1063 				zbx_strcpy_alloc(out, &out_alloc, &out_offset, tmp);
1064 			}
1065 		}
1066 		else
1067 		{
1068 			if ('$' != *pr)
1069 				zbx_chrcpy_alloc(out, &out_alloc, &out_offset, '$');
1070 			zbx_chrcpy_alloc(out, &out_alloc, &out_offset, *pr);
1071 		}
1072 
1073 		pl = pr + 1;
1074 	}
1075 
1076 	if (SUCCEED == ret)
1077 		zbx_strcpy_alloc(out, &out_alloc, &out_offset, pl);
1078 	else
1079 		zbx_free(*out);
1080 
1081 	return ret;
1082 }
1083 
1084 /******************************************************************************
1085  *                                                                            *
1086  * Function: process                                                          *
1087  *                                                                            *
1088  * Purpose: execute agent check                                               *
1089  *                                                                            *
1090  * Parameters: in_command - item key                                          *
1091  *             flags - PROCESS_LOCAL_COMMAND, allow execution of system.run   *
1092  *                     PROCESS_MODULE_COMMAND, execute item from a module     *
1093  *                     PROCESS_WITH_ALIAS, substitute agent Alias             *
1094  *                                                                            *
1095  * Return value: SUCCEED - successful execution                               *
1096  *               NOTSUPPORTED - item key is not supported or other error      *
1097  *               result - contains item value or error message                *
1098  *                                                                            *
1099  ******************************************************************************/
process(const char * in_command,unsigned flags,AGENT_RESULT * result)1100 int	process(const char *in_command, unsigned flags, AGENT_RESULT *result)
1101 {
1102 	int		ret = NOTSUPPORTED;
1103 	ZBX_METRIC	*command = NULL;
1104 	AGENT_REQUEST	request;
1105 
1106 	init_request(&request);
1107 
1108 	if (SUCCEED != parse_item_key((0 == (flags & PROCESS_WITH_ALIAS) ? in_command : zbx_alias_get(in_command)),
1109 			&request))
1110 	{
1111 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid item key format."));
1112 		goto notsupported;
1113 	}
1114 
1115 	if (0 == (flags & PROCESS_LOCAL_COMMAND) && ZBX_KEY_ACCESS_ALLOW != check_request_access_rules(&request))
1116 	{
1117 		zabbix_log(LOG_LEVEL_DEBUG, "Key access denied: \"%s\"", in_command);
1118 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Unsupported item key."));
1119 		goto notsupported;
1120 	}
1121 
1122 	/* system.run is not allowed by default except for getting hostname for daemons */
1123 	if (1 != CONFIG_ENABLE_REMOTE_COMMANDS && 0 == (flags & PROCESS_LOCAL_COMMAND) &&
1124 			0 == strcmp(request.key, "system.run"))
1125 	{
1126 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Remote commands are not enabled."));
1127 		goto notsupported;
1128 	}
1129 
1130 	if (0 != (flags & PROCESS_LOCAL_COMMAND))
1131 	{
1132 		for (command = commands_local; NULL != command->key; command++)
1133 		{
1134 			if (0 == strcmp(command->key, request.key))
1135 				break;
1136 		}
1137 	}
1138 
1139 	if (NULL == command || NULL == command->key)
1140 	{
1141 		for (command = commands; NULL != command->key; command++)
1142 		{
1143 			if (0 == strcmp(command->key, request.key))
1144 				break;
1145 		}
1146 	}
1147 
1148 	/* item key not found */
1149 	if (NULL == command->key)
1150 	{
1151 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Unsupported item key."));
1152 		goto notsupported;
1153 	}
1154 
1155 	/* expected item from a module */
1156 	if (0 != (flags & PROCESS_MODULE_COMMAND) && 0 == (command->flags & CF_MODULE))
1157 	{
1158 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Unsupported item key."));
1159 		goto notsupported;
1160 	}
1161 
1162 	/* command does not accept parameters but was called with parameters */
1163 	if (0 == (command->flags & CF_HAVEPARAMS) && 0 != request.nparam)
1164 	{
1165 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Item does not allow parameters."));
1166 		goto notsupported;
1167 	}
1168 
1169 	if (0 != (command->flags & CF_USERPARAMETER))
1170 	{
1171 		if (0 != (command->flags & CF_HAVEPARAMS))
1172 		{
1173 			char	*parameters = NULL, error[MAX_STRING_LEN];
1174 
1175 			if (FAIL == replace_param(command->test_param, &request, &parameters, error, sizeof(error)))
1176 			{
1177 				SET_MSG_RESULT(result, zbx_strdup(NULL, error));
1178 				goto notsupported;
1179 			}
1180 
1181 			free_request_params(&request);
1182 			add_request_param(&request, parameters, REQUEST_PARAMETER_TYPE_STRING);
1183 		}
1184 		else
1185 		{
1186 			free_request_params(&request);
1187 			add_request_param(&request, zbx_strdup(NULL, command->test_param),
1188 					REQUEST_PARAMETER_TYPE_STRING);
1189 		}
1190 	}
1191 
1192 	if (SYSINFO_RET_OK != command->function(&request, result))
1193 	{
1194 		/* "return NOTSUPPORTED;" would be more appropriate here for preserving original error */
1195 		/* message in "result" but would break things relying on ZBX_NOTSUPPORTED message. */
1196 		if (0 != (command->flags & CF_MODULE) && 0 == ISSET_MSG(result))
1197 			SET_MSG_RESULT(result, zbx_strdup(NULL, ZBX_NOTSUPPORTED_MSG));
1198 
1199 		goto notsupported;
1200 	}
1201 
1202 	ret = SUCCEED;
1203 
1204 notsupported:
1205 	free_request(&request);
1206 
1207 	return ret;
1208 }
1209 
add_log_result(AGENT_RESULT * result,const char * value)1210 static void	add_log_result(AGENT_RESULT *result, const char *value)
1211 {
1212 	result->log = (zbx_log_t *)zbx_malloc(result->log, sizeof(zbx_log_t));
1213 
1214 	zbx_log_init(result->log);
1215 
1216 	result->log->value = zbx_strdup(result->log->value, value);
1217 	result->type |= AR_LOG;
1218 }
1219 
set_result_type(AGENT_RESULT * result,int value_type,char * c)1220 int	set_result_type(AGENT_RESULT *result, int value_type, char *c)
1221 {
1222 	zbx_uint64_t	value_uint64;
1223 	int		ret = FAIL;
1224 
1225 	assert(result);
1226 
1227 	switch (value_type)
1228 	{
1229 		double	dbl_tmp;
1230 
1231 		case ITEM_VALUE_TYPE_UINT64:
1232 			zbx_trim_integer(c);
1233 			del_zeros(c);
1234 
1235 			if (SUCCEED == is_uint64(c, &value_uint64))
1236 			{
1237 				SET_UI64_RESULT(result, value_uint64);
1238 				ret = SUCCEED;
1239 			}
1240 			break;
1241 		case ITEM_VALUE_TYPE_FLOAT:
1242 			zbx_trim_float(c);
1243 
1244 			if (SUCCEED == is_double(c, &dbl_tmp))
1245 			{
1246 				SET_DBL_RESULT(result, dbl_tmp);
1247 				ret = SUCCEED;
1248 			}
1249 			break;
1250 		case ITEM_VALUE_TYPE_STR:
1251 			zbx_replace_invalid_utf8(c);
1252 			SET_STR_RESULT(result, zbx_strdup(NULL, c));
1253 			ret = SUCCEED;
1254 			break;
1255 		case ITEM_VALUE_TYPE_TEXT:
1256 			zbx_replace_invalid_utf8(c);
1257 			SET_TEXT_RESULT(result, zbx_strdup(NULL, c));
1258 			ret = SUCCEED;
1259 			break;
1260 		case ITEM_VALUE_TYPE_LOG:
1261 			zbx_replace_invalid_utf8(c);
1262 			add_log_result(result, c);
1263 			ret = SUCCEED;
1264 			break;
1265 	}
1266 
1267 	return ret;
1268 }
1269 
set_result_meta(AGENT_RESULT * result,zbx_uint64_t lastlogsize,int mtime)1270 void	set_result_meta(AGENT_RESULT *result, zbx_uint64_t lastlogsize, int mtime)
1271 {
1272 	result->lastlogsize = lastlogsize;
1273 	result->mtime = mtime;
1274 	result->type |= AR_META;
1275 }
1276 
get_result_ui64_value(AGENT_RESULT * result)1277 static zbx_uint64_t	*get_result_ui64_value(AGENT_RESULT *result)
1278 {
1279 	zbx_uint64_t	value;
1280 
1281 	assert(result);
1282 
1283 	if (0 != ISSET_UI64(result))
1284 	{
1285 		/* nothing to do */
1286 	}
1287 	else if (0 != ISSET_DBL(result))
1288 	{
1289 		SET_UI64_RESULT(result, result->dbl);
1290 	}
1291 	else if (0 != ISSET_STR(result))
1292 	{
1293 		zbx_trim_integer(result->str);
1294 		del_zeros(result->str);
1295 
1296 		if (SUCCEED != is_uint64(result->str, &value))
1297 			return NULL;
1298 
1299 		SET_UI64_RESULT(result, value);
1300 	}
1301 	else if (0 != ISSET_TEXT(result))
1302 	{
1303 		zbx_trim_integer(result->text);
1304 		del_zeros(result->text);
1305 
1306 		if (SUCCEED != is_uint64(result->text, &value))
1307 			return NULL;
1308 
1309 		SET_UI64_RESULT(result, value);
1310 	}
1311 	/* skip AR_MESSAGE - it is information field */
1312 
1313 	if (0 != ISSET_UI64(result))
1314 		return &result->ui64;
1315 
1316 	return NULL;
1317 }
1318 
get_result_dbl_value(AGENT_RESULT * result)1319 static double	*get_result_dbl_value(AGENT_RESULT *result)
1320 {
1321 	double	value;
1322 
1323 	assert(result);
1324 
1325 	if (0 != ISSET_DBL(result))
1326 	{
1327 		/* nothing to do */
1328 	}
1329 	else if (0 != ISSET_UI64(result))
1330 	{
1331 		SET_DBL_RESULT(result, result->ui64);
1332 	}
1333 	else if (0 != ISSET_STR(result))
1334 	{
1335 		zbx_trim_float(result->str);
1336 
1337 		if (SUCCEED != is_double(result->str, &value))
1338 			return NULL;
1339 
1340 		SET_DBL_RESULT(result, value);
1341 	}
1342 	else if (0 != ISSET_TEXT(result))
1343 	{
1344 		zbx_trim_float(result->text);
1345 
1346 		if (SUCCEED != is_double(result->text, &value))
1347 			return NULL;
1348 
1349 		SET_DBL_RESULT(result, value);
1350 	}
1351 	/* skip AR_MESSAGE - it is information field */
1352 
1353 	if (0 != ISSET_DBL(result))
1354 		return &result->dbl;
1355 
1356 	return NULL;
1357 }
1358 
get_result_str_value(AGENT_RESULT * result)1359 static char	**get_result_str_value(AGENT_RESULT *result)
1360 {
1361 	char	*p, tmp;
1362 
1363 	assert(result);
1364 
1365 	if (0 != ISSET_STR(result))
1366 	{
1367 		/* nothing to do */
1368 	}
1369 	else if (0 != ISSET_TEXT(result))
1370 	{
1371 		/* NOTE: copy only line */
1372 		for (p = result->text; '\0' != *p && '\r' != *p && '\n' != *p; p++);
1373 		tmp = *p; /* remember result->text character */
1374 		*p = '\0'; /* replace to NUL */
1375 		SET_STR_RESULT(result, zbx_strdup(NULL, result->text)); /* copy line */
1376 		*p = tmp; /* restore result->text character */
1377 	}
1378 	else if (0 != ISSET_UI64(result))
1379 	{
1380 		SET_STR_RESULT(result, zbx_dsprintf(NULL, ZBX_FS_UI64, result->ui64));
1381 	}
1382 	else if (0 != ISSET_DBL(result))
1383 	{
1384 		SET_STR_RESULT(result, zbx_dsprintf(NULL, ZBX_FS_DBL, result->dbl));
1385 	}
1386 	/* skip AR_MESSAGE - it is information field */
1387 
1388 	if (0 != ISSET_STR(result))
1389 		return &result->str;
1390 
1391 	return NULL;
1392 }
1393 
get_result_text_value(AGENT_RESULT * result)1394 static char	**get_result_text_value(AGENT_RESULT *result)
1395 {
1396 	assert(result);
1397 
1398 	if (0 != ISSET_TEXT(result))
1399 	{
1400 		/* nothing to do */
1401 	}
1402 	else if (0 != ISSET_STR(result))
1403 	{
1404 		SET_TEXT_RESULT(result, zbx_strdup(NULL, result->str));
1405 	}
1406 	else if (0 != ISSET_UI64(result))
1407 	{
1408 		SET_TEXT_RESULT(result, zbx_dsprintf(NULL, ZBX_FS_UI64, result->ui64));
1409 	}
1410 	else if (0 != ISSET_DBL(result))
1411 	{
1412 		SET_TEXT_RESULT(result, zbx_dsprintf(NULL, ZBX_FS_DBL, result->dbl));
1413 	}
1414 	/* skip AR_MESSAGE - it is information field */
1415 
1416 	if (0 != ISSET_TEXT(result))
1417 		return &result->text;
1418 
1419 	return NULL;
1420 }
1421 
get_result_log_value(AGENT_RESULT * result)1422 static zbx_log_t	*get_result_log_value(AGENT_RESULT *result)
1423 {
1424 	if (0 != ISSET_LOG(result))
1425 		return result->log;
1426 
1427 	if (0 != ISSET_VALUE(result))
1428 	{
1429 		result->log = (zbx_log_t *)zbx_malloc(result->log, sizeof(zbx_log_t));
1430 
1431 		zbx_log_init(result->log);
1432 
1433 		if (0 != ISSET_STR(result))
1434 			result->log->value = zbx_strdup(result->log->value, result->str);
1435 		else if (0 != ISSET_TEXT(result))
1436 			result->log->value = zbx_strdup(result->log->value, result->text);
1437 		else if (0 != ISSET_UI64(result))
1438 			result->log->value = zbx_dsprintf(result->log->value, ZBX_FS_UI64, result->ui64);
1439 		else if (0 != ISSET_DBL(result))
1440 			result->log->value = zbx_dsprintf(result->log->value, ZBX_FS_DBL, result->dbl);
1441 
1442 		result->type |= AR_LOG;
1443 
1444 		return result->log;
1445 	}
1446 
1447 	return NULL;
1448 }
1449 
1450 /******************************************************************************
1451  *                                                                            *
1452  * Function: get_result_value_by_type                                         *
1453  *                                                                            *
1454  * Purpose: return value of result in special type                            *
1455  *          if value missing, convert existing value to requested type        *
1456  *                                                                            *
1457  * Return value:                                                              *
1458  *         NULL - if value is missing or can't be converted                   *
1459  *                                                                            *
1460  * Author: Eugene Grigorjev                                                   *
1461  *                                                                            *
1462  * Comments:  better use definitions                                          *
1463  *                GET_UI64_RESULT                                             *
1464  *                GET_DBL_RESULT                                              *
1465  *                GET_STR_RESULT                                              *
1466  *                GET_TEXT_RESULT                                             *
1467  *                GET_LOG_RESULT                                              *
1468  *                GET_MSG_RESULT                                              *
1469  *                                                                            *
1470  *    AR_MESSAGE - skipped in conversion                                      *
1471  *                                                                            *
1472  ******************************************************************************/
get_result_value_by_type(AGENT_RESULT * result,int require_type)1473 void	*get_result_value_by_type(AGENT_RESULT *result, int require_type)
1474 {
1475 	assert(result);
1476 
1477 	switch (require_type)
1478 	{
1479 		case AR_UINT64:
1480 			return (void *)get_result_ui64_value(result);
1481 		case AR_DOUBLE:
1482 			return (void *)get_result_dbl_value(result);
1483 		case AR_STRING:
1484 			return (void *)get_result_str_value(result);
1485 		case AR_TEXT:
1486 			return (void *)get_result_text_value(result);
1487 		case AR_LOG:
1488 			return (void *)get_result_log_value(result);
1489 		case AR_MESSAGE:
1490 			if (0 != ISSET_MSG(result))
1491 				return (void *)(&result->msg);
1492 			break;
1493 		default:
1494 			break;
1495 	}
1496 
1497 	return NULL;
1498 }
1499 
1500 /******************************************************************************
1501  *                                                                            *
1502  * Function: unquote_key_param                                                *
1503  *                                                                            *
1504  * Purpose: unquotes special symbols in item key parameter                    *
1505  *                                                                            *
1506  * Parameters: param - [IN/OUT] item key parameter                            *
1507  *                                                                            *
1508  * Comments:                                                                  *
1509  *   "param"     => param                                                     *
1510  *   "\"param\"" => "param"                                                   *
1511  *                                                                            *
1512  ******************************************************************************/
unquote_key_param(char * param)1513 void	unquote_key_param(char *param)
1514 {
1515 	char	*dst;
1516 
1517 	if ('"' != *param)
1518 		return;
1519 
1520 	for (dst = param++; '\0' != *param; param++)
1521 	{
1522 		if ('\\' == *param && '"' == param[1])
1523 			continue;
1524 
1525 		*dst++ = *param;
1526 	}
1527 	*--dst = '\0';
1528 }
1529 
1530 /******************************************************************************
1531  *                                                                            *
1532  * Function: quote_key_param                                                  *
1533  *                                                                            *
1534  * Purpose: quotes special symbols in item key parameter                      *
1535  *                                                                            *
1536  * Parameters: param   - [IN/OUT] item key parameter                          *
1537  *             forced  - [IN] 1 - enclose parameter in " even if it does not  *
1538  *                                contain any special characters              *
1539  *                            0 - do nothing if the parameter does not        *
1540  *                                contain any special characters              *
1541  *                                                                            *
1542  * Return value: SUCCEED - if parameter was successfully quoted or quoting    *
1543  *                         was not necessary                                  *
1544  *               FAIL    - if parameter needs to but cannot be quoted due to  *
1545  *                         backslash in the end                               *
1546  *                                                                            *
1547  ******************************************************************************/
quote_key_param(char ** param,int forced)1548 int	quote_key_param(char **param, int forced)
1549 {
1550 	size_t	sz_src, sz_dst;
1551 
1552 	if (0 == forced)
1553 	{
1554 		if ('"' != **param && ' ' != **param && '[' != **param && NULL == strchr(*param, ',') &&
1555 				NULL == strchr(*param, ']'))
1556 		{
1557 			return SUCCEED;
1558 		}
1559 	}
1560 
1561 	if (0 != (sz_src = strlen(*param)) && '\\' == (*param)[sz_src - 1])
1562 		return FAIL;
1563 
1564 	sz_dst = zbx_get_escape_string_len(*param, "\"") + 3;
1565 
1566 	*param = (char *)zbx_realloc(*param, sz_dst);
1567 
1568 	(*param)[--sz_dst] = '\0';
1569 	(*param)[--sz_dst] = '"';
1570 
1571 	while (0 < sz_src)
1572 	{
1573 		(*param)[--sz_dst] = (*param)[--sz_src];
1574 		if ('"' == (*param)[sz_src])
1575 			(*param)[--sz_dst] = '\\';
1576 	}
1577 	(*param)[--sz_dst] = '"';
1578 
1579 	return SUCCEED;
1580 }
1581 
1582 #ifdef HAVE_KSTAT_H
get_kstat_numeric_value(const kstat_named_t * kn)1583 zbx_uint64_t	get_kstat_numeric_value(const kstat_named_t *kn)
1584 {
1585 	switch (kn->data_type)
1586 	{
1587 		case KSTAT_DATA_INT32:
1588 			return kn->value.i32;
1589 		case KSTAT_DATA_UINT32:
1590 			return kn->value.ui32;
1591 		case KSTAT_DATA_INT64:
1592 			return kn->value.i64;
1593 		case KSTAT_DATA_UINT64:
1594 			return kn->value.ui64;
1595 		default:
1596 			THIS_SHOULD_NEVER_HAPPEN;
1597 			return 0;
1598 	}
1599 }
1600 #endif
1601 
1602 #if !defined(_WINDOWS) && !defined(__MINGW32__)
1603 #if defined(WITH_AGENT2_METRICS)
zbx_execute_threaded_metric(zbx_metric_func_t metric_func,AGENT_REQUEST * request,AGENT_RESULT * result)1604 int	zbx_execute_threaded_metric(zbx_metric_func_t metric_func, AGENT_REQUEST *request, AGENT_RESULT *result)
1605 {
1606 	/* calling fork() in a multithreaded program may result in deadlock on mutex */
1607 	return metric_func(request, result);
1608 }
1609 #else
1610 /******************************************************************************
1611  *                                                                            *
1612  * Function: serialize_agent_result                                           *
1613  *                                                                            *
1614  * Purpose: serialize agent result to transfer over pipe/socket               *
1615  *                                                                            *
1616  * Parameters: data        - [IN/OUT] the data buffer                         *
1617  *             data_alloc  - [IN/OUT] the data buffer allocated size          *
1618  *             data_offset - [IN/OUT] the data buffer data size               *
1619  *             agent_ret   - [IN] the agent result return code                *
1620  *             result      - [IN] the agent result                            *
1621  *                                                                            *
1622  * Comments: The agent result is serialized as [rc][type][data] where:        *
1623  *             [rc] the agent result return code, 4 bytes                     *
1624  *             [type] the agent result data type, 1 byte                      *
1625  *             [data] the agent result data, null terminated string (optional)*
1626  *                                                                            *
1627  ******************************************************************************/
serialize_agent_result(char ** data,size_t * data_alloc,size_t * data_offset,int agent_ret,AGENT_RESULT * result)1628 static void	serialize_agent_result(char **data, size_t *data_alloc, size_t *data_offset, int agent_ret,
1629 		AGENT_RESULT *result)
1630 {
1631 	char	**pvalue, result_type;
1632 	size_t	value_len;
1633 
1634 	if (SYSINFO_RET_OK == agent_ret)
1635 	{
1636 		if (ISSET_TEXT(result))
1637 			result_type = 't';
1638 		else if (ISSET_STR(result))
1639 			result_type = 's';
1640 		else if (ISSET_UI64(result))
1641 			result_type = 'u';
1642 		else if (ISSET_DBL(result))
1643 			result_type = 'd';
1644 		else if (ISSET_MSG(result))
1645 			result_type = 'm';
1646 		else
1647 			result_type = '-';
1648 	}
1649 	else
1650 		result_type = 'm';
1651 
1652 	switch (result_type)
1653 	{
1654 		case 't':
1655 		case 's':
1656 		case 'u':
1657 		case 'd':
1658 			pvalue = GET_TEXT_RESULT(result);
1659 			break;
1660 		case 'm':
1661 			pvalue = GET_MSG_RESULT(result);
1662 			break;
1663 		default:
1664 			pvalue = NULL;
1665 	}
1666 
1667 	if (NULL != pvalue)
1668 	{
1669 		value_len = strlen(*pvalue) + 1;
1670 	}
1671 	else
1672 	{
1673 		value_len = 0;
1674 		result_type = '-';
1675 	}
1676 
1677 	if (*data_alloc - *data_offset < value_len + 1 + sizeof(int))
1678 	{
1679 		while (*data_alloc - *data_offset < value_len + 1 + sizeof(int))
1680 			*data_alloc *= 1.5;
1681 
1682 		*data = (char *)zbx_realloc(*data, *data_alloc);
1683 	}
1684 
1685 	memcpy(*data + *data_offset, &agent_ret, sizeof(int));
1686 	*data_offset += sizeof(int);
1687 
1688 	(*data)[(*data_offset)++] = result_type;
1689 
1690 	if ('-' != result_type)
1691 	{
1692 		memcpy(*data + *data_offset, *pvalue, value_len);
1693 		*data_offset += value_len;
1694 	}
1695 }
1696 
1697 /******************************************************************************
1698  *                                                                            *
1699  * Function: deserialize_agent_result                                         *
1700  *                                                                            *
1701  * Purpose: deserialize agent result                                          *
1702  *                                                                            *
1703  * Parameters: data        - [IN] the data to deserialize                     *
1704  *             result      - [OUT] the agent result                           *
1705  *                                                                            *
1706  * Return value: the agent result return code (SYSINFO_RET_*)                 *
1707  *                                                                            *
1708  ******************************************************************************/
deserialize_agent_result(char * data,AGENT_RESULT * result)1709 static int	deserialize_agent_result(char *data, AGENT_RESULT *result)
1710 {
1711 	int	ret, agent_ret;
1712 	char	type;
1713 
1714 	memcpy(&agent_ret, data, sizeof(int));
1715 	data += sizeof(int);
1716 
1717 	type = *data++;
1718 
1719 	if ('m' == type || 0 == strcmp(data, ZBX_NOTSUPPORTED))
1720 	{
1721 		SET_MSG_RESULT(result, zbx_strdup(NULL, data));
1722 		return agent_ret;
1723 	}
1724 
1725 	switch (type)
1726 	{
1727 		case 't':
1728 			ret = set_result_type(result, ITEM_VALUE_TYPE_TEXT, data);
1729 			break;
1730 		case 's':
1731 			ret = set_result_type(result, ITEM_VALUE_TYPE_STR, data);
1732 			break;
1733 		case 'u':
1734 			ret = set_result_type(result, ITEM_VALUE_TYPE_UINT64, data);
1735 			break;
1736 		case 'd':
1737 			ret = set_result_type(result, ITEM_VALUE_TYPE_FLOAT, data);
1738 			break;
1739 		default:
1740 			ret = SUCCEED;
1741 	}
1742 
1743 	/* return deserialized return code or SYSINFO_RET_FAIL if setting result data failed */
1744 	return (FAIL == ret ? SYSINFO_RET_FAIL : agent_ret);
1745 }
1746 
1747 /******************************************************************************
1748  *                                                                            *
1749  * Function: write_all                                                        *
1750  *                                                                            *
1751  * Purpose: call write in a loop, iterating until all the data is written.    *
1752  *                                                                            *
1753  * Parameters: fd      - [IN] descriptor                                      *
1754  *             buf     - [IN] buffer to write                                 *
1755  *             n       - [IN] bytes count to write                            *
1756  *                                                                            *
1757  * Return value: SUCCEED - n bytes successfully written                       *
1758  *               FAIL    - less than n bytes are written                      *
1759  *                                                                            *
1760  ******************************************************************************/
write_all(int fd,const char * buf,size_t n)1761 static int	write_all(int fd, const char *buf, size_t n)
1762 {
1763 	ssize_t	ret;
1764 
1765 	while (0 < n)
1766 	{
1767 		if (-1 != (ret = write(fd, buf, n)))
1768 		{
1769 			buf += ret;
1770 			n -= ret;
1771 		}
1772 		else if (EINTR != errno)
1773 			return FAIL;
1774 	}
1775 
1776 	return SUCCEED;
1777 }
1778 
1779 /******************************************************************************
1780  *                                                                            *
1781  * Function: zbx_execute_threaded_metric                                      *
1782  *                                                                            *
1783  * Purpose: execute metric in a separate process/thread so it can be          *
1784  *          killed/terminated when timeout is detected                        *
1785  *                                                                            *
1786  * Parameters: metric_func - [IN] the metric function to execute              *
1787  *             ...                the metric function parameters              *
1788  *                                                                            *
1789  * Return value:                                                              *
1790  *         SYSINFO_RET_OK - the metric was executed successfully              *
1791  *         SYSINFO_RET_FAIL - otherwise                                       *
1792  *                                                                            *
1793  ******************************************************************************/
zbx_execute_threaded_metric(zbx_metric_func_t metric_func,AGENT_REQUEST * request,AGENT_RESULT * result)1794 int	zbx_execute_threaded_metric(zbx_metric_func_t metric_func, AGENT_REQUEST *request, AGENT_RESULT *result)
1795 {
1796 	int	ret = SYSINFO_RET_OK;
1797 	pid_t	pid;
1798 	int	fds[2], n, status;
1799 	char	buffer[MAX_STRING_LEN], *data;
1800 	size_t	data_alloc = MAX_STRING_LEN, data_offset = 0;
1801 
1802 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() key:'%s'", __func__, request->key);
1803 
1804 	if (-1 == pipe(fds))
1805 	{
1806 		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot create data pipe: %s", strerror_from_system(errno)));
1807 		ret = SYSINFO_RET_FAIL;
1808 		goto out;
1809 	}
1810 
1811 	if (-1 == (pid = zbx_fork()))
1812 	{
1813 		close(fds[0]);
1814 		close(fds[1]);
1815 		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot fork data process: %s", strerror_from_system(errno)));
1816 		ret = SYSINFO_RET_FAIL;
1817 		goto out;
1818 	}
1819 
1820 	data = (char *)zbx_malloc(NULL, data_alloc);
1821 
1822 	if (0 == pid)
1823 	{
1824 		zabbix_log(LOG_LEVEL_DEBUG, "executing in data process for key:'%s'", request->key);
1825 
1826 		zbx_set_metric_thread_signal_handler();
1827 
1828 		close(fds[0]);
1829 
1830 		ret = metric_func(request, result);
1831 		serialize_agent_result(&data, &data_alloc, &data_offset, ret, result);
1832 
1833 		ret = write_all(fds[1], data, data_offset);
1834 
1835 		zbx_free(data);
1836 		free_result(result);
1837 
1838 		close(fds[1]);
1839 
1840 		exit(SUCCEED == ret ? EXIT_SUCCESS : EXIT_FAILURE);
1841 	}
1842 
1843 	close(fds[1]);
1844 
1845 	zbx_alarm_on(CONFIG_TIMEOUT);
1846 
1847 	while (0 != (n = read(fds[0], buffer, sizeof(buffer))))
1848 	{
1849 		if (SUCCEED == zbx_alarm_timed_out())
1850 		{
1851 			SET_MSG_RESULT(result, zbx_strdup(NULL, "Timeout while waiting for data."));
1852 			kill(pid, SIGKILL);
1853 			ret = SYSINFO_RET_FAIL;
1854 			break;
1855 		}
1856 
1857 		if (-1 == n)
1858 		{
1859 			SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Error while reading data: %s", zbx_strerror(errno)));
1860 			kill(pid, SIGKILL);
1861 			ret = SYSINFO_RET_FAIL;
1862 			break;
1863 		}
1864 
1865 		if ((int)(data_alloc - data_offset) < n + 1)
1866 		{
1867 			while ((int)(data_alloc - data_offset) < n + 1)
1868 				data_alloc *= 1.5;
1869 
1870 			data = (char *)zbx_realloc(data, data_alloc);
1871 		}
1872 
1873 		memcpy(data + data_offset, buffer, n);
1874 		data_offset += n;
1875 		data[data_offset] = '\0';
1876 	}
1877 
1878 	zbx_alarm_off();
1879 
1880 	close(fds[0]);
1881 
1882 	while (-1 == waitpid(pid, &status, 0))
1883 	{
1884 		if (EINTR != errno)
1885 		{
1886 			zabbix_log(LOG_LEVEL_ERR, "failed to wait on child processes: %s", zbx_strerror(errno));
1887 			ret = SYSINFO_RET_FAIL;
1888 			break;
1889 		}
1890 	}
1891 
1892 	if (SYSINFO_RET_OK == ret)
1893 	{
1894 		if (0 == WIFEXITED(status))
1895 		{
1896 			SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Data gathering process terminated unexpectedly with"
1897 					" error %d.", status));
1898 			kill(pid, SIGKILL);
1899 			ret = SYSINFO_RET_FAIL;
1900 		}
1901 		else if (EXIT_SUCCESS != WEXITSTATUS(status))
1902 		{
1903 			SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Data gathering process terminated with error %d.",
1904 					status));
1905 			ret = SYSINFO_RET_FAIL;
1906 		}
1907 		else
1908 			ret = deserialize_agent_result(data, result);
1909 	}
1910 
1911 	zbx_free(data);
1912 out:
1913 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s '%s'", __func__, zbx_sysinfo_ret_string(ret),
1914 			ISSET_MSG(result) ? result->msg : "");
1915 	return ret;
1916 }
1917 #endif
1918 #else
1919 
1920 static ZBX_THREAD_LOCAL zbx_uint32_t	mutex_flag = ZBX_MUTEX_ALL_ALLOW;
1921 
get_thread_global_mutex_flag()1922 zbx_uint32_t get_thread_global_mutex_flag()
1923 {
1924 	return mutex_flag;
1925 }
1926 
1927 typedef struct
1928 {
1929 	zbx_metric_func_t	func;
1930 	AGENT_REQUEST		*request;
1931 	AGENT_RESULT		*result;
1932 	zbx_uint32_t		mutex_flag; /* in regular case should always be = ZBX_MUTEX_ALL_ALLOW */
1933 	HANDLE			timeout_event;
1934 	int			agent_ret;
1935 }
1936 zbx_metric_thread_args_t;
1937 
ZBX_THREAD_ENTRY(agent_metric_thread,data)1938 ZBX_THREAD_ENTRY(agent_metric_thread, data)
1939 {
1940 	zbx_metric_thread_args_t	*args = (zbx_metric_thread_args_t *)((zbx_thread_args_t *)data)->args;
1941 	mutex_flag = args->mutex_flag;
1942 
1943 	zabbix_log(LOG_LEVEL_DEBUG, "executing in data thread for key:'%s'", args->request->key);
1944 
1945 	if (SYSINFO_RET_FAIL == (args->agent_ret = args->func(args->request, args->result, args->timeout_event)))
1946 	{
1947 		if (NULL == GET_MSG_RESULT(args->result))
1948 			SET_MSG_RESULT(args->result, zbx_strdup(NULL, ZBX_NOTSUPPORTED));
1949 	}
1950 
1951 	zbx_thread_exit(0);
1952 }
1953 
1954 /******************************************************************************
1955  *                                                                            *
1956  * Function: zbx_execute_threaded_metric                                      *
1957  *                                                                            *
1958  * Purpose: execute metric in a separate process/thread so it can be          *
1959  *          killed/terminated when timeout is detected                        *
1960  *                                                                            *
1961  * Parameters: metric_func - [IN] the metric function to execute              *
1962  *             ...                the metric function parameters              *
1963  *                                                                            *
1964  * Return value:                                                              *
1965  *         SYSINFO_RET_OK - the metric was executed successfully              *
1966  *         SYSINFO_RET_FAIL - otherwise                                       *
1967  *                                                                            *
1968  ******************************************************************************/
zbx_execute_threaded_metric(zbx_metric_func_t metric_func,AGENT_REQUEST * request,AGENT_RESULT * result)1969 int	zbx_execute_threaded_metric(zbx_metric_func_t metric_func, AGENT_REQUEST *request, AGENT_RESULT *result)
1970 {
1971 	ZBX_THREAD_HANDLE		thread;
1972 	zbx_thread_args_t		thread_args;
1973 	zbx_metric_thread_args_t	metric_args = {metric_func, request, result, ZBX_MUTEX_THREAD_DENIED |
1974 							ZBX_MUTEX_LOGGING_DENIED};
1975 	DWORD				rc;
1976 	BOOL				terminate_thread = FALSE;
1977 
1978 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() key:'%s'", __func__, request->key);
1979 
1980 	if (NULL == (metric_args.timeout_event = CreateEvent(NULL, TRUE, FALSE, NULL)))
1981 	{
1982 		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot create timeout event for data thread: %s",
1983 				strerror_from_system(GetLastError())));
1984 		return SYSINFO_RET_FAIL;
1985 	}
1986 
1987 	thread_args.args = (void *)&metric_args;
1988 
1989 	zbx_thread_start(agent_metric_thread, &thread_args, &thread);
1990 
1991 	if (ZBX_THREAD_ERROR == thread)
1992 	{
1993 		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot start data thread: %s",
1994 				strerror_from_system(GetLastError())));
1995 		CloseHandle(metric_args.timeout_event);
1996 		return SYSINFO_RET_FAIL;
1997 	}
1998 
1999 	/* 1000 is multiplier for converting seconds into milliseconds */
2000 	if (WAIT_FAILED == (rc = WaitForSingleObject(thread, CONFIG_TIMEOUT * 1000)))
2001 	{
2002 		/* unexpected error */
2003 
2004 		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot wait for data: %s",
2005 				strerror_from_system(GetLastError())));
2006 		terminate_thread = TRUE;
2007 	}
2008 	else if (WAIT_TIMEOUT == rc)
2009 	{
2010 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Timeout while waiting for data."));
2011 
2012 		/* timeout; notify thread to clean up and exit, if stuck then terminate it */
2013 
2014 		if (FALSE == SetEvent(metric_args.timeout_event))
2015 		{
2016 			zabbix_log(LOG_LEVEL_ERR, "SetEvent() failed: %s", strerror_from_system(GetLastError()));
2017 			terminate_thread = TRUE;
2018 		}
2019 		else
2020 		{
2021 			DWORD	timeout_rc = WaitForSingleObject(thread, 3000);	/* wait up to 3 seconds */
2022 
2023 			if (WAIT_FAILED == timeout_rc)
2024 			{
2025 				zabbix_log(LOG_LEVEL_ERR, "Waiting for data failed: %s",
2026 						strerror_from_system(GetLastError()));
2027 				terminate_thread = TRUE;
2028 			}
2029 			else if (WAIT_TIMEOUT == timeout_rc)
2030 			{
2031 				zabbix_log(LOG_LEVEL_ERR, "Stuck data thread");
2032 				terminate_thread = TRUE;
2033 			}
2034 			/* timeout_rc must be WAIT_OBJECT_0 (signaled) */
2035 		}
2036 	}
2037 
2038 	if (TRUE == terminate_thread)
2039 	{
2040 		if (FALSE != TerminateThread(thread, 0))
2041 		{
2042 			zabbix_log(LOG_LEVEL_ERR, "%s(): TerminateThread() for %s[%s%s] succeeded", __func__,
2043 					request->key, (0 < request->nparam) ? request->params[0] : "",
2044 					(1 < request->nparam) ? ",..." : "");
2045 		}
2046 		else
2047 		{
2048 			zabbix_log(LOG_LEVEL_ERR, "%s(): TerminateThread() for %s[%s%s] failed: %s", __func__,
2049 					request->key, (0 < request->nparam) ? request->params[0] : "",
2050 					(1 < request->nparam) ? ",..." : "",
2051 					strerror_from_system(GetLastError()));
2052 		}
2053 	}
2054 
2055 	CloseHandle(thread);
2056 	CloseHandle(metric_args.timeout_event);
2057 
2058 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s '%s'", __func__,
2059 			zbx_sysinfo_ret_string(metric_args.agent_ret), ISSET_MSG(result) ? result->msg : "");
2060 
2061 	return WAIT_OBJECT_0 == rc ? metric_args.agent_ret : SYSINFO_RET_FAIL;
2062 }
2063 #endif
2064 
2065 /******************************************************************************
2066  *                                                                            *
2067  * Function: zbx_mpoints_free                                                 *
2068  *                                                                            *
2069  * Purpose: frees previously allocated mount-point structure                  *
2070  *                                                                            *
2071  * Parameters: mpoint - [IN] pointer to structure from vector                 *
2072  *                                                                            *
2073  * Return value:                                                              *
2074  *                                                                            *
2075  ******************************************************************************/
zbx_mpoints_free(zbx_mpoint_t * mpoint)2076 void	zbx_mpoints_free(zbx_mpoint_t *mpoint)
2077 {
2078 	zbx_free(mpoint);
2079 }
2080 
2081 #ifndef _WINDOWS
hostname_handle_params(AGENT_REQUEST * request,AGENT_RESULT * result,char * hostname)2082 int	hostname_handle_params(AGENT_REQUEST *request, AGENT_RESULT *result, char *hostname)
2083 {
2084 	char	*type, *transform;
2085 
2086 	type = get_rparam(request, 0);
2087 	transform = get_rparam(request, 1);
2088 
2089 	if (NULL != type && '\0' != *type && 0 != strcmp(type, "host"))
2090 	{
2091 		if (0 == strcmp(type, "shorthost"))
2092 		{
2093 			char	*dot;
2094 
2095 			if (NULL != (dot = strchr(hostname, '.')))
2096 				*dot = '\0';
2097 		}
2098 		else if (0 == strcmp(type, "netbios"))
2099 		{
2100 			SET_MSG_RESULT(result, zbx_strdup(NULL, "NetBIOS is not supported on the current platform."));
2101 			return FAIL;
2102 		}
2103 		else
2104 		{
2105 			SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid first parameter."));
2106 			return FAIL;
2107 		}
2108 	}
2109 
2110 	if (NULL != transform && '\0' != *transform && 0 != strcmp(transform, "none"))
2111 	{
2112 		if (0 == strcmp(transform, "lower"))
2113 		{
2114 			zbx_strlower(hostname);
2115 		}
2116 		else
2117 		{
2118 			SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid second parameter."));
2119 			return FAIL;
2120 		}
2121 	}
2122 
2123 	SET_STR_RESULT(result, hostname);
2124 
2125 	return SUCCEED;
2126 }
2127 #endif
2128