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 "lld.h"
21 #include "db.h"
22 #include "log.h"
23 #include "zbxalgo.h"
24 #include "zbxserver.h"
25 
26 typedef struct
27 {
28 	zbx_uint64_t	hostmacroid;
29 	char		*macro;
30 	char		*value;
31 	char		*description;
32 	unsigned char	type;
33 #define ZBX_FLAG_LLD_HOSTMACRO_UPDATE_VALUE		__UINT64_C(0x00000001)
34 #define ZBX_FLAG_LLD_HOSTMACRO_UPDATE_DESCRIPTION	__UINT64_C(0x00000002)
35 #define ZBX_FLAG_LLD_HOSTMACRO_UPDATE_TYPE		__UINT64_C(0x00000004)
36 #define ZBX_FLAG_LLD_HOSTMACRO_UPDATE									\
37 		(ZBX_FLAG_LLD_HOSTMACRO_UPDATE_VALUE | ZBX_FLAG_LLD_HOSTMACRO_UPDATE_DESCRIPTION |	\
38 		ZBX_FLAG_LLD_HOSTMACRO_UPDATE_TYPE)
39 #define ZBX_FLAG_LLD_HOSTMACRO_REMOVE			__UINT64_C(0x00000008)
40 	zbx_uint64_t	flags;
41 }
42 zbx_lld_hostmacro_t;
43 
lld_hostmacro_free(zbx_lld_hostmacro_t * hostmacro)44 static void	lld_hostmacro_free(zbx_lld_hostmacro_t *hostmacro)
45 {
46 	zbx_free(hostmacro->macro);
47 	zbx_free(hostmacro->value);
48 	zbx_free(hostmacro->description);
49 	zbx_free(hostmacro);
50 }
51 
52 typedef struct
53 {
54 	char		*community;
55 	char		*securityname;
56 	char		*authpassphrase;
57 	char		*privpassphrase;
58 	char		*contextname;
59 	unsigned char	securitylevel;
60 	unsigned char	authprotocol;
61 	unsigned char	privprotocol;
62 	unsigned char	version;
63 	unsigned char	bulk;
64 #define ZBX_FLAG_LLD_INTERFACE_SNMP_UPDATE_TYPE		__UINT64_C(0x00000001)	/* interface_snmp.type */
65 #define ZBX_FLAG_LLD_INTERFACE_SNMP_UPDATE_BULK		__UINT64_C(0x00000002)	/* interface_snmp.bulk */
66 #define ZBX_FLAG_LLD_INTERFACE_SNMP_UPDATE_COMMUNITY	__UINT64_C(0x00000004)	/* interface_snmp.community */
67 #define ZBX_FLAG_LLD_INTERFACE_SNMP_UPDATE_SECNAME	__UINT64_C(0x00000008)	/* interface_snmp.securityname */
68 #define ZBX_FLAG_LLD_INTERFACE_SNMP_UPDATE_SECLEVEL	__UINT64_C(0x00000010)	/* interface_snmp.securitylevel */
69 #define ZBX_FLAG_LLD_INTERFACE_SNMP_UPDATE_AUTHPASS	__UINT64_C(0x00000020)	/* interface_snmp.authpassphrase */
70 #define ZBX_FLAG_LLD_INTERFACE_SNMP_UPDATE_PRIVPASS	__UINT64_C(0x00000040)	/* interface_snmp.privpassphrase */
71 #define ZBX_FLAG_LLD_INTERFACE_SNMP_UPDATE_AUTHPROTOCOL	__UINT64_C(0x00000080)	/* interface_snmp.authprotocol */
72 #define ZBX_FLAG_LLD_INTERFACE_SNMP_UPDATE_PRIVPROTOCOL	__UINT64_C(0x00000100)	/* interface_snmp.privprotocol */
73 #define ZBX_FLAG_LLD_INTERFACE_SNMP_UPDATE_CONTEXT	__UINT64_C(0x00000200)	/* interface_snmp.contextname */
74 #define ZBX_FLAG_LLD_INTERFACE_SNMP_UPDATE									\
75 		(ZBX_FLAG_LLD_INTERFACE_SNMP_UPDATE_TYPE | ZBX_FLAG_LLD_INTERFACE_SNMP_UPDATE_BULK |		\
76 		ZBX_FLAG_LLD_INTERFACE_SNMP_UPDATE_COMMUNITY | ZBX_FLAG_LLD_INTERFACE_SNMP_UPDATE_SECNAME |	\
77 		ZBX_FLAG_LLD_INTERFACE_SNMP_UPDATE_SECLEVEL | ZBX_FLAG_LLD_INTERFACE_SNMP_UPDATE_AUTHPASS |	\
78 		ZBX_FLAG_LLD_INTERFACE_SNMP_UPDATE_PRIVPASS | ZBX_FLAG_LLD_INTERFACE_SNMP_UPDATE_AUTHPROTOCOL |	\
79 		ZBX_FLAG_LLD_INTERFACE_SNMP_UPDATE_PRIVPROTOCOL | ZBX_FLAG_LLD_INTERFACE_SNMP_UPDATE_CONTEXT)
80 #define ZBX_FLAG_LLD_INTERFACE_SNMP_CREATE		__UINT64_C(0x00000400)	/* new snmp data record*/
81 	zbx_uint64_t	flags;
82 
83 }
84 zbx_lld_interface_snmp_t;
85 
86 typedef struct
87 {
88 	zbx_uint64_t	interfaceid;
89 	zbx_uint64_t	parent_interfaceid;
90 	char		*ip;
91 	char		*dns;
92 	char		*port;
93 	unsigned char	main;
94 	unsigned char	main_orig;
95 	unsigned char	type;
96 	unsigned char	type_orig;
97 	unsigned char	useip;
98 #define ZBX_FLAG_LLD_INTERFACE_UPDATE_TYPE	__UINT64_C(0x00000001)	/* interface.type field should be updated  */
99 #define ZBX_FLAG_LLD_INTERFACE_UPDATE_MAIN	__UINT64_C(0x00000002)	/* interface.main field should be updated */
100 #define ZBX_FLAG_LLD_INTERFACE_UPDATE_USEIP	__UINT64_C(0x00000004)	/* interface.useip field should be updated */
101 #define ZBX_FLAG_LLD_INTERFACE_UPDATE_IP	__UINT64_C(0x00000008)	/* interface.ip field should be updated */
102 #define ZBX_FLAG_LLD_INTERFACE_UPDATE_DNS	__UINT64_C(0x00000010)	/* interface.dns field should be updated */
103 #define ZBX_FLAG_LLD_INTERFACE_UPDATE_PORT	__UINT64_C(0x00000020)	/* interface.port field should be updated */
104 #define ZBX_FLAG_LLD_INTERFACE_UPDATE								\
105 		(ZBX_FLAG_LLD_INTERFACE_UPDATE_TYPE | ZBX_FLAG_LLD_INTERFACE_UPDATE_MAIN |	\
106 		ZBX_FLAG_LLD_INTERFACE_UPDATE_USEIP | ZBX_FLAG_LLD_INTERFACE_UPDATE_IP |	\
107 		ZBX_FLAG_LLD_INTERFACE_UPDATE_DNS | ZBX_FLAG_LLD_INTERFACE_UPDATE_PORT)
108 #define ZBX_FLAG_LLD_INTERFACE_REMOVE		__UINT64_C(0x00000080)	/* interfaces which should be deleted */
109 #define ZBX_FLAG_LLD_INTERFACE_SNMP_REMOVE	__UINT64_C(0x00000100)	/* snmp data which should be deleted */
110 #define ZBX_FLAG_LLD_INTERFACE_SNMP_DATA_EXISTS	__UINT64_C(0x00000200)	/* there is snmp data */
111 	zbx_uint64_t	flags;
112 	union _data
113 	{
114 		zbx_lld_interface_snmp_t *snmp;
115 	}
116 	data;
117 }
118 zbx_lld_interface_t;
119 
lld_interface_free(zbx_lld_interface_t * interface)120 static void	lld_interface_free(zbx_lld_interface_t *interface)
121 {
122 	zbx_free(interface->port);
123 	zbx_free(interface->dns);
124 	zbx_free(interface->ip);
125 
126 	if (0 != (interface->flags & ZBX_FLAG_LLD_INTERFACE_SNMP_DATA_EXISTS))
127 	{
128 		zbx_free(interface->data.snmp->community);
129 		zbx_free(interface->data.snmp->securityname);
130 		zbx_free(interface->data.snmp->authpassphrase);
131 		zbx_free(interface->data.snmp->privpassphrase);
132 		zbx_free(interface->data.snmp->contextname);
133 		zbx_free(interface->data.snmp);
134 	}
135 
136 	zbx_free(interface);
137 }
138 
139 typedef struct
140 {
141 	zbx_uint64_t		hostid;
142 	zbx_vector_uint64_t	new_groupids;		/* host groups which should be added */
143 	zbx_vector_uint64_t	lnk_templateids;	/* templates which should be linked */
144 	zbx_vector_uint64_t	del_templateids;	/* templates which should be unlinked */
145 	zbx_vector_ptr_t	new_hostmacros;		/* host macros which should be added, deleted or updated */
146 	zbx_vector_ptr_t	interfaces;
147 	zbx_vector_db_tag_ptr_t	tags;
148 	char			*host_proto;
149 	char			*host;
150 	char			*host_orig;
151 	char			*name;
152 	char			*name_orig;
153 	int			lastcheck;
154 	int			ts_delete;
155 #define ZBX_FLAG_LLD_HOST_DISCOVERED			__UINT64_C(0x00000001)	/* hosts which should be updated or added */
156 #define ZBX_FLAG_LLD_HOST_UPDATE_HOST			__UINT64_C(0x00000002)	/* hosts.host and host_discovery.host fields should be updated */
157 #define ZBX_FLAG_LLD_HOST_UPDATE_NAME			__UINT64_C(0x00000004)	/* hosts.name field should be updated */
158 #define ZBX_FLAG_LLD_HOST_UPDATE_PROXY			__UINT64_C(0x00000008)	/* hosts.proxy_hostid field should be updated */
159 #define ZBX_FLAG_LLD_HOST_UPDATE_IPMI_AUTH		__UINT64_C(0x00000010)	/* hosts.ipmi_authtype field should be updated */
160 #define ZBX_FLAG_LLD_HOST_UPDATE_IPMI_PRIV		__UINT64_C(0x00000020)	/* hosts.ipmi_privilege field should be updated */
161 #define ZBX_FLAG_LLD_HOST_UPDATE_IPMI_USER		__UINT64_C(0x00000040)	/* hosts.ipmi_username field should be updated */
162 #define ZBX_FLAG_LLD_HOST_UPDATE_IPMI_PASS		__UINT64_C(0x00000080)	/* hosts.ipmi_password field should be updated */
163 #define ZBX_FLAG_LLD_HOST_UPDATE_TLS_CONNECT		__UINT64_C(0x00000100)	/* hosts.tls_connect field should be updated */
164 #define ZBX_FLAG_LLD_HOST_UPDATE_TLS_ACCEPT		__UINT64_C(0x00000200)	/* hosts.tls_accept field should be updated */
165 #define ZBX_FLAG_LLD_HOST_UPDATE_TLS_ISSUER		__UINT64_C(0x00000400)	/* hosts.tls_issuer field should be updated */
166 #define ZBX_FLAG_LLD_HOST_UPDATE_TLS_SUBJECT		__UINT64_C(0x00000800)	/* hosts.tls_subject field should be updated */
167 #define ZBX_FLAG_LLD_HOST_UPDATE_TLS_PSK_IDENTITY	__UINT64_C(0x00001000)	/* hosts.tls_psk_identity field should be updated */
168 #define ZBX_FLAG_LLD_HOST_UPDATE_TLS_PSK		__UINT64_C(0x00002000)	/* hosts.tls_psk field should be updated */
169 #define ZBX_FLAG_LLD_HOST_UPDATE_CUSTOM_INTERFACES	__UINT64_C(0x00004000)	/* hosts.custom_interfaces field should be updated */
170 
171 #define ZBX_FLAG_LLD_HOST_UPDATE									\
172 		(ZBX_FLAG_LLD_HOST_UPDATE_HOST | ZBX_FLAG_LLD_HOST_UPDATE_NAME |			\
173 		ZBX_FLAG_LLD_HOST_UPDATE_PROXY | ZBX_FLAG_LLD_HOST_UPDATE_IPMI_AUTH |			\
174 		ZBX_FLAG_LLD_HOST_UPDATE_IPMI_PRIV | ZBX_FLAG_LLD_HOST_UPDATE_IPMI_USER |		\
175 		ZBX_FLAG_LLD_HOST_UPDATE_IPMI_PASS | ZBX_FLAG_LLD_HOST_UPDATE_TLS_CONNECT |		\
176 		ZBX_FLAG_LLD_HOST_UPDATE_TLS_ACCEPT | ZBX_FLAG_LLD_HOST_UPDATE_TLS_ISSUER |		\
177 		ZBX_FLAG_LLD_HOST_UPDATE_TLS_SUBJECT | ZBX_FLAG_LLD_HOST_UPDATE_TLS_PSK_IDENTITY |	\
178 		ZBX_FLAG_LLD_HOST_UPDATE_TLS_PSK | ZBX_FLAG_LLD_HOST_UPDATE_CUSTOM_INTERFACES)
179 	zbx_uint64_t		flags;
180 	const struct zbx_json_parse	*jp_row;
181 	char			inventory_mode;
182 	char			inventory_mode_orig;
183 	unsigned char		status;
184 	unsigned char		custom_interfaces;
185 }
186 zbx_lld_host_t;
187 
lld_host_free(zbx_lld_host_t * host)188 static void	lld_host_free(zbx_lld_host_t *host)
189 {
190 	zbx_vector_uint64_destroy(&host->new_groupids);
191 	zbx_vector_uint64_destroy(&host->lnk_templateids);
192 	zbx_vector_uint64_destroy(&host->del_templateids);
193 	zbx_vector_ptr_clear_ext(&host->new_hostmacros, (zbx_clean_func_t)lld_hostmacro_free);
194 	zbx_vector_ptr_destroy(&host->new_hostmacros);
195 	zbx_vector_db_tag_ptr_clear_ext(&host->tags, zbx_db_tag_free);
196 	zbx_vector_db_tag_ptr_destroy(&host->tags);
197 	zbx_vector_ptr_clear_ext(&host->interfaces, (zbx_clean_func_t)lld_interface_free);
198 	zbx_vector_ptr_destroy(&host->interfaces);
199 	zbx_free(host->host_proto);
200 	zbx_free(host->host);
201 	zbx_free(host->host_orig);
202 	zbx_free(host->name);
203 	zbx_free(host->name_orig);
204 	zbx_free(host);
205 }
206 
207 typedef struct
208 {
209 	zbx_uint64_t	group_prototypeid;
210 	char		*name;
211 }
212 zbx_lld_group_prototype_t;
213 
lld_group_prototype_free(zbx_lld_group_prototype_t * group_prototype)214 static void	lld_group_prototype_free(zbx_lld_group_prototype_t *group_prototype)
215 {
216 	zbx_free(group_prototype->name);
217 	zbx_free(group_prototype);
218 }
219 
220 typedef struct
221 {
222 	zbx_uint64_t		groupid;
223 	zbx_uint64_t		group_prototypeid;
224 	zbx_vector_ptr_t	hosts;
225 	char			*name_proto;
226 	char			*name;
227 	char			*name_orig;
228 	int			lastcheck;
229 	int			ts_delete;
230 #define ZBX_FLAG_LLD_GROUP_DISCOVERED		__UINT64_C(0x00000001)	/* groups which should be updated or added */
231 #define ZBX_FLAG_LLD_GROUP_UPDATE_NAME		__UINT64_C(0x00000002)	/* groups.name field should be updated */
232 #define ZBX_FLAG_LLD_GROUP_UPDATE		ZBX_FLAG_LLD_GROUP_UPDATE_NAME
233 	zbx_uint64_t		flags;
234 }
235 zbx_lld_group_t;
236 
lld_group_free(zbx_lld_group_t * group)237 static void	lld_group_free(zbx_lld_group_t *group)
238 {
239 	/* zbx_vector_ptr_clear_ext(&group->hosts, (zbx_clean_func_t)lld_host_free); is not missing here */
240 	zbx_vector_ptr_destroy(&group->hosts);
241 	zbx_free(group->name_proto);
242 	zbx_free(group->name);
243 	zbx_free(group->name_orig);
244 	zbx_free(group);
245 }
246 
247 typedef struct
248 {
249 	char				*name;
250 	/* permission pair (usrgrpid, permission) */
251 	zbx_vector_uint64_pair_t	rights;
252 	/* reference to the inherited rights */
253 	zbx_vector_uint64_pair_t	*prights;
254 }
255 zbx_lld_group_rights_t;
256 
257 static void	lld_host_update_tags(zbx_lld_host_t *host, const zbx_vector_db_tag_ptr_t *tags,
258 		const zbx_vector_ptr_t *lld_macros, char **info);
259 
260 /******************************************************************************
261  *                                                                            *
262  * Function: lld_hosts_get_tags                                               *
263  *                                                                            *
264  * Purpose: retrieves tags of the existing hosts                              *
265  *                                                                            *
266  * Parameters: hosts - [IN/OUT] list of hosts                                 *
267  *                                                                            *
268  ******************************************************************************/
lld_hosts_get_tags(zbx_vector_ptr_t * hosts)269 static void	lld_hosts_get_tags(zbx_vector_ptr_t *hosts)
270 {
271 	zbx_vector_uint64_t	hostids;
272 	int			i;
273 	zbx_lld_host_t		*host;
274 	DB_RESULT		result;
275 	DB_ROW			row;
276 	char			*sql = NULL;
277 	size_t			sql_alloc = 0, sql_offset = 0;
278 	zbx_uint64_t		hostid;
279 	zbx_db_tag_t		*tag;
280 
281 	zbx_vector_ptr_sort(hosts, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
282 	zbx_vector_uint64_create(&hostids);
283 
284 	for (i = 0; i < hosts->values_num; i++)
285 	{
286 		host = (zbx_lld_host_t *)hosts->values[i];
287 		zbx_vector_uint64_append(&hostids, host->hostid);
288 	}
289 
290 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "select hosttagid,hostid,tag,value from host_tag where");
291 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid", hostids.values, hostids.values_num);
292 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " order by hostid");
293 
294 	result = DBselect("%s", sql);
295 
296 	i = 0;
297 	host = (zbx_lld_host_t *)hosts->values[i];
298 
299 	while (NULL != (row = DBfetch(result)))
300 	{
301 		ZBX_STR2UINT64(hostid, row[1]);
302 		while (hostid != host->hostid)
303 		{
304 			if (++i == hosts->values_num)
305 			{
306 				THIS_SHOULD_NEVER_HAPPEN;
307 				goto out;
308 			}
309 			host = (zbx_lld_host_t *)hosts->values[i];
310 		}
311 
312 		tag = (zbx_db_tag_t *)zbx_malloc(NULL, sizeof(zbx_db_tag_t));
313 		ZBX_STR2UINT64(tag->tagid, row[0]);
314 		tag->tag = zbx_strdup(NULL, row[2]);
315 		tag->value = zbx_strdup(NULL, row[3]);
316 		tag->flags = 0;
317 		zbx_vector_db_tag_ptr_append(&host->tags, tag);
318 	}
319 out:
320 	for (i = 0; i < hosts->values_num; i++)
321 	{
322 		host = (zbx_lld_host_t *)hosts->values[i];
323 		zbx_vector_db_tag_ptr_sort(&host->tags, zbx_db_tag_compare_func);
324 	}
325 
326 	DBfree_result(result);
327 	zbx_free(sql);
328 	zbx_vector_uint64_destroy(&hostids);
329 }
330 
331 /******************************************************************************
332  *                                                                            *
333  * Function: lld_hosts_get                                                    *
334  *                                                                            *
335  * Purpose: retrieves existing hosts for the specified host prototype         *
336  *                                                                            *
337  * Parameters: parent_hostid - [IN] host prototype identifier                 *
338  *             hosts         - [OUT] list of hosts                            *
339  *                                                                            *
340  ******************************************************************************/
lld_hosts_get(zbx_uint64_t parent_hostid,zbx_vector_ptr_t * hosts,zbx_uint64_t proxy_hostid,char ipmi_authtype,unsigned char ipmi_privilege,const char * ipmi_username,const char * ipmi_password,unsigned char tls_connect,unsigned char tls_accept,const char * tls_issuer,const char * tls_subject,const char * tls_psk_identity,const char * tls_psk)341 static void	lld_hosts_get(zbx_uint64_t parent_hostid, zbx_vector_ptr_t *hosts, zbx_uint64_t proxy_hostid,
342 		char ipmi_authtype, unsigned char ipmi_privilege, const char *ipmi_username, const char *ipmi_password,
343 		unsigned char tls_connect, unsigned char tls_accept, const char *tls_issuer,
344 		const char *tls_subject, const char *tls_psk_identity, const char *tls_psk)
345 {
346 	DB_RESULT		result;
347 	DB_ROW			row;
348 	zbx_lld_host_t		*host;
349 	zbx_uint64_t		db_proxy_hostid;
350 
351 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
352 
353 	result = DBselect(
354 			"select hd.hostid,hd.host,hd.lastcheck,hd.ts_delete,h.host,h.name,h.proxy_hostid,"
355 				"h.ipmi_authtype,h.ipmi_privilege,h.ipmi_username,h.ipmi_password,hi.inventory_mode,"
356 				"h.tls_connect,h.tls_accept,h.tls_issuer,h.tls_subject,h.tls_psk_identity,h.tls_psk,"
357 				"h.custom_interfaces"
358 			" from host_discovery hd"
359 				" join hosts h"
360 					" on hd.hostid=h.hostid"
361 				" left join host_inventory hi"
362 					" on hd.hostid=hi.hostid"
363 			" where hd.parent_hostid=" ZBX_FS_UI64,
364 			parent_hostid);
365 
366 	while (NULL != (row = DBfetch(result)))
367 	{
368 		host = (zbx_lld_host_t *)zbx_malloc(NULL, sizeof(zbx_lld_host_t));
369 
370 		ZBX_STR2UINT64(host->hostid, row[0]);
371 		host->host_proto = zbx_strdup(NULL, row[1]);
372 		host->lastcheck = atoi(row[2]);
373 		host->ts_delete = atoi(row[3]);
374 		host->host = zbx_strdup(NULL, row[4]);
375 		host->host_orig = NULL;
376 		host->name = zbx_strdup(NULL, row[5]);
377 		host->name_orig = NULL;
378 		host->flags = 0x00;
379 		ZBX_STR2UCHAR(host->custom_interfaces, row[18]);
380 
381 		ZBX_DBROW2UINT64(db_proxy_hostid, row[6]);
382 		if (db_proxy_hostid != proxy_hostid)
383 			host->flags |= ZBX_FLAG_LLD_HOST_UPDATE_PROXY;
384 
385 		if ((char)atoi(row[7]) != ipmi_authtype)
386 			host->flags |= ZBX_FLAG_LLD_HOST_UPDATE_IPMI_AUTH;
387 
388 		if ((unsigned char)atoi(row[8]) != ipmi_privilege)
389 			host->flags |= ZBX_FLAG_LLD_HOST_UPDATE_IPMI_PRIV;
390 
391 		if (0 != strcmp(row[9], ipmi_username))
392 			host->flags |= ZBX_FLAG_LLD_HOST_UPDATE_IPMI_USER;
393 
394 		if (0 != strcmp(row[10], ipmi_password))
395 			host->flags |= ZBX_FLAG_LLD_HOST_UPDATE_IPMI_PASS;
396 
397 		if (atoi(row[12]) != tls_connect)
398 			host->flags |= ZBX_FLAG_LLD_HOST_UPDATE_TLS_CONNECT;
399 
400 		if (atoi(row[13]) != tls_accept)
401 			host->flags |= ZBX_FLAG_LLD_HOST_UPDATE_TLS_ACCEPT;
402 
403 		if (0 != strcmp(tls_issuer, row[14]))
404 			host->flags |= ZBX_FLAG_LLD_HOST_UPDATE_TLS_ISSUER;
405 
406 		if (0 != strcmp(tls_subject, row[15]))
407 			host->flags |= ZBX_FLAG_LLD_HOST_UPDATE_TLS_SUBJECT;
408 
409 		if (0 != strcmp(tls_psk_identity, row[16]))
410 			host->flags |= ZBX_FLAG_LLD_HOST_UPDATE_TLS_PSK_IDENTITY;
411 
412 		if (0 != strcmp(tls_psk, row[17]))
413 			host->flags |= ZBX_FLAG_LLD_HOST_UPDATE_TLS_PSK;
414 
415 		if (SUCCEED == DBis_null(row[11]))
416 			host->inventory_mode_orig = HOST_INVENTORY_DISABLED;
417 		else
418 			host->inventory_mode_orig = (char)atoi(row[11]);
419 
420 		zbx_vector_uint64_create(&host->new_groupids);
421 		zbx_vector_uint64_create(&host->lnk_templateids);
422 		zbx_vector_uint64_create(&host->del_templateids);
423 		zbx_vector_ptr_create(&host->new_hostmacros);
424 		zbx_vector_db_tag_ptr_create(&host->tags);
425 		zbx_vector_ptr_create(&host->interfaces);
426 
427 		zbx_vector_ptr_append(hosts, host);
428 	}
429 	DBfree_result(result);
430 
431 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
432 }
433 
434 /******************************************************************************
435  *                                                                            *
436  * Function: lld_hosts_validate                                               *
437  *                                                                            *
438  * Parameters: hosts - [IN] list of hosts; should be sorted by hostid         *
439  *                                                                            *
440  ******************************************************************************/
lld_hosts_validate(zbx_vector_ptr_t * hosts,char ** error)441 static void	lld_hosts_validate(zbx_vector_ptr_t *hosts, char **error)
442 {
443 	DB_RESULT		result;
444 	DB_ROW			row;
445 	int			i, j;
446 	zbx_lld_host_t		*host, *host_b;
447 	zbx_vector_uint64_t	hostids;
448 	zbx_vector_str_t	tnames, vnames;
449 
450 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
451 
452 	zbx_vector_uint64_create(&hostids);
453 	zbx_vector_str_create(&tnames);		/* list of technical host names */
454 	zbx_vector_str_create(&vnames);		/* list of visible host names */
455 
456 	/* checking a host name validity */
457 	for (i = 0; i < hosts->values_num; i++)
458 	{
459 		char	*ch_error;
460 
461 		host = (zbx_lld_host_t *)hosts->values[i];
462 
463 		if (0 == (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
464 			continue;
465 
466 		/* only new hosts or hosts with changed host name will be validated */
467 		if (0 != host->hostid && 0 == (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_HOST))
468 			continue;
469 
470 		/* host name is valid? */
471 		if (SUCCEED == zbx_check_hostname(host->host, &ch_error))
472 			continue;
473 
474 		*error = zbx_strdcatf(*error, "Cannot %s host \"%s\": %s.\n",
475 				(0 != host->hostid ? "update" : "create"), host->host, ch_error);
476 
477 		zbx_free(ch_error);
478 
479 		if (0 != host->hostid)
480 		{
481 			lld_field_str_rollback(&host->host, &host->host_orig, &host->flags,
482 					ZBX_FLAG_LLD_HOST_UPDATE_HOST);
483 		}
484 		else
485 			host->flags &= ~ZBX_FLAG_LLD_HOST_DISCOVERED;
486 	}
487 
488 	/* checking a visible host name validity */
489 	for (i = 0; i < hosts->values_num; i++)
490 	{
491 		host = (zbx_lld_host_t *)hosts->values[i];
492 
493 		if (0 == (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
494 			continue;
495 
496 		/* only new hosts or hosts with changed visible name will be validated */
497 		if (0 != host->hostid && 0 == (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_NAME))
498 			continue;
499 
500 		/* visible host name is valid utf8 sequence and has a valid length */
501 		if (SUCCEED == zbx_is_utf8(host->name) && '\0' != *host->name &&
502 				HOST_NAME_LEN >= zbx_strlen_utf8(host->name))
503 		{
504 			continue;
505 		}
506 
507 		zbx_replace_invalid_utf8(host->name);
508 		*error = zbx_strdcatf(*error, "Cannot %s host: invalid visible host name \"%s\".\n",
509 				(0 != host->hostid ? "update" : "create"), host->name);
510 
511 		if (0 != host->hostid)
512 		{
513 			lld_field_str_rollback(&host->name, &host->name_orig, &host->flags,
514 					ZBX_FLAG_LLD_HOST_UPDATE_NAME);
515 		}
516 		else
517 			host->flags &= ~ZBX_FLAG_LLD_HOST_DISCOVERED;
518 	}
519 
520 	/* checking duplicated host names */
521 	for (i = 0; i < hosts->values_num; i++)
522 	{
523 		host = (zbx_lld_host_t *)hosts->values[i];
524 
525 		if (0 == (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
526 			continue;
527 
528 		/* only new hosts or hosts with changed host name will be validated */
529 		if (0 != host->hostid && 0 == (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_HOST))
530 			continue;
531 
532 		for (j = 0; j < hosts->values_num; j++)
533 		{
534 			host_b = (zbx_lld_host_t *)hosts->values[j];
535 
536 			if (0 == (host_b->flags & ZBX_FLAG_LLD_HOST_DISCOVERED) || i == j)
537 				continue;
538 
539 			if (0 != strcmp(host->host, host_b->host))
540 				continue;
541 
542 			*error = zbx_strdcatf(*error, "Cannot %s host:"
543 					" host with the same name \"%s\" already exists.\n",
544 					(0 != host->hostid ? "update" : "create"), host->host);
545 
546 			if (0 != host->hostid)
547 			{
548 				lld_field_str_rollback(&host->host, &host->host_orig, &host->flags,
549 						ZBX_FLAG_LLD_HOST_UPDATE_HOST);
550 			}
551 			else
552 				host->flags &= ~ZBX_FLAG_LLD_HOST_DISCOVERED;
553 		}
554 	}
555 
556 	/* checking duplicated visible host names */
557 	for (i = 0; i < hosts->values_num; i++)
558 	{
559 		host = (zbx_lld_host_t *)hosts->values[i];
560 
561 		if (0 == (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
562 			continue;
563 
564 		/* only new hosts or hosts with changed visible name will be validated */
565 		if (0 != host->hostid && 0 == (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_NAME))
566 			continue;
567 
568 		for (j = 0; j < hosts->values_num; j++)
569 		{
570 			host_b = (zbx_lld_host_t *)hosts->values[j];
571 
572 			if (0 == (host_b->flags & ZBX_FLAG_LLD_HOST_DISCOVERED) || i == j)
573 				continue;
574 
575 			if (0 != strcmp(host->name, host_b->name))
576 				continue;
577 
578 			*error = zbx_strdcatf(*error, "Cannot %s host:"
579 					" host with the same visible name \"%s\" already exists.\n",
580 					(0 != host->hostid ? "update" : "create"), host->name);
581 
582 			if (0 != host->hostid)
583 			{
584 				lld_field_str_rollback(&host->name, &host->name_orig, &host->flags,
585 						ZBX_FLAG_LLD_HOST_UPDATE_NAME);
586 			}
587 			else
588 				host->flags &= ~ZBX_FLAG_LLD_HOST_DISCOVERED;
589 		}
590 	}
591 
592 	/* checking duplicated host names and visible host names in DB */
593 
594 	for (i = 0; i < hosts->values_num; i++)
595 	{
596 		host = (zbx_lld_host_t *)hosts->values[i];
597 
598 		if (0 == (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
599 			continue;
600 
601 		if (0 != host->hostid)
602 			zbx_vector_uint64_append(&hostids, host->hostid);
603 
604 		if (0 == host->hostid || 0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_HOST))
605 			zbx_vector_str_append(&tnames, host->host);
606 
607 		if (0 == host->hostid || 0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_NAME))
608 			zbx_vector_str_append(&vnames, host->name);
609 	}
610 
611 	if (0 != tnames.values_num || 0 != vnames.values_num)
612 	{
613 		char	*sql = NULL;
614 		size_t	sql_alloc = 0, sql_offset = 0;
615 
616 		zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
617 				"select host,name"
618 				" from hosts"
619 				" where status in (%d,%d,%d)"
620 					" and flags<>%d"
621 					" and",
622 				HOST_STATUS_MONITORED, HOST_STATUS_NOT_MONITORED, HOST_STATUS_TEMPLATE,
623 				ZBX_FLAG_DISCOVERY_PROTOTYPE);
624 
625 		if (0 != tnames.values_num && 0 != vnames.values_num)
626 			zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " (");
627 
628 		if (0 != tnames.values_num)
629 		{
630 			DBadd_str_condition_alloc(&sql, &sql_alloc, &sql_offset, "host",
631 					(const char **)tnames.values, tnames.values_num);
632 		}
633 
634 		if (0 != tnames.values_num && 0 != vnames.values_num)
635 			zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " or");
636 
637 		if (0 != vnames.values_num)
638 		{
639 			DBadd_str_condition_alloc(&sql, &sql_alloc, &sql_offset, "name",
640 					(const char **)vnames.values, vnames.values_num);
641 		}
642 
643 		if (0 != tnames.values_num && 0 != vnames.values_num)
644 			zbx_chrcpy_alloc(&sql, &sql_alloc, &sql_offset, ')');
645 
646 		if (0 != hostids.values_num)
647 		{
648 			zbx_vector_uint64_sort(&hostids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
649 			zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " and not");
650 			DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid",
651 					hostids.values, hostids.values_num);
652 		}
653 
654 		result = DBselect("%s", sql);
655 
656 		while (NULL != (row = DBfetch(result)))
657 		{
658 			for (i = 0; i < hosts->values_num; i++)
659 			{
660 				host = (zbx_lld_host_t *)hosts->values[i];
661 
662 				if (0 == (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
663 					continue;
664 
665 				if (0 == strcmp(host->host, row[0]))
666 				{
667 					*error = zbx_strdcatf(*error, "Cannot %s host:"
668 							" host with the same name \"%s\" already exists.\n",
669 							(0 != host->hostid ? "update" : "create"), host->host);
670 
671 					if (0 != host->hostid)
672 					{
673 						lld_field_str_rollback(&host->host, &host->host_orig, &host->flags,
674 								ZBX_FLAG_LLD_HOST_UPDATE_HOST);
675 					}
676 					else
677 						host->flags &= ~ZBX_FLAG_LLD_HOST_DISCOVERED;
678 				}
679 
680 				if (0 == strcmp(host->name, row[1]))
681 				{
682 					*error = zbx_strdcatf(*error, "Cannot %s host:"
683 							" host with the same visible name \"%s\" already exists.\n",
684 							(0 != host->hostid ? "update" : "create"), host->name);
685 
686 					if (0 != host->hostid)
687 					{
688 						lld_field_str_rollback(&host->name, &host->name_orig, &host->flags,
689 								ZBX_FLAG_LLD_HOST_UPDATE_NAME);
690 					}
691 					else
692 						host->flags &= ~ZBX_FLAG_LLD_HOST_DISCOVERED;
693 				}
694 			}
695 		}
696 		DBfree_result(result);
697 
698 		zbx_free(sql);
699 	}
700 
701 	zbx_vector_str_destroy(&vnames);
702 	zbx_vector_str_destroy(&tnames);
703 	zbx_vector_uint64_destroy(&hostids);
704 
705 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
706 }
707 
lld_host_make(zbx_vector_ptr_t * hosts,const char * host_proto,const char * name_proto,char inventory_mode_proto,unsigned char status_proto,unsigned char discover_proto,zbx_vector_db_tag_ptr_t * tags,const zbx_lld_row_t * lld_row,const zbx_vector_ptr_t * lld_macros,char ** info,unsigned char custom_iface)708 static zbx_lld_host_t	*lld_host_make(zbx_vector_ptr_t *hosts, const char *host_proto, const char *name_proto,
709 		char inventory_mode_proto, unsigned char status_proto, unsigned char discover_proto,
710 		zbx_vector_db_tag_ptr_t *tags, const zbx_lld_row_t *lld_row, const zbx_vector_ptr_t *lld_macros,
711 		char **info, unsigned char custom_iface)
712 {
713 	char			*buffer = NULL;
714 	int			i, host_found = 0;
715 	zbx_lld_host_t		*host;
716 	zbx_vector_db_tag_ptr_t	tmp_tags;
717 
718 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
719 
720 	for (i = 0; i < hosts->values_num; i++)
721 	{
722 		host = (zbx_lld_host_t *)hosts->values[i];
723 
724 		if (0 != (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
725 			continue;
726 
727 		buffer = zbx_strdup(buffer, host->host_proto);
728 		substitute_lld_macros(&buffer, &lld_row->jp_row, lld_macros, ZBX_MACRO_ANY, NULL, 0);
729 		zbx_lrtrim(buffer, ZBX_WHITESPACE);
730 
731 		if (0 == strcmp(host->host, buffer))
732 		{
733 			host_found = 1;
734 			break;
735 		}
736 	}
737 
738 	zbx_vector_db_tag_ptr_create(&tmp_tags);
739 
740 	if (0 == host_found)
741 	{
742 		host = (zbx_lld_host_t *)zbx_malloc(NULL, sizeof(zbx_lld_host_t));
743 
744 		host->hostid = 0;
745 		host->host_proto = NULL;
746 		host->lastcheck = 0;
747 		host->ts_delete = 0;
748 		host->host = zbx_strdup(NULL, host_proto);
749 		host->host_orig = NULL;
750 		substitute_lld_macros(&host->host, &lld_row->jp_row, lld_macros, ZBX_MACRO_ANY, NULL, 0);
751 		zbx_lrtrim(host->host, ZBX_WHITESPACE);
752 
753 		host->status = status_proto;
754 		host->inventory_mode = inventory_mode_proto;
755 		host->custom_interfaces = custom_iface;
756 
757 		zbx_vector_uint64_create(&host->lnk_templateids);
758 
759 		lld_override_host(&lld_row->overrides, host->host, &host->lnk_templateids, &host->inventory_mode,
760 				&tmp_tags, &host->status, &discover_proto);
761 
762 		if (ZBX_PROTOTYPE_NO_DISCOVER == discover_proto)
763 		{
764 			zbx_vector_uint64_destroy(&host->lnk_templateids);
765 			zbx_free(host->host);
766 			zbx_free(host);
767 			goto out;
768 		}
769 		else
770 		{
771 			host->name = zbx_strdup(NULL, name_proto);
772 			substitute_lld_macros(&host->name, &lld_row->jp_row, lld_macros, ZBX_MACRO_ANY, NULL, 0);
773 			zbx_lrtrim(host->name, ZBX_WHITESPACE);
774 			host->name_orig = NULL;
775 			zbx_vector_uint64_create(&host->new_groupids);
776 			zbx_vector_uint64_create(&host->del_templateids);
777 			zbx_vector_ptr_create(&host->new_hostmacros);
778 			zbx_vector_db_tag_ptr_create(&host->tags);
779 			zbx_vector_ptr_create(&host->interfaces);
780 			host->flags = ZBX_FLAG_LLD_HOST_DISCOVERED;
781 
782 			zbx_vector_ptr_append(hosts, host);
783 		}
784 	}
785 	else
786 	{
787 		/* host technical name */
788 		if (0 != strcmp(host->host_proto, host_proto))	/* the new host prototype differs */
789 		{
790 			host->host_orig = host->host;
791 			host->host = zbx_strdup(NULL, host_proto);
792 			substitute_lld_macros(&host->host, &lld_row->jp_row, lld_macros, ZBX_MACRO_ANY, NULL, 0);
793 			zbx_lrtrim(host->host, ZBX_WHITESPACE);
794 			host->flags |= ZBX_FLAG_LLD_HOST_UPDATE_HOST;
795 		}
796 
797 		host->inventory_mode = inventory_mode_proto;
798 
799 		if (host->custom_interfaces != custom_iface)
800 		{
801 			host->custom_interfaces = custom_iface;
802 			host->flags |= ZBX_FLAG_LLD_HOST_UPDATE_CUSTOM_INTERFACES;
803 		}
804 
805 		lld_override_host(&lld_row->overrides, host->host, &host->lnk_templateids, &host->inventory_mode, &tmp_tags,
806 				NULL, &discover_proto);
807 
808 		/* host visible name */
809 		buffer = zbx_strdup(buffer, name_proto);
810 		substitute_lld_macros(&buffer, &lld_row->jp_row, lld_macros, ZBX_MACRO_ANY, NULL, 0);
811 		zbx_lrtrim(buffer, ZBX_WHITESPACE);
812 		if (0 != strcmp(host->name, buffer))
813 		{
814 			host->name_orig = host->name;
815 			host->name = buffer;
816 			buffer = NULL;
817 			host->flags |= ZBX_FLAG_LLD_HOST_UPDATE_NAME;
818 		}
819 
820 		if (ZBX_PROTOTYPE_NO_DISCOVER != discover_proto)
821 			host->flags |= ZBX_FLAG_LLD_HOST_DISCOVERED;
822 	}
823 
824 	host->jp_row = &lld_row->jp_row;
825 
826 	if (0 != (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
827 	{
828 		zbx_vector_db_tag_ptr_append_array(&tmp_tags, tags->values, tags->values_num);
829 		lld_host_update_tags(host, &tmp_tags, lld_macros, info);
830 	}
831 out:
832 	zbx_vector_db_tag_ptr_destroy(&tmp_tags);
833 
834 	zbx_free(buffer);
835 
836 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%p", __func__, (void *)host);
837 
838 	return host;
839 }
840 
841 /******************************************************************************
842  *                                                                            *
843  * Function: lld_simple_groups_get                                            *
844  *                                                                            *
845  * Purpose: retrieve list of host groups which should be present on the each  *
846  *          discovered host                                                   *
847  *                                                                            *
848  * Parameters: parent_hostid - [IN] host prototype identifier                 *
849  *             groupids      - [OUT] sorted list of host groups               *
850  *                                                                            *
851  ******************************************************************************/
lld_simple_groups_get(zbx_uint64_t parent_hostid,zbx_vector_uint64_t * groupids)852 static void	lld_simple_groups_get(zbx_uint64_t parent_hostid, zbx_vector_uint64_t *groupids)
853 {
854 	DB_RESULT	result;
855 	DB_ROW		row;
856 	zbx_uint64_t	groupid;
857 
858 	result = DBselect(
859 			"select groupid"
860 			" from group_prototype"
861 			" where groupid is not null"
862 				" and hostid=" ZBX_FS_UI64,
863 			parent_hostid);
864 
865 	while (NULL != (row = DBfetch(result)))
866 	{
867 		ZBX_STR2UINT64(groupid, row[0]);
868 		zbx_vector_uint64_append(groupids, groupid);
869 	}
870 	DBfree_result(result);
871 
872 	zbx_vector_uint64_sort(groupids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
873 }
874 
875 /******************************************************************************
876  *                                                                            *
877  * Function: lld_hostgroups_make                                              *
878  *                                                                            *
879  * Parameters: groupids         - [IN] sorted list of host group ids which    *
880  *                                     should be present on the each          *
881  *                                     discovered host (Groups)               *
882  *             hosts            - [IN/OUT] list of hosts                      *
883  *                                         should be sorted by hostid         *
884  *             groups           - [IN]  list of host groups (Group prototypes)*
885  *             del_hostgroupids - [OUT] sorted list of host groups which      *
886  *                                      should be deleted                     *
887  *                                                                            *
888  ******************************************************************************/
lld_hostgroups_make(const zbx_vector_uint64_t * groupids,zbx_vector_ptr_t * hosts,const zbx_vector_ptr_t * groups,zbx_vector_uint64_t * del_hostgroupids)889 static void	lld_hostgroups_make(const zbx_vector_uint64_t *groupids, zbx_vector_ptr_t *hosts,
890 		const zbx_vector_ptr_t *groups, zbx_vector_uint64_t *del_hostgroupids)
891 {
892 	DB_RESULT		result;
893 	DB_ROW			row;
894 	int			i, j;
895 	zbx_vector_uint64_t	hostids;
896 	zbx_uint64_t		hostgroupid, hostid, groupid;
897 	zbx_lld_host_t		*host;
898 	const zbx_lld_group_t	*group;
899 
900 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
901 
902 	zbx_vector_uint64_create(&hostids);
903 
904 	for (i = 0; i < hosts->values_num; i++)
905 	{
906 		host = (zbx_lld_host_t *)hosts->values[i];
907 
908 		if (0 == (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
909 			continue;
910 
911 		zbx_vector_uint64_reserve(&host->new_groupids, groupids->values_num);
912 		for (j = 0; j < groupids->values_num; j++)
913 			zbx_vector_uint64_append(&host->new_groupids, groupids->values[j]);
914 
915 		if (0 != host->hostid)
916 			zbx_vector_uint64_append(&hostids, host->hostid);
917 	}
918 
919 	for (i = 0; i < groups->values_num; i++)
920 	{
921 		group = (zbx_lld_group_t *)groups->values[i];
922 
923 		if (0 == (group->flags & ZBX_FLAG_LLD_GROUP_DISCOVERED) || 0 == group->groupid)
924 			continue;
925 
926 		for (j = 0; j < group->hosts.values_num; j++)
927 		{
928 			host = (zbx_lld_host_t *)group->hosts.values[j];
929 
930 			zbx_vector_uint64_append(&host->new_groupids, group->groupid);
931 		}
932 	}
933 
934 	for (i = 0; i < hosts->values_num; i++)
935 	{
936 		host = (zbx_lld_host_t *)hosts->values[i];
937 		zbx_vector_uint64_sort(&host->new_groupids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
938 	}
939 
940 	if (0 != hostids.values_num)
941 	{
942 		char	*sql = NULL;
943 		size_t	sql_alloc = 0, sql_offset = 0;
944 
945 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
946 				"select hostid,groupid,hostgroupid"
947 				" from hosts_groups"
948 				" where");
949 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid", hostids.values, hostids.values_num);
950 
951 		result = DBselect("%s", sql);
952 
953 		zbx_free(sql);
954 
955 		while (NULL != (row = DBfetch(result)))
956 		{
957 			ZBX_STR2UINT64(hostid, row[0]);
958 			ZBX_STR2UINT64(groupid, row[1]);
959 
960 			if (FAIL == (i = zbx_vector_ptr_bsearch(hosts, &hostid, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
961 			{
962 				THIS_SHOULD_NEVER_HAPPEN;
963 				continue;
964 			}
965 
966 			host = (zbx_lld_host_t *)hosts->values[i];
967 
968 			if (FAIL == (i = zbx_vector_uint64_bsearch(&host->new_groupids, groupid,
969 					ZBX_DEFAULT_UINT64_COMPARE_FUNC)))
970 			{
971 				/* host groups which should be unlinked */
972 				ZBX_STR2UINT64(hostgroupid, row[2]);
973 				zbx_vector_uint64_append(del_hostgroupids, hostgroupid);
974 			}
975 			else
976 			{
977 				/* host groups which are already added */
978 				zbx_vector_uint64_remove(&host->new_groupids, i);
979 			}
980 		}
981 		DBfree_result(result);
982 
983 		zbx_vector_uint64_sort(del_hostgroupids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
984 	}
985 
986 	zbx_vector_uint64_destroy(&hostids);
987 
988 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
989 }
990 
991 /******************************************************************************
992  *                                                                            *
993  * Function: lld_group_prototypes_get                                         *
994  *                                                                            *
995  * Purpose: retrieve list of group prototypes                                 *
996  *                                                                            *
997  * Parameters: parent_hostid    - [IN] host prototype identifier              *
998  *             group_prototypes - [OUT] sorted list of group prototypes       *
999  *                                                                            *
1000  ******************************************************************************/
lld_group_prototypes_get(zbx_uint64_t parent_hostid,zbx_vector_ptr_t * group_prototypes)1001 static void	lld_group_prototypes_get(zbx_uint64_t parent_hostid, zbx_vector_ptr_t *group_prototypes)
1002 {
1003 	DB_RESULT			result;
1004 	DB_ROW				row;
1005 	zbx_lld_group_prototype_t	*group_prototype;
1006 
1007 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1008 
1009 	result = DBselect(
1010 			"select group_prototypeid,name"
1011 			" from group_prototype"
1012 			" where groupid is null"
1013 				" and hostid=" ZBX_FS_UI64,
1014 			parent_hostid);
1015 
1016 	while (NULL != (row = DBfetch(result)))
1017 	{
1018 		group_prototype = (zbx_lld_group_prototype_t *)zbx_malloc(NULL, sizeof(zbx_lld_group_prototype_t));
1019 
1020 		ZBX_STR2UINT64(group_prototype->group_prototypeid, row[0]);
1021 		group_prototype->name = zbx_strdup(NULL, row[1]);
1022 
1023 		zbx_vector_ptr_append(group_prototypes, group_prototype);
1024 	}
1025 	DBfree_result(result);
1026 
1027 	zbx_vector_ptr_sort(group_prototypes, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
1028 
1029 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1030 }
1031 
1032 /******************************************************************************
1033  *                                                                            *
1034  * Function: lld_groups_get                                                   *
1035  *                                                                            *
1036  * Purpose: retrieves existing groups for the specified host prototype        *
1037  *                                                                            *
1038  * Parameters: parent_hostid - [IN] host prototype identifier                 *
1039  *             groups        - [OUT] list of groups                           *
1040  *                                                                            *
1041  ******************************************************************************/
lld_groups_get(zbx_uint64_t parent_hostid,zbx_vector_ptr_t * groups)1042 static void	lld_groups_get(zbx_uint64_t parent_hostid, zbx_vector_ptr_t *groups)
1043 {
1044 	DB_RESULT	result;
1045 	DB_ROW		row;
1046 	zbx_lld_group_t	*group;
1047 
1048 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1049 
1050 	result = DBselect(
1051 			"select gd.groupid,gp.group_prototypeid,gd.name,gd.lastcheck,gd.ts_delete,g.name"
1052 			" from group_prototype gp,group_discovery gd"
1053 				" join hstgrp g"
1054 					" on gd.groupid=g.groupid"
1055 			" where gp.group_prototypeid=gd.parent_group_prototypeid"
1056 				" and gp.hostid=" ZBX_FS_UI64,
1057 			parent_hostid);
1058 
1059 	while (NULL != (row = DBfetch(result)))
1060 	{
1061 		group = (zbx_lld_group_t *)zbx_malloc(NULL, sizeof(zbx_lld_group_t));
1062 
1063 		ZBX_STR2UINT64(group->groupid, row[0]);
1064 		ZBX_STR2UINT64(group->group_prototypeid, row[1]);
1065 		zbx_vector_ptr_create(&group->hosts);
1066 		group->name_proto = zbx_strdup(NULL, row[2]);
1067 		group->lastcheck = atoi(row[3]);
1068 		group->ts_delete = atoi(row[4]);
1069 		group->name = zbx_strdup(NULL, row[5]);
1070 		group->name_orig = NULL;
1071 		group->flags = 0x00;
1072 
1073 		zbx_vector_ptr_append(groups, group);
1074 	}
1075 	DBfree_result(result);
1076 
1077 	zbx_vector_ptr_sort(groups, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
1078 
1079 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1080 }
1081 
1082 /******************************************************************************
1083  *                                                                            *
1084  * Function: lld_group_make                                                   *
1085  *                                                                            *
1086  ******************************************************************************/
lld_group_make(zbx_vector_ptr_t * groups,zbx_uint64_t group_prototypeid,const char * name_proto,const struct zbx_json_parse * jp_row,const zbx_vector_ptr_t * lld_macros)1087 static zbx_lld_group_t	*lld_group_make(zbx_vector_ptr_t *groups, zbx_uint64_t group_prototypeid,
1088 		const char *name_proto, const struct zbx_json_parse *jp_row, const zbx_vector_ptr_t *lld_macros)
1089 {
1090 	char		*buffer = NULL;
1091 	int		i, group_found = 0;
1092 	zbx_lld_group_t	*group = NULL;
1093 
1094 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1095 
1096 	for (i = 0; i < groups->values_num; i++)
1097 	{
1098 		group = (zbx_lld_group_t *)groups->values[i];
1099 
1100 		if (group->group_prototypeid != group_prototypeid)
1101 			continue;
1102 
1103 		if (0 != (group->flags & ZBX_FLAG_LLD_GROUP_DISCOVERED))
1104 			continue;
1105 
1106 		buffer = zbx_strdup(buffer, group->name_proto);
1107 		substitute_lld_macros(&buffer, jp_row, lld_macros, ZBX_MACRO_ANY, NULL, 0);
1108 		zbx_lrtrim(buffer, ZBX_WHITESPACE);
1109 
1110 		if (0 == strcmp(group->name, buffer))
1111 		{
1112 			group_found = 1;
1113 			break;
1114 		}
1115 	}
1116 
1117 	if (0 == group_found)
1118 	{
1119 		/* trying to find an already existing group */
1120 
1121 		buffer = zbx_strdup(buffer, name_proto);
1122 		substitute_lld_macros(&buffer, jp_row, lld_macros, ZBX_MACRO_ANY, NULL, 0);
1123 		zbx_lrtrim(buffer, ZBX_WHITESPACE);
1124 
1125 		for (i = 0; i < groups->values_num; i++)
1126 		{
1127 			group = (zbx_lld_group_t *)groups->values[i];
1128 
1129 			if (group->group_prototypeid != group_prototypeid)
1130 				continue;
1131 
1132 			if (0 == (group->flags & ZBX_FLAG_LLD_GROUP_DISCOVERED))
1133 				continue;
1134 
1135 			if (0 == strcmp(group->name, buffer))
1136 				goto out;
1137 		}
1138 
1139 		/* otherwise create a new group */
1140 
1141 		group = (zbx_lld_group_t *)zbx_malloc(NULL, sizeof(zbx_lld_group_t));
1142 
1143 		group->groupid = 0;
1144 		group->group_prototypeid = group_prototypeid;
1145 		zbx_vector_ptr_create(&group->hosts);
1146 		group->name_proto = NULL;
1147 		group->name = zbx_strdup(NULL, name_proto);
1148 		substitute_lld_macros(&group->name, jp_row, lld_macros, ZBX_MACRO_ANY, NULL, 0);
1149 		zbx_lrtrim(group->name, ZBX_WHITESPACE);
1150 		group->name_orig = NULL;
1151 		group->lastcheck = 0;
1152 		group->ts_delete = 0;
1153 		group->flags = 0x00;
1154 		group->flags = ZBX_FLAG_LLD_GROUP_DISCOVERED;
1155 
1156 		zbx_vector_ptr_append(groups, group);
1157 	}
1158 	else
1159 	{
1160 		/* update an already existing group */
1161 
1162 		/* group name */
1163 		buffer = zbx_strdup(buffer, name_proto);
1164 		substitute_lld_macros(&buffer, jp_row, lld_macros, ZBX_MACRO_ANY, NULL, 0);
1165 		zbx_lrtrim(buffer, ZBX_WHITESPACE);
1166 		if (0 != strcmp(group->name, buffer))
1167 		{
1168 			group->name_orig = group->name;
1169 			group->name = buffer;
1170 			buffer = NULL;
1171 			group->flags |= ZBX_FLAG_LLD_GROUP_UPDATE_NAME;
1172 		}
1173 
1174 		group->flags |= ZBX_FLAG_LLD_GROUP_DISCOVERED;
1175 	}
1176 out:
1177 	zbx_free(buffer);
1178 
1179 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%p", __func__, (void *)group);
1180 
1181 	return group;
1182 }
1183 
1184 /******************************************************************************
1185  *                                                                            *
1186  * Function: lld_groups_make                                                  *
1187  *                                                                            *
1188  ******************************************************************************/
lld_groups_make(zbx_lld_host_t * host,zbx_vector_ptr_t * groups,const zbx_vector_ptr_t * group_prototypes,const struct zbx_json_parse * jp_row,const zbx_vector_ptr_t * lld_macros)1189 static void	lld_groups_make(zbx_lld_host_t *host, zbx_vector_ptr_t *groups, const zbx_vector_ptr_t *group_prototypes,
1190 		const struct zbx_json_parse *jp_row, const zbx_vector_ptr_t *lld_macros)
1191 {
1192 	int	i;
1193 
1194 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1195 
1196 	for (i = 0; i < group_prototypes->values_num; i++)
1197 	{
1198 		const zbx_lld_group_prototype_t	*group_prototype;
1199 		zbx_lld_group_t			*group;
1200 
1201 		group_prototype = (zbx_lld_group_prototype_t *)group_prototypes->values[i];
1202 
1203 		group = lld_group_make(groups, group_prototype->group_prototypeid, group_prototype->name, jp_row,
1204 				lld_macros);
1205 
1206 		zbx_vector_ptr_append(&group->hosts, host);
1207 	}
1208 
1209 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1210 }
1211 
1212 /******************************************************************************
1213  *                                                                            *
1214  * Function: lld_validate_group_name                                          *
1215  *                                                                            *
1216  * Purpose: validate group name                                               *
1217  *                                                                            *
1218  * Return value: SUCCEED - the group name is valid                            *
1219  *               FAIL    - otherwise                                          *
1220  *                                                                            *
1221  ******************************************************************************/
lld_validate_group_name(const char * name)1222 static int	lld_validate_group_name(const char *name)
1223 {
1224 	/* group name cannot be empty */
1225 	if ('\0' == *name)
1226 		return FAIL;
1227 
1228 	/* group name must contain valid utf8 characters */
1229 	if (SUCCEED != zbx_is_utf8(name))
1230 		return FAIL;
1231 
1232 	/* group name cannot exceed field limits */
1233 	if (GROUP_NAME_LEN < zbx_strlen_utf8(name))
1234 		return FAIL;
1235 
1236 	/* group name cannot contain trailing and leading slashes (/) */
1237 	if ('/' == *name || '/' == name[strlen(name) - 1])
1238 		return FAIL;
1239 
1240 	/* group name cannot contain several slashes (/) in a row */
1241 	if (NULL != strstr(name, "//"))
1242 		return FAIL;
1243 
1244 	return SUCCEED;
1245 }
1246 
1247 /******************************************************************************
1248  *                                                                            *
1249  * Function: lld_groups_validate                                              *
1250  *                                                                            *
1251  * Parameters: groups - [IN] list of groups; should be sorted by groupid      *
1252  *                                                                            *
1253  ******************************************************************************/
lld_groups_validate(zbx_vector_ptr_t * groups,char ** error)1254 static void	lld_groups_validate(zbx_vector_ptr_t *groups, char **error)
1255 {
1256 	DB_RESULT		result;
1257 	DB_ROW			row;
1258 	int			i, j;
1259 	zbx_lld_group_t		*group, *group_b;
1260 	zbx_vector_uint64_t	groupids;
1261 	zbx_vector_str_t	names;
1262 
1263 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1264 
1265 	zbx_vector_uint64_create(&groupids);
1266 	zbx_vector_str_create(&names);		/* list of group names */
1267 
1268 	/* checking a group name validity */
1269 	for (i = 0; i < groups->values_num; i++)
1270 	{
1271 		group = (zbx_lld_group_t *)groups->values[i];
1272 
1273 		if (0 == (group->flags & ZBX_FLAG_LLD_GROUP_DISCOVERED))
1274 			continue;
1275 
1276 		/* only new groups or groups with changed group name will be validated */
1277 		if (0 != group->groupid && 0 == (group->flags & ZBX_FLAG_LLD_GROUP_UPDATE_NAME))
1278 			continue;
1279 
1280 		if (SUCCEED == lld_validate_group_name(group->name))
1281 			continue;
1282 
1283 		zbx_replace_invalid_utf8(group->name);
1284 		*error = zbx_strdcatf(*error, "Cannot %s group: invalid group name \"%s\".\n",
1285 				(0 != group->groupid ? "update" : "create"), group->name);
1286 
1287 		if (0 != group->groupid)
1288 		{
1289 			lld_field_str_rollback(&group->name, &group->name_orig, &group->flags,
1290 					ZBX_FLAG_LLD_GROUP_UPDATE_NAME);
1291 		}
1292 		else
1293 			group->flags &= ~ZBX_FLAG_LLD_GROUP_DISCOVERED;
1294 	}
1295 
1296 	/* checking duplicated group names */
1297 	for (i = 0; i < groups->values_num; i++)
1298 	{
1299 		group = (zbx_lld_group_t *)groups->values[i];
1300 
1301 		if (0 == (group->flags & ZBX_FLAG_LLD_GROUP_DISCOVERED))
1302 			continue;
1303 
1304 		/* only new groups or groups with changed group name will be validated */
1305 		if (0 != group->groupid && 0 == (group->flags & ZBX_FLAG_LLD_GROUP_UPDATE_NAME))
1306 			continue;
1307 
1308 		for (j = 0; j < groups->values_num; j++)
1309 		{
1310 			group_b = (zbx_lld_group_t *)groups->values[j];
1311 
1312 			if (0 == (group_b->flags & ZBX_FLAG_LLD_GROUP_DISCOVERED) || i == j)
1313 				continue;
1314 
1315 			if (0 != strcmp(group->name, group_b->name))
1316 				continue;
1317 
1318 			*error = zbx_strdcatf(*error, "Cannot %s group:"
1319 					" group with the same name \"%s\" already exists.\n",
1320 					(0 != group->groupid ? "update" : "create"), group->name);
1321 
1322 			if (0 != group->groupid)
1323 			{
1324 				lld_field_str_rollback(&group->name, &group->name_orig, &group->flags,
1325 						ZBX_FLAG_LLD_GROUP_UPDATE_NAME);
1326 			}
1327 			else
1328 				group->flags &= ~ZBX_FLAG_LLD_GROUP_DISCOVERED;
1329 		}
1330 	}
1331 
1332 	/* checking duplicated group names and group names in DB */
1333 
1334 	for (i = 0; i < groups->values_num; i++)
1335 	{
1336 		group = (zbx_lld_group_t *)groups->values[i];
1337 
1338 		if (0 == (group->flags & ZBX_FLAG_LLD_GROUP_DISCOVERED))
1339 			continue;
1340 
1341 		if (0 != group->groupid)
1342 			zbx_vector_uint64_append(&groupids, group->groupid);
1343 
1344 		if (0 == group->groupid || 0 != (group->flags & ZBX_FLAG_LLD_GROUP_UPDATE_NAME))
1345 			zbx_vector_str_append(&names, group->name);
1346 	}
1347 
1348 	if (0 != names.values_num)
1349 	{
1350 		char	*sql = NULL;
1351 		size_t	sql_alloc = 0, sql_offset = 0;
1352 
1353 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "select name from hstgrp where");
1354 		DBadd_str_condition_alloc(&sql, &sql_alloc, &sql_offset, "name",
1355 				(const char **)names.values, names.values_num);
1356 
1357 		if (0 != groupids.values_num)
1358 		{
1359 			zbx_vector_uint64_sort(&groupids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
1360 			zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " and not");
1361 			DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "groupid",
1362 					groupids.values, groupids.values_num);
1363 		}
1364 
1365 		result = DBselect("%s", sql);
1366 
1367 		while (NULL != (row = DBfetch(result)))
1368 		{
1369 			for (i = 0; i < groups->values_num; i++)
1370 			{
1371 				group = (zbx_lld_group_t *)groups->values[i];
1372 
1373 				if (0 == (group->flags & ZBX_FLAG_LLD_GROUP_DISCOVERED))
1374 					continue;
1375 
1376 				if (0 == strcmp(group->name, row[0]))
1377 				{
1378 					*error = zbx_strdcatf(*error, "Cannot %s group:"
1379 							" group with the same name \"%s\" already exists.\n",
1380 							(0 != group->groupid ? "update" : "create"), group->name);
1381 
1382 					if (0 != group->groupid)
1383 					{
1384 						lld_field_str_rollback(&group->name, &group->name_orig, &group->flags,
1385 								ZBX_FLAG_LLD_GROUP_UPDATE_NAME);
1386 					}
1387 					else
1388 						group->flags &= ~ZBX_FLAG_LLD_GROUP_DISCOVERED;
1389 				}
1390 			}
1391 		}
1392 		DBfree_result(result);
1393 
1394 		zbx_free(sql);
1395 	}
1396 
1397 	zbx_vector_str_destroy(&names);
1398 	zbx_vector_uint64_destroy(&groupids);
1399 
1400 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1401 }
1402 
1403 /******************************************************************************
1404  *                                                                            *
1405  * Function: lld_group_rights_compare                                         *
1406  *                                                                            *
1407  * Purpose: sorting function to sort group rights vector by name              *
1408  *                                                                            *
1409  ******************************************************************************/
lld_group_rights_compare(const void * d1,const void * d2)1410 static int	lld_group_rights_compare(const void *d1, const void *d2)
1411 {
1412 	const zbx_lld_group_rights_t	*r1 = *(const zbx_lld_group_rights_t **)d1;
1413 	const zbx_lld_group_rights_t	*r2 = *(const zbx_lld_group_rights_t **)d2;
1414 
1415 	return strcmp(r1->name, r2->name);
1416 }
1417 
1418 /******************************************************************************
1419  *                                                                            *
1420  * Function: lld_group_rights_append                                          *
1421  *                                                                            *
1422  * Purpose: append a new item to group rights vector                          *
1423  *                                                                            *
1424  * Return value: Index of the added item.                                     *
1425  *                                                                            *
1426  ******************************************************************************/
lld_group_rights_append(zbx_vector_ptr_t * group_rights,const char * name)1427 static int	lld_group_rights_append(zbx_vector_ptr_t *group_rights, const char *name)
1428 {
1429 	zbx_lld_group_rights_t	*rights;
1430 
1431 	rights = (zbx_lld_group_rights_t *)zbx_malloc(NULL, sizeof(zbx_lld_group_rights_t));
1432 	rights->name = zbx_strdup(NULL, name);
1433 	zbx_vector_uint64_pair_create(&rights->rights);
1434 	rights->prights = NULL;
1435 
1436 	zbx_vector_ptr_append(group_rights, rights);
1437 
1438 	return group_rights->values_num - 1;
1439 }
1440 
1441 /******************************************************************************
1442  *                                                                            *
1443  * Function: lld_group_rights_free                                            *
1444  *                                                                            *
1445  * PUrpose: frees group rights data                                           *
1446  *                                                                            *
1447  ******************************************************************************/
lld_group_rights_free(zbx_lld_group_rights_t * rights)1448 static void	lld_group_rights_free(zbx_lld_group_rights_t *rights)
1449 {
1450 	zbx_free(rights->name);
1451 	zbx_vector_uint64_pair_destroy(&rights->rights);
1452 	zbx_free(rights);
1453 }
1454 
1455 /******************************************************************************
1456  *                                                                            *
1457  * Function: lld_groups_save_rights                                           *
1458  *                                                                            *
1459  * Parameters: groups - [IN] list of new groups                               *
1460  *                                                                            *
1461  ******************************************************************************/
lld_groups_save_rights(zbx_vector_ptr_t * groups)1462 static void	lld_groups_save_rights(zbx_vector_ptr_t *groups)
1463 {
1464 	int			i, j;
1465 	DB_ROW			row;
1466 	DB_RESULT		result;
1467 	char			*ptr, *name, *sql = NULL;
1468 	size_t			sql_alloc = 0, sql_offset = 0, offset;
1469 	zbx_lld_group_t		*group;
1470 	zbx_vector_str_t	group_names;
1471 	zbx_vector_ptr_t	group_rights;
1472 	zbx_db_insert_t		db_insert;
1473 	zbx_lld_group_rights_t	*rights, rights_local, *parent_rights;
1474 	zbx_uint64_pair_t	pair;
1475 
1476 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1477 
1478 	zbx_vector_str_create(&group_names);
1479 	zbx_vector_ptr_create(&group_rights);
1480 
1481 	/* make a list of direct parent group names and a list of new group rights */
1482 	for (i = 0; i < groups->values_num; i++)
1483 	{
1484 		group = (zbx_lld_group_t *)groups->values[i];
1485 
1486 		if (NULL == (ptr = strrchr(group->name, '/')))
1487 			continue;
1488 
1489 		lld_group_rights_append(&group_rights, group->name);
1490 
1491 		name = zbx_strdup(NULL, group->name);
1492 		name[ptr - group->name] = '\0';
1493 
1494 		if (FAIL != zbx_vector_str_search(&group_names, name, ZBX_DEFAULT_STR_COMPARE_FUNC))
1495 		{
1496 			zbx_free(name);
1497 			continue;
1498 		}
1499 
1500 		zbx_vector_str_append(&group_names, name);
1501 	}
1502 
1503 	if (0 == group_names.values_num)
1504 		goto out;
1505 
1506 	/* read the parent group rights */
1507 
1508 	zbx_db_insert_prepare(&db_insert, "rights", "rightid", "id", "permission", "groupid", NULL);
1509 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
1510 			"select g.name,r.permission,r.groupid from hstgrp g,rights r"
1511 				" where r.id=g.groupid"
1512 				" and");
1513 
1514 	DBadd_str_condition_alloc(&sql, &sql_alloc, &sql_offset, "g.name", (const char **)group_names.values,
1515 			group_names.values_num);
1516 	result = DBselect("%s", sql);
1517 
1518 	while (NULL != (row = DBfetch(result)))
1519 	{
1520 		rights_local.name = row[0];
1521 		if (FAIL == (i = zbx_vector_ptr_search(&group_rights, &rights_local, lld_group_rights_compare)))
1522 			i = lld_group_rights_append(&group_rights, row[0]);
1523 
1524 		rights = (zbx_lld_group_rights_t *)group_rights.values[i];
1525 		rights->prights = &rights->rights;
1526 
1527 		ZBX_STR2UINT64(pair.first, row[2]);
1528 		pair.second = atoi(row[1]);
1529 
1530 		zbx_vector_uint64_pair_append(&rights->rights, pair);
1531 	}
1532 	DBfree_result(result);
1533 
1534 	zbx_vector_ptr_sort(&group_rights, lld_group_rights_compare);
1535 
1536 	/* assign rights for the new groups */
1537 	for (i = 0; i < group_rights.values_num; i++)
1538 	{
1539 		rights = (zbx_lld_group_rights_t *)group_rights.values[i];
1540 
1541 		if (NULL != rights->prights)
1542 			continue;
1543 
1544 		if (NULL == (ptr = strrchr(rights->name, '/')))
1545 			continue;
1546 
1547 		offset = ptr - rights->name;
1548 
1549 		for (j = 0; j < i; j++)
1550 		{
1551 			parent_rights = (zbx_lld_group_rights_t *)group_rights.values[j];
1552 
1553 			if (strlen(parent_rights->name) != offset)
1554 				continue;
1555 
1556 			if (0 != strncmp(parent_rights->name, rights->name, offset))
1557 				continue;
1558 
1559 			rights->prights = parent_rights->prights;
1560 			break;
1561 		}
1562 	}
1563 
1564 	/* save rights for the new groups */
1565 	for (i = 0; i < groups->values_num; i++)
1566 	{
1567 		group = (zbx_lld_group_t *)groups->values[i];
1568 
1569 		rights_local.name = group->name;
1570 		if (FAIL == (j = zbx_vector_ptr_bsearch(&group_rights, &rights_local, lld_group_rights_compare)))
1571 			continue;
1572 
1573 		rights = (zbx_lld_group_rights_t *)group_rights.values[j];
1574 
1575 		if (NULL == rights->prights)
1576 			continue;
1577 
1578 		for (j = 0; j < rights->prights->values_num; j++)
1579 		{
1580 			zbx_db_insert_add_values(&db_insert, __UINT64_C(0), group->groupid,
1581 					(int)rights->prights->values[j].second, rights->prights->values[j].first);
1582 		}
1583 	}
1584 
1585 	zbx_db_insert_autoincrement(&db_insert, "rightid");
1586 	zbx_db_insert_execute(&db_insert);
1587 	zbx_db_insert_clean(&db_insert);
1588 
1589 	zbx_free(sql);
1590 	zbx_vector_ptr_clear_ext(&group_rights, (zbx_clean_func_t)lld_group_rights_free);
1591 	zbx_vector_str_clear_ext(&group_names, zbx_str_free);
1592 out:
1593 	zbx_vector_ptr_destroy(&group_rights);
1594 	zbx_vector_str_destroy(&group_names);
1595 
1596 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1597 }
1598 
1599 /******************************************************************************
1600  *                                                                            *
1601  * Function: lld_groups_save                                                  *
1602  *                                                                            *
1603  * Parameters: groups           - [IN/OUT] list of groups; should be sorted   *
1604  *                                         by groupid                         *
1605  *             group_prototypes - [IN] list of group prototypes; should be    *
1606  *                                     sorted by group_prototypeid            *
1607  *                                                                            *
1608  ******************************************************************************/
lld_groups_save(zbx_vector_ptr_t * groups,const zbx_vector_ptr_t * group_prototypes)1609 static void	lld_groups_save(zbx_vector_ptr_t *groups, const zbx_vector_ptr_t *group_prototypes)
1610 {
1611 	int				i, j, upd_groups_num = 0;
1612 	zbx_lld_group_t			*group;
1613 	const zbx_lld_group_prototype_t	*group_prototype;
1614 	zbx_lld_host_t			*host;
1615 	zbx_uint64_t			groupid = 0;
1616 	char				*sql = NULL, *name_esc, *name_proto_esc;
1617 	size_t				sql_alloc = 0, sql_offset = 0;
1618 	zbx_db_insert_t			db_insert, db_insert_gdiscovery;
1619 	zbx_vector_ptr_t		new_groups;
1620 	zbx_vector_uint64_t		new_group_prototype_ids;
1621 
1622 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1623 
1624 	zbx_vector_uint64_create(&new_group_prototype_ids);
1625 
1626 	for (i = 0; i < groups->values_num; i++)
1627 	{
1628 		group = (zbx_lld_group_t *)groups->values[i];
1629 
1630 		if (0 == (group->flags & ZBX_FLAG_LLD_GROUP_DISCOVERED))
1631 			continue;
1632 
1633 		if (0 == group->groupid)
1634 			zbx_vector_uint64_append(&new_group_prototype_ids, group->group_prototypeid);
1635 		else if (0 != (group->flags & ZBX_FLAG_LLD_GROUP_UPDATE))
1636 			upd_groups_num++;
1637 	}
1638 
1639 	if (0 == new_group_prototype_ids.values_num && 0 == upd_groups_num)
1640 		goto out;
1641 
1642 	DBbegin();
1643 
1644 	if (0 != new_group_prototype_ids.values_num)
1645 	{
1646 		if (SUCCEED != DBlock_group_prototypeids(&new_group_prototype_ids))
1647 		{
1648 			/* the host group prototype was removed while processing lld rule */
1649 			DBrollback();
1650 			goto out;
1651 		}
1652 
1653 		groupid = DBget_maxid_num("hstgrp", new_group_prototype_ids.values_num);
1654 
1655 		zbx_db_insert_prepare(&db_insert, "hstgrp", "groupid", "name", "flags", NULL);
1656 
1657 		zbx_db_insert_prepare(&db_insert_gdiscovery, "group_discovery", "groupid", "parent_group_prototypeid",
1658 				"name", NULL);
1659 
1660 		zbx_vector_ptr_create(&new_groups);
1661 	}
1662 
1663 	if (0 != upd_groups_num)
1664 	{
1665 		DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset);
1666 	}
1667 
1668 	for (i = 0; i < groups->values_num; i++)
1669 	{
1670 		group = (zbx_lld_group_t *)groups->values[i];
1671 
1672 		if (0 == (group->flags & ZBX_FLAG_LLD_GROUP_DISCOVERED))
1673 			continue;
1674 
1675 		if (0 == group->groupid)
1676 		{
1677 			group->groupid = groupid++;
1678 
1679 			zbx_db_insert_add_values(&db_insert, group->groupid, group->name,
1680 					(int)ZBX_FLAG_DISCOVERY_CREATED);
1681 
1682 			if (FAIL != (j = zbx_vector_ptr_bsearch(group_prototypes, &group->group_prototypeid,
1683 					ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
1684 			{
1685 				group_prototype = (zbx_lld_group_prototype_t *)group_prototypes->values[j];
1686 
1687 				zbx_db_insert_add_values(&db_insert_gdiscovery, group->groupid,
1688 						group->group_prototypeid, group_prototype->name);
1689 			}
1690 			else
1691 				THIS_SHOULD_NEVER_HAPPEN;
1692 
1693 			for (j = 0; j < group->hosts.values_num; j++)
1694 			{
1695 				host = (zbx_lld_host_t *)group->hosts.values[j];
1696 
1697 				/* hosts will be linked to a new host groups */
1698 				zbx_vector_uint64_append(&host->new_groupids, group->groupid);
1699 			}
1700 
1701 			zbx_vector_ptr_append(&new_groups, group);
1702 		}
1703 		else
1704 		{
1705 			if (0 != (group->flags & ZBX_FLAG_LLD_GROUP_UPDATE))
1706 			{
1707 				zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "update hstgrp set ");
1708 				if (0 != (group->flags & ZBX_FLAG_LLD_GROUP_UPDATE_NAME))
1709 				{
1710 					name_esc = DBdyn_escape_string(group->name);
1711 
1712 					zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "name='%s'", name_esc);
1713 
1714 					zbx_free(name_esc);
1715 				}
1716 				zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
1717 						" where groupid=" ZBX_FS_UI64 ";\n", group->groupid);
1718 			}
1719 
1720 			if (0 != (group->flags & ZBX_FLAG_LLD_GROUP_UPDATE_NAME))
1721 			{
1722 				if (FAIL != (j = zbx_vector_ptr_bsearch(group_prototypes, &group->group_prototypeid,
1723 						ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
1724 				{
1725 					group_prototype = (zbx_lld_group_prototype_t *)group_prototypes->values[j];
1726 
1727 					name_proto_esc = DBdyn_escape_string(group_prototype->name);
1728 
1729 					zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
1730 							"update group_discovery"
1731 							" set name='%s'"
1732 							" where groupid=" ZBX_FS_UI64 ";\n",
1733 							name_proto_esc, group->groupid);
1734 
1735 					zbx_free(name_proto_esc);
1736 				}
1737 				else
1738 					THIS_SHOULD_NEVER_HAPPEN;
1739 			}
1740 		}
1741 	}
1742 
1743 	if (0 != upd_groups_num)
1744 	{
1745 		DBend_multiple_update(&sql, &sql_alloc, &sql_offset);
1746 		DBexecute("%s", sql);
1747 		zbx_free(sql);
1748 	}
1749 
1750 	if (0 != new_group_prototype_ids.values_num)
1751 	{
1752 		zbx_db_insert_execute(&db_insert);
1753 		zbx_db_insert_clean(&db_insert);
1754 
1755 		zbx_db_insert_execute(&db_insert_gdiscovery);
1756 		zbx_db_insert_clean(&db_insert_gdiscovery);
1757 
1758 		lld_groups_save_rights(&new_groups);
1759 		zbx_vector_ptr_destroy(&new_groups);
1760 	}
1761 
1762 	DBcommit();
1763 out:
1764 	zbx_vector_uint64_destroy(&new_group_prototype_ids);
1765 
1766 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1767 }
1768 
1769 /******************************************************************************
1770  *                                                                            *
1771  * Function: lld_masterhostmacros_get                                         *
1772  *                                                                            *
1773  * Purpose: retrieve list of host macros which should be present on the each  *
1774  *          discovered host                                                   *
1775  *                                                                            *
1776  * Parameters: hostmacros - [OUT] list of host macros                         *
1777  *                                                                            *
1778  ******************************************************************************/
lld_masterhostmacros_get(zbx_uint64_t lld_ruleid,zbx_vector_ptr_t * hostmacros)1779 static void	lld_masterhostmacros_get(zbx_uint64_t lld_ruleid, zbx_vector_ptr_t *hostmacros)
1780 {
1781 	DB_RESULT		result;
1782 	DB_ROW			row;
1783 	zbx_lld_hostmacro_t	*hostmacro;
1784 
1785 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1786 
1787 	result = DBselect(
1788 			"select hm.macro,hm.value,hm.description,hm.type"
1789 			" from hostmacro hm,items i"
1790 			" where hm.hostid=i.hostid"
1791 				" and i.itemid=" ZBX_FS_UI64,
1792 			lld_ruleid);
1793 
1794 	while (NULL != (row = DBfetch(result)))
1795 	{
1796 		hostmacro = (zbx_lld_hostmacro_t *)zbx_malloc(NULL, sizeof(zbx_lld_hostmacro_t));
1797 
1798 		hostmacro->macro = zbx_strdup(NULL, row[0]);
1799 		hostmacro->value = zbx_strdup(NULL, row[1]);
1800 		hostmacro->description = zbx_strdup(NULL, row[2]);
1801 		ZBX_STR2UCHAR(hostmacro->type, row[3]);
1802 
1803 		zbx_vector_ptr_append(hostmacros, hostmacro);
1804 	}
1805 	DBfree_result(result);
1806 
1807 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1808 }
1809 
1810 /******************************************************************************
1811  *                                                                            *
1812  * Function: macro_str_compare_func                                           *
1813  *                                                                            *
1814  * Purpose: compare the name of host macros for search in vector              *
1815  *                                                                            *
1816  * Parameters: d1 - [IN] first zbx_lld_hostmacro_t                            *
1817  *             d2 - [IN] second zbx_lld_hostmacro_t                           *
1818  *                                                                            *
1819  * Return value: 0 if name of macros are equal                                *
1820  *                                                                            *
1821  ******************************************************************************/
macro_str_compare_func(const void * d1,const void * d2)1822 static int	macro_str_compare_func(const void *d1, const void *d2)
1823 {
1824 	const zbx_lld_hostmacro_t *hostmacro1 = *(const zbx_lld_hostmacro_t **)d1;
1825 	const zbx_lld_hostmacro_t *hostmacro2 = *(const zbx_lld_hostmacro_t **)d2;
1826 
1827 	return strcmp(hostmacro1->macro, hostmacro2->macro);
1828 }
1829 
1830 /******************************************************************************
1831  *                                                                            *
1832  * Function: lld_hostmacros_get                                               *
1833  *                                                                            *
1834  * Purpose: retrieve list of host macros which should be present on the each  *
1835  *          discovered host                                                   *
1836  *                                                                            *
1837  * Parameters: parent_hostid    - [IN] host prototype id                      *
1838  *             masterhostmacros - [IN] list of master host macros             *
1839  *             hostmacros       - [OUT] list of host macros                   *
1840  *                                                                            *
1841  ******************************************************************************/
lld_hostmacros_get(zbx_uint64_t parent_hostid,zbx_vector_ptr_t * masterhostmacros,zbx_vector_ptr_t * hostmacros)1842 static void	lld_hostmacros_get(zbx_uint64_t parent_hostid, zbx_vector_ptr_t *masterhostmacros,
1843 		zbx_vector_ptr_t *hostmacros)
1844 {
1845 	DB_RESULT		result;
1846 	DB_ROW			row;
1847 	zbx_lld_hostmacro_t	*hostmacro;
1848 	int			i;
1849 
1850 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1851 
1852 	result = DBselect(
1853 			"select hm.macro,hm.value,hm.description,hm.type"
1854 			" from hostmacro hm"
1855 			" where hm.hostid=" ZBX_FS_UI64,
1856 			parent_hostid);
1857 
1858 	while (NULL != (row = DBfetch(result)))
1859 	{
1860 		hostmacro = (zbx_lld_hostmacro_t *)zbx_malloc(NULL, sizeof(zbx_lld_hostmacro_t));
1861 
1862 		hostmacro->macro = zbx_strdup(NULL, row[0]);
1863 		hostmacro->value = zbx_strdup(NULL, row[1]);
1864 		hostmacro->description = zbx_strdup(NULL, row[2]);
1865 		ZBX_STR2UCHAR(hostmacro->type, row[3]);
1866 
1867 		zbx_vector_ptr_append(hostmacros, hostmacro);
1868 	}
1869 	DBfree_result(result);
1870 
1871 	for (i = 0; i < masterhostmacros->values_num; i++)
1872 	{
1873 		const zbx_lld_hostmacro_t	*masterhostmacro;
1874 
1875 		if (FAIL != zbx_vector_ptr_search(hostmacros, masterhostmacros->values[i], macro_str_compare_func))
1876 			continue;
1877 
1878 		hostmacro = (zbx_lld_hostmacro_t *)zbx_malloc(NULL, sizeof(zbx_lld_hostmacro_t));
1879 
1880 		masterhostmacro = (const zbx_lld_hostmacro_t *)masterhostmacros->values[i];
1881 		hostmacro->macro = zbx_strdup(NULL, masterhostmacro->macro);
1882 		hostmacro->value = zbx_strdup(NULL, masterhostmacro->value);
1883 		hostmacro->description = zbx_strdup(NULL, masterhostmacro->description);
1884 		hostmacro->type = masterhostmacro->type;
1885 
1886 		zbx_vector_ptr_append(hostmacros, hostmacro);
1887 	}
1888 
1889 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1890 }
1891 
1892 /******************************************************************************
1893  *                                                                            *
1894  * Function: lld_hostmacro_make                                               *
1895  *                                                                            *
1896  ******************************************************************************/
lld_hostmacro_make(zbx_vector_ptr_t * hostmacros,zbx_uint64_t hostmacroid,const char * macro,const char * value,const char * description,unsigned char type)1897 static void	lld_hostmacro_make(zbx_vector_ptr_t *hostmacros, zbx_uint64_t hostmacroid, const char *macro,
1898 		const char *value, const char *description, unsigned char type)
1899 {
1900 	zbx_lld_hostmacro_t	*hostmacro;
1901 	int			i;
1902 
1903 	for (i = 0; i < hostmacros->values_num; i++)
1904 	{
1905 		hostmacro = (zbx_lld_hostmacro_t *)hostmacros->values[i];
1906 
1907 		/* check if host macro has already been added */
1908 		if (0 == hostmacro->hostmacroid && 0 == strcmp(hostmacro->macro, macro))
1909 		{
1910 			hostmacro->hostmacroid = hostmacroid;
1911 			if (0 != strcmp(hostmacro->value, value))
1912 				hostmacro->flags |= ZBX_FLAG_LLD_HOSTMACRO_UPDATE_VALUE;
1913 			if (0 != strcmp(hostmacro->description, description))
1914 				hostmacro->flags |= ZBX_FLAG_LLD_HOSTMACRO_UPDATE_DESCRIPTION;
1915 			if (hostmacro->type != type)
1916 				hostmacro->flags |= ZBX_FLAG_LLD_HOSTMACRO_UPDATE_TYPE;
1917 			return;
1918 		}
1919 	}
1920 
1921 	/* host macro is present on the host but not in new list, it should be removed */
1922 	hostmacro = (zbx_lld_hostmacro_t *)zbx_malloc(NULL, sizeof(zbx_lld_hostmacro_t));
1923 	hostmacro->hostmacroid = hostmacroid;
1924 	hostmacro->macro = NULL;
1925 	hostmacro->value = NULL;
1926 	hostmacro->description = NULL;
1927 	hostmacro->flags = ZBX_FLAG_LLD_HOSTMACRO_REMOVE;
1928 
1929 	zbx_vector_ptr_append(hostmacros, hostmacro);
1930 }
1931 
1932 /******************************************************************************
1933  *                                                                            *
1934  * Function: lld_hostmacros_make                                              *
1935  *                                                                            *
1936  * Parameters: hostmacros       - [IN] list of host macros which              *
1937  *                                     should be present on the each          *
1938  *                                     discovered host                        *
1939  *             hosts            - [IN/OUT] list of hosts                      *
1940  *                                         should be sorted by hostid         *
1941  *             del_hostmacroids - [OUT] list of host macros which should be   *
1942  *                                      deleted                               *
1943  *                                                                            *
1944  ******************************************************************************/
lld_hostmacros_make(const zbx_vector_ptr_t * hostmacros,zbx_vector_ptr_t * hosts,const zbx_vector_ptr_t * lld_macros)1945 static void	lld_hostmacros_make(const zbx_vector_ptr_t *hostmacros, zbx_vector_ptr_t *hosts,
1946 		const zbx_vector_ptr_t *lld_macros)
1947 {
1948 	DB_RESULT		result;
1949 	DB_ROW			row;
1950 	int			i, j;
1951 	zbx_vector_uint64_t	hostids;
1952 	zbx_uint64_t		hostmacroid, hostid;
1953 	zbx_lld_host_t		*host;
1954 	zbx_lld_hostmacro_t	*hostmacro = NULL;
1955 
1956 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1957 
1958 	zbx_vector_uint64_create(&hostids);
1959 
1960 	for (i = 0; i < hosts->values_num; i++)
1961 	{
1962 		host = (zbx_lld_host_t *)hosts->values[i];
1963 
1964 		if (0 == (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
1965 			continue;
1966 
1967 		zbx_vector_ptr_reserve(&host->new_hostmacros, hostmacros->values_num);
1968 		for (j = 0; j < hostmacros->values_num; j++)
1969 		{
1970 			hostmacro = (zbx_lld_hostmacro_t *)zbx_malloc(NULL, sizeof(zbx_lld_hostmacro_t));
1971 
1972 			hostmacro->hostmacroid = 0;
1973 			hostmacro->macro = zbx_strdup(NULL, ((zbx_lld_hostmacro_t *)hostmacros->values[j])->macro);
1974 			hostmacro->value = zbx_strdup(NULL, ((zbx_lld_hostmacro_t *)hostmacros->values[j])->value);
1975 			hostmacro->type = ((zbx_lld_hostmacro_t *)hostmacros->values[j])->type;
1976 			hostmacro->description = zbx_strdup(NULL,
1977 					((zbx_lld_hostmacro_t *)hostmacros->values[j])->description);
1978 			hostmacro->flags = 0x00;
1979 			substitute_lld_macros(&hostmacro->value, host->jp_row, lld_macros, ZBX_MACRO_ANY, NULL, 0);
1980 			substitute_lld_macros(&hostmacro->description, host->jp_row, lld_macros, ZBX_MACRO_ANY, NULL, 0);
1981 
1982 			zbx_vector_ptr_append(&host->new_hostmacros, hostmacro);
1983 		}
1984 
1985 		if (0 != host->hostid)
1986 			zbx_vector_uint64_append(&hostids, host->hostid);
1987 	}
1988 
1989 	if (0 != hostids.values_num)
1990 	{
1991 		char	*sql = NULL;
1992 		size_t	sql_alloc = 0, sql_offset = 0;
1993 
1994 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
1995 				"select hostmacroid,hostid,macro,value,description,type"
1996 				" from hostmacro"
1997 				" where");
1998 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid", hostids.values, hostids.values_num);
1999 
2000 		result = DBselect("%s", sql);
2001 
2002 		zbx_free(sql);
2003 
2004 		while (NULL != (row = DBfetch(result)))
2005 		{
2006 			unsigned char	type;
2007 
2008 			ZBX_STR2UINT64(hostid, row[1]);
2009 
2010 			if (FAIL == (i = zbx_vector_ptr_bsearch(hosts, &hostid, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
2011 			{
2012 				THIS_SHOULD_NEVER_HAPPEN;
2013 				continue;
2014 			}
2015 
2016 			host = (zbx_lld_host_t *)hosts->values[i];
2017 
2018 			ZBX_STR2UINT64(hostmacroid, row[0]);
2019 			ZBX_STR2UCHAR(type, row[5]);
2020 
2021 			lld_hostmacro_make(&host->new_hostmacros, hostmacroid, row[2], row[3], row[4], type);
2022 		}
2023 		DBfree_result(result);
2024 	}
2025 
2026 	zbx_vector_uint64_destroy(&hostids);
2027 
2028 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
2029 }
2030 
2031 /******************************************************************************
2032  *                                                                            *
2033  * Function: lld_tags_get                                                     *
2034  *                                                                            *
2035  * Purpose: retrieve list of host tags which should be present on the each    *
2036  *          discovered host                                                   *
2037  *                                                                            *
2038  * Parameters: parent_hostid - [IN] host prototype id                         *
2039  *             tags          - [OUT] list of host tags                        *
2040  *                                                                            *
2041  ******************************************************************************/
lld_proto_tags_get(zbx_uint64_t parent_hostid,zbx_vector_db_tag_ptr_t * tags)2042 static void	lld_proto_tags_get(zbx_uint64_t parent_hostid, zbx_vector_db_tag_ptr_t *tags)
2043 {
2044 	DB_RESULT	result;
2045 	DB_ROW		row;
2046 	zbx_db_tag_t	*tag;
2047 
2048 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
2049 
2050 	result = DBselect(
2051 			"select tag,value"
2052 			" from host_tag"
2053 			" where hostid=" ZBX_FS_UI64,
2054 			parent_hostid);
2055 
2056 	while (NULL != (row = DBfetch(result)))
2057 	{
2058 		tag = (zbx_db_tag_t *)zbx_malloc(NULL, sizeof(zbx_db_tag_t));
2059 
2060 		tag->tag = zbx_strdup(NULL, row[0]);
2061 		tag->value = zbx_strdup(NULL, row[1]);
2062 
2063 		zbx_vector_db_tag_ptr_append(tags, tag);
2064 	}
2065 	DBfree_result(result);
2066 
2067 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
2068 }
2069 
2070 /******************************************************************************
2071  *                                                                            *
2072  * Function: lld_tag_validate_field                                           *
2073  *                                                                            *
2074  * Purpose: validate host tag field                                           *
2075  *                                                                            *
2076  * Parameters: name      - [IN] the field name (tag, value)                   *
2077  *             field     - [IN] the field value                               *
2078  *             field_len - [IN] the field length                              *
2079  *             info      - [OUT] error information                            *
2080  *                                                                            *
2081  ******************************************************************************/
lld_tag_validate_field(const char * name,const char * field,size_t field_len,char ** info)2082 static int	lld_tag_validate_field(const char *name, const char *field, size_t field_len, char **info)
2083 {
2084 	if (SUCCEED != zbx_is_utf8(field))
2085 	{
2086 		char	*field_utf8;
2087 
2088 		field_utf8 = zbx_strdup(NULL, field);
2089 		zbx_replace_invalid_utf8(field_utf8);
2090 		*info = zbx_strdcatf(*info, "Cannot create host tag: %s \"%s\" has invalid UTF-8 sequence.\n",
2091 				name, field_utf8);
2092 		zbx_free(field_utf8);
2093 		return FAIL;
2094 	}
2095 
2096 	if (zbx_strlen_utf8(field) > field_len)
2097 	{
2098 		*info = zbx_strdcatf(*info, "Cannot create host tag: %s \"%128s...\" is too long.\n", name, field);
2099 		return FAIL;
2100 	}
2101 
2102 	return SUCCEED;
2103 }
2104 
2105 /******************************************************************************
2106  *                                                                            *
2107  * Function: lld_tag_validate                                                 *
2108  *                                                                            *
2109  * Purpose: validate host tag                                                 *
2110  *                                                                            *
2111  * Parameters: tags     - [IN] the current host tags                          *
2112  *             tags_num - [IN] the number of host tags                        *
2113  *             name     - [IN] the new tag name                               *
2114  *             value    - [IN] the new tag value                              *
2115  *             info     - [OUT] error information                             *
2116  *                                                                            *
2117  ******************************************************************************/
lld_tag_validate(zbx_db_tag_t ** tags,int tags_num,const char * name,const char * value,char ** info)2118 static int	lld_tag_validate(zbx_db_tag_t **tags, int tags_num, const char *name, const char *value, char **info)
2119 {
2120 	int	i;
2121 
2122 	if ('\0' == *name)
2123 	{
2124 		*info = zbx_strdcatf(*info, "Cannot create host tag: empty tag name.\n");
2125 		return FAIL;
2126 	}
2127 
2128 	if (SUCCEED != lld_tag_validate_field("name", name, TAG_NAME_LEN, info))
2129 		return FAIL;
2130 
2131 	if (SUCCEED != lld_tag_validate_field("value", value, TAG_VALUE_LEN, info))
2132 		return FAIL;
2133 
2134 	for (i = 0; i < tags_num; i++)
2135 	{
2136 		if (0 == strcmp(tags[i]->tag, name) && 0 == strcmp(tags[i]->value, value))
2137 		{
2138 			*info = zbx_strdcatf(*info, "Cannot create host tag: tag \"%s\",\"%s\" already exists.\n",
2139 					name, value);
2140 
2141 			return FAIL;
2142 		}
2143 	}
2144 
2145 	return SUCCEED;
2146 }
2147 
2148 /******************************************************************************
2149  *                                                                            *
2150  * Function: lld_host_update_tags                                             *
2151  *                                                                            *
2152  * Purpose: update host tags                                                  *
2153  *                                                                            *
2154  * Parameters: host       - [IN] a host with existing tags, sorted by tag +   *
2155  *                               value.                                       *
2156  *                        - [OUT] a host with updated tags, sorted by tagid   *
2157  *             tags       - [IN] the new tags, sorted by tag + value          *
2158  *             lld_macros - [IN] a vector of LLD macros                       *
2159  *             info       - [OUT] error information                           *
2160  *                                                                            *
2161  * Comments: No database changes are made if host tags are equal to the new   *
2162  *           tags. Otherwise the tags are updated starting with the first not *
2163  *           matching tag. If there are more host tags than new tags then the *
2164  *           extra host tags are marked for removal. If there are more new    *
2165  *           tags than host tags, then new tags are appended to the host tags.*
2166  *                                                                            *
2167  ******************************************************************************/
lld_host_update_tags(zbx_lld_host_t * host,const zbx_vector_db_tag_ptr_t * tags,const zbx_vector_ptr_t * lld_macros,char ** info)2168 static void	lld_host_update_tags(zbx_lld_host_t *host, const zbx_vector_db_tag_ptr_t *tags,
2169 		const zbx_vector_ptr_t *lld_macros, char **info)
2170 {
2171 	int			i;
2172 	zbx_db_tag_t		*host_tag, *proto_tag;
2173 	zbx_vector_db_tag_ptr_t	new_tags;
2174 	char			*tag = NULL, *value = NULL;
2175 
2176 	zbx_vector_db_tag_ptr_create(&new_tags);
2177 
2178 	/* create vector of new tags with expanded lld macros */
2179 	for (i = 0; i < tags->values_num; i++)
2180 	{
2181 		proto_tag = (zbx_db_tag_t *)tags->values[i];
2182 
2183 		tag = zbx_strdup(tag, proto_tag->tag);
2184 		value = zbx_strdup(value, proto_tag->value);
2185 		substitute_lld_macros(&tag, host->jp_row, lld_macros, ZBX_MACRO_FUNC, NULL, 0);
2186 		substitute_lld_macros(&value, host->jp_row, lld_macros, ZBX_MACRO_FUNC, NULL, 0);
2187 
2188 		if (SUCCEED != lld_tag_validate(new_tags.values, new_tags.values_num, tag, value, info))
2189 			continue;
2190 
2191 		proto_tag = (zbx_db_tag_t *)zbx_malloc(NULL, sizeof(zbx_db_tag_t));
2192 		proto_tag->tag = tag;
2193 		proto_tag->value = value;
2194 		zbx_vector_db_tag_ptr_append(&new_tags, proto_tag);
2195 
2196 		tag = NULL;
2197 		value = NULL;
2198 	}
2199 
2200 	zbx_vector_db_tag_ptr_sort(&new_tags, zbx_db_tag_compare_func);
2201 
2202 	zbx_vector_db_tag_ptr_reserve(&host->tags, new_tags.values_num);
2203 
2204 	/* update host tags or flag them for removal */
2205 	for (i = 0; i < host->tags.values_num; i++)
2206 	{
2207 		host_tag = (zbx_db_tag_t *)host->tags.values[i];
2208 		if (i < new_tags.values_num)
2209 		{
2210 			proto_tag = (zbx_db_tag_t *)new_tags.values[i];
2211 
2212 			if (0 != strcmp(host_tag->tag, proto_tag->tag))
2213 			{
2214 				host_tag->tag = zbx_strdup(host_tag->tag, proto_tag->tag);
2215 				host_tag->flags |= ZBX_FLAG_DB_TAG_UPDATE_TAG;
2216 			}
2217 
2218 			if (0 != strcmp(host_tag->value, proto_tag->value))
2219 			{
2220 				host_tag->value = zbx_strdup(host_tag->value, proto_tag->value);
2221 				host_tag->flags |= ZBX_FLAG_DB_TAG_UPDATE_VALUE;
2222 			}
2223 		}
2224 		else
2225 			host_tag->flags = ZBX_FLAG_DB_TAG_REMOVE;
2226 	}
2227 
2228 	/* add missing tags */
2229 	if (i < new_tags.values_num)
2230 	{
2231 		int	j;
2232 
2233 		/* set uninitialized properties of new tags that will be moved to host */
2234 		for (j = i; j < new_tags.values_num; j++)
2235 		{
2236 			proto_tag = (zbx_db_tag_t *)new_tags.values[j];
2237 			proto_tag->tagid = 0;
2238 			proto_tag->flags = 0;
2239 		}
2240 
2241 		zbx_vector_db_tag_ptr_append_array(&host->tags, new_tags.values + i, new_tags.values_num - i);
2242 		new_tags.values_num = i;
2243 	}
2244 
2245 	zbx_free(tag);
2246 	zbx_free(value);
2247 
2248 	/* sort existing tags by their ids for update operations */
2249 	zbx_vector_db_tag_ptr_sort(&host->tags, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
2250 
2251 	zbx_vector_db_tag_ptr_clear_ext(&new_tags, zbx_db_tag_free);
2252 	zbx_vector_db_tag_ptr_destroy(&new_tags);
2253 }
2254 
2255 /******************************************************************************
2256  *                                                                            *
2257  * Function: lld_templates_make                                               *
2258  *                                                                            *
2259  * Purpose: gets templates from a host prototype                              *
2260  *                                                                            *
2261  * Parameters: parent_hostid - [IN] host prototype identifier                 *
2262  *             hosts         - [IN/OUT] list of hosts                         *
2263  *                                      should be sorted by hostid            *
2264  *                                                                            *
2265  ******************************************************************************/
lld_templates_make(zbx_uint64_t parent_hostid,zbx_vector_ptr_t * hosts)2266 static void	lld_templates_make(zbx_uint64_t parent_hostid, zbx_vector_ptr_t *hosts)
2267 {
2268 	DB_RESULT		result;
2269 	DB_ROW			row;
2270 	zbx_vector_uint64_t	templateids, hostids;
2271 	zbx_uint64_t		templateid, hostid;
2272 	zbx_lld_host_t		*host;
2273 	int			i, j;
2274 
2275 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
2276 
2277 	zbx_vector_uint64_create(&templateids);
2278 	zbx_vector_uint64_create(&hostids);
2279 
2280 	/* select templates which should be linked */
2281 
2282 	result = DBselect("select templateid from hosts_templates where hostid=" ZBX_FS_UI64, parent_hostid);
2283 
2284 	while (NULL != (row = DBfetch(result)))
2285 	{
2286 		ZBX_STR2UINT64(templateid, row[0]);
2287 		zbx_vector_uint64_append(&templateids, templateid);
2288 	}
2289 	DBfree_result(result);
2290 
2291 	zbx_vector_uint64_sort(&templateids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
2292 
2293 	/* select list of already created hosts */
2294 
2295 	for (i = 0; i < hosts->values_num; i++)
2296 	{
2297 		host = (zbx_lld_host_t *)hosts->values[i];
2298 
2299 		if (0 == (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
2300 			continue;
2301 
2302 		zbx_vector_uint64_reserve(&host->lnk_templateids, templateids.values_num);
2303 		for (j = 0; j < templateids.values_num; j++)
2304 			zbx_vector_uint64_append(&host->lnk_templateids, templateids.values[j]);
2305 
2306 		/* sort templates which should be linked by override */
2307 		zbx_vector_uint64_sort(&host->lnk_templateids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
2308 		zbx_vector_uint64_uniq(&host->lnk_templateids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
2309 
2310 		if (0 != host->hostid)
2311 			zbx_vector_uint64_append(&hostids, host->hostid);
2312 	}
2313 
2314 	if (0 != hostids.values_num)
2315 	{
2316 		char	*sql = NULL;
2317 		size_t	sql_alloc = 0, sql_offset = 0;
2318 
2319 		/* select already linked temlates */
2320 
2321 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
2322 				"select hostid,templateid"
2323 				" from hosts_templates"
2324 				" where");
2325 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid", hostids.values, hostids.values_num);
2326 
2327 		result = DBselect("%s", sql);
2328 
2329 		zbx_free(sql);
2330 
2331 		while (NULL != (row = DBfetch(result)))
2332 		{
2333 			ZBX_STR2UINT64(hostid, row[0]);
2334 			ZBX_STR2UINT64(templateid, row[1]);
2335 
2336 			if (FAIL == (i = zbx_vector_ptr_bsearch(hosts, &hostid, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
2337 			{
2338 				THIS_SHOULD_NEVER_HAPPEN;
2339 				continue;
2340 			}
2341 
2342 			host = (zbx_lld_host_t *)hosts->values[i];
2343 
2344 			if (FAIL == (i = zbx_vector_uint64_bsearch(&host->lnk_templateids, templateid,
2345 					ZBX_DEFAULT_UINT64_COMPARE_FUNC)))
2346 			{
2347 				/* templates which should be unlinked */
2348 				zbx_vector_uint64_append(&host->del_templateids, templateid);
2349 			}
2350 			else
2351 			{
2352 				/* templates which are already linked */
2353 				zbx_vector_uint64_remove(&host->lnk_templateids, i);
2354 			}
2355 		}
2356 		DBfree_result(result);
2357 
2358 		for (i = 0; i < hosts->values_num; i++)
2359 		{
2360 			host = (zbx_lld_host_t *)hosts->values[i];
2361 
2362 			if (0 == (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
2363 				continue;
2364 
2365 			zbx_vector_uint64_sort(&host->del_templateids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
2366 		}
2367 	}
2368 
2369 	zbx_vector_uint64_destroy(&hostids);
2370 	zbx_vector_uint64_destroy(&templateids);
2371 
2372 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
2373 }
2374 
2375 /******************************************************************************
2376  *                                                                            *
2377  * Function: lld_interface_snmp_prepare_sql                                   *
2378  *                                                                            *
2379  * Purpose: prepare sql for update record of interface_snmp table             *
2380  *                                                                            *
2381  * Parameters: interfaceid - [IN] snmp interface id;                          *
2382  *             snmp        - [IN] snmp values for update                      *
2383  *             sql         - [IN/OUT] sql string                              *
2384  *             sql_alloc   - [IN/OUT] size of sql string                      *
2385  *             sql_offset  - [IN/OUT] offset in sql string                    *
2386  *                                                                            *
2387  ******************************************************************************/
lld_interface_snmp_prepare_sql(const zbx_uint64_t interfaceid,const zbx_lld_interface_snmp_t * snmp,char ** sql,size_t * sql_alloc,size_t * sql_offset)2388 static void	lld_interface_snmp_prepare_sql(const zbx_uint64_t interfaceid, const zbx_lld_interface_snmp_t *snmp,
2389 		char **sql, size_t *sql_alloc, size_t *sql_offset)
2390 {
2391 	const char	*d = "";
2392 	char		*value_esc;
2393 
2394 	zbx_strcpy_alloc(sql, sql_alloc, sql_offset, "update interface_snmp set ");
2395 
2396 	if (0 != (snmp->flags & ZBX_FLAG_LLD_INTERFACE_SNMP_UPDATE_TYPE))
2397 	{
2398 		zbx_snprintf_alloc(sql, sql_alloc, sql_offset, "version=%d", (int)snmp->version);
2399 		d = ",";
2400 	}
2401 
2402 	if (0 != (snmp->flags & ZBX_FLAG_LLD_INTERFACE_SNMP_UPDATE_BULK))
2403 	{
2404 		zbx_snprintf_alloc(sql, sql_alloc, sql_offset, "%sbulk=%d", d, (int)snmp->bulk);
2405 		d = ",";
2406 	}
2407 
2408 	if (0 != (snmp->flags & ZBX_FLAG_LLD_INTERFACE_SNMP_UPDATE_COMMUNITY))
2409 	{
2410 		value_esc = DBdyn_escape_string(snmp->community);
2411 		zbx_snprintf_alloc(sql, sql_alloc, sql_offset, "%scommunity='%s'", d, value_esc);
2412 		zbx_free(value_esc);
2413 		d = ",";
2414 	}
2415 
2416 	if (0 != (snmp->flags & ZBX_FLAG_LLD_INTERFACE_SNMP_UPDATE_SECNAME))
2417 	{
2418 		value_esc = DBdyn_escape_string(snmp->securityname);
2419 		zbx_snprintf_alloc(sql, sql_alloc, sql_offset, "%ssecurityname='%s'", d, value_esc);
2420 		zbx_free(value_esc);
2421 		d = ",";
2422 	}
2423 
2424 	if (0 != (snmp->flags & ZBX_FLAG_LLD_INTERFACE_SNMP_UPDATE_SECLEVEL))
2425 	{
2426 		zbx_snprintf_alloc(sql, sql_alloc, sql_offset, "%ssecuritylevel=%d", d, (int)snmp->securitylevel);
2427 		d = ",";
2428 	}
2429 
2430 	if (0 != (snmp->flags & ZBX_FLAG_LLD_INTERFACE_SNMP_UPDATE_AUTHPASS))
2431 	{
2432 		value_esc = DBdyn_escape_string(snmp->authpassphrase);
2433 		zbx_snprintf_alloc(sql, sql_alloc, sql_offset, "%sauthpassphrase='%s'", d, value_esc);
2434 		zbx_free(value_esc);
2435 		d = ",";
2436 	}
2437 
2438 	if (0 != (snmp->flags & ZBX_FLAG_LLD_INTERFACE_SNMP_UPDATE_PRIVPASS))
2439 	{
2440 		value_esc = DBdyn_escape_string(snmp->privpassphrase);
2441 		zbx_snprintf_alloc(sql, sql_alloc, sql_offset, "%sprivpassphrase='%s'", d, value_esc);
2442 		zbx_free(value_esc);
2443 		d = ",";
2444 	}
2445 
2446 	if (0 != (snmp->flags & ZBX_FLAG_LLD_INTERFACE_SNMP_UPDATE_AUTHPROTOCOL))
2447 	{
2448 		zbx_snprintf_alloc(sql, sql_alloc, sql_offset, "%sauthprotocol=%d", d, (int)snmp->authprotocol);
2449 		d = ",";
2450 	}
2451 
2452 	if (0 != (snmp->flags & ZBX_FLAG_LLD_INTERFACE_SNMP_UPDATE_PRIVPROTOCOL))
2453 	{
2454 		zbx_snprintf_alloc(sql, sql_alloc, sql_offset, "%sprivprotocol=%d", d, (int)snmp->privprotocol);
2455 		d = ",";
2456 	}
2457 
2458 	if (0 != (snmp->flags & ZBX_FLAG_LLD_INTERFACE_SNMP_UPDATE_CONTEXT))
2459 	{
2460 		value_esc = DBdyn_escape_string(snmp->contextname);
2461 		zbx_snprintf_alloc(sql, sql_alloc, sql_offset, "%scontextname='%s'", d, value_esc);
2462 		zbx_free(value_esc);
2463 	}
2464 
2465 	zbx_snprintf_alloc(sql, sql_alloc, sql_offset, " where interfaceid=" ZBX_FS_UI64 ";\n", interfaceid);
2466 }
2467 
2468 /******************************************************************************
2469  *                                                                            *
2470  * Function: lld_hosts_save                                                   *
2471  *                                                                            *
2472  * Parameters: parent_hostid    - [IN] parent host id                         *
2473  *             hosts            - [IN] list of hosts;                         *
2474  *             host_proto       - [IN] host proto                             *
2475  *             proxy_hostid     - [IN] proxy host id                          *
2476  *             ipmi_authtype    - [IN] ipmi authtype                          *
2477  *             ipmi_privilege   - [IN] ipmi privilege                         *
2478  *             ipmi_username    - [IN] ipmi username                          *
2479  *             ipmi_password    - [IN] ipmi password                          *
2480  *             status           - [IN] host status                            *
2481  *             inventory_mode   - [IN] host inventory mode                    *
2482  *             tls_connect      - [IN] tls connect                            *
2483  *             tls_accept       - [IN] tls accept                             *
2484  *             tls_issuer       - [IN] tls cert issuer                        *
2485  *             tls_subject      - [IN] tls cert subject                       *
2486  *             tls_psk_identity - [IN] tls psk identity                       *
2487  *             tls_psk          - [IN] tls psk                                *
2488  *             del_hostgroupids - [IN] host groups which should be deleted    *
2489  *                                                                            *
2490  ******************************************************************************/
lld_hosts_save(zbx_uint64_t parent_hostid,zbx_vector_ptr_t * hosts,const char * host_proto,zbx_uint64_t proxy_hostid,char ipmi_authtype,unsigned char ipmi_privilege,const char * ipmi_username,const char * ipmi_password,unsigned char tls_connect,unsigned char tls_accept,const char * tls_issuer,const char * tls_subject,const char * tls_psk_identity,const char * tls_psk,const zbx_vector_uint64_t * del_hostgroupids)2491 static void	lld_hosts_save(zbx_uint64_t parent_hostid, zbx_vector_ptr_t *hosts, const char *host_proto,
2492 		zbx_uint64_t proxy_hostid, char ipmi_authtype, unsigned char ipmi_privilege, const char *ipmi_username,
2493 		const char *ipmi_password, unsigned char tls_connect,
2494 		unsigned char tls_accept, const char *tls_issuer, const char *tls_subject, const char *tls_psk_identity,
2495 		const char *tls_psk, const zbx_vector_uint64_t *del_hostgroupids)
2496 {
2497 	int			i, j, new_hosts = 0, new_host_inventories = 0, upd_hosts = 0, new_hostgroups = 0,
2498 				new_hostmacros = 0, upd_hostmacros = 0, new_interfaces = 0, upd_interfaces = 0,
2499 				new_snmp = 0, upd_snmp = 0, new_tags = 0, upd_tags = 0;
2500 	zbx_lld_host_t		*host;
2501 	zbx_lld_hostmacro_t	*hostmacro;
2502 	zbx_lld_interface_t	*interface;
2503 	zbx_vector_uint64_t	upd_manual_host_inventory_hostids, upd_auto_host_inventory_hostids,
2504 				del_host_inventory_hostids, del_interfaceids,
2505 				del_snmp_ids, del_hostmacroids, del_tagids;
2506 	zbx_uint64_t		hostid = 0, hostgroupid = 0, hostmacroid = 0, interfaceid = 0;
2507 	char			*sql1 = NULL, *sql2 = NULL, *value_esc;
2508 	size_t			sql1_alloc = 0, sql1_offset = 0,
2509 				sql2_alloc = 0, sql2_offset = 0;
2510 	zbx_db_insert_t		db_insert, db_insert_hdiscovery, db_insert_hinventory, db_insert_hgroups,
2511 				db_insert_hmacro, db_insert_interface, db_insert_idiscovery, db_insert_snmp,
2512 				db_insert_tag;
2513 
2514 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
2515 
2516 	zbx_vector_uint64_create(&upd_manual_host_inventory_hostids);
2517 	zbx_vector_uint64_create(&upd_auto_host_inventory_hostids);
2518 	zbx_vector_uint64_create(&del_host_inventory_hostids);
2519 	zbx_vector_uint64_create(&del_interfaceids);
2520 	zbx_vector_uint64_create(&del_hostmacroids);
2521 	zbx_vector_uint64_create(&del_snmp_ids);
2522 	zbx_vector_uint64_create(&del_tagids);
2523 
2524 	for (i = 0; i < hosts->values_num; i++)
2525 	{
2526 		host = (zbx_lld_host_t *)hosts->values[i];
2527 
2528 		if (0 == (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
2529 			continue;
2530 
2531 		if (0 == host->hostid)
2532 		{
2533 			new_hosts++;
2534 			if (HOST_INVENTORY_DISABLED != host->inventory_mode)
2535 				new_host_inventories++;
2536 		}
2537 		else
2538 		{
2539 			if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE))
2540 				upd_hosts++;
2541 
2542 			if (host->inventory_mode_orig != host->inventory_mode)
2543 			{
2544 				if (HOST_INVENTORY_DISABLED == host->inventory_mode)
2545 					zbx_vector_uint64_append(&del_host_inventory_hostids, host->hostid);
2546 				else if (HOST_INVENTORY_DISABLED == host->inventory_mode_orig)
2547 					new_host_inventories++;
2548 				else
2549 				{
2550 					switch (host->inventory_mode)
2551 					{
2552 						case HOST_INVENTORY_MANUAL:
2553 							zbx_vector_uint64_append(&upd_manual_host_inventory_hostids,
2554 									host->hostid);
2555 							break;
2556 						case HOST_INVENTORY_AUTOMATIC:
2557 							zbx_vector_uint64_append(&upd_auto_host_inventory_hostids,
2558 									host->hostid);
2559 							break;
2560 					}
2561 				}
2562 			}
2563 		}
2564 
2565 		new_hostgroups += host->new_groupids.values_num;
2566 
2567 		for (j = 0; j < host->interfaces.values_num; j++)
2568 		{
2569 			interface = (zbx_lld_interface_t *)host->interfaces.values[j];
2570 
2571 			if (0 == interface->interfaceid)
2572 				new_interfaces++;
2573 			else if (0 != (interface->flags & ZBX_FLAG_LLD_INTERFACE_UPDATE))
2574 				upd_interfaces++;
2575 			else if (0 != (interface->flags & ZBX_FLAG_LLD_INTERFACE_REMOVE))
2576 				zbx_vector_uint64_append(&del_interfaceids, interface->interfaceid);
2577 
2578 			if (0 != (interface->flags & ZBX_FLAG_LLD_INTERFACE_SNMP_REMOVE))
2579 				zbx_vector_uint64_append(&del_snmp_ids, interface->interfaceid);
2580 
2581 			if (0 != (interface->flags & ZBX_FLAG_LLD_INTERFACE_SNMP_DATA_EXISTS))
2582 			{
2583 				if (0 == interface->interfaceid)
2584 					interface->data.snmp->flags |= ZBX_FLAG_LLD_INTERFACE_SNMP_CREATE;
2585 
2586 				if (0 != (interface->data.snmp->flags & ZBX_FLAG_LLD_INTERFACE_SNMP_CREATE))
2587 					new_snmp++;
2588 				else if (0 != (interface->data.snmp->flags & ZBX_FLAG_LLD_INTERFACE_SNMP_UPDATE))
2589 					upd_snmp++;
2590 			}
2591 		}
2592 
2593 		for (j = 0; j < host->new_hostmacros.values_num; j++)
2594 		{
2595 			hostmacro = (zbx_lld_hostmacro_t *)host->new_hostmacros.values[j];
2596 
2597 			if (0 == hostmacro->hostmacroid)
2598 				new_hostmacros++;
2599 			else if (0 != (hostmacro->flags & ZBX_FLAG_LLD_HOSTMACRO_UPDATE))
2600 				upd_hostmacros++;
2601 			else if (0 != (hostmacro->flags & ZBX_FLAG_LLD_HOSTMACRO_REMOVE))
2602 				zbx_vector_uint64_append(&del_hostmacroids, hostmacro->hostmacroid);
2603 		}
2604 
2605 		for (j = 0; j < host->tags.values_num; j++)
2606 		{
2607 			if (0 == host->tags.values[j]->tagid)
2608 				new_tags++;
2609 			else if (0 != (host->tags.values[j]->flags & ZBX_FLAG_DB_TAG_UPDATE))
2610 				upd_tags++;
2611 			else if (0 != (host->tags.values[j]->flags & ZBX_FLAG_DB_TAG_REMOVE))
2612 				zbx_vector_uint64_append(&del_tagids, host->tags.values[j]->tagid);
2613 		}
2614 	}
2615 
2616 	if (0 == new_hosts && 0 == new_host_inventories && 0 == upd_hosts && 0 == upd_interfaces &&
2617 			0 == upd_hostmacros && 0 == new_hostgroups && 0 == new_hostmacros && 0 == new_interfaces &&
2618 			0 == del_hostgroupids->values_num && 0 == del_hostmacroids.values_num &&
2619 			0 == upd_auto_host_inventory_hostids.values_num &&
2620 			0 == upd_manual_host_inventory_hostids.values_num &&
2621 			0 == del_host_inventory_hostids.values_num && 0 == del_interfaceids.values_num &&
2622 			0 == new_snmp && 0 == upd_snmp && 0 == del_snmp_ids.values_num &&
2623 			0 == new_tags && 0 == upd_tags && 0 == del_tagids.values_num)
2624 	{
2625 		goto out;
2626 	}
2627 
2628 	DBbegin();
2629 
2630 	if (SUCCEED != DBlock_hostid(parent_hostid))
2631 	{
2632 		/* the host prototype was removed while processing lld rule */
2633 		DBrollback();
2634 		goto out;
2635 	}
2636 
2637 	if (0 != new_hosts)
2638 	{
2639 		hostid = DBget_maxid_num("hosts", new_hosts);
2640 
2641 		zbx_db_insert_prepare(&db_insert, "hosts", "hostid", "host", "name", "proxy_hostid", "ipmi_authtype",
2642 				"ipmi_privilege", "ipmi_username", "ipmi_password", "status", "flags", "tls_connect",
2643 				"tls_accept", "tls_issuer", "tls_subject", "tls_psk_identity", "tls_psk",
2644 				"custom_interfaces", NULL);
2645 
2646 		zbx_db_insert_prepare(&db_insert_hdiscovery, "host_discovery", "hostid", "parent_hostid", "host", NULL);
2647 	}
2648 
2649 	if (0 != new_host_inventories)
2650 	{
2651 		zbx_db_insert_prepare(&db_insert_hinventory, "host_inventory", "hostid", "inventory_mode", NULL);
2652 	}
2653 
2654 	if (0 != upd_hosts || 0 != upd_interfaces || 0 != upd_snmp || 0 != upd_hostmacros || 0 != upd_tags)
2655 	{
2656 		DBbegin_multiple_update(&sql1, &sql1_alloc, &sql1_offset);
2657 	}
2658 
2659 	if (0 != new_hostgroups)
2660 	{
2661 		hostgroupid = DBget_maxid_num("hosts_groups", new_hostgroups);
2662 
2663 		zbx_db_insert_prepare(&db_insert_hgroups, "hosts_groups", "hostgroupid", "hostid", "groupid", NULL);
2664 	}
2665 
2666 	if (0 != new_hostmacros)
2667 	{
2668 		hostmacroid = DBget_maxid_num("hostmacro", new_hostmacros);
2669 
2670 		zbx_db_insert_prepare(&db_insert_hmacro, "hostmacro", "hostmacroid", "hostid", "macro", "value",
2671 				"description", "type", NULL);
2672 	}
2673 
2674 	if (0 != new_interfaces)
2675 	{
2676 		interfaceid = DBget_maxid_num("interface", new_interfaces);
2677 
2678 		zbx_db_insert_prepare(&db_insert_interface, "interface", "interfaceid", "hostid", "type", "main",
2679 				"useip", "ip", "dns", "port", NULL);
2680 
2681 		zbx_db_insert_prepare(&db_insert_idiscovery, "interface_discovery", "interfaceid",
2682 				"parent_interfaceid", NULL);
2683 	}
2684 
2685 	if (0 != new_snmp)
2686 	{
2687 		zbx_db_insert_prepare(&db_insert_snmp, "interface_snmp", "interfaceid", "version", "bulk", "community",
2688 				"securityname", "securitylevel", "authpassphrase", "privpassphrase", "authprotocol",
2689 				"privprotocol", "contextname", NULL);
2690 	}
2691 
2692 	if (0 != new_tags)
2693 		zbx_db_insert_prepare(&db_insert_tag, "host_tag", "hosttagid", "hostid", "tag", "value", NULL);
2694 
2695 	for (i = 0; i < hosts->values_num; i++)
2696 	{
2697 		host = (zbx_lld_host_t *)hosts->values[i];
2698 
2699 		if (0 == (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
2700 			continue;
2701 
2702 		if (0 == host->hostid)
2703 		{
2704 			host->hostid = hostid++;
2705 
2706 			zbx_db_insert_add_values(&db_insert, host->hostid, host->host, host->name, proxy_hostid,
2707 					(int)ipmi_authtype, (int)ipmi_privilege, ipmi_username, ipmi_password,
2708 					(int)host->status, (int)ZBX_FLAG_DISCOVERY_CREATED, (int)tls_connect,
2709 					(int)tls_accept, tls_issuer, tls_subject, tls_psk_identity, tls_psk,
2710 					host->custom_interfaces);
2711 
2712 			zbx_db_insert_add_values(&db_insert_hdiscovery, host->hostid, parent_hostid, host_proto);
2713 
2714 			if (HOST_INVENTORY_DISABLED != host->inventory_mode)
2715 				zbx_db_insert_add_values(&db_insert_hinventory, host->hostid, (int)host->inventory_mode);
2716 		}
2717 		else
2718 		{
2719 			if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE))
2720 			{
2721 				const char	*d = "";
2722 
2723 				zbx_strcpy_alloc(&sql1, &sql1_alloc, &sql1_offset, "update hosts set ");
2724 				if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_HOST))
2725 				{
2726 					value_esc = DBdyn_escape_string(host->host);
2727 
2728 					zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, "host='%s'", value_esc);
2729 					d = ",";
2730 
2731 					zbx_free(value_esc);
2732 				}
2733 				if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_NAME))
2734 				{
2735 					value_esc = DBdyn_escape_string(host->name);
2736 
2737 					zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
2738 							"%sname='%s'", d, value_esc);
2739 					d = ",";
2740 
2741 					zbx_free(value_esc);
2742 				}
2743 				if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_PROXY))
2744 				{
2745 					zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
2746 							"%sproxy_hostid=%s", d, DBsql_id_ins(proxy_hostid));
2747 					d = ",";
2748 				}
2749 				if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_IPMI_AUTH))
2750 				{
2751 					zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
2752 							"%sipmi_authtype=%d", d, (int)ipmi_authtype);
2753 					d = ",";
2754 				}
2755 				if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_IPMI_PRIV))
2756 				{
2757 					zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
2758 							"%sipmi_privilege=%d", d, (int)ipmi_privilege);
2759 					d = ",";
2760 				}
2761 				if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_IPMI_USER))
2762 				{
2763 					value_esc = DBdyn_escape_string(ipmi_username);
2764 
2765 					zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
2766 							"%sipmi_username='%s'", d, value_esc);
2767 					d = ",";
2768 
2769 					zbx_free(value_esc);
2770 				}
2771 				if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_IPMI_PASS))
2772 				{
2773 					value_esc = DBdyn_escape_string(ipmi_password);
2774 
2775 					zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
2776 							"%sipmi_password='%s'", d, value_esc);
2777 					d = ",";
2778 
2779 					zbx_free(value_esc);
2780 				}
2781 				if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_TLS_CONNECT))
2782 				{
2783 					zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
2784 							"%stls_connect=%d", d, tls_connect);
2785 					d = ",";
2786 				}
2787 				if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_TLS_ACCEPT))
2788 				{
2789 					zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
2790 							"%stls_accept=%d", d, tls_accept);
2791 					d = ",";
2792 				}
2793 				if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_TLS_ISSUER))
2794 				{
2795 					value_esc = DBdyn_escape_string(tls_issuer);
2796 
2797 					zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
2798 							"%stls_issuer='%s'", d, value_esc);
2799 					d = ",";
2800 
2801 					zbx_free(value_esc);
2802 				}
2803 				if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_TLS_SUBJECT))
2804 				{
2805 					value_esc = DBdyn_escape_string(tls_subject);
2806 
2807 					zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
2808 							"%stls_subject='%s'", d, value_esc);
2809 					d = ",";
2810 
2811 					zbx_free(value_esc);
2812 				}
2813 				if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_TLS_PSK_IDENTITY))
2814 				{
2815 					value_esc = DBdyn_escape_string(tls_psk_identity);
2816 
2817 					zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
2818 							"%stls_psk_identity='%s'", d, value_esc);
2819 					d = ",";
2820 
2821 					zbx_free(value_esc);
2822 				}
2823 				if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_TLS_PSK))
2824 				{
2825 					value_esc = DBdyn_escape_string(tls_psk);
2826 
2827 					zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
2828 							"%stls_psk='%s'", d, value_esc);
2829 					d = ",";
2830 
2831 					zbx_free(value_esc);
2832 				}
2833 				if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_CUSTOM_INTERFACES))
2834 				{
2835 					zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
2836 							"%scustom_interfaces=%d", d, (int)host->custom_interfaces);
2837 				}
2838 				zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, " where hostid=" ZBX_FS_UI64 ";\n",
2839 						host->hostid);
2840 			}
2841 
2842 			if (host->inventory_mode_orig != host->inventory_mode &&
2843 					HOST_INVENTORY_DISABLED == host->inventory_mode_orig)
2844 			{
2845 				zbx_db_insert_add_values(&db_insert_hinventory, host->hostid, (int)host->inventory_mode);
2846 			}
2847 
2848 			if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_HOST))
2849 			{
2850 				value_esc = DBdyn_escape_string(host_proto);
2851 
2852 				zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
2853 						"update host_discovery"
2854 						" set host='%s'"
2855 						" where hostid=" ZBX_FS_UI64 ";\n",
2856 						value_esc, host->hostid);
2857 
2858 				zbx_free(value_esc);
2859 			}
2860 		}
2861 
2862 		for (j = 0; j < host->interfaces.values_num; j++)
2863 		{
2864 			interface = (zbx_lld_interface_t *)host->interfaces.values[j];
2865 
2866 			if (0 == interface->interfaceid)
2867 			{
2868 				interface->interfaceid = interfaceid++;
2869 
2870 				zbx_db_insert_add_values(&db_insert_interface, interface->interfaceid, host->hostid,
2871 						(int)interface->type, (int)interface->main, (int)interface->useip,
2872 						interface->ip, interface->dns, interface->port);
2873 
2874 				zbx_db_insert_add_values(&db_insert_idiscovery, interface->interfaceid,
2875 						interface->parent_interfaceid);
2876 			}
2877 			else if (0 != (interface->flags & ZBX_FLAG_LLD_INTERFACE_UPDATE))
2878 			{
2879 				const char	*d = "";
2880 
2881 				zbx_strcpy_alloc(&sql1, &sql1_alloc, &sql1_offset, "update interface set ");
2882 				if (0 != (interface->flags & ZBX_FLAG_LLD_INTERFACE_UPDATE_TYPE))
2883 				{
2884 					zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, "type=%d",
2885 							(int)interface->type);
2886 					d = ",";
2887 				}
2888 				if (0 != (interface->flags & ZBX_FLAG_LLD_INTERFACE_UPDATE_MAIN))
2889 				{
2890 					zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, "%smain=%d",
2891 							d, (int)interface->main);
2892 					d = ",";
2893 				}
2894 				if (0 != (interface->flags & ZBX_FLAG_LLD_INTERFACE_UPDATE_USEIP))
2895 				{
2896 					zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, "%suseip=%d",
2897 							d, (int)interface->useip);
2898 					d = ",";
2899 				}
2900 				if (0 != (interface->flags & ZBX_FLAG_LLD_INTERFACE_UPDATE_IP))
2901 				{
2902 					value_esc = DBdyn_escape_string(interface->ip);
2903 					zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, "%sip='%s'", d, value_esc);
2904 					zbx_free(value_esc);
2905 					d = ",";
2906 				}
2907 				if (0 != (interface->flags & ZBX_FLAG_LLD_INTERFACE_UPDATE_DNS))
2908 				{
2909 					value_esc = DBdyn_escape_string(interface->dns);
2910 					zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, "%sdns='%s'", d, value_esc);
2911 					zbx_free(value_esc);
2912 					d = ",";
2913 				}
2914 				if (0 != (interface->flags & ZBX_FLAG_LLD_INTERFACE_UPDATE_PORT))
2915 				{
2916 					value_esc = DBdyn_escape_string(interface->port);
2917 					zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, "%sport='%s'",
2918 							d, value_esc);
2919 					zbx_free(value_esc);
2920 				}
2921 				zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
2922 						" where interfaceid=" ZBX_FS_UI64 ";\n", interface->interfaceid);
2923 			}
2924 
2925 			if (0 != (interface->flags & ZBX_FLAG_LLD_INTERFACE_SNMP_DATA_EXISTS))
2926 			{
2927 				if (0 != (interface->data.snmp->flags & ZBX_FLAG_LLD_INTERFACE_SNMP_CREATE))
2928 				{
2929 					zbx_db_insert_add_values(&db_insert_snmp, interface->interfaceid,
2930 							(int)interface->data.snmp->version,
2931 							(int)interface->data.snmp->bulk,
2932 							interface->data.snmp->community,
2933 							interface->data.snmp->securityname,
2934 							(int)interface->data.snmp->securitylevel,
2935 							interface->data.snmp->authpassphrase,
2936 							interface->data.snmp->privpassphrase,
2937 							(int)interface->data.snmp->authprotocol,
2938 							(int)interface->data.snmp->privprotocol,
2939 							interface->data.snmp->contextname);
2940 				}
2941 				else if (0 != (interface->data.snmp->flags & ZBX_FLAG_LLD_INTERFACE_SNMP_UPDATE))
2942 				{
2943 					lld_interface_snmp_prepare_sql(interface->interfaceid, interface->data.snmp,
2944 							&sql1, &sql1_alloc, &sql1_offset);
2945 				}
2946 			}
2947 		}
2948 
2949 		for (j = 0; j < host->new_groupids.values_num; j++)
2950 		{
2951 			zbx_db_insert_add_values(&db_insert_hgroups, hostgroupid++, host->hostid,
2952 					host->new_groupids.values[j]);
2953 		}
2954 
2955 		for (j = 0; j < host->new_hostmacros.values_num; j++)
2956 		{
2957 			hostmacro = (zbx_lld_hostmacro_t *)host->new_hostmacros.values[j];
2958 
2959 			if (0 == hostmacro->hostmacroid)
2960 			{
2961 				zbx_db_insert_add_values(&db_insert_hmacro, hostmacroid++, host->hostid,
2962 						hostmacro->macro, hostmacro->value, hostmacro->description,
2963 						(int)hostmacro->type);
2964 			}
2965 			else if (0 != (hostmacro->flags & ZBX_FLAG_LLD_HOSTMACRO_UPDATE))
2966 			{
2967 				const char	*d = "";
2968 
2969 				zbx_strcpy_alloc(&sql1, &sql1_alloc, &sql1_offset, "update hostmacro set ");
2970 				if (0 != (hostmacro->flags & ZBX_FLAG_LLD_HOSTMACRO_UPDATE_VALUE))
2971 				{
2972 					value_esc = DBdyn_escape_string(hostmacro->value);
2973 					zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, "value='%s'", value_esc);
2974 					zbx_free(value_esc);
2975 					d = ",";
2976 				}
2977 				if (0 != (hostmacro->flags & ZBX_FLAG_LLD_HOSTMACRO_UPDATE_DESCRIPTION))
2978 				{
2979 					value_esc = DBdyn_escape_string(hostmacro->description);
2980 					zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, "%sdescription='%s'",
2981 							d, value_esc);
2982 					zbx_free(value_esc);
2983 					d = ",";
2984 				}
2985 				if (0 != (hostmacro->flags & ZBX_FLAG_LLD_HOSTMACRO_UPDATE_TYPE))
2986 				{
2987 					zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, "%stype=%d",
2988 							d, hostmacro->type);
2989 				}
2990 				zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
2991 						" where hostmacroid=" ZBX_FS_UI64 ";\n", hostmacro->hostmacroid);
2992 			}
2993 		}
2994 
2995 		for (j = 0; j < host->tags.values_num; j++)
2996 		{
2997 			zbx_db_tag_t	*tag = host->tags.values[j];
2998 
2999 			if (0 == tag->tagid)
3000 			{
3001 				zbx_db_insert_add_values(&db_insert_tag, __UINT64_C(0), host->hostid, tag->tag,
3002 						tag->value);
3003 			}
3004 			else if (0 != (tag->flags & ZBX_FLAG_DB_TAG_UPDATE))
3005 			{
3006 				char	delim = ' ';
3007 
3008 				zbx_strcpy_alloc(&sql1, &sql1_alloc, &sql1_offset, "update host_tag set");
3009 
3010 				if (0 != (tag->flags & ZBX_FLAG_DB_TAG_UPDATE_TAG))
3011 				{
3012 					value_esc = DBdyn_escape_string(tag->tag);
3013 					zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, "%ctag='%s'", delim,
3014 							value_esc);
3015 					zbx_free(value_esc);
3016 					delim = ',';
3017 				}
3018 
3019 				if (0 != (tag->flags & ZBX_FLAG_DB_TAG_UPDATE_VALUE))
3020 				{
3021 					value_esc = DBdyn_escape_string(tag->value);
3022 					zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, "%cvalue='%s'", delim,
3023 							value_esc);
3024 					zbx_free(value_esc);
3025 				}
3026 
3027 				zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
3028 						" where hosttagid=" ZBX_FS_UI64 ";\n", tag->tagid);
3029 			}
3030 		}
3031 	}
3032 
3033 	if (0 != new_hosts)
3034 	{
3035 		zbx_db_insert_execute(&db_insert);
3036 		zbx_db_insert_clean(&db_insert);
3037 
3038 		zbx_db_insert_execute(&db_insert_hdiscovery);
3039 		zbx_db_insert_clean(&db_insert_hdiscovery);
3040 	}
3041 
3042 	if (0 != new_host_inventories)
3043 	{
3044 		zbx_db_insert_execute(&db_insert_hinventory);
3045 		zbx_db_insert_clean(&db_insert_hinventory);
3046 	}
3047 
3048 	if (0 != new_hostgroups)
3049 	{
3050 		zbx_db_insert_execute(&db_insert_hgroups);
3051 		zbx_db_insert_clean(&db_insert_hgroups);
3052 	}
3053 
3054 	if (0 != new_hostmacros)
3055 	{
3056 		zbx_db_insert_execute(&db_insert_hmacro);
3057 		zbx_db_insert_clean(&db_insert_hmacro);
3058 	}
3059 
3060 	if (0 != new_interfaces)
3061 	{
3062 		zbx_db_insert_execute(&db_insert_interface);
3063 		zbx_db_insert_clean(&db_insert_interface);
3064 
3065 		zbx_db_insert_execute(&db_insert_idiscovery);
3066 		zbx_db_insert_clean(&db_insert_idiscovery);
3067 	}
3068 
3069 	if (0 != new_snmp)
3070 	{
3071 		zbx_db_insert_execute(&db_insert_snmp);
3072 		zbx_db_insert_clean(&db_insert_snmp);
3073 	}
3074 
3075 	if (0 != new_tags)
3076 	{
3077 		zbx_db_insert_autoincrement(&db_insert_tag, "hosttagid");
3078 		zbx_db_insert_execute(&db_insert_tag);
3079 		zbx_db_insert_clean(&db_insert_tag);
3080 	}
3081 
3082 	if (NULL != sql1)
3083 	{
3084 		DBend_multiple_update(&sql1, &sql1_alloc, &sql1_offset);
3085 
3086 		/* in ORACLE always present begin..end; */
3087 		if (16 < sql1_offset)
3088 			DBexecute("%s", sql1);
3089 
3090 		zbx_free(sql1);
3091 	}
3092 
3093 	if (0 != del_hostgroupids->values_num || 0 != del_hostmacroids.values_num ||
3094 			0 != upd_auto_host_inventory_hostids.values_num ||
3095 			0 != upd_manual_host_inventory_hostids.values_num ||
3096 			0 != del_host_inventory_hostids.values_num ||
3097 			0 != del_interfaceids.values_num || 0 != del_snmp_ids.values_num || 0 != del_tagids.values_num)
3098 	{
3099 		DBbegin_multiple_update(&sql2, &sql2_alloc, &sql2_offset);
3100 
3101 		if (0 != del_hostgroupids->values_num)
3102 		{
3103 			zbx_strcpy_alloc(&sql2, &sql2_alloc, &sql2_offset, "delete from hosts_groups where");
3104 			DBadd_condition_alloc(&sql2, &sql2_alloc, &sql2_offset, "hostgroupid",
3105 					del_hostgroupids->values, del_hostgroupids->values_num);
3106 			zbx_strcpy_alloc(&sql2, &sql2_alloc, &sql2_offset, ";\n");
3107 		}
3108 
3109 		if (0 != del_hostmacroids.values_num)
3110 		{
3111 			zbx_vector_uint64_sort(&del_hostmacroids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
3112 			zbx_strcpy_alloc(&sql2, &sql2_alloc, &sql2_offset, "delete from hostmacro where");
3113 			DBadd_condition_alloc(&sql2, &sql2_alloc, &sql2_offset, "hostmacroid",
3114 					del_hostmacroids.values, del_hostmacroids.values_num);
3115 			zbx_strcpy_alloc(&sql2, &sql2_alloc, &sql2_offset, ";\n");
3116 		}
3117 
3118 		if (0 != upd_manual_host_inventory_hostids.values_num)
3119 		{
3120 			zbx_snprintf_alloc(&sql2, &sql2_alloc, &sql2_offset,
3121 				"update host_inventory set inventory_mode=%d where", HOST_INVENTORY_MANUAL);
3122 			DBadd_condition_alloc(&sql2, &sql2_alloc, &sql2_offset, "hostid",
3123 					upd_manual_host_inventory_hostids.values,
3124 					upd_manual_host_inventory_hostids.values_num);
3125 			zbx_strcpy_alloc(&sql2, &sql2_alloc, &sql2_offset, ";\n");
3126 		}
3127 
3128 		if (0 != upd_auto_host_inventory_hostids.values_num)
3129 		{
3130 			zbx_snprintf_alloc(&sql2, &sql2_alloc, &sql2_offset,
3131 				"update host_inventory set inventory_mode=%d where", HOST_INVENTORY_AUTOMATIC);
3132 			DBadd_condition_alloc(&sql2, &sql2_alloc, &sql2_offset, "hostid",
3133 					upd_auto_host_inventory_hostids.values,
3134 					upd_auto_host_inventory_hostids.values_num);
3135 			zbx_strcpy_alloc(&sql2, &sql2_alloc, &sql2_offset, ";\n");
3136 		}
3137 
3138 		if (0 != del_host_inventory_hostids.values_num)
3139 		{
3140 			zbx_strcpy_alloc(&sql2, &sql2_alloc, &sql2_offset, "delete from host_inventory where");
3141 			DBadd_condition_alloc(&sql2, &sql2_alloc, &sql2_offset, "hostid",
3142 					del_host_inventory_hostids.values, del_host_inventory_hostids.values_num);
3143 			zbx_strcpy_alloc(&sql2, &sql2_alloc, &sql2_offset, ";\n");
3144 		}
3145 
3146 		if (0 != del_snmp_ids.values_num)
3147 		{
3148 			zbx_strcpy_alloc(&sql2, &sql2_alloc, &sql2_offset, "delete from interface_snmp where");
3149 			DBadd_condition_alloc(&sql2, &sql2_alloc, &sql2_offset, "interfaceid",
3150 					del_snmp_ids.values, del_snmp_ids.values_num);
3151 			zbx_strcpy_alloc(&sql2, &sql2_alloc, &sql2_offset, ";\n");
3152 		}
3153 
3154 		if (0 != del_interfaceids.values_num)
3155 		{
3156 			zbx_strcpy_alloc(&sql2, &sql2_alloc, &sql2_offset, "delete from interface where");
3157 			DBadd_condition_alloc(&sql2, &sql2_alloc, &sql2_offset, "interfaceid",
3158 					del_interfaceids.values, del_interfaceids.values_num);
3159 			zbx_strcpy_alloc(&sql2, &sql2_alloc, &sql2_offset, ";\n");
3160 		}
3161 
3162 		if (0 != del_tagids.values_num)
3163 		{
3164 			zbx_strcpy_alloc(&sql2, &sql2_alloc, &sql2_offset, "delete from host_tag where");
3165 			DBadd_condition_alloc(&sql2, &sql2_alloc, &sql2_offset, "hosttagid", del_tagids.values,
3166 					del_tagids.values_num);
3167 			zbx_strcpy_alloc(&sql2, &sql2_alloc, &sql2_offset, ";\n");
3168 		}
3169 
3170 		DBend_multiple_update(&sql2, &sql2_alloc, &sql2_offset);
3171 		DBexecute("%s", sql2);
3172 		zbx_free(sql2);
3173 	}
3174 
3175 	DBcommit();
3176 out:
3177 	zbx_vector_uint64_destroy(&del_tagids);
3178 	zbx_vector_uint64_destroy(&del_snmp_ids);
3179 	zbx_vector_uint64_destroy(&del_interfaceids);
3180 	zbx_vector_uint64_destroy(&del_hostmacroids);
3181 	zbx_vector_uint64_destroy(&del_host_inventory_hostids);
3182 	zbx_vector_uint64_destroy(&upd_auto_host_inventory_hostids);
3183 	zbx_vector_uint64_destroy(&upd_manual_host_inventory_hostids);
3184 
3185 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
3186 }
3187 
3188 /******************************************************************************
3189  *                                                                            *
3190  * Function: lld_templates_link                                               *
3191  *                                                                            *
3192  ******************************************************************************/
lld_templates_link(const zbx_vector_ptr_t * hosts,char ** error)3193 static void	lld_templates_link(const zbx_vector_ptr_t *hosts, char **error)
3194 {
3195 	int		i;
3196 	zbx_lld_host_t	*host;
3197 	char		*err = NULL;
3198 
3199 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
3200 
3201 	for (i = 0; i < hosts->values_num; i++)
3202 	{
3203 		host = (zbx_lld_host_t *)hosts->values[i];
3204 
3205 		if (0 == (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
3206 			continue;
3207 
3208 		if (0 != host->del_templateids.values_num)
3209 		{
3210 			if (SUCCEED != DBdelete_template_elements(host->hostid, &host->del_templateids, &err))
3211 			{
3212 				*error = zbx_strdcatf(*error, "Cannot unlink template: %s.\n", err);
3213 				zbx_free(err);
3214 			}
3215 		}
3216 
3217 		if (0 != host->lnk_templateids.values_num)
3218 		{
3219 			if (SUCCEED != DBcopy_template_elements(host->hostid, &host->lnk_templateids, &err))
3220 			{
3221 				*error = zbx_strdcatf(*error, "Cannot link template(s) %s.\n", err);
3222 				zbx_free(err);
3223 			}
3224 		}
3225 	}
3226 
3227 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
3228 }
3229 
3230 /******************************************************************************
3231  *                                                                            *
3232  * Function: lld_hosts_remove                                                 *
3233  *                                                                            *
3234  * Purpose: updates host_discovery.lastcheck and host_discovery.ts_delete     *
3235  *          fields; removes lost resources                                    *
3236  *                                                                            *
3237  ******************************************************************************/
lld_hosts_remove(const zbx_vector_ptr_t * hosts,int lifetime,int lastcheck)3238 static void	lld_hosts_remove(const zbx_vector_ptr_t *hosts, int lifetime, int lastcheck)
3239 {
3240 	char			*sql = NULL;
3241 	size_t			sql_alloc = 0, sql_offset = 0;
3242 	const zbx_lld_host_t	*host;
3243 	zbx_vector_uint64_t	del_hostids, lc_hostids, ts_hostids;
3244 	int			i;
3245 
3246 	if (0 == hosts->values_num)
3247 		return;
3248 
3249 	zbx_vector_uint64_create(&del_hostids);
3250 	zbx_vector_uint64_create(&lc_hostids);
3251 	zbx_vector_uint64_create(&ts_hostids);
3252 
3253 	DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset);
3254 
3255 	for (i = 0; i < hosts->values_num; i++)
3256 	{
3257 		host = (zbx_lld_host_t *)hosts->values[i];
3258 
3259 		if (0 == host->hostid)
3260 			continue;
3261 
3262 		if (0 == (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
3263 		{
3264 			int	ts_delete = lld_end_of_life(host->lastcheck, lifetime);
3265 
3266 			if (lastcheck > ts_delete)
3267 			{
3268 				zbx_vector_uint64_append(&del_hostids, host->hostid);
3269 			}
3270 			else if (host->ts_delete != ts_delete)
3271 			{
3272 				zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
3273 						"update host_discovery"
3274 						" set ts_delete=%d"
3275 						" where hostid=" ZBX_FS_UI64 ";\n",
3276 						ts_delete, host->hostid);
3277 			}
3278 		}
3279 		else
3280 		{
3281 			zbx_vector_uint64_append(&lc_hostids, host->hostid);
3282 			if (0 != host->ts_delete)
3283 				zbx_vector_uint64_append(&ts_hostids, host->hostid);
3284 		}
3285 	}
3286 
3287 	if (0 != lc_hostids.values_num)
3288 	{
3289 		zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "update host_discovery set lastcheck=%d where",
3290 				lastcheck);
3291 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid",
3292 				lc_hostids.values, lc_hostids.values_num);
3293 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
3294 	}
3295 
3296 	if (0 != ts_hostids.values_num)
3297 	{
3298 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "update host_discovery set ts_delete=0 where");
3299 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid",
3300 				ts_hostids.values, ts_hostids.values_num);
3301 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
3302 	}
3303 
3304 	if (16 < sql_offset)	/* in ORACLE always present begin..end; */
3305 	{
3306 		DBend_multiple_update(&sql, &sql_alloc, &sql_offset);
3307 
3308 		DBbegin();
3309 
3310 		DBexecute("%s", sql);
3311 
3312 		DBcommit();
3313 	}
3314 
3315 	zbx_free(sql);
3316 
3317 	if (0 != del_hostids.values_num)
3318 	{
3319 		zbx_vector_uint64_sort(&del_hostids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
3320 
3321 		DBbegin();
3322 
3323 		DBdelete_hosts(&del_hostids);
3324 
3325 		DBcommit();
3326 	}
3327 
3328 	zbx_vector_uint64_destroy(&ts_hostids);
3329 	zbx_vector_uint64_destroy(&lc_hostids);
3330 	zbx_vector_uint64_destroy(&del_hostids);
3331 }
3332 
3333 /******************************************************************************
3334  *                                                                            *
3335  * Function: lld_groups_remove                                                *
3336  *                                                                            *
3337  * Purpose: updates group_discovery.lastcheck and group_discovery.ts_delete   *
3338  *          fields; removes lost resources                                    *
3339  *                                                                            *
3340  ******************************************************************************/
lld_groups_remove(const zbx_vector_ptr_t * groups,int lifetime,int lastcheck)3341 static void	lld_groups_remove(const zbx_vector_ptr_t *groups, int lifetime, int lastcheck)
3342 {
3343 	char			*sql = NULL;
3344 	size_t			sql_alloc = 0, sql_offset = 0;
3345 	const zbx_lld_group_t	*group;
3346 	zbx_vector_uint64_t	del_groupids, lc_groupids, ts_groupids;
3347 	int			i;
3348 
3349 	if (0 == groups->values_num)
3350 		return;
3351 
3352 	zbx_vector_uint64_create(&del_groupids);
3353 	zbx_vector_uint64_create(&lc_groupids);
3354 	zbx_vector_uint64_create(&ts_groupids);
3355 
3356 	DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset);
3357 
3358 	for (i = 0; i < groups->values_num; i++)
3359 	{
3360 		group = (zbx_lld_group_t *)groups->values[i];
3361 
3362 		if (0 == group->groupid)
3363 			continue;
3364 
3365 		if (0 == (group->flags & ZBX_FLAG_LLD_GROUP_DISCOVERED))
3366 		{
3367 			int	ts_delete = lld_end_of_life(group->lastcheck, lifetime);
3368 
3369 			if (lastcheck > ts_delete)
3370 			{
3371 				zbx_vector_uint64_append(&del_groupids, group->groupid);
3372 			}
3373 			else if (group->ts_delete != ts_delete)
3374 			{
3375 				zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
3376 						"update group_discovery"
3377 						" set ts_delete=%d"
3378 						" where groupid=" ZBX_FS_UI64 ";\n",
3379 						ts_delete, group->groupid);
3380 			}
3381 		}
3382 		else
3383 		{
3384 			zbx_vector_uint64_append(&lc_groupids, group->groupid);
3385 			if (0 != group->ts_delete)
3386 				zbx_vector_uint64_append(&ts_groupids, group->groupid);
3387 		}
3388 	}
3389 
3390 	if (0 != lc_groupids.values_num)
3391 	{
3392 		zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "update group_discovery set lastcheck=%d where",
3393 				lastcheck);
3394 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "groupid",
3395 				lc_groupids.values, lc_groupids.values_num);
3396 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
3397 	}
3398 
3399 	if (0 != ts_groupids.values_num)
3400 	{
3401 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "update group_discovery set ts_delete=0 where");
3402 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "groupid",
3403 				ts_groupids.values, ts_groupids.values_num);
3404 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
3405 	}
3406 
3407 	if (16 < sql_offset)	/* in ORACLE always present begin..end; */
3408 	{
3409 		DBend_multiple_update(&sql, &sql_alloc, &sql_offset);
3410 
3411 		DBbegin();
3412 
3413 		DBexecute("%s", sql);
3414 
3415 		DBcommit();
3416 	}
3417 
3418 	zbx_free(sql);
3419 
3420 	if (0 != del_groupids.values_num)
3421 	{
3422 		zbx_vector_uint64_sort(&del_groupids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
3423 
3424 		DBbegin();
3425 
3426 		DBdelete_groups(&del_groupids);
3427 
3428 		DBcommit();
3429 	}
3430 
3431 	zbx_vector_uint64_destroy(&ts_groupids);
3432 	zbx_vector_uint64_destroy(&lc_groupids);
3433 	zbx_vector_uint64_destroy(&del_groupids);
3434 }
3435 
3436 /******************************************************************************
3437  *                                                                            *
3438  * Function: lld_interfaces_get                                               *
3439  *                                                                            *
3440  * Purpose: retrieves either the list of interfaces from the lld rule's host  *
3441  *          or the list of custom interfaces defined for the host prototype   *
3442  *                                                                            *
3443  ******************************************************************************/
lld_interfaces_get(zbx_uint64_t id,zbx_vector_ptr_t * interfaces,unsigned char custom_interfaces)3444 static void	lld_interfaces_get(zbx_uint64_t id, zbx_vector_ptr_t *interfaces, unsigned char custom_interfaces)
3445 {
3446 	DB_RESULT		result;
3447 	DB_ROW			row;
3448 	zbx_lld_interface_t	*interface;
3449 
3450 	if (ZBX_HOST_PROT_INTERFACES_INHERIT == custom_interfaces)
3451 	{
3452 		result = DBselect(
3453 				"select hi.interfaceid,hi.type,hi.main,hi.useip,hi.ip,hi.dns,hi.port,s.version,s.bulk,"
3454 				"s.community,s.securityname,s.securitylevel,s.authpassphrase,s.privpassphrase,"
3455 				"s.authprotocol,s.privprotocol,s.contextname"
3456 				" from interface hi"
3457 				" inner join items i"
3458 					" on hi.hostid=i.hostid "
3459 				" left join interface_snmp s"
3460 					" on hi.interfaceid=s.interfaceid"
3461 				" where i.itemid=" ZBX_FS_UI64,
3462 				id);
3463 	}
3464 	else
3465 	{
3466 		result = DBselect(
3467 				"select hi.interfaceid,hi.type,hi.main,hi.useip,hi.ip,hi.dns,hi.port,s.version,s.bulk,"
3468 				"s.community,s.securityname,s.securitylevel,s.authpassphrase,s.privpassphrase,"
3469 				"s.authprotocol,s.privprotocol,s.contextname"
3470 				" from interface hi"
3471 				" left join interface_snmp s"
3472 					" on hi.interfaceid=s.interfaceid"
3473 				" where hi.hostid=" ZBX_FS_UI64,
3474 				id);
3475 	}
3476 
3477 	while (NULL != (row = DBfetch(result)))
3478 	{
3479 		interface = (zbx_lld_interface_t *)zbx_malloc(NULL, sizeof(zbx_lld_interface_t));
3480 
3481 		ZBX_STR2UINT64(interface->interfaceid, row[0]);
3482 		interface->type = (unsigned char)atoi(row[1]);
3483 		interface->main = (unsigned char)atoi(row[2]);
3484 		interface->useip = (unsigned char)atoi(row[3]);
3485 		interface->ip = zbx_strdup(NULL, row[4]);
3486 		interface->dns = zbx_strdup(NULL, row[5]);
3487 		interface->port = zbx_strdup(NULL, row[6]);
3488 
3489 		if (INTERFACE_TYPE_SNMP == interface->type)
3490 		{
3491 			zbx_lld_interface_snmp_t	*snmp;
3492 
3493 			snmp = (zbx_lld_interface_snmp_t *)zbx_malloc(NULL, sizeof(zbx_lld_interface_snmp_t));
3494 			ZBX_STR2UCHAR(snmp->version, row[7]);
3495 			ZBX_STR2UCHAR(snmp->bulk, row[8]);
3496 			snmp->community = zbx_strdup(NULL, row[9]);
3497 			snmp->securityname = zbx_strdup(NULL, row[10]);
3498 			ZBX_STR2UCHAR(snmp->securitylevel, row[11]);
3499 			snmp->authpassphrase = zbx_strdup(NULL, row[12]);
3500 			snmp->privpassphrase = zbx_strdup(NULL, row[13]);
3501 			ZBX_STR2UCHAR(snmp->authprotocol, row[14]);
3502 			ZBX_STR2UCHAR(snmp->privprotocol, row[15]);
3503 			snmp->contextname = zbx_strdup(NULL, row[16]);
3504 			interface->data.snmp = snmp;
3505 			interface->flags = ZBX_FLAG_LLD_INTERFACE_SNMP_DATA_EXISTS;
3506 		}
3507 		else
3508 		{
3509 			interface->data.snmp = NULL;
3510 			interface->flags = 0x00;
3511 		}
3512 
3513 		zbx_vector_ptr_append(interfaces, interface);
3514 	}
3515 	DBfree_result(result);
3516 
3517 	zbx_vector_ptr_sort(interfaces, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
3518 }
3519 
3520 /******************************************************************************
3521  *                                                                            *
3522  * Function: lld_interface_make                                               *
3523  *                                                                            *
3524  ******************************************************************************/
lld_interface_make(zbx_vector_ptr_t * interfaces,zbx_uint64_t parent_interfaceid,zbx_uint64_t interfaceid,unsigned char type,unsigned char main,unsigned char useip,const char * ip,const char * dns,const char * port,unsigned char snmp_type,unsigned char bulk,const char * community,const char * securityname,unsigned char securitylevel,const char * authpassphrase,const char * privpassphrase,unsigned char authprotocol,unsigned char privprotocol,const char * contextname)3525 static void	lld_interface_make(zbx_vector_ptr_t *interfaces, zbx_uint64_t parent_interfaceid,
3526 		zbx_uint64_t interfaceid, unsigned char type, unsigned char main, unsigned char useip, const char *ip,
3527 		const char *dns, const char *port, unsigned char snmp_type, unsigned char bulk, const char *community,
3528 		const char *securityname, unsigned char securitylevel, const char *authpassphrase,
3529 		const char *privpassphrase, unsigned char authprotocol, unsigned char privprotocol,
3530 		const char *contextname)
3531 {
3532 	zbx_lld_interface_t	*interface = NULL;
3533 	int			i, interface_found = 0;
3534 
3535 	for (i = 0; i < interfaces->values_num; i++)
3536 	{
3537 		interface = (zbx_lld_interface_t *)interfaces->values[i];
3538 
3539 		if (0 != interface->interfaceid)
3540 			continue;
3541 
3542 		if (interface->parent_interfaceid == parent_interfaceid)
3543 		{
3544 			interface_found = 1;
3545 			break;
3546 		}
3547 	}
3548 
3549 	if (0 == interface_found)
3550 	{
3551 		/* interface should be deleted */
3552 		interface = (zbx_lld_interface_t *)zbx_malloc(NULL, sizeof(zbx_lld_interface_t));
3553 
3554 		interface->interfaceid = interfaceid;
3555 		interface->parent_interfaceid = 0;
3556 		interface->type = type;
3557 		interface->main = main;
3558 		interface->useip = 0;
3559 		interface->ip = NULL;
3560 		interface->dns = NULL;
3561 		interface->port = NULL;
3562 		interface->data.snmp = NULL;
3563 		interface->flags = ZBX_FLAG_LLD_INTERFACE_REMOVE;
3564 
3565 		zbx_vector_ptr_append(interfaces, interface);
3566 	}
3567 	else
3568 	{
3569 		/* interface already has been added */
3570 		if (interface->type != type)
3571 		{
3572 			interface->type_orig = type;
3573 			interface->flags |= ZBX_FLAG_LLD_INTERFACE_UPDATE_TYPE;
3574 
3575 			if (INTERFACE_TYPE_SNMP == type)
3576 				interface->flags |= ZBX_FLAG_LLD_INTERFACE_SNMP_REMOVE;
3577 
3578 			if (INTERFACE_TYPE_SNMP == interface->type)
3579 				interface->data.snmp->flags |= ZBX_FLAG_LLD_INTERFACE_SNMP_CREATE;
3580 		}
3581 		if (interface->main != main)
3582 		{
3583 			interface->main_orig = main;
3584 			interface->flags |= ZBX_FLAG_LLD_INTERFACE_UPDATE_MAIN;
3585 		}
3586 		if (interface->useip != useip)
3587 			interface->flags |= ZBX_FLAG_LLD_INTERFACE_UPDATE_USEIP;
3588 		if (0 != strcmp(interface->ip, ip))
3589 			interface->flags |= ZBX_FLAG_LLD_INTERFACE_UPDATE_IP;
3590 		if (0 != strcmp(interface->dns, dns))
3591 			interface->flags |= ZBX_FLAG_LLD_INTERFACE_UPDATE_DNS;
3592 		if (0 != strcmp(interface->port, port))
3593 			interface->flags |= ZBX_FLAG_LLD_INTERFACE_UPDATE_PORT;
3594 
3595 		if (INTERFACE_TYPE_SNMP == interface->type && interface->type == type)
3596 		{
3597 			zbx_lld_interface_snmp_t *snmp = interface->data.snmp;
3598 
3599 			if (snmp->version != snmp_type)
3600 				snmp->flags |= ZBX_FLAG_LLD_INTERFACE_SNMP_UPDATE_TYPE;
3601 			if (snmp->bulk != bulk)
3602 				snmp->flags |= ZBX_FLAG_LLD_INTERFACE_SNMP_UPDATE_BULK;
3603 			if (0 != strcmp(snmp->community, community))
3604 				snmp->flags |= ZBX_FLAG_LLD_INTERFACE_SNMP_UPDATE_COMMUNITY;
3605 			if (0 != strcmp(snmp->securityname, securityname))
3606 				snmp->flags |= ZBX_FLAG_LLD_INTERFACE_SNMP_UPDATE_SECNAME;
3607 			if (snmp->securitylevel != securitylevel)
3608 				snmp->flags |= ZBX_FLAG_LLD_INTERFACE_SNMP_UPDATE_SECLEVEL;
3609 			if (0 != strcmp(snmp->authpassphrase, authpassphrase))
3610 				snmp->flags |= ZBX_FLAG_LLD_INTERFACE_SNMP_UPDATE_AUTHPASS;
3611 			if (0 != strcmp(snmp->privpassphrase, privpassphrase))
3612 				snmp->flags |= ZBX_FLAG_LLD_INTERFACE_SNMP_UPDATE_PRIVPASS;
3613 			if (snmp->authprotocol != authprotocol)
3614 				snmp->flags |= ZBX_FLAG_LLD_INTERFACE_SNMP_UPDATE_AUTHPROTOCOL;
3615 			if (snmp->privprotocol != privprotocol)
3616 				snmp->flags |= ZBX_FLAG_LLD_INTERFACE_SNMP_UPDATE_PRIVPROTOCOL;
3617 			if (0 != strcmp(snmp->contextname, contextname))
3618 				snmp->flags |= ZBX_FLAG_LLD_INTERFACE_SNMP_UPDATE_CONTEXT;
3619 		}
3620 	}
3621 
3622 	interface->interfaceid = interfaceid;
3623 }
3624 
3625 /******************************************************************************
3626  *                                                                            *
3627  * Function: lld_interfaces_make                                              *
3628  *                                                                            *
3629  * Parameters: interfaces - [IN] sorted list of interfaces which              *
3630  *                               should be present on the each                *
3631  *                               discovered host                              *
3632  *             hosts      - [IN/OUT] sorted list of hosts                     *
3633  *             lld_macros - [IN] list of LLD macros                           *
3634  *                                                                            *
3635  ******************************************************************************/
lld_interfaces_make(const zbx_vector_ptr_t * interfaces,zbx_vector_ptr_t * hosts,const zbx_vector_ptr_t * lld_macros)3636 static void	lld_interfaces_make(const zbx_vector_ptr_t *interfaces, zbx_vector_ptr_t *hosts,
3637 		const zbx_vector_ptr_t *lld_macros)
3638 {
3639 	DB_RESULT		result;
3640 	DB_ROW			row;
3641 	int			i, j;
3642 	zbx_vector_uint64_t	hostids;
3643 	zbx_uint64_t		parent_interfaceid, hostid, interfaceid;
3644 	zbx_lld_host_t		*host;
3645 	zbx_lld_interface_t	*new_interface, *interface;
3646 
3647 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
3648 
3649 	zbx_vector_uint64_create(&hostids);
3650 
3651 	for (i = 0; i < hosts->values_num; i++)
3652 	{
3653 		host = (zbx_lld_host_t *)hosts->values[i];
3654 
3655 		if (0 == (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
3656 			continue;
3657 
3658 		zbx_vector_ptr_reserve(&host->interfaces, interfaces->values_num);
3659 
3660 		for (j = 0; j < interfaces->values_num; j++)
3661 		{
3662 			interface = (zbx_lld_interface_t *)interfaces->values[j];
3663 
3664 			new_interface = (zbx_lld_interface_t *)zbx_malloc(NULL, sizeof(zbx_lld_interface_t));
3665 
3666 			new_interface->interfaceid = 0;
3667 			new_interface->parent_interfaceid = interface->interfaceid;
3668 			new_interface->type = interface->type;
3669 			new_interface->main = interface->main;
3670 			new_interface->useip = interface->useip;
3671 			new_interface->ip = zbx_strdup(NULL, interface->ip);
3672 			new_interface->dns = zbx_strdup(NULL, interface->dns);
3673 			new_interface->port = zbx_strdup(NULL, interface->port);
3674 
3675 			substitute_lld_macros(&new_interface->ip, host->jp_row, lld_macros, ZBX_MACRO_ANY, NULL, 0);
3676 			substitute_lld_macros(&new_interface->dns, host->jp_row, lld_macros, ZBX_MACRO_ANY, NULL, 0);
3677 			substitute_lld_macros(&new_interface->port, host->jp_row, lld_macros, ZBX_MACRO_ANY, NULL, 0);
3678 
3679 			if (INTERFACE_TYPE_SNMP == interface->type)
3680 			{
3681 				zbx_lld_interface_snmp_t *snmp;
3682 
3683 				snmp = (zbx_lld_interface_snmp_t *)zbx_malloc(NULL, sizeof(zbx_lld_interface_snmp_t));
3684 				snmp->version = interface->data.snmp->version;
3685 				snmp->bulk = interface->data.snmp->bulk;
3686 				snmp->community = zbx_strdup(NULL, interface->data.snmp->community);
3687 				snmp->securityname = zbx_strdup(NULL, interface->data.snmp->securityname);
3688 				snmp->securitylevel = interface->data.snmp->securitylevel;
3689 				snmp->authpassphrase = zbx_strdup(NULL, interface->data.snmp->authpassphrase);
3690 				snmp->privpassphrase = zbx_strdup(NULL, interface->data.snmp->privpassphrase);
3691 				snmp->authprotocol = interface->data.snmp->authprotocol;
3692 				snmp->privprotocol = interface->data.snmp->privprotocol;
3693 				snmp->contextname = zbx_strdup(NULL, interface->data.snmp->contextname);
3694 				snmp->flags = 0x00;
3695 				new_interface->flags = ZBX_FLAG_LLD_INTERFACE_SNMP_DATA_EXISTS;
3696 				new_interface->data.snmp = snmp;
3697 
3698 				substitute_lld_macros(&snmp->community, host->jp_row, lld_macros, ZBX_MACRO_ANY,
3699 						NULL, 0);
3700 				substitute_lld_macros(&snmp->securityname, host->jp_row, lld_macros, ZBX_MACRO_ANY,
3701 						NULL, 0);
3702 				substitute_lld_macros(&snmp->authpassphrase, host->jp_row, lld_macros, ZBX_MACRO_ANY,
3703 						NULL, 0);
3704 				substitute_lld_macros(&snmp->privpassphrase, host->jp_row, lld_macros, ZBX_MACRO_ANY,
3705 						NULL, 0);
3706 				substitute_lld_macros(&snmp->contextname, host->jp_row, lld_macros, ZBX_MACRO_ANY,
3707 						NULL, 0);
3708 			}
3709 			else
3710 			{
3711 				new_interface->flags = 0x00;
3712 				new_interface->data.snmp = NULL;
3713 			}
3714 
3715 			zbx_vector_ptr_append(&host->interfaces, new_interface);
3716 		}
3717 
3718 		if (0 != host->hostid)
3719 			zbx_vector_uint64_append(&hostids, host->hostid);
3720 	}
3721 
3722 	if (0 != hostids.values_num)
3723 	{
3724 		char	*sql = NULL;
3725 		size_t	sql_alloc = 0, sql_offset = 0;
3726 
3727 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
3728 				"select hi.hostid,id.parent_interfaceid,hi.interfaceid,hi.type,hi.main,hi.useip,hi.ip,"
3729 					"hi.dns,hi.port,s.version,s.bulk,s.community,s.securityname,s.securitylevel,"
3730 					"s.authpassphrase,s.privpassphrase,s.authprotocol,s.privprotocol,s.contextname"
3731 				" from interface hi"
3732 					" left join interface_discovery id"
3733 						" on hi.interfaceid=id.interfaceid"
3734 					" left join interface_snmp s"
3735 						" on hi.interfaceid=s.interfaceid"
3736 				" where");
3737 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hi.hostid", hostids.values, hostids.values_num);
3738 
3739 		result = DBselect("%s", sql);
3740 
3741 		zbx_free(sql);
3742 
3743 		while (NULL != (row = DBfetch(result)))
3744 		{
3745 			unsigned char	interface_type;
3746 
3747 			ZBX_STR2UINT64(hostid, row[0]);
3748 			ZBX_DBROW2UINT64(parent_interfaceid, row[1]);
3749 			ZBX_DBROW2UINT64(interfaceid, row[2]);
3750 
3751 			if (FAIL == (i = zbx_vector_ptr_bsearch(hosts, &hostid, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
3752 			{
3753 				THIS_SHOULD_NEVER_HAPPEN;
3754 				continue;
3755 			}
3756 
3757 			host = (zbx_lld_host_t *)hosts->values[i];
3758 			ZBX_STR2UCHAR(interface_type, row[3]);
3759 
3760 			if (INTERFACE_TYPE_SNMP == interface_type)
3761 			{
3762 				lld_interface_make(&host->interfaces, parent_interfaceid, interfaceid,
3763 						interface_type, (unsigned char)atoi(row[4]),
3764 						(unsigned char)atoi(row[5]), row[6], row[7], row[8],
3765 						(unsigned char)atoi(row[9]), (unsigned char)atoi(row[10]), row[11],
3766 						row[12], (unsigned char)atoi(row[13]), row[14], row[15],
3767 						(unsigned char)atoi(row[16]), (unsigned char)atoi(row[17]), row[18]);
3768 			}
3769 			else
3770 			{
3771 				lld_interface_make(&host->interfaces, parent_interfaceid, interfaceid,
3772 						interface_type, (unsigned char)atoi(row[4]),
3773 						(unsigned char)atoi(row[5]), row[6], row[7], row[8],
3774 						0, 0, NULL, NULL, 0, NULL, NULL,0, 0, NULL);
3775 			}
3776 		}
3777 		DBfree_result(result);
3778 	}
3779 
3780 	zbx_vector_uint64_destroy(&hostids);
3781 
3782 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
3783 }
3784 
3785 /******************************************************************************
3786  *                                                                            *
3787  * Function: another_main_interface_exists                                    *
3788  *                                                                            *
3789  * Return value: SUCCEED if interface with same type exists in the list of    *
3790  *               interfaces; FAIL - otherwise                                 *
3791  *                                                                            *
3792  * Comments: interfaces with ZBX_FLAG_LLD_INTERFACE_REMOVE flag are ignored   *
3793  *           auxiliary function for lld_interfaces_validate()                 *
3794  *                                                                            *
3795  ******************************************************************************/
another_main_interface_exists(const zbx_vector_ptr_t * interfaces,const zbx_lld_interface_t * interface)3796 static int	another_main_interface_exists(const zbx_vector_ptr_t *interfaces, const zbx_lld_interface_t *interface)
3797 {
3798 	const zbx_lld_interface_t	*interface_b;
3799 	int				i;
3800 
3801 	for (i = 0; i < interfaces->values_num; i++)
3802 	{
3803 		interface_b = (zbx_lld_interface_t *)interfaces->values[i];
3804 
3805 		if (interface_b == interface)
3806 			continue;
3807 
3808 		if (0 != (interface_b->flags & ZBX_FLAG_LLD_INTERFACE_REMOVE))
3809 			continue;
3810 
3811 		if (interface_b->type != interface->type)
3812 			continue;
3813 
3814 		if (1 == interface_b->main)
3815 			return SUCCEED;
3816 	}
3817 
3818 	return FAIL;
3819 }
3820 
3821 /******************************************************************************
3822  *                                                                            *
3823  * Function: lld_interfaces_validate                                          *
3824  *                                                                            *
3825  * Parameters: hosts - [IN/OUT] list of hosts                                 *
3826  *                                                                            *
3827  ******************************************************************************/
lld_interfaces_validate(zbx_vector_ptr_t * hosts,char ** error)3828 static void	lld_interfaces_validate(zbx_vector_ptr_t *hosts, char **error)
3829 {
3830 	DB_RESULT		result;
3831 	DB_ROW			row;
3832 	int			i, j;
3833 	zbx_vector_uint64_t	interfaceids;
3834 	zbx_uint64_t		interfaceid;
3835 	zbx_lld_host_t		*host;
3836 	zbx_lld_interface_t	*interface;
3837 	unsigned char		type;
3838 	char			*sql = NULL;
3839 	size_t			sql_alloc = 0, sql_offset = 0;
3840 
3841 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
3842 
3843 	/* validate changed types */
3844 
3845 	zbx_vector_uint64_create(&interfaceids);
3846 
3847 	for (i = 0; i < hosts->values_num; i++)
3848 	{
3849 		host = (zbx_lld_host_t *)hosts->values[i];
3850 
3851 		for (j = 0; j < host->interfaces.values_num; j++)
3852 		{
3853 			interface = (zbx_lld_interface_t *)host->interfaces.values[j];
3854 
3855 			if (0 == (interface->flags & ZBX_FLAG_LLD_INTERFACE_UPDATE_TYPE))
3856 				continue;
3857 
3858 			zbx_vector_uint64_append(&interfaceids, interface->interfaceid);
3859 		}
3860 	}
3861 
3862 	if (0 != interfaceids.values_num)
3863 	{
3864 		zbx_vector_uint64_sort(&interfaceids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
3865 
3866 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "select interfaceid,type from items where");
3867 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "interfaceid",
3868 				interfaceids.values, interfaceids.values_num);
3869 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " group by interfaceid,type");
3870 
3871 		result = DBselect("%s", sql);
3872 
3873 		while (NULL != (row = DBfetch(result)))
3874 		{
3875 			type = get_interface_type_by_item_type((unsigned char)atoi(row[1]));
3876 
3877 			if (type != INTERFACE_TYPE_ANY && type != INTERFACE_TYPE_UNKNOWN)
3878 			{
3879 				ZBX_STR2UINT64(interfaceid, row[0]);
3880 
3881 				for (i = 0; i < hosts->values_num; i++)
3882 				{
3883 					host = (zbx_lld_host_t *)hosts->values[i];
3884 
3885 					for (j = 0; j < host->interfaces.values_num; j++)
3886 					{
3887 						interface = (zbx_lld_interface_t *)host->interfaces.values[j];
3888 
3889 						if (0 == (interface->flags & ZBX_FLAG_LLD_INTERFACE_UPDATE_TYPE))
3890 							continue;
3891 
3892 						if (interface->interfaceid != interfaceid)
3893 							continue;
3894 
3895 						*error = zbx_strdcatf(*error,
3896 								"Cannot update \"%s\" interface on host \"%s\":"
3897 								" the interface is used by items.\n",
3898 								zbx_interface_type_string(interface->type_orig),
3899 								host->host);
3900 
3901 						/* return an original interface type and drop the corresponding flag */
3902 						interface->type = interface->type_orig;
3903 						interface->flags &= ~ZBX_FLAG_LLD_INTERFACE_UPDATE_TYPE;
3904 					}
3905 				}
3906 			}
3907 		}
3908 		DBfree_result(result);
3909 	}
3910 
3911 	/* validate interfaces which should be deleted */
3912 
3913 	zbx_vector_uint64_clear(&interfaceids);
3914 
3915 	for (i = 0; i < hosts->values_num; i++)
3916 	{
3917 		host = (zbx_lld_host_t *)hosts->values[i];
3918 
3919 		for (j = 0; j < host->interfaces.values_num; j++)
3920 		{
3921 			interface = (zbx_lld_interface_t *)host->interfaces.values[j];
3922 
3923 			if (0 == (interface->flags & ZBX_FLAG_LLD_INTERFACE_REMOVE))
3924 				continue;
3925 
3926 			zbx_vector_uint64_append(&interfaceids, interface->interfaceid);
3927 		}
3928 	}
3929 
3930 	if (0 != interfaceids.values_num)
3931 	{
3932 		zbx_vector_uint64_sort(&interfaceids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
3933 
3934 		sql_offset = 0;
3935 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "select interfaceid from items where");
3936 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "interfaceid",
3937 				interfaceids.values, interfaceids.values_num);
3938 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " group by interfaceid");
3939 
3940 		result = DBselect("%s", sql);
3941 
3942 		while (NULL != (row = DBfetch(result)))
3943 		{
3944 			ZBX_STR2UINT64(interfaceid, row[0]);
3945 
3946 			for (i = 0; i < hosts->values_num; i++)
3947 			{
3948 				host = (zbx_lld_host_t *)hosts->values[i];
3949 
3950 				for (j = 0; j < host->interfaces.values_num; j++)
3951 				{
3952 					interface = (zbx_lld_interface_t *)host->interfaces.values[j];
3953 
3954 					if (0 == (interface->flags & ZBX_FLAG_LLD_INTERFACE_REMOVE))
3955 						continue;
3956 
3957 					if (interface->interfaceid != interfaceid)
3958 						continue;
3959 
3960 					*error = zbx_strdcatf(*error, "Cannot delete \"%s\" interface on host \"%s\":"
3961 							" the interface is used by items.\n",
3962 							zbx_interface_type_string(interface->type), host->host);
3963 
3964 					/* drop the corresponding flag */
3965 					interface->flags &= ~ZBX_FLAG_LLD_INTERFACE_REMOVE;
3966 
3967 					if (SUCCEED == another_main_interface_exists(&host->interfaces, interface))
3968 					{
3969 						if (1 == interface->main)
3970 						{
3971 							/* drop main flag */
3972 							interface->main_orig = interface->main;
3973 							interface->main = 0;
3974 							interface->flags |= ZBX_FLAG_LLD_INTERFACE_UPDATE_MAIN;
3975 						}
3976 					}
3977 					else if (1 != interface->main)
3978 					{
3979 						/* set main flag */
3980 						interface->main_orig = interface->main;
3981 						interface->main = 1;
3982 						interface->flags |= ZBX_FLAG_LLD_INTERFACE_UPDATE_MAIN;
3983 					}
3984 				}
3985 			}
3986 		}
3987 		DBfree_result(result);
3988 	}
3989 
3990 	zbx_vector_uint64_destroy(&interfaceids);
3991 
3992 	zbx_free(sql);
3993 
3994 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
3995 }
3996 
3997 /******************************************************************************
3998  *                                                                            *
3999  * Function: lld_update_hosts                                                 *
4000  *                                                                            *
4001  * Purpose: add or update low-level discovered hosts                          *
4002  *                                                                            *
4003  ******************************************************************************/
lld_update_hosts(zbx_uint64_t lld_ruleid,const zbx_vector_ptr_t * lld_rows,const zbx_vector_ptr_t * lld_macro_paths,char ** error,int lifetime,int lastcheck)4004 void	lld_update_hosts(zbx_uint64_t lld_ruleid, const zbx_vector_ptr_t *lld_rows,
4005 		const zbx_vector_ptr_t *lld_macro_paths, char **error, int lifetime, int lastcheck)
4006 {
4007 	DB_RESULT		result;
4008 	DB_ROW			row;
4009 	zbx_vector_ptr_t	hosts, group_prototypes, groups, interfaces, masterhostmacros, hostmacros;
4010 	zbx_vector_db_tag_ptr_t	tags;
4011 	zbx_vector_uint64_t	groupids;		/* list of host groups which should be added */
4012 	zbx_vector_uint64_t	del_hostgroupids;	/* list of host groups which should be deleted */
4013 	zbx_uint64_t		proxy_hostid;
4014 	char			*ipmi_username = NULL, *ipmi_password, *tls_issuer, *tls_subject, *tls_psk_identity,
4015 				*tls_psk;
4016 	char			ipmi_authtype, inventory_mode_proto;
4017 	unsigned char		ipmi_privilege, tls_connect, tls_accept;
4018 
4019 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
4020 
4021 	result = DBselect(
4022 			"select h.proxy_hostid,h.ipmi_authtype,h.ipmi_privilege,h.ipmi_username,h.ipmi_password,"
4023 				"h.tls_connect,h.tls_accept,h.tls_issuer,h.tls_subject,h.tls_psk_identity,h.tls_psk"
4024 			" from hosts h,items i"
4025 			" where h.hostid=i.hostid"
4026 				" and i.itemid=" ZBX_FS_UI64,
4027 			lld_ruleid);
4028 
4029 	if (NULL != (row = DBfetch(result)))
4030 	{
4031 		ZBX_DBROW2UINT64(proxy_hostid, row[0]);
4032 		ipmi_authtype = (char)atoi(row[1]);
4033 		ZBX_STR2UCHAR(ipmi_privilege, row[2]);
4034 		ipmi_username = zbx_strdup(NULL, row[3]);
4035 		ipmi_password = zbx_strdup(NULL, row[4]);
4036 
4037 		ZBX_STR2UCHAR(tls_connect, row[5]);
4038 		ZBX_STR2UCHAR(tls_accept, row[6]);
4039 		tls_issuer = zbx_strdup(NULL, row[7]);
4040 		tls_subject = zbx_strdup(NULL, row[8]);
4041 		tls_psk_identity = zbx_strdup(NULL, row[9]);
4042 		tls_psk = zbx_strdup(NULL, row[10]);
4043 	}
4044 	DBfree_result(result);
4045 
4046 	if (NULL == row)
4047 	{
4048 		*error = zbx_strdcatf(*error, "Cannot process host prototypes: a parent host not found.\n");
4049 		return;
4050 	}
4051 
4052 	zbx_vector_ptr_create(&hosts);
4053 	zbx_vector_uint64_create(&groupids);
4054 	zbx_vector_ptr_create(&group_prototypes);
4055 	zbx_vector_ptr_create(&groups);
4056 	zbx_vector_uint64_create(&del_hostgroupids);
4057 	zbx_vector_ptr_create(&interfaces);
4058 	zbx_vector_ptr_create(&masterhostmacros);
4059 	zbx_vector_ptr_create(&hostmacros);
4060 	zbx_vector_db_tag_ptr_create(&tags);
4061 
4062 	lld_interfaces_get(lld_ruleid, &interfaces, 0);
4063 	lld_masterhostmacros_get(lld_ruleid, &masterhostmacros);
4064 
4065 	result = DBselect(
4066 			"select h.hostid,h.host,h.name,h.status,h.discover,hi.inventory_mode,h.custom_interfaces"
4067 			" from hosts h,host_discovery hd"
4068 				" left join host_inventory hi"
4069 					" on hd.hostid=hi.hostid"
4070 			" where h.hostid=hd.hostid"
4071 				" and hd.parent_itemid=" ZBX_FS_UI64,
4072 			lld_ruleid);
4073 
4074 	while (NULL != (row = DBfetch(result)))
4075 	{
4076 		zbx_uint64_t		parent_hostid;
4077 		const char		*host_proto, *name_proto;
4078 		zbx_lld_host_t		*host;
4079 		unsigned char		status, discover, use_custom_interfaces;
4080 		int			i;
4081 		zbx_vector_ptr_t	interfaces_custom;
4082 
4083 		ZBX_STR2UINT64(parent_hostid, row[0]);
4084 		host_proto = row[1];
4085 		name_proto = row[2];
4086 		ZBX_STR2UCHAR(status, row[3]);
4087 		ZBX_STR2UCHAR(discover, row[4]);
4088 		ZBX_STR2UCHAR(use_custom_interfaces, row[6]);
4089 
4090 		if (SUCCEED == DBis_null(row[5]))
4091 			inventory_mode_proto = HOST_INVENTORY_DISABLED;
4092 		else
4093 			inventory_mode_proto = (char)atoi(row[5]);
4094 
4095 		lld_hosts_get(parent_hostid, &hosts, proxy_hostid, ipmi_authtype, ipmi_privilege, ipmi_username,
4096 				ipmi_password, tls_connect, tls_accept, tls_issuer, tls_subject,
4097 				tls_psk_identity, tls_psk);
4098 
4099 		if (0 != hosts.values_num)
4100 			lld_hosts_get_tags(&hosts);
4101 		lld_proto_tags_get(parent_hostid, &tags);
4102 
4103 		lld_simple_groups_get(parent_hostid, &groupids);
4104 		lld_group_prototypes_get(parent_hostid, &group_prototypes);
4105 		lld_groups_get(parent_hostid, &groups);
4106 
4107 		lld_hostmacros_get(parent_hostid, &masterhostmacros, &hostmacros);
4108 
4109 		for (i = 0; i < lld_rows->values_num; i++)
4110 		{
4111 			const zbx_lld_row_t	*lld_row = (zbx_lld_row_t *)lld_rows->values[i];
4112 
4113 			if (NULL == (host = lld_host_make(&hosts, host_proto, name_proto, inventory_mode_proto,
4114 					status, discover, &tags, lld_row, lld_macro_paths, error, use_custom_interfaces)))
4115 			{
4116 				continue;
4117 			}
4118 
4119 			lld_groups_make(host, &groups, &group_prototypes, &lld_row->jp_row, lld_macro_paths);
4120 		}
4121 
4122 		zbx_vector_ptr_sort(&hosts, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
4123 
4124 		lld_groups_validate(&groups, error);
4125 		lld_hosts_validate(&hosts, error);
4126 
4127 		if (ZBX_HOST_PROT_INTERFACES_CUSTOM == use_custom_interfaces)
4128 		{
4129 			zbx_vector_ptr_create(&interfaces_custom);
4130 			lld_interfaces_get(parent_hostid, &interfaces_custom, 1);
4131 			lld_interfaces_make(&interfaces_custom, &hosts, lld_macro_paths);
4132 		}
4133 		else
4134 			lld_interfaces_make(&interfaces, &hosts, lld_macro_paths);
4135 
4136 		lld_interfaces_validate(&hosts, error);
4137 
4138 		lld_hostgroups_make(&groupids, &hosts, &groups, &del_hostgroupids);
4139 		lld_templates_make(parent_hostid, &hosts);
4140 
4141 		lld_hostmacros_make(&hostmacros, &hosts, lld_macro_paths);
4142 
4143 		lld_groups_save(&groups, &group_prototypes);
4144 		lld_hosts_save(parent_hostid, &hosts, host_proto, proxy_hostid, ipmi_authtype, ipmi_privilege,
4145 				ipmi_username, ipmi_password, tls_connect, tls_accept,
4146 				tls_issuer, tls_subject, tls_psk_identity, tls_psk, &del_hostgroupids);
4147 
4148 		/* linking of the templates */
4149 		lld_templates_link(&hosts, error);
4150 
4151 		lld_hosts_remove(&hosts, lifetime, lastcheck);
4152 		lld_groups_remove(&groups, lifetime, lastcheck);
4153 
4154 		zbx_vector_db_tag_ptr_clear_ext(&tags, zbx_db_tag_free);
4155 		zbx_vector_ptr_clear_ext(&hostmacros, (zbx_clean_func_t)lld_hostmacro_free);
4156 		zbx_vector_ptr_clear_ext(&groups, (zbx_clean_func_t)lld_group_free);
4157 		zbx_vector_ptr_clear_ext(&group_prototypes, (zbx_clean_func_t)lld_group_prototype_free);
4158 		zbx_vector_ptr_clear_ext(&hosts, (zbx_clean_func_t)lld_host_free);
4159 
4160 		zbx_vector_uint64_clear(&groupids);
4161 		zbx_vector_uint64_clear(&del_hostgroupids);
4162 
4163 		if (ZBX_HOST_PROT_INTERFACES_CUSTOM == use_custom_interfaces)
4164 		{
4165 			zbx_vector_ptr_clear_ext(&interfaces_custom, (zbx_clean_func_t)lld_interface_free);
4166 			zbx_vector_ptr_destroy(&interfaces_custom);
4167 		}
4168 	}
4169 	DBfree_result(result);
4170 
4171 	zbx_vector_ptr_clear_ext(&masterhostmacros, (zbx_clean_func_t)lld_hostmacro_free);
4172 	zbx_vector_ptr_clear_ext(&interfaces, (zbx_clean_func_t)lld_interface_free);
4173 
4174 	zbx_vector_db_tag_ptr_clear_ext(&tags, zbx_db_tag_free);
4175 	zbx_vector_db_tag_ptr_destroy(&tags);
4176 	zbx_vector_ptr_destroy(&hostmacros);
4177 	zbx_vector_ptr_destroy(&masterhostmacros);
4178 	zbx_vector_ptr_destroy(&interfaces);
4179 	zbx_vector_uint64_destroy(&del_hostgroupids);
4180 	zbx_vector_ptr_destroy(&groups);
4181 	zbx_vector_ptr_destroy(&group_prototypes);
4182 	zbx_vector_uint64_destroy(&groupids);
4183 	zbx_vector_ptr_destroy(&hosts);
4184 
4185 	zbx_free(tls_psk);
4186 	zbx_free(tls_psk_identity);
4187 	zbx_free(tls_subject);
4188 	zbx_free(tls_issuer);
4189 	zbx_free(ipmi_password);
4190 	zbx_free(ipmi_username);
4191 
4192 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
4193 }
4194