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