summaryrefslogtreecommitdiffstats
path: root/src/modules/rlm_date
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-08-26 10:41:52 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-08-26 10:41:52 +0000
commit44eafeee62e6982131c62df6f74335114ca53024 (patch)
tree1cdf833b0a76e52630d717202398ced5900e11e9 /src/modules/rlm_date
parentAdding upstream version 3.2.3+dfsg. (diff)
downloadfreeradius-upstream.tar.xz
freeradius-upstream.zip
Adding upstream version 3.2.5+dfsg.upstream/3.2.5+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/modules/rlm_date')
-rw-r--r--src/modules/rlm_date/rlm_date.c171
1 files changed, 170 insertions, 1 deletions
diff --git a/src/modules/rlm_date/rlm_date.c b/src/modules/rlm_date/rlm_date.c
index 79191e7..739395c 100644
--- a/src/modules/rlm_date/rlm_date.c
+++ b/src/modules/rlm_date/rlm_date.c
@@ -19,9 +19,10 @@
* @brief Translates timestrings between formats.
*
* @author Artur Malinowski <artur@wow.com>
+ * @author Matthew Newton
*
* @copyright 2013 Artur Malinowski <artur@wow.com>
- * @copyright 1999-2013 The FreeRADIUS Server Project.
+ * @copyright 1999-2023 The FreeRADIUS Server Project.
*/
#include <freeradius-devel/radiusd.h>
@@ -116,6 +117,173 @@ static ssize_t xlat_date_convert(void *instance, REQUEST *request, char const *f
}
DIAG_ON(format-nonliteral)
+
+/** Get time in ms since either epoch or another value
+ *
+ * %{time_since:s} - return seconds since epoch
+ * %{time_since:ms 0} - return milliseconds since epoch
+ * %{time_since:us 1695745763034443} - return microseconds since Tue 26 Sep 17:29:23.034443 BST 2023
+ * %{time_since:us &Tmp-Integer64-1} - return microseconds since value in &Tmp-Integer64-1
+ */
+
+static ssize_t xlat_time_since(UNUSED void *instance, REQUEST *request, char const *fmt, char *out, size_t outlen)
+{
+ uint64_t time_now = 0;
+ uint64_t time_delta = 0;
+ uint64_t time_since = 0;
+ struct timeval tv;
+
+ enum timebase {
+ S = 1,
+ MS = 1000,
+ US = 1000000,
+ };
+ enum timebase time_base;
+
+ while (isspace((uint8_t) *fmt)) fmt++;
+
+ /*
+ * Work out what time base we are using, s, ms or us.
+ */
+ if (fmt[0] == 'm' && fmt[1] == 's') {
+ time_base = MS;
+ fmt += 2;
+ } else if (fmt[0] == 'u' && fmt[1] == 's') {
+ time_base = US;
+ fmt += 2;
+ } else if (fmt[0] == 's') {
+ time_base = S;
+ fmt++;
+ } else {
+ REDEBUG("Time base (ms, us, s) missing in time_since xlat");
+ error:
+ *out = '\0';
+ return -1;
+ }
+
+ if (fmt[0] != '\0' && fmt[0] != ' ') {
+ REDEBUG("Invalid arguments passed to time_since xlat");
+ goto error;
+ }
+
+ while (isspace((uint8_t) *fmt)) fmt++;
+
+ /*
+ * Handle the different formats that we can be passed
+ */
+ if (fmt[0] == '\0') {
+ /*
+ * %{time_since:[mu]?s} - epoch
+ */
+ time_since = 0;
+
+ } else if (fmt[0] == '&') {
+ /*
+ * We were provided with an attribute
+ *
+ * %{time_since:[mu]?s &list:Attr-Name}
+ */
+ value_data_t outnum;
+ VALUE_PAIR *vp;
+ vp_tmpl_t vpt;
+ ssize_t slen;
+
+ fmt++;
+ slen = tmpl_from_attr_substr(&vpt, fmt, REQUEST_CURRENT, PAIR_LIST_REQUEST, false, false);
+ if (slen <= 0) {
+ /* Attribute name doesn't exist */
+ REDEBUG("Unable to parse attribute in time_since xlat");
+ goto error;
+ }
+ fmt += slen;
+
+ if (tmpl_find_vp(&vp, request, &vpt) < 0) {
+ /* Attribute exists but is not in the list */
+ RWDEBUG("Can't find &%.*s", (int)vpt.len, vpt.name);
+ goto error;
+ }
+
+ if (vp->da->type == PW_TYPE_INTEGER64) {
+ /*
+ * Int64 is easy
+ */
+ time_since = vp->vp_integer64;
+ } else {
+ /*
+ * ...but not others - try and convert, but warn it's likely nonsensical.
+ */
+ if (value_data_cast(request, &outnum,
+ PW_TYPE_INTEGER64, NULL, vp->da->type, NULL,
+ &vp->data, vp->vp_length) < 0) {
+ REDEBUG("Unable to convert %s to integer", fmt);
+ goto error;
+ }
+ if (vp->da->type == PW_TYPE_DATE) {
+ /*
+ * Special case a Date - we know it's seconds
+ */
+ RDEBUG3("Attribute \"%s\" is a date; multiplying seconds by %d", fmt, time_base);
+ time_since = outnum.integer64 * time_base;
+ } else {
+ RWDEBUG("Attribute \"%s\" is not integer, conversion may not make sense", fmt);
+ time_since = outnum.integer64;
+ }
+ }
+
+ } else if (fmt[0] == '-') {
+ REDEBUG("time_since xlat only accepts positive integers");
+ goto error;
+
+ } else {
+ /*
+ * Otherwise we hope we were provided with an integer value
+ *
+ * %{time_since:[mu]?s 12345}
+ */
+ if (sscanf(fmt, "%" PRIu64, &time_since) != 1) {
+ REDEBUG("Failed parsing \"%s\" as integer", fmt);
+ goto error;
+ }
+ }
+
+ /*
+ * Get current time and add milli/micro component if needed
+ */
+ gettimeofday(&tv, NULL);
+
+ time_now = (uint64_t)tv.tv_sec * time_base;
+
+ if (time_base == MS) {
+ time_now += (uint64_t)tv.tv_usec / 1000;
+ } else if (time_base == US) {
+ time_now += (uint64_t)tv.tv_usec;
+ }
+
+ /*
+ * time_since needs to be in the past
+ */
+ if (time_since > time_now) {
+ REDEBUG("time provided to time_since needs to be in the past");
+ goto error;
+ }
+
+ /*
+ * Calculate time since provided value
+ */
+ time_delta = time_now - time_since;
+
+ /*
+ * Write out and return
+ */
+ if ((size_t)snprintf(out, outlen, "%" PRIu64, time_delta) >= outlen) {
+ REDEBUG("Insufficient space to write 64-bit time value");
+ goto error;
+ }
+
+ return 0;
+}
+
+
static int mod_bootstrap(CONF_SECTION *conf, void *instance)
{
rlm_date_t *inst = instance;
@@ -126,6 +294,7 @@ static int mod_bootstrap(CONF_SECTION *conf, void *instance)
}
xlat_register(inst->xlat_name, xlat_date_convert, NULL, inst);
+ xlat_register("time_since", xlat_time_since, NULL, inst);
return 0;
}