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 "../poller/checks_agent.h"
22 #include "../ipmi/ipmi.h"
23 #include "../poller/checks_ssh.h"
24 #include "../poller/checks_telnet.h"
25 #include "zbxexec.h"
26 #include "zbxserver.h"
27 #include "db.h"
28 #include "log.h"
29 #include "zbxtasks.h"
30 #include "scripts.h"
31 #include "zbxjson.h"
32 #include "zbxembed.h"
33 #include "../events.h"
34 
35 extern int	CONFIG_TRAPPER_TIMEOUT;
36 extern int	CONFIG_IPMIPOLLER_FORKS;
37 
zbx_execute_script_on_agent(const DC_HOST * host,const char * command,char ** result,char * error,size_t max_error_len)38 static int	zbx_execute_script_on_agent(const DC_HOST *host, const char *command, char **result,
39 		char *error, size_t max_error_len)
40 {
41 	int		ret;
42 	AGENT_RESULT	agent_result;
43 	char		*param = NULL, *port = NULL;
44 	DC_ITEM		item;
45 
46 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
47 
48 	*error = '\0';
49 	memset(&item, 0, sizeof(item));
50 	memcpy(&item.host, host, sizeof(item.host));
51 
52 	if (SUCCEED != (ret = DCconfig_get_interface_by_type(&item.interface, host->hostid, INTERFACE_TYPE_AGENT)))
53 	{
54 		zbx_snprintf(error, max_error_len, "Zabbix agent interface is not defined for host [%s]", host->host);
55 		goto fail;
56 	}
57 
58 	port = zbx_strdup(port, item.interface.port_orig);
59 	substitute_simple_macros(NULL, NULL, NULL, NULL, &host->hostid, NULL, NULL, NULL, NULL, NULL,
60 			&port, MACRO_TYPE_COMMON, NULL, 0);
61 
62 	if (SUCCEED != (ret = is_ushort(port, &item.interface.port)))
63 	{
64 		zbx_snprintf(error, max_error_len, "Invalid port number [%s]", item.interface.port_orig);
65 		goto fail;
66 	}
67 
68 	param = zbx_strdup(param, command);
69 	if (SUCCEED != (ret = quote_key_param(&param, 0)))
70 	{
71 		zbx_snprintf(error, max_error_len, "Invalid param [%s]", param);
72 		goto fail;
73 	}
74 
75 	item.key = zbx_dsprintf(item.key, "system.run[%s%s]", param, NULL == result ? ",nowait" : "");
76 	item.value_type = ITEM_VALUE_TYPE_TEXT;
77 
78 	init_result(&agent_result);
79 
80 	zbx_alarm_on(CONFIG_TIMEOUT);
81 
82 	if (SUCCEED != (ret = get_value_agent(&item, &agent_result)))
83 	{
84 		if (ISSET_MSG(&agent_result))
85 			zbx_strlcpy(error, agent_result.msg, max_error_len);
86 		ret = FAIL;
87 	}
88 	else if (NULL != result && ISSET_TEXT(&agent_result))
89 		*result = zbx_strdup(*result, agent_result.text);
90 
91 	zbx_alarm_off();
92 
93 	free_result(&agent_result);
94 
95 	zbx_free(item.key);
96 fail:
97 	zbx_free(port);
98 	zbx_free(param);
99 
100 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
101 
102 	return ret;
103 }
104 
zbx_execute_script_on_terminal(const DC_HOST * host,const zbx_script_t * script,char ** result,char * error,size_t max_error_len)105 static int	zbx_execute_script_on_terminal(const DC_HOST *host, const zbx_script_t *script, char **result,
106 		char *error, size_t max_error_len)
107 {
108 	int		ret = FAIL, i;
109 	AGENT_RESULT	agent_result;
110 	DC_ITEM		item;
111 	int             (*function)(DC_ITEM *, AGENT_RESULT *);
112 
113 #if defined(HAVE_SSH2) || defined(HAVE_SSH)
114 	assert(ZBX_SCRIPT_TYPE_SSH == script->type || ZBX_SCRIPT_TYPE_TELNET == script->type);
115 #else
116 	assert(ZBX_SCRIPT_TYPE_TELNET == script->type);
117 #endif
118 
119 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
120 
121 	*error = '\0';
122 	memset(&item, 0, sizeof(item));
123 	memcpy(&item.host, host, sizeof(item.host));
124 
125 	for (i = 0; INTERFACE_TYPE_COUNT > i; i++)
126 	{
127 		if (SUCCEED == (ret = DCconfig_get_interface_by_type(&item.interface, host->hostid,
128 				INTERFACE_TYPE_PRIORITY[i])))
129 		{
130 			break;
131 		}
132 	}
133 
134 	if (FAIL == ret)
135 	{
136 		zbx_snprintf(error, max_error_len, "No interface defined for host [%s]", host->host);
137 		goto fail;
138 	}
139 
140 	switch (script->type)
141 	{
142 		case ZBX_SCRIPT_TYPE_SSH:
143 			item.authtype = script->authtype;
144 			item.publickey = script->publickey;
145 			item.privatekey = script->privatekey;
146 			ZBX_FALLTHROUGH;
147 		case ZBX_SCRIPT_TYPE_TELNET:
148 			item.username = script->username;
149 			item.password = script->password;
150 			break;
151 	}
152 
153 #if defined(HAVE_SSH2) || defined(HAVE_SSH)
154 	if (ZBX_SCRIPT_TYPE_SSH == script->type)
155 	{
156 		item.key = zbx_dsprintf(item.key, "ssh.run[,,%s]", script->port);
157 		function = get_value_ssh;
158 	}
159 	else
160 	{
161 #endif
162 		item.key = zbx_dsprintf(item.key, "telnet.run[,,%s]", script->port);
163 		function = get_value_telnet;
164 #if defined(HAVE_SSH2) || defined(HAVE_SSH)
165 	}
166 #endif
167 	item.value_type = ITEM_VALUE_TYPE_TEXT;
168 	item.params = zbx_strdup(item.params, script->command);
169 
170 	init_result(&agent_result);
171 
172 	zbx_alarm_on(CONFIG_TIMEOUT);
173 
174 	if (SUCCEED != (ret = function(&item, &agent_result)))
175 	{
176 		if (ISSET_MSG(&agent_result))
177 			zbx_strlcpy(error, agent_result.msg, max_error_len);
178 		ret = FAIL;
179 	}
180 	else if (NULL != result && ISSET_TEXT(&agent_result))
181 		*result = zbx_strdup(*result, agent_result.text);
182 
183 	zbx_alarm_off();
184 
185 	free_result(&agent_result);
186 
187 	zbx_free(item.params);
188 	zbx_free(item.key);
189 fail:
190 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
191 
192 	return ret;
193 }
194 
zbx_check_script_permissions(zbx_uint64_t groupid,zbx_uint64_t hostid)195 int	zbx_check_script_permissions(zbx_uint64_t groupid, zbx_uint64_t hostid)
196 {
197 	DB_RESULT		result;
198 	int			ret = SUCCEED;
199 	zbx_vector_uint64_t	groupids;
200 	char			*sql = NULL;
201 	size_t			sql_alloc = 0, sql_offset = 0;
202 
203 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() groupid:" ZBX_FS_UI64 " hostid:" ZBX_FS_UI64, __func__, groupid, hostid);
204 
205 	if (0 == groupid)
206 		goto exit;
207 
208 	zbx_vector_uint64_create(&groupids);
209 	zbx_dc_get_nested_hostgroupids(&groupid, 1, &groupids);
210 
211 	zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
212 			"select hostid"
213 			" from hosts_groups"
214 			" where hostid=" ZBX_FS_UI64
215 				" and",
216 			hostid);
217 
218 	DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "groupid", groupids.values,
219 			groupids.values_num);
220 
221 	result = DBselect("%s", sql);
222 
223 	zbx_free(sql);
224 	zbx_vector_uint64_destroy(&groupids);
225 
226 	if (NULL == DBfetch(result))
227 		ret = FAIL;
228 
229 	DBfree_result(result);
230 exit:
231 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
232 
233 	return ret;
234 }
235 
zbx_check_script_user_permissions(zbx_uint64_t userid,zbx_uint64_t hostid,zbx_script_t * script)236 int	zbx_check_script_user_permissions(zbx_uint64_t userid, zbx_uint64_t hostid, zbx_script_t *script)
237 {
238 	int		ret = SUCCEED;
239 	DB_RESULT	result;
240 
241 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() userid:" ZBX_FS_UI64 " hostid:" ZBX_FS_UI64 " scriptid:" ZBX_FS_UI64,
242 			__func__, userid, hostid, script->scriptid);
243 
244 	result = DBselect(
245 		"select null"
246 			" from hosts_groups hg,rights r,users_groups ug"
247 		" where hg.groupid=r.id"
248 			" and r.groupid=ug.usrgrpid"
249 			" and hg.hostid=" ZBX_FS_UI64
250 			" and ug.userid=" ZBX_FS_UI64
251 		" group by hg.hostid"
252 		" having min(r.permission)>%d"
253 			" and max(r.permission)>=%d",
254 		hostid,
255 		userid,
256 		PERM_DENY,
257 		script->host_access);
258 
259 	if (NULL == DBfetch(result))
260 		ret = FAIL;
261 
262 	DBfree_result(result);
263 
264 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
265 
266 	return ret;
267 }
268 
zbx_script_init(zbx_script_t * script)269 void	zbx_script_init(zbx_script_t *script)
270 {
271 	memset(script, 0, sizeof(zbx_script_t));
272 }
273 
zbx_script_clean(zbx_script_t * script)274 void	zbx_script_clean(zbx_script_t *script)
275 {
276 	zbx_free(script->port);
277 	zbx_free(script->username);
278 	zbx_free(script->publickey);
279 	zbx_free(script->privatekey);
280 	zbx_free(script->password);
281 	zbx_free(script->command);
282 	zbx_free(script->command_orig);
283 }
284 
285 /******************************************************************************
286  *                                                                            *
287  * Function: zbx_webhook_params_pack_json                                     *
288  *                                                                            *
289  * Purpose: pack webhook script parameters into JSON                          *
290  *                                                                            *
291  * Parameters: params      - [IN] vector of pairs of pointers to parameter    *
292  *                                names and values                            *
293  *             params_json - [OUT] JSON string                                *
294  *                                                                            *
295  ******************************************************************************/
zbx_webhook_params_pack_json(const zbx_vector_ptr_pair_t * params,char ** params_json)296 void	zbx_webhook_params_pack_json(const zbx_vector_ptr_pair_t *params, char **params_json)
297 {
298 	struct zbx_json	json_data;
299 	int		i;
300 
301 	zbx_json_init(&json_data, ZBX_JSON_STAT_BUF_LEN);
302 
303 	for (i = 0; i < params->values_num; i++)
304 	{
305 		zbx_ptr_pair_t	pair = params->values[i];
306 
307 		zbx_json_addstring(&json_data, pair.first, pair.second, ZBX_JSON_TYPE_STRING);
308 	}
309 
310 	zbx_json_close(&json_data);
311 	*params_json = zbx_strdup(*params_json, json_data.buffer);
312 	zbx_json_free(&json_data);
313 }
314 
315 /***********************************************************************************
316  *                                                                                 *
317  * Function: zbx_script_prepare                                                    *
318  *                                                                                 *
319  * Purpose: prepares user script                                                   *
320  *                                                                                 *
321  * Parameters: script        - [IN] the script to prepare                          *
322  *             host          - [IN] the host the script will be executed on        *
323  *             error         - [OUT] the error message buffer                      *
324  *             max_error_len - [IN] the size of error message output buffer        *
325  *                                                                                 *
326  * Return value:  SUCCEED - the script has been prepared successfully              *
327  *                FAIL    - otherwise, error contains error message                *
328  *                                                                                 *
329  * Comments: This function prepares script for execution by loading global         *
330  *           script/expanding macros (except in script body).                      *
331  *           Prepared scripts must be always freed with zbx_script_clean()         *
332  *           function.                                                             *
333  *                                                                                 *
334  ***********************************************************************************/
zbx_script_prepare(zbx_script_t * script,const zbx_uint64_t * hostid,char * error,size_t max_error_len)335 int	zbx_script_prepare(zbx_script_t *script, const zbx_uint64_t *hostid, char *error, size_t max_error_len)
336 {
337 	int	ret = FAIL;
338 
339 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
340 
341 	switch (script->type)
342 	{
343 		case ZBX_SCRIPT_TYPE_SSH:
344 			substitute_simple_macros(NULL, NULL, NULL, NULL, hostid, NULL, NULL, NULL, NULL, NULL,
345 					&script->publickey, MACRO_TYPE_COMMON, NULL, 0);
346 			substitute_simple_macros(NULL, NULL, NULL, NULL, hostid, NULL, NULL, NULL, NULL, NULL,
347 					&script->privatekey, MACRO_TYPE_COMMON, NULL, 0);
348 			ZBX_FALLTHROUGH;
349 		case ZBX_SCRIPT_TYPE_TELNET:
350 			substitute_simple_macros(NULL, NULL, NULL, NULL, hostid, NULL, NULL, NULL, NULL, NULL,
351 					&script->port, MACRO_TYPE_COMMON, NULL, 0);
352 
353 			if ('\0' != *script->port && SUCCEED != (ret = is_ushort(script->port, NULL)))
354 			{
355 				zbx_snprintf(error, max_error_len, "Invalid port number \"%s\"", script->port);
356 				goto out;
357 			}
358 
359 			substitute_simple_macros_unmasked(NULL, NULL, NULL, NULL, hostid, NULL, NULL, NULL, NULL,
360 					NULL, &script->username, MACRO_TYPE_COMMON, NULL, 0);
361 			substitute_simple_macros_unmasked(NULL, NULL, NULL, NULL, hostid, NULL, NULL, NULL, NULL,
362 					NULL, &script->password, MACRO_TYPE_COMMON, NULL, 0);
363 			break;
364 		case ZBX_SCRIPT_TYPE_CUSTOM_SCRIPT:
365 			dos2unix(script->command);	/* CR+LF (Windows) => LF (Unix) */
366 			break;
367 		case ZBX_SCRIPT_TYPE_WEBHOOK:
368 		case ZBX_SCRIPT_TYPE_IPMI:
369 			break;
370 		default:
371 			zbx_snprintf(error, max_error_len, "Invalid command type \"%d\".", (int)script->type);
372 			goto out;
373 	}
374 
375 	ret = SUCCEED;
376 out:
377 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
378 	return ret;
379 }
380 
381 /******************************************************************************
382  *                                                                            *
383  * Function: DBfetch_webhook_params                                           *
384  *                                                                            *
385  * Purpose: fetch webhook parameters                                          *
386  *                                                                            *
387  * Parameters:  scriptid  - [IN] the id of script to be executed              *
388  *              params    - [OUT] parameters name-value pairs                 *
389  *              error     - [IN/OUT] the error message                        *
390  *              error_len - [IN] the maximum error length                     *
391  *                                                                            *
392  * Return value:  SUCCEED - processed successfully                            *
393  *                FAIL - an error occurred                                    *
394  *                                                                            *
395  ******************************************************************************/
DBfetch_webhook_params(zbx_uint64_t scriptid,zbx_vector_ptr_pair_t * params,char * error,size_t error_len)396 int	DBfetch_webhook_params(zbx_uint64_t scriptid, zbx_vector_ptr_pair_t *params, char *error, size_t error_len)
397 {
398 	int		ret = SUCCEED;
399 	DB_RESULT	result;
400 	DB_ROW		row;
401 	zbx_ptr_pair_t	pair;
402 
403 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() scriptid:" ZBX_FS_UI64, __func__, scriptid);
404 
405 	result = DBselect("select name,value from script_param where scriptid=" ZBX_FS_UI64, scriptid);
406 
407 	if (NULL == result)
408 	{
409 		zbx_strlcpy(error, "Database error, cannot get webhook script parameters.", error_len);
410 		ret = FAIL;
411 		goto out;
412 	}
413 
414 	while (NULL != (row = DBfetch(result)))
415 	{
416 		pair.first = zbx_strdup(NULL, row[0]);
417 		pair.second = zbx_strdup(NULL, row[1]);
418 		zbx_vector_ptr_pair_append(params, pair);
419 	}
420 
421 	DBfree_result(result);
422 out:
423 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
424 
425 	return ret;
426 }
427 
428 /******************************************************************************
429  *                                                                            *
430  * Function: zbx_script_execute                                               *
431  *                                                                            *
432  * Purpose: executing user scripts or remote commands                         *
433  *                                                                            *
434  * Parameters:  script         - [IN] the script to be executed               *
435  *              host           - [IN] the host the script will be executed on *
436  *              params         - [IN] parameters for the script               *
437  *              result         - [OUT] the result of a script execution       *
438  *              error          - [OUT] the error reported by the script       *
439  *              max_error_len  - [IN] the maximum error length                *
440  *              debug          - [OUT] the debug data (optional)              *
441  *                                                                            *
442  * Return value:  SUCCEED - processed successfully                            *
443  *                FAIL - an error occurred                                    *
444  *                TIMEOUT_ERROR - a timeout occurred                          *
445  *                                                                            *
446  ******************************************************************************/
zbx_script_execute(const zbx_script_t * script,const DC_HOST * host,const char * params,char ** result,char * error,size_t max_error_len,char ** debug)447 int	zbx_script_execute(const zbx_script_t *script, const DC_HOST *host, const char *params, char **result,
448 		char *error, size_t max_error_len, char **debug)
449 {
450 	int	ret = FAIL;
451 
452 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
453 
454 	*error = '\0';
455 
456 	switch (script->type)
457 	{
458 		case ZBX_SCRIPT_TYPE_WEBHOOK:
459 			ret = zbx_es_execute_command(script->command, params, script->timeout, result, error,
460 					max_error_len, debug);
461 			break;
462 		case ZBX_SCRIPT_TYPE_CUSTOM_SCRIPT:
463 			switch (script->execute_on)
464 			{
465 				case ZBX_SCRIPT_EXECUTE_ON_AGENT:
466 					ret = zbx_execute_script_on_agent(host, script->command, result, error,
467 							max_error_len);
468 					break;
469 				case ZBX_SCRIPT_EXECUTE_ON_SERVER:
470 				case ZBX_SCRIPT_EXECUTE_ON_PROXY:
471 					ret = zbx_execute(script->command, result, error, max_error_len,
472 							CONFIG_TRAPPER_TIMEOUT, ZBX_EXIT_CODE_CHECKS_ENABLED, NULL);
473 					break;
474 				default:
475 					zbx_snprintf(error, max_error_len, "Invalid 'Execute on' option \"%d\".",
476 							(int)script->execute_on);
477 			}
478 			break;
479 		case ZBX_SCRIPT_TYPE_IPMI:
480 #ifdef HAVE_OPENIPMI
481 			if (0 == CONFIG_IPMIPOLLER_FORKS)
482 			{
483 				zbx_strlcpy(error, "Cannot perform IPMI request: configuration parameter"
484 						" \"StartIPMIPollers\" is 0.", max_error_len);
485 				break;
486 			}
487 
488 			if (SUCCEED == (ret = zbx_ipmi_execute_command(host, script->command, error, max_error_len)))
489 			{
490 				if (NULL != result)
491 					*result = zbx_strdup(*result, "IPMI command successfully executed.");
492 			}
493 #else
494 			zbx_strlcpy(error, "Support for IPMI commands was not compiled in.", max_error_len);
495 #endif
496 			break;
497 		case ZBX_SCRIPT_TYPE_SSH:
498 #if !defined(HAVE_SSH2) && !defined(HAVE_SSH)
499 			zbx_strlcpy(error, "Support for SSH script was not compiled in.", max_error_len);
500 			break;
501 #endif
502 		case ZBX_SCRIPT_TYPE_TELNET:
503 			ret = zbx_execute_script_on_terminal(host, script, result, error, max_error_len);
504 			break;
505 		default:
506 			zbx_snprintf(error, max_error_len, "Invalid command type \"%d\".", (int)script->type);
507 	}
508 
509 	if (SUCCEED != ret && NULL != result)
510 		*result = zbx_strdup(*result, "");
511 
512 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
513 
514 	return ret;
515 }
516 
517 /******************************************************************************
518  *                                                                            *
519  * Function: zbx_script_create_task                                           *
520  *                                                                            *
521  * Purpose: creates remote command task from a script                         *
522  *                                                                            *
523  * Return value:  the identifier of the created task or 0 in the case of      *
524  *                error                                                       *
525  *                                                                            *
526  ******************************************************************************/
zbx_script_create_task(const zbx_script_t * script,const DC_HOST * host,zbx_uint64_t alertid,int now)527 zbx_uint64_t	zbx_script_create_task(const zbx_script_t *script, const DC_HOST *host, zbx_uint64_t alertid, int now)
528 {
529 	zbx_tm_task_t	*task;
530 	unsigned short	port;
531 	zbx_uint64_t	taskid;
532 
533 	if (NULL != script->port && '\0' != script->port[0])
534 		is_ushort(script->port, &port);
535 	else
536 		port = 0;
537 
538 	DBbegin();
539 
540 	taskid = DBget_maxid("task");
541 
542 	task = zbx_tm_task_create(taskid, ZBX_TM_TASK_REMOTE_COMMAND, ZBX_TM_STATUS_NEW, now,
543 			ZBX_REMOTE_COMMAND_TTL, host->proxy_hostid);
544 
545 	task->data = zbx_tm_remote_command_create(script->type, script->command, script->execute_on, port,
546 			script->authtype, script->username, script->password, script->publickey, script->privatekey,
547 			taskid, host->hostid, alertid);
548 
549 	if (FAIL == zbx_tm_save_task(task))
550 		taskid = 0;
551 
552 	DBcommit();
553 
554 	zbx_tm_task_free(task);
555 
556 	return taskid;
557 }
558