import from branch_1_1:
[freeradius.git] / src / modules / rlm_sql / drivers / rlm_sql_mysql / sql_mysql.c
1 /*
2  * sql_mysql.c          SQL Module
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  */
24
25 #include <freeradius-devel/ident.h>
26 RCSID("$Id$")
27
28 #include <freeradius-devel/autoconf.h>
29
30 #include <stdio.h>
31 #include <sys/stat.h>
32 #include <stdlib.h>
33 #include <string.h>
34
35 #include <freeradius-devel/radiusd.h>
36
37 #include "config.h"
38
39 #ifdef HAVE_MYSQL_MYSQL_H
40 #include <mysql/errmsg.h>
41 #include <mysql/mysql.h>
42 #else
43 #ifdef HAVE_MYSQL_H
44 #include <errmsg.h>
45 #include <mysql.h>
46 #endif
47 #endif
48
49 #include        "rlm_sql.h"
50
51 typedef struct rlm_sql_mysql_sock {
52         MYSQL conn;
53         MYSQL *sock;
54         MYSQL_RES *result;
55         SQL_ROW row;
56 } rlm_sql_mysql_sock;
57
58 /*************************************************************************
59  *
60  *      Function: sql_create_socket
61  *
62  *      Purpose: Establish connection to the db
63  *
64  *************************************************************************/
65 static int sql_init_socket(SQLSOCK *sqlsocket, SQL_CONFIG *config)
66 {
67         rlm_sql_mysql_sock *mysql_sock;
68
69         if (!sqlsocket->conn) {
70                 sqlsocket->conn = (rlm_sql_mysql_sock *)rad_malloc(sizeof(rlm_sql_mysql_sock));
71                 if (!sqlsocket->conn) {
72                         return -1;
73                 }
74         }
75         mysql_sock = sqlsocket->conn;
76         memset(mysql_sock, 0, sizeof(*mysql_sock));
77
78         radlog(L_INFO, "rlm_sql_mysql: Starting connect to MySQL server for #%d",
79                         sqlsocket->id);
80
81         mysql_init(&(mysql_sock->conn));
82         mysql_options(&(mysql_sock->conn), MYSQL_READ_DEFAULT_GROUP, "freeradius");
83         if (!(mysql_sock->sock = mysql_real_connect(&(mysql_sock->conn),
84                                                     config->sql_server,
85                                                     config->sql_login,
86                                                     config->sql_password,
87                                                     config->sql_db,
88                                                     atoi(config->sql_port),
89                                                     NULL,
90                                                     CLIENT_FOUND_ROWS))) {
91                 radlog(L_ERR, "rlm_sql_mysql: Couldn't connect socket to MySQL server %s@%s:%s", config->sql_login, config->sql_server, config->sql_db);
92                 radlog(L_ERR, "rlm_sql_mysql: Mysql error '%s'", mysql_error(&mysql_sock->conn));
93                 mysql_sock->sock = NULL;
94                 return -1;
95         }
96
97
98         return 0;
99 }
100
101
102 /*************************************************************************
103  *
104  *      Function: sql_destroy_socket
105  *
106  *      Purpose: Free socket and any private connection data
107  *
108  *************************************************************************/
109 static int sql_destroy_socket(SQLSOCK *sqlsocket, UNUSED SQL_CONFIG *config)
110 {
111         free(sqlsocket->conn);
112         sqlsocket->conn = NULL;
113
114         return 0;
115 }
116
117
118 /*************************************************************************
119  *
120  *      Function: sql_check_error
121  *
122  *      Purpose: check the error to see if the server is down
123  *
124  *************************************************************************/
125 static int sql_check_error(int error)
126 {
127         switch(error) {
128         case CR_SERVER_GONE_ERROR:
129         case CR_SERVER_LOST:
130         case -1:
131                 radlog(L_DBG, "rlm_sql_mysql: MYSQL check_error: %d, returning SQL_DOWN", error);
132                 return SQL_DOWN;
133                 break;
134         case 0:
135                 return 0;
136                 break;
137         case CR_OUT_OF_MEMORY:
138         case CR_COMMANDS_OUT_OF_SYNC:
139         case CR_UNKNOWN_ERROR:
140         default:
141                 radlog(L_DBG, "rlm_sql_mysql: MYSQL check_error: %d received", error);
142                 return -1;
143                 break;
144         }
145 }
146
147
148 /*************************************************************************
149  *
150  *      Function: sql_query
151  *
152  *      Purpose: Issue a query to the database
153  *
154  *************************************************************************/
155 static int sql_query(SQLSOCK * sqlsocket, SQL_CONFIG *config, char *querystr)
156 {
157         rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
158
159         if (config->sqltrace)
160                 radlog(L_DBG,"rlm_sql_mysql: query:  %s", querystr);
161         if (mysql_sock->sock == NULL) {
162                 radlog(L_ERR, "rlm_sql_mysql: Socket not connected");
163                 return SQL_DOWN;
164         }
165
166         mysql_query(mysql_sock->sock, querystr);
167         return sql_check_error(mysql_errno(mysql_sock->sock));
168 }
169
170
171 /*************************************************************************
172  *
173  *      Function: sql_store_result
174  *
175  *      Purpose: database specific store_result function. Returns a result
176  *               set for the query.
177  *
178  *************************************************************************/
179 static int sql_store_result(SQLSOCK * sqlsocket, UNUSED SQL_CONFIG *config)
180 {
181         rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
182
183         if (mysql_sock->sock == NULL) {
184                 radlog(L_ERR, "rlm_sql_mysql: Socket not connected");
185                 return SQL_DOWN;
186         }
187         if (!(mysql_sock->result = mysql_store_result(mysql_sock->sock))) {
188                 radlog(L_ERR, "rlm_sql_mysql: MYSQL Error: Cannot get result");
189                 radlog(L_ERR, "rlm_sql_mysql: MYSQL Error: %s",
190                        mysql_error(mysql_sock->sock));
191                 return sql_check_error(mysql_errno(mysql_sock->sock));
192         }
193         return 0;
194 }
195
196
197 /*************************************************************************
198  *
199  *      Function: sql_num_fields
200  *
201  *      Purpose: database specific num_fields function. Returns number
202  *               of columns from query
203  *
204  *************************************************************************/
205 static int sql_num_fields(SQLSOCK * sqlsocket, UNUSED SQL_CONFIG *config)
206 {
207         int     num = 0;
208         rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
209
210 #if MYSQL_VERSION_ID >= 32224
211         if (!(num = mysql_field_count(mysql_sock->sock))) {
212 #else
213         if (!(num = mysql_num_fields(mysql_sock->sock))) {
214 #endif
215                 radlog(L_ERR, "rlm_sql_mysql: MYSQL Error: No Fields");
216                 radlog(L_ERR, "rlm_sql_mysql: MYSQL error: %s",
217                        mysql_error(mysql_sock->sock));
218         }
219         return num;
220 }
221
222
223 /*************************************************************************
224  *
225  *      Function: sql_select_query
226  *
227  *      Purpose: Issue a select query to the database
228  *
229  *************************************************************************/
230 static int sql_select_query(SQLSOCK *sqlsocket, SQL_CONFIG *config,
231                             char *querystr)
232 {
233         int ret;
234
235         ret = sql_query(sqlsocket, config, querystr);
236         if(ret)
237                 return ret;
238         ret = sql_store_result(sqlsocket, config);
239         if (ret) {
240                 return ret;
241         }
242
243         /* Why? Per http://www.mysql.com/doc/n/o/node_591.html,
244          * this cannot return an error.  Perhaps just to complain if no
245          * fields are found?
246          */
247         sql_num_fields(sqlsocket, config);
248
249         return ret;
250 }
251
252
253 /*************************************************************************
254  *
255  *      Function: sql_num_rows
256  *
257  *      Purpose: database specific num_rows. Returns number of rows in
258  *               query
259  *
260  *************************************************************************/
261 static int sql_num_rows(SQLSOCK * sqlsocket, UNUSED SQL_CONFIG *config)
262 {
263         rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
264
265         if (mysql_sock->result)
266                 return mysql_num_rows(mysql_sock->result);
267
268         return 0;
269 }
270
271
272 /*************************************************************************
273  *
274  *      Function: sql_fetch_row
275  *
276  *      Purpose: database specific fetch_row. Returns a SQL_ROW struct
277  *               with all the data for the query in 'sqlsocket->row'. Returns
278  *               0 on success, -1 on failure, SQL_DOWN if database is down.
279  *
280  *************************************************************************/
281 static int sql_fetch_row(SQLSOCK * sqlsocket, UNUSED SQL_CONFIG *config)
282 {
283         rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
284
285         /*
286          *  Check pointer before de-referencing it.
287          */
288         if (!mysql_sock->result) {
289                 return SQL_DOWN;
290         }
291
292         sqlsocket->row = mysql_fetch_row(mysql_sock->result);
293
294         if (sqlsocket->row == NULL) {
295                 return sql_check_error(mysql_errno(mysql_sock->sock));
296         }
297         return 0;
298 }
299
300
301 /*************************************************************************
302  *
303  *      Function: sql_free_result
304  *
305  *      Purpose: database specific free_result. Frees memory allocated
306  *               for a result set
307  *
308  *************************************************************************/
309 static int sql_free_result(SQLSOCK * sqlsocket, UNUSED SQL_CONFIG *config)
310 {
311         rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
312
313         if (mysql_sock->result) {
314                 mysql_free_result(mysql_sock->result);
315                 mysql_sock->result = NULL;
316         }
317
318         return 0;
319 }
320
321
322
323 /*************************************************************************
324  *
325  *      Function: sql_error
326  *
327  *      Purpose: database specific error. Returns error associated with
328  *               connection
329  *
330  *************************************************************************/
331 static char *sql_error(SQLSOCK * sqlsocket, UNUSED SQL_CONFIG *config)
332 {
333         rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
334
335         if (mysql_sock == NULL || mysql_sock->sock == NULL) {
336                 return "rlm_sql_mysql: no connection to db";
337         }
338         return mysql_error(mysql_sock->sock);
339 }
340
341
342 /*************************************************************************
343  *
344  *      Function: sql_close
345  *
346  *      Purpose: database specific close. Closes an open database
347  *               connection
348  *
349  *************************************************************************/
350 static int sql_close(SQLSOCK * sqlsocket, UNUSED SQL_CONFIG *config)
351 {
352         rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
353
354         if (mysql_sock && mysql_sock->sock){
355                 mysql_close(mysql_sock->sock);
356                 mysql_sock->sock = NULL;
357         }
358
359         return 0;
360 }
361
362
363 /*************************************************************************
364  *
365  *      Function: sql_finish_query
366  *
367  *      Purpose: End the query, such as freeing memory
368  *
369  *************************************************************************/
370 static int sql_finish_query(UNUSED SQLSOCK * sqlsocket, UNUSED SQL_CONFIG *config)
371 {
372         return 0;
373 }
374
375
376
377 /*************************************************************************
378  *
379  *      Function: sql_finish_select_query
380  *
381  *      Purpose: End the select query, such as freeing memory or result
382  *
383  *************************************************************************/
384 static int sql_finish_select_query(SQLSOCK * sqlsocket, SQL_CONFIG *config)
385 {
386         sql_free_result(sqlsocket, config);
387
388         return 0;
389 }
390
391
392 /*************************************************************************
393  *
394  *      Function: sql_affected_rows
395  *
396  *      Purpose: End the select query, such as freeing memory or result
397  *
398  *************************************************************************/
399 static int sql_affected_rows(SQLSOCK * sqlsocket, UNUSED SQL_CONFIG *config)
400 {
401         rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
402
403         return mysql_affected_rows(mysql_sock->sock);
404 }
405
406
407 /* Exported to rlm_sql */
408 rlm_sql_module_t rlm_sql_mysql = {
409         "rlm_sql_mysql",
410         sql_init_socket,
411         sql_destroy_socket,
412         sql_query,
413         sql_select_query,
414         sql_store_result,
415         sql_num_fields,
416         sql_num_rows,
417         sql_fetch_row,
418         sql_free_result,
419         sql_error,
420         sql_close,
421         sql_finish_query,
422         sql_finish_select_query,
423         sql_affected_rows
424 };