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