6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 * Copyright 2004,2006 The FreeRADIUS server project
21 * Copyright 2004 Alan DeKok <aland@freeradius.org>
24 #include <freeradius-devel/ident.h>
27 #include <freeradius-devel/radiusd.h>
28 #include <freeradius-devel/modules.h>
51 * Syslog facilities from main/mainconfig.c
53 extern const FR_NAME_NUMBER syslog_str2fac[];
56 * Define a structure for our module configuration.
58 typedef struct rlm_linelog_t {
61 char *syslog_facility;
70 * A mapping of configuration file names to internal variables.
72 * Note that the string is dynamically allocated, so it MUST
73 * be freed. When the configuration file parse re-reads the string,
74 * it free's the old one, and strdup's the new one, placing the pointer
75 * to the strdup'd string into 'config.string'. This gets around
78 static const CONF_PARSER module_config[] = {
79 { "filename", PW_TYPE_STRING_PTR,
80 offsetof(rlm_linelog_t,filename), NULL, NULL},
81 { "syslog_facility", PW_TYPE_STRING_PTR,
82 offsetof(rlm_linelog_t,syslog_facility), NULL, NULL},
83 { "permissions", PW_TYPE_INTEGER,
84 offsetof(rlm_linelog_t,permissions), NULL, "0600"},
85 { "group", PW_TYPE_STRING_PTR,
86 offsetof(rlm_linelog_t,group), NULL, NULL},
87 { "format", PW_TYPE_STRING_PTR,
88 offsetof(rlm_linelog_t,line), NULL, NULL},
89 { "reference", PW_TYPE_STRING_PTR,
90 offsetof(rlm_linelog_t,reference), NULL, NULL},
91 { NULL, -1, 0, NULL, NULL } /* end the list */
95 static int linelog_detach(void *instance)
97 rlm_linelog_t *inst = instance;
104 * Instantiate the module.
106 static int linelog_instantiate(CONF_SECTION *conf, void **instance)
111 * Set up a storage area for instance data
113 inst = rad_malloc(sizeof(*inst));
114 memset(inst, 0, sizeof(*inst));
117 * If the configuration parameters can't be parsed, then
120 if (cf_section_parse(conf, inst, module_config) < 0) {
121 linelog_detach(inst);
125 if (!inst->filename) {
126 radlog(L_ERR, "rlm_linelog: Must specify an output filename");
127 linelog_detach(inst);
131 #ifndef HAVE_SYSLOG_H
132 if (strcmp(inst->filename, "syslog") == 0) {
133 radlog(L_ERR, "rlm_linelog: Syslog output is not supported");
134 linelog_detach(inst);
140 if (inst->syslog_facility) {
141 inst->facility = fr_str2int(syslog_str2fac, inst->syslog_facility, -1);
142 if (inst->facility < 0) {
143 radlog(L_ERR, "rlm_linelog: Bad syslog facility '%s'", inst->syslog_facility);
144 linelog_detach(inst);
149 inst->facility |= LOG_INFO;
153 radlog(L_ERR, "rlm_linelog: Must specify a log format");
154 linelog_detach(inst);
166 * Escape unprintable characters.
168 static size_t linelog_escape_func(char *out, size_t outlen, const char *in)
172 if (outlen == 0) return 0;
181 if (outlen <= 2) break;
188 if (outlen == 1) break;
196 if (outlen <= 2) break;
204 if (outlen <= 2) break;
212 if (outlen <= 4) break;
213 snprintf(out, outlen, "\\%03o", *in);
226 static int do_linelog(void *instance, REQUEST *request)
232 rlm_linelog_t *inst = (rlm_linelog_t*) instance;
233 const char *value = inst->line;
241 if (inst->reference) {
245 radius_xlat(line + 1, sizeof(line) - 2, inst->reference,
246 request, linelog_escape_func);
247 line[0] = '.'; /* force to be in current section */
250 * Don't allow it to go back up
252 if (line[1] == '.') goto do_log;
254 ci = cf_reference_item(NULL, inst->cs, line);
256 RDEBUG2("No such entry \"%s\"", line);
257 return RLM_MODULE_NOOP;
260 if (!cf_item_is_pair(ci)) {
261 RDEBUG2("Entry \"%s\" is not a variable assignment ", line);
265 cp = cf_itemtopair(ci);
266 value = cf_pair_value(cp);
268 RDEBUG2("Entry \"%s\" has no value", line);
273 * Value exists, but is empty. Don't log anything.
275 if (!*value) return RLM_MODULE_OK;
280 * FIXME: Check length.
282 if (strcmp(inst->filename, "syslog") != 0) {
283 radius_xlat(buffer, sizeof(buffer), inst->filename, request,
286 /* check path and eventually create subdirs */
287 p = strrchr(buffer,'/');
290 if (rad_mkdir(buffer, 0700) < 0) {
291 radlog_request(L_ERR, 0, request, "rlm_linelog: Failed to create directory %s: %s", buffer, strerror(errno));
292 return RLM_MODULE_FAIL;
297 fd = open(buffer, O_WRONLY | O_APPEND | O_CREAT, inst->permissions);
299 radlog(L_ERR, "rlm_linelog: Failed to open %s: %s",
300 buffer, strerror(errno));
301 return RLM_MODULE_FAIL;
306 if (inst->group != NULL) {
307 gid = strtol(inst->group, &endptr, 10);
308 if (*endptr != '\0') {
309 grp = getgrnam(inst->group);
311 RDEBUG2("Unable to find system group \"%s\"", inst->group);
317 if (chown(buffer, -1, gid) == -1) {
318 RDEBUG2("Unable to change system group of \"%s\"", buffer);
326 * FIXME: Check length.
328 radius_xlat(line, sizeof(line) - 1, value, request,
329 linelog_escape_func);
334 write(fd, line, strlen(line));
339 syslog(inst->facility, "%s", line);
343 return RLM_MODULE_OK;
348 * Externally visible module definition.
350 module_t rlm_linelog = {
353 RLM_TYPE_CHECK_CONFIG_SAFE, /* type */
354 linelog_instantiate, /* instantiation */
355 linelog_detach, /* detach */
357 do_linelog, /* authentication */
358 do_linelog, /* authorization */
359 do_linelog, /* preaccounting */
360 do_linelog, /* accounting */
361 NULL, /* checksimul */
362 do_linelog, /* pre-proxy */
363 do_linelog, /* post-proxy */
364 do_linelog /* post-auth */
366 , do_linelog, /* recv-coa */
367 do_linelog /* send-coa */