25 RCSID(
"$Id: c73cb6ef67fff33c92915852423b299554a1bbb3 $")
27 #define LOG_PREFIX "sqlcounter"
30 #include <freeradius-devel/server/base.h>
31 #include <freeradius-devel/server/module_rlm.h>
32 #include <freeradius-devel/util/debug.h>
33 #include <freeradius-devel/unlang/function.h>
93 .dflt =
"&control.${.:instance}-Reset-Start", .quote =
T_BARE_WORD },
95 .dflt =
"&control.${.:instance}-Reset-End", .quote =
T_BARE_WORD },
122 unsigned int num = 1;
132 tm->tm_sec = tm->tm_min = 0;
137 len = strlen(
inst->reset);
140 last =
inst->reset[len - 1];
143 num = atoi(
inst->reset);
144 DEBUG3(
"num=%d, last=%c",num,last);
146 if (strcmp(
inst->reset,
"hourly") == 0 || last ==
'h') {
152 }
else if (strcmp(
inst->reset,
"daily") == 0 || last ==
'd') {
159 }
else if (strcmp(
inst->reset,
"weekly") == 0 || last ==
'w') {
164 tm->tm_mday += (7 - tm->tm_wday) +(7*(num-1));
166 }
else if (strcmp(
inst->reset,
"monthly") == 0 || last ==
'm') {
171 }
else if (strcmp(
inst->reset,
"never") == 0) {
190 unsigned int num = 1;
200 tm->tm_sec = tm->tm_min = 0;
205 len = strlen(
inst->reset);
208 last =
inst->reset[len - 1];
211 num = atoi(
inst->reset);
212 DEBUG3(
"num=%d, last=%c", num, last);
214 if (strcmp(
inst->reset,
"hourly") == 0 || last ==
'h') {
218 tm->tm_hour -= num - 1;
220 }
else if (strcmp(
inst->reset,
"daily") == 0 || last ==
'd') {
225 tm->tm_mday -= num - 1;
227 }
else if (strcmp(
inst->reset,
"weekly") == 0 || last ==
'w') {
232 tm->tm_mday -= tm->tm_wday +(7*(num-1));
234 }
else if (strcmp(
inst->reset,
"monthly") == 0 || last ==
'm') {
237 tm->tm_mon -= num - 1;
239 }
else if (strcmp(
inst->reset,
"never") == 0) {
271 uint64_t counter, res;
276 if (!sql_result || (sscanf(sql_result->vb_strvalue,
"%" PRIu64, &counter) != 1)) {
277 RDEBUG2(
"No integer found in result string \"%pV\". May be first session, setting counter to 0",
286 vp->vp_uint64 = counter;
291 if (limit->vp_uint64 <= counter) {
301 REDEBUG2(
"Rejecting user, %s value (%" PRIu64
") is less than counter value (%" PRIu64
")",
302 inst->limit_attr->name, limit->vp_uint64, counter);
307 res = limit->vp_uint64 - counter;
308 RDEBUG2(
"Allowing user, %s value (%" PRIu64
") is greater than counter value (%" PRIu64
")",
309 inst->limit_attr->name, limit->vp_uint64, counter);
325 if (
inst->auto_extend &&
330 RDEBUG2(
"Time remaining (%pV) is greater than time to reset (%" PRIu64
"s). "
331 "Adding %pV to reply value",
364 RDEBUG2(
"List or request context not available for %s, skipping...", env->
reply_attr->name);
400 inst->last_reset =
inst->reset_time;
405 RWDEBUG2(
"Couldn't find %s, doing nothing...",
inst->limit_attr->name);
413 REDEBUG(
"Couldn't create %s",
inst->start_attr->name);
437 fr_value_box_list_init(&rctx->
result);
480 #define ATTR_CHECK(_tmpl, _name) if (tmpl_is_attr_unresolved(inst->_tmpl)) { \
481 if (fr_dict_attr_add(fr_dict_unconst(dict_freeradius), fr_dict_root(dict_freeradius), tmpl_attr_tail_unresolved(inst->_tmpl), -1, FR_TYPE_UINT64, &flags) < 0) { \
482 cf_log_perr(conf, "Failed defining %s attribute", _name); \
485 } else if (tmpl_is_attr(inst->_tmpl)) { \
486 if (tmpl_attr_tail_da(inst->_tmpl)->type != FR_TYPE_UINT64) { \
487 cf_log_err(conf, "%s attribute %s must be uint64", _name, tmpl_attr_tail_da(inst->_tmpl)->name); \
521 UNUSED char const *section_name1,
UNUSED char const *section_name2,
529 query = talloc_asprintf(NULL,
"%%%s(\"%s\")",
inst->sql_name,
cf_pair_value(to_parse));
533 &(fr_sbuff_parse_rules_t){
541 }}, t_rules, 0) < 0) {
581 .name =
"sqlcounter",
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.
#define CALL_ENV_TERMINATOR
#define FR_CALL_ENV_METHOD_OUT(_inst)
Helper macro for populating the size/type fields of a call_env_method_t from the output structure typ...
@ CALL_ENV_FLAG_PARSE_ONLY
The result of parsing will not be evaluated at runtime.
@ CALL_ENV_FLAG_REQUIRED
Associated conf pair or section is required.
#define FR_CALL_ENV_PARSE_ONLY_OFFSET(_name, _cast_type, _flags, _struct, _parse_field)
Specify a call_env_parser_t which writes out the result of the parsing phase to the field specified.
#define CONF_PARSER_TERMINATOR
#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
@ CONF_FLAG_REQUIRED
Error out if no matching CONF_PAIR is found, and no dflt value is set.
@ CONF_FLAG_ATTRIBUTE
Value must resolve to attribute in dict (deprecated, use CONF_FLAG_TMPL).
@ CONF_FLAG_NOT_EMPTY
CONF_PAIR is required to have a non zero length value.
@ CONF_FLAG_XLAT
string will be dynamically expanded.
@ CONF_FLAG_OK_MISSING
OK if it's missing.
Defines a CONF_PAIR to C data type mapping.
Common header for all CONF_* types.
Configuration AVP similar to a fr_pair_t.
A section grouping multiple CONF_PAIR.
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_PAIR.
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
#define cf_log_err(_cf, _fmt,...)
unsigned int internal
Internal attribute, should not be received in protocol packets, should not be encoded.
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Values of the encryption flags.
Specifies a dictionary which must be loaded/loadable for the module to function.
void *_CONST data
Module instance's parsed configuration.
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
CONF_SECTION *_CONST conf
Module's instance configuration.
#define unlang_function_push(_request, _func, _repeat, _signal, _sigmask, _top_frame, _uctx)
Push a generic function onto the unlang stack.
TALLOC_CTX * unlang_interpret_frame_talloc_ctx(request_t *request)
Get a talloc_ctx which is valid only for this frame.
#define RWDEBUG2(fmt,...)
#define REDEBUG2(fmt,...)
@ FR_TYPE_UINT64
64 Bit unsigned integer.
struct tm * gmtime_r(time_t const *l_clock, struct tm *result)
struct tm * localtime_r(time_t const *l_clock, struct tm *result)
void * env_data
Per call environment data.
dl_module_inst_t const * inst
Dynamic loader API handle for the module.
dl_module_inst_t const * inst
Dynamic loader API handle for the module.
Temporary structure to hold arguments for module calls.
Temporary structure to hold arguments for instantiation calls.
Specifies a module method identifier.
module_instance_t * module_rlm_by_name(module_instance_t const *parent, char const *asked_name)
module_t common
Common fields presented by all modules.
int fr_pair_value_strdup(fr_pair_t *vp, char const *src, bool tainted)
Copy data into an "string" data type.
static const conf_parser_t config[]
#define RETURN_MODULE_REJECT
#define RETURN_MODULE_NOOP
#define RETURN_MODULE_UPDATED
rlm_rcode_t
Return codes indicating the result of the module call.
static int instantiate(module_inst_ctx_t const *mctx)
Prototypes and functions for the SQL module.
bool auto_extend
If the remaining allowance is sufficient to reach the next period allow for that in setting the reply...
module_rlm_t rlm_sqlcounter
char const * sql_name
Instance of SQL module to use, usually just 'sql'.
char const * reset
Daily, weekly, monthly, never or user defined.
static fr_dict_t const * dict_freeradius
static int mod_bootstrap(module_inst_ctx_t const *mctx)
xlat_exp_head_t * query_xlat
Tokenized xlat to run query.
tmpl_t * start_attr
&control.${.:instance}-Start
tmpl_t * reply_msg_attr
Attribute to write reply message to.
tmpl_t * counter_attr
Daily-Session-Time.
static unlang_action_t mod_authorize(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Check the value of a counter retrieved from an SQL query with a limit
sqlcounter_call_env_t * env
#define ATTR_CHECK(_tmpl, _name)
char const * query
SQL query to retrieve current session time.
fr_value_box_list_t result
tmpl_t * limit_attr
Max-Daily-Session.
tmpl_t * end_attr
&control.${.:instance}-End
tmpl_t * reply_attr
Attribute to write timeout to.
static int find_next_reset(rlm_sqlcounter_t *inst, fr_time_t now)
static const call_env_method_t sqlcounter_call_env
static int call_env_query_parse(TALLOC_CTX *ctx, void *out, tmpl_rules_t const *t_rules, CONF_ITEM *ci, UNUSED char const *section_name1, UNUSED char const *section_name2, void const *data, UNUSED call_env_parser_t const *rule)
Custom call_env parser to tokenize the SQL query xlat used for counter retrieval.
static const conf_parser_t module_config[]
static unlang_action_t mod_authorize_resume(rlm_rcode_t *p_result, UNUSED int *priority, request_t *request, void *uctx)
Handle the result of calling the SQL query to retrieve the counter value.
fr_dict_autoload_t rlm_sqlcounter_dict[]
static int mod_instantiate(module_inst_ctx_t const *mctx)
static int find_prev_reset(rlm_sqlcounter_t *inst, fr_time_t now)
#define FR_SBUFF_IN(_start, _len_or_end)
Set of parsing rules for *unescape_until functions.
@ MODULE_TYPE_THREAD_SAFE
Module is threadsafe.
#define MODULE_NAME_TERMINATOR
#define pair_update_reply(_attr, _da)
Return or allocate a fr_pair_t in the reply list.
#define pair_update_control(_attr, _da)
Return or allocate a fr_pair_t in the control list.
int tmpl_find_vp(fr_pair_t **out, request_t *request, tmpl_t const *vpt))
Returns the first VP matching a tmpl_t.
static fr_dict_attr_t const * tmpl_attr_tail_da(tmpl_t const *vpt)
Return the last attribute reference da.
int tmpl_find_or_add_vp(fr_pair_t **out, request_t *request, tmpl_t const *vpt)
Returns the first VP matching a tmpl_t, or if no VPs match, creates a new one.
Optional arguments passed to vp_tmpl functions.
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
eap_aka_sim_process_conf_t * inst
#define fr_time()
Allow us to arbitrarily manipulate time.
Stores an attribute, a value and various bits of other data.
#define talloc_get_type_abort_const
static int64_t fr_time_to_sec(fr_time_t when)
Convert an fr_time_t (internal time) to number of sec since the unix epoch (wallclock time)
#define fr_time_wrap(_time)
#define fr_time_lteq(_a, _b)
static int64_t fr_time_delta_to_sec(fr_time_delta_t delta)
static fr_time_t fr_time_from_sec(time_t when)
Convert a time_t (wallclock time) to a fr_time_t (internal time)
#define fr_time_gt(_a, _b)
#define fr_time_sub(_a, _b)
Subtract one time from another.
#define fr_time_neq(_a, _b)
A time delta, a difference in time measured in nanoseconds.
int unlang_xlat_push(TALLOC_CTX *ctx, bool *p_success, fr_value_box_list_t *out, request_t *request, xlat_exp_head_t const *xlat, bool top_frame)
Push a pre-compiled xlat onto the stack for evaluation.
bool xlat_needs_resolving(xlat_exp_head_t const *head)
Check to see if the expansion needs resolving.
fr_slen_t xlat_tokenize(TALLOC_CTX *ctx, xlat_exp_head_t **head, fr_sbuff_t *in, fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules, fr_value_box_safe_for_t literals_safe_for)
Tokenize an xlat expansion.
int xlat_resolve(xlat_exp_head_t *head, xlat_res_rules_t const *xr_rules)
Walk over an xlat tree recursively, resolving any unresolved functions or references.
int fr_value_box_cast(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, fr_value_box_t const *src)
Convert one type of fr_value_box_t to another.
int8_t fr_value_box_cmp(fr_value_box_t const *a, fr_value_box_t const *b)
Compare two values.
#define fr_box_time_delta(_val)
#define fr_box_time(_val)
#define fr_value_box_init(_vb, _type, _enumv, _tainted)
Initialise a fr_value_box_t.
static size_t char ** out