25 RCSID(
"$Id: c0f1a6590cd92cd855d5d20af8818d2377042da0 $")
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/util/dict.h>
34 #include <freeradius-devel/unlang/function.h>
94 .dflt =
"&control.${.:instance}-Reset-Start", .quote =
T_BARE_WORD },
96 .dflt =
"&control.${.:instance}-Reset-End", .quote =
T_BARE_WORD },
123 unsigned int num = 1;
133 tm->tm_sec = tm->tm_min = 0;
138 len = strlen(
inst->reset);
141 last =
inst->reset[len - 1];
144 num = atoi(
inst->reset);
145 DEBUG3(
"num=%d, last=%c",num,last);
147 if (strcmp(
inst->reset,
"hourly") == 0 || last ==
'h') {
153 }
else if (strcmp(
inst->reset,
"daily") == 0 || last ==
'd') {
160 }
else if (strcmp(
inst->reset,
"weekly") == 0 || last ==
'w') {
165 tm->tm_mday += (7 - tm->tm_wday) +(7*(num-1));
167 }
else if (strcmp(
inst->reset,
"monthly") == 0 || last ==
'm') {
172 }
else if (strcmp(
inst->reset,
"never") == 0) {
191 unsigned int num = 1;
201 tm->tm_sec = tm->tm_min = 0;
206 len = strlen(
inst->reset);
209 last =
inst->reset[len - 1];
212 num = atoi(
inst->reset);
213 DEBUG3(
"num=%d, last=%c", num, last);
215 if (strcmp(
inst->reset,
"hourly") == 0 || last ==
'h') {
219 tm->tm_hour -= num - 1;
221 }
else if (strcmp(
inst->reset,
"daily") == 0 || last ==
'd') {
226 tm->tm_mday -= num - 1;
228 }
else if (strcmp(
inst->reset,
"weekly") == 0 || last ==
'w') {
233 tm->tm_mday -= tm->tm_wday +(7*(num-1));
235 }
else if (strcmp(
inst->reset,
"monthly") == 0 || last ==
'm') {
238 tm->tm_mon -= num - 1;
240 }
else if (strcmp(
inst->reset,
"never") == 0) {
272 uint64_t counter, res;
277 if (!sql_result || (sscanf(sql_result->vb_strvalue,
"%" PRIu64, &counter) != 1)) {
278 RDEBUG2(
"No integer found in result string \"%pV\". May be first session, setting counter to 0",
287 vp->vp_uint64 = counter;
292 if (limit->vp_uint64 <= counter) {
302 REDEBUG2(
"Rejecting user, %s value (%" PRIu64
") is less than counter value (%" PRIu64
")",
303 inst->limit_attr->name, limit->vp_uint64, counter);
308 res = limit->vp_uint64 - counter;
309 RDEBUG2(
"Allowing user, %s value (%" PRIu64
") is greater than counter value (%" PRIu64
")",
310 inst->limit_attr->name, limit->vp_uint64, counter);
326 if (
inst->auto_extend &&
331 RDEBUG2(
"Time remaining (%pV) is greater than time to reset (%" PRIu64
"s). "
332 "Adding %pV to reply value",
365 RDEBUG2(
"List or request context not available for %s, skipping...", env->
reply_attr->name);
401 inst->last_reset =
inst->reset_time;
406 RWDEBUG2(
"Couldn't find %s, doing nothing...",
inst->limit_attr->name);
414 REDEBUG(
"Couldn't create %s",
inst->start_attr->name);
438 fr_value_box_list_init(&rctx->
result);
454 query = talloc_asprintf(NULL,
"%%%s(\"%s\")",
inst->sql_name,
cf_pair_value(to_parse));
458 &(fr_sbuff_parse_rules_t){
466 }}, t_rules, 0) < 0) {
587 .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.
module_instance_t const * mi
Module instance that the callenv is registered to.
#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,...)
#define cf_log_perr(_cf, _fmt,...)
fr_dcursor_eval_t void const * uctx
int fr_dict_attr_add_name_only(fr_dict_t *dict, fr_dict_attr_t const *parent, char const *name, fr_type_t type, fr_dict_attr_flags_t const *flags))
Add an attribute to the dictionary.
fr_dict_attr_t const * fr_dict_attr_by_name(fr_dict_attr_err_t *err, fr_dict_attr_t const *parent, char const *attr))
Locate a fr_dict_attr_t by its name.
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.
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
fr_dict_t * fr_dict_unconst(fr_dict_t const *dict)
Coerce to non-const.
Values of the encryption flags.
Specifies a dictionary which must be loaded/loadable for the module to function.
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
#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.
module_instance_t const * mi
Instance of the module being instantiated.
module_instance_t * mi
Instance of the module being instantiated.
Temporary structure to hold arguments for module calls.
Temporary structure to hold arguments for instantiation calls.
module_instance_t * module_rlm_static_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.
static int attr_check(CONF_SECTION *conf, tmpl_t *tmpl, char const *name, fr_dict_attr_flags_t *flags)
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.
static int call_env_query_parse(TALLOC_CTX *ctx, void *out, tmpl_rules_t const *t_rules, CONF_ITEM *ci, call_env_ctx_t const *cec, UNUSED call_env_parser_t const *rule)
Custom call_env parser to tokenize the SQL query xlat used for counter retrieval.
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
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 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.
#define SECTION_NAME(_name1, _name2)
Define a section name consisting of a verb and a noun.
CONF_SECTION * conf
Module's instance configuration.
void * data
Module's instance data.
#define MODULE_BINDING_TERMINATOR
Terminate a module binding list.
Named methods exported by a module.
#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.
#define tmpl_is_attr_unresolved(vpt)
static fr_dict_attr_t const * tmpl_attr_tail_da(tmpl_t const *vpt)
Return the last attribute reference da.
#define tmpl_is_attr(vpt)
static char const * tmpl_attr_tail_unresolved(tmpl_t const *vpt)
Return the last attribute reference unresolved 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
fr_aka_sim_id_type_t type
#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