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