syslog patch to rlm_detail in 1.1.0
Geoff Silver
geoff+freeradius at uslinux.net
Mon Feb 27 23:02:38 CET 2006
I had to patch rlm_detail.c so that our auth and accounting logs are sent to a
central syslog server. We have about two dozen radius servers around the
world, so auditing their access is painful. I didn't know if anyone would be
interested in putting this patch into the mainstream release, but I thought
I'd toss it out there. If nobody is interested, then I'll just maintain it
internally for us.
This adds the following configuration options to rlm_digest:
detailfile = syslog - If set to syslog, use syslog. Otherwise it's a file
hidepasswd = {yes,no} - Replace the user's User-Password value with (hidden).
logfacility = <string> - Should be a syslog facility such as auth or local0.
loglevel = <string> - Should be a syslog level such as notice or info.
logname = <string> - Whatever you want to log as (default is "radiusd").
logextra = <string> - Comma-seperated list of additional attributes to log
(since syslog isn't breaking it apart by directory). ie.
"Client-IP-Address = %{Client-IP-Address},NAS-Port=%{NAS-Port}"
In order to avoid duplicating code, rlm_detail now builds a string and then
prints it or syslog's it, rather than printing as it goes along.
Anyhow, here goes:
--- src/modules/rlm_detail/rlm_detail.c.orig 2006-02-27 15:03:45.000000000
-0500
+++ src/modules/rlm_detail/rlm_detail.c 2006-02-27 15:02:49.000000000 -0500
@@ -37,6 +37,14 @@
#include "modules.h"
#define DIRLEN 8192
+#ifdef HAVE_SYSLOG_H
+#define BUFSIZE sizeof(char)*1024
+#define SYSLOG_NAMES
+#include <syslog.h>
+static int pencode(char *);
+static int decode(char *, CODE *);
+#endif
+
static const char *packet_codes[] = {
"",
"Access-Request",
@@ -68,6 +76,21 @@
/* if we want file locking */
int locking;
+
+ /* If logging full info, do we want to hide the password? */
+ char *hidepasswd;
+
+ /* Special info we want logged */
+ char *logextra;
+
+ /* Syslog facility */
+ char *logfacility;
+
+ /* Syslog level */
+ char *loglevel;
+
+ /* Type/Name of log message app */
+ char *logname;
};
static CONF_PARSER module_config[] = {
@@ -79,6 +102,16 @@
offsetof(struct detail_instance,dirperm), NULL, "0755" },
{ "locking", PW_TYPE_BOOLEAN,
offsetof(struct detail_instance,locking), NULL, "no" },
+ { "hidepasswd", PW_TYPE_STRING_PTR,
+ offsetof(struct detail_instance,hidepasswd), NULL, "yes" },
+ { "logextra", PW_TYPE_STRING_PTR,
+ offsetof(struct detail_instance,logextra), NULL, NULL },
+ { "logfacility", PW_TYPE_STRING_PTR,
+ offsetof(struct detail_instance,logfacility), NULL, "local0" },
+ { "loglevel", PW_TYPE_STRING_PTR,
+ offsetof(struct detail_instance,loglevel), NULL, "notice" },
+ { "logname", PW_TYPE_STRING_PTR,
+ offsetof(struct detail_instance,logname), NULL, "radiusd" },
{ NULL, -1, 0, NULL, NULL }
};
@@ -115,6 +148,14 @@
int outfd;
FILE *outfp;
char buffer[DIRLEN];
+ char buffer2[DIRLEN];
+ char extra[DIRLEN];
+ char divider[8];
+ char divider2[8];
+ char *result;
+ char *tostring;
+ char *splitstr;
+ char *buf;
char *p;
struct stat st;
int locked;
@@ -125,6 +166,7 @@
VALUE_PAIR *pair = packet->vps;
struct detail_instance *inst = instance;
+ result = (char *)malloc(BUFSIZE);
/*
* Nothing to log: don't do anything.
@@ -196,6 +238,138 @@
} /* else there was no directory delimiter. */
/*
+ * Determine formatting between attributes, based on method
+ */
+ if (strcmp(buffer, "syslog") == 0) {
+ strcpy(divider, ", ");
+ strcpy(divider2, ", ");
+ } else {
+ strcpy(divider, "\n\t");
+ strcpy(divider2, "\n");
+ }
+
+ /*
+ * Build the output string
+ */
+ /*
+ * Print out names, if they're OK.
+ * Numbers, if not.
+ */
+ strcpy(result, "Packet-Type = ");
+ if ((packet->code > 0) &&
+ (packet->code <= PW_ACCESS_CHALLENGE)) {
+ strcat(result, packet_codes[packet->code]);
+ } else {
+ tostring = (char *)malloc(BUFSIZE);
+ sprintf(tostring, "%d", packet->code);
+ strcat(result, tostring);
+ free(tostring);
+ }
+ /*
+ * Post a timestamp
+ */
+ if (strcmp(buffer, "syslog") != 0) {
+ strcat(result, divider2);
+ strcat(result, strtok(CTIME_R(&request->timestamp, buffer2,
DIRLEN), "\n"));
+ }
+ strcat(result, divider);
+
+
+ /* Write each attribute/value to the log file */
+ while (pair) {
+ /*
+ * Don't print passwords in old format...
+ */
+ if (compat && (pair->attribute == PW_PASSWORD)) {
+ pair = pair->next;
+ continue;
+ }
+
+ /*
+ * Print all of the attributes.
+ */
+ buf = (char *)malloc(BUFSIZE);
+ vp_prints(buf, BUFSIZE, pair);
+ if ((strstr(buf, "User-Password") != 0) &&
+ (strcmp(inst->hidepasswd, "yes") == 0)) {
+ strcat(result, "User-Password = (hidden)");
+ } else {
+ strcat(result, buf);
+ }
+ strcat(result, divider);
+ pair = pair->next;
+ free(buf);
+ }
+
+ /*
+ * Add non-protocol attibutes.
+ */
+ if (compat) {
+ if ((pair = pairfind(request->config_items,
+ PW_PROXY_TO_REALM)) != NULL) {
+ proxy_realm = realm_find(pair->strvalue, TRUE);
+ if (proxy_realm) {
+ memset((char *) proxy_buffer, 0, 16);
+ ip_ntoa(proxy_buffer, proxy_realm->acct_ipaddr);
+ strcat(result, "Freeradius-Proxied-To = ");
+ strcat(result, proxy_buffer);
+ strcat(result, divider);
+ DEBUG("rlm_detail: Freeradius-Proxied-To set
to %s",
+ proxy_buffer);
+ }
+ }
+ tostring = (char *)malloc(BUFSIZE);
+ strcat(result, "Timestamp = ");
+ sprintf(tostring, "%ld", (unsigned long) request->timestamp);
+ strcat(result, tostring);
+ strcat(result, divider);
+ free(tostring);
+
+ if (request->packet->verified == 2) {
+ strcat(result, "Request-Authenticator = Verified");
+ strcat(result, divider);
+ } else if (request->packet->verified == 1) {
+ strcat(result, "Request-Authenticator = None");
+ strcat(result, divider);
+ }
+ }
+
+ if (inst->logextra != NULL) {
+ radius_xlat(extra, sizeof(extra), inst->logextra, request, NULL);
+ DEBUG2("rlm_detail: %s expands to %s", inst->logextra, extra);
+ splitstr = strtok(extra, ",");
+ while (splitstr != NULL)
+ {
+ strcat(result, splitstr);
+ strcat(result, divider);
+ splitstr = strtok(NULL, ",");
+ }
+ }
+
+#ifdef HAVE_SYSLOG_H
+ /*
+ * If the log file name is "syslog", then the user is
+ * requesting this message go to syslog, not to a local
+ * file.
+ */
+ if (strcmp(buffer, "syslog") == 0) {
+ int level;
+ char facil[16];
+
+ strcpy(facil, inst->logfacility);
+ strcat(facil, ".");
+ strcat(facil, inst->loglevel);
+ level = pencode(facil);
+
+ openlog(inst->logname, LOG_CONS | LOG_PID, (level |
LOG_FACMASK)),
+ syslog(level, "%s", result);
+ closelog();
+
+ return RLM_MODULE_OK;
+ }
+#endif
+
+ /*
* Open & create the file, with the given permissions.
*/
if ((outfd = open(buffer, O_WRONLY | O_APPEND | O_CREAT,
@@ -253,74 +427,8 @@
return RLM_MODULE_FAIL;
}
- /*
- * Write the information to the file.
- */
- if (!compat) {
- /*
- * Print out names, if they're OK.
- * Numbers, if not.
- */
- if ((packet->code > 0) &&
- (packet->code <= PW_ACCESS_CHALLENGE)) {
- fprintf(outfp, "Packet-Type = %s\n",
- packet_codes[packet->code]);
- } else {
- fprintf(outfp, "Packet-Type = %d\n", packet->code);
- }
- }
-
- /*
- * Post a timestamp
- */
- fseek(outfp, 0L, SEEK_END);
- fputs(CTIME_R(&request->timestamp, buffer, DIRLEN), outfp);
-
- /* Write each attribute/value to the log file */
- while (pair) {
- /*
- * Don't print passwords in old format...
- */
- if (compat && (pair->attribute == PW_PASSWORD)) {
- pair = pair->next;
- continue;
- }
-
- /*
- * Print all of the attributes.
- */
- fputs("\t", outfp);
- vp_print(outfp, pair);
- fputs("\n", outfp);
- pair = pair->next;
- }
-
- /*
- * Add non-protocol attibutes.
- */
- if (compat) {
- if ((pair = pairfind(request->config_items,
- PW_PROXY_TO_REALM)) != NULL) {
- proxy_realm = realm_find(pair->strvalue, TRUE);
- if (proxy_realm) {
- memset((char *) proxy_buffer, 0, 16);
- ip_ntoa(proxy_buffer, proxy_realm->acct_ipaddr);
- fprintf(outfp, "\tFreeradius-Proxied-To = %s\n",
- proxy_buffer);
- DEBUG("rlm_detail: Freeradius-Proxied-To set
to %s",
- proxy_buffer);
- }
- }
- 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);
- }
-
- fputs("\n", outfp);
+ /* send buffered output to file */
+ fprintf(outfp, "%s\n", result);
if (inst->locking) {
fflush(outfp);
@@ -337,6 +445,52 @@
return RLM_MODULE_OK;
}
+/* Decode a symbolic name to a numeric value
+ * this function is based on code from logger
+ */
+static int pencode(char *s)
+{
+ char *save;
+ int lev, fac = LOG_USER;
+
+ for (save = s; *s && *s != '.'; ++s);
+ if (*s) {
+ *s = '\0';
+ fac = decode(save, facilitynames);
+ if (fac < 0) {
+ fprintf(stderr, "unknown facility name: %s\n", save);
+ exit(FALSE);
+ }
+ *s++ = '.';
+ } else {
+ s = save;
+ }
+ lev = decode(s, prioritynames);
+ if (lev < 0) {
+ fprintf(stderr, "unknown priority name: %s\n", save);
+ exit(FALSE);
+ }
+ return ((lev & LOG_PRIMASK) | (fac & LOG_FACMASK));
+}
+
+/* Help decode a symbolic name to a numeric value
+ * this function is based on code from logger
+ */
+static int decode(char *name, CODE * codetab)
+{
+ CODE *c;
+
+ if (isdigit(*name))
+ return (atoi(name));
+ for (c = codetab; c->c_name; c++) {
+ if (!strcasecmp(name, c->c_name)) {
+ return (c->c_val);
+ }
+ }
+
+ return (-1);
+}
+
/*
* Accounting - write the detail files.
*/
More information about the Freeradius-Devel
mailing list