27 RCSID(
"$Id: 14672d7aac77fb61ceeea1da4a20f359fa491199 $")
29 #define LOG_PREFIX inst->name
31 #include <freeradius-devel/server/base.h>
32 #include <freeradius-devel/util/debug.h>
76 if (!handle)
return NULL;
78 handle->
log_ctx = talloc_pool(handle, 2048);
90 rcode = (
inst->driver->sql_socket_init)(handle, &
inst->config,
timeout);
100 if (
inst->config.connect_query) {
104 inst->query(&p_result, NULL, NULL, query_ctx);
126 char const *ptr, *
value;
136 if (!row[2] || row[2][0] ==
'\0') {
137 REDEBUG(
"Attribute field is empty or NULL, skipping the entire row");
144 if (row[4] != NULL && row[4][0] !=
'\0') {
146 op =
gettoken(&ptr, buf,
sizeof(buf),
false);
148 REDEBUG(
"Invalid op \"%s\" for attribute %s", row[4], row[2]);
157 REDEBUG(
"The op field for attribute '%s = %s' is NULL, or non-existent.", row[2], row[3]);
158 REDEBUG(
"You MUST FIX THIS if you want the configuration to behave as you expect");
165 REDEBUG(
"Value field is empty or NULL, skipping the entire row");
177 if (row[3] != NULL &&
178 ((row[3][0] ==
'\'') || (row[3][0] ==
'`') || (row[3][0] ==
'"')) &&
179 (row[3][0] == row[3][strlen(row[3])-1])) {
212 if (row[2][0] ==
'.') {
213 char const *p = row[2];
216 REDEBUG(
"Relative attribute '%s' can only be used immediately after an attribute of type 'group'", row[2]);
221 if (!da)
goto unknown;
223 my_list = &(*relative_vp)->vp_group;
224 my_ctx = *relative_vp;
238 RPEDEBUG(
"Unknown attribute '%s'", row[2]);
270 if (my_list ==
out)
switch (da->type) {
285 if (*relative_vp && (
vp != *relative_vp) && (my_ctx != *relative_vp)) {
313 if ((
inst->driver->uses_trunks && !query_ctx->
tconn) ||
325 (
inst->driver->sql_fetch_row)(p_result, NULL, request, query_ctx);
326 switch (query_ctx->
rcode) {
354 char const *driver =
inst->driver_submodule->name;
357 TALLOC_CTX *log_ctx = talloc_new(NULL);
359 num = (
inst->driver->sql_error)(log_ctx, log, (
NUM_ELEMENTS(log)), query_ctx);
366 for (i = 0; i < num; i++) {
367 if (force_debug)
goto debug;
369 switch (log[i].
type) {
399 if (to_free->
status > 0) {
423 .query_str = query_str,
458 if (request)
REDEBUG(
"Zero length query");
471 for (i = 0; i < (
count + 1); i++) {
474 (
inst->driver->sql_query)(p_result, NULL, request, query_ctx);
476 switch (query_ctx->
rcode) {
496 (
inst->driver->sql_finish_query)(query_ctx, &
inst->config);
511 (
inst->driver->sql_finish_query)(query_ctx, &
inst->config);
521 (
inst->driver->sql_finish_query)(query_ctx, &
inst->config);
551 if (!query_ctx->
treq)
return;
561 query_ctx->
treq = NULL;
581 if (request)
REDEBUG(
"Zero length query");
622 REDEBUG(
"Unable to enqueue SQL query");
657 if (request)
REDEBUG(
"Zero length query");
670 for (i = 0; i < (
count + 1); i++) {
673 (
inst->driver->sql_select_query)(p_result, NULL, request, query_ctx);
675 switch (query_ctx->
rcode) {
694 (
inst->driver->sql_finish_select_query)(query_ctx, &
inst->config);
716 .list_def = map_ctx->
list,
735 row = query_ctx->
row;
736 if (!row[2] || !row[3] || !row[4]) {
737 RPERROR(
"SQL query returned NULL values");
741 RPEDEBUG(
"Error parsing user data from database result");
744 if (!map->
parent) map_list_insert_tail(map_ctx->
out, map);
789 if ((write(fd, query, len) < 0) || (write(fd,
";\n", 2) < 0)) failed =
true;
791 if (failed)
ERROR(
"Failed writing to logfile '%s': %s", filename,
fr_syserror(errno));
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
@ UNLANG_ACTION_PUSHED_CHILD
unlang_t pushed a new child onto the stack, execute it instead of continuing.
@ UNLANG_ACTION_FAIL
Encountered an unexpected error.
@ UNLANG_ACTION_CALCULATE_RESULT
Calculate a new section rlm_rcode_t value.
@ UNLANG_ACTION_YIELD
Temporarily pause execution until an event occurs.
#define L(_str)
Helper for initialising arrays of string literals.
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
fr_dcursor_eval_t void const * uctx
static fr_time_delta_t timeout
fr_dict_attr_t const * fr_dict_attr_by_oid(fr_dict_attr_err_t *err, fr_dict_attr_t const *parent, char const *oid))
Resolve an attribute using an OID string.
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
fr_dict_t const * fr_dict_internal(void)
int exfile_open(exfile_t *ef, char const *filename, mode_t permissions, off_t *offset)
Open a new log file, or maybe an existing one.
int exfile_close(exfile_t *ef, int fd)
Close the log file.
#define unlang_function_push(_request, _func, _repeat, _signal, _sigmask, _top_frame, _uctx)
Push a generic function onto the unlang stack.
#define ROPTIONAL(_l_request, _l_global, _fmt,...)
Use different logging functions depending on whether request is NULL or not.
#define RPEDEBUG(fmt,...)
int map_afrom_fields(TALLOC_CTX *ctx, map_t **out, map_t **parent_p, request_t *request, char const *lhs, char const *op_str, char const *rhs, tmpl_rules_t const *lhs_rules, tmpl_rules_t const *rhs_rules)
Convert a fr_pair_t into a map.
@ L_INFO
Informational message.
@ L_DBG
Only displayed when debugging is enabled.
@ TMPL_ATTR_REF_PREFIX_AUTO
Attribute refs may have a '&' prefix.
@ TMPL_ATTR_REF_PREFIX_YES
Attribute refs must have '&' prefix.
@ FR_TYPE_TLV
Contains nested attributes.
fr_pair_t * fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Dynamically allocate a new attribute and assign a fr_dict_attr_t.
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
fr_pair_t * fr_pair_afrom_da_nested(TALLOC_CTX *ctx, fr_pair_list_t *list, fr_dict_attr_t const *da)
Create a pair (and all intermediate parents), and append it to the list.
int fr_pair_value_from_str(fr_pair_t *vp, char const *value, size_t inlen, fr_sbuff_unescape_rules_t const *uerules, bool tainted)
Convert string value to native attribute value.
fr_pool_state_t const * fr_pool_state(fr_pool_t *pool)
Get the number of connections currently in the pool.
void * fr_pool_connection_reconnect(fr_pool_t *pool, request_t *request, void *conn)
Reconnect a suspected inviable connection.
uint32_t num
Number of connections in the pool.
#define RETURN_MODULE_INVALID
rlm_rcode_t
Return codes indicating the result of the module call.
@ RLM_MODULE_OK
The module is OK, continue.
fr_dict_attr_t const * request_attr_request
Prototypes and functions for the SQL module.
rlm_sql_t const * inst
The rlm_sql instance this connection belongs to.
fr_sql_query_status_t status
Status of the query.
trunk_connection_t * tconn
Trunk connection this query is being run on.
TALLOC_CTX * log_ctx
Talloc pool used to avoid allocing memory when log strings need to be copied.
fr_sql_query_type_t type
Type of query.
void * conn
Database specific connection handle.
trunk_t * trunk
Trunk this query is being run on.
rlm_sql_t const * inst
Module instance for this query.
char const * query_str
Query string to run.
fr_sql_query_t * query_ctx
Query context.
map_list_t * out
List to append entries to.
@ RLM_SQL_QUERY_INVALID
Query syntax error.
@ RLM_SQL_ALT_QUERY
Key constraint violation, use an alternative query.
@ RLM_SQL_RECONNECT
Stale connection, should reconnect.
@ RLM_SQL_ERROR
General connection/server error.
@ RLM_SQL_NO_MORE_ROWS
No more rows available.
rlm_sql_handle_t * handle
Connection handle this query is being run on.
TALLOC_CTX * ctx
To allocate map entries in.
#define RLM_SQL_RCODE_FLAGS_ALT_QUERY
Can distinguish between other errors and those.
rlm_sql_t const * inst
Module instance data.
int rows
How many rows the query returned.
rlm_sql_row_t row
Row data from the last query.
sql_rcode_t rcode
Result code.
fr_value_box_t * query
Query string used for fetching pairs.
trunk_request_t * treq
Trunk request for this query.
@ SQL_QUERY_FAILED
Failed to submit.
@ SQL_QUERY_SUBMITTED
Submitted for execution.
fr_dict_attr_t const * list
Default list for pair evaluation.
Context used when fetching attribute value pairs as a map list.
tmpl_attr_rules_t attr
Rules/data for parsing attribute references.
@ TMPL_ATTR_LIST_ALLOW
Attribute refs are allowed to have a list.
struct tmpl_rules_s tmpl_rules_t
Optional arguments passed to vp_tmpl functions.
size_t sql_rcode_table_len
static int fr_sql_query_free(fr_sql_query_t *to_free)
Automatically run the correct finish function when freeing an SQL query.
unlang_action_t rlm_sql_fetch_row(rlm_rcode_t *p_result, UNUSED int *priority, request_t *request, void *uctx)
Call the driver's sql_fetch_row function.
void rlm_sql_query_log(rlm_sql_t const *inst, char const *filename, char const *query)
unlang_action_t sql_get_map_list(request_t *request, fr_sql_map_ctx_t *map_ctx, rlm_sql_handle_t **handle, trunk_t *trunk)
Submit the query to get any user / group check or reply pairs.
unlang_action_t rlm_sql_select_query(rlm_rcode_t *p_result, UNUSED int *priority, request_t *request, void *uctx)
Call the driver's sql_select_query method, reconnecting if necessary.
fr_table_num_sorted_t const sql_rcode_table[]
unlang_action_t rlm_sql_trunk_query(rlm_rcode_t *p_result, UNUSED int *priority, request_t *request, void *uctx)
Submit an SQL query using a trunk connection.
static void sql_trunk_query_cancel(UNUSED request_t *request, UNUSED fr_signal_t action, void *uctx)
Cancel an SQL query submitted on a trunk.
static unlang_action_t sql_trunk_query_start(UNUSED rlm_rcode_t *p_result, UNUSED int *priority, UNUSED request_t *request, UNUSED void *uctx)
Yield processing after submitting a trunk request.
static unlang_action_t sql_get_map_list_resume(rlm_rcode_t *p_result, UNUSED int *priority, request_t *request, void *uctx)
Process the results of an SQL query to produce a map list.
void rlm_sql_print_error(rlm_sql_t const *inst, request_t *request, fr_sql_query_t *query_ctx, bool force_debug)
Retrieve any errors from the SQL driver.
void * sql_mod_conn_create(TALLOC_CTX *ctx, void *instance, fr_time_delta_t timeout)
fr_sql_query_t * fr_sql_query_alloc(TALLOC_CTX *ctx, rlm_sql_t const *inst, request_t *request, rlm_sql_handle_t *handle, trunk_t *trunk, char const *query_str, fr_sql_query_type_t type)
Allocate an sql query structure.
size_t sql_rcode_description_table_len
fr_table_num_sorted_t const sql_rcode_description_table[]
unlang_action_t rlm_sql_query(rlm_rcode_t *p_result, UNUSED int *priority, request_t *request, void *uctx)
Call the driver's sql_query method, reconnecting if necessary.
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
eap_aka_sim_process_conf_t * inst
fr_aka_sim_id_type_t type
trunk_io_funcs_t trunk_io_funcs
Trunk callback functions for this driver.
unlang_function_t sql_query_resume
Callback run after an SQL trunk query is run.
sql_rcode_t(* sql_finish_query)(fr_sql_query_t *query_ctx, rlm_sql_config_t const *config)
sql_rcode_t(* sql_finish_select_query)(fr_sql_query_t *query_ctx, rlm_sql_config_t const *config)
unlang_function_t sql_select_query_resume
Callback run after an SQL select trunk query is run.
rlm_sql_driver_t const * driver
Driver's exported interface.
fr_dict_attr_t const * list_def
Default list to use with unqualified attribute reference.
fr_dict_t const * dict_def
Default dictionary to use with unqualified attribute references.
tmpl_attr_prefix_t prefix
Whether the attribute reference requires a prefix.
Stores an attribute, a value and various bits of other data.
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
An element in a lexicographically sorted array of name to num mappings.
A time delta, a difference in time measured in nanoseconds.
const bool fr_assignment_op[T_TOKEN_LAST]
fr_token_t gettoken(char const **ptr, char *buf, int buflen, bool unescape)
fr_table_num_ordered_t const fr_tokens_table[]
const bool fr_comparison_op[T_TOKEN_LAST]
trunk_enqueue_t trunk_request_enqueue(trunk_request_t **treq_out, trunk_t *trunk, request_t *request, void *preq, void *rctx)
Enqueue a request that needs data written to the trunk.
trunk_enqueue_t trunk_request_requeue(trunk_request_t *treq)
Re-enqueue a request on the same connection.
void trunk_request_signal_cancel(trunk_request_t *treq)
Cancel a trunk request.
void trunk_request_signal_complete(trunk_request_t *treq)
Signal that a trunk request is complete.
Main trunk management handle.
@ TRUNK_ENQUEUE_OK
Operation was successful.
@ TRUNK_ENQUEUE_IN_BACKLOG
Request should be enqueued in backlog.
trunk_request_cancel_mux_t request_cancel_mux
!< Read one or more requests from a connection.
@ TRUNK_REQUEST_STATE_REAPABLE
Request has been written, needs to persist, but we are not currently waiting for any response.
@ TRUNK_REQUEST_STATE_INIT
Initial state.
#define FR_TYPE_STRUCTURAL
#define FR_MAX_STRING_LEN
static size_t char ** out