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