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 "zbxserver.h"
21 #include "evalfunc.h"
22 #include "log.h"
23 #include "zbxregexp.h"
24 #include "zbxvariant.h"
25 #include "zbxeval.h"
26
27 #include "valuecache.h"
28 #include "macrofunc.h"
29 #ifdef HAVE_LIBXML2
30 # include <libxml/parser.h>
31 # include <libxml/xpath.h>
32 # include <libxml/xmlerror.h>
33
34 typedef struct
35 {
36 char *buf;
37 size_t len;
38 }
39 zbx_libxml_error_t;
40 #endif
41
42 #include "expression.h"
43
44 /* The following definitions are used to identify the request field */
45 /* for various value getters grouped by their scope: */
46
47 /* DBget_item_value(), get_interface_value() */
48 #define ZBX_REQUEST_HOST_IP 1
49 #define ZBX_REQUEST_HOST_DNS 2
50 #define ZBX_REQUEST_HOST_CONN 3
51 #define ZBX_REQUEST_HOST_PORT 4
52
53 /* DBget_history_log_value() */
54 #define ZBX_REQUEST_ITEM_LOG_DATE 201
55 #define ZBX_REQUEST_ITEM_LOG_TIME 202
56 #define ZBX_REQUEST_ITEM_LOG_AGE 203
57 #define ZBX_REQUEST_ITEM_LOG_SOURCE 204
58 #define ZBX_REQUEST_ITEM_LOG_SEVERITY 205
59 #define ZBX_REQUEST_ITEM_LOG_NSEVERITY 206
60 #define ZBX_REQUEST_ITEM_LOG_EVENTID 207
61
62 static int substitute_simple_macros_impl(const zbx_uint64_t *actionid, const DB_EVENT *event,
63 const DB_EVENT *r_event, const zbx_uint64_t *userid, const zbx_uint64_t *hostid, const DC_HOST *dc_host,
64 const DC_ITEM *dc_item, const DB_ALERT *alert, const DB_ACKNOWLEDGE *ack, const char *tz, char **data,
65 int macro_type, char *error, int maxerrlen);
66
67 static int substitute_key_macros_impl(char **data, zbx_uint64_t *hostid, DC_ITEM *dc_item,
68 const struct zbx_json_parse *jp_row, const zbx_vector_ptr_t *lld_macro_paths, int macro_type,
69 char *error, size_t maxerrlen);
70
71 /******************************************************************************
72 * *
73 * Function: get_trigger_severity_name *
74 * *
75 * Purpose: get trigger severity name *
76 * *
77 * Parameters: trigger - [IN] a trigger data with priority field; *
78 * TRIGGER_SEVERITY_* *
79 * replace_to - [OUT] pointer to a buffer that will receive *
80 * a null-terminated trigger severity string *
81 * *
82 * Return value: upon successful completion return SUCCEED *
83 * otherwise FAIL *
84 * *
85 ******************************************************************************/
get_trigger_severity_name(unsigned char priority,char ** replace_to)86 static int get_trigger_severity_name(unsigned char priority, char **replace_to)
87 {
88 zbx_config_t cfg;
89
90 if (TRIGGER_SEVERITY_COUNT <= priority)
91 return FAIL;
92
93 zbx_config_get(&cfg, ZBX_CONFIG_FLAGS_SEVERITY_NAME);
94
95 *replace_to = zbx_strdup(*replace_to, cfg.severity_name[priority]);
96
97 zbx_config_clean(&cfg);
98
99 return SUCCEED;
100 }
101
102 /******************************************************************************
103 * *
104 * Function: get_problem_update_actions *
105 * *
106 * Purpose: get human readable list of problem update actions *
107 * *
108 * Parameters: ack - [IN] the acknowledge (problem update) data *
109 * actions - [IN] the required action flags *
110 * out - [OUT] the output buffer *
111 * *
112 * Return value: SUCCEED - successfully returned list of problem update *
113 * FAIL - no matching actions were made *
114 * *
115 ******************************************************************************/
get_problem_update_actions(const DB_ACKNOWLEDGE * ack,int actions,char ** out)116 static int get_problem_update_actions(const DB_ACKNOWLEDGE *ack, int actions, char **out)
117 {
118 const char *prefixes[] = {"", ", ", ", ", ", ", ", "};
119 char *buf = NULL;
120 size_t buf_alloc = 0, buf_offset = 0;
121 int i, index, flags;
122
123 if (0 == (flags = ack->action & actions))
124 return FAIL;
125
126 for (i = 0, index = 0; i < ZBX_PROBLEM_UPDATE_ACTION_COUNT; i++)
127 {
128 if (0 != (flags & (1 << i)))
129 index++;
130 }
131
132 if (1 < index)
133 prefixes[index - 1] = " and ";
134
135 index = 0;
136
137 if (0 != (flags & ZBX_PROBLEM_UPDATE_ACKNOWLEDGE))
138 {
139 zbx_strcpy_alloc(&buf, &buf_alloc, &buf_offset, "acknowledged");
140 index++;
141 }
142
143 if (0 != (flags & ZBX_PROBLEM_UPDATE_UNACKNOWLEDGE))
144 {
145 zbx_strcpy_alloc(&buf, &buf_alloc, &buf_offset, prefixes[index++]);
146 zbx_strcpy_alloc(&buf, &buf_alloc, &buf_offset, "unacknowledged");
147 }
148
149 if (0 != (flags & ZBX_PROBLEM_UPDATE_MESSAGE))
150 {
151 zbx_strcpy_alloc(&buf, &buf_alloc, &buf_offset, prefixes[index++]);
152 zbx_strcpy_alloc(&buf, &buf_alloc, &buf_offset, "commented");
153 }
154
155 if (0 != (flags & ZBX_PROBLEM_UPDATE_SEVERITY))
156 {
157 zbx_config_t cfg;
158 const char *from = "unknown", *to = "unknown";
159
160 zbx_config_get(&cfg, ZBX_CONFIG_FLAGS_SEVERITY_NAME);
161
162 if (TRIGGER_SEVERITY_COUNT > ack->old_severity && 0 <= ack->old_severity)
163 from = cfg.severity_name[ack->old_severity];
164
165 if (TRIGGER_SEVERITY_COUNT > ack->new_severity && 0 <= ack->new_severity)
166 to = cfg.severity_name[ack->new_severity];
167
168 zbx_strcpy_alloc(&buf, &buf_alloc, &buf_offset, prefixes[index++]);
169 zbx_snprintf_alloc(&buf, &buf_alloc, &buf_offset, "changed severity from %s to %s",
170 from, to);
171
172 zbx_config_clean(&cfg);
173 }
174
175 if (0 != (flags & ZBX_PROBLEM_UPDATE_CLOSE))
176 {
177 zbx_strcpy_alloc(&buf, &buf_alloc, &buf_offset, prefixes[index++]);
178 zbx_strcpy_alloc(&buf, &buf_alloc, &buf_offset, "closed");
179 }
180
181 zbx_free(*out);
182 *out = buf;
183
184 return SUCCEED;
185 }
186
187 /******************************************************************************
188 * *
189 * Function: item_description *
190 * *
191 * Purpose: substitute key parameters and user macros in *
192 * the item description string with real values *
193 * *
194 ******************************************************************************/
item_description(char ** data,const char * key,zbx_uint64_t hostid)195 static void item_description(char **data, const char *key, zbx_uint64_t hostid)
196 {
197 AGENT_REQUEST request;
198 const char *param;
199 char c, *p, *m, *n, *str_out = NULL, *replace_to = NULL;
200 int macro_r, context_l, context_r;
201
202 init_request(&request);
203
204 if (SUCCEED != parse_item_key(key, &request))
205 goto out;
206
207 p = *data;
208
209 while (NULL != (m = strchr(p, '$')))
210 {
211 if (m > p && '{' == *(m - 1) && FAIL != zbx_user_macro_parse(m - 1, ¯o_r, &context_l, &context_r,
212 NULL))
213 {
214 /* user macros */
215
216 n = m + macro_r;
217 c = *n;
218 *n = '\0';
219 DCget_user_macro(&hostid, 1, m - 1, &replace_to);
220
221 if (NULL != replace_to)
222 {
223 *(m - 1) = '\0';
224 str_out = zbx_strdcat(str_out, p);
225 *(m - 1) = '{';
226
227 str_out = zbx_strdcat(str_out, replace_to);
228 zbx_free(replace_to);
229 }
230 else
231 str_out = zbx_strdcat(str_out, p);
232
233 *n = c;
234 p = n;
235 }
236 else if ('1' <= *(m + 1) && *(m + 1) <= '9')
237 {
238 /* macros $1, $2, ... */
239
240 *m = '\0';
241 str_out = zbx_strdcat(str_out, p);
242 *m++ = '$';
243
244 if (NULL != (param = get_rparam(&request, *m - '0' - 1)))
245 str_out = zbx_strdcat(str_out, param);
246
247 p = m + 1;
248 }
249 else
250 {
251 /* just a dollar sign */
252
253 c = *++m;
254 *m = '\0';
255 str_out = zbx_strdcat(str_out, p);
256 *m = c;
257 p = m;
258 }
259 }
260
261 if (NULL != str_out)
262 {
263 str_out = zbx_strdcat(str_out, p);
264 zbx_free(*data);
265 *data = str_out;
266 }
267 out:
268 free_request(&request);
269 }
270
271 /******************************************************************************
272 * *
273 * Function: DBget_host_value *
274 * *
275 * Purpose: request host name by hostid *
276 * *
277 * Return value: upon successful completion return SUCCEED *
278 * otherwise FAIL *
279 * *
280 ******************************************************************************/
DBget_host_value(zbx_uint64_t hostid,char ** replace_to,const char * field_name)281 static int DBget_host_value(zbx_uint64_t hostid, char **replace_to, const char *field_name)
282 {
283 DB_RESULT result;
284 DB_ROW row;
285 int ret = FAIL;
286
287 result = DBselect(
288 "select %s"
289 " from hosts"
290 " where hostid=" ZBX_FS_UI64,
291 field_name, hostid);
292
293 if (NULL != (row = DBfetch(result)))
294 {
295 *replace_to = zbx_strdup(*replace_to, row[0]);
296 ret = SUCCEED;
297 }
298 DBfree_result(result);
299
300 return ret;
301 }
302
303 /******************************************************************************
304 * *
305 * Function: DBget_templateid_by_triggerid *
306 * *
307 * Purpose: get template trigger ID from which the trigger is inherited *
308 * *
309 * Return value: upon successful completion return SUCCEED *
310 * otherwise FAIL *
311 * *
312 ******************************************************************************/
DBget_templateid_by_triggerid(zbx_uint64_t triggerid,zbx_uint64_t * templateid)313 static int DBget_templateid_by_triggerid(zbx_uint64_t triggerid, zbx_uint64_t *templateid)
314 {
315 DB_RESULT result;
316 DB_ROW row;
317 int ret = FAIL;
318
319 result = DBselect(
320 "select templateid"
321 " from triggers"
322 " where triggerid=" ZBX_FS_UI64,
323 triggerid);
324
325 if (NULL != (row = DBfetch(result)))
326 {
327 ZBX_DBROW2UINT64(*templateid, row[0]);
328 ret = SUCCEED;
329 }
330 DBfree_result(result);
331
332 return ret;
333 }
334
335 /******************************************************************************
336 * *
337 * Function: DBget_trigger_template_name *
338 * *
339 * Purpose: get comma-space separated trigger template names in which *
340 * the trigger is defined *
341 * *
342 * Return value: upon successful completion return SUCCEED *
343 * otherwise FAIL *
344 * *
345 * Comments: based on the patch submitted by Hmami Mohamed *
346 * *
347 ******************************************************************************/
DBget_trigger_template_name(zbx_uint64_t triggerid,const zbx_uint64_t * userid,char ** replace_to)348 static int DBget_trigger_template_name(zbx_uint64_t triggerid, const zbx_uint64_t *userid, char **replace_to)
349 {
350 DB_RESULT result;
351 DB_ROW row;
352 int ret = FAIL;
353 zbx_uint64_t templateid;
354 char *sql = NULL;
355 size_t replace_to_alloc = 64, replace_to_offset = 0,
356 sql_alloc = 256, sql_offset = 0;
357 int user_type = -1;
358
359 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
360
361 if (NULL != userid)
362 {
363 result = DBselect("select r.type from users u,role r where u.roleid=r.roleid and"
364 " userid=" ZBX_FS_UI64, *userid);
365
366 if (NULL != (row = DBfetch(result)) && FAIL == DBis_null(row[0]))
367 user_type = atoi(row[0]);
368 DBfree_result(result);
369
370 if (-1 == user_type)
371 {
372 zabbix_log(LOG_LEVEL_DEBUG, "%s() cannot check permissions", __func__);
373 goto out;
374 }
375 }
376
377 /* use parent trigger ID for lld generated triggers */
378 result = DBselect(
379 "select parent_triggerid"
380 " from trigger_discovery"
381 " where triggerid=" ZBX_FS_UI64,
382 triggerid);
383
384 if (NULL != (row = DBfetch(result)))
385 ZBX_STR2UINT64(triggerid, row[0]);
386 DBfree_result(result);
387
388 if (SUCCEED != DBget_templateid_by_triggerid(triggerid, &templateid) || 0 == templateid)
389 {
390 zabbix_log(LOG_LEVEL_DEBUG, "%s() trigger not found or not templated", __func__);
391 goto out;
392 }
393
394 do
395 {
396 triggerid = templateid;
397 }
398 while (SUCCEED == (ret = DBget_templateid_by_triggerid(triggerid, &templateid)) && 0 != templateid);
399
400 if (SUCCEED != ret)
401 {
402 zabbix_log(LOG_LEVEL_DEBUG, "%s() trigger not found", __func__);
403 goto out;
404 }
405
406 *replace_to = (char *)zbx_realloc(*replace_to, replace_to_alloc);
407 **replace_to = '\0';
408
409 sql = (char *)zbx_malloc(sql, sql_alloc);
410
411 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
412 "select distinct h.name"
413 " from hosts h,items i,functions f"
414 " where h.hostid=i.hostid"
415 " and i.itemid=f.itemid"
416 " and f.triggerid=" ZBX_FS_UI64,
417 triggerid);
418 if (NULL != userid && USER_TYPE_SUPER_ADMIN != user_type)
419 {
420 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
421 " and exists("
422 "select null"
423 " from hosts_groups hg,rights r,users_groups ug"
424 " where h.hostid=hg.hostid"
425 " and hg.groupid=r.id"
426 " and r.groupid=ug.usrgrpid"
427 " and ug.userid=" ZBX_FS_UI64
428 " group by hg.hostid"
429 " having min(r.permission)>=%d"
430 ")",
431 *userid, PERM_READ);
432 }
433 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " order by h.name");
434
435 result = DBselect("%s", sql);
436
437 zbx_free(sql);
438
439 while (NULL != (row = DBfetch(result)))
440 {
441 if (0 != replace_to_offset)
442 zbx_strcpy_alloc(replace_to, &replace_to_alloc, &replace_to_offset, ", ");
443 zbx_strcpy_alloc(replace_to, &replace_to_alloc, &replace_to_offset, row[0]);
444 }
445 DBfree_result(result);
446 out:
447 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
448
449 return ret;
450 }
451
452 /******************************************************************************
453 * *
454 * Function: DBget_trigger_hostgroup_name *
455 * *
456 * Purpose: get comma-space separated host group names in which the trigger *
457 * is defined *
458 * *
459 * Return value: upon successful completion return SUCCEED *
460 * otherwise FAIL *
461 * *
462 ******************************************************************************/
DBget_trigger_hostgroup_name(zbx_uint64_t triggerid,const zbx_uint64_t * userid,char ** replace_to)463 static int DBget_trigger_hostgroup_name(zbx_uint64_t triggerid, const zbx_uint64_t *userid, char **replace_to)
464 {
465 DB_RESULT result;
466 DB_ROW row;
467 int ret = FAIL;
468 char *sql = NULL;
469 size_t replace_to_alloc = 64, replace_to_offset = 0,
470 sql_alloc = 256, sql_offset = 0;
471 int user_type = -1;
472
473 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
474
475 if (NULL != userid)
476 {
477 result = DBselect("select r.type from users u,role r where u.roleid=r.roleid and"
478 " userid=" ZBX_FS_UI64, *userid);
479
480 if (NULL != (row = DBfetch(result)) && FAIL == DBis_null(row[0]))
481 user_type = atoi(row[0]);
482 DBfree_result(result);
483
484 if (-1 == user_type)
485 {
486 zabbix_log(LOG_LEVEL_DEBUG, "%s() cannot check permissions", __func__);
487 goto out;
488 }
489 }
490
491 *replace_to = (char *)zbx_realloc(*replace_to, replace_to_alloc);
492 **replace_to = '\0';
493
494 sql = (char *)zbx_malloc(sql, sql_alloc);
495
496 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
497 "select distinct g.name"
498 " from hstgrp g,hosts_groups hg,items i,functions f"
499 " where g.groupid=hg.groupid"
500 " and hg.hostid=i.hostid"
501 " and i.itemid=f.itemid"
502 " and f.triggerid=" ZBX_FS_UI64,
503 triggerid);
504 if (NULL != userid && USER_TYPE_SUPER_ADMIN != user_type)
505 {
506 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
507 " and exists("
508 "select null"
509 " from rights r,users_groups ug"
510 " where g.groupid=r.id"
511 " and r.groupid=ug.usrgrpid"
512 " and ug.userid=" ZBX_FS_UI64
513 " group by r.id"
514 " having min(r.permission)>=%d"
515 ")",
516 *userid, PERM_READ);
517 }
518 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " order by g.name");
519
520 result = DBselect("%s", sql);
521
522 zbx_free(sql);
523
524 while (NULL != (row = DBfetch(result)))
525 {
526 if (0 != replace_to_offset)
527 zbx_strcpy_alloc(replace_to, &replace_to_alloc, &replace_to_offset, ", ");
528 zbx_strcpy_alloc(replace_to, &replace_to_alloc, &replace_to_offset, row[0]);
529 ret = SUCCEED;
530 }
531 DBfree_result(result);
532 out:
533 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
534
535 return ret;
536 }
537
538 /******************************************************************************
539 * *
540 * Function: get_interface_value *
541 * *
542 * Purpose: retrieve a particular value associated with the interface *
543 * *
544 * Return value: upon successful completion return SUCCEED *
545 * otherwise FAIL *
546 * *
547 ******************************************************************************/
get_interface_value(zbx_uint64_t hostid,zbx_uint64_t itemid,char ** replace_to,int request)548 static int get_interface_value(zbx_uint64_t hostid, zbx_uint64_t itemid, char **replace_to, int request)
549 {
550 int res;
551 DC_INTERFACE interface;
552
553 if (SUCCEED != (res = DCconfig_get_interface(&interface, hostid, itemid)))
554 return res;
555
556 switch (request)
557 {
558 case ZBX_REQUEST_HOST_IP:
559 *replace_to = zbx_strdup(*replace_to, interface.ip_orig);
560 break;
561 case ZBX_REQUEST_HOST_DNS:
562 *replace_to = zbx_strdup(*replace_to, interface.dns_orig);
563 break;
564 case ZBX_REQUEST_HOST_CONN:
565 *replace_to = zbx_strdup(*replace_to, interface.addr);
566 break;
567 case ZBX_REQUEST_HOST_PORT:
568 *replace_to = zbx_strdup(*replace_to, interface.port_orig);
569 break;
570 default:
571 THIS_SHOULD_NEVER_HAPPEN;
572 res = FAIL;
573 }
574
575 return res;
576 }
577
get_host_value(zbx_uint64_t itemid,char ** replace_to,int request)578 static int get_host_value(zbx_uint64_t itemid, char **replace_to, int request)
579 {
580 int ret;
581 DC_HOST host;
582
583 DCconfig_get_hosts_by_itemids(&host, &itemid, &ret, 1);
584
585 if (FAIL == ret)
586 return FAIL;
587
588 switch (request)
589 {
590 case ZBX_REQUEST_HOST_ID:
591 *replace_to = zbx_dsprintf(*replace_to, ZBX_FS_UI64, host.hostid);
592 break;
593 case ZBX_REQUEST_HOST_HOST:
594 *replace_to = zbx_strdup(*replace_to, host.host);
595 break;
596 case ZBX_REQUEST_HOST_NAME:
597 *replace_to = zbx_strdup(*replace_to, host.name);
598 break;
599 default:
600 THIS_SHOULD_NEVER_HAPPEN;
601 ret = FAIL;
602 }
603
604 return ret;
605 }
606
607 /******************************************************************************
608 * *
609 * Function: zbx_substitute_item_name_macros *
610 * *
611 * Purpose: substitute key macros and use it to substitute item name macros *
612 * if item name is specified *
613 * *
614 * Parameters: dc_item - [IN] item information used in substitution *
615 * name - [IN] optional item name to substitute *
616 * replace_to - [OUT] expanded item name or key if name is absent *
617 * *
618 ******************************************************************************/
zbx_substitute_item_name_macros(DC_ITEM * dc_item,const char * name,char ** replace_to)619 void zbx_substitute_item_name_macros(DC_ITEM *dc_item, const char *name, char **replace_to)
620 {
621 char *key;
622
623 key = zbx_strdup(NULL, dc_item->key_orig);
624 substitute_key_macros_impl(&key, NULL, dc_item, NULL, NULL, MACRO_TYPE_ITEM_KEY, NULL, 0);
625
626 if (NULL != name)
627 {
628 *replace_to = zbx_strdup(*replace_to, name);
629 item_description(replace_to, key, dc_item->host.hostid);
630 zbx_free(key);
631 }
632 else /* ZBX_REQUEST_ITEM_KEY */
633 {
634 zbx_free(*replace_to);
635 *replace_to = key;
636 }
637 }
638
639 /******************************************************************************
640 * *
641 * Function: DBget_item_value *
642 * *
643 * Purpose: retrieve a particular value associated with the item *
644 * *
645 * Return value: upon successful completion return SUCCEED *
646 * otherwise FAIL *
647 * *
648 ******************************************************************************/
DBget_item_value(zbx_uint64_t itemid,char ** replace_to,int request)649 static int DBget_item_value(zbx_uint64_t itemid, char **replace_to, int request)
650 {
651 DB_RESULT result;
652 DB_ROW row;
653 DC_ITEM dc_item;
654 zbx_uint64_t proxy_hostid;
655 int ret = FAIL, errcode;
656
657 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
658
659 switch (request)
660 {
661 case ZBX_REQUEST_HOST_IP:
662 case ZBX_REQUEST_HOST_DNS:
663 case ZBX_REQUEST_HOST_CONN:
664 case ZBX_REQUEST_HOST_PORT:
665 return get_interface_value(0, itemid, replace_to, request);
666 case ZBX_REQUEST_HOST_ID:
667 case ZBX_REQUEST_HOST_HOST:
668 case ZBX_REQUEST_HOST_NAME:
669 return get_host_value(itemid, replace_to, request);
670 }
671
672 result = DBselect(
673 "select h.proxy_hostid,h.description,i.itemid,i.name,i.key_,i.description,i.value_type"
674 " from items i"
675 " join hosts h on h.hostid=i.hostid"
676 " where i.itemid=" ZBX_FS_UI64, itemid);
677
678 if (NULL != (row = DBfetch(result)))
679 {
680 switch (request)
681 {
682 case ZBX_REQUEST_HOST_DESCRIPTION:
683 *replace_to = zbx_strdup(*replace_to, row[1]);
684 ret = SUCCEED;
685 break;
686 case ZBX_REQUEST_ITEM_ID:
687 *replace_to = zbx_strdup(*replace_to, row[2]);
688 ret = SUCCEED;
689 break;
690 case ZBX_REQUEST_ITEM_NAME:
691 DCconfig_get_items_by_itemids(&dc_item, &itemid, &errcode, 1);
692
693 if (SUCCEED == errcode)
694 {
695 zbx_substitute_item_name_macros(&dc_item, row[3], replace_to);
696 ret = SUCCEED;
697 }
698
699 DCconfig_clean_items(&dc_item, &errcode, 1);
700 break;
701 case ZBX_REQUEST_ITEM_KEY:
702 DCconfig_get_items_by_itemids(&dc_item, &itemid, &errcode, 1);
703
704 if (SUCCEED == errcode)
705 {
706 zbx_substitute_item_name_macros(&dc_item, NULL, replace_to);
707 ret = SUCCEED;
708 }
709
710 DCconfig_clean_items(&dc_item, &errcode, 1);
711 break;
712 case ZBX_REQUEST_ITEM_DESCRIPTION:
713 DCconfig_get_items_by_itemids(&dc_item, &itemid, &errcode, 1);
714
715 if (SUCCEED == errcode)
716 {
717 *replace_to = zbx_dc_expand_user_macros(row[5], dc_item.host.hostid);
718 ret = SUCCEED;
719 }
720
721 DCconfig_clean_items(&dc_item, &errcode, 1);
722 break;
723 case ZBX_REQUEST_ITEM_NAME_ORIG:
724 *replace_to = zbx_strdup(*replace_to, row[3]);
725 ret = SUCCEED;
726 break;
727 case ZBX_REQUEST_ITEM_KEY_ORIG:
728 *replace_to = zbx_strdup(*replace_to, row[4]);
729 ret = SUCCEED;
730 break;
731 case ZBX_REQUEST_ITEM_DESCRIPTION_ORIG:
732 *replace_to = zbx_strdup(*replace_to, row[5]);
733 ret = SUCCEED;
734 break;
735 case ZBX_REQUEST_PROXY_NAME:
736 ZBX_DBROW2UINT64(proxy_hostid, row[0]);
737
738 if (0 == proxy_hostid)
739 {
740 *replace_to = zbx_strdup(*replace_to, "");
741 ret = SUCCEED;
742 }
743 else
744 ret = DBget_host_value(proxy_hostid, replace_to, "host");
745 break;
746 case ZBX_REQUEST_PROXY_DESCRIPTION:
747 ZBX_DBROW2UINT64(proxy_hostid, row[0]);
748
749 if (0 == proxy_hostid)
750 {
751 *replace_to = zbx_strdup(*replace_to, "");
752 ret = SUCCEED;
753 }
754 else
755 ret = DBget_host_value(proxy_hostid, replace_to, "description");
756 break;
757 case ZBX_REQUEST_ITEM_VALUETYPE:
758 *replace_to = zbx_strdup(*replace_to, row[6]);
759 ret = SUCCEED;
760 break;
761 }
762 }
763 DBfree_result(result);
764
765 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
766
767 return ret;
768 }
769
770 /******************************************************************************
771 * *
772 * Function: DBget_trigger_value *
773 * *
774 * Purpose: retrieve a particular value associated with the trigger's *
775 * N_functionid'th function *
776 * *
777 * Return value: upon successful completion return SUCCEED *
778 * otherwise FAIL *
779 * *
780 ******************************************************************************/
DBget_trigger_value(const DB_TRIGGER * trigger,char ** replace_to,int N_functionid,int request)781 int DBget_trigger_value(const DB_TRIGGER *trigger, char **replace_to, int N_functionid, int request)
782 {
783 zbx_uint64_t itemid;
784 int ret = FAIL;
785
786 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
787
788 if (SUCCEED == zbx_db_trigger_get_itemid(trigger, N_functionid, &itemid))
789 ret = DBget_item_value(itemid, replace_to, request);
790
791 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
792
793 return ret;
794 }
795
796 /******************************************************************************
797 * *
798 * Function: DBget_trigger_event_count *
799 * *
800 * Purpose: retrieve number of events (acknowledged or unacknowledged) for a *
801 * trigger (in an OK or PROBLEM state) which generated an event *
802 * *
803 * Parameters: triggerid - [IN] trigger identifier from database *
804 * replace_to - [IN/OUT] pointer to result buffer *
805 * problem_only - [IN] selected trigger status: *
806 * 0 - TRIGGER_VALUE_PROBLEM and TRIGGER_VALUE_OK *
807 * 1 - TRIGGER_VALUE_PROBLEM *
808 * acknowledged - [IN] acknowledged event or not *
809 * *
810 * Return value: upon successful completion return SUCCEED *
811 * otherwise FAIL *
812 * *
813 * Author: Alexander Vladishev, Aleksandrs Saveljevs *
814 * *
815 * Comments: *
816 * *
817 ******************************************************************************/
DBget_trigger_event_count(zbx_uint64_t triggerid,char ** replace_to,int problem_only,int acknowledged)818 static int DBget_trigger_event_count(zbx_uint64_t triggerid, char **replace_to, int problem_only, int acknowledged)
819 {
820 DB_RESULT result;
821 DB_ROW row;
822 char value[4];
823 int ret = FAIL;
824
825 if (problem_only)
826 zbx_snprintf(value, sizeof(value), "%d", TRIGGER_VALUE_PROBLEM);
827 else
828 zbx_snprintf(value, sizeof(value), "%d,%d", TRIGGER_VALUE_PROBLEM, TRIGGER_VALUE_OK);
829
830 result = DBselect(
831 "select count(*)"
832 " from events"
833 " where source=%d"
834 " and object=%d"
835 " and objectid=" ZBX_FS_UI64
836 " and value in (%s)"
837 " and acknowledged=%d",
838 EVENT_SOURCE_TRIGGERS,
839 EVENT_OBJECT_TRIGGER,
840 triggerid,
841 value,
842 acknowledged);
843
844 if (NULL != (row = DBfetch(result)))
845 {
846 *replace_to = zbx_strdup(*replace_to, row[0]);
847 ret = SUCCEED;
848 }
849 DBfree_result(result);
850
851 return ret;
852 }
853
854 /******************************************************************************
855 * *
856 * Function: DBget_dhost_value_by_event *
857 * *
858 * Purpose: retrieve discovered host value by event and field name *
859 * *
860 * Parameters: *
861 * *
862 * Return value: upon successful completion return SUCCEED *
863 * otherwise FAIL *
864 * *
865 * Author: Alexander Vladishev *
866 * *
867 * Comments: *
868 * *
869 ******************************************************************************/
DBget_dhost_value_by_event(const DB_EVENT * event,char ** replace_to,const char * fieldname)870 static int DBget_dhost_value_by_event(const DB_EVENT *event, char **replace_to, const char *fieldname)
871 {
872 DB_RESULT result;
873 DB_ROW row;
874 int ret = FAIL;
875 char sql[MAX_STRING_LEN];
876
877 switch (event->object)
878 {
879 case EVENT_OBJECT_DHOST:
880 zbx_snprintf(sql, sizeof(sql),
881 "select %s"
882 " from drules r,dhosts h,dservices s"
883 " where r.druleid=h.druleid"
884 " and h.dhostid=s.dhostid"
885 " and h.dhostid=" ZBX_FS_UI64
886 " order by s.dserviceid",
887 fieldname,
888 event->objectid);
889 break;
890 case EVENT_OBJECT_DSERVICE:
891 zbx_snprintf(sql, sizeof(sql),
892 "select %s"
893 " from drules r,dhosts h,dservices s"
894 " where r.druleid=h.druleid"
895 " and h.dhostid=s.dhostid"
896 " and s.dserviceid=" ZBX_FS_UI64,
897 fieldname,
898 event->objectid);
899 break;
900 default:
901 return ret;
902 }
903
904 result = DBselectN(sql, 1);
905
906 if (NULL != (row = DBfetch(result)))
907 {
908 *replace_to = zbx_strdup(*replace_to, ZBX_NULL2STR(row[0]));
909 ret = SUCCEED;
910 }
911 DBfree_result(result);
912
913 return ret;
914 }
915
916 /******************************************************************************
917 * *
918 * Function: DBget_dchecks_value_by_event *
919 * *
920 * Purpose: retrieve discovery rule check value by event and field name *
921 * *
922 * Return value: upon successful completion return SUCCEED *
923 * otherwise FAIL *
924 * *
925 ******************************************************************************/
DBget_dchecks_value_by_event(const DB_EVENT * event,char ** replace_to,const char * fieldname)926 static int DBget_dchecks_value_by_event(const DB_EVENT *event, char **replace_to, const char *fieldname)
927 {
928 DB_RESULT result;
929 DB_ROW row;
930 int ret = FAIL;
931
932 switch (event->object)
933 {
934 case EVENT_OBJECT_DSERVICE:
935 result = DBselect("select %s from dchecks c,dservices s"
936 " where c.dcheckid=s.dcheckid and s.dserviceid=" ZBX_FS_UI64,
937 fieldname, event->objectid);
938 break;
939 default:
940 return ret;
941 }
942
943 if (NULL != (row = DBfetch(result)) && SUCCEED != DBis_null(row[0]))
944 {
945 *replace_to = zbx_strdup(*replace_to, row[0]);
946 ret = SUCCEED;
947 }
948 DBfree_result(result);
949
950 return ret;
951 }
952
953 /******************************************************************************
954 * *
955 * Function: DBget_dservice_value_by_event *
956 * *
957 * Purpose: retrieve discovered service value by event and field name *
958 * *
959 * Parameters: *
960 * *
961 * Return value: upon successful completion return SUCCEED *
962 * otherwise FAIL *
963 * *
964 * Author: Alexander Vladishev *
965 * *
966 * Comments: *
967 * *
968 ******************************************************************************/
DBget_dservice_value_by_event(const DB_EVENT * event,char ** replace_to,const char * fieldname)969 static int DBget_dservice_value_by_event(const DB_EVENT *event, char **replace_to, const char *fieldname)
970 {
971 DB_RESULT result;
972 DB_ROW row;
973 int ret = FAIL;
974
975 switch (event->object)
976 {
977 case EVENT_OBJECT_DSERVICE:
978 result = DBselect("select %s from dservices s where s.dserviceid=" ZBX_FS_UI64,
979 fieldname, event->objectid);
980 break;
981 default:
982 return ret;
983 }
984
985 if (NULL != (row = DBfetch(result)) && SUCCEED != DBis_null(row[0]))
986 {
987 *replace_to = zbx_strdup(*replace_to, row[0]);
988 ret = SUCCEED;
989 }
990 DBfree_result(result);
991
992 return ret;
993 }
994
995 /******************************************************************************
996 * *
997 * Function: DBget_drule_value_by_event *
998 * *
999 * Purpose: retrieve discovery rule value by event and field name *
1000 * *
1001 * Parameters: *
1002 * *
1003 * Return value: upon successful completion return SUCCEED *
1004 * otherwise FAIL *
1005 * *
1006 * Author: Alexander Vladishev *
1007 * *
1008 * Comments: *
1009 * *
1010 ******************************************************************************/
DBget_drule_value_by_event(const DB_EVENT * event,char ** replace_to,const char * fieldname)1011 static int DBget_drule_value_by_event(const DB_EVENT *event, char **replace_to, const char *fieldname)
1012 {
1013 DB_RESULT result;
1014 DB_ROW row;
1015 int ret = FAIL;
1016
1017 if (EVENT_SOURCE_DISCOVERY != event->source)
1018 return FAIL;
1019
1020 switch (event->object)
1021 {
1022 case EVENT_OBJECT_DHOST:
1023 result = DBselect("select r.%s from drules r,dhosts h"
1024 " where r.druleid=h.druleid and h.dhostid=" ZBX_FS_UI64,
1025 fieldname, event->objectid);
1026 break;
1027 case EVENT_OBJECT_DSERVICE:
1028 result = DBselect("select r.%s from drules r,dhosts h,dservices s"
1029 " where r.druleid=h.druleid and h.dhostid=s.dhostid and s.dserviceid=" ZBX_FS_UI64,
1030 fieldname, event->objectid);
1031 break;
1032 default:
1033 return ret;
1034 }
1035
1036 if (NULL != (row = DBfetch(result)))
1037 {
1038 *replace_to = zbx_strdup(*replace_to, ZBX_NULL2STR(row[0]));
1039 ret = SUCCEED;
1040 }
1041 DBfree_result(result);
1042
1043 return ret;
1044 }
1045
1046 /******************************************************************************
1047 * *
1048 * Function: DBget_history_log_value *
1049 * *
1050 * Purpose: retrieve a particular attribute of a log value *
1051 * *
1052 * Return value: upon successful completion return SUCCEED *
1053 * otherwise FAIL *
1054 * *
1055 ******************************************************************************/
DBget_history_log_value(zbx_uint64_t itemid,char ** replace_to,int request,int clock,int ns,const char * tz)1056 static int DBget_history_log_value(zbx_uint64_t itemid, char **replace_to, int request, int clock, int ns,
1057 const char *tz)
1058 {
1059 DC_ITEM item;
1060 int ret = FAIL, errcode = FAIL;
1061 zbx_timespec_t ts = {clock, ns};
1062 zbx_history_record_t value;
1063
1064 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1065
1066 DCconfig_get_items_by_itemids(&item, &itemid, &errcode, 1);
1067
1068 if (SUCCEED != errcode || ITEM_VALUE_TYPE_LOG != item.value_type)
1069 goto out;
1070
1071 if (SUCCEED != zbx_vc_get_value(itemid, item.value_type, &ts, &value))
1072 goto out;
1073
1074 zbx_vc_flush_stats();
1075
1076 switch (request)
1077 {
1078 case ZBX_REQUEST_ITEM_LOG_DATE:
1079 *replace_to = zbx_strdup(*replace_to, zbx_date2str((time_t)value.value.log->timestamp, tz));
1080 goto success;
1081 case ZBX_REQUEST_ITEM_LOG_TIME:
1082 *replace_to = zbx_strdup(*replace_to, zbx_time2str((time_t)value.value.log->timestamp, tz));
1083 goto success;
1084 case ZBX_REQUEST_ITEM_LOG_AGE:
1085 *replace_to = zbx_strdup(*replace_to, zbx_age2str(time(NULL) - value.value.log->timestamp));
1086 goto success;
1087 }
1088
1089 /* the following attributes are set only for windows eventlog items */
1090 if (0 != strncmp(item.key_orig, "eventlog[", 9))
1091 goto clean;
1092
1093 switch (request)
1094 {
1095 case ZBX_REQUEST_ITEM_LOG_SOURCE:
1096 *replace_to = zbx_strdup(*replace_to, (NULL == value.value.log->source ? "" :
1097 value.value.log->source));
1098 break;
1099 case ZBX_REQUEST_ITEM_LOG_SEVERITY:
1100 *replace_to = zbx_strdup(*replace_to,
1101 zbx_item_logtype_string((unsigned char)value.value.log->severity));
1102 break;
1103 case ZBX_REQUEST_ITEM_LOG_NSEVERITY:
1104 *replace_to = zbx_dsprintf(*replace_to, "%d", value.value.log->severity);
1105 break;
1106 case ZBX_REQUEST_ITEM_LOG_EVENTID:
1107 *replace_to = zbx_dsprintf(*replace_to, "%d", value.value.log->logeventid);
1108 break;
1109 }
1110 success:
1111 ret = SUCCEED;
1112 clean:
1113 zbx_history_record_clear(&value, ITEM_VALUE_TYPE_LOG);
1114 out:
1115 DCconfig_clean_items(&item, &errcode, 1);
1116
1117 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
1118
1119 return ret;
1120 }
1121
1122
1123
1124 /******************************************************************************
1125 * *
1126 * Function: DBitem_get_value *
1127 * *
1128 * Purpose: retrieve item value by item id *
1129 * *
1130 * Parameters: *
1131 * *
1132 * Return value: upon successful completion return SUCCEED *
1133 * otherwise FAIL *
1134 * *
1135 ******************************************************************************/
DBitem_get_value(zbx_uint64_t itemid,char ** lastvalue,int raw,zbx_timespec_t * ts)1136 static int DBitem_get_value(zbx_uint64_t itemid, char **lastvalue, int raw, zbx_timespec_t *ts)
1137 {
1138 DB_RESULT result;
1139 DB_ROW row;
1140 int ret = FAIL;
1141
1142 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1143
1144 result = DBselect(
1145 "select value_type,valuemapid,units"
1146 " from items"
1147 " where itemid=" ZBX_FS_UI64,
1148 itemid);
1149
1150 if (NULL != (row = DBfetch(result)))
1151 {
1152 unsigned char value_type;
1153 zbx_uint64_t valuemapid;
1154 zbx_history_record_t vc_value;
1155
1156 value_type = (unsigned char)atoi(row[0]);
1157 ZBX_DBROW2UINT64(valuemapid, row[1]);
1158
1159 if (SUCCEED == zbx_vc_get_value(itemid, value_type, ts, &vc_value))
1160 {
1161 char tmp[MAX_BUFFER_LEN];
1162
1163 zbx_vc_flush_stats();
1164 zbx_history_value_print(tmp, sizeof(tmp), &vc_value.value, value_type);
1165 zbx_history_record_clear(&vc_value, value_type);
1166
1167 if (0 == raw)
1168 zbx_format_value(tmp, sizeof(tmp), valuemapid, row[2], value_type);
1169
1170 *lastvalue = zbx_strdup(*lastvalue, tmp);
1171
1172 ret = SUCCEED;
1173 }
1174 }
1175 DBfree_result(result);
1176
1177 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
1178
1179 return ret;
1180 }
1181
1182 /******************************************************************************
1183 * *
1184 * Function: DBitem_value *
1185 * *
1186 * Purpose: retrieve item value by trigger expression and number of function *
1187 * *
1188 * Return value: upon successful completion return SUCCEED *
1189 * otherwise FAIL *
1190 * *
1191 ******************************************************************************/
DBitem_value(const DB_TRIGGER * trigger,char ** value,int N_functionid,int clock,int ns,int raw)1192 static int DBitem_value(const DB_TRIGGER *trigger, char **value, int N_functionid, int clock, int ns, int raw)
1193 {
1194 zbx_uint64_t itemid;
1195 zbx_timespec_t ts = {clock, ns};
1196 int ret;
1197
1198 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1199
1200 if (SUCCEED == (ret = zbx_db_trigger_get_itemid(trigger, N_functionid, &itemid)))
1201 ret = DBitem_get_value(itemid, value, raw, &ts);
1202
1203 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
1204
1205 return ret;
1206 }
1207
1208 /******************************************************************************
1209 * *
1210 * Function: DBitem_lastvalue *
1211 * *
1212 * Purpose: retrieve item lastvalue by trigger expression *
1213 * and number of function *
1214 * *
1215 * Parameters: *
1216 * *
1217 * Return value: upon successful completion return SUCCEED *
1218 * otherwise FAIL *
1219 * *
1220 ******************************************************************************/
DBitem_lastvalue(const DB_TRIGGER * trigger,char ** lastvalue,int N_functionid,int raw)1221 static int DBitem_lastvalue(const DB_TRIGGER *trigger, char **lastvalue, int N_functionid, int raw)
1222 {
1223 int ret;
1224
1225 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1226
1227 ret = DBitem_value(trigger, lastvalue, N_functionid, time(NULL), 999999999, raw);
1228
1229 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
1230
1231 return ret;
1232 }
1233
1234 /******************************************************************************
1235 * *
1236 * Function: format_user_fullname *
1237 * *
1238 * Purpose: formats full user name from name, surname and alias *
1239 * *
1240 * Parameters: name - [IN] the user name, can be empty string *
1241 * surname - [IN] the user surname, can be empty string *
1242 * alias - [IN] the user alias *
1243 * *
1244 * Return value: the formatted user fullname *
1245 * *
1246 ******************************************************************************/
format_user_fullname(const char * name,const char * surname,const char * alias)1247 static char *format_user_fullname(const char *name, const char *surname, const char *alias)
1248 {
1249 char *buf = NULL;
1250 size_t buf_alloc = 0, buf_offset = 0;
1251
1252 zbx_strcpy_alloc(&buf, &buf_alloc, &buf_offset, name);
1253
1254 if ('\0' != *surname)
1255 {
1256 if (0 != buf_offset)
1257 zbx_chrcpy_alloc(&buf, &buf_alloc, &buf_offset, ' ');
1258
1259 zbx_strcpy_alloc(&buf, &buf_alloc, &buf_offset, surname);
1260 }
1261
1262 if ('\0' != *alias)
1263 {
1264 size_t offset = buf_offset;
1265
1266 if (0 != buf_offset)
1267 zbx_strcpy_alloc(&buf, &buf_alloc, &buf_offset, " (");
1268
1269 zbx_strcpy_alloc(&buf, &buf_alloc, &buf_offset, alias);
1270
1271 if (0 != offset)
1272 zbx_chrcpy_alloc(&buf, &buf_alloc, &buf_offset, ')');
1273 }
1274
1275 return buf;
1276 }
1277
1278 /******************************************************************************
1279 * *
1280 * Function: get_escalation_history *
1281 * *
1282 * Purpose: retrieve escalation history *
1283 * *
1284 ******************************************************************************/
get_escalation_history(zbx_uint64_t actionid,const DB_EVENT * event,const DB_EVENT * r_event,char ** replace_to,const zbx_uint64_t * recipient_userid,const char * tz)1285 static void get_escalation_history(zbx_uint64_t actionid, const DB_EVENT *event, const DB_EVENT *r_event,
1286 char **replace_to, const zbx_uint64_t *recipient_userid, const char *tz)
1287 {
1288 DB_RESULT result;
1289 DB_ROW row;
1290 char *buf = NULL, *p;
1291 size_t buf_alloc = ZBX_KIBIBYTE, buf_offset = 0;
1292 int esc_step;
1293 unsigned char type, status;
1294 time_t now;
1295 zbx_uint64_t userid;
1296
1297 buf = (char *)zbx_malloc(buf, buf_alloc);
1298
1299 zbx_snprintf_alloc(&buf, &buf_alloc, &buf_offset, "Problem started: %s %s Age: %s\n",
1300 zbx_date2str(event->clock, tz), zbx_time2str(event->clock, tz),
1301 zbx_age2str(time(NULL) - event->clock));
1302
1303 result = DBselect("select a.clock,a.alerttype,a.status,mt.name,a.sendto,a.error,a.esc_step,a.userid,a.message"
1304 " from alerts a"
1305 " left join media_type mt"
1306 " on mt.mediatypeid=a.mediatypeid"
1307 " where a.eventid=" ZBX_FS_UI64
1308 " and a.actionid=" ZBX_FS_UI64
1309 " order by a.clock",
1310 event->eventid, actionid);
1311
1312 while (NULL != (row = DBfetch(result)))
1313 {
1314 int user_permit;
1315
1316 now = atoi(row[0]);
1317 type = (unsigned char)atoi(row[1]);
1318 status = (unsigned char)atoi(row[2]);
1319 esc_step = atoi(row[6]);
1320 ZBX_DBROW2UINT64(userid, row[7]);
1321 user_permit = zbx_check_user_permissions(&userid, recipient_userid);
1322
1323 if (0 != esc_step)
1324 zbx_snprintf_alloc(&buf, &buf_alloc, &buf_offset, "%d. ", esc_step);
1325
1326 zbx_snprintf_alloc(&buf, &buf_alloc, &buf_offset, "%s %s %-7s %-11s",
1327 zbx_date2str(now, tz), zbx_time2str(now, tz), /* date, time */
1328 zbx_alert_type_string(type), /* alert type */
1329 zbx_alert_status_string(type, status)); /* alert status */
1330
1331 if (ALERT_TYPE_COMMAND == type)
1332 {
1333 if (NULL != (p = strchr(row[8], ':')))
1334 {
1335 *p = '\0';
1336 zbx_snprintf_alloc(&buf, &buf_alloc, &buf_offset, " \"%s\"", row[8]); /* host */
1337 *p = ':';
1338 }
1339 }
1340 else
1341 {
1342 const char *media_type_name, *send_to, *user_name;
1343
1344 media_type_name = (SUCCEED == DBis_null(row[3]) ? "" : row[3]);
1345
1346 if (SUCCEED == user_permit)
1347 {
1348 send_to = row[4];
1349 user_name = zbx_user_string(userid);
1350 }
1351 else
1352 {
1353 send_to = "\"Inaccessible recipient details\"";
1354 user_name = "Inaccessible user";
1355 }
1356
1357 zbx_snprintf_alloc(&buf, &buf_alloc, &buf_offset, " %s %s \"%s\"",
1358 media_type_name,
1359 send_to, /* historical recipient */
1360 user_name); /* alert user full name */
1361 }
1362
1363 if (ALERT_STATUS_FAILED == status)
1364 {
1365 /* alert error can be generated by SMTP Relay or other media and contain sensitive details */
1366 if (SUCCEED == user_permit)
1367 zbx_snprintf_alloc(&buf, &buf_alloc, &buf_offset, " %s", row[5]);
1368 else
1369 zbx_strcpy_alloc(&buf, &buf_alloc, &buf_offset, " \"Inaccessible error message\"");
1370 }
1371
1372 zbx_chrcpy_alloc(&buf, &buf_alloc, &buf_offset, '\n');
1373 }
1374 DBfree_result(result);
1375
1376 if (NULL != r_event)
1377 {
1378 zbx_snprintf_alloc(&buf, &buf_alloc, &buf_offset, "Problem ended: %s %s\n",
1379 zbx_date2str(r_event->clock, tz), zbx_time2str(r_event->clock, tz));
1380 }
1381
1382 if (0 != buf_offset)
1383 buf[--buf_offset] = '\0';
1384
1385 *replace_to = buf;
1386 }
1387
1388 /******************************************************************************
1389 * *
1390 * Function: get_event_update_history *
1391 * *
1392 * Purpose: retrieve event acknowledges history *
1393 * *
1394 * Parameters: *
1395 * *
1396 * Author: Alexander Vladishev *
1397 * *
1398 * Comments: *
1399 * *
1400 ******************************************************************************/
get_event_update_history(const DB_EVENT * event,char ** replace_to,const zbx_uint64_t * recipient_userid,const char * tz)1401 static void get_event_update_history(const DB_EVENT *event, char **replace_to, const zbx_uint64_t *recipient_userid,
1402 const char *tz)
1403 {
1404 DB_RESULT result;
1405 DB_ROW row;
1406 char *buf = NULL;
1407 size_t buf_alloc = ZBX_KIBIBYTE, buf_offset = 0;
1408
1409 buf = (char *)zbx_malloc(buf, buf_alloc);
1410 *buf = '\0';
1411
1412 result = DBselect("select clock,userid,message,action,old_severity,new_severity"
1413 " from acknowledges"
1414 " where eventid=" ZBX_FS_UI64 " order by clock",
1415 event->eventid);
1416
1417 while (NULL != (row = DBfetch(result)))
1418 {
1419 const char *user_name;
1420 char *actions = NULL;
1421 DB_ACKNOWLEDGE ack;
1422
1423 ack.clock = atoi(row[0]);
1424 ZBX_STR2UINT64(ack.userid, row[1]);
1425 ack.message = row[2];
1426 ack.acknowledgeid = 0;
1427 ack.action = atoi(row[3]);
1428 ack.old_severity = atoi(row[4]);
1429 ack.new_severity = atoi(row[5]);
1430
1431 if (SUCCEED == zbx_check_user_permissions(&ack.userid, recipient_userid))
1432 user_name = zbx_user_string(ack.userid);
1433 else
1434 user_name = "Inaccessible user";
1435
1436 zbx_snprintf_alloc(&buf, &buf_alloc, &buf_offset,
1437 "%s %s \"%s\"\n",
1438 zbx_date2str(ack.clock, tz),
1439 zbx_time2str(ack.clock, tz),
1440 user_name);
1441
1442 if (SUCCEED == get_problem_update_actions(&ack, ZBX_PROBLEM_UPDATE_ACKNOWLEDGE |
1443 ZBX_PROBLEM_UPDATE_UNACKNOWLEDGE |
1444 ZBX_PROBLEM_UPDATE_CLOSE | ZBX_PROBLEM_UPDATE_SEVERITY, &actions))
1445 {
1446 zbx_snprintf_alloc(&buf, &buf_alloc, &buf_offset, "Actions: %s.\n", actions);
1447 zbx_free(actions);
1448 }
1449
1450 if ('\0' != *ack.message)
1451 zbx_snprintf_alloc(&buf, &buf_alloc, &buf_offset, "%s\n", ack.message);
1452
1453 zbx_chrcpy_alloc(&buf, &buf_alloc, &buf_offset, '\n');
1454 }
1455 DBfree_result(result);
1456
1457 if (0 != buf_offset)
1458 {
1459 buf_offset -= 2;
1460 buf[buf_offset] = '\0';
1461 }
1462
1463 *replace_to = buf;
1464 }
1465
1466 /******************************************************************************
1467 * *
1468 * Function: get_autoreg_value_by_event *
1469 * *
1470 * Purpose: request value from autoreg_host table by event *
1471 * *
1472 * Parameters: *
1473 * *
1474 * Return value: upon successful completion return SUCCEED *
1475 * otherwise FAIL *
1476 * *
1477 * Author: Alexander Vladishev *
1478 * *
1479 * Comments: *
1480 * *
1481 ******************************************************************************/
get_autoreg_value_by_event(const DB_EVENT * event,char ** replace_to,const char * fieldname)1482 static int get_autoreg_value_by_event(const DB_EVENT *event, char **replace_to, const char *fieldname)
1483 {
1484 DB_RESULT result;
1485 DB_ROW row;
1486 int ret = FAIL;
1487
1488 result = DBselect(
1489 "select %s"
1490 " from autoreg_host"
1491 " where autoreg_hostid=" ZBX_FS_UI64, fieldname, event->objectid);
1492
1493 if (NULL != (row = DBfetch(result)))
1494 {
1495 *replace_to = zbx_strdup(*replace_to, ZBX_NULL2STR(row[0]));
1496 ret = SUCCEED;
1497 }
1498 DBfree_result(result);
1499
1500 return ret;
1501 }
1502
1503 #define MVAR_ACTION "{ACTION." /* a prefix for all action macros */
1504 #define MVAR_ACTION_ID MVAR_ACTION "ID}"
1505 #define MVAR_ACTION_NAME MVAR_ACTION "NAME}"
1506 #define MVAR_DATE "{DATE}"
1507 #define MVAR_EVENT "{EVENT." /* a prefix for all event macros */
1508 #define MVAR_EVENT_ACK_HISTORY MVAR_EVENT "ACK.HISTORY}" /* deprecated */
1509 #define MVAR_EVENT_ACK_STATUS MVAR_EVENT "ACK.STATUS}"
1510 #define MVAR_EVENT_AGE MVAR_EVENT "AGE}"
1511 #define MVAR_EVENT_DATE MVAR_EVENT "DATE}"
1512 #define MVAR_EVENT_DURATION MVAR_EVENT "DURATION}"
1513 #define MVAR_EVENT_ID MVAR_EVENT "ID}"
1514 #define MVAR_EVENT_NAME MVAR_EVENT "NAME}"
1515 #define MVAR_EVENT_STATUS MVAR_EVENT "STATUS}"
1516 #define MVAR_EVENT_TAGS MVAR_EVENT "TAGS}"
1517 #define MVAR_EVENT_TAGSJSON MVAR_EVENT "TAGSJSON}"
1518 #define MVAR_EVENT_TAGS_PREFIX MVAR_EVENT "TAGS."
1519 #define MVAR_EVENT_TIME MVAR_EVENT "TIME}"
1520 #define MVAR_EVENT_VALUE MVAR_EVENT "VALUE}"
1521 #define MVAR_EVENT_SEVERITY MVAR_EVENT "SEVERITY}"
1522 #define MVAR_EVENT_NSEVERITY MVAR_EVENT "NSEVERITY}"
1523 #define MVAR_EVENT_OBJECT MVAR_EVENT "OBJECT}"
1524 #define MVAR_EVENT_SOURCE MVAR_EVENT "SOURCE}"
1525 #define MVAR_EVENT_OPDATA MVAR_EVENT "OPDATA}"
1526 #define MVAR_EVENT_RECOVERY MVAR_EVENT "RECOVERY." /* a prefix for all recovery event macros */
1527 #define MVAR_EVENT_RECOVERY_DATE MVAR_EVENT_RECOVERY "DATE}"
1528 #define MVAR_EVENT_RECOVERY_ID MVAR_EVENT_RECOVERY "ID}"
1529 #define MVAR_EVENT_RECOVERY_STATUS MVAR_EVENT_RECOVERY "STATUS}" /* deprecated */
1530 #define MVAR_EVENT_RECOVERY_TAGS MVAR_EVENT_RECOVERY "TAGS}"
1531 #define MVAR_EVENT_RECOVERY_TAGSJSON MVAR_EVENT_RECOVERY "TAGSJSON}"
1532 #define MVAR_EVENT_RECOVERY_TIME MVAR_EVENT_RECOVERY "TIME}"
1533 #define MVAR_EVENT_RECOVERY_VALUE MVAR_EVENT_RECOVERY "VALUE}" /* deprecated */
1534 #define MVAR_EVENT_RECOVERY_NAME MVAR_EVENT_RECOVERY "NAME}"
1535 #define MVAR_EVENT_UPDATE MVAR_EVENT "UPDATE."
1536 #define MVAR_EVENT_UPDATE_ACTION MVAR_EVENT_UPDATE "ACTION}"
1537 #define MVAR_EVENT_UPDATE_DATE MVAR_EVENT_UPDATE "DATE}"
1538 #define MVAR_EVENT_UPDATE_HISTORY MVAR_EVENT_UPDATE "HISTORY}"
1539 #define MVAR_EVENT_UPDATE_MESSAGE MVAR_EVENT_UPDATE "MESSAGE}"
1540 #define MVAR_EVENT_UPDATE_TIME MVAR_EVENT_UPDATE "TIME}"
1541 #define MVAR_EVENT_UPDATE_STATUS MVAR_EVENT_UPDATE "STATUS}"
1542
1543 #define MVAR_ESC_HISTORY "{ESC.HISTORY}"
1544 #define MVAR_PROXY_NAME "{PROXY.NAME}"
1545 #define MVAR_PROXY_DESCRIPTION "{PROXY.DESCRIPTION}"
1546 #define MVAR_HOST_DNS "{HOST.DNS}"
1547 #define MVAR_HOST_CONN "{HOST.CONN}"
1548 #define MVAR_HOST_HOST "{HOST.HOST}"
1549 #define MVAR_HOST_ID "{HOST.ID}"
1550 #define MVAR_HOST_IP "{HOST.IP}"
1551 #define MVAR_IPADDRESS "{IPADDRESS}" /* deprecated */
1552 #define MVAR_HOST_METADATA "{HOST.METADATA}"
1553 #define MVAR_HOST_NAME "{HOST.NAME}"
1554 #define MVAR_HOSTNAME "{HOSTNAME}" /* deprecated */
1555 #define MVAR_HOST_DESCRIPTION "{HOST.DESCRIPTION}"
1556 #define MVAR_HOST_PORT "{HOST.PORT}"
1557 #define MVAR_HOST_TARGET_DNS "{HOST.TARGET.DNS}"
1558 #define MVAR_HOST_TARGET_CONN "{HOST.TARGET.CONN}"
1559 #define MVAR_HOST_TARGET_HOST "{HOST.TARGET.HOST}"
1560 #define MVAR_HOST_TARGET_IP "{HOST.TARGET.IP}"
1561 #define MVAR_HOST_TARGET_NAME "{HOST.TARGET.NAME}"
1562 #define MVAR_TIME "{TIME}"
1563 #define MVAR_ITEM_LASTVALUE "{ITEM.LASTVALUE}"
1564 #define MVAR_ITEM_VALUE "{ITEM.VALUE}"
1565 #define MVAR_ITEM_VALUETYPE "{ITEM.VALUETYPE}"
1566 #define MVAR_ITEM_ID "{ITEM.ID}"
1567 #define MVAR_ITEM_NAME "{ITEM.NAME}"
1568 #define MVAR_ITEM_NAME_ORIG "{ITEM.NAME.ORIG}"
1569 #define MVAR_ITEM_KEY "{ITEM.KEY}"
1570 #define MVAR_ITEM_KEY_ORIG "{ITEM.KEY.ORIG}"
1571 #define MVAR_ITEM_STATE "{ITEM.STATE}"
1572 #define MVAR_TRIGGER_KEY "{TRIGGER.KEY}" /* deprecated */
1573 #define MVAR_ITEM_DESCRIPTION "{ITEM.DESCRIPTION}"
1574 #define MVAR_ITEM_DESCRIPTION_ORIG "{ITEM.DESCRIPTION.ORIG}"
1575 #define MVAR_ITEM_LOG "{ITEM.LOG."
1576 #define MVAR_ITEM_LOG_DATE MVAR_ITEM_LOG "DATE}"
1577 #define MVAR_ITEM_LOG_TIME MVAR_ITEM_LOG "TIME}"
1578 #define MVAR_ITEM_LOG_AGE MVAR_ITEM_LOG "AGE}"
1579 #define MVAR_ITEM_LOG_SOURCE MVAR_ITEM_LOG "SOURCE}"
1580 #define MVAR_ITEM_LOG_SEVERITY MVAR_ITEM_LOG "SEVERITY}"
1581 #define MVAR_ITEM_LOG_NSEVERITY MVAR_ITEM_LOG "NSEVERITY}"
1582 #define MVAR_ITEM_LOG_EVENTID MVAR_ITEM_LOG "EVENTID}"
1583
1584 #define MVAR_TRIGGER_DESCRIPTION "{TRIGGER.DESCRIPTION}"
1585 #define MVAR_TRIGGER_COMMENT "{TRIGGER.COMMENT}" /* deprecated */
1586 #define MVAR_TRIGGER_ID "{TRIGGER.ID}"
1587 #define MVAR_TRIGGER_NAME "{TRIGGER.NAME}"
1588 #define MVAR_TRIGGER_NAME_ORIG "{TRIGGER.NAME.ORIG}"
1589 #define MVAR_TRIGGER_EXPRESSION "{TRIGGER.EXPRESSION}"
1590 #define MVAR_TRIGGER_EXPRESSION_RECOVERY "{TRIGGER.EXPRESSION.RECOVERY}"
1591 #define MVAR_TRIGGER_SEVERITY "{TRIGGER.SEVERITY}"
1592 #define MVAR_TRIGGER_NSEVERITY "{TRIGGER.NSEVERITY}"
1593 #define MVAR_TRIGGER_STATUS "{TRIGGER.STATUS}"
1594 #define MVAR_TRIGGER_STATE "{TRIGGER.STATE}"
1595 #define MVAR_TRIGGER_TEMPLATE_NAME "{TRIGGER.TEMPLATE.NAME}"
1596 #define MVAR_TRIGGER_HOSTGROUP_NAME "{TRIGGER.HOSTGROUP.NAME}"
1597 #define MVAR_STATUS "{STATUS}" /* deprecated */
1598 #define MVAR_TRIGGER_VALUE "{TRIGGER.VALUE}"
1599 #define MVAR_TRIGGER_URL "{TRIGGER.URL}"
1600
1601 #define MVAR_TRIGGER_EVENTS_ACK "{TRIGGER.EVENTS.ACK}"
1602 #define MVAR_TRIGGER_EVENTS_UNACK "{TRIGGER.EVENTS.UNACK}"
1603 #define MVAR_TRIGGER_EVENTS_PROBLEM_ACK "{TRIGGER.EVENTS.PROBLEM.ACK}"
1604 #define MVAR_TRIGGER_EVENTS_PROBLEM_UNACK "{TRIGGER.EVENTS.PROBLEM.UNACK}"
1605
1606 #define MVAR_LLDRULE_DESCRIPTION "{LLDRULE.DESCRIPTION}"
1607 #define MVAR_LLDRULE_DESCRIPTION_ORIG "{LLDRULE.DESCRIPTION.ORIG}"
1608 #define MVAR_LLDRULE_ID "{LLDRULE.ID}"
1609 #define MVAR_LLDRULE_KEY "{LLDRULE.KEY}"
1610 #define MVAR_LLDRULE_KEY_ORIG "{LLDRULE.KEY.ORIG}"
1611 #define MVAR_LLDRULE_NAME "{LLDRULE.NAME}"
1612 #define MVAR_LLDRULE_NAME_ORIG "{LLDRULE.NAME.ORIG}"
1613 #define MVAR_LLDRULE_STATE "{LLDRULE.STATE}"
1614
1615 #define MVAR_INVENTORY "{INVENTORY." /* a prefix for all inventory macros */
1616 #define MVAR_INVENTORY_TYPE MVAR_INVENTORY "TYPE}"
1617 #define MVAR_INVENTORY_TYPE_FULL MVAR_INVENTORY "TYPE.FULL}"
1618 #define MVAR_INVENTORY_NAME MVAR_INVENTORY "NAME}"
1619 #define MVAR_INVENTORY_ALIAS MVAR_INVENTORY "ALIAS}"
1620 #define MVAR_INVENTORY_OS MVAR_INVENTORY "OS}"
1621 #define MVAR_INVENTORY_OS_FULL MVAR_INVENTORY "OS.FULL}"
1622 #define MVAR_INVENTORY_OS_SHORT MVAR_INVENTORY "OS.SHORT}"
1623 #define MVAR_INVENTORY_SERIALNO_A MVAR_INVENTORY "SERIALNO.A}"
1624 #define MVAR_INVENTORY_SERIALNO_B MVAR_INVENTORY "SERIALNO.B}"
1625 #define MVAR_INVENTORY_TAG MVAR_INVENTORY "TAG}"
1626 #define MVAR_INVENTORY_ASSET_TAG MVAR_INVENTORY "ASSET.TAG}"
1627 #define MVAR_INVENTORY_MACADDRESS_A MVAR_INVENTORY "MACADDRESS.A}"
1628 #define MVAR_INVENTORY_MACADDRESS_B MVAR_INVENTORY "MACADDRESS.B}"
1629 #define MVAR_INVENTORY_HARDWARE MVAR_INVENTORY "HARDWARE}"
1630 #define MVAR_INVENTORY_HARDWARE_FULL MVAR_INVENTORY "HARDWARE.FULL}"
1631 #define MVAR_INVENTORY_SOFTWARE MVAR_INVENTORY "SOFTWARE}"
1632 #define MVAR_INVENTORY_SOFTWARE_FULL MVAR_INVENTORY "SOFTWARE.FULL}"
1633 #define MVAR_INVENTORY_SOFTWARE_APP_A MVAR_INVENTORY "SOFTWARE.APP.A}"
1634 #define MVAR_INVENTORY_SOFTWARE_APP_B MVAR_INVENTORY "SOFTWARE.APP.B}"
1635 #define MVAR_INVENTORY_SOFTWARE_APP_C MVAR_INVENTORY "SOFTWARE.APP.C}"
1636 #define MVAR_INVENTORY_SOFTWARE_APP_D MVAR_INVENTORY "SOFTWARE.APP.D}"
1637 #define MVAR_INVENTORY_SOFTWARE_APP_E MVAR_INVENTORY "SOFTWARE.APP.E}"
1638 #define MVAR_INVENTORY_CONTACT MVAR_INVENTORY "CONTACT}"
1639 #define MVAR_INVENTORY_LOCATION MVAR_INVENTORY "LOCATION}"
1640 #define MVAR_INVENTORY_LOCATION_LAT MVAR_INVENTORY "LOCATION.LAT}"
1641 #define MVAR_INVENTORY_LOCATION_LON MVAR_INVENTORY "LOCATION.LON}"
1642 #define MVAR_INVENTORY_NOTES MVAR_INVENTORY "NOTES}"
1643 #define MVAR_INVENTORY_CHASSIS MVAR_INVENTORY "CHASSIS}"
1644 #define MVAR_INVENTORY_MODEL MVAR_INVENTORY "MODEL}"
1645 #define MVAR_INVENTORY_HW_ARCH MVAR_INVENTORY "HW.ARCH}"
1646 #define MVAR_INVENTORY_VENDOR MVAR_INVENTORY "VENDOR}"
1647 #define MVAR_INVENTORY_CONTRACT_NUMBER MVAR_INVENTORY "CONTRACT.NUMBER}"
1648 #define MVAR_INVENTORY_INSTALLER_NAME MVAR_INVENTORY "INSTALLER.NAME}"
1649 #define MVAR_INVENTORY_DEPLOYMENT_STATUS MVAR_INVENTORY "DEPLOYMENT.STATUS}"
1650 #define MVAR_INVENTORY_URL_A MVAR_INVENTORY "URL.A}"
1651 #define MVAR_INVENTORY_URL_B MVAR_INVENTORY "URL.B}"
1652 #define MVAR_INVENTORY_URL_C MVAR_INVENTORY "URL.C}"
1653 #define MVAR_INVENTORY_HOST_NETWORKS MVAR_INVENTORY "HOST.NETWORKS}"
1654 #define MVAR_INVENTORY_HOST_NETMASK MVAR_INVENTORY "HOST.NETMASK}"
1655 #define MVAR_INVENTORY_HOST_ROUTER MVAR_INVENTORY "HOST.ROUTER}"
1656 #define MVAR_INVENTORY_OOB_IP MVAR_INVENTORY "OOB.IP}"
1657 #define MVAR_INVENTORY_OOB_NETMASK MVAR_INVENTORY "OOB.NETMASK}"
1658 #define MVAR_INVENTORY_OOB_ROUTER MVAR_INVENTORY "OOB.ROUTER}"
1659 #define MVAR_INVENTORY_HW_DATE_PURCHASE MVAR_INVENTORY "HW.DATE.PURCHASE}"
1660 #define MVAR_INVENTORY_HW_DATE_INSTALL MVAR_INVENTORY "HW.DATE.INSTALL}"
1661 #define MVAR_INVENTORY_HW_DATE_EXPIRY MVAR_INVENTORY "HW.DATE.EXPIRY}"
1662 #define MVAR_INVENTORY_HW_DATE_DECOMM MVAR_INVENTORY "HW.DATE.DECOMM}"
1663 #define MVAR_INVENTORY_SITE_ADDRESS_A MVAR_INVENTORY "SITE.ADDRESS.A}"
1664 #define MVAR_INVENTORY_SITE_ADDRESS_B MVAR_INVENTORY "SITE.ADDRESS.B}"
1665 #define MVAR_INVENTORY_SITE_ADDRESS_C MVAR_INVENTORY "SITE.ADDRESS.C}"
1666 #define MVAR_INVENTORY_SITE_CITY MVAR_INVENTORY "SITE.CITY}"
1667 #define MVAR_INVENTORY_SITE_STATE MVAR_INVENTORY "SITE.STATE}"
1668 #define MVAR_INVENTORY_SITE_COUNTRY MVAR_INVENTORY "SITE.COUNTRY}"
1669 #define MVAR_INVENTORY_SITE_ZIP MVAR_INVENTORY "SITE.ZIP}"
1670 #define MVAR_INVENTORY_SITE_RACK MVAR_INVENTORY "SITE.RACK}"
1671 #define MVAR_INVENTORY_SITE_NOTES MVAR_INVENTORY "SITE.NOTES}"
1672 #define MVAR_INVENTORY_POC_PRIMARY_NAME MVAR_INVENTORY "POC.PRIMARY.NAME}"
1673 #define MVAR_INVENTORY_POC_PRIMARY_EMAIL MVAR_INVENTORY "POC.PRIMARY.EMAIL}"
1674 #define MVAR_INVENTORY_POC_PRIMARY_PHONE_A MVAR_INVENTORY "POC.PRIMARY.PHONE.A}"
1675 #define MVAR_INVENTORY_POC_PRIMARY_PHONE_B MVAR_INVENTORY "POC.PRIMARY.PHONE.B}"
1676 #define MVAR_INVENTORY_POC_PRIMARY_CELL MVAR_INVENTORY "POC.PRIMARY.CELL}"
1677 #define MVAR_INVENTORY_POC_PRIMARY_SCREEN MVAR_INVENTORY "POC.PRIMARY.SCREEN}"
1678 #define MVAR_INVENTORY_POC_PRIMARY_NOTES MVAR_INVENTORY "POC.PRIMARY.NOTES}"
1679 #define MVAR_INVENTORY_POC_SECONDARY_NAME MVAR_INVENTORY "POC.SECONDARY.NAME}"
1680 #define MVAR_INVENTORY_POC_SECONDARY_EMAIL MVAR_INVENTORY "POC.SECONDARY.EMAIL}"
1681 #define MVAR_INVENTORY_POC_SECONDARY_PHONE_A MVAR_INVENTORY "POC.SECONDARY.PHONE.A}"
1682 #define MVAR_INVENTORY_POC_SECONDARY_PHONE_B MVAR_INVENTORY "POC.SECONDARY.PHONE.B}"
1683 #define MVAR_INVENTORY_POC_SECONDARY_CELL MVAR_INVENTORY "POC.SECONDARY.CELL}"
1684 #define MVAR_INVENTORY_POC_SECONDARY_SCREEN MVAR_INVENTORY "POC.SECONDARY.SCREEN}"
1685 #define MVAR_INVENTORY_POC_SECONDARY_NOTES MVAR_INVENTORY "POC.SECONDARY.NOTES}"
1686
1687 /* PROFILE.* is deprecated, use INVENTORY.* instead */
1688 #define MVAR_PROFILE "{PROFILE." /* prefix for profile macros */
1689 #define MVAR_PROFILE_DEVICETYPE MVAR_PROFILE "DEVICETYPE}"
1690 #define MVAR_PROFILE_NAME MVAR_PROFILE "NAME}"
1691 #define MVAR_PROFILE_OS MVAR_PROFILE "OS}"
1692 #define MVAR_PROFILE_SERIALNO MVAR_PROFILE "SERIALNO}"
1693 #define MVAR_PROFILE_TAG MVAR_PROFILE "TAG}"
1694 #define MVAR_PROFILE_MACADDRESS MVAR_PROFILE "MACADDRESS}"
1695 #define MVAR_PROFILE_HARDWARE MVAR_PROFILE "HARDWARE}"
1696 #define MVAR_PROFILE_SOFTWARE MVAR_PROFILE "SOFTWARE}"
1697 #define MVAR_PROFILE_CONTACT MVAR_PROFILE "CONTACT}"
1698 #define MVAR_PROFILE_LOCATION MVAR_PROFILE "LOCATION}"
1699 #define MVAR_PROFILE_NOTES MVAR_PROFILE "NOTES}"
1700
1701 #define MVAR_DISCOVERY_RULE_NAME "{DISCOVERY.RULE.NAME}"
1702 #define MVAR_DISCOVERY_SERVICE_NAME "{DISCOVERY.SERVICE.NAME}"
1703 #define MVAR_DISCOVERY_SERVICE_PORT "{DISCOVERY.SERVICE.PORT}"
1704 #define MVAR_DISCOVERY_SERVICE_STATUS "{DISCOVERY.SERVICE.STATUS}"
1705 #define MVAR_DISCOVERY_SERVICE_UPTIME "{DISCOVERY.SERVICE.UPTIME}"
1706 #define MVAR_DISCOVERY_DEVICE_IPADDRESS "{DISCOVERY.DEVICE.IPADDRESS}"
1707 #define MVAR_DISCOVERY_DEVICE_DNS "{DISCOVERY.DEVICE.DNS}"
1708 #define MVAR_DISCOVERY_DEVICE_STATUS "{DISCOVERY.DEVICE.STATUS}"
1709 #define MVAR_DISCOVERY_DEVICE_UPTIME "{DISCOVERY.DEVICE.UPTIME}"
1710
1711 #define MVAR_ALERT_SENDTO "{ALERT.SENDTO}"
1712 #define MVAR_ALERT_SUBJECT "{ALERT.SUBJECT}"
1713 #define MVAR_ALERT_MESSAGE "{ALERT.MESSAGE}"
1714
1715 #define MVAR_ACK_MESSAGE "{ACK.MESSAGE}" /* deprecated */
1716 #define MVAR_ACK_TIME "{ACK.TIME}" /* deprecated */
1717 #define MVAR_ACK_DATE "{ACK.DATE}" /* deprecated */
1718 #define MVAR_USER_ALIAS "{USER.ALIAS}" /* deprecated */
1719 #define MVAR_USER_USERNAME "{USER.USERNAME}"
1720 #define MVAR_USER_NAME "{USER.NAME}"
1721 #define MVAR_USER_SURNAME "{USER.SURNAME}"
1722 #define MVAR_USER_FULLNAME "{USER.FULLNAME}"
1723
1724 #define STR_UNKNOWN_VARIABLE "*UNKNOWN*"
1725
1726 /* macros that can be indexed */
1727 static const char *ex_macros[] =
1728 {
1729 MVAR_INVENTORY_TYPE, MVAR_INVENTORY_TYPE_FULL,
1730 MVAR_INVENTORY_NAME, MVAR_INVENTORY_ALIAS, MVAR_INVENTORY_OS, MVAR_INVENTORY_OS_FULL, MVAR_INVENTORY_OS_SHORT,
1731 MVAR_INVENTORY_SERIALNO_A, MVAR_INVENTORY_SERIALNO_B, MVAR_INVENTORY_TAG,
1732 MVAR_INVENTORY_ASSET_TAG, MVAR_INVENTORY_MACADDRESS_A, MVAR_INVENTORY_MACADDRESS_B,
1733 MVAR_INVENTORY_HARDWARE, MVAR_INVENTORY_HARDWARE_FULL, MVAR_INVENTORY_SOFTWARE, MVAR_INVENTORY_SOFTWARE_FULL,
1734 MVAR_INVENTORY_SOFTWARE_APP_A, MVAR_INVENTORY_SOFTWARE_APP_B, MVAR_INVENTORY_SOFTWARE_APP_C,
1735 MVAR_INVENTORY_SOFTWARE_APP_D, MVAR_INVENTORY_SOFTWARE_APP_E, MVAR_INVENTORY_CONTACT, MVAR_INVENTORY_LOCATION,
1736 MVAR_INVENTORY_LOCATION_LAT, MVAR_INVENTORY_LOCATION_LON, MVAR_INVENTORY_NOTES, MVAR_INVENTORY_CHASSIS,
1737 MVAR_INVENTORY_MODEL, MVAR_INVENTORY_HW_ARCH, MVAR_INVENTORY_VENDOR, MVAR_INVENTORY_CONTRACT_NUMBER,
1738 MVAR_INVENTORY_INSTALLER_NAME, MVAR_INVENTORY_DEPLOYMENT_STATUS, MVAR_INVENTORY_URL_A, MVAR_INVENTORY_URL_B,
1739 MVAR_INVENTORY_URL_C, MVAR_INVENTORY_HOST_NETWORKS, MVAR_INVENTORY_HOST_NETMASK, MVAR_INVENTORY_HOST_ROUTER,
1740 MVAR_INVENTORY_OOB_IP, MVAR_INVENTORY_OOB_NETMASK, MVAR_INVENTORY_OOB_ROUTER, MVAR_INVENTORY_HW_DATE_PURCHASE,
1741 MVAR_INVENTORY_HW_DATE_INSTALL, MVAR_INVENTORY_HW_DATE_EXPIRY, MVAR_INVENTORY_HW_DATE_DECOMM,
1742 MVAR_INVENTORY_SITE_ADDRESS_A, MVAR_INVENTORY_SITE_ADDRESS_B, MVAR_INVENTORY_SITE_ADDRESS_C,
1743 MVAR_INVENTORY_SITE_CITY, MVAR_INVENTORY_SITE_STATE, MVAR_INVENTORY_SITE_COUNTRY, MVAR_INVENTORY_SITE_ZIP,
1744 MVAR_INVENTORY_SITE_RACK, MVAR_INVENTORY_SITE_NOTES, MVAR_INVENTORY_POC_PRIMARY_NAME,
1745 MVAR_INVENTORY_POC_PRIMARY_EMAIL, MVAR_INVENTORY_POC_PRIMARY_PHONE_A, MVAR_INVENTORY_POC_PRIMARY_PHONE_B,
1746 MVAR_INVENTORY_POC_PRIMARY_CELL, MVAR_INVENTORY_POC_PRIMARY_SCREEN, MVAR_INVENTORY_POC_PRIMARY_NOTES,
1747 MVAR_INVENTORY_POC_SECONDARY_NAME, MVAR_INVENTORY_POC_SECONDARY_EMAIL, MVAR_INVENTORY_POC_SECONDARY_PHONE_A,
1748 MVAR_INVENTORY_POC_SECONDARY_PHONE_B, MVAR_INVENTORY_POC_SECONDARY_CELL, MVAR_INVENTORY_POC_SECONDARY_SCREEN,
1749 MVAR_INVENTORY_POC_SECONDARY_NOTES,
1750 /* PROFILE.* is deprecated, use INVENTORY.* instead */
1751 MVAR_PROFILE_DEVICETYPE, MVAR_PROFILE_NAME, MVAR_PROFILE_OS, MVAR_PROFILE_SERIALNO,
1752 MVAR_PROFILE_TAG, MVAR_PROFILE_MACADDRESS, MVAR_PROFILE_HARDWARE, MVAR_PROFILE_SOFTWARE,
1753 MVAR_PROFILE_CONTACT, MVAR_PROFILE_LOCATION, MVAR_PROFILE_NOTES,
1754 MVAR_HOST_HOST, MVAR_HOSTNAME, MVAR_HOST_NAME, MVAR_HOST_DESCRIPTION, MVAR_PROXY_NAME, MVAR_PROXY_DESCRIPTION,
1755 MVAR_HOST_CONN, MVAR_HOST_DNS, MVAR_HOST_IP, MVAR_HOST_PORT, MVAR_IPADDRESS, MVAR_HOST_ID,
1756 MVAR_ITEM_ID, MVAR_ITEM_NAME, MVAR_ITEM_NAME_ORIG, MVAR_ITEM_DESCRIPTION, MVAR_ITEM_DESCRIPTION_ORIG,
1757 MVAR_ITEM_KEY, MVAR_ITEM_KEY_ORIG, MVAR_TRIGGER_KEY,
1758 MVAR_ITEM_LASTVALUE,
1759 MVAR_ITEM_STATE,
1760 MVAR_ITEM_VALUE, MVAR_ITEM_VALUETYPE,
1761 MVAR_ITEM_LOG_DATE, MVAR_ITEM_LOG_TIME, MVAR_ITEM_LOG_AGE, MVAR_ITEM_LOG_SOURCE,
1762 MVAR_ITEM_LOG_SEVERITY, MVAR_ITEM_LOG_NSEVERITY, MVAR_ITEM_LOG_EVENTID,
1763 NULL
1764 };
1765
1766 /* macros that are supported as simple macro host and item key */
1767 static const char *simple_host_macros[] = {MVAR_HOST_HOST, MVAR_HOSTNAME, NULL};
1768 static const char *simple_key_macros[] = {MVAR_ITEM_KEY, MVAR_TRIGGER_KEY, NULL};
1769
1770 typedef struct
1771 {
1772 char *macro;
1773 char *functions;
1774 }
1775 zbx_macro_functions_t;
1776
1777 /* macros that can be modified using macro functions */
1778 static zbx_macro_functions_t mod_macros[] =
1779 {
1780 {MVAR_ITEM_VALUE, "regsub,iregsub,fmtnum"},
1781 {MVAR_ITEM_LASTVALUE, "regsub,iregsub,fmtnum"},
1782 {MVAR_TIME, "fmttime"},
1783 {"{?}", "fmtnum"},
1784 {NULL, NULL}
1785 };
1786
1787 typedef struct
1788 {
1789 const char *macro;
1790 int idx;
1791 } inventory_field_t;
1792
1793 static inventory_field_t inventory_fields[] =
1794 {
1795 {MVAR_INVENTORY_TYPE, 0},
1796 {MVAR_PROFILE_DEVICETYPE, 0}, /* deprecated */
1797 {MVAR_INVENTORY_TYPE_FULL, 1},
1798 {MVAR_INVENTORY_NAME, 2},
1799 {MVAR_PROFILE_NAME, 2}, /* deprecated */
1800 {MVAR_INVENTORY_ALIAS, 3},
1801 {MVAR_INVENTORY_OS, 4},
1802 {MVAR_PROFILE_OS, 4}, /* deprecated */
1803 {MVAR_INVENTORY_OS_FULL, 5},
1804 {MVAR_INVENTORY_OS_SHORT, 6},
1805 {MVAR_INVENTORY_SERIALNO_A, 7},
1806 {MVAR_PROFILE_SERIALNO, 7}, /* deprecated */
1807 {MVAR_INVENTORY_SERIALNO_B, 8},
1808 {MVAR_INVENTORY_TAG, 9},
1809 {MVAR_PROFILE_TAG, 9}, /* deprecated */
1810 {MVAR_INVENTORY_ASSET_TAG, 10},
1811 {MVAR_INVENTORY_MACADDRESS_A, 11},
1812 {MVAR_PROFILE_MACADDRESS, 11}, /* deprecated */
1813 {MVAR_INVENTORY_MACADDRESS_B, 12},
1814 {MVAR_INVENTORY_HARDWARE, 13},
1815 {MVAR_PROFILE_HARDWARE, 13}, /* deprecated */
1816 {MVAR_INVENTORY_HARDWARE_FULL, 14},
1817 {MVAR_INVENTORY_SOFTWARE, 15},
1818 {MVAR_PROFILE_SOFTWARE, 15}, /* deprecated */
1819 {MVAR_INVENTORY_SOFTWARE_FULL, 16},
1820 {MVAR_INVENTORY_SOFTWARE_APP_A, 17},
1821 {MVAR_INVENTORY_SOFTWARE_APP_B, 18},
1822 {MVAR_INVENTORY_SOFTWARE_APP_C, 19},
1823 {MVAR_INVENTORY_SOFTWARE_APP_D, 20},
1824 {MVAR_INVENTORY_SOFTWARE_APP_E, 21},
1825 {MVAR_INVENTORY_CONTACT, 22},
1826 {MVAR_PROFILE_CONTACT, 22}, /* deprecated */
1827 {MVAR_INVENTORY_LOCATION, 23},
1828 {MVAR_PROFILE_LOCATION, 23}, /* deprecated */
1829 {MVAR_INVENTORY_LOCATION_LAT, 24},
1830 {MVAR_INVENTORY_LOCATION_LON, 25},
1831 {MVAR_INVENTORY_NOTES, 26},
1832 {MVAR_PROFILE_NOTES, 26}, /* deprecated */
1833 {MVAR_INVENTORY_CHASSIS, 27},
1834 {MVAR_INVENTORY_MODEL, 28},
1835 {MVAR_INVENTORY_HW_ARCH, 29},
1836 {MVAR_INVENTORY_VENDOR, 30},
1837 {MVAR_INVENTORY_CONTRACT_NUMBER, 31},
1838 {MVAR_INVENTORY_INSTALLER_NAME, 32},
1839 {MVAR_INVENTORY_DEPLOYMENT_STATUS, 33},
1840 {MVAR_INVENTORY_URL_A, 34},
1841 {MVAR_INVENTORY_URL_B, 35},
1842 {MVAR_INVENTORY_URL_C, 36},
1843 {MVAR_INVENTORY_HOST_NETWORKS, 37},
1844 {MVAR_INVENTORY_HOST_NETMASK, 38},
1845 {MVAR_INVENTORY_HOST_ROUTER, 39},
1846 {MVAR_INVENTORY_OOB_IP, 40},
1847 {MVAR_INVENTORY_OOB_NETMASK, 41},
1848 {MVAR_INVENTORY_OOB_ROUTER, 42},
1849 {MVAR_INVENTORY_HW_DATE_PURCHASE, 43},
1850 {MVAR_INVENTORY_HW_DATE_INSTALL, 44},
1851 {MVAR_INVENTORY_HW_DATE_EXPIRY, 45},
1852 {MVAR_INVENTORY_HW_DATE_DECOMM, 46},
1853 {MVAR_INVENTORY_SITE_ADDRESS_A, 47},
1854 {MVAR_INVENTORY_SITE_ADDRESS_B, 48},
1855 {MVAR_INVENTORY_SITE_ADDRESS_C, 49},
1856 {MVAR_INVENTORY_SITE_CITY, 50},
1857 {MVAR_INVENTORY_SITE_STATE, 51},
1858 {MVAR_INVENTORY_SITE_COUNTRY, 52},
1859 {MVAR_INVENTORY_SITE_ZIP, 53},
1860 {MVAR_INVENTORY_SITE_RACK, 54},
1861 {MVAR_INVENTORY_SITE_NOTES, 55},
1862 {MVAR_INVENTORY_POC_PRIMARY_NAME, 56},
1863 {MVAR_INVENTORY_POC_PRIMARY_EMAIL, 57},
1864 {MVAR_INVENTORY_POC_PRIMARY_PHONE_A, 58},
1865 {MVAR_INVENTORY_POC_PRIMARY_PHONE_B, 59},
1866 {MVAR_INVENTORY_POC_PRIMARY_CELL, 60},
1867 {MVAR_INVENTORY_POC_PRIMARY_SCREEN, 61},
1868 {MVAR_INVENTORY_POC_PRIMARY_NOTES, 62},
1869 {MVAR_INVENTORY_POC_SECONDARY_NAME, 63},
1870 {MVAR_INVENTORY_POC_SECONDARY_EMAIL, 64},
1871 {MVAR_INVENTORY_POC_SECONDARY_PHONE_A, 65},
1872 {MVAR_INVENTORY_POC_SECONDARY_PHONE_B, 66},
1873 {MVAR_INVENTORY_POC_SECONDARY_CELL, 67},
1874 {MVAR_INVENTORY_POC_SECONDARY_SCREEN, 68},
1875 {MVAR_INVENTORY_POC_SECONDARY_NOTES, 69},
1876 {NULL}
1877 };
1878
1879 /******************************************************************************
1880 * *
1881 * Function: get_action_value *
1882 * *
1883 * Purpose: request action value by macro *
1884 * *
1885 * Return value: upon successful completion return SUCCEED *
1886 * otherwise FAIL *
1887 * *
1888 ******************************************************************************/
get_action_value(const char * macro,zbx_uint64_t actionid,char ** replace_to)1889 static int get_action_value(const char *macro, zbx_uint64_t actionid, char **replace_to)
1890 {
1891 int ret = SUCCEED;
1892
1893 if (0 == strcmp(macro, MVAR_ACTION_ID))
1894 {
1895 *replace_to = zbx_dsprintf(*replace_to, ZBX_FS_UI64, actionid);
1896 }
1897 else if (0 == strcmp(macro, MVAR_ACTION_NAME))
1898 {
1899 DB_RESULT result;
1900 DB_ROW row;
1901
1902 result = DBselect("select name from actions where actionid=" ZBX_FS_UI64, actionid);
1903
1904 if (NULL != (row = DBfetch(result)))
1905 *replace_to = zbx_strdup(*replace_to, row[0]);
1906 else
1907 ret = FAIL;
1908
1909 DBfree_result(result);
1910 }
1911
1912 return ret;
1913 }
1914
1915 /******************************************************************************
1916 * *
1917 * Function: get_host_inventory *
1918 * *
1919 * Purpose: request host inventory value by macro and trigger *
1920 * *
1921 * Return value: upon successful completion return SUCCEED *
1922 * otherwise FAIL *
1923 * *
1924 ******************************************************************************/
get_host_inventory(const char * macro,const DB_TRIGGER * trigger,char ** replace_to,int N_functionid)1925 static int get_host_inventory(const char *macro, const DB_TRIGGER *trigger, char **replace_to,
1926 int N_functionid)
1927 {
1928 int i;
1929
1930 for (i = 0; NULL != inventory_fields[i].macro; i++)
1931 {
1932 if (0 == strcmp(macro, inventory_fields[i].macro))
1933 {
1934 zbx_uint64_t itemid;
1935
1936 if (SUCCEED != zbx_db_trigger_get_itemid(trigger, N_functionid, &itemid))
1937 return FAIL;
1938
1939 return DCget_host_inventory_value_by_itemid(itemid, replace_to, inventory_fields[i].idx);
1940 }
1941 }
1942
1943 return FAIL;
1944 }
1945
1946 /******************************************************************************
1947 * *
1948 * Function: get_host_inventory_by_itemid *
1949 * *
1950 * Purpose: request host inventory value by macro and itemid *
1951 * *
1952 * Return value: upon successful completion return SUCCEED *
1953 * otherwise FAIL *
1954 * *
1955 ******************************************************************************/
get_host_inventory_by_itemid(const char * macro,zbx_uint64_t itemid,char ** replace_to)1956 static int get_host_inventory_by_itemid(const char *macro, zbx_uint64_t itemid, char **replace_to)
1957 {
1958 int i;
1959
1960 for (i = 0; NULL != inventory_fields[i].macro; i++)
1961 {
1962 if (0 == strcmp(macro, inventory_fields[i].macro))
1963 return DCget_host_inventory_value_by_itemid(itemid, replace_to, inventory_fields[i].idx);
1964 }
1965
1966 return FAIL;
1967 }
1968
1969 /******************************************************************************
1970 * *
1971 * Function: get_host_inventory_by_itemid *
1972 * *
1973 * Purpose: request host inventory value by macro and hostid *
1974 * *
1975 * Return value: upon successful completion return SUCCEED *
1976 * otherwise FAIL *
1977 * *
1978 ******************************************************************************/
get_host_inventory_by_hostid(const char * macro,zbx_uint64_t hostid,char ** replace_to)1979 static int get_host_inventory_by_hostid(const char *macro, zbx_uint64_t hostid, char **replace_to)
1980 {
1981 int i;
1982
1983 for (i = 0; NULL != inventory_fields[i].macro; i++)
1984 {
1985 if (0 == strcmp(macro, inventory_fields[i].macro))
1986 return DCget_host_inventory_value_by_hostid(hostid, replace_to, inventory_fields[i].idx);
1987 }
1988
1989 return FAIL;
1990 }
1991
1992 /******************************************************************************
1993 * *
1994 * Function: compare_tags *
1995 * *
1996 * Purpose: comparison function to sort tags by tag/value *
1997 * *
1998 ******************************************************************************/
compare_tags(const void * d1,const void * d2)1999 static int compare_tags(const void *d1, const void *d2)
2000 {
2001 int ret;
2002
2003 const zbx_tag_t *tag1 = *(const zbx_tag_t **)d1;
2004 const zbx_tag_t *tag2 = *(const zbx_tag_t **)d2;
2005
2006 if (0 == (ret = zbx_strcmp_natural(tag1->tag, tag2->tag)))
2007 ret = zbx_strcmp_natural(tag1->value, tag2->value);
2008
2009 return ret;
2010 }
2011
2012 /******************************************************************************
2013 * *
2014 * Function: get_event_tags *
2015 * *
2016 * Purpose: format event tags string in format <tag1>[:<value1>], ... *
2017 * *
2018 * Parameters: event [IN] the event *
2019 * replace_to - [OUT] replacement string *
2020 * *
2021 ******************************************************************************/
get_event_tags(const DB_EVENT * event,char ** replace_to)2022 static void get_event_tags(const DB_EVENT *event, char **replace_to)
2023 {
2024 size_t replace_to_offset = 0, replace_to_alloc = 0;
2025 int i;
2026 zbx_vector_ptr_t tags;
2027
2028 if (0 == event->tags.values_num)
2029 {
2030 *replace_to = zbx_strdup(*replace_to, "");
2031 return;
2032 }
2033
2034 zbx_free(*replace_to);
2035
2036 /* copy tags to temporary vector for sorting */
2037
2038 zbx_vector_ptr_create(&tags);
2039 zbx_vector_ptr_reserve(&tags, event->tags.values_num);
2040
2041 for (i = 0; i < event->tags.values_num; i++)
2042 zbx_vector_ptr_append(&tags, event->tags.values[i]);
2043
2044 zbx_vector_ptr_sort(&tags, compare_tags);
2045
2046 for (i = 0; i < tags.values_num; i++)
2047 {
2048 const zbx_tag_t *tag = (const zbx_tag_t *)tags.values[i];
2049
2050 if (0 != i)
2051 zbx_strcpy_alloc(replace_to, &replace_to_alloc, &replace_to_offset, ", ");
2052
2053 zbx_strcpy_alloc(replace_to, &replace_to_alloc, &replace_to_offset, tag->tag);
2054
2055 if ('\0' != *tag->value)
2056 {
2057 zbx_chrcpy_alloc(replace_to, &replace_to_alloc, &replace_to_offset, ':');
2058 zbx_strcpy_alloc(replace_to, &replace_to_alloc, &replace_to_offset, tag->value);
2059 }
2060 }
2061
2062 zbx_vector_ptr_destroy(&tags);
2063 }
2064
2065 /******************************************************************************
2066 * *
2067 * Function: get_event_tags_json *
2068 * *
2069 * Purpose: format event tags string in JSON format *
2070 * *
2071 * Parameters: event [IN] the event *
2072 * replace_to - [OUT] replacement string *
2073 * *
2074 ******************************************************************************/
get_event_tags_json(const DB_EVENT * event,char ** replace_to)2075 static void get_event_tags_json(const DB_EVENT *event, char **replace_to)
2076 {
2077 struct zbx_json json;
2078 int i;
2079
2080 zbx_json_initarray(&json, ZBX_JSON_STAT_BUF_LEN);
2081
2082 for (i = 0; i < event->tags.values_num; i++)
2083 {
2084 const zbx_tag_t *tag = (const zbx_tag_t *)event->tags.values[i];
2085
2086 zbx_json_addobject(&json, NULL);
2087 zbx_json_addstring(&json, "tag", tag->tag, ZBX_JSON_TYPE_STRING);
2088 zbx_json_addstring(&json, "value", tag->value, ZBX_JSON_TYPE_STRING);
2089 zbx_json_close(&json);
2090 }
2091
2092 zbx_json_close(&json);
2093 *replace_to = zbx_strdup(*replace_to, json.buffer);
2094 zbx_json_free(&json);
2095 }
2096
2097 /******************************************************************************
2098 * *
2099 * Function: get_recovery_event_value *
2100 * *
2101 * Purpose: request recovery event value by macro *
2102 * *
2103 ******************************************************************************/
get_recovery_event_value(const char * macro,const DB_EVENT * r_event,char ** replace_to,const char * tz)2104 static void get_recovery_event_value(const char *macro, const DB_EVENT *r_event, char **replace_to, const char *tz)
2105 {
2106 if (0 == strcmp(macro, MVAR_EVENT_RECOVERY_DATE))
2107 {
2108 *replace_to = zbx_strdup(*replace_to, zbx_date2str(r_event->clock, tz));
2109 }
2110 else if (0 == strcmp(macro, MVAR_EVENT_RECOVERY_ID))
2111 {
2112 *replace_to = zbx_dsprintf(*replace_to, ZBX_FS_UI64, r_event->eventid);
2113 }
2114 else if (0 == strcmp(macro, MVAR_EVENT_RECOVERY_STATUS))
2115 {
2116 *replace_to = zbx_strdup(*replace_to,
2117 zbx_event_value_string(r_event->source, r_event->object, r_event->value));
2118 }
2119 else if (0 == strcmp(macro, MVAR_EVENT_RECOVERY_TIME))
2120 {
2121 *replace_to = zbx_strdup(*replace_to, zbx_time2str(r_event->clock, tz));
2122 }
2123 else if (0 == strcmp(macro, MVAR_EVENT_RECOVERY_VALUE))
2124 {
2125 *replace_to = zbx_dsprintf(*replace_to, "%d", r_event->value);
2126 }
2127 else if (0 == strcmp(macro, MVAR_EVENT_RECOVERY_NAME))
2128 {
2129 *replace_to = zbx_dsprintf(*replace_to, "%s", r_event->name);
2130 }
2131 else if (EVENT_SOURCE_TRIGGERS == r_event->source)
2132 {
2133 if (0 == strcmp(macro, MVAR_EVENT_RECOVERY_TAGS))
2134 get_event_tags(r_event, replace_to);
2135 else if (0 == strcmp(macro, MVAR_EVENT_RECOVERY_TAGSJSON))
2136 get_event_tags_json(r_event, replace_to);
2137 }
2138 }
2139
2140 /******************************************************************************
2141 * *
2142 * Function: get_current_event_value *
2143 * *
2144 * Purpose: request current event value by macro *
2145 * *
2146 ******************************************************************************/
get_current_event_value(const char * macro,const DB_EVENT * event,char ** replace_to)2147 static void get_current_event_value(const char *macro, const DB_EVENT *event, char **replace_to)
2148 {
2149 if (0 == strcmp(macro, MVAR_EVENT_STATUS))
2150 {
2151 *replace_to = zbx_strdup(*replace_to,
2152 zbx_event_value_string(event->source, event->object, event->value));
2153 }
2154 else if (0 == strcmp(macro, MVAR_EVENT_VALUE))
2155 {
2156 *replace_to = zbx_dsprintf(*replace_to, "%d", event->value);
2157 }
2158 }
2159
2160 /******************************************************************************
2161 * *
2162 * Function: get_event_value *
2163 * *
2164 * Purpose: request event value by macro *
2165 * *
2166 ******************************************************************************/
get_event_value(const char * macro,const DB_EVENT * event,char ** replace_to,const zbx_uint64_t * recipient_userid,const DB_EVENT * r_event,const char * tz)2167 static void get_event_value(const char *macro, const DB_EVENT *event, char **replace_to,
2168 const zbx_uint64_t *recipient_userid, const DB_EVENT *r_event, const char *tz)
2169 {
2170 if (0 == strcmp(macro, MVAR_EVENT_AGE))
2171 {
2172 *replace_to = zbx_strdup(*replace_to, zbx_age2str(time(NULL) - event->clock));
2173 }
2174 else if (0 == strcmp(macro, MVAR_EVENT_DATE))
2175 {
2176 *replace_to = zbx_strdup(*replace_to, zbx_date2str(event->clock, tz));
2177 }
2178 else if (0 == strcmp(macro, MVAR_EVENT_DURATION))
2179 {
2180 if (NULL == r_event)
2181 *replace_to = zbx_strdup(*replace_to, zbx_age2str(time(NULL) - event->clock));
2182 else
2183 *replace_to = zbx_strdup(*replace_to, zbx_age2str(r_event->clock - event->clock));
2184 }
2185 else if (0 == strcmp(macro, MVAR_EVENT_ID))
2186 {
2187 *replace_to = zbx_dsprintf(*replace_to, ZBX_FS_UI64, event->eventid);
2188 }
2189 else if (0 == strcmp(macro, MVAR_EVENT_TIME))
2190 {
2191 *replace_to = zbx_strdup(*replace_to, zbx_time2str(event->clock, tz));
2192 }
2193 else if (0 == strcmp(macro, MVAR_EVENT_SOURCE))
2194 {
2195 *replace_to = zbx_dsprintf(*replace_to, "%d", event->source);
2196 }
2197 else if (0 == strcmp(macro, MVAR_EVENT_OBJECT))
2198 {
2199 *replace_to = zbx_dsprintf(*replace_to, "%d", event->object);
2200 }
2201 else if (EVENT_SOURCE_TRIGGERS == event->source)
2202 {
2203 if (0 == strcmp(macro, MVAR_EVENT_ACK_HISTORY) || 0 == strcmp(macro, MVAR_EVENT_UPDATE_HISTORY))
2204 {
2205 get_event_update_history(event, replace_to, recipient_userid, tz);
2206 }
2207 else if (0 == strcmp(macro, MVAR_EVENT_ACK_STATUS))
2208 {
2209 *replace_to = zbx_strdup(*replace_to, event->acknowledged ? "Yes" : "No");
2210 }
2211 else if (0 == strcmp(macro, MVAR_EVENT_TAGS))
2212 {
2213 get_event_tags(event, replace_to);
2214 }
2215 else if (0 == strcmp(macro, MVAR_EVENT_TAGSJSON))
2216 {
2217 get_event_tags_json(event, replace_to);
2218 }
2219 else if (0 == strcmp(macro, MVAR_EVENT_NSEVERITY))
2220 {
2221 *replace_to = zbx_dsprintf(*replace_to, "%d", (int)event->severity);
2222 }
2223 else if (0 == strcmp(macro, MVAR_EVENT_SEVERITY))
2224 {
2225 if (FAIL == get_trigger_severity_name(event->severity, replace_to))
2226 *replace_to = zbx_strdup(*replace_to, "unknown");
2227 }
2228 else if (0 == strncmp(macro, MVAR_EVENT_TAGS_PREFIX, ZBX_CONST_STRLEN(MVAR_EVENT_TAGS_PREFIX)))
2229 {
2230 char *name;
2231
2232 if (SUCCEED == zbx_str_extract(macro + ZBX_CONST_STRLEN(MVAR_EVENT_TAGS_PREFIX),
2233 strlen(macro) - ZBX_CONST_STRLEN(MVAR_EVENT_TAGS_PREFIX) - 1, &name))
2234 {
2235 if (0 < event->tags.values_num)
2236 {
2237 int i;
2238 zbx_tag_t *tag;
2239 zbx_vector_ptr_t ptr_tags;
2240
2241 zbx_vector_ptr_create(&ptr_tags);
2242 zbx_vector_ptr_append_array(&ptr_tags, event->tags.values,
2243 event->tags.values_num);
2244 zbx_vector_ptr_sort(&ptr_tags, compare_tags);
2245
2246 for (i = 0; i < ptr_tags.values_num; i++)
2247 {
2248 tag = (zbx_tag_t *)ptr_tags.values[i];
2249
2250 if (0 == strcmp(name, tag->tag))
2251 {
2252 *replace_to = zbx_strdup(*replace_to, tag->value);
2253 break;
2254 }
2255 }
2256
2257 zbx_vector_ptr_destroy(&ptr_tags);
2258 }
2259
2260 zbx_free(name);
2261 }
2262 }
2263 }
2264 }
2265
2266 /******************************************************************************
2267 * *
2268 * Function: get_history_log_value *
2269 * *
2270 * Purpose: retrieve a particular attribute of a log value *
2271 * *
2272 * Return value: upon successful completion return SUCCEED *
2273 * otherwise FAIL *
2274 * *
2275 ******************************************************************************/
get_history_log_value(const char * m,const DB_TRIGGER * trigger,char ** replace_to,int N_functionid,int clock,int ns,const char * tz)2276 static int get_history_log_value(const char *m, const DB_TRIGGER *trigger, char **replace_to, int N_functionid,
2277 int clock, int ns, const char *tz)
2278 {
2279 zbx_uint64_t itemid;
2280 int ret, request;
2281
2282 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
2283
2284 if (0 == strcmp(m, MVAR_ITEM_LOG_AGE))
2285 {
2286 request = ZBX_REQUEST_ITEM_LOG_AGE;
2287 }
2288 else if (0 == strcmp(m, MVAR_ITEM_LOG_DATE))
2289 {
2290 request = ZBX_REQUEST_ITEM_LOG_DATE;
2291 }
2292 else if (0 == strcmp(m, MVAR_ITEM_LOG_EVENTID))
2293 {
2294 request = ZBX_REQUEST_ITEM_LOG_EVENTID;
2295 }
2296 else if (0 == strcmp(m, MVAR_ITEM_LOG_NSEVERITY))
2297 {
2298 request = ZBX_REQUEST_ITEM_LOG_NSEVERITY;
2299 }
2300 else if (0 == strcmp(m, MVAR_ITEM_LOG_SEVERITY))
2301 {
2302 request = ZBX_REQUEST_ITEM_LOG_SEVERITY;
2303 }
2304 else if (0 == strcmp(m, MVAR_ITEM_LOG_SOURCE))
2305 {
2306 request = ZBX_REQUEST_ITEM_LOG_SOURCE;
2307 }
2308 else /* MVAR_ITEM_LOG_TIME */
2309 request = ZBX_REQUEST_ITEM_LOG_TIME;
2310
2311 if (SUCCEED == (ret = zbx_db_trigger_get_itemid(trigger, N_functionid, &itemid)))
2312 ret = DBget_history_log_value(itemid, replace_to, request, clock, ns, tz);
2313
2314 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
2315
2316 return ret;
2317 }
2318
2319 /******************************************************************************
2320 * *
2321 * Function: is_indexed_macro *
2322 * *
2323 * Purpose: check if a token contains indexed macro *
2324 * *
2325 ******************************************************************************/
is_indexed_macro(const char * str,const zbx_token_t * token)2326 static int is_indexed_macro(const char *str, const zbx_token_t *token)
2327 {
2328 const char *p;
2329
2330 switch (token->type)
2331 {
2332 case ZBX_TOKEN_MACRO:
2333 p = str + token->loc.r - 1;
2334 break;
2335 case ZBX_TOKEN_FUNC_MACRO:
2336 p = str + token->data.func_macro.macro.r - 1;
2337 break;
2338 default:
2339 THIS_SHOULD_NEVER_HAPPEN;
2340 return FAIL;
2341 }
2342
2343 return '1' <= *p && *p <= '9' ? 1 : 0;
2344 }
2345
2346 /******************************************************************************
2347 * *
2348 * Function: macro_in_list *
2349 * *
2350 * Purpose: check if a macro in string is one of the list and extract index *
2351 * *
2352 * Parameters: str - [IN] string containing potential macro *
2353 * strloc - [IN] part of the string to check *
2354 * macros - [IN] list of allowed macros (without indices) *
2355 * N_functionid - [OUT] index of the macro in string (if valid) *
2356 * *
2357 * Return value: unindexed macro from the allowed list or NULL *
2358 * *
2359 * Comments: example: N_functionid is untouched if function returns NULL, for *
2360 * a valid unindexed macro N_function is 1. *
2361 * *
2362 ******************************************************************************/
macro_in_list(const char * str,zbx_strloc_t strloc,const char ** macros,int * N_functionid)2363 static const char *macro_in_list(const char *str, zbx_strloc_t strloc, const char **macros, int *N_functionid)
2364 {
2365 const char **macro, *m;
2366 size_t i;
2367
2368 for (macro = macros; NULL != *macro; macro++)
2369 {
2370 for (m = *macro, i = strloc.l; '\0' != *m && i <= strloc.r && str[i] == *m; m++, i++)
2371 ;
2372
2373 /* check whether macro has ended while strloc hasn't or vice-versa */
2374 if (('\0' == *m && i <= strloc.r) || ('\0' != *m && i > strloc.r))
2375 continue;
2376
2377 /* strloc either fully matches macro... */
2378 if ('\0' == *m)
2379 {
2380 if (NULL != N_functionid)
2381 *N_functionid = 1;
2382
2383 break;
2384 }
2385
2386 /* ...or there is a mismatch, check if it's in a pre-last character and it's an index */
2387 if (i == strloc.r - 1 && '1' <= str[i] && str[i] <= '9' && str[i + 1] == *m && '\0' == *(m + 1))
2388 {
2389 if (NULL != N_functionid)
2390 *N_functionid = str[i] - '0';
2391
2392 break;
2393 }
2394 }
2395
2396 return *macro;
2397 }
2398
2399 /******************************************************************************
2400 * *
2401 * Function: func_macro_in_list *
2402 * *
2403 * Purpose: check if a macro function one in the list for the macro *
2404 * *
2405 * Parameters: str - [IN] string containing potential macro *
2406 * fm - [IN] function macro to check *
2407 * N_functionid - [OUT] index of the macro in string (if valid) *
2408 * *
2409 * Return value: unindexed macro from the allowed list or NULL *
2410 * *
2411 ******************************************************************************/
func_macro_in_list(const char * str,zbx_token_func_macro_t * fm,int * N_functionid)2412 static const char *func_macro_in_list(const char *str, zbx_token_func_macro_t *fm, int *N_functionid)
2413 {
2414 int i;
2415
2416 for (i = 0; NULL != mod_macros[i].macro; i++)
2417 {
2418 size_t len, fm_len;
2419
2420 len = strlen(mod_macros[i].macro);
2421 fm_len = fm->macro.r - fm->macro.l + 1;
2422
2423 if (len > fm_len || 0 != strncmp(mod_macros[i].macro, str + fm->macro.l, len - 1))
2424 continue;
2425
2426 if ('?' != mod_macros[i].macro[1] && len != fm_len)
2427 {
2428 if (SUCCEED != is_uint_n_range(str + fm->macro.l + len - 1, fm_len - len, N_functionid,
2429 sizeof(*N_functionid), 1, 9))
2430 {
2431 continue;
2432 }
2433 }
2434 else if (mod_macros[i].macro[len - 1] != str[fm->macro.l + fm_len - 1])
2435 continue;
2436
2437 if (SUCCEED == str_n_in_list(mod_macros[i].functions, str + fm->func.l, fm->func_param.l - fm->func.l,
2438 ','))
2439 {
2440 return mod_macros[i].macro;
2441 }
2442 }
2443
2444 return NULL;
2445 }
2446
2447 /******************************************************************************
2448 * *
2449 * Function: get_trigger_function_value *
2450 * *
2451 * Purpose: trying to evaluate a trigger function *
2452 * *
2453 * Parameters: expression - [IN] trigger expression, source of hostnames and *
2454 * item keys for {HOST.HOST} and {ITEM.KEY} macros *
2455 * replace_to - [OUT] evaluation result *
2456 * data - [IN] string containing simple macro *
2457 * macro - [IN] simple macro token location in string *
2458 * *
2459 * Return value: SUCCEED - successfully evaluated or invalid macro(s) in host *
2460 * and/or item key positions (in the latter case *
2461 * replace_to remains unchanged and simple macro *
2462 * shouldn't be replaced with anything) *
2463 * FAIL - evaluation failed and macro has to be replaced *
2464 * with STR_UNKNOWN_VARIABLE ("*UNKNOWN*") *
2465 * *
2466 * Author: Alexander Vladishev *
2467 * *
2468 * Comments: example: " {Zabbix server:{ITEM.KEY1}.last(0)} " to " 1.34 " *
2469 * *
2470 ******************************************************************************/
get_trigger_function_value(const DB_TRIGGER * trigger,char ** replace_to,char * data,const zbx_token_simple_macro_t * simple_macro,zbx_output_format_t format)2471 static int get_trigger_function_value(const DB_TRIGGER *trigger, char **replace_to, char *data,
2472 const zbx_token_simple_macro_t *simple_macro, zbx_output_format_t format)
2473 {
2474 char *host = NULL, *key = NULL;
2475 int N_functionid, ret = FAIL;
2476
2477 if (NULL != macro_in_list(data, simple_macro->host, simple_host_macros, &N_functionid))
2478 {
2479 if (SUCCEED != DBget_trigger_value(trigger, &host, N_functionid, ZBX_REQUEST_HOST_HOST))
2480 goto out;
2481 }
2482
2483 if (NULL != macro_in_list(data, simple_macro->key, simple_key_macros, &N_functionid))
2484 {
2485 if (SUCCEED != DBget_trigger_value(trigger, &key, N_functionid, ZBX_REQUEST_ITEM_KEY_ORIG))
2486 goto out;
2487 }
2488
2489 data[simple_macro->host.r + 1] = '\0';
2490 data[simple_macro->key.r + 1] = '\0';
2491 data[simple_macro->func_param.l] = '\0';
2492 data[simple_macro->func_param.r] = '\0';
2493
2494 ret = evaluate_macro_function(replace_to, (NULL == host ? data + simple_macro->host.l : host),
2495 (NULL == key ? data + simple_macro->key.l : key), data + simple_macro->func.l,
2496 data + simple_macro->func_param.l + 1, format);
2497
2498 data[simple_macro->host.r + 1] = ':';
2499 data[simple_macro->key.r + 1] = '.';
2500 data[simple_macro->func_param.l] = '(';
2501 data[simple_macro->func_param.r] = ')';
2502 out:
2503 zbx_free(host);
2504 zbx_free(key);
2505
2506 return ret;
2507 }
2508
2509 /******************************************************************************
2510 * *
2511 * Function: get_expression_macro_result *
2512 * *
2513 * Purpose: calculate result of expression macro *
2514 * *
2515 * Return value: upon successful completion return SUCCEED *
2516 * otherwise FAIL *
2517 * *
2518 ******************************************************************************/
get_expression_macro_result(const DB_EVENT * event,const DB_EVENT * r_event,const char * expression,char ** replace_to,char ** error)2519 static int get_expression_macro_result(const DB_EVENT *event, const DB_EVENT *r_event, const char *expression,
2520 char **replace_to, char **error)
2521 {
2522 int ret = FAIL;
2523 zbx_eval_context_t ctx;
2524 const zbx_vector_uint64_t *hostids;
2525 zbx_timespec_t ts;
2526 zbx_variant_t value;
2527 zbx_expression_eval_t eval;
2528
2529 zabbix_log(LOG_LEVEL_DEBUG, "In %s() expression:'%s'", __func__, expression);
2530
2531 ZBX_UNUSED(r_event);
2532
2533 if (SUCCEED != zbx_eval_parse_expression(&ctx, expression, ZBX_EVAL_PARSE_EXPRESSION_MACRO, error))
2534 goto out;
2535
2536 if (SUCCEED != zbx_db_trigger_get_all_hostids(&event->trigger, &hostids))
2537 {
2538 *error = zbx_strdup(NULL, "cannot obtain host identifiers for the expression macro");
2539 goto out;
2540 }
2541
2542 if (SUCCEED != zbx_eval_expand_user_macros(&ctx, hostids->values, hostids->values_num,
2543 zbx_dc_expand_user_macros_len, error))
2544 {
2545 goto out;
2546 }
2547
2548 ts.sec = event->clock;
2549 ts.ns = event->ns;
2550
2551 zbx_expression_eval_init(&eval, ZBX_EXPRESSION_NORMAL, &ctx);
2552 zbx_expression_eval_resolve_trigger_hosts(&eval, &event->trigger);
2553
2554 if (SUCCEED == (ret = zbx_expression_eval_execute(&eval, &ts, &value, error)))
2555 {
2556 *replace_to = zbx_strdup(NULL, zbx_variant_value_desc(&value));
2557 zbx_variant_clear(&value);
2558 }
2559
2560 zbx_expression_eval_clear(&eval);
2561 out:
2562 zbx_eval_clear(&ctx);
2563
2564 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
2565
2566 return ret;
2567 }
2568
2569 /******************************************************************************
2570 * *
2571 * Function: cache_item_hostid *
2572 * *
2573 * Purpose: cache host identifier referenced by an item or a lld-rule *
2574 * *
2575 * Parameters: hostids - [OUT] the host identifier cache *
2576 * itemid - [IN] the item identifier *
2577 * *
2578 ******************************************************************************/
cache_item_hostid(zbx_vector_uint64_t * hostids,zbx_uint64_t itemid)2579 static void cache_item_hostid(zbx_vector_uint64_t *hostids, zbx_uint64_t itemid)
2580 {
2581 if (0 == hostids->values_num)
2582 {
2583 DC_ITEM item;
2584 int errcode;
2585
2586 DCconfig_get_items_by_itemids(&item, &itemid, &errcode, 1);
2587
2588 if (SUCCEED == errcode)
2589 zbx_vector_uint64_append(hostids, item.host.hostid);
2590
2591 DCconfig_clean_items(&item, &errcode, 1);
2592 }
2593 }
2594
zbx_dobject_status2str(int st)2595 static const char *zbx_dobject_status2str(int st)
2596 {
2597 switch (st)
2598 {
2599 case DOBJECT_STATUS_UP:
2600 return "UP";
2601 case DOBJECT_STATUS_DOWN:
2602 return "DOWN";
2603 case DOBJECT_STATUS_DISCOVER:
2604 return "DISCOVERED";
2605 case DOBJECT_STATUS_LOST:
2606 return "LOST";
2607 default:
2608 return "UNKNOWN";
2609 }
2610 }
2611
2612 /******************************************************************************
2613 * *
2614 * Function: resolve_opdata *
2615 * *
2616 * Purpose: resolve {EVENT.OPDATA} macro *
2617 * *
2618 ******************************************************************************/
resolve_opdata(const DB_EVENT * event,char ** replace_to,const char * tz,char * error,int maxerrlen)2619 static void resolve_opdata(const DB_EVENT *event, char **replace_to, const char *tz, char *error, int maxerrlen)
2620 {
2621 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
2622
2623 if ('\0' == *event->trigger.opdata)
2624 {
2625 int i;
2626 zbx_vector_uint64_t itemids;
2627 zbx_timespec_t ts;
2628
2629 ts.sec = time(NULL);
2630 ts.ns = 999999999;
2631
2632 zbx_vector_uint64_create(&itemids);
2633 zbx_db_trigger_get_itemids(&event->trigger, &itemids);
2634
2635 for (i = 0; i < itemids.values_num; i++)
2636 {
2637 char *val = NULL;
2638
2639 if (NULL != *replace_to)
2640 *replace_to = zbx_strdcat(*replace_to, ", ");
2641
2642 if (SUCCEED == DBitem_get_value(itemids.values[i], &val, 0, &ts))
2643 {
2644 *replace_to = zbx_strdcat(*replace_to, val);
2645 zbx_free(val);
2646 }
2647 else
2648 *replace_to = zbx_strdcat(*replace_to, STR_UNKNOWN_VARIABLE);
2649 }
2650
2651 zbx_vector_uint64_destroy(&itemids);
2652 }
2653 else
2654 {
2655 *replace_to = zbx_strdup(*replace_to, event->trigger.opdata);
2656 substitute_simple_macros_impl(NULL, event, NULL, NULL, NULL, NULL, NULL, NULL, NULL, tz, replace_to,
2657 MACRO_TYPE_TRIGGER_DESCRIPTION, error, maxerrlen);
2658 }
2659
2660 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
2661 }
2662
2663 /******************************************************************************
2664 * *
2665 * Function: resolve_user_macros *
2666 * *
2667 * Purpose: resolve {USER.*} macros *
2668 * *
2669 ******************************************************************************/
resolve_user_macros(zbx_uint64_t userid,const char * m,char ** user_username,char ** user_name,char ** user_surname,int * user_names_found,char ** replace_to)2670 static void resolve_user_macros(zbx_uint64_t userid, const char *m, char **user_username, char **user_name,
2671 char **user_surname, int *user_names_found, char **replace_to)
2672 {
2673 /* use only one DB request for all occurrences of 5 macros */
2674 if (0 == *user_names_found)
2675 {
2676 if (SUCCEED == DBget_user_names(userid, user_username, user_name, user_surname))
2677 *user_names_found = 1;
2678 else
2679 return;
2680 }
2681
2682 if (0 == strcmp(m, MVAR_USER_USERNAME) || 0 == strcmp(m, MVAR_USER_ALIAS))
2683 {
2684 *replace_to = zbx_strdup(*replace_to, *user_username);
2685 }
2686 else if (0 == strcmp(m, MVAR_USER_NAME))
2687 {
2688 *replace_to = zbx_strdup(*replace_to, *user_name);
2689 }
2690 else if (0 == strcmp(m, MVAR_USER_SURNAME))
2691 {
2692 *replace_to = zbx_strdup(*replace_to, *user_surname);
2693 }
2694 else if (0 == strcmp(m, MVAR_USER_FULLNAME))
2695 {
2696 zbx_free(*replace_to);
2697 *replace_to = format_user_fullname(*user_name, *user_surname, *user_username);
2698 }
2699 }
2700
resolve_host_target_macros(const char * m,const DC_HOST * dc_host,DC_INTERFACE * interface,int * require_address,char ** replace_to)2701 static int resolve_host_target_macros(const char *m, const DC_HOST *dc_host, DC_INTERFACE *interface,
2702 int *require_address, char **replace_to)
2703 {
2704 int ret = SUCCEED;
2705
2706 if (NULL == dc_host)
2707 return SUCCEED;
2708
2709 if (0 == strcmp(m, MVAR_HOST_TARGET_DNS))
2710 {
2711 if (SUCCEED == (ret = DCconfig_get_interface(interface, dc_host->hostid, 0)))
2712 *replace_to = zbx_strdup(*replace_to, interface->dns_orig);
2713
2714 *require_address = 1;
2715 }
2716 else if (0 == strcmp(m, MVAR_HOST_TARGET_CONN))
2717 {
2718 if (SUCCEED == (ret = DCconfig_get_interface(interface, dc_host->hostid, 0)))
2719 *replace_to = zbx_strdup(*replace_to, interface->addr);
2720
2721 *require_address = 1;
2722
2723 }
2724 else if (0 == strcmp(m, MVAR_HOST_TARGET_HOST))
2725 {
2726 *replace_to = zbx_strdup(*replace_to, dc_host->host);
2727 }
2728 else if (0 == strcmp(m, MVAR_HOST_TARGET_IP))
2729 {
2730 if (SUCCEED == (ret = DCconfig_get_interface(interface, dc_host->hostid, 0)))
2731 *replace_to = zbx_strdup(*replace_to, interface->ip_orig);
2732
2733 *require_address = 1;
2734 }
2735 else if (0 == strcmp(m, MVAR_HOST_TARGET_NAME))
2736 {
2737 *replace_to = zbx_strdup(*replace_to, dc_host->name);
2738 }
2739
2740 return ret;
2741 }
2742
2743 /******************************************************************************
2744 * *
2745 * Function: substitute_simple_macros_impl *
2746 * *
2747 * Purpose: substitute simple macros in data string with real values *
2748 * *
2749 * Author: Eugene Grigorjev *
2750 * *
2751 ******************************************************************************/
substitute_simple_macros_impl(const zbx_uint64_t * actionid,const DB_EVENT * event,const DB_EVENT * r_event,const zbx_uint64_t * userid,const zbx_uint64_t * hostid,const DC_HOST * dc_host,const DC_ITEM * dc_item,const DB_ALERT * alert,const DB_ACKNOWLEDGE * ack,const char * tz,char ** data,int macro_type,char * error,int maxerrlen)2752 static int substitute_simple_macros_impl(const zbx_uint64_t *actionid, const DB_EVENT *event,
2753 const DB_EVENT *r_event, const zbx_uint64_t *userid, const zbx_uint64_t *hostid, const DC_HOST *dc_host,
2754 const DC_ITEM *dc_item, const DB_ALERT *alert, const DB_ACKNOWLEDGE *ack, const char *tz, char **data,
2755 int macro_type, char *error, int maxerrlen)
2756 {
2757 char c, *replace_to = NULL, sql[64];
2758 const char *m;
2759 int N_functionid, indexed_macro, require_address, ret, res = SUCCEED,
2760 pos = 0, found, user_names_found = 0, raw_value;
2761 size_t data_alloc, data_len;
2762 DC_INTERFACE interface;
2763 zbx_vector_uint64_t hostids;
2764 const zbx_vector_uint64_t *phostids;
2765 zbx_token_t token, inner_token;
2766 zbx_token_search_t token_search = ZBX_TOKEN_SEARCH_BASIC;
2767 char *expression = NULL, *user_username = NULL, *user_name = NULL, *user_surname = NULL;
2768
2769 if (NULL == data || NULL == *data || '\0' == **data)
2770 {
2771 zabbix_log(LOG_LEVEL_DEBUG, "In %s() data:EMPTY", __func__);
2772 return res;
2773 }
2774
2775 zabbix_log(LOG_LEVEL_DEBUG, "In %s() data:'%s'", __func__, *data);
2776
2777 if (0 != (macro_type & (MACRO_TYPE_TRIGGER_DESCRIPTION | MACRO_TYPE_EVENT_NAME)))
2778 token_search |= ZBX_TOKEN_SEARCH_REFERENCES;
2779
2780 if (0 != (macro_type & (MACRO_TYPE_EVENT_NAME)))
2781 token_search |= ZBX_TOKEN_SEARCH_EXPRESSION_MACRO;
2782
2783 if (SUCCEED != zbx_token_find(*data, pos, &token, token_search))
2784 return res;
2785
2786 zbx_vector_uint64_create(&hostids);
2787
2788 data_alloc = data_len = strlen(*data) + 1;
2789
2790 for (found = SUCCEED; SUCCEED == res && SUCCEED == found;
2791 found = zbx_token_find(*data, pos, &token, token_search))
2792 {
2793 indexed_macro = 0;
2794 require_address = 0;
2795 N_functionid = 1;
2796 raw_value = 0;
2797 pos = token.loc.l;
2798 inner_token = token;
2799
2800 switch (token.type)
2801 {
2802 case ZBX_TOKEN_OBJECTID:
2803 case ZBX_TOKEN_LLD_MACRO:
2804 case ZBX_TOKEN_LLD_FUNC_MACRO:
2805 /* neither lld nor {123123} macros are processed by this function, skip them */
2806 pos = token.loc.r + 1;
2807 continue;
2808 case ZBX_TOKEN_MACRO:
2809 if (0 != is_indexed_macro(*data, &token) &&
2810 NULL != (m = macro_in_list(*data, token.loc, ex_macros, &N_functionid)))
2811 {
2812 indexed_macro = 1;
2813 }
2814 else
2815 {
2816 m = *data + token.loc.l;
2817 c = (*data)[token.loc.r + 1];
2818 (*data)[token.loc.r + 1] = '\0';
2819 }
2820 break;
2821 case ZBX_TOKEN_FUNC_MACRO:
2822 raw_value = 1;
2823 indexed_macro = is_indexed_macro(*data, &token);
2824 if (NULL == (m = func_macro_in_list(*data, &token.data.func_macro, &N_functionid)) ||
2825 SUCCEED != zbx_token_find(*data, token.data.func_macro.macro.l,
2826 &inner_token, token_search))
2827 {
2828 /* Ignore functions with macros not supporting them, but do not skip the */
2829 /* whole token, nested macro should be resolved in this case. */
2830 pos++;
2831 continue;
2832 }
2833 break;
2834 case ZBX_TOKEN_USER_MACRO:
2835 /* To avoid *data modification DCget_user_macro() should be replaced with a function */
2836 /* that takes initial *data string and token.data.user_macro instead of m as params. */
2837 m = *data + token.loc.l;
2838 c = (*data)[token.loc.r + 1];
2839 (*data)[token.loc.r + 1] = '\0';
2840 break;
2841 case ZBX_TOKEN_SIMPLE_MACRO:
2842 if (0 == (macro_type & (MACRO_TYPE_MESSAGE_NORMAL | MACRO_TYPE_MESSAGE_RECOVERY |
2843 MACRO_TYPE_MESSAGE_ACK | MACRO_TYPE_SCRIPT_NORMAL |
2844 MACRO_TYPE_SCRIPT_RECOVERY)) ||
2845 EVENT_SOURCE_TRIGGERS != ((NULL != r_event) ? r_event : event)->source)
2846 {
2847 pos++;
2848 continue;
2849 }
2850 /* These macros (and probably all other in the future) must be resolved using only */
2851 /* information stored in token.data union. For now, force crash if they rely on m. */
2852 m = NULL;
2853 break;
2854 case ZBX_TOKEN_REFERENCE:
2855 case ZBX_TOKEN_EXPRESSION_MACRO:
2856 /* These macros (and probably all other in the future) must be resolved using only */
2857 /* information stored in token.data union. For now, force crash if they rely on m. */
2858 m = NULL;
2859 break;
2860 default:
2861 THIS_SHOULD_NEVER_HAPPEN;
2862 res = FAIL;
2863 continue;
2864 }
2865
2866 ret = SUCCEED;
2867
2868 if (0 != (macro_type & (MACRO_TYPE_MESSAGE_NORMAL | MACRO_TYPE_MESSAGE_RECOVERY |
2869 MACRO_TYPE_MESSAGE_ACK |
2870 MACRO_TYPE_SCRIPT_NORMAL | MACRO_TYPE_SCRIPT_RECOVERY)))
2871 /* MACRO_TYPE_SCRIPT_NORMAL and MACRO_TYPE_SCRIPT_RECOVERY behave pretty similar to */
2872 /* MACRO_TYPE_MESSAGE_NORMAL and MACRO_TYPE_MESSAGE_RECOVERY. Therefore the code is not duplicated */
2873 /* but few conditions are added below where behavior differs. */
2874 {
2875 const DB_EVENT *c_event;
2876
2877 c_event = ((NULL != r_event) ? r_event : event);
2878
2879 if (EVENT_SOURCE_TRIGGERS == c_event->source)
2880 {
2881 if (ZBX_TOKEN_USER_MACRO == token.type)
2882 {
2883 if (NULL == dc_host)
2884 {
2885 if (SUCCEED == zbx_db_trigger_get_all_hostids(&c_event->trigger,
2886 &phostids))
2887 {
2888 DCget_user_macro(phostids->values, phostids->values_num, m,
2889 &replace_to);
2890 }
2891 }
2892 else
2893 DCget_user_macro(&dc_host->hostid, 1, m, &replace_to);
2894
2895 pos = token.loc.r;
2896 }
2897 else if (ZBX_TOKEN_SIMPLE_MACRO == token.type)
2898 {
2899 ret = get_trigger_function_value(&c_event->trigger, &replace_to,
2900 *data, &token.data.simple_macro, ZBX_FORMAT_HUMAN);
2901 }
2902 else if (NULL != actionid &&
2903 0 == strncmp(m, MVAR_ACTION, ZBX_CONST_STRLEN(MVAR_ACTION)))
2904 {
2905 ret = get_action_value(m, *actionid, &replace_to);
2906 }
2907 else if (0 == strcmp(m, MVAR_DATE))
2908 {
2909 replace_to = zbx_strdup(replace_to, zbx_date2str(time(NULL), tz));
2910 }
2911 else if (NULL != actionid && 0 == strcmp(m, MVAR_ESC_HISTORY))
2912 {
2913 get_escalation_history(*actionid, event, r_event, &replace_to, userid, tz);
2914 }
2915 else if (0 == strncmp(m, MVAR_EVENT_RECOVERY, ZBX_CONST_STRLEN(MVAR_EVENT_RECOVERY)))
2916 {
2917 if (NULL != r_event)
2918 get_recovery_event_value(m, r_event, &replace_to, tz);
2919 }
2920 else if (0 == strcmp(m, MVAR_EVENT_STATUS) || 0 == strcmp(m, MVAR_EVENT_VALUE))
2921 {
2922 get_current_event_value(m, c_event, &replace_to);
2923 }
2924 else if (0 == strcmp(m, MVAR_EVENT_NAME))
2925 {
2926 replace_to = zbx_strdup(replace_to, event->name);
2927 }
2928 else if (0 == strcmp(m, MVAR_EVENT_OPDATA))
2929 {
2930 resolve_opdata(c_event, &replace_to, tz, error, maxerrlen);
2931 }
2932 else if (0 == strcmp(m, MVAR_ACK_MESSAGE) || 0 == strcmp(m, MVAR_EVENT_UPDATE_MESSAGE))
2933 {
2934 if (0 != (macro_type & MACRO_TYPE_MESSAGE_ACK) && NULL != ack)
2935 replace_to = zbx_strdup(replace_to, ack->message);
2936 }
2937 else if (0 == strcmp(m, MVAR_ACK_TIME) || 0 == strcmp(m, MVAR_EVENT_UPDATE_TIME))
2938 {
2939 if (0 != (macro_type & MACRO_TYPE_MESSAGE_ACK) && NULL != ack)
2940 replace_to = zbx_strdup(replace_to, zbx_time2str(ack->clock, tz));
2941 }
2942 else if (0 == strcmp(m, MVAR_ACK_DATE) || 0 == strcmp(m, MVAR_EVENT_UPDATE_DATE))
2943 {
2944 if (0 != (macro_type & MACRO_TYPE_MESSAGE_ACK) && NULL != ack)
2945 replace_to = zbx_strdup(replace_to, zbx_date2str(ack->clock, tz));
2946 }
2947 else if (0 == strcmp(m, MVAR_EVENT_UPDATE_ACTION))
2948 {
2949 if (0 != (macro_type & MACRO_TYPE_MESSAGE_ACK) && NULL != ack)
2950 {
2951 get_problem_update_actions(ack, ZBX_PROBLEM_UPDATE_ACKNOWLEDGE |
2952 ZBX_PROBLEM_UPDATE_UNACKNOWLEDGE |
2953 ZBX_PROBLEM_UPDATE_CLOSE | ZBX_PROBLEM_UPDATE_MESSAGE |
2954 ZBX_PROBLEM_UPDATE_SEVERITY, &replace_to);
2955 }
2956 }
2957 else if (0 == strcmp(m, MVAR_EVENT_UPDATE_STATUS))
2958 {
2959 if (0 != (macro_type & MACRO_TYPE_MESSAGE_ACK) && NULL != ack)
2960 replace_to = zbx_strdup(replace_to, "1");
2961 else
2962 replace_to = zbx_strdup(replace_to, "0");
2963 }
2964 else if (0 == strncmp(m, MVAR_EVENT, ZBX_CONST_STRLEN(MVAR_EVENT)))
2965 {
2966 get_event_value(m, event, &replace_to, userid, r_event, tz);
2967 }
2968 else if (0 == strcmp(m, MVAR_HOST_ID))
2969 {
2970 ret = DBget_trigger_value(&event->trigger, &replace_to,
2971 N_functionid, ZBX_REQUEST_HOST_ID);
2972 }
2973 else if (0 == strcmp(m, MVAR_HOST_HOST) || 0 == strcmp(m, MVAR_HOSTNAME))
2974 {
2975 ret = DBget_trigger_value(&c_event->trigger, &replace_to,
2976 N_functionid, ZBX_REQUEST_HOST_HOST);
2977 }
2978 else if (0 == strcmp(m, MVAR_HOST_NAME))
2979 {
2980 ret = DBget_trigger_value(&c_event->trigger, &replace_to,
2981 N_functionid, ZBX_REQUEST_HOST_NAME);
2982 }
2983 else if (0 == strcmp(m, MVAR_HOST_DESCRIPTION))
2984 {
2985 ret = DBget_trigger_value(&c_event->trigger, &replace_to,
2986 N_functionid, ZBX_REQUEST_HOST_DESCRIPTION);
2987 }
2988 else if (0 == strcmp(m, MVAR_HOST_IP) || 0 == strcmp(m, MVAR_IPADDRESS))
2989 {
2990 ret = DBget_trigger_value(&c_event->trigger, &replace_to,
2991 N_functionid, ZBX_REQUEST_HOST_IP);
2992 }
2993 else if (0 == strcmp(m, MVAR_HOST_DNS))
2994 {
2995 ret = DBget_trigger_value(&c_event->trigger, &replace_to,
2996 N_functionid, ZBX_REQUEST_HOST_DNS);
2997 }
2998 else if (0 == strcmp(m, MVAR_HOST_CONN))
2999 {
3000 ret = DBget_trigger_value(&c_event->trigger, &replace_to,
3001 N_functionid, ZBX_REQUEST_HOST_CONN);
3002 }
3003 else if (0 == strcmp(m, MVAR_HOST_PORT))
3004 {
3005 ret = DBget_trigger_value(&c_event->trigger, &replace_to,
3006 N_functionid, ZBX_REQUEST_HOST_PORT);
3007 }
3008 else if (0 == strncmp(m, MVAR_INVENTORY, ZBX_CONST_STRLEN(MVAR_INVENTORY)) ||
3009 0 == strncmp(m, MVAR_PROFILE, ZBX_CONST_STRLEN(MVAR_PROFILE)))
3010 {
3011 ret = get_host_inventory(m, &c_event->trigger, &replace_to, N_functionid);
3012 }
3013 else if (0 == strcmp(m, MVAR_ITEM_DESCRIPTION))
3014 {
3015 ret = DBget_trigger_value(&c_event->trigger, &replace_to,
3016 N_functionid, ZBX_REQUEST_ITEM_DESCRIPTION);
3017 }
3018 else if (0 == strcmp(m, MVAR_ITEM_DESCRIPTION_ORIG))
3019 {
3020 ret = DBget_trigger_value(&c_event->trigger, &replace_to,
3021 N_functionid, ZBX_REQUEST_ITEM_DESCRIPTION_ORIG);
3022 }
3023 else if (0 == strcmp(m, MVAR_ITEM_ID))
3024 {
3025 ret = DBget_trigger_value(&c_event->trigger, &replace_to,
3026 N_functionid, ZBX_REQUEST_ITEM_ID);
3027 }
3028 else if (0 == strcmp(m, MVAR_ITEM_KEY) || 0 == strcmp(m, MVAR_TRIGGER_KEY))
3029 {
3030 ret = DBget_trigger_value(&c_event->trigger, &replace_to,
3031 N_functionid, ZBX_REQUEST_ITEM_KEY);
3032 }
3033 else if (0 == strcmp(m, MVAR_ITEM_KEY_ORIG))
3034 {
3035 ret = DBget_trigger_value(&c_event->trigger, &replace_to,
3036 N_functionid, ZBX_REQUEST_ITEM_KEY_ORIG);
3037 }
3038 else if (0 == strcmp(m, MVAR_ITEM_LASTVALUE))
3039 {
3040 ret = DBitem_lastvalue(&c_event->trigger, &replace_to, N_functionid,
3041 raw_value);
3042 }
3043 else if (0 == strcmp(m, MVAR_ITEM_NAME))
3044 {
3045 ret = DBget_trigger_value(&c_event->trigger, &replace_to,
3046 N_functionid, ZBX_REQUEST_ITEM_NAME);
3047 }
3048 else if (0 == strcmp(m, MVAR_ITEM_NAME_ORIG))
3049 {
3050 ret = DBget_trigger_value(&c_event->trigger, &replace_to,
3051 N_functionid, ZBX_REQUEST_ITEM_NAME_ORIG);
3052 }
3053 else if (0 == strcmp(m, MVAR_ITEM_VALUE))
3054 {
3055 ret = DBitem_value(&c_event->trigger, &replace_to, N_functionid,
3056 c_event->clock, c_event->ns, raw_value);
3057 }
3058 else if (0 == strncmp(m, MVAR_ITEM_LOG, ZBX_CONST_STRLEN(MVAR_ITEM_LOG)))
3059 {
3060 ret = get_history_log_value(m, &c_event->trigger, &replace_to,
3061 N_functionid, c_event->clock, c_event->ns, tz);
3062 }
3063 else if (0 == strcmp(m, MVAR_ITEM_VALUETYPE))
3064 {
3065 ret = DBget_trigger_value(&c_event->trigger, &replace_to,
3066 N_functionid, ZBX_REQUEST_ITEM_VALUETYPE);
3067 }
3068 else if (0 == strcmp(m, MVAR_PROXY_NAME))
3069 {
3070 ret = DBget_trigger_value(&c_event->trigger, &replace_to,
3071 N_functionid, ZBX_REQUEST_PROXY_NAME);
3072 }
3073 else if (0 == strcmp(m, MVAR_PROXY_DESCRIPTION))
3074 {
3075 ret = DBget_trigger_value(&c_event->trigger, &replace_to,
3076 N_functionid, ZBX_REQUEST_PROXY_DESCRIPTION);
3077 }
3078 else if (0 == indexed_macro && 0 == strcmp(m, MVAR_TIME))
3079 {
3080 replace_to = zbx_strdup(replace_to, zbx_time2str(time(NULL), tz));
3081 }
3082 else if (0 == strcmp(m, MVAR_TRIGGER_DESCRIPTION) ||
3083 0 == strcmp(m, MVAR_TRIGGER_COMMENT))
3084 {
3085 replace_to = zbx_strdup(replace_to, c_event->trigger.comments);
3086 substitute_simple_macros_impl(NULL, c_event, NULL, NULL, NULL, NULL, NULL, NULL,
3087 NULL, tz, &replace_to, MACRO_TYPE_TRIGGER_COMMENTS, error,
3088 maxerrlen);
3089 }
3090 else if (0 == strcmp(m, MVAR_TRIGGER_EVENTS_ACK))
3091 {
3092 ret = DBget_trigger_event_count(c_event->objectid, &replace_to, 0, 1);
3093 }
3094 else if (0 == strcmp(m, MVAR_TRIGGER_EVENTS_PROBLEM_ACK))
3095 {
3096 ret = DBget_trigger_event_count(c_event->objectid, &replace_to, 1, 1);
3097 }
3098 else if (0 == strcmp(m, MVAR_TRIGGER_EVENTS_PROBLEM_UNACK))
3099 {
3100 ret = DBget_trigger_event_count(c_event->objectid, &replace_to, 1, 0);
3101 }
3102 else if (0 == strcmp(m, MVAR_TRIGGER_EVENTS_UNACK))
3103 {
3104 ret = DBget_trigger_event_count(c_event->objectid, &replace_to, 0, 0);
3105 }
3106 else if (0 == strcmp(m, MVAR_TRIGGER_EXPRESSION))
3107 {
3108 zbx_db_trigger_get_expression(&c_event->trigger, &replace_to);
3109 }
3110 else if (0 == strcmp(m, MVAR_TRIGGER_EXPRESSION_RECOVERY))
3111 {
3112 if (TRIGGER_RECOVERY_MODE_RECOVERY_EXPRESSION == c_event->trigger.recovery_mode)
3113 {
3114 zbx_db_trigger_get_recovery_expression(&c_event->trigger, &replace_to);
3115 }
3116 else
3117 replace_to = zbx_strdup(replace_to, "");
3118 }
3119 else if (0 == strcmp(m, MVAR_TRIGGER_HOSTGROUP_NAME))
3120 {
3121 ret = DBget_trigger_hostgroup_name(c_event->objectid, userid, &replace_to);
3122 }
3123 else if (0 == strcmp(m, MVAR_TRIGGER_ID))
3124 {
3125 replace_to = zbx_dsprintf(replace_to, ZBX_FS_UI64, c_event->objectid);
3126 }
3127 else if (0 == strcmp(m, MVAR_TRIGGER_NAME))
3128 {
3129 replace_to = zbx_strdup(replace_to, c_event->trigger.description);
3130 substitute_simple_macros_impl(NULL, c_event, NULL, NULL, NULL, NULL, NULL, NULL,
3131 NULL, tz, &replace_to, MACRO_TYPE_TRIGGER_DESCRIPTION, error,
3132 maxerrlen);
3133 }
3134 else if (0 == strcmp(m, MVAR_TRIGGER_NAME_ORIG))
3135 {
3136 replace_to = zbx_strdup(replace_to, c_event->trigger.description);
3137 }
3138 else if (0 == strcmp(m, MVAR_TRIGGER_NSEVERITY))
3139 {
3140 replace_to = zbx_dsprintf(replace_to, "%d", (int)c_event->trigger.priority);
3141 }
3142 else if (0 == strcmp(m, MVAR_TRIGGER_STATUS) || 0 == strcmp(m, MVAR_STATUS))
3143 {
3144 replace_to = zbx_strdup(replace_to,
3145 zbx_trigger_value_string(c_event->trigger.value));
3146 }
3147 else if (0 == strcmp(m, MVAR_TRIGGER_SEVERITY))
3148 {
3149 ret = get_trigger_severity_name(c_event->trigger.priority, &replace_to);
3150 }
3151 else if (0 == strcmp(m, MVAR_TRIGGER_TEMPLATE_NAME))
3152 {
3153 ret = DBget_trigger_template_name(c_event->objectid, userid, &replace_to);
3154 }
3155 else if (0 == strcmp(m, MVAR_TRIGGER_URL))
3156 {
3157 replace_to = zbx_strdup(replace_to, event->trigger.url);
3158 substitute_simple_macros_impl(NULL, event, NULL, NULL, NULL, NULL, NULL, NULL,
3159 NULL, tz, &replace_to, MACRO_TYPE_TRIGGER_URL, error, maxerrlen);
3160 }
3161 else if (0 == strcmp(m, MVAR_TRIGGER_VALUE))
3162 {
3163 replace_to = zbx_dsprintf(replace_to, "%d", c_event->trigger.value);
3164 }
3165 else if (0 != (macro_type & MACRO_TYPE_MESSAGE_ACK) && NULL != ack &&
3166 0 == strcmp(m, MVAR_USER_FULLNAME))
3167 {
3168 const char *user_name1;
3169
3170 if (SUCCEED == zbx_check_user_permissions(&ack->userid, userid))
3171 user_name1 = zbx_user_string(ack->userid);
3172 else
3173 user_name1 = "Inaccessible user";
3174
3175 replace_to = zbx_strdup(replace_to, user_name1);
3176 }
3177 else if (0 == strcmp(m, MVAR_ALERT_SENDTO))
3178 {
3179 if (NULL != alert)
3180 replace_to = zbx_strdup(replace_to, alert->sendto);
3181 }
3182 else if (0 == strcmp(m, MVAR_ALERT_SUBJECT))
3183 {
3184 if (NULL != alert)
3185 replace_to = zbx_strdup(replace_to, alert->subject);
3186 }
3187 else if (0 == strcmp(m, MVAR_ALERT_MESSAGE))
3188 {
3189 if (NULL != alert)
3190 replace_to = zbx_strdup(replace_to, alert->message);
3191 }
3192 else if (0 != (macro_type & (MACRO_TYPE_SCRIPT_NORMAL | MACRO_TYPE_SCRIPT_RECOVERY)) &&
3193 NULL != userid && (0 == strcmp(m, MVAR_USER_USERNAME) ||
3194 0 == strcmp(m, MVAR_USER_NAME) || 0 == strcmp(m, MVAR_USER_SURNAME) ||
3195 0 == strcmp(m, MVAR_USER_FULLNAME) || 0 == strcmp(m, MVAR_USER_ALIAS)))
3196 {
3197 resolve_user_macros(*userid, m, &user_username, &user_name, &user_surname,
3198 &user_names_found, &replace_to);
3199 }
3200 else if (0 == (macro_type & (MACRO_TYPE_SCRIPT_NORMAL | MACRO_TYPE_SCRIPT_RECOVERY)))
3201 {
3202 ret = resolve_host_target_macros(m, dc_host, &interface, &require_address,
3203 &replace_to);
3204 }
3205 }
3206 else if (EVENT_SOURCE_INTERNAL == c_event->source && EVENT_OBJECT_TRIGGER == c_event->object)
3207 {
3208 if (ZBX_TOKEN_USER_MACRO == token.type)
3209 {
3210 if (SUCCEED == zbx_db_trigger_get_all_hostids(&c_event->trigger, &phostids))
3211 DCget_user_macro(phostids->values, phostids->values_num, m, &replace_to);
3212 pos = token.loc.r;
3213 }
3214 else if (NULL != actionid &&
3215 0 == strncmp(m, MVAR_ACTION, ZBX_CONST_STRLEN(MVAR_ACTION)))
3216 {
3217 ret = get_action_value(m, *actionid, &replace_to);
3218 }
3219 else if (0 == strcmp(m, MVAR_DATE))
3220 {
3221 replace_to = zbx_strdup(replace_to, zbx_date2str(time(NULL), tz));
3222 }
3223 else if (NULL != actionid && 0 == strcmp(m, MVAR_ESC_HISTORY))
3224 {
3225 get_escalation_history(*actionid, event, r_event, &replace_to, userid, tz);
3226 }
3227 else if (0 == strncmp(m, MVAR_EVENT_RECOVERY, ZBX_CONST_STRLEN(MVAR_EVENT_RECOVERY)))
3228 {
3229 if (NULL != r_event)
3230 get_recovery_event_value(m, r_event, &replace_to, tz);
3231 }
3232 else if (0 == strcmp(m, MVAR_EVENT_STATUS) || 0 == strcmp(m, MVAR_EVENT_VALUE))
3233 {
3234 get_current_event_value(m, c_event, &replace_to);
3235 }
3236 else if (0 == strcmp(m, MVAR_EVENT_NAME))
3237 {
3238 replace_to = zbx_strdup(replace_to, event->name);
3239 }
3240 else if (0 == strncmp(m, MVAR_EVENT, ZBX_CONST_STRLEN(MVAR_EVENT)))
3241 {
3242 get_event_value(m, event, &replace_to, userid, r_event, tz);
3243 }
3244 else if (0 == strcmp(m, MVAR_HOST_ID))
3245 {
3246 ret = DBget_trigger_value(&event->trigger, &replace_to,
3247 N_functionid, ZBX_REQUEST_HOST_ID);
3248 }
3249 else if (0 == strcmp(m, MVAR_HOST_HOST) || 0 == strcmp(m, MVAR_HOSTNAME))
3250 {
3251 ret = DBget_trigger_value(&c_event->trigger, &replace_to,
3252 N_functionid, ZBX_REQUEST_HOST_HOST);
3253 }
3254 else if (0 == strcmp(m, MVAR_HOST_NAME))
3255 {
3256 ret = DBget_trigger_value(&c_event->trigger, &replace_to,
3257 N_functionid, ZBX_REQUEST_HOST_NAME);
3258 }
3259 else if (0 == strcmp(m, MVAR_HOST_DESCRIPTION))
3260 {
3261 ret = DBget_trigger_value(&c_event->trigger, &replace_to,
3262 N_functionid, ZBX_REQUEST_HOST_DESCRIPTION);
3263 }
3264 else if (0 == strcmp(m, MVAR_HOST_IP) || 0 == strcmp(m, MVAR_IPADDRESS))
3265 {
3266 ret = DBget_trigger_value(&c_event->trigger, &replace_to,
3267 N_functionid, ZBX_REQUEST_HOST_IP);
3268 }
3269 else if (0 == strcmp(m, MVAR_HOST_DNS))
3270 {
3271 ret = DBget_trigger_value(&c_event->trigger, &replace_to,
3272 N_functionid, ZBX_REQUEST_HOST_DNS);
3273 }
3274 else if (0 == strcmp(m, MVAR_HOST_CONN))
3275 {
3276 ret = DBget_trigger_value(&c_event->trigger, &replace_to,
3277 N_functionid, ZBX_REQUEST_HOST_CONN);
3278 }
3279 else if (0 == strcmp(m, MVAR_HOST_PORT))
3280 {
3281 ret = DBget_trigger_value(&c_event->trigger, &replace_to,
3282 N_functionid, ZBX_REQUEST_HOST_PORT);
3283 }
3284 else if (0 == strncmp(m, MVAR_INVENTORY, ZBX_CONST_STRLEN(MVAR_INVENTORY)) ||
3285 0 == strncmp(m, MVAR_PROFILE, ZBX_CONST_STRLEN(MVAR_PROFILE)))
3286 {
3287 ret = get_host_inventory(m, &c_event->trigger, &replace_to,
3288 N_functionid);
3289 }
3290 else if (0 == strcmp(m, MVAR_ITEM_DESCRIPTION))
3291 {
3292 ret = DBget_trigger_value(&c_event->trigger, &replace_to,
3293 N_functionid, ZBX_REQUEST_ITEM_DESCRIPTION);
3294 }
3295 else if (0 == strcmp(m, MVAR_ITEM_DESCRIPTION_ORIG))
3296 {
3297 ret = DBget_trigger_value(&c_event->trigger, &replace_to,
3298 N_functionid, ZBX_REQUEST_ITEM_DESCRIPTION_ORIG);
3299 }
3300 else if (0 == strcmp(m, MVAR_ITEM_ID))
3301 {
3302 ret = DBget_trigger_value(&c_event->trigger, &replace_to,
3303 N_functionid, ZBX_REQUEST_ITEM_ID);
3304 }
3305 else if (0 == strcmp(m, MVAR_ITEM_KEY) || 0 == strcmp(m, MVAR_TRIGGER_KEY))
3306 {
3307 ret = DBget_trigger_value(&c_event->trigger, &replace_to,
3308 N_functionid, ZBX_REQUEST_ITEM_KEY);
3309 }
3310 else if (0 == strcmp(m, MVAR_ITEM_KEY_ORIG))
3311 {
3312 ret = DBget_trigger_value(&c_event->trigger, &replace_to,
3313 N_functionid, ZBX_REQUEST_ITEM_KEY_ORIG);
3314 }
3315 else if (0 == strcmp(m, MVAR_ITEM_NAME))
3316 {
3317 ret = DBget_trigger_value(&c_event->trigger, &replace_to,
3318 N_functionid, ZBX_REQUEST_ITEM_NAME);
3319 }
3320 else if (0 == strcmp(m, MVAR_ITEM_NAME_ORIG))
3321 {
3322 ret = DBget_trigger_value(&c_event->trigger, &replace_to,
3323 N_functionid, ZBX_REQUEST_ITEM_NAME_ORIG);
3324 }
3325 else if (0 == strcmp(m, MVAR_ITEM_VALUETYPE))
3326 {
3327 ret = DBget_trigger_value(&c_event->trigger, &replace_to,
3328 N_functionid, ZBX_REQUEST_ITEM_VALUETYPE);
3329 }
3330 else if (0 == strcmp(m, MVAR_PROXY_NAME))
3331 {
3332 ret = DBget_trigger_value(&c_event->trigger, &replace_to,
3333 N_functionid, ZBX_REQUEST_PROXY_NAME);
3334 }
3335 else if (0 == strcmp(m, MVAR_PROXY_DESCRIPTION))
3336 {
3337 ret = DBget_trigger_value(&c_event->trigger, &replace_to,
3338 N_functionid, ZBX_REQUEST_PROXY_DESCRIPTION);
3339 }
3340 else if (0 == indexed_macro && 0 == strcmp(m, MVAR_TIME))
3341 {
3342 replace_to = zbx_strdup(replace_to, zbx_time2str(time(NULL), tz));
3343 }
3344 else if (0 == strcmp(m, MVAR_TRIGGER_DESCRIPTION) ||
3345 0 == strcmp(m, MVAR_TRIGGER_COMMENT))
3346 {
3347 replace_to = zbx_strdup(replace_to, c_event->trigger.comments);
3348 substitute_simple_macros_impl(NULL, c_event, NULL, NULL, NULL, NULL, NULL, NULL,
3349 NULL, tz, &replace_to, MACRO_TYPE_TRIGGER_COMMENTS, error,
3350 maxerrlen);
3351 }
3352 else if (0 == strcmp(m, MVAR_TRIGGER_EXPRESSION))
3353 {
3354 zbx_db_trigger_get_expression(&c_event->trigger, &replace_to);
3355 }
3356 else if (0 == strcmp(m, MVAR_TRIGGER_EXPRESSION_RECOVERY))
3357 {
3358 if (TRIGGER_RECOVERY_MODE_RECOVERY_EXPRESSION == c_event->trigger.recovery_mode)
3359 {
3360 zbx_db_trigger_get_recovery_expression(&c_event->trigger, &replace_to);
3361 }
3362 else
3363 replace_to = zbx_strdup(replace_to, "");
3364 }
3365 else if (0 == strcmp(m, MVAR_TRIGGER_HOSTGROUP_NAME))
3366 {
3367 ret = DBget_trigger_hostgroup_name(c_event->objectid, userid, &replace_to);
3368 }
3369 else if (0 == strcmp(m, MVAR_TRIGGER_ID))
3370 {
3371 replace_to = zbx_dsprintf(replace_to, ZBX_FS_UI64, c_event->objectid);
3372 }
3373 else if (0 == strcmp(m, MVAR_TRIGGER_NAME))
3374 {
3375 replace_to = zbx_strdup(replace_to, c_event->trigger.description);
3376 substitute_simple_macros_impl(NULL, c_event, NULL, NULL, NULL, NULL, NULL, NULL,
3377 NULL, tz, &replace_to, MACRO_TYPE_TRIGGER_DESCRIPTION, error,
3378 maxerrlen);
3379 }
3380 else if (0 == strcmp(m, MVAR_TRIGGER_NAME_ORIG))
3381 {
3382 replace_to = zbx_strdup(replace_to, c_event->trigger.description);
3383 }
3384 else if (0 == strcmp(m, MVAR_TRIGGER_NSEVERITY))
3385 {
3386 replace_to = zbx_dsprintf(replace_to, "%d", (int)c_event->trigger.priority);
3387 }
3388 else if (0 == strcmp(m, MVAR_TRIGGER_SEVERITY))
3389 {
3390 ret = get_trigger_severity_name(c_event->trigger.priority, &replace_to);
3391 }
3392 else if (0 == strcmp(m, MVAR_TRIGGER_STATE))
3393 {
3394 replace_to = zbx_strdup(replace_to, zbx_trigger_state_string(c_event->value));
3395 }
3396 else if (0 == strcmp(m, MVAR_TRIGGER_TEMPLATE_NAME))
3397 {
3398 ret = DBget_trigger_template_name(c_event->objectid, userid, &replace_to);
3399 }
3400 else if (0 == strcmp(m, MVAR_TRIGGER_URL))
3401 {
3402 replace_to = zbx_strdup(replace_to, event->trigger.url);
3403 substitute_simple_macros_impl(NULL, event, NULL, NULL, NULL, NULL, NULL, NULL,
3404 NULL, tz, &replace_to, MACRO_TYPE_TRIGGER_URL, error, maxerrlen);
3405 }
3406 else if (0 == strcmp(m, MVAR_ALERT_SENDTO))
3407 {
3408 if (NULL != alert)
3409 replace_to = zbx_strdup(replace_to, alert->sendto);
3410 }
3411 else if (0 == strcmp(m, MVAR_ALERT_SUBJECT))
3412 {
3413 if (NULL != alert)
3414 replace_to = zbx_strdup(replace_to, alert->subject);
3415 }
3416 else if (0 == strcmp(m, MVAR_ALERT_MESSAGE))
3417 {
3418 if (NULL != alert)
3419 replace_to = zbx_strdup(replace_to, alert->message);
3420 }
3421 }
3422 else if (0 == indexed_macro && EVENT_SOURCE_DISCOVERY == c_event->source)
3423 {
3424 if (ZBX_TOKEN_USER_MACRO == token.type)
3425 {
3426 if (NULL == dc_host)
3427 DCget_user_macro(NULL, 0, m, &replace_to);
3428 else
3429 DCget_user_macro(&dc_host->hostid, 1, m, &replace_to);
3430
3431 pos = token.loc.r;
3432 }
3433 else if (NULL != actionid &&
3434 0 == strncmp(m, MVAR_ACTION, ZBX_CONST_STRLEN(MVAR_ACTION)))
3435 {
3436 ret = get_action_value(m, *actionid, &replace_to);
3437 }
3438 else if (0 == strcmp(m, MVAR_DATE))
3439 {
3440 replace_to = zbx_strdup(replace_to, zbx_date2str(time(NULL), tz));
3441 }
3442 else if (0 == strncmp(m, MVAR_EVENT, ZBX_CONST_STRLEN(MVAR_EVENT)) &&
3443 0 != strcmp(m, MVAR_EVENT_DURATION))
3444 {
3445 get_event_value(m, event, &replace_to, userid, NULL, tz);
3446 }
3447 else if (0 == strcmp(m, MVAR_DISCOVERY_DEVICE_IPADDRESS))
3448 {
3449 ret = DBget_dhost_value_by_event(c_event, &replace_to, "s.ip");
3450 }
3451 else if (0 == strcmp(m, MVAR_DISCOVERY_DEVICE_DNS))
3452 {
3453 ret = DBget_dhost_value_by_event(c_event, &replace_to, "s.dns");
3454 }
3455 else if (0 == strcmp(m, MVAR_DISCOVERY_DEVICE_STATUS))
3456 {
3457 if (SUCCEED == (ret = DBget_dhost_value_by_event(c_event, &replace_to,
3458 "h.status")))
3459 {
3460 replace_to = zbx_strdup(replace_to,
3461 zbx_dobject_status2str(atoi(replace_to)));
3462 }
3463 }
3464 else if (0 == strcmp(m, MVAR_DISCOVERY_DEVICE_UPTIME))
3465 {
3466 zbx_snprintf(sql, sizeof(sql),
3467 "case when h.status=%d then h.lastup else h.lastdown end",
3468 DOBJECT_STATUS_UP);
3469 if (SUCCEED == (ret = DBget_dhost_value_by_event(c_event, &replace_to, sql)))
3470 {
3471 replace_to = zbx_strdup(replace_to,
3472 zbx_age2str(time(NULL) - atoi(replace_to)));
3473 }
3474 }
3475 else if (0 == strcmp(m, MVAR_DISCOVERY_RULE_NAME))
3476 {
3477 ret = DBget_drule_value_by_event(c_event, &replace_to, "name");
3478 }
3479 else if (0 == strcmp(m, MVAR_DISCOVERY_SERVICE_NAME))
3480 {
3481 if (SUCCEED == (ret = DBget_dchecks_value_by_event(c_event, &replace_to,
3482 "c.type")))
3483 {
3484 replace_to = zbx_strdup(replace_to,
3485 zbx_dservice_type_string(atoi(replace_to)));
3486 }
3487 }
3488 else if (0 == strcmp(m, MVAR_DISCOVERY_SERVICE_PORT))
3489 {
3490 ret = DBget_dservice_value_by_event(c_event, &replace_to, "s.port");
3491 }
3492 else if (0 == strcmp(m, MVAR_DISCOVERY_SERVICE_STATUS))
3493 {
3494 if (SUCCEED == (ret = DBget_dservice_value_by_event(c_event, &replace_to,
3495 "s.status")))
3496 {
3497 replace_to = zbx_strdup(replace_to,
3498 zbx_dobject_status2str(atoi(replace_to)));
3499 }
3500 }
3501 else if (0 == strcmp(m, MVAR_DISCOVERY_SERVICE_UPTIME))
3502 {
3503 zbx_snprintf(sql, sizeof(sql),
3504 "case when s.status=%d then s.lastup else s.lastdown end",
3505 DOBJECT_STATUS_UP);
3506 if (SUCCEED == (ret = DBget_dservice_value_by_event(c_event, &replace_to, sql)))
3507 {
3508 replace_to = zbx_strdup(replace_to,
3509 zbx_age2str(time(NULL) - atoi(replace_to)));
3510 }
3511 }
3512 else if (0 == strcmp(m, MVAR_PROXY_NAME))
3513 {
3514 if (SUCCEED == (ret = DBget_dhost_value_by_event(c_event, &replace_to,
3515 "r.proxy_hostid")))
3516 {
3517 zbx_uint64_t proxy_hostid;
3518
3519 ZBX_DBROW2UINT64(proxy_hostid, replace_to);
3520
3521 if (0 == proxy_hostid)
3522 replace_to = zbx_strdup(replace_to, "");
3523 else
3524 ret = DBget_host_value(proxy_hostid, &replace_to, "host");
3525 }
3526 }
3527 else if (0 == strcmp(m, MVAR_PROXY_DESCRIPTION))
3528 {
3529 if (SUCCEED == (ret = DBget_dhost_value_by_event(c_event, &replace_to,
3530 "r.proxy_hostid")))
3531 {
3532 zbx_uint64_t proxy_hostid;
3533
3534 ZBX_DBROW2UINT64(proxy_hostid, replace_to);
3535
3536 if (0 == proxy_hostid)
3537 {
3538 replace_to = zbx_strdup(replace_to, "");
3539 }
3540 else
3541 {
3542 ret = DBget_host_value(proxy_hostid, &replace_to,
3543 "description");
3544 }
3545 }
3546 }
3547 else if (0 == strcmp(m, MVAR_TIME))
3548 {
3549 replace_to = zbx_strdup(replace_to, zbx_time2str(time(NULL), tz));
3550 }
3551 else if (0 == strcmp(m, MVAR_ALERT_SENDTO))
3552 {
3553 if (NULL != alert)
3554 replace_to = zbx_strdup(replace_to, alert->sendto);
3555 }
3556 else if (0 == strcmp(m, MVAR_ALERT_SUBJECT))
3557 {
3558 if (NULL != alert)
3559 replace_to = zbx_strdup(replace_to, alert->subject);
3560 }
3561 else if (0 == strcmp(m, MVAR_ALERT_MESSAGE))
3562 {
3563 if (NULL != alert)
3564 replace_to = zbx_strdup(replace_to, alert->message);
3565 }
3566 else
3567 {
3568 ret = resolve_host_target_macros(m, dc_host, &interface, &require_address,
3569 &replace_to);
3570 }
3571 }
3572 else if (0 == indexed_macro && EVENT_SOURCE_AUTOREGISTRATION == c_event->source)
3573 {
3574 if (ZBX_TOKEN_USER_MACRO == token.type)
3575 {
3576 if (NULL == dc_host)
3577 DCget_user_macro(NULL, 0, m, &replace_to);
3578 else
3579 DCget_user_macro(&dc_host->hostid, 1, m, &replace_to);
3580
3581 pos = token.loc.r;
3582 }
3583 else if (NULL != actionid &&
3584 0 == strncmp(m, MVAR_ACTION, ZBX_CONST_STRLEN(MVAR_ACTION)))
3585 {
3586 ret = get_action_value(m, *actionid, &replace_to);
3587 }
3588 else if (0 == strcmp(m, MVAR_DATE))
3589 {
3590 replace_to = zbx_strdup(replace_to, zbx_date2str(time(NULL), tz));
3591 }
3592 else if (0 == strncmp(m, MVAR_EVENT, ZBX_CONST_STRLEN(MVAR_EVENT)) &&
3593 0 != strcmp(m, MVAR_EVENT_DURATION))
3594 {
3595 get_event_value(m, event, &replace_to, userid, NULL, tz);
3596 }
3597 else if (0 == strcmp(m, MVAR_HOST_METADATA))
3598 {
3599 ret = get_autoreg_value_by_event(c_event, &replace_to, "host_metadata");
3600 }
3601 else if (0 == strcmp(m, MVAR_HOST_HOST))
3602 {
3603 ret = get_autoreg_value_by_event(c_event, &replace_to, "host");
3604 }
3605 else if (0 == strcmp(m, MVAR_HOST_IP) || 0 == strcmp(m, MVAR_IPADDRESS))
3606 {
3607 ret = get_autoreg_value_by_event(c_event, &replace_to, "listen_ip");
3608 }
3609 else if (0 == strcmp(m, MVAR_HOST_PORT))
3610 {
3611 ret = get_autoreg_value_by_event(c_event, &replace_to, "listen_port");
3612 }
3613 else if (0 == strcmp(m, MVAR_PROXY_NAME))
3614 {
3615 if (SUCCEED == (ret = get_autoreg_value_by_event(c_event, &replace_to,
3616 "proxy_hostid")))
3617 {
3618 zbx_uint64_t proxy_hostid;
3619
3620 ZBX_DBROW2UINT64(proxy_hostid, replace_to);
3621
3622 if (0 == proxy_hostid)
3623 replace_to = zbx_strdup(replace_to, "");
3624 else
3625 ret = DBget_host_value(proxy_hostid, &replace_to, "host");
3626 }
3627 }
3628 else if (0 == strcmp(m, MVAR_PROXY_DESCRIPTION))
3629 {
3630 if (SUCCEED == (ret = get_autoreg_value_by_event(c_event, &replace_to,
3631 "proxy_hostid")))
3632 {
3633 zbx_uint64_t proxy_hostid;
3634
3635 ZBX_DBROW2UINT64(proxy_hostid, replace_to);
3636
3637 if (0 == proxy_hostid)
3638 {
3639 replace_to = zbx_strdup(replace_to, "");
3640 }
3641 else
3642 {
3643 ret = DBget_host_value(proxy_hostid, &replace_to,
3644 "description");
3645 }
3646 }
3647 }
3648 else if (0 == strcmp(m, MVAR_TIME))
3649 {
3650 replace_to = zbx_strdup(replace_to, zbx_time2str(time(NULL), tz));
3651 }
3652 else if (0 == strcmp(m, MVAR_ALERT_SENDTO))
3653 {
3654 if (NULL != alert)
3655 replace_to = zbx_strdup(replace_to, alert->sendto);
3656 }
3657 else if (0 == strcmp(m, MVAR_ALERT_SUBJECT))
3658 {
3659 if (NULL != alert)
3660 replace_to = zbx_strdup(replace_to, alert->subject);
3661 }
3662 else if (0 == strcmp(m, MVAR_ALERT_MESSAGE))
3663 {
3664 if (NULL != alert)
3665 replace_to = zbx_strdup(replace_to, alert->message);
3666 }
3667 else
3668 {
3669 ret = resolve_host_target_macros(m, dc_host, &interface, &require_address,
3670 &replace_to);
3671 }
3672 }
3673 else if (0 == indexed_macro && EVENT_SOURCE_INTERNAL == c_event->source &&
3674 EVENT_OBJECT_ITEM == c_event->object)
3675 {
3676 if (ZBX_TOKEN_USER_MACRO == token.type)
3677 {
3678 cache_item_hostid(&hostids, c_event->objectid);
3679 DCget_user_macro(hostids.values, hostids.values_num, m, &replace_to);
3680 pos = token.loc.r;
3681 }
3682 else if (NULL != actionid &&
3683 0 == strncmp(m, MVAR_ACTION, ZBX_CONST_STRLEN(MVAR_ACTION)))
3684 {
3685 ret = get_action_value(m, *actionid, &replace_to);
3686 }
3687 else if (0 == strcmp(m, MVAR_DATE))
3688 {
3689 replace_to = zbx_strdup(replace_to, zbx_date2str(time(NULL), tz));
3690 }
3691 else if (NULL != actionid && 0 == strcmp(m, MVAR_ESC_HISTORY))
3692 {
3693 get_escalation_history(*actionid, event, r_event, &replace_to, userid, tz);
3694 }
3695 else if (0 == strncmp(m, MVAR_EVENT_RECOVERY, ZBX_CONST_STRLEN(MVAR_EVENT_RECOVERY)))
3696 {
3697 if (NULL != r_event)
3698 get_recovery_event_value(m, r_event, &replace_to, tz);
3699 }
3700 else if (0 == strcmp(m, MVAR_EVENT_STATUS) || 0 == strcmp(m, MVAR_EVENT_VALUE))
3701 {
3702 get_current_event_value(m, c_event, &replace_to);
3703 }
3704 else if (0 == strcmp(m, MVAR_EVENT_NAME))
3705 {
3706 replace_to = zbx_strdup(replace_to, event->name);
3707 }
3708 else if (0 == strncmp(m, MVAR_EVENT, ZBX_CONST_STRLEN(MVAR_EVENT)))
3709 {
3710 get_event_value(m, event, &replace_to, userid, r_event, tz);
3711 }
3712 else if (0 == strcmp(m, MVAR_HOST_ID))
3713 {
3714 ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_HOST_ID);
3715 }
3716 else if (0 == strcmp(m, MVAR_HOST_HOST) || 0 == strcmp(m, MVAR_HOSTNAME))
3717 {
3718 ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_HOST_HOST);
3719 }
3720 else if (0 == strcmp(m, MVAR_HOST_NAME))
3721 {
3722 ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_HOST_NAME);
3723 }
3724 else if (0 == strcmp(m, MVAR_HOST_DESCRIPTION))
3725 {
3726 ret = DBget_item_value(c_event->objectid, &replace_to,
3727 ZBX_REQUEST_HOST_DESCRIPTION);
3728 }
3729 else if (0 == strcmp(m, MVAR_HOST_IP) || 0 == strcmp(m, MVAR_IPADDRESS))
3730 {
3731 ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_HOST_IP);
3732 }
3733 else if (0 == strcmp(m, MVAR_HOST_DNS))
3734 {
3735 ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_HOST_DNS);
3736 }
3737 else if (0 == strcmp(m, MVAR_HOST_CONN))
3738 {
3739 ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_HOST_CONN);
3740 }
3741 else if (0 == strcmp(m, MVAR_HOST_PORT))
3742 {
3743 ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_HOST_PORT);
3744 }
3745 else if (0 == strncmp(m, MVAR_INVENTORY, ZBX_CONST_STRLEN(MVAR_INVENTORY)) ||
3746 0 == strncmp(m, MVAR_PROFILE, ZBX_CONST_STRLEN(MVAR_PROFILE)))
3747 {
3748 ret = get_host_inventory_by_itemid(m, c_event->objectid, &replace_to);
3749 }
3750 else if (0 == strcmp(m, MVAR_ITEM_DESCRIPTION))
3751 {
3752 ret = DBget_item_value(c_event->objectid, &replace_to,
3753 ZBX_REQUEST_ITEM_DESCRIPTION);
3754 }
3755 else if (0 == strcmp(m, MVAR_ITEM_DESCRIPTION_ORIG))
3756 {
3757 ret = DBget_item_value(c_event->objectid, &replace_to,
3758 ZBX_REQUEST_ITEM_DESCRIPTION_ORIG);
3759 }
3760 else if (0 == strcmp(m, MVAR_ITEM_ID))
3761 {
3762 replace_to = zbx_dsprintf(replace_to, ZBX_FS_UI64, c_event->objectid);
3763 }
3764 else if (0 == strcmp(m, MVAR_ITEM_KEY) || 0 == strcmp(m, MVAR_TRIGGER_KEY))
3765 {
3766 ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_ITEM_KEY);
3767 }
3768 else if (0 == strcmp(m, MVAR_ITEM_KEY_ORIG))
3769 {
3770 ret = DBget_item_value(c_event->objectid, &replace_to,
3771 ZBX_REQUEST_ITEM_KEY_ORIG);
3772 }
3773 else if (0 == strcmp(m, MVAR_ITEM_NAME))
3774 {
3775 ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_ITEM_NAME);
3776 }
3777 else if (0 == strcmp(m, MVAR_ITEM_NAME_ORIG))
3778 {
3779 ret = DBget_item_value(c_event->objectid, &replace_to,
3780 ZBX_REQUEST_ITEM_NAME_ORIG);
3781 }
3782 else if (0 == strcmp(m, MVAR_ITEM_STATE))
3783 {
3784 replace_to = zbx_strdup(replace_to, zbx_item_state_string(c_event->value));
3785 }
3786 else if (0 == strcmp(m, MVAR_ITEM_VALUETYPE))
3787 {
3788 ret = DBget_item_value(c_event->objectid, &replace_to,
3789 ZBX_REQUEST_ITEM_VALUETYPE);
3790 }
3791 else if (0 == strcmp(m, MVAR_PROXY_NAME))
3792 {
3793 ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_PROXY_NAME);
3794 }
3795 else if (0 == strcmp(m, MVAR_PROXY_DESCRIPTION))
3796 {
3797 ret = DBget_item_value(c_event->objectid, &replace_to,
3798 ZBX_REQUEST_PROXY_DESCRIPTION);
3799 }
3800 else if (0 == strcmp(m, MVAR_TIME))
3801 {
3802 replace_to = zbx_strdup(replace_to, zbx_time2str(time(NULL), tz));
3803 }
3804 else if (0 == strcmp(m, MVAR_ALERT_SENDTO))
3805 {
3806 if (NULL != alert)
3807 replace_to = zbx_strdup(replace_to, alert->sendto);
3808 }
3809 else if (0 == strcmp(m, MVAR_ALERT_SUBJECT))
3810 {
3811 if (NULL != alert)
3812 replace_to = zbx_strdup(replace_to, alert->subject);
3813 }
3814 else if (0 == strcmp(m, MVAR_ALERT_MESSAGE))
3815 {
3816 if (NULL != alert)
3817 replace_to = zbx_strdup(replace_to, alert->message);
3818 }
3819 }
3820 else if (0 == indexed_macro && EVENT_SOURCE_INTERNAL == c_event->source &&
3821 EVENT_OBJECT_LLDRULE == c_event->object)
3822 {
3823 if (ZBX_TOKEN_USER_MACRO == token.type)
3824 {
3825 cache_item_hostid(&hostids, c_event->objectid);
3826 DCget_user_macro(hostids.values, hostids.values_num, m, &replace_to);
3827 pos = token.loc.r;
3828 }
3829 else if (NULL != actionid &&
3830 0 == strncmp(m, MVAR_ACTION, ZBX_CONST_STRLEN(MVAR_ACTION)))
3831 {
3832 ret = get_action_value(m, *actionid, &replace_to);
3833 }
3834 else if (0 == strcmp(m, MVAR_DATE))
3835 {
3836 replace_to = zbx_strdup(replace_to, zbx_date2str(time(NULL), tz));
3837 }
3838 else if (NULL != actionid && 0 == strcmp(m, MVAR_ESC_HISTORY))
3839 {
3840 get_escalation_history(*actionid, event, r_event, &replace_to, userid, tz);
3841 }
3842 else if (0 == strncmp(m, MVAR_EVENT_RECOVERY, ZBX_CONST_STRLEN(MVAR_EVENT_RECOVERY)))
3843 {
3844 if (NULL != r_event)
3845 get_recovery_event_value(m, r_event, &replace_to, tz);
3846 }
3847 else if (0 == strcmp(m, MVAR_EVENT_STATUS) || 0 == strcmp(m, MVAR_EVENT_VALUE))
3848 {
3849 get_current_event_value(m, c_event, &replace_to);
3850 }
3851 else if (0 == strncmp(m, MVAR_EVENT, ZBX_CONST_STRLEN(MVAR_EVENT)))
3852 {
3853 get_event_value(m, event, &replace_to, userid, r_event, tz);
3854 }
3855 else if (0 == strcmp(m, MVAR_HOST_ID))
3856 {
3857 ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_HOST_ID);
3858 }
3859 else if (0 == strcmp(m, MVAR_HOST_HOST) || 0 == strcmp(m, MVAR_HOSTNAME))
3860 {
3861 ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_HOST_HOST);
3862 }
3863 else if (0 == strcmp(m, MVAR_HOST_NAME))
3864 {
3865 ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_HOST_NAME);
3866 }
3867 else if (0 == strcmp(m, MVAR_HOST_DESCRIPTION))
3868 {
3869 ret = DBget_item_value(c_event->objectid, &replace_to,
3870 ZBX_REQUEST_HOST_DESCRIPTION);
3871 }
3872 else if (0 == strcmp(m, MVAR_HOST_IP) || 0 == strcmp(m, MVAR_IPADDRESS))
3873 {
3874 ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_HOST_IP);
3875 }
3876 else if (0 == strcmp(m, MVAR_HOST_DNS))
3877 {
3878 ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_HOST_DNS);
3879 }
3880 else if (0 == strcmp(m, MVAR_HOST_CONN))
3881 {
3882 ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_HOST_CONN);
3883 }
3884 else if (0 == strcmp(m, MVAR_HOST_PORT))
3885 {
3886 ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_HOST_PORT);
3887 }
3888 else if (0 == strncmp(m, MVAR_INVENTORY, ZBX_CONST_STRLEN(MVAR_INVENTORY)) ||
3889 0 == strncmp(m, MVAR_PROFILE, ZBX_CONST_STRLEN(MVAR_PROFILE)))
3890 {
3891 ret = get_host_inventory_by_itemid(m, c_event->objectid, &replace_to);
3892 }
3893 else if (0 == strcmp(m, MVAR_LLDRULE_DESCRIPTION))
3894 {
3895 ret = DBget_item_value(c_event->objectid, &replace_to,
3896 ZBX_REQUEST_ITEM_DESCRIPTION);
3897 }
3898 else if (0 == strcmp(m, MVAR_LLDRULE_DESCRIPTION_ORIG))
3899 {
3900 ret = DBget_item_value(c_event->objectid, &replace_to,
3901 ZBX_REQUEST_ITEM_DESCRIPTION_ORIG);
3902 }
3903 else if (0 == strcmp(m, MVAR_LLDRULE_ID))
3904 {
3905 replace_to = zbx_dsprintf(replace_to, ZBX_FS_UI64, c_event->objectid);
3906 }
3907 else if (0 == strcmp(m, MVAR_LLDRULE_KEY))
3908 {
3909 ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_ITEM_KEY);
3910 }
3911 else if (0 == strcmp(m, MVAR_LLDRULE_KEY_ORIG))
3912 {
3913 ret = DBget_item_value(c_event->objectid, &replace_to,
3914 ZBX_REQUEST_ITEM_KEY_ORIG);
3915 }
3916 else if (0 == strcmp(m, MVAR_LLDRULE_NAME))
3917 {
3918 ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_ITEM_NAME);
3919 }
3920 else if (0 == strcmp(m, MVAR_LLDRULE_NAME_ORIG))
3921 {
3922 ret = DBget_item_value(c_event->objectid, &replace_to,
3923 ZBX_REQUEST_ITEM_NAME_ORIG);
3924 }
3925 else if (0 == strcmp(m, MVAR_LLDRULE_STATE))
3926 {
3927 replace_to = zbx_strdup(replace_to, zbx_item_state_string(c_event->value));
3928 }
3929 else if (0 == strcmp(m, MVAR_PROXY_NAME))
3930 {
3931 ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_PROXY_NAME);
3932 }
3933 else if (0 == strcmp(m, MVAR_PROXY_DESCRIPTION))
3934 {
3935 ret = DBget_item_value(c_event->objectid, &replace_to,
3936 ZBX_REQUEST_PROXY_DESCRIPTION);
3937 }
3938 else if (0 == strcmp(m, MVAR_TIME))
3939 {
3940 replace_to = zbx_strdup(replace_to, zbx_time2str(time(NULL), tz));
3941 }
3942 else if (0 == strcmp(m, MVAR_ALERT_SENDTO))
3943 {
3944 if (NULL != alert)
3945 replace_to = zbx_strdup(replace_to, alert->sendto);
3946 }
3947 else if (0 == strcmp(m, MVAR_ALERT_SUBJECT))
3948 {
3949 if (NULL != alert)
3950 replace_to = zbx_strdup(replace_to, alert->subject);
3951 }
3952 else if (0 == strcmp(m, MVAR_ALERT_MESSAGE))
3953 {
3954 if (NULL != alert)
3955 replace_to = zbx_strdup(replace_to, alert->message);
3956 }
3957 }
3958 }
3959 else if (0 != (macro_type & (MACRO_TYPE_TRIGGER_DESCRIPTION | MACRO_TYPE_TRIGGER_COMMENTS |
3960 MACRO_TYPE_EVENT_NAME)))
3961 {
3962 if (EVENT_OBJECT_TRIGGER == event->object)
3963 {
3964 if (ZBX_TOKEN_USER_MACRO == token.type)
3965 {
3966 if (SUCCEED == zbx_db_trigger_get_all_hostids(&event->trigger, &phostids))
3967 DCget_user_macro(phostids->values, phostids->values_num, m, &replace_to);
3968 pos = token.loc.r;
3969 }
3970 else if (ZBX_TOKEN_REFERENCE == token.type)
3971 {
3972 if (SUCCEED != zbx_db_trigger_get_constant(&event->trigger,
3973 token.data.reference.index, &replace_to))
3974 {
3975 /* expansion failed, reference substitution is impossible */
3976 token_search &= ~ZBX_TOKEN_SEARCH_REFERENCES;
3977 continue;
3978 }
3979 }
3980 else if (ZBX_TOKEN_EXPRESSION_MACRO == inner_token.type)
3981 {
3982 if (0 != (macro_type & MACRO_TYPE_EVENT_NAME))
3983 {
3984 char *exp = NULL, *errmsg = NULL;
3985 size_t exp_alloc = 0, exp_offset = 0;
3986 zbx_strloc_t *loc = &inner_token.data.expression_macro.expression;
3987
3988 zbx_strncpy_alloc(&exp, &exp_alloc, &exp_offset, *data + loc->l,
3989 loc->r - loc->l + 1);
3990
3991 ret = get_expression_macro_result(event, r_event, exp, &replace_to,
3992 &errmsg);
3993 zbx_free(exp);
3994
3995 if (SUCCEED != ret)
3996 {
3997 *errmsg = tolower(*errmsg);
3998 zabbix_log(LOG_LEVEL_DEBUG, "%s() cannot evaluate"
3999 " expression macro: %s", __func__, errmsg);
4000 zbx_strlcpy(error, errmsg, maxerrlen);
4001 zbx_free(errmsg);
4002 }
4003 }
4004 }
4005 else if (0 == strcmp(m, MVAR_HOST_HOST) || 0 == strcmp(m, MVAR_HOSTNAME))
4006 {
4007 ret = DBget_trigger_value(&event->trigger, &replace_to, N_functionid,
4008 ZBX_REQUEST_HOST_HOST);
4009 }
4010 else if (0 == strcmp(m, MVAR_HOST_NAME))
4011 {
4012 ret = DBget_trigger_value(&event->trigger, &replace_to, N_functionid,
4013 ZBX_REQUEST_HOST_NAME);
4014 }
4015 else if (0 == strcmp(m, MVAR_HOST_IP) || 0 == strcmp(m, MVAR_IPADDRESS))
4016 {
4017 ret = DBget_trigger_value(&event->trigger, &replace_to, N_functionid,
4018 ZBX_REQUEST_HOST_IP);
4019 }
4020 else if (0 == strcmp(m, MVAR_HOST_DNS))
4021 {
4022 ret = DBget_trigger_value(&event->trigger, &replace_to, N_functionid,
4023 ZBX_REQUEST_HOST_DNS);
4024 }
4025 else if (0 == strcmp(m, MVAR_HOST_CONN))
4026 {
4027 ret = DBget_trigger_value(&event->trigger, &replace_to, N_functionid,
4028 ZBX_REQUEST_HOST_CONN);
4029 }
4030 else if (0 == strcmp(m, MVAR_HOST_PORT))
4031 {
4032 ret = DBget_trigger_value(&event->trigger, &replace_to, N_functionid,
4033 ZBX_REQUEST_HOST_PORT);
4034 }
4035 else if (0 == strcmp(m, MVAR_ITEM_VALUE))
4036 {
4037 ret = DBitem_value(&event->trigger, &replace_to, N_functionid,
4038 event->clock, event->ns, raw_value);
4039 }
4040 else if (0 == strncmp(m, MVAR_ITEM_LOG, ZBX_CONST_STRLEN(MVAR_ITEM_LOG)))
4041 {
4042 ret = get_history_log_value(m, &event->trigger, &replace_to,
4043 N_functionid, event->clock, event->ns, tz);
4044 }
4045 else if (0 == strcmp(m, MVAR_ITEM_LASTVALUE))
4046 {
4047 ret = DBitem_lastvalue(&event->trigger, &replace_to, N_functionid,
4048 raw_value);
4049 }
4050 else if (0 == strcmp(m, MVAR_TIME) && 0 != (macro_type & MACRO_TYPE_EVENT_NAME))
4051 {
4052 replace_to = zbx_strdup(replace_to, zbx_time2str(time(NULL), tz));
4053 }
4054 }
4055 }
4056 else if (0 != (macro_type & MACRO_TYPE_TRIGGER_EXPRESSION))
4057 {
4058 if (EVENT_OBJECT_TRIGGER == event->object)
4059 {
4060 if (0 == strcmp(m, MVAR_TRIGGER_VALUE))
4061 replace_to = zbx_dsprintf(replace_to, "%d", event->value);
4062 }
4063 }
4064 else if (0 != (macro_type & MACRO_TYPE_TRIGGER_URL))
4065 {
4066 if (EVENT_OBJECT_TRIGGER == event->object)
4067 {
4068 if (ZBX_TOKEN_USER_MACRO == token.type)
4069 {
4070 if (SUCCEED == zbx_db_trigger_get_all_hostids(&event->trigger, &phostids))
4071 DCget_user_macro(phostids->values, phostids->values_num, m, &replace_to);
4072 pos = token.loc.r;
4073 }
4074 else if (0 == strcmp(m, MVAR_HOST_ID))
4075 {
4076 ret = DBget_trigger_value(&event->trigger, &replace_to, N_functionid,
4077 ZBX_REQUEST_HOST_ID);
4078 }
4079 else if (0 == strcmp(m, MVAR_HOST_HOST))
4080 {
4081 ret = DBget_trigger_value(&event->trigger, &replace_to, N_functionid,
4082 ZBX_REQUEST_HOST_HOST);
4083 }
4084 else if (0 == strcmp(m, MVAR_HOST_NAME))
4085 {
4086 ret = DBget_trigger_value(&event->trigger, &replace_to, N_functionid,
4087 ZBX_REQUEST_HOST_NAME);
4088 }
4089 else if (0 == strcmp(m, MVAR_HOST_IP))
4090 {
4091 ret = DBget_trigger_value(&event->trigger, &replace_to, N_functionid,
4092 ZBX_REQUEST_HOST_IP);
4093 }
4094 else if (0 == strcmp(m, MVAR_HOST_DNS))
4095 {
4096 ret = DBget_trigger_value(&event->trigger, &replace_to, N_functionid,
4097 ZBX_REQUEST_HOST_DNS);
4098 }
4099 else if (0 == strcmp(m, MVAR_HOST_CONN))
4100 {
4101 ret = DBget_trigger_value(&event->trigger, &replace_to, N_functionid,
4102 ZBX_REQUEST_HOST_CONN);
4103 }
4104 else if (0 == strcmp(m, MVAR_HOST_PORT))
4105 {
4106 ret = DBget_trigger_value(&event->trigger, &replace_to, N_functionid,
4107 ZBX_REQUEST_HOST_PORT);
4108 }
4109 else if (0 == strcmp(m, MVAR_TRIGGER_ID))
4110 {
4111 replace_to = zbx_dsprintf(replace_to, ZBX_FS_UI64, event->objectid);
4112 }
4113 else if (0 == strcmp(m, MVAR_ITEM_LASTVALUE))
4114 {
4115 ret = DBitem_lastvalue(&event->trigger, &replace_to, N_functionid,
4116 raw_value);
4117 }
4118 else if (0 == strcmp(m, MVAR_ITEM_VALUE))
4119 {
4120 ret = DBitem_value(&event->trigger, &replace_to, N_functionid,
4121 event->clock, event->ns, raw_value);
4122 }
4123 else if (0 == strncmp(m, MVAR_ITEM_LOG, ZBX_CONST_STRLEN(MVAR_ITEM_LOG)))
4124 {
4125 ret = get_history_log_value(m, &event->trigger, &replace_to,
4126 N_functionid, event->clock, event->ns, tz);
4127 }
4128 else if (0 == strcmp(m, MVAR_EVENT_ID))
4129 {
4130 get_event_value(m, event, &replace_to, userid, NULL, NULL);
4131 }
4132 }
4133 }
4134 else if (0 == indexed_macro &&
4135 0 != (macro_type & (MACRO_TYPE_ITEM_KEY | MACRO_TYPE_PARAMS_FIELD |
4136 MACRO_TYPE_LLD_FILTER | MACRO_TYPE_ALLOWED_HOSTS |
4137 MACRO_TYPE_SCRIPT_PARAMS_FIELD)))
4138 {
4139 if (ZBX_TOKEN_USER_MACRO == token.type)
4140 {
4141 DCget_user_macro(&dc_item->host.hostid, 1, m, &replace_to);
4142 pos = token.loc.r;
4143 }
4144 else if (0 == strcmp(m, MVAR_HOST_HOST) || 0 == strcmp(m, MVAR_HOSTNAME))
4145 replace_to = zbx_strdup(replace_to, dc_item->host.host);
4146 else if (0 == strcmp(m, MVAR_HOST_NAME))
4147 replace_to = zbx_strdup(replace_to, dc_item->host.name);
4148 else if (0 == strcmp(m, MVAR_HOST_IP) || 0 == strcmp(m, MVAR_IPADDRESS))
4149 {
4150 if (INTERFACE_TYPE_UNKNOWN != dc_item->interface.type)
4151 {
4152 replace_to = zbx_strdup(replace_to, dc_item->interface.ip_orig);
4153 }
4154 else
4155 {
4156 ret = get_interface_value(dc_item->host.hostid, dc_item->itemid, &replace_to,
4157 ZBX_REQUEST_HOST_IP);
4158 }
4159 }
4160 else if (0 == strcmp(m, MVAR_HOST_DNS))
4161 {
4162 if (INTERFACE_TYPE_UNKNOWN != dc_item->interface.type)
4163 {
4164 replace_to = zbx_strdup(replace_to, dc_item->interface.dns_orig);
4165 }
4166 else
4167 {
4168 ret = get_interface_value(dc_item->host.hostid, dc_item->itemid, &replace_to,
4169 ZBX_REQUEST_HOST_DNS);
4170 }
4171 }
4172 else if (0 == strcmp(m, MVAR_HOST_CONN))
4173 {
4174 if (INTERFACE_TYPE_UNKNOWN != dc_item->interface.type)
4175 {
4176 replace_to = zbx_strdup(replace_to, dc_item->interface.addr);
4177 }
4178 else
4179 {
4180 ret = get_interface_value(dc_item->host.hostid, dc_item->itemid, &replace_to,
4181 ZBX_REQUEST_HOST_CONN);
4182 }
4183 }
4184 else if (0 != (macro_type & MACRO_TYPE_SCRIPT_PARAMS_FIELD))
4185 {
4186 if (0 == strcmp(m, MVAR_ITEM_ID))
4187 {
4188 replace_to = zbx_dsprintf(replace_to, ZBX_FS_UI64, dc_item->itemid);
4189 }
4190 else if (0 == strcmp(m, MVAR_ITEM_KEY))
4191 {
4192 replace_to = zbx_strdup(replace_to, dc_item->key);
4193 }
4194 else if (0 == strcmp(m, MVAR_ITEM_KEY_ORIG))
4195 {
4196 replace_to = zbx_strdup(replace_to, dc_item->key_orig);
4197 }
4198 }
4199 }
4200 else if (0 == indexed_macro && 0 != (macro_type & MACRO_TYPE_INTERFACE_ADDR))
4201 {
4202 if (ZBX_TOKEN_USER_MACRO == token.type)
4203 {
4204 DCget_user_macro(&dc_host->hostid, 1, m, &replace_to);
4205 pos = token.loc.r;
4206 }
4207 else if (0 == strcmp(m, MVAR_HOST_HOST) || 0 == strcmp(m, MVAR_HOSTNAME))
4208 replace_to = zbx_strdup(replace_to, dc_host->host);
4209 else if (0 == strcmp(m, MVAR_HOST_NAME))
4210 replace_to = zbx_strdup(replace_to, dc_host->name);
4211 else if (0 == strcmp(m, MVAR_HOST_IP) || 0 == strcmp(m, MVAR_IPADDRESS))
4212 {
4213 if (SUCCEED == (ret = DCconfig_get_interface_by_type(&interface,
4214 dc_host->hostid, INTERFACE_TYPE_AGENT)))
4215 {
4216 replace_to = zbx_strdup(replace_to, interface.ip_orig);
4217 }
4218 }
4219 else if (0 == strcmp(m, MVAR_HOST_DNS))
4220 {
4221 if (SUCCEED == (ret = DCconfig_get_interface_by_type(&interface,
4222 dc_host->hostid, INTERFACE_TYPE_AGENT)))
4223 {
4224 replace_to = zbx_strdup(replace_to, interface.dns_orig);
4225 }
4226 }
4227 else if (0 == strcmp(m, MVAR_HOST_CONN))
4228 {
4229 if (SUCCEED == (ret = DCconfig_get_interface_by_type(&interface,
4230 dc_host->hostid, INTERFACE_TYPE_AGENT)))
4231 {
4232 replace_to = zbx_strdup(replace_to, interface.addr);
4233 }
4234 }
4235 }
4236 else if (0 != (macro_type & (MACRO_TYPE_COMMON | MACRO_TYPE_SNMP_OID)))
4237 {
4238 if (ZBX_TOKEN_USER_MACRO == token.type)
4239 {
4240 if (NULL != hostid)
4241 DCget_user_macro(hostid, 1, m, &replace_to);
4242 else
4243 DCget_user_macro(NULL, 0, m, &replace_to);
4244
4245 pos = token.loc.r;
4246 }
4247 }
4248 else if (0 == indexed_macro && 0 != (macro_type & MACRO_TYPE_SCRIPT))
4249 {
4250 if (ZBX_TOKEN_USER_MACRO == token.type)
4251 {
4252 DCget_user_macro(&dc_host->hostid, 1, m, &replace_to);
4253 pos = token.loc.r;
4254 }
4255 else if (0 == strcmp(m, MVAR_HOST_HOST) || 0 == strcmp(m, MVAR_HOSTNAME))
4256 replace_to = zbx_strdup(replace_to, dc_host->host);
4257 else if (0 == strcmp(m, MVAR_HOST_NAME))
4258 replace_to = zbx_strdup(replace_to, dc_host->name);
4259 else if (0 == strcmp(m, MVAR_HOST_IP) || 0 == strcmp(m, MVAR_IPADDRESS))
4260 {
4261 if (SUCCEED == (ret = DCconfig_get_interface(&interface, dc_host->hostid, 0)))
4262 replace_to = zbx_strdup(replace_to, interface.ip_orig);
4263 require_address = 1;
4264 }
4265 else if (0 == strcmp(m, MVAR_HOST_DNS))
4266 {
4267 if (SUCCEED == (ret = DCconfig_get_interface(&interface, dc_host->hostid, 0)))
4268 replace_to = zbx_strdup(replace_to, interface.dns_orig);
4269 require_address = 1;
4270 }
4271 else if (0 == strcmp(m, MVAR_HOST_CONN))
4272 {
4273 if (SUCCEED == (ret = DCconfig_get_interface(&interface, dc_host->hostid, 0)))
4274 replace_to = zbx_strdup(replace_to, interface.addr);
4275 require_address = 1;
4276 }
4277 else if (NULL != userid)
4278 {
4279 if (0 == strcmp(m, MVAR_USER_USERNAME) || 0 == strcmp(m, MVAR_USER_NAME) ||
4280 0 == strcmp(m, MVAR_USER_SURNAME) ||
4281 0 == strcmp(m, MVAR_USER_FULLNAME) || 0 == strcmp(m, MVAR_USER_ALIAS))
4282 {
4283 resolve_user_macros(*userid, m, &user_username, &user_name, &user_surname,
4284 &user_names_found, &replace_to);
4285 }
4286 }
4287 }
4288 else if (0 == indexed_macro && 0 != (macro_type & MACRO_TYPE_HTTPTEST_FIELD))
4289 {
4290 if (ZBX_TOKEN_USER_MACRO == token.type)
4291 {
4292 DCget_user_macro(&dc_host->hostid, 1, m, &replace_to);
4293 pos = token.loc.r;
4294 }
4295 else if (0 == strcmp(m, MVAR_HOST_HOST) || 0 == strcmp(m, MVAR_HOSTNAME))
4296 replace_to = zbx_strdup(replace_to, dc_host->host);
4297 else if (0 == strcmp(m, MVAR_HOST_NAME))
4298 replace_to = zbx_strdup(replace_to, dc_host->name);
4299 else if (0 == strcmp(m, MVAR_HOST_IP) || 0 == strcmp(m, MVAR_IPADDRESS))
4300 {
4301 if (SUCCEED == (ret = DCconfig_get_interface(&interface, dc_host->hostid, 0)))
4302 replace_to = zbx_strdup(replace_to, interface.ip_orig);
4303 }
4304 else if (0 == strcmp(m, MVAR_HOST_DNS))
4305 {
4306 if (SUCCEED == (ret = DCconfig_get_interface(&interface, dc_host->hostid, 0)))
4307 replace_to = zbx_strdup(replace_to, interface.dns_orig);
4308 }
4309 else if (0 == strcmp(m, MVAR_HOST_CONN))
4310 {
4311 if (SUCCEED == (ret = DCconfig_get_interface(&interface, dc_host->hostid, 0)))
4312 replace_to = zbx_strdup(replace_to, interface.addr);
4313 }
4314 }
4315 else if (0 == indexed_macro && (0 != (macro_type & (MACRO_TYPE_HTTP_RAW | MACRO_TYPE_HTTP_JSON |
4316 MACRO_TYPE_HTTP_XML))))
4317 {
4318 if (ZBX_TOKEN_USER_MACRO == token.type)
4319 {
4320 DCget_user_macro(&dc_host->hostid, 1, m, &replace_to);
4321 pos = token.loc.r;
4322 }
4323 else if (0 == strcmp(m, MVAR_HOST_HOST) || 0 == strcmp(m, MVAR_HOSTNAME))
4324 {
4325 replace_to = zbx_strdup(replace_to, dc_host->host);
4326 }
4327 else if (0 == strcmp(m, MVAR_HOST_NAME))
4328 {
4329 replace_to = zbx_strdup(replace_to, dc_host->name);
4330 }
4331 else if (0 == strcmp(m, MVAR_HOST_IP) || 0 == strcmp(m, MVAR_IPADDRESS))
4332 {
4333 if (SUCCEED == (ret = DCconfig_get_interface(&interface, dc_host->hostid, 0)))
4334 replace_to = zbx_strdup(replace_to, interface.ip_orig);
4335 }
4336 else if (0 == strcmp(m, MVAR_HOST_DNS))
4337 {
4338 if (SUCCEED == (ret = DCconfig_get_interface(&interface, dc_host->hostid, 0)))
4339 replace_to = zbx_strdup(replace_to, interface.dns_orig);
4340 }
4341 else if (0 == strcmp(m, MVAR_HOST_CONN))
4342 {
4343 if (SUCCEED == (ret = DCconfig_get_interface(&interface, dc_host->hostid, 0)))
4344 replace_to = zbx_strdup(replace_to, interface.addr);
4345 }
4346 else if (0 == strcmp(m, MVAR_ITEM_ID))
4347 {
4348 replace_to = zbx_dsprintf(replace_to, ZBX_FS_UI64, dc_item->itemid);
4349 }
4350 else if (0 == strcmp(m, MVAR_ITEM_KEY))
4351 {
4352 replace_to = zbx_strdup(replace_to, dc_item->key);
4353 }
4354 else if (0 == strcmp(m, MVAR_ITEM_KEY_ORIG))
4355 {
4356 replace_to = zbx_strdup(replace_to, dc_item->key_orig);
4357 }
4358 }
4359 else if (0 == indexed_macro && 0 != (macro_type & MACRO_TYPE_ALERT))
4360 {
4361 if (0 == strcmp(m, MVAR_ALERT_SENDTO))
4362 replace_to = zbx_strdup(replace_to, alert->sendto);
4363 else if (0 == strcmp(m, MVAR_ALERT_SUBJECT))
4364 replace_to = zbx_strdup(replace_to, alert->subject);
4365 else if (0 == strcmp(m, MVAR_ALERT_MESSAGE))
4366 replace_to = zbx_strdup(replace_to, alert->message);
4367 }
4368 else if (0 == indexed_macro && 0 != (macro_type & MACRO_TYPE_JMX_ENDPOINT))
4369 {
4370 if (ZBX_TOKEN_USER_MACRO == token.type)
4371 {
4372 DCget_user_macro(&dc_item->host.hostid, 1, m, &replace_to);
4373 pos = token.loc.r;
4374 }
4375 else if (0 == strcmp(m, MVAR_HOST_HOST) || 0 == strcmp(m, MVAR_HOSTNAME))
4376 replace_to = zbx_strdup(replace_to, dc_item->host.host);
4377 else if (0 == strcmp(m, MVAR_HOST_NAME))
4378 replace_to = zbx_strdup(replace_to, dc_item->host.name);
4379 else if (0 == strcmp(m, MVAR_HOST_IP) || 0 == strcmp(m, MVAR_IPADDRESS))
4380 {
4381 if (INTERFACE_TYPE_UNKNOWN != dc_item->interface.type)
4382 {
4383 replace_to = zbx_strdup(replace_to, dc_item->interface.ip_orig);
4384 }
4385 else
4386 {
4387 ret = get_interface_value(dc_item->host.hostid, dc_item->itemid, &replace_to,
4388 ZBX_REQUEST_HOST_IP);
4389 }
4390 }
4391 else if (0 == strcmp(m, MVAR_HOST_DNS))
4392 {
4393 if (INTERFACE_TYPE_UNKNOWN != dc_item->interface.type)
4394 {
4395 replace_to = zbx_strdup(replace_to, dc_item->interface.dns_orig);
4396 }
4397 else
4398 {
4399 ret = get_interface_value(dc_item->host.hostid, dc_item->itemid, &replace_to,
4400 ZBX_REQUEST_HOST_DNS);
4401 }
4402 }
4403 else if (0 == strcmp(m, MVAR_HOST_CONN))
4404 {
4405 if (INTERFACE_TYPE_UNKNOWN != dc_item->interface.type)
4406 {
4407 replace_to = zbx_strdup(replace_to, dc_item->interface.addr);
4408 }
4409 else
4410 {
4411 ret = get_interface_value(dc_item->host.hostid, dc_item->itemid, &replace_to,
4412 ZBX_REQUEST_HOST_CONN);
4413 }
4414 }
4415 else if (0 == strcmp(m, MVAR_HOST_PORT))
4416 {
4417 if (INTERFACE_TYPE_UNKNOWN != dc_item->interface.type)
4418 {
4419 replace_to = zbx_dsprintf(replace_to, "%u", dc_item->interface.port);
4420 }
4421 else
4422 {
4423 ret = get_interface_value(dc_item->host.hostid, dc_item->itemid, &replace_to,
4424 ZBX_REQUEST_HOST_PORT);
4425 }
4426 }
4427 }
4428 else if (0 != (macro_type & MACRO_TYPE_TRIGGER_TAG))
4429 {
4430 if (EVENT_SOURCE_TRIGGERS == event->source || EVENT_SOURCE_INTERNAL == event->source)
4431 {
4432 if (ZBX_TOKEN_USER_MACRO == token.type)
4433 {
4434 if (SUCCEED == zbx_db_trigger_get_all_hostids(&event->trigger, &phostids))
4435 DCget_user_macro(phostids->values, phostids->values_num, m, &replace_to);
4436 pos = token.loc.r;
4437 }
4438 else if (0 == strncmp(m, MVAR_INVENTORY, ZBX_CONST_STRLEN(MVAR_INVENTORY)))
4439 {
4440 ret = get_host_inventory(m, &event->trigger, &replace_to,
4441 N_functionid);
4442 }
4443 else if (0 == strcmp(m, MVAR_HOST_ID))
4444 {
4445 ret = DBget_trigger_value(&event->trigger, &replace_to, N_functionid,
4446 ZBX_REQUEST_HOST_ID);
4447 }
4448 else if (0 == strcmp(m, MVAR_HOST_HOST))
4449 {
4450 ret = DBget_trigger_value(&event->trigger, &replace_to, N_functionid,
4451 ZBX_REQUEST_HOST_HOST);
4452 }
4453 else if (0 == strcmp(m, MVAR_HOST_NAME))
4454 {
4455 ret = DBget_trigger_value(&event->trigger, &replace_to, N_functionid,
4456 ZBX_REQUEST_HOST_NAME);
4457 }
4458 else if (0 == strcmp(m, MVAR_HOST_IP))
4459 {
4460 ret = DBget_trigger_value(&event->trigger, &replace_to, N_functionid,
4461 ZBX_REQUEST_HOST_IP);
4462 }
4463 else if (0 == strcmp(m, MVAR_HOST_DNS))
4464 {
4465 ret = DBget_trigger_value(&event->trigger, &replace_to, N_functionid,
4466 ZBX_REQUEST_HOST_DNS);
4467 }
4468 else if (0 == strcmp(m, MVAR_HOST_CONN))
4469 {
4470 ret = DBget_trigger_value(&event->trigger, &replace_to, N_functionid,
4471 ZBX_REQUEST_HOST_CONN);
4472 }
4473 else if (0 == strcmp(m, MVAR_HOST_PORT))
4474 {
4475 ret = DBget_trigger_value(&event->trigger, &replace_to, N_functionid,
4476 ZBX_REQUEST_HOST_PORT);
4477 }
4478
4479 if (EVENT_SOURCE_TRIGGERS == event->source)
4480 {
4481 if (0 == strcmp(m, MVAR_ITEM_LASTVALUE))
4482 {
4483 ret = DBitem_lastvalue(&event->trigger, &replace_to, N_functionid,
4484 raw_value);
4485 }
4486 else if (0 == strcmp(m, MVAR_ITEM_VALUE))
4487 {
4488 ret = DBitem_value(&event->trigger, &replace_to, N_functionid,
4489 event->clock, event->ns, raw_value);
4490 }
4491 else if (0 == strncmp(m, MVAR_ITEM_LOG, ZBX_CONST_STRLEN(MVAR_ITEM_LOG)))
4492 {
4493 ret = get_history_log_value(m, &event->trigger, &replace_to,
4494 N_functionid, event->clock, event->ns, tz);
4495 }
4496 else if (0 == strcmp(m, MVAR_TRIGGER_ID))
4497 {
4498 replace_to = zbx_dsprintf(replace_to, ZBX_FS_UI64, event->objectid);
4499 }
4500 }
4501 }
4502 }
4503 else if (0 == indexed_macro && 0 != (macro_type & MACRO_TYPE_ITEM_TAG))
4504 {
4505 /* Using dc_item to pass itemid and hostid only, all other fields are not initialized! */
4506
4507 if (EVENT_SOURCE_TRIGGERS == event->source && 0 == strcmp(m, MVAR_TRIGGER_ID))
4508 {
4509 replace_to = zbx_dsprintf(replace_to, ZBX_FS_UI64, event->objectid);
4510 }
4511 else if (EVENT_SOURCE_TRIGGERS == event->source || EVENT_SOURCE_INTERNAL == event->source)
4512 {
4513 if (ZBX_TOKEN_USER_MACRO == token.type)
4514 {
4515 DCget_user_macro(&dc_item->host.hostid, 1, m, &replace_to);
4516 }
4517 else if (0 == strncmp(m, MVAR_INVENTORY, ZBX_CONST_STRLEN(MVAR_INVENTORY)))
4518 {
4519 get_host_inventory_by_hostid(m, dc_item->host.hostid, &replace_to);
4520 }
4521 else if (0 == strcmp(m, MVAR_HOST_ID))
4522 {
4523 get_host_value(dc_item->itemid, &replace_to, ZBX_REQUEST_HOST_ID);
4524 }
4525 else if (0 == strcmp(m, MVAR_HOST_HOST))
4526 {
4527 get_host_value(dc_item->itemid, &replace_to, ZBX_REQUEST_HOST_HOST);
4528 }
4529 else if (0 == strcmp(m, MVAR_HOST_NAME))
4530 {
4531 get_host_value(dc_item->itemid, &replace_to, ZBX_REQUEST_HOST_NAME);
4532 }
4533 else if (0 == strcmp(m, MVAR_HOST_IP))
4534 {
4535 get_interface_value(dc_item->host.hostid, dc_item->itemid, &replace_to,
4536 ZBX_REQUEST_HOST_IP);
4537 }
4538 else if (0 == strcmp(m, MVAR_HOST_DNS))
4539 {
4540 get_interface_value(dc_item->host.hostid, dc_item->itemid, &replace_to,
4541 ZBX_REQUEST_HOST_DNS);
4542 }
4543 else if (0 == strcmp(m, MVAR_HOST_CONN))
4544 {
4545 get_interface_value(dc_item->host.hostid, dc_item->itemid, &replace_to,
4546 ZBX_REQUEST_HOST_CONN);
4547 }
4548 else if (0 == strcmp(m, MVAR_HOST_PORT))
4549 {
4550 get_interface_value(dc_item->host.hostid, dc_item->itemid, &replace_to,
4551 ZBX_REQUEST_HOST_PORT);
4552 }
4553 }
4554 }
4555 else if (0 == indexed_macro && 0 != (macro_type & MACRO_TYPE_REPORT))
4556 {
4557 if (0 == strcmp(m, MVAR_TIME))
4558 {
4559 replace_to = zbx_strdup(replace_to, zbx_time2str(time(NULL), tz));
4560 }
4561 }
4562
4563 if (0 != (macro_type & MACRO_TYPE_HTTP_JSON) && NULL != replace_to)
4564 zbx_json_escape(&replace_to);
4565
4566 if (ZBX_TOKEN_FUNC_MACRO == token.type && NULL != replace_to)
4567 {
4568 if (SUCCEED != (ret = zbx_calculate_macro_function(*data, &token.data.func_macro, &replace_to)))
4569 zbx_free(replace_to);
4570 }
4571
4572 if (NULL != replace_to)
4573 {
4574 if (1 == require_address && NULL != strstr(replace_to, "{$"))
4575 {
4576 /* Macros should be already expanded. An unexpanded user macro means either unknown */
4577 /* macro or macro value validation failure. */
4578 zbx_snprintf(error, maxerrlen, "Invalid macro '%.*s' value",
4579 (int)(token.loc.r - token.loc.l + 1), *data + token.loc.l);
4580 res = FAIL;
4581 }
4582 }
4583
4584 if (FAIL == ret)
4585 {
4586 zabbix_log(LOG_LEVEL_DEBUG, "cannot resolve macro '%.*s'",
4587 (int)(token.loc.r - token.loc.l + 1), *data + token.loc.l);
4588 replace_to = zbx_strdup(replace_to, STR_UNKNOWN_VARIABLE);
4589 }
4590
4591 if (ZBX_TOKEN_USER_MACRO == token.type || (ZBX_TOKEN_MACRO == token.type && 0 == indexed_macro))
4592 (*data)[token.loc.r + 1] = c;
4593
4594 if (NULL != replace_to)
4595 {
4596 pos = token.loc.r;
4597
4598 pos += zbx_replace_mem_dyn(data, &data_alloc, &data_len, token.loc.l,
4599 token.loc.r - token.loc.l + 1, replace_to, strlen(replace_to));
4600 zbx_free(replace_to);
4601 }
4602
4603 pos++;
4604 }
4605
4606 zbx_vc_flush_stats();
4607
4608 zbx_free(user_username);
4609 zbx_free(user_name);
4610 zbx_free(user_surname);
4611 zbx_free(expression);
4612 zbx_vector_uint64_destroy(&hostids);
4613
4614 zabbix_log(LOG_LEVEL_DEBUG, "End %s() data:'%s'", __func__, *data);
4615
4616 return res;
4617 }
4618
zbx_extract_functionids(zbx_vector_uint64_t * functionids,zbx_vector_ptr_t * triggers)4619 static void zbx_extract_functionids(zbx_vector_uint64_t *functionids, zbx_vector_ptr_t *triggers)
4620 {
4621 DC_TRIGGER *tr;
4622 int i;
4623
4624 zabbix_log(LOG_LEVEL_DEBUG, "In %s() tr_num:%d", __func__, triggers->values_num);
4625
4626 zbx_vector_uint64_reserve(functionids, triggers->values_num);
4627
4628 for (i = 0; i < triggers->values_num; i++)
4629 {
4630 tr = (DC_TRIGGER *)triggers->values[i];
4631
4632 if (NULL != tr->new_error)
4633 continue;
4634
4635 zbx_eval_get_functionids(tr->eval_ctx, functionids);
4636
4637 if (TRIGGER_RECOVERY_MODE_RECOVERY_EXPRESSION == tr->recovery_mode)
4638 zbx_eval_get_functionids(tr->eval_ctx_r, functionids);
4639 }
4640
4641 zbx_vector_uint64_sort(functionids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
4642 zbx_vector_uint64_uniq(functionids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
4643
4644 zabbix_log(LOG_LEVEL_DEBUG, "End of %s() functionids_num:%d", __func__, functionids->values_num);
4645 }
4646
4647 typedef struct
4648 {
4649 DC_TRIGGER *trigger;
4650 int start_index;
4651 int count;
4652 }
4653 zbx_trigger_func_position_t;
4654
4655 /******************************************************************************
4656 * *
4657 * Function: expand_trigger_macros *
4658 * *
4659 * Purpose: expand macros in a trigger expression *
4660 * *
4661 * Parameters: event - The trigger event structure *
4662 * trigger - The trigger where to expand macros in *
4663 * *
4664 * Author: Andrea Biscuola *
4665 * *
4666 ******************************************************************************/
expand_trigger_macros(zbx_eval_context_t * ctx,const DB_EVENT * event,char * error,size_t maxerrlen)4667 static int expand_trigger_macros(zbx_eval_context_t *ctx, const DB_EVENT *event, char *error, size_t maxerrlen)
4668 {
4669 int i;
4670
4671 for (i = 0; i < ctx->stack.values_num; i++)
4672 {
4673 zbx_eval_token_t *token = &ctx->stack.values[i];
4674
4675 if (ZBX_EVAL_TOKEN_VAR_MACRO != token->type && ZBX_EVAL_TOKEN_VAR_STR != token->type)
4676 continue;
4677
4678 /* all trigger macros macros are already extracted into strings */
4679 if (ZBX_VARIANT_STR != token->value.type)
4680 continue;
4681
4682 if (FAIL == substitute_simple_macros_impl(NULL, event, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
4683 &token->value.data.str, MACRO_TYPE_TRIGGER_EXPRESSION, error, maxerrlen))
4684 {
4685 return FAIL;
4686 }
4687 }
4688
4689 return SUCCEED;
4690 }
4691
4692 /******************************************************************************
4693 * *
4694 * Function: zbx_link_triggers_with_functions *
4695 * *
4696 * Purpose: triggers links with functions *
4697 * *
4698 * Parameters: triggers_func_pos - [IN/OUT] pointer to the list of triggers *
4699 * with functions position in functionids *
4700 * array *
4701 * functionids - [IN/OUT] array of function IDs *
4702 * trigger_order - [IN] array of triggers *
4703 * *
4704 ******************************************************************************/
zbx_link_triggers_with_functions(zbx_vector_ptr_t * triggers_func_pos,zbx_vector_uint64_t * functionids,zbx_vector_ptr_t * trigger_order)4705 static void zbx_link_triggers_with_functions(zbx_vector_ptr_t *triggers_func_pos, zbx_vector_uint64_t *functionids,
4706 zbx_vector_ptr_t *trigger_order)
4707 {
4708 zbx_vector_uint64_t funcids;
4709 DC_TRIGGER *tr;
4710 int i;
4711
4712 zabbix_log(LOG_LEVEL_DEBUG, "In %s() trigger_order_num:%d", __func__, trigger_order->values_num);
4713
4714 zbx_vector_uint64_create(&funcids);
4715 zbx_vector_uint64_reserve(&funcids, functionids->values_num);
4716
4717 for (i = 0; i < trigger_order->values_num; i++)
4718 {
4719 zbx_trigger_func_position_t *tr_func_pos;
4720
4721 tr = (DC_TRIGGER *)trigger_order->values[i];
4722
4723 if (NULL != tr->new_error)
4724 continue;
4725
4726 zbx_eval_get_functionids(tr->eval_ctx, &funcids);
4727
4728 tr_func_pos = (zbx_trigger_func_position_t *)zbx_malloc(NULL, sizeof(zbx_trigger_func_position_t));
4729 tr_func_pos->trigger = tr;
4730 tr_func_pos->start_index = functionids->values_num;
4731 tr_func_pos->count = funcids.values_num;
4732
4733 zbx_vector_uint64_append_array(functionids, funcids.values, funcids.values_num);
4734 zbx_vector_ptr_append(triggers_func_pos, tr_func_pos);
4735
4736 zbx_vector_uint64_clear(&funcids);
4737 }
4738
4739 zbx_vector_uint64_destroy(&funcids);
4740
4741 zabbix_log(LOG_LEVEL_DEBUG, "End of %s() triggers_func_pos_num:%d", __func__, triggers_func_pos->values_num);
4742 }
4743
4744 /******************************************************************************
4745 * *
4746 * Function: zbx_determine_items_in_expressions *
4747 * *
4748 * Purpose: mark triggers that use one of the items in problem expression *
4749 * with ZBX_DC_TRIGGER_PROBLEM_EXPRESSION flag *
4750 * *
4751 * Parameters: trigger_order - [IN/OUT] pointer to the list of triggers *
4752 * itemids - [IN] array of item IDs *
4753 * item_num - [IN] number of items *
4754 * *
4755 ******************************************************************************/
zbx_determine_items_in_expressions(zbx_vector_ptr_t * trigger_order,const zbx_uint64_t * itemids,int item_num)4756 void zbx_determine_items_in_expressions(zbx_vector_ptr_t *trigger_order, const zbx_uint64_t *itemids, int item_num)
4757 {
4758 zbx_vector_ptr_t triggers_func_pos;
4759 zbx_vector_uint64_t functionids, itemids_sorted;
4760 DC_FUNCTION *functions = NULL;
4761 int *errcodes = NULL, t, f;
4762
4763 zbx_vector_uint64_create(&itemids_sorted);
4764 zbx_vector_uint64_append_array(&itemids_sorted, itemids, item_num);
4765 zbx_vector_uint64_sort(&itemids_sorted, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
4766
4767 zbx_vector_ptr_create(&triggers_func_pos);
4768 zbx_vector_ptr_reserve(&triggers_func_pos, trigger_order->values_num);
4769
4770 zbx_vector_uint64_create(&functionids);
4771 zbx_vector_uint64_reserve(&functionids, item_num);
4772
4773 zbx_link_triggers_with_functions(&triggers_func_pos, &functionids, trigger_order);
4774
4775 functions = (DC_FUNCTION *)zbx_malloc(functions, sizeof(DC_FUNCTION) * functionids.values_num);
4776 errcodes = (int *)zbx_malloc(errcodes, sizeof(int) * functionids.values_num);
4777
4778 DCconfig_get_functions_by_functionids(functions, functionids.values, errcodes, functionids.values_num);
4779
4780 for (t = 0; t < triggers_func_pos.values_num; t++)
4781 {
4782 zbx_trigger_func_position_t *func_pos = (zbx_trigger_func_position_t *)triggers_func_pos.values[t];
4783
4784 for (f = func_pos->start_index; f < func_pos->start_index + func_pos->count; f++)
4785 {
4786 if (SUCCEED == errcodes[f] && FAIL != zbx_vector_uint64_bsearch(&itemids_sorted,
4787 functions[f].itemid, ZBX_DEFAULT_UINT64_COMPARE_FUNC))
4788 {
4789 func_pos->trigger->flags |= ZBX_DC_TRIGGER_PROBLEM_EXPRESSION;
4790 break;
4791 }
4792 }
4793 }
4794
4795 DCconfig_clean_functions(functions, errcodes, functionids.values_num);
4796 zbx_free(errcodes);
4797 zbx_free(functions);
4798
4799 zbx_vector_ptr_clear_ext(&triggers_func_pos, zbx_ptr_free);
4800 zbx_vector_ptr_destroy(&triggers_func_pos);
4801
4802 zbx_vector_uint64_clear(&functionids);
4803 zbx_vector_uint64_destroy(&functionids);
4804
4805 zbx_vector_uint64_clear(&itemids_sorted);
4806 zbx_vector_uint64_destroy(&itemids_sorted);
4807 }
4808
4809 typedef struct
4810 {
4811 /* input data */
4812 zbx_uint64_t itemid;
4813 char *function;
4814 char *parameter;
4815 zbx_timespec_t timespec;
4816
4817 /* output data */
4818 zbx_variant_t value;
4819 char *error;
4820 }
4821 zbx_func_t;
4822
4823 typedef struct
4824 {
4825 zbx_uint64_t functionid;
4826 zbx_func_t *func;
4827 }
4828 zbx_ifunc_t;
4829
func_hash_func(const void * data)4830 static zbx_hash_t func_hash_func(const void *data)
4831 {
4832 const zbx_func_t *func = (const zbx_func_t *)data;
4833 zbx_hash_t hash;
4834
4835 hash = ZBX_DEFAULT_UINT64_HASH_FUNC(&func->itemid);
4836 hash = ZBX_DEFAULT_STRING_HASH_ALGO(func->function, strlen(func->function), hash);
4837 hash = ZBX_DEFAULT_STRING_HASH_ALGO(func->parameter, strlen(func->parameter), hash);
4838 hash = ZBX_DEFAULT_HASH_ALGO(&func->timespec.sec, sizeof(func->timespec.sec), hash);
4839 hash = ZBX_DEFAULT_HASH_ALGO(&func->timespec.ns, sizeof(func->timespec.ns), hash);
4840
4841 return hash;
4842 }
4843
func_compare_func(const void * d1,const void * d2)4844 static int func_compare_func(const void *d1, const void *d2)
4845 {
4846 const zbx_func_t *func1 = (const zbx_func_t *)d1;
4847 const zbx_func_t *func2 = (const zbx_func_t *)d2;
4848 int ret;
4849
4850 ZBX_RETURN_IF_NOT_EQUAL(func1->itemid, func2->itemid);
4851
4852 if (0 != (ret = strcmp(func1->function, func2->function)))
4853 return ret;
4854
4855 if (0 != (ret = strcmp(func1->parameter, func2->parameter)))
4856 return ret;
4857
4858 ZBX_RETURN_IF_NOT_EQUAL(func1->timespec.sec, func2->timespec.sec);
4859 ZBX_RETURN_IF_NOT_EQUAL(func1->timespec.ns, func2->timespec.ns);
4860
4861 return 0;
4862 }
4863
func_clean(void * ptr)4864 static void func_clean(void *ptr)
4865 {
4866 zbx_func_t *func = (zbx_func_t *)ptr;
4867
4868 zbx_free(func->function);
4869 zbx_free(func->parameter);
4870 zbx_free(func->error);
4871
4872 zbx_variant_clear(&func->value);
4873 }
4874
4875 /******************************************************************************
4876 * *
4877 * Function: zbx_populate_function_items *
4878 * *
4879 * Purpose: prepare hashset of functions to evaluate *
4880 * *
4881 * Parameters: functionids - [IN] function identifiers *
4882 * funcs - [OUT] functions indexed by itemid, name, *
4883 * parameter, timestamp *
4884 * ifuncs - [OUT] function index by functionid *
4885 * trigger - [IN] vector of triggers, sorted by triggerid *
4886 * *
4887 ******************************************************************************/
zbx_populate_function_items(const zbx_vector_uint64_t * functionids,zbx_hashset_t * funcs,zbx_hashset_t * ifuncs,const zbx_vector_ptr_t * triggers)4888 static void zbx_populate_function_items(const zbx_vector_uint64_t *functionids, zbx_hashset_t *funcs,
4889 zbx_hashset_t *ifuncs, const zbx_vector_ptr_t *triggers)
4890 {
4891 int i, j;
4892 DC_TRIGGER *tr;
4893 DC_FUNCTION *functions = NULL;
4894 int *errcodes = NULL;
4895 zbx_ifunc_t ifunc_local;
4896 zbx_func_t *func, func_local;
4897
4898 zabbix_log(LOG_LEVEL_DEBUG, "In %s() functionids_num:%d", __func__, functionids->values_num);
4899
4900 zbx_variant_set_none(&func_local.value);
4901 func_local.error = NULL;
4902
4903 functions = (DC_FUNCTION *)zbx_malloc(functions, sizeof(DC_FUNCTION) * functionids->values_num);
4904 errcodes = (int *)zbx_malloc(errcodes, sizeof(int) * functionids->values_num);
4905
4906 DCconfig_get_functions_by_functionids(functions, functionids->values, errcodes, functionids->values_num);
4907
4908 for (i = 0; i < functionids->values_num; i++)
4909 {
4910 if (SUCCEED != errcodes[i])
4911 continue;
4912
4913 func_local.itemid = functions[i].itemid;
4914
4915 if (FAIL != (j = zbx_vector_ptr_bsearch(triggers, &functions[i].triggerid,
4916 ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
4917 {
4918 tr = (DC_TRIGGER *)triggers->values[j];
4919 func_local.timespec = tr->timespec;
4920 }
4921 else
4922 {
4923 func_local.timespec.sec = 0;
4924 func_local.timespec.ns = 0;
4925 }
4926
4927 func_local.function = functions[i].function;
4928 func_local.parameter = functions[i].parameter;
4929
4930 if (NULL == (func = (zbx_func_t *)zbx_hashset_search(funcs, &func_local)))
4931 {
4932 func = (zbx_func_t *)zbx_hashset_insert(funcs, &func_local, sizeof(func_local));
4933 func->function = zbx_strdup(NULL, func_local.function);
4934 func->parameter = zbx_strdup(NULL, func_local.parameter);
4935 zbx_variant_set_none(&func->value);
4936 }
4937
4938 ifunc_local.functionid = functions[i].functionid;
4939 ifunc_local.func = func;
4940 zbx_hashset_insert(ifuncs, &ifunc_local, sizeof(ifunc_local));
4941 }
4942
4943 DCconfig_clean_functions(functions, errcodes, functionids->values_num);
4944
4945 zbx_free(errcodes);
4946 zbx_free(functions);
4947
4948 zabbix_log(LOG_LEVEL_DEBUG, "End of %s() ifuncs_num:%d", __func__, ifuncs->num_data);
4949 }
4950
zbx_evaluate_item_functions(zbx_hashset_t * funcs,const zbx_vector_uint64_t * history_itemids,const DC_ITEM * history_items,const int * history_errcodes)4951 static void zbx_evaluate_item_functions(zbx_hashset_t *funcs, const zbx_vector_uint64_t *history_itemids,
4952 const DC_ITEM *history_items, const int *history_errcodes)
4953 {
4954 DC_ITEM *items = NULL;
4955 char *error = NULL;
4956 int i;
4957 zbx_func_t *func;
4958 zbx_vector_uint64_t itemids;
4959 int *errcodes = NULL;
4960 zbx_hashset_iter_t iter;
4961
4962 zabbix_log(LOG_LEVEL_DEBUG, "In %s() funcs_num:%d", __func__, funcs->num_data);
4963
4964 zbx_vector_uint64_create(&itemids);
4965
4966 zbx_hashset_iter_reset(funcs, &iter);
4967 while (NULL != (func = (zbx_func_t *)zbx_hashset_iter_next(&iter)))
4968 {
4969 if (FAIL == zbx_vector_uint64_bsearch(history_itemids, func->itemid, ZBX_DEFAULT_UINT64_COMPARE_FUNC))
4970 zbx_vector_uint64_append(&itemids, func->itemid);
4971 }
4972
4973 if (0 != itemids.values_num)
4974 {
4975 zbx_vector_uint64_sort(&itemids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
4976 zbx_vector_uint64_uniq(&itemids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
4977
4978 items = (DC_ITEM *)zbx_malloc(items, sizeof(DC_ITEM) * (size_t)itemids.values_num);
4979 errcodes = (int *)zbx_malloc(errcodes, sizeof(int) * (size_t)itemids.values_num);
4980
4981 DCconfig_get_items_by_itemids_partial(items, itemids.values, errcodes, itemids.values_num,
4982 ZBX_ITEM_GET_SYNC);
4983 }
4984
4985 zbx_hashset_iter_reset(funcs, &iter);
4986 while (NULL != (func = (zbx_func_t *)zbx_hashset_iter_next(&iter)))
4987 {
4988 int errcode;
4989 const DC_ITEM *item;
4990
4991 /* avoid double copying from configuration cache if already retrieved when saving history */
4992 if (FAIL != (i = zbx_vector_uint64_bsearch(history_itemids, func->itemid,
4993 ZBX_DEFAULT_UINT64_COMPARE_FUNC)))
4994 {
4995 item = history_items + i;
4996 errcode = history_errcodes[i];
4997 }
4998 else
4999 {
5000 i = zbx_vector_uint64_bsearch(&itemids, func->itemid, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
5001 item = items + i;
5002 errcode = errcodes[i];
5003 }
5004
5005 if (SUCCEED != errcode)
5006 {
5007 zbx_free(func->error);
5008 func->error = zbx_eval_format_function_error(func->function, NULL, NULL, func->parameter,
5009 "item does not exist");
5010 continue;
5011 }
5012
5013 /* do not evaluate if the item is disabled or belongs to a disabled host */
5014
5015 if (ITEM_STATUS_ACTIVE != item->status)
5016 {
5017 zbx_free(func->error);
5018 func->error = zbx_eval_format_function_error(func->function, item->host.host,
5019 item->key_orig, func->parameter, "item is disabled");
5020 continue;
5021 }
5022
5023 if (HOST_STATUS_MONITORED != item->host.status)
5024 {
5025 zbx_free(func->error);
5026 func->error = zbx_eval_format_function_error(func->function, item->host.host,
5027 item->key_orig, func->parameter, "item belongs to a disabled host");
5028 continue;
5029 }
5030
5031 if (ITEM_STATE_NOTSUPPORTED == item->state &&
5032 FAIL == zbx_evaluatable_for_notsupported(func->function))
5033 {
5034 /* set 'unknown' error value */
5035 zbx_variant_set_error(&func->value,
5036 zbx_eval_format_function_error(func->function, item->host.host,
5037 item->key_orig, func->parameter, "item is not supported"));
5038 continue;
5039 }
5040
5041 if (SUCCEED != evaluate_function2(&func->value, (DC_ITEM *)item, func->function, func->parameter,
5042 &func->timespec, &error))
5043 {
5044 /* compose and store error message for future use */
5045 zbx_variant_set_error(&func->value,
5046 zbx_eval_format_function_error(func->function, item->host.host,
5047 item->key_orig, func->parameter, error));
5048 zbx_free(error);
5049 continue;
5050 }
5051 }
5052
5053 zbx_vc_flush_stats();
5054
5055 DCconfig_clean_items(items, errcodes, itemids.values_num);
5056 zbx_vector_uint64_destroy(&itemids);
5057
5058 zbx_free(errcodes);
5059 zbx_free(items);
5060
5061 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
5062 }
5063
substitute_expression_functions_results(zbx_hashset_t * ifuncs,zbx_eval_context_t * ctx,char ** error)5064 static int substitute_expression_functions_results(zbx_hashset_t *ifuncs, zbx_eval_context_t *ctx, char **error)
5065 {
5066 zbx_uint64_t functionid;
5067 zbx_func_t *func;
5068 zbx_ifunc_t *ifunc;
5069 int i;
5070
5071 for (i = 0; i < ctx->stack.values_num; i++)
5072 {
5073 zbx_eval_token_t *token = &ctx->stack.values[i];
5074
5075 if (ZBX_EVAL_TOKEN_FUNCTIONID != token->type)
5076 continue;
5077
5078 if (ZBX_VARIANT_UI64 != token->value.type)
5079 {
5080 /* functionids should be already extracted into uint64 vars */
5081 THIS_SHOULD_NEVER_HAPPEN;
5082 *error = zbx_dsprintf(*error, "Cannot parse function at: \"%s\"",
5083 ctx->expression + token->loc.l);
5084 return FAIL;
5085 }
5086
5087 functionid = token->value.data.ui64;
5088 if (NULL == (ifunc = (zbx_ifunc_t *)zbx_hashset_search(ifuncs, &functionid)))
5089 {
5090 *error = zbx_dsprintf(*error, "Cannot obtain function"
5091 " and item for functionid: " ZBX_FS_UI64, functionid);
5092 return FAIL;
5093 }
5094
5095 func = ifunc->func;
5096
5097 if (NULL != func->error)
5098 {
5099 *error = zbx_strdup(*error, func->error);
5100 return FAIL;
5101 }
5102
5103 if (ZBX_VARIANT_NONE == func->value.type)
5104 {
5105 *error = zbx_strdup(*error, "Unexpected error while processing a trigger expression");
5106 return FAIL;
5107 }
5108
5109 zbx_variant_copy(&token->value, &func->value);
5110 }
5111
5112 return SUCCEED;
5113 }
5114
log_expression(const char * prefix,int index,const zbx_eval_context_t * ctx)5115 static void log_expression(const char *prefix, int index, const zbx_eval_context_t *ctx)
5116 {
5117 if (SUCCEED == ZBX_CHECK_LOG_LEVEL(LOG_LEVEL_DEBUG))
5118 {
5119 char *expression = NULL;
5120
5121 zbx_eval_compose_expression(ctx, &expression);
5122 zabbix_log(LOG_LEVEL_DEBUG, "%s() expression[%d]:'%s' => '%s'", prefix, index, ctx->expression,
5123 expression);
5124 zbx_free(expression);
5125 }
5126 }
5127
zbx_substitute_functions_results(zbx_hashset_t * ifuncs,zbx_vector_ptr_t * triggers)5128 static void zbx_substitute_functions_results(zbx_hashset_t *ifuncs, zbx_vector_ptr_t *triggers)
5129 {
5130 DC_TRIGGER *tr;
5131 int i;
5132
5133 zabbix_log(LOG_LEVEL_DEBUG, "In %s() ifuncs_num:%d tr_num:%d",
5134 __func__, ifuncs->num_data, triggers->values_num);
5135
5136 for (i = 0; i < triggers->values_num; i++)
5137 {
5138 tr = (DC_TRIGGER *)triggers->values[i];
5139
5140 if (NULL != tr->new_error)
5141 continue;
5142
5143 if( SUCCEED != substitute_expression_functions_results(ifuncs, tr->eval_ctx, &tr->new_error))
5144 {
5145 tr->new_value = TRIGGER_VALUE_UNKNOWN;
5146 continue;
5147 }
5148
5149 log_expression(__func__, i, tr->eval_ctx);
5150
5151 if (TRIGGER_RECOVERY_MODE_RECOVERY_EXPRESSION == tr->recovery_mode)
5152 {
5153 if (SUCCEED != substitute_expression_functions_results(ifuncs, tr->eval_ctx_r, &tr->new_error))
5154 {
5155 tr->new_value = TRIGGER_VALUE_UNKNOWN;
5156 continue;
5157 }
5158
5159 log_expression(__func__, i, tr->eval_ctx_r);
5160 }
5161 }
5162
5163 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
5164 }
5165
5166 /******************************************************************************
5167 * *
5168 * Function: substitute_functions *
5169 * *
5170 * Purpose: substitute expression functions with their values *
5171 * *
5172 * Parameters: triggers - [IN] vector of DC_TRIGGER pointers, sorted by *
5173 * triggerids *
5174 * unknown_msgs - vector for storing messages for NOTSUPPORTED *
5175 * items and failed functions *
5176 * *
5177 * Author: Alexei Vladishev, Alexander Vladishev, Aleksandrs Saveljevs *
5178 * *
5179 * Comments: example: "({15}>10) or ({123}=1)" => "(26.416>10) or (0=1)" *
5180 * *
5181 ******************************************************************************/
substitute_functions(zbx_vector_ptr_t * triggers,const zbx_vector_uint64_t * history_itemids,const DC_ITEM * history_items,const int * history_errcodes)5182 static void substitute_functions(zbx_vector_ptr_t *triggers, const zbx_vector_uint64_t *history_itemids,
5183 const DC_ITEM *history_items, const int *history_errcodes)
5184 {
5185 zbx_vector_uint64_t functionids;
5186 zbx_hashset_t ifuncs, funcs;
5187
5188 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
5189
5190 zbx_vector_uint64_create(&functionids);
5191 zbx_extract_functionids(&functionids, triggers);
5192
5193 if (0 == functionids.values_num)
5194 goto empty;
5195
5196 zbx_hashset_create(&ifuncs, triggers->values_num, ZBX_DEFAULT_UINT64_HASH_FUNC,
5197 ZBX_DEFAULT_UINT64_COMPARE_FUNC);
5198
5199 zbx_hashset_create_ext(&funcs, triggers->values_num, func_hash_func, func_compare_func, func_clean,
5200 ZBX_DEFAULT_MEM_MALLOC_FUNC, ZBX_DEFAULT_MEM_REALLOC_FUNC, ZBX_DEFAULT_MEM_FREE_FUNC);
5201
5202 zbx_populate_function_items(&functionids, &funcs, &ifuncs, triggers);
5203
5204 if (0 != ifuncs.num_data)
5205 {
5206 zbx_evaluate_item_functions(&funcs, history_itemids, history_items, history_errcodes);
5207 zbx_substitute_functions_results(&ifuncs, triggers);
5208 }
5209
5210 zbx_hashset_destroy(&ifuncs);
5211 zbx_hashset_destroy(&funcs);
5212 empty:
5213 zbx_vector_uint64_destroy(&functionids);
5214
5215 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
5216 }
5217
5218 /******************************************************************************
5219 * *
5220 * Function: prepare_triggers *
5221 * *
5222 * Purpose: prepare triggers for evaluation *
5223 * *
5224 * Parameters: triggers - [IN] array of DC_TRIGGER pointers *
5225 * triggres_num - [IN] the number of triggers to prepare *
5226 * *
5227 ******************************************************************************/
prepare_triggers(DC_TRIGGER ** triggers,int triggers_num)5228 void prepare_triggers(DC_TRIGGER **triggers, int triggers_num)
5229 {
5230 int i;
5231
5232 for (i = 0; i < triggers_num; i++)
5233 {
5234 DC_TRIGGER *tr = triggers[i];
5235
5236 tr->eval_ctx = zbx_eval_deserialize_dyn(tr->expression_bin, tr->expression, ZBX_EVAL_EXCTRACT_ALL);
5237
5238 if (TRIGGER_RECOVERY_MODE_RECOVERY_EXPRESSION == tr->recovery_mode)
5239 {
5240 tr->eval_ctx_r = zbx_eval_deserialize_dyn(tr->recovery_expression_bin, tr->recovery_expression,
5241 ZBX_EVAL_EXCTRACT_ALL);
5242 }
5243 }
5244 }
5245
evaluate_expression(zbx_eval_context_t * ctx,const zbx_timespec_t * ts,double * result,char ** error)5246 static int evaluate_expression(zbx_eval_context_t *ctx, const zbx_timespec_t *ts, double *result,
5247 char **error)
5248 {
5249 zbx_variant_t value;
5250
5251 if (SUCCEED != zbx_eval_execute(ctx, ts, &value, error))
5252 return FAIL;
5253
5254 if (SUCCEED == ZBX_CHECK_LOG_LEVEL(LOG_LEVEL_DEBUG))
5255 {
5256 char *expression = NULL;
5257
5258 zbx_eval_compose_expression(ctx, &expression);
5259 zabbix_log(LOG_LEVEL_DEBUG, "%s(): %s => %s", __func__, expression, zbx_variant_value_desc(&value));
5260 zbx_free(expression);
5261 }
5262
5263 if (SUCCEED != zbx_variant_convert(&value, ZBX_VARIANT_DBL))
5264 {
5265 *error = zbx_dsprintf(*error, "Cannot convert expression result of type \"%s\" to"
5266 " floating point value", zbx_variant_type_desc(&value));
5267 zbx_variant_clear(&value);
5268
5269 return FAIL;
5270 }
5271
5272 *result = value.data.dbl;
5273
5274 return SUCCEED;
5275 }
5276
5277 /******************************************************************************
5278 * *
5279 * Function: evaluate_expressions *
5280 * *
5281 * Purpose: evaluate trigger expressions *
5282 * *
5283 * Parameters: triggers - [IN] vector of DC_TRIGGER pointers, sorted by *
5284 * triggerids *
5285 * *
5286 * Author: Alexei Vladishev *
5287 * *
5288 ******************************************************************************/
evaluate_expressions(zbx_vector_ptr_t * triggers,const zbx_vector_uint64_t * history_itemids,const DC_ITEM * history_items,const int * history_errcodes)5289 void evaluate_expressions(zbx_vector_ptr_t *triggers, const zbx_vector_uint64_t *history_itemids,
5290 const DC_ITEM *history_items, const int *history_errcodes)
5291 {
5292 DB_EVENT event;
5293 DC_TRIGGER *tr;
5294 int i;
5295 double expr_result;
5296 char err[MAX_STRING_LEN];
5297
5298 zabbix_log(LOG_LEVEL_DEBUG, "In %s() tr_num:%d", __func__, triggers->values_num);
5299
5300 event.object = EVENT_OBJECT_TRIGGER;
5301
5302 for (i = 0; i < triggers->values_num; i++)
5303 {
5304 tr = (DC_TRIGGER *)triggers->values[i];
5305
5306 event.value = tr->value;
5307
5308 if (SUCCEED != expand_trigger_macros(tr->eval_ctx, &event, err, sizeof(err)))
5309 {
5310 tr->new_error = zbx_dsprintf(tr->new_error, "Cannot evaluate expression: %s", err);
5311 tr->new_value = TRIGGER_VALUE_UNKNOWN;
5312 }
5313
5314 if (TRIGGER_RECOVERY_MODE_RECOVERY_EXPRESSION == tr->recovery_mode &&
5315 SUCCEED != expand_trigger_macros(tr->eval_ctx_r, &event, err, sizeof(err)))
5316 {
5317 tr->new_error = zbx_dsprintf(tr->new_error, "Cannot evaluate expression: %s", err);
5318 tr->new_value = TRIGGER_VALUE_UNKNOWN;
5319 }
5320 }
5321
5322 substitute_functions(triggers, history_itemids, history_items, history_errcodes);
5323
5324 /* calculate new trigger values based on their recovery modes and expression evaluations */
5325 for (i = 0; i < triggers->values_num; i++)
5326 {
5327 tr = (DC_TRIGGER *)triggers->values[i];
5328
5329 if (NULL != tr->new_error)
5330 continue;
5331
5332 if (SUCCEED != evaluate_expression(tr->eval_ctx, &tr->timespec, &expr_result, &tr->new_error))
5333 continue;
5334
5335 /* trigger expression evaluates to true, set PROBLEM value */
5336 if (SUCCEED != zbx_double_compare(expr_result, 0.0))
5337 {
5338 if (0 == (tr->flags & ZBX_DC_TRIGGER_PROBLEM_EXPRESSION))
5339 {
5340 /* trigger value should remain unchanged and no PROBLEM events should be generated if */
5341 /* problem expression evaluates to true, but trigger recalculation was initiated by a */
5342 /* time-based function or a new value of an item in recovery expression */
5343 tr->new_value = TRIGGER_VALUE_NONE;
5344 }
5345 else
5346 tr->new_value = TRIGGER_VALUE_PROBLEM;
5347
5348 continue;
5349 }
5350
5351 /* otherwise try to recover trigger by setting OK value */
5352 if (TRIGGER_VALUE_PROBLEM == tr->value && TRIGGER_RECOVERY_MODE_NONE != tr->recovery_mode)
5353 {
5354 if (TRIGGER_RECOVERY_MODE_EXPRESSION == tr->recovery_mode)
5355 {
5356 tr->new_value = TRIGGER_VALUE_OK;
5357 continue;
5358 }
5359
5360 /* processing recovery expression mode */
5361 if (SUCCEED != evaluate_expression(tr->eval_ctx_r, &tr->timespec, &expr_result, &tr->new_error))
5362 {
5363 tr->new_value = TRIGGER_VALUE_UNKNOWN;
5364 continue;
5365 }
5366
5367 if (SUCCEED != zbx_double_compare(expr_result, 0.0))
5368 {
5369 tr->new_value = TRIGGER_VALUE_OK;
5370 continue;
5371 }
5372 }
5373
5374 /* no changes, keep the old value */
5375 tr->new_value = TRIGGER_VALUE_NONE;
5376 }
5377
5378 if (SUCCEED == ZBX_CHECK_LOG_LEVEL(LOG_LEVEL_DEBUG))
5379 {
5380 for (i = 0; i < triggers->values_num; i++)
5381 {
5382 tr = (DC_TRIGGER *)triggers->values[i];
5383
5384 if (NULL != tr->new_error)
5385 {
5386 zabbix_log(LOG_LEVEL_DEBUG, "%s():expression [%s] cannot be evaluated: %s",
5387 __func__, tr->expression, tr->new_error);
5388 }
5389 }
5390
5391 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
5392 }
5393 }
5394
5395 /******************************************************************************
5396 * *
5397 * Function: process_simple_macro_token *
5398 * *
5399 * Purpose: trying to resolve the discovery macros in item key parameters *
5400 * in simple macros like {host:key[].func()} *
5401 * *
5402 ******************************************************************************/
process_simple_macro_token(char ** data,zbx_token_t * token,const struct zbx_json_parse * jp_row,const zbx_vector_ptr_t * lld_macro_paths,char * error,size_t max_error_len)5403 static int process_simple_macro_token(char **data, zbx_token_t *token, const struct zbx_json_parse *jp_row,
5404 const zbx_vector_ptr_t *lld_macro_paths, char *error, size_t max_error_len)
5405 {
5406 char *key = NULL, *replace_to = NULL, *dot, *params;
5407 size_t replace_to_offset = 0, replace_to_alloc = 128, lld_start, lld_end;
5408 int ret = FAIL;
5409
5410 if ('{' == (*data)[token->data.simple_macro.host.l] &&
5411 NULL == macro_in_list(*data, token->data.simple_macro.host, simple_host_macros, NULL))
5412 {
5413 goto out;
5414 }
5415
5416 replace_to = (char *)zbx_malloc(NULL, replace_to_alloc);
5417
5418 lld_start = token->data.simple_macro.key.l;
5419 lld_end = token->data.simple_macro.func_param.r - 1;
5420 dot = *data + token->data.simple_macro.key.r + 1;
5421 params = *data + token->data.simple_macro.func_param.l + 1;
5422
5423 /* extract key and substitute macros */
5424 *dot = '\0';
5425 key = zbx_strdup(key, *data + token->data.simple_macro.key.l);
5426 substitute_key_macros_impl(&key, NULL, NULL, jp_row, lld_macro_paths, MACRO_TYPE_ITEM_KEY, NULL, 0);
5427 *dot = '.';
5428
5429 zbx_strcpy_alloc(&replace_to, &replace_to_alloc, &replace_to_offset, key);
5430 zbx_strncpy_alloc(&replace_to, &replace_to_alloc, &replace_to_offset, dot, params - dot);
5431
5432 /* substitute macros in function parameters */
5433 if (SUCCEED != substitute_function_lld_param(params, *data + lld_end - params + 1, 0, &replace_to,
5434 &replace_to_alloc, &replace_to_offset, jp_row, lld_macro_paths, error, max_error_len))
5435 {
5436 goto out;
5437 }
5438
5439 /* replace LLD part in original string and adjust token boundary */
5440 zbx_replace_string(data, lld_start, &lld_end, replace_to);
5441 token->loc.r += lld_end - (token->data.simple_macro.func_param.r - 1);
5442
5443 ret = SUCCEED;
5444 out:
5445 zbx_free(replace_to);
5446 zbx_free(key);
5447
5448 return ret;
5449 }
5450
5451 /******************************************************************************
5452 * *
5453 * Function: process_lld_macro_token *
5454 * *
5455 * Purpose: expand discovery macro in expression *
5456 * *
5457 * Parameters: data - [IN/OUT] the expression containing lld macro *
5458 * token - [IN/OUT] the token with lld macro location data *
5459 * flags - [IN] the flags passed to *
5460 * subtitute_discovery_macros() function *
5461 * jp_row - [IN] discovery data *
5462 * cur_token_inside_quote - [IN] used in autoquoting for trigger prototypes *
5463 * *
5464 ******************************************************************************/
process_lld_macro_token(char ** data,zbx_token_t * token,int flags,const struct zbx_json_parse * jp_row,const zbx_vector_ptr_t * lld_macro_paths,int cur_token_inside_quote)5465 static void process_lld_macro_token(char **data, zbx_token_t *token, int flags, const struct zbx_json_parse *jp_row,
5466 const zbx_vector_ptr_t *lld_macro_paths, int cur_token_inside_quote)
5467 {
5468 char c, *replace_to = NULL;
5469 int l ,r;
5470
5471 if (ZBX_TOKEN_LLD_FUNC_MACRO == token->type)
5472 {
5473 l = token->data.lld_func_macro.macro.l;
5474 r = token->data.lld_func_macro.macro.r;
5475 }
5476 else
5477 {
5478 l = token->loc.l;
5479 r = token->loc.r;
5480 }
5481
5482 c = (*data)[r + 1];
5483 (*data)[r + 1] = '\0';
5484
5485 if (SUCCEED != zbx_lld_macro_value_by_name(jp_row, lld_macro_paths, *data + l, &replace_to))
5486 {
5487 zabbix_log(LOG_LEVEL_DEBUG, "cannot substitute macro \"%s\": not found in value set", *data + l);
5488
5489 (*data)[r + 1] = c;
5490 zbx_free(replace_to);
5491
5492 return;
5493 }
5494
5495 (*data)[r + 1] = c;
5496
5497 if (ZBX_TOKEN_LLD_FUNC_MACRO == token->type)
5498 {
5499 if (SUCCEED != (zbx_calculate_macro_function(*data, &token->data.lld_func_macro, &replace_to)))
5500 {
5501 int len = token->data.lld_func_macro.func.r - token->data.lld_func_macro.func.l + 1;
5502
5503 zabbix_log(LOG_LEVEL_DEBUG, "cannot execute function \"%.*s\"", len,
5504 *data + token->data.lld_func_macro.func.l);
5505
5506 zbx_free(replace_to);
5507
5508 return;
5509 }
5510 }
5511
5512 if (0 != (flags & ZBX_TOKEN_JSON))
5513 {
5514 zbx_json_escape(&replace_to);
5515 }
5516 else if (0 != (flags & ZBX_TOKEN_REGEXP))
5517 {
5518 zbx_regexp_escape(&replace_to);
5519 }
5520 else if (0 != (flags & ZBX_TOKEN_REGEXP_OUTPUT))
5521 {
5522 char *replace_to_esc;
5523
5524 replace_to_esc = zbx_dyn_escape_string(replace_to, "\\");
5525 zbx_free(replace_to);
5526 replace_to = replace_to_esc;
5527 }
5528 else if (0 != (flags & ZBX_TOKEN_XPATH))
5529 {
5530 xml_escape_xpath(&replace_to);
5531 }
5532 else if (0 != (flags & ZBX_TOKEN_PROMETHEUS))
5533 {
5534 char *replace_to_esc;
5535
5536 replace_to_esc = zbx_dyn_escape_string(replace_to, "\\\n\"");
5537 zbx_free(replace_to);
5538 replace_to = replace_to_esc;
5539 }
5540 else if (0 != (flags & ZBX_TOKEN_JSONPATH) && ZBX_TOKEN_LLD_MACRO == token->type)
5541 {
5542 char *replace_to_esc;
5543
5544 replace_to_esc = zbx_dyn_escape_string(replace_to, "\\\"");
5545 zbx_free(replace_to);
5546 replace_to = replace_to_esc;
5547 }
5548 else if (0 != (flags & ZBX_TOKEN_STRING))
5549 {
5550 if (1 == cur_token_inside_quote)
5551 {
5552 char *replace_to_esc;
5553
5554 replace_to_esc = zbx_dyn_escape_string(replace_to, "\\\"");
5555 zbx_free(replace_to);
5556 replace_to = replace_to_esc;
5557 }
5558 }
5559 else if (0 != (flags & ZBX_TOKEN_STR_REPLACE))
5560 {
5561 char *replace_to_esc;
5562
5563 replace_to_esc = zbx_str_printable_dyn(replace_to);
5564
5565 zbx_free(replace_to);
5566 replace_to = replace_to_esc;
5567 }
5568
5569 if (NULL != replace_to)
5570 {
5571 size_t data_alloc, data_len;
5572
5573 data_alloc = data_len = strlen(*data) + 1;
5574 token->loc.r += zbx_replace_mem_dyn(data, &data_alloc, &data_len, token->loc.l,
5575 token->loc.r - token->loc.l + 1, replace_to, strlen(replace_to));
5576 zbx_free(replace_to);
5577 }
5578 }
5579
5580 /******************************************************************************
5581 * *
5582 * Function: process_user_macro_token *
5583 * *
5584 * Purpose: expand discovery macro in user macro context *
5585 * *
5586 * Parameters: data - [IN/OUT] the expression containing lld macro *
5587 * token - [IN/OUT] the token with user macro location *
5588 * data *
5589 * jp_row - [IN] discovery data *
5590 * error - [OUT]error buffer *
5591 * max_error_len - [IN] the size of error buffer *
5592 * *
5593 ******************************************************************************/
process_user_macro_token(char ** data,zbx_token_t * token,const struct zbx_json_parse * jp_row,const zbx_vector_ptr_t * lld_macro_paths,char * error,size_t max_error_len)5594 static int process_user_macro_token(char **data, zbx_token_t *token, const struct zbx_json_parse *jp_row,
5595 const zbx_vector_ptr_t *lld_macro_paths, char *error, size_t max_error_len)
5596 {
5597 int force_quote, ret;
5598 size_t context_r;
5599 char *context, *context_esc, *errmsg = NULL;
5600 zbx_token_user_macro_t *macro = &token->data.user_macro;
5601
5602 /* user macro without context, nothing to replace */
5603 if (0 == token->data.user_macro.context.l)
5604 return SUCCEED;
5605
5606 force_quote = ('"' == (*data)[macro->context.l]);
5607 context = zbx_user_macro_unquote_context_dyn(*data + macro->context.l, macro->context.r - macro->context.l + 1);
5608
5609 /* substitute_lld_macros() can't fail with ZBX_TOKEN_LLD_MACRO or ZBX_TOKEN_LLD_FUNC_MACRO flags set */
5610 substitute_lld_macros(&context, jp_row, lld_macro_paths, ZBX_TOKEN_LLD_MACRO | ZBX_TOKEN_LLD_FUNC_MACRO, NULL,
5611 0);
5612
5613 if (NULL != (context_esc = zbx_user_macro_quote_context_dyn(context, force_quote, &errmsg)))
5614 {
5615 context_r = macro->context.r;
5616 zbx_replace_string(data, macro->context.l, &context_r, context_esc);
5617
5618 token->loc.r += context_r - macro->context.r;
5619
5620 zbx_free(context_esc);
5621 ret = SUCCEED;
5622 }
5623 else
5624 {
5625 zbx_strlcpy(error, errmsg, max_error_len);
5626 zbx_free(errmsg);
5627 ret = FAIL;
5628 }
5629
5630 zbx_free(context);
5631
5632 return ret;
5633 }
5634
5635 /******************************************************************************
5636 * *
5637 * Function: substitute_query_filter_lld_macros *
5638 * *
5639 * Purpose: substitute lld macros in calculated item query filter *
5640 * *
5641 * Parameters: filter - [IN/OUT] the filter *
5642 * jp_row - [IN] the lld data row *
5643 * lld_macro_paths - [IN] use json path to extract from jp_row *
5644 * error - [OUT] the error message *
5645 * *
5646 * Return value: SUCCEED - the macros were expanded successfully. *
5647 * FAIL - otherwise. *
5648 * *
5649 ******************************************************************************/
substitute_query_filter_lld_macros(char ** filter,const struct zbx_json_parse * jp_row,const zbx_vector_ptr_t * lld_macro_paths,char ** error)5650 static int substitute_query_filter_lld_macros(char **filter, const struct zbx_json_parse *jp_row,
5651 const zbx_vector_ptr_t *lld_macro_paths, char **error)
5652 {
5653 char *errmsg = NULL, err[128], *new_filter = NULL;
5654 int i, ret = FAIL;
5655 zbx_eval_context_t ctx;
5656
5657 if (SUCCEED != zbx_eval_parse_expression(&ctx, *filter,
5658 ZBX_EVAL_PARSE_QUERY_EXPRESSION | ZBX_EVAL_COMPOSE_QUOTE | ZBX_EVAL_PARSE_LLDMACRO, &errmsg))
5659 {
5660 *error = zbx_dsprintf(NULL, "cannot parse item query filter: %s", errmsg);
5661 zbx_free(errmsg);
5662 goto out;
5663 }
5664
5665 for (i = 0; i < ctx.stack.values_num; i++)
5666 {
5667 zbx_eval_token_t *token = &ctx.stack.values[i];
5668 char *value;
5669
5670 switch (token->type)
5671 {
5672 case ZBX_EVAL_TOKEN_VAR_LLDMACRO:
5673 case ZBX_EVAL_TOKEN_VAR_USERMACRO:
5674 case ZBX_EVAL_TOKEN_VAR_STR:
5675 value = zbx_substr_unquote(ctx.expression, token->loc.l, token->loc.r);
5676
5677 if (FAIL == substitute_lld_macros(&value, jp_row, lld_macro_paths, ZBX_MACRO_ANY, err,
5678 sizeof(err)))
5679 {
5680 *error = zbx_strdup(NULL, err);
5681 zbx_free(value);
5682
5683 goto clean;
5684 }
5685 break;
5686 default:
5687 continue;
5688 }
5689
5690 zbx_variant_set_str(&token->value, value);
5691 }
5692
5693 zbx_eval_compose_expression(&ctx, &new_filter);
5694 zbx_free(*filter);
5695 *filter = new_filter;
5696
5697 ret = SUCCEED;
5698 clean:
5699 zbx_eval_clear(&ctx);
5700 out:
5701 return ret;
5702 }
5703
5704 /******************************************************************************
5705 * *
5706 * Function: substitute_item_query_macros *
5707 * *
5708 * Purpose: substitute lld macros in history function item query argument *
5709 * /host/key?[filter] *
5710 * *
5711 * Parameters: ctx - [IN] the calculated item formula *
5712 * token - [IN] the item query token *
5713 * jp_row - [IN] the lld data row *
5714 * lld_macro_paths - [IN] use json path to extract from jp_row *
5715 * itemquery - [OUT] the item query with expanded macros *
5716 * error - [OUT] the error message *
5717 * *
5718 * Return value: SUCCEED - the macros were expanded successfully. *
5719 * FAIL - otherwise. *
5720 * *
5721 ******************************************************************************/
substitute_item_query_lld_macros(const zbx_eval_context_t * ctx,const zbx_eval_token_t * token,const struct zbx_json_parse * jp_row,const zbx_vector_ptr_t * lld_macro_paths,char ** itemquery,char ** error)5722 static int substitute_item_query_lld_macros(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token,
5723 const struct zbx_json_parse *jp_row, const zbx_vector_ptr_t *lld_macro_paths, char **itemquery,
5724 char **error)
5725 {
5726 zbx_item_query_t query;
5727 char err[128];
5728 int ret = FAIL;
5729 size_t itemquery_alloc = 0, itemquery_offset = 0;
5730
5731 if (0 == zbx_eval_parse_query(ctx->expression + token->loc.l, token->loc.r - token->loc.l + 1, &query))
5732 {
5733 *error = zbx_strdup(NULL, "invalid item reference");
5734 return FAIL;
5735 }
5736
5737 if (SUCCEED != substitute_key_macros(&query.key, NULL, NULL, jp_row, lld_macro_paths, MACRO_TYPE_ITEM_KEY,
5738 err, sizeof(err)))
5739 {
5740 *error = zbx_strdup(NULL, err);
5741 goto out;
5742 }
5743
5744 if (NULL != query.filter && SUCCEED != substitute_query_filter_lld_macros(&query.filter, jp_row,
5745 lld_macro_paths, error))
5746 {
5747 goto out;
5748 }
5749
5750 zbx_snprintf_alloc(itemquery, &itemquery_alloc, &itemquery_offset, "/%s/%s", ZBX_NULL2EMPTY_STR(query.host),
5751 query.key);
5752 if (NULL != query.filter)
5753 zbx_snprintf_alloc(itemquery, &itemquery_alloc, &itemquery_offset, "?[%s]", query.filter);
5754
5755 ret = SUCCEED;
5756 out:
5757 zbx_eval_clear_query(&query);
5758
5759 return ret;
5760 }
5761
5762 /******************************************************************************
5763 * *
5764 * Function: zbx_substitute_expression_macros *
5765 * *
5766 * Purpose: substitutes lld macros in an expression *
5767 * *
5768 * Parameters: data - [IN/OUT] the expression *
5769 * jp_row - [IN] the lld data row *
5770 * lld_macro_paths - [IN] use json path to extract from jp_row *
5771 * error - [IN] pointer to string for reporting errors *
5772 * max_error_len - [IN] size of 'error' string *
5773 * *
5774 ******************************************************************************/
zbx_substitute_expression_lld_macros(char ** data,zbx_uint64_t rules,const struct zbx_json_parse * jp_row,const zbx_vector_ptr_t * lld_macro_paths,char ** error)5775 int zbx_substitute_expression_lld_macros(char **data, zbx_uint64_t rules, const struct zbx_json_parse *jp_row,
5776 const zbx_vector_ptr_t *lld_macro_paths, char **error)
5777 {
5778 char *exp = NULL;
5779 int i, ret = FAIL;
5780 zbx_eval_context_t ctx;
5781
5782 zabbix_log(LOG_LEVEL_DEBUG, "In %s() expression:%s", __func__, *data);
5783
5784 if (SUCCEED != zbx_eval_parse_expression(&ctx, *data, rules, error))
5785 goto out;
5786
5787 for (i = 0; i < ctx.stack.values_num; i++)
5788 {
5789 zbx_eval_token_t *token = &ctx.stack.values[i];
5790 char *value = NULL, err[128];
5791
5792 switch(token->type)
5793 {
5794 case ZBX_EVAL_TOKEN_ARG_QUERY:
5795 if (FAIL == substitute_item_query_lld_macros(&ctx, token, jp_row, lld_macro_paths,
5796 &value, error))
5797 {
5798 goto clean;
5799 }
5800 break;
5801 case ZBX_EVAL_TOKEN_VAR_LLDMACRO:
5802 case ZBX_EVAL_TOKEN_VAR_USERMACRO:
5803 case ZBX_EVAL_TOKEN_VAR_STR:
5804 case ZBX_EVAL_TOKEN_VAR_NUM:
5805 case ZBX_EVAL_TOKEN_ARG_PERIOD:
5806 value = zbx_substr_unquote(ctx.expression, token->loc.l, token->loc.r);
5807
5808 if (FAIL == substitute_lld_macros(&value, jp_row, lld_macro_paths, ZBX_MACRO_ANY, err,
5809 sizeof(err)))
5810 {
5811 *error = zbx_strdup(NULL, err);
5812 zbx_free(value);
5813 goto clean;
5814 }
5815 break;
5816 default:
5817 continue;
5818 }
5819
5820 zbx_variant_clear(&token->value);
5821 zbx_variant_set_str(&token->value, value);
5822 }
5823
5824 zbx_eval_compose_expression(&ctx, &exp);
5825
5826 zbx_free(*data);
5827 *data = exp;
5828 exp = NULL;
5829
5830 ret = SUCCEED;
5831 clean:
5832 zbx_free(exp);
5833 zbx_eval_clear(&ctx);
5834 out:
5835 zabbix_log(LOG_LEVEL_DEBUG, "End of %s() expression:%s", __func__, *data);
5836
5837 return ret;
5838 }
5839
5840 /******************************************************************************
5841 * *
5842 * Function: process_expression_macro_token *
5843 * *
5844 * Purpose: expand discovery macro in expression macro *
5845 * *
5846 * Parameters: data - [IN/OUT] the expression containing macro *
5847 * token - [IN/OUT] the macro token *
5848 * jp_row - [IN] discovery data *
5849 * lld_macro_paths - [IN] discovery data *
5850 * error - [OUT] error message *
5851 * max_error_len - [IN] the size of error buffer *
5852 * *
5853 ******************************************************************************/
process_expression_macro_token(char ** data,zbx_token_t * token,const struct zbx_json_parse * jp_row,const zbx_vector_ptr_t * lld_macro_paths,char * error,size_t error_len)5854 static int process_expression_macro_token(char **data, zbx_token_t *token, const struct zbx_json_parse *jp_row,
5855 const zbx_vector_ptr_t *lld_macro_paths, char *error, size_t error_len)
5856 {
5857 char *errmsg = NULL, *expression;
5858 size_t right = token->data.expression_macro.expression.r;
5859
5860 expression = zbx_substr(*data, token->data.expression_macro.expression.l,
5861 token->data.expression_macro.expression.r);
5862
5863 if (FAIL == zbx_substitute_expression_lld_macros(&expression, ZBX_EVAL_EXPRESSION_MACRO_LLD, jp_row,
5864 lld_macro_paths, &errmsg))
5865 {
5866 zbx_free(expression);
5867 zbx_strlcpy(error, errmsg, error_len);
5868 zbx_free(errmsg);
5869
5870 return FAIL;
5871 }
5872
5873 zbx_replace_string(data, token->data.expression_macro.expression.l, &right, expression);
5874 token->loc.r += right - token->data.expression_macro.expression.r;
5875 zbx_free(expression);
5876
5877 return SUCCEED;
5878 }
5879
5880 /******************************************************************************
5881 * *
5882 * Function: substitute_func_macro *
5883 * *
5884 * Purpose: substitute lld macros in function macro parameters *
5885 * *
5886 * Parameters: data - [IN/OUT] pointer to a buffer *
5887 * token - [IN/OUT] the token with function macro location data *
5888 * jp_row - [IN] discovery data *
5889 * error - [OUT] error message *
5890 * max_error_len - [IN] the size of error buffer *
5891 * *
5892 * Return value: SUCCEED - the lld macros were resolved successfully *
5893 * FAIL - otherwise *
5894 * *
5895 ******************************************************************************/
substitute_func_macro(char ** data,zbx_token_t * token,const struct zbx_json_parse * jp_row,const zbx_vector_ptr_t * lld_macro_paths,char * error,size_t max_error_len)5896 static int substitute_func_macro(char **data, zbx_token_t *token, const struct zbx_json_parse *jp_row,
5897 const zbx_vector_ptr_t *lld_macro_paths, char *error, size_t max_error_len)
5898 {
5899 int ret, offset = 0;
5900 char *exp = NULL;
5901 size_t exp_alloc = 0, exp_offset = 0, right;
5902 size_t par_l = token->data.func_macro.func_param.l, par_r = token->data.func_macro.func_param.r;
5903 zbx_token_t tok;
5904
5905 if (SUCCEED == zbx_token_find(*data, (int)token->data.func_macro.macro.l, &tok,
5906 ZBX_TOKEN_SEARCH_EXPRESSION_MACRO) && ZBX_TOKEN_EXPRESSION_MACRO == tok.type &&
5907 tok.loc.r <= token->data.func_macro.macro.r)
5908 {
5909 offset = (int)tok.loc.r;
5910
5911 if (SUCCEED == process_expression_macro_token(data, &tok, jp_row, lld_macro_paths, error,
5912 max_error_len))
5913 {
5914 offset = tok.loc.r - offset;
5915 }
5916 }
5917
5918 ret = substitute_function_lld_param(*data + par_l + offset + 1, par_r - (par_l + 1), 0, &exp, &exp_alloc,
5919 &exp_offset, jp_row, lld_macro_paths, error, max_error_len);
5920
5921 if (SUCCEED == ret)
5922 {
5923 right = par_r + offset - 1;
5924 zbx_replace_string(data, par_l + offset + 1, &right, exp);
5925 token->loc.r = right + 1;
5926 }
5927
5928 zbx_free(exp);
5929
5930 return ret;
5931 }
5932
5933 /******************************************************************************
5934 * *
5935 * Function: substitute_lld_macros *
5936 * *
5937 * Parameters: data - [IN/OUT] pointer to a buffer *
5938 * jp_row - [IN] discovery data *
5939 * flags - [IN] ZBX_MACRO_ANY - all LLD macros will be resolved *
5940 * without validation of the value type *
5941 * ZBX_MACRO_NUMERIC - values for LLD macros should *
5942 * be numeric *
5943 * ZBX_MACRO_SIMPLE - LLD macros, located in the *
5944 * item key parameters in simple macros will be *
5945 * resolved considering quotes. *
5946 * Flag ZBX_MACRO_NUMERIC doesn't affect these *
5947 * macros. *
5948 * ZBX_MACRO_FUNC - function macros will be *
5949 * skipped (lld macros inside function macros will *
5950 * be ignored) for macros specified in func_macros *
5951 * array *
5952 * error - [OUT] should be not NULL if ZBX_MACRO_NUMERIC flag is *
5953 * set *
5954 * max_error_len - [IN] the size of error buffer *
5955 * *
5956 * Return value: Always SUCCEED if numeric flag is not set, otherwise SUCCEED *
5957 * if all discovery macros resolved to numeric values, *
5958 * otherwise FAIL with an error message. *
5959 * *
5960 * Author: Alexander Vladishev *
5961 * *
5962 ******************************************************************************/
substitute_lld_macros(char ** data,const struct zbx_json_parse * jp_row,const zbx_vector_ptr_t * lld_macro_paths,int flags,char * error,size_t max_error_len)5963 int substitute_lld_macros(char **data, const struct zbx_json_parse *jp_row, const zbx_vector_ptr_t *lld_macro_paths,
5964 int flags, char *error, size_t max_error_len)
5965 {
5966 int ret = SUCCEED, pos = 0, prev_token_loc_r = -1, cur_token_inside_quote = 0;
5967 size_t i;
5968 zbx_token_t token;
5969
5970 zabbix_log(LOG_LEVEL_DEBUG, "In %s() data:'%s'", __func__, *data);
5971
5972 while (SUCCEED == ret && SUCCEED == zbx_token_find(*data, pos, &token, ZBX_TOKEN_SEARCH_EXPRESSION_MACRO))
5973 {
5974 for (i = prev_token_loc_r + 1; i < token.loc.l; i++)
5975 {
5976 switch ((*data)[i])
5977 {
5978 case '\\':
5979 if (0 != cur_token_inside_quote)
5980 i++;
5981 break;
5982 case '"':
5983 cur_token_inside_quote = !cur_token_inside_quote;
5984 break;
5985 }
5986 }
5987
5988 if (0 != (token.type & flags))
5989 {
5990 switch (token.type)
5991 {
5992 case ZBX_TOKEN_LLD_MACRO:
5993 case ZBX_TOKEN_LLD_FUNC_MACRO:
5994 process_lld_macro_token(data, &token, flags, jp_row, lld_macro_paths,
5995 cur_token_inside_quote);
5996 pos = token.loc.r;
5997 break;
5998 case ZBX_TOKEN_USER_MACRO:
5999 ret = process_user_macro_token(data, &token, jp_row, lld_macro_paths, error,
6000 max_error_len);
6001 pos = token.loc.r;
6002 break;
6003 case ZBX_TOKEN_SIMPLE_MACRO:
6004 process_simple_macro_token(data, &token, jp_row, lld_macro_paths, error,
6005 max_error_len);
6006 pos = token.loc.r;
6007 break;
6008 case ZBX_TOKEN_FUNC_MACRO:
6009 if (NULL != func_macro_in_list(*data, &token.data.func_macro, NULL))
6010 {
6011 ret = substitute_func_macro(data, &token, jp_row, lld_macro_paths,
6012 error, max_error_len);
6013 pos = token.loc.r;
6014 }
6015 break;
6016 case ZBX_TOKEN_EXPRESSION_MACRO:
6017 if (SUCCEED == process_expression_macro_token(data, &token, jp_row,
6018 lld_macro_paths, error, max_error_len))
6019 {
6020 pos = token.loc.r;
6021 }
6022 break;
6023 }
6024 }
6025 prev_token_loc_r = token.loc.r;
6026 pos++;
6027 }
6028
6029 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s data:'%s'", __func__, zbx_result_string(ret), *data);
6030
6031 return ret;
6032 }
6033
6034 typedef struct
6035 {
6036 zbx_uint64_t *hostid;
6037 DC_ITEM *dc_item;
6038 const struct zbx_json_parse *jp_row;
6039 const zbx_vector_ptr_t *lld_macro_paths;
6040 int macro_type;
6041 }
6042 replace_key_param_data_t;
6043
6044 /******************************************************************************
6045 * *
6046 * Function: replace_key_param *
6047 * *
6048 * Comments: auxiliary function for substitute_key_macros() *
6049 * *
6050 ******************************************************************************/
replace_key_param_cb(const char * data,int key_type,int level,int num,int quoted,void * cb_data,char ** param)6051 static int replace_key_param_cb(const char *data, int key_type, int level, int num, int quoted, void *cb_data,
6052 char **param)
6053 {
6054 replace_key_param_data_t *replace_key_param_data = (replace_key_param_data_t *)cb_data;
6055 zbx_uint64_t *hostid = replace_key_param_data->hostid;
6056 DC_ITEM *dc_item = replace_key_param_data->dc_item;
6057 const struct zbx_json_parse *jp_row = replace_key_param_data->jp_row;
6058 const zbx_vector_ptr_t *lld_macros = replace_key_param_data->lld_macro_paths;
6059 int macro_type = replace_key_param_data->macro_type, ret = SUCCEED;
6060
6061 ZBX_UNUSED(num);
6062
6063 if (ZBX_KEY_TYPE_ITEM == key_type && 0 == level)
6064 return ret;
6065
6066 if (NULL == strchr(data, '{'))
6067 return ret;
6068
6069 *param = zbx_strdup(NULL, data);
6070
6071 if (0 != level)
6072 unquote_key_param(*param);
6073
6074 if (NULL == jp_row)
6075 substitute_simple_macros_impl(NULL, NULL, NULL, NULL, hostid, NULL, dc_item, NULL, NULL, NULL,
6076 param, macro_type, NULL, 0);
6077 else
6078 substitute_lld_macros(param, jp_row, lld_macros, ZBX_MACRO_ANY, NULL, 0);
6079
6080 if (0 != level)
6081 {
6082 if (FAIL == (ret = quote_key_param(param, quoted)))
6083 zbx_free(*param);
6084 }
6085
6086 return ret;
6087 }
6088
6089 /******************************************************************************
6090 * *
6091 * Function: substitute_key_macros_impl *
6092 * *
6093 * Purpose: safely substitutes macros in parameters of an item key and OID *
6094 * *
6095 * Example: key | macro | result | return *
6096 * -------------------------+--------+-------------------+--------- *
6097 * echo.sh[{$MACRO}] | a | echo.sh[a] | SUCCEED *
6098 * echo.sh[{$MACRO}] | a\ | echo.sh[a\] | SUCCEED *
6099 * echo.sh["{$MACRO}"] | a | echo.sh["a"] | SUCCEED *
6100 * echo.sh["{$MACRO}"] | a\ | undefined | FAIL *
6101 * echo.sh[{$MACRO}] | a | echo.sh[" a"] | SUCCEED *
6102 * echo.sh[{$MACRO}] | a\ | undefined | FAIL *
6103 * echo.sh["{$MACRO}"] | a | echo.sh[" a"] | SUCCEED *
6104 * echo.sh["{$MACRO}"] | a\ | undefined | FAIL *
6105 * echo.sh[{$MACRO}] | "a" | echo.sh["\"a\""] | SUCCEED *
6106 * echo.sh[{$MACRO}] | "a"\ | undefined | FAIL *
6107 * echo.sh["{$MACRO}"] | "a" | echo.sh["\"a\""] | SUCCEED *
6108 * echo.sh["{$MACRO}"] | "a"\ | undefined | FAIL *
6109 * echo.sh[{$MACRO}] | a,b | echo.sh["a,b"] | SUCCEED *
6110 * echo.sh[{$MACRO}] | a,b\ | undefined | FAIL *
6111 * echo.sh["{$MACRO}"] | a,b | echo.sh["a,b"] | SUCCEED *
6112 * echo.sh["{$MACRO}"] | a,b\ | undefined | FAIL *
6113 * echo.sh[{$MACRO}] | a] | echo.sh["a]"] | SUCCEED *
6114 * echo.sh[{$MACRO}] | a]\ | undefined | FAIL *
6115 * echo.sh["{$MACRO}"] | a] | echo.sh["a]"] | SUCCEED *
6116 * echo.sh["{$MACRO}"] | a]\ | undefined | FAIL *
6117 * echo.sh[{$MACRO}] | [a | echo.sh["a]"] | SUCCEED *
6118 * echo.sh[{$MACRO}] | [a\ | undefined | FAIL *
6119 * echo.sh["{$MACRO}"] | [a | echo.sh["[a"] | SUCCEED *
6120 * echo.sh["{$MACRO}"] | [a\ | undefined | FAIL *
6121 * ifInOctets.{#SNMPINDEX} | 1 | ifInOctets.1 | SUCCEED *
6122 * *
6123 ******************************************************************************/
substitute_key_macros_impl(char ** data,zbx_uint64_t * hostid,DC_ITEM * dc_item,const struct zbx_json_parse * jp_row,const zbx_vector_ptr_t * lld_macro_paths,int macro_type,char * error,size_t maxerrlen)6124 static int substitute_key_macros_impl(char **data, zbx_uint64_t *hostid, DC_ITEM *dc_item,
6125 const struct zbx_json_parse *jp_row, const zbx_vector_ptr_t *lld_macro_paths, int macro_type,
6126 char *error, size_t maxerrlen)
6127 {
6128 replace_key_param_data_t replace_key_param_data;
6129 int key_type, ret;
6130
6131 zabbix_log(LOG_LEVEL_DEBUG, "In %s() data:'%s'", __func__, *data);
6132
6133 replace_key_param_data.hostid = hostid;
6134 replace_key_param_data.dc_item = dc_item;
6135 replace_key_param_data.jp_row = jp_row;
6136 replace_key_param_data.lld_macro_paths = lld_macro_paths;
6137 replace_key_param_data.macro_type = macro_type;
6138
6139 switch (macro_type)
6140 {
6141 case MACRO_TYPE_ITEM_KEY:
6142 key_type = ZBX_KEY_TYPE_ITEM;
6143 break;
6144 case MACRO_TYPE_SNMP_OID:
6145 key_type = ZBX_KEY_TYPE_OID;
6146 break;
6147 default:
6148 THIS_SHOULD_NEVER_HAPPEN;
6149 exit(EXIT_FAILURE);
6150 }
6151
6152 ret = replace_key_params_dyn(data, key_type, replace_key_param_cb, &replace_key_param_data, error, maxerrlen);
6153
6154 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s data:'%s'", __func__, zbx_result_string(ret), *data);
6155
6156 return ret;
6157 }
6158
6159 /******************************************************************************
6160 * *
6161 * Function: substitute_function_lld_param *
6162 * *
6163 * Purpose: substitute lld macros in function parameters *
6164 * *
6165 * Parameters: e - [IN] the function parameter list without *
6166 * enclosing parentheses: *
6167 * <p1>, <p2>, ...<pN> *
6168 * len - [IN] the length of function parameter list *
6169 * key_in_param - [IN] 1 - the first parameter must be host:key *
6170 * 0 - otherwise *
6171 * exp - [IN/OUT] output buffer *
6172 * exp_alloc - [IN/OUT] the size of output buffer *
6173 * exp_offset - [IN/OUT] the current position in output buffer *
6174 * jp_row - [IN] discovery data *
6175 * error - [OUT] error message *
6176 * max_error_len - [IN] the size of error buffer *
6177 * *
6178 * Return value: SUCCEED - the lld macros were resolved successfully *
6179 * FAIL - otherwise *
6180 * *
6181 ******************************************************************************/
substitute_function_lld_param(const char * e,size_t len,unsigned char key_in_param,char ** exp,size_t * exp_alloc,size_t * exp_offset,const struct zbx_json_parse * jp_row,const zbx_vector_ptr_t * lld_macro_paths,char * error,size_t max_error_len)6182 int substitute_function_lld_param(const char *e, size_t len, unsigned char key_in_param,
6183 char **exp, size_t *exp_alloc, size_t *exp_offset, const struct zbx_json_parse *jp_row,
6184 const zbx_vector_ptr_t *lld_macro_paths, char *error, size_t max_error_len)
6185 {
6186 int ret = SUCCEED;
6187 size_t sep_pos;
6188 char *param = NULL;
6189 const char *p;
6190
6191 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
6192
6193 if (0 == len)
6194 {
6195 zbx_strcpy_alloc(exp, exp_alloc, exp_offset, "");
6196 goto out;
6197 }
6198
6199 for (p = e; p < len + e ; p += sep_pos + 1)
6200 {
6201 size_t param_pos, param_len, rel_len = len - (p - e);
6202 int quoted;
6203
6204 zbx_function_param_parse(p, ¶m_pos, ¶m_len, &sep_pos);
6205
6206 /* copy what was before the parameter */
6207 zbx_strncpy_alloc(exp, exp_alloc, exp_offset, p, param_pos);
6208
6209 /* prepare the parameter (macro substitutions and quoting) */
6210
6211 zbx_free(param);
6212 param = zbx_function_param_unquote_dyn(p + param_pos, param_len, "ed);
6213
6214 if (1 == key_in_param && p == e)
6215 {
6216 char *key = NULL, *host = NULL;
6217
6218 if (SUCCEED != parse_host_key(param, &host, &key) ||
6219 SUCCEED != substitute_key_macros_impl(&key, NULL, NULL, jp_row, lld_macro_paths,
6220 MACRO_TYPE_ITEM_KEY, NULL, 0))
6221 {
6222 zbx_snprintf(error, max_error_len, "Invalid first parameter \"%s\"", param);
6223 zbx_free(host);
6224 zbx_free(key);
6225 ret = FAIL;
6226 goto out;
6227 }
6228
6229 zbx_free(param);
6230 if (NULL != host)
6231 {
6232 param = zbx_dsprintf(NULL, "%s:%s", host, key);
6233 zbx_free(host);
6234 zbx_free(key);
6235 }
6236 else
6237 param = key;
6238 }
6239 else
6240 substitute_lld_macros(¶m, jp_row, lld_macro_paths, ZBX_MACRO_ANY, NULL, 0);
6241
6242 if (SUCCEED != zbx_function_param_quote(¶m, quoted))
6243 {
6244 zbx_snprintf(error, max_error_len, "Cannot quote parameter \"%s\"", param);
6245 ret = FAIL;
6246 goto out;
6247 }
6248
6249 /* copy the parameter */
6250 zbx_strcpy_alloc(exp, exp_alloc, exp_offset, param);
6251
6252 /* copy what was after the parameter (including separator) */
6253 if (sep_pos < rel_len)
6254 zbx_strncpy_alloc(exp, exp_alloc, exp_offset, p + param_pos + param_len,
6255 sep_pos - param_pos - param_len + 1);
6256 }
6257 out:
6258 zbx_free(param);
6259
6260 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
6261
6262 return ret;
6263 }
6264
6265 /******************************************************************************
6266 * *
6267 * Function: substitute_macros_in_json_pairs *
6268 * *
6269 * Purpose: substitute LLD macros in JSON pairs *
6270 * *
6271 * Parameters: data - [IN/OUT] pointer to a buffer that JSON pair *
6272 * jp_row - [IN] discovery data for LLD macro substitution *
6273 * error - [OUT] reason for JSON pair parsing failure *
6274 * maxerrlen - [IN] the size of error buffer *
6275 * *
6276 * Return value: SUCCEED or FAIL if cannot parse JSON pair *
6277 * *
6278 ******************************************************************************/
substitute_macros_in_json_pairs(char ** data,const struct zbx_json_parse * jp_row,const zbx_vector_ptr_t * lld_macro_paths,char * error,int maxerrlen)6279 int substitute_macros_in_json_pairs(char **data, const struct zbx_json_parse *jp_row,
6280 const zbx_vector_ptr_t *lld_macro_paths, char *error, int maxerrlen)
6281 {
6282 struct zbx_json_parse jp_array, jp_object;
6283 struct zbx_json json;
6284 const char *member, *element = NULL;
6285 char name[MAX_STRING_LEN], value[MAX_STRING_LEN], *p_name = NULL, *p_value = NULL;
6286 int ret = SUCCEED;
6287
6288 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
6289
6290 if ('\0' == **data)
6291 goto exit;
6292
6293 if (SUCCEED != zbx_json_open(*data, &jp_array))
6294 {
6295 zbx_snprintf(error, maxerrlen, "cannot parse query fields: %s", zbx_json_strerror());
6296 ret = FAIL;
6297 goto exit;
6298 }
6299
6300 if (NULL == (element = zbx_json_next(&jp_array, element)))
6301 {
6302 zbx_strlcpy(error, "cannot parse query fields: array is empty", maxerrlen);
6303 ret = FAIL;
6304 goto exit;
6305 }
6306
6307 zbx_json_initarray(&json, ZBX_JSON_STAT_BUF_LEN);
6308
6309 do
6310 {
6311 if (SUCCEED != zbx_json_brackets_open(element, &jp_object) ||
6312 NULL == (member = zbx_json_pair_next(&jp_object, NULL, name, sizeof(name))) ||
6313 NULL == zbx_json_decodevalue(member, value, sizeof(value), NULL))
6314 {
6315 zbx_snprintf(error, maxerrlen, "cannot parse query fields: %s", zbx_json_strerror());
6316 ret = FAIL;
6317 goto clean;
6318 }
6319
6320 p_name = zbx_strdup(NULL, name);
6321 p_value = zbx_strdup(NULL, value);
6322
6323 substitute_lld_macros(&p_name, jp_row, lld_macro_paths, ZBX_MACRO_ANY, NULL, 0);
6324 substitute_lld_macros(&p_value, jp_row, lld_macro_paths, ZBX_MACRO_ANY, NULL, 0);
6325
6326 zbx_json_addobject(&json, NULL);
6327 zbx_json_addstring(&json, p_name, p_value, ZBX_JSON_TYPE_STRING);
6328 zbx_json_close(&json);
6329 zbx_free(p_name);
6330 zbx_free(p_value);
6331 }
6332 while (NULL != (element = zbx_json_next(&jp_array, element)));
6333
6334 zbx_free(*data);
6335 *data = zbx_strdup(NULL, json.buffer);
6336 clean:
6337 zbx_json_free(&json);
6338 exit:
6339 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
6340
6341 return ret;
6342 }
6343
6344 #ifdef HAVE_LIBXML2
6345 /******************************************************************************
6346 * *
6347 * Function: substitute_macros_in_xml_elements *
6348 * *
6349 * Comments: auxiliary function for substitute_macros_xml() *
6350 * *
6351 ******************************************************************************/
substitute_macros_in_xml_elements(const DC_ITEM * item,const struct zbx_json_parse * jp_row,const zbx_vector_ptr_t * lld_macro_paths,xmlNode * node)6352 static void substitute_macros_in_xml_elements(const DC_ITEM *item, const struct zbx_json_parse *jp_row,
6353 const zbx_vector_ptr_t *lld_macro_paths, xmlNode *node)
6354 {
6355 xmlChar *value;
6356 xmlAttr *attr;
6357 char *value_tmp;
6358
6359 for (;NULL != node; node = node->next)
6360 {
6361 switch (node->type)
6362 {
6363 case XML_TEXT_NODE:
6364 if (NULL == (value = xmlNodeGetContent(node)))
6365 break;
6366
6367 value_tmp = zbx_strdup(NULL, (const char *)value);
6368
6369 if (NULL != item)
6370 {
6371 substitute_simple_macros_impl(NULL, NULL, NULL, NULL, NULL, &item->host, item, NULL,
6372 NULL, NULL, &value_tmp, MACRO_TYPE_HTTP_XML, NULL, 0);
6373 }
6374 else
6375 {
6376 substitute_lld_macros(&value_tmp, jp_row, lld_macro_paths, ZBX_MACRO_ANY, NULL,
6377 0);
6378 }
6379
6380 xmlNodeSetContent(node, NULL);
6381 xmlNodeAddContent(node, (xmlChar *)value_tmp);
6382
6383 zbx_free(value_tmp);
6384 xmlFree(value);
6385 break;
6386 case XML_CDATA_SECTION_NODE:
6387 if (NULL == (value = xmlNodeGetContent(node)))
6388 break;
6389
6390 value_tmp = zbx_strdup(NULL, (const char *)value);
6391
6392 if (NULL != item)
6393 {
6394 substitute_simple_macros_impl(NULL, NULL, NULL, NULL, NULL, &item->host, item, NULL,
6395 NULL, NULL, &value_tmp, MACRO_TYPE_HTTP_RAW, NULL, 0);
6396 }
6397 else
6398 {
6399 substitute_lld_macros(&value_tmp, jp_row, lld_macro_paths, ZBX_MACRO_ANY, NULL,
6400 0);
6401 }
6402
6403 xmlNodeSetContent(node, NULL);
6404 xmlNodeAddContent(node, (xmlChar *)value_tmp);
6405
6406 zbx_free(value_tmp);
6407 xmlFree(value);
6408 break;
6409 case XML_ELEMENT_NODE:
6410 for (attr = node->properties; NULL != attr; attr = attr->next)
6411 {
6412 if (NULL == attr->name || NULL == (value = xmlGetProp(node, attr->name)))
6413 continue;
6414
6415 value_tmp = zbx_strdup(NULL, (const char *)value);
6416
6417 if (NULL != item)
6418 {
6419 substitute_simple_macros_impl(NULL, NULL, NULL, NULL, NULL, &item->host,
6420 item, NULL, NULL, NULL, &value_tmp, MACRO_TYPE_HTTP_XML,
6421 NULL, 0);
6422 }
6423 else
6424 {
6425 substitute_lld_macros(&value_tmp, jp_row, lld_macro_paths,
6426 ZBX_MACRO_ANY, NULL, 0);
6427 }
6428
6429 xmlSetProp(node, attr->name, (xmlChar *)value_tmp);
6430
6431 zbx_free(value_tmp);
6432 xmlFree(value);
6433 }
6434 break;
6435 default:
6436 break;
6437 }
6438
6439 substitute_macros_in_xml_elements(item, jp_row, lld_macro_paths, node->children);
6440 }
6441 }
6442 #endif
6443
6444 /******************************************************************************
6445 * *
6446 * Function: substitute_macros_xml_impl *
6447 * *
6448 * Purpose: substitute simple or LLD macros in XML text nodes, attributes of *
6449 * a node or in CDATA section, validate XML *
6450 * *
6451 * Parameters: data - [IN/OUT] pointer to a buffer that contains XML *
6452 * item - [IN] item for simple macro substitution *
6453 * jp_row - [IN] discovery data for LLD macro substitution *
6454 * error - [OUT] reason for XML parsing failure *
6455 * maxerrlen - [IN] the size of error buffer *
6456 * *
6457 * Return value: SUCCEED or FAIL if XML validation has failed *
6458 * *
6459 ******************************************************************************/
substitute_macros_xml_impl(char ** data,const DC_ITEM * item,const struct zbx_json_parse * jp_row,const zbx_vector_ptr_t * lld_macro_paths,char * error,int maxerrlen)6460 static int substitute_macros_xml_impl(char **data, const DC_ITEM *item, const struct zbx_json_parse *jp_row,
6461 const zbx_vector_ptr_t *lld_macro_paths, char *error, int maxerrlen)
6462 {
6463 #ifndef HAVE_LIBXML2
6464 ZBX_UNUSED(data);
6465 ZBX_UNUSED(item);
6466 ZBX_UNUSED(jp_row);
6467 ZBX_UNUSED(lld_macro_paths);
6468 zbx_snprintf(error, maxerrlen, "Support for XML was not compiled in");
6469 return FAIL;
6470 #else
6471 xmlDoc *doc;
6472 xmlNode *root_element;
6473 xmlChar *mem;
6474 int size, ret = FAIL;
6475
6476 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
6477
6478 if (FAIL == zbx_open_xml(*data, 0, maxerrlen, (void **)&doc, (void **)&root_element, &error))
6479 {
6480 if (NULL == doc)
6481 goto exit;
6482
6483 if (NULL == root_element)
6484 goto clean;
6485 }
6486
6487 substitute_macros_in_xml_elements(item, jp_row, lld_macro_paths, root_element);
6488 xmlDocDumpMemory(doc, &mem, &size);
6489
6490 if (FAIL == zbx_check_xml_memory((char *)mem, maxerrlen, &error))
6491 goto clean;
6492
6493 zbx_free(*data);
6494 *data = zbx_malloc(NULL, size + 1);
6495 memcpy(*data, (const char *)mem, size + 1);
6496 xmlFree(mem);
6497 ret = SUCCEED;
6498 clean:
6499 xmlFreeDoc(doc);
6500 exit:
6501 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
6502
6503 return ret;
6504 #endif
6505 }
6506
6507 #ifdef HAVE_LIBXML2
6508 /******************************************************************************
6509 * *
6510 * Function: libxml_handle_error *
6511 * *
6512 * Purpose: libxml2 callback function for error handle *
6513 * *
6514 * Parameters: user_data - [IN/OUT] the user context *
6515 * err - [IN] the libxml2 error message *
6516 * *
6517 ******************************************************************************/
libxml_handle_error(void * user_data,xmlErrorPtr err)6518 static void libxml_handle_error(void *user_data, xmlErrorPtr err)
6519 {
6520 zbx_libxml_error_t *err_ctx;
6521
6522 if (NULL == user_data)
6523 return;
6524
6525 err_ctx = (zbx_libxml_error_t *)user_data;
6526 zbx_strlcat(err_ctx->buf, err->message, err_ctx->len);
6527
6528 if (NULL != err->str1)
6529 zbx_strlcat(err_ctx->buf, err->str1, err_ctx->len);
6530
6531 if (NULL != err->str2)
6532 zbx_strlcat(err_ctx->buf, err->str2, err_ctx->len);
6533
6534 if (NULL != err->str3)
6535 zbx_strlcat(err_ctx->buf, err->str3, err_ctx->len);
6536 }
6537 #endif
6538
6539 /******************************************************************************
6540 * *
6541 * Function: xml_xpath_check *
6542 * *
6543 * Purpose: validate xpath string *
6544 * *
6545 * Parameters: xpath - [IN] the xpath value *
6546 * error - [OUT] the error message buffer *
6547 * errlen - [IN] the size of error message buffer *
6548 * *
6549 * Return value: SUCCEED - the xpath component was parsed successfully *
6550 * FAIL - xpath parsing error *
6551 * *
6552 ******************************************************************************/
xml_xpath_check(const char * xpath,char * error,size_t errlen)6553 int xml_xpath_check(const char *xpath, char *error, size_t errlen)
6554 {
6555 #ifndef HAVE_LIBXML2
6556 ZBX_UNUSED(xpath);
6557 ZBX_UNUSED(error);
6558 ZBX_UNUSED(errlen);
6559 return FAIL;
6560 #else
6561 zbx_libxml_error_t err;
6562 xmlXPathContextPtr ctx;
6563 xmlXPathCompExprPtr p;
6564
6565 err.buf = error;
6566 err.len = errlen;
6567
6568 ctx = xmlXPathNewContext(NULL);
6569 xmlSetStructuredErrorFunc(&err, &libxml_handle_error);
6570
6571 p = xmlXPathCtxtCompile(ctx, (xmlChar *)xpath);
6572 xmlSetStructuredErrorFunc(NULL, NULL);
6573
6574 if (NULL == p)
6575 {
6576 xmlXPathFreeContext(ctx);
6577 return FAIL;
6578 }
6579
6580 xmlXPathFreeCompExpr(p);
6581 xmlXPathFreeContext(ctx);
6582 return SUCCEED;
6583 #endif
6584 }
6585
6586 /******************************************************************************
6587 * *
6588 * Function: substitute_simple_macros *
6589 * *
6590 * Purpose: substitute_simple_macros with masked secret macros *
6591 * (default setting) *
6592 * *
6593 ******************************************************************************/
substitute_simple_macros(const zbx_uint64_t * actionid,const DB_EVENT * event,const DB_EVENT * r_event,const zbx_uint64_t * userid,const zbx_uint64_t * hostid,const DC_HOST * dc_host,const DC_ITEM * dc_item,const DB_ALERT * alert,const DB_ACKNOWLEDGE * ack,const char * tz,char ** data,int macro_type,char * error,int maxerrlen)6594 int substitute_simple_macros(const zbx_uint64_t *actionid, const DB_EVENT *event, const DB_EVENT *r_event,
6595 const zbx_uint64_t *userid, const zbx_uint64_t *hostid, const DC_HOST *dc_host, const DC_ITEM *dc_item,
6596 const DB_ALERT *alert, const DB_ACKNOWLEDGE *ack, const char *tz, char **data, int macro_type,
6597 char *error, int maxerrlen)
6598 {
6599 return substitute_simple_macros_impl(actionid, event, r_event, userid, hostid, dc_host, dc_item, alert, ack,
6600 tz, data, macro_type, error, maxerrlen);
6601
6602 }
6603
6604 /******************************************************************************
6605 * *
6606 * Function: substitute_simple_macros_unmasked *
6607 * *
6608 * Purpose: substitute_simple_macros with unmasked secret macros *
6609 * *
6610 ******************************************************************************/
substitute_simple_macros_unmasked(const zbx_uint64_t * actionid,const DB_EVENT * event,const DB_EVENT * r_event,const zbx_uint64_t * userid,const zbx_uint64_t * hostid,const DC_HOST * dc_host,const DC_ITEM * dc_item,const DB_ALERT * alert,const DB_ACKNOWLEDGE * ack,const char * tz,char ** data,int macro_type,char * error,int maxerrlen)6611 int substitute_simple_macros_unmasked(const zbx_uint64_t *actionid, const DB_EVENT *event, const DB_EVENT *r_event,
6612 const zbx_uint64_t *userid, const zbx_uint64_t *hostid, const DC_HOST *dc_host, const DC_ITEM *dc_item,
6613 const DB_ALERT *alert, const DB_ACKNOWLEDGE *ack, const char *tz, char **data, int macro_type,
6614 char *error, int maxerrlen)
6615 {
6616 unsigned char old_macro_env;
6617 int ret;
6618
6619 old_macro_env = zbx_dc_set_macro_env(ZBX_MACRO_ENV_SECURE);
6620 ret = substitute_simple_macros_impl(actionid, event, r_event, userid, hostid, dc_host, dc_item, alert, ack,
6621 tz, data, macro_type, error, maxerrlen);
6622 zbx_dc_set_macro_env(old_macro_env);
6623 return ret;
6624
6625 }
6626
6627 /******************************************************************************
6628 * *
6629 * Function: substitute_macros_xml *
6630 * *
6631 * substitute_macros_xml with masked secret macros *
6632 * *
6633 ******************************************************************************/
substitute_macros_xml(char ** data,const DC_ITEM * item,const struct zbx_json_parse * jp_row,const zbx_vector_ptr_t * lld_macro_paths,char * error,int maxerrlen)6634 int substitute_macros_xml(char **data, const DC_ITEM *item, const struct zbx_json_parse *jp_row,
6635 const zbx_vector_ptr_t *lld_macro_paths, char *error, int maxerrlen)
6636 {
6637 return substitute_macros_xml_impl(data, item, jp_row, lld_macro_paths, error, maxerrlen);
6638 }
6639
6640 /******************************************************************************
6641 * *
6642 * Function: substitute_macros_xml_unmasked *
6643 * *
6644 * substitute_macros_xml with unmasked secret macros *
6645 * *
6646 ******************************************************************************/
substitute_macros_xml_unmasked(char ** data,const DC_ITEM * item,const struct zbx_json_parse * jp_row,const zbx_vector_ptr_t * lld_macro_paths,char * error,int maxerrlen)6647 int substitute_macros_xml_unmasked(char **data, const DC_ITEM *item, const struct zbx_json_parse *jp_row,
6648 const zbx_vector_ptr_t *lld_macro_paths, char *error, int maxerrlen)
6649 {
6650 unsigned char old_macro_env;
6651 int ret;
6652
6653 old_macro_env = zbx_dc_set_macro_env(ZBX_MACRO_ENV_SECURE);
6654 ret = substitute_macros_xml_impl(data, item, jp_row, lld_macro_paths, error, maxerrlen);
6655 zbx_dc_set_macro_env(old_macro_env);
6656 return ret;
6657 }
6658
6659 /******************************************************************************
6660 * *
6661 * Function: substitute_key_macros *
6662 * *
6663 * substitute_key_macros with masked secret macros *
6664 * *
6665 ******************************************************************************/
substitute_key_macros(char ** data,zbx_uint64_t * hostid,DC_ITEM * dc_item,const struct zbx_json_parse * jp_row,const zbx_vector_ptr_t * lld_macro_paths,int macro_type,char * error,size_t maxerrlen)6666 int substitute_key_macros(char **data, zbx_uint64_t *hostid, DC_ITEM *dc_item, const struct zbx_json_parse *jp_row,
6667 const zbx_vector_ptr_t *lld_macro_paths, int macro_type, char *error, size_t maxerrlen)
6668 {
6669 return substitute_key_macros_impl(data, hostid, dc_item, jp_row, lld_macro_paths, macro_type, error, maxerrlen);
6670 }
6671
6672 /******************************************************************************
6673 * *
6674 * Function: substitute_key_macros_unmasked *
6675 * *
6676 * substitute_key_macros with unmasked secret macros *
6677 * *
6678 ******************************************************************************/
substitute_key_macros_unmasked(char ** data,zbx_uint64_t * hostid,DC_ITEM * dc_item,const struct zbx_json_parse * jp_row,const zbx_vector_ptr_t * lld_macro_paths,int macro_type,char * error,size_t maxerrlen)6679 int substitute_key_macros_unmasked(char **data, zbx_uint64_t *hostid, DC_ITEM *dc_item,
6680 const struct zbx_json_parse *jp_row, const zbx_vector_ptr_t *lld_macro_paths, int macro_type,
6681 char *error, size_t maxerrlen)
6682 {
6683 unsigned char old_macro_env;
6684 int ret;
6685
6686 old_macro_env = zbx_dc_set_macro_env(ZBX_MACRO_ENV_SECURE);
6687 ret = substitute_key_macros_impl(data, hostid, dc_item, jp_row, lld_macro_paths, macro_type, error, maxerrlen);
6688 zbx_dc_set_macro_env(old_macro_env);
6689 return ret;
6690 }
6691
6692 /******************************************************************************
6693 * *
6694 * Function: zbx_host_macro_index *
6695 * *
6696 * Purpose: extract index from valid indexed host macro *
6697 * *
6698 * Return value: The index or -1 if it was not valid indexed host macro *
6699 * *
6700 ******************************************************************************/
zbx_host_macro_index(const char * macro)6701 int zbx_host_macro_index(const char *macro)
6702 {
6703 zbx_strloc_t loc;
6704 int func_num;
6705
6706 loc.l = 0;
6707 loc.r = strlen(macro) - 1;
6708
6709 if (NULL != macro_in_list(macro, loc, simple_host_macros, &func_num))
6710 return func_num;
6711
6712 return -1;
6713 }
6714