Replace strncat() with strlcpy()
[freeradius.git] / src / main / log.c
index 216062a..7470897 100644 (file)
  *   along with this program; if not, write to the Free Software
  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  *
- * Copyright 2001  The FreeRADIUS server project
+ * Copyright 2001,2006  The FreeRADIUS server project
  * Copyright 2000  Miquel van Smoorenburg <miquels@cistron.nl>
  * Copyright 2000  Alan DeKok <aland@ox.org>
  * Copyright 2001  Chad Miller <cmiller@surfsouth.com>
  */
 
-static const char rcsid[] = "$Id$";
-
-#include <freeradius-devel/autoconf.h>
-
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <errno.h>
+#include <freeradius-devel/ident.h>
+RCSID("$Id$")
 
 #include <freeradius-devel/radiusd.h>
 
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
 #ifdef HAVE_SYSLOG_H
 #      include <syslog.h>
-/* keep track of whether we've run openlog() */
-static int openlog_run = 0;
 #endif
 
- /*
+/*
  * Logging facility names
  */
-static const LRAD_NAME_NUMBER levels[] = {
+static const FR_NAME_NUMBER levels[] = {
        { ": Debug: ",          L_DBG   },
        { ": Auth: ",           L_AUTH  },
        { ": Proxy: ",          L_PROXY },
        { ": Info: ",           L_INFO  },
+       { ": Acct: ",           L_ACCT  },
        { ": Error: ",          L_ERR   },
        { NULL, 0 }
 };
 
+int log_dates_utc = 0;
+
+
 /*
  *     Log the message to the logfile. Include the severity and
  *     a time stamp.
  */
 int vradlog(int lvl, const char *fmt, va_list ap)
 {
-       int fd = mainconfig.radlog_fd;
-       FILE *fp = NULL;
+       struct main_config_t *myconfig = &mainconfig;
        unsigned char *p;
        char buffer[8192];
-       int len, print_timestamp = 0;
+       int len;
 
        /*
         *      NOT debugging, and trying to log debug messages.
@@ -78,10 +76,13 @@ int vradlog(int lvl, const char *fmt, va_list ap)
         *      If we don't want any messages, then
         *      throw them away.
         */
-       if (mainconfig.radlog_dest == RADLOG_NULL) {
+       if (myconfig->radlog_dest == RADLOG_NULL) {
                return 0;
        }
-       
+
+       *buffer = '\0';
+       len = 0;
+
        /*
         *      Don't print timestamps to syslog, it does that for us.
         *      Don't print timestamps for low levels of debugging.
@@ -89,64 +90,22 @@ int vradlog(int lvl, const char *fmt, va_list ap)
         *      Print timestamps for non-debugging, and for high levels
         *      of debugging.
         */
-       if ((mainconfig.radlog_dest != RADLOG_SYSLOG) &&
+       if ((myconfig->radlog_dest != RADLOG_SYSLOG) &&
            (debug_flag != 1) && (debug_flag != 2)) {
-               print_timestamp = 1;
-       }
-
-       *buffer = '\0';
-       len = 0;
-       if (fd != -1) {
-               /*
-                *      Use it, rather than anything else.
-                */
-
-#ifdef HAVE_SYSLOG_H
-       } else if (mainconfig.radlog_dest == RADLOG_SYSLOG) {
-               /*
-                *      Open run openlog() on the first log message
-                */
-               if(!openlog_run) {
-                       openlog(progname, LOG_PID, mainconfig.syslog_facility);
-                       openlog_run = 1;
-               }
-#endif
-
-       } else if (!mainconfig.log_file) {
-               /*
-                *      Errors go to stderr, in the hope that they will
-                *      be printed somewhere.
-                */
-               if (lvl & L_ERR) {
-                       fd = STDERR_FILENO;
-                       print_timestamp = 0;
-                       snprintf(buffer, sizeof(buffer), "%s: ", progname);
-                       len = strlen(buffer);
-               } else {
-                       /*
-                        *      No log file set.  Discard it.
-                        */
-                       return 0;
-               }
-
-       } else if ((fp = fopen(mainconfig.log_file, "a")) == NULL) {
-               fprintf(stderr, "%s: Couldn't open %s for logging: %s\n",
-                       progname, mainconfig.log_file, strerror(errno));
-               
-               fprintf(stderr, "  (");
-               vfprintf(stderr, fmt, ap);  /* the message that caused the log */
-               fprintf(stderr, ")\n");
-               return -1;
-       }
-
-       if (print_timestamp) {
                const char *s;
                time_t timeval;
 
                timeval = time(NULL);
-               CTIME_R(&timeval, buffer + len, sizeof(buffer) - len - 1);
+#ifdef HAVE_GMTIME_R
+               if (log_dates_utc) {
+                       struct tm utc;
+                       gmtime_r(&timeval, &utc);
+                       asctime_r(&utc, buffer + len);
+               } else
+#endif
+                 CTIME_R(&timeval, buffer + len, sizeof(buffer) - len - 1);
 
-               s = lrad_int2str(levels, (lvl & ~L_CONS), ": ");
+               s = fr_int2str(levels, (lvl & ~L_CONS), ": ");
 
                strcat(buffer, s);
                len = strlen(buffer);
@@ -166,8 +125,10 @@ int vradlog(int lvl, const char *fmt, va_list ap)
        }
        strcat(buffer, "\n");
 
+       switch (myconfig->radlog_dest) {
+
 #ifdef HAVE_SYSLOG_H
-       if (mainconfig.radlog_dest == RADLOG_SYSLOG) {
+       case RADLOG_SYSLOG:
                switch(lvl & ~L_CONS) {
                        case L_DBG:
                                lvl = LOG_DEBUG;
@@ -178,6 +139,9 @@ int vradlog(int lvl, const char *fmt, va_list ap)
                        case L_PROXY:
                                lvl = LOG_NOTICE;
                                break;
+                       case L_ACCT:
+                               lvl = LOG_NOTICE;
+                               break;
                        case L_INFO:
                                lvl = LOG_INFO;
                                break;
@@ -186,14 +150,18 @@ int vradlog(int lvl, const char *fmt, va_list ap)
                                break;
                }
                syslog(lvl, "%s", buffer);
-       } else
+               break;
 #endif
-       if (fp != NULL) {
-               fputs(buffer, fp);
-               fflush(fp);
-               fclose(fp);
-       } else if (fd >= 0) {
-               write(fd, buffer, strlen(buffer));
+
+       case RADLOG_FILES:
+       case RADLOG_STDOUT:
+       case RADLOG_STDERR:
+               write(myconfig->radlog_fd, buffer, strlen(buffer));
+               break;
+
+       default:
+       case RADLOG_NULL:       /* should have been caught above */
+               break;
        }
 
        return 0;
@@ -236,6 +204,131 @@ void vp_listdebug(VALUE_PAIR *vp)
         }
 }
 
+extern char *request_log_file;
+#ifdef HAVE_SYS_UN_H
+extern char *debug_log_file;
+#endif
 
+void radlog_request(int lvl, int priority, REQUEST *request, const char *msg, ...)
+{
+       size_t len = 0;
+       const char *filename = request_log_file;
+       FILE *fp = NULL;
+       va_list ap;
+       char buffer[1024];
 
+       va_start(ap, msg);
 
+       /*
+        *      Debug messages get treated specially.
+        */
+       if (lvl == L_DBG) {
+               /*
+                *      There is log function, but the debug level
+                *      isn't high enough.  OR, we're in debug mode,
+                *      and the debug level isn't high enough.  Return.
+                */
+               if ((request && request->radlog &&
+                    (priority > request->options)) ||
+                   ((debug_flag != 0) && (priority > debug_flag))) {
+                       va_end(ap);
+                       return;
+               }
+
+               /*
+                *      Use the debug output file, if specified,
+                *      otherwise leave it as "request_log_file".
+                */
+#ifdef HAVE_SYS_UN_H
+               filename = debug_log_file;
+               if (!filename)
+#endif
+                 filename = request_log_file;
+
+               /*
+                *      Debug messages get mashed to L_INFO for
+                *      radius.log.
+                */
+               if (!filename) lvl = L_INFO;
+       }
+
+       if (request && filename) {
+               char *p;
+               radlog_func_t rl = request->radlog;
+
+               request->radlog = NULL;
+
+               /*
+                *      This is SLOW!  Doing it for every log message
+                *      in every request is NOT recommended!
+                */
+               
+               radius_xlat(buffer, sizeof(buffer), filename,
+                           request, NULL); /* FIXME: escape chars! */
+               request->radlog = rl;
+               
+               p = strrchr(buffer, FR_DIR_SEP);
+               if (p) {
+                       *p = '\0';
+                       if (rad_mkdir(buffer, S_IRWXU) < 0) {
+                               radlog(L_ERR, "Failed creating %s: %s",
+                                      buffer,strerror(errno));
+                               va_end(ap);
+                               return;
+                       }
+                       *p = FR_DIR_SEP;
+               }
+
+               fp = fopen(buffer, "a");
+       }
+
+       /*
+        *      Print timestamps to the file.
+        */
+       if (fp) {
+               char *s;
+               time_t timeval;
+               timeval = time(NULL);
+
+#ifdef HAVE_GMTIME_R
+               if (log_dates_utc) {
+                       struct tm utc;
+                       gmtime_r(&timeval, &utc);
+                       ASCTIME_R(&utc, buffer + len, sizeof(buffer) - len - 1);
+               } else
+#endif
+               {
+                       CTIME_R(&timeval, buffer + len, sizeof(buffer) - len - 1);
+               }
+
+               s = strrchr(buffer, '\n');
+               if (s) {
+                       s[0] = ' ';
+                       s[1] = '\0';
+               }
+               
+               len = strlen(buffer);
+
+               if (len < sizeof(buffer)) {
+                       len += strlcpy(buffer + len, fr_int2str(levels, (lvl & ~L_CONS), ": "), sizeof(buffer) - len);
+               }
+       }
+       
+       if (request && request->module[0]) {
+               snprintf(buffer + len, sizeof(buffer) - len, "[%s] ", request->module);
+               len = strlen(buffer);
+       }
+       vsnprintf(buffer + len, sizeof(buffer) - len, msg, ap);
+       
+       if (!fp) {
+               radlog(lvl, "%s", buffer);
+       } else {
+               if (strlcat(buffer, "\n", sizeof(buffer)) >= sizeof(buffer)) {
+                       buffer[sizeof(buffer) - 1] = '\n';
+               }
+               fputs(buffer, fp);
+               fclose(fp);
+       }
+
+       va_end(ap);
+}