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