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, &macro_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, &param_pos, &param_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, &quoted);
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(&param, jp_row, lld_macro_paths, ZBX_MACRO_ANY, NULL, 0);
6241 
6242 		if (SUCCEED != zbx_function_param_quote(&param, 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