1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 **/
19 
20 #include "common.h"
21 #include "db.h"
22 #include "dbcache.h"
23 #include "log.h"
24 #include "zbxserver.h"
25 #include "zbxregexp.h"
26 
27 #include "active.h"
28 #include "../../libs/zbxcrypto/tls_tcp_active.h"
29 
30 extern unsigned char	program_type;
31 
32 /******************************************************************************
33  *                                                                            *
34  * Function: get_hostid_by_host                                               *
35  *                                                                            *
36  * Purpose: check for host name and return hostid                             *
37  *                                                                            *
38  * Parameters: host - [IN] require size 'HOST_HOST_LEN_MAX'                   *
39  *                                                                            *
40  * Return value:  SUCCEED - host is found                                     *
41  *                FAIL - an error occurred or host not found                  *
42  *                                                                            *
43  * Author: Alexander Vladishev                                                *
44  *                                                                            *
45  * Comments: NB! adds host to the database if it does not exist               *
46  *                                                                            *
47  ******************************************************************************/
get_hostid_by_host(const zbx_socket_t * sock,const char * host,const char * ip,unsigned short port,const char * host_metadata,zbx_uint64_t * hostid,char * error)48 static int	get_hostid_by_host(const zbx_socket_t *sock, const char *host, const char *ip, unsigned short port,
49 		const char *host_metadata, zbx_uint64_t *hostid, char *error)
50 {
51 	const char	*__function_name = "get_hostid_by_host";
52 
53 	char		*host_esc, dns[INTERFACE_DNS_LEN_MAX], *ch_error;
54 	DB_RESULT	result;
55 	DB_ROW		row;
56 	int		ret = FAIL;
57 
58 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() host:'%s'", __function_name, host);
59 
60 	if (FAIL == zbx_check_hostname(host, &ch_error))
61 	{
62 		zbx_snprintf(error, MAX_STRING_LEN, "invalid host name [%s]: %s", host, ch_error);
63 		zbx_free(ch_error);
64 		goto out;
65 	}
66 
67 	host_esc = DBdyn_escape_string(host);
68 
69 	result =
70 #if defined(HAVE_POLARSSL) || defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
71 		DBselect(
72 			"select hostid,status,tls_accept,tls_issuer,tls_subject,tls_psk_identity"
73 			" from hosts"
74 			" where host='%s'"
75 				" and status in (%d,%d)"
76 				" and flags<>%d"
77 				" and proxy_hostid is null",
78 			host_esc, HOST_STATUS_MONITORED, HOST_STATUS_NOT_MONITORED, ZBX_FLAG_DISCOVERY_PROTOTYPE);
79 #else
80 		DBselect(
81 			"select hostid,status,tls_accept"
82 			" from hosts"
83 			" where host='%s'"
84 				" and status in (%d,%d)"
85 				" and flags<>%d"
86 				" and proxy_hostid is null",
87 			host_esc, HOST_STATUS_MONITORED, HOST_STATUS_NOT_MONITORED, ZBX_FLAG_DISCOVERY_PROTOTYPE);
88 #endif
89 	if (NULL != (row = DBfetch(result)))
90 	{
91 		if (HOST_STATUS_MONITORED == atoi(row[1]))
92 		{
93 			unsigned int	tls_accept;
94 
95 			tls_accept = (unsigned int)atoi(row[2]);
96 
97 			if (0 == (tls_accept & sock->connection_type))
98 			{
99 				zbx_snprintf(error, MAX_STRING_LEN, "connection of type \"%s\" is not allowed for host"
100 						" \"%s\"", zbx_tcp_connection_type_name(sock->connection_type), host);
101 				goto done;
102 			}
103 
104 #if defined(HAVE_POLARSSL) || defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
105 			if (ZBX_TCP_SEC_TLS_CERT == sock->connection_type)
106 			{
107 				zbx_tls_conn_attr_t	attr;
108 
109 				if (SUCCEED != zbx_tls_get_attr_cert(sock, &attr))
110 				{
111 					THIS_SHOULD_NEVER_HAPPEN;
112 
113 					zbx_snprintf(error, MAX_STRING_LEN, "cannot get connection attributes for host"
114 							" \"%s\"", host);
115 					goto done;
116 				}
117 
118 				/* simplified match, not compliant with RFC 4517, 4518 */
119 				if ('\0' != *row[3] && 0 != strcmp(row[3], attr.issuer))
120 				{
121 					zbx_snprintf(error, MAX_STRING_LEN, "certificate issuer does not match for"
122 							" host \"%s\"", host);
123 					goto done;
124 				}
125 
126 				/* simplified match, not compliant with RFC 4517, 4518 */
127 				if ('\0' != *row[4] && 0 != strcmp(row[4], attr.subject))
128 				{
129 					zbx_snprintf(error, MAX_STRING_LEN, "certificate subject does not match for"
130 							" host \"%s\"", host);
131 					goto done;
132 				}
133 			}
134 #endif
135 #if defined(HAVE_POLARSSL) || defined(HAVE_GNUTLS) || (defined(HAVE_OPENSSL) && defined(HAVE_OPENSSL_WITH_PSK))
136 			else if (ZBX_TCP_SEC_TLS_PSK == sock->connection_type)
137 			{
138 				zbx_tls_conn_attr_t	attr;
139 
140 				if (SUCCEED != zbx_tls_get_attr_psk(sock, &attr))
141 				{
142 					THIS_SHOULD_NEVER_HAPPEN;
143 
144 					zbx_snprintf(error, MAX_STRING_LEN, "cannot get connection attributes for host"
145 							" \"%s\"", host);
146 					goto done;
147 				}
148 
149 				if (strlen(row[5]) != attr.psk_identity_len ||
150 						0 != memcmp(row[5], attr.psk_identity, attr.psk_identity_len))
151 				{
152 					zbx_snprintf(error, MAX_STRING_LEN, "false PSK identity for host \"%s\"", host);
153 					goto done;
154 				}
155 			}
156 #endif
157 			ZBX_STR2UINT64(*hostid, row[0]);
158 
159 			ret = SUCCEED;
160 		}
161 		else
162 			zbx_snprintf(error, MAX_STRING_LEN, "host [%s] not monitored", host);
163 	}
164 	else
165 	{
166 		zbx_snprintf(error, MAX_STRING_LEN, "host [%s] not found", host);
167 
168 		/* remove ::ffff: prefix from IPv4-mapped IPv6 addresses */
169 		if (0 == strncmp("::ffff:", ip, 7) && SUCCEED == is_ip4(ip + 7))
170 			ip += 7;
171 
172 		zbx_alarm_on(CONFIG_TIMEOUT);
173 		zbx_gethost_by_ip(ip, dns, sizeof(dns));
174 		zbx_alarm_off();
175 
176 		DBbegin();
177 
178 		if (0 != (program_type & ZBX_PROGRAM_TYPE_SERVER))
179 			DBregister_host(0, host, ip, dns, port, host_metadata, (int)time(NULL));
180 		else if (0 != (program_type & ZBX_PROGRAM_TYPE_PROXY))
181 			DBproxy_register_host(host, ip, dns, port, host_metadata);
182 
183 		DBcommit();
184 	}
185 done:
186 	DBfree_result(result);
187 
188 	zbx_free(host_esc);
189 out:
190 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
191 
192 	return ret;
193 }
194 
get_list_of_active_checks(zbx_uint64_t hostid,zbx_vector_uint64_t * itemids)195 static void	get_list_of_active_checks(zbx_uint64_t hostid, zbx_vector_uint64_t *itemids)
196 {
197 	DB_RESULT	result;
198 	DB_ROW		row;
199 	zbx_uint64_t	itemid;
200 
201 	result = DBselect(
202 			"select itemid"
203 			" from items"
204 			" where type=%d"
205 				" and flags<>%d"
206 				" and hostid=" ZBX_FS_UI64,
207 			ITEM_TYPE_ZABBIX_ACTIVE, ZBX_FLAG_DISCOVERY_PROTOTYPE, hostid);
208 
209 	while (NULL != (row = DBfetch(result)))
210 	{
211 		ZBX_STR2UINT64(itemid, row[0]);
212 		zbx_vector_uint64_append(itemids, itemid);
213 	}
214 	DBfree_result(result);
215 }
216 
217 /******************************************************************************
218  *                                                                            *
219  * Function: send_list_of_active_checks                                       *
220  *                                                                            *
221  * Purpose: send list of active checks to the host (older version agent)      *
222  *                                                                            *
223  * Parameters: sock - open socket of server-agent connection                  *
224  *             request - request buffer                                       *
225  *                                                                            *
226  * Return value:  SUCCEED - list of active checks sent successfully           *
227  *                FAIL - an error occurred                                    *
228  *                                                                            *
229  * Comments: format of the request: ZBX_GET_ACTIVE_CHECKS\n<host name>\n      *
230  *           format of the list: key:delay:last_log_size                      *
231  *                                                                            *
232  ******************************************************************************/
send_list_of_active_checks(zbx_socket_t * sock,char * request)233 int	send_list_of_active_checks(zbx_socket_t *sock, char *request)
234 {
235 	const char		*__function_name = "send_list_of_active_checks";
236 
237 	char			*host = NULL, *p, *buffer = NULL, error[MAX_STRING_LEN];
238 	size_t			buffer_alloc = 8 * ZBX_KIBIBYTE, buffer_offset = 0;
239 	int			ret = FAIL, i;
240 	zbx_uint64_t		hostid;
241 	zbx_vector_uint64_t	itemids;
242 
243 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
244 
245 	if (NULL != (host = strchr(request, '\n')))
246 	{
247 		host++;
248 		if (NULL != (p = strchr(host, '\n')))
249 			*p = '\0';
250 	}
251 	else
252 	{
253 		zbx_snprintf(error, sizeof(error), "host is null");
254 		goto out;
255 	}
256 
257 	/* no host metadata in older versions of agent */
258 	if (FAIL == get_hostid_by_host(sock, host, sock->peer, ZBX_DEFAULT_AGENT_PORT, "", &hostid, error))
259 		goto out;
260 
261 	zbx_vector_uint64_create(&itemids);
262 
263 	get_list_of_active_checks(hostid, &itemids);
264 
265 	buffer = zbx_malloc(buffer, buffer_alloc);
266 
267 	if (0 != itemids.values_num)
268 	{
269 		DC_ITEM		*dc_items;
270 		int		*errcodes, now;
271 		zbx_config_t	cfg;
272 
273 		dc_items = zbx_malloc(NULL, sizeof(DC_ITEM) * itemids.values_num);
274 		errcodes = zbx_malloc(NULL, sizeof(int) * itemids.values_num);
275 
276 		DCconfig_get_items_by_itemids(dc_items, itemids.values, errcodes, itemids.values_num);
277 		zbx_config_get(&cfg, ZBX_CONFIG_FLAGS_REFRESH_UNSUPPORTED);
278 
279 		now = time(NULL);
280 
281 		for (i = 0; i < itemids.values_num; i++)
282 		{
283 			if (SUCCEED != errcodes[i])
284 			{
285 				zabbix_log(LOG_LEVEL_DEBUG, "%s() Item [" ZBX_FS_UI64 "] was not found in the"
286 						" server cache. Not sending now.", __function_name, itemids.values[i]);
287 				continue;
288 			}
289 
290 			if (ITEM_STATUS_ACTIVE != dc_items[i].status)
291 				continue;
292 
293 			if (HOST_STATUS_MONITORED != dc_items[i].host.status)
294 				continue;
295 
296 			if (ITEM_STATE_NOTSUPPORTED == dc_items[i].state)
297 			{
298 				if (0 == cfg.refresh_unsupported)
299 					continue;
300 
301 				if (dc_items[i].lastclock + cfg.refresh_unsupported > now)
302 					continue;
303 			}
304 
305 			zbx_snprintf_alloc(&buffer, &buffer_alloc, &buffer_offset, "%s:%d:" ZBX_FS_UI64 "\n",
306 					dc_items[i].key_orig, dc_items[i].delay, dc_items[i].lastlogsize);
307 		}
308 
309 		zbx_config_clean(&cfg);
310 
311 		DCconfig_clean_items(dc_items, errcodes, itemids.values_num);
312 
313 		zbx_free(errcodes);
314 		zbx_free(dc_items);
315 	}
316 
317 	zbx_vector_uint64_destroy(&itemids);
318 
319 	zbx_strcpy_alloc(&buffer, &buffer_alloc, &buffer_offset, "ZBX_EOF\n");
320 
321 	zabbix_log(LOG_LEVEL_DEBUG, "%s() sending [%s]", __function_name, buffer);
322 
323 	zbx_alarm_on(CONFIG_TIMEOUT);
324 	if (SUCCEED != zbx_tcp_send_raw(sock, buffer))
325 		zbx_strlcpy(error, zbx_socket_strerror(), MAX_STRING_LEN);
326 	else
327 		ret = SUCCEED;
328 	zbx_alarm_off();
329 
330 	zbx_free(buffer);
331 out:
332 	if (FAIL == ret)
333 		zabbix_log(LOG_LEVEL_WARNING, "cannot send list of active checks to \"%s\": %s", sock->peer, error);
334 
335 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
336 
337 	return ret;
338 }
339 
340 /******************************************************************************
341  *                                                                            *
342  * Function: zbx_vector_str_append_uniq                                       *
343  *                                                                            *
344  * Purpose: append non duplicate string to the string vector                  *
345  *                                                                            *
346  * Parameters: vector - [IN/OUT] the string vector                            *
347  *             str    - [IN] the string to append                             *
348  *                                                                            *
349  ******************************************************************************/
zbx_vector_str_append_uniq(zbx_vector_str_t * vector,const char * str)350 static void	zbx_vector_str_append_uniq(zbx_vector_str_t *vector, const char *str)
351 {
352 	if (FAIL == zbx_vector_str_search(vector, str, ZBX_DEFAULT_STR_COMPARE_FUNC))
353 		zbx_vector_str_append(vector, zbx_strdup(NULL, str));
354 }
355 
356 /******************************************************************************
357  *                                                                            *
358  * Function: zbx_itemkey_extract_global_regexps                               *
359  *                                                                            *
360  * Purpose: extract global regular expression names from item key             *
361  *                                                                            *
362  * Parameters: key     - [IN] the item key to parse                           *
363  *             regexps - [OUT] the extracted regular expression names         *
364  *                                                                            *
365  ******************************************************************************/
zbx_itemkey_extract_global_regexps(const char * key,zbx_vector_str_t * regexps)366 static void	zbx_itemkey_extract_global_regexps(const char *key, zbx_vector_str_t *regexps)
367 {
368 #define ZBX_KEY_LOG		1
369 #define ZBX_KEY_EVENTLOG	2
370 
371 	AGENT_REQUEST	request;
372 	int		item_key;
373 	const char	*param;
374 
375 	if (0 == strncmp(key, "log[", 4) || 0 == strncmp(key, "logrt[", 6))
376 		item_key = ZBX_KEY_LOG;
377 	else if (0 == strncmp(key, "eventlog[", 9))
378 		item_key = ZBX_KEY_EVENTLOG;
379 	else
380 		return;
381 
382 	init_request(&request);
383 
384 	if(SUCCEED != parse_item_key(key, &request))
385 		goto out;
386 
387 	/* "params" parameter */
388 	if (NULL != (param = get_rparam(&request, 1)) && '@' == *param)
389 		zbx_vector_str_append_uniq(regexps, param + 1);
390 
391 	if (ZBX_KEY_EVENTLOG == item_key)
392 	{
393 		/* "severity" parameter */
394 		if (NULL != (param = get_rparam(&request, 2)) && '@' == *param)
395 			zbx_vector_str_append_uniq(regexps, param + 1);
396 
397 		/* "source" parameter */
398 		if (NULL != (param = get_rparam(&request, 3)) && '@' == *param)
399 			zbx_vector_str_append_uniq(regexps, param + 1);
400 
401 		/* "logeventid" parameter */
402 		if (NULL != (param = get_rparam(&request, 4)) && '@' == *param)
403 			zbx_vector_str_append_uniq(regexps, param + 1);
404 	}
405 out:
406 	free_request(&request);
407 }
408 
409 /******************************************************************************
410  *                                                                            *
411  * Function: send_list_of_active_checks_json                                  *
412  *                                                                            *
413  * Purpose: send list of active checks to the host                            *
414  *                                                                            *
415  * Parameters: sock - open socket of server-agent connection                  *
416  *             json - request buffer                                          *
417  *                                                                            *
418  * Return value:  SUCCEED - list of active checks sent successfully           *
419  *                FAIL - an error occurred                                    *
420  *                                                                            *
421  * Author: Alexander Vladishev                                                *
422  *                                                                            *
423  * Comments:                                                                  *
424  *                                                                            *
425  ******************************************************************************/
send_list_of_active_checks_json(zbx_socket_t * sock,struct zbx_json_parse * jp)426 int	send_list_of_active_checks_json(zbx_socket_t *sock, struct zbx_json_parse *jp)
427 {
428 	const char		*__function_name = "send_list_of_active_checks_json";
429 
430 	char			host[HOST_HOST_LEN_MAX], tmp[MAX_STRING_LEN], ip[INTERFACE_IP_LEN_MAX],
431 				error[MAX_STRING_LEN], *host_metadata = NULL;
432 	struct zbx_json		json;
433 	int			ret = FAIL, i;
434 	zbx_uint64_t		hostid;
435 	size_t			host_metadata_alloc = 1;	/* for at least NUL-termination char */
436 	unsigned short		port;
437 	zbx_vector_uint64_t	itemids;
438 
439 	zbx_vector_ptr_t	regexps;
440 	zbx_vector_str_t	names;
441 
442 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
443 
444 	zbx_vector_ptr_create(&regexps);
445 	zbx_vector_str_create(&names);
446 
447 	if (FAIL == zbx_json_value_by_name(jp, ZBX_PROTO_TAG_HOST, host, sizeof(host)))
448 	{
449 		zbx_snprintf(error, MAX_STRING_LEN, "%s", zbx_json_strerror());
450 		goto error;
451 	}
452 
453 	host_metadata = zbx_malloc(host_metadata, host_metadata_alloc);
454 
455 	if (FAIL == zbx_json_value_by_name_dyn(jp, ZBX_PROTO_TAG_HOST_METADATA,
456 			&host_metadata, &host_metadata_alloc))
457 	{
458 		*host_metadata = '\0';
459 	}
460 
461 	if (FAIL == zbx_json_value_by_name(jp, ZBX_PROTO_TAG_IP, ip, sizeof(ip)))
462 		strscpy(ip, sock->peer);
463 
464 	if (FAIL == is_ip(ip))	/* check even if 'ip' came from get_ip_by_socket() - it can return not a valid IP */
465 	{
466 		zbx_snprintf(error, MAX_STRING_LEN, "\"%s\" is not a valid IP address", ip);
467 		goto error;
468 	}
469 
470 	if (FAIL == zbx_json_value_by_name(jp, ZBX_PROTO_TAG_PORT, tmp, sizeof(tmp)))
471 	{
472 		port = ZBX_DEFAULT_AGENT_PORT;
473 	}
474 	else if (FAIL == is_ushort(tmp, &port))
475 	{
476 		zbx_snprintf(error, MAX_STRING_LEN, "\"%s\" is not a valid port", tmp);
477 		goto error;
478 	}
479 
480 	if (FAIL == get_hostid_by_host(sock, host, ip, port, host_metadata, &hostid, error))
481 		goto error;
482 
483 	zbx_vector_uint64_create(&itemids);
484 
485 	get_list_of_active_checks(hostid, &itemids);
486 
487 	zbx_json_init(&json, ZBX_JSON_STAT_BUF_LEN);
488 	zbx_json_addstring(&json, ZBX_PROTO_TAG_RESPONSE, ZBX_PROTO_VALUE_SUCCESS, ZBX_JSON_TYPE_STRING);
489 	zbx_json_addarray(&json, ZBX_PROTO_TAG_DATA);
490 
491 	if (0 != itemids.values_num)
492 	{
493 		DC_ITEM		*dc_items;
494 		int		*errcodes, now;
495 		zbx_config_t	cfg;
496 
497 		dc_items = zbx_malloc(NULL, sizeof(DC_ITEM) * itemids.values_num);
498 		errcodes = zbx_malloc(NULL, sizeof(int) * itemids.values_num);
499 
500 		DCconfig_get_items_by_itemids(dc_items, itemids.values, errcodes, itemids.values_num);
501 		zbx_config_get(&cfg, ZBX_CONFIG_FLAGS_REFRESH_UNSUPPORTED);
502 
503 		now = time(NULL);
504 
505 		for (i = 0; i < itemids.values_num; i++)
506 		{
507 			if (SUCCEED != errcodes[i])
508 			{
509 				zabbix_log(LOG_LEVEL_DEBUG, "%s() Item [" ZBX_FS_UI64 "] was not found in the"
510 						" server cache. Not sending now.", __function_name, itemids.values[i]);
511 				continue;
512 			}
513 
514 			if (ITEM_STATUS_ACTIVE != dc_items[i].status)
515 				continue;
516 
517 			if (HOST_STATUS_MONITORED != dc_items[i].host.status)
518 				continue;
519 
520 			if (ITEM_STATE_NOTSUPPORTED == dc_items[i].state)
521 			{
522 				if (0 == cfg.refresh_unsupported)
523 					continue;
524 
525 				if (dc_items[i].lastclock + cfg.refresh_unsupported > now)
526 					continue;
527 			}
528 
529 			dc_items[i].key = zbx_strdup(dc_items[i].key, dc_items[i].key_orig);
530 			substitute_key_macros(&dc_items[i].key, NULL, &dc_items[i], NULL, MACRO_TYPE_ITEM_KEY, NULL, 0);
531 
532 			zbx_json_addobject(&json, NULL);
533 			zbx_json_addstring(&json, ZBX_PROTO_TAG_KEY, dc_items[i].key, ZBX_JSON_TYPE_STRING);
534 			if (0 != strcmp(dc_items[i].key, dc_items[i].key_orig))
535 			{
536 				zbx_json_addstring(&json, ZBX_PROTO_TAG_KEY_ORIG,
537 						dc_items[i].key_orig, ZBX_JSON_TYPE_STRING);
538 			}
539 			zbx_json_adduint64(&json, ZBX_PROTO_TAG_DELAY, dc_items[i].delay);
540 			/* The agent expects ALWAYS to have lastlogsize and mtime tags. */
541 			/* Removing those would cause older agents to fail. */
542 			zbx_json_adduint64(&json, ZBX_PROTO_TAG_LASTLOGSIZE, dc_items[i].lastlogsize);
543 			zbx_json_adduint64(&json, ZBX_PROTO_TAG_MTIME, dc_items[i].mtime);
544 			zbx_json_close(&json);
545 
546 			zbx_itemkey_extract_global_regexps(dc_items[i].key, &names);
547 
548 			zbx_free(dc_items[i].key);
549 		}
550 
551 		zbx_config_clean(&cfg);
552 
553 		DCconfig_clean_items(dc_items, errcodes, itemids.values_num);
554 
555 		zbx_free(errcodes);
556 		zbx_free(dc_items);
557 	}
558 
559 	zbx_vector_uint64_destroy(&itemids);
560 
561 	zbx_json_close(&json);
562 
563 	DCget_expressions_by_names(&regexps, (const char * const *)names.values, names.values_num);
564 
565 	if (0 < regexps.values_num)
566 	{
567 		char	buffer[32];
568 
569 		zbx_json_addarray(&json, ZBX_PROTO_TAG_REGEXP);
570 
571 		for (i = 0; i < regexps.values_num; i++)
572 		{
573 			zbx_expression_t	*regexp = regexps.values[i];
574 
575 			zbx_json_addobject(&json, NULL);
576 			zbx_json_addstring(&json, "name", regexp->name, ZBX_JSON_TYPE_STRING);
577 			zbx_json_addstring(&json, "expression", regexp->expression, ZBX_JSON_TYPE_STRING);
578 
579 			zbx_snprintf(buffer, sizeof(buffer), "%d", regexp->expression_type);
580 			zbx_json_addstring(&json, "expression_type", buffer, ZBX_JSON_TYPE_INT);
581 
582 			zbx_snprintf(buffer, sizeof(buffer), "%c", regexp->exp_delimiter);
583 			zbx_json_addstring(&json, "exp_delimiter", buffer, ZBX_JSON_TYPE_STRING);
584 
585 			zbx_snprintf(buffer, sizeof(buffer), "%d", regexp->case_sensitive);
586 			zbx_json_addstring(&json, "case_sensitive", buffer, ZBX_JSON_TYPE_INT);
587 
588 			zbx_json_close(&json);
589 		}
590 
591 		zbx_json_close(&json);
592 	}
593 
594 	zabbix_log(LOG_LEVEL_DEBUG, "%s() sending [%s]", __function_name, json.buffer);
595 
596 	zbx_alarm_on(CONFIG_TIMEOUT);
597 	if (SUCCEED != zbx_tcp_send(sock, json.buffer))
598 		strscpy(error, zbx_socket_strerror());
599 	else
600 		ret = SUCCEED;
601 	zbx_alarm_off();
602 
603 	zbx_json_free(&json);
604 
605 	goto out;
606 error:
607 	zabbix_log(LOG_LEVEL_WARNING, "cannot send list of active checks to \"%s\": %s", sock->peer, error);
608 
609 	zbx_json_init(&json, ZBX_JSON_STAT_BUF_LEN);
610 	zbx_json_addstring(&json, ZBX_PROTO_TAG_RESPONSE, ZBX_PROTO_VALUE_FAILED, ZBX_JSON_TYPE_STRING);
611 	zbx_json_addstring(&json, ZBX_PROTO_TAG_INFO, error, ZBX_JSON_TYPE_STRING);
612 
613 	zabbix_log(LOG_LEVEL_DEBUG, "%s() sending [%s]", __function_name, json.buffer);
614 
615 	ret = zbx_tcp_send(sock, json.buffer);
616 
617 	zbx_json_free(&json);
618 out:
619 	for (i = 0; i < names.values_num; i++)
620 		zbx_free(names.values[i]);
621 
622 	zbx_vector_str_destroy(&names);
623 
624 	zbx_regexp_clean_expressions(&regexps);
625 	zbx_vector_ptr_destroy(&regexps);
626 
627 	zbx_free(host_metadata);
628 
629 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
630 
631 	return ret;
632 }
633