# The `query` parameter specifies the SQL query used to get the current Counter value
# from the database.
#
-# There are `2` parameters that can be used in the query:
+# key = "%{%{Stripped-User-Name}:-%{User-Name}}"
#
-# [options="header,autowidth"]
-# |===
-# | Parameter | Description
-# | `%%b` | unix time value of beginning of the reset period.
-# | `%%e` | unix time value of end of the reset period.
-# |===
+# reset_period_start_name:: The name of the attribute which is used to store the
+# time that the current reset period started.
#
-# key = "%{%{Stripped-User-Name}:-%{User-Name}}"
+# The default is `&control.${.:instance}-Start`
+#
+# Note because we are counting seconds, this attribute is of type `uint64`, and not `date`.
+#
+# reset_period_end_name:: The name of the attribute which is used to store the
+# time that the current reset period will end.
+#
+# The default is `&control.${.:instance}-End`
+#
+# Note because we are counting seconds, this attribute is of type `uint64`, and not `date`.
#
# counter_name:: Name of the `check` attribute to use to access the counter in
# the `users` file or SQL `radcheck` or `radgroupcheck` tables.
sql_module_instance = sql
dialect = ${modules.sql.dialect}
+# reset_period_start_name = &control.${.:instance}-Reset-Start
+# reset_period_end_name = &control.${.:instance}-Reset-End
counter_name = &Daily-Session-Time
check_name = &control.Max-Daily-Session
reply_name = &reply.Session-Timeout
* be used as the instance handle.
*/
typedef struct {
- tmpl_t *paircmp_attr; //!< Daily-Session-Time.
- tmpl_t *limit_attr; //!< Max-Daily-Session.
- tmpl_t *reply_attr; //!< Session-Timeout.
- tmpl_t *key; //!< User-Name
+ tmpl_t *start_attr; //!< &control.${.:instance}-Start
+ tmpl_t *end_attr; //!< &control.${.:instance}-End
+
+ tmpl_t *paircmp_attr; //!< Daily-Session-Time.
+ tmpl_t *limit_attr; //!< Max-Daily-Session.
+ tmpl_t *reply_attr; //!< Session-Timeout.
+ tmpl_t *key; //!< User-Name
char const *sqlmod_inst; //!< Instance of SQL module to use, usually just 'sql'.
char const *query; //!< SQL query to retrieve current session time.
{ FR_CONF_OFFSET("key", FR_TYPE_TMPL | FR_TYPE_NOT_EMPTY, rlm_sqlcounter_t, key), .dflt = "%{%{Stripped-User-Name}:-%{User-Name}}", .quote = T_DOUBLE_QUOTED_STRING },
+ { FR_CONF_OFFSET("reset_period_start_name", FR_TYPE_TMPL | FR_TYPE_ATTRIBUTE, rlm_sqlcounter_t, start_attr),
+ .dflt = "&control.${.:instance}-Start" },
+ { FR_CONF_OFFSET("reset_period_end_name", FR_TYPE_TMPL | FR_TYPE_ATTRIBUTE, rlm_sqlcounter_t, end_attr),
+ .dflt = "&control.${.:instance}-End" },
+
/* Just used to register a paircmp against */
{ FR_CONF_OFFSET("counter_name", FR_TYPE_TMPL | FR_TYPE_ATTRIBUTE | FR_TYPE_REQUIRED, rlm_sqlcounter_t, paircmp_attr) },
{ FR_CONF_OFFSET("check_name", FR_TYPE_TMPL | FR_TYPE_ATTRIBUTE | FR_TYPE_REQUIRED, rlm_sqlcounter_t, limit_attr) },
*
* %b last_reset
* %e reset_time
- * %S sqlmod_inst
- *
*/
static ssize_t sqlcounter_expand(char *out, int outlen, rlm_sqlcounter_t const *inst, UNUSED request_t *request, char const *fmt)
{
{
rlm_sqlcounter_t *inst = talloc_get_type_abort(mctx->inst->data, rlm_sqlcounter_t);
uint64_t counter, res;
- fr_pair_t *limit;
+ fr_pair_t *limit, *vp;
fr_pair_t *reply_item;
char msg[128];
int ret;
}
if (tmpl_find_vp(&limit, request, inst->limit_attr) < 0) {
- RWDEBUG2("Couldn't find limit attribute, %s, doing nothing...", inst->limit_attr->name);
+ RWDEBUG2("Couldn't find %s, doing nothing...", inst->limit_attr->name);
+ RETURN_MODULE_NOOP;
+ }
+
+ if (tmpl_find_or_add_vp(&vp, request, inst->start_attr) < 0) {
+ RWDEBUG2("Couldn't find %s, doing nothing...", inst->start_attr->name);
+ RETURN_MODULE_NOOP;
+ }
+ vp->vp_uint64 = fr_time_to_sec(inst->last_reset);
+
+ if (tmpl_find_or_add_vp(&vp, request, inst->end_attr) < 0) {
+ RWDEBUG2("Couldn't find %s, doing nothing...", inst->end_attr->name);
RETURN_MODULE_NOOP;
}
+ vp->vp_uint64 = fr_time_to_sec(inst->reset_time);
/* First, expand %k, %b and %e in query */
if (sqlcounter_expand(subst, sizeof(subst), inst, request, inst->query) <= 0) {
* Check if check item > counter
*/
if (limit->vp_uint64 <= counter) {
- fr_pair_t *vp;
-
/* User is denied access, send back a reply message */
snprintf(msg, sizeof(msg), "Your maximum %s usage time has been reached", inst->reset);
fr_assert(inst->limit_attr);
memset(&flags, 0, sizeof(flags));
+ if (tmpl_attr_tail_unresolved_add(fr_dict_unconst(dict_freeradius), inst->start_attr, FR_TYPE_UINT64, &flags) < 0) {
+ cf_log_perr(conf, "Failed defining reset_period_start attribute");
+ return -1;
+ }
+
+ if (tmpl_attr_tail_unresolved_add(fr_dict_unconst(dict_freeradius), inst->paircmp_attr, FR_TYPE_UINT64, &flags) < 0) {
+ cf_log_perr(conf, "Failed defining reset_end_start attribute");
+ return -1;
+ }
+
if (tmpl_attr_tail_unresolved_add(fr_dict_unconst(dict_freeradius), inst->paircmp_attr, FR_TYPE_UINT64, &flags) < 0) {
cf_log_perr(conf, "Failed defining counter attribute");
return -1;