Update the GPL boilerplate with the new address of the FSF.
[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  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/autoconf.h>
32
33 #include <stdio.h>
34 #include <sys/stat.h>
35 #include <stdlib.h>
36 #include <string.h>
37
38 #include <freeradius-devel/radiusd.h>
39 #include <sql.h>
40 #include <sqlcli.h>
41 #include "rlm_sql.h"
42
43 typedef struct rlm_sql_db2_sock {
44         SQLHANDLE hdbc;
45         SQLHANDLE henv;
46         SQLHANDLE stmt;
47 } rlm_sql_db2_sock;
48
49 /*************************************************************************
50  *
51  *      Function: sql_create_socket
52  *
53  *      Purpose: Establish connection to the db
54  *
55  *************************************************************************/
56 static int sql_init_socket(SQLSOCK *sqlsocket, SQL_CONFIG *config)
57 {
58         SQLRETURN retval;
59         rlm_sql_db2_sock *sock;
60
61         /* allocate socket */
62         if (!sqlsocket->conn) {
63                 sqlsocket->conn = (rlm_sql_db2_sock*)rad_malloc(sizeof(rlm_sql_db2_sock));
64                 if (!sqlsocket->conn) {
65                         return -1;
66                 }
67         }
68         sock = sqlsocket->conn;
69         memset(sock, 0, sizeof(*sock));
70
71         /* allocate handles */
72         SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &(sock->henv));
73         SQLAllocHandle(SQL_HANDLE_DBC, sock->henv, &(sock->hdbc));
74
75         /* connect to database */
76         retval = SQLConnect(sock->hdbc,
77                         config->sql_server, SQL_NTS,
78                         config->sql_login,  SQL_NTS,
79                         config->sql_password, SQL_NTS);
80         if(retval != SQL_SUCCESS) {
81                 radlog(L_ERR, "could not connect to DB2 server %s\n", config->sql_server);
82                 SQLDisconnect(sock->hdbc);
83                 SQLFreeHandle(SQL_HANDLE_DBC, sock->hdbc);
84                 SQLFreeHandle(SQL_HANDLE_ENV, sock->henv);
85                 return -1;
86         }
87
88         return 0;
89 }
90
91
92 /*************************************************************************
93  *
94  *      Function: sql_destroy_socket
95  *
96  *      Purpose: Free socket and private connection data
97  *
98  *************************************************************************/
99 static int sql_destroy_socket(SQLSOCK *sqlsocket, SQL_CONFIG *config)
100 {
101         free(sqlsocket->conn);
102         sqlsocket->conn = NULL;
103         return 0;
104 }
105
106 /*************************************************************************
107  *
108  *      Function: sql_query
109  *
110  *      Purpose: Issue a query to the database
111  *
112  *************************************************************************/
113 static int sql_query(SQLSOCK * sqlsocket, SQL_CONFIG *config, char *querystr)
114 {
115         SQLRETURN retval;
116         rlm_sql_db2_sock *sock;
117
118         sock = sqlsocket->conn;
119
120         if (config->sqltrace)
121                 radlog(L_DBG,"query:\n%s", querystr);
122
123         /* allocate handle for statement */
124         SQLAllocHandle(SQL_HANDLE_STMT, sock->hdbc,
125                         &(sock->stmt));
126
127         /* execute query */
128         retval = SQLExecDirect(sock->stmt, querystr, SQL_NTS);
129         if(retval != SQL_SUCCESS) {
130                 /* XXX Check if retval means we should return SQL_DOWN */
131                 radlog(L_ERR, "could not execute statement \"%s\"\n", querystr);
132                 return -1;
133         }
134
135         return 0;
136 }
137
138
139 /*************************************************************************
140  *
141  *      Function: sql_select_query
142  *
143  *      Purpose: Issue a select query to the database
144  *
145  *************************************************************************/
146 static int sql_select_query(SQLSOCK * sqlsocket, SQL_CONFIG *config, char *querystr)
147 {
148         return sql_query(sqlsocket, config, querystr);
149 }
150
151
152 /*************************************************************************
153  *
154  *      Function: sql_store_result
155  *
156  *      Purpose: database specific store_result function. Returns a result
157  *               set for the query.
158  *
159  *************************************************************************/
160 static int sql_store_result(SQLSOCK * sqlsocket, SQL_CONFIG *config)
161 {
162         return 0;
163 }
164
165
166 /*************************************************************************
167  *
168  *      Function: sql_num_fields
169  *
170  *      Purpose: database specific num_fields function. Returns number
171  *               of columns from query
172  *
173  *************************************************************************/
174 static int sql_num_fields(SQLSOCK * sqlsocket, SQL_CONFIG *config)
175 {
176         SQLSMALLINT c;
177         rlm_sql_db2_sock *sock;
178
179         sock = sqlsocket->conn;
180         SQLNumResultCols(sock->stmt, &c);
181         return c;
182 }
183
184
185 /*************************************************************************
186  *
187  *      Function: sql_fetch_row
188  *
189  *      Purpose: database specific fetch_row. Returns a SQL_ROW struct
190  *               with all the data for the query in 'sqlsocket->row'. Returns
191  *               0 on success, -1 on failure, SQL_DOWN if 'database is down'
192  *
193  *************************************************************************/
194 static int sql_fetch_row(SQLSOCK * sqlsocket, SQL_CONFIG *config)
195 {
196         int c, i;
197         SQLINTEGER len, slen;
198         SQL_ROW retval;
199         rlm_sql_db2_sock *sock;
200
201         sock = sqlsocket->conn;
202
203         c = sql_num_fields(sqlsocket, config);
204         retval = (SQL_ROW)rad_malloc(c*sizeof(char*)+1);
205         /* advance cursor */
206         if(SQLFetch(sock->stmt) == SQL_NO_DATA_FOUND) {
207                 sqlsocket->row = NULL;
208                 return 0;
209         }
210
211         for(i = 0; i < c; i++) {
212                 /* get column length */
213                 SQLColAttribute(sock->stmt,
214                                 i+1, SQL_DESC_DISPLAY_SIZE,
215                                 NULL, 0, NULL, &len);
216                 retval[i] = (char*)rad_malloc(len+1);
217                 /* get the actual column */
218                 SQLGetData(sock->stmt,
219                                 i+1, SQL_C_CHAR, retval[i], len+1, &slen);
220                 if(slen == SQL_NULL_DATA)
221                         retval[i][0] = '\0';
222         }
223
224         sqlsocket->row = retval;
225         return 0;
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 int sql_free_result(SQLSOCK * sqlsocket, SQL_CONFIG *config)
237 {
238         rlm_sql_db2_sock *sock;
239         sock = sqlsocket->conn;
240         SQLFreeHandle(SQL_HANDLE_STMT, sock->stmt);
241         return 0;
242 }
243
244
245
246 /*************************************************************************
247  *
248  *      Function: sql_error
249  *
250  *      Purpose: database specific error. Returns error associated with
251  *               connection
252  *
253  *************************************************************************/
254 static char *sql_error(SQLSOCK * sqlsocket, SQL_CONFIG *config)
255 {
256         /* this should really be enough, if not, you still got the sqlstate */
257 #define MSGLEN 512
258         char sqlstate[6];
259         char msg[MSGLEN];
260         char *retval;
261         SQLINTEGER err;
262         SQLSMALLINT rl;
263         rlm_sql_db2_sock *sock;
264
265         sock = sqlsocket->conn;
266
267         SQLGetDiagRec(SQL_HANDLE_STMT, sock->stmt,
268                         1, sqlstate, &err, msg, MSGLEN, &rl);
269         retval = (char*)rad_malloc(strlen(msg)+20);
270         sprintf(retval, "SQLSTATE %s: %s", sqlstate, msg);
271         return retval;
272 }
273
274
275 /*************************************************************************
276  *
277  *      Function: sql_close
278  *
279  *      Purpose: database specific close. Closes an open database
280  *               connection
281  *
282  *************************************************************************/
283 static int sql_close(SQLSOCK * sqlsocket, SQL_CONFIG *config)
284 {
285         rlm_sql_db2_sock *sock;
286
287         sock = sqlsocket->conn;
288
289         SQLFreeHandle(SQL_HANDLE_DBC, sock->hdbc);
290         SQLFreeHandle(SQL_HANDLE_ENV, sock->henv);
291         return 0;
292 }
293
294
295 /*************************************************************************
296  *
297  *      Function: sql_finish_query
298  *
299  *      Purpose: End the query, such as freeing memory
300  *
301  *************************************************************************/
302 static int sql_finish_query(SQLSOCK * sqlsocket, SQL_CONFIG *config)
303 {
304         return 0;
305 }
306
307
308
309 /*************************************************************************
310  *
311  *      Function: sql_finish_select_query
312  *
313  *      Purpose: End the select query, such as freeing memory or result
314  *
315  *************************************************************************/
316 static int sql_finish_select_query(SQLSOCK * sqlsocket, SQL_CONFIG *config)
317 {
318         return sql_finish_query(sqlsocket, config);
319 }
320
321
322 /*************************************************************************
323  *
324  *      Function: sql_affected_rows
325  *
326  *      Purpose: Return the number of rows affected by the last query.
327  *
328  *************************************************************************/
329 static int sql_affected_rows(SQLSOCK * sqlsocket, SQL_CONFIG *config)
330 {
331         SQLINTEGER c;
332         rlm_sql_db2_sock *sock;
333
334         sock = sqlsocket->conn;
335
336         SQLRowCount(sock->stmt, &c);
337         return c;
338 }
339
340
341 static int
342 not_implemented(SQLSOCK * sqlsocket, SQL_CONFIG *config)
343 {
344         radlog(L_ERR, "sql_db2: calling unimplemented function");
345         exit(1);
346 }
347
348
349 /* Exported to rlm_sql */
350 rlm_sql_module_t rlm_sql_db2 = {
351         "rlm_sql_db2",
352         sql_init_socket,
353         sql_destroy_socket, /* sql_destroy_socket*/
354         sql_query,
355         sql_select_query,
356         not_implemented, /* sql_store_result */
357         sql_num_fields,
358         not_implemented, /* sql_num_rows */
359         sql_fetch_row,
360         sql_free_result,
361         sql_error,
362         sql_close,
363         sql_finish_query,
364         sql_finish_select_query,
365         sql_affected_rows,
366 };