1 /* This file is part of GNU Radius.
2 Copyright (C) 2001 Vlad Lungu
3 Copyright (C) 2000,2001,2004,2006,2007,2008 Sergey Pozniakoff
4
5 GNU Radius 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 3 of the License, or
8 (at your option) any later version.
9
10 GNU Radius 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 GNU Radius; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.*/
18
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
22
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <sys/time.h>
26 #include <sys/types.h>
27 #include <unistd.h>
28
29 #include <common.h>
30 #include <radsql.h>
31
32 #include <sql.h>
33 #include <sqlext.h>
34 #include <sqltypes.h>
35
36 typedef struct {
37 SQLHENV env;
38 SQLHDBC dbc;
39 } ODBCconn;
40
41 static void
rad_odbc_diag(SQLSMALLINT handle_type,SQLHANDLE handle,char * what)42 rad_odbc_diag(SQLSMALLINT handle_type, SQLHANDLE handle, char *what)
43 {
44 char state[16];
45 SQLINTEGER nerror;
46 SQLCHAR message[1024];
47 SQLSMALLINT msglen;
48
49 SQLGetDiagRec(handle_type,
50 handle,
51 1,
52 state,
53 &nerror,
54 message, sizeof message, &msglen);
55 grad_log(GRAD_LOG_ERR,
56 "%s: %s %d %s",
57 what, state, nerror, message);
58 }
59
60 /* ************************************************************************* */
61 /* Interface routines */
62 static int
rad_odbc_reconnect(int type,struct sql_connection * conn)63 rad_odbc_reconnect(int type, struct sql_connection *conn)
64 {
65
66 ODBCconn *oconn;
67 long result;
68 char *dbname;
69 char portbuf[16];
70 char *portstr;
71
72 switch (type) {
73 case SQL_AUTH:
74 dbname = conn->cfg->auth_db;
75 break;
76 case SQL_ACCT:
77 dbname = conn->cfg->acct_db;
78 break;
79 }
80
81 if (conn->cfg->port == 0)
82 portstr = NULL;
83 else {
84 portstr = portbuf;
85 snprintf(portbuf, sizeof(portbuf), "%d", conn->cfg->port);
86 }
87
88 oconn = grad_emalloc(sizeof(ODBCconn));
89 result = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &oconn->env);
90 if (result != SQL_SUCCESS) {
91 rad_odbc_diag(SQL_HANDLE_ENV, oconn->env,
92 "SQLAllocHandle failed");
93 return -1;
94 }
95 result = SQLSetEnvAttr(oconn->env,
96 SQL_ATTR_ODBC_VERSION,
97 (void*)SQL_OV_ODBC3, 0);
98 if (result != SQL_SUCCESS) {
99 rad_odbc_diag(SQL_HANDLE_ENV, oconn->dbc,
100 "SQLSetEnvAttr failed");
101 return -1;
102 }
103 result = SQLAllocHandle(SQL_HANDLE_DBC, oconn->env, &oconn->dbc);
104 if (result != SQL_SUCCESS) {
105 rad_odbc_diag(SQL_HANDLE_DBC, oconn->dbc,
106 "SQLAllocHandle failed");
107 return -1;
108 }
109 result = SQLConnect(oconn->dbc,
110 (SQLCHAR*)dbname, SQL_NTS,
111 (SQLCHAR*)conn->cfg->login, SQL_NTS,
112 (SQLCHAR*)conn->cfg->password, SQL_NTS);
113 if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) {
114 rad_odbc_diag(SQL_HANDLE_DBC, oconn->dbc,
115 "SQLConnect failed");
116 return -1;
117 }
118
119 conn->data = oconn;
120 conn->connected = 1;
121 return 0;
122 }
123
124 static void
rad_odbc_disconnect(struct sql_connection * conn,int drop ARG_UNUSED)125 rad_odbc_disconnect(struct sql_connection *conn, int drop ARG_UNUSED)
126 {
127 ODBCconn *odata;
128 if (!conn->data)
129 return ;
130 odata = (ODBCconn*)(conn->data);
131 SQLDisconnect(odata->dbc);
132 SQLFreeHandle(SQL_HANDLE_ENV, odata->env);
133 grad_free(conn->data);
134 conn->data = NULL;
135 conn->connected = 0;
136 }
137
138 static int
rad_odbc_query(struct sql_connection * conn,const char * query,int * return_count)139 rad_odbc_query(struct sql_connection *conn, const char *query,
140 int *return_count)
141 {
142 ODBCconn *odata;
143 long result;
144 SQLHSTMT stmt;
145 SQLINTEGER count;
146
147 if (!conn || !conn->data)
148 return -1;
149
150 GRAD_DEBUG1(1, "query: %s", query);
151 odata = (ODBCconn*)(conn->data);
152 result = SQLAllocHandle(SQL_HANDLE_STMT,odata->dbc,&stmt);
153 if (result != SQL_SUCCESS) {
154 rad_odbc_diag(SQL_HANDLE_DBC, odata->dbc,
155 "SQLAllocHandle");
156 return -1;
157 }
158
159 result = SQLExecDirect(stmt, query, SQL_NTS);
160 if (result != SQL_SUCCESS) {
161 rad_odbc_diag(SQL_HANDLE_STMT, stmt,
162 "SQLExecDirect: %s %d %s");
163 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
164 return -1;
165 }
166 result = SQLRowCount(stmt, &count);
167 if (result != SQL_SUCCESS) {
168 rad_odbc_diag(SQL_HANDLE_STMT, stmt,
169 "SQLRowCount");
170 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
171 return -1;
172 }
173 if (return_count)
174 *return_count = count;
175 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
176 return 0;
177 }
178
179 static char *
rad_odbc_getpwd(struct sql_connection * conn,const char * query)180 rad_odbc_getpwd(struct sql_connection *conn, const char *query)
181 {
182 ODBCconn *odata;
183 long result;
184 SQLHSTMT stmt;
185 SQLINTEGER size;
186 SQLCHAR passwd[128];
187 char *return_passwd = NULL;
188
189 if (!conn || !conn->data)
190 return NULL;
191
192 GRAD_DEBUG1(1, "query: %s", query);
193
194 odata = (ODBCconn*)(conn->data);
195 result = SQLAllocHandle(SQL_HANDLE_STMT, odata->dbc, &stmt);
196 if (result != SQL_SUCCESS) {
197 rad_odbc_diag(SQL_HANDLE_DBC, odata->dbc,
198 "SQLAllocHandle");
199 return NULL;
200 }
201
202 result = SQLExecDirect(stmt, query, SQL_NTS);
203 if (result != SQL_SUCCESS) {
204 rad_odbc_diag(SQL_HANDLE_STMT, stmt,
205 "SQLExecDirect");
206 return NULL;
207 }
208
209
210 result = SQLFetch(stmt);
211 if (result != SQL_SUCCESS) {
212 rad_odbc_diag(SQL_HANDLE_STMT, stmt,
213 "SQLFetch");
214 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
215 return NULL;
216 }
217
218 SQLGetData(stmt, 1, SQL_C_CHAR, passwd, 128, &size);
219 if (result != SQL_SUCCESS) {
220 rad_odbc_diag(SQL_HANDLE_STMT, stmt,
221 "SQLGetData");
222 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
223 return NULL;
224 }
225
226 result = SQLFetch(stmt);
227
228 if (result == SQL_SUCCESS) {
229 grad_log(GRAD_LOG_NOTICE,
230 _("query returned more tuples: %s"),
231 query);
232 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
233 return NULL;
234 }
235
236 if (result != SQL_NO_DATA) {
237 rad_odbc_diag(SQL_HANDLE_STMT, stmt,
238 "SQLFetch");
239 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
240 return NULL;
241 }
242
243 return_passwd = grad_estrdup(passwd);
244
245 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
246 return return_passwd;
247 }
248
249 typedef struct {
250 SQLHSTMT stmt;
251 int nfields;
252 int ntuples;
253 } EXEC_DATA;
254
255 static int
rad_odbc_n_columns(struct sql_connection * conn,void * data,size_t * np)256 rad_odbc_n_columns(struct sql_connection *conn, void *data, size_t *np)
257 {
258 EXEC_DATA *edata = (EXEC_DATA*)data;
259
260 if (!data)
261 return -1;
262 *np = edata->nfields;
263 return 0;
264 }
265
266 static int
rad_odbc_n_tuples(struct sql_connection * conn,void * data,size_t * np)267 rad_odbc_n_tuples(struct sql_connection *conn, void *data, size_t *np)
268 {
269 EXEC_DATA *edata = (EXEC_DATA*)data;
270
271 if (!data)
272 return -1;
273 *np = edata->ntuples;
274 return 0;
275 }
276
277 static void *
rad_odbc_exec(struct sql_connection * conn,const char * query)278 rad_odbc_exec(struct sql_connection *conn, const char *query)
279 {
280
281 ODBCconn *odata;
282 long result;
283 SQLHSTMT stmt;
284 SQLSMALLINT ccount;
285 SQLINTEGER rcount;
286 EXEC_DATA *data;
287
288 if (!conn || !conn->data)
289 return NULL;
290
291 GRAD_DEBUG1(1, "query: %s", query);
292
293 odata = (ODBCconn*)conn->data;
294 result = SQLAllocHandle(SQL_HANDLE_STMT,odata->dbc, &stmt);
295 if (result != SQL_SUCCESS) {
296 rad_odbc_diag(SQL_HANDLE_DBC, odata->dbc,
297 "SQLAllocHandle");
298 return NULL;
299 }
300
301 result = SQLExecDirect(stmt, query, SQL_NTS);
302 if (result != SQL_SUCCESS) {
303 rad_odbc_diag(SQL_HANDLE_STMT, stmt,
304 "SQLExecDirect");
305 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
306 return NULL;
307 }
308
309 if (SQLNumResultCols(stmt, &ccount) != SQL_SUCCESS
310 || SQLRowCount(stmt, &rcount) != SQL_SUCCESS) {
311 rad_odbc_diag(SQL_HANDLE_STMT, stmt,
312 "SQLNumResultCount");
313 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
314 return NULL;
315 }
316
317 if (rcount == 0) {
318 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
319 return NULL;
320 }
321
322
323 data = grad_emalloc(sizeof(*data));
324 data->stmt = stmt;
325 data->nfields = ccount;
326 data->ntuples = rcount;
327 return (void*)data;
328 }
329
330 static char *
rad_odbc_column(void * data,size_t ncol)331 rad_odbc_column(void *data, size_t ncol)
332 {
333 SQLCHAR buffer[1024];
334 long result;
335 SQLINTEGER size;
336 EXEC_DATA *edata = (EXEC_DATA*)data;
337
338 if (!data)
339 return NULL;
340 if (ncol >= edata->nfields) {
341 grad_log(GRAD_LOG_ERR,
342 _("too few columns returned (%d req'd)"), ncol);
343 return NULL;
344 }
345
346 result = SQLGetData(edata->stmt,ncol+1,SQL_C_CHAR,
347 buffer, sizeof buffer, &size);
348 if (result != SQL_SUCCESS) {
349 rad_odbc_diag(SQL_HANDLE_STMT, edata->stmt,
350 "SQLGetData");
351 return NULL;
352 }
353 return grad_estrdup(buffer);
354 }
355
356 /*ARGSUSED*/
357 static int
rad_odbc_next_tuple(struct sql_connection * conn,void * data)358 rad_odbc_next_tuple(struct sql_connection *conn, void *data)
359 {
360 long result;
361 EXEC_DATA *edata = (EXEC_DATA*)data;
362
363 if (!data)
364 return 1;
365
366 result = SQLFetch(edata->stmt);
367
368 if (result == SQL_SUCCESS)
369 return 0;
370
371 if (result == SQL_NO_DATA)
372 return 1;
373
374 rad_odbc_diag(SQL_HANDLE_STMT, edata->stmt,
375 "SQLFetch");
376 return 1;
377 }
378
379 /*ARGSUSED*/
380 static void
rad_odbc_free(struct sql_connection * conn,void * data)381 rad_odbc_free(struct sql_connection *conn, void *data)
382 {
383 EXEC_DATA *edata = (EXEC_DATA*)data;
384
385 if (!data)
386 return;
387
388 SQLFreeHandle(SQL_HANDLE_STMT, edata->stmt);
389 grad_free(edata);
390 }
391
392 DECL_SQL_DISPATCH_TAB(odbc) = {
393 "odbc",
394 0,
395 rad_odbc_reconnect,
396 rad_odbc_disconnect,
397 rad_odbc_query,
398 rad_odbc_getpwd,
399 rad_odbc_exec,
400 rad_odbc_column,
401 rad_odbc_next_tuple,
402 rad_odbc_free,
403 rad_odbc_n_tuples,
404 rad_odbc_n_columns,
405 };
406
407