The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
rlm_sql_sqlite.c
Go to the documentation of this file.
1/*
2 * This program is is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or (at
5 * your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: b7e7609d0988abe1bfc803374927f276a0f3b2b5 $
19 * @file rlm_sql_sqlite.c
20 * @brief SQLite driver.
21 *
22 * @copyright 2013 Network RADIUS SAS (legal@networkradius.com)
23 * @copyright 2007 Apple Inc.
24 */
25RCSID("$Id: b7e7609d0988abe1bfc803374927f276a0f3b2b5 $")
26
27#define LOG_PREFIX "sql - sqlite"
28#include <freeradius-devel/server/base.h>
29#include <freeradius-devel/util/debug.h>
30
31#include <fcntl.h>
32#include <sys/stat.h>
33
34#include <sqlite3.h>
35
36#include "rlm_sql.h"
37#include "rlm_sql_trunk.h"
38#include "config.h"
39
40#define BOOTSTRAP_MAX (1048576 * 10)
41
42/*
43 * Allow us to use versions < 3.6.0 beta0
44 */
45#ifndef SQLITE_OPEN_NOMUTEX
46# define SQLITE_OPEN_NOMUTEX 0
47#endif
48
49#ifndef HAVE_SQLITE3_INT64
50typedef sqlite_int64 sqlite3_int64;
51#endif
52
53typedef struct {
54 sqlite3 *db;
55 sqlite3_stmt *statement;
58
64
65static const conf_parser_t driver_config[] = {
67 { FR_CONF_OFFSET("busy_timeout", rlm_sql_sqlite_t, busy_timeout) },
69};
70
71/** Convert an sqlite status code to an sql_rcode_t
72 *
73 * @param status to convert.
74 * @return
75 * - RLM_SQL_OK - If no errors found.
76 * - RLM_SQL_ERROR - If a known, non-fatal, error occurred.
77 * - RLM_SQL_ALT_QUERY - If a constraints violation occurred.
78 * - RLM_SQL_RECONNECT - Anything else, we assume the connection can no longer be used.
79 */
81{
82 /*
83 * Lowest byte is error category, other byte may contain
84 * the extended error, depending on version.
85 */
86 switch (status & 0xff) {
87 /*
88 * Not errors
89 */
90 case SQLITE_OK:
91 case SQLITE_DONE:
92 case SQLITE_ROW:
93 return RLM_SQL_OK;
94 /*
95 * User/transient errors
96 */
97 case SQLITE_ERROR: /* SQL error or missing database */
98 case SQLITE_FULL:
99 case SQLITE_MISMATCH:
100 case SQLITE_BUSY: /* Can be caused by database locking */
101 WARN("SQLite reported error %d: %s", status, sqlite3_errstr(status));
102 return RLM_SQL_ERROR;
103
104 /*
105 * Constraints violations
106 */
107 case SQLITE_CONSTRAINT:
108 return RLM_SQL_ALT_QUERY;
109
110 /*
111 * Errors with the handle, that probably require reinitialisation
112 */
113 default:
114 return RLM_SQL_RECONNECT;
115 }
116}
117
118/** Determine if an error occurred, and what type of error it was
119 *
120 * @param db handle to extract error from (may be NULL).
121 * @param status to check (if unused, set to SQLITE_OK).
122 * @return
123 * - RLM_SQL_OK - If no errors found.
124 * - RLM_SQL_ERROR - If a known, non-fatal, error occurred.
125 * - RLM_SQL_ALT_QUERY - If a constraints violation occurred.
126 * - RLM_SQL_RECONNECT - Anything else. We assume the connection can no longer be used.
127 */
128static sql_rcode_t sql_check_error(sqlite3 *db, int status)
129{
130 int hstatus = SQLITE_OK;
131
132 if (db) {
133 hstatus = sqlite3_errcode(db);
134 switch (hstatus & 0xff) {
135 case SQLITE_OK:
136 case SQLITE_DONE:
137 case SQLITE_ROW:
138 hstatus = SQLITE_OK;
139 break;
140
141 default:
142 break;
143 }
144 }
145
146 switch (status & 0xff) {
147 case SQLITE_OK:
148 case SQLITE_DONE:
149 case SQLITE_ROW:
150 status = SQLITE_OK;
151 break;
152
153 default:
154 break;
155 }
156
157 if (status != SQLITE_OK) return sql_error_to_rcode(status);
158 if (hstatus != SQLITE_OK) return sql_error_to_rcode(hstatus);
159
160 return RLM_SQL_OK;
161}
162
163/** Print an error to the global debug log
164 *
165 * If status does not indicate success, write an error to the global error log.
166 *
167 * @note The error code will be appended to the fmt string in the format ": code 0x<hex> (<int>)[: <string>]".
168 *
169 * @param db handle to extract error from (may be NULL).
170 * @param status to check (if unused, set to SQLITE_OK).
171 * @param fmt to prepend.
172 * @param ... arguments to fmt.
173 */
174static void sql_print_error(sqlite3 *db, int status, char const *fmt, ...)
175 CC_HINT(format (printf, 3, 4)) CC_HINT(nonnull (3));
176static void sql_print_error(sqlite3 *db, int status, char const *fmt, ...)
177{
178 va_list ap;
179 char *p;
180 int hstatus = SQLITE_OK;
181
182 if (db) {
183 hstatus = sqlite3_errcode(db);
184 switch (hstatus & 0xff) {
185 case SQLITE_OK:
186 case SQLITE_DONE:
187 case SQLITE_ROW:
188 hstatus = SQLITE_OK;
189 break;
190
191 default:
192 break;
193 }
194 }
195
196 switch (status & 0xff) {
197 case SQLITE_OK:
198 case SQLITE_DONE:
199 case SQLITE_ROW:
200 status = SQLITE_OK;
201 break;
202
203 default:
204 break;
205 }
206
207 /*
208 * No errors!
209 */
210 if ((hstatus == SQLITE_OK) && (status == SQLITE_OK)) return;
211
212 /*
213 * At least one error...
214 */
215 va_start(ap, fmt);
216 MEM(p = talloc_vasprintf(NULL, fmt, ap));
217 va_end(ap);
218
219 /*
220 * Disagreement between handle, and function return code,
221 * print them both.
222 */
223 if ((status != SQLITE_OK) && (status != hstatus)) {
224 fr_strerror_printf("%s: Code 0x%04x (%i): %s", p, status, status, sqlite3_errstr(status));
225 }
226
227 if (hstatus != SQLITE_OK) fr_strerror_printf("%s: Code 0x%04x (%i): %s",
228 p, hstatus, hstatus, sqlite3_errmsg(db));
229}
230
231static int sql_loadfile(TALLOC_CTX *ctx, sqlite3 *db, char const *filename)
232{
233 ssize_t len;
234 int statement_len, statement_cnt = 0;
235 char *buffer;
236 char const *p;
237 int cl;
238 FILE *f;
239 struct stat finfo;
240
241 int status;
242 sqlite3_stmt *statement;
243 char const *z_tail;
244
245 INFO("Executing SQL statements from file \"%s\"", filename);
246
247 f = fopen(filename, "r");
248 if (!f) {
249 fr_strerror_printf("Failed opening SQL file \"%s\": %s", filename,
250 fr_syserror(errno));
251 return -1;
252 }
253
254 if (fstat(fileno(f), &finfo) < 0) {
255 fr_strerror_printf("Failed stating SQL file \"%s\": %s", filename,
256 fr_syserror(errno));
257 error:
258 fclose(f);
259 return -1;
260 }
261
262 if (finfo.st_size > BOOTSTRAP_MAX) {
263 too_big:
264 fr_strerror_printf("Size of SQL (%zu) file exceeds limit (%uk)",
265 (size_t) finfo.st_size / 1024, BOOTSTRAP_MAX / 1024);
266 goto error;
267 }
268
269 MEM(buffer = talloc_array(ctx, char, finfo.st_size + 1));
270 len = fread(buffer, sizeof(char), finfo.st_size, f);
271
272 if (len > finfo.st_size) {
274 goto too_big;
275 }
276
277 if (!len) {
279 if (ferror(f)) {
280 fr_strerror_printf("Failed reading from SQL file: %s", fr_syserror(errno));
281 goto error;
282 }
283
284 DEBUG("Ignoring empty SQL file");
285
286 fclose(f);
287 return 0;
288 }
289
290 buffer[len] = '\0';
291 fclose(f);
292
293 /*
294 * Check if input data is UTF-8. Allow CR/LF \t, too.
295 */
296 for (p = buffer; p < (buffer + len); p += cl) {
297 if (*p < ' ') {
298 if ((*p != 0x0a) && (*p != 0x0d) && (*p != '\t')) break;
299 cl = 1;
300 } else {
301 cl = fr_utf8_char((uint8_t const *) p, -1);
302 if (!cl) break;
303 }
304 }
305
306 if ((p - buffer) != len) {
307 fr_strerror_printf("Bootstrap file contains non-UTF8 char at offset %zu", p - buffer);
309 return -1;
310 }
311
312 p = buffer;
313 while (*p) {
314 statement_len = len - (p - buffer);
315 status = sqlite3_prepare_v2(db, p, statement_len, &statement, &z_tail);
316
317 if (sql_check_error(db, status) != RLM_SQL_OK) {
318 sql_print_error(db, status, "Failed preparing statement %i", statement_cnt);
320 return -1;
321 }
322
323 /*
324 * No SQL statement was found
325 */
326 if (!statement) break;
327
328 status = sqlite3_step(statement);
329 if (sql_check_error(db, status) != RLM_SQL_OK) {
330 sql_print_error(db, status, "Failed executing statement %i", statement_cnt);
331 sqlite3_finalize(statement);
333 return -1;
334 }
335
336 status = sqlite3_finalize(statement);
337 if (sql_check_error(db, status) != RLM_SQL_OK) {
338 sql_print_error(db, status, "Failed finalizing statement %i", statement_cnt);
340 return -1;
341 }
342
343 statement_cnt++;
344 p = z_tail;
345 }
346
348 return 0;
349}
350
351static void _sql_greatest(sqlite3_context *ctx, int num_values, sqlite3_value **values)
352{
353 int i;
354 sqlite3_int64 value, max = 0;
355
356 for (i = 0; i < num_values; i++) {
357 value = sqlite3_value_int64(values[i]);
358 if (value > max) {
359 max = value;
360 }
361 }
362
363 sqlite3_result_int64(ctx, max);
364}
365
366CC_NO_UBSAN(function) /* UBSAN: false positive - public vs private connection_t trips --fsanitize=function*/
367static connection_state_t _sql_connection_init(void **h, connection_t *conn, void *uctx)
368{
370 rlm_sql_sqlite_t *inst = talloc_get_type_abort(sql->driver_submodule->data, rlm_sql_sqlite_t);
372 int status;
373
374 MEM(c = talloc_zero(conn, rlm_sql_sqlite_conn_t));
375
376 INFO("Opening SQLite database \"%s\"", inst->filename);
377 status = sqlite3_open_v2(inst->filename, &(c->db), SQLITE_OPEN_READWRITE | SQLITE_OPEN_NOMUTEX, NULL);
378
379 if (!c->db || (sql_check_error(c->db, status) != RLM_SQL_OK)) {
380 int fd;
381
382 sql_print_error(c->db, status, "Failed opening SQLite database \"%s\"", inst->filename);
383 ERROR("%s", fr_strerror());
384
385 fd = open(inst->filename, O_RDWR);
386 if (fd < 0) {
387 if (!inst->bootstrap && (errno == ENOENT)) {
388 WARN("Perhaps use the sqlite driver 'bootstrap' option to create the database file?");
389 }
390
391 fr_strerror_printf("Cannot open \"%s\" in read/write mode - %s",
392 inst->filename, fr_syserror(errno));
393 } else {
394 close(fd);
395 fr_strerror_printf("Failed in SQLite while opening \"%s\" - the file exists, but is the database corrupted?",
396 inst->filename);
397 }
398
399 error:
400 ERROR("%s", fr_strerror());
401 talloc_free(c);
403 }
404 status = sqlite3_busy_timeout(c->db, fr_time_delta_to_msec(inst->busy_timeout));
405 if (sql_check_error(c->db, status) != RLM_SQL_OK) {
406 sql_print_error(c->db, status, "Failed setting busy timeout");
407 goto error;
408 }
409
410 /*
411 * Enable extended return codes for extra debugging info.
412 */
413 status = sqlite3_extended_result_codes(c->db, 1);
414 if (sql_check_error(c->db, status) != RLM_SQL_OK) {
415 sql_print_error(c->db, status, "Failed enabling extended result codes");
416 goto error;
417 }
418
419 status = sqlite3_create_function_v2(c->db, "GREATEST", -1, SQLITE_ANY, NULL,
420 _sql_greatest, NULL, NULL, NULL);
421 if (sql_check_error(c->db, status) != RLM_SQL_OK) {
422 sql_print_error(c->db, status, "Failed registering 'GREATEST' sql function");
423 goto error;
424 }
425
426 *h = c;
427
429}
430
431static void _sql_connection_close(UNUSED fr_event_list_t *el, void *h, UNUSED void *uctx)
432{
433 rlm_sql_sqlite_conn_t *c = talloc_get_type_abort(h, rlm_sql_sqlite_conn_t);
434 int status = 0;
435
436 DEBUG2("Socket destructor called, closing socket");
437
438 if (c->db) {
439 status = sqlite3_close(c->db);
440 if (status != SQLITE_OK) WARN("Got SQLite error when closing socket: %s",
441 sqlite3_errmsg(c->db));
442 }
443}
444
445static sql_rcode_t sql_fields(char const **out[], fr_sql_query_t *query_ctx, UNUSED rlm_sql_config_t const *config)
446{
447 rlm_sql_sqlite_conn_t *conn = talloc_get_type_abort(query_ctx->tconn->conn->h, rlm_sql_sqlite_conn_t);
448
449 int fields, i;
450 char const **names;
451
452 fields = sqlite3_column_count(conn->statement);
453 if (fields <= 0) return RLM_SQL_ERROR;
454
455 MEM(names = talloc_array(query_ctx, char const *, fields));
456
457 for (i = 0; i < fields; i++) names[i] = sqlite3_column_name(conn->statement, i);
458 *out = names;
459
460 return RLM_SQL_OK;
461}
462
463static unlang_action_t sql_fetch_row(unlang_result_t *p_result, UNUSED request_t *request, void *uctx)
464{
465 fr_sql_query_t *query_ctx = talloc_get_type_abort(uctx, fr_sql_query_t);
466 int status, i = 0;
467 rlm_sql_sqlite_conn_t *conn = talloc_get_type_abort(query_ctx->tconn->conn->h, rlm_sql_sqlite_conn_t);
468 char **row;
469
470 TALLOC_FREE(query_ctx->row);
471
472 /*
473 * Executes the SQLite query and iterates over the results
474 */
475 status = sqlite3_step(conn->statement);
476
477 /*
478 * Error getting next row
479 */
480 if (sql_check_error(conn->db, status) != RLM_SQL_OK) {
481 error:
482 query_ctx->rcode = RLM_SQL_ERROR;
484 }
485
486 /*
487 * No more rows to process (we're done)
488 */
489 if (status == SQLITE_DONE) {
490 query_ctx->rcode = RLM_SQL_NO_MORE_ROWS;
492 }
493
494 /*
495 * We only need to do this once per result set, because
496 * the number of columns won't change.
497 */
498 if (conn->col_count == 0) {
499 conn->col_count = sqlite3_column_count(conn->statement);
500 if (conn->col_count == 0) goto error;
501 }
502
503 /*
504 * Free the previous result (also gets called on finish_query)
505 */
506 MEM(row = query_ctx->row = talloc_zero_array(query_ctx, char *, conn->col_count + 1));
507
508 for (i = 0; i < conn->col_count; i++) {
509 switch (sqlite3_column_type(conn->statement, i)) {
510 case SQLITE_INTEGER:
511 MEM(row[i] = talloc_typed_asprintf(row, "%d", sqlite3_column_int(conn->statement, i)));
512 break;
513
514 case SQLITE_FLOAT:
515 MEM(row[i] = talloc_typed_asprintf(row, "%f", sqlite3_column_double(conn->statement, i)));
516 break;
517
518 case SQLITE_TEXT:
519 {
520 char const *p;
521 p = (char const *) sqlite3_column_text(conn->statement, i);
522
523 if (p) MEM(row[i] = talloc_typed_strdup(row, p));
524 }
525 break;
526
527 case SQLITE_BLOB:
528 {
529 uint8_t const *p;
530 size_t len;
531
532 p = sqlite3_column_blob(conn->statement, i);
533 if (p) {
534 len = sqlite3_column_bytes(conn->statement, i);
535
536 MEM(row[i] = talloc_zero_array(row, char, len + 1));
537 memcpy(row[i], p, len);
538 }
539 }
540 break;
541
542 default:
543 break;
544 }
545 }
546
547 query_ctx->rcode = RLM_SQL_OK;
549}
550
552{
553 rlm_sql_sqlite_conn_t *conn = talloc_get_type_abort(query_ctx->tconn->conn->h, rlm_sql_sqlite_conn_t);
554
555 if (conn->statement) {
556 TALLOC_FREE(query_ctx->row);
557
558 (void) sqlite3_finalize(conn->statement);
559 conn->statement = NULL;
560 conn->col_count = 0;
561 }
562
563 /*
564 * There's no point in checking the code returned by finalize
565 * as it'll have already been encountered elsewhere in the code.
566 *
567 * It's just the last error that occurred processing the
568 * statement.
569 */
570 return RLM_SQL_OK;
571}
572
573/** Retrieves any errors associated with the query context
574 *
575 * @note Caller will free any memory allocated in ctx.
576 *
577 * @param ctx to allocate temporary error buffers in.
578 * @param out Array of sql_log_entrys to fill.
579 * @param outlen Length of out array.
580 * @param query_ctx Query context to retrieve error for.
581 * @return number of errors written to the #sql_log_entry_t array.
582 */
583static size_t sql_error(UNUSED TALLOC_CTX *ctx, sql_log_entry_t out[], NDEBUG_UNUSED size_t outlen,
584 fr_sql_query_t *query_ctx)
585{
586 rlm_sql_sqlite_conn_t *conn = talloc_get_type_abort(query_ctx->tconn->conn->h, rlm_sql_sqlite_conn_t);
587 char const *error;
588
589 fr_assert(outlen > 0);
590
591 error = sqlite3_errmsg(conn->db);
592 if (!error) return 0;
593
594 out[0].type = L_ERR;
595 out[0].msg = error;
596
597 return 1;
598}
599
601{
602 return sql_free_result(query_ctx, config);
603}
604
605static int sql_affected_rows(fr_sql_query_t *query_ctx,
607{
608 rlm_sql_sqlite_conn_t *conn = talloc_get_type_abort(query_ctx->tconn->conn->h, rlm_sql_sqlite_conn_t);
609
610 if (conn->db) return sqlite3_changes(conn->db);
611
612 return -1;
613}
614
616
617CC_NO_UBSAN(function) /* UBSAN: false positive - public vs private connection_t trips --fsanitize=function*/
619 connection_t *conn, UNUSED void *uctx)
620{
621 rlm_sql_sqlite_conn_t *sql_conn = talloc_get_type_abort(conn->h, rlm_sql_sqlite_conn_t);
622 trunk_request_t *treq;
623 request_t *request;
624 fr_sql_query_t *query_ctx;
625 int status;
626 char const *z_tail;
627
628 if (trunk_connection_pop_request(&treq, tconn) != 0) return;
629 if (!treq) return;
630
631 query_ctx = talloc_get_type_abort(treq->preq, fr_sql_query_t);
632 request = query_ctx->request;
633 query_ctx->tconn = tconn;
634
635 ROPTIONAL(RDEBUG2, DEBUG2, "Executing query: %s", query_ctx->query_str);
636 status = sqlite3_prepare_v2(sql_conn->db, query_ctx->query_str, strlen(query_ctx->query_str),
637 &sql_conn->statement, &z_tail);
638 query_ctx->rcode = sql_check_error(sql_conn->db, status);
639 if (query_ctx->rcode != RLM_SQL_OK) {
640 error:
641 query_ctx->status = SQL_QUERY_FAILED;
643 return;
644 }
645
646 /*
647 * Set the query status to > 0 so that freeing the query_ctx
648 * will tidy up correctly.
649 */
650 query_ctx->status = SQL_QUERY_SUBMITTED;
651
652 if (query_ctx->type == SQL_QUERY_OTHER) {
653 status = sqlite3_step(sql_conn->statement);
654 query_ctx->rcode = sql_check_error(sql_conn->db, status);
655 if (query_ctx->rcode == RLM_SQL_ERROR) {
656 (void) sqlite3_finalize(sql_conn->statement);
657 sql_conn->statement = NULL;
658 goto error;
659 }
660 }
661
663
664 /* If the query went into a backlog, the request will have yielded - so mark runnable just in case */
665 if (request) unlang_interpret_mark_runnable(request);
666}
667
669
670static void sql_request_fail(UNUSED request_t *request, void *preq, UNUSED void *rctx,
671 UNUSED trunk_request_state_t state, UNUSED void *uctx)
672{
673 fr_sql_query_t *query_ctx = talloc_get_type_abort(preq, fr_sql_query_t);
674
675 query_ctx->treq = NULL;
676 if (query_ctx->rcode == RLM_SQL_OK) query_ctx->rcode = RLM_SQL_ERROR;
677}
678
679static void sql_request_complete(UNUSED request_t *request, void *preq, UNUSED void *rctx, UNUSED void *uctx)
680{
681 fr_sql_query_t *query_ctx = talloc_get_type_abort(preq, fr_sql_query_t);
682
683 sql_free_result(query_ctx, NULL);
684}
685
686static int mod_instantiate(module_inst_ctx_t const *mctx)
687{
688 rlm_sql_t const *parent = talloc_get_type_abort(mctx->mi->parent->data, rlm_sql_t);
689 rlm_sql_config_t const *config = &parent->config;
690 rlm_sql_sqlite_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_sql_sqlite_t);
691 bool exists;
692 struct stat buf;
693 int fd;
694 char const *r;
695
696 if (!inst->filename) {
697 MEM(inst->filename = talloc_typed_asprintf(inst, "%s/%s",
698 main_config->raddb_dir, config->sql_db));
699 }
700
701 /*
702 * We will try to create the database if it doesn't exist, up to and
703 * including creating the directory it should live in, in which case
704 * we get to call fr_dirfd() again. Hence failing this first fr_dirfd()
705 * just means the database isn't there.
706 */
707 if (fr_dirfd(&fd, &r, inst->filename) < 0) {
708 exists = false;
709 } else if (fstatat(fd, r, &buf, 0) == 0) {
710 exists = true;
711 } else if (errno == ENOENT) {
712 exists = false;
713 } else {
714 ERROR("Database exists, but couldn't be opened: %s", fr_syserror(errno));
715 close(fd);
716 return -1;
717 }
718
719 if (cf_pair_find(mctx->mi->conf, "bootstrap")) {
720 inst->bootstrap = true;
721 }
722
723 if (inst->bootstrap && !exists) {
724 int status;
725 int ret;
726 char const *p;
727 char *buff;
728 sqlite3 *db = NULL;
729 CONF_PAIR *cp;
730
731 INFO("Database \"%s\" doesn't exist, creating it and loading schema", inst->filename);
732
733 p = strrchr(inst->filename, '/');
734 if (p) {
735 size_t len = (p - inst->filename) + 1;
736
737 buff = talloc_array(mctx->mi->conf, char, len);
738 strlcpy(buff, inst->filename, len);
739 } else {
740 MEM(buff = talloc_typed_strdup(mctx->mi->conf, inst->filename));
741 }
742
743 ret = fr_mkdir(NULL, buff, -1, 0700, NULL, NULL);
745 if (ret < 0) {
746 PERROR("Failed creating directory for SQLite database");
747
748 return -1;
749 }
750 (void) fr_dirfd(&fd, &r, inst->filename);
751
752 status = sqlite3_open_v2(inst->filename, &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
753 if (!db) {
754 ERROR("Failed creating opening/creating SQLite database: %s",
755 sqlite3_errstr(status));
756 goto unlink;
757 }
758
759 if (sql_check_error(db, status) != RLM_SQL_OK) {
760 (void) sqlite3_close(db);
761
762 goto unlink;
763 }
764
765 /*
766 * Execute multiple bootstrap SQL files in order
767 */
768 for (cp = cf_pair_find(mctx->mi->conf, "bootstrap");
769 cp;
770 cp = cf_pair_find_next(mctx->mi->conf, cp, "bootstrap")) {
771 p = cf_pair_value(cp);
772 if (!p) continue;
773
774 ret = sql_loadfile(mctx->mi->conf, db, p);
775 if (ret < 0) {
776 ERROR("%s", fr_strerror());
777 (void) sqlite3_close(db);
778 goto unlink;
779 }
780 }
781
782 status = sqlite3_close(db);
783 if (status != SQLITE_OK) {
784 /*
785 * Safer to use sqlite3_errstr here, just in case the handle is in a weird state
786 */
787 ERROR("Failed closing SQLite handle: %s", sqlite3_errstr(status));
788 goto unlink;
789 }
790
791 if (ret < 0) {
792 unlink:
793 if ((unlinkat(fd, r, 0) < 0) && (errno != ENOENT)) {
794 ERROR("Failed to remove partially initialised database: %s",
795 fr_syserror(errno));
796 }
797 close(fd);
798 return -1;
799 }
800 }
801
802 close(fd);
803 return 0;
804}
805
806static int mod_load(void)
807{
808 if (sqlite3_libversion_number() != SQLITE_VERSION_NUMBER) {
809 WARN("libsqlite version changed since the server was built");
810 WARN("linked: %s built: %s", sqlite3_libversion(), SQLITE_VERSION);
811 }
812 INFO("libsqlite version: %s", sqlite3_libversion());
813
814 return 0;
815}
816
817/* Exported to rlm_sql */
820 .common = {
821 .name = "sql_sqlite",
822 .magic = MODULE_MAGIC_INIT,
823 .inst_size = sizeof(rlm_sql_sqlite_t),
825 .onload = mod_load,
827 },
829 .sql_query_resume = sql_query_resume,
830 .sql_select_query_resume = sql_query_resume,
831 .sql_affected_rows = sql_affected_rows,
832 .sql_fetch_row = sql_fetch_row,
833 .sql_fields = sql_fields,
834 .sql_free_result = sql_free_result,
835 .sql_error = sql_error,
836 .sql_finish_query = sql_finish_query,
837 .sql_finish_select_query = sql_finish_query,
838 .trunk_io_funcs = {
839 .connection_alloc = sql_trunk_connection_alloc,
840 .request_mux = sql_trunk_request_mux,
841 .request_complete = sql_request_complete,
842 .request_fail = sql_request_fail
843 }
844};
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition action.h:35
static int const char char buffer[256]
Definition acutest.h:576
va_end(args)
static int const char * fmt
Definition acutest.h:573
va_start(args, fmt)
#define RCSID(id)
Definition build.h:485
#define NDEBUG_UNUSED
Definition build.h:328
#define CC_NO_UBSAN(_sanitize)
Definition build.h:428
#define UNUSED
Definition build.h:317
#define CONF_PARSER_TERMINATOR
Definition cf_parse.h:658
#define FR_CONF_OFFSET(_name, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition cf_parse.h:284
conf_parser_flags_t flags
Flags which control parsing behaviour.
Definition cf_parse.h:601
#define FR_CONF_OFFSET_FLAGS(_name, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition cf_parse.h:272
@ CONF_FLAG_REQUIRED
Error out if no matching CONF_PAIR is found, and no dflt value is set.
Definition cf_parse.h:434
@ CONF_FLAG_FILE_OUTPUT
File matching value must exist, and must be writable.
Definition cf_parse.h:442
Defines a CONF_PAIR to C data type mapping.
Definition cf_parse.h:595
Configuration AVP similar to a fr_pair_t.
Definition cf_priv.h:70
CONF_PAIR * cf_pair_find_next(CONF_SECTION const *cs, CONF_PAIR const *prev, char const *attr)
Find a pair with a name matching attr, after specified pair.
Definition cf_util.c:1452
CONF_PAIR * cf_pair_find(CONF_SECTION const *cs, char const *attr)
Search for a CONF_PAIR with a specific name.
Definition cf_util.c:1438
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
Definition cf_util.c:1593
connection_state_t
Definition connection.h:45
@ CONNECTION_STATE_FAILED
Connection has failed.
Definition connection.h:54
@ CONNECTION_STATE_CONNECTED
File descriptor is open (ready for writing).
Definition connection.h:52
#define MEM(x)
Definition debug.h:36
#define ERROR(fmt,...)
Definition dhcpclient.c:41
#define DEBUG(fmt,...)
Definition dhcpclient.c:39
Test enumeration values.
Definition dict_test.h:92
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition dl_module.h:63
ssize_t fr_mkdir(int *fd_out, char const *path, ssize_t len, mode_t mode, fr_mkdir_func_t func, void *uctx)
Create directories that are missing in the specified path.
Definition file.c:219
int fr_dirfd(int *dirfd, char const **filename, char const *pathname)
From a pathname, return fd and filename needed for *at() functions.
Definition file.c:412
void unlang_interpret_mark_runnable(request_t *request)
Mark a request as resumable.
Definition interpret.c:1616
#define PERROR(_fmt,...)
Definition log.h:228
#define ROPTIONAL(_l_request, _l_global, _fmt,...)
Use different logging functions depending on whether request is NULL or not.
Definition log.h:528
talloc_free(reap)
Stores all information relating to an event list.
Definition event.c:377
@ L_ERR
Error message.
Definition log.h:56
main_config_t const * main_config
Main server configuration.
Definition main_config.c:58
char const * raddb_dir
Path to raddb directory.
Definition main_config.h:76
long int ssize_t
unsigned char uint8_t
module_instance_t * mi
Instance of the module being instantiated.
Definition module_ctx.h:51
Temporary structure to hold arguments for instantiation calls.
Definition module_ctx.h:50
size_t fr_utf8_char(uint8_t const *str, ssize_t inlen)
Checks for utf-8, taken from http://www.w3.org/International/questions/qa-forms-utf-8.
Definition print.c:39
static const conf_parser_t config[]
Definition base.c:186
#define fr_assert(_expr)
Definition rad_assert.h:38
#define RDEBUG2(fmt,...)
Definition radclient.h:54
#define DEBUG2(fmt,...)
Definition radclient.h:43
#define WARN(fmt,...)
Definition radclient.h:47
#define INFO(fmt,...)
Definition radict.c:54
#define RETURN_UNLANG_FAIL
Definition rcode.h:57
#define RETURN_UNLANG_OK
Definition rcode.h:58
static int instantiate(module_inst_ctx_t const *mctx)
Definition rlm_rest.c:1297
Prototypes and functions for the SQL module.
fr_sql_query_status_t status
Status of the query.
Definition rlm_sql.h:144
trunk_connection_t * tconn
Trunk connection this query is being run on.
Definition rlm_sql.h:140
fr_sql_query_type_t type
Type of query.
Definition rlm_sql.h:143
char const * query_str
Query string to run.
Definition rlm_sql.h:142
request_t * request
Request this query relates to.
Definition rlm_sql.h:138
sql_rcode_t
Action to take at end of an SQL query.
Definition rlm_sql.h:44
@ RLM_SQL_ALT_QUERY
Key constraint violation, use an alternative query.
Definition rlm_sql.h:49
@ RLM_SQL_RECONNECT
Stale connection, should reconnect.
Definition rlm_sql.h:48
@ RLM_SQL_ERROR
General connection/server error.
Definition rlm_sql.h:46
@ RLM_SQL_OK
Success.
Definition rlm_sql.h:47
@ RLM_SQL_NO_MORE_ROWS
No more rows available.
Definition rlm_sql.h:50
@ SQL_QUERY_OTHER
Definition rlm_sql.h:121
#define RLM_SQL_RCODE_FLAGS_ALT_QUERY
Can distinguish between other errors and those resulting from a unique key violation.
Definition rlm_sql.h:171
rlm_sql_row_t row
Row data from the last query.
Definition rlm_sql.h:146
sql_rcode_t rcode
Result code.
Definition rlm_sql.h:145
trunk_request_t * treq
Trunk request for this query.
Definition rlm_sql.h:141
@ SQL_QUERY_FAILED
Failed to submit.
Definition rlm_sql.h:127
@ SQL_QUERY_SUBMITTED
Submitted for execution.
Definition rlm_sql.h:129
Definition rlm_sql.h:61
static void sql_request_complete(UNUSED request_t *request, void *preq, UNUSED void *rctx, UNUSED void *uctx)
static size_t sql_error(UNUSED TALLOC_CTX *ctx, sql_log_entry_t out[], NDEBUG_UNUSED size_t outlen, fr_sql_query_t *query_ctx)
Retrieves any errors associated with the query context.
sqlite_int64 sqlite3_int64
static int mod_load(void)
static sql_rcode_t sql_fields(char const **out[], fr_sql_query_t *query_ctx, UNUSED rlm_sql_config_t const *config)
static SQL_TRUNK_CONNECTION_ALLOC void sql_trunk_request_mux(UNUSED fr_event_list_t *el, trunk_connection_t *tconn, connection_t *conn, UNUSED void *uctx)
static unlang_action_t sql_fetch_row(unlang_result_t *p_result, UNUSED request_t *request, void *uctx)
static void sql_print_error(sqlite3 *db, int status, char const *fmt,...))
Print an error to the global debug log.
rlm_sql_driver_t rlm_sql_sqlite
static connection_state_t _sql_connection_init(void **h, connection_t *conn, void *uctx)
char const * filename
static int sql_loadfile(TALLOC_CTX *ctx, sqlite3 *db, char const *filename)
sqlite3_stmt * statement
static void _sql_connection_close(UNUSED fr_event_list_t *el, void *h, UNUSED void *uctx)
static const conf_parser_t driver_config[]
static sql_rcode_t sql_error_to_rcode(int status)
Convert an sqlite status code to an sql_rcode_t.
#define SQLITE_OPEN_NOMUTEX
#define BOOTSTRAP_MAX
static SQL_QUERY_RESUME void sql_request_fail(UNUSED request_t *request, void *preq, UNUSED void *rctx, UNUSED trunk_request_state_t state, UNUSED void *uctx)
static sql_rcode_t sql_finish_query(fr_sql_query_t *query_ctx, rlm_sql_config_t const *config)
static sql_rcode_t sql_free_result(fr_sql_query_t *query_ctx, UNUSED rlm_sql_config_t const *config)
fr_time_delta_t busy_timeout
static int sql_affected_rows(fr_sql_query_t *query_ctx, UNUSED rlm_sql_config_t const *config)
static int mod_instantiate(module_inst_ctx_t const *mctx)
static sql_rcode_t sql_check_error(sqlite3 *db, int status)
Determine if an error occurred, and what type of error it was.
static void _sql_greatest(sqlite3_context *ctx, int num_values, sqlite3_value **values)
Macros to reduce boilerplate in trunk SQL drivers.
#define SQL_QUERY_RESUME
#define SQL_TRUNK_CONNECTION_ALLOC
Allocate an SQL trunk connection.
CONF_SECTION * conf
Module's instance configuration.
Definition module.h:349
size_t inst_size
Size of the module's instance data.
Definition module.h:212
void * data
Module's instance data.
Definition module.h:291
module_instance_t const * parent
Parent module's instance (if any).
Definition module.h:357
static char buff[sizeof("18446744073709551615")+3]
Definition size_tests.c:41
eap_aka_sim_process_conf_t * inst
size_t strlcpy(char *dst, char const *src, size_t siz)
Definition strlcpy.c:34
module_t common
Common fields for all loadable modules.
Definition rlm_sql.h:201
module_instance_t * driver_submodule
Driver's submodule.
Definition rlm_sql.h:234
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
char * talloc_typed_asprintf(TALLOC_CTX *ctx, char const *fmt,...)
Call talloc vasprintf, setting the type on the new chunk correctly.
Definition talloc.c:514
char * talloc_typed_strdup(TALLOC_CTX *ctx, char const *p)
Call talloc_strdup, setting the type on the new chunk correctly.
Definition talloc.c:467
#define talloc_get_type_abort_const
Definition talloc.h:287
static const char * names[8]
Definition time.c:584
static int64_t fr_time_delta_to_msec(fr_time_delta_t delta)
Definition time.h:637
A time delta, a difference in time measured in nanoseconds.
Definition time.h:80
void trunk_request_signal_fail(trunk_request_t *treq)
Signal that a trunk request failed.
Definition trunk.c:2131
int trunk_connection_pop_request(trunk_request_t **treq_out, trunk_connection_t *tconn)
Pop a request off a connection's pending queue.
Definition trunk.c:3882
void trunk_request_signal_reapable(trunk_request_t *treq)
Signal that the request was written to a connection successfully, but no response is expected.
Definition trunk.c:2071
Associates request queues with a connection.
Definition trunk.c:133
Wraps a normal request.
Definition trunk.c:99
trunk_request_state_t
Used for sanity checks and to simplify freeing.
Definition trunk.h:161
close(uq->fd)
static fr_event_list_t * el
static fr_slen_t parent
Definition pair.h:839
char const * fr_strerror(void)
Get the last library error.
Definition strerror.c:553
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
int nonnull(2, 5))
static size_t char ** out
Definition value.h:1020