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: e4e75b347d9fe195b8e689f1205986d82395d9d0 $
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: e4e75b347d9fe195b8e689f1205986d82395d9d0 $")
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
36#include <ctype.h>
37
38/*
39 * Note: When your counter spans more than 1 period (ie 3 months
40 * or 2 weeks), this module probably does NOT do what you want! It
41 * calculates the range of dates to count across by first calculating
42 * the End of the Current period and then subtracting the number of
43 * periods you specify from that to determine the beginning of the
44 * range.
45 *
46 * For example, if you specify a 3 month counter and today is June 15th,
47 * the end of the current period is June 30. Subtracting 3 months from
48 * that gives April 1st. So, the counter will sum radacct entries from
49 * April 1st to June 30. Then, next month, it will sum entries from
50 * May 1st to July 31st.
51 *
52 * To fix this behavior, we need to add some way of storing the Next
53 * Reset Time.
54 */
55
56/*
57 * Define a structure for our module configuration.
58 *
59 * These variables do not need to be in a structure, but it's
60 * a lot cleaner to do so, and a pointer to the structure can
61 * be used as the instance handle.
62 */
63typedef struct {
64 tmpl_t *start_attr; //!< &control.${.:instance}-Start
65 tmpl_t *end_attr; //!< &control.${.:instance}-End
66
67 tmpl_t *counter_attr; //!< Daily-Session-Time.
68 tmpl_t *limit_attr; //!< Max-Daily-Session.
69 tmpl_t *key; //!< User-Name
70
71 char const *sql_name; //!< Instance of SQL module to use, usually just 'sql'.
72 char const *query; //!< SQL query to retrieve current session time.
73 char const *reset; //!< Daily, weekly, monthly, never or user defined.
74 bool auto_extend; //!< If the remaining allowance is sufficient to reach the next
75 ///< period allow for that in setting the reply attribute.
76 bool utc; //!< Use UTC time.
77
81
82static const conf_parser_t module_config[] = {
83 { FR_CONF_OFFSET_FLAGS("sql_module_instance", CONF_FLAG_REQUIRED, rlm_sqlcounter_t, sql_name) },
84
85
88 { FR_CONF_OFFSET_FLAGS("auto_extend", CONF_FLAG_OK_MISSING, rlm_sqlcounter_t, auto_extend) },
90
91 { FR_CONF_OFFSET_FLAGS("key", CONF_FLAG_NOT_EMPTY, rlm_sqlcounter_t, key), .dflt = "%{%{Stripped-User-Name} || %{User-Name}}", .quote = T_DOUBLE_QUOTED_STRING },
92
93 { FR_CONF_OFFSET_FLAGS("reset_period_start_name", CONF_FLAG_ATTRIBUTE, rlm_sqlcounter_t, start_attr),
94 .dflt = "&control.${.:instance}-Reset-Start", .quote = T_BARE_WORD },
95 { FR_CONF_OFFSET_FLAGS("reset_period_end_name", CONF_FLAG_ATTRIBUTE, rlm_sqlcounter_t, end_attr),
96 .dflt = "&control.${.:instance}-Reset-End", .quote = T_BARE_WORD },
97
98 /* Attribute to write counter value to*/
101
103};
104
105typedef struct {
106 xlat_exp_head_t *query_xlat; //!< Tokenized xlat to run query.
107 tmpl_t *reply_attr; //!< Attribute to write timeout to.
108 tmpl_t *reply_msg_attr; //!< Attribute to write reply message to.
110
112
115 { .out = &dict_freeradius, .proto = "freeradius" },
116 { NULL }
117};
118
120{
121 int ret = 0;
122 size_t len;
123 unsigned int num = 1;
124 char last = '\0';
125 struct tm *tm, s_tm;
126 time_t time_s = fr_time_to_sec(now);
127
128 if (inst->utc) {
129 tm = gmtime_r(&time_s, &s_tm);
130 } else {
131 tm = localtime_r(&time_s, &s_tm);
132 }
133 tm->tm_sec = tm->tm_min = 0;
134
135 fr_assert(inst->reset != NULL);
136
137 if (isdigit((uint8_t) inst->reset[0])){
138 len = strlen(inst->reset);
139 if (len == 0)
140 return -1;
141 last = inst->reset[len - 1];
142 if (!isalpha((uint8_t) last))
143 last = 'd';
144 num = atoi(inst->reset);
145 DEBUG3("num=%d, last=%c",num,last);
146 }
147 if (strcmp(inst->reset, "hourly") == 0 || last == 'h') {
148 /*
149 * Round up to the next nearest hour.
150 */
151 tm->tm_hour += num;
152 inst->reset_time = fr_time_from_sec(inst->utc ? timegm(tm) : mktime(tm));
153 } else if (strcmp(inst->reset, "daily") == 0 || last == 'd') {
154 /*
155 * Round up to the next nearest day.
156 */
157 tm->tm_hour = 0;
158 tm->tm_mday += num;
159 inst->reset_time = fr_time_from_sec(inst->utc ? timegm(tm) : mktime(tm));
160 } else if (strcmp(inst->reset, "weekly") == 0 || last == 'w') {
161 /*
162 * Round up to the next nearest week.
163 */
164 tm->tm_hour = 0;
165 tm->tm_mday += (7 - tm->tm_wday) +(7*(num-1));
166 inst->reset_time = fr_time_from_sec(inst->utc ? timegm(tm) : mktime(tm));
167 } else if (strcmp(inst->reset, "monthly") == 0 || last == 'm') {
168 tm->tm_hour = 0;
169 tm->tm_mday = 1;
170 tm->tm_mon += num;
171 inst->reset_time = fr_time_from_sec(inst->utc ? timegm(tm) : mktime(tm));
172 } else if (strcmp(inst->reset, "never") == 0) {
173 inst->reset_time = fr_time_wrap(0);
174 } else {
175 return -1;
176 }
177
178 DEBUG2("Current Time: %pV, Next reset %pV", fr_box_time(now), fr_box_time(inst->reset_time));
179
180 return ret;
181}
182
183
184/* I don't believe that this routine handles Daylight Saving Time adjustments
185 properly. Any suggestions?
186*/
188{
189 int ret = 0;
190 size_t len;
191 unsigned int num = 1;
192 char last = '\0';
193 struct tm *tm, s_tm;
194 time_t time_s = fr_time_to_sec(now);
195
196 if (inst->utc) {
197 tm = gmtime_r(&time_s, &s_tm);
198 } else {
199 tm = localtime_r(&time_s, &s_tm);
200 }
201 tm->tm_sec = tm->tm_min = 0;
202
203 fr_assert(inst->reset != NULL);
204
205 if (isdigit((uint8_t) inst->reset[0])){
206 len = strlen(inst->reset);
207 if (len == 0)
208 return -1;
209 last = inst->reset[len - 1];
210 if (!isalpha((uint8_t) last))
211 last = 'd';
212 num = atoi(inst->reset);
213 DEBUG3("num=%d, last=%c", num, last);
214 }
215 if (strcmp(inst->reset, "hourly") == 0 || last == 'h') {
216 /*
217 * Round down to the prev nearest hour.
218 */
219 tm->tm_hour -= num - 1;
220 inst->last_reset = fr_time_from_sec(inst->utc ? timegm(tm) : mktime(tm));
221 } else if (strcmp(inst->reset, "daily") == 0 || last == 'd') {
222 /*
223 * Round down to the prev nearest day.
224 */
225 tm->tm_hour = 0;
226 tm->tm_mday -= num - 1;
227 inst->last_reset = fr_time_from_sec(inst->utc ? timegm(tm) : mktime(tm));
228 } else if (strcmp(inst->reset, "weekly") == 0 || last == 'w') {
229 /*
230 * Round down to the prev nearest week.
231 */
232 tm->tm_hour = 0;
233 tm->tm_mday -= tm->tm_wday +(7*(num-1));
234 inst->last_reset = fr_time_from_sec(inst->utc ? timegm(tm) : mktime(tm));
235 } else if (strcmp(inst->reset, "monthly") == 0 || last == 'm') {
236 tm->tm_hour = 0;
237 tm->tm_mday = 1;
238 tm->tm_mon -= num - 1;
239 inst->last_reset = fr_time_from_sec(inst->utc ? timegm(tm) : mktime(tm));
240 } else if (strcmp(inst->reset, "never") == 0) {
241 inst->reset_time = fr_time_wrap(0);
242 } else {
243 return -1;
244 }
245
246 DEBUG2("Current Time: %pV, Prev reset %pV", fr_box_time(now), fr_box_time(inst->last_reset));
247
248 return ret;
249}
250
258
259/** Handle the result of calling the SQL query to retrieve the `counter` value.
260 *
261 * Create / update the `counter` attribute in the control list
262 * If `counter` > `limit`, optionally populate a reply message and return RLM_MODULE_REJECT.
263 * Otherwise, optionally populate a reply attribute with the value of `limit` - `counter` and return RLM_MODULE_UPDATED.
264 * If no reply attribute is set, return RLM_MODULE_OK.
265 */
266static unlang_action_t mod_authorize_resume(rlm_rcode_t *p_result, UNUSED int *priority, request_t *request, void *uctx)
267{
268 sqlcounter_rctx_t *rctx = talloc_get_type_abort(uctx, sqlcounter_rctx_t);
269 rlm_sqlcounter_t *inst = rctx->inst;
270 sqlcounter_call_env_t *env = rctx->env;
271 fr_value_box_t *sql_result = fr_value_box_list_pop_head(&rctx->result);
272 uint64_t counter, res;
273 fr_pair_t *vp, *limit = rctx->limit;
274 int ret;
275 char msg[128];
276
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",
279 sql_result);
280 counter = 0;
281 }
282
283 /*
284 * Add the counter to the control list
285 */
286 MEM(pair_update_control(&vp, tmpl_attr_tail_da(inst->counter_attr)) >= 0);
287 vp->vp_uint64 = counter;
288
289 /*
290 * Check if check item > counter
291 */
292 if (limit->vp_uint64 <= counter) {
293 if (env->reply_msg_attr) {
294 /* User is denied access, send back a reply message */
295 snprintf(msg, sizeof(msg), "Your maximum %s usage has been reached", inst->reset);
296
298 fr_pair_value_strdup(vp, msg, false);
299 }
300
301 REDEBUG2("Maximum %s usage reached", inst->reset);
302 REDEBUG2("Rejecting user, %s value (%" PRIu64 ") is less than counter value (%" PRIu64 ")",
303 inst->limit_attr->name, limit->vp_uint64, counter);
304
306 }
307
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);
311
312 /*
313 * We are assuming that simultaneous-use=1. But
314 * even if that does not happen then our user
315 * could login at max for 2*max-usage-time Is
316 * that acceptable?
317 */
318 if (env->reply_attr) {
320
321 /*
322 * If we are near a reset then add the next
323 * limit, so that the user will not need to login
324 * again. Do this only if auto_extend is set.
325 */
326 if (inst->auto_extend &&
327 fr_time_gt(inst->reset_time, fr_time_wrap(0)) &&
328 ((int64_t)res >= fr_time_delta_to_sec(fr_time_sub(inst->reset_time, request->packet->timestamp)))) {
329 fr_time_delta_t to_reset = fr_time_sub(inst->reset_time, request->packet->timestamp);
330
331 RDEBUG2("Time remaining (%pV) is greater than time to reset (%" PRIu64 "s). "
332 "Adding %pV to reply value",
333 fr_box_time_delta(to_reset), res, fr_box_time_delta(to_reset));
334 res = fr_time_delta_to_sec(to_reset) + limit->vp_uint64;
335 }
336
337 fr_value_box_init(&vb, FR_TYPE_UINT64, NULL, false);
338 vb.vb_uint64 = res;
339
340 /*
341 * Limit the reply attribute to the minimum of the existing value, or this new one.
342 */
343 ret = tmpl_find_or_add_vp(&vp, request, env->reply_attr);
344 switch (ret) {
345 case 1: /* new */
346 break;
347
348 case 0: /* found */
349 {
350 fr_value_box_t existing;
351 fr_value_box_cast(NULL, &existing, FR_TYPE_UINT64, NULL, &vp->data);
352 if (fr_value_box_cmp(&vb, &existing) == 1) {
353 RDEBUG2("Leaving existing %s value of %pV" , env->reply_attr->name,
354 &vp->data);
356 }
357 }
358 break;
359
360 case -1: /* alloc failed */
361 REDEBUG("Error allocating attribute %s", env->reply_attr->name);
363
364 default: /* request or list unavailable */
365 RDEBUG2("List or request context not available for %s, skipping...", env->reply_attr->name);
367 }
368
369 fr_value_box_cast(vp, &vp->data, vp->data.type, NULL, &vb);
370
371 RDEBUG2("%pP", vp);
372
374 }
375
377}
378
379/** Check the value of a `counter` retrieved from an SQL query with a `limit`
380 *
381 * Module specific attributes containing the start / end times are created / updated,
382 * the query is tokenized as an xlat call to the relevant SQL module and then
383 * pushed on the stack for evaluation.
384 */
385static unlang_action_t CC_HINT(nonnull) mod_authorize(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
386{
387 rlm_sqlcounter_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_sqlcounter_t);
388 sqlcounter_call_env_t *env = talloc_get_type_abort(mctx->env_data, sqlcounter_call_env_t);
389 fr_pair_t *limit, *vp;
390 sqlcounter_rctx_t *rctx;
391
392 /*
393 * Before doing anything else, see if we have to reset
394 * the counters.
395 */
396 if (fr_time_neq(inst->reset_time, fr_time_wrap(0)) &&
397 (fr_time_lteq(inst->reset_time, request->packet->timestamp))) {
398 /*
399 * Re-set the next time and prev_time for this counters range
400 */
401 inst->last_reset = inst->reset_time;
402 find_next_reset(inst, request->packet->timestamp);
403 }
404
405 if (tmpl_find_vp(&limit, request, inst->limit_attr) < 0) {
406 RWDEBUG2("Couldn't find %s, doing nothing...", inst->limit_attr->name);
408 }
409
410 /*
411 * Populate start and end attributes for use in query expansion
412 */
413 if (tmpl_find_or_add_vp(&vp, request, inst->start_attr) < 0) {
414 REDEBUG("Couldn't create %s", inst->start_attr->name);
416 }
417 vp->vp_uint64 = fr_time_to_sec(inst->last_reset);
418
419 if (tmpl_find_or_add_vp(&vp, request, inst->end_attr) < 0) {
420 REDEBUG2("Couldn't create %s", inst->end_attr->name);
422 }
423 vp->vp_uint64 = fr_time_to_sec(inst->reset_time);
424
426 *rctx = (sqlcounter_rctx_t) {
427 .inst = inst,
428 .env = env,
429 .limit = limit
430 };
431
432 if (unlang_function_push(request, NULL, mod_authorize_resume, NULL, 0, UNLANG_SUB_FRAME, rctx) < 0) {
433 error:
434 talloc_free(rctx);
436 }
437
438 fr_value_box_list_init(&rctx->result);
439 if (unlang_xlat_push(rctx, &rctx->last_success, &rctx->result, request, env->query_xlat, UNLANG_SUB_FRAME) < 0) goto error;
440
442}
443
444/** Custom call_env parser to tokenize the SQL query xlat used for counter retrieval
445 */
446static int call_env_query_parse(TALLOC_CTX *ctx, void *out, tmpl_rules_t const *t_rules, CONF_ITEM *ci,
447 call_env_ctx_t const *cec, UNUSED call_env_parser_t const *rule)
448{
450 CONF_PAIR const *to_parse = cf_item_to_pair(ci);
451 char *query;
452 xlat_exp_head_t *ex;
453
454 query = talloc_asprintf(NULL, "%%%s(\"%s\")", inst->sql_name, cf_pair_value(to_parse));
455
456 if (xlat_tokenize(ctx, &ex,
457 &FR_SBUFF_IN(query, talloc_array_length(query)),
458 &(fr_sbuff_parse_rules_t){
459 .escapes = &(fr_sbuff_unescape_rules_t) {
460 .name = "xlat",
461 .chr = '\\',
462 .subs = {
463 ['%'] = '%',
464 ['\\'] = '\\',
465 },
466 }}, t_rules, 0) < 0) {
467 talloc_free(query);
468 return -1;
469 }
470 talloc_free(query);
471
472 if (xlat_needs_resolving(ex) &&
473 (xlat_resolve(ex, &(xlat_res_rules_t){ .allow_unresolved = false }) < 0)) {
474 talloc_free(ex);
475 return -1;
476 }
477
478 *(void**)out = ex;
479 return 0;
480}
481
492
493
494/*
495 * Do any per-module initialization that is separate to each
496 * configured instance of the module. e.g. set up connections
497 * to external databases, read configuration files, set up
498 * dictionary entries, etc.
499 *
500 * If configuration information is given in the config section
501 * that must be referenced in later calls, store a handle to it
502 * in *instance otherwise put a null pointer there.
503 */
504static int mod_instantiate(module_inst_ctx_t const *mctx)
505{
506 rlm_sqlcounter_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_sqlcounter_t);
507 CONF_SECTION *conf = mctx->mi->conf;
509 fr_assert(inst->query && *inst->query);
510
511 sql_inst = module_rlm_static_by_name(NULL, inst->sql_name);
512 if (!sql_inst) {
513 cf_log_err(conf, "Module \"%s\" not found", inst->sql_name);
514 return -1;
515 }
516
517 if (!talloc_get_type(sql_inst->data, rlm_sql_t)) {
518 cf_log_err(conf, "\"%s\" is not an instance of rlm_sql", inst->sql_name);
519 return -1;
520 }
521
522 inst->reset_time = fr_time_wrap(0);
523
524 if (find_next_reset(inst, fr_time()) == -1) {
525 cf_log_err(conf, "Invalid reset '%s'", inst->reset);
526 return -1;
527 }
528
529 /*
530 * Discover the beginning of the current time period.
531 */
532 inst->last_reset = fr_time_wrap(0);
533
534 if (find_prev_reset(inst, fr_time()) < 0) {
535 cf_log_err(conf, "Invalid reset '%s'", inst->reset);
536 return -1;
537 }
538
539 return 0;
540}
541
542static inline int attr_check(CONF_SECTION *conf, tmpl_t *tmpl, char const *name, fr_dict_attr_flags_t *flags)
543{
546 tmpl_attr_tail_unresolved(tmpl), FR_TYPE_UINT64, flags) < 0) {
547 cf_log_perr(conf, "Failed defining %s attribute", name);
548 return -1;
549 }
550 } else if (tmpl_is_attr(tmpl)) {
551 if (tmpl_attr_tail_da(tmpl)->type != FR_TYPE_UINT64) {
552 cf_log_err(conf, "%s attribute %s must be uint64", name, tmpl_attr_tail_da(tmpl)->name);
553 return -1;
554 }
555 }
556
557 return 0;
558}
559
560static int mod_bootstrap(module_inst_ctx_t const *mctx)
561{
562 rlm_sqlcounter_t const *inst = talloc_get_type_abort(mctx->mi->data, rlm_sqlcounter_t);
563 CONF_SECTION *conf = mctx->mi->conf;
564 fr_dict_attr_flags_t flags = { .internal = 1, .length = 8, .name_only = 1 };
565
566 if (unlikely(attr_check(conf, inst->start_attr, "reset_period_start", &flags) < 0)) return -1;
567 if (unlikely(attr_check(conf, inst->end_attr, "reset_period_end", &flags) < 0)) return -1;
568 if (unlikely(attr_check(conf, inst->counter_attr, "counter", &flags) < 0)) return -1;
569 if (unlikely(attr_check(conf, inst->limit_attr, "check", &flags) < 0)) return -1;
570
571 return 0;
572}
573
574/*
575 * The module name should be the only globally exported symbol.
576 * That is, everything else should be 'static'.
577 *
578 * If the module needs to temporarily modify it's instantiation
579 * data, the type should be changed to MODULE_TYPE_THREAD_UNSAFE.
580 * The server will then take care of ensuring that the module
581 * is single-threaded.
582 */
585 .common = {
586 .magic = MODULE_MAGIC_INIT,
587 .name = "sqlcounter",
588 .inst_size = sizeof(rlm_sqlcounter_t),
590 .bootstrap = mod_bootstrap,
592 },
593 .method_group = {
594 .bindings = (module_method_binding_t[]){
595 { .section = SECTION_NAME(CF_IDENT_ANY, CF_IDENT_ANY), .method = mod_authorize, .method_env = &sqlcounter_call_env },
597 }
598 }
599};
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
log_entry msg
Definition acutest.h:794
#define RCSID(id)
Definition build.h:483
#define unlikely(_x)
Definition build.h:381
#define UNUSED
Definition build.h:315
#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:664
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
Definition cf_util.c:1594
#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:1742
fr_dict_t * fr_dict_unconst(fr_dict_t const *dict)
Coerce to non-const.
Definition dict_util.c:4589
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:3267
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2404
unsigned int internal
Internal attribute, should not be received in protocol packets, should not be encoded.
Definition dict.h:87
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:281
Values of the encryption flags.
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:280
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition dl_module.h:63
#define unlang_function_push(_request, _func, _repeat, _signal, _sigmask, _top_frame, _uctx)
Push a generic function onto the unlang stack.
Definition function.h:111
TALLOC_CTX * unlang_interpret_frame_talloc_ctx(request_t *request)
Get a talloc_ctx which is valid only for this frame.
Definition interpret.c:1407
#define UNLANG_SUB_FRAME
Definition interpret.h:36
#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
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:828
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:2634
static const conf_parser_t config[]
Definition base.c:183
#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_MODULE_REJECT
Definition rcode.h:55
#define RETURN_MODULE_NOOP
Definition rcode.h:62
#define RETURN_MODULE_OK
Definition rcode.h:57
#define RETURN_MODULE_FAIL
Definition rcode.h:56
#define RETURN_MODULE_UPDATED
Definition rcode.h:63
rlm_rcode_t
Return codes indicating the result of the module call.
Definition rcode.h:40
static char const * name
static int instantiate(module_inst_ctx_t const *mctx)
Definition rlm_rest.c:1310
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
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[]
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)
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:329
size_t inst_size
Size of the module's instance data.
Definition module.h:203
void * data
Module's instance data.
Definition module.h:271
#define MODULE_BINDING_TERMINATOR
Terminate a module binding list.
Definition module.h:151
Module instance data.
Definition module.h:265
Named methods exported by a module.
Definition module.h:173
#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:889
#define tmpl_is_attr_unresolved(vpt)
Definition tmpl.h:224
#define tmpl_is_attr(vpt)
Definition tmpl.h:213
static char const * tmpl_attr_tail_unresolved(tmpl_t const *vpt)
Return the last attribute reference unresolved da.
Definition tmpl.h:886
static fr_dict_attr_t const * tmpl_attr_tail_da(tmpl_t const *vpt)
Return the last attribute reference da.
Definition tmpl.h:818
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:918
Optional arguments passed to vp_tmpl functions.
Definition tmpl.h:347
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition snprintf.c:689
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:282
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, 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.
Definition xlat.c:286
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.
Definition value.c:3352
int8_t fr_value_box_cmp(fr_value_box_t const *a, fr_value_box_t const *b)
Compare two values.
Definition value.c:676
#define fr_box_time_delta(_val)
Definition value.h:343
int nonnull(2, 5))
#define fr_box_time(_val)
Definition value.h:326
#define fr_value_box_init(_vb, _type, _enumv, _tainted)
Initialise a fr_value_box_t.
Definition value.h:587
static size_t char ** out
Definition value.h:997