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, ¶m_alloc, ¶m_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(¶meters_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(¶meters_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(¶meters_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(¶meters_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(¶meters_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(¶meters_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(¶meter_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, ¶ms))
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, ¶meters, 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