The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
rlm_date.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 * @file rlm_date.c
19 * @brief Translates timestrings between formats.
20 *
21 * @author Artur Malinowski (artur@wow.com)
22 *
23 * @copyright 2013 Artur Malinowski (artur@wow.com)
24 * @copyright 1999-2018 The FreeRADIUS Server Project.
25 */
26
27#include <freeradius-devel/server/base.h>
28#include <freeradius-devel/server/module_rlm.h>
29#include <freeradius-devel/unlang/xlat_func.h>
30#include <time.h>
31
32typedef struct {
33 char const *fmt;
34 bool utc;
36
37static const conf_parser_t module_config[] = {
38 { FR_CONF_OFFSET("format", rlm_date_t, fmt), .dflt = "%b %e %Y %H:%M:%S %Z" },
39 { FR_CONF_OFFSET("utc", rlm_date_t, utc), .dflt = "no" },
41};
42
43DIAG_OFF(format-nonliteral)
44static xlat_action_t date_convert_string(TALLOC_CTX *ctx, fr_dcursor_t *out, request_t *request,
45 const char *str, rlm_date_t const *inst)
46{
47 struct tm tminfo;
48 time_t date = 0;
50 bool utc = inst->utc;
51
52#ifdef __APPLE__
53 /*
54 * OSX "man strptime" says it only accepts the local time zone, and GMT.
55 *
56 * However, when printing dates via strftime(), it prints
57 * "UTC" instead of "GMT". So... we have to fix it up
58 * for stupid nonsense.
59 */
60 char const *tz = strstr(str, "UTC");
61 if (tz) {
62 char *my_str;
63 char *p;
64
65 /*
66 *
67 */
68 MEM(my_str = talloc_strdup(ctx, str));
69 p = my_str + (tz - str);
70 memcpy(p, "GMT", 3);
71
72 p = strptime(my_str, inst->fmt, &tminfo);
73 if (!p) {
74 REDEBUG("Failed to parse time string \"%s\" as format '%s'", my_str, inst->fmt);
75 talloc_free(my_str);
76 return XLAT_ACTION_FAIL;
77 }
78 talloc_free(my_str);
79
80 /*
81 * The output is converted to the local time zone, so
82 * we can't use UTC.
83 */
84 utc = false;
85 } else
86#endif
87
88 if (strptime(str, inst->fmt, &tminfo) == NULL) {
89 REDEBUG("Failed to parse time string \"%s\" as format '%s'", str, inst->fmt);
90 return XLAT_ACTION_FAIL;
91 }
92
93 if (utc) {
94 date = timegm(&tminfo);
95 } else {
96 date = mktime(&tminfo);
97 }
98 if (date < 0) {
99 REDEBUG("Failed converting parsed time into unix time");
100 return XLAT_ACTION_FAIL;
101 }
102
103 MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_DATE, NULL));
104 vb->vb_date = fr_unix_time_from_sec(date);
106 return XLAT_ACTION_DONE;
107}
108
110 request_t *request, char const *fmt, time_t date)
111{
112 struct tm tminfo;
113 char buff[64];
114 fr_value_box_t *vb;
115
116 if (inst->utc) {
117 if (gmtime_r(&date, &tminfo) == NULL) {
118 REDEBUG("Failed converting time string to gmtime: %s", fr_syserror(errno));
119 return XLAT_ACTION_FAIL;
120 }
121 } else {
122 if (localtime_r(&date, &tminfo) == NULL) {
123 REDEBUG("Failed converting time string to localtime: %s", fr_syserror(errno));
124 return XLAT_ACTION_FAIL;
125 }
126 }
127
128 if (strftime(buff, sizeof(buff), fmt, &tminfo) == 0) return XLAT_ACTION_FAIL;
129
130 MEM(vb = fr_value_box_alloc_null(ctx));
131 MEM(fr_value_box_strdup(ctx, vb, NULL, buff, false) == 0);
133
134 return XLAT_ACTION_DONE;
135}
136DIAG_ON(format-nonliteral)
137
139 { .required = true, .single = true, .type = FR_TYPE_VOID },
141};
142
143/** Get or convert time and date
144 *
145 * Using the format in the module instance configuration, get
146 * various timestamps, or convert strings to date format.
147 *
148 * When the request arrived:
149@verbatim
150%date(request)
151@endverbatim
152 *
153 * Now:
154@verbatim
155%date(now)
156@endverbatim
157 *
158 * Examples (Tmp-Integer-0 = 1506101100):
159@verbatim
160update request {
161 &Tmp-String-0 := %date(%{Tmp-Integer-0}) ("Fri 22 Sep 18:25:00 BST 2017")
162 &Tmp-Integer-1 := %date(%{Tmp-String-0}) (1506101100)
163}
164@endverbatim
165 *
166 * @ingroup xlat_functions
167 */
169 xlat_ctx_t const *xctx,
170 request_t *request, fr_value_box_list_t *in)
171{
172 rlm_date_t const *inst = talloc_get_type_abort(xctx->mctx->mi->data, rlm_date_t);
173 struct tm tminfo;
174 fr_value_box_t *arg = fr_value_box_list_head(in);
175
176 memset(&tminfo, 0, sizeof(tminfo));
177
178 if (!arg) goto now;
179
180 /*
181 * Certain strings have magical meanings.
182 */
183 if (arg->type == FR_TYPE_STRING) {
184 if (strcmp(arg->vb_strvalue, "request") == 0) {
185 return date_encode_strftime(ctx, out, inst, request, inst->fmt,
186 fr_time_to_sec(request->packet->timestamp));
187 }
188
189 if (strcmp(arg->vb_strvalue, "now") == 0) {
190 now:
191 return date_encode_strftime(ctx, out, inst, request, inst->fmt, fr_time_to_sec(fr_time()));
192 }
193
194 /*
195 * %date('+%A') == "Monday", to mirror the behavior of the `date` command.
196 */
197 if (arg->vb_strvalue[0] == '+') {
198 return date_encode_strftime(ctx, out, inst, request, arg->vb_strvalue + 1, fr_time_to_sec(fr_time()));
199 }
200 }
201
202 switch (arg->type) {
203 /*
204 * These are 'to' types, i.e. we'll convert the integers
205 * to a time structure, and then output it in the specified
206 * format as a string.
207 */
208 case FR_TYPE_DATE:
209 return date_encode_strftime(ctx, out, inst, request, inst->fmt, fr_unix_time_to_sec(arg->vb_date));
210
211 case FR_TYPE_UINT32:
212 return date_encode_strftime(ctx, out, inst, request, inst->fmt, (time_t) arg->vb_uint32);
213
214 case FR_TYPE_UINT64:
215 return date_encode_strftime(ctx, out, inst, request, inst->fmt, (time_t) arg->vb_uint64);
216
217 /*
218 * These are 'from' types, i.e. we'll convert the input string
219 * into a time structure, and then output it as an integer
220 * unix timestamp.
221 */
222 case FR_TYPE_STRING:
223 return date_convert_string(ctx, out, request, arg->vb_strvalue, inst);
224
225 default:
226 REDEBUG("Can't convert type %s into date", fr_type_to_str(arg->type));
227 }
228
229 return XLAT_ACTION_FAIL;
230}
231
232static int mod_bootstrap(module_inst_ctx_t const *mctx)
233{
234 xlat_t *xlat;
235
238
239 return 0;
240}
241
244 .common = {
245 .magic = MODULE_MAGIC_INIT,
246 .name = "date",
247 .inst_size = sizeof(rlm_date_t),
249 .bootstrap = mod_bootstrap
250 }
251};
static int const char * fmt
Definition acutest.h:573
#define DIAG_ON(_x)
Definition build.h:458
#define DIAG_OFF(_x)
Definition build.h:457
#define CONF_PARSER_TERMINATOR
Definition cf_parse.h:642
#define FR_CONF_OFFSET(_name, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition cf_parse.h:268
Defines a CONF_PAIR to C data type mapping.
Definition cf_parse.h:579
static int fr_dcursor_append(fr_dcursor_t *cursor, void *v)
Insert a single item at the end of the list.
Definition dcursor.h:406
#define MEM(x)
Definition debug.h:36
static fr_slen_t in
Definition dict.h:824
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition dl_module.h:63
static xlat_action_t xlat_date_convert(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
Get or convert time and date.
Definition rlm_date.c:168
talloc_free(reap)
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_DATE
Unix time stamp, always has value >2^31.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_UINT64
64 Bit unsigned integer.
@ FR_TYPE_VOID
User data.
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
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 instantiation calls.
Definition module_ctx.h:50
xlat_t * module_rlm_xlat_register(TALLOC_CTX *ctx, module_inst_ctx_t const *mctx, char const *name, xlat_func_t func, fr_type_t return_type)
Definition module_rlm.c:257
module_t common
Common fields presented by all modules.
Definition module_rlm.h:39
static const conf_parser_t config[]
Definition base.c:183
#define REDEBUG(fmt,...)
Definition radclient.h:52
char const * fmt
Definition rlm_date.c:33
module_rlm_t rlm_date
Definition rlm_date.c:243
static xlat_arg_parser_t const xlat_date_convert_args[]
Definition rlm_date.c:138
static int mod_bootstrap(module_inst_ctx_t const *mctx)
Definition rlm_date.c:232
static xlat_action_t date_encode_strftime(TALLOC_CTX *ctx, fr_dcursor_t *out, rlm_date_t const *inst, request_t *request, char const *fmt, time_t date)
Definition rlm_date.c:109
bool utc
Definition rlm_date.c:34
static const conf_parser_t module_config[]
Definition rlm_date.c:37
static xlat_action_t date_convert_string(TALLOC_CTX *ctx, fr_dcursor_t *out, request_t *request, const char *str, rlm_date_t const *inst)
Definition rlm_date.c:44
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
void * boot
Data allocated during the boostrap phase.
Definition module.h:274
static char buff[sizeof("18446744073709551615")+3]
Definition size_tests.c:41
eap_aka_sim_process_conf_t * inst
#define fr_time()
Allow us to arbitrarily manipulate time.
Definition state_test.c:8
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
Simple time functions.
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
static int64_t fr_unix_time_to_sec(fr_unix_time_t delta)
Definition time.h:506
static fr_unix_time_t fr_unix_time_from_sec(int64_t sec)
Definition time.h:449
bool required
Argument must be present, and non-empty.
Definition xlat.h:148
#define XLAT_ARG_PARSER_TERMINATOR
Definition xlat.h:168
xlat_action_t
Definition xlat.h:37
@ XLAT_ACTION_FAIL
An xlat function failed.
Definition xlat.h:44
@ XLAT_ACTION_DONE
We're done evaluating this level of nesting.
Definition xlat.h:43
Definition for a single argument consumend by an xlat function.
Definition xlat.h:147
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition types.h:433
int fr_value_box_strdup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, bool tainted)
Copy a nul terminated string to a fr_value_box_t.
Definition value.c:3927
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
Definition value.h:621
#define fr_value_box_alloc_null(_ctx)
Allocate a value box for later use with a value assignment function.
Definition value.h:632
static size_t char ** out
Definition value.h:997
module_ctx_t const * mctx
Synthesised module calling ctx.
Definition xlat_ctx.h:52
An xlat calling ctx.
Definition xlat_ctx.h:49
int xlat_func_args_set(xlat_t *x, xlat_arg_parser_t const args[])
Register the arguments of an xlat.
Definition xlat_func.c:365