d8278cce93ee2ed3a2ee1fd5eee63fb5dab8c3f0
[freeradius.git] / src / modules / rlm_date / rlm_date.c
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-2013 The FreeRADIUS Server Project.
25  */
26
27 #include <freeradius-devel/radiusd.h>
28 #include <freeradius-devel/modules.h>
29 #include <ctype.h>
30 #include <time.h>
31
32 typedef struct rlm_date_t {
33         char const *xlat_name;
34         char const *fmt;
35 } rlm_date_t;
36
37 static const CONF_PARSER module_config[] = {
38         { "format", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_date_t, fmt), "%b %e %Y %H:%M:%S %Z" },
39         CONF_PARSER_TERMINATOR
40 };
41
42 DIAG_OFF(format-nonliteral)
43 static ssize_t xlat_date_convert(void *instance, REQUEST *request, char const *fmt, char *out, size_t outlen)
44 {
45         rlm_date_t *inst = instance;
46         time_t date = 0;
47         struct tm tminfo;
48         VALUE_PAIR *vp;
49
50         memset(&tminfo, 0, sizeof(tminfo));
51
52         if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) {
53                 *out = '\0';
54                 return 0;
55         }
56
57         switch (vp->da->type) {
58         /*
59          *      These are 'to' types, i.e. we'll convert the integers
60          *      to a time structure, and then output it in the specified
61          *      format as a string.
62          */
63         case PW_TYPE_DATE:
64                 date = vp->vp_date;
65                 goto encode;
66
67         case PW_TYPE_INTEGER:
68         case PW_TYPE_INTEGER64:
69                 date = (time_t) vp->vp_integer;
70
71         encode:
72                 if (localtime_r(&date, &tminfo) == NULL) {
73                         REDEBUG("Failed converting time string to localtime");
74                         goto error;
75                 }
76                 return strftime(out, outlen, inst->fmt, &tminfo);
77
78         /*
79          *      These are 'from' types, i.e. we'll convert the input string
80          *      into a time structure, and then output it as an integer
81          *      unix timestamp.
82          */
83         case PW_TYPE_STRING:
84                 if (strptime(vp->vp_strvalue, inst->fmt, &tminfo) == NULL) {
85                         REDEBUG("Failed to parse time string \"%s\" as format '%s'", vp->vp_strvalue, inst->fmt);
86                         goto error;
87                 }
88
89                 date = mktime(&tminfo);
90                 if (date < 0) {
91                         REDEBUG("Failed converting parsed time into unix time");
92
93                 }
94                 return snprintf(out, outlen, "%" PRIu64, (uint64_t) date);
95
96         default:
97                 REDEBUG("Can't convert type %s into date", fr_int2str(dict_attr_types, vp->da->type, "<INVALID>"));
98         }
99
100         error:
101         *out = '\0';
102         return -1;
103 }
104 DIAG_ON(format-nonliteral)
105
106 static int mod_bootstrap(CONF_SECTION *conf, void *instance)
107 {
108         rlm_date_t *inst = instance;
109
110         inst->xlat_name = cf_section_name2(conf);
111         if (!inst->xlat_name) {
112                 inst->xlat_name = cf_section_name1(conf);
113         }
114
115         xlat_register(inst->xlat_name, xlat_date_convert, NULL, inst);
116
117         return 0;
118 }
119
120 extern module_t rlm_date;
121 module_t rlm_date = {
122         .magic          = RLM_MODULE_INIT,
123         .name           = "date",
124         .inst_size      = sizeof(rlm_date_t),
125         .config         = module_config,
126         .bootstrap      = mod_bootstrap
127 };
128