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