The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
rlm_sql_firebird.c
Go to the documentation of this file.
1/*
2 * sql_firebird.c Part of Firebird rlm_sql driver
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 * @copyright 2006 The FreeRADIUS server project
19 * @copyright 2006 Vitaly Bodzhgua (vitaly@eastera.net)
20 */
21RCSID("$Id: 03e43903e020e30f25fa290d814cd01522b168e8 $")
22
23#define LOG_PREFIX "sql - firebird"
24
25#include "sql_fbapi.h"
26#include <freeradius-devel/util/debug.h>
27#include "rlm_sql_trunk.h"
28
29static char tpb[] = {isc_tpb_version3, isc_tpb_wait, isc_tpb_write,
30 isc_tpb_read_committed, isc_tpb_no_rec_version};
31
32/** Establish connection to the db
33 *
34 */
35CC_NO_UBSAN(function) /* UBSAN: false positive - public vs private connection_t trips --fsanitize=function */
36static connection_state_t _sql_connection_init(void **h, connection_t *conn, void *uctx)
37{
40
41 MEM(c = talloc_zero(conn, rlm_sql_firebird_conn_t));
42
43 /*
44 * Firebird uses a client assigned structure to write info about output data.
45 * Based on standard authorize queries, we pre-allocate a structure
46 * for 5 columns in SELECT queries.
47 */
48 MEM(c->sqlda_out = (XSQLDA *)_talloc_array(conn, 1, XSQLDA_LENGTH(5), "XSQLDA"));
49 c->sqlda_out->sqln = 5;
50 c->sqlda_out->version = SQLDA_VERSION1;
51 c->sql_dialect = 3;
52
53 /*
54 * Set tpb to read_committed/wait/no_rec_version
55 */
56 c->tpb = tpb;
58
59 if (fb_connect(c, &sql->config)) {
60 ERROR("Connection failed: %s", c->error);
62 }
63
64 *h = c;
66}
67
68static void _sql_connection_close(UNUSED fr_event_list_t *el, void *h, UNUSED void *uctx)
69{
70 rlm_sql_firebird_conn_t *c = talloc_get_type_abort(h, rlm_sql_firebird_conn_t);
71
72 DEBUG2("Socket destructor called, closing socket");
73
74 fb_commit(c);
75 if (c->dbh) {
77 isc_detach_database(c->status, &(c->dbh));
78
79 if (fb_error(c)) WARN("Got error when closing socket: %s", c->error);
80 }
81
82 talloc_free_children(c);
83}
84
86
87CC_NO_UBSAN(function) /* UBSAN: false positive - public vs private connection_t trips --fsanitize=function */
89 connection_t *conn, UNUSED void *uctx)
90{
91 rlm_sql_firebird_conn_t *sql_conn = talloc_get_type_abort(conn->h, rlm_sql_firebird_conn_t);
92 trunk_request_t *treq;
93 request_t *request;
94 fr_sql_query_t *query_ctx;
95 bool deadlock = false;
96
97 if (trunk_connection_pop_request(&treq, tconn) != 0) return;
98 if (!treq) return;
99
100 query_ctx = talloc_get_type_abort(treq->preq, fr_sql_query_t);
101 request = query_ctx->request;
102 query_ctx->tconn = tconn;
103
104 ROPTIONAL(RDEBUG2, DEBUG2, "Executing query: %s", query_ctx->query_str);
105
106 try_again:
107 /*
108 * Try again query when deadlock, because in any case it
109 * will be retried.
110 */
111 if (fb_sql_query(sql_conn, query_ctx->query_str)) {
112 /* but may be lost for short sessions */
113 if ((sql_conn->sql_code == DEADLOCK_SQL_CODE) && !deadlock) {
114 ROPTIONAL(RWARN, WARN, "SQL deadlock. Retry query %s", query_ctx->query_str);
115
116 /*
117 * @todo For non READ_COMMITED transactions put
118 * rollback here
119 * fb_rollback(conn);
120 */
121 deadlock = true;
122 goto try_again;
123 }
124
125 if (sql_conn->sql_code == DUPLICATE_KEY_SQL_CODE) {
126 query_ctx->rcode = RLM_SQL_ALT_QUERY;
127 goto finish;
128 }
129
130 ROPTIONAL(RERROR, ERROR, "conn_id rlm_sql_firebird,sql_query error: sql_code=%li, error='%s', query=%s",
131 (long int) sql_conn->sql_code, sql_conn->error, query_ctx->query_str);
132
133 query_ctx->status = SQL_QUERY_FAILED;
135
136 if (sql_conn->sql_code == DOWN_SQL_CODE) {
137 reconnect:
138 query_ctx->rcode = RLM_SQL_RECONNECT;
140 return;
141 }
142
143 /* Free problem query */
144 if (fb_rollback(sql_conn)) {
145 //assume the network is down if rollback had failed
146 ROPTIONAL(RERROR, ERROR, "Fail to rollback transaction after previous error: %s", sql_conn->error);
147
148 goto reconnect;
149 }
150
151 query_ctx->rcode = RLM_SQL_ERROR;
152 return;
153 }
154
155 query_ctx->rcode = RLM_SQL_OK;
156finish:
157 query_ctx->status = SQL_QUERY_RETURNED;
159 if (request) unlang_interpret_mark_runnable(request);
160}
161
163
164static void sql_request_complete(UNUSED request_t *request, void *preq, UNUSED void *rctx, UNUSED void *uctx)
165{
166 fr_sql_query_t *query_ctx = talloc_get_type_abort(preq, fr_sql_query_t);
167 rlm_sql_firebird_conn_t *conn = talloc_get_type_abort(query_ctx->tconn->conn->h, rlm_sql_firebird_conn_t);
168
169 fb_commit(conn);
170}
171
172static void sql_request_fail(UNUSED request_t *request, void *preq, UNUSED void *rctx,
173 UNUSED trunk_request_state_t state, UNUSED void *uctx)
174{
175 fr_sql_query_t *query_ctx = talloc_get_type_abort(preq, fr_sql_query_t);
176
177 query_ctx->treq = NULL;
178 if (query_ctx->rcode == RLM_SQL_OK) query_ctx->rcode = RLM_SQL_ERROR;
179}
180
181/** Returns name of fields.
182 *
183 */
184static sql_rcode_t sql_fields(char const **out[], fr_sql_query_t *query_ctx, UNUSED rlm_sql_config_t const *config)
185{
186 rlm_sql_firebird_conn_t *conn = talloc_get_type_abort(query_ctx->tconn->conn->h, rlm_sql_firebird_conn_t);
187
188 int fields, i;
189 char const **names;
190
191 fields = conn->sqlda_out->sqld;
192 if (fields <= 0) return RLM_SQL_ERROR;
193
194 MEM(names = talloc_array(query_ctx, char const *, fields));
195
196 for (i = 0; i < fields; i++) names[i] = conn->sqlda_out->sqlvar[i].sqlname;
197 *out = names;
198
199 return RLM_SQL_OK;
200}
201
202/** Returns an individual row.
203 *
204 */
205static unlang_action_t sql_fetch_row(rlm_rcode_t *p_result, UNUSED int *priority, UNUSED request_t *request, void *uctx)
206{
207 fr_sql_query_t *query_ctx = talloc_get_type_abort(uctx, fr_sql_query_t);
208 rlm_sql_firebird_conn_t *conn = talloc_get_type_abort(query_ctx->tconn->conn->h, rlm_sql_firebird_conn_t);
209 int res;
210
211 query_ctx->row = NULL;
212
213 if (conn->statement_type != isc_info_sql_stmt_exec_procedure) {
214 res = fb_fetch(conn);
215 if (res == 100) {
216 query_ctx->rcode = RLM_SQL_NO_MORE_ROWS;
218 }
219
220 if (res) {
221 ERROR("Fetch problem: %s", conn->error);
222
223 query_ctx->rcode = RLM_SQL_ERROR;
225 }
226 } else {
227 conn->statement_type = 0;
228 }
229
230 TALLOC_FREE(conn->row);
231 query_ctx->rcode = fb_store_row(conn);
232 if (query_ctx->rcode == RLM_SQL_OK) query_ctx->row = conn->row;
233
235}
236
237/** End the query, such as freeing memory or result.
238 *
239 */
241{
242 rlm_sql_firebird_conn_t *conn = talloc_get_type_abort(query_ctx->tconn->conn->h, rlm_sql_firebird_conn_t);
243
244 fb_free_statement(conn);
245 talloc_free_children(conn->sqlda_out);
246 TALLOC_FREE(conn->row);
247 query_ctx->status = SQL_QUERY_PREPARED;
248
249 return 0;
250}
251
252/** Frees memory allocated for a result set.
253 *
254 */
256{
257 rlm_sql_firebird_conn_t *conn = talloc_get_type_abort(query_ctx->tconn->conn->h, rlm_sql_firebird_conn_t);
258
259 TALLOC_FREE(conn->row);
260 return 0;
261}
262
263/** Retrieves any errors associated with the query context
264 *
265 * @note Caller will free any memory allocated in ctx.
266 *
267 * @param ctx to allocate temporary error buffers in.
268 * @param out Array of sql_log_entrys to fill.
269 * @param outlen Length of out array.
270 * @param query_ctx Query context to retrieve error for.
271 * @return number of errors written to the #sql_log_entry_t array.
272 */
273static size_t sql_error(UNUSED TALLOC_CTX *ctx, sql_log_entry_t out[], NDEBUG_UNUSED size_t outlen,
274 fr_sql_query_t *query_ctx)
275{
276 rlm_sql_firebird_conn_t *conn = talloc_get_type_abort(query_ctx->tconn->conn->h, rlm_sql_firebird_conn_t);
277
278 fr_assert(conn);
279 fr_assert(outlen > 0);
280
281 if (!conn->error) return 0;
282
283 out[0].type = L_ERR;
284 out[0].msg = conn->error;
285
286 return 1;
287}
288
289/** Return the number of rows affected by the query (update, or insert)
290 *
291 */
293{
294 rlm_sql_firebird_conn_t *conn = talloc_get_type_abort(query_ctx->tconn->conn->h, rlm_sql_firebird_conn_t);
295
296 return fb_affected_rows(conn);
297}
298
299/* Exported to rlm_sql */
302 .common = {
303 .name = "sql_firebird",
304 .magic = MODULE_MAGIC_INIT
305 },
307 .sql_query_resume = sql_query_resume,
308 .sql_select_query_resume = sql_query_resume,
309 .sql_affected_rows = sql_affected_rows,
310 .sql_fetch_row = sql_fetch_row,
311 .sql_fields = sql_fields,
312 .sql_free_result = sql_free_result,
313 .sql_error = sql_error,
314 .sql_finish_query = sql_finish_query,
315 .sql_finish_select_query = sql_finish_query,
316 .trunk_io_funcs = {
317 .connection_alloc = sql_trunk_connection_alloc,
318 .request_mux = sql_trunk_request_mux,
319 .request_complete = sql_request_complete,
320 .request_fail = sql_request_fail
321 }
322};
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition action.h:35
#define RCSID(id)
Definition build.h:483
#define NDEBUG_UNUSED
Definition build.h:326
#define CC_NO_UBSAN(_sanitize)
Definition build.h:426
#define UNUSED
Definition build.h:315
#define NUM_ELEMENTS(_t)
Definition build.h:337
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
@ CONNECTION_FAILED
Connection is being reconnected because it failed.
Definition connection.h:84
#define MEM(x)
Definition debug.h:36
#define ERROR(fmt,...)
Definition dhcpclient.c:41
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition dl_module.h:63
void unlang_interpret_mark_runnable(request_t *request)
Mark a request as resumable.
Definition interpret.c:1359
#define ROPTIONAL(_l_request, _l_global, _fmt,...)
Use different logging functions depending on whether request is NULL or not.
Definition log.h:528
#define RWARN(fmt,...)
Definition log.h:297
#define RERROR(fmt,...)
Definition log.h:298
Stores all information relating to an event list.
Definition event.c:411
@ L_ERR
Error message.
Definition log.h:56
static const conf_parser_t config[]
Definition base.c:183
#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 RETURN_MODULE_OK
Definition rcode.h:57
#define RETURN_MODULE_FAIL
Definition rcode.h:56
rlm_rcode_t
Return codes indicating the result of the module call.
Definition rcode.h:40
fr_sql_query_status_t status
Status of the query.
Definition rlm_sql.h:138
trunk_connection_t * tconn
Trunk connection this query is being run on.
Definition rlm_sql.h:134
char const * query_str
Query string to run.
Definition rlm_sql.h:136
request_t * request
Request this query relates to.
Definition rlm_sql.h:132
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
#define RLM_SQL_RCODE_FLAGS_ALT_QUERY
Can distinguish between other errors and those resulting from a unique key violation.
Definition rlm_sql.h:164
rlm_sql_row_t row
Row data from the last query.
Definition rlm_sql.h:140
sql_rcode_t rcode
Result code.
Definition rlm_sql.h:139
trunk_request_t * treq
Trunk request for this query.
Definition rlm_sql.h:135
@ SQL_QUERY_RETURNED
Query has executed.
Definition rlm_sql.h:124
@ SQL_QUERY_FAILED
Failed to submit.
Definition rlm_sql.h:121
@ SQL_QUERY_PREPARED
Ready to submit.
Definition rlm_sql.h:122
Definition rlm_sql.h:61
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.
static sql_rcode_t sql_fields(char const **out[], fr_sql_query_t *query_ctx, UNUSED rlm_sql_config_t const *config)
Returns name of fields.
static sql_rcode_t sql_finish_query(fr_sql_query_t *query_ctx, UNUSED rlm_sql_config_t const *config)
End the query, such as freeing memory or result.
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)
rlm_sql_driver_t rlm_sql_firebird
static connection_state_t _sql_connection_init(void **h, connection_t *conn, void *uctx)
Establish connection to the db.
static unlang_action_t sql_fetch_row(rlm_rcode_t *p_result, UNUSED int *priority, UNUSED request_t *request, void *uctx)
Returns an individual row.
static void _sql_connection_close(UNUSED fr_event_list_t *el, void *h, UNUSED void *uctx)
static char tpb[]
static SQL_QUERY_RESUME void sql_request_complete(UNUSED request_t *request, void *preq, UNUSED void *rctx, UNUSED void *uctx)
static sql_rcode_t sql_free_result(fr_sql_query_t *query_ctx, UNUSED rlm_sql_config_t const *config)
Frees memory allocated for a result set.
static void sql_request_fail(UNUSED request_t *request, void *preq, UNUSED void *rctx, UNUSED trunk_request_state_t state, UNUSED void *uctx)
static int sql_affected_rows(fr_sql_query_t *query_ctx, UNUSED rlm_sql_config_t const *config)
Return the number of rows affected by the query (update, or insert)
Macros to reduce boilerplate in trunk SQL drivers.
#define SQL_QUERY_RESUME
#define SQL_TRUNK_CONNECTION_ALLOC
Allocate an SQL trunk connection.
void connection_signal_reconnect(connection_t *conn, connection_reason_t reason)
Asynchronously signal the connection should be reconnected.
module_flags_t flags
Flags that control how a module starts up and how a module is called.
Definition module.h:227
int fb_sql_query(rlm_sql_firebird_conn_t *conn, char const *query)
Definition sql_fbapi.c:396
int fb_connect(rlm_sql_firebird_conn_t *conn, rlm_sql_config_t const *config)
Definition sql_fbapi.c:271
int fb_rollback(rlm_sql_firebird_conn_t *conn)
Definition sql_fbapi.c:447
int fb_error(rlm_sql_firebird_conn_t *conn)
Definition sql_fbapi.c:63
int fb_fetch(rlm_sql_firebird_conn_t *conn)
Definition sql_fbapi.c:331
sql_rcode_t fb_store_row(rlm_sql_firebird_conn_t *conn)
Definition sql_fbapi.c:133
int fb_commit(rlm_sql_firebird_conn_t *conn)
Definition sql_fbapi.c:456
int fb_affected_rows(rlm_sql_firebird_conn_t *conn)
Definition sql_fbapi.c:413
void fb_free_statement(rlm_sql_firebird_conn_t *conn)
Definition sql_fbapi.c:440
#define DUPLICATE_KEY_SQL_CODE
Definition sql_fbapi.h:35
#define DEADLOCK_SQL_CODE
Definition sql_fbapi.h:33
#define DOWN_SQL_CODE
Definition sql_fbapi.h:34
isc_db_handle dbh
Definition sql_fbapi.h:46
ISC_STATUS status[20]
Magic interbase status code array (holds multiple error codes used to construct more detailed error m...
Definition sql_fbapi.h:50
rlm_sql_row_t row
Definition sql_fbapi.h:63
module_t common
Common fields for all loadable modules.
Definition rlm_sql.h:194
rlm_sql_config_t config
Definition rlm_sql.h:221
#define talloc_get_type_abort_const
Definition talloc.h:282
static const char * names[8]
Definition time.c:621
void trunk_request_signal_fail(trunk_request_t *treq)
Signal that a trunk request failed.
Definition trunk.c:2132
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:3883
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:2072
Associates request queues with a connection.
Definition trunk.c:134
Wraps a normal request.
Definition trunk.c:100
trunk_request_state_t
Used for sanity checks and to simplify freeing.
Definition trunk.h:161
static fr_event_list_t * el
static size_t char ** out
Definition value.h:997