2 * rlm_detail.c accounting: Write the "detail" files.
6 * This program is is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License, version 2 if the
8 * License as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 * Copyright 2000 The FreeRADIUS server project
22 static const char rcsid[] = "$Id$";
25 #include "libradius.h"
38 struct detail_instance {
42 /* detail file permissions */
45 /* directory permissions */
48 /* last made directory */
49 char *last_made_directory;
53 * A temporary holding area for config values to be extracted
54 * into, before they are copied into the instance data
56 static struct detail_instance config;
58 static CONF_PARSER module_config[] = {
59 { "detailfile", PW_TYPE_STRING_PTR, &config.detailfile, "%A/%{Client-IP-Address}/detail" },
60 { "detailperm", PW_TYPE_INTEGER, &config.detailperm, "0600" },
61 { "dirperm", PW_TYPE_INTEGER, &config.dirperm, "0755" },
62 { NULL, -1, NULL, NULL }
66 * (Re-)read radiusd.conf into memory.
68 static int detail_instantiate(CONF_SECTION *conf, void **instance)
70 struct detail_instance *inst;
72 inst = rad_malloc(sizeof *inst);
74 if (cf_section_parse(conf, module_config) < 0) {
79 inst->detailfile = config.detailfile;
80 inst->detailperm = config.detailperm;
81 inst->dirperm = config.dirperm;
82 inst->last_made_directory = NULL;
83 config.detailfile = NULL;
90 * Accounting - write the detail files.
92 static int detail_accounting(void *instance, REQUEST *request)
99 int ret = RLM_MODULE_OK;
102 struct detail_instance *inst = instance;
105 * Create a directory for this nas.
107 * Generate the path for the detail file. Use the
108 * same format, but truncate at the last /. Then
109 * feed it through radius_xlat2() to expand the
112 radius_xlat2(buffer, sizeof(buffer), inst->detailfile, request);
113 DEBUG2("rlm_detail: %s expands to %s", inst->detailfile, buffer);
116 * Grab the last directory delimiter.
118 p = strrchr(buffer,'/');
121 * There WAS a directory delimiter there, and
122 * the file doesn't exist, so
123 * we prolly must create it the dir(s)
125 if ((p) && (stat(buffer, &st) < 0)) {
128 * NO previously cached directory name, so we've
129 * got to create a new one.
131 * OR the new directory name is different than the old,
132 * so we've got to create a new one.
134 * OR the cached directory has somehow gotten removed,
135 * so we've got to create a new one.
137 if ((inst->last_made_directory == NULL) ||
138 (strcmp(inst->last_made_directory, buffer) != 0)) {
141 * Free any previously cached name.
143 if (inst->last_made_directory != NULL) {
144 free((char *) inst->last_made_directory);
145 inst->last_made_directory = NULL;
149 * Go create possibly multiple directories.
151 if (rad_mkdir(buffer, inst->dirperm) < 0) {
152 radlog(L_ERR, "rlm_detail: Failed to create directory %s: %s", buffer, strerror(errno));
153 return RLM_MODULE_FAIL;
155 inst->last_made_directory = strdup(buffer);
159 } /* else there was no directory delimiter. */
162 * Open & create the file, with the given permissions.
164 if ((outfd = open(buffer, O_WRONLY|O_APPEND|O_CREAT,
165 inst->detailperm)) < 0) {
166 radlog(L_ERR, "rlm_detail: Couldn't open file %s: %s",
167 buffer, strerror(errno));
168 ret = RLM_MODULE_FAIL;
170 } else if ((outfp = fdopen(outfd, "a")) == NULL) {
171 radlog(L_ERR, "rlm_detail: Couldn't open file %s: %s",
172 buffer, strerror(errno));
173 ret = RLM_MODULE_FAIL;
176 /* Post a timestamp */
177 fputs(ctime(&request->timestamp), outfp);
179 /* Write each attribute/value to the log file */
180 pair = request->packet->vps;
182 if (pair->attribute != PW_PASSWORD) {
184 vp_print(outfp, pair);
191 * Add non-protocol attibutes.
193 fprintf(outfp, "\tTimestamp = %ld\n", request->timestamp);
194 if (request->packet->verified)
195 fputs("\tRequest-Authenticator = Verified\n", outfp);
197 fputs("\tRequest-Authenticator = None\n", outfp);
209 static int detail_detach(void *instance)
211 struct detail_instance *inst = instance;
212 free((char *) inst->detailfile);
214 if (inst->last_made_directory)
215 free((char*) inst->last_made_directory);
221 /* globally exported name */
222 module_t rlm_detail = {
224 0, /* type: reserved */
225 NULL, /* initialization */
226 detail_instantiate, /* instantiation */
227 NULL, /* authorization */
228 NULL, /* authentication */
229 NULL, /* preaccounting */
230 detail_accounting, /* accounting */
231 NULL, /* checksimul */
232 detail_detach, /* detach */