1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 **/
19 
20 #include "common.h"
21 #include "zbxreport.h"
22 #include "report_protocol.h"
23 #include "zbxipcservice.h"
24 #include "zbxserialize.h"
25 #include "zbxalgo.h"
26 #include "db.h"
27 #include "zbxalert.h"
28 
json_uint_by_tag(const struct zbx_json_parse * jp,const char * tag,zbx_uint64_t * value,char ** error)29 static int	json_uint_by_tag(const struct zbx_json_parse *jp, const char *tag, zbx_uint64_t *value, char **error)
30 {
31 	char	buf[MAX_ID_LEN + 1];
32 
33 	if (SUCCEED != zbx_json_value_by_name(jp, tag, buf, sizeof(buf), NULL))
34 	{
35 		*error = zbx_dsprintf(*error, "cannot find tag: %s", tag);
36 		return FAIL;
37 	}
38 
39 	if (SUCCEED != is_uint64(buf, value))
40 	{
41 		*error = zbx_dsprintf(*error, "invalid tag %s value: %s", tag, buf);
42 		return FAIL;
43 	}
44 
45 	return SUCCEED;
46 }
47 
48 /******************************************************************************
49  *                                                                            *
50  * ZBX_IPC_REPORTER_TEST_REPORT message serialization/deserialization         *
51  *                                                                            *
52  ******************************************************************************/
53 
report_serialize_test_report(unsigned char ** data,const char * name,zbx_uint64_t dashboardid,zbx_uint64_t userid,zbx_uint64_t viewer_userid,int report_time,unsigned char period,const zbx_vector_ptr_pair_t * params)54 static zbx_uint32_t	report_serialize_test_report(unsigned char **data, const char *name, zbx_uint64_t dashboardid,
55 		zbx_uint64_t userid, zbx_uint64_t viewer_userid, int report_time, unsigned char period,
56 		const zbx_vector_ptr_pair_t *params)
57 {
58 	zbx_uint32_t	data_len = 0, *len, name_len;
59 	int		i;
60 	unsigned char	*ptr;
61 
62 	zbx_serialize_prepare_str(data_len, name);
63 	zbx_serialize_prepare_value(data_len, dashboardid);
64 	zbx_serialize_prepare_value(data_len, userid);
65 	zbx_serialize_prepare_value(data_len, viewer_userid);
66 	zbx_serialize_prepare_value(data_len, report_time);
67 	zbx_serialize_prepare_value(data_len, period);
68 	zbx_serialize_prepare_value(data_len, params->values_num);
69 
70 	len = (zbx_uint32_t *)zbx_malloc(NULL, params->values_num * 2 * sizeof(zbx_uint32_t));
71 
72 	for (i = 0; i < params->values_num; i++)
73 	{
74 		zbx_serialize_prepare_str_len(data_len, params->values[i].first, len[i * 2]);
75 		zbx_serialize_prepare_str_len(data_len, params->values[i].second, len[i * 2 + 1]);
76 	}
77 
78 	*data = (unsigned char *)zbx_malloc(NULL, data_len);
79 	ptr = *data;
80 
81 	ptr += zbx_serialize_str(ptr, name, name_len);
82 	ptr += zbx_serialize_value(ptr, dashboardid);
83 	ptr += zbx_serialize_value(ptr, userid);
84 	ptr += zbx_serialize_value(ptr, viewer_userid);
85 	ptr += zbx_serialize_value(ptr, report_time);
86 	ptr += zbx_serialize_value(ptr, period);
87 	ptr += zbx_serialize_value(ptr, params->values_num);
88 
89 	for (i = 0; i < params->values_num; i++)
90 	{
91 		ptr += zbx_serialize_str(ptr, params->values[i].first, len[i * 2]);
92 		ptr += zbx_serialize_str(ptr, params->values[i].second, len[i * 2 + 1]);
93 	}
94 
95 	zbx_free(len);
96 
97 	return data_len;
98 }
99 
report_deserialize_test_report(const unsigned char * data,char ** name,zbx_uint64_t * dashboardid,zbx_uint64_t * userid,zbx_uint64_t * viewer_userid,int * report_time,unsigned char * period,zbx_vector_ptr_pair_t * params)100 void	report_deserialize_test_report(const unsigned char *data, char **name, zbx_uint64_t *dashboardid,
101 		zbx_uint64_t *userid, zbx_uint64_t *viewer_userid, int *report_time, unsigned char *period,
102 		zbx_vector_ptr_pair_t *params)
103 {
104 	int		params_num, i;
105 	zbx_uint32_t	len;
106 
107 	data += zbx_deserialize_str(data, name, len);
108 	data += zbx_deserialize_value(data, dashboardid);
109 	data += zbx_deserialize_value(data, userid);
110 	data += zbx_deserialize_value(data, viewer_userid);
111 	data += zbx_deserialize_value(data, report_time);
112 	data += zbx_deserialize_value(data, period);
113 	data += zbx_deserialize_value(data, &params_num);
114 
115 	zbx_vector_ptr_pair_reserve(params, (size_t)params_num);
116 	for (i = 0; i < params_num; i++)
117 	{
118 		zbx_ptr_pair_t	pair;
119 
120 		data += zbx_deserialize_str(data, (char **)&pair.first, len);
121 		data += zbx_deserialize_str(data, (char **)&pair.second, len);
122 		zbx_vector_ptr_pair_append(params, pair);
123 	}
124 }
125 
126 #include "log.h"
127 
128 /******************************************************************************
129  *                                                                            *
130  * ZBX_IPC_REPORTER_TEST_REPORT_RESULT, ZBX_IPC_REPORTER_REPORT_RESULT        *
131  * message serialization/deserialization                                      *
132  *                                                                            *
133  ******************************************************************************/
134 
report_serialize_response(unsigned char ** data,int status,const char * error,const zbx_vector_ptr_t * results)135 zbx_uint32_t	report_serialize_response(unsigned char **data, int status, const char *error,
136 		const zbx_vector_ptr_t *results)
137 {
138 	zbx_uint32_t			data_len = 0, error_len, *recipient_len, *info_len;
139 	unsigned char			*ptr;
140 	int				i;
141 	zbx_alerter_dispatch_result_t	*result;
142 
143 	zbx_serialize_prepare_value(data_len, status);
144 	zbx_serialize_prepare_str(data_len, error);
145 
146 	if (SUCCEED == status)
147 	{
148 		zbx_serialize_prepare_value(data_len, results->values_num);
149 		recipient_len = (zbx_uint32_t *)zbx_malloc(NULL, sizeof(zbx_uint32_t) * results->values_num);
150 		info_len = (zbx_uint32_t *)zbx_malloc(NULL, sizeof(zbx_uint32_t) * results->values_num);
151 
152 		for (i = 0; i < results->values_num; i++)
153 		{
154 			result = (zbx_alerter_dispatch_result_t *)results->values[i];
155 			zbx_serialize_prepare_value(data_len, result->status);
156 			zbx_serialize_prepare_str_len(data_len, result->recipient, recipient_len[i]);
157 			zbx_serialize_prepare_str_len(data_len, result->info, info_len[i]);
158 		}
159 	}
160 	else
161 	{
162 		i = 0;
163 		zbx_serialize_prepare_value(data_len, i);
164 	}
165 
166 	*data = (unsigned char *)zbx_malloc(NULL, data_len);
167 	ptr = *data;
168 
169 	ptr += zbx_serialize_value(ptr, status);
170 	ptr += zbx_serialize_str(ptr, error, error_len);
171 
172 	if (SUCCEED == status)
173 	{
174 		ptr += zbx_serialize_value(ptr, results->values_num);
175 
176 		for (i = 0; i < results->values_num; i++)
177 		{
178 			result = (zbx_alerter_dispatch_result_t *)results->values[i];
179 			ptr += zbx_serialize_value(ptr, result->status);
180 			ptr += zbx_serialize_str(ptr, result->recipient, recipient_len[i]);
181 			ptr += zbx_serialize_str(ptr, result->info, info_len[i]);
182 		}
183 
184 		zbx_free(info_len);
185 		zbx_free(recipient_len);
186 	}
187 	else
188 		(void)zbx_serialize_value(ptr, i);
189 
190 	return data_len;
191 }
192 
report_deserialize_response(const unsigned char * data,int * status,char ** error,zbx_vector_ptr_t * results)193 void	report_deserialize_response(const unsigned char *data, int *status, char **error, zbx_vector_ptr_t *results)
194 {
195 	zbx_uint32_t	len;
196 
197 	data += zbx_deserialize_value(data, status);
198 	data += zbx_deserialize_str(data, error, len);
199 
200 	if (SUCCEED == *status && NULL != results)
201 	{
202 		int				i, results_num;
203 		zbx_alerter_dispatch_result_t	*result;
204 
205 		data += zbx_deserialize_value(data, &results_num);
206 
207 		if (0 != results_num)
208 		{
209 			zbx_vector_ptr_reserve(results, (size_t)results_num);
210 
211 			for (i = 0; i < results_num; i++)
212 			{
213 				result = zbx_malloc(NULL, sizeof(zbx_alerter_dispatch_result_t));
214 				data += zbx_deserialize_value(data, &result->status);
215 				data += zbx_deserialize_str(data, &result->recipient, len);
216 				data += zbx_deserialize_str(data, &result->info, len);
217 				zbx_vector_ptr_append(results, result);
218 			}
219 		}
220 	}
221 }
222 
223 /******************************************************************************
224  *                                                                            *
225  * ZBX_IPC_REPORTER_BEGIN_REPORT message serialization/deserialization        *
226  *                                                                            *
227  ******************************************************************************/
228 
report_serialize_begin_report(unsigned char ** data,const char * name,const char * url,const char * cookie,int width,int height,const zbx_vector_ptr_pair_t * params)229 zbx_uint32_t	report_serialize_begin_report(unsigned char **data, const char *name, const char *url,
230 		const char *cookie, int width, int height, const zbx_vector_ptr_pair_t *params)
231 {
232 	zbx_uint32_t	data_len = 0, *params_len, url_len, cookie_len, name_len;
233 	unsigned char	*ptr;
234 	int		i;
235 
236 	zbx_serialize_prepare_str(data_len, name);
237 	zbx_serialize_prepare_str(data_len, url);
238 	zbx_serialize_prepare_str(data_len, cookie);
239 	zbx_serialize_prepare_value(data_len, width);
240 	zbx_serialize_prepare_value(data_len, height);
241 	zbx_serialize_prepare_value(data_len, params->values_num);
242 
243 	params_len = (zbx_uint32_t *)zbx_malloc(NULL, params->values_num * 2 * sizeof(zbx_uint32_t));
244 	for (i = 0; i < params->values_num; i++)
245 	{
246 		zbx_serialize_prepare_str_len(data_len, params->values[i].first, params_len[i * 2]);
247 		zbx_serialize_prepare_str_len(data_len, params->values[i].second, params_len[i * 2 + 1]);
248 	}
249 
250 	*data = (unsigned char *)zbx_malloc(NULL, data_len);
251 	ptr = *data;
252 
253 	ptr += zbx_serialize_str(ptr, name, name_len);
254 	ptr += zbx_serialize_str(ptr, url, url_len);
255 	ptr += zbx_serialize_str(ptr, cookie, cookie_len);
256 	ptr += zbx_serialize_value(ptr, width);
257 	ptr += zbx_serialize_value(ptr, height);
258 
259 	ptr += zbx_serialize_value(ptr, params->values_num);
260 
261 	for (i = 0; i < params->values_num; i++)
262 	{
263 		ptr += zbx_serialize_str(ptr, params->values[i].first, params_len[i * 2]);
264 		ptr += zbx_serialize_str(ptr, params->values[i].second, params_len[i * 2 + 1]);
265 	}
266 
267 	zbx_free(params_len);
268 
269 	return data_len;
270 }
271 
report_deserialize_begin_report(const unsigned char * data,char ** name,char ** url,char ** cookie,int * width,int * height,zbx_vector_ptr_pair_t * params)272 void	report_deserialize_begin_report(const unsigned char *data, char **name, char **url, char **cookie,
273 		int *width, int *height, zbx_vector_ptr_pair_t *params)
274 {
275 	zbx_uint32_t	len;
276 	int		i, params_num;
277 
278 	data += zbx_deserialize_str(data, name, len);
279 	data += zbx_deserialize_str(data, url, len);
280 	data += zbx_deserialize_str(data, cookie, len);
281 	data += zbx_deserialize_value(data, width);
282 	data += zbx_deserialize_value(data, height);
283 
284 	data += zbx_deserialize_value(data, &params_num);
285 	zbx_vector_ptr_pair_reserve(params, (size_t)params_num);
286 	for (i = 0; i < params_num; i++)
287 	{
288 		zbx_ptr_pair_t	pair;
289 
290 		data += zbx_deserialize_str(data, (char **)&pair.first, len);
291 		data += zbx_deserialize_str(data, (char **)&pair.second, len);
292 		zbx_vector_ptr_pair_append(params, pair);
293 	}
294 }
295 
296 /******************************************************************************
297  *                                                                            *
298  * ZBX_IPC_REPORTER_SEND_REPORT message serialization/deserialization        *
299  *                                                                            *
300  ******************************************************************************/
301 
report_serialize_send_report(unsigned char ** data,const DB_MEDIATYPE * mt,const zbx_vector_str_t * emails)302 zbx_uint32_t	report_serialize_send_report(unsigned char **data, const DB_MEDIATYPE *mt,
303 		const zbx_vector_str_t *emails)
304 {
305 	zbx_uint32_t	data_len = 0, data_alloc = 1024, data_offset = 0, *params_len;
306 	unsigned char	*ptr;
307 	int		i;
308 
309 	*data = zbx_malloc(NULL, data_alloc);
310 	zbx_serialize_mediatype(data, &data_alloc, &data_offset, mt);
311 
312 	zbx_serialize_prepare_value(data_len, emails->values_num);
313 	params_len = (zbx_uint32_t *)zbx_malloc(NULL, emails->values_num * sizeof(zbx_uint32_t));
314 	for (i = 0; i < emails->values_num; i++)
315 	{
316 		zbx_serialize_prepare_str_len(data_len, emails->values[i], params_len[i]);
317 	}
318 
319 	if (data_alloc - data_offset < data_len)
320 	{
321 		data_alloc = data_offset + data_len;
322 		*data = (unsigned char *)zbx_realloc(*data, data_alloc);
323 	}
324 
325 	ptr = *data + data_offset;
326 	ptr += zbx_serialize_value(ptr, emails->values_num);
327 	for (i = 0; i < emails->values_num; i++)
328 	{
329 		ptr += zbx_serialize_str(ptr, emails->values[i], params_len[i]);
330 	}
331 
332 	zbx_free(params_len);
333 
334 	return data_offset + data_len;
335 }
336 
report_deserialize_send_report(const unsigned char * data,DB_MEDIATYPE * mt,zbx_vector_str_t * sendtos)337 void	report_deserialize_send_report(const unsigned char *data, DB_MEDIATYPE *mt, zbx_vector_str_t *sendtos)
338 {
339 	zbx_uint32_t	len;
340 	int		i, sendto_num;
341 
342 	data += zbx_deserialize_mediatype(data, mt);
343 
344 	data += zbx_deserialize_value(data, &sendto_num);
345 	zbx_vector_str_reserve(sendtos, (size_t)sendto_num);
346 	for (i = 0; i < sendto_num; i++)
347 	{
348 		char	*sendto;
349 
350 		data += zbx_deserialize_str(data, &sendto, len);
351 		zbx_vector_str_append(sendtos, sendto);
352 	}
353 }
354 
report_clear_ptr_pairs(zbx_vector_ptr_pair_t * params)355 static void	report_clear_ptr_pairs(zbx_vector_ptr_pair_t *params)
356 {
357 	int	i;
358 
359 	for (i = 0; i < params->values_num; i++)
360 	{
361 		zbx_free(params->values[i].first);
362 		zbx_free(params->values[i].second);
363 	}
364 }
365 
report_clear_params(zbx_vector_ptr_pair_t * params)366 void	report_clear_params(zbx_vector_ptr_pair_t *params)
367 {
368 	report_clear_ptr_pairs(params);
369 	zbx_vector_ptr_pair_clear(params);
370 }
371 
report_destroy_params(zbx_vector_ptr_pair_t * params)372 void	report_destroy_params(zbx_vector_ptr_pair_t *params)
373 {
374 	report_clear_ptr_pairs(params);
375 	zbx_vector_ptr_pair_destroy(params);
376 }
377 
zbx_report_test(const struct zbx_json_parse * jp,zbx_uint64_t userid,struct zbx_json * j)378 void	zbx_report_test(const struct zbx_json_parse *jp, zbx_uint64_t userid, struct zbx_json *j)
379 {
380 	zbx_uint64_t		dashboardid, viewer_userid, ui64;
381 	int			ret = FAIL, period, report_time;
382 	struct zbx_json_parse	jp_params;
383 	zbx_vector_ptr_pair_t	params;
384 	zbx_vector_ptr_t	results;
385 	zbx_uint32_t		size;
386 	unsigned char		*data = NULL, *response = NULL;
387 	char			*name = NULL, *error = NULL;
388 	size_t			name_alloc = 0;
389 
390 	zbx_vector_ptr_pair_create(&params);
391 	zbx_vector_ptr_create(&results);
392 
393 	if (SUCCEED != zbx_json_value_by_name_dyn(jp, ZBX_PROTO_TAG_NAME, &name, &name_alloc, NULL))
394 	{
395 		error = zbx_dsprintf(error, "cannot find tag: %s", ZBX_PROTO_TAG_NAME);
396 		goto out;
397 	}
398 
399 	if (SUCCEED != json_uint_by_tag(jp, ZBX_PROTO_TAG_DASHBOARDID, &dashboardid, &error))
400 		goto out;
401 
402 	if (SUCCEED != json_uint_by_tag(jp, ZBX_PROTO_TAG_USERID, &viewer_userid, &error))
403 		goto out;
404 
405 	if (SUCCEED != json_uint_by_tag(jp, ZBX_PROTO_TAG_PERIOD, &ui64, &error))
406 		goto out;
407 	period = (int)ui64;
408 
409 	if (SUCCEED != json_uint_by_tag(jp, ZBX_PROTO_TAG_NOW, &ui64, &error))
410 		goto out;
411 	report_time = (int)ui64;
412 
413 	if (SUCCEED == zbx_json_brackets_by_name(jp, ZBX_PROTO_TAG_PARAMS, &jp_params))
414 	{
415 		const char		*pnext = NULL;
416 		char			key[MAX_STRING_LEN];
417 
418 		while (NULL != (pnext = zbx_json_pair_next(&jp_params, pnext, key, sizeof(key))))
419 		{
420 			char		*value = NULL;
421 			size_t		value_alloc = 0;
422 			zbx_ptr_pair_t	pair;
423 
424 			zbx_json_decodevalue_dyn(pnext, &value, &value_alloc, NULL);
425 			pair.first = zbx_strdup(NULL, key);
426 			pair.second = value;
427 			zbx_vector_ptr_pair_append(&params, pair);
428 		}
429 	}
430 
431 	size = report_serialize_test_report(&data, name, dashboardid, userid, viewer_userid, report_time, period,
432 			&params);
433 
434 	if (SUCCEED != zbx_ipc_async_exchange(ZBX_IPC_SERVICE_REPORTER, ZBX_IPC_REPORTER_TEST,
435 			SEC_PER_MIN, data, size, &response, &error))
436 	{
437 		goto out;
438 	}
439 
440 	report_deserialize_response(response, &ret, &error, &results);
441 out:
442 	zbx_json_init(j, 1024);
443 
444 	if (SUCCEED == ret)
445 	{
446 		int				i;
447 		zbx_alerter_dispatch_result_t	*result;
448 
449 		zbx_json_addstring(j, ZBX_PROTO_TAG_RESPONSE, ZBX_PROTO_VALUE_SUCCESS, ZBX_JSON_TYPE_STRING);
450 		zbx_json_addobject(j, ZBX_PROTO_TAG_DATA);
451 		zbx_json_addarray(j, ZBX_PROTO_TAG_RECIPIENTS);
452 
453 		for (i = 0; i < results.values_num; i++)
454 		{
455 			zbx_json_addobject(j, NULL);
456 
457 			result = (zbx_alerter_dispatch_result_t *)results.values[i];
458 			zbx_json_addint64(j, ZBX_PROTO_TAG_STATUS, result->status);
459 			zbx_json_addstring(j, ZBX_PROTO_TAG_RECIPIENT, result->recipient, ZBX_JSON_TYPE_STRING);
460 			if (NULL != result->info)
461 				zbx_json_addstring(j, ZBX_PROTO_TAG_INFO, result->info, ZBX_JSON_TYPE_STRING);
462 
463 			zbx_json_close(j);
464 		}
465 	}
466 	else
467 	{
468 		zbx_json_addstring(j, ZBX_PROTO_TAG_RESPONSE, ZBX_PROTO_VALUE_FAILED, ZBX_JSON_TYPE_STRING);
469 		zbx_json_addstring(j, ZBX_PROTO_TAG_INFO, error, ZBX_JSON_TYPE_STRING);
470 	}
471 
472 	zbx_free(error);
473 	zbx_free(response);
474 	zbx_free(data);
475 	zbx_free(name);
476 
477 	zbx_vector_ptr_clear_ext(&results, (zbx_clean_func_t)zbx_alerter_dispatch_result_free);
478 	zbx_vector_ptr_destroy(&results);
479 	report_destroy_params(&params);
480 }
481