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