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 "nodecommand.h"
22 #include "comms.h"
23 #include "zbxserver.h"
24 #include "db.h"
25 #include "log.h"
26 #include "../scripts/scripts.h"
27 
28 
29 /******************************************************************************
30  *                                                                            *
31  * Function: execute_remote_script                                            *
32  *                                                                            *
33  * Purpose: execute remote command and wait for the result                    *
34  *                                                                            *
35  * Return value:  SUCCEED - the remote command was executed successfully      *
36  *                FAIL    - an error occurred                                 *
37  *                                                                            *
38  ******************************************************************************/
execute_remote_script(zbx_script_t * script,DC_HOST * host,char ** info,char * error,size_t max_error_len)39 static int	execute_remote_script(zbx_script_t *script, DC_HOST *host, char **info, char *error,
40 		size_t max_error_len)
41 {
42 	int		ret = FAIL, time_start;
43 	zbx_uint64_t	taskid;
44 	DB_RESULT	result = NULL;
45 	DB_ROW		row;
46 
47 	if (0 == (taskid = zbx_script_create_task(script, host, 0, time(NULL))))
48 	{
49 		zbx_snprintf(error, max_error_len, "Cannot create remote command task.");
50 		return FAIL;
51 	}
52 
53 	for (time_start = time(NULL); SEC_PER_MIN > time(NULL) - time_start; sleep(1))
54 	{
55 		result = DBselect(
56 				"select tr.status,tr.info"
57 				" from task t"
58 				" left join task_remote_command_result tr"
59 					" on tr.taskid=t.taskid"
60 				" where tr.parent_taskid=" ZBX_FS_UI64,
61 				taskid);
62 
63 		if (NULL != (row = DBfetch(result)))
64 		{
65 			if (SUCCEED == (ret = atoi(row[0])))
66 				*info = zbx_strdup(*info, row[1]);
67 			else
68 				zbx_strlcpy(error, row[1], max_error_len);
69 
70 			DBfree_result(result);
71 			return ret;
72 		}
73 
74 		DBfree_result(result);
75 	}
76 
77 	zbx_snprintf(error, max_error_len, "Timeout while waiting for remote command result.");
78 
79 	return FAIL;
80 }
81 
82 /******************************************************************************
83  *                                                                            *
84  * Function: execute_script                                                   *
85  *                                                                            *
86  * Purpose: executing command                                                 *
87  *                                                                            *
88  * Return value:  SUCCEED - processed successfully                            *
89  *                FAIL - an error occurred                                    *
90  *                                                                            *
91  ******************************************************************************/
execute_script(zbx_uint64_t scriptid,zbx_uint64_t hostid,const char * sessionid,char ** result)92 static int	execute_script(zbx_uint64_t scriptid, zbx_uint64_t hostid, const char *sessionid, char **result)
93 {
94 	const char	*__function_name = "execute_script";
95 	char		error[MAX_STRING_LEN];
96 	int		ret = FAIL, rc;
97 	DC_HOST		host;
98 	zbx_script_t	script;
99 	zbx_user_t	user;
100 
101 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() scriptid:" ZBX_FS_UI64 " hostid:" ZBX_FS_UI64 " sessionid:%s",
102 			__function_name, scriptid, hostid, sessionid);
103 
104 	*error = '\0';
105 
106 	if (SUCCEED != (rc = DCget_host_by_hostid(&host, hostid)))
107 	{
108 		zbx_strlcpy(error, "Unknown host identifier.", sizeof(error));
109 		goto fail;
110 	}
111 
112 	if (SUCCEED != (rc = DBget_user_by_active_session(sessionid, &user)))
113 	{
114 		zbx_strlcpy(error, "Permission denied.", sizeof(error));
115 		goto fail;
116 	}
117 
118 	zbx_script_init(&script);
119 
120 	script.type = ZBX_SCRIPT_TYPE_GLOBAL_SCRIPT;
121 	script.scriptid = scriptid;
122 
123 	if (SUCCEED == (ret = zbx_script_prepare(&script, &host, &user, error, sizeof(error))))
124 	{
125 		if (0 == host.proxy_hostid || ZBX_SCRIPT_EXECUTE_ON_SERVER == script.execute_on)
126 			ret = zbx_script_execute(&script, &host, result, error, sizeof(error));
127 		else
128 			ret = execute_remote_script(&script, &host, result, error, sizeof(error));
129 	}
130 
131 	zbx_script_clean(&script);
132 fail:
133 	if (SUCCEED != ret)
134 		*result = zbx_strdup(*result, error);
135 
136 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
137 
138 	return ret;
139 }
140 
141 /******************************************************************************
142  *                                                                            *
143  * Function: node_process_command                                             *
144  *                                                                            *
145  * Purpose: process command received from the frontend                        *
146  *                                                                            *
147  * Return value:  SUCCEED - processed successfully                            *
148  *                FAIL - an error occurred                                    *
149  *                                                                            *
150  ******************************************************************************/
node_process_command(zbx_socket_t * sock,const char * data,struct zbx_json_parse * jp)151 int	node_process_command(zbx_socket_t *sock, const char *data, struct zbx_json_parse *jp)
152 {
153 	char		*result = NULL, *send = NULL, tmp[64], sessionid[MAX_STRING_LEN];
154 	int		ret = FAIL;
155 	zbx_uint64_t	scriptid, hostid;
156 	struct zbx_json	j;
157 
158 	zabbix_log(LOG_LEVEL_DEBUG, "In node_process_command()");
159 
160 	zbx_json_init(&j, ZBX_JSON_STAT_BUF_LEN);
161 
162 	if (SUCCEED != zbx_json_value_by_name(jp, ZBX_PROTO_TAG_SCRIPTID, tmp, sizeof(tmp), NULL) ||
163 			FAIL == is_uint64(tmp, &scriptid))
164 	{
165 		result = zbx_dsprintf(result, "Failed to parse command request tag: %s.", ZBX_PROTO_TAG_SCRIPTID);
166 		goto finish;
167 	}
168 
169 	if (SUCCEED != zbx_json_value_by_name(jp, ZBX_PROTO_TAG_HOSTID, tmp, sizeof(tmp), NULL) ||
170 			FAIL == is_uint64(tmp, &hostid))
171 	{
172 		result = zbx_dsprintf(result, "Failed to parse command request tag: %s.", ZBX_PROTO_TAG_HOSTID);
173 		goto finish;
174 	}
175 
176 	if (SUCCEED != zbx_json_value_by_name(jp, ZBX_PROTO_TAG_SID, sessionid, sizeof(sessionid), NULL))
177 	{
178 		result = zbx_dsprintf(result, "Failed to parse command request tag: %s.", ZBX_PROTO_TAG_SID);
179 		goto finish;
180 	}
181 
182 	if (SUCCEED == (ret = execute_script(scriptid, hostid, sessionid, &result)))
183 	{
184 		zbx_json_addstring(&j, ZBX_PROTO_TAG_RESPONSE, ZBX_PROTO_VALUE_SUCCESS, ZBX_JSON_TYPE_STRING);
185 		zbx_json_addstring(&j, ZBX_PROTO_TAG_DATA, result, ZBX_JSON_TYPE_STRING);
186 		send = j.buffer;
187 	}
188 finish:
189 	if (SUCCEED != ret)
190 	{
191 		zbx_json_addstring(&j, ZBX_PROTO_TAG_RESPONSE, ZBX_PROTO_VALUE_FAILED, ZBX_JSON_TYPE_STRING);
192 		zbx_json_addstring(&j, ZBX_PROTO_TAG_INFO, (NULL != result ? result : "Unknown error."),
193 				ZBX_JSON_TYPE_STRING);
194 		send = j.buffer;
195 	}
196 
197 	zbx_alarm_on(CONFIG_TIMEOUT);
198 	if (SUCCEED != zbx_tcp_send(sock, send))
199 		zabbix_log(LOG_LEVEL_WARNING, "Error sending result of command");
200 	else
201 		zabbix_log(LOG_LEVEL_DEBUG, "Sending back command '%s' result '%s'", data, send);
202 	zbx_alarm_off();
203 
204 	zbx_json_free(&j);
205 	zbx_free(result);
206 
207 	return ret;
208 }
209