* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*
- * Copyright 2000 The FreeRADIUS server project
+ * Copyright 2000,2006 The FreeRADIUS server project
*/
-static const char rcsid[] = "$Id$";
+#include <freeradius-devel/ident.h>
+RCSID("$Id$")
-#include <freeradius-devel/autoconf.h>
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/rad_assert.h>
+#include <freeradius-devel/detail.h>
#include <sys/stat.h>
-#include <sys/select.h>
-
-#include <stdlib.h>
-#include <string.h>
#include <ctype.h>
#include <fcntl.h>
-#include <freeradius-devel/radiusd.h>
-#include <freeradius-devel/modules.h>
-#include <freeradius-devel/rad_assert.h>
-
#define DIRLEN 8192
-static const char *packet_codes[] = {
- "",
- "Access-Request",
- "Access-Accept",
- "Access-Reject",
- "Accounting-Request",
- "Accounting-Response",
- "Accounting-Status",
- "Password-Request",
- "Password-Accept",
- "Password-Reject",
- "Accounting-Message",
- "Access-Challenge"
-};
-
-
struct detail_instance {
/* detail file */
char *detailfile;
/* if we want file locking */
int locking;
- lrad_hash_table_t *ht;
+ /* log src/dst information */
+ int log_srcdst;
+
+ fr_hash_table_t *ht;
};
static const CONF_PARSER module_config[] = {
offsetof(struct detail_instance,dirperm), NULL, "0755" },
{ "locking", PW_TYPE_BOOLEAN,
offsetof(struct detail_instance,locking), NULL, "no" },
+ { "log_packet_header", PW_TYPE_BOOLEAN,
+ offsetof(struct detail_instance,log_srcdst), NULL, "no" },
{ NULL, -1, 0, NULL, NULL }
};
static int detail_detach(void *instance)
{
struct detail_instance *inst = instance;
- free((char *) inst->detailfile);
-
free((char*) inst->last_made_directory);
-
- if (inst->ht) lrad_hash_table_free(inst->ht);
+ if (inst->ht) fr_hash_table_free(inst->ht);
free(inst);
return 0;
static uint32_t detail_hash(const void *data)
{
const DICT_ATTR *da = data;
- return lrad_hash(&(da->attr), sizeof(da->attr));
+ return fr_hash(&(da->attr), sizeof(da->attr));
}
static int detail_cmp(const void *a, const void *b)
if (cs) {
CONF_ITEM *ci;
- inst->ht = lrad_hash_table_create(detail_hash, detail_cmp,
+ inst->ht = fr_hash_table_create(detail_hash, detail_cmp,
NULL);
for (ci = cf_item_find_next(cs, NULL);
DICT_ATTR *da;
if (!cf_item_is_pair(ci)) continue;
-
+
attr = cf_pair_attr(cf_itemtopair(ci));
if (!attr) continue; /* pair-anoia */
* since the suppression list will usually
* be small, it doesn't matter.
*/
- if (!lrad_hash_table_insert(inst->ht, da)) {
+ if (!fr_hash_table_insert(inst->ht, da)) {
radlog(L_ERR, "rlm_detail: Failed trying to remember %s", attr);
detail_detach(inst);
return -1;
int locked;
int lock_count;
struct timeval tv;
- REALM *proxy_realm;
- char proxy_buffer[16];
- VALUE_PAIR *pair = packet->vps;
+ VALUE_PAIR *pair;
struct detail_instance *inst = instance;
+ rad_assert(request != NULL);
+
/*
* Nothing to log: don't do anything.
*/
* variables.
*/
radius_xlat(buffer, sizeof(buffer), inst->detailfile, request, NULL);
- DEBUG2("rlm_detail: %s expands to %s", inst->detailfile, buffer);
+ RDEBUG2("%s expands to %s", inst->detailfile, buffer);
/*
* Grab the last directory delimiter.
* deleted a directory that the server was using.
*/
if (rad_mkdir(inst->last_made_directory, inst->dirperm) < 0) {
- radlog(L_ERR, "rlm_detail: Failed to create directory %s: %s", inst->last_made_directory, strerror(errno));
+ radlog_request(L_ERR, 0, request, "rlm_detail: Failed to create directory %s: %s", inst->last_made_directory, strerror(errno));
return RLM_MODULE_FAIL;
}
*/
if ((outfd = open(buffer, O_WRONLY | O_APPEND | O_CREAT,
inst->detailperm)) < 0) {
- radlog(L_ERR, "rlm_detail: Couldn't open file %s: %s",
+ radlog_request(L_ERR, 0, request, "rlm_detail: Couldn't open file %s: %s",
buffer, strerror(errno));
return RLM_MODULE_FAIL;
}
* the lock (race condition)
*/
if (fstat(outfd, &st) != 0) {
- radlog(L_ERR, "rlm_detail: Couldn't stat file %s: %s",
+ radlog_request(L_ERR, 0, request, "rlm_detail: Couldn't stat file %s: %s",
buffer, strerror(errno));
close(outfd);
return RLM_MODULE_FAIL;
}
if (st.st_nlink == 0) {
- DEBUG("rlm_detail: File %s removed by another program, retrying",
+ RDEBUG2("File %s removed by another program, retrying",
buffer);
close(outfd);
lock_count = 0;
continue;
}
- DEBUG("rlm_detail: Acquired filelock, tried %d time(s)",
+ RDEBUG2("Acquired filelock, tried %d time(s)",
lock_count + 1);
locked = 1;
}
if (inst->locking && !locked) {
close(outfd);
- radlog(L_ERR, "rlm_detail: Failed to aquire filelock for %s, giving up",
+ radlog_request(L_ERR, 0, request, "rlm_detail: Failed to acquire filelock for %s, giving up",
buffer);
return RLM_MODULE_FAIL;
}
* after this operation.
*/
if ((outfp = fdopen(outfd, "a")) == NULL) {
- radlog(L_ERR, "rlm_detail: Couldn't open file %s: %s",
+ radlog_request(L_ERR, 0, request, "rlm_detail: Couldn't open file %s: %s",
buffer, strerror(errno));
if (inst->locking) {
lseek(outfd, 0L, SEEK_SET);
rad_unlockfd(outfd, 0);
- DEBUG("rlm_detail: Released filelock");
+ RDEBUG2("Released filelock");
}
close(outfd); /* automatically releases the lock */
}
/*
+ * Post a timestamp
+ */
+ fseek(outfp, 0L, SEEK_END);
+ radius_xlat(timestamp, sizeof(timestamp), inst->header, request, NULL);
+ fprintf(outfp, "%s\n", timestamp);
+
+ /*
* Write the information to the file.
*/
if (!compat) {
* Numbers, if not.
*/
if ((packet->code > 0) &&
- (packet->code <= PW_ACCESS_CHALLENGE)) {
- fprintf(outfp, "Packet-Type = %s\n",
- packet_codes[packet->code]);
+ (packet->code < FR_MAX_PACKET_CODE)) {
+ fprintf(outfp, "\tPacket-Type = %s\n",
+ fr_packet_codes[packet->code]);
} else {
- fprintf(outfp, "Packet-Type = %d\n", packet->code);
+ fprintf(outfp, "\tPacket-Type = %d\n", packet->code);
}
}
- /*
- * Post a timestamp
- */
- fseek(outfp, 0L, SEEK_END);
- radius_xlat(timestamp, sizeof(timestamp), inst->header, request, NULL);
- fprintf(outfp, "%s\n", timestamp);
+ if (inst->log_srcdst) {
+ VALUE_PAIR src_vp, dst_vp;
+
+ memset(&src_vp, 0, sizeof(src_vp));
+ memset(&dst_vp, 0, sizeof(dst_vp));
+ src_vp.operator = dst_vp.operator = T_OP_EQ;
+
+ switch (packet->src_ipaddr.af) {
+ case AF_INET:
+ src_vp.type = PW_TYPE_IPADDR;
+ src_vp.attribute = PW_PACKET_SRC_IP_ADDRESS;
+ src_vp.vp_ipaddr = packet->src_ipaddr.ipaddr.ip4addr.s_addr;
+ dst_vp.type = PW_TYPE_IPADDR;
+ dst_vp.attribute = PW_PACKET_DST_IP_ADDRESS;
+ dst_vp.vp_ipaddr = packet->dst_ipaddr.ipaddr.ip4addr.s_addr;
+ break;
+ case AF_INET6:
+ src_vp.type = PW_TYPE_IPV6ADDR;
+ src_vp.attribute = PW_PACKET_SRC_IPV6_ADDRESS;
+ memcpy(src_vp.vp_strvalue,
+ &packet->src_ipaddr.ipaddr.ip6addr,
+ sizeof(packet->src_ipaddr.ipaddr.ip6addr));
+ dst_vp.type = PW_TYPE_IPV6ADDR;
+ dst_vp.attribute = PW_PACKET_DST_IPV6_ADDRESS;
+ memcpy(dst_vp.vp_strvalue,
+ &packet->dst_ipaddr.ipaddr.ip6addr,
+ sizeof(packet->dst_ipaddr.ipaddr.ip6addr));
+ break;
+ default:
+ break;
+ }
+
+ fputs("\t", outfp);
+ vp_print(outfp, &src_vp);
+ fputs("\n", outfp);
+ fputs("\t", outfp);
+ vp_print(outfp, &dst_vp);
+ fputs("\n", outfp);
+
+ src_vp.attribute = PW_PACKET_SRC_PORT;
+ src_vp.type = PW_TYPE_INTEGER;
+ src_vp.vp_integer = packet->src_port;
+ dst_vp.attribute = PW_PACKET_DST_PORT;
+ dst_vp.type = PW_TYPE_INTEGER;
+ dst_vp.vp_integer = packet->dst_port;
+
+ fputs("\t", outfp);
+ vp_print(outfp, &src_vp);
+ fputs("\n", outfp);
+ fputs("\t", outfp);
+ vp_print(outfp, &dst_vp);
+ fputs("\n", outfp);
+ }
/* Write each attribute/value to the log file */
- for (; pair != NULL; pair = pair->next) {
+ for (pair = packet->vps; pair != NULL; pair = pair->next) {
DICT_ATTR da;
da.attr = pair->attribute;
if (inst->ht &&
- lrad_hash_table_finddata(inst->ht, &da)) continue;
+ fr_hash_table_finddata(inst->ht, &da)) continue;
/*
* Don't print passwords in old format...
*/
- if (compat && (pair->attribute == PW_PASSWORD)) continue;
+ if (compat && (pair->attribute == PW_USER_PASSWORD)) continue;
/*
* Print all of the attributes.
* Add non-protocol attibutes.
*/
if (compat) {
- if ((pair = pairfind(request->config_items,
- PW_PROXY_TO_REALM)) != NULL) {
- proxy_realm = realm_find(pair->vp_strvalue, TRUE);
- if (proxy_realm) {
- memset((char *) proxy_buffer, 0, 16);
-
- rad_assert(proxy_realm->acct_ipaddr.af == AF_INET);
-
- inet_ntop(proxy_realm->acct_ipaddr.af,
- &proxy_realm->acct_ipaddr.ipaddr,
- proxy_buffer, sizeof(proxy_buffer));
- fprintf(outfp, "\tFreeradius-Proxied-To = %s\n",
+#ifdef WITH_PROXY
+ if (request->proxy) {
+ char proxy_buffer[128];
+
+ inet_ntop(request->proxy->dst_ipaddr.af,
+ &request->proxy->dst_ipaddr.ipaddr,
+ proxy_buffer, sizeof(proxy_buffer));
+ fprintf(outfp, "\tFreeradius-Proxied-To = %s\n",
proxy_buffer);
- DEBUG("rlm_detail: Freeradius-Proxied-To set to %s",
+ RDEBUG("Freeradius-Proxied-To = %s",
proxy_buffer);
- }
}
+#endif
+
fprintf(outfp, "\tTimestamp = %ld\n",
(unsigned long) request->timestamp);
- if (request->packet->verified == 2)
- fputs("\tRequest-Authenticator = Verified\n", outfp);
- else if (request->packet->verified == 1)
- fputs("\tRequest-Authenticator = None\n", outfp);
+ /*
+ * We no longer permit Accounting-Request packets
+ * with an authenticator of zero.
+ */
+ fputs("\tRequest-Authenticator = Verified\n", outfp);
}
fputs("\n", outfp);
fflush(outfp);
lseek(outfd, 0L, SEEK_SET);
rad_unlockfd(outfd, 0);
- DEBUG("rlm_detail: Released filelock");
+ RDEBUG2("Released filelock");
}
fclose(outfp);
*/
static int detail_accounting(void *instance, REQUEST *request)
{
+ if (request->listener->type == RAD_LISTEN_DETAIL &&
+ strcmp(((struct detail_instance *)instance)->detailfile,
+ ((listen_detail_t *)request->listener->data)->filename) == 0) {
+ RDEBUG("Suppressing writes to detail file as the request was just read from a detail file.");
+ return RLM_MODULE_NOOP;
+ }
return do_detail(instance,request,request->packet, TRUE);
}
return do_detail(instance,request,request->reply, FALSE);
}
+#ifdef WITH_COA
+/*
+ * Incoming CoA - write the detail files.
+ */
+static int detail_recv_coa(void *instance, REQUEST *request)
+{
+ return do_detail(instance,request,request->packet, FALSE);
+}
+
+/*
+ * Outgoing CoA - write the detail files.
+ */
+static int detail_send_coa(void *instance, REQUEST *request)
+{
+ return do_detail(instance,request,request->reply, FALSE);
+}
+#endif
/*
* Outgoing Access-Request to home server - write the detail files.
*/
+#ifdef WITH_PROXY
static int detail_pre_proxy(void *instance, REQUEST *request)
{
if (request->proxy &&
return do_detail(instance,request,request->proxy_reply, FALSE);
}
+ /*
+ * No reply: we must be doing Post-Proxy-Type = Fail.
+ *
+ * Note that we just call the normal accounting function,
+ * to minimize the amount of code, and to highlight that
+ * it's doing normal accounting.
+ */
+ if (!request->proxy_reply) {
+ int rcode;
+
+ rcode = detail_accounting(instance, request);
+ if (rcode == RLM_MODULE_OK) {
+ request->reply->code = PW_ACCOUNTING_RESPONSE;
+ }
+ return rcode;
+ }
+
return RLM_MODULE_NOOP;
}
+#endif
/* globally exported name */
module_t rlm_detail = {
RLM_MODULE_INIT,
"detail",
- RLM_TYPE_THREAD_UNSAFE, /* type: reserved */
+ RLM_TYPE_THREAD_UNSAFE | RLM_TYPE_CHECK_CONFIG_SAFE | RLM_TYPE_HUP_SAFE,
detail_instantiate, /* instantiation */
detail_detach, /* detach */
{
NULL, /* preaccounting */
detail_accounting, /* accounting */
NULL, /* checksimul */
+#ifdef WITH_PROXY
detail_pre_proxy, /* pre-proxy */
detail_post_proxy, /* post-proxy */
+#else
+ NULL, NULL,
+#endif
detail_postauth /* post-auth */
+#ifdef WITH_COA
+ , detail_recv_coa,
+ detail_send_coa
+#endif
},
};