The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
rlm_sqlcounter.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: 42a588640a97eda44e6322a6c5fec42d3b4aed5a $
19 * @file rlm_sqlcounter.c
20 * @brief Tracks data usage and other counters using SQL.
21 *
22 * @copyright 2001,2006 The FreeRADIUS server project
23 * @copyright 2001 Alan DeKok (aland@freeradius.org)
24 */
25RCSID("$Id: 42a588640a97eda44e6322a6c5fec42d3b4aed5a $")
26
27#define LOG_PREFIX "sqlcounter"
28
29#include <rlm_sql.h>
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>
35#include <freeradius-devel/unlang/action.h>
36#include <freeradius-devel/unlang/module.h>
37#include <ctype.h>
38
39/*
40 * Note: When your counter spans more than 1 period (ie 3 months
41 * or 2 weeks), this module probably does NOT do what you want! It
42 * calculates the range of dates to count across by first calculating
43 * the End of the Current period and then subtracting the number of
44 * periods you specify from that to determine the beginning of the
45 * range.
46 *
47 * For example, if you specify a 3 month counter and today is June 15th,
48 * the end of the current period is June 30. Subtracting 3 months from
49 * that gives April 1st. So, the counter will sum radacct entries from
50 * April 1st to June 30. Then, next month, it will sum entries from
51 * May 1st to July 31st.
52 *
53 * To fix this behavior, we need to add some way of storing the Next
54 * Reset Time.
55 */
56
57/*
58 * Define a structure for our module configuration.
59 *
60 * These variables do not need to be in a structure, but it's
61 * a lot cleaner to do so, and a pointer to the structure can
62 * be used as the instance handle.
63 */
64typedef struct {
65 tmpl_t *start_attr; //!< control.${.:instance}-Start
66 tmpl_t *end_attr; //!< control.${.:instance}-End
67
68 tmpl_t *counter_attr; //!< Daily-Session-Time.
69 tmpl_t *limit_attr; //!< Max-Daily-Session.
70 tmpl_t *key; //!< User-Name
71
72 char const *sql_name; //!< Instance of SQL module to use, usually just 'sql'.
73 char const *query; //!< SQL query to retrieve current session time.
74 char const *reset; //!< Daily, weekly, monthly, never or user defined.
75 bool auto_extend; //!< If the remaining allowance is sufficient to reach the next
76 ///< period allow for that in setting the reply attribute.
77 bool utc; //!< Use UTC time.
78
82
83static const conf_parser_t module_config[] = {
84 { FR_CONF_OFFSET_FLAGS("sql_module_instance", CONF_FLAG_REQUIRED, rlm_sqlcounter_t, sql_name) },
85
86
89 { FR_CONF_OFFSET_FLAGS("auto_extend", CONF_FLAG_OK_MISSING, rlm_sqlcounter_t, auto_extend) },
91
92 { FR_CONF_OFFSET_FLAGS("key", CONF_FLAG_NOT_EMPTY, rlm_sqlcounter_t, key), .dflt = "%{Stripped-User-Name || User-Name}", .quote = T_DOUBLE_QUOTED_STRING },
93
94 { FR_CONF_OFFSET_FLAGS("reset_period_start_name", CONF_FLAG_ATTRIBUTE, rlm_sqlcounter_t, start_attr),
95 .dflt = "control.${.:instance}-Reset-Start", .quote = T_BARE_WORD },
96 { FR_CONF_OFFSET_FLAGS("reset_period_end_name", CONF_FLAG_ATTRIBUTE, rlm_sqlcounter_t, end_attr),
97 .dflt = "control.${.:instance}-Reset-End", .quote = T_BARE_WORD },
98
99 /* Attribute to write counter value to*/
102
104};
105
106typedef struct {
107 xlat_exp_head_t *query_xlat; //!< Tokenized xlat to run query.
108 tmpl_t *reply_attr; //!< Attribute to write timeout to.
109 tmpl_t *reply_msg_attr; //!< Attribute to write reply message to.
111
113
116 { .out = &dict_freeradius, .proto = "freeradius" },
117 { NULL }
118};
119
121{
122 int ret = 0;
123 size_t len;
124 unsigned int num = 1;
125 char last = '\0';
126 struct tm *tm, s_tm;
127 time_t time_s = fr_time_to_sec(now);
128
129 if (inst->utc) {
130 tm = gmtime_r(&time_s, &s_tm);
131 } else {
132 tm = localtime_r(&time_s, &s_tm);
133 }
134 tm->tm_sec = tm->tm_min = 0;
135
136 fr_assert(inst->reset != NULL);
137
138 if (isdigit((uint8_t) inst->reset[0])){
139 len = strlen(inst->reset);
140 if (len == 0)
141 return -1;
142 last = inst->reset[len - 1];
143 if (!isalpha((uint8_t) last))
144 last = 'd';
145 num = atoi(inst->reset);
146 DEBUG3("num=%d, last=%c",num,last);
147 }
148 if (strcmp(inst->reset, "hourly") == 0 || last == 'h') {
149 /*
150 * Round up to the next nearest hour.
151 */
152 tm->tm_hour += num;
153 inst->reset_time = fr_time_from_sec(inst->utc ? timegm(tm) : mktime(tm));
154 } else if (strcmp(inst->reset, "daily") == 0 || last == 'd') {
155 /*
156 * Round up to the next nearest day.
157 */
158 tm->tm_hour = 0;
159 tm->tm_mday += num;
160 inst->reset_time = fr_time_from_sec(inst->utc ? timegm(tm) : mktime(tm));
161 } else if (strcmp(inst->reset, "weekly") == 0 || last == 'w') {
162 /*
163 * Round up to the next nearest week.
164 */
165 tm->tm_hour = 0;
166 tm->tm_mday += (7 - tm->tm_wday) +(7*(num-1));
167 inst->reset_time = fr_time_from_sec(inst->utc ? timegm(tm) : mktime(tm));
168 } else if (strcmp(inst->reset, "monthly") == 0 || last == 'm') {
169 tm->tm_hour = 0;
170 tm->tm_mday = 1;
171 tm->tm_mon += num;
172 inst->reset_time = fr_time_from_sec(inst->utc ? timegm(tm) : mktime(tm));
173 } else if (strcmp(inst->reset, "never") == 0) {
174 inst->reset_time = fr_time_wrap(0);
175 } else {
176 return -1;
177 }
178
179 DEBUG2("Current Time: %pV, Next reset %pV", fr_box_time(now), fr_box_time(inst->reset_time));
180
181 return ret;
182}
183
184
185/* I don't believe that this routine handles Daylight Saving Time adjustments
186 properly. Any suggestions?
187*/
189{
190 int ret = 0;
191 size_t len;
192 unsigned int num = 1;
193 char last = '\0';
194 struct tm *tm, s_tm;
195 time_t time_s = fr_time_to_sec(now);
196
197 if (inst->utc) {
198 tm = gmtime_r(&time_s, &s_tm);
199 } else {
200 tm = localtime_r(&time_s, &s_tm);
201 }
202 tm->tm_sec = tm->tm_min = 0;
203
204 fr_assert(inst->reset != NULL);
205
206 if (isdigit((uint8_t) inst->reset[0])){
207 len = strlen(inst->reset);
208 if (len == 0)
209 return -1;
210 last = inst->reset[len - 1];
211 if (!isalpha((uint8_t) last))
212 last = 'd';
213 num = atoi(inst->reset);
214 DEBUG3("num=%d, last=%c", num, last);
215 }
216 if (strcmp(inst->reset, "hourly") == 0 || last == 'h') {
217 /*
218 * Round down to the prev nearest hour.
219 */
220 tm->tm_hour -= num - 1;
221 inst->last_reset = fr_time_from_sec(inst->utc ? timegm(tm) : mktime(tm));
222 } else if (strcmp(inst->reset, "daily") == 0 || last == 'd') {
223 /*
224 * Round down to the prev nearest day.
225 */
226 tm->tm_hour = 0;
227 tm->tm_mday -= num - 1;
228 inst->last_reset = fr_time_from_sec(inst->utc ? timegm(tm) : mktime(tm));
229 } else if (strcmp(inst->reset, "weekly") == 0 || last == 'w') {
230 /*
231 * Round down to the prev nearest week.
232 */
233 tm->tm_hour = 0;
234 tm->tm_mday -= tm->tm_wday +(7*(num-1));
235 inst->last_reset = fr_time_from_sec(inst->utc ? timegm(tm) : mktime(tm));
236 } else if (strcmp(inst->reset, "monthly") == 0 || last == 'm') {
237 tm->tm_hour = 0;
238 tm->tm_mday = 1;
239 tm->tm_mon -= num - 1;
240 inst->last_reset = fr_time_from_sec(inst->utc ? timegm(tm) : mktime(tm));
241 } else if (strcmp(inst->reset, "never") == 0) {
242 inst->reset_time = fr_time_wrap(0);
243 } else {
244 return -1;
245 }
246
247 DEBUG2("Current Time: %pV, Prev reset %pV", fr_box_time(now), fr_box_time(inst->last_reset));
248
249 return ret;
250}
251
259
260/** Handle the result of calling the SQL query to retrieve the `counter` value.
261 *
262 * Create / update the `counter` attribute in the control list
263 * If `counter` > `limit`, optionally populate a reply message and return RLM_MODULE_REJECT.
264 * Otherwise, optionally populate a reply attribute with the value of `limit` - `counter` and return RLM_MODULE_UPDATED.
265 * If no reply attribute is set, return RLM_MODULE_OK.
266 */
268{
269 sqlcounter_rctx_t *rctx = talloc_get_type_abort(mctx->rctx, sqlcounter_rctx_t);
270 rlm_sqlcounter_t *inst = rctx->inst;
271 sqlcounter_call_env_t *env = rctx->env;
272 fr_value_box_t *sql_result = fr_value_box_list_pop_head(&rctx->result);
273 uint64_t counter, res;
274 fr_pair_t *vp, *limit = rctx->limit;
275 int ret;
276 char msg[128];
277
278 if (!sql_result || (sscanf(sql_result->vb_strvalue, "%" PRIu64, &counter) != 1)) {
279 RDEBUG2("No integer found in result string \"%pV\". May be first session, setting counter to 0",
280 sql_result);
281 counter = 0;
282 }
283
284 /*
285 * Add the counter to the control list
286 */
287 MEM(pair_update_control(&vp, tmpl_attr_tail_da(inst->counter_attr)) >= 0);
288 vp->vp_uint64 = counter;
289
290 /*
291 * Check if check item > counter
292 */
293 if (limit->vp_uint64 <= counter) {
294 if (env->reply_msg_attr) {
295 /* User is denied access, send back a reply message */
296 snprintf(msg, sizeof(msg), "Your maximum %s usage has been reached", inst->reset);
297
299 fr_pair_value_strdup(vp, msg, false);
300 }
301
302 REDEBUG2("Maximum %s usage reached", inst->reset);
303 REDEBUG2("Rejecting user, %s value (%" PRIu64 ") is less than counter value (%" PRIu64 ")",
304 inst->limit_attr->name, limit->vp_uint64, counter);
305
307 }
308
309 res = limit->vp_uint64 - counter;
310 RDEBUG2("Allowing user, %s value (%" PRIu64 ") is greater than counter value (%" PRIu64 ")",
311 inst->limit_attr->name, limit->vp_uint64, counter);
312
313 /*
314 * We are assuming that simultaneous-use=1. But
315 * even if that does not happen then our user
316 * could login at max for 2*max-usage-time Is
317 * that acceptable?
318 */
319 if (env->reply_attr) {
321
322 /*
323 * If we are near a reset then add the next
324 * limit, so that the user will not need to login
325 * again. Do this only if auto_extend is set.
326 */
327 if (inst->auto_extend &&
328 fr_time_gt(inst->reset_time, fr_time_wrap(0)) &&
329 ((int64_t)res >= fr_time_delta_to_sec(fr_time_sub(inst->reset_time, request->packet->timestamp)))) {
330 fr_time_delta_t to_reset = fr_time_sub(inst->reset_time, request->packet->timestamp);
331
332 RDEBUG2("Time remaining (%pV) is greater than time to reset (%" PRIu64 "s). "
333 "Adding %pV to reply value",
334 fr_box_time_delta(to_reset), res, fr_box_time_delta(to_reset));
335 res = fr_time_delta_to_sec(to_reset) + limit->vp_uint64;
336 }
337
338 fr_value_box_init(&vb, FR_TYPE_UINT64, NULL, false);
339 vb.vb_uint64 = res;
340
341 /*
342 * Limit the reply attribute to the minimum of the existing value, or this new one.
343 */
344 ret = tmpl_find_or_add_vp(&vp, request, env->reply_attr);
345 switch (ret) {
346 case 1: /* new */
347 break;
348
349 case 0: /* found */
350 {
351 fr_value_box_t existing;
352 fr_value_box_cast(NULL, &existing, FR_TYPE_UINT64, NULL, &vp->data);
353 if (fr_value_box_cmp(&vb, &existing) == 1) {
354 RDEBUG2("Leaving existing %s value of %pV" , env->reply_attr->name,
355 &vp->data);
357 }
358 }
359 break;
360
361 case -1: /* alloc failed */
362 REDEBUG("Error allocating attribute %s", env->reply_attr->name);
364
365 default: /* request or list unavailable */
366 RDEBUG2("List or request context not available for %s, skipping...", env->reply_attr->name);
368 }
369
370 fr_value_box_cast(vp, &vp->data, vp->data.type, NULL, &vb);
371
372 RDEBUG2("%pP", vp);
373
375 }
376
378}
379
380/** Check the value of a `counter` retrieved from an SQL query with a `limit`
381 *
382 * Module specific attributes containing the start / end times are created / updated,
383 * the query is tokenized as an xlat call to the relevant SQL module and then
384 * pushed on the stack for evaluation.
385 */
386static unlang_action_t CC_HINT(nonnull) mod_authorize(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
387{
388 rlm_sqlcounter_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_sqlcounter_t);
389 sqlcounter_call_env_t *env = talloc_get_type_abort(mctx->env_data, sqlcounter_call_env_t);
390 fr_pair_t *limit, *vp;
391 sqlcounter_rctx_t *rctx;
392
393 /*
394 * Before doing anything else, see if we have to reset
395 * the counters.
396 */
397 if (fr_time_neq(inst->reset_time, fr_time_wrap(0)) &&
398 (fr_time_lteq(inst->reset_time, request->packet->timestamp))) {
399 /*
400 * Re-set the next time and prev_time for this counters range
401 */
402 inst->last_reset = inst->reset_time;
403 find_next_reset(inst, request->packet->timestamp);
404 }
405
406 if (tmpl_find_vp(&limit, request, inst->limit_attr) < 0) {
407 RWDEBUG2("Couldn't find %s, doing nothing...", inst->limit_attr->name);
409 }
410
411 /*
412 * Populate start and end attributes for use in query expansion
413 */
414 if (tmpl_find_or_add_vp(&vp, request, inst->start_attr) < 0) {
415 REDEBUG("Couldn't create %s", inst->start_attr->name);
417 }
418 vp->vp_uint64 = fr_time_to_sec(inst->last_reset);
419
420 if (tmpl_find_or_add_vp(&vp, request, inst->end_attr) < 0) {
421 REDEBUG2("Couldn't create %s", inst->end_attr->name);
423 }
424 vp->vp_uint64 = fr_time_to_sec(inst->reset_time);
425
427 *rctx = (sqlcounter_rctx_t) {
428 .inst = inst,
429 .env = env,
430 .limit = limit
431 };
432
433 if (unlang_module_yield(request, mod_authorize_resume, NULL, 0, rctx) == UNLANG_ACTION_FAIL) {
434 error:
435 talloc_free(rctx);
437 }
438
439 fr_value_box_list_init(&rctx->result);
440 if (unlang_xlat_push(rctx, &rctx->last_result, &rctx->result, request, env->query_xlat, UNLANG_SUB_FRAME) < 0) goto error;
441
443}
444
445/** Custom call_env parser to tokenize the SQL query xlat used for counter retrieval
446 */
447static int call_env_query_parse(TALLOC_CTX *ctx, void *out, tmpl_rules_t const *t_rules, CONF_ITEM *ci,
448 call_env_ctx_t const *cec, UNUSED call_env_parser_t const *rule)
449{
451 CONF_PAIR const *to_parse = cf_item_to_pair(ci);
452 char *query;
453 xlat_exp_head_t *ex;
454
455 query = talloc_asprintf(NULL, "%%%s(\"%s\")", inst->sql_name, cf_pair_value(to_parse));
456
457 if (xlat_tokenize(ctx, &ex,
458 &FR_SBUFF_IN(query, talloc_array_length(query)),
459 &(fr_sbuff_parse_rules_t){
460 .escapes = &(fr_sbuff_unescape_rules_t) {
461 .name = "xlat",
462 .chr = '\\',
463 .subs = {
464 ['%'] = '%',
465 ['\\'] = '\\',
466 },
467 }}, t_rules) < 0) {
468 talloc_free(query);
469 return -1;
470 }
471 talloc_free(query);
472
473 if (xlat_needs_resolving(ex) &&
474 (xlat_resolve(ex, &(xlat_res_rules_t){ .allow_unresolved = false }) < 0)) {
475 talloc_free(ex);
476 return -1;
477 }
478
479 *(void**)out = ex;
480 return 0;
481}
482
493
494
495/*
496 * Do any per-module initialization that is separate to each
497 * configured instance of the module. e.g. set up connections
498 * to external databases, read configuration files, set up
499 * dictionary entries, etc.
500 *
501 * If configuration information is given in the config section
502 * that must be referenced in later calls, store a handle to it
503 * in *instance otherwise put a null pointer there.
504 */
505static int mod_instantiate(module_inst_ctx_t const *mctx)
506{
507 rlm_sqlcounter_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_sqlcounter_t);
508 CONF_SECTION *conf = mctx->mi->conf;
510 fr_assert(inst->query && *inst->query);
511
512 sql_inst = module_rlm_static_by_name(NULL, inst->sql_name);
513 if (!sql_inst) {
514 cf_log_err(conf, "Module \"%s\" not found", inst->sql_name);
515 return -1;
516 }
517
518 if (!talloc_get_type(sql_inst->data, rlm_sql_t)) {
519 cf_log_err(conf, "\"%s\" is not an instance of rlm_sql", inst->sql_name);
520 return -1;
521 }
522
523 inst->reset_time = fr_time_wrap(0);
524
525 if (find_next_reset(inst, fr_time()) == -1) {
526 cf_log_err(conf, "Invalid reset '%s'", inst->reset);
527 return -1;
528 }
529
530 /*
531 * Discover the beginning of the current time period.
532 */
533 inst->last_reset = fr_time_wrap(0);
534
535 if (find_prev_reset(inst, fr_time()) < 0) {
536 cf_log_err(conf, "Invalid reset '%s'", inst->reset);
537 return -1;
538 }
539
540 return 0;
541}
542
543static inline int attr_check(CONF_SECTION *conf, tmpl_t *tmpl, char const *name, fr_dict_attr_flags_t *flags)
544{
547 tmpl_attr_tail_unresolved(tmpl), FR_TYPE_UINT64, flags) < 0) {
548 cf_log_perr(conf, "Failed defining %s attribute", name);
549 return -1;
550 }
551 } else if (tmpl_is_attr(tmpl)) {
552 if (tmpl_attr_tail_da(tmpl)->type != FR_TYPE_UINT64) {
553 cf_log_err(conf, "%s attribute %s must be uint64", name, tmpl_attr_tail_da(tmpl)->name);
554 return -1;
555 }
556 }
557
558 return 0;
559}
560
561static int mod_bootstrap(module_inst_ctx_t const *mctx)
562{
563 rlm_sqlcounter_t const *inst = talloc_get_type_abort(mctx->mi->data, rlm_sqlcounter_t);
564 CONF_SECTION *conf = mctx->mi->conf;
565 fr_dict_attr_flags_t flags = { .internal = 1, .length = 8, .name_only = 1 };
566
567 if (unlikely(attr_check(conf, inst->start_attr, "reset_period_start", &flags) < 0)) return -1;
568 if (unlikely(attr_check(conf, inst->end_attr, "reset_period_end", &flags) < 0)) return -1;
569 if (unlikely(attr_check(conf, inst->counter_attr, "counter", &flags) < 0)) return -1;
570 if (unlikely(attr_check(conf, inst->limit_attr, "check", &flags) < 0)) return -1;
571
572 return 0;
573}
574
575/*
576 * The module name should be the only globally exported symbol.
577 * That is, everything else should be 'static'.
578 *
579 * If the module needs to temporarily modify it's instantiation
580 * data, the type should be changed to MODULE_TYPE_THREAD_UNSAFE.
581 * The server will then take care of ensuring that the module
582 * is single-threaded.
583 */
586 .common = {
587 .magic = MODULE_MAGIC_INIT,
588 .name = "sqlcounter",
589 .inst_size = sizeof(rlm_sqlcounter_t),
591 .bootstrap = mod_bootstrap,
593 },
594 .method_group = {
595 .bindings = (module_method_binding_t[]){
596 { .section = SECTION_NAME(CF_IDENT_ANY, CF_IDENT_ANY), .method = mod_authorize, .method_env = &sqlcounter_call_env },
598 }
599 }
600};
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition action.h:35
@ UNLANG_ACTION_PUSHED_CHILD
unlang_t pushed a new child onto the stack, execute it instead of continuing.
Definition action.h:39
@ UNLANG_ACTION_FAIL
Encountered an unexpected error.
Definition action.h:36
log_entry msg
Definition acutest.h:794
#define RCSID(id)
Definition build.h:485
#define unlikely(_x)
Definition build.h:383
#define UNUSED
Definition build.h:317
#define CALL_ENV_TERMINATOR
Definition call_env.h:236
#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...
Definition call_env.h:240
call_env_parser_t const * env
Parsing rules for call method env.
Definition call_env.h:247
@ CALL_ENV_FLAG_PARSE_ONLY
The result of parsing will not be evaluated at runtime.
Definition call_env.h:85
@ CALL_ENV_FLAG_REQUIRED
Associated conf pair or section is required.
Definition call_env.h:75
module_instance_t const * mi
Module instance that the callenv is registered to.
Definition call_env.h:229
#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.
Definition call_env.h:389
Per method call config.
Definition call_env.h:180
#define CONF_PARSER_TERMINATOR
Definition cf_parse.h:658
fr_token_t quote
Quoting around the default value. Only used for templates.
Definition cf_parse.h:650
#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_ATTRIBUTE
Value must resolve to attribute in dict (deprecated, use CONF_FLAG_TMPL).
Definition cf_parse.h:436
@ CONF_FLAG_NOT_EMPTY
CONF_PAIR is required to have a non zero length value.
Definition cf_parse.h:449
@ CONF_FLAG_XLAT
string will be dynamically expanded.
Definition cf_parse.h:445
@ CONF_FLAG_OK_MISSING
OK if it's missing.
Definition cf_parse.h:456
Defines a CONF_PAIR to C data type mapping.
Definition cf_parse.h:595
Common header for all CONF_* types.
Definition cf_priv.h:49
Configuration AVP similar to a fr_pair_t.
Definition cf_priv.h:70
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:101
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_PAIR.
Definition cf_util.c:663
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
Definition cf_util.c:1593
#define cf_log_err(_cf, _fmt,...)
Definition cf_util.h:289
#define cf_log_perr(_cf, _fmt,...)
Definition cf_util.h:296
#define CF_IDENT_ANY
Definition cf_util.h:78
#define MEM(x)
Definition debug.h:36
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.
Definition dict_util.c:1741
fr_dict_t * fr_dict_unconst(fr_dict_t const *dict)
Coerce to non-const.
Definition dict_util.c:4629
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.
Definition dict_util.c:3266
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2403
unsigned int internal
Internal attribute, should not be received in protocol packets, should not be encoded.
Definition dict.h:89
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:287
Values of the encryption flags.
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:286
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition dl_module.h:63
TALLOC_CTX * unlang_interpret_frame_talloc_ctx(request_t *request)
Get a talloc_ctx which is valid only for this frame.
Definition interpret.c:1661
#define UNLANG_SUB_FRAME
Definition interpret.h:37
#define DEBUG3(_fmt,...)
Definition log.h:266
#define RWDEBUG2(fmt,...)
Definition log.h:362
#define REDEBUG2(fmt,...)
Definition log.h:372
talloc_free(reap)
@ FR_TYPE_UINT64
64 Bit unsigned integer.
@ FR_TYPE_VOID
User data.
unsigned char uint8_t
struct tm * gmtime_r(time_t const *l_clock, struct tm *result)
Definition missing.c:201
struct tm * localtime_r(time_t const *l_clock, struct tm *result)
Definition missing.c:163
void * env_data
Per call environment data.
Definition module_ctx.h:44
module_instance_t const * mi
Instance of the module being instantiated.
Definition module_ctx.h:42
void * rctx
Resume ctx that a module previously set.
Definition module_ctx.h:45
module_instance_t * mi
Instance of the module being instantiated.
Definition module_ctx.h:51
Temporary structure to hold arguments for module calls.
Definition module_ctx.h:41
Temporary structure to hold arguments for instantiation calls.
Definition module_ctx.h:50
module_instance_t * module_rlm_static_by_name(module_instance_t const *parent, char const *asked_name)
Definition module_rlm.c:814
module_t common
Common fields presented by all modules.
Definition module_rlm.h:39
int fr_pair_value_strdup(fr_pair_t *vp, char const *src, bool tainted)
Copy data into an "string" data type.
Definition pair.c:2636
static const conf_parser_t config[]
Definition base.c:186
#define fr_assert(_expr)
Definition rad_assert.h:38
#define REDEBUG(fmt,...)
Definition radclient.h:52
#define RDEBUG2(fmt,...)
Definition radclient.h:54
#define DEBUG2(fmt,...)
Definition radclient.h:43
static rs_t * conf
Definition radsniff.c:53
#define RETURN_UNLANG_UPDATED
Definition rcode.h:64
#define RETURN_UNLANG_FAIL
Definition rcode.h:57
#define RETURN_UNLANG_REJECT
Definition rcode.h:56
#define RETURN_UNLANG_OK
Definition rcode.h:58
#define RETURN_UNLANG_NOOP
Definition rcode.h:63
static char const * name
static int instantiate(module_inst_ctx_t const *mctx)
Definition rlm_rest.c:1297
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'.
unlang_result_t last_result
char const * reset
Daily, weekly, monthly, never or user defined.
static unlang_action_t mod_authorize_resume(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
Handle the result of calling the SQL query to retrieve the counter value.
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 unlang_action_t mod_authorize(unlang_result_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
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.
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
rlm_sqlcounter_t * inst
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
bool utc
Use UTC time.
static const conf_parser_t module_config[]
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)
tmpl_t * key
User-Name.
#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.
Definition section.h:40
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
#define MODULE_BINDING_TERMINATOR
Terminate a module binding list.
Definition module.h:152
Module instance data.
Definition module.h:285
Named methods exported by a module.
Definition module.h:174
#define pair_update_reply(_attr, _da)
Return or allocate a fr_pair_t in the reply list.
Definition pair.h:129
#define pair_update_control(_attr, _da)
Return or allocate a fr_pair_t in the control list.
Definition pair.h:140
int tmpl_find_vp(fr_pair_t **out, request_t *request, tmpl_t const *vpt))
Returns the first VP matching a tmpl_t.
Definition tmpl_eval.c:768
#define tmpl_is_attr_unresolved(vpt)
Definition tmpl.h:219
#define tmpl_is_attr(vpt)
Definition tmpl.h:208
static char const * tmpl_attr_tail_unresolved(tmpl_t const *vpt)
Return the last attribute reference unresolved da.
Definition tmpl.h:869
static fr_dict_attr_t const * tmpl_attr_tail_da(tmpl_t const *vpt)
Return the last attribute reference da.
Definition tmpl.h:801
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.
Definition tmpl_eval.c:797
Optional arguments passed to vp_tmpl functions.
Definition tmpl.h:332
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition snprintf.c:689
unlang_action_t unlang_module_yield(request_t *request, module_method_t resume, unlang_module_signal_t signal, fr_signal_t sigmask, void *rctx)
Yield a request back to the interpreter from within a module.
Definition module.c:434
eap_aka_sim_process_conf_t * inst
fr_aka_sim_id_type_t type
fr_pair_t * vp
#define fr_time()
Allow us to arbitrarily manipulate time.
Definition state_test.c:8
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
#define talloc_get_type_abort_const
Definition talloc.h:287
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)
Definition time.h:731
#define fr_time_wrap(_time)
Definition time.h:145
#define fr_time_lteq(_a, _b)
Definition time.h:240
static int64_t fr_time_delta_to_sec(fr_time_delta_t delta)
Definition time.h:647
static fr_time_t fr_time_from_sec(time_t when)
Convert a time_t (wallclock time) to a fr_time_t (internal time)
Definition time.h:858
#define fr_time_gt(_a, _b)
Definition time.h:237
#define fr_time_sub(_a, _b)
Subtract one time from another.
Definition time.h:229
#define fr_time_neq(_a, _b)
Definition time.h:242
A time delta, a difference in time measured in nanoseconds.
Definition time.h:80
"server local" time.
Definition time.h:69
@ T_BARE_WORD
Definition token.h:120
@ T_DOUBLE_QUOTED_STRING
Definition token.h:121
int unlang_xlat_push(TALLOC_CTX *ctx, unlang_result_t *p_result, 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.
Definition xlat.c:282
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)
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.
Definition value.c:3574
int8_t fr_value_box_cmp(fr_value_box_t const *a, fr_value_box_t const *b)
Compare two values.
Definition value.c:722
#define fr_box_time_delta(_val)
Definition value.h:362
int nonnull(2, 5))
#define fr_box_time(_val)
Definition value.h:345
#define fr_value_box_init(_vb, _type, _enumv, _tainted)
Initialise a fr_value_box_t.
Definition value.h:606
static size_t char ** out
Definition value.h:1020