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 "checks_db.h"
21 
22 #include "zbxjson.h"
23 #include "log.h"
24 
25 #ifdef HAVE_UNIXODBC
26 
27 #include "zbxodbc.h"
28 
get_result_columns(ZBX_ODBC_DBH * dbh,char ** buffer)29 static int	get_result_columns(ZBX_ODBC_DBH *dbh, char **buffer)
30 {
31 	int		ret = SUCCEED, i, j;
32 	char		str[MAX_STRING_LEN];
33 	SQLRETURN	rc;
34 	SQLSMALLINT	len;
35 
36 	for (i = 0; i < dbh->col_num; i++)
37 	{
38 		rc = SQLColAttribute(dbh->hstmt, i + 1, SQL_DESC_LABEL, str, sizeof(str), &len, NULL);
39 
40 		if (SQL_SUCCESS != rc || sizeof(str) <= (size_t)len || '\0' == *str)
41 		{
42 			for (j = 0; j < i; j++)
43 				zbx_free(buffer[j]);
44 
45 			ret = FAIL;
46 			break;
47 		}
48 
49 		buffer[i] = zbx_strdup(NULL, str);
50 	}
51 
52 	return ret;
53 }
54 
db_odbc_discovery(DC_ITEM * item,AGENT_REQUEST * request,AGENT_RESULT * result)55 static int	db_odbc_discovery(DC_ITEM *item, AGENT_REQUEST *request, AGENT_RESULT *result)
56 {
57 	const char	*__function_name = "db_odbc_discovery";
58 
59 	int		ret = NOTSUPPORTED, i, j;
60 	ZBX_ODBC_DBH	dbh;
61 	ZBX_ODBC_ROW	row;
62 	char		**columns, *p, macro[MAX_STRING_LEN];
63 	struct zbx_json	json;
64 
65 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() query:'%s'", __function_name, item->params);
66 
67 	if (2 != request->nparam)
68 	{
69 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid number of parameters."));
70 		goto out;
71 	}
72 
73 	if (SUCCEED != odbc_DBconnect(&dbh, request->params[1], item->username, item->password, CONFIG_TIMEOUT))
74 	{
75 		SET_MSG_RESULT(result, zbx_strdup(NULL, get_last_odbc_strerror()));
76 		goto out;
77 	}
78 
79 	if (NULL != odbc_DBselect(&dbh, item->params))
80 	{
81 		columns = zbx_malloc(NULL, sizeof(char *) * dbh.col_num);
82 
83 		if (SUCCEED == get_result_columns(&dbh, columns))
84 		{
85 			for (i = 0; i < dbh.col_num; i++)
86 				zabbix_log(LOG_LEVEL_DEBUG, "%s() column[%d]:'%s'", __function_name, i + 1, columns[i]);
87 
88 			for (i = 0; i < dbh.col_num; i++)
89 			{
90 				for (p = columns[i]; '\0' != *p; p++)
91 				{
92 					if (0 != isalpha((unsigned char)*p))
93 						*p = toupper((unsigned char)*p);
94 
95 					if (SUCCEED != is_macro_char(*p))
96 					{
97 						SET_MSG_RESULT(result, zbx_dsprintf(NULL,
98 								"Cannot convert column #%d name to macro.", i + 1));
99 						goto clean;
100 					}
101 				}
102 
103 				for (j = 0; j < i; j++)
104 				{
105 					if (0 == strcmp(columns[i], columns[j]))
106 					{
107 						SET_MSG_RESULT(result, zbx_dsprintf(NULL,
108 								"Duplicate macro name: {#%s}.", columns[i]));
109 						goto clean;
110 					}
111 				}
112 			}
113 
114 			zbx_json_init(&json, ZBX_JSON_STAT_BUF_LEN);
115 			zbx_json_addarray(&json, ZBX_PROTO_TAG_DATA);
116 
117 			while (NULL != (row = odbc_DBfetch(&dbh)))
118 			{
119 				zbx_json_addobject(&json, NULL);
120 
121 				for (i = 0; i < dbh.col_num; i++)
122 				{
123 					zbx_snprintf(macro, MAX_STRING_LEN, "{#%s}", columns[i]);
124 					zbx_json_addstring(&json, macro, row[i], ZBX_JSON_TYPE_STRING);
125 				}
126 
127 				zbx_json_close(&json);
128 			}
129 
130 			zbx_json_close(&json);
131 
132 			SET_STR_RESULT(result, zbx_strdup(NULL, json.buffer));
133 
134 			zbx_json_free(&json);
135 
136 			ret = SUCCEED;
137 clean:
138 			for (i = 0; i < dbh.col_num; i++)
139 				zbx_free(columns[i]);
140 		}
141 		else
142 			SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot obtain column names."));
143 
144 		zbx_free(columns);
145 	}
146 	else
147 		SET_MSG_RESULT(result, zbx_strdup(NULL, get_last_odbc_strerror()));
148 
149 	odbc_DBclose(&dbh);
150 out:
151 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
152 
153 	return ret;
154 }
155 
db_odbc_select(DC_ITEM * item,AGENT_REQUEST * request,AGENT_RESULT * result)156 static int	db_odbc_select(DC_ITEM *item, AGENT_REQUEST *request, AGENT_RESULT *result)
157 {
158 	const char	*__function_name = "db_odbc_select";
159 
160 	int		ret = NOTSUPPORTED;
161 	ZBX_ODBC_DBH	dbh;
162 	ZBX_ODBC_ROW	row;
163 
164 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() query:'%s'", __function_name, item->params);
165 
166 	if (2 != request->nparam)
167 	{
168 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid number of parameters."));
169 		goto out;
170 	}
171 
172 	if (SUCCEED != odbc_DBconnect(&dbh, request->params[1], item->username, item->password, CONFIG_TIMEOUT))
173 	{
174 		SET_MSG_RESULT(result, zbx_strdup(NULL, get_last_odbc_strerror()));
175 		goto out;
176 	}
177 
178 	if (NULL != odbc_DBselect(&dbh, item->params))
179 	{
180 		if (NULL != (row = odbc_DBfetch(&dbh)))
181 		{
182 			if (NULL == row[0])
183 			{
184 				SET_MSG_RESULT(result, zbx_strdup(NULL, "SQL query returned NULL value."));
185 			}
186 			else if (SUCCEED == set_result_type(result, item->value_type, item->data_type, row[0]))
187 			{
188 				ret = SUCCEED;
189 			}
190 		}
191 		else
192 		{
193 			const char	*last_error = get_last_odbc_strerror();
194 
195 			if ('\0' != *last_error)
196 				SET_MSG_RESULT(result, zbx_strdup(NULL, last_error));
197 			else
198 				SET_MSG_RESULT(result, zbx_strdup(NULL, "SQL query returned empty result."));
199 		}
200 	}
201 	else
202 		SET_MSG_RESULT(result, zbx_strdup(NULL, get_last_odbc_strerror()));
203 
204 	odbc_DBclose(&dbh);
205 out:
206 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
207 
208 	return ret;
209 }
210 
211 /******************************************************************************
212  *                                                                            *
213  * Function: get_value_db                                                     *
214  *                                                                            *
215  * Purpose: retrieve data from database                                       *
216  *                                                                            *
217  * Parameters: item - item we are interested in                               *
218  *                                                                            *
219  * Return value: SUCCEED - data successfully retrieved and stored in result   *
220  *               NOTSUPPORTED - requested item is not supported               *
221  *                                                                            *
222  * Author: Eugene Grigorjev                                                   *
223  *                                                                            *
224  ******************************************************************************/
get_value_db(DC_ITEM * item,AGENT_RESULT * result)225 int	get_value_db(DC_ITEM *item, AGENT_RESULT *result)
226 {
227 	const char	*__function_name = "get_value_db";
228 
229 	AGENT_REQUEST	request;
230 	int		ret = NOTSUPPORTED;
231 
232 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() key_orig:'%s'", __function_name, item->key_orig);
233 
234 	init_request(&request);
235 
236 	if (SUCCEED == parse_item_key(item->key, &request))
237 	{
238 		if (0 == strcmp(request.key, "db.odbc.select"))
239 			ret = db_odbc_select(item, &request, result);
240 		else if (0 == strcmp(request.key, "db.odbc.discovery"))
241 			ret = db_odbc_discovery(item, &request, result);
242 		else
243 			SET_MSG_RESULT(result, zbx_strdup(NULL, "Unsupported item key for this item type."));
244 	}
245 	else
246 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid item parameter format."));
247 
248 	free_request(&request);
249 
250 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
251 
252 	return ret;
253 }
254 
255 #endif	/* HAVE_UNIXODBC */
256