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 "poller/checks_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 
30 #include "scripts.h"
31 
32 extern int	CONFIG_TRAPPER_TIMEOUT;
33 
zbx_execute_script_on_agent(DC_HOST * host,const char * command,char ** result,char * error,size_t max_error_len)34 static int	zbx_execute_script_on_agent(DC_HOST *host, const char *command, char **result,
35 		char *error, size_t max_error_len)
36 {
37 	const char	*__function_name = "zbx_execute_script_on_agent";
38 	int		ret;
39 	AGENT_RESULT	agent_result;
40 	char		*param = NULL, *port = NULL;
41 	DC_ITEM		item;
42 
43 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
44 
45 	*error = '\0';
46 	memset(&item, 0, sizeof(item));
47 	memcpy(&item.host, host, sizeof(item.host));
48 
49 	if (SUCCEED != (ret = DCconfig_get_interface_by_type(&item.interface, host->hostid, INTERFACE_TYPE_AGENT)))
50 	{
51 		zbx_snprintf(error, max_error_len, "Zabbix agent interface is not defined for host [%s]", host->host);
52 		goto fail;
53 	}
54 
55 	port = zbx_strdup(port, item.interface.port_orig);
56 	substitute_simple_macros(NULL, NULL, NULL, NULL, &host->hostid, NULL, NULL, NULL,
57 			&port, MACRO_TYPE_COMMON, NULL, 0);
58 
59 	if (SUCCEED != (ret = is_ushort(port, &item.interface.port)))
60 	{
61 		zbx_snprintf(error, max_error_len, "Invalid port number [%s]", item.interface.port_orig);
62 		goto fail;
63 	}
64 
65 	param = zbx_strdup(param, command);
66 	if (SUCCEED != (ret = quote_key_param(&param, 0)))
67 	{
68 		zbx_snprintf(error, max_error_len, "Invalid param [%s]", param);
69 		goto fail;
70 	}
71 
72 	item.key = zbx_dsprintf(item.key, "system.run[%s,%s]", param, NULL == result ? "nowait" : "wait");
73 	item.value_type = ITEM_VALUE_TYPE_TEXT;
74 
75 	init_result(&agent_result);
76 
77 	zbx_alarm_on(CONFIG_TIMEOUT);
78 
79 	if (SUCCEED != (ret = get_value_agent(&item, &agent_result)))
80 	{
81 		if (ISSET_MSG(&agent_result))
82 			zbx_strlcpy(error, agent_result.msg, max_error_len);
83 		ret = FAIL;
84 	}
85 	else if (NULL != result && ISSET_TEXT(&agent_result))
86 		*result = zbx_strdup(*result, agent_result.text);
87 
88 	zbx_alarm_off();
89 
90 	free_result(&agent_result);
91 
92 	zbx_free(item.key);
93 fail:
94 	zbx_free(port);
95 	zbx_free(param);
96 
97 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
98 
99 	return ret;
100 }
101 
102 #ifdef HAVE_OPENIPMI
zbx_execute_ipmi_command(DC_HOST * host,const char * command,char * error,size_t max_error_len)103 static int	zbx_execute_ipmi_command(DC_HOST *host, const char *command, char *error, size_t max_error_len)
104 {
105 	const char	*__function_name = "zbx_execute_ipmi_command";
106 	int		val, ret;
107 	char		*port = NULL;
108 	DC_ITEM		item;
109 
110 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
111 
112 	*error = '\0';
113 	memset(&item, 0, sizeof(item));
114 	memcpy(&item.host, host, sizeof(item.host));
115 
116 	if (SUCCEED != (ret = DCconfig_get_interface_by_type(&item.interface, host->hostid, INTERFACE_TYPE_IPMI)))
117 	{
118 		zbx_snprintf(error, max_error_len, "IPMI interface is not defined for host [%s]", host->host);
119 		goto fail;
120 	}
121 
122 	port = zbx_strdup(port, item.interface.port_orig);
123 	substitute_simple_macros(NULL, NULL, NULL, NULL, &host->hostid, NULL, NULL, NULL, &port,
124 			MACRO_TYPE_COMMON, NULL, 0);
125 
126 	if (SUCCEED != (ret = is_ushort(port, &item.interface.port)))
127 	{
128 		zbx_snprintf(error, max_error_len, "invalid port number [%s]", item.interface.port_orig);
129 		goto fail;
130 	}
131 
132 	if (SUCCEED == (ret = zbx_parse_ipmi_command(command, item.ipmi_sensor, &val, error, max_error_len)))
133 	{
134 		if (SUCCEED != (ret = zbx_set_ipmi_control_value(&item, val, error, max_error_len)))
135 			ret = FAIL;
136 	}
137 fail:
138 	zbx_free(port);
139 
140 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
141 
142 	return ret;
143 }
144 #endif
145 
zbx_execute_script_on_terminal(DC_HOST * host,zbx_script_t * script,char ** result,char * error,size_t max_error_len)146 static int	zbx_execute_script_on_terminal(DC_HOST *host, zbx_script_t *script, char **result,
147 		char *error, size_t max_error_len)
148 {
149 	const char	*__function_name = "zbx_execute_script_on_terminal";
150 	int		ret = FAIL, i;
151 	AGENT_RESULT	agent_result;
152 	DC_ITEM		item;
153 	int             (*function)(DC_ITEM *, AGENT_RESULT *);
154 
155 #ifdef HAVE_SSH2
156 	assert(ZBX_SCRIPT_TYPE_SSH == script->type || ZBX_SCRIPT_TYPE_TELNET == script->type);
157 #else
158 	assert(ZBX_SCRIPT_TYPE_TELNET == script->type);
159 #endif
160 
161 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
162 
163 	*error = '\0';
164 	memset(&item, 0, sizeof(item));
165 	memcpy(&item.host, host, sizeof(item.host));
166 
167 	for (i = 0; INTERFACE_TYPE_COUNT > i; i++)
168 	{
169 		if (SUCCEED == (ret = DCconfig_get_interface_by_type(&item.interface, host->hostid,
170 				INTERFACE_TYPE_PRIORITY[i])))
171 		{
172 			break;
173 		}
174 	}
175 
176 	if (FAIL == ret)
177 	{
178 		zbx_snprintf(error, max_error_len, "No interface defined for host [%s]", host->host);
179 		goto fail;
180 	}
181 
182 	switch (script->type)
183 	{
184 		case ZBX_SCRIPT_TYPE_SSH:
185 			item.authtype = script->authtype;
186 			item.publickey = script->publickey;
187 			item.privatekey = script->privatekey;
188 			/* break; is not missing here */
189 		case ZBX_SCRIPT_TYPE_TELNET:
190 			item.username = script->username;
191 			item.password = script->password;
192 			break;
193 	}
194 
195 	substitute_simple_macros(NULL, NULL, NULL, NULL, &host->hostid, NULL, NULL, NULL,
196 			&script->port, MACRO_TYPE_COMMON, NULL, 0);
197 
198 	if ('\0' != *script->port && SUCCEED != (ret = is_ushort(script->port, NULL)))
199 	{
200 		zbx_snprintf(error, max_error_len, "Invalid port number [%s]", script->port);
201 		goto fail;
202 	}
203 
204 #ifdef HAVE_SSH2
205 	if (ZBX_SCRIPT_TYPE_SSH == script->type)
206 	{
207 		item.key = zbx_dsprintf(item.key, "ssh.run[,,%s]", script->port);
208 		function = get_value_ssh;
209 	}
210 	else
211 	{
212 #endif
213 		item.key = zbx_dsprintf(item.key, "telnet.run[,,%s]", script->port);
214 		function = get_value_telnet;
215 #ifdef HAVE_SSH2
216 	}
217 #endif
218 	item.value_type = ITEM_VALUE_TYPE_TEXT;
219 	item.params = zbx_strdup(item.params, script->command);
220 
221 	init_result(&agent_result);
222 
223 	zbx_alarm_on(CONFIG_TIMEOUT);
224 
225 	if (SUCCEED != (ret = function(&item, &agent_result)))
226 	{
227 		if (ISSET_MSG(&agent_result))
228 			zbx_strlcpy(error, agent_result.msg, max_error_len);
229 		ret = FAIL;
230 	}
231 	else if (NULL != result && ISSET_TEXT(&agent_result))
232 		*result = zbx_strdup(*result, agent_result.text);
233 
234 	zbx_alarm_off();
235 
236 	free_result(&agent_result);
237 
238 	zbx_free(item.params);
239 	zbx_free(item.key);
240 fail:
241 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
242 
243 	return ret;
244 }
245 
DBget_script_by_scriptid(zbx_uint64_t scriptid,zbx_script_t * script,zbx_uint64_t * groupid)246 static int	DBget_script_by_scriptid(zbx_uint64_t scriptid, zbx_script_t *script, zbx_uint64_t *groupid)
247 {
248 	const char	*__function_name = "DBget_script_by_scriptid";
249 	DB_RESULT	result;
250 	DB_ROW		row;
251 	int		ret = FAIL;
252 
253 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
254 
255 	result = DBselect(
256 			"select type,execute_on,command,groupid"
257 			" from scripts"
258 			" where scriptid=" ZBX_FS_UI64,
259 			scriptid);
260 
261 	if (NULL != (row = DBfetch(result)))
262 	{
263 		script->type = (unsigned char)atoi(row[0]);
264 		script->execute_on = (unsigned char)atoi(row[1]);
265 		script->command = zbx_strdup(script->command, row[2]);
266 		ZBX_DBROW2UINT64(*groupid, row[3]);
267 		ret = SUCCEED;
268 	}
269 	DBfree_result(result);
270 
271 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
272 
273 	return ret;
274 }
275 
check_script_permissions(zbx_uint64_t groupid,zbx_uint64_t hostid,char * error,size_t max_error_len)276 static int	check_script_permissions(zbx_uint64_t groupid, zbx_uint64_t hostid, char *error, size_t max_error_len)
277 {
278 	const char	*__function_name = "check_script_permissions";
279 	DB_RESULT	result;
280 	int		ret = SUCCEED;
281 
282 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() groupid:" ZBX_FS_UI64 " hostid:" ZBX_FS_UI64,
283 			__function_name, groupid, hostid);
284 
285 	if (0 == groupid)
286 		goto exit;
287 
288 	result = DBselect(
289 			"select hostid"
290 			" from hosts_groups"
291 			" where hostid=" ZBX_FS_UI64
292 				" and groupid=" ZBX_FS_UI64,
293 			hostid, groupid);
294 
295 	if (NULL == DBfetch(result))
296 	{
297 		zbx_strlcpy(error, "Insufficient permissions. Host is not in an allowed host group.", max_error_len);
298 		ret = FAIL;
299 	}
300 	DBfree_result(result);
301 exit:
302 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
303 
304 	return ret;
305 }
306 
zbx_script_init(zbx_script_t * script)307 void	zbx_script_init(zbx_script_t *script)
308 {
309 	memset(script, 0, sizeof(zbx_script_t));
310 }
311 
zbx_script_clean(zbx_script_t * script)312 void	zbx_script_clean(zbx_script_t *script)
313 {
314 	zbx_free(script->port);
315 	zbx_free(script->username);
316 	zbx_free(script->publickey);
317 	zbx_free(script->privatekey);
318 	zbx_free(script->password);
319 	zbx_free(script->command);
320 }
321 
322 /******************************************************************************
323  *                                                                            *
324  * Function: zbx_execute_script                                               *
325  *                                                                            *
326  * Purpose: executing user scripts or remote commands                         *
327  *                                                                            *
328  * Return value:  SUCCEED - processed successfully                            *
329  *                FAIL - an error occurred                                    *
330  *                TIMEOUT_ERROR - a timeout occurred                          *
331  *                                                                            *
332  * Comments: !!! always call 'zbx_script_clean' function after                *
333  *           'zbx_execute_script' to clear allocated memory                   *
334  *                                                                            *
335  ******************************************************************************/
zbx_execute_script(DC_HOST * host,zbx_script_t * script,char ** result,char * error,size_t max_error_len)336 int	zbx_execute_script(DC_HOST *host, zbx_script_t *script, char **result, char *error, size_t max_error_len)
337 {
338 	const char	*__function_name = "zbx_execute_script";
339 	int		ret = FAIL;
340 	zbx_uint64_t	groupid;
341 
342 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
343 
344 	*error = '\0';
345 
346 	switch (script->type)
347 	{
348 		case ZBX_SCRIPT_TYPE_CUSTOM_SCRIPT:
349 			dos2unix(script->command);	/* CR+LF (Windows) => LF (Unix) */
350 
351 			switch (script->execute_on)
352 			{
353 				case ZBX_SCRIPT_EXECUTE_ON_AGENT:
354 					ret = zbx_execute_script_on_agent(host, script->command, result,
355 							error, max_error_len);
356 					break;
357 				case ZBX_SCRIPT_EXECUTE_ON_SERVER:
358 					ret = zbx_execute(script->command, result, error, max_error_len,
359 							CONFIG_TRAPPER_TIMEOUT);
360 					break;
361 				default:
362 					zbx_snprintf(error, max_error_len, "Invalid 'Execute on' option [%d]",
363 							(int)script->execute_on);
364 			}
365 			break;
366 		case ZBX_SCRIPT_TYPE_IPMI:
367 #ifdef HAVE_OPENIPMI
368 			if (SUCCEED == (ret = zbx_execute_ipmi_command(host, script->command, error, max_error_len)))
369 			{
370 				if (NULL != result)
371 					*result = zbx_strdup(*result, "IPMI command successfully executed");
372 			}
373 #else
374 			zbx_strlcpy(error, "Support for IPMI commands was not compiled in", max_error_len);
375 #endif
376 			break;
377 		case ZBX_SCRIPT_TYPE_SSH:
378 #ifdef HAVE_SSH2
379 			substitute_simple_macros(NULL, NULL, NULL, NULL, &host->hostid, NULL, NULL, NULL,
380 					&script->publickey, MACRO_TYPE_COMMON, NULL, 0);
381 			substitute_simple_macros(NULL, NULL, NULL, NULL, &host->hostid, NULL, NULL, NULL,
382 					&script->privatekey, MACRO_TYPE_COMMON, NULL, 0);
383 			/* break; is not missing here */
384 #else
385 			zbx_strlcpy(error, "Support for SSH script was not compiled in", max_error_len);
386 			break;
387 #endif
388 		case ZBX_SCRIPT_TYPE_TELNET:
389 			substitute_simple_macros(NULL, NULL, NULL, NULL, &host->hostid, NULL, NULL, NULL,
390 					&script->username, MACRO_TYPE_COMMON, NULL, 0);
391 			substitute_simple_macros(NULL, NULL, NULL, NULL, &host->hostid, NULL, NULL, NULL,
392 					&script->password, MACRO_TYPE_COMMON, NULL, 0);
393 
394 			ret = zbx_execute_script_on_terminal(host, script, result, error, max_error_len);
395 			break;
396 		case ZBX_SCRIPT_TYPE_GLOBAL_SCRIPT:
397 			if (SUCCEED != DBget_script_by_scriptid(script->scriptid, script, &groupid))
398 			{
399 				zbx_snprintf(error, max_error_len,
400 						"Unknown Script ID [" ZBX_FS_UI64 "]", script->scriptid);
401 				break;
402 			}
403 
404 			if (SUCCEED != check_script_permissions(groupid, host->hostid, error, max_error_len))
405 				break;
406 
407 			if (SUCCEED != substitute_simple_macros(NULL, NULL, NULL, NULL, NULL, host, NULL,
408 					NULL, &script->command, MACRO_TYPE_SCRIPT, error, max_error_len))
409 			{
410 				break;
411 			}
412 
413 			ret = zbx_execute_script(host, script, result, error, max_error_len);	/* recursion */
414 			break;
415 		default:
416 			zbx_snprintf(error, max_error_len, "Invalid command type [%d]", (int)script->type);
417 	}
418 
419 	if (SUCCEED != ret && NULL != result)
420 		*result = zbx_strdup(*result, "");
421 
422 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
423 
424 	return ret;
425 }
426