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 
22 #ifdef HAVE_OPENIPMI
23 
24 #include "log.h"
25 #include "zbxserialize.h"
26 #include "dbcache.h"
27 
28 #include "zbxipcservice.h"
29 #include "ipmi_protocol.h"
30 #include "checks_ipmi.h"
31 #include "zbxserver.h"
32 #include "ipmi.h"
33 
34 /******************************************************************************
35  *                                                                            *
36  * Function: zbx_ipmi_port_expand_macros                                      *
37  *                                                                            *
38  * Purpose: expands user macros in IPMI port value and converts the result to *
39  *          to unsigned short value                                           *
40  *                                                                            *
41  * Parameters: hostid    - [IN] the host identifier                           *
42  *             port_orig - [IN] the original port value                       *
43  *             port      - [OUT] the resulting port value                     *
44  *             error     - [OUT] the error message                            *
45  *                                                                            *
46  * Return value: SUCCEED - the value was converted successfully               *
47  *               FAIL    - otherwise                                          *
48  *                                                                            *
49  ******************************************************************************/
zbx_ipmi_port_expand_macros(zbx_uint64_t hostid,const char * port_orig,unsigned short * port,char ** error)50 int	zbx_ipmi_port_expand_macros(zbx_uint64_t hostid, const char *port_orig, unsigned short *port, char **error)
51 {
52 	char	*tmp;
53 	int	ret = SUCCEED;
54 
55 	tmp = zbx_strdup(NULL, port_orig);
56 	substitute_simple_macros(NULL, NULL, NULL, NULL, &hostid, NULL, NULL, NULL, NULL,
57 			&tmp, MACRO_TYPE_COMMON, NULL, 0);
58 
59 	if (FAIL == is_ushort(tmp, port) || 0 == *port)
60 	{
61 		*error = zbx_dsprintf(*error, "Invalid port value \"%s\"", port_orig);
62 		ret = FAIL;
63 	}
64 
65 	zbx_free(tmp);
66 
67 	return ret;
68 }
69 
70 /******************************************************************************
71  *                                                                            *
72  * Function: zbx_ipmi_execute_command                                         *
73  *                                                                            *
74  * Purpose: executes IPMI command                                             *
75  *                                                                            *
76  * Parameters: host          - [IN] the target host                           *
77  *             command       - [IN] the command to execute                    *
78  *             error         - [OUT] the error message buffer                 *
79  *             max_error_len - [IN] the size of error message buffer          *
80  *                                                                            *
81  * Return value: SUCCEED - the command was executed successfully              *
82  *               FAIL    - otherwise                                          *
83  *                                                                            *
84  ******************************************************************************/
zbx_ipmi_execute_command(const DC_HOST * host,const char * command,char * error,size_t max_error_len)85 int	zbx_ipmi_execute_command(const DC_HOST *host, const char *command, char *error, size_t max_error_len)
86 {
87 	zbx_ipc_socket_t	ipmi_socket;
88 	zbx_ipc_message_t	message;
89 	char			*errmsg = NULL, sensor[ITEM_IPMI_SENSOR_LEN_MAX], *value = NULL;
90 	zbx_uint32_t		data_len;
91 	unsigned char		*data = NULL;
92 	int			ret = FAIL, op;
93 	DC_INTERFACE		interface;
94 	zbx_timespec_t		ts;
95 
96 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() host:\"%s\" command:%s", __func__, host->host, command);
97 
98 	if (SUCCEED != zbx_parse_ipmi_command(command, sensor, &op, error, max_error_len))
99 		goto out;
100 
101 	if (FAIL == zbx_ipc_socket_open(&ipmi_socket, ZBX_IPC_SERVICE_IPMI, SEC_PER_MIN, &errmsg))
102 	{
103 		zabbix_log(LOG_LEVEL_CRIT, "cannot connect to IPMI service: %s", errmsg);
104 		exit(EXIT_FAILURE);
105 	}
106 
107 	zbx_ipc_message_init(&message);
108 
109 	if (FAIL == DCconfig_get_interface_by_type(&interface, host->hostid, INTERFACE_TYPE_IPMI))
110 	{
111 		zbx_strlcpy(error, "cannot find host IPMI interface", max_error_len);
112 		goto cleanup;
113 	}
114 
115 	if (FAIL == zbx_ipmi_port_expand_macros(host->hostid, interface.port_orig, &interface.port, &errmsg))
116 	{
117 		zbx_strlcpy(error, errmsg, max_error_len);
118 		zbx_free(errmsg);
119 		goto cleanup;
120 	}
121 
122 	data_len = zbx_ipmi_serialize_request(&data, host->hostid, host->hostid, interface.addr, interface.port,
123 			host->ipmi_authtype, host->ipmi_privilege, host->ipmi_username, host->ipmi_password, sensor, op,
124 			NULL);
125 
126 	if (FAIL == zbx_ipc_socket_write(&ipmi_socket, ZBX_IPC_IPMI_SCRIPT_REQUEST, data, data_len))
127 	{
128 		zbx_strlcpy(error, "cannot send script request message to IPMI service", max_error_len);
129 		goto cleanup;
130 	}
131 
132 	zbx_ipc_message_init(&message);
133 
134 	if (FAIL == zbx_ipc_socket_read(&ipmi_socket, &message))
135 	{
136 		zbx_strlcpy(error,  "cannot read script request response from IPMI service", max_error_len);
137 		goto cleanup;
138 	}
139 
140 	if (ZBX_IPC_IPMI_SCRIPT_RESULT != message.code)
141 	{
142 		zbx_snprintf(error, max_error_len, "invalid response code:%u received from IPMI service", message.code);
143 		goto cleanup;
144 	}
145 
146 	zbx_ipmi_deserialize_result(message.data, &ts, &ret, &value);
147 
148 	if (SUCCEED != ret)
149 		zbx_strlcpy(error, value, max_error_len);
150 cleanup:
151 	zbx_free(value);
152 	zbx_free(data);
153 	zbx_ipc_message_clean(&message);
154 	zbx_ipc_socket_close(&ipmi_socket);
155 
156 out:
157 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
158 
159 	return ret;
160 }
161 
162 /******************************************************************************
163  *                                                                            *
164  * Function: zbx_ipmi_test_item                                               *
165  *                                                                            *
166  * Purpose: test IPMI item                                                    *
167  *                                                                            *
168  * Parameters: item - [IN] IPMI item                                          *
169  *             info - [OUT] result or error reason                            *
170  *                                                                            *
171  * Return value: SUCCEED - the test executed without errors                   *
172  *               FAIL    - otherwise                                          *
173  *                                                                            *
174  ******************************************************************************/
zbx_ipmi_test_item(const DC_ITEM * item,char ** info)175 int	zbx_ipmi_test_item(const DC_ITEM *item, char **info)
176 {
177 	zbx_ipc_socket_t	ipmi_socket;
178 	zbx_ipc_message_t	message;
179 	char			*errmsg = NULL, *value = NULL;
180 	zbx_uint32_t		data_len;
181 	unsigned char		*data = NULL;
182 	int			ret = FAIL;
183 	zbx_timespec_t		ts;
184 
185 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() host:\"%s\"", __func__, item->host.host);
186 
187 	if (FAIL == zbx_ipc_socket_open(&ipmi_socket, ZBX_IPC_SERVICE_IPMI, SEC_PER_MIN, &errmsg))
188 	{
189 		zabbix_log(LOG_LEVEL_CRIT, "cannot connect to IPMI service: %s", errmsg);
190 		exit(EXIT_FAILURE);
191 	}
192 
193 	data_len = zbx_ipmi_serialize_request(&data, item->host.hostid, item->host.hostid, item->interface.addr,
194 			item->interface.port, item->host.ipmi_authtype, item->host.ipmi_privilege,
195 			item->host.ipmi_username, item->host.ipmi_password, item->ipmi_sensor, 0, item->key);
196 
197 	zbx_ipc_message_init(&message);
198 
199 	if (FAIL == zbx_ipc_socket_write(&ipmi_socket, ZBX_IPC_IPMI_VALUE_REQUEST, data, data_len))
200 	{
201 		*info = zbx_strdup(NULL, "cannot send script request message to IPMI service");
202 		goto cleanup;
203 	}
204 
205 	if (FAIL == zbx_ipc_socket_read(&ipmi_socket, &message))
206 	{
207 		*info = zbx_strdup(NULL, "cannot read script request response from IPMI service");
208 		goto cleanup;
209 	}
210 
211 	if (ZBX_IPC_IPMI_VALUE_RESULT != message.code)
212 	{
213 		*info = zbx_dsprintf(NULL, "invalid response code:%u received from IPMI service", message.code);
214 		goto cleanup;
215 	}
216 
217 	zbx_ipmi_deserialize_result(message.data, &ts, &ret, &value);
218 
219 	if (NULL != value)
220 	{
221 		*info = value;
222 		value = NULL;
223 	}
224 	else
225 		*info = zbx_strdup(NULL, "no value");
226 cleanup:
227 	zbx_free(value);
228 	zbx_free(data);
229 	zbx_ipc_message_clean(&message);
230 	zbx_ipc_socket_close(&ipmi_socket);
231 
232 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
233 
234 	return ret;
235 }
236 
237 #endif
238