Seeing as were probably going to end up supporting v2.x.x for a while longer...
lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
for dir in $PATH /usr/ucb; do
IFS="$lt_save_ifs"
- if (test -f "$dir/echo" || test -f "$dir/echo$ac_exeext") &&
+ if (test -f $dir/echo || test -f $dir/echo$ac_exeext) &&
test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' &&
echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` &&
test "X$echo_testing_string" = "X$echo_test_string"; then
unistd.h \
crypt.h \
errno.h \
+ execinfo.h \
resource.h \
sys/resource.h \
getopt.h \
unistd.h \
crypt.h \
errno.h \
+ execinfo.h \
resource.h \
sys/resource.h \
getopt.h \
FILES = acct_users attrs attrs.access_reject attrs.accounting_response \
attrs.pre-proxy clients.conf dictionary eap.conf templates.conf \
experimental.conf hints huntgroups ldap.attrmap \
- policy.txt preproxy_users proxy.conf radiusd.conf \
+ panic.gdb policy.txt preproxy_users proxy.conf radiusd.conf \
sql.conf sqlippool.conf users policy.conf attrs.access_challenge
#
--- /dev/null
+info locals
+info args
+thread apply all bt full
+quit
#user = radius
#group = radius
+# panic_action: Command to execute if the server dies unexpectedly.
+#
+# FOR PRODUCTION SYSTEMS, ACTIONS SHOULD ALWAYS EXIT.
+# AN INTERACTIVE ACTION MEANS THE SERVER IS NOT RESPONDING TO REQUESTS.
+# AN INTERACTICE ACTION MEANS THE SERVER WILL NOT RESTART.
+#
+# The panic action is a command which will be executed if the server
+# receives a fatal, non user generated signal, i.e. SIGSEGV, SIGBUS,
+# SIGABRT or SIGFPE.
+#
+# This can be used to start an interactive debugging session so
+# that information regarding the current state of the server can
+# be acquired.
+#
+# The following string substitutions are available:
+# - %e The currently executing program e.g. /sbin/radiusd
+# - %p The PID of the currently executing program e.g. 12345
+#
+# Standard ${} substitutions are also allowed.
+#
+# An example panic action for opening an interactive session in GDB would be:
+#
+#panic_action = "gdb %e %p"
+#
+# Again, don't use that on a production system.
+#
+# An example panic action for opening an automated session in GDB would be:
+#
+#panic_action = "gdb -silent -x ${raddbdir}/panic.gdb %e %p > ${logdir}/gdb-%e-%p.log 2>&1"
+#
+# That command can be used on a production system.
+#
+
# max_request_time: The maximum time (in seconds) to handle a request.
#
# Requests which take more time than this to process may be killed, and
# CLIENTS CONFIGURATION
#
-# Client configuration is defined in "clients.conf".
+# Client configuration is defined in "clients.conf".
#
# The 'clients.conf' file contains all of the information from the old
# listed in any other section. See 'doc/rlm_expr' for
# more information.
#
- # rlm_expr is also responsible for registering many
+ # rlm_expr is also responsible for registering many
# other xlat functions such as md5, sha1 and lc.
#
# We do not recommend removing it's listing here.
/* Define to 1 if you have the <errno.h> header file. */
#undef HAVE_ERRNO_H
+/* Define to 1 if you have the <execinfo.h> header file. */
+#undef HAVE_EXECINFO_H
+
/* Define to 1 if you have the <fcntl.h> header file. */
#undef HAVE_FCNTL_H
/*
* Several handy miscellaneous functions.
*/
+int fr_fault_setup(char const *cmd, char const *program);
+int fr_set_signal(int sig, sig_t func);
const char * ip_ntoa(char *, uint32_t);
char *ifid_ntoa(char *buffer, size_t size, uint8_t *ifid);
uint8_t *ifid_aton(const char *ifid_str, uint8_t *ifid);
int post_proxy_authorize;
#endif
int debug_memory;
+ const char *panic_action;
} MAIN_CONFIG_T;
#define DEBUG if(debug_flag)log_debug
include ../../Make.inc
-SRCS = dict.c filters.c hash.c hmac.c hmacsha1.c isaac.c log.c \
- misc.c missing.c md4.c md5.c print.c radius.c rbtree.c \
- sha1.c snprintf.c strlcat.c strlcpy.c token.c udpfromto.c \
- valuepair.c fifo.c packet.c event.c getaddrinfo.c vqp.c \
- heap.c dhcp.c base64.c
+SRCS = debug.c dict.c filters.c hash.c hmac.c hmacsha1.c isaac.c \
+ log.c misc.c missing.c md4.c md5.c print.c radius.c \
+ rbtree.c sha1.c snprintf.c strlcat.c strlcpy.c token.c \
+ udpfromto.c valuepair.c fifo.c packet.c event.c \
+ getaddrinfo.c vqp.c heap.c dhcp.c base64.c
LT_OBJS = $(SRCS:.c=.lo)
--- /dev/null
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * @file debug.c
+ * @brief Various functions to aid in debugging
+ *
+ * @copyright 2013 The FreeRADIUS server project
+ * @copyright 2013 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ */
+#include <freeradius-devel/libradius.h>
+
+/*
+ * runtime backtrace functions are not POSIX but are included in
+ * glibc, OSX >= 10.5 and various BSDs
+ */
+#ifdef HAVE_EXECINFO_H
+# include <execinfo.h>
+# define MAX_BT_FRAMES 128
+#endif
+
+static char panic_action[512];
+
+/** Prints a simple backtrace (if execinfo is available) and calls panic_action if set.
+ *
+ * @param sig caught
+ */
+static void NEVER_RETURNS _fr_fault(int sig)
+{
+ char cmd[sizeof(panic_action) + 20];
+ char *out = cmd;
+ size_t left = sizeof(cmd), ret;
+
+ char const *p = panic_action;
+ char const *q;
+
+ int code;
+
+ fprintf(stderr, "FATAL SIGNAL: %s\n", strsignal(sig));
+
+ /*
+ * Produce a simple backtrace - They've very basic but at least give us an
+ * idea of the area of the code we hit the issue in.
+ */
+#ifdef HAVE_EXECINFO_H
+ size_t frame_count, i;
+ void *stack[MAX_BT_FRAMES];
+ char **frames;
+
+ frame_count = backtrace(stack, MAX_BT_FRAMES);
+ frames = backtrace_symbols(stack, frame_count);
+
+ fprintf(stderr, "Backtrace of last %zu frames:\n", frame_count);
+ for (i = 0; i < frame_count; i++) {
+ fprintf(stderr, "%s\n", frames[i]);
+ /* Leak the backtrace strings, freeing may lead to undefined behaviour... */
+ }
+#endif
+
+ /* No panic action set... */
+ if (panic_action[0] == '\0') {
+ fprintf(stderr, "No panic action set\n");
+ _exit(1);
+ }
+
+ /* Substitute %p for the current PID (useful for attaching a debugger) */
+ while ((q = strstr(p, "%p"))) {
+ out += ret = snprintf(out, left, "%.*s%d", (int) (q - p), p, (int) getpid());
+ if (left <= ret) {
+ oob:
+ fprintf(stderr, "Panic action too long\n");
+ _exit(1);
+ }
+ left -= ret;
+ p = q + 2;
+ }
+ if (strlen(p) >= left) goto oob;
+ strlcpy(out, p, left);
+
+ fprintf(stderr, "Calling: %s\n", cmd);
+ code = system(cmd);
+ fprintf(stderr, "Panic action exited with %i\n", code);
+
+ _exit(1);
+}
+
+/** Registers signal handlers to execute panic_action on fatal signal
+ *
+ * May be called multiple time to change the panic_action/program.
+ *
+ * @param cmd to execute on fault. If present %p will be substituted
+ * for the parent PID before the command is executed, and %e
+ * will be substituted for the currently running program.
+ * @param program Name of program currently executing (argv[0]).
+ * @return 0 on success -1 on failure.
+ */
+int fr_fault_setup(char const *cmd, char const *program)
+{
+ static int setup = FALSE;
+
+ char *out = panic_action;
+ size_t left = sizeof(panic_action), ret;
+
+ char const *p = cmd;
+ char const *q;
+
+ if (cmd) {
+ /* Substitute %e for the current program */
+ while ((q = strstr(p, "%e"))) {
+ out += ret = snprintf(out, left, "%.*s%s", (int) (q - p), p, program ? program : "");
+ if (left <= ret) {
+ oob:
+ fr_strerror_printf("Panic action too long");
+ return -1;
+ }
+ left -= ret;
+ p = q + 2;
+ }
+ if (strlen(p) >= left) goto oob;
+ strlcpy(out, p, left);
+ } else {
+ *panic_action = '\0';
+ }
+
+ /* Unsure what the side effects of changing the signal handler mid execution might be */
+ if (!setup) {
+#ifdef SIGSEGV
+ if (fr_set_signal(SIGSEGV, _fr_fault) < 0) return -1;
+#endif
+#ifdef SIGBUS
+ if (fr_set_signal(SIGBUS, _fr_fault) < 0) return -1;
+#endif
+#ifdef SIGABRT
+ if (fr_set_signal(SIGABRT, _fr_fault) < 0) return -1;
+#endif
+#ifdef SIGFPE
+ if (fr_set_signal(SIGFPE, _fr_fault) < 0) return -1;
+#endif
+ }
+ setup = TRUE;
+
+ return 0;
+}
int fr_dns_lookups = 0;
int fr_debug_flag = 0;
+/** Sets a signal handler using sigaction if available, else signal
+ *
+ * @param sig to set handler for.
+ * @param func handler to set.
+ */
+int fr_set_signal(int sig, sig_t func)
+{
+#ifdef HAVE_SIGACTION
+ struct sigaction act;
+
+ memset(&act, 0, sizeof(act));
+ act.sa_flags = 0;
+ sigemptyset(&act.sa_mask);
+ act.sa_handler = func;
+
+ if (sigaction(sig, &act, NULL) < 0) {
+ fr_strerror_printf("Failed setting signal %i handler via sigaction(): %s", sig, strerror(errno));
+ return -1;
+ }
+#else
+ if (signal(sig, func) < 0) {
+ fr_strerror_printf("Failed setting signal %i handler via signal(): %s", sig, strerror(errno));
+ return -1;
+ }
+#endif
+ return 0;
+}
+
/*
* Return an IP address in standard dot notation
*
{ "run_dir", PW_TYPE_STRING_PTR, 0, &run_dir, "${localstatedir}/run/${name}"},
{ "libdir", PW_TYPE_STRING_PTR, 0, &radlib_dir, "${prefix}/lib"},
{ "radacctdir", PW_TYPE_STRING_PTR, 0, &radacct_dir, "${logdir}/radacct" },
+ { "panic_action", PW_TYPE_STRING_PTR, 0, &mainconfig.panic_action, NULL},
{ "hostname_lookups", PW_TYPE_BOOLEAN, 0, &fr_dns_lookups, "no" },
{ "max_request_time", PW_TYPE_INTEGER, 0, &mainconfig.max_request_time, Stringify(MAX_REQUEST_TIME) },
{ "cleanup_delay", PW_TYPE_INTEGER, 0, &mainconfig.cleanup_delay, Stringify(CLEANUP_DELAY) },
int flag = 0;
int from_child[2] = {-1, -1};
+ /*
+ * If the server was built with debugging enabled always install
+ * the basic fatal signal handlers.
+ */
+#ifndef NDEBUG
+ fr_fault_setup(getenv("PANIC_ACTION"), argv[0]);
+#endif
+
#ifdef HAVE_SIGACTION
struct sigaction act;
#endif
exit(1);
}
+ /* Set the panic action (if required) */
+ if (mainconfig.panic_action &&
+#ifndef NDEBUG
+ !getenv("PANIC_ACTION") &&
+#endif
+ (fr_fault_setup(mainconfig.panic_action, argv[0]) < 0)) {
+ exit(EXIT_FAILURE);
+ }
+
#ifndef __MINGW32__
/*
* Disconnect from session