eacb85011271b6c8290ba29e4a2e9b62cde8d790
[freeradius.git] / src / modules / rlm_sql / drivers / rlm_sql_db2 / rlm_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(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
56 {
57         SQLRETURN retval;
58         rlm_sql_db2_sock *sock;
59
60         /* allocate socket */
61         if (!handle->conn) {
62                 handle->conn = (rlm_sql_db2_sock*)rad_malloc(sizeof(rlm_sql_db2_sock));
63                 if (!handle->conn) {
64                         return -1;
65                 }
66         }
67         sock = handle->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(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
99 {
100         free(handle->conn);
101         handle->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(rlm_sql_handle_t * handle, rlm_sql_config_t *config, char *querystr)
113 {
114         SQLRETURN retval;
115         rlm_sql_db2_sock *sock;
116
117         sock = handle->conn;
118
119         /* allocate handle for statement */
120         SQLAllocHandle(SQL_HANDLE_STMT, sock->hdbc,
121                         &(sock->stmt));
122
123         /* execute query */
124         retval = SQLExecDirect(sock->stmt, querystr, SQL_NTS);
125         if(retval != SQL_SUCCESS) {
126                 /* XXX Check if retval means we should return SQL_DOWN */
127                 radlog(L_ERR, "could not execute statement \"%s\"\n", querystr);
128                 return -1;
129         }
130
131         return 0;
132 }
133
134
135 /*************************************************************************
136  *
137  *      Function: sql_select_query
138  *
139  *      Purpose: Issue a select query to the database
140  *
141  *************************************************************************/
142 static int sql_select_query(rlm_sql_handle_t * handle, rlm_sql_config_t *config, char *querystr)
143 {
144         return sql_query(handle, config, querystr);
145 }
146
147
148 /*************************************************************************
149  *
150  *      Function: sql_store_result
151  *
152  *      Purpose: database specific store_result function. Returns a result
153  *               set for the query.
154  *
155  *************************************************************************/
156 static int sql_store_result(rlm_sql_handle_t * handle, rlm_sql_config_t *config)
157 {
158         return 0;
159 }
160
161
162 /*************************************************************************
163  *
164  *      Function: sql_num_fields
165  *
166  *      Purpose: database specific num_fields function. Returns number
167  *               of columns from query
168  *
169  *************************************************************************/
170 static int sql_num_fields(rlm_sql_handle_t * handle, rlm_sql_config_t *config)
171 {
172         SQLSMALLINT c;
173         rlm_sql_db2_sock *sock;
174
175         sock = handle->conn;
176         SQLNumResultCols(sock->stmt, &c);
177         return c;
178 }
179
180
181 /*************************************************************************
182  *
183  *      Function: sql_fetch_row
184  *
185  *      Purpose: database specific fetch_row. Returns a rlm_sql_row_t struct
186  *               with all the data for the query in 'handle->row'. Returns
187  *               0 on success, -1 on failure, SQL_DOWN if 'database is down'
188  *
189  *************************************************************************/
190 static int sql_fetch_row(rlm_sql_handle_t * handle, rlm_sql_config_t *config)
191 {
192         int c, i;
193         SQLINTEGER len, slen;
194         rlm_sql_row_t retval;
195         rlm_sql_db2_sock *sock;
196
197         sock = handle->conn;
198
199         c = sql_num_fields(handle, config);
200         retval = (rlm_sql_row_t)rad_malloc(c*sizeof(char*)+1);
201         memset(retval, 0, c*sizeof(char*)+1);
202
203         /* advance cursor */
204         if(SQLFetch(sock->stmt) == SQL_NO_DATA_FOUND) {
205                 handle->row = NULL;
206                 goto error;
207         }
208
209         for(i = 0; i < c; i++) {
210                 /* get column length */
211                 SQLColAttribute(sock->stmt,
212                                 i+1, SQL_DESC_DISPLAY_SIZE,
213                                 NULL, 0, NULL, &len);
214                 retval[i] = (char*)rad_malloc(len+1);
215                 /* get the actual column */
216                 SQLGetData(sock->stmt,
217                                 i+1, SQL_C_CHAR, retval[i], len+1, &slen);
218                 if(slen == SQL_NULL_DATA)
219                         retval[i][0] = '\0';
220         }
221
222         handle->row = retval;
223         return 0;
224
225 error:
226         for(i = 0; i < c; i++) {
227                 free(retval[i]);
228         }
229         free(retval);
230         return -1;
231 }
232
233 /*************************************************************************
234  *
235  *      Function: sql_free_result
236  *
237  *      Purpose: database specific free_result. Frees memory allocated
238  *               for a result set
239  *
240  *************************************************************************/
241 static int sql_free_result(rlm_sql_handle_t * handle, rlm_sql_config_t *config)
242 {
243         rlm_sql_db2_sock *sock;
244         sock = handle->conn;
245         SQLFreeHandle(SQL_HANDLE_STMT, sock->stmt);
246         return 0;
247 }
248
249
250
251 /*************************************************************************
252  *
253  *      Function: sql_error
254  *
255  *      Purpose: database specific error. Returns error associated with
256  *               connection
257  *
258  *************************************************************************/
259 static char *sql_error(rlm_sql_handle_t * handle, rlm_sql_config_t *config)
260 {
261         /* this should really be enough, if not, you still got the sqlstate */
262 #define MSGLEN 512
263         char sqlstate[6];
264         char msg[MSGLEN];
265         char *retval;
266         SQLINTEGER err;
267         SQLSMALLINT rl;
268         rlm_sql_db2_sock *sock;
269
270         sock = handle->conn;
271
272         SQLGetDiagRec(SQL_HANDLE_STMT, sock->stmt,
273                         1, sqlstate, &err, msg, MSGLEN, &rl);
274         retval = (char*)rad_malloc(strlen(msg)+20);
275         sprintf(retval, "SQLSTATE %s: %s", sqlstate, msg);
276         return retval;
277 }
278
279
280 /*************************************************************************
281  *
282  *      Function: sql_close
283  *
284  *      Purpose: database specific close. Closes an open database
285  *               connection
286  *
287  *************************************************************************/
288 static int sql_close(rlm_sql_handle_t * handle, rlm_sql_config_t *config)
289 {
290         rlm_sql_db2_sock *sock;
291
292         sock = handle->conn;
293
294         SQLFreeHandle(SQL_HANDLE_DBC, sock->hdbc);
295         SQLFreeHandle(SQL_HANDLE_ENV, sock->henv);
296         return 0;
297 }
298
299
300 /*************************************************************************
301  *
302  *      Function: sql_finish_query
303  *
304  *      Purpose: End the query, such as freeing memory
305  *
306  *************************************************************************/
307 static int sql_finish_query(rlm_sql_handle_t * handle, rlm_sql_config_t *config)
308 {
309         return 0;
310 }
311
312
313
314 /*************************************************************************
315  *
316  *      Function: sql_finish_select_query
317  *
318  *      Purpose: End the select query, such as freeing memory or result
319  *
320  *************************************************************************/
321 static int sql_finish_select_query(rlm_sql_handle_t * handle, rlm_sql_config_t *config)
322 {
323         return sql_finish_query(handle, config);
324 }
325
326
327 /*************************************************************************
328  *
329  *      Function: sql_affected_rows
330  *
331  *      Purpose: Return the number of rows affected by the last query.
332  *
333  *************************************************************************/
334 static int sql_affected_rows(rlm_sql_handle_t * handle, rlm_sql_config_t *config)
335 {
336         SQLINTEGER c;
337         rlm_sql_db2_sock *sock;
338
339         sock = handle->conn;
340
341         SQLRowCount(sock->stmt, &c);
342         return c;
343 }
344
345
346 static int
347 not_implemented(rlm_sql_handle_t * handle, rlm_sql_config_t *config)
348 {
349         radlog(L_ERR, "sql_db2: calling unimplemented function");
350         exit(1);
351 }
352
353
354 /* Exported to rlm_sql */
355 rlm_sql_module_t rlm_sql_db2 = {
356         "rlm_sql_db2",
357         sql_init_socket,
358         sql_destroy_socket, /* sql_destroy_socket*/
359         sql_query,
360         sql_select_query,
361         not_implemented, /* sql_store_result */
362         sql_num_fields,
363         not_implemented, /* sql_num_rows */
364         sql_fetch_row,
365         sql_free_result,
366         sql_error,
367         sql_close,
368         sql_finish_query,
369         sql_finish_select_query,
370         sql_affected_rows,
371 };