6eccceb3014ca9fb54a2b19ba037b50fda4adf81
[freeradius.git] / src / modules / rlm_sql / drivers / rlm_sql_db2 / sql_db2.c
1 /*
2  * sql_db2.c            IBM DB2 rlm_sql driver
3  *
4  * Version:     $Id$
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 2 of the License, or
9  *   (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program; if not, write to the Free Software
18  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2000,2006  The FreeRADIUS server project
21  * Copyright 2000  Mike Machado <mike@innercite.com>
22  * Copyright 2000  Alan DeKok <aland@ox.org>
23  * Copyright 2001  Joerg Wendland <wendland@scan-plus.de>
24  */
25
26 /*
27  * Modification of rlm_sql_db2 to handle IBM DB2 UDB V7
28  * by Joerg Wendland <wendland@scan-plus.de>
29  */
30
31 #include <freeradius-devel/ident.h>
32 RCSID("$Id$")
33
34 #include <freeradius-devel/radiusd.h>
35
36 #include <sys/stat.h>
37
38 #include <sql.h>
39 #include <sqlcli.h>
40 #include "rlm_sql.h"
41
42 typedef struct rlm_sql_db2_sock {
43         SQLHANDLE hdbc;
44         SQLHANDLE henv;
45         SQLHANDLE stmt;
46 } rlm_sql_db2_sock;
47
48 /*************************************************************************
49  *
50  *      Function: sql_create_socket
51  *
52  *      Purpose: Establish connection to the db
53  *
54  *************************************************************************/
55 static int sql_init_socket(SQLSOCK *sqlsocket, SQL_CONFIG *config)
56 {
57         SQLRETURN retval;
58         rlm_sql_db2_sock *sock;
59
60         /* allocate socket */
61         if (!sqlsocket->conn) {
62                 sqlsocket->conn = (rlm_sql_db2_sock*)rad_malloc(sizeof(rlm_sql_db2_sock));
63                 if (!sqlsocket->conn) {
64                         return -1;
65                 }
66         }
67         sock = sqlsocket->conn;
68         memset(sock, 0, sizeof(*sock));
69
70         /* allocate handles */
71         SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &(sock->henv));
72         SQLAllocHandle(SQL_HANDLE_DBC, sock->henv, &(sock->hdbc));
73
74         /* connect to database */
75         retval = SQLConnect(sock->hdbc,
76                         config->sql_server, SQL_NTS,
77                         config->sql_login,  SQL_NTS,
78                         config->sql_password, SQL_NTS);
79         if(retval != SQL_SUCCESS) {
80                 radlog(L_ERR, "could not connect to DB2 server %s\n", config->sql_server);
81                 SQLDisconnect(sock->hdbc);
82                 SQLFreeHandle(SQL_HANDLE_DBC, sock->hdbc);
83                 SQLFreeHandle(SQL_HANDLE_ENV, sock->henv);
84                 return -1;
85         }
86
87         return 0;
88 }
89
90
91 /*************************************************************************
92  *
93  *      Function: sql_destroy_socket
94  *
95  *      Purpose: Free socket and private connection data
96  *
97  *************************************************************************/
98 static int sql_destroy_socket(SQLSOCK *sqlsocket, SQL_CONFIG *config)
99 {
100         free(sqlsocket->conn);
101         sqlsocket->conn = NULL;
102         return 0;
103 }
104
105 /*************************************************************************
106  *
107  *      Function: sql_query
108  *
109  *      Purpose: Issue a query to the database
110  *
111  *************************************************************************/
112 static int sql_query(SQLSOCK * sqlsocket, SQL_CONFIG *config, char *querystr)
113 {
114         SQLRETURN retval;
115         rlm_sql_db2_sock *sock;
116
117         sock = sqlsocket->conn;
118
119         if (config->sqltrace)
120                 radlog(L_DBG,"query:\n%s", querystr);
121
122         /* allocate handle for statement */
123         SQLAllocHandle(SQL_HANDLE_STMT, sock->hdbc,
124                         &(sock->stmt));
125
126         /* execute query */
127         retval = SQLExecDirect(sock->stmt, querystr, SQL_NTS);
128         if(retval != SQL_SUCCESS) {
129                 /* XXX Check if retval means we should return SQL_DOWN */
130                 radlog(L_ERR, "could not execute statement \"%s\"\n", querystr);
131                 return -1;
132         }
133
134         return 0;
135 }
136
137
138 /*************************************************************************
139  *
140  *      Function: sql_select_query
141  *
142  *      Purpose: Issue a select query to the database
143  *
144  *************************************************************************/
145 static int sql_select_query(SQLSOCK * sqlsocket, SQL_CONFIG *config, char *querystr)
146 {
147         return sql_query(sqlsocket, config, querystr);
148 }
149
150
151 /*************************************************************************
152  *
153  *      Function: sql_store_result
154  *
155  *      Purpose: database specific store_result function. Returns a result
156  *               set for the query.
157  *
158  *************************************************************************/
159 static int sql_store_result(SQLSOCK * sqlsocket, SQL_CONFIG *config)
160 {
161         return 0;
162 }
163
164
165 /*************************************************************************
166  *
167  *      Function: sql_num_fields
168  *
169  *      Purpose: database specific num_fields function. Returns number
170  *               of columns from query
171  *
172  *************************************************************************/
173 static int sql_num_fields(SQLSOCK * sqlsocket, SQL_CONFIG *config)
174 {
175         SQLSMALLINT c;
176         rlm_sql_db2_sock *sock;
177
178         sock = sqlsocket->conn;
179         SQLNumResultCols(sock->stmt, &c);
180         return c;
181 }
182
183
184 /*************************************************************************
185  *
186  *      Function: sql_fetch_row
187  *
188  *      Purpose: database specific fetch_row. Returns a SQL_ROW struct
189  *               with all the data for the query in 'sqlsocket->row'. Returns
190  *               0 on success, -1 on failure, SQL_DOWN if 'database is down'
191  *
192  *************************************************************************/
193 static int sql_fetch_row(SQLSOCK * sqlsocket, SQL_CONFIG *config)
194 {
195         int c, i;
196         SQLINTEGER len, slen;
197         SQL_ROW retval;
198         rlm_sql_db2_sock *sock;
199
200         sock = sqlsocket->conn;
201
202         c = sql_num_fields(sqlsocket, config);
203         retval = (SQL_ROW)rad_malloc(c*sizeof(char*)+1);
204         /* advance cursor */
205         if(SQLFetch(sock->stmt) == SQL_NO_DATA_FOUND) {
206                 sqlsocket->row = NULL;
207                 return 0;
208         }
209
210         for(i = 0; i < c; i++) {
211                 /* get column length */
212                 SQLColAttribute(sock->stmt,
213                                 i+1, SQL_DESC_DISPLAY_SIZE,
214                                 NULL, 0, NULL, &len);
215                 retval[i] = (char*)rad_malloc(len+1);
216                 /* get the actual column */
217                 SQLGetData(sock->stmt,
218                                 i+1, SQL_C_CHAR, retval[i], len+1, &slen);
219                 if(slen == SQL_NULL_DATA)
220                         retval[i][0] = '\0';
221         }
222
223         sqlsocket->row = retval;
224         return 0;
225 }
226
227 /*************************************************************************
228  *
229  *      Function: sql_free_result
230  *
231  *      Purpose: database specific free_result. Frees memory allocated
232  *               for a result set
233  *
234  *************************************************************************/
235 static int sql_free_result(SQLSOCK * sqlsocket, SQL_CONFIG *config)
236 {
237         rlm_sql_db2_sock *sock;
238         sock = sqlsocket->conn;
239         SQLFreeHandle(SQL_HANDLE_STMT, sock->stmt);
240         return 0;
241 }
242
243
244
245 /*************************************************************************
246  *
247  *      Function: sql_error
248  *
249  *      Purpose: database specific error. Returns error associated with
250  *               connection
251  *
252  *************************************************************************/
253 static char *sql_error(SQLSOCK * sqlsocket, SQL_CONFIG *config)
254 {
255         /* this should really be enough, if not, you still got the sqlstate */
256 #define MSGLEN 512
257         char sqlstate[6];
258         char msg[MSGLEN];
259         char *retval;
260         SQLINTEGER err;
261         SQLSMALLINT rl;
262         rlm_sql_db2_sock *sock;
263
264         sock = sqlsocket->conn;
265
266         SQLGetDiagRec(SQL_HANDLE_STMT, sock->stmt,
267                         1, sqlstate, &err, msg, MSGLEN, &rl);
268         retval = (char*)rad_malloc(strlen(msg)+20);
269         sprintf(retval, "SQLSTATE %s: %s", sqlstate, msg);
270         return retval;
271 }
272
273
274 /*************************************************************************
275  *
276  *      Function: sql_close
277  *
278  *      Purpose: database specific close. Closes an open database
279  *               connection
280  *
281  *************************************************************************/
282 static int sql_close(SQLSOCK * sqlsocket, SQL_CONFIG *config)
283 {
284         rlm_sql_db2_sock *sock;
285
286         sock = sqlsocket->conn;
287
288         SQLFreeHandle(SQL_HANDLE_DBC, sock->hdbc);
289         SQLFreeHandle(SQL_HANDLE_ENV, sock->henv);
290         return 0;
291 }
292
293
294 /*************************************************************************
295  *
296  *      Function: sql_finish_query
297  *
298  *      Purpose: End the query, such as freeing memory
299  *
300  *************************************************************************/
301 static int sql_finish_query(SQLSOCK * sqlsocket, SQL_CONFIG *config)
302 {
303         return 0;
304 }
305
306
307
308 /*************************************************************************
309  *
310  *      Function: sql_finish_select_query
311  *
312  *      Purpose: End the select query, such as freeing memory or result
313  *
314  *************************************************************************/
315 static int sql_finish_select_query(SQLSOCK * sqlsocket, SQL_CONFIG *config)
316 {
317         return sql_finish_query(sqlsocket, config);
318 }
319
320
321 /*************************************************************************
322  *
323  *      Function: sql_affected_rows
324  *
325  *      Purpose: Return the number of rows affected by the last query.
326  *
327  *************************************************************************/
328 static int sql_affected_rows(SQLSOCK * sqlsocket, SQL_CONFIG *config)
329 {
330         SQLINTEGER c;
331         rlm_sql_db2_sock *sock;
332
333         sock = sqlsocket->conn;
334
335         SQLRowCount(sock->stmt, &c);
336         return c;
337 }
338
339
340 static int
341 not_implemented(SQLSOCK * sqlsocket, SQL_CONFIG *config)
342 {
343         radlog(L_ERR, "sql_db2: calling unimplemented function");
344         exit(1);
345 }
346
347
348 /* Exported to rlm_sql */
349 rlm_sql_module_t rlm_sql_db2 = {
350         "rlm_sql_db2",
351         sql_init_socket,
352         sql_destroy_socket, /* sql_destroy_socket*/
353         sql_query,
354         sql_select_query,
355         not_implemented, /* sql_store_result */
356         sql_num_fields,
357         not_implemented, /* sql_num_rows */
358         sql_fetch_row,
359         sql_free_result,
360         sql_error,
361         sql_close,
362         sql_finish_query,
363         sql_finish_select_query,
364         sql_affected_rows,
365 };