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;
52 static CONF_PARSER module_config[] = {
53 { "detailfile", PW_TYPE_STRING_PTR,
54 offsetof(struct detail_instance,detailfile), NULL, "%A/%{Client-IP-Address}/detail" },
55 { "detailperm", PW_TYPE_INTEGER,
56 offsetof(struct detail_instance,detailperm), NULL, "0600" },
57 { "dirperm", PW_TYPE_INTEGER,
58 offsetof(struct detail_instance,dirperm), NULL, "0755" },
59 { NULL, -1, 0, NULL, NULL }
63 * (Re-)read radiusd.conf into memory.
65 static int detail_instantiate(CONF_SECTION *conf, void **instance)
67 struct detail_instance *inst;
69 inst = rad_malloc(sizeof *inst);
71 if (cf_section_parse(conf, inst, module_config) < 0) {
76 inst->last_made_directory = NULL;
83 * Accounting - write the detail files.
85 static int detail_accounting(void *instance, REQUEST *request)
92 int ret = RLM_MODULE_OK;
95 struct detail_instance *inst = instance;
98 * Create a directory for this nas.
100 * Generate the path for the detail file. Use the
101 * same format, but truncate at the last /. Then
102 * feed it through radius_xlat2() to expand the
105 radius_xlat2(buffer, sizeof(buffer), inst->detailfile, request);
106 DEBUG2("rlm_detail: %s expands to %s", inst->detailfile, buffer);
109 * Grab the last directory delimiter.
111 p = strrchr(buffer,'/');
114 * There WAS a directory delimiter there, and
115 * the file doesn't exist, so
116 * we prolly must create it the dir(s)
118 if ((p) && (stat(buffer, &st) < 0)) {
121 * NO previously cached directory name, so we've
122 * got to create a new one.
124 * OR the new directory name is different than the old,
125 * so we've got to create a new one.
127 * OR the cached directory has somehow gotten removed,
128 * so we've got to create a new one.
130 if ((inst->last_made_directory == NULL) ||
131 (strcmp(inst->last_made_directory, buffer) != 0)) {
134 * Free any previously cached name.
136 if (inst->last_made_directory != NULL) {
137 free((char *) inst->last_made_directory);
138 inst->last_made_directory = NULL;
142 * Go create possibly multiple directories.
144 if (rad_mkdir(buffer, inst->dirperm) < 0) {
145 radlog(L_ERR, "rlm_detail: Failed to create directory %s: %s", buffer, strerror(errno));
146 return RLM_MODULE_FAIL;
148 inst->last_made_directory = strdup(buffer);
152 } /* else there was no directory delimiter. */
155 * Open & create the file, with the given permissions.
157 if ((outfd = open(buffer, O_WRONLY|O_APPEND|O_CREAT,
158 inst->detailperm)) < 0) {
159 radlog(L_ERR, "rlm_detail: Couldn't open file %s: %s",
160 buffer, strerror(errno));
161 ret = RLM_MODULE_FAIL;
163 } else if ((outfp = fdopen(outfd, "a")) == NULL) {
164 radlog(L_ERR, "rlm_detail: Couldn't open file %s: %s",
165 buffer, strerror(errno));
166 ret = RLM_MODULE_FAIL;
169 /* Post a timestamp */
170 fputs(ctime(&request->timestamp), outfp);
172 /* Write each attribute/value to the log file */
173 pair = request->packet->vps;
175 if (pair->attribute != PW_PASSWORD) {
177 vp_print(outfp, pair);
184 * Add non-protocol attibutes.
186 fprintf(outfp, "\tTimestamp = %ld\n", request->timestamp);
187 if (request->packet->verified)
188 fputs("\tRequest-Authenticator = Verified\n", outfp);
190 fputs("\tRequest-Authenticator = None\n", outfp);
202 static int detail_detach(void *instance)
204 struct detail_instance *inst = instance;
205 free((char *) inst->detailfile);
207 if (inst->last_made_directory)
208 free((char*) inst->last_made_directory);
214 /* globally exported name */
215 module_t rlm_detail = {
217 0, /* type: reserved */
218 NULL, /* initialization */
219 detail_instantiate, /* instantiation */
221 NULL, /* authentication */
222 NULL, /* authorization */
223 NULL, /* preaccounting */
224 detail_accounting, /* accounting */
225 NULL /* checksimul */
227 detail_detach, /* detach */