/* * This program is is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ /** * @file rlm_date.c * @brief Translates timestrings between formats. * * @author Artur Malinowski * * @copyright 2013 Artur Malinowski * @copyright 1999-2013 The FreeRADIUS Server Project. */ #include #include #include #include typedef struct rlm_date_t { char const *xlat_name; char const *fmt; bool utc; } rlm_date_t; static const CONF_PARSER module_config[] = { { "format", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_date_t, fmt), "%b %e %Y %H:%M:%S %Z" }, { "utc", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_date_t, utc), "no" }, CONF_PARSER_TERMINATOR }; DIAG_OFF(format-nonliteral) static ssize_t xlat_date_convert(void *instance, REQUEST *request, char const *fmt, char *out, size_t outlen) { rlm_date_t *inst = instance; time_t date = 0; struct tm tminfo; VALUE_PAIR *vp; memset(&tminfo, 0, sizeof(tminfo)); if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) { *out = '\0'; return 0; } switch (vp->da->type) { /* * These are 'to' types, i.e. we'll convert the integers * to a time structure, and then output it in the specified * format as a string. */ case PW_TYPE_DATE: date = vp->vp_date; goto encode; case PW_TYPE_INTEGER: case PW_TYPE_INTEGER64: date = (time_t) vp->vp_integer; encode: if (!inst->utc) { if (localtime_r(&date, &tminfo) == NULL) { REDEBUG("Failed converting time string to localtime"); goto error; } } else { if (gmtime_r(&date, &tminfo) == NULL) { REDEBUG("Failed converting time string to gmtime"); goto error; } } return strftime(out, outlen, inst->fmt, &tminfo); /* * These are 'from' types, i.e. we'll convert the input string * into a time structure, and then output it as an integer * unix timestamp. */ case PW_TYPE_STRING: if (strptime(vp->vp_strvalue, inst->fmt, &tminfo) == NULL) { REDEBUG("Failed to parse time string \"%s\" as format '%s'", vp->vp_strvalue, inst->fmt); goto error; } if (!inst->utc) { date = mktime(&tminfo); } else { date = timegm(&tminfo); } if (date < 0) { REDEBUG("Failed converting parsed time into unix time"); } return snprintf(out, outlen, "%" PRIu64, (uint64_t) date); default: REDEBUG("Can't convert type %s into date", fr_int2str(dict_attr_types, vp->da->type, "")); } error: *out = '\0'; return -1; } DIAG_ON(format-nonliteral) static int mod_bootstrap(CONF_SECTION *conf, void *instance) { rlm_date_t *inst = instance; inst->xlat_name = cf_section_name2(conf); if (!inst->xlat_name) { inst->xlat_name = cf_section_name1(conf); } xlat_register(inst->xlat_name, xlat_date_convert, NULL, inst); return 0; } extern module_t rlm_date; module_t rlm_date = { .magic = RLM_MODULE_INIT, .name = "date", .inst_size = sizeof(rlm_date_t), .config = module_config, .bootstrap = mod_bootstrap };