2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 * @brief Logging functions used by the server core.
23 * @copyright 2000,2006 The FreeRADIUS server project
24 * @copyright 2000 Miquel van Smoorenburg <miquels@cistron.nl>
25 * @copyright 2000 Alan DeKok <aland@ox.org>
26 * @copyright 2001 Chad Miller <cmiller@surfsouth.com>
30 #include <freeradius-devel/radiusd.h>
31 #include <freeradius-devel/rad_assert.h>
33 #ifdef HAVE_SYS_STAT_H
34 # include <sys/stat.h>
49 log_lvl_t rad_debug_lvl = 0; //!< Global debugging level
50 static bool rate_limit = true; //!< Whether repeated log entries should be rate limited
52 /** Maps log categories to message prefixes
54 static const FR_NAME_NUMBER levels[] = {
55 { ": Debug: ", L_DBG },
56 { ": Auth: ", L_AUTH },
57 { ": Proxy: ", L_PROXY },
58 { ": Info: ", L_INFO },
59 { ": Warning: ", L_WARN },
60 { ": Acct: ", L_ACCT },
61 { ": Error: ", L_ERR },
62 { ": WARNING: ", L_DBG_WARN },
63 { ": ERROR: ", L_DBG_ERR },
64 { ": WARNING: ", L_DBG_WARN_REQ },
65 { ": ERROR: ", L_DBG_ERR_REQ },
69 /** @name VT100 escape sequences
71 * These sequences may be written to VT100 terminals to change the
72 * colour and style of the text.
75 fprintf(stdout, VTC_RED "This text will be coloured red" VTC_RESET);
79 #define VTC_RED "\x1b[31m" //!< Colour following text red.
80 #define VTC_YELLOW "\x1b[33m" //!< Colour following text yellow.
81 #define VTC_BOLD "\x1b[1m" //!< Embolden following text.
82 #define VTC_RESET "\x1b[0m" //!< Reset terminal text to default style/colour.
85 /** Maps log categories to VT100 style/colour escape sequences
87 static const FR_NAME_NUMBER colours[] = {
90 { VTC_BOLD, L_PROXY },
94 { VTC_BOLD VTC_YELLOW, L_WARN },
95 { VTC_BOLD VTC_RED, L_DBG_ERR },
96 { VTC_BOLD VTC_YELLOW, L_DBG_WARN },
97 { VTC_BOLD VTC_RED, L_DBG_ERR_REQ },
98 { VTC_BOLD VTC_YELLOW, L_DBG_WARN_REQ },
102 /** Syslog facility table
104 * Maps syslog facility keywords, to the syslog facility macros defined
105 * in the system's syslog.h.
107 * @note Not all facilities are supported by every operating system.
108 * If a facility is unavailable it will not appear in the table.
110 const FR_NAME_NUMBER syslog_facility_table[] = {
112 { "kern", LOG_KERN },
115 { "user", LOG_USER },
118 { "mail", LOG_MAIL },
121 { "daemon", LOG_DAEMON },
124 { "auth", LOG_AUTH },
130 { "news", LOG_NEWS },
133 { "uucp", LOG_UUCP },
136 { "cron", LOG_CRON },
139 { "authpriv", LOG_AUTHPRIV },
145 { "local0", LOG_LOCAL0 },
148 { "local1", LOG_LOCAL1 },
151 { "local2", LOG_LOCAL2 },
154 { "local3", LOG_LOCAL3 },
157 { "local4", LOG_LOCAL4 },
160 { "local5", LOG_LOCAL5 },
163 { "local6", LOG_LOCAL6 },
166 { "local7", LOG_LOCAL7 },
171 /** Syslog severity table
173 * Maps syslog severity keywords, to the syslog severity macros defined
174 * in the system's syslog.h file.
177 const FR_NAME_NUMBER syslog_severity_table[] = {
179 { "emergency", LOG_EMERG },
182 { "alert", LOG_ALERT },
185 { "critical", LOG_CRIT },
188 { "error", LOG_ERR },
191 { "warning", LOG_WARNING },
194 { "notice", LOG_NOTICE },
197 { "info", LOG_INFO },
200 { "debug", LOG_DEBUG },
205 const FR_NAME_NUMBER log_str2dst[] = {
206 { "null", L_DST_NULL },
207 { "files", L_DST_FILES },
208 { "syslog", L_DST_SYSLOG },
209 { "stdout", L_DST_STDOUT },
210 { "stderr", L_DST_STDERR },
211 { NULL, L_DST_NUM_DEST }
214 bool log_dates_utc = false;
216 fr_log_t default_log = {
217 .colourise = false, //!< Will be set later. Should be off before we do terminal detection.
224 static int stderr_fd = -1; //!< The original unmolested stderr file descriptor
225 static int stdout_fd = -1; //!< The original unmolested stdout file descriptor
227 static char const spaces[] = " ";
229 /** On fault, reset STDOUT and STDERR to something useful
233 static int _restore_std(UNUSED int sig)
235 if ((stderr_fd > 0) && (stdout_fd > 0)) {
236 dup2(stderr_fd, STDOUT_FILENO);
237 dup2(stdout_fd, STDERR_FILENO);
241 if (default_log.fd > 0) {
242 dup2(default_log.fd, STDOUT_FILENO);
243 dup2(default_log.fd, STDERR_FILENO);
250 /** Initialise file descriptors based on logging destination
252 * @param log Logger to manipulate.
253 * @param daemonize Whether the server is starting as a daemon.
254 * @return 0 on success -1 on failure.
256 int radlog_init(fr_log_t *log, bool daemonize)
260 rate_limit = daemonize;
263 * If we're running in foreground mode, save STDIN /
264 * STDERR as higher FDs, which won't get used by anyone
265 * else. When we fork/exec a program, it's STD FDs will
266 * get set to pipes. We later set STDOUT / STDERR to
267 * /dev/null, so that any library trying to write to them
268 * doesn't screw anything up.
270 * Then, when something goes wrong, restore them so that
271 * any debugger called from the panic action has access
272 * to STDOUT / STDERR.
275 fr_fault_set_cb(_restore_std);
277 stdout_fd = dup(STDOUT_FILENO);
278 stderr_fd = dup(STDERR_FILENO);
281 devnull = open("/dev/null", O_RDWR);
283 fr_strerror_printf("Error opening /dev/null: %s", fr_syserror(errno));
288 * STDOUT & STDERR go to /dev/null, unless we have "-x",
289 * then STDOUT & STDERR go to the "-l log" destination.
291 * The complexity here is because "-l log" can go to
292 * STDOUT or STDERR, too.
294 if (log->dst == L_DST_STDOUT) {
296 log->fd = STDOUT_FILENO;
299 * If we're debugging, allow STDERR to go to
300 * STDOUT too, for executed programs,
303 dup2(STDOUT_FILENO, STDERR_FILENO);
305 dup2(devnull, STDERR_FILENO);
308 } else if (log->dst == L_DST_STDERR) {
310 log->fd = STDERR_FILENO;
313 * If we're debugging, allow STDOUT to go to
314 * STDERR too, for executed programs,
317 dup2(STDERR_FILENO, STDOUT_FILENO);
319 dup2(devnull, STDOUT_FILENO);
322 } else if (log->dst == L_DST_SYSLOG) {
324 * Discard STDOUT and STDERR no matter what the
325 * status of debugging. Syslog isn't a file
326 * descriptor, so we can't use it.
328 dup2(devnull, STDOUT_FILENO);
329 dup2(devnull, STDERR_FILENO);
331 } else if (rad_debug_lvl) {
333 * If we're debugging, allow STDOUT and STDERR to
334 * go to the log file.
336 dup2(log->fd, STDOUT_FILENO);
337 dup2(log->fd, STDERR_FILENO);
341 * Not debugging, and the log isn't STDOUT or
342 * STDERR. Ensure that we move both of them to
343 * /dev/null, so that the calling terminal can
344 * exit, and the output from executed programs
345 * doesn't pollute STDOUT / STDERR.
347 dup2(devnull, STDOUT_FILENO);
348 dup2(devnull, STDERR_FILENO);
353 fr_fault_set_log_fd(log->fd);
358 /** Send a server log message to its destination
360 * @param type of log message.
361 * @param msg with printf style substitution tokens.
362 * @param ap Substitution arguments.
364 int vradlog(log_type_t type, char const *msg, va_list ap)
367 char buffer[10240]; /* The largest config item size, then extra for prefixes and suffixes */
370 int colourise = default_log.colourise;
373 * If we don't want any messages, then
376 if (default_log.dst == L_DST_NULL) {
384 len += strlcpy(buffer + len, fr_int2str(colours, type, ""), sizeof(buffer) - len) ;
391 * Mark the point where we treat the buffer as unsanitized.
393 unsan = buffer + len;
396 * Don't print timestamps to syslog, it does that for us.
397 * Don't print timestamps and error types for low levels
400 * Print timestamps for non-debugging, and for high levels
403 if (default_log.dst != L_DST_SYSLOG) {
404 if ((rad_debug_lvl != 1) && (rad_debug_lvl != 2)) {
407 timeval = time(NULL);
408 CTIME_R(&timeval, buffer + len, sizeof(buffer) - len - 1);
410 len = strlen(buffer);
411 len += strlcpy(buffer + len, fr_int2str(levels, type, ": "), sizeof(buffer) - len);
412 } else goto add_prefix;
415 if (len < sizeof(buffer)) switch (type) {
417 len += strlcpy(buffer + len, "WARNING: ", sizeof(buffer) - len);
421 len += strlcpy(buffer + len, "ERROR: ", sizeof(buffer) - len);
429 if (len < sizeof(buffer)) {
430 len += vsnprintf(buffer + len, sizeof(buffer) - len - 1, msg, ap);
434 * Filter out control chars and non UTF8 chars
436 for (p = (unsigned char *)unsan; *p != '\0'; p++) {
449 clen = fr_utf8_char(p, -1);
459 if (colourise && (len < sizeof(buffer))) {
460 len += strlcpy(buffer + len, VTC_RESET, sizeof(buffer) - len);
463 if (len < (sizeof(buffer) - 2)) {
465 buffer[len + 1] = '\0';
467 buffer[sizeof(buffer) - 2] = '\n';
468 buffer[sizeof(buffer) - 1] = '\0';
471 switch (default_log.dst) {
502 syslog(type, "%s", buffer);
509 return write(default_log.fd, buffer, strlen(buffer));
512 case L_DST_NULL: /* should have been caught above */
519 /** Send a server log message to its destination
521 * @param type of log message.
522 * @param msg with printf style substitution tokens.
523 * @param ... Substitution arguments.
525 int radlog(log_type_t type, char const *msg, ...)
533 * Non-debug message, or debugging is enabled. Log it.
535 if (((type & L_DBG) == 0) || (rad_debug_lvl > 0)) {
536 r = vradlog(type, msg, ap);
543 /** Send a server log message to its destination without evaluating its debug level
545 * @param type of log message.
546 * @param msg with printf style substitution tokens.
547 * @param ... Substitution arguments.
549 static int radlog_always(log_type_t type, char const *msg, ...) CC_HINT(format (printf, 2, 3));
550 static int radlog_always(log_type_t type, char const *msg, ...)
556 r = vradlog(type, msg, ap);
562 /** Whether a server debug message should be logged
564 * @param type of message.
565 * @param lvl of debugging this message should be logged at.
566 * @return true if message should be logged, else false.
568 inline bool debug_enabled(log_type_t type, log_lvl_t lvl)
570 if ((type & L_DBG) && (lvl <= rad_debug_lvl)) return true;
575 /** Whether rate limiting is enabled
577 bool rate_limit_enabled(void)
579 if (rate_limit || (rad_debug_lvl < 1)) return true;
584 /** Whether a request specific debug message should be logged
586 * @param type of message.
587 * @param lvl of debugging this message should be logged at.
588 * @param request The current request.
589 * @return true if message should be logged, else false.
591 inline bool radlog_debug_enabled(log_type_t type, log_lvl_t lvl, REQUEST *request)
594 * It's a debug class message, note this doesn't mean it's a debug type message.
596 * For example it could be a RIDEBUG message, which would be an informational message,
597 * instead of an RDEBUG message which would be a debug debug message.
599 * There is log function, but the request debug level isn't high enough.
600 * OR, we're in debug mode, and the global debug level isn't high enough,
601 * then don't log the message.
603 if ((type & L_DBG) &&
604 ((request && request->log.func && (lvl <= request->log.lvl)) ||
605 ((rad_debug_lvl != 0) && (lvl <= rad_debug_lvl)))) {
612 /** Send a log message to its destination, possibly including fields from the request
614 * @param type of log message, #L_ERR, #L_WARN, #L_INFO, #L_DBG.
615 * @param lvl Minimum required server or request level to output this message.
616 * @param request The current request.
617 * @param msg with printf style substitution tokens.
618 * @param ap Substitution arguments.
620 void vradlog_request(log_type_t type, log_lvl_t lvl, REQUEST *request, char const *msg, va_list ap)
623 char const *filename = default_log.file;
626 char buffer[10240]; /* The largest config item size, then extra for prefixes and suffixes */
629 char const *extra = "";
636 * Debug messages get treated specially.
638 if ((type & L_DBG) != 0) {
640 if (!radlog_debug_enabled(type, lvl, request)) {
645 * Use the debug output file, if specified,
646 * otherwise leave it as the default log file.
648 #ifdef WITH_COMMAND_SOCKET
649 filename = default_log.debug_file;
653 filename = default_log.file;
658 radlog_func_t rl = request->log.func;
660 request->log.func = NULL;
663 * This is SLOW! Doing it for every log message
664 * in every request is NOT recommended!
666 if (radius_xlat(buffer, sizeof(buffer), request, filename, rad_filename_escape, NULL) < 0) return;
667 request->log.func = rl;
670 * Ensure the directory structure exists, for
671 * where we're going to write the log file.
673 p = strrchr(buffer, FR_DIR_SEP);
676 if (rad_mkdir(buffer, S_IRWXU, -1, -1) < 0) {
677 ERROR("Failed creating %s: %s", buffer, fr_syserror(errno));
683 fp = fopen(buffer, "a");
687 * If we don't copy the original ap we get a segfault from vasprintf. This is apparently
688 * due to ap sometimes being implemented with a stack offset which is invalidated if
689 * ap is passed into another function. See here:
690 * http://julipedia.meroh.net/2011/09/using-vacopy-to-safely-pass-ap.html
692 * I don't buy that explanation, but doing a va_copy here does prevent SEGVs seen when
693 * running unit tests which generate errors under CI.
696 vsnprintf(buffer + len, sizeof(buffer) - len, msg, aq);
700 * Make sure the indent isn't set to something crazy
702 indent = request->log.indent > sizeof(spaces) ?
707 * Logging to a file descriptor
710 char time_buff[64]; /* The current timestamp */
713 timeval = time(NULL);
718 gmtime_r(&timeval, &utc);
719 ASCTIME_R(&utc, time_buff, sizeof(time_buff));
723 CTIME_R(&timeval, time_buff, sizeof(time_buff));
727 * Strip trailing new lines
729 p = strrchr(time_buff, '\n');
732 if (request->module && (request->module[0] != '\0')) {
733 fprintf(fp, "(%u) %s%s%s: %.*s%s\n",
734 request->number, time_buff, fr_int2str(levels, type, ""),
735 request->module, indent, spaces, buffer);
737 fprintf(fp, "(%u) %s%s%.*s%s\n",
738 request->number, time_buff, fr_int2str(levels, type, ""),
739 indent, spaces, buffer);
746 * Logging everywhere else
748 if (!DEBUG_ENABLED3) switch (type) {
751 type = L_DBG_WARN_REQ;
756 type = L_DBG_ERR_REQ;
762 if (request->module && (request->module[0] != '\0')) {
763 radlog_always(type, "(%u) %s: %.*s%s%s", request->number,
764 request->module, indent, spaces, extra, buffer);
766 radlog_always(type, "(%u) %.*s%s%s", request->number,
767 indent, spaces, extra, buffer);
771 /** Martial variadic log arguments into a va_list and pass to normal logging functions
773 * @see radlog_request_error for more details.
775 * @param type the log category.
776 * @param lvl of debugging this message should be logged at.
777 * @param request The current request.
778 * @param msg with printf style substitution tokens.
779 * @param ... Substitution arguments.
781 void radlog_request(log_type_t type, log_lvl_t lvl, REQUEST *request, char const *msg, ...)
787 if (!request->log.func && !(type & L_DBG)) return;
790 if (request->log.func) request->log.func(type, lvl, request, msg, ap);
791 else if (!(type & L_DBG)) vradlog_request(type, lvl, request, msg, ap);
795 /** Martial variadic log arguments into a va_list and pass to error logging functions
797 * This could all be done in a macro, but it turns out some implementations of the
798 * variadic macros do not work at all well if the va_list being written to is further
799 * up the stack (which is required as you still need a function to convert the elipses
802 * So, we use this small wrapper function instead, which will hopefully guarantee
803 * consistent behaviour.
805 * @param type the log category.
806 * @param lvl of debugging this message should be logged at.
807 * @param request The current request.
808 * @param msg with printf style substitution tokens.
809 * @param ... Substitution arguments.
811 void radlog_request_error(log_type_t type, log_lvl_t lvl, REQUEST *request, char const *msg, ...)
818 if (request->log.func) request->log.func(type, lvl, request, msg, ap);
819 else if (!(type & L_DBG)) vradlog_request(type, lvl, request, msg, ap);
820 vmodule_failure_msg(request, msg, ap);
824 /** Write the string being parsed, and a marker showing where the parse error occurred
826 * @param type the log category.
827 * @param lvl of debugging this message should be logged at.
828 * @param request The current request.
829 * @param msg string we were parsing.
830 * @param idx The position of the marker relative to the string.
831 * @param error What the parse error was.
833 void radlog_request_marker(log_type_t type, log_lvl_t lvl, REQUEST *request,
834 char const *msg, size_t idx, char const *error)
836 char const *prefix = "";
841 if (idx >= sizeof(spaces)) {
842 size_t offset = (idx - (sizeof(spaces) - 1)) + (sizeof(spaces) * 0.75);
850 * Don't want format markers being indented
852 indent = request->log.indent;
853 request->log.indent = 0;
855 radlog_request(type, lvl, request, "%s%s", prefix, msg);
856 radlog_request(type, lvl, request, "%s%.*s^ %s", prefix, (int) idx, spaces, error);
858 request->log.indent = indent;
862 /** Canonicalize error strings, removing tabs, and generate spaces for error marker
864 * @note talloc_free must be called on the buffer returned in spaces and text
866 * Used to produce error messages such as this:
868 I'm a string with a parser # error
869 ^ Unexpected character in string
872 * With code resembling this:
874 ERROR("%s", parsed_str);
875 ERROR("%s^ %s", space, text);
878 * @todo merge with above function (radlog_request_marker)
880 * @param sp Where to write a dynamically allocated buffer of spaces used to indent the error text.
881 * @param text Where to write the canonicalized version of msg (the error text).
882 * @param ctx to allocate the spaces and text buffers in.
883 * @param slen of error marker. Expects negative integer value, as returned by parse functions.
884 * @param msg to canonicalize.
886 void fr_canonicalize_error(TALLOC_CTX *ctx, char **sp, char **text, ssize_t slen, char const *msg)
888 size_t offset, skip = 0;
895 * Ensure that the error isn't indented
901 value = talloc_strdup(ctx, msg + skip);
902 memcpy(value, "...", 3);
905 value = talloc_strdup(ctx, msg);
908 spbuf = talloc_array(ctx, char, offset + 1);
909 memset(spbuf, ' ', offset);
910 spbuf[offset] = '\0';
913 * Smash tabs to spaces for the input string.
915 for (p = value; *p != '\0'; p++) {
916 if (*p == '\t') *p = ' ';
921 * Ensure that there isn't too much text after the error.
923 if (strlen(value) > 100) {
924 memcpy(value + 95, "... ", 5);