Don't leak the results of open_querys
[freeradius.git] / src / modules / rlm_sql / sql.c
1 /*
2  *  sql.c               rlm_sql - FreeRADIUS SQL Module
3  *              Main code directly taken from ICRADIUS
4  *
5  * Version:     $Id$
6  *
7  *   This program is free software; you can redistribute it and/or modify
8  *   it under the terms of the GNU General Public License as published by
9  *   the Free Software Foundation; either version 2 of the License, or
10  *   (at your option) any later version.
11  *
12  *   This program is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *   GNU General Public License for more details.
16  *
17  *   You should have received a copy of the GNU General Public License
18  *   along with this program; if not, write to the Free Software
19  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  *
21  * Copyright 2001,2006  The FreeRADIUS server project
22  * Copyright 2000  Mike Machado <mike@innercite.com>
23  * Copyright 2000  Alan DeKok <aland@ox.org>
24  * Copyright 2001  Chad Miller <cmiller@surfsouth.com>
25  */
26
27 RCSID("$Id$")
28
29 #include        <freeradius-devel/radiusd.h>
30 #include        <freeradius-devel/rad_assert.h>
31
32 #include        <sys/file.h>
33 #include        <sys/stat.h>
34
35 #include        <ctype.h>
36
37 #include        "rlm_sql.h"
38
39 #ifdef HAVE_PTHREAD_H
40 #endif
41
42 static int sql_conn_destructor(void *conn)
43 {
44         rlm_sql_handle_t *handle = conn;
45         rlm_sql_t *inst = handle->inst;
46
47         rad_assert(inst);
48
49         exec_trigger(NULL, inst->cs, "modules.sql.close", false);
50
51         return 0;
52 }
53
54 static void *mod_conn_create(void *instance)
55 {
56         int rcode;
57         rlm_sql_t *inst = instance;
58         rlm_sql_handle_t *handle;
59
60         handle = talloc_zero(instance, rlm_sql_handle_t);
61
62         /*
63          *      Handle requires a pointer to the SQL inst so the
64          *      destructor has access to the module configuration.
65          */
66         handle->inst = inst;
67         handle->init = false;
68
69         /*
70          *      When something frees this handle the destructor set by
71          *      the driver will be called first, closing any open sockets.
72          *      Then we call our destructor to trigger an modules.sql.close
73          *      event, then all the memory is freed.
74          */
75         talloc_set_destructor((void *) handle, sql_conn_destructor);
76
77         rcode = (inst->module->sql_socket_init)(handle, inst->config);
78         if (rcode != 0) {
79         fail:
80                 exec_trigger(NULL, inst->cs, "modules.sql.fail", true);
81
82                 /*
83                  *      Destroy any half opened connections.
84                  */
85                 talloc_free(handle);
86                 return NULL;
87         }
88
89         if (inst->config->open_query && *inst->config->open_query) {
90                 if (rlm_sql_select_query(&handle, inst, inst->config->open_query)) {
91                         goto fail;
92                 }
93                 (inst->module->sql_finish_select_query)(handle, inst->config);
94         }
95
96         exec_trigger(NULL, inst->cs, "modules.sql.open", false);
97         handle->init = true;
98         return handle;
99 }
100
101 /*
102  *      @todo Calls to this should eventually go away.
103  */
104 static int mod_conn_delete(UNUSED void *instance, void *handle)
105 {
106         return talloc_free(handle);
107 }
108
109 /*************************************************************************
110  *
111  *      Function: sql_socket_pool_init
112  *
113  *      Purpose: Connect to the sql server, if possible
114  *
115  *************************************************************************/
116 int sql_socket_pool_init(rlm_sql_t * inst)
117 {
118         inst->pool = fr_connection_pool_init(inst->cs, inst,
119                                              mod_conn_create, NULL, mod_conn_delete,
120                                              NULL);
121         if (!inst->pool) return -1;
122
123         return 1;
124 }
125
126 /*************************************************************************
127  *
128  *     Function: sql_poolfree
129  *
130  *     Purpose: Clean up and free sql pool
131  *
132  *************************************************************************/
133 void sql_poolfree(rlm_sql_t * inst)
134 {
135         fr_connection_pool_delete(inst->pool);
136 }
137
138
139 /*************************************************************************
140  *
141  *      Function: sql_get_socket
142  *
143  *      Purpose: Return a SQL handle from the connection pool
144  *
145  *************************************************************************/
146 rlm_sql_handle_t * sql_get_socket(rlm_sql_t * inst)
147 {
148         return fr_connection_get(inst->pool);
149 }
150
151 /*************************************************************************
152  *
153  *      Function: sql_release_socket
154  *
155  *      Purpose: Frees a SQL handle back to the connection pool
156  *
157  *************************************************************************/
158 int sql_release_socket(rlm_sql_t * inst, rlm_sql_handle_t * handle)
159 {
160         fr_connection_release(inst->pool, handle);
161         return 0;
162 }
163
164
165 /*************************************************************************
166  *
167  *      Function: sql_userparse
168  *
169  *      Purpose: Read entries from the database and fill VALUE_PAIR structures
170  *
171  *************************************************************************/
172 int sql_userparse(TALLOC_CTX *ctx, VALUE_PAIR **head, rlm_sql_row_t row)
173 {
174         VALUE_PAIR *vp;
175         char const *ptr, *value;
176         char buf[MAX_STRING_LEN];
177         char do_xlat = 0;
178         FR_TOKEN token, operator = T_EOL;
179
180         /*
181          *      Verify the 'Attribute' field
182          */
183         if (!row[2] || row[2][0] == '\0') {
184                 ERROR("rlm_sql: The 'Attribute' field is empty or NULL, skipping the entire row.");
185                 return -1;
186         }
187
188         /*
189          *      Verify the 'op' field
190          */
191         if (row[4] != NULL && row[4][0] != '\0') {
192                 ptr = row[4];
193                 operator = gettoken(&ptr, buf, sizeof(buf), false);
194                 if ((operator < T_OP_ADD) ||
195                     (operator > T_OP_CMP_EQ)) {
196                         ERROR("rlm_sql: Invalid operator \"%s\" for attribute %s", row[4], row[2]);
197                         return -1;
198                 }
199
200         } else {
201                 /*
202                  *  Complain about empty or invalid 'op' field
203                  */
204                 operator = T_OP_CMP_EQ;
205                 ERROR("rlm_sql: The 'op' field for attribute '%s = %s' is NULL, or non-existent.", row[2], row[3]);
206                 ERROR("rlm_sql: You MUST FIX THIS if you want the configuration to behave as you expect.");
207         }
208
209         /*
210          *      The 'Value' field may be empty or NULL
211          */
212         value = row[3];
213         /*
214          *      If we have a new-style quoted string, where the
215          *      *entire* string is quoted, do xlat's.
216          */
217         if (row[3] != NULL &&
218            ((row[3][0] == '\'') || (row[3][0] == '`') || (row[3][0] == '"')) &&
219            (row[3][0] == row[3][strlen(row[3])-1])) {
220
221                 token = gettoken(&value, buf, sizeof(buf), false);
222                 switch (token) {
223                 /*
224                  *      Take the unquoted string.
225                  */
226                 case T_SINGLE_QUOTED_STRING:
227                 case T_DOUBLE_QUOTED_STRING:
228                         value = buf;
229                         break;
230
231                 /*
232                  *      Mark the pair to be allocated later.
233                  */
234                 case T_BACK_QUOTED_STRING:
235                         value = NULL;
236                         do_xlat = 1;
237                         break;
238
239                 /*
240                  *      Keep the original string.
241                  */
242                 default:
243                         value = row[3];
244                         break;
245                 }
246         }
247
248         /*
249          *      Create the pair
250          */
251         vp = pairmake(ctx, NULL, row[2], NULL, operator);
252         if (!vp) {
253                 ERROR("rlm_sql: Failed to create the pair: %s",
254                        fr_strerror());
255                 return -1;
256         }
257
258         if (do_xlat) {
259                 if (pairmark_xlat(vp, value) < 0) {
260                         ERROR("rlm_sql: Error marking pair for xlat");
261
262                         talloc_free(vp);
263                         return -1;
264                 }
265         } else {
266                 if (!pairparsevalue(vp, value)) {
267                         ERROR("rlm_sql: Error parsing value: %s", fr_strerror());
268
269                         talloc_free(vp);
270                         return -1;
271                 }
272         }
273
274         /*
275          *      Add the pair into the packet
276          */
277         pairadd(head, vp);
278         return 0;
279 }
280
281
282 /*************************************************************************
283  *
284  *      Function: rlm_sql_fetch_row
285  *
286  *      Purpose: call the module's sql_fetch_row and implement re-connect
287  *
288  *************************************************************************/
289 int rlm_sql_fetch_row(rlm_sql_handle_t **handle, rlm_sql_t *inst)
290 {
291         int ret;
292
293         if (!*handle || !(*handle)->conn) {
294                 return -1;
295         }
296
297         /*
298          * We can't implement reconnect logic here, because the caller may require
299          * the original connection to free up queries or result sets associated with
300          * that connection.
301          */
302         ret = (inst->module->sql_fetch_row)(*handle, inst->config);
303         if (ret < 0) {
304                 char const *error = (inst->module->sql_error)(*handle, inst->config);
305                 EDEBUG("rlm_sql (%s): Error fetching row: %s",
306                        inst->config->xlat_name, error ? error : "<UNKNOWN>");
307         }
308
309         return ret;
310 }
311
312 static void rlm_sql_query_error(rlm_sql_handle_t *handle, rlm_sql_t *inst)
313 {
314         char const *p, *q;
315
316         p = (inst->module->sql_error)(handle, inst->config);
317         if (!p) {
318                 ERROR("rlm_sql (%s): Unknown query error", inst->config->xlat_name);
319                 return;
320         }
321
322         /*
323          *      Some drivers are nice and provide us with a ^ pointer to
324          *      the place in the query string where the error occurred.
325          *
326          *      For this to be useful we need to split log messages on
327          *      \n and output each of the lines individually.
328          */
329         while ((q = strchr(p, '\n'))) {
330                 ERROR("rlm_sql (%s): %.*s", inst->config->xlat_name, (int) (q - p), p);
331                 p = q + 1;
332         }
333
334         if (*p != '\0') {
335                 ERROR("rlm_sql (%s): %s", inst->config->xlat_name, p);
336         }
337 }
338
339 static void rlm_sql_query_debug(rlm_sql_handle_t *handle, rlm_sql_t *inst)
340 {
341         char const *p, *q;
342
343         p = (inst->module->sql_error)(handle, inst->config);
344         if (!p) {
345                 return;
346         }
347
348         /*
349          *      Some drivers are nice and provide us with a ^ pointer to
350          *      the place in the query string where the error occurred.
351          *
352          *      For this to be useful we need to split log messages on
353          *      \n and output each of the lines individually.
354          */
355         while ((q = strchr(p, '\n'))) {
356                 DEBUG2("rlm_sql (%s): %.*s", inst->config->xlat_name, (int) (q - p), p);
357                 p = q + 1;
358         }
359
360         if (*p != '\0') {
361                 DEBUG2("rlm_sql (%s): %s", inst->config->xlat_name, p);
362         }
363 }
364
365 /*************************************************************************
366  *
367  *      Function: rlm_sql_query
368  *
369  *      Purpose: call the module's sql_query and implement re-connect
370  *
371  *************************************************************************/
372 int rlm_sql_query(rlm_sql_handle_t **handle, rlm_sql_t *inst, char const *query)
373 {
374         int ret = -1;
375
376         /*
377          *      If there's no query, return an error.
378          */
379         if (!query || !*query) {
380                 return -1;
381         }
382
383         if (!*handle || !(*handle)->conn) {
384                 goto sql_down;
385         }
386
387         while (true) {
388                 DEBUG("rlm_sql (%s): Executing query: '%s'", inst->config->xlat_name, query);
389
390                 ret = (inst->module->sql_query)(*handle, inst->config, query);
391                 switch (ret) {
392                 case RLM_SQL_OK:
393                         break;
394
395                 /*
396                  *      Run through all available sockets until we exhaust all existing
397                  *      sockets in the pool and fail to establish a *new* connection.
398                  */
399                 case RLM_SQL_RECONNECT:
400                 sql_down:
401                         *handle = fr_connection_reconnect(inst->pool, *handle);
402                         if (!*handle) return RLM_SQL_RECONNECT;
403                         continue;
404
405                 case RLM_SQL_QUERY_ERROR:
406                 case RLM_SQL_ERROR:
407                         rlm_sql_query_error(*handle, inst);
408                         break;
409
410                 case RLM_SQL_DUPLICATE:
411                         rlm_sql_query_debug(*handle, inst);
412                         break;
413
414                 }
415
416                 return ret;
417         }
418 }
419
420 /*************************************************************************
421  *
422  *      Function: rlm_sql_select_query
423  *
424  *      Purpose: call the module's sql_select_query and implement re-connect
425  *
426  *************************************************************************/
427 int rlm_sql_select_query(rlm_sql_handle_t **handle, rlm_sql_t *inst, char const *query)
428 {
429         int ret = -1;
430
431         /*
432          *      If there's no query, return an error.
433          */
434         if (!query || !*query) return -1;
435
436         if (!*handle || !(*handle)->conn) goto sql_down;
437
438         while (true) {
439                 DEBUG("rlm_sql (%s): Executing query: '%s'", inst->config->xlat_name, query);
440
441                 ret = (inst->module->sql_select_query)(*handle, inst->config, query);
442                 switch (ret) {
443                 case RLM_SQL_OK:
444                         break;
445
446                 /*
447                  *      Run through all available sockets until we exhaust all existing
448                  *      sockets in the pool and fail to establish a *new* connection.
449                  */
450                 case RLM_SQL_RECONNECT:
451                 sql_down:
452                         if (!*handle) return RLM_SQL_RECONNECT;
453
454                         if (!(*handle)->init) return RLM_SQL_RECONNECT;
455
456                         *handle = fr_connection_reconnect(inst->pool, *handle);
457                         continue;
458
459                 case RLM_SQL_QUERY_ERROR:
460                 case RLM_SQL_ERROR:
461                         rlm_sql_query_error(*handle, inst);
462                         break;
463
464                 case RLM_SQL_DUPLICATE:
465                         rlm_sql_query_debug(*handle, inst);
466                         break;
467
468                 }
469
470                 return ret;
471         }
472 }
473
474
475 /*************************************************************************
476  *
477  *      Function: sql_getvpdata
478  *
479  *      Purpose: Get any group check or reply pairs
480  *
481  *************************************************************************/
482 int sql_getvpdata(rlm_sql_t * inst, rlm_sql_handle_t **handle,
483                   TALLOC_CTX *ctx, VALUE_PAIR **pair, char const *query)
484 {
485         rlm_sql_row_t row;
486         int     rows = 0;
487
488         if (rlm_sql_select_query(handle, inst, query)) {
489                 return -1;
490         }
491
492         while (rlm_sql_fetch_row(handle, inst) == 0) {
493                 row = (*handle)->row;
494                 if (!row)
495                         break;
496                 if (sql_userparse(ctx, pair, row) != 0) {
497                         ERROR("rlm_sql (%s): Error parsing user data from database result", inst->config->xlat_name);
498
499                         (inst->module->sql_finish_select_query)(*handle, inst->config);
500
501                         return -1;
502                 }
503                 rows++;
504         }
505         (inst->module->sql_finish_select_query)(*handle, inst->config);
506
507         return rows;
508 }
509
510 /*
511  *      Log the query to a file.
512  */
513 void rlm_sql_query_log(rlm_sql_t *inst, REQUEST *request,
514                        sql_acct_section_t *section, char const *query)
515 {
516         int fd;
517         char const *filename = NULL;
518         char *expanded = NULL;
519         size_t len;
520         bool failed = false;    /* Write the log message outside of the critical region */
521
522         if (section) {
523                 filename = section->logfile;
524         } else {
525                 filename = inst->config->logfile;
526         }
527
528         if (!filename) {
529                 return;
530         }
531
532         if (radius_axlat(&expanded, request, filename, NULL, NULL) < 0) {
533                 return;
534         }
535
536         fd = fr_logfile_open(inst->lf, filename, 0640);
537         if (fd < 0) {
538                 ERROR("rlm_sql (%s): Couldn't open logfile '%s': %s", inst->config->xlat_name,
539                       expanded, fr_syserror(errno));
540
541                 talloc_free(expanded);
542                 return;
543         }
544
545         len = strlen(query);
546         if ((write(fd, query, len) < 0) || (write(fd, ";\n", 2) < 0)) {
547                 failed = true;
548         }
549
550         if (failed) {
551                 ERROR("rlm_sql (%s): Failed writing to logfile '%s': %s", inst->config->xlat_name, expanded,
552                       fr_syserror(errno));
553         }
554
555         talloc_free(expanded);
556         fr_logfile_close(inst->lf, fd);
557 }