]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Link to libcap to determine process capabilities
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Mon, 3 Nov 2014 20:00:04 +0000 (15:00 -0500)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Tue, 4 Nov 2014 03:03:11 +0000 (22:03 -0500)
This lets us know whether the debugger attach check is failing because
we don't have CAP_SYS_PTRACE or because there really is another
debugger attached already.

configure
configure.ac
src/include/autoconf.h.in
src/include/libradius.h
src/lib/debug.c
src/main/radiusd.c

index 70dc00d678e4ac470f64bed433a230089d27550b..61f9213671c6461d9add2cbf4800ae31d34c4ec0 100755 (executable)
--- a/configure
+++ b/configure
@@ -763,6 +763,8 @@ with_pcap_lib_dir
 with_pcap_include_dir
 with_collectdclient_lib_dir
 with_collectdclient_include_dir
+with_cap_lib_dir
+with_cap_include_dir
 with_execinfo_lib_dir
 with_execinfo_include_dir
 with_pcre_lib_dir
@@ -1448,6 +1450,9 @@ Optional Packages:
   --with-collectdclient-include-dir=DIR
                           directory in which to look for collectdclient
                           include files
+  --with-cap-lib-dir=DIR  directory in which to look for cap library files
+  --with-cap-include-dir=DIR
+                          directory in which to look for cap include files
   --with-execinfo-lib-dir=DIR
                           directory in which to look for execinfo library
                           files
@@ -4390,7 +4395,7 @@ else
     We can't simply define LARGE_OFF_T to be 9223372036854775807,
     since some C++ compilers masquerading as C compilers
     incorrectly reject 9223372036854775807.  */
-#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
   int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
                       && LARGE_OFF_T % 2147483647 == 1)
                      ? 1 : -1];
@@ -4436,7 +4441,7 @@ else
     We can't simply define LARGE_OFF_T to be 9223372036854775807,
     since some C++ compilers masquerading as C compilers
     incorrectly reject 9223372036854775807.  */
-#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
   int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
                       && LARGE_OFF_T % 2147483647 == 1)
                      ? 1 : -1];
@@ -4460,7 +4465,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
     We can't simply define LARGE_OFF_T to be 9223372036854775807,
     since some C++ compilers masquerading as C compilers
     incorrectly reject 9223372036854775807.  */
-#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
   int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
                       && LARGE_OFF_T % 2147483647 == 1)
                      ? 1 : -1];
@@ -4505,7 +4510,7 @@ else
     We can't simply define LARGE_OFF_T to be 9223372036854775807,
     since some C++ compilers masquerading as C compilers
     incorrectly reject 9223372036854775807.  */
-#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
   int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
                       && LARGE_OFF_T % 2147483647 == 1)
                      ? 1 : -1];
@@ -4529,7 +4534,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
     We can't simply define LARGE_OFF_T to be 9223372036854775807,
     since some C++ compilers masquerading as C compilers
     incorrectly reject 9223372036854775807.  */
-#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
   int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
                       && LARGE_OFF_T % 2147483647 == 1)
                      ? 1 : -1];
@@ -6898,6 +6903,225 @@ else
 fi
 LIBS="${old_LIBS}"
 
+cap_lib_dir=
+
+# Check whether --with-cap-lib-dir was given.
+if test "${with_cap_lib_dir+set}" = set; then :
+  withval=$with_cap_lib_dir; case "$withval" in
+    no)
+      as_fn_error $? "Need cap-lib-dir" "$LINENO" 5
+      ;;
+    yes)
+      ;;
+    *)
+      cap_lib_dir="$withval"
+      ;;
+  esac
+fi
+
+
+cap_include_dir=
+
+# Check whether --with-cap-include-dir was given.
+if test "${with_cap_include_dir+set}" = set; then :
+  withval=$with_cap_include_dir; case "$withval" in
+    no)
+      as_fn_error $? "Need cap-include-dir" "$LINENO" 5
+      ;;
+    yes)
+      ;;
+    *)
+      cap_include_dir="$withval"
+      ;;
+  esac
+fi
+
+
+smart_try_dir="$cap_lib_dir"
+
+
+sm_lib_safe=`echo "cap" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "cap_get_proc" | sed 'y%./+-%__p_%'`
+
+old_LIBS="$LIBS"
+old_CPPFLAGS="$CPPFLAGS"
+smart_lib=
+smart_ldflags=
+smart_lib_dir=
+
+if test "x$smart_try_dir" != "x"; then
+  for try in $smart_try_dir; do
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for cap_get_proc in -lcap in $try" >&5
+$as_echo_n "checking for cap_get_proc in -lcap in $try... " >&6; }
+    LIBS="-lcap $old_LIBS"
+    CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+extern char cap_get_proc();
+int
+main ()
+{
+cap_get_proc()
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+                smart_lib="-lcap"
+                smart_ldflags="-L$try -Wl,-rpath,$try"
+                { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+                break
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  done
+  LIBS="$old_LIBS"
+  CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_lib" = "x"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for cap_get_proc in -lcap" >&5
+$as_echo_n "checking for cap_get_proc in -lcap... " >&6; }
+  LIBS="-lcap $old_LIBS"
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+extern char cap_get_proc();
+int
+main ()
+{
+cap_get_proc()
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+               smart_lib="-lcap"
+               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  LIBS="$old_LIBS"
+fi
+
+if test "x$smart_lib" = "x"; then
+
+
+if test "x$LOCATE" != "x"; then
+        DIRS=
+  file=libcap${libltdl_cv_shlibext}
+
+  for x in `${LOCATE} $file 2>/dev/null`; do
+                                        base=`echo $x | sed "s%/${file}%%"`
+    if test "x$x" = "x$base"; then
+      continue;
+    fi
+
+    dir=`${DIRNAME} $x 2>/dev/null`
+                exclude=`echo ${dir} | ${GREP} /home`
+    if test "x$exclude" != "x"; then
+      continue
+    fi
+
+                    already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+    if test "x$already" = "x"; then
+      DIRS="$DIRS $dir"
+    fi
+  done
+fi
+
+eval "smart_lib_dir=\"\$smart_lib_dir $DIRS\""
+
+
+
+if test "x$LOCATE" != "x"; then
+        DIRS=
+  file=libcap.a
+
+  for x in `${LOCATE} $file 2>/dev/null`; do
+                                        base=`echo $x | sed "s%/${file}%%"`
+    if test "x$x" = "x$base"; then
+      continue;
+    fi
+
+    dir=`${DIRNAME} $x 2>/dev/null`
+                exclude=`echo ${dir} | ${GREP} /home`
+    if test "x$exclude" != "x"; then
+      continue
+    fi
+
+                    already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+    if test "x$already" = "x"; then
+      DIRS="$DIRS $dir"
+    fi
+  done
+fi
+
+eval "smart_lib_dir=\"\$smart_lib_dir $DIRS\""
+
+
+  for try in $smart_lib_dir /usr/local/lib /opt/lib; do
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for cap_get_proc in -lcap in $try" >&5
+$as_echo_n "checking for cap_get_proc in -lcap in $try... " >&6; }
+    LIBS="-lcap $old_LIBS"
+    CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+extern char cap_get_proc();
+int
+main ()
+{
+cap_get_proc()
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+                 smart_lib="-lcap"
+                 smart_ldflags="-L$try -Wl,-rpath,$try"
+                 { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+                 break
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  done
+  LIBS="$old_LIBS"
+  CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_lib" != "x"; then
+  eval "ac_cv_lib_${sm_lib_safe}_${sm_func_safe}=yes"
+  LIBS="$smart_ldflags $smart_lib $old_LIBS"
+  SMART_LIBS="$smart_ldflags $smart_lib $SMART_LIBS"
+fi
+
+if test "x$ac_cv_lib_cap_cap_get_proc" != "xyes"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cap library not found, debugger checks will not be enabled. Use --with-cap-lib-dir=<path>." >&5
+$as_echo "$as_me: WARNING: cap library not found, debugger checks will not be enabled. Use --with-cap-lib-dir=<path>." >&2;}
+else
+
+$as_echo "#define HAVE_LIBCAP 1" >>confdefs.h
+
+  HAVE_LIBCAP=1
+fi
+
 
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a readline compatible library" >&5
 $as_echo_n "checking for a readline compatible library... " >&6; }
@@ -8941,6 +9165,247 @@ $as_echo "$as_me: WARNING: collectdclient headers not found. Use --with-collectd
   fi
 fi
 
+if test "x$HAVE_LIBCAP" = x; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: skipping test for cap.h." >&5
+$as_echo "$as_me: skipping test for cap.h." >&6;}
+else
+        smart_try_dir="$cap_include_dir"
+
+
+ac_safe=`echo "sys/capability.h" | sed 'y%./+-%__pm%'`
+old_CPPFLAGS="$CPPFLAGS"
+smart_include=
+smart_include_dir="/usr/local/include /opt/include"
+
+_smart_try_dir=
+_smart_include_dir=
+
+for _prefix in $smart_prefix ""; do
+  for _dir in $smart_try_dir; do
+    _smart_try_dir="${_smart_try_dir} ${_dir}/${_prefix}"
+  done
+
+  for _dir in $smart_include_dir; do
+    _smart_include_dir="${_smart_include_dir} ${_dir}/${_prefix}"
+  done
+done
+
+if test "x$_smart_try_dir" != "x"; then
+  for try in $_smart_try_dir; do
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sys/capability.h in $try" >&5
+$as_echo_n "checking for sys/capability.h in $try... " >&6; }
+    CPPFLAGS="-isystem $try $old_CPPFLAGS"
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+                   #include <sys/capability.h>
+int
+main ()
+{
+int a = 1;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+                    smart_include="-isystem $try"
+                    { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+                    break
+
+else
+
+                    smart_include=
+                    { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+  CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_include" = "x"; then
+  for _prefix in $smart_prefix; do
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${_prefix}/sys/capability.h" >&5
+$as_echo_n "checking for ${_prefix}/sys/capability.h... " >&6; }
+
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+                   #include <sys/capability.h>
+int
+main ()
+{
+int a = 1;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+                    smart_include="-isystem ${_prefix}/"
+                    { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+                    break
+
+else
+
+                    smart_include=
+                    { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+fi
+
+if test "x$smart_include" = "x"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sys/capability.h" >&5
+$as_echo_n "checking for sys/capability.h... " >&6; }
+
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+                   #include <sys/capability.h>
+int
+main ()
+{
+int a = 1;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+                    smart_include=" "
+                    { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+                    break
+
+else
+
+                    smart_include=
+                    { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+if test "x$smart_include" = "x"; then
+
+  for prefix in $smart_prefix; do
+
+
+if test "x$LOCATE" != "x"; then
+        DIRS=
+  file="${_prefix}/${1}"
+
+  for x in `${LOCATE} $file 2>/dev/null`; do
+                                        base=`echo $x | sed "s%/${file}%%"`
+    if test "x$x" = "x$base"; then
+      continue;
+    fi
+
+    dir=`${DIRNAME} $x 2>/dev/null`
+                exclude=`echo ${dir} | ${GREP} /home`
+    if test "x$exclude" != "x"; then
+      continue
+    fi
+
+                    already=`echo \$_smart_include_dir ${DIRS} | ${GREP} ${dir}`
+    if test "x$already" = "x"; then
+      DIRS="$DIRS $dir"
+    fi
+  done
+fi
+
+eval "_smart_include_dir=\"\$_smart_include_dir $DIRS\""
+
+  done
+
+
+if test "x$LOCATE" != "x"; then
+        DIRS=
+  file=sys/capability.h
+
+  for x in `${LOCATE} $file 2>/dev/null`; do
+                                        base=`echo $x | sed "s%/${file}%%"`
+    if test "x$x" = "x$base"; then
+      continue;
+    fi
+
+    dir=`${DIRNAME} $x 2>/dev/null`
+                exclude=`echo ${dir} | ${GREP} /home`
+    if test "x$exclude" != "x"; then
+      continue
+    fi
+
+                    already=`echo \$_smart_include_dir ${DIRS} | ${GREP} ${dir}`
+    if test "x$already" = "x"; then
+      DIRS="$DIRS $dir"
+    fi
+  done
+fi
+
+eval "_smart_include_dir=\"\$_smart_include_dir $DIRS\""
+
+
+  for try in $_smart_include_dir; do
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sys/capability.h in $try" >&5
+$as_echo_n "checking for sys/capability.h in $try... " >&6; }
+    CPPFLAGS="-isystem $try $old_CPPFLAGS"
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+                   #include <sys/capability.h>
+int
+main ()
+{
+int a = 1;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+                    smart_include="-isystem $try"
+                    { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+                    break
+
+else
+
+                    smart_include=
+                    { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+  CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_include" != "x"; then
+  eval "ac_cv_header_$ac_safe=yes"
+  CPPFLAGS="$smart_include $old_CPPFLAGS"
+  SMART_CPPFLAGS="$smart_include $SMART_CPPFLAGS"
+fi
+
+smart_prefix=
+
+  if test "x$ac_cv_header_sys_capability_h" == "xyes"; then
+
+$as_echo "#define HAVE_CAPABILITY_H 1" >>confdefs.h
+
+  else
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cap headers not found, will not perform debugger checks. Use --with-cap-include-dir=<path>." >&5
+$as_echo "$as_me: WARNING: cap headers not found, will not perform debugger checks. Use --with-cap-include-dir=<path>." >&2;}
+  fi
+fi
+
 
 ac_fn_c_check_type "$LINENO" "off_t" "ac_cv_type_off_t" "$ac_includes_default"
 if test "x$ac_cv_type_off_t" = xyes; then :
index 3daca299f9d6bc193e6227fdc0c6da2b0c6b9a20..c9ba53e0fe3a76ecdbe659727776ad8f49a485de 100644 (file)
@@ -887,6 +887,50 @@ fi
 dnl Set by FR_SMART_CHECKLIB
 LIBS="${old_LIBS}"
 
+dnl Check for cap
+dnl extra argument: --with-cap-lib-dir=DIR
+cap_lib_dir=
+AC_ARG_WITH(cap-lib-dir,
+  [AS_HELP_STRING([--with-cap-lib-dir=DIR],
+  [directory in which to look for cap library files])],
+  [case "$withval" in
+    no)
+      AC_MSG_ERROR([Need cap-lib-dir])
+      ;;
+    yes)
+      ;;
+    *)
+      cap_lib_dir="$withval"
+      ;;
+  esac])
+
+dnl extra argument: --with-cap-include-dir=DIR
+cap_include_dir=
+AC_ARG_WITH(cap-include-dir,
+  [AS_HELP_STRING([--with-cap-include-dir=DIR],
+  [directory in which to look for cap include files])],
+  [case "$withval" in
+    no)
+      AC_MSG_ERROR([Need cap-include-dir])
+      ;;
+    yes)
+      ;;
+    *)
+      cap_include_dir="$withval"
+      ;;
+  esac])
+
+smart_try_dir="$cap_lib_dir"
+FR_SMART_CHECK_LIB(cap, cap_get_proc)
+if test "x$ac_cv_lib_cap_cap_get_proc" != "xyes"; then
+  AC_MSG_WARN([cap library not found, debugger checks will not be enabled. Use --with-cap-lib-dir=<path>.])
+else
+  AC_DEFINE(HAVE_LIBCAP, 1,
+    [Define to 1 if you have the `cap' library (-lcap).]
+  )
+  HAVE_LIBCAP=1
+fi
+
 VL_LIB_READLINE
 
 dnl #############################################################
@@ -1151,6 +1195,24 @@ else
   fi
 fi
 
+dnl #
+dnl #  Check the CAP includes for debugger checks
+dnl #
+if test "x$HAVE_LIBCAP" = x; then
+  AC_MSG_NOTICE([skipping test for cap.h.])
+else
+  dnl #
+  dnl # Check for CAP header files
+  dnl #
+  smart_try_dir="$cap_include_dir"
+  FR_SMART_CHECK_INCLUDE([sys/capability.h])
+  if test "x$ac_cv_header_sys_capability_h" == "xyes"; then
+    AC_DEFINE(HAVE_CAPABILITY_H, 1, [Define to 1 if you have the <sys/capability.h> header file.])
+  else
+    AC_MSG_WARN([cap headers not found, will not perform debugger checks. Use --with-cap-include-dir=<path>.])
+  fi
+fi
+
 dnl #############################################################
 dnl #
 dnl #  4. Checks for typedefs
index f5000491b6afbf54a8c74ef445385f64362d927a..85ab10032a9869ce25ca490e3d61d11fdcb20c40 100644 (file)
@@ -33,6 +33,9 @@
 /* Define if the compiler supports __builtin_types_compatible_p */
 #undef HAVE_BUILTIN_TYPES_COMPATIBLE_P
 
+/* Define to 1 if you have the <sys/capability.h> header file. */
+#undef HAVE_CAPABILITY_H
+
 /* Define to 1 if you have the `closefrom' function. */
 #undef HAVE_CLOSEFROM
 
 /* define if you have IP_PKTINFO (Linux) */
 #undef HAVE_IP_PKTINFO
 
+/* Define to 1 if you have the `cap' library (-lcap). */
+#undef HAVE_LIBCAP
+
 /* Define to 1 if you have the `crypto' library (-lcrypto). */
 #undef HAVE_LIBCRYPTO
 
index a9cf09530f40e3a34bcbf9a3312569481675b826..81ea3247d126f21dca536f314ac4001e37ead032 100644 (file)
@@ -767,11 +767,18 @@ void              fr_cbuff_rp_insert(fr_cbuff_t *cbuff, void *obj);
 void           *fr_cbuff_rp_next(fr_cbuff_t *cbuff, TALLOC_CTX *ctx);
 
 /* debug.c */
-
+typedef enum {
+       DEBUG_STATE_UNKNOWN_NO_PTRACE           = -3,   //!< We don't have ptrace so can't check.
+       DEBUG_STATE_UNKNOWN_NO_PTRACE_CAP       = -2,   //!< CAP_SYS_PTRACE not set for the process.
+       DEBUG_STATE_UNKNOWN                     = -1,   //!< Unknown, likely fr_get_debug_state() not called yet.
+       DEBUG_STATE_NOT_ATTACHED                = 0,    //!< We can attach, so a debugger must not be.
+       DEBUG_STATE_ATTACHED                    = 1     //!< We can't attach, it's likely a debugger is already tracing.
+} fr_debug_state_t;
 
 #define FR_FAULT_LOG(fmt, ...) fr_fault_log(fmt "\n", ## __VA_ARGS__)
 typedef void (*fr_fault_log_t)(char const *msg, ...) CC_HINT(format (printf, 1, 2));
 extern fr_fault_log_t fr_fault_log;
+extern fr_debug_state_t fr_debug_state;
 
 /** Optional callback passed to fr_fault_setup
  *
@@ -785,6 +792,8 @@ extern fr_fault_log_t fr_fault_log;
 typedef int (*fr_fault_cb_t)(int signum);
 typedef struct fr_bt_marker fr_bt_marker_t;
 
+void           fr_store_debug_state(void);
+char const     *fr_debug_state_to_msg(fr_debug_state_t state);
 void           fr_debug_break(void);
 void           backtrace_print(fr_cbuff_t *cbuff, void *obj);
 int            fr_backtrace_do(fr_bt_marker_t *marker);
index c8f6d77062ce02efabd554275d23307997bffbbd..780e560d230ef23080bb48236c8bdcf4e61e644e 100644 (file)
@@ -98,7 +98,7 @@ static void CC_HINT(format (printf, 1, 2)) _fr_fault_log(char const *msg, ...);
 fr_fault_log_t fr_fault_log = _fr_fault_log;           //!< Function to use to process logging output.
 static int fr_fault_log_fd = STDERR_FILENO;            //!< Where to write debug output.
 
-static int debugger_attached = -1;                     //!< Whether were attached to by a debugger.
+fr_debug_state_t fr_debug_state = DEBUG_STATE_UNKNOWN; //!< Whether were attached to by a debugger.
 
 #ifdef HAVE_SYS_RESOURCE_H
 static struct rlimit core_limits;
@@ -114,30 +114,76 @@ static TALLOC_CTX *talloc_autofree_ctx;
 #    define _PTRACE(_x, _y) ptrace(_x, _y, NULL, 0)
 #  endif
 
+#  ifdef HAVE_CAPABILITY_H
+#    include <sys/capability.h>
+#  endif
+
 /** Determine if we're running under a debugger by attempting to attach using pattach
  *
- * @return 0 if we're not, EPERM if we are, -1 if we can't tell.
+ * @return 0 if we're not, 1 if we are, -1 if we can't tell because of an error,
+ *     -2 if we can't tell because we don't have the CAP_SYS_PTRACE capability.
  */
-static int fr_debugger_attached(void)
+static int fr_get_debug_state(void)
 {
        int pid;
 
        int from_child[2] = {-1, -1};
 
+#ifdef HAVE_CAPABILITY_H
+       cap_flag_value_t value;
+       cap_t current;
+
+       /*
+        *  If we're running under linux, we first need to check if we have
+        *  permission to to ptrace. We do that using the capabilities
+        *  functions.
+        */
+       current = cap_get_proc();
+       if (!current) {
+               fr_strerror_printf("Failed getting process capabilities: %s", fr_syserror(errno));
+               return DEBUG_STATE_UNKNOWN;
+       }
+
+       if (cap_get_flag(current, CAP_SYS_PTRACE, CAP_PERMITTED, &value) < 0) {
+               fr_strerror_printf("Failed getting permitted ptrace capability state: %s",
+                                  fr_syserror(errno));
+               cap_free(current);
+               return DEBUG_STATE_UNKNOWN;
+       }
+
+       if ((value == CAP_SET) && (cap_get_flag(current, CAP_SYS_PTRACE, CAP_EFFECTIVE, &value) < 0)) {
+               fr_strerror_printf("Failed getting effective ptrace capability state: %s",
+                                  fr_syserror(errno));
+               cap_free(current);
+               return DEBUG_STATE_UNKNOWN;
+       }
+
+       /*
+        *  We don't have permission to ptrace, so this test will always fail.
+        */
+       if (value == CAP_CLEAR) {
+               fr_strerror_printf("ptrace capability not set.  If debugger detection is required run as root or: "
+                                  "setcap cap_sys_ptrace+ep <path_to_radiusd>");
+               cap_free(current);
+               return DEBUG_STATE_UNKNOWN_NO_PTRACE_CAP;
+       }
+       cap_free(current);
+#endif
+
        if (pipe(from_child) < 0) {
-               fr_strerror_printf("Debugger check failed: Error opening internal pipe: %s", fr_syserror(errno));
-               return -1;
+               fr_strerror_printf("Error opening internal pipe: %s", fr_syserror(errno));
+               return DEBUG_STATE_UNKNOWN;
        }
 
        pid = fork();
        if (pid == -1) {
-               fr_strerror_printf("Debugger check failed: Error forking: %s", fr_syserror(errno));
-               return -1;
+               fr_strerror_printf("Error forking: %s", fr_syserror(errno));
+               return DEBUG_STATE_UNKNOWN;
        }
 
        /* Child */
        if (pid == 0) {
-               int ret = 0;
+               int8_t ret = DEBUG_STATE_NOT_ATTACHED;
                int ppid = getppid();
 
                /* Close parent's side */
@@ -165,7 +211,7 @@ static int fr_debugger_attached(void)
                        exit(0);
                }
 
-               ret = errno;
+               ret = DEBUG_STATE_ATTACHED;
                /* Tell the parent what happened */
                if (write(from_child[1], &ret, sizeof(ret)) < 0) {
                        fprintf(stderr, "Writing ptrace status to parent failed: %s", fr_syserror(errno));
@@ -174,7 +220,7 @@ static int fr_debugger_attached(void)
                exit(0);
        /* Parent */
        } else {
-               int ret = -1;
+               int8_t ret = DEBUG_STATE_UNKNOWN;
 
                /*
                 *      The child writes errno (reason) if pattach failed else 0.
@@ -184,14 +230,6 @@ static int fr_debugger_attached(void)
                 */
                while ((read(from_child[0], &ret, sizeof(ret)) < 0) && (errno == EINTR));
 
-               /* Ret not updated */
-               if (ret < 0) {
-                       fr_strerror_printf("Debugger check failed: Error getting status from child: %s",
-                                          fr_syserror(errno));
-               } else {
-                       fr_strerror_printf("Failed attaching to process: %s", fr_syserror(errno));
-               }
-
                /* Close the pipes here (if we did it above, it might race with pattach) */
                close(from_child[1]);
                close(from_child[0]);
@@ -203,14 +241,60 @@ static int fr_debugger_attached(void)
        }
 }
 #else
-static int fr_debugger_attached(void)
+static int fr_get_debug_state(void)
 {
-       fr_strerror_printf("Debugger check failed: PTRACE not available");
+       fr_strerror_printf("PTRACE not available");
 
-       return -1;
+       return DEBUG_STATE_UNKNOWN_NO_PTRACE;
 }
 #endif
 
+/** Should be run before using setuid or setgid to get useful results
+ *
+ * @note sets the fr_debug_state global.
+ */
+void fr_store_debug_state(void)
+{
+       fr_debug_state = fr_get_debug_state();
+
+#ifndef NDEBUG
+       /*
+        *  There are many reasons why this might happen with
+        *  a vanilla install, so we don't want to spam users
+        *  with messages they won't understand and may not
+        *  want to resolve.
+        */
+       if (fr_debug_state < 0) fprintf(stderr, "Getting debug state failed: %s\n", fr_strerror());
+#endif
+}
+
+/** Return current value of debug_state
+ *
+ * @param state to translate into a humanly readable value.
+ * @return humanly readable version of debug state.
+ */
+char const *fr_debug_state_to_msg(fr_debug_state_t state)
+{
+       switch (state) {
+       case DEBUG_STATE_UNKNOWN_NO_PTRACE:
+               return "Debug state unknown (ptrace functionality not available)";
+
+       case DEBUG_STATE_UNKNOWN_NO_PTRACE_CAP:
+               return "Debug state unknown (cap_sys_ptrace capability not set)";
+
+       case DEBUG_STATE_UNKNOWN:
+               return "Debug state unknown";
+
+       case DEBUG_STATE_ATTACHED:
+               return "Found debugger attached";
+
+       case DEBUG_STATE_NOT_ATTACHED:
+               return "Debugger not attached";
+       }
+
+       return "<INVALID>";
+}
+
 /** Break in debugger (if were running under a debugger)
  *
  * If the server is running under a debugger this will raise a
@@ -220,11 +304,8 @@ static int fr_debugger_attached(void)
  */
 void fr_debug_break(void)
 {
-       if (debugger_attached == -1) {
-               debugger_attached = fr_debugger_attached();
-       }
-
-       if (debugger_attached == 1) {
+       if (fr_debug_state < 0) fr_debug_state = fr_get_debug_state();
+       if (fr_debug_state == DEBUG_STATE_ATTACHED) {
                fprintf(stderr, "Debugger detected, raising SIGTRAP\n");
                fflush(stderr);
 
@@ -545,7 +626,7 @@ void fr_fault(int sig)
         *      The only exception are SIGUSR1 and SIGUSR2 which print out various
         *      debugging info, and should be allowed to continue.
         */
-       if (debugger_attached && (sig != SIGUSR1) && (sig != SIGUSR2)) {
+       if (fr_debug_state && (sig != SIGUSR1) && (sig != SIGUSR2)) {
                FR_FAULT_LOG("RAISING SIGNAL: %s", strsignal(sig));
                raise(sig);
                goto finish;
@@ -802,8 +883,6 @@ int fr_fault_setup(char const *cmd, char const *program)
 
        /* Unsure what the side effects of changing the signal handler mid execution might be */
        if (!setup) {
-               int ret;
-
                /*
                 *  Setup the default logger
                 */
@@ -813,15 +892,20 @@ int fr_fault_setup(char const *cmd, char const *program)
                /*
                 *  Figure out if we were started under a debugger
                 */
-
-               ret = fr_debugger_attached();
+               if (fr_debug_state < 0) fr_debug_state = fr_get_debug_state();
 
                /*
                 *  These signals can't be properly dealt with in the debugger
-                *  if we set our own signal handlers
+                *  if we set our own signal handlers.
                 */
-               if (ret == 0) {
-                       debugger_attached = 0;
+               switch (fr_debug_state) {
+               default:
+#ifndef NDEBUG
+                       FR_FAULT_LOG("Debugger check failed: %s", fr_strerror());
+                       FR_FAULT_LOG("Signal processing in debuggers may not work as expected");
+#endif
+
+               case 0:
 #ifdef SIGABRT
                        if (fr_set_signal(SIGABRT, fr_fault) < 0) return -1;
 
@@ -840,12 +924,10 @@ int fr_fault_setup(char const *cmd, char const *program)
 #ifdef SIGSEGV
                        if (fr_set_signal(SIGSEGV, fr_fault) < 0) return -1;
 #endif
+                       break;
 
-
-               } else {
-                       debugger_attached = 1;
-
-                       FR_FAULT_LOG("Not enabling panic action signal handlers: %s", fr_strerror());
+               case 1:
+                       break;
                }
 #ifdef SIGUSR1
                if (fr_set_signal(SIGUSR1, fr_fault) < 0) return -1;
index bc285bd7a1f95ac06a9e1bfeba9d0d2d311f29c0..75cd6e52cd3d6f9f19a51ac3db691a25e7914382 100644 (file)
@@ -106,17 +106,6 @@ int main(int argc, char *argv[])
         */
        TALLOC_CTX *autofree = talloc_init("main");
 
-       /*
-        *      If the server was built with debugging enabled always install
-        *      the basic fatal signal handlers.
-        */
-#ifndef NDEBUG
-       if (fr_fault_setup(getenv("PANIC_ACTION"), argv[0]) < 0) {
-               fr_perror("radiusd");
-               exit(EXIT_FAILURE);
-       }
-#endif
-
 #ifdef OSFC2
        set_auth_parameters(argc,argv);
 #endif
@@ -333,9 +322,14 @@ int main(int argc, char *argv[])
                exit(EXIT_SUCCESS);
        }
 
-       if (debug_flag) {
-               version();
-       }
+       if (debug_flag) version();
+
+       /*
+        *  Under linux CAP_SYS_PTRACE is usually only available before
+        *  setuid/setguid, so we need to check whether we can attach before
+        *  calling those functions (in main_config_init()).
+        */
+       fr_store_debug_state();
 
        /*
         *  Initialising OpenSSL once, here, is safer than having individual
@@ -358,6 +352,9 @@ int main(int argc, char *argv[])
                exit(EXIT_FAILURE);
        }
 
+       /*  This is very useful in figuring out why the panic_action didn't fire */
+       DEBUG("radiusd: #### %s ####", fr_debug_state_to_msg(fr_debug_state));
+
        /*  Check for vulnerabilities in the version of libssl were linked against */
 #ifdef HAVE_OPENSSL_CRYPTO_H
 #ifdef ENABLE_OPENSSL_VERSION_CHECK