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