/* ** Copyright (C) 2001-2025 Zabbix SIA ** ** This program is free software: you can redistribute it and/or modify it under the terms of ** the GNU Affero General Public License as published by the Free Software Foundation, version 3. ** ** This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; ** without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ** See the GNU Affero General Public License for more details. ** ** You should have received a copy of the GNU Affero General Public License along with this program. ** If not, see <https://www.gnu.org/licenses/>. **/ #include "config.h" #ifdef HAVE_OPENIPMI #include "zbxexpression.h" #include "zbxipcservice.h" #include "ipmi_protocol.h" #include "checks_ipmi.h" #include "zbxnum.h" #include "ipmi.h" #include "zbxipmi.h" #include "zbxinterface.h" #include "zbxcacheconfig.h" #include "zbxdbhigh.h" #include "zbxtime.h" /****************************************************************************** * * * Purpose: expands user macros in IPMI port value and converts result to * * unsigned short value * * * * Parameters: hostid - [IN] * * port_orig - [IN] original port value * * port - [OUT] resulting port value * * error - [OUT] * * * * Return value: SUCCEED - value was converted successfully * * FAIL - otherwise * * * ******************************************************************************/ int zbx_ipmi_port_expand_macros(zbx_uint64_t hostid, const char *port_orig, unsigned short *port, char **error) { char *tmp = zbx_strdup(NULL, port_orig); int ret = SUCCEED; zbx_substitute_simple_macros(NULL, NULL, NULL, NULL, &hostid, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &tmp, ZBX_MACRO_TYPE_COMMON, NULL, 0); if (FAIL == zbx_is_ushort(tmp, port) || 0 == *port) { *error = zbx_dsprintf(*error, "Invalid port value \"%s\"", port_orig); ret = FAIL; } zbx_free(tmp); return ret; } /****************************************************************************** * * * Purpose: executes IPMI command * * * * Parameters: host - [IN] target host * * command - [IN] command to execute * * error - [OUT] error message buffer * * max_error_len - [IN] size of error message buffer * * * * Return value: SUCCEED - command was executed successfully * * FAIL - otherwise * * * ******************************************************************************/ int zbx_ipmi_execute_command(const zbx_dc_host_t *host, const char *command, char *error, size_t max_error_len) { zbx_ipc_socket_t ipmi_socket; zbx_ipc_message_t message; char *errmsg = NULL, sensor[ZBX_ITEM_IPMI_SENSOR_LEN_MAX], *value = NULL; zbx_uint32_t data_len; unsigned char *data = NULL; int ret = FAIL, op; zbx_dc_interface_t interface; zbx_timespec_t ts; zabbix_log(LOG_LEVEL_DEBUG, "In %s() host:\"%s\" command:%s", __func__, host->host, command); if (SUCCEED != zbx_parse_ipmi_command(command, sensor, &op, error, max_error_len)) goto out; if (FAIL == zbx_ipc_socket_open(&ipmi_socket, ZBX_IPC_SERVICE_IPMI, SEC_PER_MIN, &errmsg)) { zabbix_log(LOG_LEVEL_CRIT, "cannot connect to IPMI service: %s", errmsg); exit(EXIT_FAILURE); } zbx_ipc_message_init(&message); if (FAIL == zbx_dc_config_get_interface_by_type(&interface, host->hostid, INTERFACE_TYPE_IPMI)) { zbx_strlcpy(error, "cannot find host IPMI interface", max_error_len); goto cleanup; } if (FAIL == zbx_ipmi_port_expand_macros(host->hostid, interface.port_orig, &interface.port, &errmsg)) { zbx_strlcpy(error, errmsg, max_error_len); zbx_free(errmsg); goto cleanup; } data_len = zbx_ipmi_serialize_request(&data, host->hostid, host->hostid, interface.addr, interface.port, host->ipmi_authtype, host->ipmi_privilege, host->ipmi_username, host->ipmi_password, sensor, op, NULL); if (FAIL == zbx_ipc_socket_write(&ipmi_socket, ZBX_IPC_IPMI_SCRIPT_REQUEST, data, data_len)) { zbx_strlcpy(error, "cannot send script request message to IPMI service", max_error_len); goto cleanup; } zbx_ipc_message_init(&message); if (FAIL == zbx_ipc_socket_read(&ipmi_socket, &message)) { zbx_strlcpy(error, "cannot read script request response from IPMI service", max_error_len); goto cleanup; } if (ZBX_IPC_IPMI_SCRIPT_RESULT != message.code) { zbx_snprintf(error, max_error_len, "invalid response code:%u received from IPMI service", message.code); goto cleanup; } zbx_ipmi_deserialize_result(message.data, &ts, &ret, &value); if (SUCCEED != ret) zbx_strlcpy(error, value, max_error_len); cleanup: zbx_free(value); zbx_free(data); zbx_ipc_message_clean(&message); zbx_ipc_socket_close(&ipmi_socket); out: zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); return ret; } /****************************************************************************** * * * Purpose: tests IPMI item * * * * Parameters: item - [IN] * * info - [OUT] result or error reason * * * * Return value: SUCCEED - test executed without errors * * FAIL - otherwise * * * ******************************************************************************/ int zbx_ipmi_test_item(const zbx_dc_item_t *item, char **info) { zbx_ipc_socket_t ipmi_socket; zbx_ipc_message_t message; char *errmsg = NULL, *value = NULL; zbx_uint32_t data_len; unsigned char *data = NULL; int ret = FAIL; zbx_timespec_t ts; zabbix_log(LOG_LEVEL_DEBUG, "In %s() host:\"%s\"", __func__, item->host.host); if (FAIL == zbx_ipc_socket_open(&ipmi_socket, ZBX_IPC_SERVICE_IPMI, SEC_PER_MIN, &errmsg)) { zabbix_log(LOG_LEVEL_CRIT, "cannot connect to IPMI service: %s", errmsg); exit(EXIT_FAILURE); } data_len = zbx_ipmi_serialize_request(&data, item->host.hostid, item->host.hostid, item->interface.addr, item->interface.port, item->host.ipmi_authtype, item->host.ipmi_privilege, item->host.ipmi_username, item->host.ipmi_password, item->ipmi_sensor, 0, item->key); zbx_ipc_message_init(&message); if (FAIL == zbx_ipc_socket_write(&ipmi_socket, ZBX_IPC_IPMI_VALUE_REQUEST, data, data_len)) { *info = zbx_strdup(NULL, "cannot send script request message to IPMI service"); goto cleanup; } if (FAIL == zbx_ipc_socket_read(&ipmi_socket, &message)) { *info = zbx_strdup(NULL, "cannot read script request response from IPMI service"); goto cleanup; } if (ZBX_IPC_IPMI_VALUE_RESULT != message.code) { *info = zbx_dsprintf(NULL, "invalid response code:%u received from IPMI service", message.code); goto cleanup; } zbx_ipmi_deserialize_result(message.data, &ts, &ret, &value); if (NULL != value) { *info = value; value = NULL; } else *info = zbx_strdup(NULL, "no value"); cleanup: zbx_free(value); zbx_free(data); zbx_ipc_message_clean(&message); zbx_ipc_socket_close(&ipmi_socket); zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); return ret; } #endif