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