Cleanup the last bits of non-talloc socket destruction
[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_conn {
43         SQLHANDLE hdbc;
44         SQLHANDLE henv;
45         SQLHANDLE stmt;
46 } rlm_sql_db2_conn_t;
47
48 static int sql_socket_destructor(void *c)
49 {
50         rlm_sql_db2_conn_t *conn = c;
51         
52         DEBUG2("rlm_sql_db2: Socket destructor called, closing socket");
53         
54         if (conn->hdbc) {
55                 SQLDisconnect(conn->hdbc);
56                 SQLFreeHandle(SQL_HANDLE_DBC, conn->hdbc);
57         }
58         
59         if (conn->henv) {
60                 SQLFreeHandle(SQL_HANDLE_ENV, conn->henv);
61         }
62         
63         return 0;
64 }
65
66 /*************************************************************************
67  *
68  *      Function: sql_create_socket
69  *
70  *      Purpose: Establish connection to the db
71  *
72  *************************************************************************/
73 static int sql_socket_init(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
74 {
75         SQLRETURN retval;
76         rlm_sql_db2_conn_t *conn;
77
78         MEM(conn = handle->conn = talloc_zero(handle, rlm_sql_db2_conn_t));
79         talloc_set_destructor((void *) conn, sql_socket_destructor);
80         
81         /* allocate handles */
82         SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &(conn->henv));
83         SQLAllocHandle(SQL_HANDLE_DBC, conn->henv, &(conn->hdbc));
84
85         /* connect to database */
86         retval = SQLConnect(conn->hdbc,
87                             config->sql_server, SQL_NTS,
88                             config->sql_login,  SQL_NTS,
89                             config->sql_password, SQL_NTS);
90         if(retval != SQL_SUCCESS) {
91                 radlog(L_ERR, "could not connect to DB2 server %s\n",
92                        config->sql_server);
93                        
94                 return -1;
95         }
96
97         return 0;
98 }
99
100 /*************************************************************************
101  *
102  *      Function: sql_query
103  *
104  *      Purpose: Issue a query to the database
105  *
106  *************************************************************************/
107 static int sql_query(rlm_sql_handle_t * handle, UNUSED rlm_sql_config_t *config,
108                      char *querystr)
109 {
110         SQLRETURN retval;
111         rlm_sql_db2_conn_t *conn;
112
113         conn = handle->conn;
114
115         /* allocate handle for statement */
116         SQLAllocHandle(SQL_HANDLE_STMT, conn->hdbc,
117                         &(conn->stmt));
118
119         /* execute query */
120         retval = SQLExecDirect(conn->stmt, querystr, SQL_NTS);
121         if(retval != SQL_SUCCESS) {
122                 /* XXX Check if retval means we should return SQL_DOWN */
123                 radlog(L_ERR, "could not execute statement \"%s\"\n", querystr);
124                 return -1;
125         }
126
127         return 0;
128 }
129
130
131 /*************************************************************************
132  *
133  *      Function: sql_select_query
134  *
135  *      Purpose: Issue a select query to the database
136  *
137  *************************************************************************/
138 static int sql_select_query(rlm_sql_handle_t * handle, rlm_sql_config_t *config, char *querystr)
139 {
140         return sql_query(handle, config, querystr);
141 }
142
143
144 /*************************************************************************
145  *
146  *      Function: sql_num_fields
147  *
148  *      Purpose: database specific num_fields function. Returns number
149  *               of columns from query
150  *
151  *************************************************************************/
152 static int sql_num_fields(rlm_sql_handle_t * handle, UNUSED rlm_sql_config_t *config)
153 {
154         SQLSMALLINT c;
155         rlm_sql_db2_conn_t *conn;
156
157         conn = handle->conn;
158         SQLNumResultCols(conn->stmt, &c);
159         return c;
160 }
161
162
163 /*************************************************************************
164  *
165  *      Function: sql_fetch_row
166  *
167  *      Purpose: database specific fetch_row. Returns a rlm_sql_row_t struct
168  *               with all the data for the query in 'handle->row'. Returns
169  *               0 on success, -1 on failure, SQL_DOWN if 'database is down'
170  *
171  *************************************************************************/
172 static int sql_fetch_row(rlm_sql_handle_t * handle, rlm_sql_config_t *config)
173 {
174         int c, i;
175         SQLINTEGER len, slen;
176         rlm_sql_row_t retval;
177         rlm_sql_db2_conn_t *conn;
178
179         conn = handle->conn;
180
181         c = sql_num_fields(handle, config);
182         retval = (rlm_sql_row_t)rad_malloc(c*sizeof(char*)+1);
183         memset(retval, 0, c*sizeof(char*)+1);
184
185         /* advance cursor */
186         if(SQLFetch(conn->stmt) == SQL_NO_DATA_FOUND) {
187                 handle->row = NULL;
188                 goto error;
189         }
190
191         for(i = 0; i < c; i++) {
192                 /* get column length */
193                 SQLColAttribute(conn->stmt,
194                                 i+1, SQL_DESC_DISPLAY_SIZE,
195                                 NULL, 0, NULL, &len);
196                 retval[i] = (char*)rad_malloc(len+1);
197                 /* get the actual column */
198                 SQLGetData(conn->stmt,
199                                 i+1, SQL_C_CHAR, retval[i], len+1, &slen);
200                 if(slen == SQL_NULL_DATA)
201                         retval[i][0] = '\0';
202         }
203
204         handle->row = retval;
205         return 0;
206
207 error:
208         for(i = 0; i < c; i++) {
209                 free(retval[i]);
210         }
211         free(retval);
212         return -1;
213 }
214
215 /*************************************************************************
216  *
217  *      Function: sql_free_result
218  *
219  *      Purpose: database specific free_result. Frees memory allocated
220  *               for a result set
221  *
222  *************************************************************************/
223 static int sql_free_result(rlm_sql_handle_t * handle, UNUSED rlm_sql_config_t *config)
224 {
225         rlm_sql_db2_conn_t *conn;
226         conn = handle->conn;
227         SQLFreeHandle(SQL_HANDLE_STMT, conn->stmt);
228         return 0;
229 }
230
231
232
233 /*************************************************************************
234  *
235  *      Function: sql_error
236  *
237  *      Purpose: database specific error. Returns error associated with
238  *               connection
239  *
240  *************************************************************************/
241 static const char *sql_error(rlm_sql_handle_t * handle, UNUSED rlm_sql_config_t *config)
242 {
243         /* this should really be enough, if not, you still got the sqlstate */
244 #define MSGLEN 512
245         char sqlstate[6];
246         char msg[MSGLEN];
247         char *retval;
248         SQLINTEGER err;
249         SQLSMALLINT rl;
250         rlm_sql_db2_conn_t *conn;
251
252         conn = handle->conn;
253
254         SQLGetDiagRec(SQL_HANDLE_STMT, conn->stmt,
255                         1, sqlstate, &err, msg, MSGLEN, &rl);
256         retval = (char*)rad_malloc(strlen(msg)+20);
257         sprintf(retval, "SQLSTATE %s: %s", sqlstate, msg);
258         return retval;
259 }
260
261
262 /*************************************************************************
263  *
264  *      Function: sql_finish_query
265  *
266  *      Purpose: End the query, such as freeing memory
267  *
268  *************************************************************************/
269 static int sql_finish_query(UNUSED rlm_sql_handle_t * handle, UNUSED rlm_sql_config_t *config)
270 {
271         return 0;
272 }
273
274
275
276 /*************************************************************************
277  *
278  *      Function: sql_finish_select_query
279  *
280  *      Purpose: End the select query, such as freeing memory or result
281  *
282  *************************************************************************/
283 static int sql_finish_select_query(rlm_sql_handle_t * handle, rlm_sql_config_t *config)
284 {
285         return sql_finish_query(handle, config);
286 }
287
288
289 /*************************************************************************
290  *
291  *      Function: sql_affected_rows
292  *
293  *      Purpose: Return the number of rows affected by the last query.
294  *
295  *************************************************************************/
296 static int sql_affected_rows(rlm_sql_handle_t * handle, UNUSED rlm_sql_config_t *config)
297 {
298         SQLINTEGER c;
299         rlm_sql_db2_conn_t *conn;
300
301         conn = handle->conn;
302
303         SQLRowCount(conn->stmt, &c);
304         return c;
305 }
306
307
308 static int
309 not_implemented(UNUSED rlm_sql_handle_t * handle, UNUSED rlm_sql_config_t *config)
310 {
311         radlog(L_ERR, "sql_db2: calling unimplemented function");
312         exit(1);
313 }
314
315
316 /* Exported to rlm_sql */
317 rlm_sql_module_t rlm_sql_db2 = {
318         "rlm_sql_db2",
319         NULL,
320         sql_socket_init,
321         sql_query,
322         sql_select_query,
323         not_implemented, /* sql_store_result */
324         sql_num_fields,
325         not_implemented, /* sql_num_rows */
326         sql_fetch_row,
327         sql_free_result,
328         sql_error,
329         sql_finish_query,
330         sql_finish_select_query,
331         sql_affected_rows,
332 };